[6a3a178] | 1 | import type {KeywordErrorCxt, KeywordErrorDefinition} from "../types"
|
---|
| 2 | import type {SchemaCxt} from "./index"
|
---|
| 3 | import {CodeGen, _, str, strConcat, Code, Name} from "./codegen"
|
---|
| 4 | import {SafeExpr} from "./codegen/code"
|
---|
| 5 | import {getErrorPath, Type} from "./util"
|
---|
| 6 | import N from "./names"
|
---|
| 7 |
|
---|
| 8 | export const keywordError: KeywordErrorDefinition = {
|
---|
| 9 | message: ({keyword}) => str`must pass "${keyword}" keyword validation`,
|
---|
| 10 | }
|
---|
| 11 |
|
---|
| 12 | export const keyword$DataError: KeywordErrorDefinition = {
|
---|
| 13 | message: ({keyword, schemaType}) =>
|
---|
| 14 | schemaType
|
---|
| 15 | ? str`"${keyword}" keyword must be ${schemaType} ($data)`
|
---|
| 16 | : str`"${keyword}" keyword is invalid ($data)`,
|
---|
| 17 | }
|
---|
| 18 |
|
---|
| 19 | export interface ErrorPaths {
|
---|
| 20 | instancePath?: Code
|
---|
| 21 | schemaPath?: string
|
---|
| 22 | parentSchema?: boolean
|
---|
| 23 | }
|
---|
| 24 |
|
---|
| 25 | export function reportError(
|
---|
| 26 | cxt: KeywordErrorCxt,
|
---|
| 27 | error: KeywordErrorDefinition = keywordError,
|
---|
| 28 | errorPaths?: ErrorPaths,
|
---|
| 29 | overrideAllErrors?: boolean
|
---|
| 30 | ): void {
|
---|
| 31 | const {it} = cxt
|
---|
| 32 | const {gen, compositeRule, allErrors} = it
|
---|
| 33 | const errObj = errorObjectCode(cxt, error, errorPaths)
|
---|
| 34 | if (overrideAllErrors ?? (compositeRule || allErrors)) {
|
---|
| 35 | addError(gen, errObj)
|
---|
| 36 | } else {
|
---|
| 37 | returnErrors(it, _`[${errObj}]`)
|
---|
| 38 | }
|
---|
| 39 | }
|
---|
| 40 |
|
---|
| 41 | export function reportExtraError(
|
---|
| 42 | cxt: KeywordErrorCxt,
|
---|
| 43 | error: KeywordErrorDefinition = keywordError,
|
---|
| 44 | errorPaths?: ErrorPaths
|
---|
| 45 | ): void {
|
---|
| 46 | const {it} = cxt
|
---|
| 47 | const {gen, compositeRule, allErrors} = it
|
---|
| 48 | const errObj = errorObjectCode(cxt, error, errorPaths)
|
---|
| 49 | addError(gen, errObj)
|
---|
| 50 | if (!(compositeRule || allErrors)) {
|
---|
| 51 | returnErrors(it, N.vErrors)
|
---|
| 52 | }
|
---|
| 53 | }
|
---|
| 54 |
|
---|
| 55 | export function resetErrorsCount(gen: CodeGen, errsCount: Name): void {
|
---|
| 56 | gen.assign(N.errors, errsCount)
|
---|
| 57 | gen.if(_`${N.vErrors} !== null`, () =>
|
---|
| 58 | gen.if(
|
---|
| 59 | errsCount,
|
---|
| 60 | () => gen.assign(_`${N.vErrors}.length`, errsCount),
|
---|
| 61 | () => gen.assign(N.vErrors, null)
|
---|
| 62 | )
|
---|
| 63 | )
|
---|
| 64 | }
|
---|
| 65 |
|
---|
| 66 | export function extendErrors({
|
---|
| 67 | gen,
|
---|
| 68 | keyword,
|
---|
| 69 | schemaValue,
|
---|
| 70 | data,
|
---|
| 71 | errsCount,
|
---|
| 72 | it,
|
---|
| 73 | }: KeywordErrorCxt): void {
|
---|
| 74 | /* istanbul ignore if */
|
---|
| 75 | if (errsCount === undefined) throw new Error("ajv implementation error")
|
---|
| 76 | const err = gen.name("err")
|
---|
| 77 | gen.forRange("i", errsCount, N.errors, (i) => {
|
---|
| 78 | gen.const(err, _`${N.vErrors}[${i}]`)
|
---|
| 79 | gen.if(_`${err}.instancePath === undefined`, () =>
|
---|
| 80 | gen.assign(_`${err}.instancePath`, strConcat(N.instancePath, it.errorPath))
|
---|
| 81 | )
|
---|
| 82 | gen.assign(_`${err}.schemaPath`, str`${it.errSchemaPath}/${keyword}`)
|
---|
| 83 | if (it.opts.verbose) {
|
---|
| 84 | gen.assign(_`${err}.schema`, schemaValue)
|
---|
| 85 | gen.assign(_`${err}.data`, data)
|
---|
| 86 | }
|
---|
| 87 | })
|
---|
| 88 | }
|
---|
| 89 |
|
---|
| 90 | function addError(gen: CodeGen, errObj: Code): void {
|
---|
| 91 | const err = gen.const("err", errObj)
|
---|
| 92 | gen.if(
|
---|
| 93 | _`${N.vErrors} === null`,
|
---|
| 94 | () => gen.assign(N.vErrors, _`[${err}]`),
|
---|
| 95 | _`${N.vErrors}.push(${err})`
|
---|
| 96 | )
|
---|
| 97 | gen.code(_`${N.errors}++`)
|
---|
| 98 | }
|
---|
| 99 |
|
---|
| 100 | function returnErrors(it: SchemaCxt, errs: Code): void {
|
---|
| 101 | const {gen, validateName, schemaEnv} = it
|
---|
| 102 | if (schemaEnv.$async) {
|
---|
| 103 | gen.throw(_`new ${it.ValidationError as Name}(${errs})`)
|
---|
| 104 | } else {
|
---|
| 105 | gen.assign(_`${validateName}.errors`, errs)
|
---|
| 106 | gen.return(false)
|
---|
| 107 | }
|
---|
| 108 | }
|
---|
| 109 |
|
---|
| 110 | const E = {
|
---|
| 111 | keyword: new Name("keyword"),
|
---|
| 112 | schemaPath: new Name("schemaPath"), // also used in JTD errors
|
---|
| 113 | params: new Name("params"),
|
---|
| 114 | propertyName: new Name("propertyName"),
|
---|
| 115 | message: new Name("message"),
|
---|
| 116 | schema: new Name("schema"),
|
---|
| 117 | parentSchema: new Name("parentSchema"),
|
---|
| 118 | }
|
---|
| 119 |
|
---|
| 120 | function errorObjectCode(
|
---|
| 121 | cxt: KeywordErrorCxt,
|
---|
| 122 | error: KeywordErrorDefinition,
|
---|
| 123 | errorPaths?: ErrorPaths
|
---|
| 124 | ): Code {
|
---|
| 125 | const {createErrors} = cxt.it
|
---|
| 126 | if (createErrors === false) return _`{}`
|
---|
| 127 | return errorObject(cxt, error, errorPaths)
|
---|
| 128 | }
|
---|
| 129 |
|
---|
| 130 | function errorObject(
|
---|
| 131 | cxt: KeywordErrorCxt,
|
---|
| 132 | error: KeywordErrorDefinition,
|
---|
| 133 | errorPaths: ErrorPaths = {}
|
---|
| 134 | ): Code {
|
---|
| 135 | const {gen, it} = cxt
|
---|
| 136 | const keyValues: [Name, SafeExpr | string][] = [
|
---|
| 137 | errorInstancePath(it, errorPaths),
|
---|
| 138 | errorSchemaPath(cxt, errorPaths),
|
---|
| 139 | ]
|
---|
| 140 | extraErrorProps(cxt, error, keyValues)
|
---|
| 141 | return gen.object(...keyValues)
|
---|
| 142 | }
|
---|
| 143 |
|
---|
| 144 | function errorInstancePath({errorPath}: SchemaCxt, {instancePath}: ErrorPaths): [Name, Code] {
|
---|
| 145 | const instPath = instancePath
|
---|
| 146 | ? str`${errorPath}${getErrorPath(instancePath, Type.Str)}`
|
---|
| 147 | : errorPath
|
---|
| 148 | return [N.instancePath, strConcat(N.instancePath, instPath)]
|
---|
| 149 | }
|
---|
| 150 |
|
---|
| 151 | function errorSchemaPath(
|
---|
| 152 | {keyword, it: {errSchemaPath}}: KeywordErrorCxt,
|
---|
| 153 | {schemaPath, parentSchema}: ErrorPaths
|
---|
| 154 | ): [Name, string | Code] {
|
---|
| 155 | let schPath = parentSchema ? errSchemaPath : str`${errSchemaPath}/${keyword}`
|
---|
| 156 | if (schemaPath) {
|
---|
| 157 | schPath = str`${schPath}${getErrorPath(schemaPath, Type.Str)}`
|
---|
| 158 | }
|
---|
| 159 | return [E.schemaPath, schPath]
|
---|
| 160 | }
|
---|
| 161 |
|
---|
| 162 | function extraErrorProps(
|
---|
| 163 | cxt: KeywordErrorCxt,
|
---|
| 164 | {params, message}: KeywordErrorDefinition,
|
---|
| 165 | keyValues: [Name, SafeExpr | string][]
|
---|
| 166 | ): void {
|
---|
| 167 | const {keyword, data, schemaValue, it} = cxt
|
---|
| 168 | const {opts, propertyName, topSchemaRef, schemaPath} = it
|
---|
| 169 | keyValues.push(
|
---|
| 170 | [E.keyword, keyword],
|
---|
| 171 | [E.params, typeof params == "function" ? params(cxt) : params || _`{}`]
|
---|
| 172 | )
|
---|
| 173 | if (opts.messages) {
|
---|
| 174 | keyValues.push([E.message, typeof message == "function" ? message(cxt) : message])
|
---|
| 175 | }
|
---|
| 176 | if (opts.verbose) {
|
---|
| 177 | keyValues.push(
|
---|
| 178 | [E.schema, schemaValue],
|
---|
| 179 | [E.parentSchema, _`${topSchemaRef}${schemaPath}`],
|
---|
| 180 | [N.data, data]
|
---|
| 181 | )
|
---|
| 182 | }
|
---|
| 183 | if (propertyName) keyValues.push([E.propertyName, propertyName])
|
---|
| 184 | }
|
---|