qs 6.3.2 → 6.3.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 +44 -0
- package/.eslintrc +24 -6
- package/.github/FUNDING.yml +12 -0
- package/.nycrc +13 -0
- package/CHANGELOG.md +20 -0
- package/LICENSE.md +29 -0
- package/README.md +26 -2
- package/bower.json +21 -0
- package/component.json +15 -0
- package/dist/qs.js +52 -40
- package/lib/formats.js +1 -1
- package/lib/parse.js +11 -10
- package/lib/stringify.js +23 -16
- package/lib/utils.js +15 -11
- package/package.json +52 -48
- package/test/parse.js +74 -6
- package/test/stringify.js +45 -15
- package/test/utils.js +7 -0
- package/.eslintignore +0 -1
- package/LICENSE +0 -28
- package/test/.eslintrc +0 -10
package/.editorconfig
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
indent_style = space
|
|
5
|
+
indent_size = 4
|
|
6
|
+
end_of_line = lf
|
|
7
|
+
charset = utf-8
|
|
8
|
+
trim_trailing_whitespace = true
|
|
9
|
+
insert_final_newline = true
|
|
10
|
+
max_line_length = 160
|
|
11
|
+
quote_type = single
|
|
12
|
+
|
|
13
|
+
[test/*]
|
|
14
|
+
max_line_length = off
|
|
15
|
+
|
|
16
|
+
[*.md]
|
|
17
|
+
indent_size = off
|
|
18
|
+
max_line_length = off
|
|
19
|
+
|
|
20
|
+
[*.json]
|
|
21
|
+
max_line_length = off
|
|
22
|
+
|
|
23
|
+
[Makefile]
|
|
24
|
+
max_line_length = off
|
|
25
|
+
|
|
26
|
+
[CHANGELOG.md]
|
|
27
|
+
indent_style = space
|
|
28
|
+
indent_size = 2
|
|
29
|
+
|
|
30
|
+
[LICENSE]
|
|
31
|
+
indent_size = 2
|
|
32
|
+
max_line_length = off
|
|
33
|
+
|
|
34
|
+
[coverage/**/*]
|
|
35
|
+
indent_size = off
|
|
36
|
+
indent_style = off
|
|
37
|
+
indent = off
|
|
38
|
+
max_line_length = off
|
|
39
|
+
|
|
40
|
+
[dist/*]
|
|
41
|
+
max_line_length = off
|
|
42
|
+
|
|
43
|
+
[.nycrc]
|
|
44
|
+
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
|
-
"complexity": [2,
|
|
11
|
+
"complexity": [2, 29],
|
|
8
12
|
"consistent-return": 1,
|
|
13
|
+
"func-name-matching": 0,
|
|
9
14
|
"id-length": [2, { "min": 1, "max": 25, "properties": "never" }],
|
|
10
15
|
"indent": [2, 4],
|
|
11
|
-
"max-
|
|
12
|
-
"max-
|
|
13
|
-
"
|
|
16
|
+
"max-lines-per-function": 0,
|
|
17
|
+
"max-params": [2, 12],
|
|
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,23 @@
|
|
|
1
|
+
## **6.3.3**
|
|
2
|
+
- [Fix] `parse`: ignore `__proto__` keys (#428)
|
|
3
|
+
- [Fix] fix for an impossible situation: when the formatter is called with a non-string value
|
|
4
|
+
- [Fix] `utils.merge`: avoid a crash with a null target and an array source
|
|
5
|
+
- [Fix]` `utils.merge`: avoid a crash with a null target and a truthy non-array source
|
|
6
|
+
- [Fix] `stringify`: fix a crash with `strictNullHandling` and a custom `filter`/`serializeDate` (#279)
|
|
7
|
+
- [Fix] `utils`: `merge`: fix crash when `source` is a truthy primitive & no options are provided
|
|
8
|
+
- [Fix] when `parseArrays` is false, properly handle keys ending in `[]`
|
|
9
|
+
- [Robustness] `stringify`: avoid relying on a global `undefined` (#427)
|
|
10
|
+
- [Refactor] use cached `Array.isArray`
|
|
11
|
+
- [Refactor] `stringify`: Avoid arr = arr.concat(...), push to the existing instance (#269)
|
|
12
|
+
- [Docs] Clarify the need for "arrayLimit" option
|
|
13
|
+
- [meta] fix README.md (#399)
|
|
14
|
+
- [meta] Clean up license text so it’s properly detected as BSD-3-Clause
|
|
15
|
+
- [meta] add FUNDING.yml
|
|
16
|
+
- [actions] backport actions from main
|
|
17
|
+
- [Tests] use `safer-buffer` instead of `Buffer` constructor
|
|
18
|
+
- [Tests] remove nonexistent tape option
|
|
19
|
+
- [Dev Deps] backport from main
|
|
20
|
+
|
|
1
21
|
## **6.3.2**
|
|
2
22
|
- [Fix] follow `allowPrototypes` option during merge (#201, #200)
|
|
3
23
|
- [Dev Deps] update `eslint`
|
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
|
@@ -169,7 +169,7 @@ assert.deepEqual(withIndexedEmptyString, { a: ['b', '', 'c'] });
|
|
|
169
169
|
```
|
|
170
170
|
|
|
171
171
|
**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
|
|
172
|
-
instead be converted to an object with the index as the key
|
|
172
|
+
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.
|
|
173
173
|
|
|
174
174
|
```javascript
|
|
175
175
|
var withMaxIndex = qs.parse('a[100]=b');
|
|
@@ -245,6 +245,30 @@ var decoded = qs.parse('x=z', { decoder: function (str) {
|
|
|
245
245
|
}})
|
|
246
246
|
```
|
|
247
247
|
|
|
248
|
+
You can encode keys and values using different logic by using the type argument provided to the encoder:
|
|
249
|
+
|
|
250
|
+
```javascript
|
|
251
|
+
var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str, defaultEncoder, charset, type) {
|
|
252
|
+
if (type === 'key') {
|
|
253
|
+
return // Encoded key
|
|
254
|
+
} else if (type === 'value') {
|
|
255
|
+
return // Encoded value
|
|
256
|
+
}
|
|
257
|
+
}})
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
The type argument is also provided to the decoder:
|
|
261
|
+
|
|
262
|
+
```javascript
|
|
263
|
+
var decoded = qs.parse('x=z', { decoder: function (str, defaultDecoder, charset, type) {
|
|
264
|
+
if (type === 'key') {
|
|
265
|
+
return // Decoded key
|
|
266
|
+
} else if (type === 'value') {
|
|
267
|
+
return // Decoded value
|
|
268
|
+
}
|
|
269
|
+
}})
|
|
270
|
+
```
|
|
271
|
+
|
|
248
272
|
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.
|
|
249
273
|
|
|
250
274
|
When arrays are stringified, by default they are given explicit indices:
|
|
@@ -400,7 +424,7 @@ assert.equal(nullsSkipped, 'a=b');
|
|
|
400
424
|
|
|
401
425
|
### Dealing with special character sets
|
|
402
426
|
|
|
403
|
-
By default the encoding and decoding of characters is done in `utf-8`. If you
|
|
427
|
+
By default the encoding and decoding of characters is done in `utf-8`. If you
|
|
404
428
|
wish to encode querystrings to a different character set (i.e.
|
|
405
429
|
[Shift JIS](https://en.wikipedia.org/wiki/Shift_JIS)) you can use the
|
|
406
430
|
[`qs-iconv`](https://github.com/martinheidegger/qs-iconv) library:
|
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": "hapijs/qs",
|
|
4
|
+
"description": "query-string parser / stringifier with nesting support",
|
|
5
|
+
"version": "6.3.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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Qs = f()}})(function(){var define,module,exports;return (function e
|
|
1
|
+
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Qs = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var replace = String.prototype.replace;
|
|
@@ -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',
|
|
@@ -84,23 +84,25 @@ var parseObject = function parseObjectRecursive(chain, val, options) {
|
|
|
84
84
|
var root = chain.shift();
|
|
85
85
|
|
|
86
86
|
var obj;
|
|
87
|
-
if (root === '[]') {
|
|
87
|
+
if (root === '[]' && options.parseArrays) {
|
|
88
88
|
obj = [];
|
|
89
89
|
obj = obj.concat(parseObject(chain, val, options));
|
|
90
90
|
} else {
|
|
91
91
|
obj = options.plainObjects ? Object.create(null) : {};
|
|
92
92
|
var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
|
|
93
93
|
var index = parseInt(cleanRoot, 10);
|
|
94
|
-
if (
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
94
|
+
if (!options.parseArrays && cleanRoot === '') {
|
|
95
|
+
obj = { 0: val };
|
|
96
|
+
} else if (
|
|
97
|
+
!isNaN(index)
|
|
98
|
+
&& root !== cleanRoot
|
|
99
|
+
&& String(index) === cleanRoot
|
|
100
|
+
&& index >= 0
|
|
101
|
+
&& (options.parseArrays && index <= options.arrayLimit)
|
|
100
102
|
) {
|
|
101
103
|
obj = [];
|
|
102
104
|
obj[index] = parseObject(chain, val, options);
|
|
103
|
-
} else {
|
|
105
|
+
} else if (cleanRoot !== '__proto__') {
|
|
104
106
|
obj[cleanRoot] = parseObject(chain, val, options);
|
|
105
107
|
}
|
|
106
108
|
}
|
|
@@ -130,8 +132,7 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
|
|
|
130
132
|
|
|
131
133
|
var keys = [];
|
|
132
134
|
if (parent) {
|
|
133
|
-
// If we aren't using plain objects, optionally prefix keys
|
|
134
|
-
// that would overwrite object prototype properties
|
|
135
|
+
// If we aren't using plain objects, optionally prefix keys that would overwrite object prototype properties
|
|
135
136
|
if (!options.plainObjects && has.call(Object.prototype, parent)) {
|
|
136
137
|
if (!options.allowPrototypes) {
|
|
137
138
|
return;
|
|
@@ -207,31 +208,37 @@ var utils = require('./utils');
|
|
|
207
208
|
var formats = require('./formats');
|
|
208
209
|
|
|
209
210
|
var arrayPrefixGenerators = {
|
|
210
|
-
brackets: function brackets(prefix) {
|
|
211
|
+
brackets: function brackets(prefix) {
|
|
211
212
|
return prefix + '[]';
|
|
212
213
|
},
|
|
213
|
-
indices: function indices(prefix, key) {
|
|
214
|
+
indices: function indices(prefix, key) {
|
|
214
215
|
return prefix + '[' + key + ']';
|
|
215
216
|
},
|
|
216
|
-
repeat: function repeat(prefix) {
|
|
217
|
+
repeat: function repeat(prefix) {
|
|
217
218
|
return prefix;
|
|
218
219
|
}
|
|
219
220
|
};
|
|
220
221
|
|
|
222
|
+
var isArray = Array.isArray;
|
|
223
|
+
var push = Array.prototype.push;
|
|
224
|
+
var pushToArray = function (arr, valueOrArray) {
|
|
225
|
+
push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
|
|
226
|
+
};
|
|
227
|
+
|
|
221
228
|
var toISO = Date.prototype.toISOString;
|
|
222
229
|
|
|
223
230
|
var defaults = {
|
|
224
231
|
delimiter: '&',
|
|
225
232
|
encode: true,
|
|
226
233
|
encoder: utils.encode,
|
|
227
|
-
serializeDate: function serializeDate(date) {
|
|
234
|
+
serializeDate: function serializeDate(date) {
|
|
228
235
|
return toISO.call(date);
|
|
229
236
|
},
|
|
230
237
|
skipNulls: false,
|
|
231
238
|
strictNullHandling: false
|
|
232
239
|
};
|
|
233
240
|
|
|
234
|
-
var stringify = function stringify(
|
|
241
|
+
var stringify = function stringify(
|
|
235
242
|
object,
|
|
236
243
|
prefix,
|
|
237
244
|
generateArrayPrefix,
|
|
@@ -249,7 +256,9 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
249
256
|
obj = filter(prefix, obj);
|
|
250
257
|
} else if (obj instanceof Date) {
|
|
251
258
|
obj = serializeDate(obj);
|
|
252
|
-
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (obj === null) {
|
|
253
262
|
if (strictNullHandling) {
|
|
254
263
|
return encoder ? encoder(prefix) : prefix;
|
|
255
264
|
}
|
|
@@ -271,7 +280,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
271
280
|
}
|
|
272
281
|
|
|
273
282
|
var objKeys;
|
|
274
|
-
if (
|
|
283
|
+
if (isArray(filter)) {
|
|
275
284
|
objKeys = filter;
|
|
276
285
|
} else {
|
|
277
286
|
var keys = Object.keys(obj);
|
|
@@ -285,8 +294,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
285
294
|
continue;
|
|
286
295
|
}
|
|
287
296
|
|
|
288
|
-
if (
|
|
289
|
-
values
|
|
297
|
+
if (isArray(obj)) {
|
|
298
|
+
pushToArray(values, stringify(
|
|
290
299
|
obj[key],
|
|
291
300
|
generateArrayPrefix(prefix, key),
|
|
292
301
|
generateArrayPrefix,
|
|
@@ -300,7 +309,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
300
309
|
formatter
|
|
301
310
|
));
|
|
302
311
|
} else {
|
|
303
|
-
values
|
|
312
|
+
pushToArray(values, stringify(
|
|
304
313
|
obj[key],
|
|
305
314
|
prefix + (allowDots ? '.' + key : '[' + key + ']'),
|
|
306
315
|
generateArrayPrefix,
|
|
@@ -323,7 +332,7 @@ module.exports = function (object, opts) {
|
|
|
323
332
|
var obj = object;
|
|
324
333
|
var options = opts || {};
|
|
325
334
|
|
|
326
|
-
if (options.encoder !== null && options.encoder !== undefined && typeof options.encoder !== 'function') {
|
|
335
|
+
if (options.encoder !== null && typeof options.encoder !== 'undefined' && typeof options.encoder !== 'function') {
|
|
327
336
|
throw new TypeError('Encoder has to be a function.');
|
|
328
337
|
}
|
|
329
338
|
|
|
@@ -331,12 +340,12 @@ module.exports = function (object, opts) {
|
|
|
331
340
|
var strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : defaults.strictNullHandling;
|
|
332
341
|
var skipNulls = typeof options.skipNulls === 'boolean' ? options.skipNulls : defaults.skipNulls;
|
|
333
342
|
var encode = typeof options.encode === 'boolean' ? options.encode : defaults.encode;
|
|
334
|
-
var encoder = encode ?
|
|
343
|
+
var encoder = encode ? typeof options.encoder === 'function' ? options.encoder : defaults.encoder : null;
|
|
335
344
|
var sort = typeof options.sort === 'function' ? options.sort : null;
|
|
336
345
|
var allowDots = typeof options.allowDots === 'undefined' ? false : options.allowDots;
|
|
337
346
|
var serializeDate = typeof options.serializeDate === 'function' ? options.serializeDate : defaults.serializeDate;
|
|
338
347
|
if (typeof options.format === 'undefined') {
|
|
339
|
-
options.format = formats
|
|
348
|
+
options.format = formats['default'];
|
|
340
349
|
} else if (!Object.prototype.hasOwnProperty.call(formats.formatters, options.format)) {
|
|
341
350
|
throw new TypeError('Unknown format option provided.');
|
|
342
351
|
}
|
|
@@ -347,7 +356,7 @@ module.exports = function (object, opts) {
|
|
|
347
356
|
if (typeof options.filter === 'function') {
|
|
348
357
|
filter = options.filter;
|
|
349
358
|
obj = filter('', obj);
|
|
350
|
-
} else if (
|
|
359
|
+
} else if (isArray(options.filter)) {
|
|
351
360
|
filter = options.filter;
|
|
352
361
|
objKeys = filter;
|
|
353
362
|
}
|
|
@@ -383,8 +392,7 @@ module.exports = function (object, opts) {
|
|
|
383
392
|
if (skipNulls && obj[key] === null) {
|
|
384
393
|
continue;
|
|
385
394
|
}
|
|
386
|
-
|
|
387
|
-
keys = keys.concat(stringify(
|
|
395
|
+
pushToArray(keys, stringify(
|
|
388
396
|
obj[key],
|
|
389
397
|
key,
|
|
390
398
|
generateArrayPrefix,
|
|
@@ -435,8 +443,8 @@ exports.merge = function (target, source, options) {
|
|
|
435
443
|
if (typeof source !== 'object') {
|
|
436
444
|
if (Array.isArray(target)) {
|
|
437
445
|
target.push(source);
|
|
438
|
-
} else if (typeof target === 'object') {
|
|
439
|
-
if (options.plainObjects || options.allowPrototypes || !has.call(Object.prototype, source)) {
|
|
446
|
+
} else if (target && typeof target === 'object') {
|
|
447
|
+
if ((options && (options.plainObjects || options.allowPrototypes)) || !has.call(Object.prototype, source)) {
|
|
440
448
|
target[source] = true;
|
|
441
449
|
}
|
|
442
450
|
} else {
|
|
@@ -446,7 +454,7 @@ exports.merge = function (target, source, options) {
|
|
|
446
454
|
return target;
|
|
447
455
|
}
|
|
448
456
|
|
|
449
|
-
if (typeof target !== 'object') {
|
|
457
|
+
if (!target || typeof target !== 'object') {
|
|
450
458
|
return [target].concat(source);
|
|
451
459
|
}
|
|
452
460
|
|
|
@@ -504,13 +512,13 @@ exports.encode = function (str) {
|
|
|
504
512
|
var c = string.charCodeAt(i);
|
|
505
513
|
|
|
506
514
|
if (
|
|
507
|
-
c === 0x2D
|
|
508
|
-
c === 0x2E
|
|
509
|
-
c === 0x5F
|
|
510
|
-
c === 0x7E
|
|
511
|
-
(c >= 0x30 && c <= 0x39)
|
|
512
|
-
(c >= 0x41 && c <= 0x5A)
|
|
513
|
-
(c >= 0x61 && c <= 0x7A) // A-Z
|
|
515
|
+
c === 0x2D // -
|
|
516
|
+
|| c === 0x2E // .
|
|
517
|
+
|| c === 0x5F // _
|
|
518
|
+
|| c === 0x7E // ~
|
|
519
|
+
|| (c >= 0x30 && c <= 0x39) // 0-9
|
|
520
|
+
|| (c >= 0x41 && c <= 0x5A) // a-z
|
|
521
|
+
|| (c >= 0x61 && c <= 0x7A) // A-Z
|
|
514
522
|
) {
|
|
515
523
|
out += string.charAt(i);
|
|
516
524
|
continue;
|
|
@@ -533,7 +541,11 @@ exports.encode = function (str) {
|
|
|
533
541
|
|
|
534
542
|
i += 1;
|
|
535
543
|
c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
|
|
536
|
-
|
|
544
|
+
/* eslint operator-linebreak: [2, "before"] */
|
|
545
|
+
out += hexTable[0xF0 | (c >> 18)]
|
|
546
|
+
+ hexTable[0x80 | ((c >> 12) & 0x3F)]
|
|
547
|
+
+ hexTable[0x80 | ((c >> 6) & 0x3F)]
|
|
548
|
+
+ hexTable[0x80 | (c & 0x3F)];
|
|
537
549
|
}
|
|
538
550
|
|
|
539
551
|
return out;
|
|
@@ -587,4 +599,4 @@ exports.isBuffer = function (obj) {
|
|
|
587
599
|
};
|
|
588
600
|
|
|
589
601
|
},{}]},{},[2])(2)
|
|
590
|
-
});
|
|
602
|
+
});
|
package/lib/formats.js
CHANGED
package/lib/parse.js
CHANGED
|
@@ -50,23 +50,25 @@ var parseObject = function parseObjectRecursive(chain, val, options) {
|
|
|
50
50
|
var root = chain.shift();
|
|
51
51
|
|
|
52
52
|
var obj;
|
|
53
|
-
if (root === '[]') {
|
|
53
|
+
if (root === '[]' && options.parseArrays) {
|
|
54
54
|
obj = [];
|
|
55
55
|
obj = obj.concat(parseObject(chain, val, options));
|
|
56
56
|
} else {
|
|
57
57
|
obj = options.plainObjects ? Object.create(null) : {};
|
|
58
58
|
var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
|
|
59
59
|
var index = parseInt(cleanRoot, 10);
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
if (!options.parseArrays && cleanRoot === '') {
|
|
61
|
+
obj = { 0: val };
|
|
62
|
+
} else if (
|
|
63
|
+
!isNaN(index)
|
|
64
|
+
&& root !== cleanRoot
|
|
65
|
+
&& String(index) === cleanRoot
|
|
66
|
+
&& index >= 0
|
|
67
|
+
&& (options.parseArrays && index <= options.arrayLimit)
|
|
66
68
|
) {
|
|
67
69
|
obj = [];
|
|
68
70
|
obj[index] = parseObject(chain, val, options);
|
|
69
|
-
} else {
|
|
71
|
+
} else if (cleanRoot !== '__proto__') {
|
|
70
72
|
obj[cleanRoot] = parseObject(chain, val, options);
|
|
71
73
|
}
|
|
72
74
|
}
|
|
@@ -96,8 +98,7 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
|
|
|
96
98
|
|
|
97
99
|
var keys = [];
|
|
98
100
|
if (parent) {
|
|
99
|
-
// If we aren't using plain objects, optionally prefix keys
|
|
100
|
-
// that would overwrite object prototype properties
|
|
101
|
+
// If we aren't using plain objects, optionally prefix keys that would overwrite object prototype properties
|
|
101
102
|
if (!options.plainObjects && has.call(Object.prototype, parent)) {
|
|
102
103
|
if (!options.allowPrototypes) {
|
|
103
104
|
return;
|
package/lib/stringify.js
CHANGED
|
@@ -4,31 +4,37 @@ 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 = {
|
|
21
27
|
delimiter: '&',
|
|
22
28
|
encode: true,
|
|
23
29
|
encoder: utils.encode,
|
|
24
|
-
serializeDate: function serializeDate(date) {
|
|
30
|
+
serializeDate: function serializeDate(date) {
|
|
25
31
|
return toISO.call(date);
|
|
26
32
|
},
|
|
27
33
|
skipNulls: false,
|
|
28
34
|
strictNullHandling: false
|
|
29
35
|
};
|
|
30
36
|
|
|
31
|
-
var stringify = function stringify(
|
|
37
|
+
var stringify = function stringify(
|
|
32
38
|
object,
|
|
33
39
|
prefix,
|
|
34
40
|
generateArrayPrefix,
|
|
@@ -46,7 +52,9 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
46
52
|
obj = filter(prefix, obj);
|
|
47
53
|
} else if (obj instanceof Date) {
|
|
48
54
|
obj = serializeDate(obj);
|
|
49
|
-
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (obj === null) {
|
|
50
58
|
if (strictNullHandling) {
|
|
51
59
|
return encoder ? encoder(prefix) : prefix;
|
|
52
60
|
}
|
|
@@ -68,7 +76,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
68
76
|
}
|
|
69
77
|
|
|
70
78
|
var objKeys;
|
|
71
|
-
if (
|
|
79
|
+
if (isArray(filter)) {
|
|
72
80
|
objKeys = filter;
|
|
73
81
|
} else {
|
|
74
82
|
var keys = Object.keys(obj);
|
|
@@ -82,8 +90,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
82
90
|
continue;
|
|
83
91
|
}
|
|
84
92
|
|
|
85
|
-
if (
|
|
86
|
-
values
|
|
93
|
+
if (isArray(obj)) {
|
|
94
|
+
pushToArray(values, stringify(
|
|
87
95
|
obj[key],
|
|
88
96
|
generateArrayPrefix(prefix, key),
|
|
89
97
|
generateArrayPrefix,
|
|
@@ -97,7 +105,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
97
105
|
formatter
|
|
98
106
|
));
|
|
99
107
|
} else {
|
|
100
|
-
values
|
|
108
|
+
pushToArray(values, stringify(
|
|
101
109
|
obj[key],
|
|
102
110
|
prefix + (allowDots ? '.' + key : '[' + key + ']'),
|
|
103
111
|
generateArrayPrefix,
|
|
@@ -120,7 +128,7 @@ module.exports = function (object, opts) {
|
|
|
120
128
|
var obj = object;
|
|
121
129
|
var options = opts || {};
|
|
122
130
|
|
|
123
|
-
if (options.encoder !== null && options.encoder !== undefined && typeof options.encoder !== 'function') {
|
|
131
|
+
if (options.encoder !== null && typeof options.encoder !== 'undefined' && typeof options.encoder !== 'function') {
|
|
124
132
|
throw new TypeError('Encoder has to be a function.');
|
|
125
133
|
}
|
|
126
134
|
|
|
@@ -128,12 +136,12 @@ module.exports = function (object, opts) {
|
|
|
128
136
|
var strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : defaults.strictNullHandling;
|
|
129
137
|
var skipNulls = typeof options.skipNulls === 'boolean' ? options.skipNulls : defaults.skipNulls;
|
|
130
138
|
var encode = typeof options.encode === 'boolean' ? options.encode : defaults.encode;
|
|
131
|
-
var encoder = encode ?
|
|
139
|
+
var encoder = encode ? typeof options.encoder === 'function' ? options.encoder : defaults.encoder : null;
|
|
132
140
|
var sort = typeof options.sort === 'function' ? options.sort : null;
|
|
133
141
|
var allowDots = typeof options.allowDots === 'undefined' ? false : options.allowDots;
|
|
134
142
|
var serializeDate = typeof options.serializeDate === 'function' ? options.serializeDate : defaults.serializeDate;
|
|
135
143
|
if (typeof options.format === 'undefined') {
|
|
136
|
-
options.format = formats
|
|
144
|
+
options.format = formats['default'];
|
|
137
145
|
} else if (!Object.prototype.hasOwnProperty.call(formats.formatters, options.format)) {
|
|
138
146
|
throw new TypeError('Unknown format option provided.');
|
|
139
147
|
}
|
|
@@ -144,7 +152,7 @@ module.exports = function (object, opts) {
|
|
|
144
152
|
if (typeof options.filter === 'function') {
|
|
145
153
|
filter = options.filter;
|
|
146
154
|
obj = filter('', obj);
|
|
147
|
-
} else if (
|
|
155
|
+
} else if (isArray(options.filter)) {
|
|
148
156
|
filter = options.filter;
|
|
149
157
|
objKeys = filter;
|
|
150
158
|
}
|
|
@@ -180,8 +188,7 @@ module.exports = function (object, opts) {
|
|
|
180
188
|
if (skipNulls && obj[key] === null) {
|
|
181
189
|
continue;
|
|
182
190
|
}
|
|
183
|
-
|
|
184
|
-
keys = keys.concat(stringify(
|
|
191
|
+
pushToArray(keys, stringify(
|
|
185
192
|
obj[key],
|
|
186
193
|
key,
|
|
187
194
|
generateArrayPrefix,
|
package/lib/utils.js
CHANGED
|
@@ -30,8 +30,8 @@ exports.merge = function (target, source, options) {
|
|
|
30
30
|
if (typeof source !== 'object') {
|
|
31
31
|
if (Array.isArray(target)) {
|
|
32
32
|
target.push(source);
|
|
33
|
-
} else if (typeof target === 'object') {
|
|
34
|
-
if (options.plainObjects || options.allowPrototypes || !has.call(Object.prototype, source)) {
|
|
33
|
+
} else if (target && typeof target === 'object') {
|
|
34
|
+
if ((options && (options.plainObjects || options.allowPrototypes)) || !has.call(Object.prototype, source)) {
|
|
35
35
|
target[source] = true;
|
|
36
36
|
}
|
|
37
37
|
} else {
|
|
@@ -41,7 +41,7 @@ exports.merge = function (target, source, options) {
|
|
|
41
41
|
return target;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
if (typeof target !== 'object') {
|
|
44
|
+
if (!target || typeof target !== 'object') {
|
|
45
45
|
return [target].concat(source);
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -99,13 +99,13 @@ exports.encode = function (str) {
|
|
|
99
99
|
var c = string.charCodeAt(i);
|
|
100
100
|
|
|
101
101
|
if (
|
|
102
|
-
c === 0x2D
|
|
103
|
-
c === 0x2E
|
|
104
|
-
c === 0x5F
|
|
105
|
-
c === 0x7E
|
|
106
|
-
(c >= 0x30 && c <= 0x39)
|
|
107
|
-
(c >= 0x41 && c <= 0x5A)
|
|
108
|
-
(c >= 0x61 && c <= 0x7A) // A-Z
|
|
102
|
+
c === 0x2D // -
|
|
103
|
+
|| c === 0x2E // .
|
|
104
|
+
|| c === 0x5F // _
|
|
105
|
+
|| c === 0x7E // ~
|
|
106
|
+
|| (c >= 0x30 && c <= 0x39) // 0-9
|
|
107
|
+
|| (c >= 0x41 && c <= 0x5A) // a-z
|
|
108
|
+
|| (c >= 0x61 && c <= 0x7A) // A-Z
|
|
109
109
|
) {
|
|
110
110
|
out += string.charAt(i);
|
|
111
111
|
continue;
|
|
@@ -128,7 +128,11 @@ exports.encode = function (str) {
|
|
|
128
128
|
|
|
129
129
|
i += 1;
|
|
130
130
|
c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
|
|
131
|
-
|
|
131
|
+
/* eslint operator-linebreak: [2, "before"] */
|
|
132
|
+
out += hexTable[0xF0 | (c >> 18)]
|
|
133
|
+
+ hexTable[0x80 | ((c >> 12) & 0x3F)]
|
|
134
|
+
+ hexTable[0x80 | ((c >> 6) & 0x3F)]
|
|
135
|
+
+ hexTable[0x80 | (c & 0x3F)];
|
|
132
136
|
}
|
|
133
137
|
|
|
134
138
|
return out;
|
package/package.json
CHANGED
|
@@ -1,50 +1,54 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
2
|
+
"name": "qs",
|
|
3
|
+
"description": "A querystring parser that supports nesting and arrays, with a depth limit",
|
|
4
|
+
"homepage": "https://github.com/ljharb/qs",
|
|
5
|
+
"version": "6.3.3",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/ljharb/qs.git"
|
|
9
|
+
},
|
|
10
|
+
"main": "lib/index.js",
|
|
11
|
+
"contributors": [
|
|
12
|
+
{
|
|
13
|
+
"name": "Jordan Harband",
|
|
14
|
+
"email": "ljharb@gmail.com",
|
|
15
|
+
"url": "http://ljharb.codes"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"keywords": [
|
|
19
|
+
"querystring",
|
|
20
|
+
"qs"
|
|
21
|
+
],
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=0.6"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
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",
|
|
31
|
+
"evalmd": "^0.0.17",
|
|
32
|
+
"iconv-lite": "^0.4.24",
|
|
33
|
+
"in-publish": "^2.0.1",
|
|
34
|
+
"mkdirp": "^0.5.1",
|
|
35
|
+
"nyc": "^10.3.2",
|
|
36
|
+
"qs-iconv": "^1.0.4",
|
|
37
|
+
"safe-publish-latest": "^2.0.0",
|
|
38
|
+
"safer-buffer": "^2.1.2",
|
|
39
|
+
"tape": "^5.4.0"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"prepublishOnly": "safe-publish-latest && npm run dist",
|
|
43
|
+
"prepublish": "not-in-publish || npm run prepublishOnly",
|
|
44
|
+
"pretest": "npm run --silent readme && npm run --silent lint",
|
|
45
|
+
"test": "npm run --silent tests-only",
|
|
46
|
+
"tests-only": "nyc tape 'test/**/*.js'",
|
|
47
|
+
"posttest": "aud --production",
|
|
48
|
+
"readme": "evalmd README.md",
|
|
49
|
+
"postlint": "eclint check $(git ls-files | xargs find 2> /dev/null | grep -vE 'node_modules|\\.git')",
|
|
50
|
+
"lint": "eslint --ext=js,mjs .",
|
|
51
|
+
"dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js"
|
|
52
|
+
},
|
|
53
|
+
"license": "BSD-3-Clause"
|
|
50
54
|
}
|
package/test/parse.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var test = require('tape');
|
|
4
4
|
var qs = require('../');
|
|
5
5
|
var iconv = require('iconv-lite');
|
|
6
|
+
var SaferBuffer = require('safer-buffer').Buffer;
|
|
6
7
|
|
|
7
8
|
test('parse()', function (t) {
|
|
8
9
|
t.test('parses a simple string', function (st) {
|
|
@@ -230,7 +231,7 @@ test('parse()', function (t) {
|
|
|
230
231
|
});
|
|
231
232
|
|
|
232
233
|
t.test('parses buffers correctly', function (st) {
|
|
233
|
-
var b =
|
|
234
|
+
var b = SaferBuffer.from('test');
|
|
234
235
|
st.deepEqual(qs.parse({ a: b }), { a: b });
|
|
235
236
|
st.end();
|
|
236
237
|
});
|
|
@@ -255,7 +256,7 @@ test('parse()', function (t) {
|
|
|
255
256
|
st.end();
|
|
256
257
|
});
|
|
257
258
|
|
|
258
|
-
t.test('should not throw when a native prototype has an enumerable property',
|
|
259
|
+
t.test('should not throw when a native prototype has an enumerable property', function (st) {
|
|
259
260
|
Object.prototype.crash = '';
|
|
260
261
|
Array.prototype.crash = '';
|
|
261
262
|
st.doesNotThrow(qs.parse.bind(null, 'a=b'));
|
|
@@ -300,7 +301,14 @@ test('parse()', function (t) {
|
|
|
300
301
|
});
|
|
301
302
|
|
|
302
303
|
t.test('allows disabling array parsing', function (st) {
|
|
303
|
-
|
|
304
|
+
var indices = qs.parse('a[0]=b&a[1]=c', { parseArrays: false });
|
|
305
|
+
st.deepEqual(indices, { a: { 0: 'b', 1: 'c' } });
|
|
306
|
+
st.equal(Array.isArray(indices.a), false, 'parseArrays:false, indices case is not an array');
|
|
307
|
+
|
|
308
|
+
var emptyBrackets = qs.parse('a[]=b', { parseArrays: false });
|
|
309
|
+
st.deepEqual(emptyBrackets, { a: { 0: 'b' } });
|
|
310
|
+
st.equal(Array.isArray(emptyBrackets.a), false, 'parseArrays:false, empty brackets case is not an array');
|
|
311
|
+
|
|
304
312
|
st.end();
|
|
305
313
|
});
|
|
306
314
|
|
|
@@ -472,13 +480,73 @@ test('parse()', function (t) {
|
|
|
472
480
|
|
|
473
481
|
st.deepEqual(
|
|
474
482
|
qs.parse('a[b]=c&a=toString', { plainObjects: true }),
|
|
475
|
-
{ a: { b: 'c', toString: true } },
|
|
483
|
+
{ __proto__: null, a: { __proto__: null, b: 'c', toString: true } },
|
|
476
484
|
'can overwrite prototype with plainObjects true'
|
|
477
485
|
);
|
|
478
486
|
|
|
479
487
|
st.end();
|
|
480
488
|
});
|
|
481
489
|
|
|
490
|
+
t.test('dunder proto is ignored', function (st) {
|
|
491
|
+
var payload = 'categories[__proto__]=login&categories[__proto__]&categories[length]=42';
|
|
492
|
+
var result = qs.parse(payload, { allowPrototypes: true });
|
|
493
|
+
|
|
494
|
+
st.deepEqual(
|
|
495
|
+
result,
|
|
496
|
+
{
|
|
497
|
+
categories: {
|
|
498
|
+
length: '42'
|
|
499
|
+
}
|
|
500
|
+
},
|
|
501
|
+
'silent [[Prototype]] payload'
|
|
502
|
+
);
|
|
503
|
+
|
|
504
|
+
var plainResult = qs.parse(payload, { allowPrototypes: true, plainObjects: true });
|
|
505
|
+
|
|
506
|
+
st.deepEqual(
|
|
507
|
+
plainResult,
|
|
508
|
+
{
|
|
509
|
+
__proto__: null,
|
|
510
|
+
categories: {
|
|
511
|
+
__proto__: null,
|
|
512
|
+
length: '42'
|
|
513
|
+
}
|
|
514
|
+
},
|
|
515
|
+
'silent [[Prototype]] payload: plain objects'
|
|
516
|
+
);
|
|
517
|
+
|
|
518
|
+
var query = qs.parse('categories[__proto__]=cats&categories[__proto__]=dogs&categories[some][json]=toInject', { allowPrototypes: true });
|
|
519
|
+
|
|
520
|
+
st.notOk(Array.isArray(query.categories), 'is not an array');
|
|
521
|
+
st.notOk(query.categories instanceof Array, 'is not instanceof an array');
|
|
522
|
+
st.deepEqual(query.categories, { some: { json: 'toInject' } });
|
|
523
|
+
st.equal(JSON.stringify(query.categories), '{"some":{"json":"toInject"}}', 'stringifies as a non-array');
|
|
524
|
+
|
|
525
|
+
st.deepEqual(
|
|
526
|
+
qs.parse('foo[__proto__][hidden]=value&foo[bar]=stuffs', { allowPrototypes: true }),
|
|
527
|
+
{
|
|
528
|
+
foo: {
|
|
529
|
+
bar: 'stuffs'
|
|
530
|
+
}
|
|
531
|
+
},
|
|
532
|
+
'hidden values'
|
|
533
|
+
);
|
|
534
|
+
|
|
535
|
+
st.deepEqual(
|
|
536
|
+
qs.parse('foo[__proto__][hidden]=value&foo[bar]=stuffs', { allowPrototypes: true, plainObjects: true }),
|
|
537
|
+
{
|
|
538
|
+
__proto__: null,
|
|
539
|
+
foo: {
|
|
540
|
+
__proto__: null,
|
|
541
|
+
bar: 'stuffs'
|
|
542
|
+
}
|
|
543
|
+
},
|
|
544
|
+
'hidden values: plain objects'
|
|
545
|
+
);
|
|
546
|
+
|
|
547
|
+
st.end();
|
|
548
|
+
});
|
|
549
|
+
|
|
482
550
|
t.test('can return null objects', { skip: !Object.create }, function (st) {
|
|
483
551
|
var expected = Object.create(null);
|
|
484
552
|
expected.a = Object.create(null);
|
|
@@ -504,14 +572,14 @@ test('parse()', function (t) {
|
|
|
504
572
|
result.push(parseInt(parts[1], 16));
|
|
505
573
|
parts = reg.exec(str);
|
|
506
574
|
}
|
|
507
|
-
return iconv.decode(
|
|
575
|
+
return iconv.decode(SaferBuffer.from(result), 'shift_jis').toString();
|
|
508
576
|
}
|
|
509
577
|
}), { 県: '大阪府' });
|
|
510
578
|
st.end();
|
|
511
579
|
});
|
|
512
580
|
|
|
513
581
|
t.test('throws error with wrong decoder', function (st) {
|
|
514
|
-
st
|
|
582
|
+
st['throws'](function () {
|
|
515
583
|
qs.parse({}, { decoder: 'string' });
|
|
516
584
|
}, new TypeError('Decoder has to be a function.'));
|
|
517
585
|
st.end();
|
package/test/stringify.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var test = require('tape');
|
|
4
4
|
var qs = require('../');
|
|
5
5
|
var iconv = require('iconv-lite');
|
|
6
|
+
var SaferBuffer = require('safer-buffer').Buffer;
|
|
6
7
|
|
|
7
8
|
test('stringify()', function (t) {
|
|
8
9
|
t.test('stringifies a querystring object', function (st) {
|
|
@@ -325,8 +326,8 @@ test('stringify()', function (t) {
|
|
|
325
326
|
});
|
|
326
327
|
|
|
327
328
|
t.test('stringifies buffer values', function (st) {
|
|
328
|
-
st.equal(qs.stringify({ a:
|
|
329
|
-
st.equal(qs.stringify({ a: { b:
|
|
329
|
+
st.equal(qs.stringify({ a: SaferBuffer.from('test') }), 'a=test');
|
|
330
|
+
st.equal(qs.stringify({ a: { b: SaferBuffer.from('test') } }), 'a%5Bb%5D=test');
|
|
330
331
|
st.end();
|
|
331
332
|
});
|
|
332
333
|
|
|
@@ -453,14 +454,14 @@ test('stringify()', function (t) {
|
|
|
453
454
|
});
|
|
454
455
|
|
|
455
456
|
t.test('throws error with wrong encoder', function (st) {
|
|
456
|
-
st
|
|
457
|
+
st['throws'](function () {
|
|
457
458
|
qs.stringify({}, { encoder: 'string' });
|
|
458
459
|
}, new TypeError('Encoder has to be a function.'));
|
|
459
460
|
st.end();
|
|
460
461
|
});
|
|
461
462
|
|
|
462
463
|
t.test('can use custom encoder for a buffer object', { skip: typeof Buffer === 'undefined' }, function (st) {
|
|
463
|
-
st.equal(qs.stringify({ a:
|
|
464
|
+
st.equal(qs.stringify({ a: SaferBuffer.from([1]) }, {
|
|
464
465
|
encoder: function (buffer) {
|
|
465
466
|
if (typeof buffer === 'string') {
|
|
466
467
|
return buffer;
|
|
@@ -468,6 +469,12 @@ test('stringify()', function (t) {
|
|
|
468
469
|
return String.fromCharCode(buffer.readUInt8(0) + 97);
|
|
469
470
|
}
|
|
470
471
|
}), 'a=b');
|
|
472
|
+
|
|
473
|
+
st.equal(qs.stringify({ a: SaferBuffer.from('a b') }, {
|
|
474
|
+
encoder: function (buffer) {
|
|
475
|
+
return buffer;
|
|
476
|
+
}
|
|
477
|
+
}), 'a=a b');
|
|
471
478
|
st.end();
|
|
472
479
|
});
|
|
473
480
|
|
|
@@ -483,7 +490,7 @@ test('stringify()', function (t) {
|
|
|
483
490
|
mutatedDate.toISOString = function () {
|
|
484
491
|
throw new SyntaxError();
|
|
485
492
|
};
|
|
486
|
-
st
|
|
493
|
+
st['throws'](function () {
|
|
487
494
|
mutatedDate.toISOString();
|
|
488
495
|
}, SyntaxError);
|
|
489
496
|
st.equal(
|
|
@@ -508,31 +515,54 @@ test('stringify()', function (t) {
|
|
|
508
515
|
t.test('RFC 1738 spaces serialization', function (st) {
|
|
509
516
|
st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.RFC1738 }), 'a=b+c');
|
|
510
517
|
st.equal(qs.stringify({ 'a b': 'c d' }, { format: qs.formats.RFC1738 }), 'a+b=c+d');
|
|
518
|
+
st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }, { format: qs.formats.RFC1738 }), 'a+b=a+b');
|
|
511
519
|
st.end();
|
|
512
520
|
});
|
|
513
521
|
|
|
514
522
|
t.test('RFC 3986 spaces serialization', function (st) {
|
|
515
523
|
st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.RFC3986 }), 'a=b%20c');
|
|
516
524
|
st.equal(qs.stringify({ 'a b': 'c d' }, { format: qs.formats.RFC3986 }), 'a%20b=c%20d');
|
|
525
|
+
st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }, { format: qs.formats.RFC3986 }), 'a%20b=a%20b');
|
|
517
526
|
st.end();
|
|
518
527
|
});
|
|
519
528
|
|
|
520
529
|
t.test('Backward compatibility to RFC 3986', function (st) {
|
|
521
530
|
st.equal(qs.stringify({ a: 'b c' }), 'a=b%20c');
|
|
531
|
+
st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }), 'a%20b=a%20b');
|
|
522
532
|
st.end();
|
|
523
533
|
});
|
|
524
534
|
|
|
525
535
|
t.test('Edge cases and unknown formats', function (st) {
|
|
526
|
-
['UFO1234', false, 1234, null, {}, []].forEach(
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
}
|
|
535
|
-
);
|
|
536
|
+
['UFO1234', false, 1234, null, {}, []].forEach(function (format) {
|
|
537
|
+
st['throws'](
|
|
538
|
+
function () {
|
|
539
|
+
qs.stringify({ a: 'b c' }, { format: format });
|
|
540
|
+
},
|
|
541
|
+
new TypeError('Unknown format option provided.')
|
|
542
|
+
);
|
|
543
|
+
});
|
|
536
544
|
st.end();
|
|
537
545
|
});
|
|
546
|
+
|
|
547
|
+
t.test('strictNullHandling works with custom filter', function (st) {
|
|
548
|
+
var filter = function (prefix, value) {
|
|
549
|
+
return value;
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
var options = { strictNullHandling: true, filter: filter };
|
|
553
|
+
st.equal(qs.stringify({ key: null }, options), 'key');
|
|
554
|
+
st.end();
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
t.test('strictNullHandling works with null serializeDate', function (st) {
|
|
558
|
+
var serializeDate = function () {
|
|
559
|
+
return null;
|
|
560
|
+
};
|
|
561
|
+
var options = { strictNullHandling: true, serializeDate: serializeDate };
|
|
562
|
+
var date = new Date();
|
|
563
|
+
st.equal(qs.stringify({ key: date }, options), 'key');
|
|
564
|
+
st.end();
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
t.end();
|
|
538
568
|
});
|
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,5 +22,8 @@ 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
|
+
|
|
21
28
|
t.end();
|
|
22
29
|
});
|
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
|