mirror of
https://github.com/honojs/hono.git
synced 2024-12-01 11:51:01 +01:00
9a0389e723
* refactor(JSONPath): improve typing of JSONPath
* chore(vscode-settings): add deno.enable=false
* fix(validator): add null to type Type def
* feat(JSON-Path): add support for array JSONPath-Plus syntax
* fix(validator): update isRequired to pass valid bool types
* test: update tests for isRequired validator
* feat(validator): add support for JSON array path validation
* chore(deno): denoify array support changes
* fix(validator): type check all vals in array
* chore(deno): denoify changes
* test(validator): add tests for array type checking
* fix(validator): change JSONPrimative to JSONPrimitive
* refactor(json): More compatible with https://jsonpath.com/.
* implementation of `asArray`
* fix(validator): update JSONPath implementation and add isArray check in validation
* fix(validator): fix typing errors on SchemaToProp
* Revert "fix(validator): fix typing errors on SchemaToProp"
This reverts commit b8ddef85d0
.
* fix(validator): fix SchemaToProp error for VTypeArrays
* chore(deno): denoify
Co-authored-by: Taku Amano <taku@taaas.jp>
Co-authored-by: Yusuke Wada <yusuke@kamawada.com>
125 lines
2.9 KiB
TypeScript
125 lines
2.9 KiB
TypeScript
import type { Context } from '../../context.ts'
|
|
import type { Environment, Next, ValidatedData } from '../../hono.ts'
|
|
import { VBase, Validator } from './validator.ts'
|
|
import type {
|
|
VString,
|
|
VNumber,
|
|
VBoolean,
|
|
VObject,
|
|
VNumberArray,
|
|
VStringArray,
|
|
VBooleanArray,
|
|
ValidateResult,
|
|
} from './validator.ts'
|
|
|
|
type Schema = {
|
|
[key: string]:
|
|
| VString
|
|
| VNumber
|
|
| VBoolean
|
|
| VObject
|
|
| VStringArray
|
|
| VNumberArray
|
|
| VBooleanArray
|
|
| Schema
|
|
}
|
|
|
|
type SchemaToProp<T> = {
|
|
[K in keyof T]: T[K] extends VNumberArray
|
|
? number[]
|
|
: T[K] extends VBooleanArray
|
|
? boolean[]
|
|
: T[K] extends VStringArray
|
|
? string[]
|
|
: T[K] extends VNumber
|
|
? number
|
|
: T[K] extends VBoolean
|
|
? boolean
|
|
: T[K] extends VString
|
|
? string
|
|
: T[K] extends VObject
|
|
? object
|
|
: T[K] extends Schema
|
|
? SchemaToProp<T[K]>
|
|
: never
|
|
}
|
|
|
|
type ResultSet = {
|
|
hasError: boolean
|
|
messages: string[]
|
|
results: ValidateResult[]
|
|
}
|
|
|
|
type Done<Env extends Partial<Environment>> = (
|
|
resultSet: ResultSet,
|
|
context: Context<string, Env>
|
|
) => Response | void
|
|
|
|
type ValidationFunction<T, Env extends Partial<Environment>> = (
|
|
v: Validator,
|
|
c: Context<string, Env>
|
|
) => T
|
|
|
|
type MiddlewareHandler<
|
|
Data extends ValidatedData = ValidatedData,
|
|
Env extends Partial<Environment> = Environment
|
|
> = (c: Context<string, Env, Data>, next: Next) => Promise<void> | Promise<Response | undefined>
|
|
|
|
export const validatorMiddleware = <T extends Schema, Env extends Partial<Environment>>(
|
|
validationFunction: ValidationFunction<T, Env>,
|
|
options?: { done?: Done<Env> }
|
|
) => {
|
|
const v = new Validator()
|
|
const handler: MiddlewareHandler<SchemaToProp<T>, Env> = async (c, next) => {
|
|
const resultSet: ResultSet = {
|
|
hasError: false,
|
|
messages: [],
|
|
results: [],
|
|
}
|
|
|
|
const validatorList = getValidatorList(validationFunction(v, c))
|
|
|
|
for (const [keys, validator] of validatorList) {
|
|
const result = await validator.validate(c.req)
|
|
if (result.isValid) {
|
|
// Set data on request object
|
|
c.req.valid(keys, result.value)
|
|
} else {
|
|
resultSet.hasError = true
|
|
if (result.message !== undefined) {
|
|
resultSet.messages.push(result.message)
|
|
}
|
|
}
|
|
resultSet.results.push(result)
|
|
}
|
|
|
|
if (options && options.done) {
|
|
const res = options.done(resultSet, c)
|
|
if (res) {
|
|
return res
|
|
}
|
|
}
|
|
|
|
if (resultSet.hasError) {
|
|
return c.text(resultSet.messages.join('\n'), 400)
|
|
}
|
|
await next()
|
|
}
|
|
return handler
|
|
}
|
|
|
|
function getValidatorList<T extends Schema>(schema: T): [string[], VBase][] {
|
|
const map: [string[], VBase][] = []
|
|
for (const [key, value] of Object.entries(schema)) {
|
|
if (value instanceof VBase) {
|
|
map.push([[key], value])
|
|
} else {
|
|
const children = getValidatorList(value)
|
|
for (const [keys, validator] of children) {
|
|
map.push([[key, ...keys], validator])
|
|
}
|
|
}
|
|
}
|
|
return map
|
|
}
|