qs 2.4.0 → 3.1.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/.eslintignore +1 -0
- package/.npmignore +1 -0
- package/CHANGELOG.md +27 -7
- package/LICENSE +0 -0
- package/README.md +83 -2
- package/bower.json +22 -0
- package/lib/index.js +0 -0
- package/lib/parse.js +24 -15
- package/lib/stringify.js +33 -9
- package/lib/utils.js +62 -4
- package/package.json +5 -8
- package/test/parse.js +140 -98
- package/test/stringify.js +54 -4
- package/test/utils.js +28 -0
package/.eslintignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
dist
|
package/.npmignore
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,13 +1,34 @@
|
|
|
1
1
|
|
|
2
|
-
## [**
|
|
3
|
-
- [**#
|
|
2
|
+
## [**3.1.0**](https://github.com/hapijs/qs/issues?milestone=24&state=open)
|
|
3
|
+
- [**#89**](https://github.com/hapijs/qs/issues/89) Add option to disable "Transform dot notation to bracket notation"
|
|
4
|
+
|
|
5
|
+
## [**3.0.0**](https://github.com/hapijs/qs/issues?milestone=23&state=closed)
|
|
6
|
+
- [**#77**](https://github.com/hapijs/qs/issues/77) Perf boost
|
|
7
|
+
- [**#60**](https://github.com/hapijs/qs/issues/60) Add explicit option to disable array parsing
|
|
8
|
+
- [**#80**](https://github.com/hapijs/qs/issues/80) qs.parse silently drops properties
|
|
9
|
+
- [**#74**](https://github.com/hapijs/qs/issues/74) Bad parse when turning array into object
|
|
10
|
+
- [**#81**](https://github.com/hapijs/qs/issues/81) Add a `filter` option
|
|
11
|
+
- [**#68**](https://github.com/hapijs/qs/issues/68) Fixed issue with recursion and passing strings into objects.
|
|
12
|
+
- [**#66**](https://github.com/hapijs/qs/issues/66) Add mixed array and object dot notation support Closes: #47
|
|
13
|
+
- [**#76**](https://github.com/hapijs/qs/issues/76) RFC 3986
|
|
14
|
+
- [**#85**](https://github.com/hapijs/qs/issues/85) No equal sign
|
|
15
|
+
- [**#84**](https://github.com/hapijs/qs/issues/84) update license attribute
|
|
16
|
+
|
|
17
|
+
## [**2.4.1**](https://github.com/hapijs/qs/issues?milestone=20&state=closed)
|
|
18
|
+
- [**#73**](https://github.com/hapijs/qs/issues/73) Property 'hasOwnProperty' of object #<Object> is not a function
|
|
19
|
+
|
|
20
|
+
## [**2.4.0**](https://github.com/hapijs/qs/issues?milestone=19&state=closed)
|
|
21
|
+
- [**#70**](https://github.com/hapijs/qs/issues/70) Add arrayFormat option
|
|
22
|
+
|
|
23
|
+
## [**2.3.3**](https://github.com/hapijs/qs/issues?milestone=18&state=closed)
|
|
24
|
+
- [**#59**](https://github.com/hapijs/qs/issues/59) make sure array indexes are >= 0, closes #57
|
|
4
25
|
- [**#58**](https://github.com/hapijs/qs/issues/58) make qs usable for browser loader
|
|
5
26
|
|
|
6
27
|
## [**2.3.2**](https://github.com/hapijs/qs/issues?milestone=17&state=closed)
|
|
7
28
|
- [**#55**](https://github.com/hapijs/qs/issues/55) allow merging a string into an object
|
|
8
29
|
|
|
9
30
|
## [**2.3.1**](https://github.com/hapijs/qs/issues?milestone=16&state=closed)
|
|
10
|
-
- [**#52**](https://github.com/hapijs/qs/issues/52) Return
|
|
31
|
+
- [**#52**](https://github.com/hapijs/qs/issues/52) Return "undefined" and "false" instead of throwing "TypeError".
|
|
11
32
|
|
|
12
33
|
## [**2.3.0**](https://github.com/hapijs/qs/issues?milestone=15&state=closed)
|
|
13
34
|
- [**#50**](https://github.com/hapijs/qs/issues/50) add option to omit array indices, closes #46
|
|
@@ -34,9 +55,9 @@
|
|
|
34
55
|
- [**#31**](https://github.com/hapijs/qs/issues/31) qs.parse stackoverflow on circular objects
|
|
35
56
|
|
|
36
57
|
## [**2.2.0**](https://github.com/hapijs/qs/issues?milestone=9&state=closed)
|
|
37
|
-
- [**#26**](https://github.com/hapijs/qs/issues/26) Don
|
|
58
|
+
- [**#26**](https://github.com/hapijs/qs/issues/26) Don't use Buffer global if it's not present
|
|
38
59
|
- [**#30**](https://github.com/hapijs/qs/issues/30) Bug when merging non-object values into arrays
|
|
39
|
-
- [**#29**](https://github.com/hapijs/qs/issues/29) Don
|
|
60
|
+
- [**#29**](https://github.com/hapijs/qs/issues/29) Don't call Utils.clone at the top of Utils.merge
|
|
40
61
|
- [**#23**](https://github.com/hapijs/qs/issues/23) Ability to not limit parameters?
|
|
41
62
|
|
|
42
63
|
## [**2.1.0**](https://github.com/hapijs/qs/issues?milestone=8&state=closed)
|
|
@@ -48,7 +69,7 @@
|
|
|
48
69
|
- [**#21**](https://github.com/hapijs/qs/issues/21) make all limits optional, for #18, for #20
|
|
49
70
|
|
|
50
71
|
## [**1.2.2**](https://github.com/hapijs/qs/issues?milestone=6&state=closed)
|
|
51
|
-
- [**#19**](https://github.com/hapijs/qs/issues/19) Don
|
|
72
|
+
- [**#19**](https://github.com/hapijs/qs/issues/19) Don't overwrite null values
|
|
52
73
|
|
|
53
74
|
## [**1.2.1**](https://github.com/hapijs/qs/issues?milestone=5&state=closed)
|
|
54
75
|
- [**#16**](https://github.com/hapijs/qs/issues/16) ignore non-string delimiters
|
|
@@ -65,4 +86,3 @@
|
|
|
65
86
|
|
|
66
87
|
## [**1.0.2**](https://github.com/hapijs/qs/issues?milestone=2&state=closed)
|
|
67
88
|
- [**#5**](https://github.com/hapijs/qs/issues/5) array holes incorrectly copied into object on large index
|
|
68
|
-
|
package/LICENSE
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ var str = Qs.stringify(obj); // 'a=c'
|
|
|
23
23
|
Qs.parse(string, [options]);
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
**qs** allows you to create nested objects within your query strings, by surrounding the name of sub-keys with square brackets `[]
|
|
26
|
+
**qs** allows you to create nested objects within your query strings, by surrounding the name of sub-keys with square brackets `[]`, or prefixing the sub-key with a dot `.`.
|
|
27
27
|
For example, the string `'foo[bar]=baz'` converts to:
|
|
28
28
|
|
|
29
29
|
```javascript
|
|
@@ -34,6 +34,13 @@ For example, the string `'foo[bar]=baz'` converts to:
|
|
|
34
34
|
}
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
+
The parsed value is returned as a plain object, created via `Object.create(null)` and as such you should be aware that prototype methods do not exist on it and a user may set those names to whatever value they like:
|
|
38
|
+
|
|
39
|
+
```javascript
|
|
40
|
+
Qs.parse('a.hasOwnProperty=b');
|
|
41
|
+
// { a: { hasOwnProperty: 'b' } }
|
|
42
|
+
```
|
|
43
|
+
|
|
37
44
|
URI encoded strings work too:
|
|
38
45
|
|
|
39
46
|
```javascript
|
|
@@ -153,7 +160,12 @@ Qs.parse('a[1]=b', { arrayLimit: 0 });
|
|
|
153
160
|
// { a: { '1': 'b' } }
|
|
154
161
|
```
|
|
155
162
|
|
|
156
|
-
To disable array parsing entirely, set `
|
|
163
|
+
To disable array parsing entirely, set `parseArrays` to `false`.
|
|
164
|
+
|
|
165
|
+
```javascript
|
|
166
|
+
Qs.parse('a[]=b', { parseArrays: false });
|
|
167
|
+
// { a: { '0': 'b' } }
|
|
168
|
+
```
|
|
157
169
|
|
|
158
170
|
If you mix notations, **qs** will merge the two items into an object:
|
|
159
171
|
|
|
@@ -200,6 +212,17 @@ Qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false });
|
|
|
200
212
|
// 'a=b&a=c&a=d'
|
|
201
213
|
```
|
|
202
214
|
|
|
215
|
+
You may use the `arrayFormat` option to specify the format of the output array
|
|
216
|
+
|
|
217
|
+
```javascript
|
|
218
|
+
Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })
|
|
219
|
+
// 'a[0]=b&a[1]=c'
|
|
220
|
+
Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })
|
|
221
|
+
// 'a[]=b&a[]=c'
|
|
222
|
+
Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })
|
|
223
|
+
// 'a=b&a=c'
|
|
224
|
+
```
|
|
225
|
+
|
|
203
226
|
Empty strings and null values will omit the value, but the equals sign (=) remains in place:
|
|
204
227
|
|
|
205
228
|
```javascript
|
|
@@ -220,3 +243,61 @@ The delimiter may be overridden with stringify as well:
|
|
|
220
243
|
Qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' });
|
|
221
244
|
// 'a=b;c=d'
|
|
222
245
|
```
|
|
246
|
+
|
|
247
|
+
Finally, you can use the `filter` option to restrict which keys will be included in the stringified output.
|
|
248
|
+
If you pass a function, it will be called for each key to obtain the replacement value. Otherwise, if you
|
|
249
|
+
pass an array, it will be used to select properties and array indices for stringification:
|
|
250
|
+
|
|
251
|
+
```javascript
|
|
252
|
+
function filterFunc(prefix, value) {
|
|
253
|
+
if (prefix == 'b') {
|
|
254
|
+
// Return an `undefined` value to omit a property.
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
if (prefix == 'e[f]') {
|
|
258
|
+
return value.getTime();
|
|
259
|
+
}
|
|
260
|
+
if (prefix == 'e[g][0]') {
|
|
261
|
+
return value * 2;
|
|
262
|
+
}
|
|
263
|
+
return value;
|
|
264
|
+
}
|
|
265
|
+
Qs.stringify({ a: 'b', c: 'd', e: { f: new Date(123), g: [2] } }, { filter: filterFunc })
|
|
266
|
+
// 'a=b&c=d&e[f]=123&e[g][0]=4'
|
|
267
|
+
Qs.stringify({ a: 'b', c: 'd', e: 'f' }, { filter: ['a', 'e'] })
|
|
268
|
+
// 'a=b&e=f'
|
|
269
|
+
Qs.stringify({ a: ['b', 'c', 'd'], e: 'f' }, { filter: ['a', 0, 2] })
|
|
270
|
+
// 'a[0]=b&a[2]=d'
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Handling of `null` values
|
|
274
|
+
|
|
275
|
+
By default, `null` values are treated like empty strings:
|
|
276
|
+
|
|
277
|
+
```javascript
|
|
278
|
+
Qs.stringify({ a: null, b: '' });
|
|
279
|
+
// 'a=&b='
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Parsing does not distinguish between parameters with and without equal signs. Both are converted to empty strings.
|
|
283
|
+
|
|
284
|
+
```javascript
|
|
285
|
+
Qs.parse('a&b=')
|
|
286
|
+
// { a: '', b: '' }
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
To distinguish between `null` values and empty strings use the `strictNullHandling` flag. In the result string the `null`
|
|
290
|
+
values have no `=` sign:
|
|
291
|
+
|
|
292
|
+
```javascript
|
|
293
|
+
Qs.stringify({ a: null, b: '' }, { strictNullHandling: true });
|
|
294
|
+
// 'a&b='
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
To parse values without `=` back to `null` use the `strictNullHandling` flag:
|
|
298
|
+
|
|
299
|
+
```javascript
|
|
300
|
+
Qs.parse('a&b=', { strictNullHandling: true });
|
|
301
|
+
// { a: null, b: '' }
|
|
302
|
+
|
|
303
|
+
```
|
package/bower.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "qs",
|
|
3
|
+
"main": "dist/qs.js",
|
|
4
|
+
"version": "3.0.0",
|
|
5
|
+
"homepage": "https://github.com/hapijs/qs",
|
|
6
|
+
"authors": [
|
|
7
|
+
"Nathan LaFreniere <quitlahok@gmail.com>"
|
|
8
|
+
],
|
|
9
|
+
"description": "A querystring parser that supports nesting and arrays, with a depth limit",
|
|
10
|
+
"keywords": [
|
|
11
|
+
"querystring",
|
|
12
|
+
"qs"
|
|
13
|
+
],
|
|
14
|
+
"license": "BSD-3-Clause",
|
|
15
|
+
"ignore": [
|
|
16
|
+
"**/.*",
|
|
17
|
+
"node_modules",
|
|
18
|
+
"bower_components",
|
|
19
|
+
"test",
|
|
20
|
+
"tests"
|
|
21
|
+
]
|
|
22
|
+
}
|
package/lib/index.js
CHANGED
|
File without changes
|
package/lib/parse.js
CHANGED
|
@@ -9,7 +9,8 @@ var internals = {
|
|
|
9
9
|
delimiter: '&',
|
|
10
10
|
depth: 5,
|
|
11
11
|
arrayLimit: 20,
|
|
12
|
-
parameterLimit: 1000
|
|
12
|
+
parameterLimit: 1000,
|
|
13
|
+
strictNullHandling: false
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
|
|
@@ -24,12 +25,16 @@ internals.parseValues = function (str, options) {
|
|
|
24
25
|
|
|
25
26
|
if (pos === -1) {
|
|
26
27
|
obj[Utils.decode(part)] = '';
|
|
28
|
+
|
|
29
|
+
if (options.strictNullHandling) {
|
|
30
|
+
obj[Utils.decode(part)] = null;
|
|
31
|
+
}
|
|
27
32
|
}
|
|
28
33
|
else {
|
|
29
34
|
var key = Utils.decode(part.slice(0, pos));
|
|
30
35
|
var val = Utils.decode(part.slice(pos + 1));
|
|
31
36
|
|
|
32
|
-
if (!
|
|
37
|
+
if (!Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
33
38
|
obj[key] = val;
|
|
34
39
|
}
|
|
35
40
|
else {
|
|
@@ -50,12 +55,13 @@ internals.parseObject = function (chain, val, options) {
|
|
|
50
55
|
|
|
51
56
|
var root = chain.shift();
|
|
52
57
|
|
|
53
|
-
var obj
|
|
58
|
+
var obj;
|
|
54
59
|
if (root === '[]') {
|
|
55
60
|
obj = [];
|
|
56
61
|
obj = obj.concat(internals.parseObject(chain, val, options));
|
|
57
62
|
}
|
|
58
63
|
else {
|
|
64
|
+
obj = Object.create(null);
|
|
59
65
|
var cleanRoot = root[0] === '[' && root[root.length - 1] === ']' ? root.slice(1, root.length - 1) : root;
|
|
60
66
|
var index = parseInt(cleanRoot, 10);
|
|
61
67
|
var indexString = '' + index;
|
|
@@ -63,7 +69,8 @@ internals.parseObject = function (chain, val, options) {
|
|
|
63
69
|
root !== cleanRoot &&
|
|
64
70
|
indexString === cleanRoot &&
|
|
65
71
|
index >= 0 &&
|
|
66
|
-
|
|
72
|
+
(options.parseArrays &&
|
|
73
|
+
index <= options.arrayLimit)) {
|
|
67
74
|
|
|
68
75
|
obj = [];
|
|
69
76
|
obj[index] = internals.parseObject(chain, val, options);
|
|
@@ -83,6 +90,12 @@ internals.parseKeys = function (key, val, options) {
|
|
|
83
90
|
return;
|
|
84
91
|
}
|
|
85
92
|
|
|
93
|
+
// Transform dot notation to bracket notation
|
|
94
|
+
|
|
95
|
+
if (options.allowDots) {
|
|
96
|
+
key = key.replace(/\.([^\.\[]+)/g, '[$1]');
|
|
97
|
+
}
|
|
98
|
+
|
|
86
99
|
// The regex chunks
|
|
87
100
|
|
|
88
101
|
var parent = /^([^\[\]]*)/;
|
|
@@ -92,12 +105,6 @@ internals.parseKeys = function (key, val, options) {
|
|
|
92
105
|
|
|
93
106
|
var segment = parent.exec(key);
|
|
94
107
|
|
|
95
|
-
// Don't allow them to overwrite object prototype properties
|
|
96
|
-
|
|
97
|
-
if (Object.prototype.hasOwnProperty(segment[1])) {
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
108
|
// Stash the parent if it exists
|
|
102
109
|
|
|
103
110
|
var keys = [];
|
|
@@ -111,9 +118,7 @@ internals.parseKeys = function (key, val, options) {
|
|
|
111
118
|
while ((segment = child.exec(key)) !== null && i < options.depth) {
|
|
112
119
|
|
|
113
120
|
++i;
|
|
114
|
-
|
|
115
|
-
keys.push(segment[1]);
|
|
116
|
-
}
|
|
121
|
+
keys.push(segment[1]);
|
|
117
122
|
}
|
|
118
123
|
|
|
119
124
|
// If there's a remainder, just add whatever is left
|
|
@@ -132,17 +137,21 @@ module.exports = function (str, options) {
|
|
|
132
137
|
str === null ||
|
|
133
138
|
typeof str === 'undefined') {
|
|
134
139
|
|
|
135
|
-
return
|
|
140
|
+
return Object.create(null);
|
|
136
141
|
}
|
|
137
142
|
|
|
138
143
|
options = options || {};
|
|
139
144
|
options.delimiter = typeof options.delimiter === 'string' || Utils.isRegExp(options.delimiter) ? options.delimiter : internals.delimiter;
|
|
140
145
|
options.depth = typeof options.depth === 'number' ? options.depth : internals.depth;
|
|
141
146
|
options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : internals.arrayLimit;
|
|
147
|
+
options.parseArrays = options.parseArrays !== false;
|
|
148
|
+
options.allowDots = options.allowDots !== false;
|
|
142
149
|
options.parameterLimit = typeof options.parameterLimit === 'number' ? options.parameterLimit : internals.parameterLimit;
|
|
150
|
+
options.strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : internals.strictNullHandling;
|
|
151
|
+
|
|
143
152
|
|
|
144
153
|
var tempObj = typeof str === 'string' ? internals.parseValues(str, options) : str;
|
|
145
|
-
var obj =
|
|
154
|
+
var obj = Object.create(null);
|
|
146
155
|
|
|
147
156
|
// Iterate over the keys and setup the new object
|
|
148
157
|
|
package/lib/stringify.js
CHANGED
|
@@ -9,27 +9,38 @@ var internals = {
|
|
|
9
9
|
delimiter: '&',
|
|
10
10
|
arrayPrefixGenerators: {
|
|
11
11
|
brackets: function (prefix, key) {
|
|
12
|
+
|
|
12
13
|
return prefix + '[]';
|
|
13
14
|
},
|
|
14
15
|
indices: function (prefix, key) {
|
|
16
|
+
|
|
15
17
|
return prefix + '[' + key + ']';
|
|
16
18
|
},
|
|
17
19
|
repeat: function (prefix, key) {
|
|
20
|
+
|
|
18
21
|
return prefix;
|
|
19
22
|
}
|
|
20
|
-
}
|
|
23
|
+
},
|
|
24
|
+
strictNullHandling: false
|
|
21
25
|
};
|
|
22
26
|
|
|
23
27
|
|
|
24
|
-
internals.stringify = function (obj, prefix, generateArrayPrefix) {
|
|
28
|
+
internals.stringify = function (obj, prefix, generateArrayPrefix, strictNullHandling, filter) {
|
|
25
29
|
|
|
26
|
-
if (
|
|
30
|
+
if (typeof filter === 'function') {
|
|
31
|
+
obj = filter(prefix, obj);
|
|
32
|
+
}
|
|
33
|
+
else if (Utils.isBuffer(obj)) {
|
|
27
34
|
obj = obj.toString();
|
|
28
35
|
}
|
|
29
36
|
else if (obj instanceof Date) {
|
|
30
37
|
obj = obj.toISOString();
|
|
31
38
|
}
|
|
32
39
|
else if (obj === null) {
|
|
40
|
+
if (strictNullHandling) {
|
|
41
|
+
return Utils.encode(prefix);
|
|
42
|
+
}
|
|
43
|
+
|
|
33
44
|
obj = '';
|
|
34
45
|
}
|
|
35
46
|
|
|
@@ -37,7 +48,7 @@ internals.stringify = function (obj, prefix, generateArrayPrefix) {
|
|
|
37
48
|
typeof obj === 'number' ||
|
|
38
49
|
typeof obj === 'boolean') {
|
|
39
50
|
|
|
40
|
-
return [
|
|
51
|
+
return [Utils.encode(prefix) + '=' + Utils.encode(obj)];
|
|
41
52
|
}
|
|
42
53
|
|
|
43
54
|
var values = [];
|
|
@@ -46,14 +57,15 @@ internals.stringify = function (obj, prefix, generateArrayPrefix) {
|
|
|
46
57
|
return values;
|
|
47
58
|
}
|
|
48
59
|
|
|
49
|
-
var objKeys = Object.keys(obj);
|
|
60
|
+
var objKeys = Array.isArray(filter) ? filter : Object.keys(obj);
|
|
50
61
|
for (var i = 0, il = objKeys.length; i < il; ++i) {
|
|
51
62
|
var key = objKeys[i];
|
|
63
|
+
|
|
52
64
|
if (Array.isArray(obj)) {
|
|
53
|
-
values = values.concat(internals.stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix));
|
|
65
|
+
values = values.concat(internals.stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix, strictNullHandling, filter));
|
|
54
66
|
}
|
|
55
67
|
else {
|
|
56
|
-
values = values.concat(internals.stringify(obj[key], prefix + '[' + key + ']', generateArrayPrefix));
|
|
68
|
+
values = values.concat(internals.stringify(obj[key], prefix + '[' + key + ']', generateArrayPrefix, strictNullHandling, filter));
|
|
57
69
|
}
|
|
58
70
|
}
|
|
59
71
|
|
|
@@ -65,6 +77,16 @@ module.exports = function (obj, options) {
|
|
|
65
77
|
|
|
66
78
|
options = options || {};
|
|
67
79
|
var delimiter = typeof options.delimiter === 'undefined' ? internals.delimiter : options.delimiter;
|
|
80
|
+
var strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : internals.strictNullHandling;
|
|
81
|
+
var objKeys;
|
|
82
|
+
var filter;
|
|
83
|
+
if (typeof options.filter === 'function') {
|
|
84
|
+
filter = options.filter;
|
|
85
|
+
obj = filter('', obj);
|
|
86
|
+
}
|
|
87
|
+
else if (Array.isArray(options.filter)) {
|
|
88
|
+
objKeys = filter = options.filter;
|
|
89
|
+
}
|
|
68
90
|
|
|
69
91
|
var keys = [];
|
|
70
92
|
|
|
@@ -87,10 +109,12 @@ module.exports = function (obj, options) {
|
|
|
87
109
|
|
|
88
110
|
var generateArrayPrefix = internals.arrayPrefixGenerators[arrayFormat];
|
|
89
111
|
|
|
90
|
-
|
|
112
|
+
if (!objKeys) {
|
|
113
|
+
objKeys = Object.keys(obj);
|
|
114
|
+
}
|
|
91
115
|
for (var i = 0, il = objKeys.length; i < il; ++i) {
|
|
92
116
|
var key = objKeys[i];
|
|
93
|
-
keys = keys.concat(internals.stringify(obj[key], key, generateArrayPrefix));
|
|
117
|
+
keys = keys.concat(internals.stringify(obj[key], key, generateArrayPrefix, strictNullHandling, filter));
|
|
94
118
|
}
|
|
95
119
|
|
|
96
120
|
return keys.join(delimiter);
|
package/lib/utils.js
CHANGED
|
@@ -4,11 +4,15 @@
|
|
|
4
4
|
// Declare internals
|
|
5
5
|
|
|
6
6
|
var internals = {};
|
|
7
|
+
internals.hexTable = new Array(256);
|
|
8
|
+
for (var i = 0; i < 256; ++i) {
|
|
9
|
+
internals.hexTable[i] = '%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase();
|
|
10
|
+
}
|
|
7
11
|
|
|
8
12
|
|
|
9
13
|
exports.arrayToObject = function (source) {
|
|
10
14
|
|
|
11
|
-
var obj =
|
|
15
|
+
var obj = Object.create(null);
|
|
12
16
|
for (var i = 0, il = source.length; i < il; ++i) {
|
|
13
17
|
if (typeof source[i] !== 'undefined') {
|
|
14
18
|
|
|
@@ -30,9 +34,12 @@ exports.merge = function (target, source) {
|
|
|
30
34
|
if (Array.isArray(target)) {
|
|
31
35
|
target.push(source);
|
|
32
36
|
}
|
|
33
|
-
else {
|
|
37
|
+
else if (typeof target === 'object') {
|
|
34
38
|
target[source] = true;
|
|
35
39
|
}
|
|
40
|
+
else {
|
|
41
|
+
target = [target, source];
|
|
42
|
+
}
|
|
36
43
|
|
|
37
44
|
return target;
|
|
38
45
|
}
|
|
@@ -74,6 +81,56 @@ exports.decode = function (str) {
|
|
|
74
81
|
}
|
|
75
82
|
};
|
|
76
83
|
|
|
84
|
+
exports.encode = function (str) {
|
|
85
|
+
|
|
86
|
+
// This code was originally written by Brian White (mscdex) for the io.js core querystring library.
|
|
87
|
+
// It has been adapted here for stricter adherence to RFC 3986
|
|
88
|
+
if (str.length === 0) {
|
|
89
|
+
return str;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (typeof str !== 'string') {
|
|
93
|
+
str = '' + str;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
var out = '';
|
|
97
|
+
for (var i = 0, il = str.length; i < il; ++i) {
|
|
98
|
+
var c = str.charCodeAt(i);
|
|
99
|
+
|
|
100
|
+
if (c === 0x2D || // -
|
|
101
|
+
c === 0x2E || // .
|
|
102
|
+
c === 0x5F || // _
|
|
103
|
+
c === 0x7E || // ~
|
|
104
|
+
(c >= 0x30 && c <= 0x39) || // 0-9
|
|
105
|
+
(c >= 0x41 && c <= 0x5A) || // a-z
|
|
106
|
+
(c >= 0x61 && c <= 0x7A)) { // A-Z
|
|
107
|
+
|
|
108
|
+
out += str[i];
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (c < 0x80) {
|
|
113
|
+
out += internals.hexTable[c];
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (c < 0x800) {
|
|
118
|
+
out += internals.hexTable[0xC0 | (c >> 6)] + internals.hexTable[0x80 | (c & 0x3F)];
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (c < 0xD800 || c >= 0xE000) {
|
|
123
|
+
out += internals.hexTable[0xE0 | (c >> 12)] + internals.hexTable[0x80 | ((c >> 6) & 0x3F)] + internals.hexTable[0x80 | (c & 0x3F)];
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
++i;
|
|
128
|
+
c = 0x10000 + (((c & 0x3FF) << 10) | (str.charCodeAt(i) & 0x3FF));
|
|
129
|
+
out += internals.hexTable[0xF0 | (c >> 18)] + internals.hexTable[0x80 | ((c >> 12) & 0x3F)] + internals.hexTable[0x80 | ((c >> 6) & 0x3F)] + internals.hexTable[0x80 | (c & 0x3F)];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return out;
|
|
133
|
+
};
|
|
77
134
|
|
|
78
135
|
exports.compact = function (obj, refs) {
|
|
79
136
|
|
|
@@ -114,6 +171,7 @@ exports.compact = function (obj, refs) {
|
|
|
114
171
|
|
|
115
172
|
|
|
116
173
|
exports.isRegExp = function (obj) {
|
|
174
|
+
|
|
117
175
|
return Object.prototype.toString.call(obj) === '[object RegExp]';
|
|
118
176
|
};
|
|
119
177
|
|
|
@@ -127,6 +185,6 @@ exports.isBuffer = function (obj) {
|
|
|
127
185
|
}
|
|
128
186
|
|
|
129
187
|
return !!(obj.constructor &&
|
|
130
|
-
|
|
131
|
-
|
|
188
|
+
obj.constructor.isBuffer &&
|
|
189
|
+
obj.constructor.isBuffer(obj));
|
|
132
190
|
};
|
package/package.json
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qs",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "A querystring parser that supports nesting and arrays, with a depth limit",
|
|
5
5
|
"homepage": "https://github.com/hapijs/qs",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"dependencies": {},
|
|
8
8
|
"devDependencies": {
|
|
9
|
+
"browserify": "^10.2.1",
|
|
9
10
|
"code": "1.x.x",
|
|
10
11
|
"lab": "5.x.x"
|
|
11
12
|
},
|
|
12
13
|
"scripts": {
|
|
13
|
-
"test": "make test-cov"
|
|
14
|
+
"test": "make test-cov",
|
|
15
|
+
"dist": "browserify --standalone Qs index.js > dist/qs.js"
|
|
14
16
|
},
|
|
15
17
|
"repository": {
|
|
16
18
|
"type": "git",
|
|
@@ -20,10 +22,5 @@
|
|
|
20
22
|
"querystring",
|
|
21
23
|
"qs"
|
|
22
24
|
],
|
|
23
|
-
"
|
|
24
|
-
{
|
|
25
|
-
"type": "BSD",
|
|
26
|
-
"url": "http://github.com/hapijs/qs/raw/master/LICENSE"
|
|
27
|
-
}
|
|
28
|
-
]
|
|
25
|
+
"license": "BSD-3-Clause"
|
|
29
26
|
}
|
package/test/parse.js
CHANGED
|
@@ -23,174 +23,194 @@ describe('parse()', function () {
|
|
|
23
23
|
|
|
24
24
|
it('parses a simple string', function (done) {
|
|
25
25
|
|
|
26
|
-
expect(Qs.parse('0=foo')).to.deep.equal({ '0': 'foo' });
|
|
27
|
-
expect(Qs.parse('foo=c++')).to.deep.equal({ foo: 'c ' });
|
|
28
|
-
expect(Qs.parse('a[>=]=23')).to.deep.equal({ a: { '>=': '23' } });
|
|
29
|
-
expect(Qs.parse('a[<=>]==23')).to.deep.equal({ a: { '<=>': '=23' } });
|
|
30
|
-
expect(Qs.parse('a[==]=23')).to.deep.equal({ a: { '==': '23' } });
|
|
31
|
-
expect(Qs.parse('foo')).to.deep.equal({ foo:
|
|
32
|
-
expect(Qs.parse('foo
|
|
33
|
-
expect(Qs.parse('
|
|
34
|
-
expect(Qs.parse('foo=bar
|
|
35
|
-
expect(Qs.parse('foo=bar
|
|
36
|
-
expect(Qs.parse('foo=bar
|
|
26
|
+
expect(Qs.parse('0=foo')).to.deep.equal({ '0': 'foo' }, { prototype: false });
|
|
27
|
+
expect(Qs.parse('foo=c++')).to.deep.equal({ foo: 'c ' }, { prototype: false });
|
|
28
|
+
expect(Qs.parse('a[>=]=23')).to.deep.equal({ a: { '>=': '23' } }, { prototype: false });
|
|
29
|
+
expect(Qs.parse('a[<=>]==23')).to.deep.equal({ a: { '<=>': '=23' } }, { prototype: false });
|
|
30
|
+
expect(Qs.parse('a[==]=23')).to.deep.equal({ a: { '==': '23' } }, { prototype: false });
|
|
31
|
+
expect(Qs.parse('foo', {strictNullHandling: true})).to.deep.equal({ foo: null }, { prototype: false });
|
|
32
|
+
expect(Qs.parse('foo' )).to.deep.equal({ foo: '' }, { prototype: false });
|
|
33
|
+
expect(Qs.parse('foo=')).to.deep.equal({ foo: '' }, { prototype: false });
|
|
34
|
+
expect(Qs.parse('foo=bar')).to.deep.equal({ foo: 'bar' }, { prototype: false });
|
|
35
|
+
expect(Qs.parse(' foo = bar = baz ')).to.deep.equal({ ' foo ': ' bar = baz ' }, { prototype: false });
|
|
36
|
+
expect(Qs.parse('foo=bar=baz')).to.deep.equal({ foo: 'bar=baz' }, { prototype: false });
|
|
37
|
+
expect(Qs.parse('foo=bar&bar=baz')).to.deep.equal({ foo: 'bar', bar: 'baz' }, { prototype: false });
|
|
38
|
+
expect(Qs.parse('foo2=bar2&baz2=')).to.deep.equal({ foo2: 'bar2', baz2: '' }, { prototype: false });
|
|
39
|
+
expect(Qs.parse('foo=bar&baz', {strictNullHandling: true})).to.deep.equal({ foo: 'bar', baz: null }, { prototype: false });
|
|
40
|
+
expect(Qs.parse('foo=bar&baz')).to.deep.equal({ foo: 'bar', baz: '' }, { prototype: false });
|
|
37
41
|
expect(Qs.parse('cht=p3&chd=t:60,40&chs=250x100&chl=Hello|World')).to.deep.equal({
|
|
38
42
|
cht: 'p3',
|
|
39
43
|
chd: 't:60,40',
|
|
40
44
|
chs: '250x100',
|
|
41
45
|
chl: 'Hello|World'
|
|
42
|
-
});
|
|
46
|
+
}, { prototype: false });
|
|
47
|
+
done();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('allows disabling dot notation', function (done) {
|
|
51
|
+
|
|
52
|
+
expect(Qs.parse('a.b=c')).to.deep.equal({ a: { b: 'c' } }, { prototype: false });
|
|
53
|
+
expect(Qs.parse('a.b=c', { allowDots: false })).to.deep.equal({ 'a.b': 'c' }, { prototype: false });
|
|
43
54
|
done();
|
|
44
55
|
});
|
|
45
56
|
|
|
46
57
|
it('parses a single nested string', function (done) {
|
|
47
58
|
|
|
48
|
-
expect(Qs.parse('a[b]=c')).to.deep.equal({ a: { b: 'c' } });
|
|
59
|
+
expect(Qs.parse('a[b]=c')).to.deep.equal({ a: { b: 'c' } }, { prototype: false });
|
|
49
60
|
done();
|
|
50
61
|
});
|
|
51
62
|
|
|
52
63
|
it('parses a double nested string', function (done) {
|
|
53
64
|
|
|
54
|
-
expect(Qs.parse('a[b][c]=d')).to.deep.equal({ a: { b: { c: 'd' } } });
|
|
65
|
+
expect(Qs.parse('a[b][c]=d')).to.deep.equal({ a: { b: { c: 'd' } } }, { prototype: false });
|
|
55
66
|
done();
|
|
56
67
|
});
|
|
57
68
|
|
|
58
69
|
it('defaults to a depth of 5', function (done) {
|
|
59
70
|
|
|
60
|
-
expect(Qs.parse('a[b][c][d][e][f][g][h]=i')).to.deep.equal({ a: { b: { c: { d: { e: { f: { '[g][h]': 'i' } } } } } } });
|
|
71
|
+
expect(Qs.parse('a[b][c][d][e][f][g][h]=i')).to.deep.equal({ a: { b: { c: { d: { e: { f: { '[g][h]': 'i' } } } } } } }, { prototype: false });
|
|
61
72
|
done();
|
|
62
73
|
});
|
|
63
74
|
|
|
64
75
|
it('only parses one level when depth = 1', function (done) {
|
|
65
76
|
|
|
66
|
-
expect(Qs.parse('a[b][c]=d', { depth: 1 })).to.deep.equal({ a: { b: { '[c]': 'd' } } });
|
|
67
|
-
expect(Qs.parse('a[b][c][d]=e', { depth: 1 })).to.deep.equal({ a: { b: { '[c][d]': 'e' } } });
|
|
77
|
+
expect(Qs.parse('a[b][c]=d', { depth: 1 })).to.deep.equal({ a: { b: { '[c]': 'd' } } }, { prototype: false });
|
|
78
|
+
expect(Qs.parse('a[b][c][d]=e', { depth: 1 })).to.deep.equal({ a: { b: { '[c][d]': 'e' } } }, { prototype: false });
|
|
68
79
|
done();
|
|
69
80
|
});
|
|
70
81
|
|
|
71
82
|
it('parses a simple array', function (done) {
|
|
72
83
|
|
|
73
|
-
expect(Qs.parse('a=b&a=c')).to.deep.equal({ a: ['b', 'c'] });
|
|
84
|
+
expect(Qs.parse('a=b&a=c')).to.deep.equal({ a: ['b', 'c'] }, { prototype: false });
|
|
74
85
|
done();
|
|
75
86
|
});
|
|
76
87
|
|
|
77
88
|
it('parses an explicit array', function (done) {
|
|
78
89
|
|
|
79
|
-
expect(Qs.parse('a[]=b')).to.deep.equal({ a: ['b'] });
|
|
80
|
-
expect(Qs.parse('a[]=b&a[]=c')).to.deep.equal({ a: ['b', 'c'] });
|
|
81
|
-
expect(Qs.parse('a[]=b&a[]=c&a[]=d')).to.deep.equal({ a: ['b', 'c', 'd'] });
|
|
90
|
+
expect(Qs.parse('a[]=b')).to.deep.equal({ a: ['b'] }, { prototype: false });
|
|
91
|
+
expect(Qs.parse('a[]=b&a[]=c')).to.deep.equal({ a: ['b', 'c'] }, { prototype: false });
|
|
92
|
+
expect(Qs.parse('a[]=b&a[]=c&a[]=d')).to.deep.equal({ a: ['b', 'c', 'd'] }, { prototype: false });
|
|
82
93
|
done();
|
|
83
94
|
});
|
|
84
95
|
|
|
85
96
|
it('parses a mix of simple and explicit arrays', function (done) {
|
|
86
97
|
|
|
87
|
-
expect(Qs.parse('a=b&a[]=c')).to.deep.equal({ a: ['b', 'c'] });
|
|
88
|
-
expect(Qs.parse('a[]=b&a=c')).to.deep.equal({ a: ['b', 'c'] });
|
|
89
|
-
expect(Qs.parse('a[0]=b&a=c')).to.deep.equal({ a: ['b', 'c'] });
|
|
90
|
-
expect(Qs.parse('a=b&a[0]=c')).to.deep.equal({ a: ['b', 'c'] });
|
|
91
|
-
expect(Qs.parse('a[1]=b&a=c')).to.deep.equal({ a: ['b', 'c'] });
|
|
92
|
-
expect(Qs.parse('a=b&a[1]=c')).to.deep.equal({ a: ['b', 'c'] });
|
|
98
|
+
expect(Qs.parse('a=b&a[]=c')).to.deep.equal({ a: ['b', 'c'] }, { prototype: false });
|
|
99
|
+
expect(Qs.parse('a[]=b&a=c')).to.deep.equal({ a: ['b', 'c'] }, { prototype: false });
|
|
100
|
+
expect(Qs.parse('a[0]=b&a=c')).to.deep.equal({ a: ['b', 'c'] }, { prototype: false });
|
|
101
|
+
expect(Qs.parse('a=b&a[0]=c')).to.deep.equal({ a: ['b', 'c'] }, { prototype: false });
|
|
102
|
+
expect(Qs.parse('a[1]=b&a=c')).to.deep.equal({ a: ['b', 'c'] }, { prototype: false });
|
|
103
|
+
expect(Qs.parse('a=b&a[1]=c')).to.deep.equal({ a: ['b', 'c'] }, { prototype: false });
|
|
93
104
|
done();
|
|
94
105
|
});
|
|
95
106
|
|
|
96
107
|
it('parses a nested array', function (done) {
|
|
97
108
|
|
|
98
|
-
expect(Qs.parse('a[b][]=c&a[b][]=d')).to.deep.equal({ a: { b: ['c', 'd'] } });
|
|
99
|
-
expect(Qs.parse('a[>=]=25')).to.deep.equal({ a: { '>=': '25' } });
|
|
109
|
+
expect(Qs.parse('a[b][]=c&a[b][]=d')).to.deep.equal({ a: { b: ['c', 'd'] } }, { prototype: false });
|
|
110
|
+
expect(Qs.parse('a[>=]=25')).to.deep.equal({ a: { '>=': '25' } }, { prototype: false });
|
|
100
111
|
done();
|
|
101
112
|
});
|
|
102
113
|
|
|
103
114
|
it('allows to specify array indices', function (done) {
|
|
104
115
|
|
|
105
|
-
expect(Qs.parse('a[1]=c&a[0]=b&a[2]=d')).to.deep.equal({ a: ['b', 'c', 'd'] });
|
|
106
|
-
expect(Qs.parse('a[1]=c&a[0]=b')).to.deep.equal({ a: ['b', 'c'] });
|
|
107
|
-
expect(Qs.parse('a[1]=c')).to.deep.equal({ a: ['c'] });
|
|
116
|
+
expect(Qs.parse('a[1]=c&a[0]=b&a[2]=d')).to.deep.equal({ a: ['b', 'c', 'd'] }, { prototype: false });
|
|
117
|
+
expect(Qs.parse('a[1]=c&a[0]=b')).to.deep.equal({ a: ['b', 'c'] }, { prototype: false });
|
|
118
|
+
expect(Qs.parse('a[1]=c')).to.deep.equal({ a: ['c'] }, { prototype: false });
|
|
108
119
|
done();
|
|
109
120
|
});
|
|
110
121
|
|
|
111
122
|
it('limits specific array indices to 20', function (done) {
|
|
112
123
|
|
|
113
|
-
expect(Qs.parse('a[20]=a')).to.deep.equal({ a: ['a'] });
|
|
114
|
-
expect(Qs.parse('a[21]=a')).to.deep.equal({ a: { '21': 'a' } });
|
|
124
|
+
expect(Qs.parse('a[20]=a')).to.deep.equal({ a: ['a'] }, { prototype: false });
|
|
125
|
+
expect(Qs.parse('a[21]=a')).to.deep.equal({ a: { '21': 'a' } }, { prototype: false });
|
|
115
126
|
done();
|
|
116
127
|
});
|
|
117
128
|
|
|
118
129
|
it('supports keys that begin with a number', function (done) {
|
|
119
130
|
|
|
120
|
-
expect(Qs.parse('a[12b]=c')).to.deep.equal({ a: { '12b': 'c' } });
|
|
131
|
+
expect(Qs.parse('a[12b]=c')).to.deep.equal({ a: { '12b': 'c' } }, { prototype: false });
|
|
121
132
|
done();
|
|
122
133
|
});
|
|
123
134
|
|
|
124
135
|
it('supports encoded = signs', function (done) {
|
|
125
136
|
|
|
126
|
-
expect(Qs.parse('he%3Dllo=th%3Dere')).to.deep.equal({ 'he=llo': 'th=ere' });
|
|
137
|
+
expect(Qs.parse('he%3Dllo=th%3Dere')).to.deep.equal({ 'he=llo': 'th=ere' }, { prototype: false });
|
|
127
138
|
done();
|
|
128
139
|
});
|
|
129
140
|
|
|
130
141
|
it('is ok with url encoded strings', function (done) {
|
|
131
142
|
|
|
132
|
-
expect(Qs.parse('a[b%20c]=d')).to.deep.equal({ a: { 'b c': 'd' } });
|
|
133
|
-
expect(Qs.parse('a[b]=c%20d')).to.deep.equal({ a: { b: 'c d' } });
|
|
143
|
+
expect(Qs.parse('a[b%20c]=d')).to.deep.equal({ a: { 'b c': 'd' } }, { prototype: false });
|
|
144
|
+
expect(Qs.parse('a[b]=c%20d')).to.deep.equal({ a: { b: 'c d' } }, { prototype: false });
|
|
134
145
|
done();
|
|
135
146
|
});
|
|
136
147
|
|
|
137
148
|
it('allows brackets in the value', function (done) {
|
|
138
149
|
|
|
139
|
-
expect(Qs.parse('pets=["tobi"]')).to.deep.equal({ pets: '["tobi"]' });
|
|
140
|
-
expect(Qs.parse('operators=[">=", "<="]')).to.deep.equal({ operators: '[">=", "<="]' });
|
|
150
|
+
expect(Qs.parse('pets=["tobi"]')).to.deep.equal({ pets: '["tobi"]' }, { prototype: false });
|
|
151
|
+
expect(Qs.parse('operators=[">=", "<="]')).to.deep.equal({ operators: '[">=", "<="]' }, { prototype: false });
|
|
141
152
|
done();
|
|
142
153
|
});
|
|
143
154
|
|
|
144
155
|
it('allows empty values', function (done) {
|
|
145
156
|
|
|
146
|
-
expect(Qs.parse('')).to.deep.equal({});
|
|
147
|
-
expect(Qs.parse(null)).to.deep.equal({});
|
|
148
|
-
expect(Qs.parse(undefined)).to.deep.equal({});
|
|
157
|
+
expect(Qs.parse('')).to.deep.equal({}, { prototype: false });
|
|
158
|
+
expect(Qs.parse(null)).to.deep.equal({}, { prototype: false });
|
|
159
|
+
expect(Qs.parse(undefined)).to.deep.equal({}, { prototype: false });
|
|
149
160
|
done();
|
|
150
161
|
});
|
|
151
162
|
|
|
152
163
|
it('transforms arrays to objects', function (done) {
|
|
153
164
|
|
|
154
|
-
expect(Qs.parse('foo[0]=bar&foo[bad]=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } });
|
|
155
|
-
expect(Qs.parse('foo[bad]=baz&foo[0]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } });
|
|
156
|
-
expect(Qs.parse('foo[bad]=baz&foo[]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } });
|
|
157
|
-
expect(Qs.parse('foo[]=bar&foo[bad]=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } });
|
|
158
|
-
expect(Qs.parse('foo[bad]=baz&foo[]=bar&foo[]=foo')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar', '1': 'foo' } });
|
|
159
|
-
expect(Qs.parse('foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb')).to.deep.equal({foo: [ {a: 'a', b: 'b'}, {a: 'aa', b: 'bb'} ]});
|
|
165
|
+
expect(Qs.parse('foo[0]=bar&foo[bad]=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } }, { prototype: false });
|
|
166
|
+
expect(Qs.parse('foo[bad]=baz&foo[0]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } }, { prototype: false });
|
|
167
|
+
expect(Qs.parse('foo[bad]=baz&foo[]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } }, { prototype: false });
|
|
168
|
+
expect(Qs.parse('foo[]=bar&foo[bad]=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } }, { prototype: false });
|
|
169
|
+
expect(Qs.parse('foo[bad]=baz&foo[]=bar&foo[]=foo')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar', '1': 'foo' } }, { prototype: false });
|
|
170
|
+
expect(Qs.parse('foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb')).to.deep.equal({foo: [ {a: 'a', b: 'b'}, {a: 'aa', b: 'bb'} ]}, { prototype: false });
|
|
171
|
+
expect(Qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c')).to.deep.equal({ a: { '0': 'b', t: 'u', hasOwnProperty: 'c' } }, { prototype: false });
|
|
172
|
+
expect(Qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y')).to.deep.equal({ a: { '0': 'b', hasOwnProperty: 'c', x: 'y' } }, { prototype: false });
|
|
160
173
|
done();
|
|
161
174
|
});
|
|
162
175
|
|
|
163
|
-
it('
|
|
176
|
+
it('transforms arrays to objects (dot notation)', function (done) {
|
|
164
177
|
|
|
165
|
-
expect(Qs.parse('
|
|
178
|
+
expect(Qs.parse('foo[0].baz=bar&fool.bad=baz')).to.deep.equal({ foo: [ { baz: 'bar'} ], fool: { bad: 'baz' } }, { prototype: false });
|
|
179
|
+
expect(Qs.parse('foo[0].baz=bar&fool.bad.boo=baz')).to.deep.equal({ foo: [ { baz: 'bar'} ], fool: { bad: { boo: 'baz' } } }, { prototype: false });
|
|
180
|
+
expect(Qs.parse('foo[0][0].baz=bar&fool.bad=baz')).to.deep.equal({ foo: [[ { baz: 'bar'} ]], fool: { bad: 'baz' } }, { prototype: false });
|
|
181
|
+
expect(Qs.parse('foo[0].baz[0]=15&foo[0].bar=2')).to.deep.equal({ foo: [{ baz: ['15'], bar: '2' }] }, { prototype: false });
|
|
182
|
+
expect(Qs.parse('foo[0].baz[0]=15&foo[0].baz[1]=16&foo[0].bar=2')).to.deep.equal({ foo: [{ baz: ['15', '16'], bar: '2' }] }, { prototype: false });
|
|
183
|
+
expect(Qs.parse('foo.bad=baz&foo[0]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } }, { prototype: false });
|
|
184
|
+
expect(Qs.parse('foo.bad=baz&foo[]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } }, { prototype: false });
|
|
185
|
+
expect(Qs.parse('foo[]=bar&foo.bad=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } }, { prototype: false });
|
|
186
|
+
expect(Qs.parse('foo.bad=baz&foo[]=bar&foo[]=foo')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar', '1': 'foo' } }, { prototype: false });
|
|
187
|
+
expect(Qs.parse('foo[0].a=a&foo[0].b=b&foo[1].a=aa&foo[1].b=bb')).to.deep.equal({foo: [ {a: 'a', b: 'b'}, {a: 'aa', b: 'bb'} ]}, { prototype: false });
|
|
166
188
|
done();
|
|
167
189
|
});
|
|
168
190
|
|
|
169
|
-
it('
|
|
191
|
+
it('can add keys to objects', function (done) {
|
|
170
192
|
|
|
171
|
-
expect(Qs.parse('a[
|
|
193
|
+
expect(Qs.parse('a[b]=c&a=d')).to.deep.equal({ a: { b: 'c', d: true } }, { prototype: false });
|
|
172
194
|
done();
|
|
173
195
|
});
|
|
174
196
|
|
|
175
|
-
it('
|
|
197
|
+
it('correctly prunes undefined values when converting an array to an object', function (done) {
|
|
176
198
|
|
|
177
|
-
expect(Qs.parse('
|
|
178
|
-
expect(Qs.parse('foo=%:%}')).to.deep.equal({ foo: '%:%}' });
|
|
199
|
+
expect(Qs.parse('a[2]=b&a[99999999]=c')).to.deep.equal({ a: { '2': 'b', '99999999': 'c' } }, { prototype: false });
|
|
179
200
|
done();
|
|
180
201
|
});
|
|
181
202
|
|
|
182
|
-
it('
|
|
203
|
+
it('supports malformed uri characters', function (done) {
|
|
183
204
|
|
|
184
|
-
expect(Qs.parse('
|
|
205
|
+
expect(Qs.parse('{%:%}', {strictNullHandling: true})).to.deep.equal({ '{%:%}': null }, { prototype: false });
|
|
206
|
+
expect(Qs.parse('{%:%}=')).to.deep.equal({ '{%:%}': '' }, { prototype: false });
|
|
207
|
+
expect(Qs.parse('foo=%:%}')).to.deep.equal({ foo: '%:%}' }, { prototype: false });
|
|
185
208
|
done();
|
|
186
209
|
});
|
|
187
210
|
|
|
188
|
-
it('
|
|
211
|
+
it('doesn\'t produce empty keys', function (done) {
|
|
189
212
|
|
|
190
|
-
|
|
191
|
-
expect(typeof obj.toString).to.equal('function');
|
|
192
|
-
expect(typeof obj.bad.toString).to.equal('function');
|
|
193
|
-
expect(typeof obj.constructor).to.equal('function');
|
|
213
|
+
expect(Qs.parse('_r=1&')).to.deep.equal({ '_r': '1' }, { prototype: false });
|
|
194
214
|
done();
|
|
195
215
|
});
|
|
196
216
|
|
|
@@ -204,43 +224,45 @@ describe('parse()', function () {
|
|
|
204
224
|
|
|
205
225
|
it('parses arrays of objects', function (done) {
|
|
206
226
|
|
|
207
|
-
expect(Qs.parse('a[][b]=c')).to.deep.equal({ a: [{ b: 'c' }] });
|
|
208
|
-
expect(Qs.parse('a[0][b]=c')).to.deep.equal({ a: [{ b: 'c' }] });
|
|
227
|
+
expect(Qs.parse('a[][b]=c')).to.deep.equal({ a: [{ b: 'c' }] }, { prototype: false });
|
|
228
|
+
expect(Qs.parse('a[0][b]=c')).to.deep.equal({ a: [{ b: 'c' }] }, { prototype: false });
|
|
209
229
|
done();
|
|
210
230
|
});
|
|
211
231
|
|
|
212
232
|
it('allows for empty strings in arrays', function (done) {
|
|
213
233
|
|
|
214
|
-
expect(Qs.parse('a[]=b&a[]=&a[]=c')).to.deep.equal({ a: ['b', '', 'c'] });
|
|
215
|
-
expect(Qs.parse('a[0]=b&a[1]
|
|
216
|
-
expect(Qs.parse('a[]=&a[]=
|
|
234
|
+
expect(Qs.parse('a[]=b&a[]=&a[]=c')).to.deep.equal({ a: ['b', '', 'c'] }, { prototype: false });
|
|
235
|
+
expect(Qs.parse('a[0]=b&a[1]&a[2]=c&a[19]=', {strictNullHandling: true})).to.deep.equal({ a: ['b', null, 'c', ''] }, { prototype: false });
|
|
236
|
+
expect(Qs.parse('a[0]=b&a[1]=&a[2]=c&a[19]', {strictNullHandling: true})).to.deep.equal({ a: ['b', '', 'c', null] }, { prototype: false });
|
|
237
|
+
expect(Qs.parse('a[]=&a[]=b&a[]=c')).to.deep.equal({ a: ['', 'b', 'c'] }, { prototype: false });
|
|
217
238
|
done();
|
|
218
239
|
});
|
|
219
240
|
|
|
220
241
|
it('compacts sparse arrays', function (done) {
|
|
221
242
|
|
|
222
|
-
expect(Qs.parse('a[10]=1&a[2]=2')).to.deep.equal({ a: ['2', '1'] });
|
|
243
|
+
expect(Qs.parse('a[10]=1&a[2]=2')).to.deep.equal({ a: ['2', '1'] }, { prototype: false });
|
|
223
244
|
done();
|
|
224
245
|
});
|
|
225
246
|
|
|
226
247
|
it('parses semi-parsed strings', function (done) {
|
|
227
248
|
|
|
228
|
-
expect(Qs.parse({ 'a[b]': 'c' })).to.deep.equal({ a: { b: 'c' } });
|
|
229
|
-
expect(Qs.parse({ 'a[b]': 'c', 'a[d]': 'e' })).to.deep.equal({ a: { b: 'c', d: 'e' } });
|
|
249
|
+
expect(Qs.parse({ 'a[b]': 'c' })).to.deep.equal({ a: { b: 'c' } }, { prototype: false });
|
|
250
|
+
expect(Qs.parse({ 'a[b]': 'c', 'a[d]': 'e' })).to.deep.equal({ a: { b: 'c', d: 'e' } }, { prototype: false });
|
|
230
251
|
done();
|
|
231
252
|
});
|
|
232
253
|
|
|
233
254
|
it('parses buffers correctly', function (done) {
|
|
234
255
|
|
|
235
256
|
var b = new Buffer('test');
|
|
236
|
-
expect(Qs.parse({ a: b })).to.deep.equal({ a: b });
|
|
257
|
+
expect(Qs.parse({ a: b })).to.deep.equal({ a: b }, { prototype: false });
|
|
237
258
|
done();
|
|
238
259
|
});
|
|
239
260
|
|
|
240
261
|
it('continues parsing when no parent is found', function (done) {
|
|
241
262
|
|
|
242
|
-
expect(Qs.parse('[]
|
|
243
|
-
expect(Qs.parse('[
|
|
263
|
+
expect(Qs.parse('[]=&a=b')).to.deep.equal({ '0': '', a: 'b' }, { prototype: false });
|
|
264
|
+
expect(Qs.parse('[]&a=b', {strictNullHandling: true})).to.deep.equal({ '0': null, a: 'b' }, { prototype: false });
|
|
265
|
+
expect(Qs.parse('[foo]=bar')).to.deep.equal({ foo: 'bar' }, { prototype: false });
|
|
244
266
|
done();
|
|
245
267
|
});
|
|
246
268
|
|
|
@@ -264,9 +286,9 @@ describe('parse()', function () {
|
|
|
264
286
|
Object.prototype.crash = '';
|
|
265
287
|
Array.prototype.crash = '';
|
|
266
288
|
expect(Qs.parse.bind(null, 'a=b')).to.not.throw();
|
|
267
|
-
expect(Qs.parse('a=b')).to.deep.equal({ a: 'b' });
|
|
289
|
+
expect(Qs.parse('a=b')).to.deep.equal({ a: 'b' }, { prototype: false });
|
|
268
290
|
expect(Qs.parse.bind(null, 'a[][b]=c')).to.not.throw();
|
|
269
|
-
expect(Qs.parse('a[][b]=c')).to.deep.equal({ a: [{ b: 'c' }] });
|
|
291
|
+
expect(Qs.parse('a[][b]=c')).to.deep.equal({ a: [{ b: 'c' }] }, { prototype: false });
|
|
270
292
|
delete Object.prototype.crash;
|
|
271
293
|
delete Array.prototype.crash;
|
|
272
294
|
done();
|
|
@@ -274,39 +296,45 @@ describe('parse()', function () {
|
|
|
274
296
|
|
|
275
297
|
it('parses a string with an alternative string delimiter', function (done) {
|
|
276
298
|
|
|
277
|
-
expect(Qs.parse('a=b;c=d', { delimiter: ';' })).to.deep.equal({ a: 'b', c: 'd' });
|
|
299
|
+
expect(Qs.parse('a=b;c=d', { delimiter: ';' })).to.deep.equal({ a: 'b', c: 'd' }, { prototype: false });
|
|
278
300
|
done();
|
|
279
301
|
});
|
|
280
302
|
|
|
281
303
|
it('parses a string with an alternative RegExp delimiter', function (done) {
|
|
282
304
|
|
|
283
|
-
expect(Qs.parse('a=b; c=d', { delimiter: /[;,] */ })).to.deep.equal({ a: 'b', c: 'd' });
|
|
305
|
+
expect(Qs.parse('a=b; c=d', { delimiter: /[;,] */ })).to.deep.equal({ a: 'b', c: 'd' }, { prototype: false });
|
|
284
306
|
done();
|
|
285
307
|
});
|
|
286
308
|
|
|
287
309
|
it('does not use non-splittable objects as delimiters', function (done) {
|
|
288
310
|
|
|
289
|
-
expect(Qs.parse('a=b&c=d', { delimiter: true })).to.deep.equal({ a: 'b', c: 'd' });
|
|
311
|
+
expect(Qs.parse('a=b&c=d', { delimiter: true })).to.deep.equal({ a: 'b', c: 'd' }, { prototype: false });
|
|
290
312
|
done();
|
|
291
313
|
});
|
|
292
314
|
|
|
293
315
|
it('allows overriding parameter limit', function (done) {
|
|
294
316
|
|
|
295
|
-
expect(Qs.parse('a=b&c=d', { parameterLimit: 1 })).to.deep.equal({ a: 'b' });
|
|
317
|
+
expect(Qs.parse('a=b&c=d', { parameterLimit: 1 })).to.deep.equal({ a: 'b' }, { prototype: false });
|
|
296
318
|
done();
|
|
297
319
|
});
|
|
298
320
|
|
|
299
321
|
it('allows setting the parameter limit to Infinity', function (done) {
|
|
300
322
|
|
|
301
|
-
expect(Qs.parse('a=b&c=d', { parameterLimit: Infinity })).to.deep.equal({ a: 'b', c: 'd' });
|
|
323
|
+
expect(Qs.parse('a=b&c=d', { parameterLimit: Infinity })).to.deep.equal({ a: 'b', c: 'd' }, { prototype: false });
|
|
302
324
|
done();
|
|
303
325
|
});
|
|
304
326
|
|
|
305
327
|
it('allows overriding array limit', function (done) {
|
|
306
328
|
|
|
307
|
-
expect(Qs.parse('a[0]=b', { arrayLimit: -1 })).to.deep.equal({ a: { '0': 'b' } });
|
|
308
|
-
expect(Qs.parse('a[-1]=b', { arrayLimit: -1 })).to.deep.equal({ a: { '-1': 'b' } });
|
|
309
|
-
expect(Qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 })).to.deep.equal({ a: { '0': 'b', '1': 'c' } });
|
|
329
|
+
expect(Qs.parse('a[0]=b', { arrayLimit: -1 })).to.deep.equal({ a: { '0': 'b' } }, { prototype: false });
|
|
330
|
+
expect(Qs.parse('a[-1]=b', { arrayLimit: -1 })).to.deep.equal({ a: { '-1': 'b' } }, { prototype: false });
|
|
331
|
+
expect(Qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 })).to.deep.equal({ a: { '0': 'b', '1': 'c' } }, { prototype: false });
|
|
332
|
+
done();
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('allows disabling array parsing', function (done) {
|
|
336
|
+
|
|
337
|
+
expect(Qs.parse('a[0]=b&a[1]=c', { parseArrays: false })).to.deep.equal({ a: { '0': 'b', '1': 'c' } }, { prototype: false });
|
|
310
338
|
done();
|
|
311
339
|
});
|
|
312
340
|
|
|
@@ -326,7 +354,27 @@ describe('parse()', function () {
|
|
|
326
354
|
|
|
327
355
|
var result = Qs.parse(input);
|
|
328
356
|
|
|
329
|
-
expect(result).to.deep.equal(expected);
|
|
357
|
+
expect(result).to.deep.equal(expected, { prototype: false });
|
|
358
|
+
done();
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
it('parses an object in dot notation', function (done) {
|
|
362
|
+
|
|
363
|
+
var input = {
|
|
364
|
+
'user.name': {'pop[bob]': 3},
|
|
365
|
+
'user.email.': null
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
var expected = {
|
|
369
|
+
'user': {
|
|
370
|
+
'name': {'pop[bob]': 3},
|
|
371
|
+
'email': null
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
var result = Qs.parse(input);
|
|
376
|
+
|
|
377
|
+
expect(result).to.deep.equal(expected, { prototype: false });
|
|
330
378
|
done();
|
|
331
379
|
});
|
|
332
380
|
|
|
@@ -346,7 +394,7 @@ describe('parse()', function () {
|
|
|
346
394
|
|
|
347
395
|
var result = Qs.parse(input);
|
|
348
396
|
|
|
349
|
-
expect(result).to.deep.equal(expected);
|
|
397
|
+
expect(result).to.deep.equal(expected, { prototype: false });
|
|
350
398
|
done();
|
|
351
399
|
});
|
|
352
400
|
|
|
@@ -356,13 +404,7 @@ describe('parse()', function () {
|
|
|
356
404
|
delete global.Buffer;
|
|
357
405
|
var result = Qs.parse('a=b&c=d');
|
|
358
406
|
global.Buffer = tempBuffer;
|
|
359
|
-
expect(result).to.deep.equal({ a: 'b', c: 'd' });
|
|
360
|
-
done();
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
it('does not crash when using invalid dot notation', function (done) {
|
|
364
|
-
|
|
365
|
-
expect(Qs.parse('roomInfoList[0].childrenAges[0]=15&roomInfoList[0].numberOfAdults=2')).to.deep.equal({ roomInfoList: [['15', '2']] });
|
|
407
|
+
expect(result).to.deep.equal({ a: 'b', c: 'd' }, { prototype: false });
|
|
366
408
|
done();
|
|
367
409
|
});
|
|
368
410
|
|
|
@@ -381,7 +423,7 @@ describe('parse()', function () {
|
|
|
381
423
|
expect(parsed).to.contain('foo');
|
|
382
424
|
expect(parsed.foo).to.contain('bar', 'baz');
|
|
383
425
|
expect(parsed.foo.bar).to.equal('baz');
|
|
384
|
-
expect(parsed.foo.baz).to.deep.equal(a);
|
|
426
|
+
expect(parsed.foo.baz).to.deep.equal(a, { prototype: false });
|
|
385
427
|
done();
|
|
386
428
|
});
|
|
387
429
|
|
|
@@ -390,24 +432,24 @@ describe('parse()', function () {
|
|
|
390
432
|
var a = Object.create(null);
|
|
391
433
|
a.b = 'c';
|
|
392
434
|
|
|
393
|
-
expect(Qs.parse(a)).to.deep.equal({ b: 'c' });
|
|
435
|
+
expect(Qs.parse(a)).to.deep.equal({ b: 'c' }, { prototype: false });
|
|
394
436
|
var result = Qs.parse({ a: a });
|
|
395
437
|
expect(result).to.contain('a');
|
|
396
|
-
expect(result.a).to.deep.equal(a);
|
|
438
|
+
expect(result.a).to.deep.equal(a, { prototype: false });
|
|
397
439
|
done();
|
|
398
440
|
});
|
|
399
441
|
|
|
400
442
|
it('parses dates correctly', function (done) {
|
|
401
443
|
|
|
402
444
|
var now = new Date();
|
|
403
|
-
expect(Qs.parse({ a: now })).to.deep.equal({ a: now });
|
|
445
|
+
expect(Qs.parse({ a: now })).to.deep.equal({ a: now }, { prototype: false });
|
|
404
446
|
done();
|
|
405
447
|
});
|
|
406
448
|
|
|
407
449
|
it('parses regular expressions correctly', function (done) {
|
|
408
450
|
|
|
409
451
|
var re = /^test$/;
|
|
410
|
-
expect(Qs.parse({ a: re })).to.deep.equal({ a: re });
|
|
452
|
+
expect(Qs.parse({ a: re })).to.deep.equal({ a: re }, { prototype: false });
|
|
411
453
|
done();
|
|
412
454
|
});
|
|
413
455
|
});
|
package/test/stringify.js
CHANGED
|
@@ -26,6 +26,11 @@ describe('stringify()', function () {
|
|
|
26
26
|
expect(Qs.stringify({ a: 'b' })).to.equal('a=b');
|
|
27
27
|
expect(Qs.stringify({ a: 1 })).to.equal('a=1');
|
|
28
28
|
expect(Qs.stringify({ a: 1, b: 2 })).to.equal('a=1&b=2');
|
|
29
|
+
expect(Qs.stringify({ a: 'A_Z' })).to.equal('a=A_Z');
|
|
30
|
+
expect(Qs.stringify({ a: '€' })).to.equal('a=%E2%82%AC');
|
|
31
|
+
expect(Qs.stringify({ a: '' })).to.equal('a=%EE%80%80');
|
|
32
|
+
expect(Qs.stringify({ a: 'א' })).to.equal('a=%D7%90');
|
|
33
|
+
expect(Qs.stringify({ a: '𐐷' })).to.equal('a=%F0%90%90%B7');
|
|
29
34
|
done();
|
|
30
35
|
});
|
|
31
36
|
|
|
@@ -106,9 +111,15 @@ describe('stringify()', function () {
|
|
|
106
111
|
it('stringifies an empty value', function (done) {
|
|
107
112
|
|
|
108
113
|
expect(Qs.stringify({ a: '' })).to.equal('a=');
|
|
114
|
+
expect(Qs.stringify({ a: null }, {strictNullHandling: true})).to.equal('a');
|
|
115
|
+
|
|
109
116
|
expect(Qs.stringify({ a: '', b: '' })).to.equal('a=&b=');
|
|
110
|
-
expect(Qs.stringify({ a: null })).to.equal('a=');
|
|
111
|
-
|
|
117
|
+
expect(Qs.stringify({ a: null, b: '' }, {strictNullHandling: true})).to.equal('a&b=');
|
|
118
|
+
|
|
119
|
+
expect(Qs.stringify({ a: { b: '' } })).to.equal('a%5Bb%5D=');
|
|
120
|
+
expect(Qs.stringify({ a: { b: null } }, {strictNullHandling: true})).to.equal('a%5Bb%5D');
|
|
121
|
+
expect(Qs.stringify({ a: { b: null } }, {strictNullHandling: false})).to.equal('a%5Bb%5D=');
|
|
122
|
+
|
|
112
123
|
done();
|
|
113
124
|
});
|
|
114
125
|
|
|
@@ -143,7 +154,10 @@ describe('stringify()', function () {
|
|
|
143
154
|
it('drops keys with a value of undefined', function (done) {
|
|
144
155
|
|
|
145
156
|
expect(Qs.stringify({ a: undefined })).to.equal('');
|
|
146
|
-
|
|
157
|
+
|
|
158
|
+
expect(Qs.stringify({ a: { b: undefined, c: null } }, {strictNullHandling: true})).to.equal('a%5Bc%5D');
|
|
159
|
+
expect(Qs.stringify({ a: { b: undefined, c: null } }, {strictNullHandling: false})).to.equal('a%5Bc%5D=');
|
|
160
|
+
expect(Qs.stringify({ a: { b: undefined, c: '' } })).to.equal('a%5Bc%5D=');
|
|
147
161
|
done();
|
|
148
162
|
});
|
|
149
163
|
|
|
@@ -163,7 +177,7 @@ describe('stringify()', function () {
|
|
|
163
177
|
|
|
164
178
|
it('stringifies the weird object from qs', function (done) {
|
|
165
179
|
|
|
166
|
-
expect(Qs.stringify({ 'my weird field': 'q1!2"\'w$5&7/z8)?' })).to.equal('my%20weird%20field
|
|
180
|
+
expect(Qs.stringify({ 'my weird field': '~q1!2"\'w$5&7/z8)?' })).to.equal('my%20weird%20field=~q1%212%22%27w%245%267%2Fz8%29%3F');
|
|
167
181
|
done();
|
|
168
182
|
});
|
|
169
183
|
|
|
@@ -206,4 +220,40 @@ describe('stringify()', function () {
|
|
|
206
220
|
global.Buffer = tempBuffer;
|
|
207
221
|
done();
|
|
208
222
|
});
|
|
223
|
+
|
|
224
|
+
it('selects properties when filter=array', function (done) {
|
|
225
|
+
|
|
226
|
+
expect(Qs.stringify({ a: 'b' }, { filter: ['a'] })).to.equal('a=b');
|
|
227
|
+
expect(Qs.stringify({ a: 1}, { filter: [] })).to.equal('');
|
|
228
|
+
expect(Qs.stringify({ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' }, { filter: ['a', 'b', 0, 2]})).to.equal('a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3');
|
|
229
|
+
done();
|
|
230
|
+
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('supports custom representations when filter=function', function (done) {
|
|
234
|
+
|
|
235
|
+
var calls = 0;
|
|
236
|
+
var obj = { a: 'b', c: 'd', e: { f: new Date(1257894000000) } };
|
|
237
|
+
var filterFunc = function (prefix, value) {
|
|
238
|
+
|
|
239
|
+
calls++;
|
|
240
|
+
if (calls === 1) {
|
|
241
|
+
expect(prefix).to.be.empty();
|
|
242
|
+
expect(value).to.equal(obj);
|
|
243
|
+
}
|
|
244
|
+
else if (prefix === 'c') {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
else if (value instanceof Date) {
|
|
248
|
+
expect(prefix).to.equal('e[f]');
|
|
249
|
+
return value.getTime();
|
|
250
|
+
}
|
|
251
|
+
return value;
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
expect(Qs.stringify(obj, { filter: filterFunc })).to.equal('a=b&e%5Bf%5D=1257894000000');
|
|
255
|
+
expect(calls).to.equal(5);
|
|
256
|
+
done();
|
|
257
|
+
|
|
258
|
+
});
|
|
209
259
|
});
|
package/test/utils.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Load modules
|
|
2
|
+
|
|
3
|
+
var Code = require('code');
|
|
4
|
+
var Lab = require('lab');
|
|
5
|
+
var Utils = require('../lib/utils');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
// Declare internals
|
|
9
|
+
|
|
10
|
+
var internals = {};
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
// Test shortcuts
|
|
14
|
+
|
|
15
|
+
var lab = exports.lab = Lab.script();
|
|
16
|
+
var expect = Code.expect;
|
|
17
|
+
var describe = lab.experiment;
|
|
18
|
+
var it = lab.test;
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
describe('merge()', function () {
|
|
22
|
+
|
|
23
|
+
it('can merge two objects with the same key', function (done) {
|
|
24
|
+
|
|
25
|
+
expect(Utils.merge({ a: 'b' }, { a: 'c' })).to.deep.equal({ a: ['b', 'c'] });
|
|
26
|
+
done();
|
|
27
|
+
});
|
|
28
|
+
});
|