diff --git a/README.md b/README.md
index 0b28771..25ff36b 100644
--- a/README.md
+++ b/README.md
@@ -201,7 +201,7 @@ await navigation.navigate("/").finished;
Polyfill Global Window Types
See [`@types/dom-navigation`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/dom-navigation/package.json) for a standardised type definition for the Navigation API
-which can be utilised alongside this polyfill.
+which can be utilised alongside this polyfill.
```bash
yarn add --dev @types/dom-navigation
@@ -219,4 +219,39 @@ This should then be included as a type in your `tsconfig.json`:
}
```
+
+
+Polyfill Serializer
+
+You may want to set a custom serializer to store state in history
+
+The default serializer is [JSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON)
+
+In the past, a [structured clone like serializer](https://www.npmjs.com/package/@ungap/structured-clone) was used. This may be useful for you if
+you're using native types rather than just JSON compatible values.
+
+An example of making use of a custom serializer with the polyfill:
+
+```typescript
+import { setSerializer } from "@virtualstate/navigation/polyfill";
+import { serialize, deserialize } from "@ungap/structured-clone";
+
+setSerializer({
+ stringify(value) {
+ return serialize(value)
+ },
+ parse(value) {
+ return deserialize(value)
+ }
+});
+```
+
+
+
+## What's Changed
+
+Change Log
+
+- (1.0.1-alpha.x) Updated default serializer for polyfill to JSON [#35](https://github.com/virtualstate/navigation/pull/35)
+
\ No newline at end of file
diff --git a/example/polyfill-rollup.js b/example/polyfill-rollup.js
index c721aa6..2514db9 100644
--- a/example/polyfill-rollup.js
+++ b/example/polyfill-rollup.js
@@ -1,3 +1,7 @@
+'use strict';
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
let globalNavigation = undefined;
if (typeof window !== "undefined" && window.navigation) {
const navigation = window.navigation;
@@ -1756,25 +1760,15 @@ function getNavigation() {
return (navigation$1 = new Navigation());
}
-
-const getStructuredClone = () => json;
-
-async function getStructuredCloneModule() {
- const { stringify, parse } = await Promise.resolve().then(function () { return json; });
- return { stringify, parse };
+let GLOBAL_SERIALIZER = JSON;
+function setSerializer(serializer) {
+ GLOBAL_SERIALIZER = serializer;
}
-function structuredCloneFallback() {
- const stringify = JSON.stringify.bind(JSON), parse = JSON.parse.bind(JSON);
- return {
- stringify,
- parse
- };
+function stringify(value) {
+ return GLOBAL_SERIALIZER.stringify(value);
}
-function stringify$1(value) {
- return getStructuredClone().stringify(value);
-}
-function parse$1(value) {
- return getStructuredClone().parse(value);
+function parse(value) {
+ return GLOBAL_SERIALIZER.parse(value);
}
const AppLocationCheckChange = Symbol.for("@virtualstate/navigation/location/checkChange");
@@ -2095,7 +2089,7 @@ function setHistoryState(navigation, history, entry, persist, limit) {
if (typeof sessionStorage === "undefined")
return;
try {
- const raw = stringify$1(getSerializableState());
+ const raw = stringify(getSerializableState());
sessionStorage.setItem(entry.key, raw);
}
catch { }
@@ -2132,7 +2126,9 @@ function getHistoryState(history, entry) {
const raw = sessionStorage.getItem(entry.key);
if (!raw)
return undefined;
- const state = parse$1(raw);
+ const state = parse(raw);
+ if (!like(state))
+ return undefined;
if (!isStateHistoryWithMeta(state))
return undefined;
return state[NavigationKey].state;
@@ -2687,267 +2683,5 @@ if (shouldApplyPolyfill(navigation)) {
}
}
-const VOID = -1;
-const PRIMITIVE = 0;
-const ARRAY = 1;
-const OBJECT = 2;
-const DATE = 3;
-const REGEXP = 4;
-const MAP = 5;
-const SET = 6;
-const ERROR = 7;
-const BIGINT = 8;
-// export const SYMBOL = 9;
-
-const env = typeof self === 'object' ? self : globalThis;
-
-const deserializer = ($, _) => {
- const as = (out, index) => {
- $.set(index, out);
- return out;
- };
-
- const unpair = index => {
- if ($.has(index))
- return $.get(index);
-
- const [type, value] = _[index];
- switch (type) {
- case PRIMITIVE:
- case VOID:
- return as(value, index);
- case ARRAY: {
- const arr = as([], index);
- for (const index of value)
- arr.push(unpair(index));
- return arr;
- }
- case OBJECT: {
- const object = as({}, index);
- for (const [key, index] of value)
- object[unpair(key)] = unpair(index);
- return object;
- }
- case DATE:
- return as(new Date(value), index);
- case REGEXP: {
- const {source, flags} = value;
- return as(new RegExp(source, flags), index);
- }
- case MAP: {
- const map = as(new Map, index);
- for (const [key, index] of value)
- map.set(unpair(key), unpair(index));
- return map;
- }
- case SET: {
- const set = as(new Set, index);
- for (const index of value)
- set.add(unpair(index));
- return set;
- }
- case ERROR: {
- const {name, message} = value;
- return as(new env[name](message), index);
- }
- case BIGINT:
- return as(BigInt(value), index);
- case 'BigInt':
- return as(Object(BigInt(value)), index);
- }
- return as(new env[type](value), index);
- };
-
- return unpair;
-};
-
-/**
- * @typedef {Array} Record a type representation
- */
-
-/**
- * Returns a deserialized value from a serialized array of Records.
- * @param {Record[]} serialized a previously serialized value.
- * @returns {any}
- */
-const deserialize = serialized => deserializer(new Map, serialized)(0);
-
-const EMPTY = '';
-
-const {toString} = {};
-const {keys} = Object;
-
-const typeOf = value => {
- const type = typeof value;
- if (type !== 'object' || !value)
- return [PRIMITIVE, type];
-
- const asString = toString.call(value).slice(8, -1);
- switch (asString) {
- case 'Array':
- return [ARRAY, EMPTY];
- case 'Object':
- return [OBJECT, EMPTY];
- case 'Date':
- return [DATE, EMPTY];
- case 'RegExp':
- return [REGEXP, EMPTY];
- case 'Map':
- return [MAP, EMPTY];
- case 'Set':
- return [SET, EMPTY];
- }
-
- if (asString.includes('Array'))
- return [ARRAY, asString];
-
- if (asString.includes('Error'))
- return [ERROR, asString];
-
- return [OBJECT, asString];
-};
-
-const shouldSkip = ([TYPE, type]) => (
- TYPE === PRIMITIVE &&
- (type === 'function' || type === 'symbol')
-);
-
-const serializer = (strict, json, $, _) => {
-
- const as = (out, value) => {
- const index = _.push(out) - 1;
- $.set(value, index);
- return index;
- };
-
- const pair = value => {
- if ($.has(value))
- return $.get(value);
-
- let [TYPE, type] = typeOf(value);
- switch (TYPE) {
- case PRIMITIVE: {
- let entry = value;
- switch (type) {
- case 'bigint':
- TYPE = BIGINT;
- entry = value.toString();
- break;
- case 'function':
- case 'symbol':
- if (strict)
- throw new TypeError('unable to serialize ' + type);
- entry = null;
- break;
- case 'undefined':
- return as([VOID], value);
- }
- return as([TYPE, entry], value);
- }
- case ARRAY: {
- if (type)
- return as([type, [...value]], value);
-
- const arr = [];
- const index = as([TYPE, arr], value);
- for (const entry of value)
- arr.push(pair(entry));
- return index;
- }
- case OBJECT: {
- if (type) {
- switch (type) {
- case 'BigInt':
- return as([type, value.toString()], value);
- case 'Boolean':
- case 'Number':
- case 'String':
- return as([type, value.valueOf()], value);
- }
- }
-
- if (json && ('toJSON' in value))
- return pair(value.toJSON());
-
- const entries = [];
- const index = as([TYPE, entries], value);
- for (const key of keys(value)) {
- if (strict || !shouldSkip(typeOf(value[key])))
- entries.push([pair(key), pair(value[key])]);
- }
- return index;
- }
- case DATE:
- return as([TYPE, value.toISOString()], value);
- case REGEXP: {
- const {source, flags} = value;
- return as([TYPE, {source, flags}], value);
- }
- case MAP: {
- const entries = [];
- const index = as([TYPE, entries], value);
- for (const [key, entry] of value) {
- if (strict || !(shouldSkip(typeOf(key)) || shouldSkip(typeOf(entry))))
- entries.push([pair(key), pair(entry)]);
- }
- return index;
- }
- case SET: {
- const entries = [];
- const index = as([TYPE, entries], value);
- for (const entry of value) {
- if (strict || !shouldSkip(typeOf(entry)))
- entries.push(pair(entry));
- }
- return index;
- }
- }
-
- const {message} = value;
- return as([TYPE, {name: type, message}], value);
- };
-
- return pair;
-};
-
-/**
- * @typedef {Array} Record a type representation
- */
-
-/**
- * Returns an array of serialized Records.
- * @param {any} value a serializable value.
- * @param {{lossy?: boolean}?} options an object with a `lossy` property that,
- * if `true`, will not throw errors on incompatible types, and behave more
- * like JSON stringify would behave. Symbol and Function will be discarded.
- * @returns {Record[]}
- */
- const serialize = (value, {json, lossy} = {}) => {
- const _ = [];
- return serializer(!(json || lossy), !!json, new Map, _)(value), _;
-};
-
-/*! (c) Andrea Giammarchi - ISC */
-
-const {parse: $parse, stringify: $stringify} = JSON;
-const options = {json: true, lossy: true};
-
-/**
- * Revive a previously stringified structured clone.
- * @param {string} str previously stringified data as string.
- * @returns {any} whatever was previously stringified as clone.
- */
-const parse = str => deserialize($parse(str));
-
-/**
- * Represent a structured clone value as string.
- * @param {any} any some clone-able value to stringify.
- * @returns {string} the value stringified.
- */
-const stringify = any => $stringify(serialize(any, options));
-
-var json = /*#__PURE__*/Object.freeze({
- __proto__: null,
- parse: parse,
- stringify: stringify
-});
+exports.setSerializer = setSerializer;
+//# sourceMappingURL=polyfill-rollup.js.map
diff --git a/example/rollup.js b/example/rollup.js
index a1de8bb..e57e437 100644
--- a/example/rollup.js
+++ b/example/rollup.js
@@ -2016,27 +2016,15 @@ async function transition(navigation) {
return finalPromise;
}
-/** post rollup replace json **/
-const structuredClone = (await getStructuredCloneModule()
- .catch(structuredCloneFallback));
-const getStructuredClone = () => structuredClone;
-/** post rollup replace json **/
-async function getStructuredCloneModule() {
- const { stringify, parse } = await Promise.resolve().then(function () { return json; });
- return { stringify, parse };
-}
-function structuredCloneFallback() {
- const stringify = JSON.stringify.bind(JSON), parse = JSON.parse.bind(JSON);
- return {
- stringify,
- parse
- };
+let GLOBAL_SERIALIZER = JSON;
+function setSerializer(serializer) {
+ GLOBAL_SERIALIZER = serializer;
}
-function stringify$1(value) {
- return getStructuredClone().stringify(value);
+function stringify(value) {
+ return GLOBAL_SERIALIZER.stringify(value);
}
-function parse$1(value) {
- return getStructuredClone().parse(value);
+function parse(value) {
+ return GLOBAL_SERIALIZER.parse(value);
}
const globalWindow = typeof window === "undefined" ? undefined : window;
@@ -2098,7 +2086,7 @@ function setHistoryState(navigation, history, entry, persist, limit) {
if (typeof sessionStorage === "undefined")
return;
try {
- const raw = stringify$1(getSerializableState());
+ const raw = stringify(getSerializableState());
sessionStorage.setItem(entry.key, raw);
}
catch { }
@@ -2135,7 +2123,9 @@ function getHistoryState(history, entry) {
const raw = sessionStorage.getItem(entry.key);
if (!raw)
return undefined;
- const state = parse$1(raw);
+ const state = parse(raw);
+ if (!like(state))
+ return undefined;
if (!isStateHistoryWithMeta(state))
return undefined;
return state[NavigationKey].state;
@@ -2686,270 +2676,5 @@ function applyPolyfill(options = DEFAULT_POLYFILL_OPTIONS) {
return navigation;
}
-const VOID = -1;
-const PRIMITIVE = 0;
-const ARRAY = 1;
-const OBJECT = 2;
-const DATE = 3;
-const REGEXP = 4;
-const MAP = 5;
-const SET = 6;
-const ERROR = 7;
-const BIGINT = 8;
-// export const SYMBOL = 9;
-
-const env = typeof self === 'object' ? self : globalThis;
-
-const deserializer = ($, _) => {
- const as = (out, index) => {
- $.set(index, out);
- return out;
- };
-
- const unpair = index => {
- if ($.has(index))
- return $.get(index);
-
- const [type, value] = _[index];
- switch (type) {
- case PRIMITIVE:
- case VOID:
- return as(value, index);
- case ARRAY: {
- const arr = as([], index);
- for (const index of value)
- arr.push(unpair(index));
- return arr;
- }
- case OBJECT: {
- const object = as({}, index);
- for (const [key, index] of value)
- object[unpair(key)] = unpair(index);
- return object;
- }
- case DATE:
- return as(new Date(value), index);
- case REGEXP: {
- const {source, flags} = value;
- return as(new RegExp(source, flags), index);
- }
- case MAP: {
- const map = as(new Map, index);
- for (const [key, index] of value)
- map.set(unpair(key), unpair(index));
- return map;
- }
- case SET: {
- const set = as(new Set, index);
- for (const index of value)
- set.add(unpair(index));
- return set;
- }
- case ERROR: {
- const {name, message} = value;
- return as(new env[name](message), index);
- }
- case BIGINT:
- return as(BigInt(value), index);
- case 'BigInt':
- return as(Object(BigInt(value)), index);
- }
- return as(new env[type](value), index);
- };
-
- return unpair;
-};
-
-/**
- * @typedef {Array} Record a type representation
- */
-
-/**
- * Returns a deserialized value from a serialized array of Records.
- * @param {Record[]} serialized a previously serialized value.
- * @returns {any}
- */
-const deserialize = serialized => deserializer(new Map, serialized)(0);
-
-const EMPTY = '';
-
-const {toString} = {};
-const {keys} = Object;
-
-const typeOf = value => {
- const type = typeof value;
- if (type !== 'object' || !value)
- return [PRIMITIVE, type];
-
- const asString = toString.call(value).slice(8, -1);
- switch (asString) {
- case 'Array':
- return [ARRAY, EMPTY];
- case 'Object':
- return [OBJECT, EMPTY];
- case 'Date':
- return [DATE, EMPTY];
- case 'RegExp':
- return [REGEXP, EMPTY];
- case 'Map':
- return [MAP, EMPTY];
- case 'Set':
- return [SET, EMPTY];
- }
-
- if (asString.includes('Array'))
- return [ARRAY, asString];
-
- if (asString.includes('Error'))
- return [ERROR, asString];
-
- return [OBJECT, asString];
-};
-
-const shouldSkip = ([TYPE, type]) => (
- TYPE === PRIMITIVE &&
- (type === 'function' || type === 'symbol')
-);
-
-const serializer = (strict, json, $, _) => {
-
- const as = (out, value) => {
- const index = _.push(out) - 1;
- $.set(value, index);
- return index;
- };
-
- const pair = value => {
- if ($.has(value))
- return $.get(value);
-
- let [TYPE, type] = typeOf(value);
- switch (TYPE) {
- case PRIMITIVE: {
- let entry = value;
- switch (type) {
- case 'bigint':
- TYPE = BIGINT;
- entry = value.toString();
- break;
- case 'function':
- case 'symbol':
- if (strict)
- throw new TypeError('unable to serialize ' + type);
- entry = null;
- break;
- case 'undefined':
- return as([VOID], value);
- }
- return as([TYPE, entry], value);
- }
- case ARRAY: {
- if (type)
- return as([type, [...value]], value);
-
- const arr = [];
- const index = as([TYPE, arr], value);
- for (const entry of value)
- arr.push(pair(entry));
- return index;
- }
- case OBJECT: {
- if (type) {
- switch (type) {
- case 'BigInt':
- return as([type, value.toString()], value);
- case 'Boolean':
- case 'Number':
- case 'String':
- return as([type, value.valueOf()], value);
- }
- }
-
- if (json && ('toJSON' in value))
- return pair(value.toJSON());
-
- const entries = [];
- const index = as([TYPE, entries], value);
- for (const key of keys(value)) {
- if (strict || !shouldSkip(typeOf(value[key])))
- entries.push([pair(key), pair(value[key])]);
- }
- return index;
- }
- case DATE:
- return as([TYPE, value.toISOString()], value);
- case REGEXP: {
- const {source, flags} = value;
- return as([TYPE, {source, flags}], value);
- }
- case MAP: {
- const entries = [];
- const index = as([TYPE, entries], value);
- for (const [key, entry] of value) {
- if (strict || !(shouldSkip(typeOf(key)) || shouldSkip(typeOf(entry))))
- entries.push([pair(key), pair(entry)]);
- }
- return index;
- }
- case SET: {
- const entries = [];
- const index = as([TYPE, entries], value);
- for (const entry of value) {
- if (strict || !shouldSkip(typeOf(entry)))
- entries.push(pair(entry));
- }
- return index;
- }
- }
-
- const {message} = value;
- return as([TYPE, {name: type, message}], value);
- };
-
- return pair;
-};
-
-/**
- * @typedef {Array} Record a type representation
- */
-
-/**
- * Returns an array of serialized Records.
- * @param {any} value a serializable value.
- * @param {{lossy?: boolean}?} options an object with a `lossy` property that,
- * if `true`, will not throw errors on incompatible types, and behave more
- * like JSON stringify would behave. Symbol and Function will be discarded.
- * @returns {Record[]}
- */
- const serialize = (value, {json, lossy} = {}) => {
- const _ = [];
- return serializer(!(json || lossy), !!json, new Map, _)(value), _;
-};
-
-/*! (c) Andrea Giammarchi - ISC */
-
-const {parse: $parse, stringify: $stringify} = JSON;
-const options = {json: true, lossy: true};
-
-/**
- * Revive a previously stringified structured clone.
- * @param {string} str previously stringified data as string.
- * @returns {any} whatever was previously stringified as clone.
- */
-const parse = str => deserialize($parse(str));
-
-/**
- * Represent a structured clone value as string.
- * @param {any} any some clone-able value to stringify.
- * @returns {string} the value stringified.
- */
-const stringify = any => $stringify(serialize(any, options));
-
-var json = /*#__PURE__*/Object.freeze({
- __proto__: null,
- parse: parse,
- stringify: stringify
-});
-
-export { AppLocationAwaitFinished, AppLocationCheckChange, AppLocationTransitionURL, AppLocationUrl, EventTarget, NAVIGATION_LOCATION_DEFAULT_URL, Navigation, NavigationCanIntercept, NavigationCurrentEntryChangeEvent, NavigationDisposeState, NavigationFormData, NavigationGetState, NavigationHistory, NavigationLocation, NavigationSetCurrentIndex, NavigationSetCurrentKey, NavigationSetEntries, NavigationSetOptions, NavigationSetState, NavigationSync, NavigationTransitionFinally, NavigationUserInitiated, applyPolyfill, getCompletePolyfill, getPolyfill, isInterceptEvent, isNavigationNavigationType, transition };
+export { AppLocationAwaitFinished, AppLocationCheckChange, AppLocationTransitionURL, AppLocationUrl, EventTarget, NAVIGATION_LOCATION_DEFAULT_URL, Navigation, NavigationCanIntercept, NavigationCurrentEntryChangeEvent, NavigationDisposeState, NavigationFormData, NavigationGetState, NavigationHistory, NavigationLocation, NavigationSetCurrentIndex, NavigationSetCurrentKey, NavigationSetEntries, NavigationSetOptions, NavigationSetState, NavigationSync, NavigationTransitionFinally, NavigationUserInitiated, applyPolyfill, getCompletePolyfill, getPolyfill, isInterceptEvent, isNavigationNavigationType, setSerializer, transition };
//# sourceMappingURL=rollup.js.map
diff --git a/example/routes-rollup.js b/example/routes-rollup.js
index 27af1bb..f64940d 100644
--- a/example/routes-rollup.js
+++ b/example/routes-rollup.js
@@ -3724,3 +3724,4 @@ function routes(...args) {
}
export { Router, enableURLPatternCache, getRouter, getRouterRoutes, isRouter, route, routes, transitionEvent };
+//# sourceMappingURL=routes-rollup.js.map
diff --git a/import-map-deno.json b/import-map-deno.json
index dcc4169..98eee48 100644
--- a/import-map-deno.json
+++ b/import-map-deno.json
@@ -24,8 +24,6 @@
"@virtualstate/navigation-imported/event-target/sync": "./src/event-target/sync-event-target.ts",
"@virtualstate/navigation-imported/event-target/async": "./src/event-target/async-event-target.ts",
"@virtualstate/navigation-imported/event-target": "./src/event-target/sync-event-target.ts",
- "@ungap/structured-clone": "https://cdn.skypack.dev/@ungap/structured-clone",
- "@ungap/structured-clone/json": "https://cdn.skypack.dev/@ungap/structured-clone/json",
"dom-lite": "https://cdn.skypack.dev/dom-lite",
"iterable": "https://cdn.skypack.dev/iterable@6.0.1-beta.5",
"https://cdn.skypack.dev/-/iterable@v5.7.0-CNtyuMJo9f2zFu6CuB1D/dist=es2019,mode=imports/optimized/iterable.js": "https://cdn.skypack.dev/iterable@6.0.1-beta.5",
@@ -84,9 +82,9 @@
"./src/global-abort-controller": "./src/global-abort-controller.ts",
"./esnext/util/parse-dom-deno.js": "./src/util/parse-dom-deno.ts",
"./esnext/util/parse-dom.js": "./src/util/parse-dom-deno.ts",
- "./esnext/util/structured-json": "./src/util/structured-json.ts",
- "./esnext/util/structured-json.js": "./src/util/structured-json.ts",
- "./src/util/structured-json.js": "./src/util/structured-json.ts",
+ "./esnext/util/serialization": "./src/util/serialization.ts",
+ "./esnext/util/serialization.js": "./src/util/serialization.ts",
+ "./src/util/serialization.js": "./src/util/serialization.ts",
"./src/config": "./src/config.ts",
"./src/is": "./src/is.ts",
"./src/base-url": "./src/base-url.ts",
diff --git a/package.json b/package.json
index 6a62489..da8bdc6 100644
--- a/package.json
+++ b/package.json
@@ -55,7 +55,7 @@
"./esnext/polyfill": "./esnext/polyfill.js",
"./esnext/get-polyfill": "./esnext/get-polyfill.js",
"./esnext/apply-polyfill": "./esnext/apply-polyfill.js",
- "./esnext/util/structured-json": "./esnext/util/structured-json.js",
+ "./esnext/util/serialization": "./esnext/util/serialization.js",
"./polyfill": {
"require": "./esnext/polyfill-rollup.js",
"import": "./esnext/polyfill.js",
@@ -84,7 +84,6 @@
"author": "Fabian Cook ",
"license": "MIT",
"dependencies": {
- "@ungap/structured-clone": "^1.0.2",
"@virtualstate/composite-key": "^1.0.0"
},
"devDependencies": {
diff --git a/scripts/post-build.js b/scripts/post-build.js
index 2bec979..0e79687 100644
--- a/scripts/post-build.js
+++ b/scripts/post-build.js
@@ -37,12 +37,10 @@ const cwd = resolve(dirname(pathname), "..")
});
await bundle.write({
sourcemap: true,
- output: {
- file: "./esnext/tests/rollup.js",
- },
+ file: "./esnext/tests/rollup.js",
inlineDynamicImports: true,
- format: "cjs",
- interop: "auto",
+ format: "es",
+ interop: "esModule",
globals: {
"esnext/tests/navigation.playwright.js": "globalThis"
}
@@ -100,9 +98,7 @@ const cwd = resolve(dirname(pathname), "..")
});
await bundle.write({
sourcemap: true,
- output: {
- file: "./esnext/routes-rollup.js",
- },
+ file: "./esnext/routes-rollup.js",
inlineDynamicImports: true,
format: "esm",
interop: "auto",
@@ -137,15 +133,14 @@ const cwd = resolve(dirname(pathname), "..")
});
await bundle.write({
sourcemap: true,
- output: {
- file: "./esnext/polyfill-rollup.js",
- },
+ file: "./esnext/polyfill-rollup.js",
inlineDynamicImports: true,
format: "cjs",
- interop: "auto",
+ interop: "esModule",
globals: {
- }
+ },
+ exports: "auto"
});
}
@@ -213,43 +208,11 @@ if (!process.env.NO_COVERAGE_BADGE_UPDATE) {
{
- async function rollupReplacements(fileName) {
- let file = await fs.readFile(fileName, "utf-8");
-
- const importJsonMarker = "/** post rollup replace json **/";
-
- function replaceInsideMarkers(marker, replacement) {
- const startIndex = file.indexOf(marker),
- endIndex = file.lastIndexOf(marker) + marker.length;
-
- const fileStart = file.slice(0, startIndex - 1),
- fileEnd = file.slice(endIndex + 1);
-
- const replacing = file.slice(startIndex, endIndex);
-
- if (typeof replacement === "function") {
- replacement = replacement(replacing.replaceAll(marker, ""));
- }
-
- file = `${fileStart}\n\n${replacement}\n\n${fileEnd}`
- }
-
- replaceInsideMarkers(importJsonMarker, "const getStructuredClone = () => json;");
-
- await fs.writeFile(fileName, file);
- }
-
- await rollupReplacements("esnext/polyfill-rollup.js");
-
- await fs.cp("esnext/rollup.js", "esnext/rollup-input.cjs");
-
- await rollupReplacements("esnext/rollup-input.cjs");
-
{
const bundle = await rollup({
- input: "./esnext/rollup-input.cjs",
+ input: "./esnext/rollup.js",
plugins: [
ignore([
`${cwd}/esnext/tests/navigation.playwright.js`,
@@ -277,8 +240,6 @@ if (!process.env.NO_COVERAGE_BADGE_UPDATE) {
});
}
- await fs.rm("./esnext/rollup-input.cjs");
-
await fs.cp("esnext/polyfill-rollup.js", "example/polyfill-rollup.js");
await fs.cp("esnext/routes-rollup.js", "example/routes-rollup.js");
await fs.cp("esnext/rollup.js", "example/rollup.js");
diff --git a/src/get-polyfill.ts b/src/get-polyfill.ts
index 98e33df..2bcf008 100644
--- a/src/get-polyfill.ts
+++ b/src/get-polyfill.ts
@@ -7,7 +7,7 @@ import {
} from "./navigation";
import { InvalidStateError } from "./navigation-errors";
import { InternalNavigationNavigateOptions, NavigationDownloadRequest, NavigationFormData, NavigationOriginalEvent, NavigationUserInitiated } from "./create-navigation-transition";
-import { stringify, parse } from './util/structured-json';
+import { stringify, parse } from './util/serialization';
import {NavigationHistory} from "./history";
import {like, ok} from "./is";
import {
@@ -232,7 +232,8 @@ function getHistoryState(
const raw = sessionStorage.getItem(entry.key);
if (!raw) return undefined;
const state = parse(raw);
- if (!isStateHistoryWithMeta(state)) return undefined;
+ if (!like(state)) return undefined;
+ if (!isStateHistoryWithMeta(state)) return undefined;
return state[NavigationKey].state;
} catch {
return undefined;
diff --git a/src/index.ts b/src/index.ts
index d194b34..0aa469e 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -16,4 +16,5 @@ export {
NavigationCurrentEntryChangeEvent
} from "./events";
export { applyPolyfill } from "./apply-polyfill"
-export { getPolyfill, getCompletePolyfill } from "./get-polyfill";
\ No newline at end of file
+export { getPolyfill, getCompletePolyfill } from "./get-polyfill";
+export { setSerializer, Serializer } from "./util/serialization";
\ No newline at end of file
diff --git a/src/polyfill.ts b/src/polyfill.ts
index 5eb3f1d..7522630 100644
--- a/src/polyfill.ts
+++ b/src/polyfill.ts
@@ -1,5 +1,6 @@
import { getNavigation } from "./get-navigation";
import { applyPolyfill, shouldApplyPolyfill } from "./apply-polyfill";
+import { setSerializer } from "./util/serialization";
const navigation = getNavigation();
@@ -12,4 +13,8 @@ if (shouldApplyPolyfill(navigation)) {
console.error("Failed to apply polyfill");
console.error(error);
}
+}
+
+export {
+ setSerializer
}
\ No newline at end of file
diff --git a/src/tests/dependencies-input.ts b/src/tests/dependencies-input.ts
index 6446787..726c1f6 100644
--- a/src/tests/dependencies-input.ts
+++ b/src/tests/dependencies-input.ts
@@ -22,9 +22,7 @@ export const DefaultDependencies = [
"@virtualstate/composite-key",
"dom-lite",
"iterable",
- "urlpattern-polyfill",
- "@ungap/structured-clone",
- "@ungap/structured-clone/json"
+ "urlpattern-polyfill"
] as const;
export const DefaultImportMap = Object.fromEntries(
DefaultDependencies.filter(
diff --git a/src/types/structured-json.d.ts b/src/types/structured-json.d.ts
deleted file mode 100644
index 13f00c0..0000000
--- a/src/types/structured-json.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-declare module "@ungap/structured-clone/json" {
- export const stringify: (x: any) => string
- export const parse: (x: string) => any
-}
\ No newline at end of file
diff --git a/src/util/serialization.ts b/src/util/serialization.ts
new file mode 100644
index 0000000..4964476
--- /dev/null
+++ b/src/util/serialization.ts
@@ -0,0 +1,18 @@
+export interface Serializer {
+ stringify(value: unknown): string;
+ parse(value: string): unknown
+}
+
+let GLOBAL_SERIALIZER: Serializer = JSON;
+
+export function setSerializer(serializer: Serializer) {
+ GLOBAL_SERIALIZER = serializer;
+}
+
+export function stringify(value: unknown) {
+ return GLOBAL_SERIALIZER.stringify(value);
+}
+
+export function parse(value: string) {
+ return GLOBAL_SERIALIZER.parse(value);
+}
\ No newline at end of file
diff --git a/src/util/structured-json.ts b/src/util/structured-json.ts
deleted file mode 100644
index f214c4c..0000000
--- a/src/util/structured-json.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-
-/** post rollup replace json **/
-const structuredClone = (
- await getStructuredCloneModule()
- .catch(structuredCloneFallback)
-)
-const getStructuredClone = () => structuredClone
-/** post rollup replace json **/
-
-async function getStructuredCloneModule() {
- const { stringify, parse } = await import("@ungap/structured-clone/json")
- return { stringify, parse };
-}
-
-function structuredCloneFallback() {
- const stringify = JSON.stringify.bind(JSON),
- parse = JSON.parse.bind(JSON);
- return {
- stringify,
- parse
- };
-}
-
-export function stringify(value: unknown) {
- return getStructuredClone().stringify(value);
-}
-
-export function parse(value: string) {
- return getStructuredClone().parse(value);
-}
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index 2665320..591a841 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1088,11 +1088,6 @@
"@types/node" "*"
"@types/webidl-conversions" "*"
-"@ungap/structured-clone@^1.0.2":
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.0.2.tgz#112bd30f3c27cb4c7b85d59ee3918c13803238ad"
- integrity sha512-06PHwE0K24Wi8FBmC8MuMi/+nQ3DTpcXYL3y/IaZz2ScY2GOJXOe8fyMykVXyLOKxpL2Y0frAnJZmm65OxzMLQ==
-
"@virtualstate/composite-key@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@virtualstate/composite-key/-/composite-key-1.0.0.tgz#352b93df5b9199951cc370897bca8bb5b171a375"