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/stringify.js
CHANGED
|
@@ -1,291 +1,235 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
var test = require('tape');
|
|
4
|
+
var qs = require('../');
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const lab = exports.lab = Lab.script();
|
|
19
|
-
const expect = Code.expect;
|
|
20
|
-
const describe = lab.experiment;
|
|
21
|
-
const it = lab.test;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
describe('stringify()', () => {
|
|
25
|
-
|
|
26
|
-
it('stringifies a querystring object', (done) => {
|
|
27
|
-
|
|
28
|
-
expect(Qs.stringify({ a: 'b' })).to.equal('a=b');
|
|
29
|
-
expect(Qs.stringify({ a: 1 })).to.equal('a=1');
|
|
30
|
-
expect(Qs.stringify({ a: 1, b: 2 })).to.equal('a=1&b=2');
|
|
31
|
-
expect(Qs.stringify({ a: 'A_Z' })).to.equal('a=A_Z');
|
|
32
|
-
expect(Qs.stringify({ a: '€' })).to.equal('a=%E2%82%AC');
|
|
33
|
-
expect(Qs.stringify({ a: '' })).to.equal('a=%EE%80%80');
|
|
34
|
-
expect(Qs.stringify({ a: 'א' })).to.equal('a=%D7%90');
|
|
35
|
-
expect(Qs.stringify({ a: '𐐷' })).to.equal('a=%F0%90%90%B7');
|
|
36
|
-
done();
|
|
6
|
+
test('stringify()', function (t) {
|
|
7
|
+
t.test('stringifies a querystring object', function (st) {
|
|
8
|
+
st.equal(qs.stringify({ a: 'b' }), 'a=b');
|
|
9
|
+
st.equal(qs.stringify({ a: 1 }), 'a=1');
|
|
10
|
+
st.equal(qs.stringify({ a: 1, b: 2 }), 'a=1&b=2');
|
|
11
|
+
st.equal(qs.stringify({ a: 'A_Z' }), 'a=A_Z');
|
|
12
|
+
st.equal(qs.stringify({ a: '€' }), 'a=%E2%82%AC');
|
|
13
|
+
st.equal(qs.stringify({ a: '' }), 'a=%EE%80%80');
|
|
14
|
+
st.equal(qs.stringify({ a: 'א' }), 'a=%D7%90');
|
|
15
|
+
st.equal(qs.stringify({ a: '𐐷' }), 'a=%F0%90%90%B7');
|
|
16
|
+
st.end();
|
|
37
17
|
});
|
|
38
18
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
done();
|
|
19
|
+
t.test('stringifies a nested object', function (st) {
|
|
20
|
+
st.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
|
|
21
|
+
st.equal(qs.stringify({ a: { b: { c: { d: 'e' } } } }), 'a%5Bb%5D%5Bc%5D%5Bd%5D=e');
|
|
22
|
+
st.end();
|
|
44
23
|
});
|
|
45
24
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
done();
|
|
25
|
+
t.test('stringifies an array value', function (st) {
|
|
26
|
+
st.equal(qs.stringify({ a: ['b', 'c', 'd'] }), 'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d');
|
|
27
|
+
st.end();
|
|
50
28
|
});
|
|
51
29
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
done();
|
|
30
|
+
t.test('omits nulls when asked', function (st) {
|
|
31
|
+
st.equal(qs.stringify({ a: 'b', c: null }, { skipNulls: true }), 'a=b');
|
|
32
|
+
st.end();
|
|
56
33
|
});
|
|
57
34
|
|
|
58
35
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
done();
|
|
36
|
+
t.test('omits nested nulls when asked', function (st) {
|
|
37
|
+
st.equal(qs.stringify({ a: { b: 'c', d: null } }, { skipNulls: true }), 'a%5Bb%5D=c');
|
|
38
|
+
st.end();
|
|
63
39
|
});
|
|
64
40
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
done();
|
|
41
|
+
t.test('omits array indices when asked', function (st) {
|
|
42
|
+
st.equal(qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false }), 'a=b&a=c&a=d');
|
|
43
|
+
st.end();
|
|
69
44
|
});
|
|
70
45
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
done();
|
|
46
|
+
t.test('stringifies a nested array value', function (st) {
|
|
47
|
+
st.equal(qs.stringify({ a: { b: ['c', 'd'] } }), 'a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d');
|
|
48
|
+
st.end();
|
|
75
49
|
});
|
|
76
50
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
done();
|
|
51
|
+
t.test('stringifies an object inside an array', function (st) {
|
|
52
|
+
st.equal(qs.stringify({ a: [{ b: 'c' }] }), 'a%5B0%5D%5Bb%5D=c');
|
|
53
|
+
st.equal(qs.stringify({ a: [{ b: { c: [1] } }] }), 'a%5B0%5D%5Bb%5D%5Bc%5D%5B0%5D=1');
|
|
54
|
+
st.end();
|
|
82
55
|
});
|
|
83
56
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
done();
|
|
57
|
+
t.test('does not omit object keys when indices = false', function (st) {
|
|
58
|
+
st.equal(qs.stringify({ a: [{ b: 'c' }] }, { indices: false }), 'a%5Bb%5D=c');
|
|
59
|
+
st.end();
|
|
88
60
|
});
|
|
89
61
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
done();
|
|
62
|
+
t.test('uses indices notation for arrays when indices=true', function (st) {
|
|
63
|
+
st.equal(qs.stringify({ a: ['b', 'c'] }, { indices: true }), 'a%5B0%5D=b&a%5B1%5D=c');
|
|
64
|
+
st.end();
|
|
94
65
|
});
|
|
95
66
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
done();
|
|
67
|
+
t.test('uses indices notation for arrays when no arrayFormat is specified', function (st) {
|
|
68
|
+
st.equal(qs.stringify({ a: ['b', 'c'] }), 'a%5B0%5D=b&a%5B1%5D=c');
|
|
69
|
+
st.end();
|
|
100
70
|
});
|
|
101
71
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
done();
|
|
72
|
+
t.test('uses indices notation for arrays when no arrayFormat=indices', function (st) {
|
|
73
|
+
st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' }), 'a%5B0%5D=b&a%5B1%5D=c');
|
|
74
|
+
st.end();
|
|
106
75
|
});
|
|
107
76
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
done();
|
|
77
|
+
t.test('uses repeat notation for arrays when no arrayFormat=repeat', function (st) {
|
|
78
|
+
st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' }), 'a=b&a=c');
|
|
79
|
+
st.end();
|
|
112
80
|
});
|
|
113
81
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
done();
|
|
82
|
+
t.test('uses brackets notation for arrays when no arrayFormat=brackets', function (st) {
|
|
83
|
+
st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' }), 'a%5B%5D=b&a%5B%5D=c');
|
|
84
|
+
st.end();
|
|
118
85
|
});
|
|
119
86
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
done();
|
|
87
|
+
t.test('stringifies a complicated object', function (st) {
|
|
88
|
+
st.equal(qs.stringify({ a: { b: 'c', d: 'e' } }), 'a%5Bb%5D=c&a%5Bd%5D=e');
|
|
89
|
+
st.end();
|
|
124
90
|
});
|
|
125
91
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
expect(Qs.stringify({ a: null }, { strictNullHandling: true })).to.equal('a');
|
|
92
|
+
t.test('stringifies an empty value', function (st) {
|
|
93
|
+
st.equal(qs.stringify({ a: '' }), 'a=');
|
|
94
|
+
st.equal(qs.stringify({ a: null }, { strictNullHandling: true }), 'a');
|
|
130
95
|
|
|
131
|
-
|
|
132
|
-
|
|
96
|
+
st.equal(qs.stringify({ a: '', b: '' }), 'a=&b=');
|
|
97
|
+
st.equal(qs.stringify({ a: null, b: '' }, { strictNullHandling: true }), 'a&b=');
|
|
133
98
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
99
|
+
st.equal(qs.stringify({ a: { b: '' } }), 'a%5Bb%5D=');
|
|
100
|
+
st.equal(qs.stringify({ a: { b: null } }, { strictNullHandling: true }), 'a%5Bb%5D');
|
|
101
|
+
st.equal(qs.stringify({ a: { b: null } }, { strictNullHandling: false }), 'a%5Bb%5D=');
|
|
137
102
|
|
|
138
|
-
|
|
103
|
+
st.end();
|
|
139
104
|
});
|
|
140
105
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const obj = Object.create(null);
|
|
106
|
+
t.test('stringifies an empty object', function (st) {
|
|
107
|
+
var obj = Object.create(null);
|
|
144
108
|
obj.a = 'b';
|
|
145
|
-
|
|
146
|
-
|
|
109
|
+
st.equal(qs.stringify(obj), 'a=b');
|
|
110
|
+
st.end();
|
|
147
111
|
});
|
|
148
112
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
done();
|
|
113
|
+
t.test('returns an empty string for invalid input', function (st) {
|
|
114
|
+
st.equal(qs.stringify(undefined), '');
|
|
115
|
+
st.equal(qs.stringify(false), '');
|
|
116
|
+
st.equal(qs.stringify(null), '');
|
|
117
|
+
st.equal(qs.stringify(''), '');
|
|
118
|
+
st.end();
|
|
156
119
|
});
|
|
157
120
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
const obj = {
|
|
121
|
+
t.test('stringifies an object with an empty object as a child', function (st) {
|
|
122
|
+
var obj = {
|
|
161
123
|
a: Object.create(null)
|
|
162
124
|
};
|
|
163
125
|
|
|
164
126
|
obj.a.b = 'c';
|
|
165
|
-
|
|
166
|
-
|
|
127
|
+
st.equal(qs.stringify(obj), 'a%5Bb%5D=c');
|
|
128
|
+
st.end();
|
|
167
129
|
});
|
|
168
130
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
expect(Qs.stringify({ a: undefined })).to.equal('');
|
|
131
|
+
t.test('drops keys with a value of undefined', function (st) {
|
|
132
|
+
st.equal(qs.stringify({ a: undefined }), '');
|
|
172
133
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
134
|
+
st.equal(qs.stringify({ a: { b: undefined, c: null } }, { strictNullHandling: true }), 'a%5Bc%5D');
|
|
135
|
+
st.equal(qs.stringify({ a: { b: undefined, c: null } }, { strictNullHandling: false }), 'a%5Bc%5D=');
|
|
136
|
+
st.equal(qs.stringify({ a: { b: undefined, c: '' } }), 'a%5Bc%5D=');
|
|
137
|
+
st.end();
|
|
177
138
|
});
|
|
178
139
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
done();
|
|
140
|
+
t.test('url encodes values', function (st) {
|
|
141
|
+
st.equal(qs.stringify({ a: 'b c' }), 'a=b%20c');
|
|
142
|
+
st.end();
|
|
183
143
|
});
|
|
184
144
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
done();
|
|
145
|
+
t.test('stringifies a date', function (st) {
|
|
146
|
+
var now = new Date();
|
|
147
|
+
var str = 'a=' + encodeURIComponent(now.toISOString());
|
|
148
|
+
st.equal(qs.stringify({ a: now }), str);
|
|
149
|
+
st.end();
|
|
191
150
|
});
|
|
192
151
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
done();
|
|
152
|
+
t.test('stringifies the weird object from qs', function (st) {
|
|
153
|
+
st.equal(qs.stringify({ 'my weird field': '~q1!2"\'w$5&7/z8)?' }), 'my%20weird%20field=~q1%212%22%27w%245%267%2Fz8%29%3F');
|
|
154
|
+
st.end();
|
|
197
155
|
});
|
|
198
156
|
|
|
199
|
-
|
|
200
|
-
|
|
157
|
+
t.test('skips properties that are part of the object prototype', function (st) {
|
|
201
158
|
Object.prototype.crash = 'test';
|
|
202
|
-
|
|
203
|
-
|
|
159
|
+
st.equal(qs.stringify({ a: 'b' }), 'a=b');
|
|
160
|
+
st.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
|
|
204
161
|
delete Object.prototype.crash;
|
|
205
|
-
|
|
162
|
+
st.end();
|
|
206
163
|
});
|
|
207
164
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
done();
|
|
165
|
+
t.test('stringifies boolean values', function (st) {
|
|
166
|
+
st.equal(qs.stringify({ a: true }), 'a=true');
|
|
167
|
+
st.equal(qs.stringify({ a: { b: true } }), 'a%5Bb%5D=true');
|
|
168
|
+
st.equal(qs.stringify({ b: false }), 'b=false');
|
|
169
|
+
st.equal(qs.stringify({ b: { c: false } }), 'b%5Bc%5D=false');
|
|
170
|
+
st.end();
|
|
215
171
|
});
|
|
216
172
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
done();
|
|
173
|
+
t.test('stringifies buffer values', function (st) {
|
|
174
|
+
st.equal(qs.stringify({ a: new Buffer('test') }), 'a=test');
|
|
175
|
+
st.equal(qs.stringify({ a: { b: new Buffer('test') } }), 'a%5Bb%5D=test');
|
|
176
|
+
st.end();
|
|
222
177
|
});
|
|
223
178
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
done();
|
|
179
|
+
t.test('stringifies an object using an alternative delimiter', function (st) {
|
|
180
|
+
st.equal(qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' }), 'a=b;c=d');
|
|
181
|
+
st.end();
|
|
228
182
|
});
|
|
229
183
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
const tempBuffer = global.Buffer;
|
|
184
|
+
t.test('doesn\'t blow up when Buffer global is missing', function (st) {
|
|
185
|
+
var tempBuffer = global.Buffer;
|
|
233
186
|
delete global.Buffer;
|
|
234
|
-
|
|
187
|
+
var result = qs.stringify({ a: 'b', c: 'd' });
|
|
235
188
|
global.Buffer = tempBuffer;
|
|
236
|
-
|
|
237
|
-
|
|
189
|
+
st.equal(result, 'a=b&c=d');
|
|
190
|
+
st.end();
|
|
238
191
|
});
|
|
239
192
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
done();
|
|
246
|
-
|
|
193
|
+
t.test('selects properties when filter=array', function (st) {
|
|
194
|
+
st.equal(qs.stringify({ a: 'b' }, { filter: ['a'] }), 'a=b');
|
|
195
|
+
st.equal(qs.stringify({ a: 1 }, { filter: [] }), '');
|
|
196
|
+
st.equal(qs.stringify({ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' }, { filter: ['a', 'b', 0, 2] }), 'a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3');
|
|
197
|
+
st.end();
|
|
247
198
|
});
|
|
248
199
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
const filterFunc = function (prefix, value) {
|
|
254
|
-
|
|
200
|
+
t.test('supports custom representations when filter=function', function (st) {
|
|
201
|
+
var calls = 0;
|
|
202
|
+
var obj = { a: 'b', c: 'd', e: { f: new Date(1257894000000) } };
|
|
203
|
+
var filterFunc = function (prefix, value) {
|
|
255
204
|
calls++;
|
|
256
205
|
if (calls === 1) {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
else if (prefix === 'c') {
|
|
206
|
+
st.equal(prefix, '', 'prefix is empty');
|
|
207
|
+
st.equal(value, obj);
|
|
208
|
+
} else if (prefix === 'c') {
|
|
261
209
|
return;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
expect(prefix).to.equal('e[f]');
|
|
210
|
+
} else if (value instanceof Date) {
|
|
211
|
+
st.equal(prefix, 'e[f]');
|
|
265
212
|
return value.getTime();
|
|
266
213
|
}
|
|
267
214
|
return value;
|
|
268
215
|
};
|
|
269
216
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
217
|
+
st.equal(qs.stringify(obj, { filter: filterFunc }), 'a=b&e%5Bf%5D=1257894000000');
|
|
218
|
+
st.equal(calls, 5);
|
|
219
|
+
st.end();
|
|
274
220
|
});
|
|
275
221
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
done();
|
|
222
|
+
t.test('can disable uri encoding', function (st) {
|
|
223
|
+
st.equal(qs.stringify({ a: 'b' }, { encode: false }), 'a=b');
|
|
224
|
+
st.equal(qs.stringify({ a: { b: 'c' } }, { encode: false }), 'a[b]=c');
|
|
225
|
+
st.equal(qs.stringify({ a: 'b', c: null }, { strictNullHandling: true, encode: false }), 'a=b&c');
|
|
226
|
+
st.end();
|
|
282
227
|
});
|
|
283
228
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
done();
|
|
229
|
+
t.test('can sort the keys', function (st) {
|
|
230
|
+
var sort = function (a, b) { return a.localeCompare(b); };
|
|
231
|
+
st.equal(qs.stringify({ a: 'c', z: 'y', b: 'f' }, { sort: sort }), 'a=c&b=f&z=y');
|
|
232
|
+
st.equal(qs.stringify({ a: 'c', z: { j: 'a', i: 'b' }, b: 'f' }, { sort: sort }), 'a=c&b=f&z%5Bi%5D=b&z%5Bj%5D=a');
|
|
233
|
+
st.end();
|
|
290
234
|
});
|
|
291
235
|
});
|
package/test/utils.js
CHANGED
|
@@ -1,30 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
var test = require('tape');
|
|
4
|
+
var utils = require('../lib/utils');
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// Declare internals
|
|
11
|
-
|
|
12
|
-
const internals = {};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
// Test shortcuts
|
|
16
|
-
|
|
17
|
-
const lab = exports.lab = Lab.script();
|
|
18
|
-
const expect = Code.expect;
|
|
19
|
-
const describe = lab.experiment;
|
|
20
|
-
const it = lab.test;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
describe('merge()', () => {
|
|
24
|
-
|
|
25
|
-
it('can merge two objects with the same key', (done) => {
|
|
26
|
-
|
|
27
|
-
expect(Utils.merge({ a: 'b' }, { a: 'c' })).to.deep.equal({ a: ['b', 'c'] });
|
|
28
|
-
done();
|
|
29
|
-
});
|
|
6
|
+
test('merge()', function (t) {
|
|
7
|
+
t.deepEqual(utils.merge({ a: 'b' }, { a: 'c' }), { a: ['b', 'c'] }, 'merges two objects with the same key');
|
|
8
|
+
t.end();
|
|
30
9
|
});
|