11import type { MatchedRoute , MethodData , Node , RouterContext } from "./types.ts" ;
22
3- // p: path
4- // s: path parts
5- // l: path parts length
6- // m: method
7- // e: Empty group
8-
93/**
104 * Compiles the router instance into a faster route-matching function.
115 *
@@ -28,7 +22,7 @@ export function compileRouter<T>(
2822 router : RouterContext < T > ,
2923) : ( method : string , path : string ) => MatchedRoute < T > | undefined {
3024 const deps : any [ ] = [ ] ;
31- const compiled = _compileRouteMatch ( router , deps ) ;
25+ const compiled = compileRouteMatch ( router , deps ) ;
3226 return new Function (
3327 ...deps . map ( ( _ , i ) => "d" + ( i + 1 ) ) ,
3428 `let e={groups:{}};return(m,p)=>{${ compiled } }` ,
@@ -37,15 +31,39 @@ export function compileRouter<T>(
3731
3832// ------- internal functions -------
3933
34+ // p: path
35+ // s: path parts
36+ // l: path parts length
37+ // m: method
38+ // e: Empty group
39+
4040/**
41- * Whether the current node has children nodes
42- * @param n
41+ * Compile a router to pattern matching statements
42+ * @param router
43+ * @param deps - Dependencies of the function scope
4344 */
44- function _hasChild ( n : Node < any > ) : boolean {
45- return n . static != null || n . param != null || n . wildcard != null ;
45+ function compileRouteMatch ( router : RouterContext < any > , deps : any [ ] ) : string {
46+ // Ignore trailing slash
47+ let str = `if(p[p.length-1]==='/')p=p.slice(0,-1)||'/';` ;
48+
49+ const staticNodes = new Set < Node > ( ) ;
50+
51+ for ( const key in router . static ) {
52+ const node = router . static [ key ] ;
53+ if ( node ?. methods ) {
54+ staticNodes . add ( node ) ;
55+ str += `if(p===${ JSON . stringify ( key . replace ( / \/ $ / , "" ) || "/" ) } ){${ compileMethodMatch ( node . methods , [ ] , deps , - 1 ) } }` ;
56+ }
57+ }
58+
59+ return (
60+ str +
61+ "let s=p.split('/').filter(q=>q!==''),l=s.length;" +
62+ compileNode ( router . root , [ ] , 0 , deps , false , staticNodes )
63+ ) ;
4664}
4765
48- function _compileMethodMatch (
66+ function compileMethodMatch (
4967 methods : Record < string , MethodData < any > [ ] | undefined > ,
5068 params : string [ ] ,
5169 deps : any [ ] ,
@@ -54,14 +72,14 @@ function _compileMethodMatch(
5472 let str = "" ;
5573 for ( const key in methods ) {
5674 const data = methods [ key ] ;
57- if ( data != null && data . length > 0 ) {
75+ if ( data && data ? .length > 0 ) {
5876 // Don't check for all method handler
59- if ( key !== "" ) str += `if(m===" ${ key } " )` ;
77+ if ( key !== "" ) str += `if(m===' ${ key } ' )` ;
6078 let returnData = `return{data:d${ deps . push ( data [ 0 ] . data ) } ` ;
6179
6280 // Add param properties
6381 const { paramsMap } = data [ 0 ] ;
64- if ( paramsMap != null && paramsMap . length > 0 ) {
82+ if ( paramsMap && paramsMap . length > 0 ) {
6583 // Check for optional end parameters
6684 const required =
6785 ! paramsMap [ paramsMap . length - 1 ] [ 2 ] && currentIdx !== - 1 ;
@@ -89,44 +107,51 @@ function _compileMethodMatch(
89107/**
90108 * Compile a node to matcher logic
91109 */
92- function _compileNode (
110+ function compileNode (
93111 node : Node < any > ,
94112 params : string [ ] ,
95113 startIdx : number ,
96114 deps : any [ ] ,
97115 isParamNode : boolean ,
116+ staticNodes : Set < Node > ,
98117) : string {
99118 let str = "" ;
100119
101- if ( node . methods != null )
102- str += `if(l===${ startIdx } ${ isParamNode ? `||l===${ startIdx - 1 } ` : "" } ){${ _compileMethodMatch ( node . methods , params , deps , isParamNode ? startIdx : - 1 ) } }` ;
120+ if ( node . methods && ! staticNodes . has ( node ) ) {
121+ str += `if(l===${ startIdx } ${ isParamNode ? `||l===${ startIdx - 1 } ` : "" } ){${ compileMethodMatch ( node . methods , params , deps , isParamNode ? startIdx : - 1 ) } }` ;
122+ }
103123
104- if ( node . static != null )
124+ if ( node . static ) {
105125 for ( const key in node . static )
106- str += `if(s[${ startIdx } ]===${ JSON . stringify ( key ) } ){${ _compileNode (
126+ str += `if(s[${ startIdx } ]===${ JSON . stringify ( key ) } ){${ compileNode (
107127 node . static [ key ] ,
108128 params ,
109129 startIdx + 1 ,
110130 deps ,
111131 false ,
132+ staticNodes ,
112133 ) } }`;
134+ }
113135
114- if ( node . param != null )
115- str += _compileNode (
136+ if ( node . param ) {
137+ str += compileNode (
116138 node . param ,
117139 [ ...params , `s[${ startIdx } ]` ] ,
118140 startIdx + 1 ,
119141 deps ,
120142 true ,
143+ staticNodes ,
121144 ) ;
145+ }
122146
123- if ( node . wildcard != null ) {
147+ if ( node . wildcard ) {
124148 const { wildcard } = node ;
125- if ( _hasChild ( wildcard ) )
149+ if ( hasChild ( wildcard ) ) {
126150 throw new Error ( "Compiler mode does not support patterns after wildcard" ) ;
151+ }
127152
128- if ( wildcard . methods != null )
129- str += _compileMethodMatch (
153+ if ( wildcard . methods )
154+ str += compileMethodMatch (
130155 wildcard . methods ,
131156 [ ...params , `s.slice(${ startIdx } ).join('/')` ] ,
132157 deps ,
@@ -138,23 +163,9 @@ function _compileNode(
138163}
139164
140165/**
141- * Compile a router to pattern matching statements
142- * @param router
143- * @param deps - Dependencies of the function scope
166+ * Whether the current node has children nodes
167+ * @param n
144168 */
145- function _compileRouteMatch ( router : RouterContext < any > , deps : any [ ] ) : string {
146- // Support trailing slash
147- let str = "if(p[p.length-1]==='/')p=p.slice(0,-1);" ;
148-
149- for ( const key in router . static ) {
150- const node = router . static [ key ] ;
151- if ( node != null && node . methods != null )
152- str += `if(p===${ JSON . stringify ( key ) } ){${ _compileMethodMatch ( node . methods , [ ] , deps , - 1 ) } }` ;
153- }
154-
155- return (
156- str +
157- "let s=p.split('/').filter(q=>q!==''),l=s.length;" +
158- _compileNode ( router . root , [ ] , 0 , deps , false )
159- ) ;
169+ function hasChild ( n : Node < any > ) : boolean {
170+ return ! ! ( n . static || n . param || n . wildcard ) ;
160171}
0 commit comments