0
0
mirror of https://github.com/honojs/hono.git synced 2024-12-01 10:51:01 +00:00
hono/deno_dist/request.ts
Jayden 760ae30251
Fix detecting node runtime (#696)
* Fix

* Denoify

* Avoid error in other runtime

* chore: remove unnecessary config testPathIgnorePatterns (#697)

* Fix vercel

Co-authored-by: Horie Issei <issei.horie@is2ei.com>
2022-12-02 11:28:49 +09:00

174 lines
4.8 KiB
TypeScript

import { parseBody } from './utils/body.ts'
import type { BodyData } from './utils/body.ts'
import type { Cookie } from './utils/cookie.ts'
import { parse } from './utils/cookie.ts'
import { getQueryStringFromURL } from './utils/url.ts'
type ValidatedData = Record<string, unknown>
declare global {
interface Request<
// eslint-disable-next-line @typescript-eslint/no-unused-vars
CfHostMetadata = unknown,
ParamKeyType extends string = string,
Data extends ValidatedData = ValidatedData
> {
paramData?: Record<ParamKeyType, string>
param: {
(key: ParamKeyType): string
(): Record<ParamKeyType, string>
}
queryData?: Record<string, string>
query: {
(key: string): string
(): Record<string, string>
}
queries: {
(key: string): string[]
(): Record<string, string[]>
}
headerData?: Record<string, string>
header: {
(name: string): string
(): Record<string, string>
}
cookie: {
(name: string): string
(): Cookie
}
bodyData?: BodyData
parseBody<BodyType extends BodyData>(): Promise<BodyType>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
jsonData?: any
json<T>(): Promise<T>
data: Data
valid: {
(key: string | string[], value: unknown): Data
(): Data
}
}
}
export function extendRequestPrototype() {
if (!!Request.prototype.param as boolean) {
// already extended
return
}
Request.prototype.param = function (this: Request, key?: string) {
if (this.paramData) {
if (key) {
return decodeURIComponent(this.paramData[key])
} else {
const decoded: Record<string, string> = {}
for (const [key, value] of Object.entries(this.paramData)) {
decoded[key] = decodeURIComponent(value)
}
return decoded
}
}
return null
} as InstanceType<typeof Request>['param']
Request.prototype.header = function (this: Request, name?: string) {
if (!this.headerData) {
this.headerData = {}
this.headers.forEach((value, key) => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.headerData![key] = value
})
}
if (name) {
return this.headerData[name.toLowerCase()]
} else {
return this.headerData
}
} as InstanceType<typeof Request>['header']
Request.prototype.query = function (this: Request, key?: string) {
const queryString = getQueryStringFromURL(this.url)
const searchParams = new URLSearchParams(queryString)
if (!this.queryData) {
this.queryData = {}
for (const key of searchParams.keys()) {
this.queryData[key] = searchParams.get(key) || ''
}
}
if (key) {
return this.queryData[key]
} else {
return this.queryData
}
} as InstanceType<typeof Request>['query']
Request.prototype.queries = function (this: Request, key?: string) {
const queryString = getQueryStringFromURL(this.url)
const searchParams = new URLSearchParams(queryString)
if (key) {
return searchParams.getAll(key)
} else {
const result: Record<string, string[]> = {}
for (const key of searchParams.keys()) {
result[key] = searchParams.getAll(key)
}
return result
}
} as InstanceType<typeof Request>['queries']
Request.prototype.cookie = function (this: Request, key?: string) {
const cookie = this.headers.get('Cookie') || ''
const obj = parse(cookie)
if (key) {
const value = obj[key]
return value
} else {
return obj
}
} as InstanceType<typeof Request>['cookie']
Request.prototype.parseBody = async function <BodyType extends BodyData>(
this: Request
): Promise<BodyType> {
// Cache the parsed body
let body: BodyType
if (!this.bodyData) {
body = await parseBody<BodyType>(this)
this.bodyData = body
} else {
body = this.bodyData as BodyType
}
return body
} as InstanceType<typeof Request>['parseBody']
Request.prototype.json = async function <JSONData = unknown>(this: Request) {
// Cache the JSON body
let jsonData: Partial<JSONData>
if (!this.jsonData) {
jsonData = JSON.parse(await this.text())
this.jsonData = jsonData
} else {
jsonData = this.jsonData
}
return jsonData
} as InstanceType<typeof Request>['jsonData']
Request.prototype.valid = function (this: Request, keys?: string | string[], value?: unknown) {
if (!this.data) {
this.data = {}
}
if (keys !== undefined) {
if (typeof keys === 'string') {
keys = [keys]
}
let data = this.data
for (let i = 0; i < keys.length - 1; i++) {
data = (data[keys[i]] ||= {}) as ValidatedData
}
data[keys[keys.length - 1]] = value
}
return this.data
} as InstanceType<typeof Request>['valid']
}