zustand-querystring 0.0.19 → 0.1.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.
@@ -0,0 +1,19 @@
1
+ import {
2
+ stringify
3
+ } from "./chunk-OEB5LU3Z.mjs";
4
+
5
+ // src/utils.ts
6
+ var createURL = ({
7
+ baseUrl,
8
+ key,
9
+ state
10
+ }) => {
11
+ const url = new URL(baseUrl);
12
+ const stringified = stringify(state);
13
+ url.searchParams.set(key, stringified);
14
+ return url.href;
15
+ };
16
+
17
+ export {
18
+ createURL
19
+ };
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  parse,
3
3
  stringify
4
- } from "./chunk-ZM24AXRE.mjs";
4
+ } from "./chunk-OEB5LU3Z.mjs";
5
5
 
6
6
  // src/middleware.ts
7
- import { mergeWith, isEqual, cloneDeep } from "lodash-es";
7
+ import { cloneDeep, isEqual, mergeWith } from "lodash-es";
8
8
  var compact = (newState, initialState) => {
9
9
  const output = {};
10
10
  Object.keys(newState).forEach((key) => {
@@ -40,29 +40,19 @@ var translateSelectionToState = (selection, state) => {
40
40
  return acc;
41
41
  }, {});
42
42
  };
43
- var escapeStringRegexp = (string) => {
44
- if (typeof string !== "string") {
45
- throw new TypeError("Expected a string");
46
- }
47
- return string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&");
48
- };
49
43
  var queryStringImpl = (fn, options) => (set, get, api) => {
50
44
  const defaultedOptions = {
51
- key: "$",
45
+ key: "state",
52
46
  ...options
53
47
  };
54
- const escapedKey = escapeStringRegexp(defaultedOptions.key);
55
- const stateMatcher = new RegExp(`${escapedKey}=(.*);;|${escapedKey}=(.*)$`);
56
- const splitMatcher = new RegExp(`${escapedKey}=.*;;|${escapedKey}=.*$`);
57
- const parseQueryString = (querystring2) => {
58
- var _a;
59
- const match = querystring2.match(stateMatcher);
48
+ const { url } = defaultedOptions;
49
+ const getStateFromUrl = (url2) => {
50
+ const match = url2.searchParams.get(defaultedOptions.key);
60
51
  if (match) {
61
- return parse((_a = match[1]) != null ? _a : match[2]);
52
+ return parse(match);
62
53
  }
63
54
  return null;
64
55
  };
65
- const url = defaultedOptions.url;
66
56
  const getSelectedState = (state, pathname) => {
67
57
  if (defaultedOptions.select) {
68
58
  const selection = defaultedOptions.select(pathname);
@@ -73,18 +63,13 @@ var queryStringImpl = (fn, options) => (set, get, api) => {
73
63
  };
74
64
  const initialize = (url2, initialState) => {
75
65
  try {
76
- const queryString = url2.search.substring(1);
77
- const pathname = url2.pathname;
78
- if (!queryString) {
79
- return initialState;
80
- }
81
- const parsed = parseQueryString(queryString);
82
- if (!parsed) {
66
+ const stateFromURl = getStateFromUrl(url2);
67
+ if (!stateFromURl) {
83
68
  return initialState;
84
69
  }
85
70
  const merged = mergeWith(
86
71
  cloneDeep(initialState),
87
- getSelectedState(parsed, pathname)
72
+ getSelectedState(stateFromURl, url2.pathname)
88
73
  );
89
74
  set(merged, true);
90
75
  return merged;
@@ -105,49 +90,17 @@ var queryStringImpl = (fn, options) => (set, get, api) => {
105
90
  )
106
91
  );
107
92
  const setQuery = () => {
108
- const selectedState = getSelectedState(get(), location.pathname);
109
- const currentQueryString = location.search;
110
- const currentParsed = parseQueryString(currentQueryString);
111
- const newMerged = {
112
- ...currentParsed,
113
- ...selectedState
114
- };
115
- const splitIgnored = currentQueryString.split(splitMatcher);
116
- let ignored = "";
117
- for (let str of splitIgnored) {
118
- if (!str || str === "?" || str === "&") {
119
- continue;
120
- }
121
- if (str.startsWith("&") || str.startsWith("?")) {
122
- str = str.substring(1);
123
- }
124
- if (str.endsWith("&")) {
125
- str = str.substring(0, str.length - 1);
126
- }
127
- ignored += (ignored ? "&" : "?") + str;
128
- }
129
- const newCompacted = compact(newMerged, initialState);
130
- let newQueryString = "";
93
+ const url2 = new URL(window.location.href);
94
+ const selectedState = getSelectedState(get(), url2.pathname);
95
+ const newCompacted = compact(selectedState, initialState);
96
+ const previous = url2.search;
131
97
  if (Object.keys(newCompacted).length) {
132
- const stringified = stringify(newCompacted);
133
- const newQueryState = `${defaultedOptions.key}=${stringified};;`;
134
- if (currentParsed) {
135
- newQueryString = currentQueryString.replace(
136
- splitMatcher,
137
- newQueryState
138
- );
139
- } else if (ignored) {
140
- newQueryString = ignored + "&" + newQueryState;
141
- } else {
142
- newQueryString = "?" + newQueryState;
143
- }
98
+ url2.searchParams.set(defaultedOptions.key, stringify(newCompacted));
144
99
  } else {
145
- newQueryString = ignored;
100
+ url2.searchParams.delete(defaultedOptions.key);
146
101
  }
147
- const currentUrl = location.pathname + location.search;
148
- const newUrl = location.pathname + newQueryString;
149
- if (newUrl !== currentUrl) {
150
- history.replaceState(history.state, "", newUrl);
102
+ if (url2.search !== previous) {
103
+ history.replaceState(history.state, "", url2);
151
104
  }
152
105
  };
153
106
  if (!api.__ZUSTAND_QUERYSTRING_INIT__) {
@@ -156,7 +109,7 @@ var queryStringImpl = (fn, options) => (set, get, api) => {
156
109
  const cb = () => {
157
110
  if (location.pathname !== previousPathname) {
158
111
  previousPathname = location.pathname;
159
- setQuery();
112
+ setTimeout(setQuery, 100);
160
113
  }
161
114
  requestAnimationFrame(cb);
162
115
  };
@@ -167,12 +120,9 @@ var queryStringImpl = (fn, options) => (set, get, api) => {
167
120
  originalSetState(...args);
168
121
  setQuery();
169
122
  };
170
- return initialize(new URL(location.href), initialState);
123
+ return initialize(new URL(window.location.href), initialState);
171
124
  } else if (url) {
172
- return initialize(
173
- new URL(decodeURIComponent(url), "http://localhost"),
174
- fn(set, get, api)
175
- );
125
+ return initialize(new URL(url, "http://localhost"), fn(set, get, api));
176
126
  }
177
127
  return fn(set, get, api);
178
128
  };
@@ -0,0 +1,12 @@
1
+ // src/parser.ts
2
+ function stringify(input) {
3
+ return encodeURIComponent(JSON.stringify(input));
4
+ }
5
+ function parse(str) {
6
+ return JSON.parse(decodeURIComponent(str));
7
+ }
8
+
9
+ export {
10
+ stringify,
11
+ parse
12
+ };
package/dist/index.js CHANGED
@@ -26,135 +26,18 @@ __export(src_exports, {
26
26
  });
27
27
  module.exports = __toCommonJS(src_exports);
28
28
 
29
+ // src/middleware.ts
30
+ var import_lodash_es = require("lodash-es");
31
+
29
32
  // src/parser.ts
30
- var keyStringifyRegexp = /([=:@$/])/g;
31
- var valueStringifyRegexp = /([&;/])/g;
32
- var keyParseRegexp = /[=:@$]/;
33
- var valueParseRegexp = /[&;]/;
34
- function encodeString(str, regexp) {
35
- return encodeURI(str.replace(regexp, "/$1"));
36
- }
37
- function trim(res) {
38
- return typeof res === "string" ? res.replace(/;+$/g, "").replace(/^\$/, "") : res;
39
- }
40
- function stringify(input, recursive) {
41
- if (!recursive) {
42
- return trim(stringify(input, true));
43
- }
44
- if (typeof input === "function") {
45
- return;
46
- }
47
- if (typeof input === "number" || input === true || input === false || input === null) {
48
- return ":" + input;
49
- }
50
- const res = [];
51
- if (Array.isArray(input)) {
52
- for (const elem of input) {
53
- typeof elem === "undefined" ? res.push(":null") : res.push(stringify(elem, true));
54
- }
55
- return "@" + res.join("&") + ";";
56
- }
57
- if (input instanceof Date) {
58
- return "=!Date:" + encodeString(input.toISOString(), valueStringifyRegexp);
59
- }
60
- if (typeof input === "object") {
61
- for (const [key, value] of Object.entries(input)) {
62
- const stringifiedValue = stringify(value, true);
63
- if (stringifiedValue) {
64
- res.push(encodeString(key, keyStringifyRegexp) + stringifiedValue);
65
- }
66
- }
67
- return "$" + res.join("&") + ";";
68
- }
69
- if (typeof input === "undefined") {
70
- return;
71
- }
72
- return "=" + encodeString(input.toString(), valueStringifyRegexp);
33
+ function stringify(input) {
34
+ return encodeURIComponent(JSON.stringify(input));
73
35
  }
74
36
  function parse(str) {
75
- if (!str.startsWith("$")) {
76
- str = "$" + str;
77
- }
78
- let pos = 0;
79
- str = decodeURI(str);
80
- function readToken(regexp) {
81
- let token = "";
82
- for (; pos !== str.length; ++pos) {
83
- if (str.charAt(pos) === "/") {
84
- pos += 1;
85
- if (pos === str.length) {
86
- token += ";";
87
- break;
88
- }
89
- } else if (str.charAt(pos).match(regexp)) {
90
- break;
91
- }
92
- token += str.charAt(pos);
93
- }
94
- return token;
95
- }
96
- function parseToken() {
97
- const type = str.charAt(pos++);
98
- if (type === "=") {
99
- const value = readToken(valueParseRegexp);
100
- if (value.startsWith("!Date:")) {
101
- return new Date(value.slice("!Date:".length));
102
- }
103
- return value;
104
- }
105
- if (type === ":") {
106
- const value = readToken(valueParseRegexp);
107
- if (value === "true") {
108
- return true;
109
- }
110
- if (value === "false") {
111
- return false;
112
- }
113
- const parsedValue = parseFloat(value);
114
- return isNaN(parsedValue) ? null : parsedValue;
115
- }
116
- if (type === "@") {
117
- const res = [];
118
- loop: {
119
- if (pos >= str.length || str.charAt(pos) === ";") {
120
- break loop;
121
- }
122
- while (1) {
123
- res.push(parseToken());
124
- if (pos >= str.length || str.charAt(pos) === ";") {
125
- break loop;
126
- }
127
- pos += 1;
128
- }
129
- }
130
- pos += 1;
131
- return res;
132
- }
133
- if (type === "$") {
134
- const res = {};
135
- loop: {
136
- if (pos >= str.length || str.charAt(pos) === ";") {
137
- break loop;
138
- }
139
- while (1) {
140
- var name = readToken(keyParseRegexp);
141
- res[name] = parseToken();
142
- if (pos >= str.length || str.charAt(pos) === ";") {
143
- break loop;
144
- }
145
- pos += 1;
146
- }
147
- }
148
- pos += 1;
149
- return res;
150
- }
151
- throw new Error("Unexpected char " + type);
152
- }
153
- return parseToken();
37
+ return JSON.parse(decodeURIComponent(str));
154
38
  }
155
39
 
156
40
  // src/middleware.ts
157
- var import_lodash_es = require("lodash-es");
158
41
  var compact = (newState, initialState) => {
159
42
  const output = {};
160
43
  Object.keys(newState).forEach((key) => {
@@ -190,29 +73,19 @@ var translateSelectionToState = (selection, state) => {
190
73
  return acc;
191
74
  }, {});
192
75
  };
193
- var escapeStringRegexp = (string) => {
194
- if (typeof string !== "string") {
195
- throw new TypeError("Expected a string");
196
- }
197
- return string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&");
198
- };
199
76
  var queryStringImpl = (fn, options) => (set, get, api) => {
200
77
  const defaultedOptions = {
201
- key: "$",
78
+ key: "state",
202
79
  ...options
203
80
  };
204
- const escapedKey = escapeStringRegexp(defaultedOptions.key);
205
- const stateMatcher = new RegExp(`${escapedKey}=(.*);;|${escapedKey}=(.*)$`);
206
- const splitMatcher = new RegExp(`${escapedKey}=.*;;|${escapedKey}=.*$`);
207
- const parseQueryString2 = (querystring2) => {
208
- var _a;
209
- const match = querystring2.match(stateMatcher);
81
+ const { url } = defaultedOptions;
82
+ const getStateFromUrl = (url2) => {
83
+ const match = url2.searchParams.get(defaultedOptions.key);
210
84
  if (match) {
211
- return parse((_a = match[1]) != null ? _a : match[2]);
85
+ return parse(match);
212
86
  }
213
87
  return null;
214
88
  };
215
- const url = defaultedOptions.url;
216
89
  const getSelectedState = (state, pathname) => {
217
90
  if (defaultedOptions.select) {
218
91
  const selection = defaultedOptions.select(pathname);
@@ -223,18 +96,13 @@ var queryStringImpl = (fn, options) => (set, get, api) => {
223
96
  };
224
97
  const initialize = (url2, initialState) => {
225
98
  try {
226
- const queryString = url2.search.substring(1);
227
- const pathname = url2.pathname;
228
- if (!queryString) {
229
- return initialState;
230
- }
231
- const parsed = parseQueryString2(queryString);
232
- if (!parsed) {
99
+ const stateFromURl = getStateFromUrl(url2);
100
+ if (!stateFromURl) {
233
101
  return initialState;
234
102
  }
235
103
  const merged = (0, import_lodash_es.mergeWith)(
236
104
  (0, import_lodash_es.cloneDeep)(initialState),
237
- getSelectedState(parsed, pathname)
105
+ getSelectedState(stateFromURl, url2.pathname)
238
106
  );
239
107
  set(merged, true);
240
108
  return merged;
@@ -255,49 +123,17 @@ var queryStringImpl = (fn, options) => (set, get, api) => {
255
123
  )
256
124
  );
257
125
  const setQuery = () => {
258
- const selectedState = getSelectedState(get(), location.pathname);
259
- const currentQueryString = location.search;
260
- const currentParsed = parseQueryString2(currentQueryString);
261
- const newMerged = {
262
- ...currentParsed,
263
- ...selectedState
264
- };
265
- const splitIgnored = currentQueryString.split(splitMatcher);
266
- let ignored = "";
267
- for (let str of splitIgnored) {
268
- if (!str || str === "?" || str === "&") {
269
- continue;
270
- }
271
- if (str.startsWith("&") || str.startsWith("?")) {
272
- str = str.substring(1);
273
- }
274
- if (str.endsWith("&")) {
275
- str = str.substring(0, str.length - 1);
276
- }
277
- ignored += (ignored ? "&" : "?") + str;
278
- }
279
- const newCompacted = compact(newMerged, initialState);
280
- let newQueryString = "";
126
+ const url2 = new URL(window.location.href);
127
+ const selectedState = getSelectedState(get(), url2.pathname);
128
+ const newCompacted = compact(selectedState, initialState);
129
+ const previous = url2.search;
281
130
  if (Object.keys(newCompacted).length) {
282
- const stringified = stringify(newCompacted);
283
- const newQueryState = `${defaultedOptions.key}=${stringified};;`;
284
- if (currentParsed) {
285
- newQueryString = currentQueryString.replace(
286
- splitMatcher,
287
- newQueryState
288
- );
289
- } else if (ignored) {
290
- newQueryString = ignored + "&" + newQueryState;
291
- } else {
292
- newQueryString = "?" + newQueryState;
293
- }
131
+ url2.searchParams.set(defaultedOptions.key, stringify(newCompacted));
294
132
  } else {
295
- newQueryString = ignored;
133
+ url2.searchParams.delete(defaultedOptions.key);
296
134
  }
297
- const currentUrl = location.pathname + location.search;
298
- const newUrl = location.pathname + newQueryString;
299
- if (newUrl !== currentUrl) {
300
- history.replaceState(history.state, "", newUrl);
135
+ if (url2.search !== previous) {
136
+ history.replaceState(history.state, "", url2);
301
137
  }
302
138
  };
303
139
  if (!api.__ZUSTAND_QUERYSTRING_INIT__) {
@@ -306,7 +142,7 @@ var queryStringImpl = (fn, options) => (set, get, api) => {
306
142
  const cb = () => {
307
143
  if (location.pathname !== previousPathname) {
308
144
  previousPathname = location.pathname;
309
- setQuery();
145
+ setTimeout(setQuery, 100);
310
146
  }
311
147
  requestAnimationFrame(cb);
312
148
  };
@@ -317,71 +153,24 @@ var queryStringImpl = (fn, options) => (set, get, api) => {
317
153
  originalSetState(...args);
318
154
  setQuery();
319
155
  };
320
- return initialize(new URL(location.href), initialState);
156
+ return initialize(new URL(window.location.href), initialState);
321
157
  } else if (url) {
322
- return initialize(
323
- new URL(decodeURIComponent(url), "http://localhost"),
324
- fn(set, get, api)
325
- );
158
+ return initialize(new URL(url, "http://localhost"), fn(set, get, api));
326
159
  }
327
160
  return fn(set, get, api);
328
161
  };
329
162
  var querystring = queryStringImpl;
330
163
 
331
164
  // src/utils.ts
332
- var escapeStringRegexp2 = (string) => {
333
- if (typeof string !== "string") {
334
- throw new TypeError("Expected a string");
335
- }
336
- return string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&");
337
- };
338
- var parseQueryString = (key, querystring2) => {
339
- var _a;
340
- const stateMatcher = new RegExp(`${key}=(.*);;|${key}=(.*)$`);
341
- const match = querystring2.match(stateMatcher);
342
- if (match) {
343
- return parse((_a = match[1]) != null ? _a : match[2]);
344
- }
345
- return null;
346
- };
347
165
  var createURL = ({
348
166
  baseUrl,
349
167
  key,
350
168
  state
351
169
  }) => {
352
- const escapedKey = escapeStringRegexp2(key);
170
+ const url = new URL(baseUrl);
353
171
  const stringified = stringify(state);
354
- const newQueryState = `${key}=${stringified};;`;
355
- const match = baseUrl.indexOf("?");
356
- const currentQueryString = match >= 0 ? baseUrl.substring(match) : "";
357
- const currentParsed = parseQueryString(escapedKey, currentQueryString);
358
- const splitMatcher = new RegExp(`${escapedKey}=.*;;|${escapedKey}=.*$`);
359
- const splitIgnored = currentQueryString.split(splitMatcher);
360
- let ignored = "";
361
- for (let str of splitIgnored) {
362
- if (!str || str === "?" || str === "&") {
363
- continue;
364
- }
365
- if (str.startsWith("&") || str.startsWith("?")) {
366
- str = str.substring(1);
367
- }
368
- if (str.endsWith("&")) {
369
- str = str.substring(0, str.length - 1);
370
- }
371
- ignored += (ignored ? "&" : "?") + str;
372
- }
373
- let newQueryString = "";
374
- if (currentParsed) {
375
- newQueryString = currentQueryString.replace(splitMatcher, newQueryState);
376
- } else if (ignored) {
377
- newQueryString = ignored + "&" + newQueryState;
378
- } else {
379
- newQueryString = "?" + newQueryState;
380
- }
381
- if (currentQueryString) {
382
- return baseUrl.replace(currentQueryString, newQueryString);
383
- }
384
- return baseUrl + newQueryString;
172
+ url.searchParams.set(key, stringified);
173
+ return url.href;
385
174
  };
386
175
  // Annotate the CommonJS export names for ESM import in node:
387
176
  0 && (module.exports = {
package/dist/index.mjs CHANGED
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  querystring
3
- } from "./chunk-S5N6DUVJ.mjs";
3
+ } from "./chunk-HU2467IM.mjs";
4
4
  import {
5
5
  createURL
6
- } from "./chunk-PYA77ZUK.mjs";
6
+ } from "./chunk-HC4H2XL3.mjs";
7
7
  import {
8
8
  parse,
9
9
  stringify
10
- } from "./chunk-ZM24AXRE.mjs";
10
+ } from "./chunk-OEB5LU3Z.mjs";
11
11
  export {
12
12
  createURL,
13
13
  parse,
@@ -1,14 +1,14 @@
1
1
  import { StoreMutatorIdentifier, StateCreator } from 'zustand/vanilla';
2
2
 
3
- type DeepSelect<T> = T extends object ? {
4
- [P in keyof T]?: DeepSelect<T[P]> | boolean;
5
- } : boolean;
6
- interface QueryStringOptions<T> {
7
- url?: string;
8
- select?: (pathname: string) => DeepSelect<T>;
9
- key?: string;
10
- }
11
- type QueryString = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, Mps, Mcs>, options?: QueryStringOptions<T>) => StateCreator<T, Mps, Mcs>;
3
+ type DeepSelect<T> = T extends object ? {
4
+ [P in keyof T]?: DeepSelect<T[P]> | boolean;
5
+ } : boolean;
6
+ interface QueryStringOptions<T> {
7
+ url?: string;
8
+ select?: (pathname: string) => DeepSelect<T>;
9
+ key?: string;
10
+ }
11
+ type QueryString = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, Mps, Mcs>, options?: QueryStringOptions<T>) => StateCreator<T, Mps, Mcs>;
12
12
  declare const querystring: QueryString;
13
13
 
14
14
  export { QueryStringOptions, querystring };