root / HServer / 00.Server / 00.Program / node_modules / qs / README.md
이력 | 보기 | 이력해설 | 다운로드 (14.3 KB)
| 1 | 39 | HKM | # qs <sup>[![Version Badge][2]][1]</sup> |
|---|---|---|---|
| 2 | |||
| 3 | [![Build Status][3]][4] |
||
| 4 | [![dependency status][5]][6] |
||
| 5 | [![dev dependency status][7]][8] |
||
| 6 | [![License][license-image]][license-url] |
||
| 7 | [![Downloads][downloads-image]][downloads-url] |
||
| 8 | |||
| 9 | [![npm badge][11]][1] |
||
| 10 | |||
| 11 | A querystring parsing and stringifying library with some added security. |
||
| 12 | |||
| 13 | Lead Maintainer: [Jordan Harband](https://github.com/ljharb) |
||
| 14 | |||
| 15 | The **qs** module was originally created and maintained by [TJ Holowaychuk](https://github.com/visionmedia/node-querystring). |
||
| 16 | |||
| 17 | ## Usage |
||
| 18 | |||
| 19 | ```javascript |
||
| 20 | var qs = require('qs');
|
||
| 21 | var assert = require('assert');
|
||
| 22 | |||
| 23 | var obj = qs.parse('a=c');
|
||
| 24 | assert.deepEqual(obj, { a: 'c' });
|
||
| 25 | |||
| 26 | var str = qs.stringify(obj); |
||
| 27 | assert.equal(str, 'a=c'); |
||
| 28 | ``` |
||
| 29 | |||
| 30 | ### Parsing Objects |
||
| 31 | |||
| 32 | [](#preventEval) |
||
| 33 | ```javascript |
||
| 34 | qs.parse(string, [options]); |
||
| 35 | ``` |
||
| 36 | |||
| 37 | **qs** allows you to create nested objects within your query strings, by surrounding the name of sub-keys with square brackets `[]`. |
||
| 38 | For example, the string `'foo[bar]=baz'` converts to: |
||
| 39 | |||
| 40 | ```javascript |
||
| 41 | assert.deepEqual(qs.parse('foo[bar]=baz'), {
|
||
| 42 | foo: {
|
||
| 43 | bar: 'baz' |
||
| 44 | } |
||
| 45 | }); |
||
| 46 | ``` |
||
| 47 | |||
| 48 | When using the `plainObjects` option the parsed value is returned as a null object, created via `Object.create(null)` and as such you should be aware that prototype methods will not exist on it and a user may set those names to whatever value they like: |
||
| 49 | |||
| 50 | ```javascript |
||
| 51 | var nullObject = qs.parse('a[hasOwnProperty]=b', { plainObjects: true });
|
||
| 52 | assert.deepEqual(nullObject, { a: { hasOwnProperty: 'b' } });
|
||
| 53 | ``` |
||
| 54 | |||
| 55 | By default parameters that would overwrite properties on the object prototype are ignored, if you wish to keep the data from those fields either use `plainObjects` as mentioned above, or set `allowPrototypes` to `true` which will allow user input to overwrite those properties. *WARNING* It is generally a bad idea to enable this option as it can cause problems when attempting to use the properties that have been overwritten. Always be careful with this option. |
||
| 56 | |||
| 57 | ```javascript |
||
| 58 | var protoObject = qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true });
|
||
| 59 | assert.deepEqual(protoObject, { a: { hasOwnProperty: 'b' } });
|
||
| 60 | ``` |
||
| 61 | |||
| 62 | URI encoded strings work too: |
||
| 63 | |||
| 64 | ```javascript |
||
| 65 | assert.deepEqual(qs.parse('a%5Bb%5D=c'), {
|
||
| 66 | a: { b: 'c' }
|
||
| 67 | }); |
||
| 68 | ``` |
||
| 69 | |||
| 70 | You can also nest your objects, like `'foo[bar][baz]=foobarbaz'`: |
||
| 71 | |||
| 72 | ```javascript |
||
| 73 | assert.deepEqual(qs.parse('foo[bar][baz]=foobarbaz'), {
|
||
| 74 | foo: {
|
||
| 75 | bar: {
|
||
| 76 | baz: 'foobarbaz' |
||
| 77 | } |
||
| 78 | } |
||
| 79 | }); |
||
| 80 | ``` |
||
| 81 | |||
| 82 | By default, when nesting objects **qs** will only parse up to 5 children deep. This means if you attempt to parse a string like |
||
| 83 | `'a[b][c][d][e][f][g][h][i]=j'` your resulting object will be: |
||
| 84 | |||
| 85 | ```javascript |
||
| 86 | var expected = {
|
||
| 87 | a: {
|
||
| 88 | b: {
|
||
| 89 | c: {
|
||
| 90 | d: {
|
||
| 91 | e: {
|
||
| 92 | f: {
|
||
| 93 | '[g][h][i]': 'j' |
||
| 94 | } |
||
| 95 | } |
||
| 96 | } |
||
| 97 | } |
||
| 98 | } |
||
| 99 | } |
||
| 100 | }; |
||
| 101 | var string = 'a[b][c][d][e][f][g][h][i]=j'; |
||
| 102 | assert.deepEqual(qs.parse(string), expected); |
||
| 103 | ``` |
||
| 104 | |||
| 105 | This depth can be overridden by passing a `depth` option to `qs.parse(string, [options])`: |
||
| 106 | |||
| 107 | ```javascript |
||
| 108 | var deep = qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1 });
|
||
| 109 | assert.deepEqual(deep, { a: { b: { '[c][d][e][f][g][h][i]': 'j' } } });
|
||
| 110 | ``` |
||
| 111 | |||
| 112 | 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. |
||
| 113 | |||
| 114 | For similar reasons, by default **qs** will only parse up to 1000 parameters. This can be overridden by passing a `parameterLimit` option: |
||
| 115 | |||
| 116 | ```javascript |
||
| 117 | var limited = qs.parse('a=b&c=d', { parameterLimit: 1 });
|
||
| 118 | assert.deepEqual(limited, { a: 'b' });
|
||
| 119 | ``` |
||
| 120 | |||
| 121 | To bypass the leading question mark, use `ignoreQueryPrefix`: |
||
| 122 | |||
| 123 | ```javascript |
||
| 124 | var prefixed = qs.parse('?a=b&c=d', { ignoreQueryPrefix: true });
|
||
| 125 | assert.deepEqual(prefixed, { a: 'b', c: 'd' });
|
||
| 126 | ``` |
||
| 127 | |||
| 128 | An optional delimiter can also be passed: |
||
| 129 | |||
| 130 | ```javascript |
||
| 131 | var delimited = qs.parse('a=b;c=d', { delimiter: ';' });
|
||
| 132 | assert.deepEqual(delimited, { a: 'b', c: 'd' });
|
||
| 133 | ``` |
||
| 134 | |||
| 135 | Delimiters can be a regular expression too: |
||
| 136 | |||
| 137 | ```javascript |
||
| 138 | var regexed = qs.parse('a=b;c=d,e=f', { delimiter: /[;,]/ });
|
||
| 139 | assert.deepEqual(regexed, { a: 'b', c: 'd', e: 'f' });
|
||
| 140 | ``` |
||
| 141 | |||
| 142 | Option `allowDots` can be used to enable dot notation: |
||
| 143 | |||
| 144 | ```javascript |
||
| 145 | var withDots = qs.parse('a.b=c', { allowDots: true });
|
||
| 146 | assert.deepEqual(withDots, { a: { b: 'c' } });
|
||
| 147 | ``` |
||
| 148 | |||
| 149 | ### Parsing Arrays |
||
| 150 | |||
| 151 | **qs** can also parse arrays using a similar `[]` notation: |
||
| 152 | |||
| 153 | ```javascript |
||
| 154 | var withArray = qs.parse('a[]=b&a[]=c');
|
||
| 155 | assert.deepEqual(withArray, { a: ['b', 'c'] });
|
||
| 156 | ``` |
||
| 157 | |||
| 158 | You may specify an index as well: |
||
| 159 | |||
| 160 | ```javascript |
||
| 161 | var withIndexes = qs.parse('a[1]=c&a[0]=b');
|
||
| 162 | assert.deepEqual(withIndexes, { a: ['b', 'c'] });
|
||
| 163 | ``` |
||
| 164 | |||
| 165 | 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 |
||
| 166 | to create an array. When creating arrays with specific indices, **qs** will compact a sparse array to only the existing values preserving |
||
| 167 | their order: |
||
| 168 | |||
| 169 | ```javascript |
||
| 170 | var noSparse = qs.parse('a[1]=b&a[15]=c');
|
||
| 171 | assert.deepEqual(noSparse, { a: ['b', 'c'] });
|
||
| 172 | ``` |
||
| 173 | |||
| 174 | Note that an empty string is also a value, and will be preserved: |
||
| 175 | |||
| 176 | ```javascript |
||
| 177 | var withEmptyString = qs.parse('a[]=&a[]=b');
|
||
| 178 | assert.deepEqual(withEmptyString, { a: ['', 'b'] });
|
||
| 179 | |||
| 180 | var withIndexedEmptyString = qs.parse('a[0]=b&a[1]=&a[2]=c');
|
||
| 181 | assert.deepEqual(withIndexedEmptyString, { a: ['b', '', 'c'] });
|
||
| 182 | ``` |
||
| 183 | |||
| 184 | **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 |
||
| 185 | instead be converted to an object with the index as the key: |
||
| 186 | |||
| 187 | ```javascript |
||
| 188 | var withMaxIndex = qs.parse('a[100]=b');
|
||
| 189 | assert.deepEqual(withMaxIndex, { a: { '100': 'b' } });
|
||
| 190 | ``` |
||
| 191 | |||
| 192 | This limit can be overridden by passing an `arrayLimit` option: |
||
| 193 | |||
| 194 | ```javascript |
||
| 195 | var withArrayLimit = qs.parse('a[1]=b', { arrayLimit: 0 });
|
||
| 196 | assert.deepEqual(withArrayLimit, { a: { '1': 'b' } });
|
||
| 197 | ``` |
||
| 198 | |||
| 199 | To disable array parsing entirely, set `parseArrays` to `false`. |
||
| 200 | |||
| 201 | ```javascript |
||
| 202 | var noParsingArrays = qs.parse('a[]=b', { parseArrays: false });
|
||
| 203 | assert.deepEqual(noParsingArrays, { a: { '0': 'b' } });
|
||
| 204 | ``` |
||
| 205 | |||
| 206 | If you mix notations, **qs** will merge the two items into an object: |
||
| 207 | |||
| 208 | ```javascript |
||
| 209 | var mixedNotation = qs.parse('a[0]=b&a[b]=c');
|
||
| 210 | assert.deepEqual(mixedNotation, { a: { '0': 'b', b: 'c' } });
|
||
| 211 | ``` |
||
| 212 | |||
| 213 | You can also create arrays of objects: |
||
| 214 | |||
| 215 | ```javascript |
||
| 216 | var arraysOfObjects = qs.parse('a[][b]=c');
|
||
| 217 | assert.deepEqual(arraysOfObjects, { a: [{ b: 'c' }] });
|
||
| 218 | ``` |
||
| 219 | |||
| 220 | ### Stringifying |
||
| 221 | |||
| 222 | [](#preventEval) |
||
| 223 | ```javascript |
||
| 224 | qs.stringify(object, [options]); |
||
| 225 | ``` |
||
| 226 | |||
| 227 | When stringifying, **qs** by default URI encodes output. Objects are stringified as you would expect: |
||
| 228 | |||
| 229 | ```javascript |
||
| 230 | assert.equal(qs.stringify({ a: 'b' }), 'a=b');
|
||
| 231 | assert.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
|
||
| 232 | ``` |
||
| 233 | |||
| 234 | This encoding can be disabled by setting the `encode` option to `false`: |
||
| 235 | |||
| 236 | ```javascript |
||
| 237 | var unencoded = qs.stringify({ a: { b: 'c' } }, { encode: false });
|
||
| 238 | assert.equal(unencoded, 'a[b]=c'); |
||
| 239 | ``` |
||
| 240 | |||
| 241 | Encoding can be disabled for keys by setting the `encodeValuesOnly` option to `true`: |
||
| 242 | ```javascript |
||
| 243 | var encodedValues = qs.stringify( |
||
| 244 | { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
|
||
| 245 | { encodeValuesOnly: true }
|
||
| 246 | ); |
||
| 247 | assert.equal(encodedValues,'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h'); |
||
| 248 | ``` |
||
| 249 | |||
| 250 | This encoding can also be replaced by a custom encoding method set as `encoder` option: |
||
| 251 | |||
| 252 | ```javascript |
||
| 253 | var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str) {
|
||
| 254 | // Passed in values `a`, `b`, `c` |
||
| 255 | return // Return encoded string |
||
| 256 | }}) |
||
| 257 | ``` |
||
| 258 | |||
| 259 | _(Note: the `encoder` option does not apply if `encode` is `false`)_ |
||
| 260 | |||
| 261 | Analogue to the `encoder` there is a `decoder` option for `parse` to override decoding of properties and values: |
||
| 262 | |||
| 263 | ```javascript |
||
| 264 | var decoded = qs.parse('x=z', { decoder: function (str) {
|
||
| 265 | // Passed in values `x`, `z` |
||
| 266 | return // Return decoded string |
||
| 267 | }}) |
||
| 268 | ``` |
||
| 269 | |||
| 270 | Examples beyond this point will be shown as though the output is not URI encoded for clarity. Please note that the return values in these cases *will* be URI encoded during real usage. |
||
| 271 | |||
| 272 | When arrays are stringified, by default they are given explicit indices: |
||
| 273 | |||
| 274 | ```javascript |
||
| 275 | qs.stringify({ a: ['b', 'c', 'd'] });
|
||
| 276 | // 'a[0]=b&a[1]=c&a[2]=d' |
||
| 277 | ``` |
||
| 278 | |||
| 279 | You may override this by setting the `indices` option to `false`: |
||
| 280 | |||
| 281 | ```javascript |
||
| 282 | qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false });
|
||
| 283 | // 'a=b&a=c&a=d' |
||
| 284 | ``` |
||
| 285 | |||
| 286 | You may use the `arrayFormat` option to specify the format of the output array: |
||
| 287 | |||
| 288 | ```javascript |
||
| 289 | qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })
|
||
| 290 | // 'a[0]=b&a[1]=c' |
||
| 291 | qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })
|
||
| 292 | // 'a[]=b&a[]=c' |
||
| 293 | qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })
|
||
| 294 | // 'a=b&a=c' |
||
| 295 | ``` |
||
| 296 | |||
| 297 | When objects are stringified, by default they use bracket notation: |
||
| 298 | |||
| 299 | ```javascript |
||
| 300 | qs.stringify({ a: { b: { c: 'd', e: 'f' } } });
|
||
| 301 | // 'a[b][c]=d&a[b][e]=f' |
||
| 302 | ``` |
||
| 303 | |||
| 304 | You may override this to use dot notation by setting the `allowDots` option to `true`: |
||
| 305 | |||
| 306 | ```javascript |
||
| 307 | qs.stringify({ a: { b: { c: 'd', e: 'f' } } }, { allowDots: true });
|
||
| 308 | // 'a.b.c=d&a.b.e=f' |
||
| 309 | ``` |
||
| 310 | |||
| 311 | Empty strings and null values will omit the value, but the equals sign (=) remains in place: |
||
| 312 | |||
| 313 | ```javascript |
||
| 314 | assert.equal(qs.stringify({ a: '' }), 'a=');
|
||
| 315 | ``` |
||
| 316 | |||
| 317 | Key with no values (such as an empty object or array) will return nothing: |
||
| 318 | |||
| 319 | ```javascript |
||
| 320 | assert.equal(qs.stringify({ a: [] }), '');
|
||
| 321 | assert.equal(qs.stringify({ a: {} }), '');
|
||
| 322 | assert.equal(qs.stringify({ a: [{}] }), '');
|
||
| 323 | assert.equal(qs.stringify({ a: { b: []} }), '');
|
||
| 324 | assert.equal(qs.stringify({ a: { b: {}} }), '');
|
||
| 325 | ``` |
||
| 326 | |||
| 327 | Properties that are set to `undefined` will be omitted entirely: |
||
| 328 | |||
| 329 | ```javascript |
||
| 330 | assert.equal(qs.stringify({ a: null, b: undefined }), 'a=');
|
||
| 331 | ``` |
||
| 332 | |||
| 333 | The query string may optionally be prepended with a question mark: |
||
| 334 | |||
| 335 | ```javascript |
||
| 336 | assert.equal(qs.stringify({ a: 'b', c: 'd' }, { addQueryPrefix: true }), '?a=b&c=d');
|
||
| 337 | ``` |
||
| 338 | |||
| 339 | The delimiter may be overridden with stringify as well: |
||
| 340 | |||
| 341 | ```javascript |
||
| 342 | assert.equal(qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' }), 'a=b;c=d');
|
||
| 343 | ``` |
||
| 344 | |||
| 345 | If you only want to override the serialization of `Date` objects, you can provide a `serializeDate` option: |
||
| 346 | |||
| 347 | ```javascript |
||
| 348 | var date = new Date(7); |
||
| 349 | assert.equal(qs.stringify({ a: date }), 'a=1970-01-01T00:00:00.007Z'.replace(/:/g, '%3A'));
|
||
| 350 | assert.equal( |
||
| 351 | qs.stringify({ a: date }, { serializeDate: function (d) { return d.getTime(); } }),
|
||
| 352 | 'a=7' |
||
| 353 | ); |
||
| 354 | ``` |
||
| 355 | |||
| 356 | You may use the `sort` option to affect the order of parameter keys: |
||
| 357 | |||
| 358 | ```javascript |
||
| 359 | function alphabeticalSort(a, b) {
|
||
| 360 | return a.localeCompare(b); |
||
| 361 | } |
||
| 362 | assert.equal(qs.stringify({ a: 'c', z: 'y', b : 'f' }, { sort: alphabeticalSort }), 'a=c&b=f&z=y');
|
||
| 363 | ``` |
||
| 364 | |||
| 365 | Finally, you can use the `filter` option to restrict which keys will be included in the stringified output. |
||
| 366 | If you pass a function, it will be called for each key to obtain the replacement value. Otherwise, if you |
||
| 367 | pass an array, it will be used to select properties and array indices for stringification: |
||
| 368 | |||
| 369 | ```javascript |
||
| 370 | function filterFunc(prefix, value) {
|
||
| 371 | if (prefix == 'b') {
|
||
| 372 | // Return an `undefined` value to omit a property. |
||
| 373 | return; |
||
| 374 | } |
||
| 375 | if (prefix == 'e[f]') {
|
||
| 376 | return value.getTime(); |
||
| 377 | } |
||
| 378 | if (prefix == 'e[g][0]') {
|
||
| 379 | return value * 2; |
||
| 380 | } |
||
| 381 | return value; |
||
| 382 | } |
||
| 383 | qs.stringify({ a: 'b', c: 'd', e: { f: new Date(123), g: [2] } }, { filter: filterFunc });
|
||
| 384 | // 'a=b&c=d&e[f]=123&e[g][0]=4' |
||
| 385 | qs.stringify({ a: 'b', c: 'd', e: 'f' }, { filter: ['a', 'e'] });
|
||
| 386 | // 'a=b&e=f' |
||
| 387 | qs.stringify({ a: ['b', 'c', 'd'], e: 'f' }, { filter: ['a', 0, 2] });
|
||
| 388 | // 'a[0]=b&a[2]=d' |
||
| 389 | ``` |
||
| 390 | |||
| 391 | ### Handling of `null` values |
||
| 392 | |||
| 393 | By default, `null` values are treated like empty strings: |
||
| 394 | |||
| 395 | ```javascript |
||
| 396 | var withNull = qs.stringify({ a: null, b: '' });
|
||
| 397 | assert.equal(withNull, 'a=&b='); |
||
| 398 | ``` |
||
| 399 | |||
| 400 | Parsing does not distinguish between parameters with and without equal signs. Both are converted to empty strings. |
||
| 401 | |||
| 402 | ```javascript |
||
| 403 | var equalsInsensitive = qs.parse('a&b=');
|
||
| 404 | assert.deepEqual(equalsInsensitive, { a: '', b: '' });
|
||
| 405 | ``` |
||
| 406 | |||
| 407 | To distinguish between `null` values and empty strings use the `strictNullHandling` flag. In the result string the `null` |
||
| 408 | values have no `=` sign: |
||
| 409 | |||
| 410 | ```javascript |
||
| 411 | var strictNull = qs.stringify({ a: null, b: '' }, { strictNullHandling: true });
|
||
| 412 | assert.equal(strictNull, 'a&b='); |
||
| 413 | ``` |
||
| 414 | |||
| 415 | To parse values without `=` back to `null` use the `strictNullHandling` flag: |
||
| 416 | |||
| 417 | ```javascript |
||
| 418 | var parsedStrictNull = qs.parse('a&b=', { strictNullHandling: true });
|
||
| 419 | assert.deepEqual(parsedStrictNull, { a: null, b: '' });
|
||
| 420 | ``` |
||
| 421 | |||
| 422 | To completely skip rendering keys with `null` values, use the `skipNulls` flag: |
||
| 423 | |||
| 424 | ```javascript |
||
| 425 | var nullsSkipped = qs.stringify({ a: 'b', c: null}, { skipNulls: true });
|
||
| 426 | assert.equal(nullsSkipped, 'a=b'); |
||
| 427 | ``` |
||
| 428 | |||
| 429 | ### Dealing with special character sets |
||
| 430 | |||
| 431 | By default the encoding and decoding of characters is done in `utf-8`. If you |
||
| 432 | wish to encode querystrings to a different character set (i.e. |
||
| 433 | [Shift JIS](https://en.wikipedia.org/wiki/Shift_JIS)) you can use the |
||
| 434 | [`qs-iconv`](https://github.com/martinheidegger/qs-iconv) library: |
||
| 435 | |||
| 436 | ```javascript |
||
| 437 | var encoder = require('qs-iconv/encoder')('shift_jis');
|
||
| 438 | var shiftJISEncoded = qs.stringify({ a: 'こんにちは!' }, { encoder: encoder });
|
||
| 439 | assert.equal(shiftJISEncoded, 'a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I'); |
||
| 440 | ``` |
||
| 441 | |||
| 442 | This also works for decoding of query strings: |
||
| 443 | |||
| 444 | ```javascript |
||
| 445 | var decoder = require('qs-iconv/decoder')('shift_jis');
|
||
| 446 | var obj = qs.parse('a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I', { decoder: decoder });
|
||
| 447 | assert.deepEqual(obj, { a: 'こんにちは!' });
|
||
| 448 | ``` |
||
| 449 | |||
| 450 | ### RFC 3986 and RFC 1738 space encoding |
||
| 451 | |||
| 452 | RFC3986 used as default option and encodes ' ' to *%20* which is backward compatible. |
||
| 453 | In the same time, output can be stringified as per RFC1738 with ' ' equal to '+'. |
||
| 454 | |||
| 455 | ``` |
||
| 456 | assert.equal(qs.stringify({ a: 'b c' }), 'a=b%20c');
|
||
| 457 | assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC3986' }), 'a=b%20c');
|
||
| 458 | assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC1738' }), 'a=b+c');
|
||
| 459 | ``` |
||
| 460 | |||
| 461 | [1]: https://npmjs.org/package/qs |
||
| 462 | [2]: http://versionbadg.es/ljharb/qs.svg |
||
| 463 | [3]: https://api.travis-ci.org/ljharb/qs.svg |
||
| 464 | [4]: https://travis-ci.org/ljharb/qs |
||
| 465 | [5]: https://david-dm.org/ljharb/qs.svg |
||
| 466 | [6]: https://david-dm.org/ljharb/qs |
||
| 467 | [7]: https://david-dm.org/ljharb/qs/dev-status.svg |
||
| 468 | [8]: https://david-dm.org/ljharb/qs?type=dev |
||
| 469 | [9]: https://ci.testling.com/ljharb/qs.png |
||
| 470 | [10]: https://ci.testling.com/ljharb/qs |
||
| 471 | [11]: https://nodei.co/npm/qs.png?downloads=true&stars=true |
||
| 472 | [license-image]: http://img.shields.io/npm/l/qs.svg |
||
| 473 | [license-url]: LICENSE |
||
| 474 | [downloads-image]: http://img.shields.io/npm/dm/qs.svg |
||
| 475 | [downloads-url]: http://npm-stat.com/charts.html?package=qs |