| import type {AnySchema} from "../../types" |
| import type {SchemaObjCxt} from ".." |
| import {_, str, getProperty, Code, Name} from "../codegen" |
| import {escapeFragment, getErrorPath, Type} from "../util" |
| import type {JSONType} from "../rules" |
| |
| export interface SubschemaContext { |
| // TODO use Optional? align with SchemCxt property types |
| schema: AnySchema |
| schemaPath: Code |
| errSchemaPath: string |
| topSchemaRef?: Code |
| errorPath?: Code |
| dataLevel?: number |
| dataTypes?: JSONType[] |
| data?: Name |
| parentData?: Name |
| parentDataProperty?: Code | number |
| dataNames?: Name[] |
| dataPathArr?: (Code | number)[] |
| propertyName?: Name |
| jtdDiscriminator?: string |
| jtdMetadata?: boolean |
| compositeRule?: true |
| createErrors?: boolean |
| allErrors?: boolean |
| } |
| |
| export type SubschemaArgs = Partial<{ |
| keyword: string |
| schemaProp: string | number |
| schema: AnySchema |
| schemaPath: Code |
| errSchemaPath: string |
| topSchemaRef: Code |
| data: Name | Code |
| dataProp: Code | string | number |
| dataTypes: JSONType[] |
| definedProperties: Set<string> |
| propertyName: Name |
| dataPropType: Type |
| jtdDiscriminator: string |
| jtdMetadata: boolean |
| compositeRule: true |
| createErrors: boolean |
| allErrors: boolean |
| }> |
| |
| export function getSubschema( |
| it: SchemaObjCxt, |
| {keyword, schemaProp, schema, schemaPath, errSchemaPath, topSchemaRef}: SubschemaArgs |
| ): SubschemaContext { |
| if (keyword !== undefined && schema !== undefined) { |
| throw new Error('both "keyword" and "schema" passed, only one allowed') |
| } |
| |
| if (keyword !== undefined) { |
| const sch = it.schema[keyword] |
| return schemaProp === undefined |
| ? { |
| schema: sch, |
| schemaPath: _`${it.schemaPath}${getProperty(keyword)}`, |
| errSchemaPath: `${it.errSchemaPath}/${keyword}`, |
| } |
| : { |
| schema: sch[schemaProp], |
| schemaPath: _`${it.schemaPath}${getProperty(keyword)}${getProperty(schemaProp)}`, |
| errSchemaPath: `${it.errSchemaPath}/${keyword}/${escapeFragment(schemaProp)}`, |
| } |
| } |
| |
| if (schema !== undefined) { |
| if (schemaPath === undefined || errSchemaPath === undefined || topSchemaRef === undefined) { |
| throw new Error('"schemaPath", "errSchemaPath" and "topSchemaRef" are required with "schema"') |
| } |
| return { |
| schema, |
| schemaPath, |
| topSchemaRef, |
| errSchemaPath, |
| } |
| } |
| |
| throw new Error('either "keyword" or "schema" must be passed') |
| } |
| |
| export function extendSubschemaData( |
| subschema: SubschemaContext, |
| it: SchemaObjCxt, |
| {dataProp, dataPropType: dpType, data, dataTypes, propertyName}: SubschemaArgs |
| ): void { |
| if (data !== undefined && dataProp !== undefined) { |
| throw new Error('both "data" and "dataProp" passed, only one allowed') |
| } |
| |
| const {gen} = it |
| |
| if (dataProp !== undefined) { |
| const {errorPath, dataPathArr, opts} = it |
| const nextData = gen.let("data", _`${it.data}${getProperty(dataProp)}`, true) |
| dataContextProps(nextData) |
| subschema.errorPath = str`${errorPath}${getErrorPath(dataProp, dpType, opts.jsPropertySyntax)}` |
| subschema.parentDataProperty = _`${dataProp}` |
| subschema.dataPathArr = [...dataPathArr, subschema.parentDataProperty] |
| } |
| |
| if (data !== undefined) { |
| const nextData = data instanceof Name ? data : gen.let("data", data, true) // replaceable if used once? |
| dataContextProps(nextData) |
| if (propertyName !== undefined) subschema.propertyName = propertyName |
| // TODO something is possibly wrong here with not changing parentDataProperty and not appending dataPathArr |
| } |
| |
| if (dataTypes) subschema.dataTypes = dataTypes |
| |
| function dataContextProps(_nextData: Name): void { |
| subschema.data = _nextData |
| subschema.dataLevel = it.dataLevel + 1 |
| subschema.dataTypes = [] |
| it.definedProperties = new Set<string>() |
| subschema.parentData = it.data |
| subschema.dataNames = [...it.dataNames, _nextData] |
| } |
| } |
| |
| export function extendSubschemaMode( |
| subschema: SubschemaContext, |
| {jtdDiscriminator, jtdMetadata, compositeRule, createErrors, allErrors}: SubschemaArgs |
| ): void { |
| if (compositeRule !== undefined) subschema.compositeRule = compositeRule |
| if (createErrors !== undefined) subschema.createErrors = createErrors |
| if (allErrors !== undefined) subschema.allErrors = allErrors |
| subschema.jtdDiscriminator = jtdDiscriminator // not inherited |
| subschema.jtdMetadata = jtdMetadata // not inherited |
| } |