zustand-querystring 0.5.0 → 0.6.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.
- package/README.md +6 -3
- package/dist/format/plain.d.mts +7 -1
- package/dist/format/plain.d.ts +7 -1
- package/dist/format/plain.js +33 -20
- package/dist/format/plain.mjs +33 -20
- package/dist/index.js +9 -1
- package/dist/index.mjs +9 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -171,12 +171,15 @@ Dot notation for nesting, comma-separated arrays.
|
|
|
171
171
|
import { createFormat } from 'zustand-querystring/format/plain';
|
|
172
172
|
|
|
173
173
|
const format = createFormat({
|
|
174
|
-
entrySeparator: ',',
|
|
175
|
-
nestingSeparator: '.',
|
|
176
|
-
arraySeparator: ',',
|
|
174
|
+
entrySeparator: ',', // between entries in namespaced mode
|
|
175
|
+
nestingSeparator: '.', // for nested keys
|
|
176
|
+
arraySeparator: ',', // or 'repeat' for ?tags=a&tags=b&tags=c
|
|
177
177
|
escapeChar: '_',
|
|
178
178
|
nullString: 'null',
|
|
179
179
|
undefinedString: 'undefined',
|
|
180
|
+
infinityString: 'Infinity', // string representation of Infinity
|
|
181
|
+
negativeInfinityString: '-Infinity',
|
|
182
|
+
nanString: 'NaN',
|
|
180
183
|
});
|
|
181
184
|
```
|
|
182
185
|
|
package/dist/format/plain.d.mts
CHANGED
|
@@ -31,6 +31,12 @@ interface PlainFormatOptions {
|
|
|
31
31
|
nullString?: string;
|
|
32
32
|
/** String representation of undefined @default 'undefined' */
|
|
33
33
|
undefinedString?: string;
|
|
34
|
+
/** String representation of Infinity @default 'Infinity' */
|
|
35
|
+
infinityString?: string;
|
|
36
|
+
/** String representation of -Infinity @default '-Infinity' */
|
|
37
|
+
negativeInfinityString?: string;
|
|
38
|
+
/** String representation of NaN @default 'NaN' */
|
|
39
|
+
nanString?: string;
|
|
34
40
|
}
|
|
35
41
|
/**
|
|
36
42
|
* Create a plain format with custom configuration.
|
|
@@ -41,7 +47,7 @@ declare function createFormat(options?: PlainFormatOptions): QueryStringFormat;
|
|
|
41
47
|
*
|
|
42
48
|
* - Entry separator: `,`
|
|
43
49
|
* - Nesting separator: `.`
|
|
44
|
-
* - Array separator:
|
|
50
|
+
* - Array separator: `repeat` (repeated keys, e.g. `?tag=a&tag=b`)
|
|
45
51
|
* - Escape character: `_`
|
|
46
52
|
*/
|
|
47
53
|
declare const plain: QueryStringFormat;
|
package/dist/format/plain.d.ts
CHANGED
|
@@ -31,6 +31,12 @@ interface PlainFormatOptions {
|
|
|
31
31
|
nullString?: string;
|
|
32
32
|
/** String representation of undefined @default 'undefined' */
|
|
33
33
|
undefinedString?: string;
|
|
34
|
+
/** String representation of Infinity @default 'Infinity' */
|
|
35
|
+
infinityString?: string;
|
|
36
|
+
/** String representation of -Infinity @default '-Infinity' */
|
|
37
|
+
negativeInfinityString?: string;
|
|
38
|
+
/** String representation of NaN @default 'NaN' */
|
|
39
|
+
nanString?: string;
|
|
34
40
|
}
|
|
35
41
|
/**
|
|
36
42
|
* Create a plain format with custom configuration.
|
|
@@ -41,7 +47,7 @@ declare function createFormat(options?: PlainFormatOptions): QueryStringFormat;
|
|
|
41
47
|
*
|
|
42
48
|
* - Entry separator: `,`
|
|
43
49
|
* - Nesting separator: `.`
|
|
44
|
-
* - Array separator:
|
|
50
|
+
* - Array separator: `repeat` (repeated keys, e.g. `?tag=a&tag=b`)
|
|
45
51
|
* - Escape character: `_`
|
|
46
52
|
*/
|
|
47
53
|
declare const plain: QueryStringFormat;
|
package/dist/format/plain.js
CHANGED
|
@@ -24,14 +24,17 @@ __export(plain_exports, {
|
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(plain_exports);
|
|
26
26
|
function resolveOptions(opts = {}) {
|
|
27
|
-
var _a, _b, _c, _d, _e, _f;
|
|
27
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
28
28
|
return {
|
|
29
29
|
entrySep: (_a = opts.entrySeparator) != null ? _a : ",",
|
|
30
30
|
nestingSep: (_b = opts.nestingSeparator) != null ? _b : ".",
|
|
31
|
-
arraySep: (_c = opts.arraySeparator) != null ? _c : "
|
|
31
|
+
arraySep: (_c = opts.arraySeparator) != null ? _c : "repeat",
|
|
32
32
|
escape: (_d = opts.escapeChar) != null ? _d : "_",
|
|
33
33
|
nullStr: (_e = opts.nullString) != null ? _e : "null",
|
|
34
|
-
undefStr: (_f = opts.undefinedString) != null ? _f : "undefined"
|
|
34
|
+
undefStr: (_f = opts.undefinedString) != null ? _f : "undefined",
|
|
35
|
+
infStr: (_g = opts.infinityString) != null ? _g : "Infinity",
|
|
36
|
+
negInfStr: (_h = opts.negativeInfinityString) != null ? _h : "-Infinity",
|
|
37
|
+
nanStr: (_i = opts.nanString) != null ? _i : "NaN"
|
|
35
38
|
};
|
|
36
39
|
}
|
|
37
40
|
function validateOptions(opts) {
|
|
@@ -89,13 +92,16 @@ function isObject(value) {
|
|
|
89
92
|
return value !== null && typeof value === "object" && !Array.isArray(value) && !isDate(value);
|
|
90
93
|
}
|
|
91
94
|
var ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/;
|
|
92
|
-
var NUMBER_RE =
|
|
95
|
+
var NUMBER_RE = /^-?(\d+\.?\d*|\d*\.?\d+)([eE][+-]?\d+)?$/;
|
|
93
96
|
function tryParseBoolean(str) {
|
|
94
97
|
if (str === "true") return true;
|
|
95
98
|
if (str === "false") return false;
|
|
96
99
|
return null;
|
|
97
100
|
}
|
|
98
|
-
function tryParseNumber(str) {
|
|
101
|
+
function tryParseNumber(str, opts) {
|
|
102
|
+
if (str === opts.infStr) return Infinity;
|
|
103
|
+
if (str === opts.negInfStr) return -Infinity;
|
|
104
|
+
if (str === opts.nanStr) return NaN;
|
|
99
105
|
if (!NUMBER_RE.test(str)) return null;
|
|
100
106
|
const n = parseFloat(str);
|
|
101
107
|
return isFinite(n) ? n : null;
|
|
@@ -109,7 +115,12 @@ function serializeValue(value, opts) {
|
|
|
109
115
|
if (value === null) return opts.nullStr;
|
|
110
116
|
if (value === void 0) return opts.undefStr;
|
|
111
117
|
if (typeof value === "boolean") return String(value);
|
|
112
|
-
if (typeof value === "number")
|
|
118
|
+
if (typeof value === "number") {
|
|
119
|
+
if (Number.isNaN(value)) return opts.nanStr;
|
|
120
|
+
if (value === Infinity) return opts.infStr;
|
|
121
|
+
if (value === -Infinity) return opts.negInfStr;
|
|
122
|
+
return String(value);
|
|
123
|
+
}
|
|
113
124
|
if (isDate(value)) return value.toISOString();
|
|
114
125
|
return String(value);
|
|
115
126
|
}
|
|
@@ -120,8 +131,8 @@ function parseValue(str, hint, opts) {
|
|
|
120
131
|
if (hint !== null && hint !== void 0) {
|
|
121
132
|
if (typeof hint === "string") return str;
|
|
122
133
|
if (typeof hint === "number") {
|
|
123
|
-
const n2 = tryParseNumber(str);
|
|
124
|
-
if (n2 !== null) return n2;
|
|
134
|
+
const n2 = tryParseNumber(str, opts);
|
|
135
|
+
if (n2 !== null || Number.isNaN(n2)) return n2;
|
|
125
136
|
}
|
|
126
137
|
if (typeof hint === "boolean") {
|
|
127
138
|
const b2 = tryParseBoolean(str);
|
|
@@ -139,8 +150,8 @@ function parseValue(str, hint, opts) {
|
|
|
139
150
|
if (b !== null) return b;
|
|
140
151
|
const d = tryParseDate(str);
|
|
141
152
|
if (d !== null) return d;
|
|
142
|
-
const n = tryParseNumber(str);
|
|
143
|
-
if (n !== null) return n;
|
|
153
|
+
const n = tryParseNumber(str, opts);
|
|
154
|
+
if (n !== null || Number.isNaN(n)) return n;
|
|
144
155
|
return str;
|
|
145
156
|
}
|
|
146
157
|
function escape(str, chars, esc) {
|
|
@@ -334,22 +345,25 @@ function unflatten(entries, initialState, opts) {
|
|
|
334
345
|
if (opts.arraySep !== "repeat") {
|
|
335
346
|
valueSpecials.push(opts.arraySep);
|
|
336
347
|
}
|
|
337
|
-
|
|
348
|
+
const unescapeValue = (v) => unescape(v, opts.escape, valueSpecials);
|
|
349
|
+
let values;
|
|
350
|
+
if (opts.arraySep !== "repeat" && rawValues.length === 1) {
|
|
351
|
+
const parts = splitEscaped(rawValues[0], opts.arraySep, opts.escape);
|
|
352
|
+
const isArray = parts.length > 1 || isArrayHint;
|
|
353
|
+
values = isArray ? parts.map(unescapeValue) : [unescapeValue(rawValues[0])];
|
|
354
|
+
} else {
|
|
355
|
+
values = rawValues.map(unescapeValue);
|
|
356
|
+
}
|
|
338
357
|
if (values.length === 1 && values[0] === "" && isArrayHint) {
|
|
339
358
|
setAtPath(result, path, []);
|
|
340
359
|
continue;
|
|
341
360
|
}
|
|
342
|
-
if (opts.arraySep !== "repeat" && isArrayHint && values.length === 1) {
|
|
343
|
-
values = splitEscaped(values[0], opts.arraySep, opts.escape).map((v) => unescape(v, opts.escape, valueSpecials));
|
|
344
|
-
}
|
|
345
361
|
if (values.length === 1 && !isArrayHint) {
|
|
346
|
-
|
|
347
|
-
setAtPath(result, path, parsed);
|
|
362
|
+
setAtPath(result, path, parseValue(values[0], hint, opts));
|
|
348
363
|
continue;
|
|
349
364
|
}
|
|
350
|
-
const elementHint =
|
|
351
|
-
|
|
352
|
-
setAtPath(result, path, parsedArray);
|
|
365
|
+
const elementHint = isArrayHint ? hint[0] : void 0;
|
|
366
|
+
setAtPath(result, path, values.map((v) => parseValue(v, elementHint, opts)));
|
|
353
367
|
}
|
|
354
368
|
return result;
|
|
355
369
|
}
|
|
@@ -441,6 +455,5 @@ var plain = createFormat();
|
|
|
441
455
|
createFormat,
|
|
442
456
|
plain
|
|
443
457
|
});
|
|
444
|
-
/* v8 ignore next -- @preserve: defensive - regex already filters non-finite number strings */
|
|
445
458
|
/* v8 ignore next 3 -- @preserve: defensive code - unflatten always extracts hint[0] before calling parseValue */
|
|
446
459
|
/* v8 ignore next 3 -- @preserve: defensive - handles non-serializable types like Symbol, Set, Map */
|
package/dist/format/plain.mjs
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
// src/format/plain.ts
|
|
2
2
|
function resolveOptions(opts = {}) {
|
|
3
|
-
var _a, _b, _c, _d, _e, _f;
|
|
3
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
4
4
|
return {
|
|
5
5
|
entrySep: (_a = opts.entrySeparator) != null ? _a : ",",
|
|
6
6
|
nestingSep: (_b = opts.nestingSeparator) != null ? _b : ".",
|
|
7
|
-
arraySep: (_c = opts.arraySeparator) != null ? _c : "
|
|
7
|
+
arraySep: (_c = opts.arraySeparator) != null ? _c : "repeat",
|
|
8
8
|
escape: (_d = opts.escapeChar) != null ? _d : "_",
|
|
9
9
|
nullStr: (_e = opts.nullString) != null ? _e : "null",
|
|
10
|
-
undefStr: (_f = opts.undefinedString) != null ? _f : "undefined"
|
|
10
|
+
undefStr: (_f = opts.undefinedString) != null ? _f : "undefined",
|
|
11
|
+
infStr: (_g = opts.infinityString) != null ? _g : "Infinity",
|
|
12
|
+
negInfStr: (_h = opts.negativeInfinityString) != null ? _h : "-Infinity",
|
|
13
|
+
nanStr: (_i = opts.nanString) != null ? _i : "NaN"
|
|
11
14
|
};
|
|
12
15
|
}
|
|
13
16
|
function validateOptions(opts) {
|
|
@@ -65,13 +68,16 @@ function isObject(value) {
|
|
|
65
68
|
return value !== null && typeof value === "object" && !Array.isArray(value) && !isDate(value);
|
|
66
69
|
}
|
|
67
70
|
var ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/;
|
|
68
|
-
var NUMBER_RE =
|
|
71
|
+
var NUMBER_RE = /^-?(\d+\.?\d*|\d*\.?\d+)([eE][+-]?\d+)?$/;
|
|
69
72
|
function tryParseBoolean(str) {
|
|
70
73
|
if (str === "true") return true;
|
|
71
74
|
if (str === "false") return false;
|
|
72
75
|
return null;
|
|
73
76
|
}
|
|
74
|
-
function tryParseNumber(str) {
|
|
77
|
+
function tryParseNumber(str, opts) {
|
|
78
|
+
if (str === opts.infStr) return Infinity;
|
|
79
|
+
if (str === opts.negInfStr) return -Infinity;
|
|
80
|
+
if (str === opts.nanStr) return NaN;
|
|
75
81
|
if (!NUMBER_RE.test(str)) return null;
|
|
76
82
|
const n = parseFloat(str);
|
|
77
83
|
return isFinite(n) ? n : null;
|
|
@@ -85,7 +91,12 @@ function serializeValue(value, opts) {
|
|
|
85
91
|
if (value === null) return opts.nullStr;
|
|
86
92
|
if (value === void 0) return opts.undefStr;
|
|
87
93
|
if (typeof value === "boolean") return String(value);
|
|
88
|
-
if (typeof value === "number")
|
|
94
|
+
if (typeof value === "number") {
|
|
95
|
+
if (Number.isNaN(value)) return opts.nanStr;
|
|
96
|
+
if (value === Infinity) return opts.infStr;
|
|
97
|
+
if (value === -Infinity) return opts.negInfStr;
|
|
98
|
+
return String(value);
|
|
99
|
+
}
|
|
89
100
|
if (isDate(value)) return value.toISOString();
|
|
90
101
|
return String(value);
|
|
91
102
|
}
|
|
@@ -96,8 +107,8 @@ function parseValue(str, hint, opts) {
|
|
|
96
107
|
if (hint !== null && hint !== void 0) {
|
|
97
108
|
if (typeof hint === "string") return str;
|
|
98
109
|
if (typeof hint === "number") {
|
|
99
|
-
const n2 = tryParseNumber(str);
|
|
100
|
-
if (n2 !== null) return n2;
|
|
110
|
+
const n2 = tryParseNumber(str, opts);
|
|
111
|
+
if (n2 !== null || Number.isNaN(n2)) return n2;
|
|
101
112
|
}
|
|
102
113
|
if (typeof hint === "boolean") {
|
|
103
114
|
const b2 = tryParseBoolean(str);
|
|
@@ -115,8 +126,8 @@ function parseValue(str, hint, opts) {
|
|
|
115
126
|
if (b !== null) return b;
|
|
116
127
|
const d = tryParseDate(str);
|
|
117
128
|
if (d !== null) return d;
|
|
118
|
-
const n = tryParseNumber(str);
|
|
119
|
-
if (n !== null) return n;
|
|
129
|
+
const n = tryParseNumber(str, opts);
|
|
130
|
+
if (n !== null || Number.isNaN(n)) return n;
|
|
120
131
|
return str;
|
|
121
132
|
}
|
|
122
133
|
function escape(str, chars, esc) {
|
|
@@ -310,22 +321,25 @@ function unflatten(entries, initialState, opts) {
|
|
|
310
321
|
if (opts.arraySep !== "repeat") {
|
|
311
322
|
valueSpecials.push(opts.arraySep);
|
|
312
323
|
}
|
|
313
|
-
|
|
324
|
+
const unescapeValue = (v) => unescape(v, opts.escape, valueSpecials);
|
|
325
|
+
let values;
|
|
326
|
+
if (opts.arraySep !== "repeat" && rawValues.length === 1) {
|
|
327
|
+
const parts = splitEscaped(rawValues[0], opts.arraySep, opts.escape);
|
|
328
|
+
const isArray = parts.length > 1 || isArrayHint;
|
|
329
|
+
values = isArray ? parts.map(unescapeValue) : [unescapeValue(rawValues[0])];
|
|
330
|
+
} else {
|
|
331
|
+
values = rawValues.map(unescapeValue);
|
|
332
|
+
}
|
|
314
333
|
if (values.length === 1 && values[0] === "" && isArrayHint) {
|
|
315
334
|
setAtPath(result, path, []);
|
|
316
335
|
continue;
|
|
317
336
|
}
|
|
318
|
-
if (opts.arraySep !== "repeat" && isArrayHint && values.length === 1) {
|
|
319
|
-
values = splitEscaped(values[0], opts.arraySep, opts.escape).map((v) => unescape(v, opts.escape, valueSpecials));
|
|
320
|
-
}
|
|
321
337
|
if (values.length === 1 && !isArrayHint) {
|
|
322
|
-
|
|
323
|
-
setAtPath(result, path, parsed);
|
|
338
|
+
setAtPath(result, path, parseValue(values[0], hint, opts));
|
|
324
339
|
continue;
|
|
325
340
|
}
|
|
326
|
-
const elementHint =
|
|
327
|
-
|
|
328
|
-
setAtPath(result, path, parsedArray);
|
|
341
|
+
const elementHint = isArrayHint ? hint[0] : void 0;
|
|
342
|
+
setAtPath(result, path, values.map((v) => parseValue(v, elementHint, opts)));
|
|
329
343
|
}
|
|
330
344
|
return result;
|
|
331
345
|
}
|
|
@@ -416,6 +430,5 @@ export {
|
|
|
416
430
|
createFormat,
|
|
417
431
|
plain
|
|
418
432
|
};
|
|
419
|
-
/* v8 ignore next -- @preserve: defensive - regex already filters non-finite number strings */
|
|
420
433
|
/* v8 ignore next 3 -- @preserve: defensive code - unflatten always extracts hint[0] before calling parseValue */
|
|
421
434
|
/* v8 ignore next 3 -- @preserve: defensive - handles non-serializable types like Symbol, Set, Map */
|
package/dist/index.js
CHANGED
|
@@ -520,6 +520,7 @@ var queryStringImpl = (fn, options) => (set, get, api) => {
|
|
|
520
520
|
get,
|
|
521
521
|
api
|
|
522
522
|
);
|
|
523
|
+
let previouslyManagedKeys = /* @__PURE__ */ new Set();
|
|
523
524
|
const setQuery = () => {
|
|
524
525
|
const url = new URL(window.location.href);
|
|
525
526
|
const selectedState = getSelectedState(get(), url.pathname);
|
|
@@ -534,7 +535,9 @@ var queryStringImpl = (fn, options) => (set, get, api) => {
|
|
|
534
535
|
let managedKeys;
|
|
535
536
|
if (standalone) {
|
|
536
537
|
const allParams = format.stringifyStandalone(selectedState);
|
|
537
|
-
|
|
538
|
+
const currentKeys = new Set(Object.keys(allParams).map((k) => defaultedOptions.prefix + k));
|
|
539
|
+
managedKeys = /* @__PURE__ */ new Set([...Array.from(currentKeys), ...Array.from(previouslyManagedKeys)]);
|
|
540
|
+
previouslyManagedKeys = currentKeys;
|
|
538
541
|
const compactedParams = format.stringifyStandalone(newCompacted);
|
|
539
542
|
stateParams = {};
|
|
540
543
|
for (const [key, values] of Object.entries(compactedParams)) {
|
|
@@ -600,6 +603,11 @@ var queryStringImpl = (fn, options) => (set, get, api) => {
|
|
|
600
603
|
setQuery();
|
|
601
604
|
};
|
|
602
605
|
const initialized = initialize(new URL(window.location.href), initialState);
|
|
606
|
+
if (standalone) {
|
|
607
|
+
const initSelected = getSelectedState(initialized, new URL(window.location.href).pathname);
|
|
608
|
+
const initParams = format.stringifyStandalone(initSelected);
|
|
609
|
+
previouslyManagedKeys = new Set(Object.keys(initParams).map((k) => defaultedOptions.prefix + k));
|
|
610
|
+
}
|
|
603
611
|
api.getInitialState = () => initialized;
|
|
604
612
|
return initialized;
|
|
605
613
|
} else if (defaultedOptions.url) {
|
package/dist/index.mjs
CHANGED
|
@@ -141,6 +141,7 @@ var queryStringImpl = (fn, options) => (set, get, api) => {
|
|
|
141
141
|
get,
|
|
142
142
|
api
|
|
143
143
|
);
|
|
144
|
+
let previouslyManagedKeys = /* @__PURE__ */ new Set();
|
|
144
145
|
const setQuery = () => {
|
|
145
146
|
const url = new URL(window.location.href);
|
|
146
147
|
const selectedState = getSelectedState(get(), url.pathname);
|
|
@@ -155,7 +156,9 @@ var queryStringImpl = (fn, options) => (set, get, api) => {
|
|
|
155
156
|
let managedKeys;
|
|
156
157
|
if (standalone) {
|
|
157
158
|
const allParams = format.stringifyStandalone(selectedState);
|
|
158
|
-
|
|
159
|
+
const currentKeys = new Set(Object.keys(allParams).map((k) => defaultedOptions.prefix + k));
|
|
160
|
+
managedKeys = /* @__PURE__ */ new Set([...Array.from(currentKeys), ...Array.from(previouslyManagedKeys)]);
|
|
161
|
+
previouslyManagedKeys = currentKeys;
|
|
159
162
|
const compactedParams = format.stringifyStandalone(newCompacted);
|
|
160
163
|
stateParams = {};
|
|
161
164
|
for (const [key, values] of Object.entries(compactedParams)) {
|
|
@@ -221,6 +224,11 @@ var queryStringImpl = (fn, options) => (set, get, api) => {
|
|
|
221
224
|
setQuery();
|
|
222
225
|
};
|
|
223
226
|
const initialized = initialize(new URL(window.location.href), initialState);
|
|
227
|
+
if (standalone) {
|
|
228
|
+
const initSelected = getSelectedState(initialized, new URL(window.location.href).pathname);
|
|
229
|
+
const initParams = format.stringifyStandalone(initSelected);
|
|
230
|
+
previouslyManagedKeys = new Set(Object.keys(initParams).map((k) => defaultedOptions.prefix + k));
|
|
231
|
+
}
|
|
224
232
|
api.getInitialState = () => initialized;
|
|
225
233
|
return initialized;
|
|
226
234
|
} else if (defaultedOptions.url) {
|