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.
		
		
		
		
		
			
		
			
				
					92 lines
				
				2.8 KiB
			
		
		
			
		
	
	
					92 lines
				
				2.8 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								import type {CodeKeywordDefinition} from "../../types"
							 | 
						||
| 
								 | 
							
								import type {KeywordCxt} from "../../compile/validate"
							 | 
						||
| 
								 | 
							
								import {allSchemaProperties, usePattern} from "../code"
							 | 
						||
| 
								 | 
							
								import {_, not, Name} from "../../compile/codegen"
							 | 
						||
| 
								 | 
							
								import {alwaysValidSchema, checkStrictMode} from "../../compile/util"
							 | 
						||
| 
								 | 
							
								import {evaluatedPropsToName, Type} from "../../compile/util"
							 | 
						||
| 
								 | 
							
								import {AnySchema} from "../../types"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const def: CodeKeywordDefinition = {
							 | 
						||
| 
								 | 
							
								  keyword: "patternProperties",
							 | 
						||
| 
								 | 
							
								  type: "object",
							 | 
						||
| 
								 | 
							
								  schemaType: "object",
							 | 
						||
| 
								 | 
							
								  code(cxt: KeywordCxt) {
							 | 
						||
| 
								 | 
							
								    const {gen, schema, data, parentSchema, it} = cxt
							 | 
						||
| 
								 | 
							
								    const {opts} = it
							 | 
						||
| 
								 | 
							
								    const patterns = allSchemaProperties(schema)
							 | 
						||
| 
								 | 
							
								    const alwaysValidPatterns = patterns.filter((p) =>
							 | 
						||
| 
								 | 
							
								      alwaysValidSchema(it, schema[p] as AnySchema)
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (
							 | 
						||
| 
								 | 
							
								      patterns.length === 0 ||
							 | 
						||
| 
								 | 
							
								      (alwaysValidPatterns.length === patterns.length &&
							 | 
						||
| 
								 | 
							
								        (!it.opts.unevaluated || it.props === true))
							 | 
						||
| 
								 | 
							
								    ) {
							 | 
						||
| 
								 | 
							
								      return
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const checkProperties =
							 | 
						||
| 
								 | 
							
								      opts.strictSchema && !opts.allowMatchingProperties && parentSchema.properties
							 | 
						||
| 
								 | 
							
								    const valid = gen.name("valid")
							 | 
						||
| 
								 | 
							
								    if (it.props !== true && !(it.props instanceof Name)) {
							 | 
						||
| 
								 | 
							
								      it.props = evaluatedPropsToName(gen, it.props)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    const {props} = it
							 | 
						||
| 
								 | 
							
								    validatePatternProperties()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function validatePatternProperties(): void {
							 | 
						||
| 
								 | 
							
								      for (const pat of patterns) {
							 | 
						||
| 
								 | 
							
								        if (checkProperties) checkMatchingProperties(pat)
							 | 
						||
| 
								 | 
							
								        if (it.allErrors) {
							 | 
						||
| 
								 | 
							
								          validateProperties(pat)
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								          gen.var(valid, true) // TODO var
							 | 
						||
| 
								 | 
							
								          validateProperties(pat)
							 | 
						||
| 
								 | 
							
								          gen.if(valid)
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function checkMatchingProperties(pat: string): void {
							 | 
						||
| 
								 | 
							
								      for (const prop in checkProperties) {
							 | 
						||
| 
								 | 
							
								        if (new RegExp(pat).test(prop)) {
							 | 
						||
| 
								 | 
							
								          checkStrictMode(
							 | 
						||
| 
								 | 
							
								            it,
							 | 
						||
| 
								 | 
							
								            `property ${prop} matches pattern ${pat} (use allowMatchingProperties)`
							 | 
						||
| 
								 | 
							
								          )
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function validateProperties(pat: string): void {
							 | 
						||
| 
								 | 
							
								      gen.forIn("key", data, (key) => {
							 | 
						||
| 
								 | 
							
								        gen.if(_`${usePattern(cxt, pat)}.test(${key})`, () => {
							 | 
						||
| 
								 | 
							
								          const alwaysValid = alwaysValidPatterns.includes(pat)
							 | 
						||
| 
								 | 
							
								          if (!alwaysValid) {
							 | 
						||
| 
								 | 
							
								            cxt.subschema(
							 | 
						||
| 
								 | 
							
								              {
							 | 
						||
| 
								 | 
							
								                keyword: "patternProperties",
							 | 
						||
| 
								 | 
							
								                schemaProp: pat,
							 | 
						||
| 
								 | 
							
								                dataProp: key,
							 | 
						||
| 
								 | 
							
								                dataPropType: Type.Str,
							 | 
						||
| 
								 | 
							
								              },
							 | 
						||
| 
								 | 
							
								              valid
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          if (it.opts.unevaluated && props !== true) {
							 | 
						||
| 
								 | 
							
								            gen.assign(_`${props}[${key}]`, true)
							 | 
						||
| 
								 | 
							
								          } else if (!alwaysValid && !it.allErrors) {
							 | 
						||
| 
								 | 
							
								            // can short-circuit if `unevaluatedProperties` is not supported (opts.next === false)
							 | 
						||
| 
								 | 
							
								            // or if all properties were evaluated (props === true)
							 | 
						||
| 
								 | 
							
								            gen.if(not(valid), () => gen.break())
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        })
							 | 
						||
| 
								 | 
							
								      })
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export default def
							 |