qs 6.2.0 → 6.2.4
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 +45 -0
- package/.eslintrc +35 -15
- package/.github/FUNDING.yml +12 -0
- package/.nycrc +13 -0
- package/CHANGELOG.md +36 -0
- package/LICENSE.md +29 -0
- package/README.md +400 -0
- package/bower.json +21 -0
- package/component.json +15 -0
- package/dist/qs.js +145 -64
- package/lib/index.js +0 -0
- package/lib/parse.js +34 -33
- package/lib/stringify.js +52 -10
- package/lib/utils.js +57 -19
- package/package.json +52 -46
- package/test/index.js +2 -0
- package/test/parse.js +195 -41
- package/test/stringify.js +11 -13
- package/test/utils.js +20 -0
- package/.eslintignore +0 -1
- package/.jscs.json +0 -176
- package/LICENSE +0 -28
package/lib/utils.js
CHANGED
|
@@ -9,8 +9,23 @@ var hexTable = (function () {
|
|
|
9
9
|
return array;
|
|
10
10
|
}());
|
|
11
11
|
|
|
12
|
+
var has = Object.prototype.hasOwnProperty;
|
|
13
|
+
|
|
12
14
|
exports.arrayToObject = function (source, options) {
|
|
13
|
-
var obj = options.plainObjects ? Object.create(null) : {};
|
|
15
|
+
var obj = options && options.plainObjects ? Object.create(null) : {};
|
|
16
|
+
for (var i = 0; i < source.length; ++i) {
|
|
17
|
+
if (typeof source[i] !== 'undefined') {
|
|
18
|
+
obj[i] = source[i];
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return obj;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
var isArray = Array.isArray;
|
|
26
|
+
|
|
27
|
+
var arrayToObject = function arrayToObject(source, options) {
|
|
28
|
+
var obj = options && options.plainObjects ? Object.create(null) : {};
|
|
14
29
|
for (var i = 0; i < source.length; ++i) {
|
|
15
30
|
if (typeof source[i] !== 'undefined') {
|
|
16
31
|
obj[i] = source[i];
|
|
@@ -20,16 +35,19 @@ exports.arrayToObject = function (source, options) {
|
|
|
20
35
|
return obj;
|
|
21
36
|
};
|
|
22
37
|
|
|
23
|
-
exports.merge = function (target, source, options) {
|
|
38
|
+
exports.merge = function merge(target, source, options) {
|
|
39
|
+
/* eslint no-param-reassign: 0 */
|
|
24
40
|
if (!source) {
|
|
25
41
|
return target;
|
|
26
42
|
}
|
|
27
43
|
|
|
28
44
|
if (typeof source !== 'object') {
|
|
29
|
-
if (
|
|
45
|
+
if (isArray(target)) {
|
|
30
46
|
target.push(source);
|
|
31
|
-
} else if (typeof target === 'object') {
|
|
32
|
-
|
|
47
|
+
} else if (target && typeof target === 'object') {
|
|
48
|
+
if ((options && (options.plainObjects || options.allowPrototypes)) || !has.call(Object.prototype, source)) {
|
|
49
|
+
target[source] = true;
|
|
50
|
+
}
|
|
33
51
|
} else {
|
|
34
52
|
return [target, source];
|
|
35
53
|
}
|
|
@@ -37,20 +55,36 @@ exports.merge = function (target, source, options) {
|
|
|
37
55
|
return target;
|
|
38
56
|
}
|
|
39
57
|
|
|
40
|
-
if (typeof target !== 'object') {
|
|
58
|
+
if (!target || typeof target !== 'object') {
|
|
41
59
|
return [target].concat(source);
|
|
42
60
|
}
|
|
43
61
|
|
|
44
62
|
var mergeTarget = target;
|
|
45
|
-
if (
|
|
46
|
-
mergeTarget =
|
|
63
|
+
if (isArray(target) && !isArray(source)) {
|
|
64
|
+
mergeTarget = arrayToObject(target, options);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (isArray(target) && isArray(source)) {
|
|
68
|
+
source.forEach(function (item, i) {
|
|
69
|
+
if (has.call(target, i)) {
|
|
70
|
+
var targetItem = target[i];
|
|
71
|
+
if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') {
|
|
72
|
+
target[i] = merge(targetItem, item, options);
|
|
73
|
+
} else {
|
|
74
|
+
target.push(item);
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
target[i] = item;
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
return target;
|
|
47
81
|
}
|
|
48
82
|
|
|
49
83
|
return Object.keys(source).reduce(function (acc, key) {
|
|
50
84
|
var value = source[key];
|
|
51
85
|
|
|
52
|
-
if (
|
|
53
|
-
acc[key] =
|
|
86
|
+
if (has.call(acc, key)) {
|
|
87
|
+
acc[key] = merge(acc[key], value, options);
|
|
54
88
|
} else {
|
|
55
89
|
acc[key] = value;
|
|
56
90
|
}
|
|
@@ -80,13 +114,13 @@ exports.encode = function (str) {
|
|
|
80
114
|
var c = string.charCodeAt(i);
|
|
81
115
|
|
|
82
116
|
if (
|
|
83
|
-
c === 0x2D
|
|
84
|
-
c === 0x2E
|
|
85
|
-
c === 0x5F
|
|
86
|
-
c === 0x7E
|
|
87
|
-
(c >= 0x30 && c <= 0x39)
|
|
88
|
-
(c >= 0x41 && c <= 0x5A)
|
|
89
|
-
(c >= 0x61 && c <= 0x7A) // A-Z
|
|
117
|
+
c === 0x2D // -
|
|
118
|
+
|| c === 0x2E // .
|
|
119
|
+
|| c === 0x5F // _
|
|
120
|
+
|| c === 0x7E // ~
|
|
121
|
+
|| (c >= 0x30 && c <= 0x39) // 0-9
|
|
122
|
+
|| (c >= 0x41 && c <= 0x5A) // a-z
|
|
123
|
+
|| (c >= 0x61 && c <= 0x7A) // A-Z
|
|
90
124
|
) {
|
|
91
125
|
out += string.charAt(i);
|
|
92
126
|
continue;
|
|
@@ -109,7 +143,11 @@ exports.encode = function (str) {
|
|
|
109
143
|
|
|
110
144
|
i += 1;
|
|
111
145
|
c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
|
|
112
|
-
|
|
146
|
+
/* eslint operator-linebreak: [2, "before"] */
|
|
147
|
+
out += hexTable[0xF0 | (c >> 18)]
|
|
148
|
+
+ hexTable[0x80 | ((c >> 12) & 0x3F)]
|
|
149
|
+
+ hexTable[0x80 | ((c >> 6) & 0x3F)]
|
|
150
|
+
+ hexTable[0x80 | (c & 0x3F)];
|
|
113
151
|
}
|
|
114
152
|
|
|
115
153
|
return out;
|
|
@@ -128,7 +166,7 @@ exports.compact = function (obj, references) {
|
|
|
128
166
|
|
|
129
167
|
refs.push(obj);
|
|
130
168
|
|
|
131
|
-
if (
|
|
169
|
+
if (isArray(obj)) {
|
|
132
170
|
var compacted = [];
|
|
133
171
|
|
|
134
172
|
for (var i = 0; i < obj.length; ++i) {
|
package/package.json
CHANGED
|
@@ -1,48 +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
|
-
|
|
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.2.4",
|
|
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"
|
|
48
54
|
}
|
package/test/index.js
CHANGED
package/test/parse.js
CHANGED
|
@@ -3,10 +3,11 @@
|
|
|
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) {
|
|
9
|
-
st.deepEqual(qs.parse('0=foo'), {
|
|
10
|
+
st.deepEqual(qs.parse('0=foo'), { 0: 'foo' });
|
|
10
11
|
st.deepEqual(qs.parse('foo=c++'), { foo: 'c ' });
|
|
11
12
|
st.deepEqual(qs.parse('a[>=]=23'), { a: { '>=': '23' } });
|
|
12
13
|
st.deepEqual(qs.parse('a[<=>]==23'), { a: { '<=>': '=23' } });
|
|
@@ -84,7 +85,7 @@ test('parse()', function (t) {
|
|
|
84
85
|
|
|
85
86
|
t.test('limits specific array indices to 20', function (st) {
|
|
86
87
|
st.deepEqual(qs.parse('a[20]=a'), { a: ['a'] });
|
|
87
|
-
st.deepEqual(qs.parse('a[21]=a'), { a: {
|
|
88
|
+
st.deepEqual(qs.parse('a[21]=a'), { a: { 21: 'a' } });
|
|
88
89
|
st.end();
|
|
89
90
|
});
|
|
90
91
|
|
|
@@ -115,14 +116,17 @@ test('parse()', function (t) {
|
|
|
115
116
|
});
|
|
116
117
|
|
|
117
118
|
t.test('transforms arrays to objects', function (st) {
|
|
118
|
-
st.deepEqual(qs.parse('foo[0]=bar&foo[bad]=baz'), { foo: {
|
|
119
|
-
st.deepEqual(qs.parse('foo[bad]=baz&foo[0]=bar'), { foo: { bad: 'baz',
|
|
120
|
-
st.deepEqual(qs.parse('foo[bad]=baz&foo[]=bar'), { foo: { bad: 'baz',
|
|
121
|
-
st.deepEqual(qs.parse('foo[]=bar&foo[bad]=baz'), { foo: {
|
|
122
|
-
st.deepEqual(qs.parse('foo[bad]=baz&foo[]=bar&foo[]=foo'), { foo: { bad: 'baz',
|
|
119
|
+
st.deepEqual(qs.parse('foo[0]=bar&foo[bad]=baz'), { foo: { 0: 'bar', bad: 'baz' } });
|
|
120
|
+
st.deepEqual(qs.parse('foo[bad]=baz&foo[0]=bar'), { foo: { bad: 'baz', 0: 'bar' } });
|
|
121
|
+
st.deepEqual(qs.parse('foo[bad]=baz&foo[]=bar'), { foo: { bad: 'baz', 0: 'bar' } });
|
|
122
|
+
st.deepEqual(qs.parse('foo[]=bar&foo[bad]=baz'), { foo: { 0: 'bar', bad: 'baz' } });
|
|
123
|
+
st.deepEqual(qs.parse('foo[bad]=baz&foo[]=bar&foo[]=foo'), { foo: { bad: 'baz', 0: 'bar', 1: 'foo' } });
|
|
123
124
|
st.deepEqual(qs.parse('foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb'), { foo: [{ a: 'a', b: 'b' }, { a: 'aa', b: 'bb' }] });
|
|
124
|
-
|
|
125
|
-
st.deepEqual(qs.parse('a[]=b&a[
|
|
125
|
+
|
|
126
|
+
st.deepEqual(qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c', { allowPrototypes: false }), { a: { 0: 'b', t: 'u' } });
|
|
127
|
+
st.deepEqual(qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c', { allowPrototypes: true }), { a: { 0: 'b', t: 'u', hasOwnProperty: 'c' } });
|
|
128
|
+
st.deepEqual(qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y', { allowPrototypes: false }), { a: { 0: 'b', x: 'y' } });
|
|
129
|
+
st.deepEqual(qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y', { allowPrototypes: true }), { a: { 0: 'b', hasOwnProperty: 'c', x: 'y' } });
|
|
126
130
|
st.end();
|
|
127
131
|
});
|
|
128
132
|
|
|
@@ -132,18 +136,16 @@ test('parse()', function (t) {
|
|
|
132
136
|
st.deepEqual(qs.parse('foo[0][0].baz=bar&fool.bad=baz', { allowDots: true }), { foo: [[{ baz: 'bar' }]], fool: { bad: 'baz' } });
|
|
133
137
|
st.deepEqual(qs.parse('foo[0].baz[0]=15&foo[0].bar=2', { allowDots: true }), { foo: [{ baz: ['15'], bar: '2' }] });
|
|
134
138
|
st.deepEqual(qs.parse('foo[0].baz[0]=15&foo[0].baz[1]=16&foo[0].bar=2', { allowDots: true }), { foo: [{ baz: ['15', '16'], bar: '2' }] });
|
|
135
|
-
st.deepEqual(qs.parse('foo.bad=baz&foo[0]=bar', { allowDots: true }), { foo: { bad: 'baz',
|
|
136
|
-
st.deepEqual(qs.parse('foo.bad=baz&foo[]=bar', { allowDots: true }), { foo: { bad: 'baz',
|
|
137
|
-
st.deepEqual(qs.parse('foo[]=bar&foo.bad=baz', { allowDots: true }), { foo: {
|
|
138
|
-
st.deepEqual(qs.parse('foo.bad=baz&foo[]=bar&foo[]=foo', { allowDots: true }), { foo: { bad: 'baz',
|
|
139
|
+
st.deepEqual(qs.parse('foo.bad=baz&foo[0]=bar', { allowDots: true }), { foo: { bad: 'baz', 0: 'bar' } });
|
|
140
|
+
st.deepEqual(qs.parse('foo.bad=baz&foo[]=bar', { allowDots: true }), { foo: { bad: 'baz', 0: 'bar' } });
|
|
141
|
+
st.deepEqual(qs.parse('foo[]=bar&foo.bad=baz', { allowDots: true }), { foo: { 0: 'bar', bad: 'baz' } });
|
|
142
|
+
st.deepEqual(qs.parse('foo.bad=baz&foo[]=bar&foo[]=foo', { allowDots: true }), { foo: { bad: 'baz', 0: 'bar', 1: 'foo' } });
|
|
139
143
|
st.deepEqual(qs.parse('foo[0].a=a&foo[0].b=b&foo[1].a=aa&foo[1].b=bb', { allowDots: true }), { foo: [{ a: 'a', b: 'b' }, { a: 'aa', b: 'bb' }] });
|
|
140
144
|
st.end();
|
|
141
145
|
});
|
|
142
146
|
|
|
143
|
-
t.deepEqual(qs.parse('a[b]=c&a=d'), { a: { b: 'c', d: true } }, 'can add keys to objects');
|
|
144
|
-
|
|
145
147
|
t.test('correctly prunes undefined values when converting an array to an object', function (st) {
|
|
146
|
-
st.deepEqual(qs.parse('a[2]=b&a[99999999]=c'), { a: {
|
|
148
|
+
st.deepEqual(qs.parse('a[2]=b&a[99999999]=c'), { a: { 2: 'b', 99999999: 'c' } });
|
|
147
149
|
st.end();
|
|
148
150
|
});
|
|
149
151
|
|
|
@@ -155,7 +157,7 @@ test('parse()', function (t) {
|
|
|
155
157
|
});
|
|
156
158
|
|
|
157
159
|
t.test('doesn\'t produce empty keys', function (st) {
|
|
158
|
-
st.deepEqual(qs.parse('_r=1&'), {
|
|
160
|
+
st.deepEqual(qs.parse('_r=1&'), { _r: '1' });
|
|
159
161
|
st.end();
|
|
160
162
|
});
|
|
161
163
|
|
|
@@ -174,9 +176,34 @@ test('parse()', function (t) {
|
|
|
174
176
|
|
|
175
177
|
t.test('allows for empty strings in arrays', function (st) {
|
|
176
178
|
st.deepEqual(qs.parse('a[]=b&a[]=&a[]=c'), { a: ['b', '', 'c'] });
|
|
177
|
-
|
|
178
|
-
st.deepEqual(
|
|
179
|
-
|
|
179
|
+
|
|
180
|
+
st.deepEqual(
|
|
181
|
+
qs.parse('a[0]=b&a[1]&a[2]=c&a[19]=', { strictNullHandling: true, arrayLimit: 20 }),
|
|
182
|
+
{ a: ['b', null, 'c', ''] },
|
|
183
|
+
'with arrayLimit 20 + array indices: null then empty string works'
|
|
184
|
+
);
|
|
185
|
+
st.deepEqual(
|
|
186
|
+
qs.parse('a[]=b&a[]&a[]=c&a[]=', { strictNullHandling: true, arrayLimit: 0 }),
|
|
187
|
+
{ a: ['b', null, 'c', ''] },
|
|
188
|
+
'with arrayLimit 0 + array brackets: null then empty string works'
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
st.deepEqual(
|
|
192
|
+
qs.parse('a[0]=b&a[1]=&a[2]=c&a[19]', { strictNullHandling: true, arrayLimit: 20 }),
|
|
193
|
+
{ a: ['b', '', 'c', null] },
|
|
194
|
+
'with arrayLimit 20 + array indices: empty string then null works'
|
|
195
|
+
);
|
|
196
|
+
st.deepEqual(
|
|
197
|
+
qs.parse('a[]=b&a[]=&a[]=c&a[]', { strictNullHandling: true, arrayLimit: 0 }),
|
|
198
|
+
{ a: ['b', '', 'c', null] },
|
|
199
|
+
'with arrayLimit 0 + array brackets: empty string then null works'
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
st.deepEqual(
|
|
203
|
+
qs.parse('a[]=&a[]=b&a[]=c'),
|
|
204
|
+
{ a: ['', 'b', 'c'] },
|
|
205
|
+
'array brackets: empty strings work'
|
|
206
|
+
);
|
|
180
207
|
st.end();
|
|
181
208
|
});
|
|
182
209
|
|
|
@@ -195,14 +222,14 @@ test('parse()', function (t) {
|
|
|
195
222
|
});
|
|
196
223
|
|
|
197
224
|
t.test('parses buffers correctly', function (st) {
|
|
198
|
-
var b =
|
|
225
|
+
var b = SaferBuffer.from('test');
|
|
199
226
|
st.deepEqual(qs.parse({ a: b }), { a: b });
|
|
200
227
|
st.end();
|
|
201
228
|
});
|
|
202
229
|
|
|
203
230
|
t.test('continues parsing when no parent is found', function (st) {
|
|
204
|
-
st.deepEqual(qs.parse('[]=&a=b'), {
|
|
205
|
-
st.deepEqual(qs.parse('[]&a=b', { strictNullHandling: true }), {
|
|
231
|
+
st.deepEqual(qs.parse('[]=&a=b'), { 0: '', a: 'b' });
|
|
232
|
+
st.deepEqual(qs.parse('[]&a=b', { strictNullHandling: true }), { 0: null, a: 'b' });
|
|
206
233
|
st.deepEqual(qs.parse('[foo]=bar'), { foo: 'bar' });
|
|
207
234
|
st.end();
|
|
208
235
|
});
|
|
@@ -218,7 +245,7 @@ test('parse()', function (t) {
|
|
|
218
245
|
st.end();
|
|
219
246
|
});
|
|
220
247
|
|
|
221
|
-
t.test('should not throw when a native prototype has an enumerable property',
|
|
248
|
+
t.test('should not throw when a native prototype has an enumerable property', function (st) {
|
|
222
249
|
Object.prototype.crash = '';
|
|
223
250
|
Array.prototype.crash = '';
|
|
224
251
|
st.doesNotThrow(qs.parse.bind(null, 'a=b'));
|
|
@@ -256,14 +283,21 @@ test('parse()', function (t) {
|
|
|
256
283
|
});
|
|
257
284
|
|
|
258
285
|
t.test('allows overriding array limit', function (st) {
|
|
259
|
-
st.deepEqual(qs.parse('a[0]=b', { arrayLimit: -1 }), { a: {
|
|
286
|
+
st.deepEqual(qs.parse('a[0]=b', { arrayLimit: -1 }), { a: { 0: 'b' } });
|
|
260
287
|
st.deepEqual(qs.parse('a[-1]=b', { arrayLimit: -1 }), { a: { '-1': 'b' } });
|
|
261
|
-
st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 }), { a: {
|
|
288
|
+
st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 }), { a: { 0: 'b', 1: 'c' } });
|
|
262
289
|
st.end();
|
|
263
290
|
});
|
|
264
291
|
|
|
265
292
|
t.test('allows disabling array parsing', function (st) {
|
|
266
|
-
|
|
293
|
+
var indices = qs.parse('a[0]=b&a[1]=c', { parseArrays: false });
|
|
294
|
+
st.deepEqual(indices, { a: { 0: 'b', 1: 'c' } });
|
|
295
|
+
st.equal(Array.isArray(indices.a), false, 'parseArrays:false, indices case is not an array');
|
|
296
|
+
|
|
297
|
+
var emptyBrackets = qs.parse('a[]=b', { parseArrays: false });
|
|
298
|
+
st.deepEqual(emptyBrackets, { a: { 0: 'b' } });
|
|
299
|
+
st.equal(Array.isArray(emptyBrackets.a), false, 'parseArrays:false, empty brackets case is not an array');
|
|
300
|
+
|
|
267
301
|
st.end();
|
|
268
302
|
});
|
|
269
303
|
|
|
@@ -307,13 +341,13 @@ test('parse()', function (t) {
|
|
|
307
341
|
|
|
308
342
|
t.test('parses an object and not child values', function (st) {
|
|
309
343
|
var input = {
|
|
310
|
-
'user[name]': { 'pop[bob]': {
|
|
344
|
+
'user[name]': { 'pop[bob]': { test: 3 } },
|
|
311
345
|
'user[email]': null
|
|
312
346
|
};
|
|
313
347
|
|
|
314
348
|
var expected = {
|
|
315
349
|
user: {
|
|
316
|
-
name: { 'pop[bob]': {
|
|
350
|
+
name: { 'pop[bob]': { test: 3 } },
|
|
317
351
|
email: null
|
|
318
352
|
}
|
|
319
353
|
};
|
|
@@ -374,13 +408,135 @@ test('parse()', function (t) {
|
|
|
374
408
|
st.end();
|
|
375
409
|
});
|
|
376
410
|
|
|
411
|
+
t.test('does not allow overwriting prototype properties', function (st) {
|
|
412
|
+
st.deepEqual(qs.parse('a[hasOwnProperty]=b', { allowPrototypes: false }), {});
|
|
413
|
+
st.deepEqual(qs.parse('hasOwnProperty=b', { allowPrototypes: false }), {});
|
|
414
|
+
|
|
415
|
+
st.deepEqual(
|
|
416
|
+
qs.parse('toString', { allowPrototypes: false }),
|
|
417
|
+
{},
|
|
418
|
+
'bare "toString" results in {}'
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
st.end();
|
|
422
|
+
});
|
|
423
|
+
|
|
377
424
|
t.test('can allow overwriting prototype properties', function (st) {
|
|
378
|
-
st.deepEqual(qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true }), { a: { hasOwnProperty: 'b' } }
|
|
379
|
-
st.deepEqual(qs.parse('hasOwnProperty=b', { allowPrototypes: true }), { hasOwnProperty: 'b' }
|
|
425
|
+
st.deepEqual(qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true }), { a: { hasOwnProperty: 'b' } });
|
|
426
|
+
st.deepEqual(qs.parse('hasOwnProperty=b', { allowPrototypes: true }), { hasOwnProperty: 'b' });
|
|
427
|
+
|
|
428
|
+
st.deepEqual(
|
|
429
|
+
qs.parse('toString', { allowPrototypes: true }),
|
|
430
|
+
{ toString: '' },
|
|
431
|
+
'bare "toString" results in { toString: "" }'
|
|
432
|
+
);
|
|
433
|
+
|
|
434
|
+
st.end();
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
t.test('params starting with a closing bracket', function (st) {
|
|
438
|
+
st.deepEqual(qs.parse(']=toString'), { ']': 'toString' });
|
|
439
|
+
st.deepEqual(qs.parse(']]=toString'), { ']]': 'toString' });
|
|
440
|
+
st.deepEqual(qs.parse(']hello]=toString'), { ']hello]': 'toString' });
|
|
441
|
+
st.end();
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
t.test('params starting with a starting bracket', function (st) {
|
|
445
|
+
st.deepEqual(qs.parse('[=toString'), { '[': 'toString' });
|
|
446
|
+
st.deepEqual(qs.parse('[[=toString'), { '[[': 'toString' });
|
|
447
|
+
st.deepEqual(qs.parse('[hello[=toString'), { '[hello[': 'toString' });
|
|
448
|
+
st.end();
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
t.test('add keys to objects', function (st) {
|
|
452
|
+
st.deepEqual(
|
|
453
|
+
qs.parse('a[b]=c&a=d'),
|
|
454
|
+
{ a: { b: 'c', d: true } },
|
|
455
|
+
'can add keys to objects'
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
st.deepEqual(
|
|
459
|
+
qs.parse('a[b]=c&a=toString'),
|
|
460
|
+
{ a: { b: 'c' } },
|
|
461
|
+
'can not overwrite prototype'
|
|
462
|
+
);
|
|
463
|
+
|
|
464
|
+
st.deepEqual(
|
|
465
|
+
qs.parse('a[b]=c&a=toString', { allowPrototypes: true }),
|
|
466
|
+
{ a: { b: 'c', toString: true } },
|
|
467
|
+
'can overwrite prototype with allowPrototypes true'
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
st.deepEqual(
|
|
471
|
+
qs.parse('a[b]=c&a=toString', { plainObjects: true }),
|
|
472
|
+
{ __proto__: null, a: { __proto__: null, b: 'c', toString: true } },
|
|
473
|
+
'can overwrite prototype with plainObjects true'
|
|
474
|
+
);
|
|
475
|
+
|
|
476
|
+
st.end();
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
t.test('dunder proto is ignored', function (st) {
|
|
480
|
+
var payload = 'categories[__proto__]=login&categories[__proto__]&categories[length]=42';
|
|
481
|
+
var result = qs.parse(payload, { allowPrototypes: true });
|
|
482
|
+
|
|
483
|
+
st.deepEqual(
|
|
484
|
+
result,
|
|
485
|
+
{
|
|
486
|
+
categories: {
|
|
487
|
+
length: '42'
|
|
488
|
+
}
|
|
489
|
+
},
|
|
490
|
+
'silent [[Prototype]] payload'
|
|
491
|
+
);
|
|
492
|
+
|
|
493
|
+
var plainResult = qs.parse(payload, { allowPrototypes: true, plainObjects: true });
|
|
494
|
+
|
|
495
|
+
st.deepEqual(
|
|
496
|
+
plainResult,
|
|
497
|
+
{
|
|
498
|
+
__proto__: null,
|
|
499
|
+
categories: {
|
|
500
|
+
__proto__: null,
|
|
501
|
+
length: '42'
|
|
502
|
+
}
|
|
503
|
+
},
|
|
504
|
+
'silent [[Prototype]] payload: plain objects'
|
|
505
|
+
);
|
|
506
|
+
|
|
507
|
+
var query = qs.parse('categories[__proto__]=cats&categories[__proto__]=dogs&categories[some][json]=toInject', { allowPrototypes: true });
|
|
508
|
+
|
|
509
|
+
st.notOk(Array.isArray(query.categories), 'is not an array');
|
|
510
|
+
st.notOk(query.categories instanceof Array, 'is not instanceof an array');
|
|
511
|
+
st.deepEqual(query.categories, { some: { json: 'toInject' } });
|
|
512
|
+
st.equal(JSON.stringify(query.categories), '{"some":{"json":"toInject"}}', 'stringifies as a non-array');
|
|
513
|
+
|
|
514
|
+
st.deepEqual(
|
|
515
|
+
qs.parse('foo[__proto__][hidden]=value&foo[bar]=stuffs', { allowPrototypes: true }),
|
|
516
|
+
{
|
|
517
|
+
foo: {
|
|
518
|
+
bar: 'stuffs'
|
|
519
|
+
}
|
|
520
|
+
},
|
|
521
|
+
'hidden values'
|
|
522
|
+
);
|
|
523
|
+
|
|
524
|
+
st.deepEqual(
|
|
525
|
+
qs.parse('foo[__proto__][hidden]=value&foo[bar]=stuffs', { allowPrototypes: true, plainObjects: true }),
|
|
526
|
+
{
|
|
527
|
+
__proto__: null,
|
|
528
|
+
foo: {
|
|
529
|
+
__proto__: null,
|
|
530
|
+
bar: 'stuffs'
|
|
531
|
+
}
|
|
532
|
+
},
|
|
533
|
+
'hidden values: plain objects'
|
|
534
|
+
);
|
|
535
|
+
|
|
380
536
|
st.end();
|
|
381
537
|
});
|
|
382
538
|
|
|
383
|
-
t.test('can return
|
|
539
|
+
t.test('can return null objects', { skip: !Object.create }, function (st) {
|
|
384
540
|
var expected = Object.create(null);
|
|
385
541
|
expected.a = Object.create(null);
|
|
386
542
|
expected.a.b = 'c';
|
|
@@ -398,25 +554,23 @@ test('parse()', function (t) {
|
|
|
398
554
|
t.test('can parse with custom encoding', function (st) {
|
|
399
555
|
st.deepEqual(qs.parse('%8c%a7=%91%e5%8d%e3%95%7b', {
|
|
400
556
|
decoder: function (str) {
|
|
401
|
-
var reg =
|
|
557
|
+
var reg = /%([0-9A-F]{2})/ig;
|
|
402
558
|
var result = [];
|
|
403
559
|
var parts;
|
|
404
|
-
var last = 0;
|
|
405
|
-
while (parts = reg.exec(str)) {
|
|
560
|
+
// var last = 0;
|
|
561
|
+
while ((parts = reg.exec(str))) {
|
|
406
562
|
result.push(parseInt(parts[1], 16));
|
|
407
|
-
last = parts.index + parts[0].length;
|
|
563
|
+
// last = parts.index + parts[0].length;
|
|
408
564
|
}
|
|
409
|
-
return iconv.decode(
|
|
565
|
+
return iconv.decode(SaferBuffer.from(result), 'shift_jis').toString();
|
|
410
566
|
}
|
|
411
567
|
}), { 県: '大阪府' });
|
|
412
568
|
st.end();
|
|
413
569
|
});
|
|
414
570
|
|
|
415
571
|
t.test('throws error with wrong decoder', function (st) {
|
|
416
|
-
st
|
|
417
|
-
qs.parse({}, {
|
|
418
|
-
decoder: 'string'
|
|
419
|
-
});
|
|
572
|
+
st['throws'](function () {
|
|
573
|
+
qs.parse({}, { decoder: 'string' });
|
|
420
574
|
}, new TypeError('Decoder has to be a function.'));
|
|
421
575
|
st.end();
|
|
422
576
|
});
|