1 import type {CodeKeywordDefinition} from "../../types"
2 import type {KeywordCxt} from "../../compile/validate"
3 import {schemaProperties, usePattern} from "../code"
4 import {_, not, Name} from "../../compile/codegen"
5 import {checkStrictMode} from "../../compile/util"
6 import {evaluatedPropsToName, Type} from "../../compile/util"
8 const def: CodeKeywordDefinition = {
9 keyword: "patternProperties",
12 code(cxt: KeywordCxt) {
13 const {gen, schema, data, parentSchema, it} = cxt
15 const patterns = schemaProperties(it, schema)
16 // TODO mark properties matching patterns with always valid schemas as evaluated
17 if (patterns.length === 0) return
18 const checkProperties =
19 opts.strictSchema && !opts.allowMatchingProperties && parentSchema.properties
20 const valid = gen.name("valid")
21 if (it.props !== true && !(it.props instanceof Name)) {
22 it.props = evaluatedPropsToName(gen, it.props)
25 validatePatternProperties()
27 function validatePatternProperties(): void {
28 for (const pat of patterns) {
29 if (checkProperties) checkMatchingProperties(pat)
31 validateProperties(pat)
33 gen.var(valid, true) // TODO var
34 validateProperties(pat)
40 function checkMatchingProperties(pat: string): void {
41 for (const prop in checkProperties) {
42 if (new RegExp(pat).test(prop)) {
45 `property ${prop} matches pattern ${pat} (use allowMatchingProperties)`
51 function validateProperties(pat: string): void {
52 gen.forIn("key", data, (key) => {
53 gen.if(_`${usePattern(gen, pat)}.test(${key})`, () => {
56 keyword: "patternProperties",
59 dataPropType: Type.Str,
63 if (it.opts.unevaluated && props !== true) {
64 gen.assign(_`${props}[${key}]`, true)
65 } else if (!it.allErrors) {
66 // can short-circuit if `unevaluatedProperties` is not supported (opts.next === false)
67 // or if all properties were evaluated (props === true)
68 gen.if(not(valid), () => gen.break())