qs 6.2.4 → 6.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +1 -0
- package/.eslintrc +8 -28
- package/CHANGELOG.md +13 -25
- package/LICENSE +28 -0
- package/README.md +27 -29
- package/dist/qs.js +125 -119
- package/lib/formats.js +18 -0
- package/lib/index.js +6 -4
- package/lib/parse.js +29 -31
- package/lib/stringify.js +37 -29
- package/lib/utils.js +27 -49
- package/package.json +48 -52
- package/test/.eslintrc +9 -0
- package/test/parse.js +37 -155
- package/test/stringify.js +260 -25
- package/test/utils.js +0 -7
- package/.editorconfig +0 -45
- package/.github/FUNDING.yml +0 -12
- package/.nycrc +0 -13
- package/LICENSE.md +0 -29
- package/bower.json +0 -21
- package/component.json +0 -15
package/test/parse.js
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
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;
|
|
7
6
|
|
|
8
7
|
test('parse()', function (t) {
|
|
9
8
|
t.test('parses a simple string', function (st) {
|
|
@@ -65,8 +64,15 @@ test('parse()', function (t) {
|
|
|
65
64
|
st.deepEqual(qs.parse('a[]=b&a=c'), { a: ['b', 'c'] });
|
|
66
65
|
st.deepEqual(qs.parse('a[0]=b&a=c'), { a: ['b', 'c'] });
|
|
67
66
|
st.deepEqual(qs.parse('a=b&a[0]=c'), { a: ['b', 'c'] });
|
|
68
|
-
|
|
69
|
-
st.deepEqual(qs.parse('a=b&a
|
|
67
|
+
|
|
68
|
+
st.deepEqual(qs.parse('a[1]=b&a=c', { arrayLimit: 20 }), { a: ['b', 'c'] });
|
|
69
|
+
st.deepEqual(qs.parse('a[]=b&a=c', { arrayLimit: 0 }), { a: ['b', 'c'] });
|
|
70
|
+
st.deepEqual(qs.parse('a[]=b&a=c'), { a: ['b', 'c'] });
|
|
71
|
+
|
|
72
|
+
st.deepEqual(qs.parse('a=b&a[1]=c', { arrayLimit: 20 }), { a: ['b', 'c'] });
|
|
73
|
+
st.deepEqual(qs.parse('a=b&a[]=c', { arrayLimit: 0 }), { a: ['b', 'c'] });
|
|
74
|
+
st.deepEqual(qs.parse('a=b&a[]=c'), { a: ['b', 'c'] });
|
|
75
|
+
|
|
70
76
|
st.end();
|
|
71
77
|
});
|
|
72
78
|
|
|
@@ -79,13 +85,15 @@ test('parse()', function (t) {
|
|
|
79
85
|
t.test('allows to specify array indices', function (st) {
|
|
80
86
|
st.deepEqual(qs.parse('a[1]=c&a[0]=b&a[2]=d'), { a: ['b', 'c', 'd'] });
|
|
81
87
|
st.deepEqual(qs.parse('a[1]=c&a[0]=b'), { a: ['b', 'c'] });
|
|
88
|
+
st.deepEqual(qs.parse('a[1]=c', { arrayLimit: 20 }), { a: ['c'] });
|
|
89
|
+
st.deepEqual(qs.parse('a[1]=c', { arrayLimit: 0 }), { a: { 1: 'c' } });
|
|
82
90
|
st.deepEqual(qs.parse('a[1]=c'), { a: ['c'] });
|
|
83
91
|
st.end();
|
|
84
92
|
});
|
|
85
93
|
|
|
86
|
-
t.test('limits specific array indices to
|
|
87
|
-
st.deepEqual(qs.parse('a[20]=a'), { a: ['a'] });
|
|
88
|
-
st.deepEqual(qs.parse('a[21]=a'), { a: { 21: 'a' } });
|
|
94
|
+
t.test('limits specific array indices to arrayLimit', function (st) {
|
|
95
|
+
st.deepEqual(qs.parse('a[20]=a', { arrayLimit: 20 }), { a: ['a'] });
|
|
96
|
+
st.deepEqual(qs.parse('a[21]=a', { arrayLimit: 20 }), { a: { 21: 'a' } });
|
|
89
97
|
st.end();
|
|
90
98
|
});
|
|
91
99
|
|
|
@@ -123,9 +131,9 @@ test('parse()', function (t) {
|
|
|
123
131
|
st.deepEqual(qs.parse('foo[bad]=baz&foo[]=bar&foo[]=foo'), { foo: { bad: 'baz', 0: 'bar', 1: 'foo' } });
|
|
124
132
|
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' }] });
|
|
125
133
|
|
|
126
|
-
st.deepEqual(qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c', { allowPrototypes: false }), { a: { 0: 'b', t: 'u' } });
|
|
134
|
+
st.deepEqual(qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c', { allowPrototypes: false }), { a: { 0: 'b', c: true, t: 'u' } });
|
|
127
135
|
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' } });
|
|
136
|
+
st.deepEqual(qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y', { allowPrototypes: false }), { a: { 0: 'b', 1: 'c', x: 'y' } });
|
|
129
137
|
st.deepEqual(qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y', { allowPrototypes: true }), { a: { 0: 'b', hasOwnProperty: 'c', x: 'y' } });
|
|
130
138
|
st.end();
|
|
131
139
|
});
|
|
@@ -144,6 +152,8 @@ test('parse()', function (t) {
|
|
|
144
152
|
st.end();
|
|
145
153
|
});
|
|
146
154
|
|
|
155
|
+
t.deepEqual(qs.parse('a[b]=c&a=d'), { a: { b: 'c', d: true } }, 'can add keys to objects');
|
|
156
|
+
|
|
147
157
|
t.test('correctly prunes undefined values when converting an array to an object', function (st) {
|
|
148
158
|
st.deepEqual(qs.parse('a[2]=b&a[99999999]=c'), { a: { 2: 'b', 99999999: 'c' } });
|
|
149
159
|
st.end();
|
|
@@ -208,10 +218,10 @@ test('parse()', function (t) {
|
|
|
208
218
|
});
|
|
209
219
|
|
|
210
220
|
t.test('compacts sparse arrays', function (st) {
|
|
211
|
-
st.deepEqual(qs.parse('a[10]=1&a[2]=2'), { a: ['2', '1'] });
|
|
212
|
-
st.deepEqual(qs.parse('a[1][b][2][c]=1'), { a: [{ b: [{ c: '1' }] }] });
|
|
213
|
-
st.deepEqual(qs.parse('a[1][2][3][c]=1'), { a: [[[{ c: '1' }]]] });
|
|
214
|
-
st.deepEqual(qs.parse('a[1][2][3][c][1]=1'), { a: [[[{ c: ['1'] }]]] });
|
|
221
|
+
st.deepEqual(qs.parse('a[10]=1&a[2]=2', { arrayLimit: 20 }), { a: ['2', '1'] });
|
|
222
|
+
st.deepEqual(qs.parse('a[1][b][2][c]=1', { arrayLimit: 20 }), { a: [{ b: [{ c: '1' }] }] });
|
|
223
|
+
st.deepEqual(qs.parse('a[1][2][3][c]=1', { arrayLimit: 20 }), { a: [[[{ c: '1' }]]] });
|
|
224
|
+
st.deepEqual(qs.parse('a[1][2][3][c][1]=1', { arrayLimit: 20 }), { a: [[[{ c: ['1'] }]]] });
|
|
215
225
|
st.end();
|
|
216
226
|
});
|
|
217
227
|
|
|
@@ -222,7 +232,7 @@ test('parse()', function (t) {
|
|
|
222
232
|
});
|
|
223
233
|
|
|
224
234
|
t.test('parses buffers correctly', function (st) {
|
|
225
|
-
var b =
|
|
235
|
+
var b = new Buffer('test');
|
|
226
236
|
st.deepEqual(qs.parse({ a: b }), { a: b });
|
|
227
237
|
st.end();
|
|
228
238
|
});
|
|
@@ -240,12 +250,14 @@ test('parse()', function (t) {
|
|
|
240
250
|
str = str + '&' + str;
|
|
241
251
|
}
|
|
242
252
|
|
|
243
|
-
st.doesNotThrow(function () {
|
|
253
|
+
st.doesNotThrow(function () {
|
|
254
|
+
qs.parse(str);
|
|
255
|
+
});
|
|
244
256
|
|
|
245
257
|
st.end();
|
|
246
258
|
});
|
|
247
259
|
|
|
248
|
-
t.test('should not throw when a native prototype has an enumerable property', function (st) {
|
|
260
|
+
t.test('should not throw when a native prototype has an enumerable property', { parallel: false }, function (st) {
|
|
249
261
|
Object.prototype.crash = '';
|
|
250
262
|
Array.prototype.crash = '';
|
|
251
263
|
st.doesNotThrow(qs.parse.bind(null, 'a=b'));
|
|
@@ -290,14 +302,7 @@ test('parse()', function (t) {
|
|
|
290
302
|
});
|
|
291
303
|
|
|
292
304
|
t.test('allows disabling array parsing', function (st) {
|
|
293
|
-
|
|
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
|
-
|
|
305
|
+
st.deepEqual(qs.parse('a[0]=b&a[1]=c', { parseArrays: false }), { a: { 0: 'b', 1: 'c' } });
|
|
301
306
|
st.end();
|
|
302
307
|
});
|
|
303
308
|
|
|
@@ -385,7 +390,7 @@ test('parse()', function (t) {
|
|
|
385
390
|
st.end();
|
|
386
391
|
});
|
|
387
392
|
|
|
388
|
-
t.test('parses
|
|
393
|
+
t.test('parses null objects correctly', { skip: !Object.create }, function (st) {
|
|
389
394
|
var a = Object.create(null);
|
|
390
395
|
a.b = 'c';
|
|
391
396
|
|
|
@@ -408,131 +413,9 @@ test('parse()', function (t) {
|
|
|
408
413
|
st.end();
|
|
409
414
|
});
|
|
410
415
|
|
|
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
|
-
|
|
424
416
|
t.test('can allow overwriting prototype properties', function (st) {
|
|
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
|
-
|
|
417
|
+
st.deepEqual(qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true }), { a: { hasOwnProperty: 'b' } }, { prototype: false });
|
|
418
|
+
st.deepEqual(qs.parse('hasOwnProperty=b', { allowPrototypes: true }), { hasOwnProperty: 'b' }, { prototype: false });
|
|
536
419
|
st.end();
|
|
537
420
|
});
|
|
538
421
|
|
|
@@ -545,7 +428,7 @@ test('parse()', function (t) {
|
|
|
545
428
|
st.deepEqual(qs.parse(null, { plainObjects: true }), Object.create(null));
|
|
546
429
|
var expectedArray = Object.create(null);
|
|
547
430
|
expectedArray.a = Object.create(null);
|
|
548
|
-
expectedArray.a[
|
|
431
|
+
expectedArray.a[0] = 'b';
|
|
549
432
|
expectedArray.a.c = 'd';
|
|
550
433
|
st.deepEqual(qs.parse('a[]=b&a[c]=d', { plainObjects: true }), expectedArray);
|
|
551
434
|
st.end();
|
|
@@ -556,20 +439,19 @@ test('parse()', function (t) {
|
|
|
556
439
|
decoder: function (str) {
|
|
557
440
|
var reg = /%([0-9A-F]{2})/ig;
|
|
558
441
|
var result = [];
|
|
559
|
-
var parts;
|
|
560
|
-
|
|
561
|
-
while ((parts = reg.exec(str))) {
|
|
442
|
+
var parts = reg.exec(str);
|
|
443
|
+
while (parts) {
|
|
562
444
|
result.push(parseInt(parts[1], 16));
|
|
563
|
-
|
|
445
|
+
parts = reg.exec(str);
|
|
564
446
|
}
|
|
565
|
-
return iconv.decode(
|
|
447
|
+
return iconv.decode(new Buffer(result), 'shift_jis').toString();
|
|
566
448
|
}
|
|
567
449
|
}), { 県: '大阪府' });
|
|
568
450
|
st.end();
|
|
569
451
|
});
|
|
570
452
|
|
|
571
453
|
t.test('throws error with wrong decoder', function (st) {
|
|
572
|
-
st
|
|
454
|
+
st.throws(function () {
|
|
573
455
|
qs.parse({}, { decoder: 'string' });
|
|
574
456
|
}, new TypeError('Decoder has to be a function.'));
|
|
575
457
|
st.end();
|
package/test/stringify.js
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
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;
|
|
7
6
|
|
|
8
7
|
test('stringify()', function (t) {
|
|
9
8
|
t.test('stringifies a querystring object', function (st) {
|
|
@@ -31,7 +30,21 @@ test('stringify()', function (t) {
|
|
|
31
30
|
});
|
|
32
31
|
|
|
33
32
|
t.test('stringifies an array value', function (st) {
|
|
34
|
-
st.equal(
|
|
33
|
+
st.equal(
|
|
34
|
+
qs.stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'indices' }),
|
|
35
|
+
'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d',
|
|
36
|
+
'indices => indices'
|
|
37
|
+
);
|
|
38
|
+
st.equal(
|
|
39
|
+
qs.stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'brackets' }),
|
|
40
|
+
'a%5B%5D=b&a%5B%5D=c&a%5B%5D=d',
|
|
41
|
+
'brackets => brackets'
|
|
42
|
+
);
|
|
43
|
+
st.equal(
|
|
44
|
+
qs.stringify({ a: ['b', 'c', 'd'] }),
|
|
45
|
+
'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d',
|
|
46
|
+
'default => indices'
|
|
47
|
+
);
|
|
35
48
|
st.end();
|
|
36
49
|
});
|
|
37
50
|
|
|
@@ -51,29 +64,149 @@ test('stringify()', function (t) {
|
|
|
51
64
|
});
|
|
52
65
|
|
|
53
66
|
t.test('stringifies a nested array value', function (st) {
|
|
67
|
+
st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { arrayFormat: 'indices' }), 'a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d');
|
|
68
|
+
st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { arrayFormat: 'brackets' }), 'a%5Bb%5D%5B%5D=c&a%5Bb%5D%5B%5D=d');
|
|
54
69
|
st.equal(qs.stringify({ a: { b: ['c', 'd'] } }), 'a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d');
|
|
55
70
|
st.end();
|
|
56
71
|
});
|
|
57
72
|
|
|
58
73
|
t.test('stringifies a nested array value with dots notation', function (st) {
|
|
59
|
-
st.equal(
|
|
74
|
+
st.equal(
|
|
75
|
+
qs.stringify(
|
|
76
|
+
{ a: { b: ['c', 'd'] } },
|
|
77
|
+
{ allowDots: true, encode: false, arrayFormat: 'indices' }
|
|
78
|
+
),
|
|
79
|
+
'a.b[0]=c&a.b[1]=d',
|
|
80
|
+
'indices: stringifies with dots + indices'
|
|
81
|
+
);
|
|
82
|
+
st.equal(
|
|
83
|
+
qs.stringify(
|
|
84
|
+
{ a: { b: ['c', 'd'] } },
|
|
85
|
+
{ allowDots: true, encode: false, arrayFormat: 'brackets' }
|
|
86
|
+
),
|
|
87
|
+
'a.b[]=c&a.b[]=d',
|
|
88
|
+
'brackets: stringifies with dots + brackets'
|
|
89
|
+
);
|
|
90
|
+
st.equal(
|
|
91
|
+
qs.stringify(
|
|
92
|
+
{ a: { b: ['c', 'd'] } },
|
|
93
|
+
{ allowDots: true, encode: false }
|
|
94
|
+
),
|
|
95
|
+
'a.b[0]=c&a.b[1]=d',
|
|
96
|
+
'default: stringifies with dots + indices'
|
|
97
|
+
);
|
|
60
98
|
st.end();
|
|
61
99
|
});
|
|
62
100
|
|
|
63
101
|
t.test('stringifies an object inside an array', function (st) {
|
|
64
|
-
st.equal(
|
|
65
|
-
|
|
102
|
+
st.equal(
|
|
103
|
+
qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'indices' }),
|
|
104
|
+
'a%5B0%5D%5Bb%5D=c',
|
|
105
|
+
'indices => brackets'
|
|
106
|
+
);
|
|
107
|
+
st.equal(
|
|
108
|
+
qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'brackets' }),
|
|
109
|
+
'a%5B%5D%5Bb%5D=c',
|
|
110
|
+
'brackets => brackets'
|
|
111
|
+
);
|
|
112
|
+
st.equal(
|
|
113
|
+
qs.stringify({ a: [{ b: 'c' }] }),
|
|
114
|
+
'a%5B0%5D%5Bb%5D=c',
|
|
115
|
+
'default => indices'
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
st.equal(
|
|
119
|
+
qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'indices' }),
|
|
120
|
+
'a%5B0%5D%5Bb%5D%5Bc%5D%5B0%5D=1',
|
|
121
|
+
'indices => indices'
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
st.equal(
|
|
125
|
+
qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'brackets' }),
|
|
126
|
+
'a%5B%5D%5Bb%5D%5Bc%5D%5B%5D=1',
|
|
127
|
+
'brackets => brackets'
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
st.equal(
|
|
131
|
+
qs.stringify({ a: [{ b: { c: [1] } }] }),
|
|
132
|
+
'a%5B0%5D%5Bb%5D%5Bc%5D%5B0%5D=1',
|
|
133
|
+
'default => indices'
|
|
134
|
+
);
|
|
135
|
+
|
|
66
136
|
st.end();
|
|
67
137
|
});
|
|
68
138
|
|
|
69
139
|
t.test('stringifies an array with mixed objects and primitives', function (st) {
|
|
70
|
-
st.equal(
|
|
140
|
+
st.equal(
|
|
141
|
+
qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false, arrayFormat: 'indices' }),
|
|
142
|
+
'a[0][b]=1&a[1]=2&a[2]=3',
|
|
143
|
+
'indices => indices'
|
|
144
|
+
);
|
|
145
|
+
st.equal(
|
|
146
|
+
qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false, arrayFormat: 'brackets' }),
|
|
147
|
+
'a[][b]=1&a[]=2&a[]=3',
|
|
148
|
+
'brackets => brackets'
|
|
149
|
+
);
|
|
150
|
+
st.equal(
|
|
151
|
+
qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false }),
|
|
152
|
+
'a[0][b]=1&a[1]=2&a[2]=3',
|
|
153
|
+
'default => indices'
|
|
154
|
+
);
|
|
155
|
+
|
|
71
156
|
st.end();
|
|
72
157
|
});
|
|
73
158
|
|
|
74
159
|
t.test('stringifies an object inside an array with dots notation', function (st) {
|
|
75
|
-
st.equal(
|
|
76
|
-
|
|
160
|
+
st.equal(
|
|
161
|
+
qs.stringify(
|
|
162
|
+
{ a: [{ b: 'c' }] },
|
|
163
|
+
{ allowDots: true, encode: false, arrayFormat: 'indices' }
|
|
164
|
+
),
|
|
165
|
+
'a[0].b=c',
|
|
166
|
+
'indices => indices'
|
|
167
|
+
);
|
|
168
|
+
st.equal(
|
|
169
|
+
qs.stringify(
|
|
170
|
+
{ a: [{ b: 'c' }] },
|
|
171
|
+
{ allowDots: true, encode: false, arrayFormat: 'brackets' }
|
|
172
|
+
),
|
|
173
|
+
'a[].b=c',
|
|
174
|
+
'brackets => brackets'
|
|
175
|
+
);
|
|
176
|
+
st.equal(
|
|
177
|
+
qs.stringify(
|
|
178
|
+
{ a: [{ b: 'c' }] },
|
|
179
|
+
{ allowDots: true, encode: false }
|
|
180
|
+
),
|
|
181
|
+
'a[0].b=c',
|
|
182
|
+
'default => indices'
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
st.equal(
|
|
186
|
+
qs.stringify(
|
|
187
|
+
{ a: [{ b: { c: [1] } }] },
|
|
188
|
+
{ allowDots: true, encode: false, arrayFormat: 'indices' }
|
|
189
|
+
),
|
|
190
|
+
'a[0].b.c[0]=1',
|
|
191
|
+
'indices => indices'
|
|
192
|
+
);
|
|
193
|
+
st.equal(
|
|
194
|
+
qs.stringify(
|
|
195
|
+
{ a: [{ b: { c: [1] } }] },
|
|
196
|
+
{ allowDots: true, encode: false, arrayFormat: 'brackets' }
|
|
197
|
+
),
|
|
198
|
+
'a[].b.c[]=1',
|
|
199
|
+
'brackets => brackets'
|
|
200
|
+
);
|
|
201
|
+
st.equal(
|
|
202
|
+
qs.stringify(
|
|
203
|
+
{ a: [{ b: { c: [1] } }] },
|
|
204
|
+
{ allowDots: true, encode: false }
|
|
205
|
+
),
|
|
206
|
+
'a[0].b.c[0]=1',
|
|
207
|
+
'default => indices'
|
|
208
|
+
);
|
|
209
|
+
|
|
77
210
|
st.end();
|
|
78
211
|
});
|
|
79
212
|
|
|
@@ -126,7 +259,7 @@ test('stringify()', function (t) {
|
|
|
126
259
|
st.end();
|
|
127
260
|
});
|
|
128
261
|
|
|
129
|
-
t.test('stringifies
|
|
262
|
+
t.test('stringifies a null object', { skip: !Object.create }, function (st) {
|
|
130
263
|
var obj = Object.create(null);
|
|
131
264
|
obj.a = 'b';
|
|
132
265
|
st.equal(qs.stringify(obj), 'a=b');
|
|
@@ -141,10 +274,8 @@ test('stringify()', function (t) {
|
|
|
141
274
|
st.end();
|
|
142
275
|
});
|
|
143
276
|
|
|
144
|
-
t.test('stringifies an object with
|
|
145
|
-
var obj = {
|
|
146
|
-
a: Object.create(null)
|
|
147
|
-
};
|
|
277
|
+
t.test('stringifies an object with a null object as a child', { skip: !Object.create }, function (st) {
|
|
278
|
+
var obj = { a: Object.create(null) };
|
|
148
279
|
|
|
149
280
|
obj.a.b = 'c';
|
|
150
281
|
st.equal(qs.stringify(obj), 'a%5Bb%5D=c');
|
|
@@ -194,8 +325,8 @@ test('stringify()', function (t) {
|
|
|
194
325
|
});
|
|
195
326
|
|
|
196
327
|
t.test('stringifies buffer values', function (st) {
|
|
197
|
-
st.equal(qs.stringify({ a:
|
|
198
|
-
st.equal(qs.stringify({ a: { b:
|
|
328
|
+
st.equal(qs.stringify({ a: new Buffer('test') }), 'a=test');
|
|
329
|
+
st.equal(qs.stringify({ a: { b: new Buffer('test') } }), 'a%5Bb%5D=test');
|
|
199
330
|
st.end();
|
|
200
331
|
});
|
|
201
332
|
|
|
@@ -216,7 +347,32 @@ test('stringify()', function (t) {
|
|
|
216
347
|
t.test('selects properties when filter=array', function (st) {
|
|
217
348
|
st.equal(qs.stringify({ a: 'b' }, { filter: ['a'] }), 'a=b');
|
|
218
349
|
st.equal(qs.stringify({ a: 1 }, { filter: [] }), '');
|
|
219
|
-
|
|
350
|
+
|
|
351
|
+
st.equal(
|
|
352
|
+
qs.stringify(
|
|
353
|
+
{ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' },
|
|
354
|
+
{ filter: ['a', 'b', 0, 2], arrayFormat: 'indices' }
|
|
355
|
+
),
|
|
356
|
+
'a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3',
|
|
357
|
+
'indices => indices'
|
|
358
|
+
);
|
|
359
|
+
st.equal(
|
|
360
|
+
qs.stringify(
|
|
361
|
+
{ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' },
|
|
362
|
+
{ filter: ['a', 'b', 0, 2], arrayFormat: 'brackets' }
|
|
363
|
+
),
|
|
364
|
+
'a%5Bb%5D%5B%5D=1&a%5Bb%5D%5B%5D=3',
|
|
365
|
+
'brackets => brackets'
|
|
366
|
+
);
|
|
367
|
+
st.equal(
|
|
368
|
+
qs.stringify(
|
|
369
|
+
{ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' },
|
|
370
|
+
{ filter: ['a', 'b', 0, 2] }
|
|
371
|
+
),
|
|
372
|
+
'a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3',
|
|
373
|
+
'default => indices'
|
|
374
|
+
);
|
|
375
|
+
|
|
220
376
|
st.end();
|
|
221
377
|
});
|
|
222
378
|
|
|
@@ -250,16 +406,32 @@ test('stringify()', function (t) {
|
|
|
250
406
|
});
|
|
251
407
|
|
|
252
408
|
t.test('can sort the keys', function (st) {
|
|
253
|
-
var sort = function (a, b) {
|
|
409
|
+
var sort = function (a, b) {
|
|
410
|
+
return a.localeCompare(b);
|
|
411
|
+
};
|
|
254
412
|
st.equal(qs.stringify({ a: 'c', z: 'y', b: 'f' }, { sort: sort }), 'a=c&b=f&z=y');
|
|
255
413
|
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');
|
|
256
414
|
st.end();
|
|
257
415
|
});
|
|
258
416
|
|
|
259
417
|
t.test('can sort the keys at depth 3 or more too', function (st) {
|
|
260
|
-
var sort = function (a, b) {
|
|
261
|
-
|
|
262
|
-
|
|
418
|
+
var sort = function (a, b) {
|
|
419
|
+
return a.localeCompare(b);
|
|
420
|
+
};
|
|
421
|
+
st.equal(
|
|
422
|
+
qs.stringify(
|
|
423
|
+
{ a: 'a', z: { zj: { zjb: 'zjb', zja: 'zja' }, zi: { zib: 'zib', zia: 'zia' } }, b: 'b' },
|
|
424
|
+
{ sort: sort, encode: false }
|
|
425
|
+
),
|
|
426
|
+
'a=a&b=b&z[zi][zia]=zia&z[zi][zib]=zib&z[zj][zja]=zja&z[zj][zjb]=zjb'
|
|
427
|
+
);
|
|
428
|
+
st.equal(
|
|
429
|
+
qs.stringify(
|
|
430
|
+
{ a: 'a', z: { zj: { zjb: 'zjb', zja: 'zja' }, zi: { zib: 'zib', zia: 'zia' } }, b: 'b' },
|
|
431
|
+
{ sort: null, encode: false }
|
|
432
|
+
),
|
|
433
|
+
'a=a&z[zj][zjb]=zjb&z[zj][zja]=zja&z[zi][zib]=zib&z[zi][zia]=zia&b=b'
|
|
434
|
+
);
|
|
263
435
|
st.end();
|
|
264
436
|
});
|
|
265
437
|
|
|
@@ -281,16 +453,14 @@ test('stringify()', function (t) {
|
|
|
281
453
|
});
|
|
282
454
|
|
|
283
455
|
t.test('throws error with wrong encoder', function (st) {
|
|
284
|
-
st
|
|
285
|
-
qs.stringify({}, {
|
|
286
|
-
encoder: 'string'
|
|
287
|
-
});
|
|
456
|
+
st.throws(function () {
|
|
457
|
+
qs.stringify({}, { encoder: 'string' });
|
|
288
458
|
}, new TypeError('Encoder has to be a function.'));
|
|
289
459
|
st.end();
|
|
290
460
|
});
|
|
291
461
|
|
|
292
462
|
t.test('can use custom encoder for a buffer object', { skip: typeof Buffer === 'undefined' }, function (st) {
|
|
293
|
-
st.equal(qs.stringify({ a:
|
|
463
|
+
st.equal(qs.stringify({ a: new Buffer([1]) }, {
|
|
294
464
|
encoder: function (buffer) {
|
|
295
465
|
if (typeof buffer === 'string') {
|
|
296
466
|
return buffer;
|
|
@@ -300,4 +470,69 @@ test('stringify()', function (t) {
|
|
|
300
470
|
}), 'a=b');
|
|
301
471
|
st.end();
|
|
302
472
|
});
|
|
473
|
+
|
|
474
|
+
t.test('serializeDate option', function (st) {
|
|
475
|
+
var date = new Date();
|
|
476
|
+
st.equal(
|
|
477
|
+
qs.stringify({ a: date }),
|
|
478
|
+
'a=' + date.toISOString().replace(/:/g, '%3A'),
|
|
479
|
+
'default is toISOString'
|
|
480
|
+
);
|
|
481
|
+
|
|
482
|
+
var mutatedDate = new Date();
|
|
483
|
+
mutatedDate.toISOString = function () {
|
|
484
|
+
throw new SyntaxError();
|
|
485
|
+
};
|
|
486
|
+
st.throws(function () {
|
|
487
|
+
mutatedDate.toISOString();
|
|
488
|
+
}, SyntaxError);
|
|
489
|
+
st.equal(
|
|
490
|
+
qs.stringify({ a: mutatedDate }),
|
|
491
|
+
'a=' + Date.prototype.toISOString.call(mutatedDate).replace(/:/g, '%3A'),
|
|
492
|
+
'toISOString works even when method is not locally present'
|
|
493
|
+
);
|
|
494
|
+
|
|
495
|
+
var specificDate = new Date(6);
|
|
496
|
+
st.equal(
|
|
497
|
+
qs.stringify(
|
|
498
|
+
{ a: specificDate },
|
|
499
|
+
{ serializeDate: function (d) { return d.getTime() * 7; } }
|
|
500
|
+
),
|
|
501
|
+
'a=42',
|
|
502
|
+
'custom serializeDate function called'
|
|
503
|
+
);
|
|
504
|
+
|
|
505
|
+
st.end();
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
t.test('RFC 1738 spaces serialization', function (st) {
|
|
509
|
+
st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.RFC1738 }), 'a=b+c');
|
|
510
|
+
st.equal(qs.stringify({ 'a b': 'c d' }, { format: qs.formats.RFC1738 }), 'a+b=c+d');
|
|
511
|
+
st.end();
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
t.test('RFC 3986 spaces serialization', function (st) {
|
|
515
|
+
st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.RFC3986 }), 'a=b%20c');
|
|
516
|
+
st.equal(qs.stringify({ 'a b': 'c d' }, { format: qs.formats.RFC3986 }), 'a%20b=c%20d');
|
|
517
|
+
st.end();
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
t.test('Backward compatibility to RFC 3986', function (st) {
|
|
521
|
+
st.equal(qs.stringify({ a: 'b c' }), 'a=b%20c');
|
|
522
|
+
st.end();
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
t.test('Edge cases and unknown formats', function (st) {
|
|
526
|
+
['UFO1234', false, 1234, null, {}, []].forEach(
|
|
527
|
+
function (format) {
|
|
528
|
+
st.throws(
|
|
529
|
+
function () {
|
|
530
|
+
qs.stringify({ a: 'b c' }, { format: format });
|
|
531
|
+
},
|
|
532
|
+
new TypeError('Unknown format option provided.')
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
);
|
|
536
|
+
st.end();
|
|
537
|
+
});
|
|
303
538
|
});
|