mirror of
https://github.com/honojs/hono.git
synced 2024-11-21 10:08:58 +01:00
refactor(router): use #
for private props to reduce the minified file size (#3660)
This commit is contained in:
parent
7e17b76ce9
commit
7b308358f4
@ -10,7 +10,7 @@ const splitPathRe = /\/(:\w+(?:{(?:(?:{[\d,]+})|[^}])+})?)|\/[^\/\?]+|(\?)/g
|
||||
const splitByStarRe = /\*/
|
||||
export class LinearRouter<T> implements Router<T> {
|
||||
name: string = 'LinearRouter'
|
||||
routes: [string, string, T][] = []
|
||||
#routes: [string, string, T][] = []
|
||||
|
||||
add(method: string, path: string, handler: T) {
|
||||
for (
|
||||
@ -18,14 +18,14 @@ export class LinearRouter<T> implements Router<T> {
|
||||
i < len;
|
||||
i++
|
||||
) {
|
||||
this.routes.push([method, paths[i], handler])
|
||||
this.#routes.push([method, paths[i], handler])
|
||||
}
|
||||
}
|
||||
|
||||
match(method: string, path: string): Result<T> {
|
||||
const handlers: [T, Params][] = []
|
||||
ROUTES_LOOP: for (let i = 0, len = this.routes.length; i < len; i++) {
|
||||
const [routeMethod, routePath, handler] = this.routes[i]
|
||||
ROUTES_LOOP: for (let i = 0, len = this.#routes.length; i < len; i++) {
|
||||
const [routeMethod, routePath, handler] = this.#routes[i]
|
||||
if (routeMethod === method || routeMethod === METHOD_NAME_ALL) {
|
||||
if (routePath === '*' || routePath === '/*') {
|
||||
handlers.push([handler, emptyParams])
|
||||
|
@ -43,9 +43,9 @@ function compareKey(a: string, b: string): number {
|
||||
}
|
||||
|
||||
export class Node {
|
||||
index?: number
|
||||
varIndex?: number
|
||||
children: Record<string, Node> = Object.create(null)
|
||||
#index?: number
|
||||
#varIndex?: number
|
||||
#children: Record<string, Node> = Object.create(null)
|
||||
|
||||
insert(
|
||||
tokens: readonly string[],
|
||||
@ -55,14 +55,14 @@ export class Node {
|
||||
pathErrorCheckOnly: boolean
|
||||
): void {
|
||||
if (tokens.length === 0) {
|
||||
if (this.index !== undefined) {
|
||||
if (this.#index !== undefined) {
|
||||
throw PATH_ERROR
|
||||
}
|
||||
if (pathErrorCheckOnly) {
|
||||
return
|
||||
}
|
||||
|
||||
this.index = index
|
||||
this.#index = index
|
||||
return
|
||||
}
|
||||
|
||||
@ -88,10 +88,10 @@ export class Node {
|
||||
}
|
||||
}
|
||||
|
||||
node = this.children[regexpStr]
|
||||
node = this.#children[regexpStr]
|
||||
if (!node) {
|
||||
if (
|
||||
Object.keys(this.children).some(
|
||||
Object.keys(this.#children).some(
|
||||
(k) => k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR
|
||||
)
|
||||
) {
|
||||
@ -100,19 +100,19 @@ export class Node {
|
||||
if (pathErrorCheckOnly) {
|
||||
return
|
||||
}
|
||||
node = this.children[regexpStr] = new Node()
|
||||
node = this.#children[regexpStr] = new Node()
|
||||
if (name !== '') {
|
||||
node.varIndex = context.varIndex++
|
||||
node.#varIndex = context.varIndex++
|
||||
}
|
||||
}
|
||||
if (!pathErrorCheckOnly && name !== '') {
|
||||
paramMap.push([name, node.varIndex as number])
|
||||
paramMap.push([name, node.#varIndex as number])
|
||||
}
|
||||
} else {
|
||||
node = this.children[token]
|
||||
node = this.#children[token]
|
||||
if (!node) {
|
||||
if (
|
||||
Object.keys(this.children).some(
|
||||
Object.keys(this.#children).some(
|
||||
(k) =>
|
||||
k.length > 1 && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR
|
||||
)
|
||||
@ -122,7 +122,7 @@ export class Node {
|
||||
if (pathErrorCheckOnly) {
|
||||
return
|
||||
}
|
||||
node = this.children[token] = new Node()
|
||||
node = this.#children[token] = new Node()
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,21 +130,21 @@ export class Node {
|
||||
}
|
||||
|
||||
buildRegExpStr(): string {
|
||||
const childKeys = Object.keys(this.children).sort(compareKey)
|
||||
const childKeys = Object.keys(this.#children).sort(compareKey)
|
||||
|
||||
const strList = childKeys.map((k) => {
|
||||
const c = this.children[k]
|
||||
const c = this.#children[k]
|
||||
return (
|
||||
(typeof c.varIndex === 'number'
|
||||
? `(${k})@${c.varIndex}`
|
||||
(typeof c.#varIndex === 'number'
|
||||
? `(${k})@${c.#varIndex}`
|
||||
: regExpMetaChars.has(k)
|
||||
? `\\${k}`
|
||||
: k) + c.buildRegExpStr()
|
||||
)
|
||||
})
|
||||
|
||||
if (typeof this.index === 'number') {
|
||||
strList.unshift(`#${this.index}`)
|
||||
if (typeof this.#index === 'number') {
|
||||
strList.unshift(`#${this.#index}`)
|
||||
}
|
||||
|
||||
if (strList.length === 0) {
|
||||
|
@ -123,16 +123,17 @@ function findMiddleware<T>(
|
||||
|
||||
export class RegExpRouter<T> implements Router<T> {
|
||||
name: string = 'RegExpRouter'
|
||||
middleware?: Record<string, Record<string, HandlerWithMetadata<T>[]>>
|
||||
routes?: Record<string, Record<string, HandlerWithMetadata<T>[]>>
|
||||
#middleware?: Record<string, Record<string, HandlerWithMetadata<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]: Object.create(null) }
|
||||
this.#routes = { [METHOD_NAME_ALL]: Object.create(null) }
|
||||
}
|
||||
|
||||
add(method: string, path: string, handler: T) {
|
||||
const { middleware, routes } = this
|
||||
const middleware = this.#middleware
|
||||
const routes = this.#routes
|
||||
|
||||
if (!middleware || !routes) {
|
||||
throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT)
|
||||
@ -232,14 +233,14 @@ export class RegExpRouter<T> implements Router<T> {
|
||||
#buildAllMatchers(): Record<string, Matcher<T> | null> {
|
||||
const matchers: Record<string, Matcher<T> | null> = Object.create(null)
|
||||
|
||||
Object.keys(this.routes!)
|
||||
.concat(Object.keys(this.middleware!))
|
||||
Object.keys(this.#routes!)
|
||||
.concat(Object.keys(this.#middleware!))
|
||||
.forEach((method) => {
|
||||
matchers[method] ||= this.#buildMatcher(method)
|
||||
})
|
||||
|
||||
// Release cache
|
||||
this.middleware = this.routes = undefined
|
||||
this.#middleware = this.#routes = undefined
|
||||
|
||||
return matchers
|
||||
}
|
||||
@ -249,7 +250,7 @@ export class RegExpRouter<T> implements Router<T> {
|
||||
|
||||
let hasOwnRoute = method === METHOD_NAME_ALL
|
||||
|
||||
;[this.middleware!, this.routes!].forEach((r) => {
|
||||
;[this.#middleware!, this.#routes!].forEach((r) => {
|
||||
const ownRoute = r[method]
|
||||
? Object.keys(r[method]).map((path) => [path, r[method][path]])
|
||||
: []
|
||||
|
@ -4,8 +4,8 @@ import { Node } from './node'
|
||||
export type ReplacementMap = number[]
|
||||
|
||||
export class Trie {
|
||||
context: Context = { varIndex: 0 }
|
||||
root: Node = new Node()
|
||||
#context: Context = { varIndex: 0 }
|
||||
#root: Node = new Node()
|
||||
|
||||
insert(path: string, index: number, pathErrorCheckOnly: boolean): ParamAssocArray {
|
||||
const paramAssoc: ParamAssocArray = []
|
||||
@ -41,13 +41,13 @@ export class Trie {
|
||||
}
|
||||
}
|
||||
|
||||
this.root.insert(tokens, index, paramAssoc, this.context, pathErrorCheckOnly)
|
||||
this.#root.insert(tokens, index, paramAssoc, this.#context, pathErrorCheckOnly)
|
||||
|
||||
return paramAssoc
|
||||
}
|
||||
|
||||
buildRegExp(): [RegExp, ReplacementMap, ReplacementMap] {
|
||||
let regexp = this.root.buildRegExpStr()
|
||||
let regexp = this.#root.buildRegExpStr()
|
||||
if (regexp === '') {
|
||||
return [/^$/, [], []] // never match
|
||||
}
|
||||
|
@ -3,27 +3,29 @@ import { MESSAGE_MATCHER_IS_ALREADY_BUILT, UnsupportedPathError } from '../../ro
|
||||
|
||||
export class SmartRouter<T> implements Router<T> {
|
||||
name: string = 'SmartRouter'
|
||||
routers: Router<T>[] = []
|
||||
routes?: [string, string, T][] = []
|
||||
#routers: Router<T>[] = []
|
||||
#routes?: [string, string, T][] = []
|
||||
|
||||
constructor(init: Pick<SmartRouter<T>, 'routers'>) {
|
||||
Object.assign(this, init)
|
||||
constructor(init: { routers: Router<T>[] }) {
|
||||
this.#routers = init.routers
|
||||
}
|
||||
|
||||
add(method: string, path: string, handler: T) {
|
||||
if (!this.routes) {
|
||||
if (!this.#routes) {
|
||||
throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT)
|
||||
}
|
||||
|
||||
this.routes.push([method, path, handler])
|
||||
this.#routes.push([method, path, handler])
|
||||
}
|
||||
|
||||
match(method: string, path: string): Result<T> {
|
||||
if (!this.routes) {
|
||||
if (!this.#routes) {
|
||||
throw new Error('Fatal error')
|
||||
}
|
||||
|
||||
const { routers, routes } = this
|
||||
const routers = this.#routers
|
||||
const routes = this.#routes
|
||||
|
||||
const len = routers.length
|
||||
let i = 0
|
||||
let res
|
||||
@ -42,8 +44,8 @@ export class SmartRouter<T> implements Router<T> {
|
||||
}
|
||||
|
||||
this.match = router.match.bind(router)
|
||||
this.routers = [router]
|
||||
this.routes = undefined
|
||||
this.#routers = [router]
|
||||
this.#routes = undefined
|
||||
break
|
||||
}
|
||||
|
||||
@ -59,10 +61,10 @@ export class SmartRouter<T> implements Router<T> {
|
||||
}
|
||||
|
||||
get activeRouter(): Router<T> {
|
||||
if (this.routes || this.routers.length !== 1) {
|
||||
if (this.#routes || this.#routers.length !== 1) {
|
||||
throw new Error('No active router has been determined yet.')
|
||||
}
|
||||
|
||||
return this.routers[0]
|
||||
return this.#routers[0]
|
||||
}
|
||||
}
|
||||
|
@ -14,26 +14,26 @@ type HandlerParamsSet<T> = HandlerSet<T> & {
|
||||
}
|
||||
|
||||
export class Node<T> {
|
||||
methods: Record<string, HandlerSet<T>>[]
|
||||
#methods: Record<string, HandlerSet<T>>[]
|
||||
|
||||
children: Record<string, Node<T>>
|
||||
patterns: Pattern[]
|
||||
order: number = 0
|
||||
params: Record<string, string> = Object.create(null)
|
||||
#children: Record<string, Node<T>>
|
||||
#patterns: Pattern[]
|
||||
#order: number = 0
|
||||
#params: Record<string, string> = Object.create(null)
|
||||
|
||||
constructor(method?: string, handler?: T, children?: Record<string, Node<T>>) {
|
||||
this.children = children || Object.create(null)
|
||||
this.methods = []
|
||||
this.#children = children || Object.create(null)
|
||||
this.#methods = []
|
||||
if (method && handler) {
|
||||
const m: Record<string, HandlerSet<T>> = Object.create(null)
|
||||
m[method] = { handler, possibleKeys: [], score: 0 }
|
||||
this.methods = [m]
|
||||
this.#methods = [m]
|
||||
}
|
||||
this.patterns = []
|
||||
this.#patterns = []
|
||||
}
|
||||
|
||||
insert(method: string, path: string, handler: T): Node<T> {
|
||||
this.order = ++this.order
|
||||
this.#order = ++this.#order
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
let curNode: Node<T> = this
|
||||
@ -44,8 +44,8 @@ export class Node<T> {
|
||||
for (let i = 0, len = parts.length; i < len; i++) {
|
||||
const p: string = parts[i]
|
||||
|
||||
if (Object.keys(curNode.children).includes(p)) {
|
||||
curNode = curNode.children[p]
|
||||
if (Object.keys(curNode.#children).includes(p)) {
|
||||
curNode = curNode.#children[p]
|
||||
const pattern = getPattern(p)
|
||||
if (pattern) {
|
||||
possibleKeys.push(pattern[1])
|
||||
@ -53,14 +53,14 @@ export class Node<T> {
|
||||
continue
|
||||
}
|
||||
|
||||
curNode.children[p] = new Node()
|
||||
curNode.#children[p] = new Node()
|
||||
|
||||
const pattern = getPattern(p)
|
||||
if (pattern) {
|
||||
curNode.patterns.push(pattern)
|
||||
curNode.#patterns.push(pattern)
|
||||
possibleKeys.push(pattern[1])
|
||||
}
|
||||
curNode = curNode.children[p]
|
||||
curNode = curNode.#children[p]
|
||||
}
|
||||
|
||||
const m: Record<string, HandlerSet<T>> = Object.create(null)
|
||||
@ -68,11 +68,11 @@ export class Node<T> {
|
||||
const handlerSet: HandlerSet<T> = {
|
||||
handler,
|
||||
possibleKeys: possibleKeys.filter((v, i, a) => a.indexOf(v) === i),
|
||||
score: this.order,
|
||||
score: this.#order,
|
||||
}
|
||||
|
||||
m[method] = handlerSet
|
||||
curNode.methods.push(m)
|
||||
curNode.#methods.push(m)
|
||||
|
||||
return curNode
|
||||
}
|
||||
@ -85,8 +85,8 @@ export class Node<T> {
|
||||
params: Record<string, string>
|
||||
): HandlerParamsSet<T>[] {
|
||||
const handlerSets: HandlerParamsSet<T>[] = []
|
||||
for (let i = 0, len = node.methods.length; i < len; i++) {
|
||||
const m = node.methods[i]
|
||||
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 processedSet: Record<number, boolean> = {}
|
||||
if (handlerSet !== undefined) {
|
||||
@ -107,7 +107,7 @@ export class Node<T> {
|
||||
|
||||
search(method: string, path: string): [[T, Params][]] {
|
||||
const handlerSets: HandlerParamsSet<T>[] = []
|
||||
this.params = Object.create(null)
|
||||
this.#params = Object.create(null)
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const curNode: Node<T> = this
|
||||
@ -121,42 +121,42 @@ export class Node<T> {
|
||||
|
||||
for (let j = 0, len2 = curNodes.length; j < len2; j++) {
|
||||
const node = curNodes[j]
|
||||
const nextNode = node.children[part]
|
||||
const nextNode = node.#children[part]
|
||||
|
||||
if (nextNode) {
|
||||
nextNode.params = node.params
|
||||
nextNode.#params = node.#params
|
||||
if (isLast) {
|
||||
// '/hello/*' => match '/hello'
|
||||
if (nextNode.children['*']) {
|
||||
if (nextNode.#children['*']) {
|
||||
handlerSets.push(
|
||||
...this.#getHandlerSets(
|
||||
nextNode.children['*'],
|
||||
nextNode.#children['*'],
|
||||
method,
|
||||
node.params,
|
||||
node.#params,
|
||||
Object.create(null)
|
||||
)
|
||||
)
|
||||
}
|
||||
handlerSets.push(
|
||||
...this.#getHandlerSets(nextNode, method, node.params, Object.create(null))
|
||||
...this.#getHandlerSets(nextNode, method, node.#params, Object.create(null))
|
||||
)
|
||||
} else {
|
||||
tempNodes.push(nextNode)
|
||||
}
|
||||
}
|
||||
|
||||
for (let k = 0, len3 = node.patterns.length; k < len3; k++) {
|
||||
const pattern = node.patterns[k]
|
||||
for (let k = 0, len3 = node.#patterns.length; k < len3; k++) {
|
||||
const pattern = node.#patterns[k]
|
||||
|
||||
const params = { ...node.params }
|
||||
const params = { ...node.#params }
|
||||
|
||||
// Wildcard
|
||||
// '/hello/*/foo' => match /hello/bar/foo
|
||||
if (pattern === '*') {
|
||||
const astNode = node.children['*']
|
||||
const astNode = node.#children['*']
|
||||
if (astNode) {
|
||||
handlerSets.push(
|
||||
...this.#getHandlerSets(astNode, method, node.params, Object.create(null))
|
||||
...this.#getHandlerSets(astNode, method, node.#params, Object.create(null))
|
||||
)
|
||||
tempNodes.push(astNode)
|
||||
}
|
||||
@ -169,27 +169,27 @@ export class Node<T> {
|
||||
|
||||
const [key, name, matcher] = pattern
|
||||
|
||||
const child = node.children[key]
|
||||
const child = node.#children[key]
|
||||
|
||||
// `/js/:filename{[a-z]+.js}` => match /js/chunk/123.js
|
||||
const restPathString = parts.slice(i).join('/')
|
||||
if (matcher instanceof RegExp && matcher.test(restPathString)) {
|
||||
params[name] = restPathString
|
||||
handlerSets.push(...this.#getHandlerSets(child, method, node.params, params))
|
||||
handlerSets.push(...this.#getHandlerSets(child, method, node.#params, params))
|
||||
continue
|
||||
}
|
||||
|
||||
if (matcher === true || matcher.test(part)) {
|
||||
params[name] = part
|
||||
if (isLast) {
|
||||
handlerSets.push(...this.#getHandlerSets(child, method, params, node.params))
|
||||
if (child.children['*']) {
|
||||
handlerSets.push(...this.#getHandlerSets(child, method, params, node.#params))
|
||||
if (child.#children['*']) {
|
||||
handlerSets.push(
|
||||
...this.#getHandlerSets(child.children['*'], method, params, node.params)
|
||||
...this.#getHandlerSets(child.#children['*'], method, params, node.#params)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
child.params = params
|
||||
child.#params = params
|
||||
tempNodes.push(child)
|
||||
}
|
||||
}
|
||||
|
@ -4,25 +4,25 @@ import { Node } from './node'
|
||||
|
||||
export class TrieRouter<T> implements Router<T> {
|
||||
name: string = 'TrieRouter'
|
||||
node: Node<T>
|
||||
#node: Node<T>
|
||||
|
||||
constructor() {
|
||||
this.node = new Node()
|
||||
this.#node = new Node()
|
||||
}
|
||||
|
||||
add(method: string, path: string, handler: T) {
|
||||
const results = checkOptionalParameter(path)
|
||||
if (results) {
|
||||
for (let i = 0, len = results.length; i < len; i++) {
|
||||
this.node.insert(method, results[i], handler)
|
||||
this.#node.insert(method, results[i], handler)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
this.node.insert(method, path, handler)
|
||||
this.#node.insert(method, path, handler)
|
||||
}
|
||||
|
||||
match(method: string, path: string): Result<T> {
|
||||
return this.node.search(method, path)
|
||||
return this.#node.search(method, path)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user