qs 6.4.0 → 6.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +44 -0
- package/.eslintrc +23 -4
- package/.github/FUNDING.yml +12 -0
- package/.nycrc +13 -0
- package/CHANGELOG.md +28 -0
- package/LICENSE.md +29 -0
- package/README.md +64 -5
- package/bower.json +21 -0
- package/component.json +15 -0
- package/dist/qs.js +61 -49
- package/lib/formats.js +1 -1
- package/lib/parse.js +15 -14
- package/lib/stringify.js +22 -15
- package/lib/utils.js +21 -17
- package/package.json +52 -48
- package/test/parse.js +74 -6
- package/test/stringify.js +37 -6
- package/test/utils.js +7 -0
- package/.eslintignore +0 -1
- package/.jscs.json +0 -176
- package/LICENSE +0 -28
- package/test/.eslintrc +0 -11
package/lib/parse.js
CHANGED
|
@@ -18,7 +18,7 @@ var defaults = {
|
|
|
18
18
|
|
|
19
19
|
var parseValues = function parseQueryStringValues(str, options) {
|
|
20
20
|
var obj = {};
|
|
21
|
-
var parts = str.split(options.delimiter, options.parameterLimit === Infinity ? undefined : options.parameterLimit);
|
|
21
|
+
var parts = str.split(options.delimiter, options.parameterLimit === Infinity ? void undefined : options.parameterLimit);
|
|
22
22
|
|
|
23
23
|
for (var i = 0; i < parts.length; ++i) {
|
|
24
24
|
var part = parts[i];
|
|
@@ -50,23 +50,25 @@ var parseObject = function parseObjectRecursive(chain, val, options) {
|
|
|
50
50
|
var root = chain.shift();
|
|
51
51
|
|
|
52
52
|
var obj;
|
|
53
|
-
if (root === '[]') {
|
|
53
|
+
if (root === '[]' && options.parseArrays) {
|
|
54
54
|
obj = [];
|
|
55
55
|
obj = obj.concat(parseObject(chain, val, options));
|
|
56
56
|
} else {
|
|
57
57
|
obj = options.plainObjects ? Object.create(null) : {};
|
|
58
58
|
var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
|
|
59
59
|
var index = parseInt(cleanRoot, 10);
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
if (!options.parseArrays && cleanRoot === '') {
|
|
61
|
+
obj = { 0: val };
|
|
62
|
+
} else if (
|
|
63
|
+
!isNaN(index)
|
|
64
|
+
&& root !== cleanRoot
|
|
65
|
+
&& String(index) === cleanRoot
|
|
66
|
+
&& index >= 0
|
|
67
|
+
&& (options.parseArrays && index <= options.arrayLimit)
|
|
66
68
|
) {
|
|
67
69
|
obj = [];
|
|
68
70
|
obj[index] = parseObject(chain, val, options);
|
|
69
|
-
} else {
|
|
71
|
+
} else if (cleanRoot !== '__proto__') {
|
|
70
72
|
obj[cleanRoot] = parseObject(chain, val, options);
|
|
71
73
|
}
|
|
72
74
|
}
|
|
@@ -96,15 +98,14 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
|
|
|
96
98
|
|
|
97
99
|
var keys = [];
|
|
98
100
|
if (parent) {
|
|
99
|
-
// If we aren't using plain objects, optionally prefix keys
|
|
100
|
-
// that would overwrite object prototype properties
|
|
101
|
+
// If we aren't using plain objects, optionally prefix keys that would overwrite object prototype properties
|
|
101
102
|
if (!options.plainObjects && has.call(Object.prototype, parent)) {
|
|
102
103
|
if (!options.allowPrototypes) {
|
|
103
104
|
return;
|
|
104
105
|
}
|
|
105
106
|
}
|
|
106
107
|
|
|
107
|
-
keys.
|
|
108
|
+
keys[keys.length] = parent;
|
|
108
109
|
}
|
|
109
110
|
|
|
110
111
|
// Loop through children appending to the array until we hit depth
|
|
@@ -117,13 +118,13 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
|
|
|
117
118
|
return;
|
|
118
119
|
}
|
|
119
120
|
}
|
|
120
|
-
keys.
|
|
121
|
+
keys[keys.length] = segment[1];
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
// If there's a remainder, just add whatever is left
|
|
124
125
|
|
|
125
126
|
if (segment) {
|
|
126
|
-
keys.
|
|
127
|
+
keys[keys.length] = '[' + key.slice(segment.index + ']');
|
|
127
128
|
}
|
|
128
129
|
|
|
129
130
|
return parseObject(keys, val, options);
|
package/lib/stringify.js
CHANGED
|
@@ -4,17 +4,23 @@ var utils = require('./utils');
|
|
|
4
4
|
var formats = require('./formats');
|
|
5
5
|
|
|
6
6
|
var arrayPrefixGenerators = {
|
|
7
|
-
brackets: function brackets(prefix) {
|
|
7
|
+
brackets: function brackets(prefix) {
|
|
8
8
|
return prefix + '[]';
|
|
9
9
|
},
|
|
10
|
-
indices: function indices(prefix, key) {
|
|
10
|
+
indices: function indices(prefix, key) {
|
|
11
11
|
return prefix + '[' + key + ']';
|
|
12
12
|
},
|
|
13
|
-
repeat: function repeat(prefix) {
|
|
13
|
+
repeat: function repeat(prefix) {
|
|
14
14
|
return prefix;
|
|
15
15
|
}
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
var isArray = Array.isArray;
|
|
19
|
+
var push = Array.prototype.push;
|
|
20
|
+
var pushToArray = function (arr, valueOrArray) {
|
|
21
|
+
push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
|
|
22
|
+
};
|
|
23
|
+
|
|
18
24
|
var toISO = Date.prototype.toISOString;
|
|
19
25
|
|
|
20
26
|
var defaults = {
|
|
@@ -22,14 +28,14 @@ var defaults = {
|
|
|
22
28
|
encode: true,
|
|
23
29
|
encoder: utils.encode,
|
|
24
30
|
encodeValuesOnly: false,
|
|
25
|
-
serializeDate: function serializeDate(date) {
|
|
31
|
+
serializeDate: function serializeDate(date) {
|
|
26
32
|
return toISO.call(date);
|
|
27
33
|
},
|
|
28
34
|
skipNulls: false,
|
|
29
35
|
strictNullHandling: false
|
|
30
36
|
};
|
|
31
37
|
|
|
32
|
-
var stringify = function stringify(
|
|
38
|
+
var stringify = function stringify(
|
|
33
39
|
object,
|
|
34
40
|
prefix,
|
|
35
41
|
generateArrayPrefix,
|
|
@@ -48,7 +54,9 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
48
54
|
obj = filter(prefix, obj);
|
|
49
55
|
} else if (obj instanceof Date) {
|
|
50
56
|
obj = serializeDate(obj);
|
|
51
|
-
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (obj === null) {
|
|
52
60
|
if (strictNullHandling) {
|
|
53
61
|
return encoder && !encodeValuesOnly ? encoder(prefix) : prefix;
|
|
54
62
|
}
|
|
@@ -71,7 +79,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
71
79
|
}
|
|
72
80
|
|
|
73
81
|
var objKeys;
|
|
74
|
-
if (
|
|
82
|
+
if (isArray(filter)) {
|
|
75
83
|
objKeys = filter;
|
|
76
84
|
} else {
|
|
77
85
|
var keys = Object.keys(obj);
|
|
@@ -85,8 +93,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
85
93
|
continue;
|
|
86
94
|
}
|
|
87
95
|
|
|
88
|
-
if (
|
|
89
|
-
values
|
|
96
|
+
if (isArray(obj)) {
|
|
97
|
+
pushToArray(values, stringify(
|
|
90
98
|
obj[key],
|
|
91
99
|
generateArrayPrefix(prefix, key),
|
|
92
100
|
generateArrayPrefix,
|
|
@@ -101,7 +109,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
|
101
109
|
encodeValuesOnly
|
|
102
110
|
));
|
|
103
111
|
} else {
|
|
104
|
-
values
|
|
112
|
+
pushToArray(values, stringify(
|
|
105
113
|
obj[key],
|
|
106
114
|
prefix + (allowDots ? '.' + key : '[' + key + ']'),
|
|
107
115
|
generateArrayPrefix,
|
|
@@ -125,7 +133,7 @@ module.exports = function (object, opts) {
|
|
|
125
133
|
var obj = object;
|
|
126
134
|
var options = opts || {};
|
|
127
135
|
|
|
128
|
-
if (options.encoder !== null && options.encoder !== undefined && typeof options.encoder !== 'function') {
|
|
136
|
+
if (options.encoder !== null && typeof options.encoder !== 'undefined' && typeof options.encoder !== 'function') {
|
|
129
137
|
throw new TypeError('Encoder has to be a function.');
|
|
130
138
|
}
|
|
131
139
|
|
|
@@ -139,7 +147,7 @@ module.exports = function (object, opts) {
|
|
|
139
147
|
var serializeDate = typeof options.serializeDate === 'function' ? options.serializeDate : defaults.serializeDate;
|
|
140
148
|
var encodeValuesOnly = typeof options.encodeValuesOnly === 'boolean' ? options.encodeValuesOnly : defaults.encodeValuesOnly;
|
|
141
149
|
if (typeof options.format === 'undefined') {
|
|
142
|
-
options.format = formats
|
|
150
|
+
options.format = formats['default'];
|
|
143
151
|
} else if (!Object.prototype.hasOwnProperty.call(formats.formatters, options.format)) {
|
|
144
152
|
throw new TypeError('Unknown format option provided.');
|
|
145
153
|
}
|
|
@@ -150,7 +158,7 @@ module.exports = function (object, opts) {
|
|
|
150
158
|
if (typeof options.filter === 'function') {
|
|
151
159
|
filter = options.filter;
|
|
152
160
|
obj = filter('', obj);
|
|
153
|
-
} else if (
|
|
161
|
+
} else if (isArray(options.filter)) {
|
|
154
162
|
filter = options.filter;
|
|
155
163
|
objKeys = filter;
|
|
156
164
|
}
|
|
@@ -186,8 +194,7 @@ module.exports = function (object, opts) {
|
|
|
186
194
|
if (skipNulls && obj[key] === null) {
|
|
187
195
|
continue;
|
|
188
196
|
}
|
|
189
|
-
|
|
190
|
-
keys = keys.concat(stringify(
|
|
197
|
+
pushToArray(keys, stringify(
|
|
191
198
|
obj[key],
|
|
192
199
|
key,
|
|
193
200
|
generateArrayPrefix,
|
package/lib/utils.js
CHANGED
|
@@ -5,7 +5,7 @@ var has = Object.prototype.hasOwnProperty;
|
|
|
5
5
|
var hexTable = (function () {
|
|
6
6
|
var array = [];
|
|
7
7
|
for (var i = 0; i < 256; ++i) {
|
|
8
|
-
array.
|
|
8
|
+
array[array.length] = '%' + ((i < 16 ? '0' : '' + i.toString(16)).toUpperCase());
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
return array;
|
|
@@ -29,9 +29,9 @@ exports.merge = function (target, source, options) {
|
|
|
29
29
|
|
|
30
30
|
if (typeof source !== 'object') {
|
|
31
31
|
if (Array.isArray(target)) {
|
|
32
|
-
target.
|
|
33
|
-
} else if (typeof target === 'object') {
|
|
34
|
-
if (options.plainObjects || options.allowPrototypes || !has.call(Object.prototype, source)) {
|
|
32
|
+
target[target.length] = source;
|
|
33
|
+
} else if (target && typeof target === 'object') {
|
|
34
|
+
if ((options && (options.plainObjects || options.allowPrototypes)) || !has.call(Object.prototype, source)) {
|
|
35
35
|
target[source] = true;
|
|
36
36
|
}
|
|
37
37
|
} else {
|
|
@@ -41,7 +41,7 @@ exports.merge = function (target, source, options) {
|
|
|
41
41
|
return target;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
if (typeof target !== 'object') {
|
|
44
|
+
if (!target || typeof target !== 'object') {
|
|
45
45
|
return [target].concat(source);
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -56,7 +56,7 @@ exports.merge = function (target, source, options) {
|
|
|
56
56
|
if (target[i] && typeof target[i] === 'object') {
|
|
57
57
|
target[i] = exports.merge(target[i], item, options);
|
|
58
58
|
} else {
|
|
59
|
-
target.
|
|
59
|
+
target[target.length] = item;
|
|
60
60
|
}
|
|
61
61
|
} else {
|
|
62
62
|
target[i] = item;
|
|
@@ -99,13 +99,13 @@ exports.encode = function (str) {
|
|
|
99
99
|
var c = string.charCodeAt(i);
|
|
100
100
|
|
|
101
101
|
if (
|
|
102
|
-
c === 0x2D
|
|
103
|
-
c === 0x2E
|
|
104
|
-
c === 0x5F
|
|
105
|
-
c === 0x7E
|
|
106
|
-
(c >= 0x30 && c <= 0x39)
|
|
107
|
-
(c >= 0x41 && c <= 0x5A)
|
|
108
|
-
(c >= 0x61 && c <= 0x7A) // A-Z
|
|
102
|
+
c === 0x2D // -
|
|
103
|
+
|| c === 0x2E // .
|
|
104
|
+
|| c === 0x5F // _
|
|
105
|
+
|| c === 0x7E // ~
|
|
106
|
+
|| (c >= 0x30 && c <= 0x39) // 0-9
|
|
107
|
+
|| (c >= 0x41 && c <= 0x5A) // a-z
|
|
108
|
+
|| (c >= 0x61 && c <= 0x7A) // A-Z
|
|
109
109
|
) {
|
|
110
110
|
out += string.charAt(i);
|
|
111
111
|
continue;
|
|
@@ -128,7 +128,11 @@ exports.encode = function (str) {
|
|
|
128
128
|
|
|
129
129
|
i += 1;
|
|
130
130
|
c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
|
|
131
|
-
|
|
131
|
+
/* eslint operator-linebreak: [2, "before"] */
|
|
132
|
+
out += hexTable[0xF0 | (c >> 18)]
|
|
133
|
+
+ hexTable[0x80 | ((c >> 12) & 0x3F)]
|
|
134
|
+
+ hexTable[0x80 | ((c >> 6) & 0x3F)]
|
|
135
|
+
+ hexTable[0x80 | (c & 0x3F)];
|
|
132
136
|
}
|
|
133
137
|
|
|
134
138
|
return out;
|
|
@@ -145,16 +149,16 @@ exports.compact = function (obj, references) {
|
|
|
145
149
|
return refs[lookup];
|
|
146
150
|
}
|
|
147
151
|
|
|
148
|
-
refs.
|
|
152
|
+
refs[refs.length] = obj;
|
|
149
153
|
|
|
150
154
|
if (Array.isArray(obj)) {
|
|
151
155
|
var compacted = [];
|
|
152
156
|
|
|
153
157
|
for (var i = 0; i < obj.length; ++i) {
|
|
154
158
|
if (obj[i] && typeof obj[i] === 'object') {
|
|
155
|
-
compacted.
|
|
159
|
+
compacted[compacted.length] = exports.compact(obj[i], refs);
|
|
156
160
|
} else if (typeof obj[i] !== 'undefined') {
|
|
157
|
-
compacted.
|
|
161
|
+
compacted[compacted.length] = obj[i];
|
|
158
162
|
}
|
|
159
163
|
}
|
|
160
164
|
|
package/package.json
CHANGED
|
@@ -1,50 +1,54 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
2
|
+
"name": "qs",
|
|
3
|
+
"description": "A querystring parser that supports nesting and arrays, with a depth limit",
|
|
4
|
+
"homepage": "https://github.com/ljharb/qs",
|
|
5
|
+
"version": "6.4.2",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/ljharb/qs.git"
|
|
9
|
+
},
|
|
10
|
+
"main": "lib/index.js",
|
|
11
|
+
"contributors": [
|
|
12
|
+
{
|
|
13
|
+
"name": "Jordan Harband",
|
|
14
|
+
"email": "ljharb@gmail.com",
|
|
15
|
+
"url": "http://ljharb.codes"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"keywords": [
|
|
19
|
+
"querystring",
|
|
20
|
+
"qs"
|
|
21
|
+
],
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=0.6"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@ljharb/eslint-config": "^20.1.0",
|
|
27
|
+
"aud": "^1.1.5",
|
|
28
|
+
"browserify": "^16.5.2",
|
|
29
|
+
"eclint": "^2.8.1",
|
|
30
|
+
"eslint": "^8.6.0",
|
|
31
|
+
"evalmd": "^0.0.17",
|
|
32
|
+
"iconv-lite": "^0.4.24",
|
|
33
|
+
"in-publish": "^2.0.1",
|
|
34
|
+
"mkdirp": "^0.5.1",
|
|
35
|
+
"nyc": "^10.3.2",
|
|
36
|
+
"qs-iconv": "^1.0.4",
|
|
37
|
+
"safe-publish-latest": "^2.0.0",
|
|
38
|
+
"safer-buffer": "^2.1.2",
|
|
39
|
+
"tape": "^5.4.0"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"prepublishOnly": "safe-publish-latest && npm run dist",
|
|
43
|
+
"prepublish": "not-in-publish || npm run prepublishOnly",
|
|
44
|
+
"pretest": "npm run --silent readme && npm run --silent lint",
|
|
45
|
+
"test": "npm run --silent tests-only",
|
|
46
|
+
"tests-only": "nyc tape 'test/**/*.js'",
|
|
47
|
+
"posttest": "aud --production",
|
|
48
|
+
"readme": "evalmd README.md",
|
|
49
|
+
"postlint": "eclint check $(git ls-files | xargs find 2> /dev/null | grep -vE 'node_modules|\\.git')",
|
|
50
|
+
"lint": "eslint --ext=js,mjs .",
|
|
51
|
+
"dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js"
|
|
52
|
+
},
|
|
53
|
+
"license": "BSD-3-Clause"
|
|
50
54
|
}
|
package/test/parse.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var test = require('tape');
|
|
4
4
|
var qs = require('../');
|
|
5
5
|
var iconv = require('iconv-lite');
|
|
6
|
+
var SaferBuffer = require('safer-buffer').Buffer;
|
|
6
7
|
|
|
7
8
|
test('parse()', function (t) {
|
|
8
9
|
t.test('parses a simple string', function (st) {
|
|
@@ -230,7 +231,7 @@ test('parse()', function (t) {
|
|
|
230
231
|
});
|
|
231
232
|
|
|
232
233
|
t.test('parses buffers correctly', function (st) {
|
|
233
|
-
var b =
|
|
234
|
+
var b = SaferBuffer.from('test');
|
|
234
235
|
st.deepEqual(qs.parse({ a: b }), { a: b });
|
|
235
236
|
st.end();
|
|
236
237
|
});
|
|
@@ -255,7 +256,7 @@ test('parse()', function (t) {
|
|
|
255
256
|
st.end();
|
|
256
257
|
});
|
|
257
258
|
|
|
258
|
-
t.test('should not throw when a native prototype has an enumerable property',
|
|
259
|
+
t.test('should not throw when a native prototype has an enumerable property', function (st) {
|
|
259
260
|
Object.prototype.crash = '';
|
|
260
261
|
Array.prototype.crash = '';
|
|
261
262
|
st.doesNotThrow(qs.parse.bind(null, 'a=b'));
|
|
@@ -300,7 +301,14 @@ test('parse()', function (t) {
|
|
|
300
301
|
});
|
|
301
302
|
|
|
302
303
|
t.test('allows disabling array parsing', function (st) {
|
|
303
|
-
|
|
304
|
+
var indices = qs.parse('a[0]=b&a[1]=c', { parseArrays: false });
|
|
305
|
+
st.deepEqual(indices, { a: { 0: 'b', 1: 'c' } });
|
|
306
|
+
st.equal(Array.isArray(indices.a), false, 'parseArrays:false, indices case is not an array');
|
|
307
|
+
|
|
308
|
+
var emptyBrackets = qs.parse('a[]=b', { parseArrays: false });
|
|
309
|
+
st.deepEqual(emptyBrackets, { a: { 0: 'b' } });
|
|
310
|
+
st.equal(Array.isArray(emptyBrackets.a), false, 'parseArrays:false, empty brackets case is not an array');
|
|
311
|
+
|
|
304
312
|
st.end();
|
|
305
313
|
});
|
|
306
314
|
|
|
@@ -472,13 +480,73 @@ test('parse()', function (t) {
|
|
|
472
480
|
|
|
473
481
|
st.deepEqual(
|
|
474
482
|
qs.parse('a[b]=c&a=toString', { plainObjects: true }),
|
|
475
|
-
{ a: { b: 'c', toString: true } },
|
|
483
|
+
{ __proto__: null, a: { __proto__: null, b: 'c', toString: true } },
|
|
476
484
|
'can overwrite prototype with plainObjects true'
|
|
477
485
|
);
|
|
478
486
|
|
|
479
487
|
st.end();
|
|
480
488
|
});
|
|
481
489
|
|
|
490
|
+
t.test('dunder proto is ignored', function (st) {
|
|
491
|
+
var payload = 'categories[__proto__]=login&categories[__proto__]&categories[length]=42';
|
|
492
|
+
var result = qs.parse(payload, { allowPrototypes: true });
|
|
493
|
+
|
|
494
|
+
st.deepEqual(
|
|
495
|
+
result,
|
|
496
|
+
{
|
|
497
|
+
categories: {
|
|
498
|
+
length: '42'
|
|
499
|
+
}
|
|
500
|
+
},
|
|
501
|
+
'silent [[Prototype]] payload'
|
|
502
|
+
);
|
|
503
|
+
|
|
504
|
+
var plainResult = qs.parse(payload, { allowPrototypes: true, plainObjects: true });
|
|
505
|
+
|
|
506
|
+
st.deepEqual(
|
|
507
|
+
plainResult,
|
|
508
|
+
{
|
|
509
|
+
__proto__: null,
|
|
510
|
+
categories: {
|
|
511
|
+
__proto__: null,
|
|
512
|
+
length: '42'
|
|
513
|
+
}
|
|
514
|
+
},
|
|
515
|
+
'silent [[Prototype]] payload: plain objects'
|
|
516
|
+
);
|
|
517
|
+
|
|
518
|
+
var query = qs.parse('categories[__proto__]=cats&categories[__proto__]=dogs&categories[some][json]=toInject', { allowPrototypes: true });
|
|
519
|
+
|
|
520
|
+
st.notOk(Array.isArray(query.categories), 'is not an array');
|
|
521
|
+
st.notOk(query.categories instanceof Array, 'is not instanceof an array');
|
|
522
|
+
st.deepEqual(query.categories, { some: { json: 'toInject' } });
|
|
523
|
+
st.equal(JSON.stringify(query.categories), '{"some":{"json":"toInject"}}', 'stringifies as a non-array');
|
|
524
|
+
|
|
525
|
+
st.deepEqual(
|
|
526
|
+
qs.parse('foo[__proto__][hidden]=value&foo[bar]=stuffs', { allowPrototypes: true }),
|
|
527
|
+
{
|
|
528
|
+
foo: {
|
|
529
|
+
bar: 'stuffs'
|
|
530
|
+
}
|
|
531
|
+
},
|
|
532
|
+
'hidden values'
|
|
533
|
+
);
|
|
534
|
+
|
|
535
|
+
st.deepEqual(
|
|
536
|
+
qs.parse('foo[__proto__][hidden]=value&foo[bar]=stuffs', { allowPrototypes: true, plainObjects: true }),
|
|
537
|
+
{
|
|
538
|
+
__proto__: null,
|
|
539
|
+
foo: {
|
|
540
|
+
__proto__: null,
|
|
541
|
+
bar: 'stuffs'
|
|
542
|
+
}
|
|
543
|
+
},
|
|
544
|
+
'hidden values: plain objects'
|
|
545
|
+
);
|
|
546
|
+
|
|
547
|
+
st.end();
|
|
548
|
+
});
|
|
549
|
+
|
|
482
550
|
t.test('can return null objects', { skip: !Object.create }, function (st) {
|
|
483
551
|
var expected = Object.create(null);
|
|
484
552
|
expected.a = Object.create(null);
|
|
@@ -504,14 +572,14 @@ test('parse()', function (t) {
|
|
|
504
572
|
result.push(parseInt(parts[1], 16));
|
|
505
573
|
parts = reg.exec(str);
|
|
506
574
|
}
|
|
507
|
-
return iconv.decode(
|
|
575
|
+
return iconv.decode(SaferBuffer.from(result), 'shift_jis').toString();
|
|
508
576
|
}
|
|
509
577
|
}), { 県: '大阪府' });
|
|
510
578
|
st.end();
|
|
511
579
|
});
|
|
512
580
|
|
|
513
581
|
t.test('throws error with wrong decoder', function (st) {
|
|
514
|
-
st
|
|
582
|
+
st['throws'](function () {
|
|
515
583
|
qs.parse({}, { decoder: 'string' });
|
|
516
584
|
}, new TypeError('Decoder has to be a function.'));
|
|
517
585
|
st.end();
|
package/test/stringify.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var test = require('tape');
|
|
4
4
|
var qs = require('../');
|
|
5
5
|
var iconv = require('iconv-lite');
|
|
6
|
+
var SaferBuffer = require('safer-buffer').Buffer;
|
|
6
7
|
|
|
7
8
|
test('stringify()', function (t) {
|
|
8
9
|
t.test('stringifies a querystring object', function (st) {
|
|
@@ -325,8 +326,8 @@ test('stringify()', function (t) {
|
|
|
325
326
|
});
|
|
326
327
|
|
|
327
328
|
t.test('stringifies buffer values', function (st) {
|
|
328
|
-
st.equal(qs.stringify({ a:
|
|
329
|
-
st.equal(qs.stringify({ a: { b:
|
|
329
|
+
st.equal(qs.stringify({ a: SaferBuffer.from('test') }), 'a=test');
|
|
330
|
+
st.equal(qs.stringify({ a: { b: SaferBuffer.from('test') } }), 'a%5Bb%5D=test');
|
|
330
331
|
st.end();
|
|
331
332
|
});
|
|
332
333
|
|
|
@@ -453,14 +454,14 @@ test('stringify()', function (t) {
|
|
|
453
454
|
});
|
|
454
455
|
|
|
455
456
|
t.test('throws error with wrong encoder', function (st) {
|
|
456
|
-
st
|
|
457
|
+
st['throws'](function () {
|
|
457
458
|
qs.stringify({}, { encoder: 'string' });
|
|
458
459
|
}, new TypeError('Encoder has to be a function.'));
|
|
459
460
|
st.end();
|
|
460
461
|
});
|
|
461
462
|
|
|
462
463
|
t.test('can use custom encoder for a buffer object', { skip: typeof Buffer === 'undefined' }, function (st) {
|
|
463
|
-
st.equal(qs.stringify({ a:
|
|
464
|
+
st.equal(qs.stringify({ a: SaferBuffer.from([1]) }, {
|
|
464
465
|
encoder: function (buffer) {
|
|
465
466
|
if (typeof buffer === 'string') {
|
|
466
467
|
return buffer;
|
|
@@ -468,6 +469,12 @@ test('stringify()', function (t) {
|
|
|
468
469
|
return String.fromCharCode(buffer.readUInt8(0) + 97);
|
|
469
470
|
}
|
|
470
471
|
}), 'a=b');
|
|
472
|
+
|
|
473
|
+
st.equal(qs.stringify({ a: SaferBuffer.from('a b') }, {
|
|
474
|
+
encoder: function (buffer) {
|
|
475
|
+
return buffer;
|
|
476
|
+
}
|
|
477
|
+
}), 'a=a b');
|
|
471
478
|
st.end();
|
|
472
479
|
});
|
|
473
480
|
|
|
@@ -483,7 +490,7 @@ test('stringify()', function (t) {
|
|
|
483
490
|
mutatedDate.toISOString = function () {
|
|
484
491
|
throw new SyntaxError();
|
|
485
492
|
};
|
|
486
|
-
st
|
|
493
|
+
st['throws'](function () {
|
|
487
494
|
mutatedDate.toISOString();
|
|
488
495
|
}, SyntaxError);
|
|
489
496
|
st.equal(
|
|
@@ -508,24 +515,27 @@ test('stringify()', function (t) {
|
|
|
508
515
|
t.test('RFC 1738 spaces serialization', function (st) {
|
|
509
516
|
st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.RFC1738 }), 'a=b+c');
|
|
510
517
|
st.equal(qs.stringify({ 'a b': 'c d' }, { format: qs.formats.RFC1738 }), 'a+b=c+d');
|
|
518
|
+
st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }, { format: qs.formats.RFC1738 }), 'a+b=a+b');
|
|
511
519
|
st.end();
|
|
512
520
|
});
|
|
513
521
|
|
|
514
522
|
t.test('RFC 3986 spaces serialization', function (st) {
|
|
515
523
|
st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.RFC3986 }), 'a=b%20c');
|
|
516
524
|
st.equal(qs.stringify({ 'a b': 'c d' }, { format: qs.formats.RFC3986 }), 'a%20b=c%20d');
|
|
525
|
+
st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }, { format: qs.formats.RFC3986 }), 'a%20b=a%20b');
|
|
517
526
|
st.end();
|
|
518
527
|
});
|
|
519
528
|
|
|
520
529
|
t.test('Backward compatibility to RFC 3986', function (st) {
|
|
521
530
|
st.equal(qs.stringify({ a: 'b c' }), 'a=b%20c');
|
|
531
|
+
st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }), 'a%20b=a%20b');
|
|
522
532
|
st.end();
|
|
523
533
|
});
|
|
524
534
|
|
|
525
535
|
t.test('Edge cases and unknown formats', function (st) {
|
|
526
536
|
['UFO1234', false, 1234, null, {}, []].forEach(
|
|
527
537
|
function (format) {
|
|
528
|
-
st
|
|
538
|
+
st['throws'](
|
|
529
539
|
function () {
|
|
530
540
|
qs.stringify({ a: 'b c' }, { format: format });
|
|
531
541
|
},
|
|
@@ -564,4 +574,25 @@ test('stringify()', function (t) {
|
|
|
564
574
|
st.end();
|
|
565
575
|
});
|
|
566
576
|
|
|
577
|
+
t.test('strictNullHandling works with custom filter', function (st) {
|
|
578
|
+
var filter = function (prefix, value) {
|
|
579
|
+
return value;
|
|
580
|
+
};
|
|
581
|
+
|
|
582
|
+
var options = { strictNullHandling: true, filter: filter };
|
|
583
|
+
st.equal(qs.stringify({ key: null }, options), 'key');
|
|
584
|
+
st.end();
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
t.test('strictNullHandling works with null serializeDate', function (st) {
|
|
588
|
+
var serializeDate = function () {
|
|
589
|
+
return null;
|
|
590
|
+
};
|
|
591
|
+
var options = { strictNullHandling: true, serializeDate: serializeDate };
|
|
592
|
+
var date = new Date();
|
|
593
|
+
st.equal(qs.stringify({ key: date }, options), 'key');
|
|
594
|
+
st.end();
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
t.end();
|
|
567
598
|
});
|
package/test/utils.js
CHANGED
|
@@ -4,6 +4,10 @@ var test = require('tape');
|
|
|
4
4
|
var utils = require('../lib/utils');
|
|
5
5
|
|
|
6
6
|
test('merge()', function (t) {
|
|
7
|
+
t.deepEqual(utils.merge(null, true), [null, true], 'merges true into null');
|
|
8
|
+
|
|
9
|
+
t.deepEqual(utils.merge(null, [42]), [null, 42], 'merges null into an array');
|
|
10
|
+
|
|
7
11
|
t.deepEqual(utils.merge({ a: 'b' }, { a: 'c' }), { a: ['b', 'c'] }, 'merges two objects with the same key');
|
|
8
12
|
|
|
9
13
|
var oneMerged = utils.merge({ foo: 'bar' }, { foo: { first: '123' } });
|
|
@@ -18,5 +22,8 @@ test('merge()', function (t) {
|
|
|
18
22
|
var nestedArrays = utils.merge({ foo: ['baz'] }, { foo: ['bar', 'xyzzy'] });
|
|
19
23
|
t.deepEqual(nestedArrays, { foo: ['baz', 'bar', 'xyzzy'] });
|
|
20
24
|
|
|
25
|
+
var noOptionsNonObjectSource = utils.merge({ foo: 'baz' }, 'bar');
|
|
26
|
+
t.deepEqual(noOptionsNonObjectSource, { foo: 'baz', bar: true });
|
|
27
|
+
|
|
21
28
|
t.end();
|
|
22
29
|
});
|
package/.eslintignore
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
dist
|