qs 6.2.1 → 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/.eslintrc CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
- "root": true,
2
+ "root": true,
3
3
 
4
- "extends": "@ljharb",
4
+ "extends": "@ljharb",
5
5
 
6
- "rules": {
7
- "complexity": [2, 22],
8
- "consistent-return": [1],
9
- "id-length": [2, { "min": 1, "max": 25, "properties": "never" }],
10
- "indent": [2, 4],
11
- "max-params": [2, 9],
12
- "max-statements": [2, 36],
13
- "no-extra-parens": [1],
14
- "no-continue": [1],
15
- "no-magic-numbers": 0,
16
- "no-restricted-syntax": [2, "BreakStatement", "DebuggerStatement", "ForInStatement", "LabeledStatement", "WithStatement"],
17
- "operator-linebreak": 1
18
- }
6
+ "rules": {
7
+ "complexity": [2, 25],
8
+ "consistent-return": [1],
9
+ "id-length": [2, { "min": 1, "max": 25, "properties": "never" }],
10
+ "indent": [2, 4],
11
+ "max-params": [2, 11],
12
+ "max-statements": [2, 42],
13
+ "no-extra-parens": [1],
14
+ "no-continue": [1],
15
+ "no-magic-numbers": 0,
16
+ "no-restricted-syntax": [2, "BreakStatement", "DebuggerStatement", "ForInStatement", "LabeledStatement", "WithStatement"],
17
+ "operator-linebreak": 1
18
+ }
19
19
  }
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## **6.3.0**
2
+ - [New] Add support for RFC 1738 (#174, #173)
3
+ - [New] `stringify`: Add `serializeDate` option to customize Date serialization (#159)
4
+ - [Fix] ensure `utils.merge` handles merging two arrays
5
+ - [Refactor] only constructors should be capitalized
6
+ - [Refactor] capitalized var names are for constructors only
7
+ - [Refactor] avoid using a sparse array
8
+ - [Robustness] `formats`: cache `String#replace`
9
+ - [Dev Deps] update `browserify`, `eslint`, `@ljharb/eslint-config`; add `safe-publish-latest`
10
+ - [Tests] up to `node` `v6.8`, `v4.6`; improve test matrix
11
+ - [Tests] flesh out arrayLimit/arrayFormat tests (#107)
12
+ - [Tests] skip Object.create tests when null objects are not available
13
+ - [Tests] Turn on eslint for test files (#175)
14
+
1
15
  ## **6.2.1**
2
16
  - [Fix] ensure `key[]=x&key[]&key[]=y` results in 3, not 2, values
3
17
  - [Refactor] Be explicit and use `Object.prototype.hasOwnProperty.call`
package/README.md CHANGED
@@ -39,11 +39,11 @@ assert.deepEqual(qs.parse('foo[bar]=baz'), {
39
39
  });
40
40
  ```
41
41
 
42
- When using the `plainObjects` option the parsed value is returned as a plain object, created via `Object.create(null)` and as such you should be aware that prototype methods will not exist on it and a user may set those names to whatever value they like:
42
+ When using the `plainObjects` option the parsed value is returned as a null object, created via `Object.create(null)` and as such you should be aware that prototype methods will not exist on it and a user may set those names to whatever value they like:
43
43
 
44
44
  ```javascript
45
- var plainObject = qs.parse('a[hasOwnProperty]=b', { plainObjects: true });
46
- assert.deepEqual(plainObject, { a: { hasOwnProperty: 'b' } });
45
+ var nullObject = qs.parse('a[hasOwnProperty]=b', { plainObjects: true });
46
+ assert.deepEqual(nullObject, { a: { hasOwnProperty: 'b' } });
47
47
  ```
48
48
 
49
49
  By default parameters that would overwrite properties on the object prototype are ignored, if you wish to keep the data from those fields either use `plainObjects` as mentioned above, or set `allowPrototypes` to `true` which will allow user input to overwrite those properties. *WARNING* It is generally a bad idea to enable this option as it can cause problems when attempting to use the properties that have been overwritten. Always be careful with this option.
@@ -290,6 +290,17 @@ The delimiter may be overridden with stringify as well:
290
290
  assert.equal(qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' }), 'a=b;c=d');
291
291
  ```
292
292
 
293
+ If you only want to override the serialization of `Date` objects, you can provide a `serializeDate` option:
294
+
295
+ ```javascript
296
+ var date = new Date(7);
297
+ assert.equal(qs.stringify({ a: date }), 'a=1970-01-01T00:00:00.007Z'.replace(/:/g, '%3A'));
298
+ assert.equal(
299
+ qs.stringify({ a: date }, { serializeDate: function (d) { return d.getTime(); } }),
300
+ 'a=7'
301
+ );
302
+ ```
303
+
293
304
  Finally, you can use the `filter` option to restrict which keys will be included in the stringified output.
294
305
  If you pass a function, it will be called for each key to obtain the replacement value. Otherwise, if you
295
306
  pass an array, it will be used to select properties and array indices for stringification:
@@ -374,3 +385,14 @@ var decoder = require('qs-iconv/decoder')('shift_jis');
374
385
  var obj = qs.parse('a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I', { decoder: decoder });
375
386
  assert.deepEqual(obj, { a: 'こんにちは!' });
376
387
  ```
388
+
389
+ ### RFC 3986 and RFC 1738 space encoding
390
+
391
+ RFC3986 used as default option and encodes ' ' to *%20* which is backward compatible.
392
+ In the same time, output can be stringified as per RFC1738 with ' ' equal to '+'.
393
+
394
+ ```
395
+ assert.equal(qs.stringify({ a: 'b c' }), 'a=b%20c');
396
+ assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC3986' }), 'a=b%20c');
397
+ assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC1738' }), 'a=b+c');
398
+ ```
package/dist/qs.js CHANGED
@@ -1,31 +1,53 @@
1
1
  (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Qs = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
2
2
  'use strict';
3
3
 
4
- var Stringify = require('./stringify');
5
- var Parse = require('./parse');
4
+ var replace = String.prototype.replace;
5
+ var percentTwenties = /%20/g;
6
6
 
7
7
  module.exports = {
8
- stringify: Stringify,
9
- parse: Parse
8
+ 'default': 'RFC3986',
9
+ formatters: {
10
+ RFC1738: function (value) {
11
+ return replace.call(value, percentTwenties, '+');
12
+ },
13
+ RFC3986: function (value) {
14
+ return value;
15
+ }
16
+ },
17
+ RFC1738: 'RFC1738',
18
+ RFC3986: 'RFC3986'
19
+ };
20
+
21
+ },{}],2:[function(require,module,exports){
22
+ 'use strict';
23
+
24
+ var stringify = require('./stringify');
25
+ var parse = require('./parse');
26
+ var formats = require('./formats');
27
+
28
+ module.exports = {
29
+ formats: formats,
30
+ parse: parse,
31
+ stringify: stringify
10
32
  };
11
33
 
12
- },{"./parse":2,"./stringify":3}],2:[function(require,module,exports){
34
+ },{"./formats":1,"./parse":3,"./stringify":4}],3:[function(require,module,exports){
13
35
  'use strict';
14
36
 
15
- var Utils = require('./utils');
37
+ var utils = require('./utils');
16
38
 
17
39
  var has = Object.prototype.hasOwnProperty;
18
40
 
19
41
  var defaults = {
42
+ allowDots: false,
43
+ allowPrototypes: false,
44
+ arrayLimit: 20,
45
+ decoder: utils.decode,
20
46
  delimiter: '&',
21
47
  depth: 5,
22
- arrayLimit: 20,
23
48
  parameterLimit: 1000,
24
- strictNullHandling: false,
25
49
  plainObjects: false,
26
- allowPrototypes: false,
27
- allowDots: false,
28
- decoder: Utils.decode
50
+ strictNullHandling: false
29
51
  };
30
52
 
31
53
  var parseValues = function parseValues(str, options) {
@@ -147,7 +169,7 @@ module.exports = function (str, opts) {
147
169
  throw new TypeError('Decoder has to be a function.');
148
170
  }
149
171
 
150
- options.delimiter = typeof options.delimiter === 'string' || Utils.isRegExp(options.delimiter) ? options.delimiter : defaults.delimiter;
172
+ options.delimiter = typeof options.delimiter === 'string' || utils.isRegExp(options.delimiter) ? options.delimiter : defaults.delimiter;
151
173
  options.depth = typeof options.depth === 'number' ? options.depth : defaults.depth;
152
174
  options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : defaults.arrayLimit;
153
175
  options.parseArrays = options.parseArrays !== false;
@@ -171,16 +193,17 @@ module.exports = function (str, opts) {
171
193
  for (var i = 0; i < keys.length; ++i) {
172
194
  var key = keys[i];
173
195
  var newObj = parseKeys(key, tempObj[key], options);
174
- obj = Utils.merge(obj, newObj, options);
196
+ obj = utils.merge(obj, newObj, options);
175
197
  }
176
198
 
177
- return Utils.compact(obj);
199
+ return utils.compact(obj);
178
200
  };
179
201
 
180
- },{"./utils":4}],3:[function(require,module,exports){
202
+ },{"./utils":5}],4:[function(require,module,exports){
181
203
  'use strict';
182
204
 
183
- var Utils = require('./utils');
205
+ var utils = require('./utils');
206
+ var formats = require('./formats');
184
207
 
185
208
  var arrayPrefixGenerators = {
186
209
  brackets: function brackets(prefix) {
@@ -194,20 +217,25 @@ var arrayPrefixGenerators = {
194
217
  }
195
218
  };
196
219
 
220
+ var toISO = Date.prototype.toISOString;
221
+
197
222
  var defaults = {
198
223
  delimiter: '&',
199
- strictNullHandling: false,
200
- skipNulls: false,
201
224
  encode: true,
202
- encoder: Utils.encode
225
+ encoder: utils.encode,
226
+ serializeDate: function serializeDate(date) {
227
+ return toISO.call(date);
228
+ },
229
+ skipNulls: false,
230
+ strictNullHandling: false
203
231
  };
204
232
 
205
- var stringify = function stringify(object, prefix, generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots) {
233
+ var stringify = function stringify(object, prefix, generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots, serializeDate, formatter) {
206
234
  var obj = object;
207
235
  if (typeof filter === 'function') {
208
236
  obj = filter(prefix, obj);
209
237
  } else if (obj instanceof Date) {
210
- obj = obj.toISOString();
238
+ obj = serializeDate(obj);
211
239
  } else if (obj === null) {
212
240
  if (strictNullHandling) {
213
241
  return encoder ? encoder(prefix) : prefix;
@@ -216,11 +244,11 @@ var stringify = function stringify(object, prefix, generateArrayPrefix, strictNu
216
244
  obj = '';
217
245
  }
218
246
 
219
- if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean' || Utils.isBuffer(obj)) {
247
+ if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean' || utils.isBuffer(obj)) {
220
248
  if (encoder) {
221
- return [encoder(prefix) + '=' + encoder(obj)];
249
+ return [formatter(encoder(prefix)) + '=' + formatter(encoder(obj))];
222
250
  }
223
- return [prefix + '=' + String(obj)];
251
+ return [formatter(prefix) + '=' + formatter(String(obj))];
224
252
  }
225
253
 
226
254
  var values = [];
@@ -245,9 +273,33 @@ var stringify = function stringify(object, prefix, generateArrayPrefix, strictNu
245
273
  }
246
274
 
247
275
  if (Array.isArray(obj)) {
248
- values = values.concat(stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots));
276
+ values = values.concat(stringify(
277
+ obj[key],
278
+ generateArrayPrefix(prefix, key),
279
+ generateArrayPrefix,
280
+ strictNullHandling,
281
+ skipNulls,
282
+ encoder,
283
+ filter,
284
+ sort,
285
+ allowDots,
286
+ serializeDate,
287
+ formatter
288
+ ));
249
289
  } else {
250
- values = values.concat(stringify(obj[key], prefix + (allowDots ? '.' + key : '[' + key + ']'), generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots));
290
+ values = values.concat(stringify(
291
+ obj[key],
292
+ prefix + (allowDots ? '.' + key : '[' + key + ']'),
293
+ generateArrayPrefix,
294
+ strictNullHandling,
295
+ skipNulls,
296
+ encoder,
297
+ filter,
298
+ sort,
299
+ allowDots,
300
+ serializeDate,
301
+ formatter
302
+ ));
251
303
  }
252
304
  }
253
305
 
@@ -264,6 +316,13 @@ module.exports = function (object, opts) {
264
316
  var encoder = encode ? (typeof options.encoder === 'function' ? options.encoder : defaults.encoder) : null;
265
317
  var sort = typeof options.sort === 'function' ? options.sort : null;
266
318
  var allowDots = typeof options.allowDots === 'undefined' ? false : options.allowDots;
319
+ var serializeDate = typeof options.serializeDate === 'function' ? options.serializeDate : defaults.serializeDate;
320
+ if (typeof options.format === 'undefined') {
321
+ options.format = formats.default;
322
+ } else if (!Object.prototype.hasOwnProperty.call(formats.formatters, options.format)) {
323
+ throw new TypeError('Unknown format option provided.');
324
+ }
325
+ var formatter = formats.formatters[options.format];
267
326
  var objKeys;
268
327
  var filter;
269
328
 
@@ -275,7 +334,8 @@ module.exports = function (object, opts) {
275
334
  filter = options.filter;
276
335
  obj = filter('', obj);
277
336
  } else if (Array.isArray(options.filter)) {
278
- objKeys = filter = options.filter;
337
+ filter = options.filter;
338
+ objKeys = filter;
279
339
  }
280
340
 
281
341
  var keys = [];
@@ -310,26 +370,40 @@ module.exports = function (object, opts) {
310
370
  continue;
311
371
  }
312
372
 
313
- keys = keys.concat(stringify(obj[key], key, generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots));
373
+ keys = keys.concat(stringify(
374
+ obj[key],
375
+ key,
376
+ generateArrayPrefix,
377
+ strictNullHandling,
378
+ skipNulls,
379
+ encoder,
380
+ filter,
381
+ sort,
382
+ allowDots,
383
+ serializeDate,
384
+ formatter
385
+ ));
314
386
  }
315
387
 
316
388
  return keys.join(delimiter);
317
389
  };
318
390
 
319
- },{"./utils":4}],4:[function(require,module,exports){
391
+ },{"./formats":1,"./utils":5}],5:[function(require,module,exports){
320
392
  'use strict';
321
393
 
394
+ var has = Object.prototype.hasOwnProperty;
395
+
322
396
  var hexTable = (function () {
323
- var array = new Array(256);
397
+ var array = [];
324
398
  for (var i = 0; i < 256; ++i) {
325
- array[i] = '%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase();
399
+ array.push('%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase());
326
400
  }
327
401
 
328
402
  return array;
329
403
  }());
330
404
 
331
405
  exports.arrayToObject = function (source, options) {
332
- var obj = options.plainObjects ? Object.create(null) : {};
406
+ var obj = options && options.plainObjects ? Object.create(null) : {};
333
407
  for (var i = 0; i < source.length; ++i) {
334
408
  if (typeof source[i] !== 'undefined') {
335
409
  obj[i] = source[i];
@@ -365,6 +439,21 @@ exports.merge = function (target, source, options) {
365
439
  mergeTarget = exports.arrayToObject(target, options);
366
440
  }
367
441
 
442
+ if (Array.isArray(target) && Array.isArray(source)) {
443
+ source.forEach(function (item, i) {
444
+ if (has.call(target, i)) {
445
+ if (target[i] && typeof target[i] === 'object') {
446
+ target[i] = exports.merge(target[i], item, options);
447
+ } else {
448
+ target.push(item);
449
+ }
450
+ } else {
451
+ target[i] = item;
452
+ }
453
+ });
454
+ return target;
455
+ }
456
+
368
457
  return Object.keys(source).reduce(function (acc, key) {
369
458
  var value = source[key];
370
459
 
@@ -462,10 +551,9 @@ exports.compact = function (obj, references) {
462
551
  }
463
552
 
464
553
  var keys = Object.keys(obj);
465
- for (var j = 0; j < keys.length; ++j) {
466
- var key = keys[j];
554
+ keys.forEach(function (key) {
467
555
  obj[key] = exports.compact(obj[key], refs);
468
- }
556
+ });
469
557
 
470
558
  return obj;
471
559
  };
@@ -482,5 +570,5 @@ exports.isBuffer = function (obj) {
482
570
  return !!(obj.constructor && obj.constructor.isBuffer && obj.constructor.isBuffer(obj));
483
571
  };
484
572
 
485
- },{}]},{},[1])(1)
573
+ },{}]},{},[2])(2)
486
574
  });
package/lib/formats.js ADDED
@@ -0,0 +1,18 @@
1
+ 'use strict';
2
+
3
+ var replace = String.prototype.replace;
4
+ var percentTwenties = /%20/g;
5
+
6
+ module.exports = {
7
+ 'default': 'RFC3986',
8
+ formatters: {
9
+ RFC1738: function (value) {
10
+ return replace.call(value, percentTwenties, '+');
11
+ },
12
+ RFC3986: function (value) {
13
+ return value;
14
+ }
15
+ },
16
+ RFC1738: 'RFC1738',
17
+ RFC3986: 'RFC3986'
18
+ };
package/lib/index.js CHANGED
@@ -1,9 +1,11 @@
1
1
  'use strict';
2
2
 
3
- var Stringify = require('./stringify');
4
- var Parse = require('./parse');
3
+ var stringify = require('./stringify');
4
+ var parse = require('./parse');
5
+ var formats = require('./formats');
5
6
 
6
7
  module.exports = {
7
- stringify: Stringify,
8
- parse: Parse
8
+ formats: formats,
9
+ parse: parse,
10
+ stringify: stringify
9
11
  };
package/lib/parse.js CHANGED
@@ -1,19 +1,19 @@
1
1
  'use strict';
2
2
 
3
- var Utils = require('./utils');
3
+ var utils = require('./utils');
4
4
 
5
5
  var has = Object.prototype.hasOwnProperty;
6
6
 
7
7
  var defaults = {
8
+ allowDots: false,
9
+ allowPrototypes: false,
10
+ arrayLimit: 20,
11
+ decoder: utils.decode,
8
12
  delimiter: '&',
9
13
  depth: 5,
10
- arrayLimit: 20,
11
14
  parameterLimit: 1000,
12
- strictNullHandling: false,
13
15
  plainObjects: false,
14
- allowPrototypes: false,
15
- allowDots: false,
16
- decoder: Utils.decode
16
+ strictNullHandling: false
17
17
  };
18
18
 
19
19
  var parseValues = function parseValues(str, options) {
@@ -135,7 +135,7 @@ module.exports = function (str, opts) {
135
135
  throw new TypeError('Decoder has to be a function.');
136
136
  }
137
137
 
138
- options.delimiter = typeof options.delimiter === 'string' || Utils.isRegExp(options.delimiter) ? options.delimiter : defaults.delimiter;
138
+ options.delimiter = typeof options.delimiter === 'string' || utils.isRegExp(options.delimiter) ? options.delimiter : defaults.delimiter;
139
139
  options.depth = typeof options.depth === 'number' ? options.depth : defaults.depth;
140
140
  options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : defaults.arrayLimit;
141
141
  options.parseArrays = options.parseArrays !== false;
@@ -159,8 +159,8 @@ module.exports = function (str, opts) {
159
159
  for (var i = 0; i < keys.length; ++i) {
160
160
  var key = keys[i];
161
161
  var newObj = parseKeys(key, tempObj[key], options);
162
- obj = Utils.merge(obj, newObj, options);
162
+ obj = utils.merge(obj, newObj, options);
163
163
  }
164
164
 
165
- return Utils.compact(obj);
165
+ return utils.compact(obj);
166
166
  };
package/lib/stringify.js CHANGED
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var Utils = require('./utils');
3
+ var utils = require('./utils');
4
+ var formats = require('./formats');
4
5
 
5
6
  var arrayPrefixGenerators = {
6
7
  brackets: function brackets(prefix) {
@@ -14,20 +15,25 @@ var arrayPrefixGenerators = {
14
15
  }
15
16
  };
16
17
 
18
+ var toISO = Date.prototype.toISOString;
19
+
17
20
  var defaults = {
18
21
  delimiter: '&',
19
- strictNullHandling: false,
20
- skipNulls: false,
21
22
  encode: true,
22
- encoder: Utils.encode
23
+ encoder: utils.encode,
24
+ serializeDate: function serializeDate(date) {
25
+ return toISO.call(date);
26
+ },
27
+ skipNulls: false,
28
+ strictNullHandling: false
23
29
  };
24
30
 
25
- var stringify = function stringify(object, prefix, generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots) {
31
+ var stringify = function stringify(object, prefix, generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots, serializeDate, formatter) {
26
32
  var obj = object;
27
33
  if (typeof filter === 'function') {
28
34
  obj = filter(prefix, obj);
29
35
  } else if (obj instanceof Date) {
30
- obj = obj.toISOString();
36
+ obj = serializeDate(obj);
31
37
  } else if (obj === null) {
32
38
  if (strictNullHandling) {
33
39
  return encoder ? encoder(prefix) : prefix;
@@ -36,11 +42,11 @@ var stringify = function stringify(object, prefix, generateArrayPrefix, strictNu
36
42
  obj = '';
37
43
  }
38
44
 
39
- if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean' || Utils.isBuffer(obj)) {
45
+ if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean' || utils.isBuffer(obj)) {
40
46
  if (encoder) {
41
- return [encoder(prefix) + '=' + encoder(obj)];
47
+ return [formatter(encoder(prefix)) + '=' + formatter(encoder(obj))];
42
48
  }
43
- return [prefix + '=' + String(obj)];
49
+ return [formatter(prefix) + '=' + formatter(String(obj))];
44
50
  }
45
51
 
46
52
  var values = [];
@@ -65,9 +71,33 @@ var stringify = function stringify(object, prefix, generateArrayPrefix, strictNu
65
71
  }
66
72
 
67
73
  if (Array.isArray(obj)) {
68
- values = values.concat(stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots));
74
+ values = values.concat(stringify(
75
+ obj[key],
76
+ generateArrayPrefix(prefix, key),
77
+ generateArrayPrefix,
78
+ strictNullHandling,
79
+ skipNulls,
80
+ encoder,
81
+ filter,
82
+ sort,
83
+ allowDots,
84
+ serializeDate,
85
+ formatter
86
+ ));
69
87
  } else {
70
- values = values.concat(stringify(obj[key], prefix + (allowDots ? '.' + key : '[' + key + ']'), generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots));
88
+ values = values.concat(stringify(
89
+ obj[key],
90
+ prefix + (allowDots ? '.' + key : '[' + key + ']'),
91
+ generateArrayPrefix,
92
+ strictNullHandling,
93
+ skipNulls,
94
+ encoder,
95
+ filter,
96
+ sort,
97
+ allowDots,
98
+ serializeDate,
99
+ formatter
100
+ ));
71
101
  }
72
102
  }
73
103
 
@@ -84,6 +114,13 @@ module.exports = function (object, opts) {
84
114
  var encoder = encode ? (typeof options.encoder === 'function' ? options.encoder : defaults.encoder) : null;
85
115
  var sort = typeof options.sort === 'function' ? options.sort : null;
86
116
  var allowDots = typeof options.allowDots === 'undefined' ? false : options.allowDots;
117
+ var serializeDate = typeof options.serializeDate === 'function' ? options.serializeDate : defaults.serializeDate;
118
+ if (typeof options.format === 'undefined') {
119
+ options.format = formats.default;
120
+ } else if (!Object.prototype.hasOwnProperty.call(formats.formatters, options.format)) {
121
+ throw new TypeError('Unknown format option provided.');
122
+ }
123
+ var formatter = formats.formatters[options.format];
87
124
  var objKeys;
88
125
  var filter;
89
126
 
@@ -95,7 +132,8 @@ module.exports = function (object, opts) {
95
132
  filter = options.filter;
96
133
  obj = filter('', obj);
97
134
  } else if (Array.isArray(options.filter)) {
98
- objKeys = filter = options.filter;
135
+ filter = options.filter;
136
+ objKeys = filter;
99
137
  }
100
138
 
101
139
  var keys = [];
@@ -130,7 +168,19 @@ module.exports = function (object, opts) {
130
168
  continue;
131
169
  }
132
170
 
133
- keys = keys.concat(stringify(obj[key], key, generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots));
171
+ keys = keys.concat(stringify(
172
+ obj[key],
173
+ key,
174
+ generateArrayPrefix,
175
+ strictNullHandling,
176
+ skipNulls,
177
+ encoder,
178
+ filter,
179
+ sort,
180
+ allowDots,
181
+ serializeDate,
182
+ formatter
183
+ ));
134
184
  }
135
185
 
136
186
  return keys.join(delimiter);
package/lib/utils.js CHANGED
@@ -1,16 +1,18 @@
1
1
  'use strict';
2
2
 
3
+ var has = Object.prototype.hasOwnProperty;
4
+
3
5
  var hexTable = (function () {
4
- var array = new Array(256);
6
+ var array = [];
5
7
  for (var i = 0; i < 256; ++i) {
6
- array[i] = '%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase();
8
+ array.push('%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase());
7
9
  }
8
10
 
9
11
  return array;
10
12
  }());
11
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) : {};
14
16
  for (var i = 0; i < source.length; ++i) {
15
17
  if (typeof source[i] !== 'undefined') {
16
18
  obj[i] = source[i];
@@ -46,6 +48,21 @@ exports.merge = function (target, source, options) {
46
48
  mergeTarget = exports.arrayToObject(target, options);
47
49
  }
48
50
 
51
+ if (Array.isArray(target) && Array.isArray(source)) {
52
+ source.forEach(function (item, i) {
53
+ if (has.call(target, i)) {
54
+ if (target[i] && typeof target[i] === 'object') {
55
+ target[i] = exports.merge(target[i], item, options);
56
+ } else {
57
+ target.push(item);
58
+ }
59
+ } else {
60
+ target[i] = item;
61
+ }
62
+ });
63
+ return target;
64
+ }
65
+
49
66
  return Object.keys(source).reduce(function (acc, key) {
50
67
  var value = source[key];
51
68
 
@@ -143,10 +160,9 @@ exports.compact = function (obj, references) {
143
160
  }
144
161
 
145
162
  var keys = Object.keys(obj);
146
- for (var j = 0; j < keys.length; ++j) {
147
- var key = keys[j];
163
+ keys.forEach(function (key) {
148
164
  obj[key] = exports.compact(obj[key], refs);
149
- }
165
+ });
150
166
 
151
167
  return obj;
152
168
  };