qs 6.5.2 → 6.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +14 -1
- package/.eslintrc +21 -3
- package/.github/FUNDING.yml +12 -0
- package/.nycrc +13 -0
- package/CHANGELOG.md +24 -0
- package/LICENSE.md +29 -0
- package/README.md +54 -19
- package/bower.json +21 -0
- package/component.json +15 -0
- package/dist/qs.js +35 -25
- package/lib/formats.js +1 -1
- package/lib/parse.js +6 -5
- package/lib/stringify.js +21 -14
- package/lib/utils.js +7 -5
- package/package.json +18 -16
- package/test/parse.js +79 -4
- package/test/stringify.js +45 -0
- package/test/utils.js +31 -0
- package/.eslintignore +0 -1
- package/LICENSE +0 -28
- package/test/.eslintrc +0 -15
package/.editorconfig
CHANGED
|
@@ -7,11 +7,15 @@ end_of_line = lf
|
|
|
7
7
|
charset = utf-8
|
|
8
8
|
trim_trailing_whitespace = true
|
|
9
9
|
insert_final_newline = true
|
|
10
|
-
max_line_length =
|
|
10
|
+
max_line_length = 160
|
|
11
|
+
quote_type = single
|
|
11
12
|
|
|
12
13
|
[test/*]
|
|
13
14
|
max_line_length = off
|
|
14
15
|
|
|
16
|
+
[LICENSE.md]
|
|
17
|
+
indent_size = off
|
|
18
|
+
|
|
15
19
|
[*.md]
|
|
16
20
|
max_line_length = off
|
|
17
21
|
|
|
@@ -28,3 +32,12 @@ indent_size = 2
|
|
|
28
32
|
[LICENSE]
|
|
29
33
|
indent_size = 2
|
|
30
34
|
max_line_length = off
|
|
35
|
+
|
|
36
|
+
[coverage/**/*]
|
|
37
|
+
indent_size = off
|
|
38
|
+
indent_style = off
|
|
39
|
+
indent = off
|
|
40
|
+
max_line_length = off
|
|
41
|
+
|
|
42
|
+
[.nycrc]
|
|
43
|
+
indent_style = tab
|
package/.eslintrc
CHANGED
|
@@ -3,17 +3,35 @@
|
|
|
3
3
|
|
|
4
4
|
"extends": "@ljharb",
|
|
5
5
|
|
|
6
|
+
"ignorePatterns": [
|
|
7
|
+
"dist/",
|
|
8
|
+
],
|
|
9
|
+
|
|
6
10
|
"rules": {
|
|
7
11
|
"complexity": 0,
|
|
8
12
|
"consistent-return": 1,
|
|
9
|
-
|
|
13
|
+
"func-name-matching": 0,
|
|
10
14
|
"id-length": [2, { "min": 1, "max": 25, "properties": "never" }],
|
|
11
15
|
"indent": [2, 4],
|
|
16
|
+
"max-lines-per-function": 0,
|
|
12
17
|
"max-params": [2, 12],
|
|
13
18
|
"max-statements": [2, 45],
|
|
19
|
+
"multiline-comment-style": 0,
|
|
14
20
|
"no-continue": 1,
|
|
15
21
|
"no-magic-numbers": 0,
|
|
22
|
+
"no-param-reassign": 1,
|
|
16
23
|
"no-restricted-syntax": [2, "BreakStatement", "DebuggerStatement", "ForInStatement", "LabeledStatement", "WithStatement"],
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
"overrides": [
|
|
27
|
+
{
|
|
28
|
+
"files": "test/**",
|
|
29
|
+
"rules": {
|
|
30
|
+
"max-lines-per-function": 0,
|
|
31
|
+
"max-statements": 0,
|
|
32
|
+
"no-extend-native": 0,
|
|
33
|
+
"function-paren-newline": 0,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
],
|
|
19
37
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# These are supported funding model platforms
|
|
2
|
+
|
|
3
|
+
github: [ljharb]
|
|
4
|
+
patreon: # Replace with a single Patreon username
|
|
5
|
+
open_collective: # Replace with a single Open Collective username
|
|
6
|
+
ko_fi: # Replace with a single Ko-fi username
|
|
7
|
+
tidelift: npm/qs
|
|
8
|
+
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
|
9
|
+
liberapay: # Replace with a single Liberapay username
|
|
10
|
+
issuehunt: # Replace with a single IssueHunt username
|
|
11
|
+
otechie: # Replace with a single Otechie username
|
|
12
|
+
custom: # Replace with a single custom sponsorship URL
|
package/.nycrc
ADDED
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
## **6.5.3**
|
|
2
|
+
- [Fix] `parse`: ignore `__proto__` keys (#428)
|
|
3
|
+
- [Fix]` `utils.merge`: avoid a crash with a null target and a truthy non-array source
|
|
4
|
+
- [Fix] correctly parse nested arrays
|
|
5
|
+
- [Fix] `stringify`: fix a crash with `strictNullHandling` and a custom `filter`/`serializeDate` (#279)
|
|
6
|
+
- [Fix] `utils`: `merge`: fix crash when `source` is a truthy primitive & no options are provided
|
|
7
|
+
- [Fix] when `parseArrays` is false, properly handle keys ending in `[]`
|
|
8
|
+
- [Fix] fix for an impossible situation: when the formatter is called with a non-string value
|
|
9
|
+
- [Fix] `utils.merge`: avoid a crash with a null target and an array source
|
|
10
|
+
- [Refactor] `utils`: reduce observable [[Get]]s
|
|
11
|
+
- [Refactor] use cached `Array.isArray`
|
|
12
|
+
- [Refactor] `stringify`: Avoid arr = arr.concat(...), push to the existing instance (#269)
|
|
13
|
+
- [Refactor] `parse`: only need to reassign the var once
|
|
14
|
+
- [Robustness] `stringify`: avoid relying on a global `undefined` (#427)
|
|
15
|
+
- [readme] remove travis badge; add github actions/codecov badges; update URLs
|
|
16
|
+
- [Docs] Clean up license text so it’s properly detected as BSD-3-Clause
|
|
17
|
+
- [Docs] Clarify the need for "arrayLimit" option
|
|
18
|
+
- [meta] fix README.md (#399)
|
|
19
|
+
- [meta] add FUNDING.yml
|
|
20
|
+
- [actions] backport actions from main
|
|
21
|
+
- [Tests] always use `String(x)` over `x.toString()`
|
|
22
|
+
- [Tests] remove nonexistent tape option
|
|
23
|
+
- [Dev Deps] backport from main
|
|
24
|
+
|
|
1
25
|
## **6.5.2**
|
|
2
26
|
- [Fix] use `safer-buffer` instead of `Buffer` constructor
|
|
3
27
|
- [Refactor] utils: `module.exports` one thing, instead of mutating `exports` (#230)
|
package/LICENSE.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2014, Nathan LaFreniere and other [contributors](https://github.com/ljharb/qs/graphs/contributors)
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
17
|
+
contributors may be used to endorse or promote products derived from
|
|
18
|
+
this software without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# qs <sup>[![Version Badge][2]][1]</sup>
|
|
2
2
|
|
|
3
|
-
[![
|
|
4
|
-
[![
|
|
5
|
-
[![
|
|
3
|
+
[![github actions][actions-image]][actions-url]
|
|
4
|
+
[![coverage][codecov-image]][codecov-url]
|
|
5
|
+
[![dependency status][deps-svg]][deps-url]
|
|
6
|
+
[![dev dependency status][dev-deps-svg]][dev-deps-url]
|
|
6
7
|
[![License][license-image]][license-url]
|
|
7
8
|
[![Downloads][downloads-image]][downloads-url]
|
|
8
9
|
|
|
9
|
-
[![npm badge][
|
|
10
|
+
[![npm badge][npm-badge-png]][package-url]
|
|
10
11
|
|
|
11
12
|
A querystring parsing and stringifying library with some added security.
|
|
12
13
|
|
|
@@ -182,7 +183,7 @@ assert.deepEqual(withIndexedEmptyString, { a: ['b', '', 'c'] });
|
|
|
182
183
|
```
|
|
183
184
|
|
|
184
185
|
**qs** will also limit specifying indices in an array to a maximum index of `20`. Any array members with an index of greater than `20` will
|
|
185
|
-
instead be converted to an object with the index as the key
|
|
186
|
+
instead be converted to an object with the index as the key. This is needed to handle cases when someone sent, for example, `a[999999999]` and it will take significant time to iterate over this huge array.
|
|
186
187
|
|
|
187
188
|
```javascript
|
|
188
189
|
var withMaxIndex = qs.parse('a[100]=b');
|
|
@@ -267,6 +268,30 @@ var decoded = qs.parse('x=z', { decoder: function (str) {
|
|
|
267
268
|
}})
|
|
268
269
|
```
|
|
269
270
|
|
|
271
|
+
You can encode keys and values using different logic by using the type argument provided to the encoder:
|
|
272
|
+
|
|
273
|
+
```javascript
|
|
274
|
+
var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str, defaultEncoder, charset, type) {
|
|
275
|
+
if (type === 'key') {
|
|
276
|
+
return // Encoded key
|
|
277
|
+
} else if (type === 'value') {
|
|
278
|
+
return // Encoded value
|
|
279
|
+
}
|
|
280
|
+
}})
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
The type argument is also provided to the decoder:
|
|
284
|
+
|
|
285
|
+
```javascript
|
|
286
|
+
var decoded = qs.parse('x=z', { decoder: function (str, defaultDecoder, charset, type) {
|
|
287
|
+
if (type === 'key') {
|
|
288
|
+
return // Decoded key
|
|
289
|
+
} else if (type === 'value') {
|
|
290
|
+
return // Decoded value
|
|
291
|
+
}
|
|
292
|
+
}})
|
|
293
|
+
```
|
|
294
|
+
|
|
270
295
|
Examples beyond this point will be shown as though the output is not URI encoded for clarity. Please note that the return values in these cases *will* be URI encoded during real usage.
|
|
271
296
|
|
|
272
297
|
When arrays are stringified, by default they are given explicit indices:
|
|
@@ -458,18 +483,28 @@ assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC3986' }), 'a=b%20c');
|
|
|
458
483
|
assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC1738' }), 'a=b+c');
|
|
459
484
|
```
|
|
460
485
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
[
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
[
|
|
470
|
-
|
|
471
|
-
[
|
|
472
|
-
[
|
|
486
|
+
## Security
|
|
487
|
+
|
|
488
|
+
Please email [@ljharb](https://github.com/ljharb) or see https://tidelift.com/security if you have a potential security vulnerability to report.
|
|
489
|
+
|
|
490
|
+
## qs for enterprise
|
|
491
|
+
|
|
492
|
+
Available as part of the Tidelift Subscription
|
|
493
|
+
|
|
494
|
+
The maintainers of qs and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-qs?utm_source=npm-qs&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
|
|
495
|
+
|
|
496
|
+
[package-url]: https://npmjs.org/package/qs
|
|
497
|
+
[npm-version-svg]: https://versionbadg.es/ljharb/qs.svg
|
|
498
|
+
[deps-svg]: https://david-dm.org/ljharb/qs.svg
|
|
499
|
+
[deps-url]: https://david-dm.org/ljharb/qs
|
|
500
|
+
[dev-deps-svg]: https://david-dm.org/ljharb/qs/dev-status.svg
|
|
501
|
+
[dev-deps-url]: https://david-dm.org/ljharb/qs#info=devDependencies
|
|
502
|
+
[npm-badge-png]: https://nodei.co/npm/qs.png?downloads=true&stars=true
|
|
503
|
+
[license-image]: https://img.shields.io/npm/l/qs.svg
|
|
473
504
|
[license-url]: LICENSE
|
|
474
|
-
[downloads-image]:
|
|
475
|
-
[downloads-url]:
|
|
505
|
+
[downloads-image]: https://img.shields.io/npm/dm/qs.svg
|
|
506
|
+
[downloads-url]: https://npm-stat.com/charts.html?package=qs
|
|
507
|
+
[codecov-image]: https://codecov.io/gh/ljharb/qs/branch/main/graphs/badge.svg
|
|
508
|
+
[codecov-url]: https://app.codecov.io/gh/ljharb/qs/
|
|
509
|
+
[actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/ljharb/qs
|
|
510
|
+
[actions-url]: https://github.com/ljharb/qs/actions
|
package/bower.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "qs",
|
|
3
|
+
"main": "dist/qs.js",
|
|
4
|
+
"homepage": "https://github.com/hapijs/qs",
|
|
5
|
+
"authors": [
|
|
6
|
+
"Nathan LaFreniere <quitlahok@gmail.com>"
|
|
7
|
+
],
|
|
8
|
+
"description": "A querystring parser that supports nesting and arrays, with a depth limit",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"querystring",
|
|
11
|
+
"qs"
|
|
12
|
+
],
|
|
13
|
+
"license": "BSD-3-Clause",
|
|
14
|
+
"ignore": [
|
|
15
|
+
"**/.*",
|
|
16
|
+
"node_modules",
|
|
17
|
+
"bower_components",
|
|
18
|
+
"test",
|
|
19
|
+
"tests"
|
|
20
|
+
]
|
|
21
|
+
}
|
package/component.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "qs",
|
|
3
|
+
"repository": "ljharb/qs",
|
|
4
|
+
"description": "query-string parser / stringifier with nesting support",
|
|
5
|
+
"version": "6.5.3",
|
|
6
|
+
"keywords": ["querystring", "query", "parser"],
|
|
7
|
+
"main": "lib/index.js",
|
|
8
|
+
"scripts": [
|
|
9
|
+
"lib/index.js",
|
|
10
|
+
"lib/parse.js",
|
|
11
|
+
"lib/stringify.js",
|
|
12
|
+
"lib/utils.js"
|
|
13
|
+
],
|
|
14
|
+
"license": "BSD-3-Clause"
|
|
15
|
+
}
|
package/dist/qs.js
CHANGED
|
@@ -11,7 +11,7 @@ module.exports = {
|
|
|
11
11
|
return replace.call(value, percentTwenties, '+');
|
|
12
12
|
},
|
|
13
13
|
RFC3986: function (value) {
|
|
14
|
-
return value;
|
|
14
|
+
return String(value);
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
17
|
RFC1738: 'RFC1738',
|
|
@@ -87,14 +87,15 @@ var parseObject = function (chain, val, options) {
|
|
|
87
87
|
var obj;
|
|
88
88
|
var root = chain[i];
|
|
89
89
|
|
|
90
|
-
if (root === '[]') {
|
|
91
|
-
obj = [];
|
|
92
|
-
obj = obj.concat(leaf);
|
|
90
|
+
if (root === '[]' && options.parseArrays) {
|
|
91
|
+
obj = [].concat(leaf);
|
|
93
92
|
} else {
|
|
94
93
|
obj = options.plainObjects ? Object.create(null) : {};
|
|
95
94
|
var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
|
|
96
95
|
var index = parseInt(cleanRoot, 10);
|
|
97
|
-
if (
|
|
96
|
+
if (!options.parseArrays && cleanRoot === '') {
|
|
97
|
+
obj = { 0: leaf };
|
|
98
|
+
} else if (
|
|
98
99
|
!isNaN(index)
|
|
99
100
|
&& root !== cleanRoot
|
|
100
101
|
&& String(index) === cleanRoot
|
|
@@ -103,7 +104,7 @@ var parseObject = function (chain, val, options) {
|
|
|
103
104
|
) {
|
|
104
105
|
obj = [];
|
|
105
106
|
obj[index] = leaf;
|
|
106
|
-
} else {
|
|
107
|
+
} else if (cleanRoot !== '__proto__') {
|
|
107
108
|
obj[cleanRoot] = leaf;
|
|
108
109
|
}
|
|
109
110
|
}
|
|
@@ -214,17 +215,23 @@ var utils = require('./utils');
|
|
|
214
215
|
var formats = require('./formats');
|
|
215
216
|
|
|
216
217
|
var arrayPrefixGenerators = {
|
|
217
|
-
brackets: function brackets(prefix) {
|
|
218
|
+
brackets: function brackets(prefix) {
|
|
218
219
|
return prefix + '[]';
|
|
219
220
|
},
|
|
220
|
-
indices: function indices(prefix, key) {
|
|
221
|
+
indices: function indices(prefix, key) {
|
|
221
222
|
return prefix + '[' + key + ']';
|
|
222
223
|
},
|
|
223
|
-
repeat: function repeat(prefix) {
|
|
224
|
+
repeat: function repeat(prefix) {
|
|
224
225
|
return prefix;
|
|
225
226
|
}
|
|
226
227
|
};
|
|
227
228
|
|
|
229
|
+
var isArray = Array.isArray;
|
|
230
|
+
var push = Array.prototype.push;
|
|
231
|
+
var pushToArray = function (arr, valueOrArray) {
|
|
232
|
+
push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
|
|
233
|
+
};
|
|
234
|
+
|
|
228
235
|
var toISO = Date.prototype.toISOString;
|
|
229
236
|
|
|
230
237
|
var defaults = {
|
|
@@ -232,14 +239,14 @@ var defaults = {
|
|
|
232
239
|
encode: true,
|
|
233
240
|
encoder: utils.encode,
|
|
234
241
|
encodeValuesOnly: false,
|
|
235
|
-
serializeDate: function serializeDate(date) {
|
|
242
|
+
serializeDate: function serializeDate(date) {
|
|
236
243
|
return toISO.call(date);
|
|
237
244
|
},
|
|
238
245
|
skipNulls: false,
|
|
239
246
|
strictNullHandling: false
|
|
240
247
|
};
|
|
241
248
|
|
|
242
|
-
var stringify = function stringify(
|
|
249
|
+
var stringify = function stringify(
|
|
243
250
|
object,
|
|
244
251
|
prefix,
|
|
245
252
|
generateArrayPrefix,
|
|
@@ -258,7 +265,9 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
258
265
|
obj = filter(prefix, obj);
|
|
259
266
|
} else if (obj instanceof Date) {
|
|
260
267
|
obj = serializeDate(obj);
|
|
261
|
-
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (obj === null) {
|
|
262
271
|
if (strictNullHandling) {
|
|
263
272
|
return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder) : prefix;
|
|
264
273
|
}
|
|
@@ -281,7 +290,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
281
290
|
}
|
|
282
291
|
|
|
283
292
|
var objKeys;
|
|
284
|
-
if (
|
|
293
|
+
if (isArray(filter)) {
|
|
285
294
|
objKeys = filter;
|
|
286
295
|
} else {
|
|
287
296
|
var keys = Object.keys(obj);
|
|
@@ -295,8 +304,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
295
304
|
continue;
|
|
296
305
|
}
|
|
297
306
|
|
|
298
|
-
if (
|
|
299
|
-
values
|
|
307
|
+
if (isArray(obj)) {
|
|
308
|
+
pushToArray(values, stringify(
|
|
300
309
|
obj[key],
|
|
301
310
|
generateArrayPrefix(prefix, key),
|
|
302
311
|
generateArrayPrefix,
|
|
@@ -311,7 +320,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
311
320
|
encodeValuesOnly
|
|
312
321
|
));
|
|
313
322
|
} else {
|
|
314
|
-
values
|
|
323
|
+
pushToArray(values, stringify(
|
|
315
324
|
obj[key],
|
|
316
325
|
prefix + (allowDots ? '.' + key : '[' + key + ']'),
|
|
317
326
|
generateArrayPrefix,
|
|
@@ -335,7 +344,7 @@ module.exports = function (object, opts) {
|
|
|
335
344
|
var obj = object;
|
|
336
345
|
var options = opts ? utils.assign({}, opts) : {};
|
|
337
346
|
|
|
338
|
-
if (options.encoder !== null && options.encoder !== undefined && typeof options.encoder !== 'function') {
|
|
347
|
+
if (options.encoder !== null && typeof options.encoder !== 'undefined' && typeof options.encoder !== 'function') {
|
|
339
348
|
throw new TypeError('Encoder has to be a function.');
|
|
340
349
|
}
|
|
341
350
|
|
|
@@ -360,7 +369,7 @@ module.exports = function (object, opts) {
|
|
|
360
369
|
if (typeof options.filter === 'function') {
|
|
361
370
|
filter = options.filter;
|
|
362
371
|
obj = filter('', obj);
|
|
363
|
-
} else if (
|
|
372
|
+
} else if (isArray(options.filter)) {
|
|
364
373
|
filter = options.filter;
|
|
365
374
|
objKeys = filter;
|
|
366
375
|
}
|
|
@@ -396,8 +405,7 @@ module.exports = function (object, opts) {
|
|
|
396
405
|
if (skipNulls && obj[key] === null) {
|
|
397
406
|
continue;
|
|
398
407
|
}
|
|
399
|
-
|
|
400
|
-
keys = keys.concat(stringify(
|
|
408
|
+
pushToArray(keys, stringify(
|
|
401
409
|
obj[key],
|
|
402
410
|
key,
|
|
403
411
|
generateArrayPrefix,
|
|
@@ -475,8 +483,8 @@ var merge = function merge(target, source, options) {
|
|
|
475
483
|
if (typeof source !== 'object') {
|
|
476
484
|
if (Array.isArray(target)) {
|
|
477
485
|
target.push(source);
|
|
478
|
-
} else if (typeof target === 'object') {
|
|
479
|
-
if (options.plainObjects || options.allowPrototypes || !has.call(Object.prototype, source)) {
|
|
486
|
+
} else if (target && typeof target === 'object') {
|
|
487
|
+
if ((options && (options.plainObjects || options.allowPrototypes)) || !has.call(Object.prototype, source)) {
|
|
480
488
|
target[source] = true;
|
|
481
489
|
}
|
|
482
490
|
} else {
|
|
@@ -486,7 +494,7 @@ var merge = function merge(target, source, options) {
|
|
|
486
494
|
return target;
|
|
487
495
|
}
|
|
488
496
|
|
|
489
|
-
if (typeof target !== 'object') {
|
|
497
|
+
if (!target || typeof target !== 'object') {
|
|
490
498
|
return [target].concat(source);
|
|
491
499
|
}
|
|
492
500
|
|
|
@@ -498,8 +506,9 @@ var merge = function merge(target, source, options) {
|
|
|
498
506
|
if (Array.isArray(target) && Array.isArray(source)) {
|
|
499
507
|
source.forEach(function (item, i) {
|
|
500
508
|
if (has.call(target, i)) {
|
|
501
|
-
|
|
502
|
-
|
|
509
|
+
var targetItem = target[i];
|
|
510
|
+
if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') {
|
|
511
|
+
target[i] = merge(targetItem, item, options);
|
|
503
512
|
} else {
|
|
504
513
|
target.push(item);
|
|
505
514
|
}
|
|
@@ -580,6 +589,7 @@ var encode = function encode(str) {
|
|
|
580
589
|
|
|
581
590
|
i += 1;
|
|
582
591
|
c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
|
|
592
|
+
/* eslint operator-linebreak: [2, "before"] */
|
|
583
593
|
out += hexTable[0xF0 | (c >> 18)]
|
|
584
594
|
+ hexTable[0x80 | ((c >> 12) & 0x3F)]
|
|
585
595
|
+ hexTable[0x80 | ((c >> 6) & 0x3F)]
|
package/lib/formats.js
CHANGED
package/lib/parse.js
CHANGED
|
@@ -53,14 +53,15 @@ var parseObject = function (chain, val, options) {
|
|
|
53
53
|
var obj;
|
|
54
54
|
var root = chain[i];
|
|
55
55
|
|
|
56
|
-
if (root === '[]') {
|
|
57
|
-
obj = [];
|
|
58
|
-
obj = obj.concat(leaf);
|
|
56
|
+
if (root === '[]' && options.parseArrays) {
|
|
57
|
+
obj = [].concat(leaf);
|
|
59
58
|
} else {
|
|
60
59
|
obj = options.plainObjects ? Object.create(null) : {};
|
|
61
60
|
var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
|
|
62
61
|
var index = parseInt(cleanRoot, 10);
|
|
63
|
-
if (
|
|
62
|
+
if (!options.parseArrays && cleanRoot === '') {
|
|
63
|
+
obj = { 0: leaf };
|
|
64
|
+
} else if (
|
|
64
65
|
!isNaN(index)
|
|
65
66
|
&& root !== cleanRoot
|
|
66
67
|
&& String(index) === cleanRoot
|
|
@@ -69,7 +70,7 @@ var parseObject = function (chain, val, options) {
|
|
|
69
70
|
) {
|
|
70
71
|
obj = [];
|
|
71
72
|
obj[index] = leaf;
|
|
72
|
-
} else {
|
|
73
|
+
} else if (cleanRoot !== '__proto__') {
|
|
73
74
|
obj[cleanRoot] = leaf;
|
|
74
75
|
}
|
|
75
76
|
}
|
package/lib/stringify.js
CHANGED
|
@@ -4,17 +4,23 @@ var utils = require('./utils');
|
|
|
4
4
|
var formats = require('./formats');
|
|
5
5
|
|
|
6
6
|
var arrayPrefixGenerators = {
|
|
7
|
-
brackets: function brackets(prefix) {
|
|
7
|
+
brackets: function brackets(prefix) {
|
|
8
8
|
return prefix + '[]';
|
|
9
9
|
},
|
|
10
|
-
indices: function indices(prefix, key) {
|
|
10
|
+
indices: function indices(prefix, key) {
|
|
11
11
|
return prefix + '[' + key + ']';
|
|
12
12
|
},
|
|
13
|
-
repeat: function repeat(prefix) {
|
|
13
|
+
repeat: function repeat(prefix) {
|
|
14
14
|
return prefix;
|
|
15
15
|
}
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
var isArray = Array.isArray;
|
|
19
|
+
var push = Array.prototype.push;
|
|
20
|
+
var pushToArray = function (arr, valueOrArray) {
|
|
21
|
+
push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
|
|
22
|
+
};
|
|
23
|
+
|
|
18
24
|
var toISO = Date.prototype.toISOString;
|
|
19
25
|
|
|
20
26
|
var defaults = {
|
|
@@ -22,14 +28,14 @@ var defaults = {
|
|
|
22
28
|
encode: true,
|
|
23
29
|
encoder: utils.encode,
|
|
24
30
|
encodeValuesOnly: false,
|
|
25
|
-
serializeDate: function serializeDate(date) {
|
|
31
|
+
serializeDate: function serializeDate(date) {
|
|
26
32
|
return toISO.call(date);
|
|
27
33
|
},
|
|
28
34
|
skipNulls: false,
|
|
29
35
|
strictNullHandling: false
|
|
30
36
|
};
|
|
31
37
|
|
|
32
|
-
var stringify = function stringify(
|
|
38
|
+
var stringify = function stringify(
|
|
33
39
|
object,
|
|
34
40
|
prefix,
|
|
35
41
|
generateArrayPrefix,
|
|
@@ -48,7 +54,9 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
48
54
|
obj = filter(prefix, obj);
|
|
49
55
|
} else if (obj instanceof Date) {
|
|
50
56
|
obj = serializeDate(obj);
|
|
51
|
-
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (obj === null) {
|
|
52
60
|
if (strictNullHandling) {
|
|
53
61
|
return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder) : prefix;
|
|
54
62
|
}
|
|
@@ -71,7 +79,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
71
79
|
}
|
|
72
80
|
|
|
73
81
|
var objKeys;
|
|
74
|
-
if (
|
|
82
|
+
if (isArray(filter)) {
|
|
75
83
|
objKeys = filter;
|
|
76
84
|
} else {
|
|
77
85
|
var keys = Object.keys(obj);
|
|
@@ -85,8 +93,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
85
93
|
continue;
|
|
86
94
|
}
|
|
87
95
|
|
|
88
|
-
if (
|
|
89
|
-
values
|
|
96
|
+
if (isArray(obj)) {
|
|
97
|
+
pushToArray(values, stringify(
|
|
90
98
|
obj[key],
|
|
91
99
|
generateArrayPrefix(prefix, key),
|
|
92
100
|
generateArrayPrefix,
|
|
@@ -101,7 +109,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
101
109
|
encodeValuesOnly
|
|
102
110
|
));
|
|
103
111
|
} else {
|
|
104
|
-
values
|
|
112
|
+
pushToArray(values, stringify(
|
|
105
113
|
obj[key],
|
|
106
114
|
prefix + (allowDots ? '.' + key : '[' + key + ']'),
|
|
107
115
|
generateArrayPrefix,
|
|
@@ -125,7 +133,7 @@ module.exports = function (object, opts) {
|
|
|
125
133
|
var obj = object;
|
|
126
134
|
var options = opts ? utils.assign({}, opts) : {};
|
|
127
135
|
|
|
128
|
-
if (options.encoder !== null && options.encoder !== undefined && typeof options.encoder !== 'function') {
|
|
136
|
+
if (options.encoder !== null && typeof options.encoder !== 'undefined' && typeof options.encoder !== 'function') {
|
|
129
137
|
throw new TypeError('Encoder has to be a function.');
|
|
130
138
|
}
|
|
131
139
|
|
|
@@ -150,7 +158,7 @@ module.exports = function (object, opts) {
|
|
|
150
158
|
if (typeof options.filter === 'function') {
|
|
151
159
|
filter = options.filter;
|
|
152
160
|
obj = filter('', obj);
|
|
153
|
-
} else if (
|
|
161
|
+
} else if (isArray(options.filter)) {
|
|
154
162
|
filter = options.filter;
|
|
155
163
|
objKeys = filter;
|
|
156
164
|
}
|
|
@@ -186,8 +194,7 @@ module.exports = function (object, opts) {
|
|
|
186
194
|
if (skipNulls && obj[key] === null) {
|
|
187
195
|
continue;
|
|
188
196
|
}
|
|
189
|
-
|
|
190
|
-
keys = keys.concat(stringify(
|
|
197
|
+
pushToArray(keys, stringify(
|
|
191
198
|
obj[key],
|
|
192
199
|
key,
|
|
193
200
|
generateArrayPrefix,
|
package/lib/utils.js
CHANGED
|
@@ -53,8 +53,8 @@ var merge = function merge(target, source, options) {
|
|
|
53
53
|
if (typeof source !== 'object') {
|
|
54
54
|
if (Array.isArray(target)) {
|
|
55
55
|
target.push(source);
|
|
56
|
-
} else if (typeof target === 'object') {
|
|
57
|
-
if (options.plainObjects || options.allowPrototypes || !has.call(Object.prototype, source)) {
|
|
56
|
+
} else if (target && typeof target === 'object') {
|
|
57
|
+
if ((options && (options.plainObjects || options.allowPrototypes)) || !has.call(Object.prototype, source)) {
|
|
58
58
|
target[source] = true;
|
|
59
59
|
}
|
|
60
60
|
} else {
|
|
@@ -64,7 +64,7 @@ var merge = function merge(target, source, options) {
|
|
|
64
64
|
return target;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
if (typeof target !== 'object') {
|
|
67
|
+
if (!target || typeof target !== 'object') {
|
|
68
68
|
return [target].concat(source);
|
|
69
69
|
}
|
|
70
70
|
|
|
@@ -76,8 +76,9 @@ var merge = function merge(target, source, options) {
|
|
|
76
76
|
if (Array.isArray(target) && Array.isArray(source)) {
|
|
77
77
|
source.forEach(function (item, i) {
|
|
78
78
|
if (has.call(target, i)) {
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
var targetItem = target[i];
|
|
80
|
+
if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') {
|
|
81
|
+
target[i] = merge(targetItem, item, options);
|
|
81
82
|
} else {
|
|
82
83
|
target.push(item);
|
|
83
84
|
}
|
|
@@ -158,6 +159,7 @@ var encode = function encode(str) {
|
|
|
158
159
|
|
|
159
160
|
i += 1;
|
|
160
161
|
c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
|
|
162
|
+
/* eslint operator-linebreak: [2, "before"] */
|
|
161
163
|
out += hexTable[0xF0 | (c >> 18)]
|
|
162
164
|
+ hexTable[0x80 | ((c >> 12) & 0x3F)]
|
|
163
165
|
+ hexTable[0x80 | ((c >> 6) & 0x3F)]
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "qs",
|
|
3
3
|
"description": "A querystring parser that supports nesting and arrays, with a depth limit",
|
|
4
4
|
"homepage": "https://github.com/ljharb/qs",
|
|
5
|
-
"version": "6.5.
|
|
5
|
+
"version": "6.5.3",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "https://github.com/ljharb/qs.git"
|
|
@@ -22,30 +22,32 @@
|
|
|
22
22
|
"engines": {
|
|
23
23
|
"node": ">=0.6"
|
|
24
24
|
},
|
|
25
|
-
"dependencies": {},
|
|
26
25
|
"devDependencies": {
|
|
27
|
-
"@ljharb/eslint-config": "^
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"eslint": "^
|
|
26
|
+
"@ljharb/eslint-config": "^20.1.0",
|
|
27
|
+
"aud": "^1.1.5",
|
|
28
|
+
"browserify": "^16.5.2",
|
|
29
|
+
"eclint": "^2.8.1",
|
|
30
|
+
"eslint": "^8.6.0",
|
|
32
31
|
"evalmd": "^0.0.17",
|
|
33
|
-
"iconv-lite": "^0.4.
|
|
32
|
+
"iconv-lite": "^0.4.24",
|
|
33
|
+
"in-publish": "^2.0.1",
|
|
34
34
|
"mkdirp": "^0.5.1",
|
|
35
|
+
"nyc": "^10.3.2",
|
|
35
36
|
"qs-iconv": "^1.0.4",
|
|
36
|
-
"safe-publish-latest": "^
|
|
37
|
+
"safe-publish-latest": "^2.0.0",
|
|
37
38
|
"safer-buffer": "^2.1.2",
|
|
38
|
-
"tape": "^4.
|
|
39
|
+
"tape": "^5.4.0"
|
|
39
40
|
},
|
|
40
41
|
"scripts": {
|
|
41
|
-
"
|
|
42
|
+
"prepublishOnly": "safe-publish-latest && npm run dist",
|
|
43
|
+
"prepublish": "not-in-publish || npm run prepublishOnly",
|
|
42
44
|
"pretest": "npm run --silent readme && npm run --silent lint",
|
|
43
|
-
"test": "npm run --silent
|
|
44
|
-
"tests-only": "
|
|
45
|
+
"test": "npm run --silent tests-only",
|
|
46
|
+
"tests-only": "nyc tape 'test/**/*.js'",
|
|
47
|
+
"posttest": "aud --production",
|
|
45
48
|
"readme": "evalmd README.md",
|
|
46
|
-
"
|
|
47
|
-
"lint": "eslint
|
|
48
|
-
"coverage": "covert test",
|
|
49
|
+
"postlint": "eclint check $(git ls-files | xargs find 2> /dev/null | grep -vE 'node_modules|\\.git')",
|
|
50
|
+
"lint": "eslint --ext=js,mjs .",
|
|
49
51
|
"dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js"
|
|
50
52
|
},
|
|
51
53
|
"license": "BSD-3-Clause"
|
package/test/parse.js
CHANGED
|
@@ -237,6 +237,14 @@ test('parse()', function (t) {
|
|
|
237
237
|
st.end();
|
|
238
238
|
});
|
|
239
239
|
|
|
240
|
+
t.test('parses jquery-param strings', function (st) {
|
|
241
|
+
// readable = 'filter[0][]=int1&filter[0][]==&filter[0][]=77&filter[]=and&filter[2][]=int2&filter[2][]==&filter[2][]=8'
|
|
242
|
+
var encoded = 'filter%5B0%5D%5B%5D=int1&filter%5B0%5D%5B%5D=%3D&filter%5B0%5D%5B%5D=77&filter%5B%5D=and&filter%5B2%5D%5B%5D=int2&filter%5B2%5D%5B%5D=%3D&filter%5B2%5D%5B%5D=8';
|
|
243
|
+
var expected = { filter: [['int1', '=', '77'], 'and', ['int2', '=', '8']] };
|
|
244
|
+
st.deepEqual(qs.parse(encoded), expected);
|
|
245
|
+
st.end();
|
|
246
|
+
});
|
|
247
|
+
|
|
240
248
|
t.test('continues parsing when no parent is found', function (st) {
|
|
241
249
|
st.deepEqual(qs.parse('[]=&a=b'), { 0: '', a: 'b' });
|
|
242
250
|
st.deepEqual(qs.parse('[]&a=b', { strictNullHandling: true }), { 0: null, a: 'b' });
|
|
@@ -257,7 +265,7 @@ test('parse()', function (t) {
|
|
|
257
265
|
st.end();
|
|
258
266
|
});
|
|
259
267
|
|
|
260
|
-
t.test('should not throw when a native prototype has an enumerable property',
|
|
268
|
+
t.test('should not throw when a native prototype has an enumerable property', function (st) {
|
|
261
269
|
Object.prototype.crash = '';
|
|
262
270
|
Array.prototype.crash = '';
|
|
263
271
|
st.doesNotThrow(qs.parse.bind(null, 'a=b'));
|
|
@@ -302,7 +310,14 @@ test('parse()', function (t) {
|
|
|
302
310
|
});
|
|
303
311
|
|
|
304
312
|
t.test('allows disabling array parsing', function (st) {
|
|
305
|
-
|
|
313
|
+
var indices = qs.parse('a[0]=b&a[1]=c', { parseArrays: false });
|
|
314
|
+
st.deepEqual(indices, { a: { 0: 'b', 1: 'c' } });
|
|
315
|
+
st.equal(Array.isArray(indices.a), false, 'parseArrays:false, indices case is not an array');
|
|
316
|
+
|
|
317
|
+
var emptyBrackets = qs.parse('a[]=b', { parseArrays: false });
|
|
318
|
+
st.deepEqual(emptyBrackets, { a: { 0: 'b' } });
|
|
319
|
+
st.equal(Array.isArray(emptyBrackets.a), false, 'parseArrays:false, empty brackets case is not an array');
|
|
320
|
+
|
|
306
321
|
st.end();
|
|
307
322
|
});
|
|
308
323
|
|
|
@@ -508,13 +523,73 @@ test('parse()', function (t) {
|
|
|
508
523
|
|
|
509
524
|
st.deepEqual(
|
|
510
525
|
qs.parse('a[b]=c&a=toString', { plainObjects: true }),
|
|
511
|
-
{ a: { b: 'c', toString: true } },
|
|
526
|
+
{ __proto__: null, a: { __proto__: null, b: 'c', toString: true } },
|
|
512
527
|
'can overwrite prototype with plainObjects true'
|
|
513
528
|
);
|
|
514
529
|
|
|
515
530
|
st.end();
|
|
516
531
|
});
|
|
517
532
|
|
|
533
|
+
t.test('dunder proto is ignored', function (st) {
|
|
534
|
+
var payload = 'categories[__proto__]=login&categories[__proto__]&categories[length]=42';
|
|
535
|
+
var result = qs.parse(payload, { allowPrototypes: true });
|
|
536
|
+
|
|
537
|
+
st.deepEqual(
|
|
538
|
+
result,
|
|
539
|
+
{
|
|
540
|
+
categories: {
|
|
541
|
+
length: '42'
|
|
542
|
+
}
|
|
543
|
+
},
|
|
544
|
+
'silent [[Prototype]] payload'
|
|
545
|
+
);
|
|
546
|
+
|
|
547
|
+
var plainResult = qs.parse(payload, { allowPrototypes: true, plainObjects: true });
|
|
548
|
+
|
|
549
|
+
st.deepEqual(
|
|
550
|
+
plainResult,
|
|
551
|
+
{
|
|
552
|
+
__proto__: null,
|
|
553
|
+
categories: {
|
|
554
|
+
__proto__: null,
|
|
555
|
+
length: '42'
|
|
556
|
+
}
|
|
557
|
+
},
|
|
558
|
+
'silent [[Prototype]] payload: plain objects'
|
|
559
|
+
);
|
|
560
|
+
|
|
561
|
+
var query = qs.parse('categories[__proto__]=cats&categories[__proto__]=dogs&categories[some][json]=toInject', { allowPrototypes: true });
|
|
562
|
+
|
|
563
|
+
st.notOk(Array.isArray(query.categories), 'is not an array');
|
|
564
|
+
st.notOk(query.categories instanceof Array, 'is not instanceof an array');
|
|
565
|
+
st.deepEqual(query.categories, { some: { json: 'toInject' } });
|
|
566
|
+
st.equal(JSON.stringify(query.categories), '{"some":{"json":"toInject"}}', 'stringifies as a non-array');
|
|
567
|
+
|
|
568
|
+
st.deepEqual(
|
|
569
|
+
qs.parse('foo[__proto__][hidden]=value&foo[bar]=stuffs', { allowPrototypes: true }),
|
|
570
|
+
{
|
|
571
|
+
foo: {
|
|
572
|
+
bar: 'stuffs'
|
|
573
|
+
}
|
|
574
|
+
},
|
|
575
|
+
'hidden values'
|
|
576
|
+
);
|
|
577
|
+
|
|
578
|
+
st.deepEqual(
|
|
579
|
+
qs.parse('foo[__proto__][hidden]=value&foo[bar]=stuffs', { allowPrototypes: true, plainObjects: true }),
|
|
580
|
+
{
|
|
581
|
+
__proto__: null,
|
|
582
|
+
foo: {
|
|
583
|
+
__proto__: null,
|
|
584
|
+
bar: 'stuffs'
|
|
585
|
+
}
|
|
586
|
+
},
|
|
587
|
+
'hidden values: plain objects'
|
|
588
|
+
);
|
|
589
|
+
|
|
590
|
+
st.end();
|
|
591
|
+
});
|
|
592
|
+
|
|
518
593
|
t.test('can return null objects', { skip: !Object.create }, function (st) {
|
|
519
594
|
var expected = Object.create(null);
|
|
520
595
|
expected.a = Object.create(null);
|
|
@@ -540,7 +615,7 @@ test('parse()', function (t) {
|
|
|
540
615
|
result.push(parseInt(parts[1], 16));
|
|
541
616
|
parts = reg.exec(str);
|
|
542
617
|
}
|
|
543
|
-
return iconv.decode(SaferBuffer.from(result), 'shift_jis')
|
|
618
|
+
return String(iconv.decode(SaferBuffer.from(result), 'shift_jis'));
|
|
544
619
|
}
|
|
545
620
|
}), { 県: '大阪府' });
|
|
546
621
|
st.end();
|
package/test/stringify.js
CHANGED
|
@@ -19,6 +19,15 @@ test('stringify()', function (t) {
|
|
|
19
19
|
st.end();
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
+
t.test('stringifies falsy values', function (st) {
|
|
23
|
+
st.equal(qs.stringify(undefined), '');
|
|
24
|
+
st.equal(qs.stringify(null), '');
|
|
25
|
+
st.equal(qs.stringify(null, { strictNullHandling: true }), '');
|
|
26
|
+
st.equal(qs.stringify(false), '');
|
|
27
|
+
st.equal(qs.stringify(0), '');
|
|
28
|
+
st.end();
|
|
29
|
+
});
|
|
30
|
+
|
|
22
31
|
t.test('adds query prefix', function (st) {
|
|
23
32
|
st.equal(qs.stringify({ a: 'b' }, { addQueryPrefix: true }), '?a=b');
|
|
24
33
|
st.end();
|
|
@@ -29,6 +38,13 @@ test('stringify()', function (t) {
|
|
|
29
38
|
st.end();
|
|
30
39
|
});
|
|
31
40
|
|
|
41
|
+
t.test('stringifies nested falsy values', function (st) {
|
|
42
|
+
st.equal(qs.stringify({ a: { b: { c: null } } }), 'a%5Bb%5D%5Bc%5D=');
|
|
43
|
+
st.equal(qs.stringify({ a: { b: { c: null } } }, { strictNullHandling: true }), 'a%5Bb%5D%5Bc%5D');
|
|
44
|
+
st.equal(qs.stringify({ a: { b: { c: false } } }), 'a%5Bb%5D%5Bc%5D=false');
|
|
45
|
+
st.end();
|
|
46
|
+
});
|
|
47
|
+
|
|
32
48
|
t.test('stringifies a nested object', function (st) {
|
|
33
49
|
st.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
|
|
34
50
|
st.equal(qs.stringify({ a: { b: { c: { d: 'e' } } } }), 'a%5Bb%5D%5Bc%5D%5Bd%5D=e');
|
|
@@ -490,6 +506,12 @@ test('stringify()', function (t) {
|
|
|
490
506
|
return String.fromCharCode(buffer.readUInt8(0) + 97);
|
|
491
507
|
}
|
|
492
508
|
}), 'a=b');
|
|
509
|
+
|
|
510
|
+
st.equal(qs.stringify({ a: SaferBuffer.from('a b') }, {
|
|
511
|
+
encoder: function (buffer) {
|
|
512
|
+
return buffer;
|
|
513
|
+
}
|
|
514
|
+
}), 'a=a b');
|
|
493
515
|
st.end();
|
|
494
516
|
});
|
|
495
517
|
|
|
@@ -530,17 +552,20 @@ test('stringify()', function (t) {
|
|
|
530
552
|
t.test('RFC 1738 spaces serialization', function (st) {
|
|
531
553
|
st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.RFC1738 }), 'a=b+c');
|
|
532
554
|
st.equal(qs.stringify({ 'a b': 'c d' }, { format: qs.formats.RFC1738 }), 'a+b=c+d');
|
|
555
|
+
st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }, { format: qs.formats.RFC1738 }), 'a+b=a+b');
|
|
533
556
|
st.end();
|
|
534
557
|
});
|
|
535
558
|
|
|
536
559
|
t.test('RFC 3986 spaces serialization', function (st) {
|
|
537
560
|
st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.RFC3986 }), 'a=b%20c');
|
|
538
561
|
st.equal(qs.stringify({ 'a b': 'c d' }, { format: qs.formats.RFC3986 }), 'a%20b=c%20d');
|
|
562
|
+
st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }, { format: qs.formats.RFC3986 }), 'a%20b=a%20b');
|
|
539
563
|
st.end();
|
|
540
564
|
});
|
|
541
565
|
|
|
542
566
|
t.test('Backward compatibility to RFC 3986', function (st) {
|
|
543
567
|
st.equal(qs.stringify({ a: 'b c' }), 'a=b%20c');
|
|
568
|
+
st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }), 'a%20b=a%20b');
|
|
544
569
|
st.end();
|
|
545
570
|
});
|
|
546
571
|
|
|
@@ -593,5 +618,25 @@ test('stringify()', function (t) {
|
|
|
593
618
|
st.end();
|
|
594
619
|
});
|
|
595
620
|
|
|
621
|
+
t.test('strictNullHandling works with custom filter', function (st) {
|
|
622
|
+
var filter = function (prefix, value) {
|
|
623
|
+
return value;
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
var options = { strictNullHandling: true, filter: filter };
|
|
627
|
+
st.equal(qs.stringify({ key: null }, options), 'key');
|
|
628
|
+
st.end();
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
t.test('strictNullHandling works with null serializeDate', function (st) {
|
|
632
|
+
var serializeDate = function () {
|
|
633
|
+
return null;
|
|
634
|
+
};
|
|
635
|
+
var options = { strictNullHandling: true, serializeDate: serializeDate };
|
|
636
|
+
var date = new Date();
|
|
637
|
+
st.equal(qs.stringify({ key: date }, options), 'key');
|
|
638
|
+
st.end();
|
|
639
|
+
});
|
|
640
|
+
|
|
596
641
|
t.end();
|
|
597
642
|
});
|
package/test/utils.js
CHANGED
|
@@ -4,6 +4,10 @@ var test = require('tape');
|
|
|
4
4
|
var utils = require('../lib/utils');
|
|
5
5
|
|
|
6
6
|
test('merge()', function (t) {
|
|
7
|
+
t.deepEqual(utils.merge(null, true), [null, true], 'merges true into null');
|
|
8
|
+
|
|
9
|
+
t.deepEqual(utils.merge(null, [42]), [null, 42], 'merges null into an array');
|
|
10
|
+
|
|
7
11
|
t.deepEqual(utils.merge({ a: 'b' }, { a: 'c' }), { a: ['b', 'c'] }, 'merges two objects with the same key');
|
|
8
12
|
|
|
9
13
|
var oneMerged = utils.merge({ foo: 'bar' }, { foo: { first: '123' } });
|
|
@@ -18,6 +22,33 @@ test('merge()', function (t) {
|
|
|
18
22
|
var nestedArrays = utils.merge({ foo: ['baz'] }, { foo: ['bar', 'xyzzy'] });
|
|
19
23
|
t.deepEqual(nestedArrays, { foo: ['baz', 'bar', 'xyzzy'] });
|
|
20
24
|
|
|
25
|
+
var noOptionsNonObjectSource = utils.merge({ foo: 'baz' }, 'bar');
|
|
26
|
+
t.deepEqual(noOptionsNonObjectSource, { foo: 'baz', bar: true });
|
|
27
|
+
|
|
28
|
+
t.test(
|
|
29
|
+
'avoids invoking array setters unnecessarily',
|
|
30
|
+
{ skip: typeof Object.defineProperty !== 'function' },
|
|
31
|
+
function (st) {
|
|
32
|
+
var setCount = 0;
|
|
33
|
+
var getCount = 0;
|
|
34
|
+
var observed = [];
|
|
35
|
+
Object.defineProperty(observed, 0, {
|
|
36
|
+
get: function () {
|
|
37
|
+
getCount += 1;
|
|
38
|
+
return { bar: 'baz' };
|
|
39
|
+
},
|
|
40
|
+
set: function () { setCount += 1; }
|
|
41
|
+
});
|
|
42
|
+
utils.merge(observed, [null]);
|
|
43
|
+
st.equal(setCount, 0);
|
|
44
|
+
st.equal(getCount, 1);
|
|
45
|
+
observed[0] = observed[0]; // eslint-disable-line no-self-assign
|
|
46
|
+
st.equal(setCount, 1);
|
|
47
|
+
st.equal(getCount, 2);
|
|
48
|
+
st.end();
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
|
|
21
52
|
t.end();
|
|
22
53
|
});
|
|
23
54
|
|
package/.eslintignore
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
dist
|
package/LICENSE
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
Copyright (c) 2014 Nathan LaFreniere and other contributors.
|
|
2
|
-
All rights reserved.
|
|
3
|
-
|
|
4
|
-
Redistribution and use in source and binary forms, with or without
|
|
5
|
-
modification, are permitted provided that the following conditions are met:
|
|
6
|
-
* Redistributions of source code must retain the above copyright
|
|
7
|
-
notice, this list of conditions and the following disclaimer.
|
|
8
|
-
* Redistributions in binary form must reproduce the above copyright
|
|
9
|
-
notice, this list of conditions and the following disclaimer in the
|
|
10
|
-
documentation and/or other materials provided with the distribution.
|
|
11
|
-
* The names of any contributors may not be used to endorse or promote
|
|
12
|
-
products derived from this software without specific prior written
|
|
13
|
-
permission.
|
|
14
|
-
|
|
15
|
-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
16
|
-
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
17
|
-
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
18
|
-
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY
|
|
19
|
-
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
20
|
-
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
21
|
-
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
22
|
-
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
23
|
-
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
24
|
-
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
25
|
-
|
|
26
|
-
* * *
|
|
27
|
-
|
|
28
|
-
The complete list of contributors can be found at: https://github.com/hapijs/qs/graphs/contributors
|
package/test/.eslintrc
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"rules": {
|
|
3
|
-
"array-bracket-newline": 0,
|
|
4
|
-
"array-element-newline": 0,
|
|
5
|
-
"consistent-return": 2,
|
|
6
|
-
"max-lines": 0,
|
|
7
|
-
"max-nested-callbacks": [2, 3],
|
|
8
|
-
"max-statements": 0,
|
|
9
|
-
"no-buffer-constructor": 0,
|
|
10
|
-
"no-extend-native": 0,
|
|
11
|
-
"no-magic-numbers": 0,
|
|
12
|
-
"object-curly-newline": 0,
|
|
13
|
-
"sort-keys": 0
|
|
14
|
-
}
|
|
15
|
-
}
|