qs 6.13.0 → 6.14.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/.eslintrc +1 -0
- package/CHANGELOG.md +22 -0
- package/README.md +25 -1
- package/dist/qs.js +95 -44
- package/lib/parse.js +44 -12
- package/lib/stringify.js +11 -6
- package/lib/utils.js +7 -4
- package/package.json +9 -7
- package/test/parse.js +133 -27
- package/test/stringify.js +19 -11
- package/test/utils.js +126 -0
package/lib/parse.js
CHANGED
|
@@ -25,7 +25,8 @@ var defaults = {
|
|
|
25
25
|
parseArrays: true,
|
|
26
26
|
plainObjects: false,
|
|
27
27
|
strictDepth: false,
|
|
28
|
-
strictNullHandling: false
|
|
28
|
+
strictNullHandling: false,
|
|
29
|
+
throwOnLimitExceeded: false
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
var interpretNumericEntities = function (str) {
|
|
@@ -34,11 +35,15 @@ var interpretNumericEntities = function (str) {
|
|
|
34
35
|
});
|
|
35
36
|
};
|
|
36
37
|
|
|
37
|
-
var parseArrayValue = function (val, options) {
|
|
38
|
+
var parseArrayValue = function (val, options, currentArrayLength) {
|
|
38
39
|
if (val && typeof val === 'string' && options.comma && val.indexOf(',') > -1) {
|
|
39
40
|
return val.split(',');
|
|
40
41
|
}
|
|
41
42
|
|
|
43
|
+
if (options.throwOnLimitExceeded && currentArrayLength >= options.arrayLimit) {
|
|
44
|
+
throw new RangeError('Array limit exceeded. Only ' + options.arrayLimit + ' element' + (options.arrayLimit === 1 ? '' : 's') + ' allowed in an array.');
|
|
45
|
+
}
|
|
46
|
+
|
|
42
47
|
return val;
|
|
43
48
|
};
|
|
44
49
|
|
|
@@ -57,8 +62,17 @@ var parseValues = function parseQueryStringValues(str, options) {
|
|
|
57
62
|
|
|
58
63
|
var cleanStr = options.ignoreQueryPrefix ? str.replace(/^\?/, '') : str;
|
|
59
64
|
cleanStr = cleanStr.replace(/%5B/gi, '[').replace(/%5D/gi, ']');
|
|
65
|
+
|
|
60
66
|
var limit = options.parameterLimit === Infinity ? undefined : options.parameterLimit;
|
|
61
|
-
var parts = cleanStr.split(
|
|
67
|
+
var parts = cleanStr.split(
|
|
68
|
+
options.delimiter,
|
|
69
|
+
options.throwOnLimitExceeded ? limit + 1 : limit
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
if (options.throwOnLimitExceeded && parts.length > limit) {
|
|
73
|
+
throw new RangeError('Parameter limit exceeded. Only ' + limit + ' parameter' + (limit === 1 ? '' : 's') + ' allowed.');
|
|
74
|
+
}
|
|
75
|
+
|
|
62
76
|
var skipIndex = -1; // Keep track of where the utf8 sentinel was found
|
|
63
77
|
var i;
|
|
64
78
|
|
|
@@ -86,14 +100,20 @@ var parseValues = function parseQueryStringValues(str, options) {
|
|
|
86
100
|
var bracketEqualsPos = part.indexOf(']=');
|
|
87
101
|
var pos = bracketEqualsPos === -1 ? part.indexOf('=') : bracketEqualsPos + 1;
|
|
88
102
|
|
|
89
|
-
var key
|
|
103
|
+
var key;
|
|
104
|
+
var val;
|
|
90
105
|
if (pos === -1) {
|
|
91
106
|
key = options.decoder(part, defaults.decoder, charset, 'key');
|
|
92
107
|
val = options.strictNullHandling ? null : '';
|
|
93
108
|
} else {
|
|
94
109
|
key = options.decoder(part.slice(0, pos), defaults.decoder, charset, 'key');
|
|
110
|
+
|
|
95
111
|
val = utils.maybeMap(
|
|
96
|
-
parseArrayValue(
|
|
112
|
+
parseArrayValue(
|
|
113
|
+
part.slice(pos + 1),
|
|
114
|
+
options,
|
|
115
|
+
isArray(obj[key]) ? obj[key].length : 0
|
|
116
|
+
),
|
|
97
117
|
function (encodedVal) {
|
|
98
118
|
return options.decoder(encodedVal, defaults.decoder, charset, 'value');
|
|
99
119
|
}
|
|
@@ -101,7 +121,7 @@ var parseValues = function parseQueryStringValues(str, options) {
|
|
|
101
121
|
}
|
|
102
122
|
|
|
103
123
|
if (val && options.interpretNumericEntities && charset === 'iso-8859-1') {
|
|
104
|
-
val = interpretNumericEntities(val);
|
|
124
|
+
val = interpretNumericEntities(String(val));
|
|
105
125
|
}
|
|
106
126
|
|
|
107
127
|
if (part.indexOf('[]=') > -1) {
|
|
@@ -120,7 +140,13 @@ var parseValues = function parseQueryStringValues(str, options) {
|
|
|
120
140
|
};
|
|
121
141
|
|
|
122
142
|
var parseObject = function (chain, val, options, valuesParsed) {
|
|
123
|
-
var
|
|
143
|
+
var currentArrayLength = 0;
|
|
144
|
+
if (chain.length > 0 && chain[chain.length - 1] === '[]') {
|
|
145
|
+
var parentKey = chain.slice(0, -1).join('');
|
|
146
|
+
currentArrayLength = Array.isArray(val) && val[parentKey] ? val[parentKey].length : 0;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
var leaf = valuesParsed ? val : parseArrayValue(val, options, currentArrayLength);
|
|
124
150
|
|
|
125
151
|
for (var i = chain.length - 1; i >= 0; --i) {
|
|
126
152
|
var obj;
|
|
@@ -129,9 +155,9 @@ var parseObject = function (chain, val, options, valuesParsed) {
|
|
|
129
155
|
if (root === '[]' && options.parseArrays) {
|
|
130
156
|
obj = options.allowEmptyArrays && (leaf === '' || (options.strictNullHandling && leaf === null))
|
|
131
157
|
? []
|
|
132
|
-
: []
|
|
158
|
+
: utils.combine([], leaf);
|
|
133
159
|
} else {
|
|
134
|
-
obj = options.plainObjects ?
|
|
160
|
+
obj = options.plainObjects ? { __proto__: null } : {};
|
|
135
161
|
var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
|
|
136
162
|
var decodedRoot = options.decodeDotInKeys ? cleanRoot.replace(/%2E/g, '.') : cleanRoot;
|
|
137
163
|
var index = parseInt(decodedRoot, 10);
|
|
@@ -234,6 +260,11 @@ var normalizeParseOptions = function normalizeParseOptions(opts) {
|
|
|
234
260
|
if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') {
|
|
235
261
|
throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined');
|
|
236
262
|
}
|
|
263
|
+
|
|
264
|
+
if (typeof opts.throwOnLimitExceeded !== 'undefined' && typeof opts.throwOnLimitExceeded !== 'boolean') {
|
|
265
|
+
throw new TypeError('`throwOnLimitExceeded` option must be a boolean');
|
|
266
|
+
}
|
|
267
|
+
|
|
237
268
|
var charset = typeof opts.charset === 'undefined' ? defaults.charset : opts.charset;
|
|
238
269
|
|
|
239
270
|
var duplicates = typeof opts.duplicates === 'undefined' ? defaults.duplicates : opts.duplicates;
|
|
@@ -265,7 +296,8 @@ var normalizeParseOptions = function normalizeParseOptions(opts) {
|
|
|
265
296
|
parseArrays: opts.parseArrays !== false,
|
|
266
297
|
plainObjects: typeof opts.plainObjects === 'boolean' ? opts.plainObjects : defaults.plainObjects,
|
|
267
298
|
strictDepth: typeof opts.strictDepth === 'boolean' ? !!opts.strictDepth : defaults.strictDepth,
|
|
268
|
-
strictNullHandling: typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults.strictNullHandling
|
|
299
|
+
strictNullHandling: typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults.strictNullHandling,
|
|
300
|
+
throwOnLimitExceeded: typeof opts.throwOnLimitExceeded === 'boolean' ? opts.throwOnLimitExceeded : false
|
|
269
301
|
};
|
|
270
302
|
};
|
|
271
303
|
|
|
@@ -273,11 +305,11 @@ module.exports = function (str, opts) {
|
|
|
273
305
|
var options = normalizeParseOptions(opts);
|
|
274
306
|
|
|
275
307
|
if (str === '' || str === null || typeof str === 'undefined') {
|
|
276
|
-
return options.plainObjects ?
|
|
308
|
+
return options.plainObjects ? { __proto__: null } : {};
|
|
277
309
|
}
|
|
278
310
|
|
|
279
311
|
var tempObj = typeof str === 'string' ? parseValues(str, options) : str;
|
|
280
|
-
var obj = options.plainObjects ?
|
|
312
|
+
var obj = options.plainObjects ? { __proto__: null } : {};
|
|
281
313
|
|
|
282
314
|
// Iterate over the keys and setup the new object
|
|
283
315
|
|
package/lib/stringify.js
CHANGED
|
@@ -34,11 +34,13 @@ var defaults = {
|
|
|
34
34
|
arrayFormat: 'indices',
|
|
35
35
|
charset: 'utf-8',
|
|
36
36
|
charsetSentinel: false,
|
|
37
|
+
commaRoundTrip: false,
|
|
37
38
|
delimiter: '&',
|
|
38
39
|
encode: true,
|
|
39
40
|
encodeDotInKeys: false,
|
|
40
41
|
encoder: utils.encode,
|
|
41
42
|
encodeValuesOnly: false,
|
|
43
|
+
filter: void undefined,
|
|
42
44
|
format: defaultFormat,
|
|
43
45
|
formatter: formats.formatters[defaultFormat],
|
|
44
46
|
// deprecated
|
|
@@ -150,7 +152,7 @@ var stringify = function stringify(
|
|
|
150
152
|
objKeys = sort ? keys.sort(sort) : keys;
|
|
151
153
|
}
|
|
152
154
|
|
|
153
|
-
var encodedPrefix = encodeDotInKeys ? prefix.replace(/\./g, '%2E') : prefix;
|
|
155
|
+
var encodedPrefix = encodeDotInKeys ? String(prefix).replace(/\./g, '%2E') : String(prefix);
|
|
154
156
|
|
|
155
157
|
var adjustedPrefix = commaRoundTrip && isArray(obj) && obj.length === 1 ? encodedPrefix + '[]' : encodedPrefix;
|
|
156
158
|
|
|
@@ -160,13 +162,15 @@ var stringify = function stringify(
|
|
|
160
162
|
|
|
161
163
|
for (var j = 0; j < objKeys.length; ++j) {
|
|
162
164
|
var key = objKeys[j];
|
|
163
|
-
var value = typeof key === 'object' && typeof key.value !== 'undefined'
|
|
165
|
+
var value = typeof key === 'object' && key && typeof key.value !== 'undefined'
|
|
166
|
+
? key.value
|
|
167
|
+
: obj[key];
|
|
164
168
|
|
|
165
169
|
if (skipNulls && value === null) {
|
|
166
170
|
continue;
|
|
167
171
|
}
|
|
168
172
|
|
|
169
|
-
var encodedKey = allowDots && encodeDotInKeys ? key.replace(/\./g, '%2E') : key;
|
|
173
|
+
var encodedKey = allowDots && encodeDotInKeys ? String(key).replace(/\./g, '%2E') : String(key);
|
|
170
174
|
var keyPrefix = isArray(obj)
|
|
171
175
|
? typeof generateArrayPrefix === 'function' ? generateArrayPrefix(adjustedPrefix, encodedKey) : adjustedPrefix
|
|
172
176
|
: adjustedPrefix + (allowDots ? '.' + encodedKey : '[' + encodedKey + ']');
|
|
@@ -257,7 +261,7 @@ var normalizeStringifyOptions = function normalizeStringifyOptions(opts) {
|
|
|
257
261
|
arrayFormat: arrayFormat,
|
|
258
262
|
charset: charset,
|
|
259
263
|
charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel,
|
|
260
|
-
commaRoundTrip: opts.commaRoundTrip,
|
|
264
|
+
commaRoundTrip: !!opts.commaRoundTrip,
|
|
261
265
|
delimiter: typeof opts.delimiter === 'undefined' ? defaults.delimiter : opts.delimiter,
|
|
262
266
|
encode: typeof opts.encode === 'boolean' ? opts.encode : defaults.encode,
|
|
263
267
|
encodeDotInKeys: typeof opts.encodeDotInKeys === 'boolean' ? opts.encodeDotInKeys : defaults.encodeDotInKeys,
|
|
@@ -308,12 +312,13 @@ module.exports = function (object, opts) {
|
|
|
308
312
|
var sideChannel = getSideChannel();
|
|
309
313
|
for (var i = 0; i < objKeys.length; ++i) {
|
|
310
314
|
var key = objKeys[i];
|
|
315
|
+
var value = obj[key];
|
|
311
316
|
|
|
312
|
-
if (options.skipNulls &&
|
|
317
|
+
if (options.skipNulls && value === null) {
|
|
313
318
|
continue;
|
|
314
319
|
}
|
|
315
320
|
pushToArray(keys, stringify(
|
|
316
|
-
|
|
321
|
+
value,
|
|
317
322
|
key,
|
|
318
323
|
generateArrayPrefix,
|
|
319
324
|
commaRoundTrip,
|
package/lib/utils.js
CHANGED
|
@@ -34,7 +34,7 @@ var compactQueue = function compactQueue(queue) {
|
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
var arrayToObject = function arrayToObject(source, options) {
|
|
37
|
-
var obj = options && options.plainObjects ?
|
|
37
|
+
var obj = options && options.plainObjects ? { __proto__: null } : {};
|
|
38
38
|
for (var i = 0; i < source.length; ++i) {
|
|
39
39
|
if (typeof source[i] !== 'undefined') {
|
|
40
40
|
obj[i] = source[i];
|
|
@@ -50,11 +50,14 @@ var merge = function merge(target, source, options) {
|
|
|
50
50
|
return target;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
if (typeof source !== 'object') {
|
|
53
|
+
if (typeof source !== 'object' && typeof source !== 'function') {
|
|
54
54
|
if (isArray(target)) {
|
|
55
55
|
target.push(source);
|
|
56
56
|
} else if (target && typeof target === 'object') {
|
|
57
|
-
if (
|
|
57
|
+
if (
|
|
58
|
+
(options && (options.plainObjects || options.allowPrototypes))
|
|
59
|
+
|| !has.call(Object.prototype, source)
|
|
60
|
+
) {
|
|
58
61
|
target[source] = true;
|
|
59
62
|
}
|
|
60
63
|
} else {
|
|
@@ -108,7 +111,7 @@ var assign = function assignSingleSource(target, source) {
|
|
|
108
111
|
}, target);
|
|
109
112
|
};
|
|
110
113
|
|
|
111
|
-
var decode = function (str,
|
|
114
|
+
var decode = function (str, defaultDecoder, charset) {
|
|
112
115
|
var strWithoutPlus = str.replace(/\+/g, ' ');
|
|
113
116
|
if (charset === 'iso-8859-1') {
|
|
114
117
|
// unescape never throws, no try...catch needed:
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "qs",
|
|
3
3
|
"description": "A querystring parser that supports nesting and arrays, with a depth limit",
|
|
4
4
|
"homepage": "https://github.com/ljharb/qs",
|
|
5
|
-
"version": "6.
|
|
5
|
+
"version": "6.14.0",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "https://github.com/ljharb/qs.git"
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"node": ">=0.6"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"side-channel": "^1.0
|
|
34
|
+
"side-channel": "^1.1.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@browserify/envify": "^6.0.0",
|
|
@@ -41,27 +41,29 @@
|
|
|
41
41
|
"bundle-collapser": "^1.4.0",
|
|
42
42
|
"common-shakeify": "~1.0.0",
|
|
43
43
|
"eclint": "^2.8.1",
|
|
44
|
-
"es-value-fixtures": "^1.
|
|
44
|
+
"es-value-fixtures": "^1.7.0",
|
|
45
45
|
"eslint": "=8.8.0",
|
|
46
46
|
"evalmd": "^0.0.19",
|
|
47
47
|
"for-each": "^0.3.3",
|
|
48
48
|
"glob": "=10.3.7",
|
|
49
|
+
"has-bigints": "^1.1.0",
|
|
49
50
|
"has-override-mistake": "^1.0.1",
|
|
50
51
|
"has-property-descriptors": "^1.0.2",
|
|
51
|
-
"has-
|
|
52
|
+
"has-proto": "^1.2.0",
|
|
53
|
+
"has-symbols": "^1.1.0",
|
|
52
54
|
"iconv-lite": "^0.5.1",
|
|
53
55
|
"in-publish": "^2.0.1",
|
|
54
56
|
"jackspeak": "=2.1.1",
|
|
55
57
|
"mkdirp": "^0.5.5",
|
|
56
|
-
"mock-property": "^1.0
|
|
58
|
+
"mock-property": "^1.1.0",
|
|
57
59
|
"module-deps": "^6.2.3",
|
|
58
60
|
"npmignore": "^0.3.1",
|
|
59
61
|
"nyc": "^10.3.2",
|
|
60
|
-
"object-inspect": "^1.13.
|
|
62
|
+
"object-inspect": "^1.13.3",
|
|
61
63
|
"qs-iconv": "^1.0.4",
|
|
62
64
|
"safe-publish-latest": "^2.0.0",
|
|
63
65
|
"safer-buffer": "^2.1.2",
|
|
64
|
-
"tape": "^5.
|
|
66
|
+
"tape": "^5.9.0",
|
|
65
67
|
"unassertify": "^3.0.1"
|
|
66
68
|
},
|
|
67
69
|
"scripts": {
|
package/test/parse.js
CHANGED
|
@@ -9,6 +9,7 @@ var SaferBuffer = require('safer-buffer').Buffer;
|
|
|
9
9
|
var v = require('es-value-fixtures');
|
|
10
10
|
var inspect = require('object-inspect');
|
|
11
11
|
var emptyTestCases = require('./empty-keys-cases').emptyTestCases;
|
|
12
|
+
var hasProto = require('has-proto')();
|
|
12
13
|
|
|
13
14
|
var qs = require('../');
|
|
14
15
|
var utils = require('../lib/utils');
|
|
@@ -117,7 +118,7 @@ test('parse()', function (t) {
|
|
|
117
118
|
st.end();
|
|
118
119
|
});
|
|
119
120
|
|
|
120
|
-
t.test('
|
|
121
|
+
t.test('decodes dot in key of object, and allow enabling dot notation when decodeDotInKeys is set to true and allowDots is undefined', function (st) {
|
|
121
122
|
st.deepEqual(
|
|
122
123
|
qs.parse(
|
|
123
124
|
'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe',
|
|
@@ -130,7 +131,7 @@ test('parse()', function (t) {
|
|
|
130
131
|
st.end();
|
|
131
132
|
});
|
|
132
133
|
|
|
133
|
-
t.test('
|
|
134
|
+
t.test('throws when decodeDotInKeys is not of type boolean', function (st) {
|
|
134
135
|
st['throws'](
|
|
135
136
|
function () { qs.parse('foo[]&bar=baz', { decodeDotInKeys: 'foobar' }); },
|
|
136
137
|
TypeError
|
|
@@ -160,7 +161,7 @@ test('parse()', function (t) {
|
|
|
160
161
|
st.end();
|
|
161
162
|
});
|
|
162
163
|
|
|
163
|
-
t.test('
|
|
164
|
+
t.test('throws when allowEmptyArrays is not of type boolean', function (st) {
|
|
164
165
|
st['throws'](
|
|
165
166
|
function () { qs.parse('foo[]&bar=baz', { allowEmptyArrays: 'foobar' }); },
|
|
166
167
|
TypeError
|
|
@@ -443,7 +444,7 @@ test('parse()', function (t) {
|
|
|
443
444
|
st.end();
|
|
444
445
|
});
|
|
445
446
|
|
|
446
|
-
t.test('
|
|
447
|
+
t.test('does not throw when a native prototype has an enumerable property', function (st) {
|
|
447
448
|
st.intercept(Object.prototype, 'crash', { value: '' });
|
|
448
449
|
st.intercept(Array.prototype, 'crash', { value: '' });
|
|
449
450
|
|
|
@@ -691,9 +692,8 @@ test('parse()', function (t) {
|
|
|
691
692
|
st.end();
|
|
692
693
|
});
|
|
693
694
|
|
|
694
|
-
t.test('parses null objects correctly', { skip: !
|
|
695
|
-
var a =
|
|
696
|
-
a.b = 'c';
|
|
695
|
+
t.test('parses null objects correctly', { skip: !hasProto }, function (st) {
|
|
696
|
+
var a = { __proto__: null, b: 'c' };
|
|
697
697
|
|
|
698
698
|
st.deepEqual(qs.parse(a), { b: 'c' });
|
|
699
699
|
var result = qs.parse({ a: a });
|
|
@@ -870,17 +870,25 @@ test('parse()', function (t) {
|
|
|
870
870
|
st.end();
|
|
871
871
|
});
|
|
872
872
|
|
|
873
|
-
t.test('can return null objects', { skip: !
|
|
874
|
-
var expected =
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
873
|
+
t.test('can return null objects', { skip: !hasProto }, function (st) {
|
|
874
|
+
var expected = {
|
|
875
|
+
__proto__: null,
|
|
876
|
+
a: {
|
|
877
|
+
__proto__: null,
|
|
878
|
+
b: 'c',
|
|
879
|
+
hasOwnProperty: 'd'
|
|
880
|
+
}
|
|
881
|
+
};
|
|
878
882
|
st.deepEqual(qs.parse('a[b]=c&a[hasOwnProperty]=d', { plainObjects: true }), expected);
|
|
879
|
-
st.deepEqual(qs.parse(null, { plainObjects: true }),
|
|
880
|
-
var expectedArray =
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
883
|
+
st.deepEqual(qs.parse(null, { plainObjects: true }), { __proto__: null });
|
|
884
|
+
var expectedArray = {
|
|
885
|
+
__proto__: null,
|
|
886
|
+
a: {
|
|
887
|
+
__proto__: null,
|
|
888
|
+
0: 'b',
|
|
889
|
+
c: 'd'
|
|
890
|
+
}
|
|
891
|
+
};
|
|
884
892
|
st.deepEqual(qs.parse('a[]=b&a[c]=d', { plainObjects: true }), expectedArray);
|
|
885
893
|
st.end();
|
|
886
894
|
});
|
|
@@ -957,7 +965,7 @@ test('parse()', function (t) {
|
|
|
957
965
|
st.end();
|
|
958
966
|
});
|
|
959
967
|
|
|
960
|
-
t.test('
|
|
968
|
+
t.test('ignores an utf8 sentinel with an unknown value', function (st) {
|
|
961
969
|
st.deepEqual(qs.parse('utf8=foo&' + urlEncodedOSlashInUtf8 + '=' + urlEncodedOSlashInUtf8, { charsetSentinel: true, charset: 'utf-8' }), { ø: 'ø' });
|
|
962
970
|
st.end();
|
|
963
971
|
});
|
|
@@ -998,6 +1006,15 @@ test('parse()', function (t) {
|
|
|
998
1006
|
st.end();
|
|
999
1007
|
});
|
|
1000
1008
|
|
|
1009
|
+
t.test('interpretNumericEntities with comma:true and iso charset does not crash', function (st) {
|
|
1010
|
+
st.deepEqual(
|
|
1011
|
+
qs.parse('b&a[]=1,' + urlEncodedNumSmiley, { comma: true, charset: 'iso-8859-1', interpretNumericEntities: true }),
|
|
1012
|
+
{ b: '', a: ['1,☺'] }
|
|
1013
|
+
);
|
|
1014
|
+
|
|
1015
|
+
st.end();
|
|
1016
|
+
});
|
|
1017
|
+
|
|
1001
1018
|
t.test('does not interpret %uXXXX syntax in iso-8859-1 mode', function (st) {
|
|
1002
1019
|
st.deepEqual(qs.parse('%u263A=%u263A', { charset: 'iso-8859-1' }), { '%u263A': '%u263A' });
|
|
1003
1020
|
st.end();
|
|
@@ -1018,6 +1035,95 @@ test('parse()', function (t) {
|
|
|
1018
1035
|
st.end();
|
|
1019
1036
|
});
|
|
1020
1037
|
|
|
1038
|
+
t.test('parameter limit tests', function (st) {
|
|
1039
|
+
st.test('does not throw error when within parameter limit', function (sst) {
|
|
1040
|
+
var result = qs.parse('a=1&b=2&c=3', { parameterLimit: 5, throwOnLimitExceeded: true });
|
|
1041
|
+
sst.deepEqual(result, { a: '1', b: '2', c: '3' }, 'parses without errors');
|
|
1042
|
+
sst.end();
|
|
1043
|
+
});
|
|
1044
|
+
|
|
1045
|
+
st.test('throws error when throwOnLimitExceeded is present but not boolean', function (sst) {
|
|
1046
|
+
sst['throws'](
|
|
1047
|
+
function () {
|
|
1048
|
+
qs.parse('a=1&b=2&c=3&d=4&e=5&f=6', { parameterLimit: 3, throwOnLimitExceeded: 'true' });
|
|
1049
|
+
},
|
|
1050
|
+
new TypeError('`throwOnLimitExceeded` option must be a boolean'),
|
|
1051
|
+
'throws error when throwOnLimitExceeded is present and not boolean'
|
|
1052
|
+
);
|
|
1053
|
+
sst.end();
|
|
1054
|
+
});
|
|
1055
|
+
|
|
1056
|
+
st.test('throws error when parameter limit exceeded', function (sst) {
|
|
1057
|
+
sst['throws'](
|
|
1058
|
+
function () {
|
|
1059
|
+
qs.parse('a=1&b=2&c=3&d=4&e=5&f=6', { parameterLimit: 3, throwOnLimitExceeded: true });
|
|
1060
|
+
},
|
|
1061
|
+
new RangeError('Parameter limit exceeded. Only 3 parameters allowed.'),
|
|
1062
|
+
'throws error when parameter limit is exceeded'
|
|
1063
|
+
);
|
|
1064
|
+
sst.end();
|
|
1065
|
+
});
|
|
1066
|
+
|
|
1067
|
+
st.test('silently truncates when throwOnLimitExceeded is not given', function (sst) {
|
|
1068
|
+
var result = qs.parse('a=1&b=2&c=3&d=4&e=5', { parameterLimit: 3 });
|
|
1069
|
+
sst.deepEqual(result, { a: '1', b: '2', c: '3' }, 'parses and truncates silently');
|
|
1070
|
+
sst.end();
|
|
1071
|
+
});
|
|
1072
|
+
|
|
1073
|
+
st.test('silently truncates when parameter limit exceeded without error', function (sst) {
|
|
1074
|
+
var result = qs.parse('a=1&b=2&c=3&d=4&e=5', { parameterLimit: 3, throwOnLimitExceeded: false });
|
|
1075
|
+
sst.deepEqual(result, { a: '1', b: '2', c: '3' }, 'parses and truncates silently');
|
|
1076
|
+
sst.end();
|
|
1077
|
+
});
|
|
1078
|
+
|
|
1079
|
+
st.test('allows unlimited parameters when parameterLimit set to Infinity', function (sst) {
|
|
1080
|
+
var result = qs.parse('a=1&b=2&c=3&d=4&e=5&f=6', { parameterLimit: Infinity });
|
|
1081
|
+
sst.deepEqual(result, { a: '1', b: '2', c: '3', d: '4', e: '5', f: '6' }, 'parses all parameters without truncation');
|
|
1082
|
+
sst.end();
|
|
1083
|
+
});
|
|
1084
|
+
|
|
1085
|
+
st.end();
|
|
1086
|
+
});
|
|
1087
|
+
|
|
1088
|
+
t.test('array limit tests', function (st) {
|
|
1089
|
+
st.test('does not throw error when array is within limit', function (sst) {
|
|
1090
|
+
var result = qs.parse('a[]=1&a[]=2&a[]=3', { arrayLimit: 5, throwOnLimitExceeded: true });
|
|
1091
|
+
sst.deepEqual(result, { a: ['1', '2', '3'] }, 'parses array without errors');
|
|
1092
|
+
sst.end();
|
|
1093
|
+
});
|
|
1094
|
+
|
|
1095
|
+
st.test('throws error when throwOnLimitExceeded is present but not boolean for array limit', function (sst) {
|
|
1096
|
+
sst['throws'](
|
|
1097
|
+
function () {
|
|
1098
|
+
qs.parse('a[]=1&a[]=2&a[]=3&a[]=4', { arrayLimit: 3, throwOnLimitExceeded: 'true' });
|
|
1099
|
+
},
|
|
1100
|
+
new TypeError('`throwOnLimitExceeded` option must be a boolean'),
|
|
1101
|
+
'throws error when throwOnLimitExceeded is present and not boolean for array limit'
|
|
1102
|
+
);
|
|
1103
|
+
sst.end();
|
|
1104
|
+
});
|
|
1105
|
+
|
|
1106
|
+
st.test('throws error when array limit exceeded', function (sst) {
|
|
1107
|
+
sst['throws'](
|
|
1108
|
+
function () {
|
|
1109
|
+
qs.parse('a[]=1&a[]=2&a[]=3&a[]=4', { arrayLimit: 3, throwOnLimitExceeded: true });
|
|
1110
|
+
},
|
|
1111
|
+
new RangeError('Array limit exceeded. Only 3 elements allowed in an array.'),
|
|
1112
|
+
'throws error when array limit is exceeded'
|
|
1113
|
+
);
|
|
1114
|
+
sst.end();
|
|
1115
|
+
});
|
|
1116
|
+
|
|
1117
|
+
st.test('converts array to object if length is greater than limit', function (sst) {
|
|
1118
|
+
var result = qs.parse('a[1]=1&a[2]=2&a[3]=3&a[4]=4&a[5]=5&a[6]=6', { arrayLimit: 5 });
|
|
1119
|
+
|
|
1120
|
+
sst.deepEqual(result, { a: { 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6' } }, 'parses into object if array length is greater than limit');
|
|
1121
|
+
sst.end();
|
|
1122
|
+
});
|
|
1123
|
+
|
|
1124
|
+
st.end();
|
|
1125
|
+
});
|
|
1126
|
+
|
|
1021
1127
|
t.end();
|
|
1022
1128
|
});
|
|
1023
1129
|
|
|
@@ -1076,7 +1182,7 @@ test('qs strictDepth option - throw cases', function (t) {
|
|
|
1076
1182
|
qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1, strictDepth: true });
|
|
1077
1183
|
},
|
|
1078
1184
|
RangeError,
|
|
1079
|
-
'
|
|
1185
|
+
'throws RangeError'
|
|
1080
1186
|
);
|
|
1081
1187
|
st.end();
|
|
1082
1188
|
});
|
|
@@ -1087,7 +1193,7 @@ test('qs strictDepth option - throw cases', function (t) {
|
|
|
1087
1193
|
qs.parse('a[0][1][2][3][4]=b', { depth: 3, strictDepth: true });
|
|
1088
1194
|
},
|
|
1089
1195
|
RangeError,
|
|
1090
|
-
'
|
|
1196
|
+
'throws RangeError'
|
|
1091
1197
|
);
|
|
1092
1198
|
st.end();
|
|
1093
1199
|
});
|
|
@@ -1098,7 +1204,7 @@ test('qs strictDepth option - throw cases', function (t) {
|
|
|
1098
1204
|
qs.parse('a[b][c][0][d][e]=f', { depth: 3, strictDepth: true });
|
|
1099
1205
|
},
|
|
1100
1206
|
RangeError,
|
|
1101
|
-
'
|
|
1207
|
+
'throws RangeError'
|
|
1102
1208
|
);
|
|
1103
1209
|
st.end();
|
|
1104
1210
|
});
|
|
@@ -1109,7 +1215,7 @@ test('qs strictDepth option - throw cases', function (t) {
|
|
|
1109
1215
|
qs.parse('a[b][c][d][e]=true&a[b][c][d][f]=42', { depth: 3, strictDepth: true });
|
|
1110
1216
|
},
|
|
1111
1217
|
RangeError,
|
|
1112
|
-
'
|
|
1218
|
+
'throws RangeError'
|
|
1113
1219
|
);
|
|
1114
1220
|
st.end();
|
|
1115
1221
|
});
|
|
@@ -1123,7 +1229,7 @@ test('qs strictDepth option - non-throw cases', function (t) {
|
|
|
1123
1229
|
qs.parse('a[b][c][d][e]=true&a[b][c][d][f]=42', { depth: 0, strictDepth: true });
|
|
1124
1230
|
},
|
|
1125
1231
|
RangeError,
|
|
1126
|
-
'
|
|
1232
|
+
'does not throw RangeError'
|
|
1127
1233
|
);
|
|
1128
1234
|
st.end();
|
|
1129
1235
|
});
|
|
@@ -1132,7 +1238,7 @@ test('qs strictDepth option - non-throw cases', function (t) {
|
|
|
1132
1238
|
st.doesNotThrow(
|
|
1133
1239
|
function () {
|
|
1134
1240
|
var result = qs.parse('a[b]=c', { depth: 1, strictDepth: true });
|
|
1135
|
-
st.deepEqual(result, { a: { b: 'c' } }, '
|
|
1241
|
+
st.deepEqual(result, { a: { b: 'c' } }, 'parses correctly');
|
|
1136
1242
|
}
|
|
1137
1243
|
);
|
|
1138
1244
|
st.end();
|
|
@@ -1142,7 +1248,7 @@ test('qs strictDepth option - non-throw cases', function (t) {
|
|
|
1142
1248
|
st.doesNotThrow(
|
|
1143
1249
|
function () {
|
|
1144
1250
|
var result = qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1 });
|
|
1145
|
-
st.deepEqual(result, { a: { b: { '[c][d][e][f][g][h][i]': 'j' } } }, '
|
|
1251
|
+
st.deepEqual(result, { a: { b: { '[c][d][e][f][g][h][i]': 'j' } } }, 'parses with depth limit');
|
|
1146
1252
|
}
|
|
1147
1253
|
);
|
|
1148
1254
|
st.end();
|
|
@@ -1152,7 +1258,7 @@ test('qs strictDepth option - non-throw cases', function (t) {
|
|
|
1152
1258
|
st.doesNotThrow(
|
|
1153
1259
|
function () {
|
|
1154
1260
|
var result = qs.parse('a[b]=c', { depth: 1 });
|
|
1155
|
-
st.deepEqual(result, { a: { b: 'c' } }, '
|
|
1261
|
+
st.deepEqual(result, { a: { b: 'c' } }, 'parses correctly');
|
|
1156
1262
|
}
|
|
1157
1263
|
);
|
|
1158
1264
|
st.end();
|
|
@@ -1162,7 +1268,7 @@ test('qs strictDepth option - non-throw cases', function (t) {
|
|
|
1162
1268
|
st.doesNotThrow(
|
|
1163
1269
|
function () {
|
|
1164
1270
|
var result = qs.parse('a[b][c]=d', { depth: 2, strictDepth: true });
|
|
1165
|
-
st.deepEqual(result, { a: { b: { c: 'd' } } }, '
|
|
1271
|
+
st.deepEqual(result, { a: { b: { c: 'd' } } }, 'parses correctly');
|
|
1166
1272
|
}
|
|
1167
1273
|
);
|
|
1168
1274
|
st.end();
|
package/test/stringify.js
CHANGED
|
@@ -8,7 +8,8 @@ var SaferBuffer = require('safer-buffer').Buffer;
|
|
|
8
8
|
var hasSymbols = require('has-symbols');
|
|
9
9
|
var mockProperty = require('mock-property');
|
|
10
10
|
var emptyTestCases = require('./empty-keys-cases').emptyTestCases;
|
|
11
|
-
var
|
|
11
|
+
var hasProto = require('has-proto')();
|
|
12
|
+
var hasBigInt = require('has-bigints')();
|
|
12
13
|
|
|
13
14
|
test('stringify()', function (t) {
|
|
14
15
|
t.test('stringifies a querystring object', function (st) {
|
|
@@ -650,10 +651,8 @@ test('stringify()', function (t) {
|
|
|
650
651
|
st.end();
|
|
651
652
|
});
|
|
652
653
|
|
|
653
|
-
t.test('stringifies a null object', { skip: !
|
|
654
|
-
|
|
655
|
-
obj.a = 'b';
|
|
656
|
-
st.equal(qs.stringify(obj), 'a=b');
|
|
654
|
+
t.test('stringifies a null object', { skip: !hasProto }, function (st) {
|
|
655
|
+
st.equal(qs.stringify({ __proto__: null, a: 'b' }), 'a=b');
|
|
657
656
|
st.end();
|
|
658
657
|
});
|
|
659
658
|
|
|
@@ -665,11 +664,8 @@ test('stringify()', function (t) {
|
|
|
665
664
|
st.end();
|
|
666
665
|
});
|
|
667
666
|
|
|
668
|
-
t.test('stringifies an object with a null object as a child', { skip: !
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
obj.a.b = 'c';
|
|
672
|
-
st.equal(qs.stringify(obj), 'a%5Bb%5D=c');
|
|
667
|
+
t.test('stringifies an object with a null object as a child', { skip: !hasProto }, function (st) {
|
|
668
|
+
st.equal(qs.stringify({ a: { __proto__: null, b: 'c' } }), 'a%5Bb%5D=c');
|
|
673
669
|
st.end();
|
|
674
670
|
});
|
|
675
671
|
|
|
@@ -1254,7 +1250,7 @@ test('stringify()', function (t) {
|
|
|
1254
1250
|
};
|
|
1255
1251
|
|
|
1256
1252
|
st.equal(
|
|
1257
|
-
qs.stringify(obj, { arrayFormat: '
|
|
1253
|
+
qs.stringify(obj, { arrayFormat: 'brackets', charset: 'utf-8' }),
|
|
1258
1254
|
'foo=' + expected.join('')
|
|
1259
1255
|
);
|
|
1260
1256
|
|
|
@@ -1295,4 +1291,16 @@ test('stringifies empty keys', function (t) {
|
|
|
1295
1291
|
|
|
1296
1292
|
st.end();
|
|
1297
1293
|
});
|
|
1294
|
+
|
|
1295
|
+
t.test('stringifies non-string keys', function (st) {
|
|
1296
|
+
var actual = qs.stringify({ a: 'b', 'false': {} }, {
|
|
1297
|
+
filter: ['a', false, null],
|
|
1298
|
+
allowDots: true,
|
|
1299
|
+
encodeDotInKeys: true
|
|
1300
|
+
});
|
|
1301
|
+
|
|
1302
|
+
st.equal(actual, 'a=b', 'stringifies correctly');
|
|
1303
|
+
|
|
1304
|
+
st.end();
|
|
1305
|
+
});
|
|
1298
1306
|
});
|