2023-10-16 01:39:37 +02:00
|
|
|
import type { Result, Router, Params } from '../../router.ts'
|
|
|
|
import { METHOD_NAME_ALL, UnsupportedPathError } from '../../router.ts'
|
2023-04-26 03:15:45 +02:00
|
|
|
|
2023-06-03 02:08:01 +02:00
|
|
|
type Route<T> = [RegExp, string, T] // [pattern, method, handler, path]
|
2023-04-26 03:15:45 +02:00
|
|
|
|
|
|
|
export class PatternRouter<T> implements Router<T> {
|
2023-05-17 17:05:28 +02:00
|
|
|
name: string = 'PatternRouter'
|
2023-04-26 03:15:45 +02:00
|
|
|
private routes: Route<T>[] = []
|
|
|
|
|
|
|
|
add(method: string, path: string, handler: T) {
|
2023-04-30 14:18:32 +02:00
|
|
|
const endsWithWildcard = path[path.length - 1] === '*'
|
2023-04-26 03:15:45 +02:00
|
|
|
if (endsWithWildcard) {
|
|
|
|
path = path.slice(0, -2)
|
|
|
|
}
|
|
|
|
|
2024-02-14 10:02:48 +01:00
|
|
|
const parts = path.match(/\/?(:\w+(?:{(?:(?:{[\d,]+})|[^}])+})?)|\/?[^\/\?]+|(\?)/g) || []
|
2023-04-26 03:15:45 +02:00
|
|
|
if (parts[parts.length - 1] === '?') {
|
|
|
|
this.add(method, parts.slice(0, parts.length - 2).join(''), handler)
|
|
|
|
parts.pop()
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let i = 0, len = parts.length; i < len; i++) {
|
|
|
|
const match = parts[i].match(/^\/:([^{]+)(?:{(.*)})?/)
|
|
|
|
if (match) {
|
2023-10-16 01:39:37 +02:00
|
|
|
parts[i] = `/(?<${match[1]}>${match[2] || '[^/]+'})`
|
2023-04-26 03:15:45 +02:00
|
|
|
} else if (parts[i] === '/*') {
|
|
|
|
parts[i] = '/[^/]+'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-16 01:39:37 +02:00
|
|
|
let re
|
|
|
|
try {
|
|
|
|
re = new RegExp(`^${parts.join('')}${endsWithWildcard ? '' : '/?$'}`)
|
|
|
|
} catch (e) {
|
|
|
|
throw new UnsupportedPathError()
|
|
|
|
}
|
|
|
|
this.routes.push([re, method, handler])
|
2023-04-26 03:15:45 +02:00
|
|
|
}
|
|
|
|
|
2023-10-16 01:39:37 +02:00
|
|
|
match(method: string, path: string): Result<T> {
|
|
|
|
const handlers: [T, Params][] = []
|
2023-06-03 02:08:01 +02:00
|
|
|
|
2023-04-26 03:15:45 +02:00
|
|
|
for (const [pattern, routeMethod, handler] of this.routes) {
|
|
|
|
if (routeMethod === METHOD_NAME_ALL || routeMethod === method) {
|
|
|
|
const match = pattern.exec(path)
|
|
|
|
if (match) {
|
2023-10-16 01:39:37 +02:00
|
|
|
handlers.push([handler, match.groups || {}])
|
2023-04-26 03:15:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-06-03 02:08:01 +02:00
|
|
|
|
2023-10-16 01:39:37 +02:00
|
|
|
return [handlers]
|
2023-04-26 03:15:45 +02:00
|
|
|
}
|
|
|
|
}
|