Skip to content

Commit

Permalink
Merge branch 'master' into test-remove-leaky-handles
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathanong authored Aug 31, 2024
2 parents edd319e + b95dfcb commit 0af97fe
Show file tree
Hide file tree
Showing 8 changed files with 1,297 additions and 917 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:

strategy:
matrix:
node-version: [18.x, 20.x]
node-version: [18.x, 20.x, 22.x]

steps:
- uses: actions/checkout@v4
Expand All @@ -25,3 +25,4 @@ jobs:
- run: npm run lint
- run: npm test -- --coverage --maxWorkers 2
- run: npx codecov
continue-on-error: true
40 changes: 40 additions & 0 deletions __tests__/lib/search-params.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const sp = require('../../lib/search-params')
const assert = require('assert')

describe('search-params', () => {
describe('stringify', () => {
it('Should stringify a simple object', () => {
assert.deepStrictEqual(sp.stringify({ a: 1, b: 'b' }), 'a=1&b=b')
})

it('Should stringify an object with an array', () => {
assert.deepStrictEqual(sp.stringify({ a: [1, 2] }), 'a=1&a=2')
})

it('Should stringify an object with an array with a single value', () => {
assert.deepStrictEqual(sp.stringify({ a: [1] }), 'a=1')
})

it('Stringify an object with an array with a single empty value', () => {
assert.deepStrictEqual(sp.stringify({ a: [''] }), 'a=')
})

it('Should not stringify an object with a nested object', () => {
assert.deepStrictEqual(sp.stringify({ a: { b: 1 } }), 'a=')
})
})

describe('parse', () => {
it('Should parse a simple query string', () => {
assert.deepStrictEqual(sp.parse('a=1&b=2'), { a: '1', b: '2' })
})

it('Should parse a query string with same key and multiple values', () => {
assert.deepEqual(sp.parse('a=1&a=2'), { a: ['1', '2'] })
})

it('Should parse a query string with an array with a single empty value', () => {
assert.deepStrictEqual(sp.parse('a='), { a: '' })
})
})
})
21 changes: 21 additions & 0 deletions docs/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
- [Response Middleware](#response-middleware)
- [Async operations](#async-operations)
- [Debugging Koa](#debugging-koa)
- [HTTP2](#http2)

## Writing Middleware

Expand Down Expand Up @@ -246,3 +247,23 @@ app.use(publicFiles);
```
koa:application use static /public +0ms
```

## HTTP2

Example of setting up an HTTP2 server with Koa using the HTTP compatibility layer:

```js
import Koa from 'koa'
import http2 from 'node:http2'
import fs from 'node:fs'

const app = new Koa();

const onRequestHandler = app.callback();
const serverOptions = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
}

const server = http2.createSecureServer(serverOptions, onRequestHandler);
```
1 change: 1 addition & 0 deletions docs/koa-vs-express.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
| Sending Files | || |
| JSONP | || |

> NOTE: this doesn't mean Koa is incapable of supporting these features, these features are simply supported by other modules (middleware, plugins, etc.) versus the framework itself.
Thus, if you'd like to be closer to Node.js and traditional Node.js-style coding, you probably want to stick to Connect/Express or similar frameworks.
If you want to get rid of callbacks, use Koa.
Expand Down
8 changes: 4 additions & 4 deletions lib/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ const accepts = require('accepts')
const contentType = require('content-type')
const stringify = require('url').format
const parse = require('parseurl')
const qs = require('querystring')
const sp = require('./search-params.js')

const typeis = require('type-is')
const fresh = require('fresh')
const only = require('./only.js')
Expand Down Expand Up @@ -171,7 +172,7 @@ module.exports = {
get query () {
const str = this.querystring
const c = this._querycache = this._querycache || {}
return c[str] || (c[str] = qs.parse(str))
return c[str] || (c[str] = sp.parse(str))
},

/**
Expand All @@ -182,7 +183,7 @@ module.exports = {
*/

set query (obj) {
this.querystring = qs.stringify(obj)
this.querystring = sp.stringify(obj)
},

/**
Expand Down Expand Up @@ -210,7 +211,6 @@ module.exports = {

url.search = str
url.path = null

this.url = stringify(url)
},

Expand Down
33 changes: 33 additions & 0 deletions lib/search-params.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const URLSearchParams = require('url').URLSearchParams

module.exports = {
stringify: (obj) => {
const searchParams = new URLSearchParams()
const addKey = (k, v, params) => {
const val = typeof v === 'string' || typeof v === 'number' ? v : ''
params.append(k, val)
}

for (const [key, value] of Object.entries(obj)) {
if (Array.isArray(value)) {
const lgth = value.length
for (let i = 0; i < lgth; i++) {
addKey(key, value[i], searchParams)
}
} else {
addKey(key, value, searchParams)
}
}
return searchParams.toString()
},

parse: (str) => {
const searchParams = new URLSearchParams(str)
const obj = {}
for (const key of searchParams.keys()) {
const values = searchParams.getAll(key)
obj[key] = values.length <= 1 ? values[0] : values
}
return obj
}
}
Loading

0 comments on commit 0af97fe

Please sign in to comment.