import type { CodeKeywordDefinition, KeywordErrorDefinition, ErrorObject, AnySchema, } from "../../types" import {_, not, and, Name, Code} from "../../compile/codegen" import {alwaysValidSchema} from "../../compile/util" import N from "../../compile/names" import {Type} from "../../compile/subschema" export type UnevaluatedPropertiesError = ErrorObject< "unevaluatedProperties", {unevaluatedProperty: string}, AnySchema > const error: KeywordErrorDefinition = { message: "should NOT have unevaluated properties", params: ({params}) => _`{unevaluatedProperty: ${params.unevaluatedProperty}}`, } const def: CodeKeywordDefinition = { keyword: "unevaluatedProperties", type: "object", schemaType: ["boolean", "object"], trackErrors: true, error, code(cxt) { const {gen, schema, data, errsCount, it} = cxt /* istanbul ignore if */ if (!errsCount) throw new Error("ajv implementation error") const {allErrors, props} = it if (props instanceof Name) { gen.if(_`${props} !== true`, () => gen.forIn("key", data, (key: Name) => gen.if(unevaluatedDynamic(props, key), () => unevaluatedPropCode(key)) ) ) } else if (props !== true) { gen.forIn("key", data, (key: Name) => props === undefined ? unevaluatedPropCode(key) : gen.if(unevaluatedStatic(props, key), () => unevaluatedPropCode(key)) ) } it.props = true cxt.ok(_`${errsCount} === ${N.errors}`) function unevaluatedPropCode(key: Name): void { if (schema === false) { cxt.setParams({unevaluatedProperty: key}) cxt.error() if (!allErrors) gen.break() return } if (!alwaysValidSchema(it, schema)) { const valid = gen.name("valid") cxt.subschema( { keyword: "unevaluatedProperties", dataProp: key, dataPropType: Type.Str, }, valid ) if (!allErrors) gen.if(not(valid), () => gen.break()) } } function unevaluatedDynamic(evaluatedProps: Name, key: Name): Code { return _`!${evaluatedProps} || !${evaluatedProps}[${key}]` } function unevaluatedStatic(evaluatedProps: {[K in string]?: true}, key: Name): Code { const ps: Code[] = [] for (const p in evaluatedProps) { if (evaluatedProps[p] === true) ps.push(_`${key} !== ${p}`) } return and(...ps) } }, } export default def