diff --git a/src/router/reg-exp-router/router.ts b/src/router/reg-exp-router/router.ts index a9f6285c4..0412ffbb0 100644 --- a/src/router/reg-exp-router/router.ts +++ b/src/router/reg-exp-router/router.ts @@ -14,11 +14,12 @@ type StaticMap = Record> type Matcher = [RegExp, HandlerData[], StaticMap] type HandlerWithMetadata = [T, number] // [handler, paramCount] +const createEmptyRecord = () => Object.create(null) const emptyParam: string[] = [] // eslint-disable-next-line @typescript-eslint/no-explicit-any -const nullMatcher: Matcher = [/^$/, [], Object.create(null)] +const nullMatcher: Matcher = [/^$/, [], createEmptyRecord()] -let wildcardRegExpCache: Record = Object.create(null) +let wildcardRegExpCache: Record = createEmptyRecord() function buildWildcardRegExp(path: string): RegExp { return (wildcardRegExpCache[path] ??= new RegExp( path === '*' @@ -30,7 +31,7 @@ function buildWildcardRegExp(path: string): RegExp { } function clearWildcardRegExpCache() { - wildcardRegExpCache = Object.create(null) + wildcardRegExpCache = createEmptyRecord() } function buildMatcherFromPreprocessedRoutes( @@ -50,11 +51,11 @@ function buildMatcherFromPreprocessedRoutes( isStaticA ? 1 : isStaticB ? -1 : pathA.length - pathB.length ) - const staticMap: StaticMap = Object.create(null) + const staticMap: StaticMap = createEmptyRecord() for (let i = 0, j = -1, len = routesWithStaticPathFlag.length; i < len; i++) { const [pathErrorCheckOnly, path, handlers] = routesWithStaticPathFlag[i] if (pathErrorCheckOnly) { - staticMap[path] = [handlers.map(([h]) => [h, Object.create(null)]), emptyParam] + staticMap[path] = [handlers.map(([h]) => [h, createEmptyRecord()]), emptyParam] } else { j++ } @@ -71,7 +72,7 @@ function buildMatcherFromPreprocessedRoutes( } handlerData[j] = handlers.map(([h, paramCount]) => { - const paramIndexMap: ParamIndexMap = Object.create(null) + const paramIndexMap: ParamIndexMap = createEmptyRecord() paramCount -= 1 for (; paramCount >= 0; paramCount--) { const [key, value] = paramAssoc[paramCount] @@ -127,8 +128,8 @@ export class RegExpRouter implements Router { #routes?: Record[]>> constructor() { - this.#middleware = { [METHOD_NAME_ALL]: Object.create(null) } - this.#routes = { [METHOD_NAME_ALL]: Object.create(null) } + this.#middleware = { [METHOD_NAME_ALL]: createEmptyRecord() } + this.#routes = { [METHOD_NAME_ALL]: createEmptyRecord() } } add(method: string, path: string, handler: T) { @@ -141,7 +142,7 @@ export class RegExpRouter implements Router { if (!middleware[method]) { ;[middleware, routes].forEach((handlerMap) => { - handlerMap[method] = Object.create(null) + handlerMap[method] = createEmptyRecord() Object.keys(handlerMap[METHOD_NAME_ALL]).forEach((p) => { handlerMap[method][p] = [...handlerMap[METHOD_NAME_ALL][p]] }) @@ -231,7 +232,7 @@ export class RegExpRouter implements Router { } #buildAllMatchers(): Record | null> { - const matchers: Record | null> = Object.create(null) + const matchers: Record | null> = createEmptyRecord() Object.keys(this.#routes!) .concat(Object.keys(this.#middleware!)) diff --git a/src/router/trie-router/node.ts b/src/router/trie-router/node.ts index 94ab4de19..9bff18a4d 100644 --- a/src/router/trie-router/node.ts +++ b/src/router/trie-router/node.ts @@ -13,27 +13,28 @@ type HandlerParamsSet = HandlerSet & { params: Record } +const createEmptyRecord = () => Object.create(null) + +const emptyParams = createEmptyRecord() + export class Node { - #methods: Record>[] + #methods: Record>[] = [] - #children: Record> - #patterns: Pattern[] + #children: Record> = createEmptyRecord() + #patterns: Pattern[] = [] #order: number = 0 - #params: Record = Object.create(null) + #params: Record = createEmptyRecord() - constructor(method?: string, handler?: T, children?: Record>) { - this.#children = children || Object.create(null) - this.#methods = [] + constructor(method?: string, handler?: T) { if (method && handler) { - const m: Record> = Object.create(null) + const m: Record> = createEmptyRecord() m[method] = { handler, possibleKeys: [], score: 0 } this.#methods = [m] } - this.#patterns = [] } insert(method: string, path: string, handler: T): Node { - this.#order = ++this.#order + this.#order++ // eslint-disable-next-line @typescript-eslint/no-this-alias let curNode: Node = this @@ -43,10 +44,10 @@ export class Node { for (let i = 0, len = parts.length; i < len; i++) { const p: string = parts[i] + const pattern = getPattern(p) - if (Object.keys(curNode.#children).includes(p)) { + if (curNode.#children[p]) { curNode = curNode.#children[p] - const pattern = getPattern(p) if (pattern) { possibleKeys.push(pattern[1]) } @@ -55,7 +56,6 @@ export class Node { curNode.#children[p] = new Node() - const pattern = getPattern(p) if (pattern) { curNode.#patterns.push(pattern) possibleKeys.push(pattern[1]) @@ -63,7 +63,7 @@ export class Node { curNode = curNode.#children[p] } - const m: Record> = Object.create(null) + const m: Record> = createEmptyRecord() const handlerSet: HandlerSet = { handler, @@ -77,7 +77,6 @@ export class Node { return curNode } - // getHandlerSets #getHandlerSets( node: Node, method: string, @@ -87,10 +86,10 @@ export class Node { const handlerSets: HandlerParamsSet[] = [] for (let i = 0, len = node.#methods.length; i < len; i++) { const m = node.#methods[i] - const handlerSet = (m[method] || m[METHOD_NAME_ALL]) as HandlerParamsSet + const handlerSet = (m[method] || m[METHOD_NAME_ALL]) as HandlerParamsSet | undefined const processedSet: Record = {} - if (handlerSet !== undefined) { - handlerSet.params = Object.create(null) + if (handlerSet) { + handlerSet.params = createEmptyRecord() for (let i = 0, len = handlerSet.possibleKeys.length; i < len; i++) { const key = handlerSet.possibleKeys[i] const processed = processedSet[handlerSet.score] @@ -107,7 +106,6 @@ export class Node { search(method: string, path: string): [[T, Params][]] { const handlerSets: HandlerParamsSet[] = [] - this.#params = Object.create(null) // eslint-disable-next-line @typescript-eslint/no-this-alias const curNode: Node = this @@ -129,17 +127,10 @@ export class Node { // '/hello/*' => match '/hello' if (nextNode.#children['*']) { handlerSets.push( - ...this.#getHandlerSets( - nextNode.#children['*'], - method, - node.#params, - Object.create(null) - ) + ...this.#getHandlerSets(nextNode.#children['*'], method, node.#params, emptyParams) ) } - handlerSets.push( - ...this.#getHandlerSets(nextNode, method, node.#params, Object.create(null)) - ) + handlerSets.push(...this.#getHandlerSets(nextNode, method, node.#params, emptyParams)) } else { tempNodes.push(nextNode) } @@ -153,12 +144,12 @@ export class Node { // Wildcard // '/hello/*/foo' => match /hello/bar/foo if (pattern === '*') { - const astNode = node.#children['*'] - if (astNode) { + const wildcardNode = node.#children['*'] + if (wildcardNode) { handlerSets.push( - ...this.#getHandlerSets(astNode, method, node.#params, Object.create(null)) + ...this.#getHandlerSets(wildcardNode, method, node.#params, createEmptyRecord()) ) - tempNodes.push(astNode) + tempNodes.push(wildcardNode) } continue } @@ -173,13 +164,16 @@ export class Node { // `/js/:filename{[a-z]+.js}` => match /js/chunk/123.js const restPathString = parts.slice(i).join('/') - if (matcher instanceof RegExp && matcher.test(restPathString)) { + + const isMatcher = matcher instanceof RegExp + + if (isMatcher && matcher.test(restPathString)) { params[name] = restPathString handlerSets.push(...this.#getHandlerSets(child, method, node.#params, params)) continue } - if (matcher === true || matcher.test(part)) { + if (!isMatcher || matcher.test(part)) { params[name] = part if (isLast) { handlerSets.push(...this.#getHandlerSets(child, method, params, node.#params)) @@ -205,6 +199,8 @@ export class Node { }) } + this.#params = createEmptyRecord() + return [handlerSets.map(({ handler, params }) => [handler, params] as [T, Params])] } } diff --git a/src/utils/body.ts b/src/utils/body.ts index de94080c3..da59dadff 100644 --- a/src/utils/body.ts +++ b/src/utils/body.ts @@ -91,11 +91,12 @@ interface ParseBody { options?: Partial ): Promise } -export const parseBody: ParseBody = async ( - request: HonoRequest | Request, - options = Object.create(null) -) => { - const { all = false, dot = false } = options +export const parseBody: ParseBody = async (request: HonoRequest | Request, options = {}) => { + const { all, dot } = { + all: false, + dot: false, + ...options, + } const headers = request instanceof HonoRequest ? request.raw.headers : request.headers const contentType = headers.get('Content-Type') diff --git a/src/utils/url.ts b/src/utils/url.ts index 1c7c168b5..c08bf1c84 100644 --- a/src/utils/url.ts +++ b/src/utils/url.ts @@ -52,7 +52,6 @@ export const getPattern = (label: string): Pattern | null => { // * => wildcard // :id{[0-9]+} => ([0-9]+) // :id => (.+) - //const name = '' if (label === '*') { return '*' @@ -61,11 +60,7 @@ export const getPattern = (label: string): Pattern | null => { const match = label.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/) if (match) { if (!patternCache[label]) { - if (match[2]) { - patternCache[label] = [label, match[1], new RegExp('^' + match[2] + '$')] - } else { - patternCache[label] = [label, match[1], true] - } + patternCache[label] = [label, match[1], match[2] ? new RegExp('^' + match[2] + '$') : true] } return patternCache[label]