Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: clean up and reduced code size #3711

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
21 changes: 11 additions & 10 deletions src/router/reg-exp-router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ type StaticMap<T> = Record<string, Result<T>>
type Matcher<T> = [RegExp, HandlerData<T>[], StaticMap<T>]
type HandlerWithMetadata<T> = [T, number] // [handler, paramCount]

const createEmptyRecord = () => Object.create(null)
const emptyParam: string[] = []
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const nullMatcher: Matcher<any> = [/^$/, [], Object.create(null)]
const nullMatcher: Matcher<any> = [/^$/, [], createEmptyRecord()]

let wildcardRegExpCache: Record<string, RegExp> = Object.create(null)
let wildcardRegExpCache: Record<string, RegExp> = createEmptyRecord()
function buildWildcardRegExp(path: string): RegExp {
return (wildcardRegExpCache[path] ??= new RegExp(
path === '*'
Expand All @@ -30,7 +31,7 @@ function buildWildcardRegExp(path: string): RegExp {
}

function clearWildcardRegExpCache() {
wildcardRegExpCache = Object.create(null)
wildcardRegExpCache = createEmptyRecord()
}

function buildMatcherFromPreprocessedRoutes<T>(
Expand All @@ -50,11 +51,11 @@ function buildMatcherFromPreprocessedRoutes<T>(
isStaticA ? 1 : isStaticB ? -1 : pathA.length - pathB.length
)

const staticMap: StaticMap<T> = Object.create(null)
const staticMap: StaticMap<T> = 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++
}
Expand All @@ -71,7 +72,7 @@ function buildMatcherFromPreprocessedRoutes<T>(
}

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]
Expand Down Expand Up @@ -127,8 +128,8 @@ export class RegExpRouter<T> implements Router<T> {
#routes?: Record<string, Record<string, HandlerWithMetadata<T>[]>>

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) {
Expand All @@ -141,7 +142,7 @@ export class RegExpRouter<T> implements Router<T> {

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]]
})
Expand Down Expand Up @@ -231,7 +232,7 @@ export class RegExpRouter<T> implements Router<T> {
}

#buildAllMatchers(): Record<string, Matcher<T> | null> {
const matchers: Record<string, Matcher<T> | null> = Object.create(null)
const matchers: Record<string, Matcher<T> | null> = createEmptyRecord()

Object.keys(this.#routes!)
.concat(Object.keys(this.#middleware!))
Expand Down
64 changes: 30 additions & 34 deletions src/router/trie-router/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,28 @@
params: Record<string, string>
}

const createEmptyRecord = () => Object.create(null)

const emptyParams = createEmptyRecord()

export class Node<T> {
#methods: Record<string, HandlerSet<T>>[]
#methods: Record<string, HandlerSet<T>>[] = []

#children: Record<string, Node<T>>
#patterns: Pattern[]
#children: Record<string, Node<T>> = createEmptyRecord()
#patterns: Pattern[] = []
#order: number = 0
#params: Record<string, string> = Object.create(null)
#params: Record<string, string> = createEmptyRecord()

constructor(method?: string, handler?: T, children?: Record<string, Node<T>>) {
this.#children = children || Object.create(null)
this.#methods = []
constructor(method?: string, handler?: T) {
if (method && handler) {
const m: Record<string, HandlerSet<T>> = Object.create(null)
const m: Record<string, HandlerSet<T>> = createEmptyRecord()
m[method] = { handler, possibleKeys: [], score: 0 }
this.#methods = [m]
}
this.#patterns = []
}

insert(method: string, path: string, handler: T): Node<T> {
this.#order = ++this.#order
this.#order++

// eslint-disable-next-line @typescript-eslint/no-this-alias
let curNode: Node<T> = this
Expand All @@ -43,10 +44,10 @@

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])
}
Expand All @@ -55,15 +56,14 @@

curNode.#children[p] = new Node()

const pattern = getPattern(p)
if (pattern) {
curNode.#patterns.push(pattern)
possibleKeys.push(pattern[1])
}
curNode = curNode.#children[p]
}

const m: Record<string, HandlerSet<T>> = Object.create(null)
const m: Record<string, HandlerSet<T>> = createEmptyRecord()

const handlerSet: HandlerSet<T> = {
handler,
Expand All @@ -77,7 +77,6 @@
return curNode
}

// getHandlerSets
#getHandlerSets(
node: Node<T>,
method: string,
Expand All @@ -87,10 +86,10 @@
const handlerSets: HandlerParamsSet<T>[] = []
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<T>
const handlerSet = (m[method] || m[METHOD_NAME_ALL]) as HandlerParamsSet<T> | undefined
const processedSet: Record<number, boolean> = {}
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]
Expand All @@ -107,7 +106,6 @@

search(method: string, path: string): [[T, Params][]] {
const handlerSets: HandlerParamsSet<T>[] = []
this.#params = Object.create(null)

// eslint-disable-next-line @typescript-eslint/no-this-alias
const curNode: Node<T> = this
Expand All @@ -129,17 +127,10 @@
// '/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)
}
Expand All @@ -153,12 +144,12 @@
// 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
}
Expand All @@ -173,13 +164,16 @@

// `/js/:filename{[a-z]+.js}` => match /js/chunk/123.js
const restPathString = parts.slice(i).join('/')
if (matcher instanceof RegExp && matcher.test(restPathString)) {

Check warning on line 167 in src/router/trie-router/node.ts

View check run for this annotation

Codecov / codecov/patch

src/router/trie-router/node.ts#L167

Added line #L167 was not covered by tests
const isMatcher = matcher instanceof RegExp

Check warning on line 169 in src/router/trie-router/node.ts

View check run for this annotation

Codecov / codecov/patch

src/router/trie-router/node.ts#L169

Added line #L169 was not covered by tests
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))
Expand All @@ -205,6 +199,8 @@
})
}

this.#params = createEmptyRecord()

Check warning on line 203 in src/router/trie-router/node.ts

View check run for this annotation

Codecov / codecov/patch

src/router/trie-router/node.ts#L203

Added line #L203 was not covered by tests
return [handlerSets.map(({ handler, params }) => [handler, params] as [T, Params])]
}
}
11 changes: 6 additions & 5 deletions src/utils/body.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,12 @@ interface ParseBody {
options?: Partial<ParseBodyOptions>
): Promise<T>
}
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')
Expand Down
7 changes: 1 addition & 6 deletions src/utils/url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ export const getPattern = (label: string): Pattern | null => {
// * => wildcard
// :id{[0-9]+} => ([0-9]+)
// :id => (.+)
//const name = ''

if (label === '*') {
return '*'
Expand All @@ -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]
Expand Down
Loading