@mapl/router 0.1.3 → 0.1.8

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/README.md CHANGED
@@ -1,3 +1,10 @@
1
- # `@mapl/router`
1
+ A route compiler for web frameworks.
2
2
 
3
- A fast compiled radix tree router.
3
+ Features:
4
+ - Route grouping
5
+ - Fast compilation times
6
+ - Customizable compilation
7
+
8
+ Required dependencies:
9
+ - `@mapl/router`
10
+ - `safe-throw`
package/constants.d.ts CHANGED
@@ -1,6 +1,15 @@
1
- export declare const REQ = "r";
2
- export declare const PATH = "p";
3
- export declare const PATH_LEN = "l";
4
- export declare const PARAMS = "q";
5
- export declare const PREV_PARAM_IDX = "i";
6
- export declare const CURRENT_PARAM_IDX = "j";
1
+ export * from "@mapl/router/constants";
2
+ export declare const MAPL = "m";
3
+ export declare const IS_ERR: string;
4
+ /**
5
+ * Request headers
6
+ */
7
+ export declare const HEADERS: string;
8
+ /**
9
+ * Start async scope
10
+ */
11
+ export declare const ASYNC_START = "return (async()=>{";
12
+ /**
13
+ * End async scope
14
+ */
15
+ export declare const ASYNC_END = "})()";
package/constants.js CHANGED
@@ -1 +1 @@
1
- export var REQ="r";export var PATH="p";export var PATH_LEN="l";export var PARAMS="q";export var PREV_PARAM_IDX="i";export var CURRENT_PARAM_IDX="j";
1
+ export*from"@mapl/router/constants";export let MAPL=`m`;export let IS_ERR=MAPL+`e`;export let HEADERS=MAPL+`h`;export let ASYNC_START=`return (async()=>{`;export let ASYNC_END=`})()`;
package/index.d.ts CHANGED
@@ -1,5 +1,71 @@
1
- import { type Node } from './tree/node.js';
2
- export type Router = [staticMap: Record<string, string> | null, root: Node | null];
3
- export declare function createRouter(): Router;
4
- export declare function insertItem(router: Router, path: string, item: string): void;
5
- export declare function compileRouter(router: Router, contentBuilder: string[]): void;
1
+ import { type Router } from "@mapl/router/method";
2
+ import type { Err } from "safe-throw";
3
+ /**
4
+ * Describe a middleware function
5
+ */
6
+ export type MiddlewareFunc<T = unknown> = (c: T, ...args: any[]) => any;
7
+ /**
8
+ * Describe a middleware function
9
+ */
10
+ export type Func = (...args: any[]) => any;
11
+ /**
12
+ * Describe a function
13
+ */
14
+ export type ErrorFunc = (err: Err, ...args: any[]) => any;
15
+ /**
16
+ * Describe an error handler
17
+ */
18
+ export type ErrorHandler<
19
+ T extends ErrorFunc = ErrorFunc,
20
+ Data = any
21
+ > = [handler: T, data: Data];
22
+ /**
23
+ * Describe a middleware
24
+ */
25
+ export type Middleware<T extends MiddlewareFunc> = [-1, (scope: ScopeState) => string] | [0 | 2, T] | [1 | 3, T, key: string];
26
+ /**
27
+ * Describe a handler store
28
+ */
29
+ export type Handler<
30
+ T extends Func = Func,
31
+ Data = unknown
32
+ > = [method: string, path: string, handler: T, data: Data];
33
+ /**
34
+ * Describe a handler group
35
+ */
36
+ export type Group<
37
+ E extends ErrorFunc = ErrorFunc,
38
+ T extends Func = Func,
39
+ Data = any
40
+ > = [middlewares: Middleware<T>[], handlers: Handler<T, Data>[], errHandler: ErrorHandler<ErrorFunc, Data> | null, children: ChildGroup<E, T, Data>[]];
41
+ /**
42
+ * Describe a handler child group data
43
+ */
44
+ export type ChildGroup<
45
+ E extends ErrorFunc,
46
+ T extends Func,
47
+ Data = any
48
+ > = [prefix: string, group: Group<E, T, Data>];
49
+ /**
50
+ * Describe a hook
51
+ */
52
+ export type Hook<T extends any[]> = (...args: [...data: T, scope: Readonly<ScopeState>]) => string;
53
+ /**
54
+ * State for compilation
55
+ */
56
+ export type CompilerState = [router: Router<string>, dependencies: any[], contextInit: string, compileHandler: Hook<[handler: Handler[2], data: Handler[3], path: string]>, compileErrorHandler: Hook<ErrorHandler>];
57
+ /**
58
+ * This state doesn't change frequently
59
+ */
60
+ export type ScopeState = [scopeAsync: boolean, contextCreated: boolean, errorHandler: ErrorHandler | null, compiledErrorHandler: string | null];
61
+ /**
62
+ * The context initialization function
63
+ */
64
+ export type ContextInit<T = unknown> = (headers: [string, string][]) => T;
65
+ export declare const createArgSet: (args: string[]) => string[];
66
+ export declare const concatPrefix: (prefix: string, path: string) => string;
67
+ export declare const AsyncFunction: Function;
68
+ export declare const compilerState: CompilerState;
69
+ export declare const createContext: (scope: ScopeState) => string;
70
+ export declare const createAsyncScope: (scope: ScopeState) => string;
71
+ export declare const compileGroup: (group: Group, scope: ScopeState, prefix: string, content: string) => void;
package/index.js CHANGED
@@ -1 +1 @@
1
- import compileNode from"./tree/compiler.js";import{createNode,insertItem as nodeInsertItem}from"./tree/node.js";export function createRouter(){return[null,null]}export function insertItem(router,path,item){if(path.includes("*"))nodeInsertItem(router[1]??=createNode("/"),path,item);else(router[0]??={})[path]=item}export function compileRouter(router,contentBuilder){if(router[0]!==null){let staticMap=router[0];contentBuilder.push("switch(p){");for(let key in staticMap)contentBuilder.push(`case "${key.slice(1).replace(/"/g,"\\\"")}":{${staticMap[key]}break;}`);contentBuilder.push("}")}if(router[1]!==null){contentBuilder.push("let l=p.length;");compileNode(router[1],contentBuilder,false,false,-1,"")}}
1
+ import{insertItem}from"@mapl/router/method";export let createArgSet=args=>{let len=args.length;let arr=new Array(len+1);arr[0]=``;for(let i=1;i<=len;i++)arr[i]=args.slice(0,i).join();return arr};export let concatPrefix=(prefix,path)=>{let p=prefix+path;return/.\/$/.test(p)?prefix:p};export let AsyncFunction=(async()=>{}).constructor;export let compilerState=new Array(5);export let createContext=scope=>{if(!scope[1]){scope[1]=true;if(scope[2]!==null)scope[3]=null;return compilerState[2]}return``};export let createAsyncScope=scope=>{if(!scope[0]){scope[0]=true;if(scope[2]!==null)scope[3]=null;return`return (async()=>{`}return``};export let compileGroup=(group,scope,prefix,content)=>{if(group[2]!=null){scope[2]=group[2];scope[3]=null}for(let i=0,middlewares=group[0];i<middlewares.length;i++){let middleware=middlewares[i];let fn=middleware[1];if(middleware[0]===-1)content+=fn(scope);else{let call=`f`+compilerState[1].push(fn)+`(`;if(fn.length>0){call+=`c`;content+=createContext(scope)}call+=`);`;if(fn instanceof AsyncFunction){call=`await `+call;content+=createAsyncScope(scope)}if((middleware[0]&1)===1){call=`c.`+middleware[2]+`=`+call;content+=createContext(scope)}content+=middleware[0]>1?`{let t=`+call+`if(me(t)){`+(scope[3]??=compilerState[4](scope[2][0],scope[2][1],scope))+`}}`:call}}for(let i=0,handlers=group[1],asyncEnd=scope[0]?`})()`:``;i<handlers.length;i++){let handler=handlers[i];let pathTransform=concatPrefix(prefix,handler[1]);insertItem(compilerState[0],handler[0],pathTransform,content+compilerState[3](handler[2],handler[3],pathTransform,scope)+asyncEnd)}for(let i=0,childGroups=group[3];i<childGroups.length;i++)compileGroup(childGroups[i][1],[...scope],childGroups[i][0]===`/`?prefix:prefix+childGroups[i][0],content)};
package/package.json CHANGED
@@ -1,34 +1,18 @@
1
1
  {
2
- "name": "@mapl/router",
3
- "version": "0.1.3",
4
- "main": "./index.js",
5
- "devDependencies": {
6
- "@stylistic/eslint-plugin": "latest",
7
- "eslint": "latest",
8
- "typescript-eslint": "latest",
9
- "eslint-plugin-jsdoc": "latest",
10
- "@types/bun": "latest",
11
- "mitata": "latest",
12
- "typescript": "latest"
13
- },
14
- "description": "Fast compiled router for all runtimes",
15
- "keywords": [
16
- "fast",
17
- "compiled",
18
- "router",
19
- "node",
20
- "bun",
21
- "deno"
22
- ],
23
- "license": "MIT",
24
- "scripts": {
25
- "build:test": "bun scripts/build.ts && bun test",
26
- "build:bench": "bun build:test && bun scripts/bench.ts",
27
- "build:publish": "bun build:test && bun scripts/publish.ts",
28
- "lint": "eslint ./src",
29
- "lint:fix": "eslint ./src --fix"
30
- },
31
- "sideEffects": false,
32
- "type": "module",
33
- "types": "./index.d.ts"
2
+ "name": "@mapl/router",
3
+ "version": "0.1.8",
4
+ "description": "A route compiler",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/mapljs/framework.git"
8
+ },
9
+ "license": "MIT",
10
+ "type": "module",
11
+ "main": "./index.js",
12
+ "types": "./index.d.ts",
13
+ "packageManager": "pnpm@10.12.1+sha512.f0dda8580f0ee9481c5c79a1d927b9164f2c478e90992ad268bbb2465a736984391d6333d2c327913578b2804af33474ca554ba29c04a8b13060a717675ae3ac",
14
+ "exports": {
15
+ "./constants": "./constants.js",
16
+ ".": "./index.js"
34
17
  }
18
+ }
@@ -1,3 +0,0 @@
1
- import type { Node } from './node.js';
2
- declare const f: (node: Node, builder: string[], hasParam: boolean, hasMultipleParams: boolean, startIndexValue: number, startIndexPrefix: string) => void;
3
- export default f;
package/tree/compiler.js DELETED
@@ -1 +0,0 @@
1
- let f=(node,builder,hasParam,hasMultipleParams,startIndexValue,startIndexPrefix)=>{let part=node[0];let partLen=part.length;if(partLen!==1){builder.push(`if(l>${startIndexPrefix}${startIndexValue+partLen-1})`);for(let i=1;i<partLen;i++)builder.push(`if(p.charCodeAt(${startIndexPrefix}${startIndexValue+i})===${part.charCodeAt(i)})`);builder.push("{")}startIndexValue+=partLen;if(node[1]!==null)builder.push(`if(l===${startIndexPrefix}${startIndexValue}){${node[1]}}`);if(node[2]!==null){let children=node[2];let childrenEntries=Object.entries(children);if(childrenEntries.length===1){builder.push(`if(p.charCodeAt(${startIndexPrefix}${startIndexValue})===${childrenEntries[0][0]}){`);f(childrenEntries[0][1],builder,hasParam,hasMultipleParams,startIndexValue,startIndexPrefix);builder.push("}")}else{builder.push(`switch(p.charCodeAt(${startIndexPrefix}${startIndexValue})){`);for(let i=0,l=childrenEntries.length;i<l;i++){builder.push(`case ${childrenEntries[i][0]}:`);f(childrenEntries[i][1],builder,hasParam,hasMultipleParams,startIndexValue,startIndexPrefix);builder.push("break;")}builder.push("}")}}if(node[3]!==null){let params=node[3];let hasStore=params[1]!==null;let hasChild=params[0]!==null;let requireAllocation=hasParam?hasMultipleParams:hasChild||!hasStore;if(requireAllocation)builder.push("{");if(hasParam)builder.push(`${hasMultipleParams?"":"let "}i=${startIndexPrefix}${startIndexValue};`);let currentIndex=hasParam?"i":startIndexPrefix+startIndexValue;let slashIndex=`p.indexOf('/'${currentIndex==="0"?"":","+currentIndex})`;if(hasChild||!hasStore)builder.push(`${hasParam?"":"let "}j=${slashIndex};`);if(hasStore){let paramsVal=currentIndex==="0"?"p":`p.slice(${currentIndex})`;builder.push(`if(${hasChild?"j":slashIndex}===-1){${hasParam?`q.push(${paramsVal})`:`let q=[${paramsVal}]`};${params[1]}}`)}if(hasChild){let paramsVal=`p.substring(${currentIndex},j)`;builder.push(`if(j${hasStore?"!==":">"}${currentIndex}){${hasParam?`q.push(${paramsVal})`:`let q=[${paramsVal}]`};`);f(params[0],builder,true,hasParam,0,"j+");if(!requireAllocation)builder.push("q.pop();");builder.push("}")}if(requireAllocation)builder.push("}")}if(node[4]!==null){let noStore=node[1]===null;let currentIndex=startIndexPrefix+startIndexValue;if(noStore)builder.push(`if(l!==${currentIndex}){`);let paramsVal=currentIndex==="0"?"p":`p.slice(${currentIndex})`;builder.push(`${hasParam?`q.push(${paramsVal})`:`let q=[${paramsVal}]`};${node[4]}`);if(noStore)builder.push("}")}if(partLen!==1)builder.push("}")};export default f;
package/tree/node.d.ts DELETED
@@ -1,12 +0,0 @@
1
- export type Node = [
2
- part: string,
3
- store: string | null,
4
- children: Node[] | null,
5
- params: ParamNode | null,
6
- wildcardStore: string | null
7
- ];
8
- export type ParamNode = [
9
- child: Node | null,
10
- store: string | null
11
- ];
12
- export declare const createNode: (part: string) => Node, createParamNode: (nextNode: ParamNode[0]) => ParamNode, cloneNode: (node: Node, part: string) => Node, resetNode: (node: Node, part: string, children: Node[2]) => void, visitNode: (node: Node, path: string) => Node, insertItem: (node: Node, path: string, item: string) => void;
package/tree/node.js DELETED
@@ -1 +0,0 @@
1
- export var createNode=(part)=>[part,null,null,null,null];export var createParamNode=(nextNode)=>[nextNode,null];export var cloneNode=(node,part)=>[part,node[1],node[2],node[3],node[4]];export var resetNode=(node,part,children)=>{node[0]=part;node[2]=children;node[1]=null;node[3]=null;node[4]=null};export var visitNode=(node,path)=>{for(let i=0,parts=path.split("*"),l=parts.length;i<l;++i){if(i!==0){if(node[3]===null){let nextNode=createNode(parts[i]);node[3]=createParamNode(nextNode);node=nextNode}else node=node[3][0]??=createNode(parts[i])}for(let j=0,pathPart=parts[i];;++j){let nodePart=node[0];if(j===pathPart.length){if(j<nodePart.length){let children=[];children[nodePart.charCodeAt(j)]=cloneNode(node,nodePart.slice(j));resetNode(node,pathPart,children)}break}if(j===nodePart.length){if(node[2]===null)node[2]=[];else{let nextNode=node[2][pathPart.charCodeAt(j)];if(typeof nextNode!=="undefined"){node=nextNode;pathPart=pathPart.slice(j);j=0;continue}}let nextNode=createNode(pathPart.slice(j));node[2][pathPart.charCodeAt(j)]=nextNode;node=nextNode;break}if(pathPart.charCodeAt(j)!==nodePart.charCodeAt(j)){let children=[];children[nodePart.charCodeAt(j)]=cloneNode(node,nodePart.slice(j));let nextNode=createNode(pathPart.slice(j));children[pathPart.charCodeAt(j)]=nextNode;resetNode(node,nodePart.substring(0,j),children);node=nextNode;break}}}return node};export var insertItem=(node,path,item)=>{if(path.charCodeAt(path.length-1)===42){if(path.charCodeAt(path.length-2)===42)visitNode(node,path.substring(0,path.length-2))[4]=item;else(visitNode(node,path.substring(0,path.length-1))[3]??=createParamNode(null))[1]=item}else visitNode(node,path)[1]=item};