subschema.ts
1 import type {AnySchema} from "../../types" 2 import type {SchemaObjCxt} from ".." 3 import {_, str, getProperty, Code, Name} from "../codegen" 4 import {escapeFragment, getErrorPath, Type} from "../util" 5 import type {JSONType} from "../rules" 6 7 export interface SubschemaContext { 8 // TODO use Optional? align with SchemCxt property types 9 schema: AnySchema 10 schemaPath: Code 11 errSchemaPath: string 12 topSchemaRef?: Code 13 errorPath?: Code 14 dataLevel?: number 15 dataTypes?: JSONType[] 16 data?: Name 17 parentData?: Name 18 parentDataProperty?: Code | number 19 dataNames?: Name[] 20 dataPathArr?: (Code | number)[] 21 propertyName?: Name 22 jtdDiscriminator?: string 23 jtdMetadata?: boolean 24 compositeRule?: true 25 createErrors?: boolean 26 allErrors?: boolean 27 } 28 29 export type SubschemaArgs = Partial<{ 30 keyword: string 31 schemaProp: string | number 32 schema: AnySchema 33 schemaPath: Code 34 errSchemaPath: string 35 topSchemaRef: Code 36 data: Name | Code 37 dataProp: Code | string | number 38 dataTypes: JSONType[] 39 definedProperties: Set<string> 40 propertyName: Name 41 dataPropType: Type 42 jtdDiscriminator: string 43 jtdMetadata: boolean 44 compositeRule: true 45 createErrors: boolean 46 allErrors: boolean 47 }> 48 49 export function getSubschema( 50 it: SchemaObjCxt, 51 {keyword, schemaProp, schema, schemaPath, errSchemaPath, topSchemaRef}: SubschemaArgs 52 ): SubschemaContext { 53 if (keyword !== undefined && schema !== undefined) { 54 throw new Error('both "keyword" and "schema" passed, only one allowed') 55 } 56 57 if (keyword !== undefined) { 58 const sch = it.schema[keyword] 59 return schemaProp === undefined 60 ? { 61 schema: sch, 62 schemaPath: _`${it.schemaPath}${getProperty(keyword)}`, 63 errSchemaPath: `${it.errSchemaPath}/${keyword}`, 64 } 65 : { 66 schema: sch[schemaProp], 67 schemaPath: _`${it.schemaPath}${getProperty(keyword)}${getProperty(schemaProp)}`, 68 errSchemaPath: `${it.errSchemaPath}/${keyword}/${escapeFragment(schemaProp)}`, 69 } 70 } 71 72 if (schema !== undefined) { 73 if (schemaPath === undefined || errSchemaPath === undefined || topSchemaRef === undefined) { 74 throw new Error('"schemaPath", "errSchemaPath" and "topSchemaRef" are required with "schema"') 75 } 76 return { 77 schema, 78 schemaPath, 79 topSchemaRef, 80 errSchemaPath, 81 } 82 } 83 84 throw new Error('either "keyword" or "schema" must be passed') 85 } 86 87 export function extendSubschemaData( 88 subschema: SubschemaContext, 89 it: SchemaObjCxt, 90 {dataProp, dataPropType: dpType, data, dataTypes, propertyName}: SubschemaArgs 91 ): void { 92 if (data !== undefined && dataProp !== undefined) { 93 throw new Error('both "data" and "dataProp" passed, only one allowed') 94 } 95 96 const {gen} = it 97 98 if (dataProp !== undefined) { 99 const {errorPath, dataPathArr, opts} = it 100 const nextData = gen.let("data", _`${it.data}${getProperty(dataProp)}`, true) 101 dataContextProps(nextData) 102 subschema.errorPath = str`${errorPath}${getErrorPath(dataProp, dpType, opts.jsPropertySyntax)}` 103 subschema.parentDataProperty = _`${dataProp}` 104 subschema.dataPathArr = [...dataPathArr, subschema.parentDataProperty] 105 } 106 107 if (data !== undefined) { 108 const nextData = data instanceof Name ? data : gen.let("data", data, true) // replaceable if used once? 109 dataContextProps(nextData) 110 if (propertyName !== undefined) subschema.propertyName = propertyName 111 // TODO something is possibly wrong here with not changing parentDataProperty and not appending dataPathArr 112 } 113 114 if (dataTypes) subschema.dataTypes = dataTypes 115 116 function dataContextProps(_nextData: Name): void { 117 subschema.data = _nextData 118 subschema.dataLevel = it.dataLevel + 1 119 subschema.dataTypes = [] 120 it.definedProperties = new Set<string>() 121 subschema.parentData = it.data 122 subschema.dataNames = [...it.dataNames, _nextData] 123 } 124 } 125 126 export function extendSubschemaMode( 127 subschema: SubschemaContext, 128 {jtdDiscriminator, jtdMetadata, compositeRule, createErrors, allErrors}: SubschemaArgs 129 ): void { 130 if (compositeRule !== undefined) subschema.compositeRule = compositeRule 131 if (createErrors !== undefined) subschema.createErrors = createErrors 132 if (allErrors !== undefined) subschema.allErrors = allErrors 133 subschema.jtdDiscriminator = jtdDiscriminator // not inherited 134 subschema.jtdMetadata = jtdMetadata // not inherited 135 }