UNPKG

2.87 kBPlain TextView Raw
1import type {CodeKeywordDefinition} from "../../types"
2import type {KeywordCxt} from "../../compile/validate"
3import {allSchemaProperties, usePattern} from "../code"
4import {_, not, Name} from "../../compile/codegen"
5import {alwaysValidSchema, checkStrictMode} from "../../compile/util"
6import {evaluatedPropsToName, Type} from "../../compile/util"
7import {AnySchema} from "../../types"
8
9const def: CodeKeywordDefinition = {
10 keyword: "patternProperties",
11 type: "object",
12 schemaType: "object",
13 code(cxt: KeywordCxt) {
14 const {gen, schema, data, parentSchema, it} = cxt
15 const {opts} = it
16 const patterns = allSchemaProperties(schema)
17 const alwaysValidPatterns = patterns.filter((p) =>
18 alwaysValidSchema(it, schema[p] as AnySchema)
19 )
20
21 if (
22 patterns.length === 0 ||
23 (alwaysValidPatterns.length === patterns.length &&
24 (!it.opts.unevaluated || it.props === true))
25 ) {
26 return
27 }
28
29 const checkProperties =
30 opts.strictSchema && !opts.allowMatchingProperties && parentSchema.properties
31 const valid = gen.name("valid")
32 if (it.props !== true && !(it.props instanceof Name)) {
33 it.props = evaluatedPropsToName(gen, it.props)
34 }
35 const {props} = it
36 validatePatternProperties()
37
38 function validatePatternProperties(): void {
39 for (const pat of patterns) {
40 if (checkProperties) checkMatchingProperties(pat)
41 if (it.allErrors) {
42 validateProperties(pat)
43 } else {
44 gen.var(valid, true) // TODO var
45 validateProperties(pat)
46 gen.if(valid)
47 }
48 }
49 }
50
51 function checkMatchingProperties(pat: string): void {
52 for (const prop in checkProperties) {
53 if (new RegExp(pat).test(prop)) {
54 checkStrictMode(
55 it,
56 `property ${prop} matches pattern ${pat} (use allowMatchingProperties)`
57 )
58 }
59 }
60 }
61
62 function validateProperties(pat: string): void {
63 gen.forIn("key", data, (key) => {
64 gen.if(_`${usePattern(cxt, pat)}.test(${key})`, () => {
65 const alwaysValid = alwaysValidPatterns.includes(pat)
66 if (!alwaysValid) {
67 cxt.subschema(
68 {
69 keyword: "patternProperties",
70 schemaProp: pat,
71 dataProp: key,
72 dataPropType: Type.Str,
73 },
74 valid
75 )
76 }
77
78 if (it.opts.unevaluated && props !== true) {
79 gen.assign(_`${props}[${key}]`, true)
80 } else if (!alwaysValid && !it.allErrors) {
81 // can short-circuit if `unevaluatedProperties` is not supported (opts.next === false)
82 // or if all properties were evaluated (props === true)
83 gen.if(not(valid), () => gen.break())
84 }
85 })
86 })
87 }
88 },
89}
90
91export default def