You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					136 lines
				
				4.3 KiB
			
		
		
			
		
	
	
					136 lines
				
				4.3 KiB
			| 
											3 years ago
										 | 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
 | ||
|  | } |