memoirist
Version:
Elysia's Radix Tree router for fast matching dynamic parameters
5 lines (3 loc) • 4.1 kB
JavaScript
// @bun
var Y=(v,b)=>{let A=b?.length?{}:null;if(A)for(let Q of b)A[Q.part.charCodeAt(0)]=Q;return{part:v,store:null,inert:A,params:null,wildcardStore:null}},k=(v,b)=>({...v,part:b}),T=(v)=>({name:v,store:null,inert:null});class _{config;root={};history=[];deferred=[];constructor(v={}){this.config=v;if(v.lazy)this.find=this.lazyFind;if(v.onParam&&!Array.isArray(v.onParam))this.config.onParam=[this.config.onParam]}static regex={static:/:.+?(?=\/|$)/,params:/:.+?(?=\/|$)/g,optionalParams:/(\/:\w+\?)/g};lazyFind=(v,b)=>{if(!this.config.lazy)return this.find;return this.build(),this.find(v,b)};build(){if(!this.config.lazy)return;for(let[v,b,A]of this.deferred)this.add(v,b,A,{lazy:!1,ignoreHistory:!0});this.deferred=[],this.find=(v,b)=>{let A=this.root[v];if(!A)return null;return $(b,b.length,A,0,this.config.onParam)}}add(v,b,A,{ignoreError:Q=!1,ignoreHistory:O=!1,lazy:V=this.config.lazy}={}){if(V)return this.find=this.lazyFind,this.deferred.push([v,b,A]),A;if(typeof b!=="string")throw new TypeError("Route path must be a string");if(b==="")b="/";else if(b[0]!=="/")b=`/${b}`;let X=b[b.length-1]==="*",J=b.match(_.regex.optionalParams);if(J){let F=b.replaceAll("?","");this.add(v,F,A,{ignoreError:Q,ignoreHistory:O,lazy:V});for(let B=0;B<J.length;B++){let D=b.replace(J[B],"");this.add(v,D,A,{ignoreError:!0,ignoreHistory:O,lazy:V})}return A}if(J)b=b.replaceAll("?","");if(this.history.find(([F,B,D])=>F===v&&B===b))return A;if(X||J&&b.charCodeAt(b.length-1)===63)b=b.slice(0,-1);if(!O)this.history.push([v,b,A]);let K=b.split(_.regex.static),G=b.match(_.regex.params)||[];if(K[K.length-1]==="")K.pop();let q;if(!this.root[v])q=this.root[v]=Y("/");else q=this.root[v];let U=0;for(let F=0;F<K.length;++F){let B=K[F];if(F>0){let D=G[U++].slice(1);if(q.params===null)q.params=T(D);else if(q.params.name!==D)if(Q)return A;else throw new Error(`Cannot create route "${b}" with parameter "${D}" because a route already exists with a different parameter name ("${q.params.name}") in the same location`);let S=q.params;if(S.inert===null){q=S.inert=Y(B);continue}q=S.inert}for(let D=0;;){if(D===B.length){if(D<q.part.length){let S=k(q,q.part.slice(D));Object.assign(q,Y(B,[S]))}break}if(D===q.part.length){if(q.inert===null)q.inert={};let S=q.inert[B.charCodeAt(D)];if(S){q=S,B=B.slice(D),D=0;continue}let Z=Y(B.slice(D));q.inert[B.charCodeAt(D)]=Z,q=Z;break}if(B[D]!==q.part[D]){let S=k(q,q.part.slice(D)),Z=Y(B.slice(D));Object.assign(q,Y(q.part.slice(0,D),[S,Z])),q=Z;break}++D}}if(U<G.length){let B=G[U].slice(1);if(q.params===null)q.params=T(B);else if(q.params.name!==B)if(Q)return A;else throw new Error(`Cannot create route "${b}" with parameter "${B}" because a route already exists with a different parameter name ("${q.params.name}") in the same location`);if(q.params.store===null)q.params.store=A;return q.params.store}if(X){if(q.wildcardStore===null)q.wildcardStore=A;return q.wildcardStore}if(q.store===null)q.store=A;return q.store}find(v,b){let A=this.root[v];if(!A)return null;return $(b,b.length,A,0,this.config.onParam)}}var $=(v,b,A,Q,O)=>{let V=A.part,X=V.length,J=Q+X;if(X>1){if(J>b)return null;if(X<15){for(let K=1,G=Q+1;K<X;++K,++G)if(V.charCodeAt(K)!==v.charCodeAt(G))return null}else if(v.slice(Q,J)!==V)return null}if(J===b){if(A.store!==null)return{store:A.store,params:{}};if(A.wildcardStore!==null)return{store:A.wildcardStore,params:{"*":""}};return null}if(A.inert!==null){let K=A.inert[v.charCodeAt(J)];if(K!==void 0){let G=$(v,b,K,J,O);if(G!==null)return G}}if(A.params!==null){let{store:K,name:G,inert:q}=A.params,U=v.indexOf("/",J);if(U!==J){if(U===-1||U>=b){if(K!==null){let F={};if(F[G]=v.substring(J,b),O)for(let B=0;B<O.length;B++){let D=O[B](F[G],G);if(D!==void 0)F[G]=D}return{store:K,params:F}}}else if(q!==null){let F=$(v,b,q,U,O);if(F!==null){if(F.params[G]=v.substring(J,U),O)for(let B=0;B<O.length;B++){let D=O[B](F.params[G],G);if(D!==void 0)F.params[G]=D}return F}}}}if(A.wildcardStore!==null)return{store:A.wildcardStore,params:{"*":v.substring(J,b)}};return null},w=_;export{w as default,_ as Memoirist};
//# debugId=7CB9F845001CCC1464756E2164756E21