zustand-querystring 0.2.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
+ };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,30 @@
1
- export { QueryStringOptions, querystring } from './middleware.mjs';
2
- export { parse, stringify } from './parser.mjs';
3
- export { createURL } from './utils.mjs';
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.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
@@ -17,14 +17,14 @@ var __copyProps = (to, from, except, desc) => {
17
17
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
18
 
19
19
  // src/index.ts
20
- var index_exports = {};
21
- __export(index_exports, {
20
+ var src_exports = {};
21
+ __export(src_exports, {
22
22
  createURL: () => createURL,
23
23
  parse: () => parse,
24
24
  querystring: () => querystring,
25
25
  stringify: () => stringify
26
26
  });
27
- module.exports = __toCommonJS(index_exports);
27
+ module.exports = __toCommonJS(src_exports);
28
28
 
29
29
  // src/middleware.ts
30
30
  var import_lodash_es = require("lodash-es");
@@ -83,9 +83,15 @@ var queryStringImpl = (fn, options) => (set, get, api) => {
83
83
  ...options
84
84
  };
85
85
  const getStateFromUrl = (url) => {
86
- const match = url.searchParams.get(defaultedOptions.key);
87
- if (match) {
88
- return defaultedOptions.format.parse(match);
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
+ }
89
95
  }
90
96
  return null;
91
97
  };
@@ -128,14 +134,22 @@ var queryStringImpl = (fn, options) => (set, get, api) => {
128
134
  const selectedState = getSelectedState(get(), url.pathname);
129
135
  const newCompacted = compact(selectedState, initialState);
130
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
+ });
131
147
  if (Object.keys(newCompacted).length) {
132
- url.searchParams.set(
133
- defaultedOptions.key,
134
- defaultedOptions.format.stringify(newCompacted)
135
- );
136
- } else {
137
- url.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}`);
138
151
  }
152
+ url.search = otherParams.length ? "?" + otherParams.join("&") : "";
139
153
  if (url.search !== previous) {
140
154
  history.replaceState(history.state, "", url);
141
155
  }
package/dist/index.mjs CHANGED
@@ -1,13 +1,174 @@
1
- import {
2
- querystring
3
- } from "./chunk-L542GMLN.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.2.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"
@@ -44,10 +67,7 @@
44
67
  "rimraf": "^6.0.1",
45
68
  "tsup": "^8.4.0",
46
69
  "typescript": "^5.8.2",
70
+ "vitest": "^4.0.12",
47
71
  "zustand": "^5.0.3"
48
- },
49
- "scripts": {
50
- "build": "tsup src --dts",
51
- "dev": "tsup src --dts --watch"
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,144 +0,0 @@
1
- import {
2
- parse,
3
- stringify
4
- } from "./chunk-OEB5LU3Z.mjs";
5
-
6
- // src/middleware.ts
7
- import { 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
- format: {
47
- stringify,
48
- parse
49
- },
50
- ...options
51
- };
52
- const getStateFromUrl = (url) => {
53
- const match = url.searchParams.get(defaultedOptions.key);
54
- if (match) {
55
- return defaultedOptions.format.parse(match);
56
- }
57
- return null;
58
- };
59
- const getSelectedState = (state, pathname) => {
60
- if (defaultedOptions.select) {
61
- const selection = defaultedOptions.select(pathname);
62
- const selectedState = translateSelectionToState(selection, state);
63
- return selectedState;
64
- }
65
- return state != null ? state : {};
66
- };
67
- const initialize = (url, initialState) => {
68
- try {
69
- const stateFromURl = getStateFromUrl(url);
70
- if (!stateFromURl) {
71
- return initialState;
72
- }
73
- const merged = mergeWith(
74
- {},
75
- initialState,
76
- getSelectedState(stateFromURl, url.pathname)
77
- );
78
- return merged;
79
- } catch (error) {
80
- console.error(error);
81
- return initialState;
82
- }
83
- };
84
- if (typeof window !== "undefined") {
85
- const initialState = fn(
86
- (...args) => {
87
- set(...args);
88
- setQuery();
89
- },
90
- get,
91
- api
92
- );
93
- const setQuery = () => {
94
- const url = new URL(window.location.href);
95
- const selectedState = getSelectedState(get(), url.pathname);
96
- const newCompacted = compact(selectedState, initialState);
97
- const previous = url.search;
98
- if (Object.keys(newCompacted).length) {
99
- url.searchParams.set(
100
- defaultedOptions.key,
101
- defaultedOptions.format.stringify(newCompacted)
102
- );
103
- } else {
104
- url.searchParams.delete(defaultedOptions.key);
105
- }
106
- if (url.search !== previous) {
107
- history.replaceState(history.state, "", url);
108
- }
109
- };
110
- if (!api.__ZUSTAND_QUERYSTRING_INIT__) {
111
- api.__ZUSTAND_QUERYSTRING_INIT__ = true;
112
- let previousPathname = "";
113
- const cb = () => {
114
- if (location.pathname !== previousPathname) {
115
- previousPathname = location.pathname;
116
- setTimeout(setQuery, 100);
117
- }
118
- requestAnimationFrame(cb);
119
- };
120
- requestAnimationFrame(cb);
121
- }
122
- const originalSetState = api.setState;
123
- api.setState = (...args) => {
124
- originalSetState(...args);
125
- setQuery();
126
- };
127
- const initialized = initialize(new URL(window.location.href), initialState);
128
- api.getInitialState = () => initialized;
129
- return initialized;
130
- } else if (defaultedOptions.url) {
131
- const initialized = initialize(
132
- new URL(defaultedOptions.url, "http://localhost"),
133
- fn(set, get, api)
134
- );
135
- api.getInitialState = () => initialized;
136
- return initialized;
137
- }
138
- return fn(set, get, api);
139
- };
140
- var querystring = queryStringImpl;
141
-
142
- export {
143
- querystring
144
- };
@@ -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,21 +0,0 @@
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
- export { type QueryStringOptions, querystring };
@@ -1,21 +0,0 @@
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
- export { type QueryStringOptions, querystring };
@@ -1,172 +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
- format: {
75
- stringify,
76
- parse
77
- },
78
- ...options
79
- };
80
- const getStateFromUrl = (url) => {
81
- const match = url.searchParams.get(defaultedOptions.key);
82
- if (match) {
83
- return defaultedOptions.format.parse(match);
84
- }
85
- return null;
86
- };
87
- const getSelectedState = (state, pathname) => {
88
- if (defaultedOptions.select) {
89
- const selection = defaultedOptions.select(pathname);
90
- const selectedState = translateSelectionToState(selection, state);
91
- return selectedState;
92
- }
93
- return state != null ? state : {};
94
- };
95
- const initialize = (url, initialState) => {
96
- try {
97
- const stateFromURl = getStateFromUrl(url);
98
- if (!stateFromURl) {
99
- return initialState;
100
- }
101
- const merged = (0, import_lodash_es.mergeWith)(
102
- {},
103
- initialState,
104
- getSelectedState(stateFromURl, url.pathname)
105
- );
106
- return merged;
107
- } catch (error) {
108
- console.error(error);
109
- return initialState;
110
- }
111
- };
112
- if (typeof window !== "undefined") {
113
- const initialState = fn(
114
- (...args) => {
115
- set(...args);
116
- setQuery();
117
- },
118
- get,
119
- api
120
- );
121
- const setQuery = () => {
122
- const url = new URL(window.location.href);
123
- const selectedState = getSelectedState(get(), url.pathname);
124
- const newCompacted = compact(selectedState, initialState);
125
- const previous = url.search;
126
- if (Object.keys(newCompacted).length) {
127
- url.searchParams.set(
128
- defaultedOptions.key,
129
- defaultedOptions.format.stringify(newCompacted)
130
- );
131
- } else {
132
- url.searchParams.delete(defaultedOptions.key);
133
- }
134
- if (url.search !== previous) {
135
- history.replaceState(history.state, "", url);
136
- }
137
- };
138
- if (!api.__ZUSTAND_QUERYSTRING_INIT__) {
139
- api.__ZUSTAND_QUERYSTRING_INIT__ = true;
140
- let previousPathname = "";
141
- const cb = () => {
142
- if (location.pathname !== previousPathname) {
143
- previousPathname = location.pathname;
144
- setTimeout(setQuery, 100);
145
- }
146
- requestAnimationFrame(cb);
147
- };
148
- requestAnimationFrame(cb);
149
- }
150
- const originalSetState = api.setState;
151
- api.setState = (...args) => {
152
- originalSetState(...args);
153
- setQuery();
154
- };
155
- const initialized = initialize(new URL(window.location.href), initialState);
156
- api.getInitialState = () => initialized;
157
- return initialized;
158
- } else if (defaultedOptions.url) {
159
- const initialized = initialize(
160
- new URL(defaultedOptions.url, "http://localhost"),
161
- fn(set, get, api)
162
- );
163
- api.getInitialState = () => initialized;
164
- return initialized;
165
- }
166
- return fn(set, get, api);
167
- };
168
- var querystring = queryStringImpl;
169
- // Annotate the CommonJS export names for ESM import in node:
170
- 0 && (module.exports = {
171
- querystring
172
- });
@@ -1,7 +0,0 @@
1
- import {
2
- querystring
3
- } from "./chunk-L542GMLN.mjs";
4
- import "./chunk-OEB5LU3Z.mjs";
5
- export {
6
- querystring
7
- };
package/dist/parser.d.mts 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.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.mts 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.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
- };