qs 6.4.1 → 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 +3 -4
- package/.eslintrc +1 -1
- package/CHANGELOG.md +60 -6
- package/README.md +51 -40
- package/component.json +2 -2
- package/dist/qs.js +116 -77
- package/lib/parse.js +42 -35
- package/lib/stringify.js +8 -5
- package/lib/utils.js +69 -40
- package/package.json +1 -1
- package/test/parse.js +63 -1
- package/test/stringify.js +44 -0
- package/test/utils.js +36 -0
package/.editorconfig
CHANGED
|
@@ -13,8 +13,10 @@ quote_type = single
|
|
|
13
13
|
[test/*]
|
|
14
14
|
max_line_length = off
|
|
15
15
|
|
|
16
|
-
[
|
|
16
|
+
[LICENSE.md]
|
|
17
17
|
indent_size = off
|
|
18
|
+
|
|
19
|
+
[*.md]
|
|
18
20
|
max_line_length = off
|
|
19
21
|
|
|
20
22
|
[*.json]
|
|
@@ -37,8 +39,5 @@ indent_style = off
|
|
|
37
39
|
indent = off
|
|
38
40
|
max_line_length = off
|
|
39
41
|
|
|
40
|
-
[dist/*]
|
|
41
|
-
max_line_length = off
|
|
42
|
-
|
|
43
42
|
[.nycrc]
|
|
44
43
|
indent_style = tab
|
package/.eslintrc
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,24 +1,53 @@
|
|
|
1
|
-
## **6.
|
|
1
|
+
## **6.5.3**
|
|
2
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] use `safer-buffer` instead of `Buffer` constructor
|
|
5
|
-
- [Fix] `utils.merge`: avoid a crash with a null target and an array source
|
|
6
3
|
- [Fix]` `utils.merge`: avoid a crash with a null target and a truthy non-array source
|
|
4
|
+
- [Fix] correctly parse nested arrays
|
|
7
5
|
- [Fix] `stringify`: fix a crash with `strictNullHandling` and a custom `filter`/`serializeDate` (#279)
|
|
8
6
|
- [Fix] `utils`: `merge`: fix crash when `source` is a truthy primitive & no options are provided
|
|
9
7
|
- [Fix] when `parseArrays` is false, properly handle keys ending in `[]`
|
|
10
|
-
- [
|
|
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
11
|
- [Refactor] use cached `Array.isArray`
|
|
12
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)
|
|
13
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
|
|
14
17
|
- [Docs] Clarify the need for "arrayLimit" option
|
|
15
18
|
- [meta] fix README.md (#399)
|
|
16
|
-
- [meta] Clean up license text so it’s properly detected as BSD-3-Clause
|
|
17
19
|
- [meta] add FUNDING.yml
|
|
18
20
|
- [actions] backport actions from main
|
|
21
|
+
- [Tests] always use `String(x)` over `x.toString()`
|
|
19
22
|
- [Tests] remove nonexistent tape option
|
|
20
23
|
- [Dev Deps] backport from main
|
|
21
24
|
|
|
25
|
+
## **6.5.2**
|
|
26
|
+
- [Fix] use `safer-buffer` instead of `Buffer` constructor
|
|
27
|
+
- [Refactor] utils: `module.exports` one thing, instead of mutating `exports` (#230)
|
|
28
|
+
- [Dev Deps] update `browserify`, `eslint`, `iconv-lite`, `safer-buffer`, `tape`, `browserify`
|
|
29
|
+
|
|
30
|
+
## **6.5.1**
|
|
31
|
+
- [Fix] Fix parsing & compacting very deep objects (#224)
|
|
32
|
+
- [Refactor] name utils functions
|
|
33
|
+
- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `tape`
|
|
34
|
+
- [Tests] up to `node` `v8.4`; use `nvm install-latest-npm` so newer npm doesn’t break older node
|
|
35
|
+
- [Tests] Use precise dist for Node.js 0.6 runtime (#225)
|
|
36
|
+
- [Tests] make 0.6 required, now that it’s passing
|
|
37
|
+
- [Tests] on `node` `v8.2`; fix npm on node 0.6
|
|
38
|
+
|
|
39
|
+
## **6.5.0**
|
|
40
|
+
- [New] add `utils.assign`
|
|
41
|
+
- [New] pass default encoder/decoder to custom encoder/decoder functions (#206)
|
|
42
|
+
- [New] `parse`/`stringify`: add `ignoreQueryPrefix`/`addQueryPrefix` options, respectively (#213)
|
|
43
|
+
- [Fix] Handle stringifying empty objects with addQueryPrefix (#217)
|
|
44
|
+
- [Fix] do not mutate `options` argument (#207)
|
|
45
|
+
- [Refactor] `parse`: cache index to reuse in else statement (#182)
|
|
46
|
+
- [Docs] add various badges to readme (#208)
|
|
47
|
+
- [Dev Deps] update `eslint`, `browserify`, `iconv-lite`, `tape`
|
|
48
|
+
- [Tests] up to `node` `v8.1`, `v7.10`, `v6.11`; npm v4.6 breaks on node < v1; npm v5+ breaks on node < v4
|
|
49
|
+
- [Tests] add `editorconfig-tools`
|
|
50
|
+
|
|
22
51
|
## **6.4.0**
|
|
23
52
|
- [New] `qs.stringify`: add `encodeValuesOnly` option
|
|
24
53
|
- [Fix] follow `allowPrototypes` option during merge (#201, #201)
|
|
@@ -28,6 +57,13 @@
|
|
|
28
57
|
- [Tests] up to `node` `v7.7`, `v6.10`,` v4.8`; disable osx builds since they block linux builds
|
|
29
58
|
- [eslint] reduce warnings
|
|
30
59
|
|
|
60
|
+
## **6.3.2**
|
|
61
|
+
- [Fix] follow `allowPrototypes` option during merge (#201, #200)
|
|
62
|
+
- [Dev Deps] update `eslint`
|
|
63
|
+
- [Fix] chmod a-x
|
|
64
|
+
- [Fix] support keys starting with brackets (#202, #200)
|
|
65
|
+
- [Tests] up to `node` `v7.7`, `v6.10`,` v4.8`; disable osx builds since they block linux builds
|
|
66
|
+
|
|
31
67
|
## **6.3.1**
|
|
32
68
|
- [Fix] ensure that `allowPrototypes: false` does not ever shadow Object.prototype properties (thanks, @snyk!)
|
|
33
69
|
- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `browserify`, `iconv-lite`, `qs-iconv`, `tape`
|
|
@@ -54,6 +90,12 @@
|
|
|
54
90
|
- [Tests] skip Object.create tests when null objects are not available
|
|
55
91
|
- [Tests] Turn on eslint for test files (#175)
|
|
56
92
|
|
|
93
|
+
## **6.2.3**
|
|
94
|
+
- [Fix] follow `allowPrototypes` option during merge (#201, #200)
|
|
95
|
+
- [Fix] chmod a-x
|
|
96
|
+
- [Fix] support keys starting with brackets (#202, #200)
|
|
97
|
+
- [Tests] up to `node` `v7.7`, `v6.10`,` v4.8`; disable osx builds since they block linux builds
|
|
98
|
+
|
|
57
99
|
## **6.2.2**
|
|
58
100
|
- [Fix] ensure that `allowPrototypes: false` does not ever shadow Object.prototype properties
|
|
59
101
|
|
|
@@ -69,6 +111,12 @@
|
|
|
69
111
|
- [New] add "encoder" and "decoder" options, for custom param encoding/decoding (#160)
|
|
70
112
|
- [Fix] fix compacting of nested sparse arrays (#150)
|
|
71
113
|
|
|
114
|
+
## **6.1.2
|
|
115
|
+
- [Fix] follow `allowPrototypes` option during merge (#201, #200)
|
|
116
|
+
- [Fix] chmod a-x
|
|
117
|
+
- [Fix] support keys starting with brackets (#202, #200)
|
|
118
|
+
- [Tests] up to `node` `v7.7`, `v6.10`,` v4.8`; disable osx builds since they block linux builds
|
|
119
|
+
|
|
72
120
|
## **6.1.1**
|
|
73
121
|
- [Fix] ensure that `allowPrototypes: false` does not ever shadow Object.prototype properties
|
|
74
122
|
|
|
@@ -77,6 +125,12 @@
|
|
|
77
125
|
- [Fix] "sort" option should work at a depth of 3 or more (#151)
|
|
78
126
|
- [Fix] Restore `dist` directory; will be removed in v7 (#148)
|
|
79
127
|
|
|
128
|
+
## **6.0.4**
|
|
129
|
+
- [Fix] follow `allowPrototypes` option during merge (#201, #200)
|
|
130
|
+
- [Fix] chmod a-x
|
|
131
|
+
- [Fix] support keys starting with brackets (#202, #200)
|
|
132
|
+
- [Tests] up to `node` `v7.7`, `v6.10`,` v4.8`; disable osx builds since they block linux builds
|
|
133
|
+
|
|
80
134
|
## **6.0.3**
|
|
81
135
|
- [Fix] ensure that `allowPrototypes: false` does not ever shadow Object.prototype properties
|
|
82
136
|
- [Fix] Restore `dist` directory; will be removed in v7 (#148)
|
package/README.md
CHANGED
|
@@ -11,8 +11,6 @@
|
|
|
11
11
|
|
|
12
12
|
A querystring parsing and stringifying library with some added security.
|
|
13
13
|
|
|
14
|
-
[](http://travis-ci.org/ljharb/qs)
|
|
15
|
-
|
|
16
14
|
Lead Maintainer: [Jordan Harband](https://github.com/ljharb)
|
|
17
15
|
|
|
18
16
|
The **qs** module was originally created and maintained by [TJ Holowaychuk](https://github.com/visionmedia/node-querystring).
|
|
@@ -42,9 +40,9 @@ For example, the string `'foo[bar]=baz'` converts to:
|
|
|
42
40
|
|
|
43
41
|
```javascript
|
|
44
42
|
assert.deepEqual(qs.parse('foo[bar]=baz'), {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
foo: {
|
|
44
|
+
bar: 'baz'
|
|
45
|
+
}
|
|
48
46
|
});
|
|
49
47
|
```
|
|
50
48
|
|
|
@@ -66,7 +64,7 @@ URI encoded strings work too:
|
|
|
66
64
|
|
|
67
65
|
```javascript
|
|
68
66
|
assert.deepEqual(qs.parse('a%5Bb%5D=c'), {
|
|
69
|
-
|
|
67
|
+
a: { b: 'c' }
|
|
70
68
|
});
|
|
71
69
|
```
|
|
72
70
|
|
|
@@ -74,11 +72,11 @@ You can also nest your objects, like `'foo[bar][baz]=foobarbaz'`:
|
|
|
74
72
|
|
|
75
73
|
```javascript
|
|
76
74
|
assert.deepEqual(qs.parse('foo[bar][baz]=foobarbaz'), {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
foo: {
|
|
76
|
+
bar: {
|
|
77
|
+
baz: 'foobarbaz'
|
|
78
|
+
}
|
|
80
79
|
}
|
|
81
|
-
}
|
|
82
80
|
});
|
|
83
81
|
```
|
|
84
82
|
|
|
@@ -87,19 +85,19 @@ By default, when nesting objects **qs** will only parse up to 5 children deep. T
|
|
|
87
85
|
|
|
88
86
|
```javascript
|
|
89
87
|
var expected = {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
88
|
+
a: {
|
|
89
|
+
b: {
|
|
90
|
+
c: {
|
|
91
|
+
d: {
|
|
92
|
+
e: {
|
|
93
|
+
f: {
|
|
94
|
+
'[g][h][i]': 'j'
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
97
98
|
}
|
|
98
|
-
}
|
|
99
99
|
}
|
|
100
|
-
}
|
|
101
100
|
}
|
|
102
|
-
}
|
|
103
101
|
};
|
|
104
102
|
var string = 'a[b][c][d][e][f][g][h][i]=j';
|
|
105
103
|
assert.deepEqual(qs.parse(string), expected);
|
|
@@ -121,6 +119,13 @@ var limited = qs.parse('a=b&c=d', { parameterLimit: 1 });
|
|
|
121
119
|
assert.deepEqual(limited, { a: 'b' });
|
|
122
120
|
```
|
|
123
121
|
|
|
122
|
+
To bypass the leading question mark, use `ignoreQueryPrefix`:
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
var prefixed = qs.parse('?a=b&c=d', { ignoreQueryPrefix: true });
|
|
126
|
+
assert.deepEqual(prefixed, { a: 'b', c: 'd' });
|
|
127
|
+
```
|
|
128
|
+
|
|
124
129
|
An optional delimiter can also be passed:
|
|
125
130
|
|
|
126
131
|
```javascript
|
|
@@ -236,10 +241,10 @@ assert.equal(unencoded, 'a[b]=c');
|
|
|
236
241
|
|
|
237
242
|
Encoding can be disabled for keys by setting the `encodeValuesOnly` option to `true`:
|
|
238
243
|
```javascript
|
|
239
|
-
var encodedValues
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
)
|
|
244
|
+
var encodedValues = qs.stringify(
|
|
245
|
+
{ a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
|
|
246
|
+
{ encodeValuesOnly: true }
|
|
247
|
+
);
|
|
243
248
|
assert.equal(encodedValues,'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h');
|
|
244
249
|
```
|
|
245
250
|
|
|
@@ -247,8 +252,8 @@ This encoding can also be replaced by a custom encoding method set as `encoder`
|
|
|
247
252
|
|
|
248
253
|
```javascript
|
|
249
254
|
var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str) {
|
|
250
|
-
|
|
251
|
-
|
|
255
|
+
// Passed in values `a`, `b`, `c`
|
|
256
|
+
return // Return encoded string
|
|
252
257
|
}})
|
|
253
258
|
```
|
|
254
259
|
|
|
@@ -258,8 +263,8 @@ Analogue to the `encoder` there is a `decoder` option for `parse` to override de
|
|
|
258
263
|
|
|
259
264
|
```javascript
|
|
260
265
|
var decoded = qs.parse('x=z', { decoder: function (str) {
|
|
261
|
-
|
|
262
|
-
|
|
266
|
+
// Passed in values `x`, `z`
|
|
267
|
+
return // Return decoded string
|
|
263
268
|
}})
|
|
264
269
|
```
|
|
265
270
|
|
|
@@ -350,6 +355,12 @@ Properties that are set to `undefined` will be omitted entirely:
|
|
|
350
355
|
assert.equal(qs.stringify({ a: null, b: undefined }), 'a=');
|
|
351
356
|
```
|
|
352
357
|
|
|
358
|
+
The query string may optionally be prepended with a question mark:
|
|
359
|
+
|
|
360
|
+
```javascript
|
|
361
|
+
assert.equal(qs.stringify({ a: 'b', c: 'd' }, { addQueryPrefix: true }), '?a=b&c=d');
|
|
362
|
+
```
|
|
363
|
+
|
|
353
364
|
The delimiter may be overridden with stringify as well:
|
|
354
365
|
|
|
355
366
|
```javascript
|
|
@@ -371,7 +382,7 @@ You may use the `sort` option to affect the order of parameter keys:
|
|
|
371
382
|
|
|
372
383
|
```javascript
|
|
373
384
|
function alphabeticalSort(a, b) {
|
|
374
|
-
|
|
385
|
+
return a.localeCompare(b);
|
|
375
386
|
}
|
|
376
387
|
assert.equal(qs.stringify({ a: 'c', z: 'y', b : 'f' }, { sort: alphabeticalSort }), 'a=c&b=f&z=y');
|
|
377
388
|
```
|
|
@@ -382,17 +393,17 @@ pass an array, it will be used to select properties and array indices for string
|
|
|
382
393
|
|
|
383
394
|
```javascript
|
|
384
395
|
function filterFunc(prefix, value) {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
+
if (prefix == 'b') {
|
|
397
|
+
// Return an `undefined` value to omit a property.
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
if (prefix == 'e[f]') {
|
|
401
|
+
return value.getTime();
|
|
402
|
+
}
|
|
403
|
+
if (prefix == 'e[g][0]') {
|
|
404
|
+
return value * 2;
|
|
405
|
+
}
|
|
406
|
+
return value;
|
|
396
407
|
}
|
|
397
408
|
qs.stringify({ a: 'b', c: 'd', e: { f: new Date(123), g: [2] } }, { filter: filterFunc });
|
|
398
409
|
// 'a=b&c=d&e[f]=123&e[g][0]=4'
|
package/component.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qs",
|
|
3
|
-
"repository": "
|
|
3
|
+
"repository": "ljharb/qs",
|
|
4
4
|
"description": "query-string parser / stringifier with nesting support",
|
|
5
|
-
"version": "6.
|
|
5
|
+
"version": "6.5.3",
|
|
6
6
|
"keywords": ["querystring", "query", "parser"],
|
|
7
7
|
"main": "lib/index.js",
|
|
8
8
|
"scripts": [
|
package/dist/qs.js
CHANGED
|
@@ -52,19 +52,23 @@ var defaults = {
|
|
|
52
52
|
|
|
53
53
|
var parseValues = function parseQueryStringValues(str, options) {
|
|
54
54
|
var obj = {};
|
|
55
|
-
var
|
|
55
|
+
var cleanStr = options.ignoreQueryPrefix ? str.replace(/^\?/, '') : str;
|
|
56
|
+
var limit = options.parameterLimit === Infinity ? undefined : options.parameterLimit;
|
|
57
|
+
var parts = cleanStr.split(options.delimiter, limit);
|
|
56
58
|
|
|
57
59
|
for (var i = 0; i < parts.length; ++i) {
|
|
58
60
|
var part = parts[i];
|
|
59
|
-
|
|
61
|
+
|
|
62
|
+
var bracketEqualsPos = part.indexOf(']=');
|
|
63
|
+
var pos = bracketEqualsPos === -1 ? part.indexOf('=') : bracketEqualsPos + 1;
|
|
60
64
|
|
|
61
65
|
var key, val;
|
|
62
66
|
if (pos === -1) {
|
|
63
|
-
key = options.decoder(part);
|
|
67
|
+
key = options.decoder(part, defaults.decoder);
|
|
64
68
|
val = options.strictNullHandling ? null : '';
|
|
65
69
|
} else {
|
|
66
|
-
key = options.decoder(part.slice(0, pos));
|
|
67
|
-
val = options.decoder(part.slice(pos + 1));
|
|
70
|
+
key = options.decoder(part.slice(0, pos), defaults.decoder);
|
|
71
|
+
val = options.decoder(part.slice(pos + 1), defaults.decoder);
|
|
68
72
|
}
|
|
69
73
|
if (has.call(obj, key)) {
|
|
70
74
|
obj[key] = [].concat(obj[key]).concat(val);
|
|
@@ -76,38 +80,39 @@ var parseValues = function parseQueryStringValues(str, options) {
|
|
|
76
80
|
return obj;
|
|
77
81
|
};
|
|
78
82
|
|
|
79
|
-
var parseObject = function
|
|
80
|
-
|
|
81
|
-
return val;
|
|
82
|
-
}
|
|
83
|
+
var parseObject = function (chain, val, options) {
|
|
84
|
+
var leaf = val;
|
|
83
85
|
|
|
84
|
-
var
|
|
86
|
+
for (var i = chain.length - 1; i >= 0; --i) {
|
|
87
|
+
var obj;
|
|
88
|
+
var root = chain[i];
|
|
85
89
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
obj[cleanRoot] = parseObject(chain, val, options);
|
|
90
|
+
if (root === '[]' && options.parseArrays) {
|
|
91
|
+
obj = [].concat(leaf);
|
|
92
|
+
} else {
|
|
93
|
+
obj = options.plainObjects ? Object.create(null) : {};
|
|
94
|
+
var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
|
|
95
|
+
var index = parseInt(cleanRoot, 10);
|
|
96
|
+
if (!options.parseArrays && cleanRoot === '') {
|
|
97
|
+
obj = { 0: leaf };
|
|
98
|
+
} else if (
|
|
99
|
+
!isNaN(index)
|
|
100
|
+
&& root !== cleanRoot
|
|
101
|
+
&& String(index) === cleanRoot
|
|
102
|
+
&& index >= 0
|
|
103
|
+
&& (options.parseArrays && index <= options.arrayLimit)
|
|
104
|
+
) {
|
|
105
|
+
obj = [];
|
|
106
|
+
obj[index] = leaf;
|
|
107
|
+
} else if (cleanRoot !== '__proto__') {
|
|
108
|
+
obj[cleanRoot] = leaf;
|
|
109
|
+
}
|
|
107
110
|
}
|
|
111
|
+
|
|
112
|
+
leaf = obj;
|
|
108
113
|
}
|
|
109
114
|
|
|
110
|
-
return
|
|
115
|
+
return leaf;
|
|
111
116
|
};
|
|
112
117
|
|
|
113
118
|
var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
|
|
@@ -132,7 +137,8 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
|
|
|
132
137
|
|
|
133
138
|
var keys = [];
|
|
134
139
|
if (parent) {
|
|
135
|
-
// If we aren't using plain objects, optionally prefix keys
|
|
140
|
+
// If we aren't using plain objects, optionally prefix keys
|
|
141
|
+
// that would overwrite object prototype properties
|
|
136
142
|
if (!options.plainObjects && has.call(Object.prototype, parent)) {
|
|
137
143
|
if (!options.allowPrototypes) {
|
|
138
144
|
return;
|
|
@@ -165,12 +171,13 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
|
|
|
165
171
|
};
|
|
166
172
|
|
|
167
173
|
module.exports = function (str, opts) {
|
|
168
|
-
var options = opts
|
|
174
|
+
var options = opts ? utils.assign({}, opts) : {};
|
|
169
175
|
|
|
170
176
|
if (options.decoder !== null && options.decoder !== undefined && typeof options.decoder !== 'function') {
|
|
171
177
|
throw new TypeError('Decoder has to be a function.');
|
|
172
178
|
}
|
|
173
179
|
|
|
180
|
+
options.ignoreQueryPrefix = options.ignoreQueryPrefix === true;
|
|
174
181
|
options.delimiter = typeof options.delimiter === 'string' || utils.isRegExp(options.delimiter) ? options.delimiter : defaults.delimiter;
|
|
175
182
|
options.depth = typeof options.depth === 'number' ? options.depth : defaults.depth;
|
|
176
183
|
options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : defaults.arrayLimit;
|
|
@@ -262,7 +269,7 @@ var stringify = function stringify(
|
|
|
262
269
|
|
|
263
270
|
if (obj === null) {
|
|
264
271
|
if (strictNullHandling) {
|
|
265
|
-
return encoder && !encodeValuesOnly ? encoder(prefix) : prefix;
|
|
272
|
+
return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder) : prefix;
|
|
266
273
|
}
|
|
267
274
|
|
|
268
275
|
obj = '';
|
|
@@ -270,8 +277,8 @@ var stringify = function stringify(
|
|
|
270
277
|
|
|
271
278
|
if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean' || utils.isBuffer(obj)) {
|
|
272
279
|
if (encoder) {
|
|
273
|
-
var keyValue = encodeValuesOnly ? prefix : encoder(prefix);
|
|
274
|
-
return [formatter(keyValue) + '=' + formatter(encoder(obj))];
|
|
280
|
+
var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder);
|
|
281
|
+
return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder))];
|
|
275
282
|
}
|
|
276
283
|
return [formatter(prefix) + '=' + formatter(String(obj))];
|
|
277
284
|
}
|
|
@@ -335,7 +342,7 @@ var stringify = function stringify(
|
|
|
335
342
|
|
|
336
343
|
module.exports = function (object, opts) {
|
|
337
344
|
var obj = object;
|
|
338
|
-
var options = opts
|
|
345
|
+
var options = opts ? utils.assign({}, opts) : {};
|
|
339
346
|
|
|
340
347
|
if (options.encoder !== null && typeof options.encoder !== 'undefined' && typeof options.encoder !== 'function') {
|
|
341
348
|
throw new TypeError('Encoder has to be a function.');
|
|
@@ -414,7 +421,10 @@ module.exports = function (object, opts) {
|
|
|
414
421
|
));
|
|
415
422
|
}
|
|
416
423
|
|
|
417
|
-
|
|
424
|
+
var joined = keys.join(delimiter);
|
|
425
|
+
var prefix = options.addQueryPrefix === true ? '?' : '';
|
|
426
|
+
|
|
427
|
+
return joined.length > 0 ? prefix + joined : '';
|
|
418
428
|
};
|
|
419
429
|
|
|
420
430
|
},{"./formats":1,"./utils":5}],5:[function(require,module,exports){
|
|
@@ -431,7 +441,30 @@ var hexTable = (function () {
|
|
|
431
441
|
return array;
|
|
432
442
|
}());
|
|
433
443
|
|
|
434
|
-
|
|
444
|
+
var compactQueue = function compactQueue(queue) {
|
|
445
|
+
var obj;
|
|
446
|
+
|
|
447
|
+
while (queue.length) {
|
|
448
|
+
var item = queue.pop();
|
|
449
|
+
obj = item.obj[item.prop];
|
|
450
|
+
|
|
451
|
+
if (Array.isArray(obj)) {
|
|
452
|
+
var compacted = [];
|
|
453
|
+
|
|
454
|
+
for (var j = 0; j < obj.length; ++j) {
|
|
455
|
+
if (typeof obj[j] !== 'undefined') {
|
|
456
|
+
compacted.push(obj[j]);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
item.obj[item.prop] = compacted;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return obj;
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
var arrayToObject = function arrayToObject(source, options) {
|
|
435
468
|
var obj = options && options.plainObjects ? Object.create(null) : {};
|
|
436
469
|
for (var i = 0; i < source.length; ++i) {
|
|
437
470
|
if (typeof source[i] !== 'undefined') {
|
|
@@ -442,7 +475,7 @@ exports.arrayToObject = function (source, options) {
|
|
|
442
475
|
return obj;
|
|
443
476
|
};
|
|
444
477
|
|
|
445
|
-
|
|
478
|
+
var merge = function merge(target, source, options) {
|
|
446
479
|
if (!source) {
|
|
447
480
|
return target;
|
|
448
481
|
}
|
|
@@ -467,14 +500,15 @@ exports.merge = function (target, source, options) {
|
|
|
467
500
|
|
|
468
501
|
var mergeTarget = target;
|
|
469
502
|
if (Array.isArray(target) && !Array.isArray(source)) {
|
|
470
|
-
mergeTarget =
|
|
503
|
+
mergeTarget = arrayToObject(target, options);
|
|
471
504
|
}
|
|
472
505
|
|
|
473
506
|
if (Array.isArray(target) && Array.isArray(source)) {
|
|
474
507
|
source.forEach(function (item, i) {
|
|
475
508
|
if (has.call(target, i)) {
|
|
476
|
-
|
|
477
|
-
|
|
509
|
+
var targetItem = target[i];
|
|
510
|
+
if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') {
|
|
511
|
+
target[i] = merge(targetItem, item, options);
|
|
478
512
|
} else {
|
|
479
513
|
target.push(item);
|
|
480
514
|
}
|
|
@@ -488,8 +522,8 @@ exports.merge = function (target, source, options) {
|
|
|
488
522
|
return Object.keys(source).reduce(function (acc, key) {
|
|
489
523
|
var value = source[key];
|
|
490
524
|
|
|
491
|
-
if (
|
|
492
|
-
acc[key] =
|
|
525
|
+
if (has.call(acc, key)) {
|
|
526
|
+
acc[key] = merge(acc[key], value, options);
|
|
493
527
|
} else {
|
|
494
528
|
acc[key] = value;
|
|
495
529
|
}
|
|
@@ -497,7 +531,14 @@ exports.merge = function (target, source, options) {
|
|
|
497
531
|
}, mergeTarget);
|
|
498
532
|
};
|
|
499
533
|
|
|
500
|
-
|
|
534
|
+
var assign = function assignSingleSource(target, source) {
|
|
535
|
+
return Object.keys(source).reduce(function (acc, key) {
|
|
536
|
+
acc[key] = source[key];
|
|
537
|
+
return acc;
|
|
538
|
+
}, target);
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
var decode = function (str) {
|
|
501
542
|
try {
|
|
502
543
|
return decodeURIComponent(str.replace(/\+/g, ' '));
|
|
503
544
|
} catch (e) {
|
|
@@ -505,7 +546,7 @@ exports.decode = function (str) {
|
|
|
505
546
|
}
|
|
506
547
|
};
|
|
507
548
|
|
|
508
|
-
|
|
549
|
+
var encode = function encode(str) {
|
|
509
550
|
// This code was originally written by Brian White (mscdex) for the io.js core querystring library.
|
|
510
551
|
// It has been adapted here for stricter adherence to RFC 3986
|
|
511
552
|
if (str.length === 0) {
|
|
@@ -558,46 +599,33 @@ exports.encode = function (str) {
|
|
|
558
599
|
return out;
|
|
559
600
|
};
|
|
560
601
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
}
|
|
602
|
+
var compact = function compact(value) {
|
|
603
|
+
var queue = [{ obj: { o: value }, prop: 'o' }];
|
|
604
|
+
var refs = [];
|
|
565
605
|
|
|
566
|
-
var
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
return refs[lookup];
|
|
570
|
-
}
|
|
606
|
+
for (var i = 0; i < queue.length; ++i) {
|
|
607
|
+
var item = queue[i];
|
|
608
|
+
var obj = item.obj[item.prop];
|
|
571
609
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
compacted.push(exports.compact(obj[i], refs));
|
|
580
|
-
} else if (typeof obj[i] !== 'undefined') {
|
|
581
|
-
compacted.push(obj[i]);
|
|
610
|
+
var keys = Object.keys(obj);
|
|
611
|
+
for (var j = 0; j < keys.length; ++j) {
|
|
612
|
+
var key = keys[j];
|
|
613
|
+
var val = obj[key];
|
|
614
|
+
if (typeof val === 'object' && val !== null && refs.indexOf(val) === -1) {
|
|
615
|
+
queue.push({ obj: obj, prop: key });
|
|
616
|
+
refs.push(val);
|
|
582
617
|
}
|
|
583
618
|
}
|
|
584
|
-
|
|
585
|
-
return compacted;
|
|
586
619
|
}
|
|
587
620
|
|
|
588
|
-
|
|
589
|
-
keys.forEach(function (key) {
|
|
590
|
-
obj[key] = exports.compact(obj[key], refs);
|
|
591
|
-
});
|
|
592
|
-
|
|
593
|
-
return obj;
|
|
621
|
+
return compactQueue(queue);
|
|
594
622
|
};
|
|
595
623
|
|
|
596
|
-
|
|
624
|
+
var isRegExp = function isRegExp(obj) {
|
|
597
625
|
return Object.prototype.toString.call(obj) === '[object RegExp]';
|
|
598
626
|
};
|
|
599
627
|
|
|
600
|
-
|
|
628
|
+
var isBuffer = function isBuffer(obj) {
|
|
601
629
|
if (obj === null || typeof obj === 'undefined') {
|
|
602
630
|
return false;
|
|
603
631
|
}
|
|
@@ -605,5 +633,16 @@ exports.isBuffer = function (obj) {
|
|
|
605
633
|
return !!(obj.constructor && obj.constructor.isBuffer && obj.constructor.isBuffer(obj));
|
|
606
634
|
};
|
|
607
635
|
|
|
636
|
+
module.exports = {
|
|
637
|
+
arrayToObject: arrayToObject,
|
|
638
|
+
assign: assign,
|
|
639
|
+
compact: compact,
|
|
640
|
+
decode: decode,
|
|
641
|
+
encode: encode,
|
|
642
|
+
isBuffer: isBuffer,
|
|
643
|
+
isRegExp: isRegExp,
|
|
644
|
+
merge: merge
|
|
645
|
+
};
|
|
646
|
+
|
|
608
647
|
},{}]},{},[2])(2)
|
|
609
648
|
});
|
package/lib/parse.js
CHANGED
|
@@ -18,19 +18,23 @@ var defaults = {
|
|
|
18
18
|
|
|
19
19
|
var parseValues = function parseQueryStringValues(str, options) {
|
|
20
20
|
var obj = {};
|
|
21
|
-
var
|
|
21
|
+
var cleanStr = options.ignoreQueryPrefix ? str.replace(/^\?/, '') : str;
|
|
22
|
+
var limit = options.parameterLimit === Infinity ? undefined : options.parameterLimit;
|
|
23
|
+
var parts = cleanStr.split(options.delimiter, limit);
|
|
22
24
|
|
|
23
25
|
for (var i = 0; i < parts.length; ++i) {
|
|
24
26
|
var part = parts[i];
|
|
25
|
-
|
|
27
|
+
|
|
28
|
+
var bracketEqualsPos = part.indexOf(']=');
|
|
29
|
+
var pos = bracketEqualsPos === -1 ? part.indexOf('=') : bracketEqualsPos + 1;
|
|
26
30
|
|
|
27
31
|
var key, val;
|
|
28
32
|
if (pos === -1) {
|
|
29
|
-
key = options.decoder(part);
|
|
33
|
+
key = options.decoder(part, defaults.decoder);
|
|
30
34
|
val = options.strictNullHandling ? null : '';
|
|
31
35
|
} else {
|
|
32
|
-
key = options.decoder(part.slice(0, pos));
|
|
33
|
-
val = options.decoder(part.slice(pos + 1));
|
|
36
|
+
key = options.decoder(part.slice(0, pos), defaults.decoder);
|
|
37
|
+
val = options.decoder(part.slice(pos + 1), defaults.decoder);
|
|
34
38
|
}
|
|
35
39
|
if (has.call(obj, key)) {
|
|
36
40
|
obj[key] = [].concat(obj[key]).concat(val);
|
|
@@ -42,38 +46,39 @@ var parseValues = function parseQueryStringValues(str, options) {
|
|
|
42
46
|
return obj;
|
|
43
47
|
};
|
|
44
48
|
|
|
45
|
-
var parseObject = function
|
|
46
|
-
|
|
47
|
-
return val;
|
|
48
|
-
}
|
|
49
|
+
var parseObject = function (chain, val, options) {
|
|
50
|
+
var leaf = val;
|
|
49
51
|
|
|
50
|
-
var
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
52
|
+
for (var i = chain.length - 1; i >= 0; --i) {
|
|
53
|
+
var obj;
|
|
54
|
+
var root = chain[i];
|
|
55
|
+
|
|
56
|
+
if (root === '[]' && options.parseArrays) {
|
|
57
|
+
obj = [].concat(leaf);
|
|
58
|
+
} else {
|
|
59
|
+
obj = options.plainObjects ? Object.create(null) : {};
|
|
60
|
+
var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
|
|
61
|
+
var index = parseInt(cleanRoot, 10);
|
|
62
|
+
if (!options.parseArrays && cleanRoot === '') {
|
|
63
|
+
obj = { 0: leaf };
|
|
64
|
+
} else if (
|
|
65
|
+
!isNaN(index)
|
|
66
|
+
&& root !== cleanRoot
|
|
67
|
+
&& String(index) === cleanRoot
|
|
68
|
+
&& index >= 0
|
|
69
|
+
&& (options.parseArrays && index <= options.arrayLimit)
|
|
70
|
+
) {
|
|
71
|
+
obj = [];
|
|
72
|
+
obj[index] = leaf;
|
|
73
|
+
} else if (cleanRoot !== '__proto__') {
|
|
74
|
+
obj[cleanRoot] = leaf;
|
|
75
|
+
}
|
|
73
76
|
}
|
|
77
|
+
|
|
78
|
+
leaf = obj;
|
|
74
79
|
}
|
|
75
80
|
|
|
76
|
-
return
|
|
81
|
+
return leaf;
|
|
77
82
|
};
|
|
78
83
|
|
|
79
84
|
var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
|
|
@@ -98,7 +103,8 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
|
|
|
98
103
|
|
|
99
104
|
var keys = [];
|
|
100
105
|
if (parent) {
|
|
101
|
-
// If we aren't using plain objects, optionally prefix keys
|
|
106
|
+
// If we aren't using plain objects, optionally prefix keys
|
|
107
|
+
// that would overwrite object prototype properties
|
|
102
108
|
if (!options.plainObjects && has.call(Object.prototype, parent)) {
|
|
103
109
|
if (!options.allowPrototypes) {
|
|
104
110
|
return;
|
|
@@ -131,12 +137,13 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
|
|
|
131
137
|
};
|
|
132
138
|
|
|
133
139
|
module.exports = function (str, opts) {
|
|
134
|
-
var options = opts
|
|
140
|
+
var options = opts ? utils.assign({}, opts) : {};
|
|
135
141
|
|
|
136
142
|
if (options.decoder !== null && options.decoder !== undefined && typeof options.decoder !== 'function') {
|
|
137
143
|
throw new TypeError('Decoder has to be a function.');
|
|
138
144
|
}
|
|
139
145
|
|
|
146
|
+
options.ignoreQueryPrefix = options.ignoreQueryPrefix === true;
|
|
140
147
|
options.delimiter = typeof options.delimiter === 'string' || utils.isRegExp(options.delimiter) ? options.delimiter : defaults.delimiter;
|
|
141
148
|
options.depth = typeof options.depth === 'number' ? options.depth : defaults.depth;
|
|
142
149
|
options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : defaults.arrayLimit;
|
package/lib/stringify.js
CHANGED
|
@@ -58,7 +58,7 @@ var stringify = function stringify(
|
|
|
58
58
|
|
|
59
59
|
if (obj === null) {
|
|
60
60
|
if (strictNullHandling) {
|
|
61
|
-
return encoder && !encodeValuesOnly ? encoder(prefix) : prefix;
|
|
61
|
+
return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder) : prefix;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
obj = '';
|
|
@@ -66,8 +66,8 @@ var stringify = function stringify(
|
|
|
66
66
|
|
|
67
67
|
if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean' || utils.isBuffer(obj)) {
|
|
68
68
|
if (encoder) {
|
|
69
|
-
var keyValue = encodeValuesOnly ? prefix : encoder(prefix);
|
|
70
|
-
return [formatter(keyValue) + '=' + formatter(encoder(obj))];
|
|
69
|
+
var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder);
|
|
70
|
+
return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder))];
|
|
71
71
|
}
|
|
72
72
|
return [formatter(prefix) + '=' + formatter(String(obj))];
|
|
73
73
|
}
|
|
@@ -131,7 +131,7 @@ var stringify = function stringify(
|
|
|
131
131
|
|
|
132
132
|
module.exports = function (object, opts) {
|
|
133
133
|
var obj = object;
|
|
134
|
-
var options = opts
|
|
134
|
+
var options = opts ? utils.assign({}, opts) : {};
|
|
135
135
|
|
|
136
136
|
if (options.encoder !== null && typeof options.encoder !== 'undefined' && typeof options.encoder !== 'function') {
|
|
137
137
|
throw new TypeError('Encoder has to be a function.');
|
|
@@ -210,5 +210,8 @@ module.exports = function (object, opts) {
|
|
|
210
210
|
));
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
|
|
213
|
+
var joined = keys.join(delimiter);
|
|
214
|
+
var prefix = options.addQueryPrefix === true ? '?' : '';
|
|
215
|
+
|
|
216
|
+
return joined.length > 0 ? prefix + joined : '';
|
|
214
217
|
};
|
package/lib/utils.js
CHANGED
|
@@ -11,7 +11,30 @@ var hexTable = (function () {
|
|
|
11
11
|
return array;
|
|
12
12
|
}());
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
var compactQueue = function compactQueue(queue) {
|
|
15
|
+
var obj;
|
|
16
|
+
|
|
17
|
+
while (queue.length) {
|
|
18
|
+
var item = queue.pop();
|
|
19
|
+
obj = item.obj[item.prop];
|
|
20
|
+
|
|
21
|
+
if (Array.isArray(obj)) {
|
|
22
|
+
var compacted = [];
|
|
23
|
+
|
|
24
|
+
for (var j = 0; j < obj.length; ++j) {
|
|
25
|
+
if (typeof obj[j] !== 'undefined') {
|
|
26
|
+
compacted.push(obj[j]);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
item.obj[item.prop] = compacted;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return obj;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
var arrayToObject = function arrayToObject(source, options) {
|
|
15
38
|
var obj = options && options.plainObjects ? Object.create(null) : {};
|
|
16
39
|
for (var i = 0; i < source.length; ++i) {
|
|
17
40
|
if (typeof source[i] !== 'undefined') {
|
|
@@ -22,7 +45,7 @@ exports.arrayToObject = function (source, options) {
|
|
|
22
45
|
return obj;
|
|
23
46
|
};
|
|
24
47
|
|
|
25
|
-
|
|
48
|
+
var merge = function merge(target, source, options) {
|
|
26
49
|
if (!source) {
|
|
27
50
|
return target;
|
|
28
51
|
}
|
|
@@ -47,14 +70,15 @@ exports.merge = function (target, source, options) {
|
|
|
47
70
|
|
|
48
71
|
var mergeTarget = target;
|
|
49
72
|
if (Array.isArray(target) && !Array.isArray(source)) {
|
|
50
|
-
mergeTarget =
|
|
73
|
+
mergeTarget = arrayToObject(target, options);
|
|
51
74
|
}
|
|
52
75
|
|
|
53
76
|
if (Array.isArray(target) && Array.isArray(source)) {
|
|
54
77
|
source.forEach(function (item, i) {
|
|
55
78
|
if (has.call(target, i)) {
|
|
56
|
-
|
|
57
|
-
|
|
79
|
+
var targetItem = target[i];
|
|
80
|
+
if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') {
|
|
81
|
+
target[i] = merge(targetItem, item, options);
|
|
58
82
|
} else {
|
|
59
83
|
target.push(item);
|
|
60
84
|
}
|
|
@@ -68,8 +92,8 @@ exports.merge = function (target, source, options) {
|
|
|
68
92
|
return Object.keys(source).reduce(function (acc, key) {
|
|
69
93
|
var value = source[key];
|
|
70
94
|
|
|
71
|
-
if (
|
|
72
|
-
acc[key] =
|
|
95
|
+
if (has.call(acc, key)) {
|
|
96
|
+
acc[key] = merge(acc[key], value, options);
|
|
73
97
|
} else {
|
|
74
98
|
acc[key] = value;
|
|
75
99
|
}
|
|
@@ -77,7 +101,14 @@ exports.merge = function (target, source, options) {
|
|
|
77
101
|
}, mergeTarget);
|
|
78
102
|
};
|
|
79
103
|
|
|
80
|
-
|
|
104
|
+
var assign = function assignSingleSource(target, source) {
|
|
105
|
+
return Object.keys(source).reduce(function (acc, key) {
|
|
106
|
+
acc[key] = source[key];
|
|
107
|
+
return acc;
|
|
108
|
+
}, target);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
var decode = function (str) {
|
|
81
112
|
try {
|
|
82
113
|
return decodeURIComponent(str.replace(/\+/g, ' '));
|
|
83
114
|
} catch (e) {
|
|
@@ -85,7 +116,7 @@ exports.decode = function (str) {
|
|
|
85
116
|
}
|
|
86
117
|
};
|
|
87
118
|
|
|
88
|
-
|
|
119
|
+
var encode = function encode(str) {
|
|
89
120
|
// This code was originally written by Brian White (mscdex) for the io.js core querystring library.
|
|
90
121
|
// It has been adapted here for stricter adherence to RFC 3986
|
|
91
122
|
if (str.length === 0) {
|
|
@@ -138,49 +169,47 @@ exports.encode = function (str) {
|
|
|
138
169
|
return out;
|
|
139
170
|
};
|
|
140
171
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
for (var i = 0; i < obj.length; ++i) {
|
|
158
|
-
if (obj[i] && typeof obj[i] === 'object') {
|
|
159
|
-
compacted.push(exports.compact(obj[i], refs));
|
|
160
|
-
} else if (typeof obj[i] !== 'undefined') {
|
|
161
|
-
compacted.push(obj[i]);
|
|
172
|
+
var compact = function compact(value) {
|
|
173
|
+
var queue = [{ obj: { o: value }, prop: 'o' }];
|
|
174
|
+
var refs = [];
|
|
175
|
+
|
|
176
|
+
for (var i = 0; i < queue.length; ++i) {
|
|
177
|
+
var item = queue[i];
|
|
178
|
+
var obj = item.obj[item.prop];
|
|
179
|
+
|
|
180
|
+
var keys = Object.keys(obj);
|
|
181
|
+
for (var j = 0; j < keys.length; ++j) {
|
|
182
|
+
var key = keys[j];
|
|
183
|
+
var val = obj[key];
|
|
184
|
+
if (typeof val === 'object' && val !== null && refs.indexOf(val) === -1) {
|
|
185
|
+
queue.push({ obj: obj, prop: key });
|
|
186
|
+
refs.push(val);
|
|
162
187
|
}
|
|
163
188
|
}
|
|
164
|
-
|
|
165
|
-
return compacted;
|
|
166
189
|
}
|
|
167
190
|
|
|
168
|
-
|
|
169
|
-
keys.forEach(function (key) {
|
|
170
|
-
obj[key] = exports.compact(obj[key], refs);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
return obj;
|
|
191
|
+
return compactQueue(queue);
|
|
174
192
|
};
|
|
175
193
|
|
|
176
|
-
|
|
194
|
+
var isRegExp = function isRegExp(obj) {
|
|
177
195
|
return Object.prototype.toString.call(obj) === '[object RegExp]';
|
|
178
196
|
};
|
|
179
197
|
|
|
180
|
-
|
|
198
|
+
var isBuffer = function isBuffer(obj) {
|
|
181
199
|
if (obj === null || typeof obj === 'undefined') {
|
|
182
200
|
return false;
|
|
183
201
|
}
|
|
184
202
|
|
|
185
203
|
return !!(obj.constructor && obj.constructor.isBuffer && obj.constructor.isBuffer(obj));
|
|
186
204
|
};
|
|
205
|
+
|
|
206
|
+
module.exports = {
|
|
207
|
+
arrayToObject: arrayToObject,
|
|
208
|
+
assign: assign,
|
|
209
|
+
compact: compact,
|
|
210
|
+
decode: decode,
|
|
211
|
+
encode: encode,
|
|
212
|
+
isBuffer: isBuffer,
|
|
213
|
+
isRegExp: isRegExp,
|
|
214
|
+
merge: merge
|
|
215
|
+
};
|
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
|
+
"version": "6.5.3",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "https://github.com/ljharb/qs.git"
|
package/test/parse.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var test = require('tape');
|
|
4
4
|
var qs = require('../');
|
|
5
|
+
var utils = require('../lib/utils');
|
|
5
6
|
var iconv = require('iconv-lite');
|
|
6
7
|
var SaferBuffer = require('safer-buffer').Buffer;
|
|
7
8
|
|
|
@@ -236,6 +237,14 @@ test('parse()', function (t) {
|
|
|
236
237
|
st.end();
|
|
237
238
|
});
|
|
238
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
|
+
|
|
239
248
|
t.test('continues parsing when no parent is found', function (st) {
|
|
240
249
|
st.deepEqual(qs.parse('[]=&a=b'), { 0: '', a: 'b' });
|
|
241
250
|
st.deepEqual(qs.parse('[]&a=b', { strictNullHandling: true }), { 0: null, a: 'b' });
|
|
@@ -312,6 +321,13 @@ test('parse()', function (t) {
|
|
|
312
321
|
st.end();
|
|
313
322
|
});
|
|
314
323
|
|
|
324
|
+
t.test('allows for query string prefix', function (st) {
|
|
325
|
+
st.deepEqual(qs.parse('?foo=bar', { ignoreQueryPrefix: true }), { foo: 'bar' });
|
|
326
|
+
st.deepEqual(qs.parse('foo=bar', { ignoreQueryPrefix: true }), { foo: 'bar' });
|
|
327
|
+
st.deepEqual(qs.parse('?foo=bar', { ignoreQueryPrefix: false }), { '?foo': 'bar' });
|
|
328
|
+
st.end();
|
|
329
|
+
});
|
|
330
|
+
|
|
315
331
|
t.test('parses an object', function (st) {
|
|
316
332
|
var input = {
|
|
317
333
|
'user[name]': { 'pop[bob]': 3 },
|
|
@@ -396,6 +412,33 @@ test('parse()', function (t) {
|
|
|
396
412
|
st.end();
|
|
397
413
|
});
|
|
398
414
|
|
|
415
|
+
t.test('does not crash when parsing deep objects', function (st) {
|
|
416
|
+
var parsed;
|
|
417
|
+
var str = 'foo';
|
|
418
|
+
|
|
419
|
+
for (var i = 0; i < 5000; i++) {
|
|
420
|
+
str += '[p]';
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
str += '=bar';
|
|
424
|
+
|
|
425
|
+
st.doesNotThrow(function () {
|
|
426
|
+
parsed = qs.parse(str, { depth: 5000 });
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
st.equal('foo' in parsed, true, 'parsed has "foo" property');
|
|
430
|
+
|
|
431
|
+
var depth = 0;
|
|
432
|
+
var ref = parsed.foo;
|
|
433
|
+
while ((ref = ref.p)) {
|
|
434
|
+
depth += 1;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
st.equal(depth, 5000, 'parsed is 5000 properties deep');
|
|
438
|
+
|
|
439
|
+
st.end();
|
|
440
|
+
});
|
|
441
|
+
|
|
399
442
|
t.test('parses null objects correctly', { skip: !Object.create }, function (st) {
|
|
400
443
|
var a = Object.create(null);
|
|
401
444
|
a.b = 'c';
|
|
@@ -572,16 +615,35 @@ test('parse()', function (t) {
|
|
|
572
615
|
result.push(parseInt(parts[1], 16));
|
|
573
616
|
parts = reg.exec(str);
|
|
574
617
|
}
|
|
575
|
-
return iconv.decode(SaferBuffer.from(result), 'shift_jis')
|
|
618
|
+
return String(iconv.decode(SaferBuffer.from(result), 'shift_jis'));
|
|
576
619
|
}
|
|
577
620
|
}), { 県: '大阪府' });
|
|
578
621
|
st.end();
|
|
579
622
|
});
|
|
580
623
|
|
|
624
|
+
t.test('receives the default decoder as a second argument', function (st) {
|
|
625
|
+
st.plan(1);
|
|
626
|
+
qs.parse('a', {
|
|
627
|
+
decoder: function (str, defaultDecoder) {
|
|
628
|
+
st.equal(defaultDecoder, utils.decode);
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
st.end();
|
|
632
|
+
});
|
|
633
|
+
|
|
581
634
|
t.test('throws error with wrong decoder', function (st) {
|
|
582
635
|
st['throws'](function () {
|
|
583
636
|
qs.parse({}, { decoder: 'string' });
|
|
584
637
|
}, new TypeError('Decoder has to be a function.'));
|
|
585
638
|
st.end();
|
|
586
639
|
});
|
|
640
|
+
|
|
641
|
+
t.test('does not mutate the options argument', function (st) {
|
|
642
|
+
var options = {};
|
|
643
|
+
qs.parse('a[b]=true', options);
|
|
644
|
+
st.deepEqual(options, {});
|
|
645
|
+
st.end();
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
t.end();
|
|
587
649
|
});
|
package/test/stringify.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var test = require('tape');
|
|
4
4
|
var qs = require('../');
|
|
5
|
+
var utils = require('../lib/utils');
|
|
5
6
|
var iconv = require('iconv-lite');
|
|
6
7
|
var SaferBuffer = require('safer-buffer').Buffer;
|
|
7
8
|
|
|
@@ -18,6 +19,32 @@ test('stringify()', function (t) {
|
|
|
18
19
|
st.end();
|
|
19
20
|
});
|
|
20
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
|
+
|
|
31
|
+
t.test('adds query prefix', function (st) {
|
|
32
|
+
st.equal(qs.stringify({ a: 'b' }, { addQueryPrefix: true }), '?a=b');
|
|
33
|
+
st.end();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
t.test('with query prefix, outputs blank string given an empty object', function (st) {
|
|
37
|
+
st.equal(qs.stringify({}, { addQueryPrefix: true }), '');
|
|
38
|
+
st.end();
|
|
39
|
+
});
|
|
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
|
+
|
|
21
48
|
t.test('stringifies a nested object', function (st) {
|
|
22
49
|
st.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
|
|
23
50
|
st.equal(qs.stringify({ a: { b: { c: { d: 'e' } } } }), 'a%5Bb%5D%5Bc%5D%5Bd%5D=e');
|
|
@@ -453,6 +480,16 @@ test('stringify()', function (t) {
|
|
|
453
480
|
st.end();
|
|
454
481
|
});
|
|
455
482
|
|
|
483
|
+
t.test('receives the default encoder as a second argument', function (st) {
|
|
484
|
+
st.plan(2);
|
|
485
|
+
qs.stringify({ a: 1 }, {
|
|
486
|
+
encoder: function (str, defaultEncoder) {
|
|
487
|
+
st.equal(defaultEncoder, utils.encode);
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
st.end();
|
|
491
|
+
});
|
|
492
|
+
|
|
456
493
|
t.test('throws error with wrong encoder', function (st) {
|
|
457
494
|
st['throws'](function () {
|
|
458
495
|
qs.stringify({}, { encoder: 'string' });
|
|
@@ -574,6 +611,13 @@ test('stringify()', function (t) {
|
|
|
574
611
|
st.end();
|
|
575
612
|
});
|
|
576
613
|
|
|
614
|
+
t.test('does not mutate the options argument', function (st) {
|
|
615
|
+
var options = {};
|
|
616
|
+
qs.stringify({}, options);
|
|
617
|
+
st.deepEqual(options, {});
|
|
618
|
+
st.end();
|
|
619
|
+
});
|
|
620
|
+
|
|
577
621
|
t.test('strictNullHandling works with custom filter', function (st) {
|
|
578
622
|
var filter = function (prefix, value) {
|
|
579
623
|
return value;
|
package/test/utils.js
CHANGED
|
@@ -25,5 +25,41 @@ test('merge()', function (t) {
|
|
|
25
25
|
var noOptionsNonObjectSource = utils.merge({ foo: 'baz' }, 'bar');
|
|
26
26
|
t.deepEqual(noOptionsNonObjectSource, { foo: 'baz', bar: true });
|
|
27
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
|
+
|
|
52
|
+
t.end();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('assign()', function (t) {
|
|
56
|
+
var target = { a: 1, b: 2 };
|
|
57
|
+
var source = { b: 3, c: 4 };
|
|
58
|
+
var result = utils.assign(target, source);
|
|
59
|
+
|
|
60
|
+
t.equal(result, target, 'returns the target');
|
|
61
|
+
t.deepEqual(target, { a: 1, b: 3, c: 4 }, 'target and source are merged');
|
|
62
|
+
t.deepEqual(source, { b: 3, c: 4 }, 'source is untouched');
|
|
63
|
+
|
|
28
64
|
t.end();
|
|
29
65
|
});
|