0
0
mirror of https://github.com/honojs/hono.git synced 2024-12-01 11:51:01 +01:00
hono/deno_dist/utils/url.ts

135 lines
3.3 KiB
TypeScript
Raw Normal View History

2022-07-02 08:09:45 +02:00
export type Pattern = readonly [string, string, RegExp | true] | '*'
export const splitPath = (path: string): string[] => {
const paths = path.split(/\//) // faster than path.split('/')
if (paths[0] === '') {
paths.shift()
}
return paths
}
export const splitRoutingPath = (path: string): string[] => {
const groups: [string, string][] = [] // [mark, original string]
for (let i = 0; ; ) {
let replaced = false
path = path.replace(/\{[^}]+\}/g, (m) => {
const mark = `@\\${i}`
groups[i] = [mark, m]
i++
replaced = true
return mark
})
if (!replaced) {
break
}
}
const paths = path.split(/\//) // faster than path.split('/')
if (paths[0] === '') {
paths.shift()
}
for (let i = groups.length - 1; i >= 0; i--) {
const [mark] = groups[i]
for (let j = paths.length - 1; j >= 0; j--) {
if (paths[j].indexOf(mark) !== -1) {
paths[j] = paths[j].replace(mark, groups[i][1])
break
}
}
}
return paths
}
2022-07-02 08:09:45 +02:00
const patternCache: { [key: string]: Pattern } = {}
export const getPattern = (label: string): Pattern | null => {
// * => wildcard
// :id{[0-9]+} => ([0-9]+)
// :id => (.+)
//const name = ''
if (label === '*') {
return '*'
}
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]
}
}
return patternCache[label]
}
return null
}
2023-01-10 13:24:21 +01:00
export const getPathFromURL = (url: string, strict: boolean = true): [string, number] => {
2022-07-02 08:09:45 +02:00
const queryIndex = url.indexOf('?')
const result = url.substring(url.indexOf('/', 8), queryIndex === -1 ? url.length : queryIndex)
// if strict routing is false => `/hello/hey/` and `/hello/hey` are treated the same
// default is true
if (strict === false && result.endsWith('/')) {
2023-01-10 13:24:21 +01:00
return [result.slice(0, -1), queryIndex]
2022-07-02 08:09:45 +02:00
}
2023-01-10 13:24:21 +01:00
return [result, queryIndex]
2022-07-02 08:09:45 +02:00
}
2023-01-10 13:24:21 +01:00
export const getQueryStringFromURL = (url: string, queryIndex?: number): string => {
queryIndex ||= url.indexOf('?')
const result = queryIndex !== -1 ? url.substring(queryIndex) : ''
return result
}
2022-07-02 08:09:45 +02:00
export const mergePath = (...paths: string[]): string => {
let p: string = ''
let endsWithSlash = false
for (let path of paths) {
/* ['/hey/','/say'] => ['/hey', '/say'] */
if (p.endsWith('/')) {
p = p.slice(0, -1)
endsWithSlash = true
}
/* ['/hey','say'] => ['/hey', '/say'] */
if (!path.startsWith('/')) {
path = `/${path}`
}
/* ['/hey/', '/'] => `/hey/` */
if (path === '/' && endsWithSlash) {
p = `${p}/`
} else if (path !== '/') {
p = `${p}${path}`
}
/* ['/', '/'] => `/` */
if (path === '/' && p === '') {
p = '/'
}
}
return p
}
export const checkOptionalParameter = (path: string): string[] | null => {
/*
If path is `/api/animals/:type?` it will return:
[`/api/animals`, `/api/animals/:type`]
in other cases it will return null
*/
const match = path.match(/(^.+)(\/\:[^\/]+)\?$/)
if (!match) return null
const base = match[1]
const optional = base + match[2]
return [base, optional]
}