Skip to content

Commit

Permalink
fix: consider max depth when multiple placeholders are candidate (#96)
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 committed Mar 25, 2024
1 parent 1b5d3e9 commit 56a908e
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 11 deletions.
35 changes: 25 additions & 10 deletions src/router.ts
Expand Up @@ -63,15 +63,22 @@ function lookup<T extends RadixNodeData = RadixNodeData>(
// Exact matches take precedence over placeholders
const nextNode = node.children.get(section);
if (nextNode === undefined) {
node = node.placeholderChildNode;
if (node === null) {
break;
if (node && node.placeholderChildren.length > 1) {
// https://github.com/unjs/radix3/issues/95
const remaining = sections.length - i;
node =
node.placeholderChildren.find((c) => c.maxDepth === remaining) ||
null;
} else {
if (node.paramName) {
params[node.paramName] = section;
}
paramsFound = true;
node = node.placeholderChildren[0] || null;
}
if (!node) {
break;
}
if (node.paramName) {
params[node.paramName] = section;
}
paramsFound = true;
} else {
node = nextNode;
}
Expand Down Expand Up @@ -106,6 +113,8 @@ function insert(ctx: RadixRouterContext, path: string, data: any) {

let _unnamedPlaceholderCtr = 0;

const matchedNodes = [node];

for (const section of sections) {
let childNode: RadixNode<RadixNodeData> | undefined;

Expand All @@ -122,18 +131,23 @@ function insert(ctx: RadixRouterContext, path: string, data: any) {
if (type === NODE_TYPES.PLACEHOLDER) {
childNode.paramName =
section === "*" ? `_${_unnamedPlaceholderCtr++}` : section.slice(1);
node.placeholderChildNode = childNode;
node.placeholderChildren.push(childNode);
isStaticRoute = false;
} else if (type === NODE_TYPES.WILDCARD) {
node.wildcardChildNode = childNode;
childNode.paramName = section.slice(3 /* "**:" */) || "_";
isStaticRoute = false;
}

matchedNodes.push(childNode);
node = childNode;
}
}

for (const [depth, node] of matchedNodes.entries()) {
node.maxDepth = Math.max(matchedNodes.length - depth, node.maxDepth || 0);
}

// Store whatever data was provided into the node
node.data = data;

Expand Down Expand Up @@ -164,7 +178,7 @@ function remove(ctx: RadixRouterContext, path: string) {
if (Object.keys(node.children).length === 0 && node.parent) {
node.parent.children.delete(lastSection);
node.parent.wildcardChildNode = null;
node.parent.placeholderChildNode = null;
node.parent.placeholderChildren = [];
}
success = true;
}
Expand All @@ -175,12 +189,13 @@ function remove(ctx: RadixRouterContext, path: string) {
function createRadixNode(options: Partial<RadixNode> = {}): RadixNode {
return {
type: options.type || NODE_TYPES.NORMAL,
maxDepth: 0,
parent: options.parent || null,
children: new Map(),
data: options.data || null,
paramName: options.paramName || null,
wildcardChildNode: null,
placeholderChildNode: null,
placeholderChildren: [],
};
}

Expand Down
3 changes: 2 additions & 1 deletion src/types.ts
Expand Up @@ -18,12 +18,13 @@ export type MatchedRoute<T extends RadixNodeData = RadixNodeData> = Omit<

export interface RadixNode<T extends RadixNodeData = RadixNodeData> {
type: NODE_TYPE;
maxDepth: number;
parent: RadixNode<T> | null;
children: Map<string, RadixNode<T>>;
data: RadixNodeData | null;
paramName: string | null;
wildcardChildNode: RadixNode<T> | null;
placeholderChildNode: RadixNode<T> | null;
placeholderChildren: RadixNode<T>[];
}

export interface RadixRouterOptions {
Expand Down
34 changes: 34 additions & 0 deletions tests/router.test.ts
Expand Up @@ -62,6 +62,40 @@ describe("Router lookup", function () {
},
},
);

testRouter(["/", "/:a", "/:a/:y/:x/:b", "/:a/:x/:b", "/:a/:b"], {
"/": { path: "/" },
"/a": {
path: "/:a",
params: {
a: "a",
},
},
"/a/b": {
path: "/:a/:b",
params: {
a: "a",
b: "b",
},
},
"/a/x/b": {
path: "/:a/:x/:b",
params: {
a: "a",
b: "b",
x: "x",
},
},
"/a/y/x/b": {
path: "/:a/:y/:x/:b",
params: {
a: "a",
b: "b",
x: "x",
y: "y",
},
},
});
});

describe("should be able to perform wildcard lookups", function () {
Expand Down

0 comments on commit 56a908e

Please sign in to comment.