UNPKG

4.37 kBPlain TextView Raw
1import type {AnySchema} from "../../types"
2import type {SchemaObjCxt} from ".."
3import {_, str, getProperty, Code, Name} from "../codegen"
4import {escapeFragment, getErrorPath, Type} from "../util"
5import type {JSONType} from "../rules"
6
7export 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
29export 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
49export 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
87export 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
126export 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}