@real-router/hash-plugin 0.7.3 → 0.7.4

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/cjs/index.js CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`@real-router/core/api`),t=require(`@real-router/core`);const n=()=>globalThis.window!==void 0&&!!globalThis.history,r=(e,t)=>{globalThis.history.pushState(e,``,t)},i=(e,t)=>{globalThis.history.replaceState(e,``,t)},a=e=>(globalThis.addEventListener(`popstate`,e),()=>{globalThis.removeEventListener(`popstate`,e)}),o=()=>globalThis.location.hash;function s(e){if(!e)return e;let t=e.replaceAll(/\/+/g,`/`);return t.startsWith(`/`)||(t=`/${t}`),t.length>1&&t.endsWith(`/`)&&(t=t.slice(0,-1)),t===`/`?``:t}const c=e=>{try{return encodeURI(decodeURI(e))}catch(t){return console.warn(`[browser-env] Could not encode path "${e}"`,t),e}},l=()=>{},u=e=>{let t=!1;return n=>{t||=(console.warn(`[browser-env] Browser API is running in a non-browser environment (context: "${e}"). Method "${n}" is a no-op. This is expected for SSR, but may indicate misconfiguration if you expected browser behavior.`),!0)}},d=e=>{let t=u(e);return{pushState:()=>{t(`pushState`)},replaceState:()=>{t(`replaceState`)},addPopstateListener:()=>(t(`addPopstateListener`),l),getHash:()=>(t(`getHash`),``)}},f=/^[A-Z_a-z][\w-]*(?:\.[A-Z_a-z][\w-]*)*$/;function p(e){return typeof e==`string`?e===``?!0:e.length>1e4?!1:e.startsWith(`@@`)?!0:f.test(e):!1}function m(e,t=new WeakSet){if(e==null)return!0;let n=typeof e;if(n===`string`||n===`boolean`)return!0;if(n===`number`)return Number.isFinite(e);if(n===`function`||n===`symbol`)return!1;if(Array.isArray(e))return t.has(e)?!1:(t.add(e),e.every(e=>m(e,t)));if(n===`object`){if(t.has(e))return!1;t.add(e);let n=Object.getPrototypeOf(e);return n!==null&&n!==Object.prototype?!1:Object.values(e).every(e=>m(e,t))}return!1}function h(e){if(e==null)return!0;let t=typeof e;return t===`string`||t===`boolean`?!0:t===`number`?Number.isFinite(e):!1}function g(e){if(typeof e!=`object`||!e||Array.isArray(e))return!1;let t=Object.getPrototypeOf(e);if(t!==null&&t!==Object.prototype)return!1;let n=!1;for(let t in e){if(!Object.hasOwn(e,t))continue;let r=e[t];if(!h(r)){let e=typeof r;if(e===`function`||e===`symbol`)return!1;n=!0;break}}return n?m(e):!0}function _(e){return p(e.name)&&typeof e.path==`string`&&g(e.params)}function v(e){return!(typeof e!=`object`||!e||!_(e))}function y(e,t,n){return v(e.state)?t.makeState(e.state.name,e.state.params,e.state.path):t.matchPath(n.getLocation())}function b(e,t,n,r){let i={name:e.name,params:e.params,path:e.path};n?r.replaceState(i,t):r.pushState(i,t)}function x(e,t,n){return r=>{if(r)for(let i of Object.keys(r)){if(!(i in e))continue;let a=r[i];if(a===void 0)continue;let o=typeof e[i],s=typeof a;if(s!==o)throw Error(`[${t}] Invalid type for '${i}': expected ${o}, got ${s}`);let c=n?.[i];if(c){let e=c.validate(a);if(e!==null)throw Error(`[${t}] Invalid '${i}': ${e}`)}}}}const S=/[\u0000-\u001F\u007F]/,C={validate:e=>S.test(e)?`must not contain control characters`:e.split(`/`).includes(`..`)?`must not contain '..' segments`:null},w={validate:e=>S.test(e)?`must not contain control characters`:e.includes(`/`)?`must not contain '/' (slash is added before the path automatically)`:e.includes(`#`)?`must not contain '#' (it is added as the hash delimiter)`:e.includes(`?`)?`must not contain '?' (it conflicts with the query delimiter)`:null};function T(e,t){if(n())return{pushState:r,replaceState:i,addPopstateListener:a,getLocation:e,getHash:o};let s=u(t);return{...d(t),getLocation:()=>(s(`getLocation`),``)}}function E(e,t){if(!e.getCurrentHash)return{};let n=e.getCurrentHash();return n!==(e.getCurrentContextHash?e.getCurrentContextHash():``)&&e.router.getState()?.path===t?{hash:n,force:!0,hashChange:!0}:{hash:n}}function D(e){let n=!1,r=null;function i(){if(r){let t=r;r=null,console.warn(`[${e.loggerContext}] Processing deferred popstate event`),s(t)}}function a(){let t=e.router.getState();if(!t)return;let n=t.context?.url?.hash,r=e.buildUrl(t.name,t.params,n?{hash:n}:void 0);e.browser.replaceState(t,r)}function o(t){console.error(`[${e.loggerContext}] Critical error in onPopState`,t);try{a()}catch(t){console.error(`[${e.loggerContext}] Failed to recover from critical error`,t)}}async function s(s){if(n){console.warn(`[${e.loggerContext}] Transition in progress, deferring popstate event`),r=s;return}n=!0;try{let n=y(s,e.api,e.browser);if(n)await e.api.navigateToState(n,{...e.transitionOptions,...E(e,n.path)});else if(e.allowNotFound)e.router.navigateToNotFound(e.browser.getLocation());else{let n=new t.RouterError(t.errorCodes.ROUTE_NOT_FOUND,{path:e.browser.getLocation()});e.api.emitTransitionError(n),a()}}catch(e){if(e instanceof t.RouterError)try{a()}catch{}else o(e)}finally{n=!1,i()}}return e=>void s(e)}function O(e){return{onStart:()=>{e.shared.removePopStateListener&&e.shared.removePopStateListener(),e.shared.removePopStateListener=e.browser.addPopstateListener(e.handler)},onStop:()=>{e.shared.removePopStateListener&&(e.shared.removePopStateListener(),e.shared.removePopStateListener=void 0)},teardown:()=>{e.shared.removePopStateListener&&(e.shared.removePopStateListener(),e.shared.removePopStateListener=void 0),e.cleanup()}}}function k(e){return encodeURI(e).replaceAll(`#`,`%23`)}function A(e){try{return decodeURIComponent(e)}catch{return e}}function j(e){let t=e;for(;t.startsWith(`#`);)t=t.slice(1);return A(t)}function M(e){let t=e,n=t.indexOf(`://`);if(n!==-1){let e=n+3,r=t.length;for(let n=e;n<t.length;n++){let e=t[n];if(e===`/`||e===`?`||e===`#`){r=n;break}}t=r===t.length?`/`:t.slice(r),(t.startsWith(`?`)||t.startsWith(`#`))&&(t=`/${t}`)}let r=t.indexOf(`#`),i=r===-1?``:t.slice(r),a=r===-1?t:t.slice(0,r),o=a.indexOf(`?`),s=o===-1?``:a.slice(o);return{pathname:o===-1?a:a.slice(0,o),search:s,hash:i}}function N(e,t){return e.addInterceptor(`start`,(e,n)=>e(n??t.getLocation()))}function P(e,t,n,r,i=!0){let a={name:``,params:{},path:``};return(o,s={},c)=>{let l=e.buildState(o,s);if(!l)throw Error(`[real-router] Cannot replace state: route "${o}" is not found`);let u=e.makeState(l.name,l.params,t.buildPath(l.name,l.params),{params:l.meta}),d;if(c?.hash!==void 0){let e=j(c.hash);d=e?`#${k(e)}`:``}else d=i?n.getHash():``;let f=r(o,s)+d;a.name=u.name,a.params=u.params,a.path=u.path,n.replaceState(a,f)}}function F(e,t,n){return e.replace===!0?!0:n?!!e.reload&&t.path===n.path:e.replace!==!1}const I={hashPrefix:``,base:``,forceDeactivate:!0},L=`hash-plugin`;function R(e){return e.replaceAll(/[$()*+.?[\\\]^{|}-]/g,String.raw`\$&`)}function z(e){return e?RegExp(`^#${R(e)}`):null}function B(e,t){return e===``||e===`#`?`/`:(t?e.replace(t,``):e.slice(1))||`/`}function V(e,t){let n=M(e),r=B(n.hash,t);return r.includes(`?`)?r:r+n.search}function H(e,t,n){let r=c(B(e,n));return r.includes(`?`)?r:r+t}var U=class{#e;#t;#n;#r;#i;#a;constructor(e,t,n,r,i,a,o){this.#e=e,this.#t=r,this.#n=N(t,r);let s=!1,c=()=>{s||(s=!0,console.warn("[@real-router/hash-plugin] `hash` option is ignored — `#` is reserved for the route delimiter. URL fragments are not supported with hash-plugin; use @real-router/browser-plugin or @real-router/navigation-plugin if you need them."))},l=`${n.base}#${n.hashPrefix}`,u=(t,n,r)=>(r?.hash!==void 0&&c(),l+e.buildPath(t,n));this.#a=c,this.#r=t.extendRouter({buildUrl:u,matchUrl:e=>t.matchPath(V(e,i))??void 0,replaceHistoryState:P(t,e,r,u,!1)});let d=D({router:e,api:t,browser:r,allowNotFound:t.getOptions().allowNotFound,transitionOptions:a,loggerContext:L,buildUrl:u});this.#i=O({browser:r,shared:o,handler:d,cleanup:()=>{this.#n(),this.#r()}})}getPlugin(){return{...this.#i,onTransitionSuccess:(e,t,n)=>{n.hash!==void 0&&this.#a();let r=F(n,e,t);b(e,this.#e.buildUrl(e.name,e.params),r,this.#t)}}}};const W=x(I,L,{base:C,hashPrefix:w});function G(t,n){W(t);let r=t?Object.fromEntries(Object.entries(t).filter(([,e])=>e!==void 0)):{},i={...I,...r};i.base=s(i.base);let a=z(i.hashPrefix),o=n??T(()=>H(globalThis.location.hash,globalThis.location.search,a),`hash-plugin`),c={forceDeactivate:i.forceDeactivate,source:`popstate`,replace:!0},l={removePopStateListener:void 0};return function(t){return new U(t,(0,e.getPluginApi)(t),i,o,a,c,l).getPlugin()}}exports.hashPluginFactory=G,exports.isState=v;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@real-router/core/api"),t=require("@real-router/core");const n=()=>globalThis.window!==void 0&&!!globalThis.history,r=(e,t)=>{globalThis.history.pushState(e,``,t)},i=(e,t)=>{globalThis.history.replaceState(e,``,t)},a=e=>(globalThis.addEventListener(`popstate`,e),()=>{globalThis.removeEventListener(`popstate`,e)}),o=()=>globalThis.location.hash;function s(e){if(!e)return e;let t=e.replaceAll(/\/+/g,`/`);return t.startsWith(`/`)||(t=`/${t}`),t.length>1&&t.endsWith(`/`)&&(t=t.slice(0,-1)),t===`/`?``:t}const c=e=>{try{return encodeURI(decodeURI(e))}catch(t){return console.warn(`[browser-env] Could not encode path "${e}"`,t),e}},l=()=>{},u=e=>{let t=!1;return n=>{t||=(console.warn(`[browser-env] Browser API is running in a non-browser environment (context: "${e}"). Method "${n}" is a no-op. This is expected for SSR, but may indicate misconfiguration if you expected browser behavior.`),!0)}},d=e=>{let t=u(e);return{pushState:()=>{t(`pushState`)},replaceState:()=>{t(`replaceState`)},addPopstateListener:()=>(t(`addPopstateListener`),l),getHash:()=>(t(`getHash`),``)}},f=/^[A-Z_a-z][\w-]*(?:\.[A-Z_a-z][\w-]*)*$/;function p(e){return typeof e==`string`?e===``?!0:e.length>1e4?!1:e.startsWith(`@@`)?!0:f.test(e):!1}function m(e,t=new WeakSet){if(e==null)return!0;let n=typeof e;if(n===`string`||n===`boolean`)return!0;if(n===`number`)return Number.isFinite(e);if(n===`function`||n===`symbol`)return!1;if(Array.isArray(e))return t.has(e)?!1:(t.add(e),e.every(e=>m(e,t)));if(n===`object`){if(t.has(e))return!1;t.add(e);let n=Object.getPrototypeOf(e);return n!==null&&n!==Object.prototype?!1:Object.values(e).every(e=>m(e,t))}return!1}function h(e){if(e==null)return!0;let t=typeof e;return t===`string`||t===`boolean`?!0:t===`number`?Number.isFinite(e):!1}function g(e){if(typeof e!=`object`||!e||Array.isArray(e))return!1;let t=Object.getPrototypeOf(e);if(t!==null&&t!==Object.prototype)return!1;let n=!1;for(let t in e){if(!Object.hasOwn(e,t))continue;let r=e[t];if(!h(r)){let e=typeof r;if(e===`function`||e===`symbol`)return!1;n=!0;break}}return n?m(e):!0}function _(e){return p(e.name)&&typeof e.path==`string`&&g(e.params)}function v(e){return!(typeof e!=`object`||!e||!_(e))}function y(e,t,n){return v(e.state)?t.makeState(e.state.name,e.state.params,e.state.path):t.matchPath(n.getLocation())}function b(e,t,n,r){let i={name:e.name,params:e.params,path:e.path};n?r.replaceState(i,t):r.pushState(i,t)}function x(e,t,n){return r=>{if(r)for(let i of Object.keys(r)){if(!(i in e))continue;let a=r[i];if(a===void 0)continue;let o=typeof e[i],s=typeof a;if(s!==o)throw Error(`[${t}] Invalid type for '${i}': expected ${o}, got ${s}`);let c=n?.[i];if(c){let e=c.validate(a);if(e!==null)throw Error(`[${t}] Invalid '${i}': ${e}`)}}}}const S=/[\u0000-\u001F\u007F]/,C={validate:e=>S.test(e)?`must not contain control characters`:e.split(`/`).includes(`..`)?`must not contain '..' segments`:null},w={validate:e=>S.test(e)?`must not contain control characters`:e.includes(`/`)?`must not contain '/' (slash is added before the path automatically)`:e.includes(`#`)?`must not contain '#' (it is added as the hash delimiter)`:e.includes(`?`)?`must not contain '?' (it conflicts with the query delimiter)`:null};function T(e,t){if(n())return{pushState:r,replaceState:i,addPopstateListener:a,getLocation:e,getHash:o};let s=u(t);return{...d(t),getLocation:()=>(s(`getLocation`),``)}}function E(e,t){if(!e.getCurrentHash)return{};let n=e.getCurrentHash();return n!==(e.getCurrentContextHash?e.getCurrentContextHash():``)&&e.router.getState()?.path===t?{hash:n,force:!0,hashChange:!0}:{hash:n}}function D(e){let n=!1,r=null;function i(){if(r){let t=r;r=null,console.warn(`[${e.loggerContext}] Processing deferred popstate event`),s(t)}}function a(){let t=e.router.getState();if(!t)return;let n=t.context?.url?.hash,r=e.buildUrl(t.name,t.params,n?{hash:n}:void 0);e.browser.replaceState(t,r)}function o(t){console.error(`[${e.loggerContext}] Critical error in onPopState`,t);try{a()}catch(t){console.error(`[${e.loggerContext}] Failed to recover from critical error`,t)}}async function s(s){if(n){console.warn(`[${e.loggerContext}] Transition in progress, deferring popstate event`),r=s;return}n=!0;try{let n=y(s,e.api,e.browser);if(n)await e.api.navigateToState(n,{...e.transitionOptions,...E(e,n.path)});else if(e.allowNotFound)e.router.navigateToNotFound(e.browser.getLocation());else{let n=new t.RouterError(t.errorCodes.ROUTE_NOT_FOUND,{path:e.browser.getLocation()});e.api.emitTransitionError(n),a()}}catch(e){if(e instanceof t.RouterError)try{a()}catch{}else o(e)}finally{n=!1,i()}}return e=>void s(e)}function O(e){return{onStart:()=>{e.shared.removePopStateListener&&e.shared.removePopStateListener(),e.shared.removePopStateListener=e.browser.addPopstateListener(e.handler)},onStop:()=>{e.shared.removePopStateListener&&(e.shared.removePopStateListener(),e.shared.removePopStateListener=void 0)},teardown:()=>{e.shared.removePopStateListener&&(e.shared.removePopStateListener(),e.shared.removePopStateListener=void 0),e.cleanup()}}}function k(e){return encodeURI(e).replaceAll(`#`,`%23`)}function A(e){try{return decodeURIComponent(e)}catch{return e}}function j(e){let t=e;for(;t.startsWith(`#`);)t=t.slice(1);return A(t)}function M(e){let t=e,n=t.indexOf(`://`);if(n!==-1){let e=n+3,r=t.length;for(let n=e;n<t.length;n++){let e=t[n];if(e===`/`||e===`?`||e===`#`){r=n;break}}t=r===t.length?`/`:t.slice(r),(t.startsWith(`?`)||t.startsWith(`#`))&&(t=`/${t}`)}let r=t.indexOf(`#`),i=r===-1?``:t.slice(r),a=r===-1?t:t.slice(0,r),o=a.indexOf(`?`),s=o===-1?``:a.slice(o);return{pathname:o===-1?a:a.slice(0,o),search:s,hash:i}}function N(e,t){return e.addInterceptor(`start`,(e,n)=>e(n??t.getLocation()))}function P(e,t,n,r,i=!0){let a={name:``,params:{},path:``};return(o,s={},c)=>{let l=e.buildState(o,s);if(!l)throw Error(`[real-router] Cannot replace state: route "${o}" is not found`);let u=e.makeState(l.name,l.params,t.buildPath(l.name,l.params),{params:l.meta}),d;if(c?.hash!==void 0){let e=j(c.hash);d=e?`#${k(e)}`:``}else d=i?n.getHash():``;let f=r(o,s)+d;a.name=u.name,a.params=u.params,a.path=u.path,n.replaceState(a,f)}}function F(e,t,n){return e.replace===!0?!0:n?!!e.reload&&t.path===n.path:e.replace!==!1}const I={hashPrefix:``,base:``,forceDeactivate:!0},L=`hash-plugin`;function R(e){return e.replaceAll(/[$()*+.?[\\\]^{|}-]/g,String.raw`\$&`)}function z(e){return e?RegExp(`^#${R(e)}`):null}function B(e,t){return e===``||e===`#`?`/`:(t?e.replace(t,``):e.slice(1))||`/`}function V(e,t){let n=M(e),r=B(n.hash,t);return r.includes(`?`)?r:r+n.search}function H(e,t,n){let r=c(B(e,n));return r.includes(`?`)?r:r+t}var U=class{#e;#t;#n;#r;#i;#a;constructor(e,t,n,r,i,a,o){this.#e=e,this.#t=r,this.#n=N(t,r);let s=!1,c=()=>{s||(s=!0,console.warn("[@real-router/hash-plugin] `hash` option is ignored — `#` is reserved for the route delimiter. URL fragments are not supported with hash-plugin; use @real-router/browser-plugin or @real-router/navigation-plugin if you need them."))},l=`${n.base}#${n.hashPrefix}`,u=(t,n,r)=>(r?.hash!==void 0&&c(),l+e.buildPath(t,n));this.#a=c,this.#r=t.extendRouter({buildUrl:u,matchUrl:e=>t.matchPath(V(e,i))??void 0,replaceHistoryState:P(t,e,r,u,!1)});let d=D({router:e,api:t,browser:r,allowNotFound:t.getOptions().allowNotFound,transitionOptions:a,loggerContext:L,buildUrl:u});this.#i=O({browser:r,shared:o,handler:d,cleanup:()=>{this.#n(),this.#r()}})}getPlugin(){return{...this.#i,onTransitionSuccess:(e,t,n)=>{n.hash!==void 0&&this.#a();let r=F(n,e,t);b(e,this.#e.buildUrl(e.name,e.params),r,this.#t)}}}};const W=x(I,L,{base:C,hashPrefix:w});function G(t,n){W(t);let r=t?Object.fromEntries(Object.entries(t).filter(([,e])=>e!==void 0)):{},i={...I,...r};i.base=s(i.base);let a=z(i.hashPrefix),o=n??T(()=>H(globalThis.location.hash,globalThis.location.search,a),`hash-plugin`),c={forceDeactivate:i.forceDeactivate,source:`popstate`,replace:!0},l={removePopStateListener:void 0};return function(t){return new U(t,(0,e.getPluginApi)(t),i,o,a,c,l).getPlugin()}}exports.hashPluginFactory=G,exports.isState=v;
2
2
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@real-router/hash-plugin",
3
- "version": "0.7.3",
3
+ "version": "0.7.4",
4
4
  "type": "commonjs",
5
5
  "description": "Hash-based routing plugin for Real-Router",
6
6
  "main": "./dist/cjs/index.js",
@@ -43,12 +43,12 @@
43
43
  },
44
44
  "sideEffects": false,
45
45
  "dependencies": {
46
- "@real-router/core": "^0.54.1",
46
+ "@real-router/core": "^0.55.0",
47
47
  "@real-router/types": "^0.35.0"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@testing-library/jest-dom": "6.9.1",
51
- "jsdom": "28.1.0",
51
+ "jsdom": "29.1.1",
52
52
  "type-guards": "^0.4.9"
53
53
  },
54
54
  "scripts": {