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 = { message : ( { params : { missingProperty } } ) => str `must have required property '${ missingProperty }'` , params : ( { params : { missingProperty } } ) => _ `{missingProperty: ${ missingProperty }}` , } ; const def = { keyword : "required" , type : "object" , schemaType : "array" , $data : true , error , code ( cxt ) { 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 ( ) { if ( useLoop || $data ) { cxt . block$data ( nil , loopAllRequired ) ; } else { for ( const prop of schema ) { checkReportMissingProp ( cxt , prop ) ; } } } function exitOnErrorMode ( ) { 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 ( ) { gen . forOf ( "prop" , schemaCode as Code , ( prop ) => { cxt . setParams ( { missingProperty : prop } ) ; gen . if ( noPropertyInData ( gen , data , prop , opts . ownProperties ) , ( ) => cxt . error ( ) ) ; } ) ; } function loopUntilMissing ( missing , valid ) { 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 ;