@common.js/query-string 9.1.1 → 9.4.1

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/README.md +1 -1
  2. package/base.d.ts +124 -20
  3. package/base.js +208 -157
  4. package/package.json +3 -3
package/README.md CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  The [query-string](https://www.npmjs.com/package/query-string) package exported as CommonJS modules.
4
4
 
5
- Exported from [query-string@9.1.1](https://www.npmjs.com/package/query-string/v/9.1.1) using https://github.com/etienne-martin/common.js.
5
+ Exported from [query-string@9.4.1](https://www.npmjs.com/package/query-string/v/9.4.1) using https://github.com/etienne-martin/common.js.
package/base.d.ts CHANGED
@@ -178,18 +178,18 @@ export type ParseOptions = {
178
178
  readonly parseFragmentIdentifier?: boolean;
179
179
 
180
180
  /**
181
- Specify a pre-defined schema to be used when parsing values. The types specified will take precedence over options such as: `parseNumber`, `parseBooleans`, and `arrayFormat`.
181
+ Specifies a schema for parsing query values with explicit type declarations. When defined, the types provided here take precedence over general parsing options such as `parseNumbers`, `parseBooleans`, and `arrayFormat`.
182
182
 
183
- Use this feature to override the type of a value. This can be useful when the type is ambiguous such as a phone number (see example 1 and 2).
183
+ Use this option to explicitly define the type of a specific parameter—particularly useful in cases where the type might otherwise be ambiguous (e.g., phone numbers or IDs).
184
184
 
185
- It is possible to provide a custom function as the parameter type. The parameter's value will equal the function's return value (see example 4).
185
+ You can also provide a custom function to transform the value. The function will receive the raw string and should return the desired parsed result. When used with array formats (like `comma`, `separator`, `bracket`, etc.), the function is applied to each array element individually.
186
186
 
187
- NOTE: Array types (`string[]` and `number[]`) will have no effect if `arrayFormat` is set to `none` (see example 5).
187
+ NOTE: Array types (`string[]`, `number[]`) are ignored if `arrayFormat` is set to `'none'`.
188
188
 
189
189
  @default {}
190
190
 
191
191
  @example
192
- Parse `phoneNumber` as a string, overriding the `parseNumber` option:
192
+ Parse `phoneNumber` as a string, overriding the `parseNumbers` option:
193
193
  ```
194
194
  import queryString from 'query-string';
195
195
 
@@ -203,12 +203,12 @@ export type ParseOptions = {
203
203
  ```
204
204
 
205
205
  @example
206
- Parse `items` as an array of strings, overriding the `parseNumber` option:
206
+ Parse `items` as an array of strings, overriding the `parseNumbers` option:
207
207
  ```
208
208
  import queryString from 'query-string';
209
209
 
210
210
  queryString.parse('?age=20&items=1%2C2%2C3', {
211
- parseNumber: true,
211
+ parseNumbers: true,
212
212
  types: {
213
213
  items: 'string[]',
214
214
  }
@@ -217,7 +217,7 @@ export type ParseOptions = {
217
217
  ```
218
218
 
219
219
  @example
220
- Parse `age` as a number, even when `parseNumber` is false:
220
+ Force `age` to be parsed as a number even when `parseNumbers` is false:
221
221
  ```
222
222
  import queryString from 'query-string';
223
223
 
@@ -226,24 +226,39 @@ export type ParseOptions = {
226
226
  age: 'number',
227
227
  }
228
228
  });
229
- //=> {age: 20, id: '01234', zipcode: '90210 }
229
+ //=> {age: 20, id: '01234', zipcode: '90210'}
230
230
  ```
231
231
 
232
232
  @example
233
- Parse `age` using a custom value parser:
233
+ Use a custom parser function to transform the value of `age`:
234
234
  ```
235
235
  import queryString from 'query-string';
236
236
 
237
237
  queryString.parse('?age=20&id=01234&zipcode=90210', {
238
238
  types: {
239
- age: (value) => value * 2,
239
+ age: value => value * 2,
240
+ }
241
+ });
242
+ //=> {age: 40, id: '01234', zipcode: '90210'}
243
+ ```
244
+
245
+ @example
246
+ Custom functions are applied to each array element when using array formats:
247
+ ```
248
+ import queryString from 'query-string';
249
+
250
+ // With arrays, the function is applied to each element
251
+ queryString.parse('?scores=10,20,30', {
252
+ arrayFormat: 'comma',
253
+ types: {
254
+ scores: value => Number(value) * 2,
240
255
  }
241
256
  });
242
- //=> {age: 40, id: '01234', zipcode: '90210 }
257
+ //=> {scores: [20, 40, 60]}
243
258
  ```
244
259
 
245
260
  @example
246
- Array types will have no effect when `arrayFormat` is set to `none`
261
+ Array types are ignored when `arrayFormat` is set to `'none'`:
247
262
  ```
248
263
  queryString.parse('ids=001%2C002%2C003&foods=apple%2Corange%2Cmango', {
249
264
  arrayFormat: 'none',
@@ -256,7 +271,7 @@ export type ParseOptions = {
256
271
  ```
257
272
 
258
273
  @example
259
- Parse a query utilizing all types:
274
+ Parse a query using multiple type definitions:
260
275
  ```
261
276
  import queryString from 'query-string';
262
277
 
@@ -267,16 +282,31 @@ export type ParseOptions = {
267
282
  items: 'string[]',
268
283
  price: 'string',
269
284
  numbers: 'number[]',
270
- double: (value) => value * 2,
285
+ double: value => value * 2,
271
286
  number: 'number',
272
287
  },
273
288
  });
274
289
  //=> {ids: '001,002,003', items: ['1', '2', '3'], price: '22.00', numbers: [1, 2, 3], double: 10, number: 20}
275
290
  ```
291
+
292
+ @example
293
+ Force `flagged` to be parsed as a boolean even when `parseBooleans` is false:
294
+ ```
295
+ queryString.parse('?isAdmin=true&flagged=true&isOkay=0', {
296
+ parseBooleans: false,
297
+ types: {
298
+ flagged: 'boolean',
299
+ isOkay: 'boolean',
300
+ },
301
+ });
302
+ //=> {isAdmin: 'true', flagged: true, isOkay: false}
303
+ ```
304
+
305
+ Note: The `'boolean'` type also converts `'0'` and `'1'` to booleans, and treats valueless keys (e.g. `?flag`) as `true`.
276
306
  */
277
307
  readonly types?: Record<
278
308
  string,
279
- 'number' | 'string' | 'string[]' | 'number[]' | ((value: string) => unknown)
309
+ 'boolean' | 'number' | 'string' | 'string[]' | 'number[]' | ((value: string) => unknown)
280
310
  >;
281
311
  };
282
312
 
@@ -310,9 +340,10 @@ export type ParsedUrl = {
310
340
  /**
311
341
  Extract the URL and the query string as an object.
312
342
 
313
- If the `parseFragmentIdentifier` option is `true`, the object will also contain a `fragmentIdentifier` property.
314
-
315
343
  @param url - The URL to parse.
344
+ @returns An object with a `url` and `query` property.
345
+
346
+ If the `parseFragmentIdentifier` option is `true`, the object will also contain a `fragmentIdentifier` property.
316
347
 
317
348
  @example
318
349
  ```
@@ -519,17 +550,80 @@ export type StringifyOptions = {
519
550
  ```
520
551
  */
521
552
  readonly skipEmptyString?: boolean;
553
+
554
+ /**
555
+ A function that transforms key-value pairs before stringification.
556
+
557
+ Similar to the `replacer` parameter of `JSON.stringify()`, this function is called for each key-value pair and can be used to transform values before they are stringified.
558
+
559
+ The function receives the key and value, and should return the transformed value. Returning `undefined` will omit the key-value pair from the resulting query string.
560
+
561
+ This is useful for custom serialization of non-primitive types like `Date`:
562
+
563
+ @example
564
+ ```
565
+ import queryString from 'query-string';
566
+
567
+ queryString.stringify({
568
+ date: new Date('2024-01-15T10:30:00Z'),
569
+ name: 'John'
570
+ }, {
571
+ replacer: (key, value) => {
572
+ if (value instanceof Date) {
573
+ return value.toISOString();
574
+ }
575
+
576
+ return value;
577
+ }
578
+ });
579
+ //=> 'date=2024-01-15T10%3A30%3A00.000Z&name=John'
580
+ ```
581
+
582
+ @example
583
+ ```
584
+ import queryString from 'query-string';
585
+
586
+ // Omit keys with null values using replacer instead of skipNull
587
+ queryString.stringify({
588
+ a: 1,
589
+ b: null,
590
+ c: 3
591
+ }, {
592
+ replacer: (key, value) => value === null ? undefined : value
593
+ });
594
+ //=> 'a=1&c=3'
595
+ ```
596
+ */
597
+ readonly replacer?: (key: string, value: unknown) => unknown;
522
598
  };
523
599
 
600
+ /**
601
+ Supported value types for query string parameters.
602
+
603
+ Note: `Symbol`, functions, and objects (except arrays) are not supported and will throw an error when stringified.
604
+ */
524
605
  export type Stringifiable = string | boolean | number | bigint | null | undefined; // eslint-disable-line @typescript-eslint/ban-types
525
606
 
607
+ /**
608
+ A record of stringifiable values.
609
+ */
526
610
  export type StringifiableRecord = Record<
527
611
  string,
528
612
  Stringifiable | readonly Stringifiable[]
529
613
  >;
530
614
 
531
615
  /**
532
- Stringify an object into a query string and sort the keys.
616
+ Stringify an object into a query string and sorting the keys.
617
+
618
+ @param object - Object to stringify. Supported value types are: `string`, `number`, `bigint`, `boolean`, `null`, `undefined`, and arrays of these types. Other types like `Symbol`, functions, or objects (except arrays) will throw an error.
619
+
620
+ @example
621
+ ```
622
+ import queryString from 'query-string';
623
+
624
+ queryString.stringify({foo: 'bar', baz: 42, qux: true});
625
+ //=> 'baz=42&foo=bar&qux=true'
626
+ ```
533
627
  */
534
628
  export function stringify(
535
629
  // TODO: Use the below instead when the following TS issues are fixed:
@@ -544,7 +638,13 @@ export function stringify(
544
638
  /**
545
639
  Extract a query string from a URL that can be passed into `.parse()`.
546
640
 
547
- Note: This behaviour can be changed with the `skipNull` option.
641
+ @example
642
+ ```
643
+ import queryString from 'query-string';
644
+
645
+ queryString.extract('https://foo.bar?foo=bar');
646
+ //=> 'foo=bar'
647
+ ```
548
648
  */
549
649
  export function extract(url: string): string;
550
650
 
@@ -565,6 +665,10 @@ export type UrlObject = {
565
665
  /**
566
666
  Stringify an object into a URL with a query string and sorting the keys. The inverse of [`.parseUrl()`](https://github.com/sindresorhus/query-string#parseurlstring-options)
567
667
 
668
+ The `options` are the same as for `.stringify()`.
669
+
670
+ @returns A string with the URL and a query string.
671
+
568
672
  Query items in the `query` property overrides queries in the `url` property.
569
673
 
570
674
  The `fragmentIdentifier` property overrides the fragment identifier in the `url` property.
package/base.js CHANGED
@@ -42,9 +42,6 @@ function _arrayLikeToArray(arr, len) {
42
42
  function _arrayWithHoles(arr) {
43
43
  if (Array.isArray(arr)) return arr;
44
44
  }
45
- function _arrayWithoutHoles(arr) {
46
- if (Array.isArray(arr)) return _arrayLikeToArray(arr);
47
- }
48
45
  function _defineProperty(obj, key, value) {
49
46
  if (key in obj) {
50
47
  Object.defineProperty(obj, key, {
@@ -63,9 +60,6 @@ function _interopRequireDefault(obj) {
63
60
  default: obj
64
61
  };
65
62
  }
66
- function _iterableToArray(iter) {
67
- if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
68
- }
69
63
  function _iterableToArrayLimit(arr, i) {
70
64
  var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
71
65
  if (_i == null) return;
@@ -93,9 +87,6 @@ function _iterableToArrayLimit(arr, i) {
93
87
  function _nonIterableRest() {
94
88
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
95
89
  }
96
- function _nonIterableSpread() {
97
- throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
98
- }
99
90
  function _objectSpread(target) {
100
91
  for(var i = 1; i < arguments.length; i++){
101
92
  var source = arguments[i] != null ? arguments[i] : {};
@@ -114,9 +105,6 @@ function _objectSpread(target) {
114
105
  function _slicedToArray(arr, i) {
115
106
  return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
116
107
  }
117
- function _toConsumableArray(arr) {
118
- return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
119
- }
120
108
  function _unsupportedIterableToArray(o, minLen) {
121
109
  if (!o) return;
122
110
  if (typeof o === "string") return _arrayLikeToArray(o, minLen);
@@ -146,24 +134,22 @@ function encoderForArrayFormat(options) {
146
134
  return result;
147
135
  }
148
136
  if (value === null) {
149
- return _toConsumableArray(result).concat([
150
- [
151
- encode(key, options),
152
- "[",
153
- index,
154
- "]"
155
- ].join(""),
156
- ]);
157
- }
158
- return _toConsumableArray(result).concat([
159
- [
137
+ result.push([
160
138
  encode(key, options),
161
139
  "[",
162
- encode(index, options),
163
- "]=",
164
- encode(value, options)
165
- ].join(""),
166
- ]);
140
+ index,
141
+ "]"
142
+ ].join(""));
143
+ return result;
144
+ }
145
+ result.push([
146
+ encode(key, options),
147
+ "[",
148
+ encode(index, options),
149
+ "]=",
150
+ encode(value, options)
151
+ ].join(""));
152
+ return result;
167
153
  };
168
154
  };
169
155
  }
@@ -175,20 +161,18 @@ function encoderForArrayFormat(options) {
175
161
  return result;
176
162
  }
177
163
  if (value === null) {
178
- return _toConsumableArray(result).concat([
179
- [
180
- encode(key, options),
181
- "[]"
182
- ].join(""),
183
- ]);
184
- }
185
- return _toConsumableArray(result).concat([
186
- [
164
+ result.push([
187
165
  encode(key, options),
188
- "[]=",
189
- encode(value, options)
190
- ].join(""),
191
- ]);
166
+ "[]"
167
+ ].join(""));
168
+ return result;
169
+ }
170
+ result.push([
171
+ encode(key, options),
172
+ "[]=",
173
+ encode(value, options)
174
+ ].join(""));
175
+ return result;
192
176
  };
193
177
  };
194
178
  }
@@ -200,20 +184,18 @@ function encoderForArrayFormat(options) {
200
184
  return result;
201
185
  }
202
186
  if (value === null) {
203
- return _toConsumableArray(result).concat([
204
- [
205
- encode(key, options),
206
- ":list="
207
- ].join(""),
208
- ]);
209
- }
210
- return _toConsumableArray(result).concat([
211
- [
187
+ result.push([
212
188
  encode(key, options),
213
- ":list=",
214
- encode(value, options)
215
- ].join(""),
216
- ]);
189
+ ":list="
190
+ ].join(""));
191
+ return result;
192
+ }
193
+ result.push([
194
+ encode(key, options),
195
+ ":list=",
196
+ encode(value, options)
197
+ ].join(""));
198
+ return result;
217
199
  };
218
200
  };
219
201
  }
@@ -230,20 +212,15 @@ function encoderForArrayFormat(options) {
230
212
  // Translate null to an empty string so that it doesn't serialize as 'null'
231
213
  value = value === null ? "" : value;
232
214
  if (result.length === 0) {
233
- return [
234
- [
235
- encode(key, options),
236
- keyValueSeparator,
237
- encode(value, options)
238
- ].join("")
239
- ];
240
- }
241
- return [
242
- [
243
- result,
215
+ result.push([
216
+ encode(key, options),
217
+ keyValueSeparator,
244
218
  encode(value, options)
245
- ].join(options.arrayFormatSeparator)
246
- ];
219
+ ].join(""));
220
+ return result;
221
+ }
222
+ result.push(encode(value, options));
223
+ return result;
247
224
  };
248
225
  };
249
226
  }
@@ -255,17 +232,15 @@ function encoderForArrayFormat(options) {
255
232
  return result;
256
233
  }
257
234
  if (value === null) {
258
- return _toConsumableArray(result).concat([
259
- encode(key, options),
260
- ]);
235
+ result.push(encode(key, options));
236
+ return result;
261
237
  }
262
- return _toConsumableArray(result).concat([
263
- [
264
- encode(key, options),
265
- "=",
266
- encode(value, options)
267
- ].join(""),
268
- ]);
238
+ result.push([
239
+ encode(key, options),
240
+ "=",
241
+ encode(value, options)
242
+ ].join(""));
243
+ return result;
269
244
  };
270
245
  };
271
246
  }
@@ -304,9 +279,14 @@ function parserForArrayFormat(options) {
304
279
  ];
305
280
  return;
306
281
  }
307
- accumulator[key] = _toConsumableArray(accumulator[key]).concat([
308
- value
309
- ]);
282
+ if (!Array.isArray(accumulator[key])) {
283
+ accumulator[key] = [
284
+ accumulator[key],
285
+ value
286
+ ];
287
+ return;
288
+ }
289
+ accumulator[key].push(value);
310
290
  };
311
291
  }
312
292
  case "colon-list-separator":
@@ -324,9 +304,14 @@ function parserForArrayFormat(options) {
324
304
  ];
325
305
  return;
326
306
  }
327
- accumulator[key] = _toConsumableArray(accumulator[key]).concat([
328
- value
329
- ]);
307
+ if (!Array.isArray(accumulator[key])) {
308
+ accumulator[key] = [
309
+ accumulator[key],
310
+ value
311
+ ];
312
+ return;
313
+ }
314
+ accumulator[key].push(value);
330
315
  };
331
316
  }
332
317
  case "comma":
@@ -334,9 +319,7 @@ function parserForArrayFormat(options) {
334
319
  {
335
320
  return function(key, value, accumulator) {
336
321
  var isArray = typeof value === "string" && value.includes(options.arrayFormatSeparator);
337
- var isEncodedArray = typeof value === "string" && !isArray && decode(value, options).includes(options.arrayFormatSeparator);
338
- value = isEncodedArray ? decode(value, options) : value;
339
- var newValue = isArray || isEncodedArray ? value.split(options.arrayFormatSeparator).map(function(item) {
322
+ var newValue = isArray ? value.split(options.arrayFormatSeparator).map(function(item) {
340
323
  return decode(item, options);
341
324
  }) : value === null ? value : decode(value, options);
342
325
  accumulator[key] = newValue;
@@ -356,7 +339,31 @@ function parserForArrayFormat(options) {
356
339
  accumulator[key] = arrayValue;
357
340
  return;
358
341
  }
359
- accumulator[key] = _toConsumableArray(accumulator[key]).concat(_toConsumableArray(arrayValue));
342
+ if (!Array.isArray(accumulator[key])) {
343
+ accumulator[key] = [
344
+ accumulator[key]
345
+ ];
346
+ }
347
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
348
+ try {
349
+ for(var _iterator = arrayValue[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
350
+ var item = _step.value;
351
+ accumulator[key].push(item);
352
+ }
353
+ } catch (err) {
354
+ _didIteratorError = true;
355
+ _iteratorError = err;
356
+ } finally{
357
+ try {
358
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
359
+ _iterator.return();
360
+ }
361
+ } finally{
362
+ if (_didIteratorError) {
363
+ throw _iteratorError;
364
+ }
365
+ }
366
+ }
360
367
  };
361
368
  }
362
369
  default:
@@ -366,11 +373,14 @@ function parserForArrayFormat(options) {
366
373
  accumulator[key] = value;
367
374
  return;
368
375
  }
369
- accumulator[key] = _toConsumableArray([
370
- accumulator[key]
371
- ].flat()).concat([
376
+ if (Array.isArray(accumulator[key])) {
377
+ accumulator[key].push(value);
378
+ return;
379
+ }
380
+ accumulator[key] = [
381
+ accumulator[key],
372
382
  value
373
- ]);
383
+ ];
374
384
  };
375
385
  }
376
386
  }
@@ -420,6 +430,11 @@ function getHash(url) {
420
430
  }
421
431
  return hash;
422
432
  }
433
+ function getUrlWithoutQuery(url) {
434
+ // Avoid `split('?')` so query-heavy URLs don't allocate large arrays.
435
+ var queryStart = url.indexOf("?");
436
+ return queryStart === -1 ? url : url.slice(0, queryStart);
437
+ }
423
438
  function parseValue(value, options, type) {
424
439
  if (type === "string" && typeof value === "string") {
425
440
  return value;
@@ -427,12 +442,31 @@ function parseValue(value, options, type) {
427
442
  if (typeof type === "function" && typeof value === "string") {
428
443
  return type(value);
429
444
  }
430
- if (options.parseBooleans && value !== null && (value.toLowerCase() === "true" || value.toLowerCase() === "false")) {
445
+ if (type === "boolean" && value === null) {
446
+ return true;
447
+ }
448
+ if (type === "boolean" && value !== null && (value.toLowerCase() === "true" || value.toLowerCase() === "false")) {
431
449
  return value.toLowerCase() === "true";
432
450
  }
451
+ if (type === "boolean" && value !== null && (value.toLowerCase() === "1" || value.toLowerCase() === "0")) {
452
+ return value.toLowerCase() === "1";
453
+ }
454
+ if (type === "string[]" && options.arrayFormat !== "none" && typeof value === "string") {
455
+ return [
456
+ value
457
+ ];
458
+ }
459
+ if (type === "number[]" && options.arrayFormat !== "none" && !Number.isNaN(Number(value)) && typeof value === "string" && value.trim() !== "") {
460
+ return [
461
+ Number(value)
462
+ ];
463
+ }
433
464
  if (type === "number" && !Number.isNaN(Number(value)) && typeof value === "string" && value.trim() !== "") {
434
465
  return Number(value);
435
466
  }
467
+ if (options.parseBooleans && value !== null && (value.toLowerCase() === "true" || value.toLowerCase() === "false")) {
468
+ return value.toLowerCase() === "true";
469
+ }
436
470
  if (options.parseNumbers && !Number.isNaN(Number(value)) && typeof value === "string" && value.trim() !== "") {
437
471
  return Number(value);
438
472
  }
@@ -467,64 +501,56 @@ function parse(query, options) {
467
501
  if (!query) {
468
502
  return returnValue;
469
503
  }
470
- var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
471
- try {
472
- for(var _iterator = query.split("&")[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
473
- var parameter = _step.value;
474
- if (parameter === "") {
475
- continue;
476
- }
477
- var parameter_ = options.decode ? parameter.replaceAll("+", " ") : parameter;
478
- var ref = _slicedToArray((0, _splitOnFirst.default)(parameter_, "="), 2), key = ref[0], value = ref[1];
479
- if (key === undefined) {
480
- key = parameter_;
481
- }
482
- // Missing `=` should be `null`:
483
- // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters
484
- value = value === undefined ? null : [
485
- "comma",
486
- "separator",
487
- "bracket-separator"
488
- ].includes(options.arrayFormat) ? value : decode(value, options);
489
- formatter(decode(key, options), value, returnValue);
504
+ // Avoid `split('&')` so separator-heavy inputs don't allocate large arrays of empty strings.
505
+ var parameterStart = 0;
506
+ for(var index = 0; index <= query.length; index++){
507
+ if (index < query.length && query[index] !== "&") {
508
+ continue;
490
509
  }
491
- } catch (err) {
492
- _didIteratorError = true;
493
- _iteratorError = err;
494
- } finally{
495
- try {
496
- if (!_iteratorNormalCompletion && _iterator.return != null) {
497
- _iterator.return();
498
- }
499
- } finally{
500
- if (_didIteratorError) {
501
- throw _iteratorError;
502
- }
510
+ if (index === parameterStart) {
511
+ parameterStart = index + 1;
512
+ continue;
513
+ }
514
+ var parameter = query.slice(parameterStart, index);
515
+ parameterStart = index + 1;
516
+ var parameter_ = options.decode ? parameter.replaceAll("+", " ") : parameter;
517
+ var ref = _slicedToArray((0, _splitOnFirst.default)(parameter_, "="), 2), key = ref[0], value = ref[1];
518
+ if (key === undefined) {
519
+ key = parameter_;
503
520
  }
521
+ // Missing `=` should be `null`:
522
+ // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters
523
+ value = value === undefined ? null : [
524
+ "comma",
525
+ "separator",
526
+ "bracket-separator"
527
+ ].includes(options.arrayFormat) ? value : decode(value, options);
528
+ formatter(decode(key, options), value, returnValue);
504
529
  }
505
- var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
530
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
506
531
  try {
507
- for(var _iterator1 = Object.entries(returnValue)[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
508
- var _value = _slicedToArray(_step1.value, 2), key1 = _value[0], value1 = _value[1];
532
+ for(var _iterator = Object.entries(returnValue)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
533
+ var _value = _slicedToArray(_step.value, 2), key1 = _value[0], value1 = _value[1];
509
534
  if (typeof value1 === "object" && value1 !== null && options.types[key1] !== "string") {
510
- var _iteratorNormalCompletion2 = true, _didIteratorError2 = false, _iteratorError2 = undefined;
535
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
511
536
  try {
512
- for(var _iterator2 = Object.entries(value1)[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true){
513
- var _value1 = _slicedToArray(_step2.value, 2), key2 = _value1[0], value2 = _value1[1];
514
- var type = options.types[key1] ? options.types[key1].replace("[]", "") : undefined;
537
+ for(var _iterator1 = Object.entries(value1)[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
538
+ var _value1 = _slicedToArray(_step1.value, 2), key2 = _value1[0], value2 = _value1[1];
539
+ var typeOption = options.types[key1];
540
+ var type = typeof typeOption === "function" ? typeOption : typeOption ? typeOption.replace("[]", "") : undefined;
515
541
  value1[key2] = parseValue(value2, options, type);
516
542
  }
517
543
  } catch (err) {
518
- _didIteratorError2 = true;
519
- _iteratorError2 = err;
544
+ _didIteratorError1 = true;
545
+ _iteratorError1 = err;
520
546
  } finally{
521
547
  try {
522
- if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
523
- _iterator2.return();
548
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
549
+ _iterator1.return();
524
550
  }
525
551
  } finally{
526
- if (_didIteratorError2) {
527
- throw _iteratorError2;
552
+ if (_didIteratorError1) {
553
+ throw _iteratorError1;
528
554
  }
529
555
  }
530
556
  }
@@ -535,16 +561,16 @@ function parse(query, options) {
535
561
  }
536
562
  }
537
563
  } catch (err) {
538
- _didIteratorError1 = true;
539
- _iteratorError1 = err;
564
+ _didIteratorError = true;
565
+ _iteratorError = err;
540
566
  } finally{
541
567
  try {
542
- if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
543
- _iterator1.return();
568
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
569
+ _iterator.return();
544
570
  }
545
571
  } finally{
546
- if (_didIteratorError1) {
547
- throw _iteratorError1;
572
+ if (_didIteratorError) {
573
+ throw _iteratorError;
548
574
  }
549
575
  }
550
576
  }
@@ -603,6 +629,14 @@ function stringify(object, options) {
603
629
  }
604
630
  return keys.map(function(key) {
605
631
  var value = object[key];
632
+ // Apply replacer function if provided
633
+ if (options.replacer) {
634
+ value = options.replacer(key, value);
635
+ // If replacer returns undefined, skip this key
636
+ if (value === undefined) {
637
+ return "";
638
+ }
639
+ }
606
640
  if (value === undefined) {
607
641
  return "";
608
642
  }
@@ -613,7 +647,23 @@ function stringify(object, options) {
613
647
  if (value.length === 0 && options.arrayFormat === "bracket-separator") {
614
648
  return encode(key, options) + "[]";
615
649
  }
616
- return value.reduce(formatter(key), []).join("&");
650
+ // Apply replacer to array elements if provided
651
+ // Note: We don't re-apply replacer to the array itself, only to elements
652
+ var processedArray = value;
653
+ if (options.replacer) {
654
+ processedArray = value.map(function(item, index) {
655
+ return options.replacer("".concat(key, "[").concat(index, "]"), item);
656
+ }).filter(function(item) {
657
+ return item !== undefined;
658
+ });
659
+ }
660
+ var result = processedArray.reduce(formatter(key), []);
661
+ var arrayFormatSeparator = [
662
+ "comma",
663
+ "separator",
664
+ "bracket-separator"
665
+ ].includes(options.arrayFormat) ? options.arrayFormatSeparator : "&";
666
+ return result.join(arrayFormatSeparator);
617
667
  }
618
668
  return encode(key, options) + "=" + encode(value, options);
619
669
  }).filter(function(x) {
@@ -621,17 +671,15 @@ function stringify(object, options) {
621
671
  }).join("&");
622
672
  }
623
673
  function parseUrl(url, options) {
624
- var ref;
625
674
  options = _objectSpread({
626
675
  decode: true
627
676
  }, options);
628
- var ref1 = _slicedToArray((0, _splitOnFirst.default)(url, "#"), 2), url_ = ref1[0], hash = ref1[1];
677
+ var ref = _slicedToArray((0, _splitOnFirst.default)(url, "#"), 2), url_ = ref[0], hash = ref[1];
629
678
  if (url_ === undefined) {
630
679
  url_ = url;
631
680
  }
632
- var ref2;
633
681
  return _objectSpread({
634
- url: (ref2 = (ref = url_ === null || url_ === void 0 ? void 0 : url_.split("?")) === null || ref === void 0 ? void 0 : ref[0]) !== null && ref2 !== void 0 ? ref2 : "",
682
+ url: getUrlWithoutQuery(url_ !== null && url_ !== void 0 ? url_ : ""),
635
683
  query: parse(extract(url), options)
636
684
  }, options && options.parseFragmentIdentifier && hash ? {
637
685
  fragmentIdentifier: decode(hash, options)
@@ -642,16 +690,16 @@ function stringifyUrl(object, options) {
642
690
  encode: true,
643
691
  strict: true
644
692
  }, encodeFragmentIdentifier, true), options);
645
- var url = removeHash(object.url).split("?")[0] || "";
693
+ var url = getUrlWithoutQuery(removeHash(object.url)) || "";
646
694
  var queryFromUrl = extract(object.url);
647
- var query = _objectSpread({}, parse(queryFromUrl, {
695
+ var query = _objectSpread({}, parse(queryFromUrl, _objectSpread({
648
696
  sort: false
649
- }), object.query);
697
+ }, options)), object.query);
650
698
  var queryString = stringify(query, options);
651
699
  queryString && (queryString = "?".concat(queryString));
652
700
  var hash = getHash(object.url);
653
701
  if (typeof object.fragmentIdentifier === "string") {
654
- var urlObjectForFragmentEncode = new URL(url);
702
+ var urlObjectForFragmentEncode = new URL(url, "https://query-string.invalid");
655
703
  urlObjectForFragmentEncode.hash = object.fragmentIdentifier;
656
704
  hash = options[encodeFragmentIdentifier] ? urlObjectForFragmentEncode.hash : "#".concat(object.fragmentIdentifier);
657
705
  }
@@ -669,10 +717,13 @@ function pick(input, filter, options) {
669
717
  }, options);
670
718
  }
671
719
  function exclude(input, filter, options) {
672
- var exclusionFilter = Array.isArray(filter) ? function(key) {
673
- return !filter.includes(key);
674
- } : function(key, value) {
720
+ if (Array.isArray(filter)) {
721
+ var filterSet = new Set(filter);
722
+ return pick(input, function(key) {
723
+ return !filterSet.has(key);
724
+ }, options);
725
+ }
726
+ return pick(input, function(key, value) {
675
727
  return !filter(key, value);
676
- };
677
- return pick(input, exclusionFilter, options);
728
+ }, options);
678
729
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@common.js/query-string",
3
- "version": "9.1.1",
3
+ "version": "9.4.1",
4
4
  "description": "query-string package exported as CommonJS modules",
5
5
  "license": "MIT",
6
6
  "repository": "etienne-martin/common.js",
@@ -39,6 +39,6 @@
39
39
  }
40
40
  },
41
41
  "homepage": "https://github.com/etienne-martin/common.js#readme",
42
- "types": "./index.d.ts",
43
- "main": "./index.js"
42
+ "main": "./index.js",
43
+ "types": "./index.d.ts"
44
44
  }