| import type {CodeKeywordDefinition, AnySchemaObject} from "../../types" |
| import type {KeywordCxt} from "../../compile/validate" |
| import {compileSchema, SchemaEnv} from "../../compile" |
| import {_, not, nil, stringify} from "../../compile/codegen" |
| import MissingRefError from "../../compile/ref_error" |
| import N from "../../compile/names" |
| import {getValidate, callRef} from "../core/ref" |
| import {checkMetadata} from "./metadata" |
| |
| const def: CodeKeywordDefinition = { |
| keyword: "ref", |
| schemaType: "string", |
| code(cxt: KeywordCxt) { |
| checkMetadata(cxt) |
| const {gen, data, schema: ref, parentSchema, it} = cxt |
| const { |
| schemaEnv: {root}, |
| } = it |
| const valid = gen.name("valid") |
| if (parentSchema.nullable) { |
| gen.var(valid, _`${data} === null`) |
| gen.if(not(valid), validateJtdRef) |
| } else { |
| gen.var(valid, false) |
| validateJtdRef() |
| } |
| cxt.ok(valid) |
| |
| function validateJtdRef(): void { |
| const refSchema = (root.schema as AnySchemaObject).definitions?.[ref] |
| if (!refSchema) throw new MissingRefError("", ref, `No definition ${ref}`) |
| if (hasRef(refSchema) || !it.opts.inlineRefs) callValidate(refSchema) |
| else inlineRefSchema(refSchema) |
| } |
| |
| function callValidate(schema: AnySchemaObject): void { |
| const sch = compileSchema.call( |
| it.self, |
| new SchemaEnv({schema, root, schemaPath: `/definitions/${ref}`}) |
| ) |
| const v = getValidate(cxt, sch) |
| const errsCount = gen.const("_errs", N.errors) |
| callRef(cxt, v, sch, sch.$async) |
| gen.assign(valid, _`${errsCount} === ${N.errors}`) |
| } |
| |
| function inlineRefSchema(schema: AnySchemaObject): void { |
| const schName = gen.scopeValue( |
| "schema", |
| it.opts.code.source === true ? {ref: schema, code: stringify(schema)} : {ref: schema} |
| ) |
| cxt.subschema( |
| { |
| schema, |
| dataTypes: [], |
| schemaPath: nil, |
| topSchemaRef: schName, |
| errSchemaPath: `/definitions/${ref}`, |
| }, |
| valid |
| ) |
| } |
| }, |
| } |
| |
| export function hasRef(schema: AnySchemaObject): boolean { |
| for (const key in schema) { |
| let sch: AnySchemaObject |
| if (key === "ref" || (typeof (sch = schema[key]) == "object" && hasRef(sch))) return true |
| } |
| return false |
| } |
| |
| export default def |