query-string 5.1.1 → 6.3.0

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.
Files changed (4) hide show
  1. package/index.d.ts +135 -0
  2. package/index.js +98 -87
  3. package/package.json +13 -10
  4. package/readme.md +10 -3
package/index.d.ts ADDED
@@ -0,0 +1,135 @@
1
+ export interface ParseOptions {
2
+ /**
3
+ * Decode the keys and values. URI components are decoded with [`decode-uri-component`](https://github.com/SamVerschueren/decode-uri-component).
4
+ *
5
+ * @default true
6
+ */
7
+ readonly decode?: boolean;
8
+
9
+ /**
10
+ * Supports both `index` for an indexed array representation or `bracket` for a *bracketed* array representation.
11
+ *
12
+ * @default 'none'
13
+ *
14
+ * - `bracket`: stands for parsing correctly arrays with bracket representation on the query string, such as:
15
+ *
16
+ *
17
+ * queryString.parse('foo[]=1&foo[]=2&foo[]=3', {arrayFormat: 'bracket'});
18
+ * //=> foo: [1,2,3]
19
+ *
20
+ * - `index`: stands for parsing taking the index into account, such as:
21
+ *
22
+ *
23
+ * queryString.parse('foo[0]=1&foo[1]=2&foo[3]=3', {arrayFormat: 'index'});
24
+ * //=> foo: [1,2,3]
25
+ *
26
+ * - `none`: is the **default** option and removes any bracket representation, such as:
27
+ *
28
+ *
29
+ * queryString.parse('foo=1&foo=2&foo=3');
30
+ * //=> foo: [1,2,3]
31
+ */
32
+ readonly arrayFormat?: 'bracket' | 'index' | 'none';
33
+ }
34
+
35
+ export interface ParsedQuery {
36
+ readonly [key: string]: string | string[] | undefined;
37
+ }
38
+
39
+ /**
40
+ * Parse a query string into an object. Leading `?` or `#` are ignored, so you can pass `location.search` or `location.hash` directly.
41
+ *
42
+ * The returned object is created with [`Object.create(null)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create) and thus does not have a `prototype`.
43
+ *
44
+ * @param query - The query string to parse.
45
+ */
46
+ export function parse(query: string, options?: ParseOptions): ParsedQuery;
47
+
48
+ export interface ParsedUrl {
49
+ readonly url: string;
50
+ readonly query: ParsedQuery;
51
+ }
52
+
53
+ /**
54
+ * Extract the URL and the query string as an object.
55
+ *
56
+ * @param url - The URL to parse.
57
+ *
58
+ * @example
59
+ *
60
+ * queryString.parseUrl('https://foo.bar?foo=bar');
61
+ * //=> {url: 'https://foo.bar', query: {foo: 'bar'}}
62
+ */
63
+ export function parseUrl(url: string, options?: ParseOptions): ParsedUrl;
64
+
65
+ export interface StringifyOptions {
66
+ /**
67
+ * Strictly encode URI components with [`strict-uri-encode`](https://github.com/kevva/strict-uri-encode). It uses [`encodeURIComponent`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent) if set to `false`. You probably [don't care](https://github.com/sindresorhus/query-string/issues/42) about this option.
68
+ *
69
+ * @default true
70
+ */
71
+ readonly strict?: boolean;
72
+
73
+ /**
74
+ * [URL encode](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent) the keys and values.
75
+ *
76
+ * @default true
77
+ */
78
+ readonly encode?: boolean;
79
+
80
+ /**
81
+ * Supports both `index` for an indexed array representation or `bracket` for a *bracketed* array representation.
82
+ *
83
+ * @default 'none'
84
+ *
85
+ * - `bracket`: stands for parsing correctly arrays with bracket representation on the query string, such as:
86
+ *
87
+ *
88
+ * queryString.stringify({foo: [1,2,3]}, {arrayFormat: 'bracket'});
89
+ * // => foo[]=1&foo[]=2&foo[]=3
90
+ *
91
+ * - `index`: stands for parsing taking the index into account, such as:
92
+ *
93
+ *
94
+ * queryString.stringify({foo: [1,2,3]}, {arrayFormat: 'index'});
95
+ * // => foo[0]=1&foo[1]=2&foo[3]=3
96
+ *
97
+ * - `none`: is the **default** option and removes any bracket representation, such as:
98
+ *
99
+ *
100
+ * queryString.stringify({foo: [1,2,3]});
101
+ * // => foo=1&foo=2&foo=3
102
+ */
103
+ readonly arrayFormat?: 'bracket' | 'index' | 'none';
104
+
105
+ /**
106
+ * Supports both `Function` as a custom sorting function or `false` to disable sorting.
107
+ *
108
+ * If omitted, keys are sorted using `Array#sort`, which means, converting them to strings and comparing strings in Unicode code point order.
109
+ *
110
+ * @example
111
+ *
112
+ * const order = ['c', 'a', 'b'];
113
+ * queryString.stringify({ a: 1, b: 2, c: 3}, {
114
+ * sort: (itemLeft, itemRight) => order.indexOf(itemLeft) - order.indexOf(itemRight)
115
+ * });
116
+ * // => 'c=3&a=1&b=2'
117
+ *
118
+ * queryString.stringify({ b: 1, c: 2, a: 3}, {sort: false});
119
+ * // => 'b=1&c=2&a=3'
120
+ */
121
+ readonly sort?: ((itemLeft: string, itemRight: string) => number) | false;
122
+ }
123
+
124
+ /**
125
+ * Stringify an object into a query string, sorting the keys.
126
+ */
127
+ export function stringify(
128
+ object: {[key: string]: unknown},
129
+ options?: StringifyOptions
130
+ ): string;
131
+
132
+ /**
133
+ * Extract a query string from a URL that can be passed into `.parse()`.
134
+ */
135
+ export function extract(url: string): string;
package/index.js CHANGED
@@ -1,52 +1,51 @@
1
1
  'use strict';
2
- var strictUriEncode = require('strict-uri-encode');
3
- var objectAssign = require('object-assign');
4
- var decodeComponent = require('decode-uri-component');
2
+ const strictUriEncode = require('strict-uri-encode');
3
+ const decodeComponent = require('decode-uri-component');
5
4
 
6
- function encoderForArrayFormat(opts) {
7
- switch (opts.arrayFormat) {
5
+ function encoderForArrayFormat(options) {
6
+ switch (options.arrayFormat) {
8
7
  case 'index':
9
- return function (key, value, index) {
8
+ return (key, value, index) => {
10
9
  return value === null ? [
11
- encode(key, opts),
10
+ encode(key, options),
12
11
  '[',
13
12
  index,
14
13
  ']'
15
14
  ].join('') : [
16
- encode(key, opts),
15
+ encode(key, options),
17
16
  '[',
18
- encode(index, opts),
17
+ encode(index, options),
19
18
  ']=',
20
- encode(value, opts)
19
+ encode(value, options)
21
20
  ].join('');
22
21
  };
23
22
 
24
23
  case 'bracket':
25
- return function (key, value) {
26
- return value === null ? encode(key, opts) : [
27
- encode(key, opts),
24
+ return (key, value) => {
25
+ return value === null ? [encode(key, options), '[]'].join('') : [
26
+ encode(key, options),
28
27
  '[]=',
29
- encode(value, opts)
28
+ encode(value, options)
30
29
  ].join('');
31
30
  };
32
31
 
33
32
  default:
34
- return function (key, value) {
35
- return value === null ? encode(key, opts) : [
36
- encode(key, opts),
33
+ return (key, value) => {
34
+ return value === null ? encode(key, options) : [
35
+ encode(key, options),
37
36
  '=',
38
- encode(value, opts)
37
+ encode(value, options)
39
38
  ].join('');
40
39
  };
41
40
  }
42
41
  }
43
42
 
44
- function parserForArrayFormat(opts) {
45
- var result;
43
+ function parserForArrayFormat(options) {
44
+ let result;
46
45
 
47
- switch (opts.arrayFormat) {
46
+ switch (options.arrayFormat) {
48
47
  case 'index':
49
- return function (key, value, accumulator) {
48
+ return (key, value, accumulator) => {
50
49
  result = /\[(\d*)\]$/.exec(key);
51
50
 
52
51
  key = key.replace(/\[\d*\]$/, '');
@@ -64,14 +63,16 @@ function parserForArrayFormat(opts) {
64
63
  };
65
64
 
66
65
  case 'bracket':
67
- return function (key, value, accumulator) {
66
+ return (key, value, accumulator) => {
68
67
  result = /(\[\])$/.exec(key);
69
68
  key = key.replace(/\[\]$/, '');
70
69
 
71
70
  if (!result) {
72
71
  accumulator[key] = value;
73
72
  return;
74
- } else if (accumulator[key] === undefined) {
73
+ }
74
+
75
+ if (accumulator[key] === undefined) {
75
76
  accumulator[key] = [value];
76
77
  return;
77
78
  }
@@ -80,7 +81,7 @@ function parserForArrayFormat(opts) {
80
81
  };
81
82
 
82
83
  default:
83
- return function (key, value, accumulator) {
84
+ return (key, value, accumulator) => {
84
85
  if (accumulator[key] === undefined) {
85
86
  accumulator[key] = value;
86
87
  return;
@@ -91,9 +92,17 @@ function parserForArrayFormat(opts) {
91
92
  }
92
93
  }
93
94
 
94
- function encode(value, opts) {
95
- if (opts.encode) {
96
- return opts.strict ? strictUriEncode(value) : encodeURIComponent(value);
95
+ function encode(value, options) {
96
+ if (options.encode) {
97
+ return options.strict ? strictUriEncode(value) : encodeURIComponent(value);
98
+ }
99
+
100
+ return value;
101
+ }
102
+
103
+ function decode(value, options) {
104
+ if (options.decode) {
105
+ return decodeComponent(value);
97
106
  }
98
107
 
99
108
  return value;
@@ -102,65 +111,61 @@ function encode(value, opts) {
102
111
  function keysSorter(input) {
103
112
  if (Array.isArray(input)) {
104
113
  return input.sort();
105
- } else if (typeof input === 'object') {
106
- return keysSorter(Object.keys(input)).sort(function (a, b) {
107
- return Number(a) - Number(b);
108
- }).map(function (key) {
109
- return input[key];
110
- });
114
+ }
115
+
116
+ if (typeof input === 'object') {
117
+ return keysSorter(Object.keys(input))
118
+ .sort((a, b) => Number(a) - Number(b))
119
+ .map(key => input[key]);
111
120
  }
112
121
 
113
122
  return input;
114
123
  }
115
124
 
116
- function extract(str) {
117
- var queryStart = str.indexOf('?');
125
+ function extract(input) {
126
+ const queryStart = input.indexOf('?');
118
127
  if (queryStart === -1) {
119
128
  return '';
120
129
  }
121
- return str.slice(queryStart + 1);
130
+
131
+ return input.slice(queryStart + 1);
122
132
  }
123
133
 
124
- function parse(str, opts) {
125
- opts = objectAssign({arrayFormat: 'none'}, opts);
134
+ function parse(input, options) {
135
+ options = Object.assign({decode: true, arrayFormat: 'none'}, options);
126
136
 
127
- var formatter = parserForArrayFormat(opts);
137
+ const formatter = parserForArrayFormat(options);
128
138
 
129
139
  // Create an object with no prototype
130
- // https://github.com/sindresorhus/query-string/issues/47
131
- var ret = Object.create(null);
140
+ const ret = Object.create(null);
132
141
 
133
- if (typeof str !== 'string') {
142
+ if (typeof input !== 'string') {
134
143
  return ret;
135
144
  }
136
145
 
137
- str = str.trim().replace(/^[?#&]/, '');
146
+ input = input.trim().replace(/^[?#&]/, '');
138
147
 
139
- if (!str) {
148
+ if (!input) {
140
149
  return ret;
141
150
  }
142
151
 
143
- str.split('&').forEach(function (param) {
144
- var parts = param.replace(/\+/g, ' ').split('=');
145
- // Firefox (pre 40) decodes `%3D` to `=`
146
- // https://github.com/sindresorhus/query-string/pull/37
147
- var key = parts.shift();
148
- var val = parts.length > 0 ? parts.join('=') : undefined;
152
+ for (const param of input.split('&')) {
153
+ let [key, value] = param.replace(/\+/g, ' ').split('=');
149
154
 
150
- // missing `=` should be `null`:
155
+ // Missing `=` should be `null`:
151
156
  // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters
152
- val = val === undefined ? null : decodeComponent(val);
157
+ value = value === undefined ? null : decode(value, options);
153
158
 
154
- formatter(decodeComponent(key), val, ret);
155
- });
159
+ formatter(decode(key, options), value, ret);
160
+ }
156
161
 
157
- return Object.keys(ret).sort().reduce(function (result, key) {
158
- var val = ret[key];
159
- if (Boolean(val) && typeof val === 'object' && !Array.isArray(val)) {
162
+ return Object.keys(ret).sort().reduce((result, key) => {
163
+ const value = ret[key];
164
+ if (Boolean(value) && typeof value === 'object' && !Array.isArray(value)) {
160
165
  // Sort object keys, not values
161
- result[key] = keysSorter(val);
166
+ result[key] = keysSorter(value);
162
167
  } else {
163
- result[key] = val;
168
+ result[key] = value;
164
169
  }
165
170
 
166
171
  return result;
@@ -170,55 +175,61 @@ function parse(str, opts) {
170
175
  exports.extract = extract;
171
176
  exports.parse = parse;
172
177
 
173
- exports.stringify = function (obj, opts) {
174
- var defaults = {
178
+ exports.stringify = (obj, options) => {
179
+ if (!obj) {
180
+ return '';
181
+ }
182
+
183
+ options = Object.assign({
175
184
  encode: true,
176
185
  strict: true,
177
186
  arrayFormat: 'none'
178
- };
187
+ }, options);
179
188
 
180
- opts = objectAssign(defaults, opts);
189
+ const formatter = encoderForArrayFormat(options);
190
+ const keys = Object.keys(obj);
181
191
 
182
- if (opts.sort === false) {
183
- opts.sort = function () {};
192
+ if (options.sort !== false) {
193
+ keys.sort(options.sort);
184
194
  }
185
195
 
186
- var formatter = encoderForArrayFormat(opts);
187
-
188
- return obj ? Object.keys(obj).sort(opts.sort).map(function (key) {
189
- var val = obj[key];
196
+ return keys.map(key => {
197
+ const value = obj[key];
190
198
 
191
- if (val === undefined) {
199
+ if (value === undefined) {
192
200
  return '';
193
201
  }
194
202
 
195
- if (val === null) {
196
- return encode(key, opts);
203
+ if (value === null) {
204
+ return encode(key, options);
197
205
  }
198
206
 
199
- if (Array.isArray(val)) {
200
- var result = [];
207
+ if (Array.isArray(value)) {
208
+ const result = [];
201
209
 
202
- val.slice().forEach(function (val2) {
203
- if (val2 === undefined) {
204
- return;
210
+ for (const value2 of value.slice()) {
211
+ if (value2 === undefined) {
212
+ continue;
205
213
  }
206
214
 
207
- result.push(formatter(key, val2, result.length));
208
- });
215
+ result.push(formatter(key, value2, result.length));
216
+ }
209
217
 
210
218
  return result.join('&');
211
219
  }
212
220
 
213
- return encode(key, opts) + '=' + encode(val, opts);
214
- }).filter(function (x) {
215
- return x.length > 0;
216
- }).join('&') : '';
221
+ return encode(key, options) + '=' + encode(value, options);
222
+ }).filter(x => x.length > 0).join('&');
217
223
  };
218
224
 
219
- exports.parseUrl = function (str, opts) {
225
+ exports.parseUrl = (input, options) => {
226
+ const hashStart = input.indexOf('#');
227
+ if (hashStart !== -1) {
228
+ input = input.slice(0, hashStart);
229
+ }
230
+
220
231
  return {
221
- url: str.split('?')[0] || '',
222
- query: parse(extract(str), opts)
232
+ url: input.split('?')[0] || '',
233
+ query: parse(extract(input), options)
223
234
  };
224
235
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "query-string",
3
- "version": "5.1.1",
3
+ "version": "6.3.0",
4
4
  "description": "Parse and stringify URL query strings",
5
5
  "license": "MIT",
6
6
  "repository": "sindresorhus/query-string",
@@ -10,13 +10,14 @@
10
10
  "url": "sindresorhus.com"
11
11
  },
12
12
  "engines": {
13
- "node": ">=0.10.0"
13
+ "node": ">=6"
14
14
  },
15
15
  "scripts": {
16
- "test": "xo && ava"
16
+ "test": "xo && ava && tsd-check"
17
17
  },
18
18
  "files": [
19
- "index.js"
19
+ "index.js",
20
+ "index.d.ts"
20
21
  ],
21
22
  "keywords": [
22
23
  "browser",
@@ -27,19 +28,21 @@
27
28
  "param",
28
29
  "parameter",
29
30
  "url",
30
- "uri",
31
31
  "parse",
32
32
  "stringify",
33
33
  "encode",
34
- "decode"
34
+ "decode",
35
+ "searchparams"
35
36
  ],
36
37
  "dependencies": {
37
38
  "decode-uri-component": "^0.2.0",
38
- "object-assign": "^4.1.0",
39
- "strict-uri-encode": "^1.0.0"
39
+ "strict-uri-encode": "^2.0.0"
40
40
  },
41
41
  "devDependencies": {
42
- "ava": "^0.17.0",
43
- "xo": "^0.16.0"
42
+ "ava": "^1.2.1",
43
+ "deep-equal": "^1.0.1",
44
+ "fast-check": "^1.5.0",
45
+ "tsd-check": "^0.3.0",
46
+ "xo": "^0.24.0"
44
47
  }
45
48
  }
package/readme.md CHANGED
@@ -15,6 +15,8 @@
15
15
  $ npm install query-string
16
16
  ```
17
17
 
18
+ This module targets Node.js 6 or later and the latest version of Chrome, Firefox, and Safari. If you want support for older browsers, or, [if your project is using create-react-app v1](https://github.com/sindresorhus/query-string/pull/148#issuecomment-399656020), use version 5: `npm install query-string@5`.
19
+
18
20
  <a href="https://www.patreon.com/sindresorhus">
19
21
  <img src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" width="160">
20
22
  </a>
@@ -60,7 +62,12 @@ Parse a query string into an object. Leading `?` or `#` are ignored, so you can
60
62
 
61
63
  The returned object is created with [`Object.create(null)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create) and thus does not have a `prototype`.
62
64
 
63
- URI components are decoded with [`decode-uri-component`](https://github.com/SamVerschueren/decode-uri-component).
65
+ #### decode
66
+
67
+ Type: `boolean`<br>
68
+ Default: `true`
69
+
70
+ Decode the keys and values. URI components are decoded with [`decode-uri-component`](https://github.com/SamVerschueren/decode-uri-component).
64
71
 
65
72
  #### arrayFormat
66
73
 
@@ -146,14 +153,14 @@ Supports both `Function` as a custom sorting function or `false` to disable sort
146
153
  ```js
147
154
  const order = ['c', 'a', 'b'];
148
155
  queryString.stringify({ a: 1, b: 2, c: 3}, {
149
- sort: (m, n) => order.indexOf(m) >= order.indexOf(n)
156
+ sort: (m, n) => order.indexOf(m) - order.indexOf(n)
150
157
  });
151
158
  // => 'c=3&a=1&b=2'
152
159
  ```
153
160
 
154
161
  ```js
155
162
  queryString.stringify({ b: 1, c: 2, a: 3}, {sort: false});
156
- // => 'c=3&a=1&b=2'
163
+ // => 'b=1&c=2&a=3'
157
164
  ```
158
165
 
159
166
  If omitted, keys are sorted using `Array#sort`, which means, converting them to strings and comparing strings in Unicode code point order.