reworked dynamic parameters to be positional rather than fixed
This commit is contained in:
@ -49,6 +49,20 @@ router
|
||||
);
|
||||
});
|
||||
|
||||
router
|
||||
.get("/user/:id/:name/*", (c) => {
|
||||
return c.html(
|
||||
`id = ${c.params.id}, name = ${c.params.name}, rest = ${c.params.restOfThePath}`,
|
||||
);
|
||||
});
|
||||
|
||||
router
|
||||
.get("/user/:idButDifferent", (c) => {
|
||||
return c.html(
|
||||
`idButDifferent = ${c.params.idButDifferent}`,
|
||||
);
|
||||
});
|
||||
|
||||
export default {
|
||||
async fetch(req, connInfo) {
|
||||
return await router.handleRequest(req, connInfo);
|
||||
|
||||
@ -41,7 +41,6 @@ class HttpRouter {
|
||||
method: string,
|
||||
handler: RequestHandler<string>,
|
||||
): HttpRouter;
|
||||
|
||||
add(
|
||||
path: string | string[],
|
||||
method: string,
|
||||
@ -103,7 +102,7 @@ class HttpRouter {
|
||||
? this.pathPreprocessor(c.path)
|
||||
: c.path;
|
||||
|
||||
let params: Params<string> = {};
|
||||
let params: string[] = [];
|
||||
|
||||
const handler = this.routerTree
|
||||
.find(path)
|
||||
@ -152,6 +151,10 @@ class HttpRouter {
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
private setParams(path: string, params: string[]): Params<string> {
|
||||
path.split("/").filter((segmet) => segmet.startsWith(":"));
|
||||
}
|
||||
}
|
||||
|
||||
export type ExtractRouteParams<T extends string> = T extends string
|
||||
|
||||
@ -6,6 +6,7 @@ const DEFAULT_PATH_SEPARATOR = "/";
|
||||
|
||||
interface Node<T> {
|
||||
handler: Option<T>;
|
||||
paramNames: string[];
|
||||
addChild(
|
||||
segment: string,
|
||||
wildcardSymbol: string,
|
||||
@ -22,6 +23,7 @@ class StaticNode<T> implements Node<T> {
|
||||
protected dynamicChild: Option<DynamicNode<T>> = none;
|
||||
protected wildcardChild: Option<WildcardNode<T>> = none;
|
||||
public handler: Option<T> = none;
|
||||
public paramNames: string[] = [];
|
||||
|
||||
constructor(handler?: T) {
|
||||
this.handler = fromNullableVal(handler);
|
||||
@ -33,8 +35,8 @@ class StaticNode<T> implements Node<T> {
|
||||
return child;
|
||||
}
|
||||
|
||||
setDynamicChild(paramName: string, handler?: T): DynamicNode<T> {
|
||||
const child = new DynamicNode(paramName, handler);
|
||||
setDynamicChild(handler?: T): DynamicNode<T> {
|
||||
const child = new DynamicNode(handler);
|
||||
this.dynamicChild = some(child);
|
||||
return child;
|
||||
}
|
||||
@ -55,8 +57,7 @@ class StaticNode<T> implements Node<T> {
|
||||
return this.setWildcardNode(handler);
|
||||
}
|
||||
if (segment.startsWith(paramPrefixSymbol)) {
|
||||
const paramName = segment.slice(paramPrefixSymbol.length);
|
||||
return this.setDynamicChild(paramName, handler);
|
||||
return this.setDynamicChild(handler);
|
||||
}
|
||||
return this.addStaticChild(segment, handler);
|
||||
}
|
||||
@ -91,7 +92,6 @@ class StaticNode<T> implements Node<T> {
|
||||
// TODO: get rid of fixed param name
|
||||
class DynamicNode<T> extends StaticNode<T> implements Node<T> {
|
||||
constructor(
|
||||
public readonly paramName: string,
|
||||
handler?: T,
|
||||
) {
|
||||
super(handler);
|
||||
@ -104,6 +104,7 @@ class DynamicNode<T> extends StaticNode<T> implements Node<T> {
|
||||
|
||||
class WildcardNode<T> implements Node<T> {
|
||||
public handler: Option<T>;
|
||||
public paramNames: string[] = [];
|
||||
|
||||
constructor(handler?: T) {
|
||||
this.handler = fromNullableVal(handler);
|
||||
@ -144,6 +145,7 @@ export class RouterTree<T> {
|
||||
|
||||
public add(path: string, handler: T): void {
|
||||
const segments = this.splitPath(path);
|
||||
const paramNames: string[] = this.extractParams(segments);
|
||||
let current: TreeNode<T> = this.root;
|
||||
|
||||
for (const segment of segments) {
|
||||
@ -157,15 +159,21 @@ export class RouterTree<T> {
|
||||
)
|
||||
);
|
||||
|
||||
if (current.isWildcardNode()) break;
|
||||
if (current.isWildcardNode()) {
|
||||
current.paramNames = paramNames;
|
||||
current.paramNames.push("restOfThePath");
|
||||
current.handler = some(handler);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
current.paramNames = paramNames;
|
||||
current.handler = some(handler);
|
||||
}
|
||||
|
||||
public find(path: string): Option<RouteMatch<T>> {
|
||||
const segments = this.splitPath(path);
|
||||
const params: Record<string, string> = {};
|
||||
const paramValues: string[] = [];
|
||||
let current: TreeNode<T> = this.root;
|
||||
let i = 0;
|
||||
|
||||
@ -175,7 +183,7 @@ export class RouterTree<T> {
|
||||
|
||||
const nextNode = current.getChild(segment).ifSome((child) => {
|
||||
if (child.isDynamicNode()) {
|
||||
params[child.paramName] = segment;
|
||||
paramValues.push(segment);
|
||||
}
|
||||
current = child;
|
||||
});
|
||||
@ -186,10 +194,16 @@ export class RouterTree<T> {
|
||||
if (current.isWildcardNode()) {
|
||||
const rest = segments.slice(i - 1);
|
||||
if (rest.length > 0) {
|
||||
params["restOfThePath"] = rest.join(this.pathSeparator);
|
||||
paramValues.push(rest.join(this.pathSeparator));
|
||||
}
|
||||
}
|
||||
|
||||
const params: Params = {};
|
||||
|
||||
for (let i = 0; i < paramValues.length; i++) {
|
||||
params[current.paramNames[i]] = paramValues[i];
|
||||
}
|
||||
|
||||
return current.handler.map((value) => ({ value, params }));
|
||||
}
|
||||
|
||||
@ -214,6 +228,16 @@ export class RouterTree<T> {
|
||||
const trimmed = path.trim().replace(/^\/+/, "").replace(/\/+$/, "");
|
||||
return trimmed ? trimmed.split(this.pathSeparator) : [];
|
||||
}
|
||||
|
||||
public extractParams(segments: string[]): string[] {
|
||||
return segments.filter((segment) =>
|
||||
segment.startsWith(this.paramPrefixSymbol)
|
||||
).map((segment) => this.stripParamPrefix(segment));
|
||||
}
|
||||
|
||||
public stripParamPrefix(segment: string): string {
|
||||
return segment.slice(this.paramPrefixSymbol.length);
|
||||
}
|
||||
}
|
||||
|
||||
export type Params = Record<string, string>;
|
||||
|
||||
Reference in New Issue
Block a user