qs 6.8.3 → 6.8.5

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/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## **6.8.5**
2
+ - [Fix] fix regressions from robustness refactor
3
+ - [meta] add `npmignore` to autogenerate an npmignore file
4
+ - [actions] update reusable workflows
5
+
6
+ ## **6.8.4**
7
+ - [Robustness] avoid `.push`, use `void`
8
+ - [readme] clarify `parseArrays` and `arrayLimit` documentation (#543)
9
+ - [readme] document that `addQueryPrefix` does not add `?` to empty output (#418)
10
+ - [readme] replace runkit CI badge with shields.io check-runs badge
11
+ - [actions] fix rebase workflow permissions
12
+
1
13
  ## **6.8.3**
2
14
  - [Fix] `parse`: ignore `__proto__` keys (#428)
3
15
  - [Robustness] `stringify`: avoid relying on a global `undefined` (#427)
package/README.md CHANGED
@@ -238,7 +238,7 @@ var withIndexedEmptyString = qs.parse('a[0]=b&a[1]=&a[2]=c');
238
238
  assert.deepEqual(withIndexedEmptyString, { a: ['b', '', 'c'] });
239
239
  ```
240
240
 
241
- **qs** will also limit specifying indices in an array to a maximum index of `20`. Any array members with an index of greater than `20` will
241
+ **qs** will also limit arrays to a maximum of `20` elements. Any array members with an index of `20` or greater will
242
242
  instead be converted to an object with the index as the key. This is needed to handle cases when someone sent, for example, `a[999999999]` and it will take significant time to iterate over this huge array.
243
243
 
244
244
  ```javascript
@@ -253,7 +253,7 @@ var withArrayLimit = qs.parse('a[1]=b', { arrayLimit: 0 });
253
253
  assert.deepEqual(withArrayLimit, { a: { '1': 'b' } });
254
254
  ```
255
255
 
256
- To disable array parsing entirely, set `parseArrays` to `false`.
256
+ To prevent array syntax (`a[]`, `a[0]`) from being parsed as arrays, set `parseArrays` to `false`.
257
257
 
258
258
  ```javascript
259
259
  var noParsingArrays = qs.parse('a[]=b', { parseArrays: false });
@@ -437,6 +437,12 @@ The query string may optionally be prepended with a question mark:
437
437
  assert.equal(qs.stringify({ a: 'b', c: 'd' }, { addQueryPrefix: true }), '?a=b&c=d');
438
438
  ```
439
439
 
440
+ Note that when the output is an empty string, the prefix will not be added:
441
+
442
+ ```javascript
443
+ assert.equal(qs.stringify({}, { addQueryPrefix: true }), '');
444
+ ```
445
+
440
446
  The delimiter may be overridden with stringify as well:
441
447
 
442
448
  ```javascript
@@ -612,5 +618,5 @@ The maintainers of qs and thousands of other packages are working with Tidelift
612
618
  [downloads-url]: https://npm-stat.com/charts.html?package=qs
613
619
  [codecov-image]: https://codecov.io/gh/ljharb/qs/branch/main/graphs/badge.svg
614
620
  [codecov-url]: https://app.codecov.io/gh/ljharb/qs/
615
- [actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/ljharb/qs
621
+ [actions-image]: https://img.shields.io/github/check-runs/ljharb/qs/main
616
622
  [actions-url]: https://github.com/ljharb/qs/actions
package/dist/qs.js CHANGED
@@ -83,7 +83,7 @@ var maybeMap = function maybeMap(val, fn) {
83
83
  if (isArray(val)) {
84
84
  var mapped = [];
85
85
  for (var i = 0; i < val.length; i += 1) {
86
- mapped.push(fn(val[i]));
86
+ mapped[mapped.length] = fn(val[i]);
87
87
  }
88
88
  return mapped;
89
89
  }
@@ -103,7 +103,7 @@ var charsetSentinel = 'utf8=%E2%9C%93'; // encodeURIComponent('✓')
103
103
  var parseValues = function parseQueryStringValues(str, options) {
104
104
  var obj = {};
105
105
  var cleanStr = options.ignoreQueryPrefix ? str.replace(/^\?/, '') : str;
106
- var limit = options.parameterLimit === Infinity ? undefined : options.parameterLimit;
106
+ var limit = options.parameterLimit === Infinity ? void undefined : options.parameterLimit;
107
107
  var parts = cleanStr.split(options.delimiter, limit);
108
108
  var skipIndex = -1; // Keep track of where the utf8 sentinel was found
109
109
  var i;
@@ -228,7 +228,7 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesPars
228
228
  }
229
229
  }
230
230
 
231
- keys.push(parent);
231
+ keys[keys.length] = parent;
232
232
  }
233
233
 
234
234
  // Loop through children appending to the array until we hit depth
@@ -241,13 +241,13 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesPars
241
241
  return;
242
242
  }
243
243
  }
244
- keys.push(segment[1]);
244
+ keys[keys.length] = segment[1];
245
245
  }
246
246
 
247
247
  // If there's a remainder, just add whatever is left
248
248
 
249
249
  if (segment) {
250
- keys.push('[' + key.slice(segment.index) + ']');
250
+ keys[keys.length] = '[' + key.slice(segment.index) + ']';
251
251
  }
252
252
 
253
253
  return parseObject(keys, val, options, valuesParsed);
@@ -595,7 +595,7 @@ var isArray = Array.isArray;
595
595
  var hexTable = (function () {
596
596
  var array = [];
597
597
  for (var i = 0; i < 256; ++i) {
598
- array.push('%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase());
598
+ array[array.length] = '%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase();
599
599
  }
600
600
 
601
601
  return array;
@@ -611,7 +611,7 @@ var compactQueue = function compactQueue(queue) {
611
611
 
612
612
  for (var j = 0; j < obj.length; ++j) {
613
613
  if (typeof obj[j] !== 'undefined') {
614
- compacted.push(obj[j]);
614
+ compacted[compacted.length] = obj[j];
615
615
  }
616
616
  }
617
617
 
@@ -638,7 +638,7 @@ var merge = function merge(target, source, options) {
638
638
 
639
639
  if (typeof source !== 'object') {
640
640
  if (isArray(target)) {
641
- target.push(source);
641
+ target[target.length] = source;
642
642
  } else if (target && typeof target === 'object') {
643
643
  if ((options && (options.plainObjects || options.allowPrototypes)) || !has.call(Object.prototype, source)) {
644
644
  target[source] = true; // eslint-disable-line no-param-reassign
@@ -666,7 +666,7 @@ var merge = function merge(target, source, options) {
666
666
  if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') {
667
667
  target[i] = merge(targetItem, item, options); // eslint-disable-line no-param-reassign
668
668
  } else {
669
- target.push(item);
669
+ target[target.length] = item;
670
670
  }
671
671
  } else {
672
672
  target[i] = item; // eslint-disable-line no-param-reassign
@@ -785,8 +785,8 @@ var compact = function compact(value) {
785
785
  var key = keys[j];
786
786
  var val = obj[key];
787
787
  if (typeof val === 'object' && val !== null && refs.indexOf(val) === -1) {
788
- queue.push({ obj: obj, prop: key });
789
- refs.push(val);
788
+ queue[queue.length] = { obj: obj, prop: key };
789
+ refs[refs.length] = val;
790
790
  }
791
791
  }
792
792
  }
package/lib/parse.js CHANGED
@@ -41,7 +41,7 @@ var maybeMap = function maybeMap(val, fn) {
41
41
  if (isArray(val)) {
42
42
  var mapped = [];
43
43
  for (var i = 0; i < val.length; i += 1) {
44
- mapped.push(fn(val[i]));
44
+ mapped[mapped.length] = fn(val[i]);
45
45
  }
46
46
  return mapped;
47
47
  }
@@ -61,7 +61,7 @@ var charsetSentinel = 'utf8=%E2%9C%93'; // encodeURIComponent('✓')
61
61
  var parseValues = function parseQueryStringValues(str, options) {
62
62
  var obj = {};
63
63
  var cleanStr = options.ignoreQueryPrefix ? str.replace(/^\?/, '') : str;
64
- var limit = options.parameterLimit === Infinity ? undefined : options.parameterLimit;
64
+ var limit = options.parameterLimit === Infinity ? void undefined : options.parameterLimit;
65
65
  var parts = cleanStr.split(options.delimiter, limit);
66
66
  var skipIndex = -1; // Keep track of where the utf8 sentinel was found
67
67
  var i;
@@ -186,7 +186,7 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesPars
186
186
  }
187
187
  }
188
188
 
189
- keys.push(parent);
189
+ keys[keys.length] = parent;
190
190
  }
191
191
 
192
192
  // Loop through children appending to the array until we hit depth
@@ -199,13 +199,13 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesPars
199
199
  return;
200
200
  }
201
201
  }
202
- keys.push(segment[1]);
202
+ keys[keys.length] = segment[1];
203
203
  }
204
204
 
205
205
  // If there's a remainder, just add whatever is left
206
206
 
207
207
  if (segment) {
208
- keys.push('[' + key.slice(segment.index) + ']');
208
+ keys[keys.length] = '[' + key.slice(segment.index) + ']';
209
209
  }
210
210
 
211
211
  return parseObject(keys, val, options, valuesParsed);
package/lib/utils.js CHANGED
@@ -6,7 +6,7 @@ var isArray = Array.isArray;
6
6
  var hexTable = (function () {
7
7
  var array = [];
8
8
  for (var i = 0; i < 256; ++i) {
9
- array.push('%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase());
9
+ array[array.length] = '%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase();
10
10
  }
11
11
 
12
12
  return array;
@@ -22,7 +22,7 @@ var compactQueue = function compactQueue(queue) {
22
22
 
23
23
  for (var j = 0; j < obj.length; ++j) {
24
24
  if (typeof obj[j] !== 'undefined') {
25
- compacted.push(obj[j]);
25
+ compacted[compacted.length] = obj[j];
26
26
  }
27
27
  }
28
28
 
@@ -49,7 +49,7 @@ var merge = function merge(target, source, options) {
49
49
 
50
50
  if (typeof source !== 'object') {
51
51
  if (isArray(target)) {
52
- target.push(source);
52
+ target[target.length] = source;
53
53
  } else if (target && typeof target === 'object') {
54
54
  if ((options && (options.plainObjects || options.allowPrototypes)) || !has.call(Object.prototype, source)) {
55
55
  target[source] = true; // eslint-disable-line no-param-reassign
@@ -77,7 +77,7 @@ var merge = function merge(target, source, options) {
77
77
  if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') {
78
78
  target[i] = merge(targetItem, item, options); // eslint-disable-line no-param-reassign
79
79
  } else {
80
- target.push(item);
80
+ target[target.length] = item;
81
81
  }
82
82
  } else {
83
83
  target[i] = item; // eslint-disable-line no-param-reassign
@@ -196,8 +196,8 @@ var compact = function compact(value) {
196
196
  var key = keys[j];
197
197
  var val = obj[key];
198
198
  if (typeof val === 'object' && val !== null && refs.indexOf(val) === -1) {
199
- queue.push({ obj: obj, prop: key });
200
- refs.push(val);
199
+ queue[queue.length] = { obj: obj, prop: key };
200
+ refs[refs.length] = val;
201
201
  }
202
202
  }
203
203
  }
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.8.3",
5
+ "version": "6.8.5",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/ljharb/qs.git"
@@ -45,10 +45,11 @@
45
45
  "qs-iconv": "^1.0.4",
46
46
  "safe-publish-latest": "^2.0.0",
47
47
  "safer-buffer": "^2.1.2",
48
- "tape": "^5.4.0"
48
+ "tape": "^5.4.0",
49
+ "npmignore": "^0.3.1"
49
50
  },
50
51
  "scripts": {
51
- "prepublishOnly": "safe-publish-latest && npm run dist",
52
+ "prepublishOnly": "safe-publish-latest && npmignore --auto --commentLines=autogenerated && npm run dist",
52
53
  "prepublish": "not-in-publish || npm run prepublishOnly",
53
54
  "pretest": "npm run --silent readme && npm run --silent lint",
54
55
  "test": "npm run --silent coverage",
@@ -60,5 +61,13 @@
60
61
  "coverage": "covert test",
61
62
  "dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js"
62
63
  },
63
- "license": "BSD-3-Clause"
64
+ "license": "BSD-3-Clause",
65
+ "publishConfig": {
66
+ "ignore": [
67
+ "!dist/*",
68
+ "bower.json",
69
+ "component.json",
70
+ ".github/workflows"
71
+ ]
72
+ }
64
73
  }
package/test/parse.js CHANGED
@@ -84,6 +84,15 @@ test('parse()', function (t) {
84
84
  st.end();
85
85
  });
86
86
 
87
+ t.test('correctly computes the remainder when depth is exceeded', function (st) {
88
+ st.deepEqual(
89
+ qs.parse('a[b][c][d][e]=f', { depth: 2 }),
90
+ { a: { b: { c: { '[d][e]': 'f' } } } },
91
+ 'the remainder is "[d][e]", not the full original key'
92
+ );
93
+ st.end();
94
+ });
95
+
87
96
  t.test('uses original key when depth = 0', function (st) {
88
97
  st.deepEqual(qs.parse('a[0]=b&a[1]=c', { depth: 0 }), { 'a[0]': 'b', 'a[1]': 'c' });
89
98
  st.deepEqual(qs.parse('a[0][0]=b&a[0][1]=c&a[1]=d&e=2', { depth: 0 }), { 'a[0][0]': 'b', 'a[0][1]': 'c', 'a[1]': 'd', e: '2' });
package/test/stringify.js CHANGED
@@ -21,6 +21,12 @@ test('stringify()', function (t) {
21
21
  st.end();
22
22
  });
23
23
 
24
+ t.test('correctly encodes low-byte characters', function (st) {
25
+ st.equal(qs.stringify({ a: String.fromCharCode(1) }), 'a=%01', 'encodes 0x01');
26
+ st.equal(qs.stringify({ a: String.fromCharCode(15) }), 'a=%0F', 'encodes 0x0F');
27
+ st.end();
28
+ });
29
+
24
30
  t.test('stringifies falsy values', function (st) {
25
31
  st.equal(qs.stringify(undefined), '');
26
32
  st.equal(qs.stringify(null), '');