qs 6.3.2 → 6.5.0
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 +30 -0
- package/.eslintrc +4 -5
- package/CHANGELOG.md +49 -0
- package/README.md +82 -38
- package/dist/qs.js +55 -30
- package/lib/parse.js +16 -11
- package/lib/stringify.js +20 -10
- package/lib/utils.js +19 -9
- package/package.json +49 -48
- package/test/.eslintrc +2 -1
- package/test/parse.js +27 -0
- package/test/stringify.js +58 -0
- package/test/utils.js +12 -0
package/.editorconfig
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
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 = 140
|
|
11
|
+
|
|
12
|
+
[test/*]
|
|
13
|
+
max_line_length = off
|
|
14
|
+
|
|
15
|
+
[*.md]
|
|
16
|
+
max_line_length = off
|
|
17
|
+
|
|
18
|
+
[*.json]
|
|
19
|
+
max_line_length = off
|
|
20
|
+
|
|
21
|
+
[Makefile]
|
|
22
|
+
max_line_length = off
|
|
23
|
+
|
|
24
|
+
[CHANGELOG.md]
|
|
25
|
+
indent_style = space
|
|
26
|
+
indent_size = 2
|
|
27
|
+
|
|
28
|
+
[LICENSE]
|
|
29
|
+
indent_size = 2
|
|
30
|
+
max_line_length = off
|
package/.eslintrc
CHANGED
|
@@ -4,16 +4,15 @@
|
|
|
4
4
|
"extends": "@ljharb",
|
|
5
5
|
|
|
6
6
|
"rules": {
|
|
7
|
-
"complexity": [2,
|
|
7
|
+
"complexity": [2, 28],
|
|
8
8
|
"consistent-return": 1,
|
|
9
9
|
"id-length": [2, { "min": 1, "max": 25, "properties": "never" }],
|
|
10
10
|
"indent": [2, 4],
|
|
11
|
-
"max-params": [2,
|
|
12
|
-
"max-statements": [2,
|
|
13
|
-
"no-extra-parens": 1,
|
|
11
|
+
"max-params": [2, 12],
|
|
12
|
+
"max-statements": [2, 45],
|
|
14
13
|
"no-continue": 1,
|
|
15
14
|
"no-magic-numbers": 0,
|
|
16
15
|
"no-restricted-syntax": [2, "BreakStatement", "DebuggerStatement", "ForInStatement", "LabeledStatement", "WithStatement"],
|
|
17
|
-
"operator-linebreak":
|
|
16
|
+
"operator-linebreak": [2, "before"],
|
|
18
17
|
}
|
|
19
18
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
## **6.5.0**
|
|
2
|
+
- [New] add `utils.assign`
|
|
3
|
+
- [New] pass default encoder/decoder to custom encoder/decoder functions (#206)
|
|
4
|
+
- [New] `parse`/`stringify`: add `ignoreQueryPrefix`/`addQueryPrefix` options, respectively (#213)
|
|
5
|
+
- [Fix] Handle stringifying empty objects with addQueryPrefix (#217)
|
|
6
|
+
- [Fix] do not mutate `options` argument (#207)
|
|
7
|
+
- [Refactor] `parse`: cache index to reuse in else statement (#182)
|
|
8
|
+
- [Docs] add various badges to readme (#208)
|
|
9
|
+
- [Dev Deps] update `eslint`, `browserify`, `iconv-lite`, `tape`
|
|
10
|
+
- [Tests] up to `node` `v8.1`, `v7.10`, `v6.11`; npm v4.6 breaks on node < v1; npm v5+ breaks on node < v4
|
|
11
|
+
- [Tests] add `editorconfig-tools`
|
|
12
|
+
|
|
13
|
+
## **6.4.0**
|
|
14
|
+
- [New] `qs.stringify`: add `encodeValuesOnly` option
|
|
15
|
+
- [Fix] follow `allowPrototypes` option during merge (#201, #201)
|
|
16
|
+
- [Fix] support keys starting with brackets (#202, #200)
|
|
17
|
+
- [Fix] chmod a-x
|
|
18
|
+
- [Dev Deps] update `eslint`
|
|
19
|
+
- [Tests] up to `node` `v7.7`, `v6.10`,` v4.8`; disable osx builds since they block linux builds
|
|
20
|
+
- [eslint] reduce warnings
|
|
21
|
+
|
|
1
22
|
## **6.3.2**
|
|
2
23
|
- [Fix] follow `allowPrototypes` option during merge (#201, #200)
|
|
3
24
|
- [Dev Deps] update `eslint`
|
|
@@ -31,6 +52,15 @@
|
|
|
31
52
|
- [Tests] skip Object.create tests when null objects are not available
|
|
32
53
|
- [Tests] Turn on eslint for test files (#175)
|
|
33
54
|
|
|
55
|
+
## **6.2.3**
|
|
56
|
+
- [Fix] follow `allowPrototypes` option during merge (#201, #200)
|
|
57
|
+
- [Fix] chmod a-x
|
|
58
|
+
- [Fix] support keys starting with brackets (#202, #200)
|
|
59
|
+
- [Tests] up to `node` `v7.7`, `v6.10`,` v4.8`; disable osx builds since they block linux builds
|
|
60
|
+
|
|
61
|
+
## **6.2.2**
|
|
62
|
+
- [Fix] ensure that `allowPrototypes: false` does not ever shadow Object.prototype properties
|
|
63
|
+
|
|
34
64
|
## **6.2.1**
|
|
35
65
|
- [Fix] ensure `key[]=x&key[]&key[]=y` results in 3, not 2, values
|
|
36
66
|
- [Refactor] Be explicit and use `Object.prototype.hasOwnProperty.call`
|
|
@@ -43,11 +73,30 @@
|
|
|
43
73
|
- [New] add "encoder" and "decoder" options, for custom param encoding/decoding (#160)
|
|
44
74
|
- [Fix] fix compacting of nested sparse arrays (#150)
|
|
45
75
|
|
|
76
|
+
## **6.1.2
|
|
77
|
+
- [Fix] follow `allowPrototypes` option during merge (#201, #200)
|
|
78
|
+
- [Fix] chmod a-x
|
|
79
|
+
- [Fix] support keys starting with brackets (#202, #200)
|
|
80
|
+
- [Tests] up to `node` `v7.7`, `v6.10`,` v4.8`; disable osx builds since they block linux builds
|
|
81
|
+
|
|
82
|
+
## **6.1.1**
|
|
83
|
+
- [Fix] ensure that `allowPrototypes: false` does not ever shadow Object.prototype properties
|
|
84
|
+
|
|
46
85
|
## [**6.1.0**](https://github.com/ljharb/qs/issues?milestone=35&state=closed)
|
|
47
86
|
- [New] allowDots option for `stringify` (#151)
|
|
48
87
|
- [Fix] "sort" option should work at a depth of 3 or more (#151)
|
|
49
88
|
- [Fix] Restore `dist` directory; will be removed in v7 (#148)
|
|
50
89
|
|
|
90
|
+
## **6.0.4**
|
|
91
|
+
- [Fix] follow `allowPrototypes` option during merge (#201, #200)
|
|
92
|
+
- [Fix] chmod a-x
|
|
93
|
+
- [Fix] support keys starting with brackets (#202, #200)
|
|
94
|
+
- [Tests] up to `node` `v7.7`, `v6.10`,` v4.8`; disable osx builds since they block linux builds
|
|
95
|
+
|
|
96
|
+
## **6.0.3**
|
|
97
|
+
- [Fix] ensure that `allowPrototypes: false` does not ever shadow Object.prototype properties
|
|
98
|
+
- [Fix] Restore `dist` directory; will be removed in v7 (#148)
|
|
99
|
+
|
|
51
100
|
## [**6.0.2**](https://github.com/ljharb/qs/issues?milestone=33&state=closed)
|
|
52
101
|
- Revert ES6 requirement and restore support for node down to v0.8.
|
|
53
102
|
|
package/README.md
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
# qs
|
|
1
|
+
# qs <sup>[![Version Badge][2]][1]</sup>
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[![Build Status][3]][4]
|
|
4
|
+
[![dependency status][5]][6]
|
|
5
|
+
[![dev dependency status][7]][8]
|
|
6
|
+
[![License][license-image]][license-url]
|
|
7
|
+
[![Downloads][downloads-image]][downloads-url]
|
|
8
|
+
|
|
9
|
+
[![npm badge][11]][1]
|
|
4
10
|
|
|
5
|
-
|
|
11
|
+
A querystring parsing and stringifying library with some added security.
|
|
6
12
|
|
|
7
13
|
Lead Maintainer: [Jordan Harband](https://github.com/ljharb)
|
|
8
14
|
|
|
@@ -33,9 +39,9 @@ For example, the string `'foo[bar]=baz'` converts to:
|
|
|
33
39
|
|
|
34
40
|
```javascript
|
|
35
41
|
assert.deepEqual(qs.parse('foo[bar]=baz'), {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
42
|
+
foo: {
|
|
43
|
+
bar: 'baz'
|
|
44
|
+
}
|
|
39
45
|
});
|
|
40
46
|
```
|
|
41
47
|
|
|
@@ -57,7 +63,7 @@ URI encoded strings work too:
|
|
|
57
63
|
|
|
58
64
|
```javascript
|
|
59
65
|
assert.deepEqual(qs.parse('a%5Bb%5D=c'), {
|
|
60
|
-
|
|
66
|
+
a: { b: 'c' }
|
|
61
67
|
});
|
|
62
68
|
```
|
|
63
69
|
|
|
@@ -65,11 +71,11 @@ You can also nest your objects, like `'foo[bar][baz]=foobarbaz'`:
|
|
|
65
71
|
|
|
66
72
|
```javascript
|
|
67
73
|
assert.deepEqual(qs.parse('foo[bar][baz]=foobarbaz'), {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
74
|
+
foo: {
|
|
75
|
+
bar: {
|
|
76
|
+
baz: 'foobarbaz'
|
|
77
|
+
}
|
|
71
78
|
}
|
|
72
|
-
}
|
|
73
79
|
});
|
|
74
80
|
```
|
|
75
81
|
|
|
@@ -78,19 +84,19 @@ By default, when nesting objects **qs** will only parse up to 5 children deep. T
|
|
|
78
84
|
|
|
79
85
|
```javascript
|
|
80
86
|
var expected = {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
a: {
|
|
88
|
+
b: {
|
|
89
|
+
c: {
|
|
90
|
+
d: {
|
|
91
|
+
e: {
|
|
92
|
+
f: {
|
|
93
|
+
'[g][h][i]': 'j'
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
88
97
|
}
|
|
89
|
-
}
|
|
90
98
|
}
|
|
91
|
-
}
|
|
92
99
|
}
|
|
93
|
-
}
|
|
94
100
|
};
|
|
95
101
|
var string = 'a[b][c][d][e][f][g][h][i]=j';
|
|
96
102
|
assert.deepEqual(qs.parse(string), expected);
|
|
@@ -112,6 +118,13 @@ var limited = qs.parse('a=b&c=d', { parameterLimit: 1 });
|
|
|
112
118
|
assert.deepEqual(limited, { a: 'b' });
|
|
113
119
|
```
|
|
114
120
|
|
|
121
|
+
To bypass the leading question mark, use `ignoreQueryPrefix`:
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
var prefixed = qs.parse('?a=b&c=d', { ignoreQueryPrefix: true });
|
|
125
|
+
assert.deepEqual(prefixed, { a: 'b', c: 'd' });
|
|
126
|
+
```
|
|
127
|
+
|
|
115
128
|
An optional delimiter can also be passed:
|
|
116
129
|
|
|
117
130
|
```javascript
|
|
@@ -225,12 +238,21 @@ var unencoded = qs.stringify({ a: { b: 'c' } }, { encode: false });
|
|
|
225
238
|
assert.equal(unencoded, 'a[b]=c');
|
|
226
239
|
```
|
|
227
240
|
|
|
241
|
+
Encoding can be disabled for keys by setting the `encodeValuesOnly` option to `true`:
|
|
242
|
+
```javascript
|
|
243
|
+
var encodedValues = qs.stringify(
|
|
244
|
+
{ a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
|
|
245
|
+
{ encodeValuesOnly: true }
|
|
246
|
+
);
|
|
247
|
+
assert.equal(encodedValues,'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h');
|
|
248
|
+
```
|
|
249
|
+
|
|
228
250
|
This encoding can also be replaced by a custom encoding method set as `encoder` option:
|
|
229
251
|
|
|
230
252
|
```javascript
|
|
231
253
|
var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str) {
|
|
232
|
-
|
|
233
|
-
|
|
254
|
+
// Passed in values `a`, `b`, `c`
|
|
255
|
+
return // Return encoded string
|
|
234
256
|
}})
|
|
235
257
|
```
|
|
236
258
|
|
|
@@ -240,8 +262,8 @@ Analogue to the `encoder` there is a `decoder` option for `parse` to override de
|
|
|
240
262
|
|
|
241
263
|
```javascript
|
|
242
264
|
var decoded = qs.parse('x=z', { decoder: function (str) {
|
|
243
|
-
|
|
244
|
-
|
|
265
|
+
// Passed in values `x`, `z`
|
|
266
|
+
return // Return decoded string
|
|
245
267
|
}})
|
|
246
268
|
```
|
|
247
269
|
|
|
@@ -308,6 +330,12 @@ Properties that are set to `undefined` will be omitted entirely:
|
|
|
308
330
|
assert.equal(qs.stringify({ a: null, b: undefined }), 'a=');
|
|
309
331
|
```
|
|
310
332
|
|
|
333
|
+
The query string may optionally be prepended with a question mark:
|
|
334
|
+
|
|
335
|
+
```javascript
|
|
336
|
+
assert.equal(qs.stringify({ a: 'b', c: 'd' }, { addQueryPrefix: true }), '?a=b&c=d');
|
|
337
|
+
```
|
|
338
|
+
|
|
311
339
|
The delimiter may be overridden with stringify as well:
|
|
312
340
|
|
|
313
341
|
```javascript
|
|
@@ -329,7 +357,7 @@ You may use the `sort` option to affect the order of parameter keys:
|
|
|
329
357
|
|
|
330
358
|
```javascript
|
|
331
359
|
function alphabeticalSort(a, b) {
|
|
332
|
-
|
|
360
|
+
return a.localeCompare(b);
|
|
333
361
|
}
|
|
334
362
|
assert.equal(qs.stringify({ a: 'c', z: 'y', b : 'f' }, { sort: alphabeticalSort }), 'a=c&b=f&z=y');
|
|
335
363
|
```
|
|
@@ -340,17 +368,17 @@ pass an array, it will be used to select properties and array indices for string
|
|
|
340
368
|
|
|
341
369
|
```javascript
|
|
342
370
|
function filterFunc(prefix, value) {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
371
|
+
if (prefix == 'b') {
|
|
372
|
+
// Return an `undefined` value to omit a property.
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
if (prefix == 'e[f]') {
|
|
376
|
+
return value.getTime();
|
|
377
|
+
}
|
|
378
|
+
if (prefix == 'e[g][0]') {
|
|
379
|
+
return value * 2;
|
|
380
|
+
}
|
|
381
|
+
return value;
|
|
354
382
|
}
|
|
355
383
|
qs.stringify({ a: 'b', c: 'd', e: { f: new Date(123), g: [2] } }, { filter: filterFunc });
|
|
356
384
|
// 'a=b&c=d&e[f]=123&e[g][0]=4'
|
|
@@ -400,7 +428,7 @@ assert.equal(nullsSkipped, 'a=b');
|
|
|
400
428
|
|
|
401
429
|
### Dealing with special character sets
|
|
402
430
|
|
|
403
|
-
By default the encoding and decoding of characters is done in `utf-8`. If you
|
|
431
|
+
By default the encoding and decoding of characters is done in `utf-8`. If you
|
|
404
432
|
wish to encode querystrings to a different character set (i.e.
|
|
405
433
|
[Shift JIS](https://en.wikipedia.org/wiki/Shift_JIS)) you can use the
|
|
406
434
|
[`qs-iconv`](https://github.com/martinheidegger/qs-iconv) library:
|
|
@@ -429,3 +457,19 @@ assert.equal(qs.stringify({ a: 'b c' }), 'a=b%20c');
|
|
|
429
457
|
assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC3986' }), 'a=b%20c');
|
|
430
458
|
assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC1738' }), 'a=b+c');
|
|
431
459
|
```
|
|
460
|
+
|
|
461
|
+
[1]: https://npmjs.org/package/qs
|
|
462
|
+
[2]: http://versionbadg.es/ljharb/qs.svg
|
|
463
|
+
[3]: https://api.travis-ci.org/ljharb/qs.svg
|
|
464
|
+
[4]: https://travis-ci.org/ljharb/qs
|
|
465
|
+
[5]: https://david-dm.org/ljharb/qs.svg
|
|
466
|
+
[6]: https://david-dm.org/ljharb/qs
|
|
467
|
+
[7]: https://david-dm.org/ljharb/qs/dev-status.svg
|
|
468
|
+
[8]: https://david-dm.org/ljharb/qs?type=dev
|
|
469
|
+
[9]: https://ci.testling.com/ljharb/qs.png
|
|
470
|
+
[10]: https://ci.testling.com/ljharb/qs
|
|
471
|
+
[11]: https://nodei.co/npm/qs.png?downloads=true&stars=true
|
|
472
|
+
[license-image]: http://img.shields.io/npm/l/qs.svg
|
|
473
|
+
[license-url]: LICENSE
|
|
474
|
+
[downloads-image]: http://img.shields.io/npm/dm/qs.svg
|
|
475
|
+
[downloads-url]: http://npm-stat.com/charts.html?package=qs
|
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);
|
|
@@ -92,11 +96,11 @@ var parseObject = function parseObjectRecursive(chain, val, options) {
|
|
|
92
96
|
var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
|
|
93
97
|
var index = parseInt(cleanRoot, 10);
|
|
94
98
|
if (
|
|
95
|
-
!isNaN(index)
|
|
96
|
-
root !== cleanRoot
|
|
97
|
-
String(index) === cleanRoot
|
|
98
|
-
index >= 0
|
|
99
|
-
(options.parseArrays && index <= options.arrayLimit)
|
|
99
|
+
!isNaN(index)
|
|
100
|
+
&& root !== cleanRoot
|
|
101
|
+
&& String(index) === cleanRoot
|
|
102
|
+
&& index >= 0
|
|
103
|
+
&& (options.parseArrays && index <= options.arrayLimit)
|
|
100
104
|
) {
|
|
101
105
|
obj = [];
|
|
102
106
|
obj[index] = parseObject(chain, val, options);
|
|
@@ -164,12 +168,13 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
|
|
|
164
168
|
};
|
|
165
169
|
|
|
166
170
|
module.exports = function (str, opts) {
|
|
167
|
-
var options = opts
|
|
171
|
+
var options = opts ? utils.assign({}, opts) : {};
|
|
168
172
|
|
|
169
173
|
if (options.decoder !== null && options.decoder !== undefined && typeof options.decoder !== 'function') {
|
|
170
174
|
throw new TypeError('Decoder has to be a function.');
|
|
171
175
|
}
|
|
172
176
|
|
|
177
|
+
options.ignoreQueryPrefix = options.ignoreQueryPrefix === true;
|
|
173
178
|
options.delimiter = typeof options.delimiter === 'string' || utils.isRegExp(options.delimiter) ? options.delimiter : defaults.delimiter;
|
|
174
179
|
options.depth = typeof options.depth === 'number' ? options.depth : defaults.depth;
|
|
175
180
|
options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : defaults.arrayLimit;
|
|
@@ -224,6 +229,7 @@ var defaults = {
|
|
|
224
229
|
delimiter: '&',
|
|
225
230
|
encode: true,
|
|
226
231
|
encoder: utils.encode,
|
|
232
|
+
encodeValuesOnly: false,
|
|
227
233
|
serializeDate: function serializeDate(date) { // eslint-disable-line func-name-matching
|
|
228
234
|
return toISO.call(date);
|
|
229
235
|
},
|
|
@@ -242,7 +248,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
242
248
|
sort,
|
|
243
249
|
allowDots,
|
|
244
250
|
serializeDate,
|
|
245
|
-
formatter
|
|
251
|
+
formatter,
|
|
252
|
+
encodeValuesOnly
|
|
246
253
|
) {
|
|
247
254
|
var obj = object;
|
|
248
255
|
if (typeof filter === 'function') {
|
|
@@ -251,7 +258,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
251
258
|
obj = serializeDate(obj);
|
|
252
259
|
} else if (obj === null) {
|
|
253
260
|
if (strictNullHandling) {
|
|
254
|
-
return encoder ? encoder(prefix) : prefix;
|
|
261
|
+
return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder) : prefix;
|
|
255
262
|
}
|
|
256
263
|
|
|
257
264
|
obj = '';
|
|
@@ -259,7 +266,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
259
266
|
|
|
260
267
|
if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean' || utils.isBuffer(obj)) {
|
|
261
268
|
if (encoder) {
|
|
262
|
-
|
|
269
|
+
var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder);
|
|
270
|
+
return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder))];
|
|
263
271
|
}
|
|
264
272
|
return [formatter(prefix) + '=' + formatter(String(obj))];
|
|
265
273
|
}
|
|
@@ -297,7 +305,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
297
305
|
sort,
|
|
298
306
|
allowDots,
|
|
299
307
|
serializeDate,
|
|
300
|
-
formatter
|
|
308
|
+
formatter,
|
|
309
|
+
encodeValuesOnly
|
|
301
310
|
));
|
|
302
311
|
} else {
|
|
303
312
|
values = values.concat(stringify(
|
|
@@ -311,7 +320,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
311
320
|
sort,
|
|
312
321
|
allowDots,
|
|
313
322
|
serializeDate,
|
|
314
|
-
formatter
|
|
323
|
+
formatter,
|
|
324
|
+
encodeValuesOnly
|
|
315
325
|
));
|
|
316
326
|
}
|
|
317
327
|
}
|
|
@@ -321,7 +331,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
321
331
|
|
|
322
332
|
module.exports = function (object, opts) {
|
|
323
333
|
var obj = object;
|
|
324
|
-
var options = opts
|
|
334
|
+
var options = opts ? utils.assign({}, opts) : {};
|
|
325
335
|
|
|
326
336
|
if (options.encoder !== null && options.encoder !== undefined && typeof options.encoder !== 'function') {
|
|
327
337
|
throw new TypeError('Encoder has to be a function.');
|
|
@@ -331,10 +341,11 @@ module.exports = function (object, opts) {
|
|
|
331
341
|
var strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : defaults.strictNullHandling;
|
|
332
342
|
var skipNulls = typeof options.skipNulls === 'boolean' ? options.skipNulls : defaults.skipNulls;
|
|
333
343
|
var encode = typeof options.encode === 'boolean' ? options.encode : defaults.encode;
|
|
334
|
-
var encoder =
|
|
344
|
+
var encoder = typeof options.encoder === 'function' ? options.encoder : defaults.encoder;
|
|
335
345
|
var sort = typeof options.sort === 'function' ? options.sort : null;
|
|
336
346
|
var allowDots = typeof options.allowDots === 'undefined' ? false : options.allowDots;
|
|
337
347
|
var serializeDate = typeof options.serializeDate === 'function' ? options.serializeDate : defaults.serializeDate;
|
|
348
|
+
var encodeValuesOnly = typeof options.encodeValuesOnly === 'boolean' ? options.encodeValuesOnly : defaults.encodeValuesOnly;
|
|
338
349
|
if (typeof options.format === 'undefined') {
|
|
339
350
|
options.format = formats.default;
|
|
340
351
|
} else if (!Object.prototype.hasOwnProperty.call(formats.formatters, options.format)) {
|
|
@@ -390,16 +401,20 @@ module.exports = function (object, opts) {
|
|
|
390
401
|
generateArrayPrefix,
|
|
391
402
|
strictNullHandling,
|
|
392
403
|
skipNulls,
|
|
393
|
-
encoder,
|
|
404
|
+
encode ? encoder : null,
|
|
394
405
|
filter,
|
|
395
406
|
sort,
|
|
396
407
|
allowDots,
|
|
397
408
|
serializeDate,
|
|
398
|
-
formatter
|
|
409
|
+
formatter,
|
|
410
|
+
encodeValuesOnly
|
|
399
411
|
));
|
|
400
412
|
}
|
|
401
413
|
|
|
402
|
-
|
|
414
|
+
var joined = keys.join(delimiter);
|
|
415
|
+
var prefix = options.addQueryPrefix === true ? '?' : '';
|
|
416
|
+
|
|
417
|
+
return joined.length > 0 ? prefix + joined : '';
|
|
403
418
|
};
|
|
404
419
|
|
|
405
420
|
},{"./formats":1,"./utils":5}],5:[function(require,module,exports){
|
|
@@ -473,7 +488,7 @@ exports.merge = function (target, source, options) {
|
|
|
473
488
|
return Object.keys(source).reduce(function (acc, key) {
|
|
474
489
|
var value = source[key];
|
|
475
490
|
|
|
476
|
-
if (
|
|
491
|
+
if (has.call(acc, key)) {
|
|
477
492
|
acc[key] = exports.merge(acc[key], value, options);
|
|
478
493
|
} else {
|
|
479
494
|
acc[key] = value;
|
|
@@ -482,6 +497,13 @@ exports.merge = function (target, source, options) {
|
|
|
482
497
|
}, mergeTarget);
|
|
483
498
|
};
|
|
484
499
|
|
|
500
|
+
exports.assign = function assignSingleSource(target, source) {
|
|
501
|
+
return Object.keys(source).reduce(function (acc, key) {
|
|
502
|
+
acc[key] = source[key];
|
|
503
|
+
return acc;
|
|
504
|
+
}, target);
|
|
505
|
+
};
|
|
506
|
+
|
|
485
507
|
exports.decode = function (str) {
|
|
486
508
|
try {
|
|
487
509
|
return decodeURIComponent(str.replace(/\+/g, ' '));
|
|
@@ -504,13 +526,13 @@ exports.encode = function (str) {
|
|
|
504
526
|
var c = string.charCodeAt(i);
|
|
505
527
|
|
|
506
528
|
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
|
|
529
|
+
c === 0x2D // -
|
|
530
|
+
|| c === 0x2E // .
|
|
531
|
+
|| c === 0x5F // _
|
|
532
|
+
|| c === 0x7E // ~
|
|
533
|
+
|| (c >= 0x30 && c <= 0x39) // 0-9
|
|
534
|
+
|| (c >= 0x41 && c <= 0x5A) // a-z
|
|
535
|
+
|| (c >= 0x61 && c <= 0x7A) // A-Z
|
|
514
536
|
) {
|
|
515
537
|
out += string.charAt(i);
|
|
516
538
|
continue;
|
|
@@ -533,7 +555,10 @@ exports.encode = function (str) {
|
|
|
533
555
|
|
|
534
556
|
i += 1;
|
|
535
557
|
c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
|
|
536
|
-
out += hexTable[0xF0 | (c >> 18)]
|
|
558
|
+
out += hexTable[0xF0 | (c >> 18)]
|
|
559
|
+
+ hexTable[0x80 | ((c >> 12) & 0x3F)]
|
|
560
|
+
+ hexTable[0x80 | ((c >> 6) & 0x3F)]
|
|
561
|
+
+ hexTable[0x80 | (c & 0x3F)];
|
|
537
562
|
}
|
|
538
563
|
|
|
539
564
|
return out;
|
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);
|
|
@@ -58,11 +62,11 @@ var parseObject = function parseObjectRecursive(chain, val, options) {
|
|
|
58
62
|
var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
|
|
59
63
|
var index = parseInt(cleanRoot, 10);
|
|
60
64
|
if (
|
|
61
|
-
!isNaN(index)
|
|
62
|
-
root !== cleanRoot
|
|
63
|
-
String(index) === cleanRoot
|
|
64
|
-
index >= 0
|
|
65
|
-
(options.parseArrays && index <= options.arrayLimit)
|
|
65
|
+
!isNaN(index)
|
|
66
|
+
&& root !== cleanRoot
|
|
67
|
+
&& String(index) === cleanRoot
|
|
68
|
+
&& index >= 0
|
|
69
|
+
&& (options.parseArrays && index <= options.arrayLimit)
|
|
66
70
|
) {
|
|
67
71
|
obj = [];
|
|
68
72
|
obj[index] = parseObject(chain, val, options);
|
|
@@ -130,12 +134,13 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
|
|
|
130
134
|
};
|
|
131
135
|
|
|
132
136
|
module.exports = function (str, opts) {
|
|
133
|
-
var options = opts
|
|
137
|
+
var options = opts ? utils.assign({}, opts) : {};
|
|
134
138
|
|
|
135
139
|
if (options.decoder !== null && options.decoder !== undefined && typeof options.decoder !== 'function') {
|
|
136
140
|
throw new TypeError('Decoder has to be a function.');
|
|
137
141
|
}
|
|
138
142
|
|
|
143
|
+
options.ignoreQueryPrefix = options.ignoreQueryPrefix === true;
|
|
139
144
|
options.delimiter = typeof options.delimiter === 'string' || utils.isRegExp(options.delimiter) ? options.delimiter : defaults.delimiter;
|
|
140
145
|
options.depth = typeof options.depth === 'number' ? options.depth : defaults.depth;
|
|
141
146
|
options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : defaults.arrayLimit;
|
package/lib/stringify.js
CHANGED
|
@@ -21,6 +21,7 @@ var defaults = {
|
|
|
21
21
|
delimiter: '&',
|
|
22
22
|
encode: true,
|
|
23
23
|
encoder: utils.encode,
|
|
24
|
+
encodeValuesOnly: false,
|
|
24
25
|
serializeDate: function serializeDate(date) { // eslint-disable-line func-name-matching
|
|
25
26
|
return toISO.call(date);
|
|
26
27
|
},
|
|
@@ -39,7 +40,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
39
40
|
sort,
|
|
40
41
|
allowDots,
|
|
41
42
|
serializeDate,
|
|
42
|
-
formatter
|
|
43
|
+
formatter,
|
|
44
|
+
encodeValuesOnly
|
|
43
45
|
) {
|
|
44
46
|
var obj = object;
|
|
45
47
|
if (typeof filter === 'function') {
|
|
@@ -48,7 +50,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
48
50
|
obj = serializeDate(obj);
|
|
49
51
|
} else if (obj === null) {
|
|
50
52
|
if (strictNullHandling) {
|
|
51
|
-
return encoder ? encoder(prefix) : prefix;
|
|
53
|
+
return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder) : prefix;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
obj = '';
|
|
@@ -56,7 +58,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
56
58
|
|
|
57
59
|
if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean' || utils.isBuffer(obj)) {
|
|
58
60
|
if (encoder) {
|
|
59
|
-
|
|
61
|
+
var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder);
|
|
62
|
+
return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder))];
|
|
60
63
|
}
|
|
61
64
|
return [formatter(prefix) + '=' + formatter(String(obj))];
|
|
62
65
|
}
|
|
@@ -94,7 +97,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
94
97
|
sort,
|
|
95
98
|
allowDots,
|
|
96
99
|
serializeDate,
|
|
97
|
-
formatter
|
|
100
|
+
formatter,
|
|
101
|
+
encodeValuesOnly
|
|
98
102
|
));
|
|
99
103
|
} else {
|
|
100
104
|
values = values.concat(stringify(
|
|
@@ -108,7 +112,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
108
112
|
sort,
|
|
109
113
|
allowDots,
|
|
110
114
|
serializeDate,
|
|
111
|
-
formatter
|
|
115
|
+
formatter,
|
|
116
|
+
encodeValuesOnly
|
|
112
117
|
));
|
|
113
118
|
}
|
|
114
119
|
}
|
|
@@ -118,7 +123,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
118
123
|
|
|
119
124
|
module.exports = function (object, opts) {
|
|
120
125
|
var obj = object;
|
|
121
|
-
var options = opts
|
|
126
|
+
var options = opts ? utils.assign({}, opts) : {};
|
|
122
127
|
|
|
123
128
|
if (options.encoder !== null && options.encoder !== undefined && typeof options.encoder !== 'function') {
|
|
124
129
|
throw new TypeError('Encoder has to be a function.');
|
|
@@ -128,10 +133,11 @@ module.exports = function (object, opts) {
|
|
|
128
133
|
var strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : defaults.strictNullHandling;
|
|
129
134
|
var skipNulls = typeof options.skipNulls === 'boolean' ? options.skipNulls : defaults.skipNulls;
|
|
130
135
|
var encode = typeof options.encode === 'boolean' ? options.encode : defaults.encode;
|
|
131
|
-
var encoder =
|
|
136
|
+
var encoder = typeof options.encoder === 'function' ? options.encoder : defaults.encoder;
|
|
132
137
|
var sort = typeof options.sort === 'function' ? options.sort : null;
|
|
133
138
|
var allowDots = typeof options.allowDots === 'undefined' ? false : options.allowDots;
|
|
134
139
|
var serializeDate = typeof options.serializeDate === 'function' ? options.serializeDate : defaults.serializeDate;
|
|
140
|
+
var encodeValuesOnly = typeof options.encodeValuesOnly === 'boolean' ? options.encodeValuesOnly : defaults.encodeValuesOnly;
|
|
135
141
|
if (typeof options.format === 'undefined') {
|
|
136
142
|
options.format = formats.default;
|
|
137
143
|
} else if (!Object.prototype.hasOwnProperty.call(formats.formatters, options.format)) {
|
|
@@ -187,14 +193,18 @@ module.exports = function (object, opts) {
|
|
|
187
193
|
generateArrayPrefix,
|
|
188
194
|
strictNullHandling,
|
|
189
195
|
skipNulls,
|
|
190
|
-
encoder,
|
|
196
|
+
encode ? encoder : null,
|
|
191
197
|
filter,
|
|
192
198
|
sort,
|
|
193
199
|
allowDots,
|
|
194
200
|
serializeDate,
|
|
195
|
-
formatter
|
|
201
|
+
formatter,
|
|
202
|
+
encodeValuesOnly
|
|
196
203
|
));
|
|
197
204
|
}
|
|
198
205
|
|
|
199
|
-
|
|
206
|
+
var joined = keys.join(delimiter);
|
|
207
|
+
var prefix = options.addQueryPrefix === true ? '?' : '';
|
|
208
|
+
|
|
209
|
+
return joined.length > 0 ? prefix + joined : '';
|
|
200
210
|
};
|
package/lib/utils.js
CHANGED
|
@@ -68,7 +68,7 @@ exports.merge = function (target, source, options) {
|
|
|
68
68
|
return Object.keys(source).reduce(function (acc, key) {
|
|
69
69
|
var value = source[key];
|
|
70
70
|
|
|
71
|
-
if (
|
|
71
|
+
if (has.call(acc, key)) {
|
|
72
72
|
acc[key] = exports.merge(acc[key], value, options);
|
|
73
73
|
} else {
|
|
74
74
|
acc[key] = value;
|
|
@@ -77,6 +77,13 @@ exports.merge = function (target, source, options) {
|
|
|
77
77
|
}, mergeTarget);
|
|
78
78
|
};
|
|
79
79
|
|
|
80
|
+
exports.assign = function assignSingleSource(target, source) {
|
|
81
|
+
return Object.keys(source).reduce(function (acc, key) {
|
|
82
|
+
acc[key] = source[key];
|
|
83
|
+
return acc;
|
|
84
|
+
}, target);
|
|
85
|
+
};
|
|
86
|
+
|
|
80
87
|
exports.decode = function (str) {
|
|
81
88
|
try {
|
|
82
89
|
return decodeURIComponent(str.replace(/\+/g, ' '));
|
|
@@ -99,13 +106,13 @@ exports.encode = function (str) {
|
|
|
99
106
|
var c = string.charCodeAt(i);
|
|
100
107
|
|
|
101
108
|
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
|
|
109
|
+
c === 0x2D // -
|
|
110
|
+
|| c === 0x2E // .
|
|
111
|
+
|| c === 0x5F // _
|
|
112
|
+
|| c === 0x7E // ~
|
|
113
|
+
|| (c >= 0x30 && c <= 0x39) // 0-9
|
|
114
|
+
|| (c >= 0x41 && c <= 0x5A) // a-z
|
|
115
|
+
|| (c >= 0x61 && c <= 0x7A) // A-Z
|
|
109
116
|
) {
|
|
110
117
|
out += string.charAt(i);
|
|
111
118
|
continue;
|
|
@@ -128,7 +135,10 @@ exports.encode = function (str) {
|
|
|
128
135
|
|
|
129
136
|
i += 1;
|
|
130
137
|
c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
|
|
131
|
-
out += hexTable[0xF0 | (c >> 18)]
|
|
138
|
+
out += hexTable[0xF0 | (c >> 18)]
|
|
139
|
+
+ hexTable[0x80 | ((c >> 12) & 0x3F)]
|
|
140
|
+
+ hexTable[0x80 | ((c >> 6) & 0x3F)]
|
|
141
|
+
+ hexTable[0x80 | (c & 0x3F)];
|
|
132
142
|
}
|
|
133
143
|
|
|
134
144
|
return out;
|
package/package.json
CHANGED
|
@@ -1,50 +1,51 @@
|
|
|
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.5.0",
|
|
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
|
+
"dependencies": {},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@ljharb/eslint-config": "^11.0.0",
|
|
28
|
+
"browserify": "^14.4.0",
|
|
29
|
+
"covert": "^1.1.0",
|
|
30
|
+
"editorconfig-tools": "^0.1.1",
|
|
31
|
+
"eslint": "^3.19.0",
|
|
32
|
+
"evalmd": "^0.0.17",
|
|
33
|
+
"iconv-lite": "^0.4.18",
|
|
34
|
+
"mkdirp": "^0.5.1",
|
|
35
|
+
"qs-iconv": "^1.0.4",
|
|
36
|
+
"safe-publish-latest": "^1.1.1",
|
|
37
|
+
"tape": "^4.7.0"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"prepublish": "safe-publish-latest && npm run dist",
|
|
41
|
+
"pretest": "npm run --silent readme && npm run --silent lint",
|
|
42
|
+
"test": "npm run --silent coverage",
|
|
43
|
+
"tests-only": "node test",
|
|
44
|
+
"readme": "evalmd README.md",
|
|
45
|
+
"prelint": "editorconfig-tools check * lib/* test/*",
|
|
46
|
+
"lint": "eslint lib/*.js test/*.js",
|
|
47
|
+
"coverage": "covert test",
|
|
48
|
+
"dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js"
|
|
49
|
+
},
|
|
50
|
+
"license": "BSD-3-Clause"
|
|
50
51
|
}
|
package/test/.eslintrc
CHANGED
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
|
|
|
7
8
|
test('parse()', function (t) {
|
|
@@ -304,6 +305,13 @@ test('parse()', function (t) {
|
|
|
304
305
|
st.end();
|
|
305
306
|
});
|
|
306
307
|
|
|
308
|
+
t.test('allows for query string prefix', function (st) {
|
|
309
|
+
st.deepEqual(qs.parse('?foo=bar', { ignoreQueryPrefix: true }), { foo: 'bar' });
|
|
310
|
+
st.deepEqual(qs.parse('foo=bar', { ignoreQueryPrefix: true }), { foo: 'bar' });
|
|
311
|
+
st.deepEqual(qs.parse('?foo=bar', { ignoreQueryPrefix: false }), { '?foo': 'bar' });
|
|
312
|
+
st.end();
|
|
313
|
+
});
|
|
314
|
+
|
|
307
315
|
t.test('parses an object', function (st) {
|
|
308
316
|
var input = {
|
|
309
317
|
'user[name]': { 'pop[bob]': 3 },
|
|
@@ -510,10 +518,29 @@ test('parse()', function (t) {
|
|
|
510
518
|
st.end();
|
|
511
519
|
});
|
|
512
520
|
|
|
521
|
+
t.test('receives the default decoder as a second argument', function (st) {
|
|
522
|
+
st.plan(1);
|
|
523
|
+
qs.parse('a', {
|
|
524
|
+
decoder: function (str, defaultDecoder) {
|
|
525
|
+
st.equal(defaultDecoder, utils.decode);
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
st.end();
|
|
529
|
+
});
|
|
530
|
+
|
|
513
531
|
t.test('throws error with wrong decoder', function (st) {
|
|
514
532
|
st.throws(function () {
|
|
515
533
|
qs.parse({}, { decoder: 'string' });
|
|
516
534
|
}, new TypeError('Decoder has to be a function.'));
|
|
517
535
|
st.end();
|
|
518
536
|
});
|
|
537
|
+
|
|
538
|
+
t.test('does not mutate the options argument', function (st) {
|
|
539
|
+
var options = {};
|
|
540
|
+
qs.parse('a[b]=true', options);
|
|
541
|
+
st.deepEqual(options, {});
|
|
542
|
+
st.end();
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
t.end();
|
|
519
546
|
});
|
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
|
|
|
7
8
|
test('stringify()', function (t) {
|
|
@@ -17,6 +18,16 @@ test('stringify()', function (t) {
|
|
|
17
18
|
st.end();
|
|
18
19
|
});
|
|
19
20
|
|
|
21
|
+
t.test('adds query prefix', function (st) {
|
|
22
|
+
st.equal(qs.stringify({ a: 'b' }, { addQueryPrefix: true }), '?a=b');
|
|
23
|
+
st.end();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
t.test('with query prefix, outputs blank string given an empty object', function (st) {
|
|
27
|
+
st.equal(qs.stringify({}, { addQueryPrefix: true }), '');
|
|
28
|
+
st.end();
|
|
29
|
+
});
|
|
30
|
+
|
|
20
31
|
t.test('stringifies a nested object', function (st) {
|
|
21
32
|
st.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
|
|
22
33
|
st.equal(qs.stringify({ a: { b: { c: { d: 'e' } } } }), 'a%5Bb%5D%5Bc%5D%5Bd%5D=e');
|
|
@@ -452,6 +463,16 @@ test('stringify()', function (t) {
|
|
|
452
463
|
st.end();
|
|
453
464
|
});
|
|
454
465
|
|
|
466
|
+
t.test('receives the default encoder as a second argument', function (st) {
|
|
467
|
+
st.plan(2);
|
|
468
|
+
qs.stringify({ a: 1 }, {
|
|
469
|
+
encoder: function (str, defaultEncoder) {
|
|
470
|
+
st.equal(defaultEncoder, utils.encode);
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
st.end();
|
|
474
|
+
});
|
|
475
|
+
|
|
455
476
|
t.test('throws error with wrong encoder', function (st) {
|
|
456
477
|
st.throws(function () {
|
|
457
478
|
qs.stringify({}, { encoder: 'string' });
|
|
@@ -535,4 +556,41 @@ test('stringify()', function (t) {
|
|
|
535
556
|
);
|
|
536
557
|
st.end();
|
|
537
558
|
});
|
|
559
|
+
|
|
560
|
+
t.test('encodeValuesOnly', function (st) {
|
|
561
|
+
st.equal(
|
|
562
|
+
qs.stringify(
|
|
563
|
+
{ a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
|
|
564
|
+
{ encodeValuesOnly: true }
|
|
565
|
+
),
|
|
566
|
+
'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h'
|
|
567
|
+
);
|
|
568
|
+
st.equal(
|
|
569
|
+
qs.stringify(
|
|
570
|
+
{ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }
|
|
571
|
+
),
|
|
572
|
+
'a=b&c%5B0%5D=d&c%5B1%5D=e&f%5B0%5D%5B0%5D=g&f%5B1%5D%5B0%5D=h'
|
|
573
|
+
);
|
|
574
|
+
st.end();
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
t.test('encodeValuesOnly - strictNullHandling', function (st) {
|
|
578
|
+
st.equal(
|
|
579
|
+
qs.stringify(
|
|
580
|
+
{ a: { b: null } },
|
|
581
|
+
{ encodeValuesOnly: true, strictNullHandling: true }
|
|
582
|
+
),
|
|
583
|
+
'a[b]'
|
|
584
|
+
);
|
|
585
|
+
st.end();
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
t.test('does not mutate the options argument', function (st) {
|
|
589
|
+
var options = {};
|
|
590
|
+
qs.stringify({}, options);
|
|
591
|
+
st.deepEqual(options, {});
|
|
592
|
+
st.end();
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
t.end();
|
|
538
596
|
});
|
package/test/utils.js
CHANGED
|
@@ -20,3 +20,15 @@ test('merge()', function (t) {
|
|
|
20
20
|
|
|
21
21
|
t.end();
|
|
22
22
|
});
|
|
23
|
+
|
|
24
|
+
test('assign()', function (t) {
|
|
25
|
+
var target = { a: 1, b: 2 };
|
|
26
|
+
var source = { b: 3, c: 4 };
|
|
27
|
+
var result = utils.assign(target, source);
|
|
28
|
+
|
|
29
|
+
t.equal(result, target, 'returns the target');
|
|
30
|
+
t.deepEqual(target, { a: 1, b: 3, c: 4 }, 'target and source are merged');
|
|
31
|
+
t.deepEqual(source, { b: 3, c: 4 }, 'source is untouched');
|
|
32
|
+
|
|
33
|
+
t.end();
|
|
34
|
+
});
|