Spaces:
Running
Running
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 | |
} | |