Skip to content

Commit

Permalink
Merge pull request #1436 from honojs/next
Browse files Browse the repository at this point in the history
  • Loading branch information
yusukebe authored Sep 10, 2023
2 parents d6ec48e + e4c4322 commit ba04dac
Show file tree
Hide file tree
Showing 31 changed files with 942 additions and 137 deletions.
6 changes: 5 additions & 1 deletion deno_dist/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export const hc = <T extends Hono<any, any, any>>(
baseUrl: string,
options?: ClientRequestOptions
) =>
createProxy(async (opts) => {
createProxy((opts) => {
const parts = [...opts.path]

let method = ''
Expand All @@ -128,6 +128,10 @@ export const hc = <T extends Hono<any, any, any>>(

const path = parts.join('/')
const url = mergePath(baseUrl, path)
if (method === 'url') {
return new URL(url)
}

const req = new ClientRequestImpl(url, method)
if (method) {
options ??= {}
Expand Down
2 changes: 2 additions & 0 deletions deno_dist/client/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ type ClientRequest<S extends Schema> = {
options?: ClientRequestOptions
) => Promise<ClientResponse<O>>
: never
} & {
$url: () => URL
}

type BlankRecordToNever<T> = T extends Record<infer R, unknown>
Expand Down
46 changes: 41 additions & 5 deletions deno_dist/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,15 @@ export interface ExecutionContext {
waitUntil(promise: Promise<unknown>): void
passThroughOnException(): void
}

export interface ContextVariableMap {}

export interface ContextRenderer {}
interface DefaultRenderer {
(content: string): Response | Promise<Response>
}
type Renderer = ContextRenderer extends Function ? ContextRenderer : DefaultRenderer

interface Get<E extends Env> {
<Key extends keyof ContextVariableMap>(key: Key): ContextVariableMap[Key]
<Key extends keyof E['Variables']>(key: Key): E['Variables'][Key]
Expand Down Expand Up @@ -87,16 +94,17 @@ export class Context<
> {
req: HonoRequest<P, I['out']>
env: E['Bindings'] = {}
private _var: E['Variables'] = {}
finalized: boolean = false
error: Error | undefined = undefined

private _status: StatusCode = 200
private _exCtx: FetchEventLike | ExecutionContext | undefined // _executionCtx
private _map: Record<string, unknown> | undefined
private _h: Headers | undefined = undefined // _headers
private _pH: Record<string, string> | undefined = undefined // _preparedHeaders
private _res: Response | undefined
private _init = true
private _renderer: Renderer = (content: string) => this.html(content)
private notFoundHandler: NotFoundHandler<E> = () => new Response()

constructor(req: HonoRequest<P, I['out']>, options?: ContextOptions<E>) {
Expand Down Expand Up @@ -143,6 +151,25 @@ export class Context<
this.finalized = true
}

/**
* @experimental
* `c.render()` is an experimental feature.
* The API might be changed.
*/
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-explicit-any
render: Renderer = (...args: any[]) => this._renderer(...args)

/**
* @experimental
* `c.setRenderer()` is an experimental feature.
* The API might be changed.
*/
setRenderer = (renderer: Renderer) => {
this._renderer = renderer
}

header = (name: string, value: string | undefined, options?: { append?: boolean }): void => {
// Clear the header
if (value === undefined) {
Expand Down Expand Up @@ -187,12 +214,17 @@ export class Context<
}

set: Set<E> = (key: string, value: unknown) => {
this._map ||= {}
this._map[key as string] = value
this._var ??= {}
this._var[key as string] = value
}

get: Get<E> = (key: string) => {
return this._map ? this._map[key] : undefined
return this._var ? this._var[key] : undefined
}

// c.var.propName is a read-only
get var(): Readonly<E['Variables']> {
return { ...this._var }
}

newResponse: NewResponse = (
Expand Down Expand Up @@ -309,11 +341,15 @@ export class Context<
: T
: never
> => {
const response =
typeof arg === 'number' ? this.json(object, arg, headers) : this.json(object, arg)

return {
response: typeof arg === 'number' ? this.json(object, arg, headers) : this.json(object, arg),
response,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
data: object as any,
format: 'json',
status: response.status,
}
}

Expand Down
10 changes: 10 additions & 0 deletions deno_dist/helper/factory/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { Env, Input, MiddlewareHandler } from '../../types.ts'

/**
* @experimental
* `middleware()` is an experimental feature.
* The API might be changed.
*/
export const middleware = <E extends Env = Env, P extends string = string, I extends Input = {}>(
middleware: MiddlewareHandler<E, P, I>
) => middleware
27 changes: 27 additions & 0 deletions deno_dist/jsx/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { html } from '../helper/html/index.ts'
import { Hono } from '../hono.ts'
import type { FC } from './index.ts'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { jsx, memo, Fragment } from './index.ts'

Expand Down Expand Up @@ -271,6 +272,32 @@ describe('render to string', () => {
})
})

describe('FC', () => {
it('Should define the type correctly', () => {
const Layout: FC<{ title: string }> = (props) => {
return (
<html>
<head>
<title>{props.title}</title>
</head>
<body>{props.children}</body>
</html>
)
}

const Top = (
<Layout title='Home page'>
<h1>Hono</h1>
<p>Hono is great</p>
</Layout>
)

expect(Top.toString()).toBe(
'<html><head><title>Home page</title></head><body><h1>Hono</h1><p>Hono is great</p></body></html>'
)
})
})

describe('style attribute', () => {
it('should convert the object to strings', () => {
const template = (
Expand Down
4 changes: 2 additions & 2 deletions deno_dist/jsx/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ const jsxFn = (
}
}

type FC<T = Props> = (props: T) => HtmlEscapedString
export type FC<T = Props> = (props: T & { children?: Child }) => HtmlEscapedString

const shallowEqual = (a: Props, b: Props): boolean => {
if (a === b) {
Expand Down Expand Up @@ -226,7 +226,7 @@ export const memo = <T>(
): FC<T> => {
let computed = undefined
let prevProps: T | undefined = undefined
return ((props: T): HtmlEscapedString => {
return ((props: T & { children?: Child }): HtmlEscapedString => {
if (prevProps && !propsAreEqual(prevProps, props)) {
computed = undefined
}
Expand Down
2 changes: 1 addition & 1 deletion deno_dist/middleware/bearer-auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const bearerAuth = (options: {
const realm = options.realm?.replace(/"/g, '\\"')

return async (c, next) => {
const headerToken = c.req.headers.get('Authorization')
const headerToken = c.req.header('Authorization')

if (!headerToken) {
// No Authorization header
Expand Down
4 changes: 2 additions & 2 deletions deno_dist/middleware/cors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const cors = (options?: CORSOptions): MiddlewareHandler => {
c.res.headers.set(key, value)
}

const allowOrigin = findAllowOrigin(c.req.headers.get('origin') || '')
const allowOrigin = findAllowOrigin(c.req.header('origin') || '')
if (allowOrigin) {
set('Access-Control-Allow-Origin', allowOrigin)
}
Expand Down Expand Up @@ -70,7 +70,7 @@ export const cors = (options?: CORSOptions): MiddlewareHandler => {

let headers = opts.allowHeaders
if (!headers?.length) {
const requestHeaders = c.req.headers.get('Access-Control-Request-Headers')
const requestHeaders = c.req.header('Access-Control-Request-Headers')
if (requestHeaders) {
headers = requestHeaders.split(/\s*,\s*/)
}
Expand Down
2 changes: 1 addition & 1 deletion deno_dist/middleware/etag/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const etag = (options?: ETagOptions): MiddlewareHandler => {
const weak = options?.weak ?? false

return async (c, next) => {
const ifNoneMatch = c.req.headers.get('If-None-Match')
const ifNoneMatch = c.req.header('If-None-Match') ?? null

await next()

Expand Down
2 changes: 1 addition & 1 deletion deno_dist/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export type {
ToSchema,
TypedResponse,
} from './types.ts'
export type { Context, ContextVariableMap } from './context.ts'
export type { Context, ContextVariableMap, ContextRenderer } from './context.ts'
export type { HonoRequest } from './request.ts'
export { Hono }
export { HTTPException } from './http-exception.ts'
Expand Down
36 changes: 36 additions & 0 deletions deno_dist/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,27 +181,63 @@ export class HonoRequest<P extends string = '/', I extends Input['out'] = {}> {
get url() {
return this.raw.url
}

get method() {
return this.raw.method
}

/** @deprecated
* Use `c.req.raw.headers` instead of `c.req.headers`. The `c.req.headers` will be removed in v4.
* Or you can get the header values with using `c.req.header`.
* @example
*
* app.get('/', (c) => {
* const userAgent = c.req.header('User-Agent')
* //...
* })
*/
get headers() {
return this.raw.headers
}

/** @deprecated
* Use `c.req.raw.body` instead of `c.req.body`. The `c.req.body` will be removed in v4.
*/
get body() {
return this.raw.body
}

/** @deprecated
* Use `c.req.raw.bodyUsed` instead of `c.req.bodyUsed`. The `c.req.bodyUsed` will be removed in v4.
*/
get bodyUsed() {
return this.raw.bodyUsed
}

/** @deprecated
* Use `c.req.raw.integrity` instead of `c.req.integrity`. The `c.req.integrity` will be removed in v4.
*/
get integrity() {
return this.raw.integrity
}

/** @deprecated
* Use `c.req.raw.keepalive` instead of `c.req.keepalive`. The `c.req.keepalive` will be removed in v4.
*/
get keepalive() {
return this.raw.keepalive
}

/** @deprecated
* Use `c.req.raw.referrer` instead of `c.req.referrer`. The `c.req.referrer` will be removed in v4.
*/
get referrer() {
return this.raw.referrer
}

/** @deprecated
* Use `c.req.raw.signal` instead of `c.req.signal`. The `c.req.signal` will be removed in v4.
*/
get signal() {
return this.raw.signal
}
Expand Down
Loading

0 comments on commit ba04dac

Please sign in to comment.