zustand-querystring 0.1.0 → 0.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.
@@ -0,0 +1,4 @@
1
+ declare function stringify(input: unknown, recursive?: boolean): string;
2
+ declare function parse<T = unknown>(str: string): T;
3
+
4
+ export { parse, stringify };
@@ -0,0 +1,4 @@
1
+ declare function stringify(input: unknown, recursive?: boolean): string;
2
+ declare function parse<T = unknown>(str: string): T;
3
+
4
+ export { parse, stringify };
@@ -0,0 +1,164 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+
19
+ // src/format/readable.ts
20
+ var readable_exports = {};
21
+ __export(readable_exports, {
22
+ parse: () => parse,
23
+ stringify: () => stringify
24
+ });
25
+ module.exports = __toCommonJS(readable_exports);
26
+ var keyStringifyRegexp = /([=:@$/.])/g;
27
+ var valueStringifyRegexp = /([.~/])/g;
28
+ var keyParseRegexp = /[=:@$.]/;
29
+ var valueParseRegexp = /[.~]/;
30
+ function encodeString(str, regexp) {
31
+ return encodeURI(str.replace(regexp, "/$1"));
32
+ }
33
+ function trim(res) {
34
+ return typeof res === "string" ? res.replace(/~+$/g, "").replace(/^\$/, "") : res;
35
+ }
36
+ function stringify(input, recursive) {
37
+ if (!recursive) {
38
+ return trim(stringify(input, true));
39
+ }
40
+ if (typeof input === "function") {
41
+ return "";
42
+ }
43
+ if (typeof input === "number" || input === true || input === false || input === null) {
44
+ const value = String(input);
45
+ return ":" + value.replace(/\./g, "/.");
46
+ }
47
+ const res = [];
48
+ if (Array.isArray(input)) {
49
+ for (const elem of input) {
50
+ typeof elem === "undefined" ? res.push(":null") : res.push(stringify(elem, true));
51
+ }
52
+ return "@" + res.join("..") + "~";
53
+ }
54
+ if (input instanceof Date) {
55
+ return "=!Date:" + encodeString(input.toISOString(), valueStringifyRegexp);
56
+ }
57
+ if (typeof input === "object") {
58
+ for (const [key, value] of Object.entries(input)) {
59
+ const stringifiedValue = stringify(value, true);
60
+ if (stringifiedValue) {
61
+ res.push(encodeString(key, keyStringifyRegexp) + stringifiedValue);
62
+ }
63
+ }
64
+ return "$" + res.join("..") + "~";
65
+ }
66
+ if (typeof input === "undefined") {
67
+ return "";
68
+ }
69
+ return "=" + encodeString(input.toString(), valueStringifyRegexp);
70
+ }
71
+ function parse(str) {
72
+ if (!str.startsWith("$")) {
73
+ str = "$" + str;
74
+ }
75
+ let pos = 0;
76
+ str = decodeURI(str);
77
+ function readToken(regexp) {
78
+ let token = "";
79
+ for (; pos !== str.length; ++pos) {
80
+ if (str.charAt(pos) === "/") {
81
+ pos += 1;
82
+ if (pos === str.length) {
83
+ token += "~";
84
+ break;
85
+ }
86
+ } else if (str.charAt(pos).match(regexp)) {
87
+ break;
88
+ }
89
+ token += str.charAt(pos);
90
+ }
91
+ return token;
92
+ }
93
+ function parseToken() {
94
+ const type = str.charAt(pos++);
95
+ if (type === "=") {
96
+ const value = readToken(valueParseRegexp);
97
+ if (value.startsWith("!Date:")) {
98
+ return new Date(value.slice("!Date:".length));
99
+ }
100
+ return value;
101
+ }
102
+ if (type === ":") {
103
+ const value = readToken(valueParseRegexp);
104
+ if (value === "true") {
105
+ return true;
106
+ }
107
+ if (value === "false") {
108
+ return false;
109
+ }
110
+ const parsedValue = parseFloat(value);
111
+ return isNaN(parsedValue) ? null : parsedValue;
112
+ }
113
+ if (type === "@") {
114
+ const res = [];
115
+ loop: {
116
+ if (pos >= str.length || str.charAt(pos) === "~") {
117
+ break loop;
118
+ }
119
+ while (true) {
120
+ res.push(parseToken());
121
+ if (pos >= str.length || str.charAt(pos) === "~") {
122
+ break loop;
123
+ }
124
+ if (str.charAt(pos) === "." && str.charAt(pos + 1) === ".") {
125
+ pos += 2;
126
+ } else {
127
+ pos += 1;
128
+ }
129
+ }
130
+ }
131
+ pos += 1;
132
+ return res;
133
+ }
134
+ if (type === "$") {
135
+ const res = {};
136
+ loop: {
137
+ if (pos >= str.length || str.charAt(pos) === "~") {
138
+ break loop;
139
+ }
140
+ while (true) {
141
+ const name = readToken(keyParseRegexp);
142
+ res[name] = parseToken();
143
+ if (pos >= str.length || str.charAt(pos) === "~") {
144
+ break loop;
145
+ }
146
+ if (str.charAt(pos) === "." && str.charAt(pos + 1) === ".") {
147
+ pos += 2;
148
+ } else {
149
+ pos += 1;
150
+ }
151
+ }
152
+ }
153
+ pos += 1;
154
+ return res;
155
+ }
156
+ throw new Error('Unexpected char "' + type + '" at position ' + (pos - 1));
157
+ }
158
+ return parseToken();
159
+ }
160
+ // Annotate the CommonJS export names for ESM import in node:
161
+ 0 && (module.exports = {
162
+ parse,
163
+ stringify
164
+ });
@@ -0,0 +1,139 @@
1
+ // src/format/readable.ts
2
+ var keyStringifyRegexp = /([=:@$/.])/g;
3
+ var valueStringifyRegexp = /([.~/])/g;
4
+ var keyParseRegexp = /[=:@$.]/;
5
+ var valueParseRegexp = /[.~]/;
6
+ function encodeString(str, regexp) {
7
+ return encodeURI(str.replace(regexp, "/$1"));
8
+ }
9
+ function trim(res) {
10
+ return typeof res === "string" ? res.replace(/~+$/g, "").replace(/^\$/, "") : res;
11
+ }
12
+ function stringify(input, recursive) {
13
+ if (!recursive) {
14
+ return trim(stringify(input, true));
15
+ }
16
+ if (typeof input === "function") {
17
+ return "";
18
+ }
19
+ if (typeof input === "number" || input === true || input === false || input === null) {
20
+ const value = String(input);
21
+ return ":" + value.replace(/\./g, "/.");
22
+ }
23
+ const res = [];
24
+ if (Array.isArray(input)) {
25
+ for (const elem of input) {
26
+ typeof elem === "undefined" ? res.push(":null") : res.push(stringify(elem, true));
27
+ }
28
+ return "@" + res.join("..") + "~";
29
+ }
30
+ if (input instanceof Date) {
31
+ return "=!Date:" + encodeString(input.toISOString(), valueStringifyRegexp);
32
+ }
33
+ if (typeof input === "object") {
34
+ for (const [key, value] of Object.entries(input)) {
35
+ const stringifiedValue = stringify(value, true);
36
+ if (stringifiedValue) {
37
+ res.push(encodeString(key, keyStringifyRegexp) + stringifiedValue);
38
+ }
39
+ }
40
+ return "$" + res.join("..") + "~";
41
+ }
42
+ if (typeof input === "undefined") {
43
+ return "";
44
+ }
45
+ return "=" + encodeString(input.toString(), valueStringifyRegexp);
46
+ }
47
+ function parse(str) {
48
+ if (!str.startsWith("$")) {
49
+ str = "$" + str;
50
+ }
51
+ let pos = 0;
52
+ str = decodeURI(str);
53
+ function readToken(regexp) {
54
+ let token = "";
55
+ for (; pos !== str.length; ++pos) {
56
+ if (str.charAt(pos) === "/") {
57
+ pos += 1;
58
+ if (pos === str.length) {
59
+ token += "~";
60
+ break;
61
+ }
62
+ } else if (str.charAt(pos).match(regexp)) {
63
+ break;
64
+ }
65
+ token += str.charAt(pos);
66
+ }
67
+ return token;
68
+ }
69
+ function parseToken() {
70
+ const type = str.charAt(pos++);
71
+ if (type === "=") {
72
+ const value = readToken(valueParseRegexp);
73
+ if (value.startsWith("!Date:")) {
74
+ return new Date(value.slice("!Date:".length));
75
+ }
76
+ return value;
77
+ }
78
+ if (type === ":") {
79
+ const value = readToken(valueParseRegexp);
80
+ if (value === "true") {
81
+ return true;
82
+ }
83
+ if (value === "false") {
84
+ return false;
85
+ }
86
+ const parsedValue = parseFloat(value);
87
+ return isNaN(parsedValue) ? null : parsedValue;
88
+ }
89
+ if (type === "@") {
90
+ const res = [];
91
+ loop: {
92
+ if (pos >= str.length || str.charAt(pos) === "~") {
93
+ break loop;
94
+ }
95
+ while (true) {
96
+ res.push(parseToken());
97
+ if (pos >= str.length || str.charAt(pos) === "~") {
98
+ break loop;
99
+ }
100
+ if (str.charAt(pos) === "." && str.charAt(pos + 1) === ".") {
101
+ pos += 2;
102
+ } else {
103
+ pos += 1;
104
+ }
105
+ }
106
+ }
107
+ pos += 1;
108
+ return res;
109
+ }
110
+ if (type === "$") {
111
+ const res = {};
112
+ loop: {
113
+ if (pos >= str.length || str.charAt(pos) === "~") {
114
+ break loop;
115
+ }
116
+ while (true) {
117
+ const name = readToken(keyParseRegexp);
118
+ res[name] = parseToken();
119
+ if (pos >= str.length || str.charAt(pos) === "~") {
120
+ break loop;
121
+ }
122
+ if (str.charAt(pos) === "." && str.charAt(pos + 1) === ".") {
123
+ pos += 2;
124
+ } else {
125
+ pos += 1;
126
+ }
127
+ }
128
+ }
129
+ pos += 1;
130
+ return res;
131
+ }
132
+ throw new Error('Unexpected char "' + type + '" at position ' + (pos - 1));
133
+ }
134
+ return parseToken();
135
+ }
136
+ export {
137
+ parse,
138
+ stringify
139
+ };
@@ -3,12 +3,28 @@ import { StoreMutatorIdentifier, StateCreator } from 'zustand/vanilla';
3
3
  type DeepSelect<T> = T extends object ? {
4
4
  [P in keyof T]?: DeepSelect<T[P]> | boolean;
5
5
  } : boolean;
6
+ type DeepPartial<T> = T extends object ? {
7
+ [P in keyof T]?: DeepPartial<T[P]>;
8
+ } : T;
6
9
  interface QueryStringOptions<T> {
7
10
  url?: string;
8
11
  select?: (pathname: string) => DeepSelect<T>;
9
12
  key?: string;
13
+ format?: {
14
+ stringify: (value: DeepPartial<T>) => string;
15
+ parse: (value: string) => DeepPartial<T>;
16
+ };
10
17
  }
11
18
  type QueryString = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, Mps, Mcs>, options?: QueryStringOptions<T>) => StateCreator<T, Mps, Mcs>;
12
19
  declare const querystring: QueryString;
13
20
 
14
- export { QueryStringOptions, querystring };
21
+ declare function stringify(input: unknown): string;
22
+ declare function parse(str: string): any;
23
+
24
+ declare const createURL: ({ baseUrl, key, state, }: {
25
+ baseUrl: string;
26
+ key: string;
27
+ state: Object;
28
+ }) => string;
29
+
30
+ export { type QueryStringOptions, createURL, parse, querystring, stringify };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,30 @@
1
- export { QueryStringOptions, querystring } from './middleware.js';
2
- export { parse, stringify } from './parser.js';
3
- export { createURL } from './utils.js';
4
- import 'zustand/vanilla';
1
+ import { StoreMutatorIdentifier, StateCreator } from 'zustand/vanilla';
2
+
3
+ type DeepSelect<T> = T extends object ? {
4
+ [P in keyof T]?: DeepSelect<T[P]> | boolean;
5
+ } : boolean;
6
+ type DeepPartial<T> = T extends object ? {
7
+ [P in keyof T]?: DeepPartial<T[P]>;
8
+ } : T;
9
+ interface QueryStringOptions<T> {
10
+ url?: string;
11
+ select?: (pathname: string) => DeepSelect<T>;
12
+ key?: string;
13
+ format?: {
14
+ stringify: (value: DeepPartial<T>) => string;
15
+ parse: (value: string) => DeepPartial<T>;
16
+ };
17
+ }
18
+ type QueryString = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, Mps, Mcs>, options?: QueryStringOptions<T>) => StateCreator<T, Mps, Mcs>;
19
+ declare const querystring: QueryString;
20
+
21
+ declare function stringify(input: unknown): string;
22
+ declare function parse(str: string): any;
23
+
24
+ declare const createURL: ({ baseUrl, key, state, }: {
25
+ baseUrl: string;
26
+ key: string;
27
+ state: Object;
28
+ }) => string;
29
+
30
+ export { type QueryStringOptions, createURL, parse, querystring, stringify };
package/dist/index.js CHANGED
@@ -76,13 +76,22 @@ var translateSelectionToState = (selection, state) => {
76
76
  var queryStringImpl = (fn, options) => (set, get, api) => {
77
77
  const defaultedOptions = {
78
78
  key: "state",
79
+ format: {
80
+ stringify,
81
+ parse
82
+ },
79
83
  ...options
80
84
  };
81
- const { url } = defaultedOptions;
82
- const getStateFromUrl = (url2) => {
83
- const match = url2.searchParams.get(defaultedOptions.key);
84
- if (match) {
85
- return parse(match);
85
+ const getStateFromUrl = (url) => {
86
+ const params = url.search.slice(1).split("&");
87
+ for (const param of params) {
88
+ const eqIndex = param.indexOf("=");
89
+ if (eqIndex === -1) continue;
90
+ const key = param.slice(0, eqIndex);
91
+ if (key === defaultedOptions.key) {
92
+ const value = param.slice(eqIndex + 1);
93
+ return value ? defaultedOptions.format.parse(value) : null;
94
+ }
86
95
  }
87
96
  return null;
88
97
  };
@@ -94,17 +103,17 @@ var queryStringImpl = (fn, options) => (set, get, api) => {
94
103
  }
95
104
  return state != null ? state : {};
96
105
  };
97
- const initialize = (url2, initialState) => {
106
+ const initialize = (url, initialState) => {
98
107
  try {
99
- const stateFromURl = getStateFromUrl(url2);
108
+ const stateFromURl = getStateFromUrl(url);
100
109
  if (!stateFromURl) {
101
110
  return initialState;
102
111
  }
103
112
  const merged = (0, import_lodash_es.mergeWith)(
104
- (0, import_lodash_es.cloneDeep)(initialState),
105
- getSelectedState(stateFromURl, url2.pathname)
113
+ {},
114
+ initialState,
115
+ getSelectedState(stateFromURl, url.pathname)
106
116
  );
107
- set(merged, true);
108
117
  return merged;
109
118
  } catch (error) {
110
119
  console.error(error);
@@ -112,28 +121,37 @@ var queryStringImpl = (fn, options) => (set, get, api) => {
112
121
  }
113
122
  };
114
123
  if (typeof window !== "undefined") {
115
- const initialState = (0, import_lodash_es.cloneDeep)(
116
- fn(
117
- (...args) => {
118
- set(...args);
119
- setQuery();
120
- },
121
- get,
122
- api
123
- )
124
+ const initialState = fn(
125
+ (...args) => {
126
+ set(...args);
127
+ setQuery();
128
+ },
129
+ get,
130
+ api
124
131
  );
125
132
  const setQuery = () => {
126
- const url2 = new URL(window.location.href);
127
- const selectedState = getSelectedState(get(), url2.pathname);
133
+ const url = new URL(window.location.href);
134
+ const selectedState = getSelectedState(get(), url.pathname);
128
135
  const newCompacted = compact(selectedState, initialState);
129
- const previous = url2.search;
136
+ const previous = url.search;
137
+ const params = url.search.slice(1).split("&").filter(Boolean);
138
+ let stateIndex = -1;
139
+ const otherParams = params.filter((p, i) => {
140
+ const [key] = p.split("=", 1);
141
+ if (key === defaultedOptions.key) {
142
+ stateIndex = i;
143
+ return false;
144
+ }
145
+ return true;
146
+ });
130
147
  if (Object.keys(newCompacted).length) {
131
- url2.searchParams.set(defaultedOptions.key, stringify(newCompacted));
132
- } else {
133
- url2.searchParams.delete(defaultedOptions.key);
148
+ const value = defaultedOptions.format.stringify(newCompacted);
149
+ const position = stateIndex === -1 ? otherParams.length : stateIndex;
150
+ otherParams.splice(position, 0, `${defaultedOptions.key}=${value}`);
134
151
  }
135
- if (url2.search !== previous) {
136
- history.replaceState(history.state, "", url2);
152
+ url.search = otherParams.length ? "?" + otherParams.join("&") : "";
153
+ if (url.search !== previous) {
154
+ history.replaceState(history.state, "", url);
137
155
  }
138
156
  };
139
157
  if (!api.__ZUSTAND_QUERYSTRING_INIT__) {
@@ -153,9 +171,16 @@ var queryStringImpl = (fn, options) => (set, get, api) => {
153
171
  originalSetState(...args);
154
172
  setQuery();
155
173
  };
156
- return initialize(new URL(window.location.href), initialState);
157
- } else if (url) {
158
- return initialize(new URL(url, "http://localhost"), fn(set, get, api));
174
+ const initialized = initialize(new URL(window.location.href), initialState);
175
+ api.getInitialState = () => initialized;
176
+ return initialized;
177
+ } else if (defaultedOptions.url) {
178
+ const initialized = initialize(
179
+ new URL(defaultedOptions.url, "http://localhost"),
180
+ fn(set, get, api)
181
+ );
182
+ api.getInitialState = () => initialized;
183
+ return initialized;
159
184
  }
160
185
  return fn(set, get, api);
161
186
  };
package/dist/index.mjs CHANGED
@@ -1,13 +1,174 @@
1
- import {
2
- querystring
3
- } from "./chunk-HU2467IM.mjs";
4
- import {
5
- createURL
6
- } from "./chunk-HC4H2XL3.mjs";
7
- import {
8
- parse,
9
- stringify
10
- } from "./chunk-OEB5LU3Z.mjs";
1
+ // src/middleware.ts
2
+ import { isEqual, mergeWith } from "lodash-es";
3
+
4
+ // src/parser.ts
5
+ function stringify(input) {
6
+ return encodeURIComponent(JSON.stringify(input));
7
+ }
8
+ function parse(str) {
9
+ return JSON.parse(decodeURIComponent(str));
10
+ }
11
+
12
+ // src/middleware.ts
13
+ var compact = (newState, initialState) => {
14
+ const output = {};
15
+ Object.keys(newState).forEach((key) => {
16
+ if (newState[key] !== null && newState[key] !== void 0 && typeof newState[key] !== "function" && !isEqual(newState[key], initialState[key])) {
17
+ if (typeof newState[key] === "object" && !Array.isArray(newState[key])) {
18
+ const value = compact(newState[key], initialState[key]);
19
+ if (value && Object.keys(value).length > 0) {
20
+ output[key] = value;
21
+ }
22
+ } else {
23
+ output[key] = newState[key];
24
+ }
25
+ }
26
+ });
27
+ return output;
28
+ };
29
+ var translateSelectionToState = (selection, state) => {
30
+ if (typeof state !== "object" || !state) {
31
+ return {};
32
+ }
33
+ return Object.keys(selection).reduce((acc, key) => {
34
+ if (!(key in state)) {
35
+ return acc;
36
+ }
37
+ const value = selection[key];
38
+ if (typeof value === "boolean") {
39
+ if (value) {
40
+ acc[key] = state[key];
41
+ }
42
+ } else {
43
+ acc[key] = translateSelectionToState(value, state[key]);
44
+ }
45
+ return acc;
46
+ }, {});
47
+ };
48
+ var queryStringImpl = (fn, options) => (set, get, api) => {
49
+ const defaultedOptions = {
50
+ key: "state",
51
+ format: {
52
+ stringify,
53
+ parse
54
+ },
55
+ ...options
56
+ };
57
+ const getStateFromUrl = (url) => {
58
+ const params = url.search.slice(1).split("&");
59
+ for (const param of params) {
60
+ const eqIndex = param.indexOf("=");
61
+ if (eqIndex === -1) continue;
62
+ const key = param.slice(0, eqIndex);
63
+ if (key === defaultedOptions.key) {
64
+ const value = param.slice(eqIndex + 1);
65
+ return value ? defaultedOptions.format.parse(value) : null;
66
+ }
67
+ }
68
+ return null;
69
+ };
70
+ const getSelectedState = (state, pathname) => {
71
+ if (defaultedOptions.select) {
72
+ const selection = defaultedOptions.select(pathname);
73
+ const selectedState = translateSelectionToState(selection, state);
74
+ return selectedState;
75
+ }
76
+ return state != null ? state : {};
77
+ };
78
+ const initialize = (url, initialState) => {
79
+ try {
80
+ const stateFromURl = getStateFromUrl(url);
81
+ if (!stateFromURl) {
82
+ return initialState;
83
+ }
84
+ const merged = mergeWith(
85
+ {},
86
+ initialState,
87
+ getSelectedState(stateFromURl, url.pathname)
88
+ );
89
+ return merged;
90
+ } catch (error) {
91
+ console.error(error);
92
+ return initialState;
93
+ }
94
+ };
95
+ if (typeof window !== "undefined") {
96
+ const initialState = fn(
97
+ (...args) => {
98
+ set(...args);
99
+ setQuery();
100
+ },
101
+ get,
102
+ api
103
+ );
104
+ const setQuery = () => {
105
+ const url = new URL(window.location.href);
106
+ const selectedState = getSelectedState(get(), url.pathname);
107
+ const newCompacted = compact(selectedState, initialState);
108
+ const previous = url.search;
109
+ const params = url.search.slice(1).split("&").filter(Boolean);
110
+ let stateIndex = -1;
111
+ const otherParams = params.filter((p, i) => {
112
+ const [key] = p.split("=", 1);
113
+ if (key === defaultedOptions.key) {
114
+ stateIndex = i;
115
+ return false;
116
+ }
117
+ return true;
118
+ });
119
+ if (Object.keys(newCompacted).length) {
120
+ const value = defaultedOptions.format.stringify(newCompacted);
121
+ const position = stateIndex === -1 ? otherParams.length : stateIndex;
122
+ otherParams.splice(position, 0, `${defaultedOptions.key}=${value}`);
123
+ }
124
+ url.search = otherParams.length ? "?" + otherParams.join("&") : "";
125
+ if (url.search !== previous) {
126
+ history.replaceState(history.state, "", url);
127
+ }
128
+ };
129
+ if (!api.__ZUSTAND_QUERYSTRING_INIT__) {
130
+ api.__ZUSTAND_QUERYSTRING_INIT__ = true;
131
+ let previousPathname = "";
132
+ const cb = () => {
133
+ if (location.pathname !== previousPathname) {
134
+ previousPathname = location.pathname;
135
+ setTimeout(setQuery, 100);
136
+ }
137
+ requestAnimationFrame(cb);
138
+ };
139
+ requestAnimationFrame(cb);
140
+ }
141
+ const originalSetState = api.setState;
142
+ api.setState = (...args) => {
143
+ originalSetState(...args);
144
+ setQuery();
145
+ };
146
+ const initialized = initialize(new URL(window.location.href), initialState);
147
+ api.getInitialState = () => initialized;
148
+ return initialized;
149
+ } else if (defaultedOptions.url) {
150
+ const initialized = initialize(
151
+ new URL(defaultedOptions.url, "http://localhost"),
152
+ fn(set, get, api)
153
+ );
154
+ api.getInitialState = () => initialized;
155
+ return initialized;
156
+ }
157
+ return fn(set, get, api);
158
+ };
159
+ var querystring = queryStringImpl;
160
+
161
+ // src/utils.ts
162
+ var createURL = ({
163
+ baseUrl,
164
+ key,
165
+ state
166
+ }) => {
167
+ const url = new URL(baseUrl);
168
+ const stringified = stringify(state);
169
+ url.searchParams.set(key, stringified);
170
+ return url.href;
171
+ };
11
172
  export {
12
173
  createURL,
13
174
  parse,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zustand-querystring",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -13,21 +13,44 @@
13
13
  "type": "github",
14
14
  "url": "https://github.com/nitedani/zustand-querystring"
15
15
  },
16
+ "scripts": {
17
+ "build": "tsup",
18
+ "dev": "tsup --watch",
19
+ "test": "vitest run",
20
+ "test:watch": "vitest"
21
+ },
16
22
  "exports": {
17
23
  ".": {
18
24
  "types": "./dist/index.d.ts",
19
25
  "import": "./dist/index.mjs",
20
26
  "require": "./dist/index.js"
21
27
  },
28
+ "./format/readable": {
29
+ "types": "./dist/format/readable.d.ts",
30
+ "import": "./dist/format/readable.mjs",
31
+ "require": "./dist/format/readable.js"
32
+ },
22
33
  "./package.json": "./package.json"
23
34
  },
35
+ "typesVersions": {
36
+ "*": {
37
+ "format/readable": [
38
+ "./dist/format/readable.d.ts"
39
+ ]
40
+ }
41
+ },
24
42
  "tsup": {
25
43
  "clean": true,
26
44
  "target": "es2019",
27
45
  "format": [
28
46
  "cjs",
29
47
  "esm"
30
- ]
48
+ ],
49
+ "entry": {
50
+ "index": "src/index.ts",
51
+ "format/readable": "src/format/readable.ts"
52
+ },
53
+ "dts": true
31
54
  },
32
55
  "files": [
33
56
  "/dist"
@@ -41,13 +64,10 @@
41
64
  },
42
65
  "devDependencies": {
43
66
  "@types/lodash-es": "^4.17.12",
44
- "rimraf": "^3.0.2",
45
- "tsup": "^6.7.0",
46
- "typescript": "^4.9.5",
47
- "zustand": "^4.5.4"
48
- },
49
- "scripts": {
50
- "build": "tsup src --dts",
51
- "dev": "tsup src --dts --watch"
67
+ "rimraf": "^6.0.1",
68
+ "tsup": "^8.4.0",
69
+ "typescript": "^5.8.2",
70
+ "vitest": "^4.0.12",
71
+ "zustand": "^5.0.3"
52
72
  }
53
- }
73
+ }
@@ -1,19 +0,0 @@
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,133 +0,0 @@
1
- import {
2
- parse,
3
- stringify
4
- } from "./chunk-OEB5LU3Z.mjs";
5
-
6
- // src/middleware.ts
7
- import { cloneDeep, isEqual, mergeWith } from "lodash-es";
8
- var compact = (newState, initialState) => {
9
- const output = {};
10
- Object.keys(newState).forEach((key) => {
11
- if (newState[key] !== null && newState[key] !== void 0 && typeof newState[key] !== "function" && !isEqual(newState[key], initialState[key])) {
12
- if (typeof newState[key] === "object" && !Array.isArray(newState[key])) {
13
- const value = compact(newState[key], initialState[key]);
14
- if (value && Object.keys(value).length > 0) {
15
- output[key] = value;
16
- }
17
- } else {
18
- output[key] = newState[key];
19
- }
20
- }
21
- });
22
- return output;
23
- };
24
- var translateSelectionToState = (selection, state) => {
25
- if (typeof state !== "object" || !state) {
26
- return {};
27
- }
28
- return Object.keys(selection).reduce((acc, key) => {
29
- if (!(key in state)) {
30
- return acc;
31
- }
32
- const value = selection[key];
33
- if (typeof value === "boolean") {
34
- if (value) {
35
- acc[key] = state[key];
36
- }
37
- } else {
38
- acc[key] = translateSelectionToState(value, state[key]);
39
- }
40
- return acc;
41
- }, {});
42
- };
43
- var queryStringImpl = (fn, options) => (set, get, api) => {
44
- const defaultedOptions = {
45
- key: "state",
46
- ...options
47
- };
48
- const { url } = defaultedOptions;
49
- const getStateFromUrl = (url2) => {
50
- const match = url2.searchParams.get(defaultedOptions.key);
51
- if (match) {
52
- return parse(match);
53
- }
54
- return null;
55
- };
56
- const getSelectedState = (state, pathname) => {
57
- if (defaultedOptions.select) {
58
- const selection = defaultedOptions.select(pathname);
59
- const selectedState = translateSelectionToState(selection, state);
60
- return selectedState;
61
- }
62
- return state != null ? state : {};
63
- };
64
- const initialize = (url2, initialState) => {
65
- try {
66
- const stateFromURl = getStateFromUrl(url2);
67
- if (!stateFromURl) {
68
- return initialState;
69
- }
70
- const merged = mergeWith(
71
- cloneDeep(initialState),
72
- getSelectedState(stateFromURl, url2.pathname)
73
- );
74
- set(merged, true);
75
- return merged;
76
- } catch (error) {
77
- console.error(error);
78
- return initialState;
79
- }
80
- };
81
- if (typeof window !== "undefined") {
82
- const initialState = cloneDeep(
83
- fn(
84
- (...args) => {
85
- set(...args);
86
- setQuery();
87
- },
88
- get,
89
- api
90
- )
91
- );
92
- const setQuery = () => {
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;
97
- if (Object.keys(newCompacted).length) {
98
- url2.searchParams.set(defaultedOptions.key, stringify(newCompacted));
99
- } else {
100
- url2.searchParams.delete(defaultedOptions.key);
101
- }
102
- if (url2.search !== previous) {
103
- history.replaceState(history.state, "", url2);
104
- }
105
- };
106
- if (!api.__ZUSTAND_QUERYSTRING_INIT__) {
107
- api.__ZUSTAND_QUERYSTRING_INIT__ = true;
108
- let previousPathname = "";
109
- const cb = () => {
110
- if (location.pathname !== previousPathname) {
111
- previousPathname = location.pathname;
112
- setTimeout(setQuery, 100);
113
- }
114
- requestAnimationFrame(cb);
115
- };
116
- requestAnimationFrame(cb);
117
- }
118
- const originalSetState = api.setState;
119
- api.setState = (...args) => {
120
- originalSetState(...args);
121
- setQuery();
122
- };
123
- return initialize(new URL(window.location.href), initialState);
124
- } else if (url) {
125
- return initialize(new URL(url, "http://localhost"), fn(set, get, api));
126
- }
127
- return fn(set, get, api);
128
- };
129
- var querystring = queryStringImpl;
130
-
131
- export {
132
- querystring
133
- };
@@ -1,12 +0,0 @@
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
- };
@@ -1,161 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
- var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- var __export = (target, all) => {
6
- for (var name in all)
7
- __defProp(target, name, { get: all[name], enumerable: true });
8
- };
9
- var __copyProps = (to, from, except, desc) => {
10
- if (from && typeof from === "object" || typeof from === "function") {
11
- for (let key of __getOwnPropNames(from))
12
- if (!__hasOwnProp.call(to, key) && key !== except)
13
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
- }
15
- return to;
16
- };
17
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
-
19
- // src/middleware.ts
20
- var middleware_exports = {};
21
- __export(middleware_exports, {
22
- querystring: () => querystring
23
- });
24
- module.exports = __toCommonJS(middleware_exports);
25
- var import_lodash_es = require("lodash-es");
26
-
27
- // src/parser.ts
28
- function stringify(input) {
29
- return encodeURIComponent(JSON.stringify(input));
30
- }
31
- function parse(str) {
32
- return JSON.parse(decodeURIComponent(str));
33
- }
34
-
35
- // src/middleware.ts
36
- var compact = (newState, initialState) => {
37
- const output = {};
38
- Object.keys(newState).forEach((key) => {
39
- if (newState[key] !== null && newState[key] !== void 0 && typeof newState[key] !== "function" && !(0, import_lodash_es.isEqual)(newState[key], initialState[key])) {
40
- if (typeof newState[key] === "object" && !Array.isArray(newState[key])) {
41
- const value = compact(newState[key], initialState[key]);
42
- if (value && Object.keys(value).length > 0) {
43
- output[key] = value;
44
- }
45
- } else {
46
- output[key] = newState[key];
47
- }
48
- }
49
- });
50
- return output;
51
- };
52
- var translateSelectionToState = (selection, state) => {
53
- if (typeof state !== "object" || !state) {
54
- return {};
55
- }
56
- return Object.keys(selection).reduce((acc, key) => {
57
- if (!(key in state)) {
58
- return acc;
59
- }
60
- const value = selection[key];
61
- if (typeof value === "boolean") {
62
- if (value) {
63
- acc[key] = state[key];
64
- }
65
- } else {
66
- acc[key] = translateSelectionToState(value, state[key]);
67
- }
68
- return acc;
69
- }, {});
70
- };
71
- var queryStringImpl = (fn, options) => (set, get, api) => {
72
- const defaultedOptions = {
73
- key: "state",
74
- ...options
75
- };
76
- const { url } = defaultedOptions;
77
- const getStateFromUrl = (url2) => {
78
- const match = url2.searchParams.get(defaultedOptions.key);
79
- if (match) {
80
- return parse(match);
81
- }
82
- return null;
83
- };
84
- const getSelectedState = (state, pathname) => {
85
- if (defaultedOptions.select) {
86
- const selection = defaultedOptions.select(pathname);
87
- const selectedState = translateSelectionToState(selection, state);
88
- return selectedState;
89
- }
90
- return state != null ? state : {};
91
- };
92
- const initialize = (url2, initialState) => {
93
- try {
94
- const stateFromURl = getStateFromUrl(url2);
95
- if (!stateFromURl) {
96
- return initialState;
97
- }
98
- const merged = (0, import_lodash_es.mergeWith)(
99
- (0, import_lodash_es.cloneDeep)(initialState),
100
- getSelectedState(stateFromURl, url2.pathname)
101
- );
102
- set(merged, true);
103
- return merged;
104
- } catch (error) {
105
- console.error(error);
106
- return initialState;
107
- }
108
- };
109
- if (typeof window !== "undefined") {
110
- const initialState = (0, import_lodash_es.cloneDeep)(
111
- fn(
112
- (...args) => {
113
- set(...args);
114
- setQuery();
115
- },
116
- get,
117
- api
118
- )
119
- );
120
- const setQuery = () => {
121
- const url2 = new URL(window.location.href);
122
- const selectedState = getSelectedState(get(), url2.pathname);
123
- const newCompacted = compact(selectedState, initialState);
124
- const previous = url2.search;
125
- if (Object.keys(newCompacted).length) {
126
- url2.searchParams.set(defaultedOptions.key, stringify(newCompacted));
127
- } else {
128
- url2.searchParams.delete(defaultedOptions.key);
129
- }
130
- if (url2.search !== previous) {
131
- history.replaceState(history.state, "", url2);
132
- }
133
- };
134
- if (!api.__ZUSTAND_QUERYSTRING_INIT__) {
135
- api.__ZUSTAND_QUERYSTRING_INIT__ = true;
136
- let previousPathname = "";
137
- const cb = () => {
138
- if (location.pathname !== previousPathname) {
139
- previousPathname = location.pathname;
140
- setTimeout(setQuery, 100);
141
- }
142
- requestAnimationFrame(cb);
143
- };
144
- requestAnimationFrame(cb);
145
- }
146
- const originalSetState = api.setState;
147
- api.setState = (...args) => {
148
- originalSetState(...args);
149
- setQuery();
150
- };
151
- return initialize(new URL(window.location.href), initialState);
152
- } else if (url) {
153
- return initialize(new URL(url, "http://localhost"), fn(set, get, api));
154
- }
155
- return fn(set, get, api);
156
- };
157
- var querystring = queryStringImpl;
158
- // Annotate the CommonJS export names for ESM import in node:
159
- 0 && (module.exports = {
160
- querystring
161
- });
@@ -1,7 +0,0 @@
1
- import {
2
- querystring
3
- } from "./chunk-HU2467IM.mjs";
4
- import "./chunk-OEB5LU3Z.mjs";
5
- export {
6
- querystring
7
- };
package/dist/parser.d.ts DELETED
@@ -1,4 +0,0 @@
1
- declare function stringify(input: unknown): string;
2
- declare function parse(str: string): any;
3
-
4
- export { parse, stringify };
package/dist/parser.js DELETED
@@ -1,36 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
- var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- var __export = (target, all) => {
6
- for (var name in all)
7
- __defProp(target, name, { get: all[name], enumerable: true });
8
- };
9
- var __copyProps = (to, from, except, desc) => {
10
- if (from && typeof from === "object" || typeof from === "function") {
11
- for (let key of __getOwnPropNames(from))
12
- if (!__hasOwnProp.call(to, key) && key !== except)
13
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
- }
15
- return to;
16
- };
17
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
-
19
- // src/parser.ts
20
- var parser_exports = {};
21
- __export(parser_exports, {
22
- parse: () => parse,
23
- stringify: () => stringify
24
- });
25
- module.exports = __toCommonJS(parser_exports);
26
- function stringify(input) {
27
- return encodeURIComponent(JSON.stringify(input));
28
- }
29
- function parse(str) {
30
- return JSON.parse(decodeURIComponent(str));
31
- }
32
- // Annotate the CommonJS export names for ESM import in node:
33
- 0 && (module.exports = {
34
- parse,
35
- stringify
36
- });
package/dist/parser.mjs DELETED
@@ -1,8 +0,0 @@
1
- import {
2
- parse,
3
- stringify
4
- } from "./chunk-OEB5LU3Z.mjs";
5
- export {
6
- parse,
7
- stringify
8
- };
package/dist/utils.d.ts DELETED
@@ -1,7 +0,0 @@
1
- declare const createURL: ({ baseUrl, key, state, }: {
2
- baseUrl: string;
3
- key: string;
4
- state: Object;
5
- }) => string;
6
-
7
- export { createURL };
package/dist/utils.js DELETED
@@ -1,45 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
- var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- var __export = (target, all) => {
6
- for (var name in all)
7
- __defProp(target, name, { get: all[name], enumerable: true });
8
- };
9
- var __copyProps = (to, from, except, desc) => {
10
- if (from && typeof from === "object" || typeof from === "function") {
11
- for (let key of __getOwnPropNames(from))
12
- if (!__hasOwnProp.call(to, key) && key !== except)
13
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
- }
15
- return to;
16
- };
17
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
-
19
- // src/utils.ts
20
- var utils_exports = {};
21
- __export(utils_exports, {
22
- createURL: () => createURL
23
- });
24
- module.exports = __toCommonJS(utils_exports);
25
-
26
- // src/parser.ts
27
- function stringify(input) {
28
- return encodeURIComponent(JSON.stringify(input));
29
- }
30
-
31
- // src/utils.ts
32
- var createURL = ({
33
- baseUrl,
34
- key,
35
- state
36
- }) => {
37
- const url = new URL(baseUrl);
38
- const stringified = stringify(state);
39
- url.searchParams.set(key, stringified);
40
- return url.href;
41
- };
42
- // Annotate the CommonJS export names for ESM import in node:
43
- 0 && (module.exports = {
44
- createURL
45
- });
package/dist/utils.mjs DELETED
@@ -1,7 +0,0 @@
1
- import {
2
- createURL
3
- } from "./chunk-HC4H2XL3.mjs";
4
- import "./chunk-OEB5LU3Z.mjs";
5
- export {
6
- createURL
7
- };