Skip to content

Commit

Permalink
Merge branch 'main' into v4
Browse files Browse the repository at this point in the history
  • Loading branch information
usualoma committed Feb 3, 2024
2 parents 88f2983 + f44c705 commit 0623c21
Show file tree
Hide file tree
Showing 11 changed files with 143 additions and 61 deletions.
17 changes: 3 additions & 14 deletions deno_dist/helper/html/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,7 @@
import { escapeToBuffer, stringBufferToString } from '../../utils/html.ts'
import type {
StringBuffer,
HtmlEscaped,
HtmlEscapedString,
HtmlEscapedCallback,
} from '../../utils/html.ts'
import { escapeToBuffer, stringBufferToString, raw } from '../../utils/html.ts'
import type { StringBuffer, HtmlEscaped, HtmlEscapedString } from '../../utils/html.ts'

export const raw = (value: unknown, callbacks?: HtmlEscapedCallback[]): HtmlEscapedString => {
const escapedString = new String(value) as HtmlEscapedString
escapedString.isEscaped = true
escapedString.callbacks = callbacks

return escapedString
}
export { raw }

export const html = (
strings: TemplateStringsArray,
Expand Down
7 changes: 4 additions & 3 deletions deno_dist/router/trie-router/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ export class Node<T> {
search(method: string, path: string): [[T, Params][]] {
const handlerSets: HandlerParamsSet<T>[] = []
this.params = {}
const params: Record<string, string> = {}

// eslint-disable-next-line @typescript-eslint/no-this-alias
const curNode: Node<T> = this
Expand Down Expand Up @@ -151,6 +150,8 @@ export class Node<T> {
for (let k = 0, len3 = node.patterns.length; k < len3; k++) {
const pattern = node.patterns[k]

const params = { ...node.params }

// Wildcard
// '/hello/*/foo' => match /hello/bar/foo
if (pattern === '*') {
Expand Down Expand Up @@ -184,10 +185,10 @@ export class Node<T> {
if (isLast === true) {
handlerSets.push(...this.gHSets(child, method, params, node.params))
if (child.children['*']) {
handlerSets.push(...this.gHSets(child.children['*'], method, node.params, params))
handlerSets.push(...this.gHSets(child.children['*'], method, params, node.params))
}
} else {
child.params = { ...params }
child.params = params
tempNodes.push(child)
}
}
Expand Down
28 changes: 25 additions & 3 deletions deno_dist/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/* eslint-disable @typescript-eslint/ban-types */
import type { Context } from './context.ts'
import type { Hono } from './hono.ts'
import type { IfAnyThenEmptyObject, UnionToIntersection } from './utils/types.ts'
import type { IfAnyThenEmptyObject, RemoveBlankRecord, UnionToIntersection } from './utils/types.ts'

////////////////////////////////////////
////// //////
Expand Down Expand Up @@ -1595,8 +1595,30 @@ export type Schema = {
}
}

export type MergeSchemaPath<OrigSchema, SubPath extends string> = {
[K in keyof OrigSchema as `${MergePath<SubPath, K & string>}`]: OrigSchema[K]
type ExtractParams<Path extends string> = string extends Path
? Record<string, string>
: Path extends `${infer Start}:${infer Param}/${infer Rest}`
? { [K in Param | keyof ExtractParams<`/${Rest}`>]: string }
: Path extends `${infer Start}:${infer Param}`
? { [K in Param]: string }
: never

export type MergeSchemaPath<OrigSchema extends Schema, SubPath extends string> = {
[P in keyof OrigSchema as MergePath<SubPath, P & string>]: {
[M in keyof OrigSchema[P]]: OrigSchema[P][M] extends {
input: infer Input
output: infer Output
}
? {
input: Input extends { param: infer Params }
? { param: Params & ExtractParams<SubPath> }
: RemoveBlankRecord<ExtractParams<SubPath>> extends never
? Input
: Input & { param: ExtractParams<SubPath> }
output: Output
}
: never
}
}

export type AddParam<I, P extends string> = ParamKeys<P> extends never
Expand Down
8 changes: 7 additions & 1 deletion deno_dist/utils/html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,13 @@ export type HtmlEscapedString = string & HtmlEscaped
*/
export type StringBuffer = (string | Promise<string>)[]

import { raw } from '../helper/html/index.ts'
export const raw = (value: unknown, callbacks?: HtmlEscapedCallback[]): HtmlEscapedString => {
const escapedString = new String(value) as HtmlEscapedString
escapedString.isEscaped = true
escapedString.callbacks = callbacks

return escapedString
}

// The `escapeToBuffer` implementation is based on code from the MIT licensed `react-dom` package.
// https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/server/escapeTextForBrowser.js
Expand Down
32 changes: 14 additions & 18 deletions src/adapter/bun/serve-static.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
// @denoify-ignore
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { existsSync } from 'fs'
import type { Context } from '../../context'
import type { Env, MiddlewareHandler } from '../../types'
import { getFilePath } from '../../utils/filepath'
import { getMimeType } from '../../utils/mime'

// @ts-ignore
const { file } = Bun

export type ServeStaticOptions<E extends Env = Env> = {
root?: string
path?: string
Expand Down Expand Up @@ -43,21 +39,21 @@ export const serveStatic = <E extends Env = Env>(

path = `./${path}`

if (existsSync(path)) {
const content = file(path)
if (content) {
let mimeType: string | undefined = undefined
if (options.mimes) {
mimeType = getMimeType(path, options.mimes) ?? getMimeType(path)
} else {
mimeType = getMimeType(path)
}
if (mimeType) {
c.header('Content-Type', mimeType)
}
// Return Response object
return c.body(content)
// @ts-ignore
const file = Bun.file(path)
const isExists = await file.exists()
if (isExists) {
let mimeType: string | undefined = undefined
if (options.mimes) {
mimeType = getMimeType(path, options.mimes) ?? getMimeType(path)
} else {
mimeType = getMimeType(path)
}
if (mimeType) {
c.header('Content-Type', mimeType)
}
// Return Response object
return c.body(file)
}

await options.onNotFound?.(path, c)
Expand Down
17 changes: 3 additions & 14 deletions src/helper/html/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,7 @@
import { escapeToBuffer, stringBufferToString } from '../../utils/html'
import type {
StringBuffer,
HtmlEscaped,
HtmlEscapedString,
HtmlEscapedCallback,
} from '../../utils/html'
import { escapeToBuffer, stringBufferToString, raw } from '../../utils/html'
import type { StringBuffer, HtmlEscaped, HtmlEscapedString } from '../../utils/html'

export const raw = (value: unknown, callbacks?: HtmlEscapedCallback[]): HtmlEscapedString => {
const escapedString = new String(value) as HtmlEscapedString
escapedString.isEscaped = true
escapedString.callbacks = callbacks

return escapedString
}
export { raw }

export const html = (
strings: TemplateStringsArray,
Expand Down
15 changes: 15 additions & 0 deletions src/router/trie-router/node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -768,4 +768,19 @@ describe('The same name is used for path params', () => {
expect(res[0][1]).toEqual({ b: 'about', a: 'me' })
})
})

describe('Complex with tails', () => {
const node = new Node()
node.insert('get', '/:id/:id2/comments', 'a')
node.insert('get', '/posts/:id/comments', 'b')
it('/posts/123/comments', () => {
const [res] = node.search('get', '/posts/123/comments')
expect(res).not.toBeNull()
expect(res.length).toBe(2)
expect(res[0][0]).toEqual('a')
expect(res[0][1]).toEqual({ id: 'posts', id2: '123' })
expect(res[1][0]).toEqual('b')
expect(res[1][1]).toEqual({ id: '123' })
})
})
})
7 changes: 4 additions & 3 deletions src/router/trie-router/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ export class Node<T> {
search(method: string, path: string): [[T, Params][]] {
const handlerSets: HandlerParamsSet<T>[] = []
this.params = {}
const params: Record<string, string> = {}

// eslint-disable-next-line @typescript-eslint/no-this-alias
const curNode: Node<T> = this
Expand Down Expand Up @@ -151,6 +150,8 @@ export class Node<T> {
for (let k = 0, len3 = node.patterns.length; k < len3; k++) {
const pattern = node.patterns[k]

const params = { ...node.params }

// Wildcard
// '/hello/*/foo' => match /hello/bar/foo
if (pattern === '*') {
Expand Down Expand Up @@ -184,10 +185,10 @@ export class Node<T> {
if (isLast === true) {
handlerSets.push(...this.gHSets(child, method, params, node.params))
if (child.children['*']) {
handlerSets.push(...this.gHSets(child.children['*'], method, node.params, params))
handlerSets.push(...this.gHSets(child.children['*'], method, params, node.params))
}
} else {
child.params = { ...params }
child.params = params
tempNodes.push(child)
}
}
Expand Down
37 changes: 36 additions & 1 deletion src/types.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,6 @@ describe('merge path', () => {
message: string
}
}
} & {
$get: {
input: {}
output: {
Expand Down Expand Up @@ -557,6 +556,42 @@ describe('merge path', () => {
type Actual = MergeSchemaPath<Sub, '/tags'>
type verify = Expect<Equal<'/tags', GetKey<Actual>>>
})

test('MergeSchemaPath - SubPath has path params', () => {
type Actual = MergeSchemaPath<ToSchema<'get', '/', {}, {}>, '/a/:b'>
type Expected = {
'/a/:b': {
$get: {
input: {
param: {
b: string
}
}
output: {}
}
}
}
type verify = Expect<Equal<Expected, Actual>>
})

test('MergeSchemaPath - Path and SubPath have path params', () => {
type Actual = MergeSchemaPath<ToSchema<'get', '/c/:d', {}, {}>, '/a/:b'>
type Expected = {
'/a/:b/c/:d': {
$get: {
input: {
param: {
d: string
} & {
b: string
}
}
output: {}
}
}
}
type verify = Expect<Equal<Expected, Actual>>
})
})

describe('Different types using json()', () => {
Expand Down
28 changes: 25 additions & 3 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/* eslint-disable @typescript-eslint/ban-types */
import type { Context } from './context'
import type { Hono } from './hono'
import type { IfAnyThenEmptyObject, UnionToIntersection } from './utils/types'
import type { IfAnyThenEmptyObject, RemoveBlankRecord, UnionToIntersection } from './utils/types'

////////////////////////////////////////
////// //////
Expand Down Expand Up @@ -1595,8 +1595,30 @@ export type Schema = {
}
}

export type MergeSchemaPath<OrigSchema, SubPath extends string> = {
[K in keyof OrigSchema as `${MergePath<SubPath, K & string>}`]: OrigSchema[K]
type ExtractParams<Path extends string> = string extends Path
? Record<string, string>
: Path extends `${infer Start}:${infer Param}/${infer Rest}`
? { [K in Param | keyof ExtractParams<`/${Rest}`>]: string }
: Path extends `${infer Start}:${infer Param}`
? { [K in Param]: string }
: never

export type MergeSchemaPath<OrigSchema extends Schema, SubPath extends string> = {
[P in keyof OrigSchema as MergePath<SubPath, P & string>]: {
[M in keyof OrigSchema[P]]: OrigSchema[P][M] extends {
input: infer Input
output: infer Output
}
? {
input: Input extends { param: infer Params }
? { param: Params & ExtractParams<SubPath> }
: RemoveBlankRecord<ExtractParams<SubPath>> extends never
? Input
: Input & { param: ExtractParams<SubPath> }
output: Output
}
: never
}
}

export type AddParam<I, P extends string> = ParamKeys<P> extends never
Expand Down
8 changes: 7 additions & 1 deletion src/utils/html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,13 @@ export type HtmlEscapedString = string & HtmlEscaped
*/
export type StringBuffer = (string | Promise<string>)[]

import { raw } from '../helper/html'
export const raw = (value: unknown, callbacks?: HtmlEscapedCallback[]): HtmlEscapedString => {
const escapedString = new String(value) as HtmlEscapedString
escapedString.isEscaped = true
escapedString.callbacks = callbacks

return escapedString
}

// The `escapeToBuffer` implementation is based on code from the MIT licensed `react-dom` package.
// https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/server/escapeTextForBrowser.js
Expand Down

0 comments on commit 0623c21

Please sign in to comment.