qs 6.0.3 → 6.1.2

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
@@ -4,10 +4,10 @@
4
4
  "extends": "@ljharb",
5
5
 
6
6
  "rules": {
7
- "complexity": [2, 18],
7
+ "complexity": [2, 19],
8
8
  "consistent-return": [1],
9
- "max-params": [2, 8],
10
- "max-statements": [2, 32],
9
+ "max-params": [2, 9],
10
+ "max-statements": [2, 33],
11
11
  "no-extra-parens": [1],
12
12
  "no-continue": [1],
13
13
  "no-magic-numbers": 0,
package/.travis.yml CHANGED
@@ -1,69 +1,173 @@
1
1
  language: node_js
2
+ os:
3
+ - linux
2
4
  node_js:
3
- - "5.3"
4
- - "5.2"
5
- - "5.1"
6
- - "5.0"
7
- - "4.2"
8
- - "4.1"
9
- - "4.0"
5
+ - "7.7"
6
+ - "6.10"
7
+ - "5.12"
8
+ - "4.8"
10
9
  - "iojs-v3.3"
11
- - "iojs-v3.2"
12
- - "iojs-v3.1"
13
- - "iojs-v3.0"
14
10
  - "iojs-v2.5"
15
- - "iojs-v2.4"
16
- - "iojs-v2.3"
17
- - "iojs-v2.2"
18
- - "iojs-v2.1"
19
- - "iojs-v2.0"
20
11
  - "iojs-v1.8"
21
- - "iojs-v1.7"
22
- - "iojs-v1.6"
23
- - "iojs-v1.5"
24
- - "iojs-v1.4"
25
- - "iojs-v1.3"
26
- - "iojs-v1.2"
27
- - "iojs-v1.1"
28
- - "iojs-v1.0"
29
12
  - "0.12"
30
- - "0.11"
31
13
  - "0.10"
32
- - "0.9"
33
14
  - "0.8"
34
- - "0.6"
35
- - "0.4"
36
15
  before_install:
37
- - 'if [ "${TRAVIS_NODE_VERSION}" != "0.9" ]; then case "$(npm --version)" in 1.*) npm install -g npm@1.4.28 ;; 2.*) npm install -g npm@2 ;; esac ; fi'
16
+ - 'if [ "${TRAVIS_NODE_VERSION}" = "0.6" ]; then npm install -g npm@1.3 ; elif [ "${TRAVIS_NODE_VERSION}" != "0.9" ]; then case "$(npm --version)" in 1.*) npm install -g npm@1.4.28 ;; 2.*) npm install -g npm@2 ;; esac ; fi'
38
17
  - 'if [ "${TRAVIS_NODE_VERSION}" != "0.6" ] && [ "${TRAVIS_NODE_VERSION}" != "0.9" ]; then npm install -g npm; fi'
39
18
  script:
40
- - 'if [ "${TRAVIS_NODE_VERSION}" != "4.2" ]; then npm run tests-only ; else npm test ; fi'
19
+ - 'if [ -n "${PRETEST-}" ]; then npm run pretest ; fi'
20
+ - 'if [ -n "${POSTTEST-}" ]; then npm run posttest ; fi'
21
+ - 'if [ -n "${COVERAGE-}" ]; then npm run coverage ; fi'
22
+ - 'if [ -n "${TEST-}" ]; then npm run tests-only ; fi'
41
23
  sudo: false
24
+ env:
25
+ - TEST=true
42
26
  matrix:
43
27
  fast_finish: true
44
- allow_failures:
28
+ include:
29
+ - node_js: "node"
30
+ env: PRETEST=true
31
+ - node_js: "4"
32
+ env: COVERAGE=true
33
+ - node_js: "7.6"
34
+ env: TEST=true ALLOW_FAILURE=true
35
+ - node_js: "7.5"
36
+ env: TEST=true ALLOW_FAILURE=true
37
+ - node_js: "7.4"
38
+ env: TEST=true ALLOW_FAILURE=true
39
+ - node_js: "7.3"
40
+ env: TEST=true ALLOW_FAILURE=true
41
+ - node_js: "7.2"
42
+ env: TEST=true ALLOW_FAILURE=true
43
+ - node_js: "7.1"
44
+ env: TEST=true ALLOW_FAILURE=true
45
+ - node_js: "7.0"
46
+ env: TEST=true ALLOW_FAILURE=true
47
+ - node_js: "6.9"
48
+ env: TEST=true ALLOW_FAILURE=true
49
+ - node_js: "6.8"
50
+ env: TEST=true ALLOW_FAILURE=true
51
+ - node_js: "6.7"
52
+ env: TEST=true ALLOW_FAILURE=true
53
+ - node_js: "6.6"
54
+ env: TEST=true ALLOW_FAILURE=true
55
+ - node_js: "6.5"
56
+ env: TEST=true ALLOW_FAILURE=true
57
+ - node_js: "6.4"
58
+ env: TEST=true ALLOW_FAILURE=true
59
+ - node_js: "6.3"
60
+ env: TEST=true ALLOW_FAILURE=true
61
+ - node_js: "6.2"
62
+ env: TEST=true ALLOW_FAILURE=true
63
+ - node_js: "6.1"
64
+ env: TEST=true ALLOW_FAILURE=true
65
+ - node_js: "6.0"
66
+ env: TEST=true ALLOW_FAILURE=true
67
+ - node_js: "5.11"
68
+ env: TEST=true ALLOW_FAILURE=true
69
+ - node_js: "5.10"
70
+ env: TEST=true ALLOW_FAILURE=true
71
+ - node_js: "5.9"
72
+ env: TEST=true ALLOW_FAILURE=true
73
+ - node_js: "5.8"
74
+ env: TEST=true ALLOW_FAILURE=true
75
+ - node_js: "5.7"
76
+ env: TEST=true ALLOW_FAILURE=true
77
+ - node_js: "5.6"
78
+ env: TEST=true ALLOW_FAILURE=true
79
+ - node_js: "5.5"
80
+ env: TEST=true ALLOW_FAILURE=true
81
+ - node_js: "5.4"
82
+ env: TEST=true ALLOW_FAILURE=true
83
+ - node_js: "5.3"
84
+ env: TEST=true ALLOW_FAILURE=true
45
85
  - node_js: "5.2"
86
+ env: TEST=true ALLOW_FAILURE=true
46
87
  - node_js: "5.1"
88
+ env: TEST=true ALLOW_FAILURE=true
47
89
  - node_js: "5.0"
90
+ env: TEST=true ALLOW_FAILURE=true
91
+ - node_js: "4.7"
92
+ env: TEST=true ALLOW_FAILURE=true
93
+ - node_js: "4.6"
94
+ env: TEST=true ALLOW_FAILURE=true
95
+ - node_js: "4.5"
96
+ env: TEST=true ALLOW_FAILURE=true
97
+ - node_js: "4.4"
98
+ env: TEST=true ALLOW_FAILURE=true
99
+ - node_js: "4.3"
100
+ env: TEST=true ALLOW_FAILURE=true
101
+ - node_js: "4.2"
102
+ env: TEST=true ALLOW_FAILURE=true
48
103
  - node_js: "4.1"
104
+ env: TEST=true ALLOW_FAILURE=true
49
105
  - node_js: "4.0"
106
+ env: TEST=true ALLOW_FAILURE=true
50
107
  - node_js: "iojs-v3.2"
108
+ env: TEST=true ALLOW_FAILURE=true
51
109
  - node_js: "iojs-v3.1"
110
+ env: TEST=true ALLOW_FAILURE=true
52
111
  - node_js: "iojs-v3.0"
112
+ env: TEST=true ALLOW_FAILURE=true
53
113
  - node_js: "iojs-v2.4"
114
+ env: TEST=true ALLOW_FAILURE=true
54
115
  - node_js: "iojs-v2.3"
116
+ env: TEST=true ALLOW_FAILURE=true
55
117
  - node_js: "iojs-v2.2"
118
+ env: TEST=true ALLOW_FAILURE=true
56
119
  - node_js: "iojs-v2.1"
120
+ env: TEST=true ALLOW_FAILURE=true
57
121
  - node_js: "iojs-v2.0"
122
+ env: TEST=true ALLOW_FAILURE=true
58
123
  - node_js: "iojs-v1.7"
124
+ env: TEST=true ALLOW_FAILURE=true
59
125
  - node_js: "iojs-v1.6"
126
+ env: TEST=true ALLOW_FAILURE=true
60
127
  - node_js: "iojs-v1.5"
128
+ env: TEST=true ALLOW_FAILURE=true
61
129
  - node_js: "iojs-v1.4"
130
+ env: TEST=true ALLOW_FAILURE=true
62
131
  - node_js: "iojs-v1.3"
132
+ env: TEST=true ALLOW_FAILURE=true
63
133
  - node_js: "iojs-v1.2"
134
+ env: TEST=true ALLOW_FAILURE=true
64
135
  - node_js: "iojs-v1.1"
136
+ env: TEST=true ALLOW_FAILURE=true
65
137
  - node_js: "iojs-v1.0"
138
+ env: TEST=true ALLOW_FAILURE=true
66
139
  - node_js: "0.11"
140
+ env: TEST=true ALLOW_FAILURE=true
67
141
  - node_js: "0.9"
142
+ env: TEST=true ALLOW_FAILURE=true
68
143
  - node_js: "0.6"
144
+ env: TEST=true ALLOW_FAILURE=true
69
145
  - node_js: "0.4"
146
+ env: TEST=true ALLOW_FAILURE=true
147
+ ##- node_js: "7"
148
+ #env: TEST=true
149
+ #os: osx
150
+ #- node_js: "6"
151
+ #env: TEST=true
152
+ #os: osx
153
+ #- node_js: "5"
154
+ #env: TEST=true
155
+ #os: osx
156
+ #- node_js: "4"
157
+ #env: TEST=true
158
+ #os: osx
159
+ #- node_js: "iojs"
160
+ #env: TEST=true
161
+ #os: osx
162
+ #- node_js: "0.12"
163
+ #env: TEST=true
164
+ #os: osx
165
+ #- node_js: "0.10"
166
+ #env: TEST=true
167
+ #os: osx
168
+ #- node_js: "0.8"
169
+ #env: TEST=true
170
+ #os: osx
171
+ allow_failures:
172
+ - os: osx
173
+ - env: TEST=true ALLOW_FAILURE=true
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
- ## **6.0.3**
1
+ ## **6.1.2**
2
+ - [Fix] follow `allowPrototypes` option during merge (#201, #200)
3
+ - [Fix] chmod a-x
4
+ - [Fix] support keys starting with brackets (#202, #200)
5
+ - [Tests] up to `node` `v7.7`, `v6.10`,` v4.8`; disable osx builds since they block linux builds
6
+
7
+ ## **6.1.1**
2
8
  - [Fix] ensure that `allowPrototypes: false` does not ever shadow Object.prototype properties
9
+
10
+ ## [**6.1.0**](https://github.com/ljharb/qs/issues?milestone=34&state=closed)
11
+ - [New] allowDots option for `stringify` (#151)
12
+ - [Fix] "sort" option should work at a depth of 3 or more (#151)
3
13
  - [Fix] Restore `dist` directory; will be removed in v7 (#148)
4
14
 
5
15
  ## [**6.0.2**](https://github.com/ljharb/qs/issues?milestone=33&state=closed)
package/bower.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "name": "qs",
3
3
  "main": "dist/qs.js",
4
- "version": "5.2.0",
5
4
  "homepage": "https://github.com/hapijs/qs",
6
5
  "authors": [
7
6
  "Nathan LaFreniere <quitlahok@gmail.com>"
package/component.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "qs",
3
3
  "repository": "hapijs/qs",
4
4
  "description": "query-string parser / stringifier with nesting support",
5
- "version": "6.0.3",
5
+ "version": "6.1.2",
6
6
  "keywords": ["querystring", "query", "parser"],
7
7
  "main": "lib/index.js",
8
8
  "scripts": [
package/dist/qs.js CHANGED
@@ -25,6 +25,8 @@ var internals = {
25
25
  allowDots: false
26
26
  };
27
27
 
28
+ var has = Object.prototype.hasOwnProperty;
29
+
28
30
  internals.parseValues = function (str, options) {
29
31
  var obj = {};
30
32
  var parts = str.split(options.delimiter, options.parameterLimit === Infinity ? undefined : options.parameterLimit);
@@ -43,7 +45,7 @@ internals.parseValues = function (str, options) {
43
45
  var key = Utils.decode(part.slice(0, pos));
44
46
  var val = Utils.decode(part.slice(pos + 1));
45
47
 
46
- if (Object.prototype.hasOwnProperty.call(obj, key)) {
48
+ if (has.call(obj, key)) {
47
49
  obj[key] = [].concat(obj[key]).concat(val);
48
50
  } else {
49
51
  obj[key] = val;
@@ -96,26 +98,27 @@ internals.parseKeys = function (givenKey, val, options) {
96
98
 
97
99
  // The regex chunks
98
100
 
99
- var parent = /^([^[]*)/;
101
+ var brackets = /(\[[^[\]]*])/;
100
102
  var child = /(\[[^[\]]*])/g;
101
103
 
102
104
  // Get the parent
103
105
 
104
- var segment = parent.exec(key);
106
+ var segment = brackets.exec(key);
107
+ var parent = segment ? key.slice(0, segment.index) : key;
105
108
 
106
109
  // Stash the parent if it exists
107
110
 
108
111
  var keys = [];
109
- if (segment[1]) {
112
+ if (parent) {
110
113
  // If we aren't using plain objects, optionally prefix keys
111
114
  // that would overwrite object prototype properties
112
- if (!options.plainObjects && Object.prototype.hasOwnProperty(segment[1])) {
115
+ if (!options.plainObjects && has.call(Object.prototype, parent)) {
113
116
  if (!options.allowPrototypes) {
114
117
  return;
115
118
  }
116
119
  }
117
120
 
118
- keys.push(segment[1]);
121
+ keys.push(parent);
119
122
  }
120
123
 
121
124
  // Loop through children appending to the array until we hit depth
@@ -123,7 +126,7 @@ internals.parseKeys = function (givenKey, val, options) {
123
126
  var i = 0;
124
127
  while ((segment = child.exec(key)) !== null && i < options.depth) {
125
128
  i += 1;
126
- if (!options.plainObjects && Object.prototype.hasOwnProperty.call(Object.prototype, segment[1].slice(1, -1))) {
129
+ if (!options.plainObjects && has.call(Object.prototype, segment[1].slice(1, -1))) {
127
130
  if (!options.allowPrototypes) {
128
131
  return;
129
132
  }
@@ -198,7 +201,7 @@ var internals = {
198
201
  encode: true
199
202
  };
200
203
 
201
- internals.stringify = function (object, prefix, generateArrayPrefix, strictNullHandling, skipNulls, encode, filter, sort) {
204
+ internals.stringify = function (object, prefix, generateArrayPrefix, strictNullHandling, skipNulls, encode, filter, sort, allowDots) {
202
205
  var obj = object;
203
206
  if (typeof filter === 'function') {
204
207
  obj = filter(prefix, obj);
@@ -243,9 +246,9 @@ internals.stringify = function (object, prefix, generateArrayPrefix, strictNullH
243
246
  }
244
247
 
245
248
  if (Array.isArray(obj)) {
246
- values = values.concat(internals.stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix, strictNullHandling, skipNulls, encode, filter));
249
+ values = values.concat(internals.stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix, strictNullHandling, skipNulls, encode, filter, sort, allowDots));
247
250
  } else {
248
- values = values.concat(internals.stringify(obj[key], prefix + '[' + key + ']', generateArrayPrefix, strictNullHandling, skipNulls, encode, filter));
251
+ values = values.concat(internals.stringify(obj[key], prefix + (allowDots ? '.' + key : '[' + key + ']'), generateArrayPrefix, strictNullHandling, skipNulls, encode, filter, sort, allowDots));
249
252
  }
250
253
  }
251
254
 
@@ -260,6 +263,7 @@ module.exports = function (object, opts) {
260
263
  var skipNulls = typeof options.skipNulls === 'boolean' ? options.skipNulls : internals.skipNulls;
261
264
  var encode = typeof options.encode === 'boolean' ? options.encode : internals.encode;
262
265
  var sort = typeof options.sort === 'function' ? options.sort : null;
266
+ var allowDots = typeof options.allowDots === 'undefined' ? false : options.allowDots;
263
267
  var objKeys;
264
268
  var filter;
265
269
  if (typeof options.filter === 'function') {
@@ -301,7 +305,7 @@ module.exports = function (object, opts) {
301
305
  continue;
302
306
  }
303
307
 
304
- keys = keys.concat(internals.stringify(obj[key], key, generateArrayPrefix, strictNullHandling, skipNulls, encode, filter, sort));
308
+ keys = keys.concat(internals.stringify(obj[key], key, generateArrayPrefix, strictNullHandling, skipNulls, encode, filter, sort, allowDots));
305
309
  }
306
310
 
307
311
  return keys.join(delimiter);
@@ -319,6 +323,8 @@ var hexTable = (function () {
319
323
  return array;
320
324
  }());
321
325
 
326
+ var has = Object.prototype.hasOwnProperty;
327
+
322
328
  exports.arrayToObject = function (source, options) {
323
329
  var obj = options.plainObjects ? Object.create(null) : {};
324
330
  for (var i = 0; i < source.length; ++i) {
@@ -339,7 +345,9 @@ exports.merge = function (target, source, options) {
339
345
  if (Array.isArray(target)) {
340
346
  target.push(source);
341
347
  } else if (typeof target === 'object') {
342
- target[source] = true;
348
+ if (options.plainObjects || options.allowPrototypes || !has.call(Object.prototype, source)) {
349
+ target[source] = true;
350
+ }
343
351
  } else {
344
352
  return [target, source];
345
353
  }
@@ -359,7 +367,7 @@ exports.merge = function (target, source, options) {
359
367
  return Object.keys(source).reduce(function (acc, key) {
360
368
  var value = source[key];
361
369
 
362
- if (Object.prototype.hasOwnProperty.call(acc, key)) {
370
+ if (has.call(acc, key)) {
363
371
  acc[key] = exports.merge(acc[key], value, options);
364
372
  } else {
365
373
  acc[key] = value;
package/lib/index.js CHANGED
File without changes
package/lib/parse.js CHANGED
@@ -13,6 +13,8 @@ var internals = {
13
13
  allowDots: false
14
14
  };
15
15
 
16
+ var has = Object.prototype.hasOwnProperty;
17
+
16
18
  internals.parseValues = function (str, options) {
17
19
  var obj = {};
18
20
  var parts = str.split(options.delimiter, options.parameterLimit === Infinity ? undefined : options.parameterLimit);
@@ -31,7 +33,7 @@ internals.parseValues = function (str, options) {
31
33
  var key = Utils.decode(part.slice(0, pos));
32
34
  var val = Utils.decode(part.slice(pos + 1));
33
35
 
34
- if (Object.prototype.hasOwnProperty.call(obj, key)) {
36
+ if (has.call(obj, key)) {
35
37
  obj[key] = [].concat(obj[key]).concat(val);
36
38
  } else {
37
39
  obj[key] = val;
@@ -84,26 +86,27 @@ internals.parseKeys = function (givenKey, val, options) {
84
86
 
85
87
  // The regex chunks
86
88
 
87
- var parent = /^([^[]*)/;
89
+ var brackets = /(\[[^[\]]*])/;
88
90
  var child = /(\[[^[\]]*])/g;
89
91
 
90
92
  // Get the parent
91
93
 
92
- var segment = parent.exec(key);
94
+ var segment = brackets.exec(key);
95
+ var parent = segment ? key.slice(0, segment.index) : key;
93
96
 
94
97
  // Stash the parent if it exists
95
98
 
96
99
  var keys = [];
97
- if (segment[1]) {
100
+ if (parent) {
98
101
  // If we aren't using plain objects, optionally prefix keys
99
102
  // that would overwrite object prototype properties
100
- if (!options.plainObjects && Object.prototype.hasOwnProperty(segment[1])) {
103
+ if (!options.plainObjects && has.call(Object.prototype, parent)) {
101
104
  if (!options.allowPrototypes) {
102
105
  return;
103
106
  }
104
107
  }
105
108
 
106
- keys.push(segment[1]);
109
+ keys.push(parent);
107
110
  }
108
111
 
109
112
  // Loop through children appending to the array until we hit depth
@@ -111,7 +114,7 @@ internals.parseKeys = function (givenKey, val, options) {
111
114
  var i = 0;
112
115
  while ((segment = child.exec(key)) !== null && i < options.depth) {
113
116
  i += 1;
114
- if (!options.plainObjects && Object.prototype.hasOwnProperty.call(Object.prototype, segment[1].slice(1, -1))) {
117
+ if (!options.plainObjects && has.call(Object.prototype, segment[1].slice(1, -1))) {
115
118
  if (!options.allowPrototypes) {
116
119
  return;
117
120
  }
package/lib/stringify.js CHANGED
@@ -20,7 +20,7 @@ var internals = {
20
20
  encode: true
21
21
  };
22
22
 
23
- internals.stringify = function (object, prefix, generateArrayPrefix, strictNullHandling, skipNulls, encode, filter, sort) {
23
+ internals.stringify = function (object, prefix, generateArrayPrefix, strictNullHandling, skipNulls, encode, filter, sort, allowDots) {
24
24
  var obj = object;
25
25
  if (typeof filter === 'function') {
26
26
  obj = filter(prefix, obj);
@@ -65,9 +65,9 @@ internals.stringify = function (object, prefix, generateArrayPrefix, strictNullH
65
65
  }
66
66
 
67
67
  if (Array.isArray(obj)) {
68
- values = values.concat(internals.stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix, strictNullHandling, skipNulls, encode, filter));
68
+ values = values.concat(internals.stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix, strictNullHandling, skipNulls, encode, filter, sort, allowDots));
69
69
  } else {
70
- values = values.concat(internals.stringify(obj[key], prefix + '[' + key + ']', generateArrayPrefix, strictNullHandling, skipNulls, encode, filter));
70
+ values = values.concat(internals.stringify(obj[key], prefix + (allowDots ? '.' + key : '[' + key + ']'), generateArrayPrefix, strictNullHandling, skipNulls, encode, filter, sort, allowDots));
71
71
  }
72
72
  }
73
73
 
@@ -82,6 +82,7 @@ module.exports = function (object, opts) {
82
82
  var skipNulls = typeof options.skipNulls === 'boolean' ? options.skipNulls : internals.skipNulls;
83
83
  var encode = typeof options.encode === 'boolean' ? options.encode : internals.encode;
84
84
  var sort = typeof options.sort === 'function' ? options.sort : null;
85
+ var allowDots = typeof options.allowDots === 'undefined' ? false : options.allowDots;
85
86
  var objKeys;
86
87
  var filter;
87
88
  if (typeof options.filter === 'function') {
@@ -123,7 +124,7 @@ module.exports = function (object, opts) {
123
124
  continue;
124
125
  }
125
126
 
126
- keys = keys.concat(internals.stringify(obj[key], key, generateArrayPrefix, strictNullHandling, skipNulls, encode, filter, sort));
127
+ keys = keys.concat(internals.stringify(obj[key], key, generateArrayPrefix, strictNullHandling, skipNulls, encode, filter, sort, allowDots));
127
128
  }
128
129
 
129
130
  return keys.join(delimiter);
package/lib/utils.js CHANGED
@@ -9,6 +9,8 @@ var hexTable = (function () {
9
9
  return array;
10
10
  }());
11
11
 
12
+ var has = Object.prototype.hasOwnProperty;
13
+
12
14
  exports.arrayToObject = function (source, options) {
13
15
  var obj = options.plainObjects ? Object.create(null) : {};
14
16
  for (var i = 0; i < source.length; ++i) {
@@ -29,7 +31,9 @@ exports.merge = function (target, source, options) {
29
31
  if (Array.isArray(target)) {
30
32
  target.push(source);
31
33
  } else if (typeof target === 'object') {
32
- target[source] = true;
34
+ if (options.plainObjects || options.allowPrototypes || !has.call(Object.prototype, source)) {
35
+ target[source] = true;
36
+ }
33
37
  } else {
34
38
  return [target, source];
35
39
  }
@@ -49,7 +53,7 @@ exports.merge = function (target, source, options) {
49
53
  return Object.keys(source).reduce(function (acc, key) {
50
54
  var value = source[key];
51
55
 
52
- if (Object.prototype.hasOwnProperty.call(acc, key)) {
56
+ if (has.call(acc, key)) {
53
57
  acc[key] = exports.merge(acc[key], value, options);
54
58
  } else {
55
59
  acc[key] = value;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "qs",
3
3
  "description": "A querystring parser that supports nesting and arrays, with a depth limit",
4
4
  "homepage": "https://github.com/ljharb/qs",
5
- "version": "6.0.3",
5
+ "version": "6.1.2",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/ljharb/qs.git"
@@ -34,7 +34,8 @@
34
34
  "evalmd": "^0.0.16"
35
35
  },
36
36
  "scripts": {
37
- "test": "parallelshell 'npm run readme' 'npm run lint' 'npm run coverage'",
37
+ "pretest": "npm run lint && npm run readme",
38
+ "test": "npm run coverage",
38
39
  "tests-only": "node test",
39
40
  "readme": "evalmd README.md",
40
41
  "lint": "eslint lib/*.js text/*.js",
package/test/parse.js CHANGED
@@ -142,8 +142,6 @@ test('parse()', function (t) {
142
142
  st.end();
143
143
  });
144
144
 
145
- t.deepEqual(qs.parse('a[b]=c&a=d'), { a: { b: 'c', d: true } }, 'can add keys to objects');
146
-
147
145
  t.test('correctly prunes undefined values when converting an array to an object', function (st) {
148
146
  st.deepEqual(qs.parse('a[2]=b&a[99999999]=c'), { a: { '2': 'b', '99999999': 'c' } });
149
147
  st.end();
@@ -401,10 +399,47 @@ test('parse()', function (t) {
401
399
 
402
400
  t.test('params starting with a closing bracket', function (st) {
403
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
+
404
439
  st.end();
405
440
  });
406
441
 
407
- t.test('can return plain objects', function (st) {
442
+ t.test('can return null objects', { skip: !Object.create }, function (st) {
408
443
  var expected = Object.create(null);
409
444
  expected.a = Object.create(null);
410
445
  expected.a.b = 'c';
package/test/stringify.js CHANGED
@@ -21,6 +21,12 @@ test('stringify()', function (t) {
21
21
  st.equal(qs.stringify({ a: { b: { c: { d: 'e' } } } }), 'a%5Bb%5D%5Bc%5D%5Bd%5D=e');
22
22
  st.end();
23
23
  });
24
+
25
+ t.test('stringifies a nested object with dots notation', function (st) {
26
+ st.equal(qs.stringify({ a: { b: 'c' } }, { allowDots: true }), 'a.b=c');
27
+ st.equal(qs.stringify({ a: { b: { c: { d: 'e' } } } }, { allowDots: true }), 'a.b.c.d=e');
28
+ st.end();
29
+ });
24
30
 
25
31
  t.test('stringifies an array value', function (st) {
26
32
  st.equal(qs.stringify({ a: ['b', 'c', 'd'] }), 'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d');
@@ -47,12 +53,23 @@ test('stringify()', function (t) {
47
53
  st.equal(qs.stringify({ a: { b: ['c', 'd'] } }), 'a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d');
48
54
  st.end();
49
55
  });
56
+
57
+ t.test('stringifies a nested array value with dots notation', function (st) {
58
+ st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { allowDots: true, encode: false }), 'a.b[0]=c&a.b[1]=d');
59
+ st.end();
60
+ });
50
61
 
51
62
  t.test('stringifies an object inside an array', function (st) {
52
63
  st.equal(qs.stringify({ a: [{ b: 'c' }] }), 'a%5B0%5D%5Bb%5D=c');
53
64
  st.equal(qs.stringify({ a: [{ b: { c: [1] } }] }), 'a%5B0%5D%5Bb%5D%5Bc%5D%5B0%5D=1');
54
65
  st.end();
55
66
  });
67
+
68
+ t.test('stringifies an object inside an array with dots notation', function (st) {
69
+ st.equal(qs.stringify({ a: [{ b: 'c' }] }, { allowDots: true, encode: false }), 'a[0].b=c');
70
+ st.equal(qs.stringify({ a: [{ b: { c: [1] } }] }, { allowDots: true, encode: false }), 'a[0].b.c[0]=1');
71
+ st.end();
72
+ });
56
73
 
57
74
  t.test('does not omit object keys when indices = false', function (st) {
58
75
  st.equal(qs.stringify({ a: [{ b: 'c' }] }, { indices: false }), 'a%5Bb%5D=c');
@@ -232,4 +249,11 @@ test('stringify()', function (t) {
232
249
  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
250
  st.end();
234
251
  });
252
+
253
+ t.test('can sort the keys at depth 3 or more too', function (st) {
254
+ var sort = function (a, b) { return a.localeCompare(b); };
255
+ st.equal(qs.stringify({ a: 'a', z: { zj: {zjb: 'zjb', zja: 'zja'}, zi: {zib: 'zib', zia: 'zia'} }, b: 'b' }, { sort: sort, encode: false }), 'a=a&b=b&z[zi][zia]=zia&z[zi][zib]=zib&z[zj][zja]=zja&z[zj][zjb]=zjb');
256
+ st.equal(qs.stringify({ a: 'a', z: { zj: {zjb: 'zjb', zja: 'zja'}, zi: {zib: 'zib', zia: 'zia'} }, b: 'b' }, { sort: null, encode: false }), 'a=a&z[zj][zjb]=zjb&z[zj][zja]=zja&z[zi][zib]=zib&z[zi][zia]=zia&b=b');
257
+ st.end();
258
+ });
235
259
  });
package/test/utils.js CHANGED
File without changes