qs 6.0.0 → 6.0.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/.eslintignore +1 -1
- package/.eslintrc +17 -0
- package/.npmignore +18 -18
- package/.travis.yml +173 -8
- package/CHANGELOG.md +111 -90
- package/README.md +85 -81
- package/bower.json +0 -1
- package/component.json +1 -1
- package/dist/qs.js +107 -181
- package/lib/index.js +6 -12
- package/lib/parse.js +52 -74
- package/lib/stringify.js +39 -66
- package/lib/utils.js +52 -85
- package/package.json +29 -11
- package/test/index.js +5 -0
- package/test/parse.js +308 -332
- package/test/stringify.js +146 -202
- package/test/utils.js +5 -26
package/test/parse.js
CHANGED
|
@@ -1,480 +1,456 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
describe('parse()', () => {
|
|
25
|
-
|
|
26
|
-
it('parses a simple string', (done) => {
|
|
27
|
-
|
|
28
|
-
expect(Qs.parse('0=foo')).to.deep.equal({ '0': 'foo' });
|
|
29
|
-
expect(Qs.parse('foo=c++')).to.deep.equal({ foo: 'c ' });
|
|
30
|
-
expect(Qs.parse('a[>=]=23')).to.deep.equal({ a: { '>=': '23' } });
|
|
31
|
-
expect(Qs.parse('a[<=>]==23')).to.deep.equal({ a: { '<=>': '=23' } });
|
|
32
|
-
expect(Qs.parse('a[==]=23')).to.deep.equal({ a: { '==': '23' } });
|
|
33
|
-
expect(Qs.parse('foo', { strictNullHandling: true })).to.deep.equal({ foo: null });
|
|
34
|
-
expect(Qs.parse('foo')).to.deep.equal({ foo: '' });
|
|
35
|
-
expect(Qs.parse('foo=')).to.deep.equal({ foo: '' });
|
|
36
|
-
expect(Qs.parse('foo=bar')).to.deep.equal({ foo: 'bar' });
|
|
37
|
-
expect(Qs.parse(' foo = bar = baz ')).to.deep.equal({ ' foo ': ' bar = baz ' });
|
|
38
|
-
expect(Qs.parse('foo=bar=baz')).to.deep.equal({ foo: 'bar=baz' });
|
|
39
|
-
expect(Qs.parse('foo=bar&bar=baz')).to.deep.equal({ foo: 'bar', bar: 'baz' });
|
|
40
|
-
expect(Qs.parse('foo2=bar2&baz2=')).to.deep.equal({ foo2: 'bar2', baz2: '' });
|
|
41
|
-
expect(Qs.parse('foo=bar&baz', { strictNullHandling: true })).to.deep.equal({ foo: 'bar', baz: null });
|
|
42
|
-
expect(Qs.parse('foo=bar&baz')).to.deep.equal({ foo: 'bar', baz: '' });
|
|
43
|
-
expect(Qs.parse('cht=p3&chd=t:60,40&chs=250x100&chl=Hello|World')).to.deep.equal({
|
|
3
|
+
var test = require('tape');
|
|
4
|
+
var qs = require('../');
|
|
5
|
+
|
|
6
|
+
test('parse()', function (t) {
|
|
7
|
+
t.test('parses a simple string', function (st) {
|
|
8
|
+
st.deepEqual(qs.parse('0=foo'), { '0': 'foo' });
|
|
9
|
+
st.deepEqual(qs.parse('foo=c++'), { foo: 'c ' });
|
|
10
|
+
st.deepEqual(qs.parse('a[>=]=23'), { a: { '>=': '23' } });
|
|
11
|
+
st.deepEqual(qs.parse('a[<=>]==23'), { a: { '<=>': '=23' } });
|
|
12
|
+
st.deepEqual(qs.parse('a[==]=23'), { a: { '==': '23' } });
|
|
13
|
+
st.deepEqual(qs.parse('foo', { strictNullHandling: true }), { foo: null });
|
|
14
|
+
st.deepEqual(qs.parse('foo'), { foo: '' });
|
|
15
|
+
st.deepEqual(qs.parse('foo='), { foo: '' });
|
|
16
|
+
st.deepEqual(qs.parse('foo=bar'), { foo: 'bar' });
|
|
17
|
+
st.deepEqual(qs.parse(' foo = bar = baz '), { ' foo ': ' bar = baz ' });
|
|
18
|
+
st.deepEqual(qs.parse('foo=bar=baz'), { foo: 'bar=baz' });
|
|
19
|
+
st.deepEqual(qs.parse('foo=bar&bar=baz'), { foo: 'bar', bar: 'baz' });
|
|
20
|
+
st.deepEqual(qs.parse('foo2=bar2&baz2='), { foo2: 'bar2', baz2: '' });
|
|
21
|
+
st.deepEqual(qs.parse('foo=bar&baz', { strictNullHandling: true }), { foo: 'bar', baz: null });
|
|
22
|
+
st.deepEqual(qs.parse('foo=bar&baz'), { foo: 'bar', baz: '' });
|
|
23
|
+
st.deepEqual(qs.parse('cht=p3&chd=t:60,40&chs=250x100&chl=Hello|World'), {
|
|
44
24
|
cht: 'p3',
|
|
45
25
|
chd: 't:60,40',
|
|
46
26
|
chs: '250x100',
|
|
47
27
|
chl: 'Hello|World'
|
|
48
28
|
});
|
|
49
|
-
|
|
29
|
+
st.end();
|
|
50
30
|
});
|
|
51
31
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
done();
|
|
32
|
+
t.test('allows enabling dot notation', function (st) {
|
|
33
|
+
st.deepEqual(qs.parse('a.b=c'), { 'a.b': 'c' });
|
|
34
|
+
st.deepEqual(qs.parse('a.b=c', { allowDots: true }), { a: { b: 'c' } });
|
|
35
|
+
st.end();
|
|
57
36
|
});
|
|
58
37
|
|
|
59
|
-
|
|
38
|
+
t.deepEqual(qs.parse('a[b]=c'), { a: { b: 'c' } }, 'parses a single nested string');
|
|
39
|
+
t.deepEqual(qs.parse('a[b][c]=d'), { a: { b: { c: 'd' } } }, 'parses a double nested string');
|
|
40
|
+
t.deepEqual(
|
|
41
|
+
qs.parse('a[b][c][d][e][f][g][h]=i'),
|
|
42
|
+
{ a: { b: { c: { d: { e: { f: { '[g][h]': 'i' } } } } } } },
|
|
43
|
+
'defaults to a depth of 5'
|
|
44
|
+
);
|
|
60
45
|
|
|
61
|
-
|
|
62
|
-
|
|
46
|
+
t.test('only parses one level when depth = 1', function (st) {
|
|
47
|
+
st.deepEqual(qs.parse('a[b][c]=d', { depth: 1 }), { a: { b: { '[c]': 'd' } } });
|
|
48
|
+
st.deepEqual(qs.parse('a[b][c][d]=e', { depth: 1 }), { a: { b: { '[c][d]': 'e' } } });
|
|
49
|
+
st.end();
|
|
63
50
|
});
|
|
64
51
|
|
|
65
|
-
|
|
52
|
+
t.deepEqual(qs.parse('a=b&a=c'), { a: ['b', 'c'] }, 'parses a simple array');
|
|
66
53
|
|
|
67
|
-
|
|
68
|
-
|
|
54
|
+
t.test('parses an explicit array', function (st) {
|
|
55
|
+
st.deepEqual(qs.parse('a[]=b'), { a: ['b'] });
|
|
56
|
+
st.deepEqual(qs.parse('a[]=b&a[]=c'), { a: ['b', 'c'] });
|
|
57
|
+
st.deepEqual(qs.parse('a[]=b&a[]=c&a[]=d'), { a: ['b', 'c', 'd'] });
|
|
58
|
+
st.end();
|
|
69
59
|
});
|
|
70
60
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
61
|
+
t.test('parses a mix of simple and explicit arrays', function (st) {
|
|
62
|
+
st.deepEqual(qs.parse('a=b&a[]=c'), { a: ['b', 'c'] });
|
|
63
|
+
st.deepEqual(qs.parse('a[]=b&a=c'), { a: ['b', 'c'] });
|
|
64
|
+
st.deepEqual(qs.parse('a[0]=b&a=c'), { a: ['b', 'c'] });
|
|
65
|
+
st.deepEqual(qs.parse('a=b&a[0]=c'), { a: ['b', 'c'] });
|
|
66
|
+
st.deepEqual(qs.parse('a[1]=b&a=c'), { a: ['b', 'c'] });
|
|
67
|
+
st.deepEqual(qs.parse('a=b&a[1]=c'), { a: ['b', 'c'] });
|
|
68
|
+
st.end();
|
|
75
69
|
});
|
|
76
70
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
done();
|
|
71
|
+
t.test('parses a nested array', function (st) {
|
|
72
|
+
st.deepEqual(qs.parse('a[b][]=c&a[b][]=d'), { a: { b: ['c', 'd'] } });
|
|
73
|
+
st.deepEqual(qs.parse('a[>=]=25'), { a: { '>=': '25' } });
|
|
74
|
+
st.end();
|
|
82
75
|
});
|
|
83
76
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
77
|
+
t.test('allows to specify array indices', function (st) {
|
|
78
|
+
st.deepEqual(qs.parse('a[1]=c&a[0]=b&a[2]=d'), { a: ['b', 'c', 'd'] });
|
|
79
|
+
st.deepEqual(qs.parse('a[1]=c&a[0]=b'), { a: ['b', 'c'] });
|
|
80
|
+
st.deepEqual(qs.parse('a[1]=c'), { a: ['c'] });
|
|
81
|
+
st.end();
|
|
88
82
|
});
|
|
89
83
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
expect(Qs.parse('a[]=b&a[]=c&a[]=d')).to.deep.equal({ a: ['b', 'c', 'd'] });
|
|
95
|
-
done();
|
|
84
|
+
t.test('limits specific array indices to 20', function (st) {
|
|
85
|
+
st.deepEqual(qs.parse('a[20]=a'), { a: ['a'] });
|
|
86
|
+
st.deepEqual(qs.parse('a[21]=a'), { a: { '21': 'a' } });
|
|
87
|
+
st.end();
|
|
96
88
|
});
|
|
97
89
|
|
|
98
|
-
|
|
90
|
+
t.deepEqual(qs.parse('a[12b]=c'), { a: { '12b': 'c' } }, 'supports keys that begin with a number');
|
|
99
91
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
expect(Qs.parse('a=b&a[0]=c')).to.deep.equal({ a: ['b', 'c'] });
|
|
104
|
-
expect(Qs.parse('a[1]=b&a=c')).to.deep.equal({ a: ['b', 'c'] });
|
|
105
|
-
expect(Qs.parse('a=b&a[1]=c')).to.deep.equal({ a: ['b', 'c'] });
|
|
106
|
-
done();
|
|
92
|
+
t.test('supports encoded = signs', function (st) {
|
|
93
|
+
st.deepEqual(qs.parse('he%3Dllo=th%3Dere'), { 'he=llo': 'th=ere' });
|
|
94
|
+
st.end();
|
|
107
95
|
});
|
|
108
96
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
done();
|
|
97
|
+
t.test('is ok with url encoded strings', function (st) {
|
|
98
|
+
st.deepEqual(qs.parse('a[b%20c]=d'), { a: { 'b c': 'd' } });
|
|
99
|
+
st.deepEqual(qs.parse('a[b]=c%20d'), { a: { b: 'c d' } });
|
|
100
|
+
st.end();
|
|
114
101
|
});
|
|
115
102
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
expect(Qs.parse('a[1]=c')).to.deep.equal({ a: ['c'] });
|
|
121
|
-
done();
|
|
103
|
+
t.test('allows brackets in the value', function (st) {
|
|
104
|
+
st.deepEqual(qs.parse('pets=["tobi"]'), { pets: '["tobi"]' });
|
|
105
|
+
st.deepEqual(qs.parse('operators=[">=", "<="]'), { operators: '[">=", "<="]' });
|
|
106
|
+
st.end();
|
|
122
107
|
});
|
|
123
108
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
109
|
+
t.test('allows empty values', function (st) {
|
|
110
|
+
st.deepEqual(qs.parse(''), {});
|
|
111
|
+
st.deepEqual(qs.parse(null), {});
|
|
112
|
+
st.deepEqual(qs.parse(undefined), {});
|
|
113
|
+
st.end();
|
|
129
114
|
});
|
|
130
115
|
|
|
131
|
-
|
|
116
|
+
t.test('transforms arrays to objects', function (st) {
|
|
117
|
+
st.deepEqual(qs.parse('foo[0]=bar&foo[bad]=baz'), { foo: { '0': 'bar', bad: 'baz' } });
|
|
118
|
+
st.deepEqual(qs.parse('foo[bad]=baz&foo[0]=bar'), { foo: { bad: 'baz', '0': 'bar' } });
|
|
119
|
+
st.deepEqual(qs.parse('foo[bad]=baz&foo[]=bar'), { foo: { bad: 'baz', '0': 'bar' } });
|
|
120
|
+
st.deepEqual(qs.parse('foo[]=bar&foo[bad]=baz'), { foo: { '0': 'bar', bad: 'baz' } });
|
|
121
|
+
st.deepEqual(qs.parse('foo[bad]=baz&foo[]=bar&foo[]=foo'), { foo: { bad: 'baz', '0': 'bar', '1': 'foo' } });
|
|
122
|
+
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' }] });
|
|
132
123
|
|
|
133
|
-
|
|
134
|
-
|
|
124
|
+
st.deepEqual(qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c', { allowPrototypes: false }), { a: { 0: 'b', t: 'u' } });
|
|
125
|
+
st.deepEqual(qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c', { allowPrototypes: true }), { a: { 0: 'b', t: 'u', hasOwnProperty: 'c' } });
|
|
126
|
+
st.deepEqual(qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y', { allowPrototypes: false }), { a: { 0: 'b', x: 'y' } });
|
|
127
|
+
st.deepEqual(qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y', { allowPrototypes: true }), { a: { 0: 'b', hasOwnProperty: 'c', x: 'y' } });
|
|
128
|
+
st.end();
|
|
135
129
|
});
|
|
136
130
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
131
|
+
t.test('transforms arrays to objects (dot notation)', function (st) {
|
|
132
|
+
st.deepEqual(qs.parse('foo[0].baz=bar&fool.bad=baz', { allowDots: true }), { foo: [{ baz: 'bar' }], fool: { bad: 'baz' } });
|
|
133
|
+
st.deepEqual(qs.parse('foo[0].baz=bar&fool.bad.boo=baz', { allowDots: true }), { foo: [{ baz: 'bar' }], fool: { bad: { boo: 'baz' } } });
|
|
134
|
+
st.deepEqual(qs.parse('foo[0][0].baz=bar&fool.bad=baz', { allowDots: true }), { foo: [[{ baz: 'bar' }]], fool: { bad: 'baz' } });
|
|
135
|
+
st.deepEqual(qs.parse('foo[0].baz[0]=15&foo[0].bar=2', { allowDots: true }), { foo: [{ baz: ['15'], bar: '2' }] });
|
|
136
|
+
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' }] });
|
|
137
|
+
st.deepEqual(qs.parse('foo.bad=baz&foo[0]=bar', { allowDots: true }), { foo: { bad: 'baz', '0': 'bar' } });
|
|
138
|
+
st.deepEqual(qs.parse('foo.bad=baz&foo[]=bar', { allowDots: true }), { foo: { bad: 'baz', '0': 'bar' } });
|
|
139
|
+
st.deepEqual(qs.parse('foo[]=bar&foo.bad=baz', { allowDots: true }), { foo: { '0': 'bar', bad: 'baz' } });
|
|
140
|
+
st.deepEqual(qs.parse('foo.bad=baz&foo[]=bar&foo[]=foo', { allowDots: true }), { foo: { bad: 'baz', '0': 'bar', '1': 'foo' } });
|
|
141
|
+
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' }] });
|
|
142
|
+
st.end();
|
|
141
143
|
});
|
|
142
144
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
expect(Qs.parse('a[b]=c%20d')).to.deep.equal({ a: { b: 'c d' } });
|
|
147
|
-
done();
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it('allows brackets in the value', (done) => {
|
|
151
|
-
|
|
152
|
-
expect(Qs.parse('pets=["tobi"]')).to.deep.equal({ pets: '["tobi"]' });
|
|
153
|
-
expect(Qs.parse('operators=[">=", "<="]')).to.deep.equal({ operators: '[">=", "<="]' });
|
|
154
|
-
done();
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it('allows empty values', (done) => {
|
|
158
|
-
|
|
159
|
-
expect(Qs.parse('')).to.deep.equal({});
|
|
160
|
-
expect(Qs.parse(null)).to.deep.equal({});
|
|
161
|
-
expect(Qs.parse(undefined)).to.deep.equal({});
|
|
162
|
-
done();
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
it('transforms arrays to objects', (done) => {
|
|
166
|
-
|
|
167
|
-
expect(Qs.parse('foo[0]=bar&foo[bad]=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } });
|
|
168
|
-
expect(Qs.parse('foo[bad]=baz&foo[0]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } });
|
|
169
|
-
expect(Qs.parse('foo[bad]=baz&foo[]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } });
|
|
170
|
-
expect(Qs.parse('foo[]=bar&foo[bad]=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } });
|
|
171
|
-
expect(Qs.parse('foo[bad]=baz&foo[]=bar&foo[]=foo')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar', '1': 'foo' } });
|
|
172
|
-
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' }] });
|
|
173
|
-
expect(Qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c')).to.deep.equal({ a: { '0': 'b', t: 'u', c: true } });
|
|
174
|
-
expect(Qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y')).to.deep.equal({ a: { '0': 'b', '1': 'c', x: 'y' } });
|
|
175
|
-
done();
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
it('transforms arrays to objects (dot notation)', (done) => {
|
|
179
|
-
|
|
180
|
-
expect(Qs.parse('foo[0].baz=bar&fool.bad=baz', { allowDots: true })).to.deep.equal({ foo: [{ baz: 'bar' }], fool: { bad: 'baz' } });
|
|
181
|
-
expect(Qs.parse('foo[0].baz=bar&fool.bad.boo=baz', { allowDots: true })).to.deep.equal({ foo: [{ baz: 'bar' }], fool: { bad: { boo: 'baz' } } });
|
|
182
|
-
expect(Qs.parse('foo[0][0].baz=bar&fool.bad=baz', { allowDots: true })).to.deep.equal({ foo: [[{ baz: 'bar' }]], fool: { bad: 'baz' } });
|
|
183
|
-
expect(Qs.parse('foo[0].baz[0]=15&foo[0].bar=2', { allowDots: true })).to.deep.equal({ foo: [{ baz: ['15'], bar: '2' }] });
|
|
184
|
-
expect(Qs.parse('foo[0].baz[0]=15&foo[0].baz[1]=16&foo[0].bar=2', { allowDots: true })).to.deep.equal({ foo: [{ baz: ['15', '16'], bar: '2' }] });
|
|
185
|
-
expect(Qs.parse('foo.bad=baz&foo[0]=bar', { allowDots: true })).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } });
|
|
186
|
-
expect(Qs.parse('foo.bad=baz&foo[]=bar', { allowDots: true })).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } });
|
|
187
|
-
expect(Qs.parse('foo[]=bar&foo.bad=baz', { allowDots: true })).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } });
|
|
188
|
-
expect(Qs.parse('foo.bad=baz&foo[]=bar&foo[]=foo', { allowDots: true })).to.deep.equal({ foo: { bad: 'baz', '0': 'bar', '1': 'foo' } });
|
|
189
|
-
expect(Qs.parse('foo[0].a=a&foo[0].b=b&foo[1].a=aa&foo[1].b=bb', { allowDots: true })).to.deep.equal({ foo: [{ a: 'a', b: 'b' }, { a: 'aa', b: 'bb' }] });
|
|
190
|
-
done();
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
it('can add keys to objects', (done) => {
|
|
194
|
-
|
|
195
|
-
expect(Qs.parse('a[b]=c&a=d')).to.deep.equal({ a: { b: 'c', d: true } });
|
|
196
|
-
done();
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
it('correctly prunes undefined values when converting an array to an object', (done) => {
|
|
200
|
-
|
|
201
|
-
expect(Qs.parse('a[2]=b&a[99999999]=c')).to.deep.equal({ a: { '2': 'b', '99999999': 'c' } });
|
|
202
|
-
done();
|
|
145
|
+
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: { '2': 'b', '99999999': 'c' } });
|
|
147
|
+
st.end();
|
|
203
148
|
});
|
|
204
149
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
done();
|
|
150
|
+
t.test('supports malformed uri characters', function (st) {
|
|
151
|
+
st.deepEqual(qs.parse('{%:%}', { strictNullHandling: true }), { '{%:%}': null });
|
|
152
|
+
st.deepEqual(qs.parse('{%:%}='), { '{%:%}': '' });
|
|
153
|
+
st.deepEqual(qs.parse('foo=%:%}'), { foo: '%:%}' });
|
|
154
|
+
st.end();
|
|
211
155
|
});
|
|
212
156
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
done();
|
|
157
|
+
t.test('doesn\'t produce empty keys', function (st) {
|
|
158
|
+
st.deepEqual(qs.parse('_r=1&'), { '_r': '1' });
|
|
159
|
+
st.end();
|
|
217
160
|
});
|
|
218
161
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
done();
|
|
162
|
+
t.test('cannot access Object prototype', function (st) {
|
|
163
|
+
qs.parse('constructor[prototype][bad]=bad');
|
|
164
|
+
qs.parse('bad[constructor][prototype][bad]=bad');
|
|
165
|
+
st.equal(typeof Object.prototype.bad, 'undefined');
|
|
166
|
+
st.end();
|
|
225
167
|
});
|
|
226
168
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
done();
|
|
169
|
+
t.test('parses arrays of objects', function (st) {
|
|
170
|
+
st.deepEqual(qs.parse('a[][b]=c'), { a: [{ b: 'c' }] });
|
|
171
|
+
st.deepEqual(qs.parse('a[0][b]=c'), { a: [{ b: 'c' }] });
|
|
172
|
+
st.end();
|
|
232
173
|
});
|
|
233
174
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
done();
|
|
175
|
+
t.test('allows for empty strings in arrays', function (st) {
|
|
176
|
+
st.deepEqual(qs.parse('a[]=b&a[]=&a[]=c'), { a: ['b', '', 'c'] });
|
|
177
|
+
st.deepEqual(qs.parse('a[0]=b&a[1]&a[2]=c&a[19]=', { strictNullHandling: true }), { a: ['b', null, 'c', ''] });
|
|
178
|
+
st.deepEqual(qs.parse('a[0]=b&a[1]=&a[2]=c&a[19]', { strictNullHandling: true }), { a: ['b', '', 'c', null] });
|
|
179
|
+
st.deepEqual(qs.parse('a[]=&a[]=b&a[]=c'), { a: ['', 'b', 'c'] });
|
|
180
|
+
st.end();
|
|
241
181
|
});
|
|
242
182
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
done();
|
|
183
|
+
t.test('compacts sparse arrays', function (st) {
|
|
184
|
+
st.deepEqual(qs.parse('a[10]=1&a[2]=2'), { a: ['2', '1'] });
|
|
185
|
+
st.end();
|
|
247
186
|
});
|
|
248
187
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
done();
|
|
188
|
+
t.test('parses semi-parsed strings', function (st) {
|
|
189
|
+
st.deepEqual(qs.parse({ 'a[b]': 'c' }), { a: { b: 'c' } });
|
|
190
|
+
st.deepEqual(qs.parse({ 'a[b]': 'c', 'a[d]': 'e' }), { a: { b: 'c', d: 'e' } });
|
|
191
|
+
st.end();
|
|
254
192
|
});
|
|
255
193
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
done();
|
|
194
|
+
t.test('parses buffers correctly', function (st) {
|
|
195
|
+
var b = new Buffer('test');
|
|
196
|
+
st.deepEqual(qs.parse({ a: b }), { a: b });
|
|
197
|
+
st.end();
|
|
261
198
|
});
|
|
262
199
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
done();
|
|
200
|
+
t.test('continues parsing when no parent is found', function (st) {
|
|
201
|
+
st.deepEqual(qs.parse('[]=&a=b'), { '0': '', a: 'b' });
|
|
202
|
+
st.deepEqual(qs.parse('[]&a=b', { strictNullHandling: true }), { '0': null, a: 'b' });
|
|
203
|
+
st.deepEqual(qs.parse('[foo]=bar'), { foo: 'bar' });
|
|
204
|
+
st.end();
|
|
269
205
|
});
|
|
270
206
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
let str = 'a[]=a';
|
|
207
|
+
t.test('does not error when parsing a very long array', function (st) {
|
|
208
|
+
var str = 'a[]=a';
|
|
274
209
|
while (Buffer.byteLength(str) < 128 * 1024) {
|
|
275
210
|
str = str + '&' + str;
|
|
276
211
|
}
|
|
277
212
|
|
|
278
|
-
|
|
213
|
+
st.doesNotThrow(function () { qs.parse(str); });
|
|
279
214
|
|
|
280
|
-
|
|
281
|
-
}).to.not.throw();
|
|
282
|
-
|
|
283
|
-
done();
|
|
215
|
+
st.end();
|
|
284
216
|
});
|
|
285
217
|
|
|
286
|
-
|
|
287
|
-
|
|
218
|
+
t.test('should not throw when a native prototype has an enumerable property', { parallel: false }, function (st) {
|
|
288
219
|
Object.prototype.crash = '';
|
|
289
220
|
Array.prototype.crash = '';
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
221
|
+
st.doesNotThrow(qs.parse.bind(null, 'a=b'));
|
|
222
|
+
st.deepEqual(qs.parse('a=b'), { a: 'b' });
|
|
223
|
+
st.doesNotThrow(qs.parse.bind(null, 'a[][b]=c'));
|
|
224
|
+
st.deepEqual(qs.parse('a[][b]=c'), { a: [{ b: 'c' }] });
|
|
294
225
|
delete Object.prototype.crash;
|
|
295
226
|
delete Array.prototype.crash;
|
|
296
|
-
|
|
227
|
+
st.end();
|
|
297
228
|
});
|
|
298
229
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
done();
|
|
230
|
+
t.test('parses a string with an alternative string delimiter', function (st) {
|
|
231
|
+
st.deepEqual(qs.parse('a=b;c=d', { delimiter: ';' }), { a: 'b', c: 'd' });
|
|
232
|
+
st.end();
|
|
303
233
|
});
|
|
304
234
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
done();
|
|
235
|
+
t.test('parses a string with an alternative RegExp delimiter', function (st) {
|
|
236
|
+
st.deepEqual(qs.parse('a=b; c=d', { delimiter: /[;,] */ }), { a: 'b', c: 'd' });
|
|
237
|
+
st.end();
|
|
309
238
|
});
|
|
310
239
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
done();
|
|
240
|
+
t.test('does not use non-splittable objects as delimiters', function (st) {
|
|
241
|
+
st.deepEqual(qs.parse('a=b&c=d', { delimiter: true }), { a: 'b', c: 'd' });
|
|
242
|
+
st.end();
|
|
315
243
|
});
|
|
316
244
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
done();
|
|
245
|
+
t.test('allows overriding parameter limit', function (st) {
|
|
246
|
+
st.deepEqual(qs.parse('a=b&c=d', { parameterLimit: 1 }), { a: 'b' });
|
|
247
|
+
st.end();
|
|
321
248
|
});
|
|
322
249
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
done();
|
|
250
|
+
t.test('allows setting the parameter limit to Infinity', function (st) {
|
|
251
|
+
st.deepEqual(qs.parse('a=b&c=d', { parameterLimit: Infinity }), { a: 'b', c: 'd' });
|
|
252
|
+
st.end();
|
|
327
253
|
});
|
|
328
254
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
done();
|
|
255
|
+
t.test('allows overriding array limit', function (st) {
|
|
256
|
+
st.deepEqual(qs.parse('a[0]=b', { arrayLimit: -1 }), { a: { '0': 'b' } });
|
|
257
|
+
st.deepEqual(qs.parse('a[-1]=b', { arrayLimit: -1 }), { a: { '-1': 'b' } });
|
|
258
|
+
st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 }), { a: { '0': 'b', '1': 'c' } });
|
|
259
|
+
st.end();
|
|
335
260
|
});
|
|
336
261
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
done();
|
|
262
|
+
t.test('allows disabling array parsing', function (st) {
|
|
263
|
+
st.deepEqual(qs.parse('a[0]=b&a[1]=c', { parseArrays: false }), { a: { '0': 'b', '1': 'c' } });
|
|
264
|
+
st.end();
|
|
341
265
|
});
|
|
342
266
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
const input = {
|
|
267
|
+
t.test('parses an object', function (st) {
|
|
268
|
+
var input = {
|
|
346
269
|
'user[name]': { 'pop[bob]': 3 },
|
|
347
270
|
'user[email]': null
|
|
348
271
|
};
|
|
349
272
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
273
|
+
var expected = {
|
|
274
|
+
user: {
|
|
275
|
+
name: { 'pop[bob]': 3 },
|
|
276
|
+
email: null
|
|
354
277
|
}
|
|
355
278
|
};
|
|
356
279
|
|
|
357
|
-
|
|
280
|
+
var result = qs.parse(input);
|
|
358
281
|
|
|
359
|
-
|
|
360
|
-
|
|
282
|
+
st.deepEqual(result, expected);
|
|
283
|
+
st.end();
|
|
361
284
|
});
|
|
362
285
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
const input = {
|
|
286
|
+
t.test('parses an object in dot notation', function (st) {
|
|
287
|
+
var input = {
|
|
366
288
|
'user.name': { 'pop[bob]': 3 },
|
|
367
289
|
'user.email.': null
|
|
368
290
|
};
|
|
369
291
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
292
|
+
var expected = {
|
|
293
|
+
user: {
|
|
294
|
+
name: { 'pop[bob]': 3 },
|
|
295
|
+
email: null
|
|
374
296
|
}
|
|
375
297
|
};
|
|
376
298
|
|
|
377
|
-
|
|
299
|
+
var result = qs.parse(input, { allowDots: true });
|
|
378
300
|
|
|
379
|
-
|
|
380
|
-
|
|
301
|
+
st.deepEqual(result, expected);
|
|
302
|
+
st.end();
|
|
381
303
|
});
|
|
382
304
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
const input = {
|
|
305
|
+
t.test('parses an object and not child values', function (st) {
|
|
306
|
+
var input = {
|
|
386
307
|
'user[name]': { 'pop[bob]': { 'test': 3 } },
|
|
387
308
|
'user[email]': null
|
|
388
309
|
};
|
|
389
310
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
311
|
+
var expected = {
|
|
312
|
+
user: {
|
|
313
|
+
name: { 'pop[bob]': { 'test': 3 } },
|
|
314
|
+
email: null
|
|
394
315
|
}
|
|
395
316
|
};
|
|
396
317
|
|
|
397
|
-
|
|
318
|
+
var result = qs.parse(input);
|
|
398
319
|
|
|
399
|
-
|
|
400
|
-
|
|
320
|
+
st.deepEqual(result, expected);
|
|
321
|
+
st.end();
|
|
401
322
|
});
|
|
402
323
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
const tempBuffer = global.Buffer;
|
|
324
|
+
t.test('does not blow up when Buffer global is missing', function (st) {
|
|
325
|
+
var tempBuffer = global.Buffer;
|
|
406
326
|
delete global.Buffer;
|
|
407
|
-
|
|
327
|
+
var result = qs.parse('a=b&c=d');
|
|
408
328
|
global.Buffer = tempBuffer;
|
|
409
|
-
|
|
410
|
-
|
|
329
|
+
st.deepEqual(result, { a: 'b', c: 'd' });
|
|
330
|
+
st.end();
|
|
411
331
|
});
|
|
412
332
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
const a = {};
|
|
333
|
+
t.test('does not crash when parsing circular references', function (st) {
|
|
334
|
+
var a = {};
|
|
416
335
|
a.b = a;
|
|
417
336
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
expect(() => {
|
|
337
|
+
var parsed;
|
|
421
338
|
|
|
422
|
-
|
|
423
|
-
|
|
339
|
+
st.doesNotThrow(function () {
|
|
340
|
+
parsed = qs.parse({ 'foo[bar]': 'baz', 'foo[baz]': a });
|
|
341
|
+
});
|
|
424
342
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
343
|
+
st.equal('foo' in parsed, true, 'parsed has "foo" property');
|
|
344
|
+
st.equal('bar' in parsed.foo, true);
|
|
345
|
+
st.equal('baz' in parsed.foo, true);
|
|
346
|
+
st.equal(parsed.foo.bar, 'baz');
|
|
347
|
+
st.deepEqual(parsed.foo.baz, a);
|
|
348
|
+
st.end();
|
|
430
349
|
});
|
|
431
350
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
const a = Object.create(null);
|
|
351
|
+
t.test('parses plain objects correctly', function (st) {
|
|
352
|
+
var a = Object.create(null);
|
|
435
353
|
a.b = 'c';
|
|
436
354
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
355
|
+
st.deepEqual(qs.parse(a), { b: 'c' });
|
|
356
|
+
var result = qs.parse({ a: a });
|
|
357
|
+
st.equal('a' in result, true, 'result has "a" property');
|
|
358
|
+
st.deepEqual(result.a, a);
|
|
359
|
+
st.end();
|
|
442
360
|
});
|
|
443
361
|
|
|
444
|
-
|
|
362
|
+
t.test('parses dates correctly', function (st) {
|
|
363
|
+
var now = new Date();
|
|
364
|
+
st.deepEqual(qs.parse({ a: now }), { a: now });
|
|
365
|
+
st.end();
|
|
366
|
+
});
|
|
445
367
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
368
|
+
t.test('parses regular expressions correctly', function (st) {
|
|
369
|
+
var re = /^test$/;
|
|
370
|
+
st.deepEqual(qs.parse({ a: re }), { a: re });
|
|
371
|
+
st.end();
|
|
449
372
|
});
|
|
450
373
|
|
|
451
|
-
|
|
374
|
+
t.test('does not allow overwriting prototype properties', function (st) {
|
|
375
|
+
st.deepEqual(qs.parse('a[hasOwnProperty]=b', { allowPrototypes: false }), {});
|
|
376
|
+
st.deepEqual(qs.parse('hasOwnProperty=b', { allowPrototypes: false }), {});
|
|
452
377
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
378
|
+
st.deepEqual(
|
|
379
|
+
qs.parse('toString', { allowPrototypes: false }),
|
|
380
|
+
{},
|
|
381
|
+
'bare "toString" results in {}'
|
|
382
|
+
);
|
|
383
|
+
|
|
384
|
+
st.end();
|
|
456
385
|
});
|
|
457
386
|
|
|
458
|
-
|
|
387
|
+
t.test('can allow overwriting prototype properties', function (st) {
|
|
388
|
+
st.deepEqual(qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true }), { a: { hasOwnProperty: 'b' } });
|
|
389
|
+
st.deepEqual(qs.parse('hasOwnProperty=b', { allowPrototypes: true }), { hasOwnProperty: 'b' });
|
|
390
|
+
|
|
391
|
+
st.deepEqual(
|
|
392
|
+
qs.parse('toString', { allowPrototypes: true }),
|
|
393
|
+
{ toString: '' },
|
|
394
|
+
'bare "toString" results in { toString: "" }'
|
|
395
|
+
);
|
|
459
396
|
|
|
460
|
-
|
|
461
|
-
expect(Qs.parse('hasOwnProperty=b', { allowPrototypes: true })).to.deep.equal({ hasOwnProperty: 'b' }, { prototype: false });
|
|
462
|
-
done();
|
|
397
|
+
st.end();
|
|
463
398
|
});
|
|
464
399
|
|
|
465
|
-
|
|
400
|
+
t.test('params starting with a closing bracket', function (st) {
|
|
401
|
+
st.deepEqual(qs.parse(']=toString'), { ']': 'toString' });
|
|
402
|
+
st.deepEqual(qs.parse(']]=toString'), { ']]': 'toString' });
|
|
403
|
+
st.deepEqual(qs.parse(']hello]=toString'), { ']hello]': 'toString' });
|
|
404
|
+
st.end();
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
t.test('params starting with a starting bracket', function (st) {
|
|
408
|
+
st.deepEqual(qs.parse('[=toString'), { '[': 'toString' });
|
|
409
|
+
st.deepEqual(qs.parse('[[=toString'), { '[[': 'toString' });
|
|
410
|
+
st.deepEqual(qs.parse('[hello[=toString'), { '[hello[': 'toString' });
|
|
411
|
+
st.end();
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
t.test('add keys to objects', function (st) {
|
|
415
|
+
st.deepEqual(
|
|
416
|
+
qs.parse('a[b]=c&a=d'),
|
|
417
|
+
{ a: { b: 'c', d: true } },
|
|
418
|
+
'can add keys to objects'
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
st.deepEqual(
|
|
422
|
+
qs.parse('a[b]=c&a=toString'),
|
|
423
|
+
{ a: { b: 'c' } },
|
|
424
|
+
'can not overwrite prototype'
|
|
425
|
+
);
|
|
426
|
+
|
|
427
|
+
st.deepEqual(
|
|
428
|
+
qs.parse('a[b]=c&a=toString', { allowPrototypes: true }),
|
|
429
|
+
{ a: { b: 'c', toString: true } },
|
|
430
|
+
'can overwrite prototype with allowPrototypes true'
|
|
431
|
+
);
|
|
432
|
+
|
|
433
|
+
st.deepEqual(
|
|
434
|
+
qs.parse('a[b]=c&a=toString', { plainObjects: true }),
|
|
435
|
+
{ a: { b: 'c', toString: true } },
|
|
436
|
+
'can overwrite prototype with plainObjects true'
|
|
437
|
+
);
|
|
438
|
+
|
|
439
|
+
st.end();
|
|
440
|
+
});
|
|
466
441
|
|
|
467
|
-
|
|
442
|
+
t.test('can return null objects', { skip: !Object.create }, function (st) {
|
|
443
|
+
var expected = Object.create(null);
|
|
468
444
|
expected.a = Object.create(null);
|
|
469
445
|
expected.a.b = 'c';
|
|
470
446
|
expected.a.hasOwnProperty = 'd';
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
447
|
+
st.deepEqual(qs.parse('a[b]=c&a[hasOwnProperty]=d', { plainObjects: true }), expected);
|
|
448
|
+
st.deepEqual(qs.parse(null, { plainObjects: true }), Object.create(null));
|
|
449
|
+
var expectedArray = Object.create(null);
|
|
474
450
|
expectedArray.a = Object.create(null);
|
|
475
451
|
expectedArray.a['0'] = 'b';
|
|
476
452
|
expectedArray.a.c = 'd';
|
|
477
|
-
|
|
478
|
-
|
|
453
|
+
st.deepEqual(qs.parse('a[]=b&a[c]=d', { plainObjects: true }), expectedArray);
|
|
454
|
+
st.end();
|
|
479
455
|
});
|
|
480
456
|
});
|