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.
		
		
		
		
		
			
		
			
				
					99 lines
				
				2.9 KiB
			
		
		
			
		
	
	
					99 lines
				
				2.9 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								import type {CodeKeywordDefinition, ErrorObject, KeywordErrorDefinition} from "../../types"
							 | 
						||
| 
								 | 
							
								import type {KeywordCxt} from "../../compile/validate"
							 | 
						||
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
								  checkReportMissingProp,
							 | 
						||
| 
								 | 
							
								  checkMissingProp,
							 | 
						||
| 
								 | 
							
								  reportMissingProp,
							 | 
						||
| 
								 | 
							
								  propertyInData,
							 | 
						||
| 
								 | 
							
								  noPropertyInData,
							 | 
						||
| 
								 | 
							
								} from "../code"
							 | 
						||
| 
								 | 
							
								import {_, str, nil, not, Name, Code} from "../../compile/codegen"
							 | 
						||
| 
								 | 
							
								import {checkStrictMode} from "../../compile/util"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export type RequiredError = ErrorObject<
							 | 
						||
| 
								 | 
							
								  "required",
							 | 
						||
| 
								 | 
							
								  {missingProperty: string},
							 | 
						||
| 
								 | 
							
								  string[] | {$data: string}
							 | 
						||
| 
								 | 
							
								>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const error: KeywordErrorDefinition = {
							 | 
						||
| 
								 | 
							
								  message: ({params: {missingProperty}}) => str`must have required property '${missingProperty}'`,
							 | 
						||
| 
								 | 
							
								  params: ({params: {missingProperty}}) => _`{missingProperty: ${missingProperty}}`,
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const def: CodeKeywordDefinition = {
							 | 
						||
| 
								 | 
							
								  keyword: "required",
							 | 
						||
| 
								 | 
							
								  type: "object",
							 | 
						||
| 
								 | 
							
								  schemaType: "array",
							 | 
						||
| 
								 | 
							
								  $data: true,
							 | 
						||
| 
								 | 
							
								  error,
							 | 
						||
| 
								 | 
							
								  code(cxt: KeywordCxt) {
							 | 
						||
| 
								 | 
							
								    const {gen, schema, schemaCode, data, $data, it} = cxt
							 | 
						||
| 
								 | 
							
								    const {opts} = it
							 | 
						||
| 
								 | 
							
								    if (!$data && schema.length === 0) return
							 | 
						||
| 
								 | 
							
								    const useLoop = schema.length >= opts.loopRequired
							 | 
						||
| 
								 | 
							
								    if (it.allErrors) allErrorsMode()
							 | 
						||
| 
								 | 
							
								    else exitOnErrorMode()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (opts.strictRequired) {
							 | 
						||
| 
								 | 
							
								      const props = cxt.parentSchema.properties
							 | 
						||
| 
								 | 
							
								      const {definedProperties} = cxt.it
							 | 
						||
| 
								 | 
							
								      for (const requiredKey of schema) {
							 | 
						||
| 
								 | 
							
								        if (props?.[requiredKey] === undefined && !definedProperties.has(requiredKey)) {
							 | 
						||
| 
								 | 
							
								          const schemaPath = it.schemaEnv.baseId + it.errSchemaPath
							 | 
						||
| 
								 | 
							
								          const msg = `required property "${requiredKey}" is not defined at "${schemaPath}" (strictRequired)`
							 | 
						||
| 
								 | 
							
								          checkStrictMode(it, msg, it.opts.strictRequired)
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function allErrorsMode(): void {
							 | 
						||
| 
								 | 
							
								      if (useLoop || $data) {
							 | 
						||
| 
								 | 
							
								        cxt.block$data(nil, loopAllRequired)
							 | 
						||
| 
								 | 
							
								      } else {
							 | 
						||
| 
								 | 
							
								        for (const prop of schema) {
							 | 
						||
| 
								 | 
							
								          checkReportMissingProp(cxt, prop)
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function exitOnErrorMode(): void {
							 | 
						||
| 
								 | 
							
								      const missing = gen.let("missing")
							 | 
						||
| 
								 | 
							
								      if (useLoop || $data) {
							 | 
						||
| 
								 | 
							
								        const valid = gen.let("valid", true)
							 | 
						||
| 
								 | 
							
								        cxt.block$data(valid, () => loopUntilMissing(missing, valid))
							 | 
						||
| 
								 | 
							
								        cxt.ok(valid)
							 | 
						||
| 
								 | 
							
								      } else {
							 | 
						||
| 
								 | 
							
								        gen.if(checkMissingProp(cxt, schema, missing))
							 | 
						||
| 
								 | 
							
								        reportMissingProp(cxt, missing)
							 | 
						||
| 
								 | 
							
								        gen.else()
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function loopAllRequired(): void {
							 | 
						||
| 
								 | 
							
								      gen.forOf("prop", schemaCode as Code, (prop) => {
							 | 
						||
| 
								 | 
							
								        cxt.setParams({missingProperty: prop})
							 | 
						||
| 
								 | 
							
								        gen.if(noPropertyInData(gen, data, prop, opts.ownProperties), () => cxt.error())
							 | 
						||
| 
								 | 
							
								      })
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function loopUntilMissing(missing: Name, valid: Name): void {
							 | 
						||
| 
								 | 
							
								      cxt.setParams({missingProperty: missing})
							 | 
						||
| 
								 | 
							
								      gen.forOf(
							 | 
						||
| 
								 | 
							
								        missing,
							 | 
						||
| 
								 | 
							
								        schemaCode as Code,
							 | 
						||
| 
								 | 
							
								        () => {
							 | 
						||
| 
								 | 
							
								          gen.assign(valid, propertyInData(gen, data, missing, opts.ownProperties))
							 | 
						||
| 
								 | 
							
								          gen.if(not(valid), () => {
							 | 
						||
| 
								 | 
							
								            cxt.error()
							 | 
						||
| 
								 | 
							
								            gen.break()
							 | 
						||
| 
								 | 
							
								          })
							 | 
						||
| 
								 | 
							
								        },
							 | 
						||
| 
								 | 
							
								        nil
							 | 
						||
| 
								 | 
							
								      )
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export default def
							 |