opusdev/vector-similarity-api
1
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[](https://bestpractices.coreinfrastructure.org/projects/9058)12 13[![npm badge][npm-badge-png]][package-url]14 15A querystring parsing and stringifying library with some added security.16 17Lead Maintainer: [Jordan Harband](https://github.com/ljharb)18 19The **qs** module was originally created and maintained by [TJ Holowaychuk](https://github.com/visionmedia/node-querystring).20 21## Usage22 23```javascript24var qs = require('qs');25var assert = require('assert');26 27var obj = qs.parse('a=c');28assert.deepEqual(obj, { a: 'c' });29 30var str = qs.stringify(obj);31assert.equal(str, 'a=c');32```33 34### Parsing Objects35 36[](#preventEval)37```javascript38qs.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 `[]`.42For example, the string `'foo[bar]=baz'` converts to:43 44```javascript45assert.deepEqual(qs.parse('foo[bar]=baz'), {46 foo: {47 bar: 'baz'48 }49});50```51 52When 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```javascript55var nullObject = qs.parse('a[hasOwnProperty]=b', { plainObjects: true });56assert.deepEqual(nullObject, { a: { hasOwnProperty: 'b' } });57```58 59By 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.61Always be careful with this option.62 63```javascript64var protoObject = qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true });65assert.deepEqual(protoObject, { a: { hasOwnProperty: 'b' } });66```67 68URI encoded strings work too:69 70```javascript71assert.deepEqual(qs.parse('a%5Bb%5D=c'), {72 a: { b: 'c' }73});74```75 76You can also nest your objects, like `'foo[bar][baz]=foobarbaz'`:77 78```javascript79assert.deepEqual(qs.parse('foo[bar][baz]=foobarbaz'), {80 foo: {81 bar: {82 baz: 'foobarbaz'83 }84 }85});86```87 88By default, when nesting objects **qs** will only parse up to 5 children deep.89This 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```javascript92var 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};107var string = 'a[b][c][d][e][f][g][h][i]=j';108assert.deepEqual(qs.parse(string), expected);109```110 111This depth can be overridden by passing a `depth` option to `qs.parse(string, [options])`:112 113```javascript114var deep = qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1 });115assert.deepEqual(deep, { a: { b: { '[c][d][e][f][g][h][i]': 'j' } } });116```117 118You can configure **qs** to throw an error when parsing nested input beyond this depth using the `strictDepth` option (defaulted to false):119 120```javascript121try {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 129The 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 131For similar reasons, by default **qs** will only parse up to 1000 parameters. This can be overridden by passing a `parameterLimit` option:132 133```javascript134var limited = qs.parse('a=b&c=d', { parameterLimit: 1 });135assert.deepEqual(limited, { a: 'b' });136```137 138If 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```javascript140try {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 148When `throwOnLimitExceeded` is set to `false` (default), **qs** will parse up to the specified `parameterLimit` and ignore the rest without throwing an error.149 150To bypass the leading question mark, use `ignoreQueryPrefix`:151 152```javascript153var prefixed = qs.parse('?a=b&c=d', { ignoreQueryPrefix: true });154assert.deepEqual(prefixed, { a: 'b', c: 'd' });155```156 157An optional delimiter can also be passed:158 159```javascript160var delimited = qs.parse('a=b;c=d', { delimiter: ';' });161assert.deepEqual(delimited, { a: 'b', c: 'd' });162```163 164Delimiters can be a regular expression too:165 166```javascript167var regexed = qs.parse('a=b;c=d,e=f', { delimiter: /[;,]/ });168assert.deepEqual(regexed, { a: 'b', c: 'd', e: 'f' });169```170 171Option `allowDots` can be used to enable dot notation:172 173```javascript174var withDots = qs.parse('a.b=c', { allowDots: true });175assert.deepEqual(withDots, { a: { b: 'c' } });176```177 178Option `decodeDotInKeys` can be used to decode dots in keys179Note: it implies `allowDots`, so `parse` will error if you set `decodeDotInKeys` to `true`, and `allowDots` to `false`.180 181```javascript182var withDots = qs.parse('name%252Eobj.first=John&name%252Eobj.last=Doe', { decodeDotInKeys: true });183assert.deepEqual(withDots, { 'name.obj': { first: 'John', last: 'Doe' }});184```185 186Option `allowEmptyArrays` can be used to allowing empty array values in object187```javascript188var withEmptyArrays = qs.parse('foo[]&bar=baz', { allowEmptyArrays: true });189assert.deepEqual(withEmptyArrays, { foo: [], bar: 'baz' });190```191 192Option `duplicates` can be used to change the behavior when duplicate keys are encountered193```javascript194assert.deepEqual(qs.parse('foo=bar&foo=baz'), { foo: ['bar', 'baz'] });195assert.deepEqual(qs.parse('foo=bar&foo=baz', { duplicates: 'combine' }), { foo: ['bar', 'baz'] });196assert.deepEqual(qs.parse('foo=bar&foo=baz', { duplicates: 'first' }), { foo: 'bar' });197assert.deepEqual(qs.parse('foo=bar&foo=baz', { duplicates: 'last' }), { foo: 'baz' });198```199 200If you have to deal with legacy browsers or services, there's also support for decoding percent-encoded octets as iso-8859-1:201 202```javascript203var oldCharset = qs.parse('a=%A7', { charset: 'iso-8859-1' });204assert.deepEqual(oldCharset, { a: '§' });205```206 207Some services add an initial `utf8=✓` value to forms so that old Internet Explorer versions are more likely to submit the form as utf-8.208Additionally, 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.211If specified, the `utf8` parameter will be omitted from the returned object.212It 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.215In that sense the `charset` will behave as the default charset rather than the authoritative charset.216 217```javascript218var detectedAsUtf8 = qs.parse('utf8=%E2%9C%93&a=%C3%B8', {219 charset: 'iso-8859-1',220 charsetSentinel: true221});222assert.deepEqual(detectedAsUtf8, { a: 'ø' });223 224// Browsers encode the checkmark as ✓ when submitting as iso-8859-1:225var detectedAsIso8859_1 = qs.parse('utf8=%26%2310003%3B&a=%F8', {226 charset: 'utf-8',227 charsetSentinel: true228});229assert.deepEqual(detectedAsIso8859_1, { a: 'ø' });230```231 232If you want to decode the `&#...;` syntax to the actual character, you can specify the `interpretNumericEntities` option as well:233 234```javascript235var detectedAsIso8859_1 = qs.parse('a=%26%239786%3B', {236 charset: 'iso-8859-1',237 interpretNumericEntities: true238});239assert.deepEqual(detectedAsIso8859_1, { a: '☺' });240```241 242It also works when the charset has been detected in `charsetSentinel` mode.243 244### Parsing Arrays245 246**qs** can also parse arrays using a similar `[]` notation:247 248```javascript249var withArray = qs.parse('a[]=b&a[]=c');250assert.deepEqual(withArray, { a: ['b', 'c'] });251```252 253You may specify an index as well:254 255```javascript256var withIndexes = qs.parse('a[1]=c&a[0]=b');257assert.deepEqual(withIndexes, { a: ['b', 'c'] });258```259 260Note 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.261When creating arrays with specific indices, **qs** will compact a sparse array to only the existing values preserving their order:262 263```javascript264var noSparse = qs.parse('a[1]=b&a[15]=c');265assert.deepEqual(noSparse, { a: ['b', 'c'] });266```267 268You may also use `allowSparse` option to parse sparse arrays:269 270```javascript271var sparseArray = qs.parse('a[1]=2&a[3]=5', { allowSparse: true });272assert.deepEqual(sparseArray, { a: [, '2', , '5'] });273```274 275Note that an empty string is also a value, and will be preserved:276 277```javascript278var withEmptyString = qs.parse('a[]=&a[]=b');279assert.deepEqual(withEmptyString, { a: ['', 'b'] });280 281var withIndexedEmptyString = qs.parse('a[0]=b&a[1]=&a[2]=c');282assert.deepEqual(withIndexedEmptyString, { a: ['b', '', 'c'] });283```284 285**qs** will also limit specifying indices in an array to a maximum index of `20`.286Any array members with an index of greater than `20` will instead be converted to an object with the index as the key.287This 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```javascript290var withMaxIndex = qs.parse('a[100]=b');291assert.deepEqual(withMaxIndex, { a: { '100': 'b' } });292```293 294This limit can be overridden by passing an `arrayLimit` option:295 296```javascript297var withArrayLimit = qs.parse('a[1]=b', { arrayLimit: 0 });298assert.deepEqual(withArrayLimit, { a: { '1': 'b' } });299```300 301If 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```javascript303try {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 311When `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 key312 313To disable array parsing entirely, set `parseArrays` to `false`.314 315```javascript316var noParsingArrays = qs.parse('a[]=b', { parseArrays: false });317assert.deepEqual(noParsingArrays, { a: { '0': 'b' } });318```319 320If you mix notations, **qs** will merge the two items into an object:321 322```javascript323var mixedNotation = qs.parse('a[0]=b&a[b]=c');324assert.deepEqual(mixedNotation, { a: { '0': 'b', b: 'c' } });325```326 327You can also create arrays of objects:328 329```javascript330var arraysOfObjects = qs.parse('a[][b]=c');331assert.deepEqual(arraysOfObjects, { a: [{ b: 'c' }] });332```333 334Some people use comma to join array, **qs** can parse it:335```javascript336var arraysOfObjects = qs.parse('a=b,c', { comma: true })337assert.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 343By default, all values are parsed as strings.344This behavior will not change and is explained in [issue #91](https://github.com/ljharb/qs/issues/91).345 346```javascript347var primitiveValues = qs.parse('a=15&b=true&c=null');348assert.deepEqual(primitiveValues, { a: '15', b: 'true', c: 'null' });349```350 351If 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### Stringifying354 355[](#preventEval)356```javascript357qs.stringify(object, [options]);358```359 360When stringifying, **qs** by default URI encodes output. Objects are stringified as you would expect:361 362```javascript363assert.equal(qs.stringify({ a: 'b' }), 'a=b');364assert.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');365```366 367This encoding can be disabled by setting the `encode` option to `false`:368 369```javascript370var unencoded = qs.stringify({ a: { b: 'c' } }, { encode: false });371assert.equal(unencoded, 'a[b]=c');372```373 374Encoding can be disabled for keys by setting the `encodeValuesOnly` option to `true`:375```javascript376var encodedValues = qs.stringify(377 { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },378 { encodeValuesOnly: true }379);380assert.equal(encodedValues,'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h');381```382 383This encoding can also be replaced by a custom encoding method set as `encoder` option:384 385```javascript386var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str) {387 // Passed in values `a`, `b`, `c`388 return // Return encoded string389}})390```391 392_(Note: the `encoder` option does not apply if `encode` is `false`)_393 394Analogue to the `encoder` there is a `decoder` option for `parse` to override decoding of properties and values:395 396```javascript397var decoded = qs.parse('x=z', { decoder: function (str) {398 // Passed in values `x`, `z`399 return // Return decoded string400}})401```402 403You can encode keys and values using different logic by using the type argument provided to the encoder:404 405```javascript406var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str, defaultEncoder, charset, type) {407 if (type === 'key') {408 return // Encoded key409 } else if (type === 'value') {410 return // Encoded value411 }412}})413```414 415The type argument is also provided to the decoder:416 417```javascript418var decoded = qs.parse('x=z', { decoder: function (str, defaultDecoder, charset, type) {419 if (type === 'key') {420 return // Decoded key421 } else if (type === 'value') {422 return // Decoded value423 }424}})425```426 427Examples beyond this point will be shown as though the output is not URI encoded for clarity.428Please note that the return values in these cases *will* be URI encoded during real usage.429 430When arrays are stringified, they follow the `arrayFormat` option, which defaults to `indices`:431 432```javascript433qs.stringify({ a: ['b', 'c', 'd'] });434// 'a[0]=b&a[1]=c&a[2]=d'435```436 437You may override this by setting the `indices` option to `false`, or to be more explicit, the `arrayFormat` option to `repeat`:438 439```javascript440qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false });441// 'a=b&a=c&a=d'442```443 444You may use the `arrayFormat` option to specify the format of the output array:445 446```javascript447qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })448// 'a[0]=b&a[1]=c'449qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })450// 'a[]=b&a[]=c'451qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })452// 'a=b&a=c'453qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'comma' })454// 'a=b,c'455```456 457Note: 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 459When objects are stringified, by default they use bracket notation:460 461```javascript462qs.stringify({ a: { b: { c: 'd', e: 'f' } } });463// 'a[b][c]=d&a[b][e]=f'464```465 466You may override this to use dot notation by setting the `allowDots` option to `true`:467 468```javascript469qs.stringify({ a: { b: { c: 'd', e: 'f' } } }, { allowDots: true });470// 'a.b.c=d&a.b.e=f'471```472 473You may encode the dot notation in the keys of object with option `encodeDotInKeys` by setting it to `true`:474Note: it implies `allowDots`, so `stringify` will error if you set `decodeDotInKeys` to `true`, and `allowDots` to `false`.475Caveat: when `encodeValuesOnly` is `true` as well as `encodeDotInKeys`, only dots in keys and nothing else will be encoded.476```javascript477qs.stringify({ "name.obj": { "first": "John", "last": "Doe" } }, { allowDots: true, encodeDotInKeys: true })478// 'name%252Eobj.first=John&name%252Eobj.last=Doe'479```480 481You may allow empty array values by setting the `allowEmptyArrays` option to `true`:482```javascript483qs.stringify({ foo: [], bar: 'baz' }, { allowEmptyArrays: true });484// 'foo[]&bar=baz'485```486 487Empty strings and null values will omit the value, but the equals sign (=) remains in place:488 489```javascript490assert.equal(qs.stringify({ a: '' }), 'a=');491```492 493Key with no values (such as an empty object or array) will return nothing:494 495```javascript496assert.equal(qs.stringify({ a: [] }), '');497assert.equal(qs.stringify({ a: {} }), '');498assert.equal(qs.stringify({ a: [{}] }), '');499assert.equal(qs.stringify({ a: { b: []} }), '');500assert.equal(qs.stringify({ a: { b: {}} }), '');501```502 503Properties that are set to `undefined` will be omitted entirely:504 505```javascript506assert.equal(qs.stringify({ a: null, b: undefined }), 'a=');507```508 509The query string may optionally be prepended with a question mark:510 511```javascript512assert.equal(qs.stringify({ a: 'b', c: 'd' }, { addQueryPrefix: true }), '?a=b&c=d');513```514 515The delimiter may be overridden with stringify as well:516 517```javascript518assert.equal(qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' }), 'a=b;c=d');519```520 521If you only want to override the serialization of `Date` objects, you can provide a `serializeDate` option:522 523```javascript524var date = new Date(7);525assert.equal(qs.stringify({ a: date }), 'a=1970-01-01T00:00:00.007Z'.replace(/:/g, '%3A'));526assert.equal(527 qs.stringify({ a: date }, { serializeDate: function (d) { return d.getTime(); } }),528 'a=7'529);530```531 532You may use the `sort` option to affect the order of parameter keys:533 534```javascript535function alphabeticalSort(a, b) {536 return a.localeCompare(b);537}538assert.equal(qs.stringify({ a: 'c', z: 'y', b : 'f' }, { sort: alphabeticalSort }), 'a=c&b=f&z=y');539```540 541Finally, you can use the `filter` option to restrict which keys will be included in the stringified output.542If you pass a function, it will be called for each key to obtain the replacement value.543Otherwise, if you pass an array, it will be used to select properties and array indices for stringification:544 545```javascript546function 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}559qs.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'561qs.stringify({ a: 'b', c: 'd', e: 'f' }, { filter: ['a', 'e'] });562// 'a=b&e=f'563qs.stringify({ a: ['b', 'c', 'd'], e: 'f' }, { filter: ['a', 0, 2] });564// 'a[0]=b&a[2]=d'565```566 567You could also use `filter` to inject custom serialization for user defined types.568Consider you're working with some api that expects query strings of the format for ranges:569 570```571https://domain.com/endpoint?range=30...70572```573 574For which you model as:575 576```javascript577class Range {578 constructor(from, to) {579 this.from = from;580 this.to = to;581 }582}583```584 585You could _inject_ a custom serializer to handle values of this type:586 587```javascript588qs.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 way598 return value;599 },600 }601);602// range=30...70603```604 605### Handling of `null` values606 607By default, `null` values are treated like empty strings:608 609```javascript610var withNull = qs.stringify({ a: null, b: '' });611assert.equal(withNull, 'a=&b=');612```613 614Parsing does not distinguish between parameters with and without equal signs.615Both are converted to empty strings.616 617```javascript618var equalsInsensitive = qs.parse('a&b=');619assert.deepEqual(equalsInsensitive, { a: '', b: '' });620```621 622To distinguish between `null` values and empty strings use the `strictNullHandling` flag. In the result string the `null`623values have no `=` sign:624 625```javascript626var strictNull = qs.stringify({ a: null, b: '' }, { strictNullHandling: true });627assert.equal(strictNull, 'a&b=');628```629 630To parse values without `=` back to `null` use the `strictNullHandling` flag:631 632```javascript633var parsedStrictNull = qs.parse('a&b=', { strictNullHandling: true });634assert.deepEqual(parsedStrictNull, { a: null, b: '' });635```636 637To completely skip rendering keys with `null` values, use the `skipNulls` flag:638 639```javascript640var nullsSkipped = qs.stringify({ a: 'b', c: null}, { skipNulls: true });641assert.equal(nullsSkipped, 'a=b');642```643 644If you're communicating with legacy systems, you can switch to `iso-8859-1` using the `charset` option:645 646```javascript647var iso = qs.stringify({ æ: 'æ' }, { charset: 'iso-8859-1' });648assert.equal(iso, '%E6=%E6');649```650 651Characters that don't exist in `iso-8859-1` will be converted to numeric entities, similar to what browsers do:652 653```javascript654var numeric = qs.stringify({ a: '☺' }, { charset: 'iso-8859-1' });655assert.equal(numeric, 'a=%26%239786%3B');656```657 658You 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```javascript661var sentinel = qs.stringify({ a: '☺' }, { charsetSentinel: true });662assert.equal(sentinel, 'utf8=%E2%9C%93&a=%E2%98%BA');663 664var isoSentinel = qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' });665assert.equal(isoSentinel, 'utf8=%26%2310003%3B&a=%E6');666```667 668### Dealing with special character sets669 670By 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 672If 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 the674[`qs-iconv`](https://github.com/martinheidegger/qs-iconv) library:675 676```javascript677var encoder = require('qs-iconv/encoder')('shift_jis');678var shiftJISEncoded = qs.stringify({ a: 'こんにちは!' }, { encoder: encoder });679assert.equal(shiftJISEncoded, 'a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I');680```681 682This also works for decoding of query strings:683 684```javascript685var decoder = require('qs-iconv/decoder')('shift_jis');686var obj = qs.parse('a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I', { decoder: decoder });687assert.deepEqual(obj, { a: 'こんにちは!' });688```689 690### RFC 3986 and RFC 1738 space encoding691 692RFC3986 used as default option and encodes ' ' to *%20* which is backward compatible.693In the same time, output can be stringified as per RFC1738 with ' ' equal to '+'.694 695```696assert.equal(qs.stringify({ a: 'b c' }), 'a=b%20c');697assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC3986' }), 'a=b%20c');698assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC1738' }), 'a=b+c');699```700 701## Security702 703Please 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 enterprise706 707Available as part of the Tidelift Subscription708 709The 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.710Save 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/qs714[npm-version-svg]: https://versionbadg.es/ljharb/qs.svg715[deps-svg]: https://david-dm.org/ljharb/qs.svg716[deps-url]: https://david-dm.org/ljharb/qs717[dev-deps-svg]: https://david-dm.org/ljharb/qs/dev-status.svg718[dev-deps-url]: https://david-dm.org/ljharb/qs#info=devDependencies719[npm-badge-png]: https://nodei.co/npm/qs.png?downloads=true&stars=true720[license-image]: https://img.shields.io/npm/l/qs.svg721[license-url]: LICENSE722[downloads-image]: https://img.shields.io/npm/dm/qs.svg723[downloads-url]: https://npm-stat.com/charts.html?package=qs724[codecov-image]: https://codecov.io/gh/ljharb/qs/branch/main/graphs/badge.svg725[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/qs727[actions-url]: https://github.com/ljharb/qs/actions728 729## Acknowledgements730 731qs 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)734 