Skip to content

Commit

Permalink
Merge branch 'master' into statuses@2
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathanong authored Aug 31, 2024
2 parents 1c37f14 + 7cf1462 commit 550a6f7
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 5 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);
```
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
}
}

0 comments on commit 550a6f7

Please sign in to comment.