Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default unjs({
"no-unused-expressions": 0,
"unicorn/no-for-loop": 0,
"unicorn/prefer-regexp-test": 0,
"unicorn/prefer-spread": 0,
"unicorn/no-array-callback-reference": 0,
"unicorn/no-array-method-this-argument": 0,
"unicorn/prefer-at": 0,
Expand Down
77 changes: 39 additions & 38 deletions src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,19 +84,22 @@ interface CompilerContext {

function compileRouteMatch(ctx: CompilerContext): string {
let code = "";
const staticNodes = new Set<Node>();

for (const key in ctx.router.static) {
const node = ctx.router.static[key];
if (node?.methods) {
staticNodes.add(node);
code += `if(p===${JSON.stringify(key.replace(/\/$/, "") || "/")}){${compileMethodMatch(ctx, node.methods, [], -1)}}`;
{
let hasIf = false;
for (const key in ctx.router.static) {
const node = ctx.router.static[key];
if (node?.methods) {
code += `${hasIf ? "else " : ""}if(p===${JSON.stringify(key.replace(/\/$/, "") || "/")}){${compileMethodMatch(ctx, node.methods, [], -1)}}`;
hasIf = true;
}
}
}

const match = compileNode(ctx, ctx.router.root, [], 0, staticNodes);
const match = compileNode(ctx, ctx.router.root, [], 1);
// Empty root node emit an empty bound check
if (match) {
code += `let s=p.split("/"),l=s.length-1;${match}`;
code += `let s=p.split("/"),l=s.length;${match}`;
}

if (!code) {
Expand All @@ -115,7 +118,7 @@ function compileMethodMatch(
let code = "";
for (const key in methods) {
const matchers = methods[key];
if (matchers && matchers?.length > 0) {
if (matchers && matchers.length > 0) {
if (key !== "")
code += `if(m==="${key}")${matchers.length > 1 ? "{" : ""}`;
const _matchers = matchers
Expand Down Expand Up @@ -146,7 +149,7 @@ function compileFinalMatch(
// Check for optional end parameters
const required = !paramsMap[paramsMap.length - 1][2] && currentIdx !== -1;
if (required) {
conditions.push(`l>=${currentIdx}`);
conditions.push(`l>${currentIdx}`);
}
for (let i = 0; i < paramsRegexp.length; i++) {
const regexp = paramsRegexp[i];
Expand Down Expand Up @@ -179,50 +182,51 @@ function compileNode(
ctx: CompilerContext,
node: Node<any>,
params: string[],
startIdx: number,
staticNodes: Set<Node>,
currentIdx: number,
): string {
let code = "";
const hasLastOptionalParam = node.key === "*";
let code = "",
hasIf = false;

if (node.methods && !staticNodes.has(node)) {
if (node.methods && params.length > 0) {
const match = compileMethodMatch(
ctx,
node.methods,
params,
node.key === "*" ? startIdx : -1,
hasLastOptionalParam ? currentIdx - 1 : -1,
);
if (match) {
const hasLastOptionalParam = node.key === "*";
code += `if(l===${startIdx}${hasLastOptionalParam ? `||l===${startIdx - 1}` : ""}){${match}}`;
code += `if(l===${currentIdx}${hasLastOptionalParam ? `||l===${currentIdx - 1}` : ""}){${match}}`;
hasIf = true;
}
}

if (node.static) {
let staticCode = "";
const notNeedBoundCheck = hasIf;

for (const key in node.static) {
const match = compileNode(
ctx,
node.static[key],
params,
startIdx + 1,
staticNodes,
);
const match = compileNode(ctx, node.static[key], params, currentIdx + 1);
if (match) {
code += `if(s[${startIdx + 1}]===${JSON.stringify(key)}){${match}}`;
staticCode += `${hasIf ? "else " : ""}if(s[${currentIdx}]===${JSON.stringify(key)}){${match}}`;
hasIf = true;
}
}

if (staticCode)
code += notNeedBoundCheck
? staticCode
: `if(l>${currentIdx}){${staticCode}}`;
}

if (node.param) {
const match = compileNode(
code += compileNode(
ctx,
node.param,
[...params, `s[${startIdx + 1}]`],
startIdx + 1,
staticNodes,
// Prevent deopt
params.concat(`s[${currentIdx}]`),
currentIdx + 1,
);
if (match) {
code += match;
}
}

if (node.wildcard) {
Expand All @@ -232,15 +236,12 @@ function compileNode(
}

if (wildcard.methods) {
const match = compileMethodMatch(
code += compileMethodMatch(
ctx,
wildcard.methods,
[...params, `s.slice(${startIdx + 1}).join('/')`],
startIdx,
params.concat(`s.slice(${currentIdx}).join('/')`),
currentIdx,
);
if (match) {
code += match;
}
}
}

Expand Down
24 changes: 13 additions & 11 deletions test/.snapshot/compiled-all.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,25 @@
if (p.charCodeAt(p.length - 1) === 47) p = p.slice(0, -1) || "/";
if (p === "/foo") {
if (m === "GET") r.unshift({ data: $0 });
}
if (p === "/foo/bar") {
} else if (p === "/foo/bar") {
if (m === "GET") r.unshift({ data: $1 });
}
if (p === "/foo/bar/baz") {
} else if (p === "/foo/bar/baz") {
if (m === "GET") r.unshift({ data: $2 });
}
let s = p.split("/"),
l = s.length - 1;
if (s[1] === "foo") {
if (s[3] === "baz") {
if (l === 3) {
if (m === "GET") r.unshift({ data: $3, params: { _0: s[2] } });
l = s.length;
if (l > 1) {
if (s[1] === "foo") {
if (l > 3) {
if (s[3] === "baz") {
if (l === 4) {
if (m === "GET") r.unshift({ data: $3, params: { _0: s[2] } });
}
}
}
if (m === "GET")
r.unshift({ data: $4, params: { _: s.slice(2).join("/") } });
}
if (m === "GET")
r.unshift({ data: $4, params: { _: s.slice(2).join("/") } });
}
if (m === "GET") r.unshift({ data: $5, params: { _: s.slice(1).join("/") } });
return r;
Expand Down
61 changes: 28 additions & 33 deletions test/.snapshot/compiled-aot.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,53 +17,48 @@ const findRoute = /* @__PURE__ */ (() => {
if (p.charCodeAt(p.length - 1) === 47) p = p.slice(0, -1) || "/";
if (p === "/test") {
if (m === "GET") return { data: $0 };
}
if (p === "/test/foo") {
} else if (p === "/test/foo") {
if (m === "GET") return { data: $1 };
}
if (p === "/test/foo/bar/qux") {
} else if (p === "/test/foo/bar/qux") {
if (m === "GET") return { data: $2 };
}
if (p === "/test/foo/baz") {
} else if (p === "/test/foo/baz") {
if (m === "GET") return { data: $3 };
}
if (p === "/test/fooo") {
} else if (p === "/test/fooo") {
if (m === "GET") return { data: $4 };
}
if (p === "/another/path") {
} else if (p === "/another/path") {
if (m === "GET") return { data: $5 };
}
if (p === "/static%3Apath/*/**") {
} else if (p === "/static%3Apath/*/**") {
if (m === "GET") return { data: $6 };
}
let s = p.split("/"),
l = s.length - 1;
if (s[1] === "test") {
if (s[2] === "foo") {
if (l === 3 || l === 2) {
if (m === "GET") return { data: $7, params: { _0: s[3] } };
}
if (m === "GET")
return { data: $8, params: { _: s.slice(3).join("/") } };
}
if (l === 2 || l === 1) {
if (m === "GET") if (l >= 2) return { data: $9, params: { id: s[2] } };
}
if (s[3] === "y") {
if (l === 3) {
if (m === "GET") return { data: $10, params: { idY: s[2] } };
l = s.length;
if (l > 1) {
if (s[1] === "test") {
if (l > 2) {
if (s[2] === "foo") {
if (l === 4 || l === 3) {
if (m === "GET") return { data: $7, params: { _0: s[3] } };
}
if (m === "GET")
return { data: $8, params: { _: s.slice(3).join("/") } };
}
}
if (s[4] === "z") {
if (l === 3 || l === 2) {
if (m === "GET") if (l > 2) return { data: $9, params: { id: s[2] } };
} else if (s[3] === "y") {
if (l === 4) {
if (m === "GET") return { data: $11, params: { idYZ: s[2] } };
if (m === "GET") return { data: $10, params: { idY: s[2] } };
} else if (s[4] === "z") {
if (l === 5) {
if (m === "GET") return { data: $11, params: { idYZ: s[2] } };
}
}
}
} else if (s[1] === "wildcard") {
if (m === "GET")
return { data: $12, params: { _: s.slice(2).join("/") } };
}
}
if (s[1] === "wildcard") {
if (m === "GET")
return { data: $12, params: { _: s.slice(2).join("/") } };
}
if (m === "GET") return { data: $13, params: { _: s.slice(1).join("/") } };
};
})();
59 changes: 28 additions & 31 deletions test/.snapshot/compiled-jit.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,47 @@
if (p.charCodeAt(p.length - 1) === 47) p = p.slice(0, -1) || "/";
if (p === "/test") {
if (m === "GET") return { data: $0 };
}
if (p === "/test/foo") {
} else if (p === "/test/foo") {
if (m === "GET") return { data: $1 };
}
if (p === "/test/foo/bar/qux") {
} else if (p === "/test/foo/bar/qux") {
if (m === "GET") return { data: $2 };
}
if (p === "/test/foo/baz") {
} else if (p === "/test/foo/baz") {
if (m === "GET") return { data: $3 };
}
if (p === "/test/fooo") {
} else if (p === "/test/fooo") {
if (m === "GET") return { data: $4 };
}
if (p === "/another/path") {
} else if (p === "/another/path") {
if (m === "GET") return { data: $5 };
}
if (p === "/static%3Apath/*/**") {
} else if (p === "/static%3Apath/*/**") {
if (m === "GET") return { data: $6 };
}
let s = p.split("/"),
l = s.length - 1;
if (s[1] === "test") {
if (s[2] === "foo") {
if (l === 3 || l === 2) {
if (m === "GET") return { data: $7, params: { _0: s[3] } };
}
if (m === "GET") return { data: $8, params: { _: s.slice(3).join("/") } };
}
if (l === 2 || l === 1) {
if (m === "GET") if (l >= 2) return { data: $9, params: { id: s[2] } };
}
if (s[3] === "y") {
if (l === 3) {
if (m === "GET") return { data: $10, params: { idY: s[2] } };
l = s.length;
if (l > 1) {
if (s[1] === "test") {
if (l > 2) {
if (s[2] === "foo") {
if (l === 4 || l === 3) {
if (m === "GET") return { data: $7, params: { _0: s[3] } };
}
if (m === "GET")
return { data: $8, params: { _: s.slice(3).join("/") } };
}
}
if (s[4] === "z") {
if (l === 3 || l === 2) {
if (m === "GET") if (l > 2) return { data: $9, params: { id: s[2] } };
} else if (s[3] === "y") {
if (l === 4) {
if (m === "GET") return { data: $11, params: { idYZ: s[2] } };
if (m === "GET") return { data: $10, params: { idY: s[2] } };
} else if (s[4] === "z") {
if (l === 5) {
if (m === "GET") return { data: $11, params: { idYZ: s[2] } };
}
}
}
} else if (s[1] === "wildcard") {
if (m === "GET")
return { data: $12, params: { _: s.slice(2).join("/") } };
}
}
if (s[1] === "wildcard") {
if (m === "GET") return { data: $12, params: { _: s.slice(2).join("/") } };
}
if (m === "GET") return { data: $13, params: { _: s.slice(1).join("/") } };
};