123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- import type {
- CodeKeywordDefinition,
- ErrorObject,
- KeywordErrorDefinition,
- SchemaMap,
- AnySchema,
- } from "../../types"
- import type {KeywordCxt} from "../../compile/validate"
- import {_, str} from "../../compile/codegen"
- import {alwaysValidSchema} from "../../compile/util"
- import {checkReportMissingProp, checkMissingProp, reportMissingProp, propertyInData} from "../code"
- export type PropertyDependencies = {[K in string]?: string[]}
- export interface DependenciesErrorParams {
- property: string
- missingProperty: string
- depsCount: number
- deps: string // TODO change to string[]
- }
- type SchemaDependencies = SchemaMap
- export type DependenciesError = ErrorObject<
- "dependencies",
- DependenciesErrorParams,
- {[K in string]?: string[] | AnySchema}
- >
- export const error: KeywordErrorDefinition = {
- message: ({params: {property, depsCount, deps}}) => {
- const property_ies = depsCount === 1 ? "property" : "properties"
- return str`must have ${property_ies} ${deps} when property ${property} is present`
- },
- params: ({params: {property, depsCount, deps, missingProperty}}) =>
- _`{property: ${property},
- missingProperty: ${missingProperty},
- depsCount: ${depsCount},
- deps: ${deps}}`, // TODO change to reference
- }
- const def: CodeKeywordDefinition = {
- keyword: "dependencies",
- type: "object",
- schemaType: "object",
- error,
- code(cxt: KeywordCxt) {
- const [propDeps, schDeps] = splitDependencies(cxt)
- validatePropertyDeps(cxt, propDeps)
- validateSchemaDeps(cxt, schDeps)
- },
- }
- function splitDependencies({schema}: KeywordCxt): [PropertyDependencies, SchemaDependencies] {
- const propertyDeps: PropertyDependencies = {}
- const schemaDeps: SchemaDependencies = {}
- for (const key in schema) {
- if (key === "__proto__") continue
- const deps = Array.isArray(schema[key]) ? propertyDeps : schemaDeps
- deps[key] = schema[key]
- }
- return [propertyDeps, schemaDeps]
- }
- export function validatePropertyDeps(
- cxt: KeywordCxt,
- propertyDeps: {[K in string]?: string[]} = cxt.schema
- ): void {
- const {gen, data, it} = cxt
- if (Object.keys(propertyDeps).length === 0) return
- const missing = gen.let("missing")
- for (const prop in propertyDeps) {
- const deps = propertyDeps[prop] as string[]
- if (deps.length === 0) continue
- const hasProperty = propertyInData(gen, data, prop, it.opts.ownProperties)
- cxt.setParams({
- property: prop,
- depsCount: deps.length,
- deps: deps.join(", "),
- })
- if (it.allErrors) {
- gen.if(hasProperty, () => {
- for (const depProp of deps) {
- checkReportMissingProp(cxt, depProp)
- }
- })
- } else {
- gen.if(_`${hasProperty} && (${checkMissingProp(cxt, deps, missing)})`)
- reportMissingProp(cxt, missing)
- gen.else()
- }
- }
- }
- export function validateSchemaDeps(cxt: KeywordCxt, schemaDeps: SchemaMap = cxt.schema): void {
- const {gen, data, keyword, it} = cxt
- const valid = gen.name("valid")
- for (const prop in schemaDeps) {
- if (alwaysValidSchema(it, schemaDeps[prop] as AnySchema)) continue
- gen.if(
- propertyInData(gen, data, prop, it.opts.ownProperties),
- () => {
- const schCxt = cxt.subschema({keyword, schemaProp: prop}, valid)
- cxt.mergeValidEvaluated(schCxt, valid)
- },
- () => gen.var(valid, true) // TODO var
- )
- cxt.ok(valid)
- }
- }
- export default def
|