123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- import type {KeywordErrorCxt, KeywordErrorDefinition} from "../types"
- import type {SchemaCxt} from "./index"
- import {CodeGen, _, str, strConcat, Code, Name} from "./codegen"
- import {SafeExpr} from "./codegen/code"
- import {getErrorPath, Type} from "./util"
- import N from "./names"
- export const keywordError: KeywordErrorDefinition = {
- message: ({keyword}) => str`must pass "${keyword}" keyword validation`,
- }
- export const keyword$DataError: KeywordErrorDefinition = {
- message: ({keyword, schemaType}) =>
- schemaType
- ? str`"${keyword}" keyword must be ${schemaType} ($data)`
- : str`"${keyword}" keyword is invalid ($data)`,
- }
- export interface ErrorPaths {
- instancePath?: Code
- schemaPath?: string
- parentSchema?: boolean
- }
- export function reportError(
- cxt: KeywordErrorCxt,
- error: KeywordErrorDefinition = keywordError,
- errorPaths?: ErrorPaths,
- overrideAllErrors?: boolean
- ): void {
- const {it} = cxt
- const {gen, compositeRule, allErrors} = it
- const errObj = errorObjectCode(cxt, error, errorPaths)
- if (overrideAllErrors ?? (compositeRule || allErrors)) {
- addError(gen, errObj)
- } else {
- returnErrors(it, _`[${errObj}]`)
- }
- }
- export function reportExtraError(
- cxt: KeywordErrorCxt,
- error: KeywordErrorDefinition = keywordError,
- errorPaths?: ErrorPaths
- ): void {
- const {it} = cxt
- const {gen, compositeRule, allErrors} = it
- const errObj = errorObjectCode(cxt, error, errorPaths)
- addError(gen, errObj)
- if (!(compositeRule || allErrors)) {
- returnErrors(it, N.vErrors)
- }
- }
- export function resetErrorsCount(gen: CodeGen, errsCount: Name): void {
- gen.assign(N.errors, errsCount)
- gen.if(_`${N.vErrors} !== null`, () =>
- gen.if(
- errsCount,
- () => gen.assign(_`${N.vErrors}.length`, errsCount),
- () => gen.assign(N.vErrors, null)
- )
- )
- }
- export function extendErrors({
- gen,
- keyword,
- schemaValue,
- data,
- errsCount,
- it,
- }: KeywordErrorCxt): void {
- /* istanbul ignore if */
- if (errsCount === undefined) throw new Error("ajv implementation error")
- const err = gen.name("err")
- gen.forRange("i", errsCount, N.errors, (i) => {
- gen.const(err, _`${N.vErrors}[${i}]`)
- gen.if(_`${err}.instancePath === undefined`, () =>
- gen.assign(_`${err}.instancePath`, strConcat(N.instancePath, it.errorPath))
- )
- gen.assign(_`${err}.schemaPath`, str`${it.errSchemaPath}/${keyword}`)
- if (it.opts.verbose) {
- gen.assign(_`${err}.schema`, schemaValue)
- gen.assign(_`${err}.data`, data)
- }
- })
- }
- function addError(gen: CodeGen, errObj: Code): void {
- const err = gen.const("err", errObj)
- gen.if(
- _`${N.vErrors} === null`,
- () => gen.assign(N.vErrors, _`[${err}]`),
- _`${N.vErrors}.push(${err})`
- )
- gen.code(_`${N.errors}++`)
- }
- function returnErrors(it: SchemaCxt, errs: Code): void {
- const {gen, validateName, schemaEnv} = it
- if (schemaEnv.$async) {
- gen.throw(_`new ${it.ValidationError as Name}(${errs})`)
- } else {
- gen.assign(_`${validateName}.errors`, errs)
- gen.return(false)
- }
- }
- const E = {
- keyword: new Name("keyword"),
- schemaPath: new Name("schemaPath"), // also used in JTD errors
- params: new Name("params"),
- propertyName: new Name("propertyName"),
- message: new Name("message"),
- schema: new Name("schema"),
- parentSchema: new Name("parentSchema"),
- }
- function errorObjectCode(
- cxt: KeywordErrorCxt,
- error: KeywordErrorDefinition,
- errorPaths?: ErrorPaths
- ): Code {
- const {createErrors} = cxt.it
- if (createErrors === false) return _`{}`
- return errorObject(cxt, error, errorPaths)
- }
- function errorObject(
- cxt: KeywordErrorCxt,
- error: KeywordErrorDefinition,
- errorPaths: ErrorPaths = {}
- ): Code {
- const {gen, it} = cxt
- const keyValues: [Name, SafeExpr | string][] = [
- errorInstancePath(it, errorPaths),
- errorSchemaPath(cxt, errorPaths),
- ]
- extraErrorProps(cxt, error, keyValues)
- return gen.object(...keyValues)
- }
- function errorInstancePath({errorPath}: SchemaCxt, {instancePath}: ErrorPaths): [Name, Code] {
- const instPath = instancePath
- ? str`${errorPath}${getErrorPath(instancePath, Type.Str)}`
- : errorPath
- return [N.instancePath, strConcat(N.instancePath, instPath)]
- }
- function errorSchemaPath(
- {keyword, it: {errSchemaPath}}: KeywordErrorCxt,
- {schemaPath, parentSchema}: ErrorPaths
- ): [Name, string | Code] {
- let schPath = parentSchema ? errSchemaPath : str`${errSchemaPath}/${keyword}`
- if (schemaPath) {
- schPath = str`${schPath}${getErrorPath(schemaPath, Type.Str)}`
- }
- return [E.schemaPath, schPath]
- }
- function extraErrorProps(
- cxt: KeywordErrorCxt,
- {params, message}: KeywordErrorDefinition,
- keyValues: [Name, SafeExpr | string][]
- ): void {
- const {keyword, data, schemaValue, it} = cxt
- const {opts, propertyName, topSchemaRef, schemaPath} = it
- keyValues.push(
- [E.keyword, keyword],
- [E.params, typeof params == "function" ? params(cxt) : params || _`{}`]
- )
- if (opts.messages) {
- keyValues.push([E.message, typeof message == "function" ? message(cxt) : message])
- }
- if (opts.verbose) {
- keyValues.push(
- [E.schema, schemaValue],
- [E.parentSchema, _`${topSchemaRef}${schemaPath}`],
- [N.data, data]
- )
- }
- if (propertyName) keyValues.push([E.propertyName, propertyName])
- }
|