/ node_modules / qs / README.md
README.md
  1  <p align="center">
  2      <img alt="qs" src="./logos/banner_default.png" width="800" />
  3  </p>
  4  
  5  # qs <sup>[![Version Badge][npm-version-svg]][package-url]</sup>
  6  
  7  [![github actions][actions-image]][actions-url]
  8  [![coverage][codecov-image]][codecov-url]
  9  [![License][license-image]][license-url]
 10  [![Downloads][downloads-image]][downloads-url]
 11  [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/9058/badge)](https://bestpractices.coreinfrastructure.org/projects/9058)
 12  
 13  [![npm badge][npm-badge-png]][package-url]
 14  
 15  A querystring parsing and stringifying library with some added security.
 16  
 17  Lead Maintainer: [Jordan Harband](https://github.com/ljharb)
 18  
 19  The **qs** module was originally created and maintained by [TJ Holowaychuk](https://github.com/visionmedia/node-querystring).
 20  
 21  ## Usage
 22  
 23  ```javascript
 24  var qs = require('qs');
 25  var assert = require('assert');
 26  
 27  var obj = qs.parse('a=c');
 28  assert.deepEqual(obj, { a: 'c' });
 29  
 30  var str = qs.stringify(obj);
 31  assert.equal(str, 'a=c');
 32  ```
 33  
 34  ### Parsing Objects
 35  
 36  [](#preventEval)
 37  ```javascript
 38  qs.parse(string, [options]);
 39  ```
 40  
 41  **qs** allows you to create nested objects within your query strings, by surrounding the name of sub-keys with square brackets `[]`.
 42  For example, the string `'foo[bar]=baz'` converts to:
 43  
 44  ```javascript
 45  assert.deepEqual(qs.parse('foo[bar]=baz'), {
 46      foo: {
 47          bar: 'baz'
 48      }
 49  });
 50  ```
 51  
 52  When using the `plainObjects` option the parsed value is returned as a null object, created via `{ __proto__: 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:
 53  
 54  ```javascript
 55  var nullObject = qs.parse('a[hasOwnProperty]=b', { plainObjects: true });
 56  assert.deepEqual(nullObject, { a: { hasOwnProperty: 'b' } });
 57  ```
 58  
 59  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.
 60  *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.
 61  Always be careful with this option.
 62  
 63  ```javascript
 64  var protoObject = qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true });
 65  assert.deepEqual(protoObject, { a: { hasOwnProperty: 'b' } });
 66  ```
 67  
 68  URI encoded strings work too:
 69  
 70  ```javascript
 71  assert.deepEqual(qs.parse('a%5Bb%5D=c'), {
 72      a: { b: 'c' }
 73  });
 74  ```
 75  
 76  You can also nest your objects, like `'foo[bar][baz]=foobarbaz'`:
 77  
 78  ```javascript
 79  assert.deepEqual(qs.parse('foo[bar][baz]=foobarbaz'), {
 80      foo: {
 81          bar: {
 82              baz: 'foobarbaz'
 83          }
 84      }
 85  });
 86  ```
 87  
 88  By default, when nesting objects **qs** will only parse up to 5 children deep.
 89  This means if you attempt to parse a string like `'a[b][c][d][e][f][g][h][i]=j'` your resulting object will be:
 90  
 91  ```javascript
 92  var expected = {
 93      a: {
 94          b: {
 95              c: {
 96                  d: {
 97                      e: {
 98                          f: {
 99                              '[g][h][i]': 'j'
100                          }
101                      }
102                  }
103              }
104          }
105      }
106  };
107  var string = 'a[b][c][d][e][f][g][h][i]=j';
108  assert.deepEqual(qs.parse(string), expected);
109  ```
110  
111  This depth can be overridden by passing a `depth` option to `qs.parse(string, [options])`:
112  
113  ```javascript
114  var deep = qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1 });
115  assert.deepEqual(deep, { a: { b: { '[c][d][e][f][g][h][i]': 'j' } } });
116  ```
117  
118  You can configure **qs** to throw an error when parsing nested input beyond this depth using the `strictDepth` option (defaulted to false):
119  
120  ```javascript
121  try {
122      qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1, strictDepth: true });
123  } catch (err) {
124      assert(err instanceof RangeError);
125      assert.strictEqual(err.message, 'Input depth exceeded depth option of 1 and strictDepth is true');
126  }
127  ```
128  
129  The depth limit helps mitigate abuse when **qs** is used to parse user input, and it is recommended to keep it a reasonably small number. The strictDepth option adds a layer of protection by throwing an error when the limit is exceeded, allowing you to catch and handle such cases.
130  
131  For similar reasons, by default **qs** will only parse up to 1000 parameters. This can be overridden by passing a `parameterLimit` option:
132  
133  ```javascript
134  var limited = qs.parse('a=b&c=d', { parameterLimit: 1 });
135  assert.deepEqual(limited, { a: 'b' });
136  ```
137  
138  If you want an error to be thrown whenever the a limit is exceeded (eg, `parameterLimit`, `arrayLimit`), set the `throwOnLimitExceeded` option to `true`. This option will generate a descriptive error if the query string exceeds a configured limit.
139  ```javascript
140  try {
141      qs.parse('a=1&b=2&c=3&d=4', { parameterLimit: 3, throwOnLimitExceeded: true });
142  } catch (err) {
143      assert(err instanceof Error);
144      assert.strictEqual(err.message, 'Parameter limit exceeded. Only 3 parameters allowed.');
145  }
146  ```
147  
148  When `throwOnLimitExceeded` is set to `false` (default), **qs** will parse up to the specified `parameterLimit` and ignore the rest without throwing an error.
149  
150  To bypass the leading question mark, use `ignoreQueryPrefix`:
151  
152  ```javascript
153  var prefixed = qs.parse('?a=b&c=d', { ignoreQueryPrefix: true });
154  assert.deepEqual(prefixed, { a: 'b', c: 'd' });
155  ```
156  
157  An optional delimiter can also be passed:
158  
159  ```javascript
160  var delimited = qs.parse('a=b;c=d', { delimiter: ';' });
161  assert.deepEqual(delimited, { a: 'b', c: 'd' });
162  ```
163  
164  Delimiters can be a regular expression too:
165  
166  ```javascript
167  var regexed = qs.parse('a=b;c=d,e=f', { delimiter: /[;,]/ });
168  assert.deepEqual(regexed, { a: 'b', c: 'd', e: 'f' });
169  ```
170  
171  Option `allowDots` can be used to enable dot notation:
172  
173  ```javascript
174  var withDots = qs.parse('a.b=c', { allowDots: true });
175  assert.deepEqual(withDots, { a: { b: 'c' } });
176  ```
177  
178  Option `decodeDotInKeys` can be used to decode dots in keys
179  Note: it implies `allowDots`, so `parse` will error if you set `decodeDotInKeys` to `true`, and `allowDots` to `false`.
180  
181  ```javascript
182  var withDots = qs.parse('name%252Eobj.first=John&name%252Eobj.last=Doe', { decodeDotInKeys: true });
183  assert.deepEqual(withDots, { 'name.obj': { first: 'John', last: 'Doe' }});
184  ```
185  
186  Option `allowEmptyArrays` can be used to allowing empty array values in object
187  ```javascript
188  var withEmptyArrays = qs.parse('foo[]&bar=baz', { allowEmptyArrays: true });
189  assert.deepEqual(withEmptyArrays, { foo: [], bar: 'baz' });
190  ```
191  
192  Option `duplicates` can be used to change the behavior when duplicate keys are encountered
193  ```javascript
194  assert.deepEqual(qs.parse('foo=bar&foo=baz'), { foo: ['bar', 'baz'] });
195  assert.deepEqual(qs.parse('foo=bar&foo=baz', { duplicates: 'combine' }), { foo: ['bar', 'baz'] });
196  assert.deepEqual(qs.parse('foo=bar&foo=baz', { duplicates: 'first' }), { foo: 'bar' });
197  assert.deepEqual(qs.parse('foo=bar&foo=baz', { duplicates: 'last' }), { foo: 'baz' });
198  ```
199  
200  If you have to deal with legacy browsers or services, there's also support for decoding percent-encoded octets as iso-8859-1:
201  
202  ```javascript
203  var oldCharset = qs.parse('a=%A7', { charset: 'iso-8859-1' });
204  assert.deepEqual(oldCharset, { a: '§' });
205  ```
206  
207  Some services add an initial `utf8=✓` value to forms so that old Internet Explorer versions are more likely to submit the form as utf-8.
208  Additionally, the server can check the value against wrong encodings of the checkmark character and detect that a query string or `application/x-www-form-urlencoded` body was *not* sent as utf-8, eg. if the form had an `accept-charset` parameter or the containing page had a different character set.
209  
210  **qs** supports this mechanism via the `charsetSentinel` option.
211  If specified, the `utf8` parameter will be omitted from the returned object.
212  It will be used to switch to `iso-8859-1`/`utf-8` mode depending on how the checkmark is encoded.
213  
214  **Important**: When you specify both the `charset` option and the `charsetSentinel` option, the `charset` will be overridden when the request contains a `utf8` parameter from which the actual charset can be deduced.
215  In that sense the `charset` will behave as the default charset rather than the authoritative charset.
216  
217  ```javascript
218  var detectedAsUtf8 = qs.parse('utf8=%E2%9C%93&a=%C3%B8', {
219      charset: 'iso-8859-1',
220      charsetSentinel: true
221  });
222  assert.deepEqual(detectedAsUtf8, { a: 'ø' });
223  
224  // Browsers encode the checkmark as &#10003; when submitting as iso-8859-1:
225  var detectedAsIso8859_1 = qs.parse('utf8=%26%2310003%3B&a=%F8', {
226      charset: 'utf-8',
227      charsetSentinel: true
228  });
229  assert.deepEqual(detectedAsIso8859_1, { a: 'ø' });
230  ```
231  
232  If you want to decode the `&#...;` syntax to the actual character, you can specify the `interpretNumericEntities` option as well:
233  
234  ```javascript
235  var detectedAsIso8859_1 = qs.parse('a=%26%239786%3B', {
236      charset: 'iso-8859-1',
237      interpretNumericEntities: true
238  });
239  assert.deepEqual(detectedAsIso8859_1, { a: '☺' });
240  ```
241  
242  It also works when the charset has been detected in `charsetSentinel` mode.
243  
244  ### Parsing Arrays
245  
246  **qs** can also parse arrays using a similar `[]` notation:
247  
248  ```javascript
249  var withArray = qs.parse('a[]=b&a[]=c');
250  assert.deepEqual(withArray, { a: ['b', 'c'] });
251  ```
252  
253  You may specify an index as well:
254  
255  ```javascript
256  var withIndexes = qs.parse('a[1]=c&a[0]=b');
257  assert.deepEqual(withIndexes, { a: ['b', 'c'] });
258  ```
259  
260  Note that the only difference between an index in an array and a key in an object is that the value between the brackets must be a number to create an array.
261  When creating arrays with specific indices, **qs** will compact a sparse array to only the existing values preserving their order:
262  
263  ```javascript
264  var noSparse = qs.parse('a[1]=b&a[15]=c');
265  assert.deepEqual(noSparse, { a: ['b', 'c'] });
266  ```
267  
268  You may also use `allowSparse` option to parse sparse arrays:
269  
270  ```javascript
271  var sparseArray = qs.parse('a[1]=2&a[3]=5', { allowSparse: true });
272  assert.deepEqual(sparseArray, { a: [, '2', , '5'] });
273  ```
274  
275  Note that an empty string is also a value, and will be preserved:
276  
277  ```javascript
278  var withEmptyString = qs.parse('a[]=&a[]=b');
279  assert.deepEqual(withEmptyString, { a: ['', 'b'] });
280  
281  var withIndexedEmptyString = qs.parse('a[0]=b&a[1]=&a[2]=c');
282  assert.deepEqual(withIndexedEmptyString, { a: ['b', '', 'c'] });
283  ```
284  
285  **qs** will also limit specifying indices in an array to a maximum index of `20`.
286  Any array members with an index of greater than `20` will instead be converted to an object with the index as the key.
287  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.
288  
289  ```javascript
290  var withMaxIndex = qs.parse('a[100]=b');
291  assert.deepEqual(withMaxIndex, { a: { '100': 'b' } });
292  ```
293  
294  This limit can be overridden by passing an `arrayLimit` option:
295  
296  ```javascript
297  var withArrayLimit = qs.parse('a[1]=b', { arrayLimit: 0 });
298  assert.deepEqual(withArrayLimit, { a: { '1': 'b' } });
299  ```
300  
301  If you want to throw an error whenever the array limit is exceeded, set the `throwOnLimitExceeded` option to `true`. This option will generate a descriptive error if the query string exceeds a configured limit.
302  ```javascript
303  try {
304      qs.parse('a[1]=b', { arrayLimit: 0, throwOnLimitExceeded: true });
305  } catch (err) {
306      assert(err instanceof Error);
307      assert.strictEqual(err.message, 'Array limit exceeded. Only 0 elements allowed in an array.');
308  }
309  ```
310  
311  When `throwOnLimitExceeded` is set to `false` (default), **qs** will parse up to the specified `arrayLimit` and if the limit is exceeded, the array will instead be converted to an object with the index as the key
312  
313  To disable array parsing entirely, set `parseArrays` to `false`.
314  
315  ```javascript
316  var noParsingArrays = qs.parse('a[]=b', { parseArrays: false });
317  assert.deepEqual(noParsingArrays, { a: { '0': 'b' } });
318  ```
319  
320  If you mix notations, **qs** will merge the two items into an object:
321  
322  ```javascript
323  var mixedNotation = qs.parse('a[0]=b&a[b]=c');
324  assert.deepEqual(mixedNotation, { a: { '0': 'b', b: 'c' } });
325  ```
326  
327  You can also create arrays of objects:
328  
329  ```javascript
330  var arraysOfObjects = qs.parse('a[][b]=c');
331  assert.deepEqual(arraysOfObjects, { a: [{ b: 'c' }] });
332  ```
333  
334  Some people use comma to join array, **qs** can parse it:
335  ```javascript
336  var arraysOfObjects = qs.parse('a=b,c', { comma: true })
337  assert.deepEqual(arraysOfObjects, { a: ['b', 'c'] })
338  ```
339  (_this cannot convert nested objects, such as `a={b:1},{c:d}`_)
340  
341  ### Parsing primitive/scalar values (numbers, booleans, null, etc)
342  
343  By default, all values are parsed as strings.
344  This behavior will not change and is explained in [issue #91](https://github.com/ljharb/qs/issues/91).
345  
346  ```javascript
347  var primitiveValues = qs.parse('a=15&b=true&c=null');
348  assert.deepEqual(primitiveValues, { a: '15', b: 'true', c: 'null' });
349  ```
350  
351  If you wish to auto-convert values which look like numbers, booleans, and other values into their primitive counterparts, you can use the [query-types Express JS middleware](https://github.com/xpepermint/query-types) which will auto-convert all request query parameters.
352  
353  ### Stringifying
354  
355  [](#preventEval)
356  ```javascript
357  qs.stringify(object, [options]);
358  ```
359  
360  When stringifying, **qs** by default URI encodes output. Objects are stringified as you would expect:
361  
362  ```javascript
363  assert.equal(qs.stringify({ a: 'b' }), 'a=b');
364  assert.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
365  ```
366  
367  This encoding can be disabled by setting the `encode` option to `false`:
368  
369  ```javascript
370  var unencoded = qs.stringify({ a: { b: 'c' } }, { encode: false });
371  assert.equal(unencoded, 'a[b]=c');
372  ```
373  
374  Encoding can be disabled for keys by setting the `encodeValuesOnly` option to `true`:
375  ```javascript
376  var encodedValues = qs.stringify(
377      { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
378      { encodeValuesOnly: true }
379  );
380  assert.equal(encodedValues,'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h');
381  ```
382  
383  This encoding can also be replaced by a custom encoding method set as `encoder` option:
384  
385  ```javascript
386  var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str) {
387      // Passed in values `a`, `b`, `c`
388      return // Return encoded string
389  }})
390  ```
391  
392  _(Note: the `encoder` option does not apply if `encode` is `false`)_
393  
394  Analogue to the `encoder` there is a `decoder` option for `parse` to override decoding of properties and values:
395  
396  ```javascript
397  var decoded = qs.parse('x=z', { decoder: function (str) {
398      // Passed in values `x`, `z`
399      return // Return decoded string
400  }})
401  ```
402  
403  You can encode keys and values using different logic by using the type argument provided to the encoder:
404  
405  ```javascript
406  var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str, defaultEncoder, charset, type) {
407      if (type === 'key') {
408          return // Encoded key
409      } else if (type === 'value') {
410          return // Encoded value
411      }
412  }})
413  ```
414  
415  The type argument is also provided to the decoder:
416  
417  ```javascript
418  var decoded = qs.parse('x=z', { decoder: function (str, defaultDecoder, charset, type) {
419      if (type === 'key') {
420          return // Decoded key
421      } else if (type === 'value') {
422          return // Decoded value
423      }
424  }})
425  ```
426  
427  Examples beyond this point will be shown as though the output is not URI encoded for clarity.
428  Please note that the return values in these cases *will* be URI encoded during real usage.
429  
430  When arrays are stringified, they follow the `arrayFormat` option, which defaults to `indices`:
431  
432  ```javascript
433  qs.stringify({ a: ['b', 'c', 'd'] });
434  // 'a[0]=b&a[1]=c&a[2]=d'
435  ```
436  
437  You may override this by setting the `indices` option to `false`, or to be more explicit, the `arrayFormat` option to `repeat`:
438  
439  ```javascript
440  qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false });
441  // 'a=b&a=c&a=d'
442  ```
443  
444  You may use the `arrayFormat` option to specify the format of the output array:
445  
446  ```javascript
447  qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })
448  // 'a[0]=b&a[1]=c'
449  qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })
450  // 'a[]=b&a[]=c'
451  qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })
452  // 'a=b&a=c'
453  qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'comma' })
454  // 'a=b,c'
455  ```
456  
457  Note: when using `arrayFormat` set to `'comma'`, you can also pass the `commaRoundTrip` option set to `true` or `false`, to append `[]` on single-item arrays, so that they can round trip through a parse.
458  
459  When objects are stringified, by default they use bracket notation:
460  
461  ```javascript
462  qs.stringify({ a: { b: { c: 'd', e: 'f' } } });
463  // 'a[b][c]=d&a[b][e]=f'
464  ```
465  
466  You may override this to use dot notation by setting the `allowDots` option to `true`:
467  
468  ```javascript
469  qs.stringify({ a: { b: { c: 'd', e: 'f' } } }, { allowDots: true });
470  // 'a.b.c=d&a.b.e=f'
471  ```
472  
473  You may encode the dot notation in the keys of object with option `encodeDotInKeys` by setting it to `true`:
474  Note: it implies `allowDots`, so `stringify` will error if you set `decodeDotInKeys` to `true`, and `allowDots` to `false`.
475  Caveat: when `encodeValuesOnly` is `true` as well as `encodeDotInKeys`, only dots in keys and nothing else will be encoded.
476  ```javascript
477  qs.stringify({ "name.obj": { "first": "John", "last": "Doe" } }, { allowDots: true, encodeDotInKeys: true })
478  // 'name%252Eobj.first=John&name%252Eobj.last=Doe'
479  ```
480  
481  You may allow empty array values by setting the `allowEmptyArrays` option to `true`:
482  ```javascript
483  qs.stringify({ foo: [], bar: 'baz' }, { allowEmptyArrays: true });
484  // 'foo[]&bar=baz'
485  ```
486  
487  Empty strings and null values will omit the value, but the equals sign (=) remains in place:
488  
489  ```javascript
490  assert.equal(qs.stringify({ a: '' }), 'a=');
491  ```
492  
493  Key with no values (such as an empty object or array) will return nothing:
494  
495  ```javascript
496  assert.equal(qs.stringify({ a: [] }), '');
497  assert.equal(qs.stringify({ a: {} }), '');
498  assert.equal(qs.stringify({ a: [{}] }), '');
499  assert.equal(qs.stringify({ a: { b: []} }), '');
500  assert.equal(qs.stringify({ a: { b: {}} }), '');
501  ```
502  
503  Properties that are set to `undefined` will be omitted entirely:
504  
505  ```javascript
506  assert.equal(qs.stringify({ a: null, b: undefined }), 'a=');
507  ```
508  
509  The query string may optionally be prepended with a question mark:
510  
511  ```javascript
512  assert.equal(qs.stringify({ a: 'b', c: 'd' }, { addQueryPrefix: true }), '?a=b&c=d');
513  ```
514  
515  The delimiter may be overridden with stringify as well:
516  
517  ```javascript
518  assert.equal(qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' }), 'a=b;c=d');
519  ```
520  
521  If you only want to override the serialization of `Date` objects, you can provide a `serializeDate` option:
522  
523  ```javascript
524  var date = new Date(7);
525  assert.equal(qs.stringify({ a: date }), 'a=1970-01-01T00:00:00.007Z'.replace(/:/g, '%3A'));
526  assert.equal(
527      qs.stringify({ a: date }, { serializeDate: function (d) { return d.getTime(); } }),
528      'a=7'
529  );
530  ```
531  
532  You may use the `sort` option to affect the order of parameter keys:
533  
534  ```javascript
535  function alphabeticalSort(a, b) {
536      return a.localeCompare(b);
537  }
538  assert.equal(qs.stringify({ a: 'c', z: 'y', b : 'f' }, { sort: alphabeticalSort }), 'a=c&b=f&z=y');
539  ```
540  
541  Finally, you can use the `filter` option to restrict which keys will be included in the stringified output.
542  If you pass a function, it will be called for each key to obtain the replacement value.
543  Otherwise, if you pass an array, it will be used to select properties and array indices for stringification:
544  
545  ```javascript
546  function filterFunc(prefix, value) {
547      if (prefix == 'b') {
548          // Return an `undefined` value to omit a property.
549          return;
550      }
551      if (prefix == 'e[f]') {
552          return value.getTime();
553      }
554      if (prefix == 'e[g][0]') {
555          return value * 2;
556      }
557      return value;
558  }
559  qs.stringify({ a: 'b', c: 'd', e: { f: new Date(123), g: [2] } }, { filter: filterFunc });
560  // 'a=b&c=d&e[f]=123&e[g][0]=4'
561  qs.stringify({ a: 'b', c: 'd', e: 'f' }, { filter: ['a', 'e'] });
562  // 'a=b&e=f'
563  qs.stringify({ a: ['b', 'c', 'd'], e: 'f' }, { filter: ['a', 0, 2] });
564  // 'a[0]=b&a[2]=d'
565  ```
566  
567  You could also use `filter` to inject custom serialization for user defined types.
568  Consider you're working with some api that expects query strings of the format for ranges:
569  
570  ```
571  https://domain.com/endpoint?range=30...70
572  ```
573  
574  For which you model as:
575  
576  ```javascript
577  class Range {
578      constructor(from, to) {
579          this.from = from;
580          this.to = to;
581      }
582  }
583  ```
584  
585  You could _inject_ a custom serializer to handle values of this type:
586  
587  ```javascript
588  qs.stringify(
589      {
590          range: new Range(30, 70),
591      },
592      {
593          filter: (prefix, value) => {
594              if (value instanceof Range) {
595                  return `${value.from}...${value.to}`;
596              }
597              // serialize the usual way
598              return value;
599          },
600      }
601  );
602  // range=30...70
603  ```
604  
605  ### Handling of `null` values
606  
607  By default, `null` values are treated like empty strings:
608  
609  ```javascript
610  var withNull = qs.stringify({ a: null, b: '' });
611  assert.equal(withNull, 'a=&b=');
612  ```
613  
614  Parsing does not distinguish between parameters with and without equal signs.
615  Both are converted to empty strings.
616  
617  ```javascript
618  var equalsInsensitive = qs.parse('a&b=');
619  assert.deepEqual(equalsInsensitive, { a: '', b: '' });
620  ```
621  
622  To distinguish between `null` values and empty strings use the `strictNullHandling` flag. In the result string the `null`
623  values have no `=` sign:
624  
625  ```javascript
626  var strictNull = qs.stringify({ a: null, b: '' }, { strictNullHandling: true });
627  assert.equal(strictNull, 'a&b=');
628  ```
629  
630  To parse values without `=` back to `null` use the `strictNullHandling` flag:
631  
632  ```javascript
633  var parsedStrictNull = qs.parse('a&b=', { strictNullHandling: true });
634  assert.deepEqual(parsedStrictNull, { a: null, b: '' });
635  ```
636  
637  To completely skip rendering keys with `null` values, use the `skipNulls` flag:
638  
639  ```javascript
640  var nullsSkipped = qs.stringify({ a: 'b', c: null}, { skipNulls: true });
641  assert.equal(nullsSkipped, 'a=b');
642  ```
643  
644  If you're communicating with legacy systems, you can switch to `iso-8859-1` using the `charset` option:
645  
646  ```javascript
647  var iso = qs.stringify({ æ: 'æ' }, { charset: 'iso-8859-1' });
648  assert.equal(iso, '%E6=%E6');
649  ```
650  
651  Characters that don't exist in `iso-8859-1` will be converted to numeric entities, similar to what browsers do:
652  
653  ```javascript
654  var numeric = qs.stringify({ a: '☺' }, { charset: 'iso-8859-1' });
655  assert.equal(numeric, 'a=%26%239786%3B');
656  ```
657  
658  You can use the `charsetSentinel` option to announce the character by including an `utf8=✓` parameter with the proper encoding if the checkmark, similar to what Ruby on Rails and others do when submitting forms.
659  
660  ```javascript
661  var sentinel = qs.stringify({ a: '☺' }, { charsetSentinel: true });
662  assert.equal(sentinel, 'utf8=%E2%9C%93&a=%E2%98%BA');
663  
664  var isoSentinel = qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' });
665  assert.equal(isoSentinel, 'utf8=%26%2310003%3B&a=%E6');
666  ```
667  
668  ### Dealing with special character sets
669  
670  By default the encoding and decoding of characters is done in `utf-8`, and `iso-8859-1` support is also built in via the `charset` parameter.
671  
672  If you wish to encode querystrings to a different character set (i.e.
673  [Shift JIS](https://en.wikipedia.org/wiki/Shift_JIS)) you can use the
674  [`qs-iconv`](https://github.com/martinheidegger/qs-iconv) library:
675  
676  ```javascript
677  var encoder = require('qs-iconv/encoder')('shift_jis');
678  var shiftJISEncoded = qs.stringify({ a: 'こんにちは!' }, { encoder: encoder });
679  assert.equal(shiftJISEncoded, 'a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I');
680  ```
681  
682  This also works for decoding of query strings:
683  
684  ```javascript
685  var decoder = require('qs-iconv/decoder')('shift_jis');
686  var obj = qs.parse('a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I', { decoder: decoder });
687  assert.deepEqual(obj, { a: 'こんにちは!' });
688  ```
689  
690  ### RFC 3986 and RFC 1738 space encoding
691  
692  RFC3986 used as default option and encodes ' ' to *%20* which is backward compatible.
693  In the same time, output can be stringified as per RFC1738 with ' ' equal to '+'.
694  
695  ```
696  assert.equal(qs.stringify({ a: 'b c' }), 'a=b%20c');
697  assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC3986' }), 'a=b%20c');
698  assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC1738' }), 'a=b+c');
699  ```
700  
701  ## Security
702  
703  Please email [@ljharb](https://github.com/ljharb) or see https://tidelift.com/security if you have a potential security vulnerability to report.
704  
705  ## qs for enterprise
706  
707  Available as part of the Tidelift Subscription
708  
709  The maintainers of qs and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications.
710  Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use.
711  [Learn more.](https://tidelift.com/subscription/pkg/npm-qs?utm_source=npm-qs&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
712  
713  [package-url]: https://npmjs.org/package/qs
714  [npm-version-svg]: https://versionbadg.es/ljharb/qs.svg
715  [deps-svg]: https://david-dm.org/ljharb/qs.svg
716  [deps-url]: https://david-dm.org/ljharb/qs
717  [dev-deps-svg]: https://david-dm.org/ljharb/qs/dev-status.svg
718  [dev-deps-url]: https://david-dm.org/ljharb/qs#info=devDependencies
719  [npm-badge-png]: https://nodei.co/npm/qs.png?downloads=true&stars=true
720  [license-image]: https://img.shields.io/npm/l/qs.svg
721  [license-url]: LICENSE
722  [downloads-image]: https://img.shields.io/npm/dm/qs.svg
723  [downloads-url]: https://npm-stat.com/charts.html?package=qs
724  [codecov-image]: https://codecov.io/gh/ljharb/qs/branch/main/graphs/badge.svg
725  [codecov-url]: https://app.codecov.io/gh/ljharb/qs/
726  [actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/ljharb/qs
727  [actions-url]: https://github.com/ljharb/qs/actions
728  
729  ## Acknowledgements
730  
731  qs logo by [NUMI](https://github.com/numi-hq/open-design):
732  
733  [<img src="https://raw.githubusercontent.com/numi-hq/open-design/main/assets/numi-lockup.png" alt="NUMI Logo" style="width: 200px;"/>](https://numi.tech/?ref=qs)