@buildinams/core 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-5KDGGGVO.js +40 -0
- package/dist/chunk-5KDGGGVO.js.map +1 -0
- package/dist/navigation/index.d.ts +46 -26
- package/dist/navigation/index.js +3 -10
- package/dist/navigation/index.js.map +1 -1
- package/dist/schema/index.d.ts +58 -0
- package/dist/schema/index.js +3 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema-CfQvhbuU.d.ts +87 -0
- package/package.json +9 -2
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// src/schema/schema.ts
|
|
2
|
+
var createSchema = (template) => ({
|
|
3
|
+
...template,
|
|
4
|
+
parserialize: (value, next) => {
|
|
5
|
+
return template.serialize(next(template.parse(value)));
|
|
6
|
+
}
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
// src/schema/string-schema.ts
|
|
10
|
+
var createStringSchema = (template) => {
|
|
11
|
+
const schema = createSchema({
|
|
12
|
+
serialize: template.stringify,
|
|
13
|
+
parse: template.parse
|
|
14
|
+
});
|
|
15
|
+
return {
|
|
16
|
+
parse: schema.parse,
|
|
17
|
+
stringify: schema.serialize,
|
|
18
|
+
parseStringify: schema.parserialize
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// src/schema/href-schema.ts
|
|
23
|
+
var hrefSchema = createStringSchema({
|
|
24
|
+
parse: (href) => {
|
|
25
|
+
const [pathname = "", search = ""] = href.split("?");
|
|
26
|
+
return {
|
|
27
|
+
pathname,
|
|
28
|
+
searchParams: new URLSearchParams(search)
|
|
29
|
+
};
|
|
30
|
+
},
|
|
31
|
+
stringify: (state) => {
|
|
32
|
+
if (!state.searchParams) return state.pathname;
|
|
33
|
+
const paramsString = state.searchParams.toString();
|
|
34
|
+
return state.pathname + (paramsString ? `?${paramsString}` : "");
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export { createSchema, createStringSchema, hrefSchema };
|
|
39
|
+
//# sourceMappingURL=chunk-5KDGGGVO.js.map
|
|
40
|
+
//# sourceMappingURL=chunk-5KDGGGVO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/schema/schema.ts","../src/schema/string-schema.ts","../src/schema/href-schema.ts"],"names":[],"mappings":";AAkGO,IAAM,YAAA,GAAe,CAK3B,QAAA,MACmD;AAAA,EACnD,GAAG,QAAA;AAAA,EAEH,YAAA,EAAc,CAAC,KAAA,EAAO,IAAA,KAAS;AAC9B,IAAA,OAAO,SAAS,SAAA,CAAU,IAAA,CAAK,SAAS,KAAA,CAAM,KAAK,CAAC,CAAC,CAAA;AAAA,EACtD;AACD,CAAA;;;AC9FO,IAAM,kBAAA,GAAqB,CACjC,QAAA,KAC4C;AAC5C,EAAA,MAAM,SAAS,YAAA,CAA+C;AAAA,IAC7D,WAAW,QAAA,CAAS,SAAA;AAAA,IACpB,OAAO,QAAA,CAAS;AAAA,GAChB,CAAA;AAED,EAAA,OAAO;AAAA,IACN,OAAO,MAAA,CAAO,KAAA;AAAA,IACd,WAAW,MAAA,CAAO,SAAA;AAAA,IAClB,gBAAgB,MAAA,CAAO;AAAA,GACxB;AACD;;;ACKO,IAAM,aAAa,kBAAA,CASxB;AAAA,EACD,KAAA,EAAO,CAAC,IAAA,KAAS;AAChB,IAAA,MAAM,CAAC,WAAW,EAAA,EAAI,MAAA,GAAS,EAAE,CAAA,GAAI,IAAA,CAAK,MAAM,GAAG,CAAA;AACnD,IAAA,OAAO;AAAA,MACN,QAAA;AAAA,MACA,YAAA,EAAc,IAAI,eAAA,CAAgB,MAAM;AAAA,KACzC;AAAA,EACD,CAAA;AAAA,EACA,SAAA,EAAW,CAAC,KAAA,KAAU;AACrB,IAAA,IAAI,CAAC,KAAA,CAAM,YAAA,EAAc,OAAO,KAAA,CAAM,QAAA;AACtC,IAAA,MAAM,YAAA,GAAe,KAAA,CAAM,YAAA,CAAa,QAAA,EAAS;AACjD,IAAA,OAAO,KAAA,CAAM,QAAA,IAAY,YAAA,GAAe,CAAA,CAAA,EAAI,YAAY,CAAA,CAAA,GAAK,EAAA,CAAA;AAAA,EAC9D;AACD,CAAC","file":"chunk-5KDGGGVO.js","sourcesContent":["/**\n * Defines the schema for parsing and stringifying states to and from primitive values.\n *\n * The `Schema` type is a generic type that takes:\n * - `State`: A state object type.\n * - `Serialized`: The raw value type\n * - `SerializableState?`: (optional) A (partial) state object type that can be used for serialization. Defaults to `State` if not provided.\n *\n * It returns the following methods:\n * - `parse`: A function that takes a raw value and returns the corresponding state object.\n * - `serialize`: A function that takes a (serializable) state object and returns a raw value that represents the given state.\n * - `parserialize`: A function that takes a raw value and a reducer function - it returns a new raw value that represents the reduced state.\n *\n * @see createSchema for a helper function to create a `Schema` from simpler parsing and serializing functions.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type Schema<State = any, Serialized = any, SerializableState = State> = {\n\t/** Parse a raw value into the state shape */\n\tparse: (value: Serialized) => State;\n\t/** Serialize a state shape into a raw value */\n\tserialize: (state: SerializableState) => Serialized;\n\n\t/** Compute a new serialized value based on a given serialized value and a reducer of the current state. */\n\tparserialize: (\n\t\tvalue: Serialized,\n\t\tnext: (state: State) => SerializableState,\n\t) => Serialized;\n};\n\n/**\n * A utility type to extract the state shape from a given `Schema`.\n */\nexport type SchemaState<T extends Schema> =\n\tT extends Schema<infer U> ? U : never;\n\n/**\n * A utility type to extract the serialized value type from a given `Schema`.\n */\nexport type SchemaSerialized<T extends Schema> =\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tT extends Schema<any, infer U> ? U : never;\n\n/**\n * A utility type to extract the serializable state shape from a given `Schema`.\n */\nexport type SchemaSerializableState<T extends Schema> =\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tT extends Schema<any, any, infer U> ? U : never;\n\n/**\n * Low-level helper function to create a basic `Schema` that receives the config for converting between serialized values and state objects.\n *\n * The template requires two methods:\n * - `parse`: A method that takes a serialized value and returns the corresponding state object.\n * - `serialize`: A method that takes a state object and returns a serialized value that represents the given state.\n *\n * The `parserialize` method is automatically implemented based on the provided `parse` and `serialize` methods, allowing you to compute a new serialized value based on an existing serialized value and a reducer function for the state.\n *\n * @example\n * ```ts\n * import { createSchema } from \"@buildinams/core/schema\";\n *\n * const numberSchema = createSchema<\n * number, // State\n * string // Serialized\n * >({\n * parse: (value) => parseInt(value, 10),\n * serialize: (state) => state.toString(),\n * });\n *\n * const result = numberSchema.parserialize(\"42\", (state) => state + 1);\n * console.log(result); // \"43\"\n * ```\n *\n * @example\n * ```ts\n * import { createSchema } from \"@buildinams/core/schema\";\n *\n * const hrefSchema: createSchema<\n * { pathname: string, searchParams: URLSearchParams },\n * string,\n * { pathname: string, searchParams?: URLSearchParams } // SerializableState allows to define different state used for serialization, in this case making searchParams optional to allow for more flexible stringification logic\n * >({\n * parse: (href) => {\n * const [pathname = \"\", search = \"\"] = href.split(\"?\");\n * return {\n * pathname,\n * searchParams: new URLSearchParams(search),\n * };\n * },\n * serialize: (serializableState) => {\n * if (!serializableState.searchParams) return serializableState.pathname;\n * const paramsString = serializableState.searchParams.toString();\n * return serializableState.pathname + (paramsString ? `?${paramsString}` : \"\");\n * },\n * })\n * ```\n */\nexport const createSchema = <\n\tState = never,\n\tSerialized = never,\n\tSerializableState = State,\n>(\n\ttemplate: Omit<Schema<State, Serialized, SerializableState>, \"parserialize\">,\n): Schema<State, Serialized, SerializableState> => ({\n\t...template,\n\n\tparserialize: (value, next) => {\n\t\treturn template.serialize(next(template.parse(value)));\n\t},\n});\n","import type { Schema } from \"./schema\";\nimport { createSchema } from \"./schema\";\n\nexport type StringSchema<State = never, SerializableState = State> = {\n\tparse: Schema<State, string, SerializableState>[\"parse\"];\n\tstringify: Schema<State, string, SerializableState>[\"serialize\"];\n\tparseStringify: Schema<State, string, SerializableState>[\"parserialize\"];\n};\n\n/**\n * Helper function to create a `StringSchema` which converts between strings and state objects.\n *\n * The template requires two functions:\n * - `parse`: A function that takes a string and returns the corresponding state object.\n * - `stringify`: A function that takes a state object and returns a string that represents the given state.\n */\nexport const createStringSchema = <State = never, SerializableState = State>(\n\ttemplate: Omit<StringSchema<State, SerializableState>, \"parseStringify\">,\n): StringSchema<State, SerializableState> => {\n\tconst schema = createSchema<State, string, SerializableState>({\n\t\tserialize: template.stringify,\n\t\tparse: template.parse,\n\t});\n\n\treturn {\n\t\tparse: schema.parse,\n\t\tstringify: schema.serialize,\n\t\tparseStringify: schema.parserialize,\n\t};\n};\n","import { createStringSchema } from \"./string-schema\";\n\n/**\n * Utility schema for parsing and stringifying href strings into structured state objects that include the pathname and URL search parameters.\n *\n * @example\n * ```ts\n * import { createSchema, hrefSchema } from \"@buildinams/core/schema\";\n *\n * const myHrefSchema = createSchema<{\n * page: number,\n * // Used to compute next href - don't use directly. Use `.stringify()` instead\n * _href: string\n * }>({\n * parse: (href) => {\n * const { searchParams } = hrefSchema.parse(href);\n * return {\n * page: parseInt(searchParams.get(\"page\") || \"1\", 10),\n * _href: href,\n * }\n * },\n * serialize: (state) => {\n * const { pathname, searchParams } = hrefSchema.parse(state._href);\n * searchParams.delete(\"page\");\n * if (state.page > 1) {\n * searchParams.set(\"page\", state.page.toString());\n * }\n *\n * // note that `searchParams` are optional for serialization\n * return hrefSchema.stringify({ pathname, searchParams });\n * }\n * });\n * ```\n */\nexport const hrefSchema = createStringSchema<\n\t{\n\t\tpathname: string;\n\t\tsearchParams: URLSearchParams;\n\t},\n\t{\n\t\tpathname: string;\n\t\tsearchParams?: URLSearchParams;\n\t}\n>({\n\tparse: (href) => {\n\t\tconst [pathname = \"\", search = \"\"] = href.split(\"?\");\n\t\treturn {\n\t\t\tpathname,\n\t\t\tsearchParams: new URLSearchParams(search),\n\t\t};\n\t},\n\tstringify: (state) => {\n\t\tif (!state.searchParams) return state.pathname;\n\t\tconst paramsString = state.searchParams.toString();\n\t\treturn state.pathname + (paramsString ? `?${paramsString}` : \"\");\n\t},\n});\n"]}
|
|
@@ -1,33 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
* - `parse`: A function that takes an href string and returns the corresponding state object.
|
|
7
|
-
* - `stringify`: A function that takes a state object and the current href, and returns a new href string that represents the given state.
|
|
8
|
-
* - `parseStringify`: A function that takes a current href and a mutation function, and returns a new href string that represents the mutated state.
|
|
9
|
-
*
|
|
10
|
-
* This schema is used to map application state to URL hrefs and vice versa.
|
|
11
|
-
*/
|
|
12
|
-
type HrefSchema<State = any> = {
|
|
1
|
+
import { S as Schema } from '../schema-CfQvhbuU.js';
|
|
2
|
+
|
|
3
|
+
/** @deprecated use `Schema` directly */
|
|
4
|
+
type HrefSchema<State = never> = {
|
|
13
5
|
/** Parse a href string into the state shape */
|
|
14
|
-
parse:
|
|
6
|
+
parse: Schema<State & {
|
|
15
7
|
href: string;
|
|
16
|
-
};
|
|
17
|
-
/** Stringify a state shape
|
|
18
|
-
stringify:
|
|
8
|
+
}, string>["parse"];
|
|
9
|
+
/** Stringify a state shape into a href string */
|
|
10
|
+
stringify: Schema<State & {
|
|
11
|
+
href: string;
|
|
12
|
+
}, string>["serialize"];
|
|
13
|
+
/** Compute a new href string based on a given href string and a reducer of the current state. */
|
|
14
|
+
parseStringify: Schema<State & {
|
|
19
15
|
href: string;
|
|
20
|
-
}
|
|
21
|
-
/** Compute a new href string based on a given href and a mutation of the current state. */
|
|
22
|
-
parseStringify: (href: string, mutate: (state: State) => State) => string;
|
|
23
|
-
/**
|
|
24
|
-
* @internal
|
|
25
|
-
*/
|
|
26
|
-
_template: HrefSchemaTemplate<State>;
|
|
16
|
+
}, string>["parserialize"];
|
|
27
17
|
};
|
|
28
|
-
/**
|
|
29
|
-
* A utility type to extract the state shape from a given `HrefSchema`. It infers the state type from the `HrefSchema` and adds the `href` property to it.
|
|
30
|
-
*/
|
|
18
|
+
/** @deprecated use `SchemaState` directly */
|
|
31
19
|
type HrefSchemaState<T extends HrefSchema> = T extends HrefSchema<infer U> ? U & {
|
|
32
20
|
href: string;
|
|
33
21
|
} : never;
|
|
@@ -39,6 +27,38 @@ type HrefSchemaState<T extends HrefSchema> = T extends HrefSchema<infer U> ? U &
|
|
|
39
27
|
* - `stateToUrl`: A function that takes a state object and the current URL, and returns a new URL object that represents the given state.
|
|
40
28
|
*
|
|
41
29
|
* This allows you to focus on the logic for how your application's state maps to the URL structure without having to manually handle the parsing and stringifying of hrefs.
|
|
30
|
+
*
|
|
31
|
+
* @deprecated The `createHrefSchema` function is deprecated in favor of using the more flexible `createStringSchema` function directly with custom parsing and stringifying logic. The `createStringSchema` function can be used to achieve the same functionality without being tied specifically to hrefs, allowing for greater reuse and adaptability in different contexts.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { createHrefSchema } from "@buildinams/core/schema";
|
|
36
|
+
*
|
|
37
|
+
* const myHrefSchema = createHrefSchema<{
|
|
38
|
+
* page: number,
|
|
39
|
+
* }>({
|
|
40
|
+
* urlToState: (url) => {
|
|
41
|
+
* return {
|
|
42
|
+
* page: parseInt(url.searchParams.get("page") || "1", 10),
|
|
43
|
+
* }
|
|
44
|
+
* },
|
|
45
|
+
* stateToUrl: (state, url) => {
|
|
46
|
+
* url.searchParams.delete("page");
|
|
47
|
+
* if (state.page > 1) {
|
|
48
|
+
* url.searchParams.set("page", state.page.toString());
|
|
49
|
+
* }
|
|
50
|
+
* return url;
|
|
51
|
+
* }
|
|
52
|
+
* });
|
|
53
|
+
*
|
|
54
|
+
* // Using the schema to parse a href string into state
|
|
55
|
+
* const state = myHrefSchema.parse("/products?page=2");
|
|
56
|
+
* console.log(state); // { page: 2, href: "/products?page=2" }
|
|
57
|
+
*
|
|
58
|
+
* // Using the schema to stringify a state object into a href string
|
|
59
|
+
* const href = myHrefSchema.stringify({ page: 3, href: "/products?page=2" });
|
|
60
|
+
* console.log(href); // "/products?page=3"
|
|
61
|
+
* ```
|
|
42
62
|
*/
|
|
43
63
|
declare const createHrefSchema: <T>(template: HrefSchemaTemplate<T>) => HrefSchema<T>;
|
|
44
64
|
type HrefSchemaTemplate<State = never> = {
|
package/dist/navigation/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { createStringSchema } from '../chunk-5KDGGGVO.js';
|
|
2
|
+
|
|
1
3
|
// src/navigation/href-schema.ts
|
|
2
4
|
var hrefToUrl = (href) => new URL(href, "http://localhost");
|
|
3
|
-
var createHrefSchema = (template) => ({
|
|
4
|
-
_template: template,
|
|
5
|
+
var createHrefSchema = (template) => createStringSchema({
|
|
5
6
|
stringify: (state) => {
|
|
6
7
|
const current = hrefToUrl(state.href);
|
|
7
8
|
const next = template.stateToUrl(state, current);
|
|
@@ -13,14 +14,6 @@ var createHrefSchema = (template) => ({
|
|
|
13
14
|
...template.urlToState(current),
|
|
14
15
|
href: current.pathname + current.search
|
|
15
16
|
};
|
|
16
|
-
},
|
|
17
|
-
parseStringify: (href, mutate) => {
|
|
18
|
-
const current = hrefToUrl(href);
|
|
19
|
-
const next = template.stateToUrl(
|
|
20
|
-
mutate(template.urlToState(current)),
|
|
21
|
-
current
|
|
22
|
-
);
|
|
23
|
-
return next.pathname + next.search;
|
|
24
17
|
}
|
|
25
18
|
});
|
|
26
19
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/navigation/href-schema.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/navigation/href-schema.ts"],"names":[],"mappings":";;;AAMA,IAAM,YAAY,CAAC,IAAA,KAAiB,IAAI,GAAA,CAAI,MAAM,kBAAkB,CAAA;AAyD7D,IAAM,gBAAA,GAAmB,CAC/B,QAAA,KAEA,kBAAA,CAAyC;AAAA,EACxC,SAAA,EAAW,CAAC,KAAA,KAAU;AACrB,IAAA,MAAM,OAAA,GAAU,SAAA,CAAU,KAAA,CAAM,IAAI,CAAA;AACpC,IAAA,MAAM,IAAA,GAAO,QAAA,CAAS,UAAA,CAAW,KAAA,EAAO,OAAO,CAAA;AAC/C,IAAA,OAAO,IAAA,CAAK,WAAW,IAAA,CAAK,MAAA;AAAA,EAC7B,CAAA;AAAA,EAEA,KAAA,EAAO,CAAC,IAAA,KAAS;AAChB,IAAA,MAAM,OAAA,GAAU,UAAU,IAAI,CAAA;AAC9B,IAAA,OAAO;AAAA,MACN,GAAG,QAAA,CAAS,UAAA,CAAW,OAAO,CAAA;AAAA,MAC9B,IAAA,EAAM,OAAA,CAAQ,QAAA,GAAW,OAAA,CAAQ;AAAA,KAClC;AAAA,EACD;AACD,CAAC","file":"index.js","sourcesContent":["// This is fine as we only use the `pathname` an `search` properties from the URL object,\n\nimport type { Schema } from \"../schema\";\nimport { createStringSchema } from \"../schema\";\n\n// which do not contain the \"https://localhost\" origin.\nconst hrefToUrl = (href: string) => new URL(href, \"http://localhost\");\n\n/** @deprecated use `Schema` directly */\nexport type HrefSchema<State = never> = {\n\t/** Parse a href string into the state shape */\n\tparse: Schema<State & { href: string }, string>[\"parse\"];\n\t/** Stringify a state shape into a href string */\n\tstringify: Schema<State & { href: string }, string>[\"serialize\"];\n\t/** Compute a new href string based on a given href string and a reducer of the current state. */\n\tparseStringify: Schema<State & { href: string }, string>[\"parserialize\"];\n};\n\n/** @deprecated use `SchemaState` directly */\nexport type HrefSchemaState<T extends HrefSchema> =\n\tT extends HrefSchema<infer U> ? U & { href: string } : never;\n\n/**\n * Helper function to create a `HrefSchema` from a simpler template that only requires the logic for converting between URLs and state objects. The `createSchema` function takes care of implementing the `parse`, `stringify`, and `parseStringify` methods based on the provided template functions.\n *\n * The template requires two functions:\n * - `urlToState`: A function that takes a URL object and returns the corresponding state object.\n * - `stateToUrl`: A function that takes a state object and the current URL, and returns a new URL object that represents the given state.\n *\n * This allows you to focus on the logic for how your application's state maps to the URL structure without having to manually handle the parsing and stringifying of hrefs.\n *\n * @deprecated The `createHrefSchema` function is deprecated in favor of using the more flexible `createStringSchema` function directly with custom parsing and stringifying logic. The `createStringSchema` function can be used to achieve the same functionality without being tied specifically to hrefs, allowing for greater reuse and adaptability in different contexts.\n *\n * @example\n * ```ts\n * import { createHrefSchema } from \"@buildinams/core/schema\";\n *\n * const myHrefSchema = createHrefSchema<{\n * page: number,\n * }>({\n * urlToState: (url) => {\n * return {\n * page: parseInt(url.searchParams.get(\"page\") || \"1\", 10),\n * }\n * },\n * stateToUrl: (state, url) => {\n * url.searchParams.delete(\"page\");\n * if (state.page > 1) {\n * url.searchParams.set(\"page\", state.page.toString());\n * }\n * return url;\n * }\n * });\n *\n * // Using the schema to parse a href string into state\n * const state = myHrefSchema.parse(\"/products?page=2\");\n * console.log(state); // { page: 2, href: \"/products?page=2\" }\n *\n * // Using the schema to stringify a state object into a href string\n * const href = myHrefSchema.stringify({ page: 3, href: \"/products?page=2\" });\n * console.log(href); // \"/products?page=3\"\n * ```\n */\nexport const createHrefSchema = <T>(\n\ttemplate: HrefSchemaTemplate<T>,\n): HrefSchema<T> =>\n\tcreateStringSchema<T & { href: string }>({\n\t\tstringify: (state) => {\n\t\t\tconst current = hrefToUrl(state.href);\n\t\t\tconst next = template.stateToUrl(state, current);\n\t\t\treturn next.pathname + next.search;\n\t\t},\n\n\t\tparse: (href) => {\n\t\t\tconst current = hrefToUrl(href);\n\t\t\treturn {\n\t\t\t\t...template.urlToState(current),\n\t\t\t\thref: current.pathname + current.search,\n\t\t\t};\n\t\t},\n\t});\n\ntype HrefSchemaTemplate<State = never> = {\n\t/** Parse a href string into the state shape */\n\turlToState: (url: URL) => State;\n\t/** Stringify a state shape and current href into a new href string */\n\tstateToUrl: (state: State, url: URL) => URL;\n};\n"]}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { S as Schema } from '../schema-CfQvhbuU.js';
|
|
2
|
+
export { c as SchemaSerializableState, b as SchemaSerialized, a as SchemaState, d as createSchema } from '../schema-CfQvhbuU.js';
|
|
3
|
+
|
|
4
|
+
type StringSchema<State = never, SerializableState = State> = {
|
|
5
|
+
parse: Schema<State, string, SerializableState>["parse"];
|
|
6
|
+
stringify: Schema<State, string, SerializableState>["serialize"];
|
|
7
|
+
parseStringify: Schema<State, string, SerializableState>["parserialize"];
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Helper function to create a `StringSchema` which converts between strings and state objects.
|
|
11
|
+
*
|
|
12
|
+
* The template requires two functions:
|
|
13
|
+
* - `parse`: A function that takes a string and returns the corresponding state object.
|
|
14
|
+
* - `stringify`: A function that takes a state object and returns a string that represents the given state.
|
|
15
|
+
*/
|
|
16
|
+
declare const createStringSchema: <State = never, SerializableState = State>(template: Omit<StringSchema<State, SerializableState>, "parseStringify">) => StringSchema<State, SerializableState>;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Utility schema for parsing and stringifying href strings into structured state objects that include the pathname and URL search parameters.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { createSchema, hrefSchema } from "@buildinams/core/schema";
|
|
24
|
+
*
|
|
25
|
+
* const myHrefSchema = createSchema<{
|
|
26
|
+
* page: number,
|
|
27
|
+
* // Used to compute next href - don't use directly. Use `.stringify()` instead
|
|
28
|
+
* _href: string
|
|
29
|
+
* }>({
|
|
30
|
+
* parse: (href) => {
|
|
31
|
+
* const { searchParams } = hrefSchema.parse(href);
|
|
32
|
+
* return {
|
|
33
|
+
* page: parseInt(searchParams.get("page") || "1", 10),
|
|
34
|
+
* _href: href,
|
|
35
|
+
* }
|
|
36
|
+
* },
|
|
37
|
+
* serialize: (state) => {
|
|
38
|
+
* const { pathname, searchParams } = hrefSchema.parse(state._href);
|
|
39
|
+
* searchParams.delete("page");
|
|
40
|
+
* if (state.page > 1) {
|
|
41
|
+
* searchParams.set("page", state.page.toString());
|
|
42
|
+
* }
|
|
43
|
+
*
|
|
44
|
+
* // note that `searchParams` are optional for serialization
|
|
45
|
+
* return hrefSchema.stringify({ pathname, searchParams });
|
|
46
|
+
* }
|
|
47
|
+
* });
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
declare const hrefSchema: StringSchema<{
|
|
51
|
+
pathname: string;
|
|
52
|
+
searchParams: URLSearchParams;
|
|
53
|
+
}, {
|
|
54
|
+
pathname: string;
|
|
55
|
+
searchParams?: URLSearchParams;
|
|
56
|
+
}>;
|
|
57
|
+
|
|
58
|
+
export { Schema, type StringSchema, createStringSchema, hrefSchema };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Defines the schema for parsing and stringifying states to and from primitive values.
|
|
3
|
+
*
|
|
4
|
+
* The `Schema` type is a generic type that takes:
|
|
5
|
+
* - `State`: A state object type.
|
|
6
|
+
* - `Serialized`: The raw value type
|
|
7
|
+
* - `SerializableState?`: (optional) A (partial) state object type that can be used for serialization. Defaults to `State` if not provided.
|
|
8
|
+
*
|
|
9
|
+
* It returns the following methods:
|
|
10
|
+
* - `parse`: A function that takes a raw value and returns the corresponding state object.
|
|
11
|
+
* - `serialize`: A function that takes a (serializable) state object and returns a raw value that represents the given state.
|
|
12
|
+
* - `parserialize`: A function that takes a raw value and a reducer function - it returns a new raw value that represents the reduced state.
|
|
13
|
+
*
|
|
14
|
+
* @see createSchema for a helper function to create a `Schema` from simpler parsing and serializing functions.
|
|
15
|
+
*/
|
|
16
|
+
type Schema<State = any, Serialized = any, SerializableState = State> = {
|
|
17
|
+
/** Parse a raw value into the state shape */
|
|
18
|
+
parse: (value: Serialized) => State;
|
|
19
|
+
/** Serialize a state shape into a raw value */
|
|
20
|
+
serialize: (state: SerializableState) => Serialized;
|
|
21
|
+
/** Compute a new serialized value based on a given serialized value and a reducer of the current state. */
|
|
22
|
+
parserialize: (value: Serialized, next: (state: State) => SerializableState) => Serialized;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* A utility type to extract the state shape from a given `Schema`.
|
|
26
|
+
*/
|
|
27
|
+
type SchemaState<T extends Schema> = T extends Schema<infer U> ? U : never;
|
|
28
|
+
/**
|
|
29
|
+
* A utility type to extract the serialized value type from a given `Schema`.
|
|
30
|
+
*/
|
|
31
|
+
type SchemaSerialized<T extends Schema> = T extends Schema<any, infer U> ? U : never;
|
|
32
|
+
/**
|
|
33
|
+
* A utility type to extract the serializable state shape from a given `Schema`.
|
|
34
|
+
*/
|
|
35
|
+
type SchemaSerializableState<T extends Schema> = T extends Schema<any, any, infer U> ? U : never;
|
|
36
|
+
/**
|
|
37
|
+
* Low-level helper function to create a basic `Schema` that receives the config for converting between serialized values and state objects.
|
|
38
|
+
*
|
|
39
|
+
* The template requires two methods:
|
|
40
|
+
* - `parse`: A method that takes a serialized value and returns the corresponding state object.
|
|
41
|
+
* - `serialize`: A method that takes a state object and returns a serialized value that represents the given state.
|
|
42
|
+
*
|
|
43
|
+
* The `parserialize` method is automatically implemented based on the provided `parse` and `serialize` methods, allowing you to compute a new serialized value based on an existing serialized value and a reducer function for the state.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* import { createSchema } from "@buildinams/core/schema";
|
|
48
|
+
*
|
|
49
|
+
* const numberSchema = createSchema<
|
|
50
|
+
* number, // State
|
|
51
|
+
* string // Serialized
|
|
52
|
+
* >({
|
|
53
|
+
* parse: (value) => parseInt(value, 10),
|
|
54
|
+
* serialize: (state) => state.toString(),
|
|
55
|
+
* });
|
|
56
|
+
*
|
|
57
|
+
* const result = numberSchema.parserialize("42", (state) => state + 1);
|
|
58
|
+
* console.log(result); // "43"
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* import { createSchema } from "@buildinams/core/schema";
|
|
64
|
+
*
|
|
65
|
+
* const hrefSchema: createSchema<
|
|
66
|
+
* { pathname: string, searchParams: URLSearchParams },
|
|
67
|
+
* string,
|
|
68
|
+
* { pathname: string, searchParams?: URLSearchParams } // SerializableState allows to define different state used for serialization, in this case making searchParams optional to allow for more flexible stringification logic
|
|
69
|
+
* >({
|
|
70
|
+
* parse: (href) => {
|
|
71
|
+
* const [pathname = "", search = ""] = href.split("?");
|
|
72
|
+
* return {
|
|
73
|
+
* pathname,
|
|
74
|
+
* searchParams: new URLSearchParams(search),
|
|
75
|
+
* };
|
|
76
|
+
* },
|
|
77
|
+
* serialize: (serializableState) => {
|
|
78
|
+
* if (!serializableState.searchParams) return serializableState.pathname;
|
|
79
|
+
* const paramsString = serializableState.searchParams.toString();
|
|
80
|
+
* return serializableState.pathname + (paramsString ? `?${paramsString}` : "");
|
|
81
|
+
* },
|
|
82
|
+
* })
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
declare const createSchema: <State = never, Serialized = never, SerializableState = State>(template: Omit<Schema<State, Serialized, SerializableState>, "parserialize">) => Schema<State, Serialized, SerializableState>;
|
|
86
|
+
|
|
87
|
+
export { type Schema as S, type SchemaState as a, type SchemaSerialized as b, type SchemaSerializableState as c, createSchema as d };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buildinams/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "Build in Amsterdam <development@buildinamsterdam.com> (https://www.buildinamsterdam.com/)",
|
|
6
6
|
"repository": {
|
|
@@ -29,6 +29,10 @@
|
|
|
29
29
|
"types": "./dist/navigation/index.d.ts",
|
|
30
30
|
"default": "./dist/navigation/index.js"
|
|
31
31
|
},
|
|
32
|
+
"./schema": {
|
|
33
|
+
"types": "./dist/schema/index.d.ts",
|
|
34
|
+
"default": "./dist/schema/index.js"
|
|
35
|
+
},
|
|
32
36
|
"./store": {
|
|
33
37
|
"types": "./dist/store/index.d.ts",
|
|
34
38
|
"default": "./dist/store/index.js"
|
|
@@ -42,6 +46,9 @@
|
|
|
42
46
|
"./navigation": [
|
|
43
47
|
"./dist/navigation/index.d.ts"
|
|
44
48
|
],
|
|
49
|
+
"./schema": [
|
|
50
|
+
"./dist/schema/index.d.ts"
|
|
51
|
+
],
|
|
45
52
|
"./store": [
|
|
46
53
|
"./dist/store/index.d.ts"
|
|
47
54
|
]
|
|
@@ -52,7 +59,7 @@
|
|
|
52
59
|
"README.md"
|
|
53
60
|
],
|
|
54
61
|
"publishConfig": {
|
|
55
|
-
"registry": "https://
|
|
62
|
+
"registry": "https://registry.npmjs.org",
|
|
56
63
|
"access": "public"
|
|
57
64
|
},
|
|
58
65
|
"devDependencies": {
|