@@ -6,38 +6,57 @@ import type { MatchedRoute, MethodData, Node, RouterContext } from "./types.ts";
66// m: method
77// e: Empty group
88
9+ /**
10+ * Compiles the router instance into a faster route-matching function.
11+ *
12+ * **IMPORTANT:** Compiler is an experimental feature, may contain issues and the API may change between versions.
13+ *
14+ * **IMPORTANT:** This function requires eval (`new Function`) support in the runtime environment for JIT (Just-In-Time)
15+ * compilation.
16+ *
17+ * @example
18+ * import { createRouter, addRoute } from "rou3";
19+ * import { compileRouter } from "rou3/experimental-compiler";
20+ * const router = createRouter();
21+ * // [add some routes]
22+ * const findRoute = compileRouter(router);
23+ * findRoute("GET", "/path/foo/bar");
24+ *
25+ * @param router - The router context to compile.
26+ */
27+ export function compileRouter < T > (
28+ router : RouterContext < T > ,
29+ ) : ( method : string , path : string ) => MatchedRoute < T > | undefined {
30+ const deps : any [ ] = [ ] ;
31+ const compiled = _compileRouteMatch ( router , deps ) ;
32+ return new Function (
33+ ...deps . map ( ( _ , i ) => "d" + ( i + 1 ) ) ,
34+ `let e={groups:{}};return(m,p)=>{${ compiled } }` ,
35+ ) ( ...deps ) ;
36+ }
37+
38+ // ------- internal functions -------
39+
940/**
1041 * Whether the current node has children nodes
1142 * @param n
1243 */
13- const _hasChild = ( n : Node < any > ) : boolean =>
14- n . static != null || n . param != null || n . wildcard != null ;
15-
16- // Skip a native call for common methods
17- const _fastMethodStringify = ( m : string ) =>
18- m === "GET"
19- ? '"GET"'
20- : m === "POST"
21- ? '"POST"'
22- : // eslint-disable-next-line
23- m === "PUT"
24- ? '"PUT"'
25- : m === "DELETE"
26- ? '"DELETE"'
27- : JSON . stringify ( m ) ;
28-
29- const _compileMethodMatch = (
44+ function _hasChild ( n : Node < any > ) : boolean {
45+ return n . static != null || n . param != null || n . wildcard != null ;
46+ }
47+
48+ function _compileMethodMatch (
3049 methods : Record < string , MethodData < any > [ ] | undefined > ,
3150 params : string [ ] ,
3251 deps : any [ ] ,
3352 currentIdx : number , // Set to -1 for non-param node
34- ) : string => {
53+ ) : string {
3554 let str = "" ;
3655 for ( const key in methods ) {
3756 const data = methods [ key ] ;
3857 if ( data != null && data . length > 0 ) {
3958 // Don't check for all method handler
40- if ( key !== "" ) str += `if(m===${ _fastMethodStringify ( key ) } )` ;
59+ if ( key !== "" ) str += `if(m===" ${ key } " )` ;
4160 let returnData = `return{data:d${ deps . push ( data [ 0 ] . data ) } ` ;
4261
4362 // Add param properties
@@ -65,18 +84,18 @@ const _compileMethodMatch = (
6584 }
6685 }
6786 return str ;
68- } ;
87+ }
6988
7089/**
7190 * Compile a node to matcher logic
7291 */
73- const _compileNode = (
92+ function _compileNode (
7493 node : Node < any > ,
7594 params : string [ ] ,
7695 startIdx : number ,
7796 deps : any [ ] ,
7897 isParamNode : boolean ,
79- ) : string => {
98+ ) : string {
8099 let str = "" ;
81100
82101 if ( node . methods != null )
@@ -116,17 +135,14 @@ const _compileNode = (
116135 }
117136
118137 return str ;
119- } ;
138+ }
120139
121140/**
122141 * Compile a router to pattern matching statements
123142 * @param router
124143 * @param deps - Dependencies of the function scope
125144 */
126- const _compileRouteMatch = (
127- router : RouterContext < any > ,
128- deps : any [ ] ,
129- ) : string => {
145+ function _compileRouteMatch ( router : RouterContext < any > , deps : any [ ] ) : string {
130146 // Support trailing slash
131147 let str = "if(p[p.length-1]==='/')p=p.slice(0,-1);" ;
132148
@@ -141,33 +157,4 @@ const _compileRouteMatch = (
141157 "let s=p.split('/').filter(q=>q!==''),l=s.length;" +
142158 _compileNode ( router . root , [ ] , 0 , deps , false )
143159 ) ;
144- } ;
145-
146- /**
147- * Compiles the router instance into a faster route-matching function.
148- *
149- * **IMPORTANT:** Compiler is an experimental feature, may contain issues and the API may change between versions.
150- *
151- * **IMPORTANT:** This function requires eval (`new Function`) support in the runtime environment for JIT (Just-In-Time)
152- * compilation.
153- *
154- * @example
155- * import { createRouter, addRoute } from "rou3";
156- * import { compileRouter } from "rou3/experimental-compiler";
157- * const router = createRouter();
158- * // [add some routes]
159- * const findRoute = compileRouter(router);
160- * findRoute("GET", "/path/foo/bar");
161- *
162- * @param router - The router context to compile.
163- */
164- export const compileRouter = < T > (
165- router : RouterContext < T > ,
166- ) : ( ( method : string , path : string ) => MatchedRoute < T > | undefined ) => {
167- const deps : any [ ] = [ ] ;
168- const compiled = _compileRouteMatch ( router , deps ) ;
169- return new Function (
170- ...deps . map ( ( _ , i ) => "d" + ( i + 1 ) ) ,
171- `let e={groups:{}};return(m,p)=>{${ compiled } }` ,
172- ) ( ...deps ) ;
173- } ;
160+ }
0 commit comments