z-schema 12.0.4 → 12.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/z-schema +7 -2
- package/cjs/index.d.ts +541 -530
- package/cjs/index.js +3963 -7740
- package/dist/errors.d.mts +64 -0
- package/dist/errors.mjs +67 -0
- package/dist/format-validators.d.mts +14 -0
- package/dist/format-validators.mjs +261 -0
- package/dist/index.d.mts +10 -0
- package/dist/index.mjs +7 -0
- package/dist/json-schema-versions.d.mts +137 -0
- package/dist/json-schema-versions.mjs +11 -0
- package/dist/json-schema.d.mts +61 -0
- package/dist/json-schema.mjs +53 -0
- package/dist/json-validation.mjs +441 -0
- package/dist/report.d.mts +97 -0
- package/dist/report.mjs +194 -0
- package/dist/schema-cache.d.mts +23 -0
- package/dist/schema-cache.mjs +144 -0
- package/dist/schema-compiler.d.mts +23 -0
- package/dist/schema-compiler.mjs +265 -0
- package/dist/schema-validator.d.mts +15 -0
- package/dist/schema-validator.mjs +446 -0
- package/dist/schemas/draft-04-schema.mjs +125 -0
- package/dist/schemas/draft-06-schema.mjs +126 -0
- package/dist/schemas/draft-07-schema.mjs +141 -0
- package/dist/schemas/draft-2019-09-meta-applicator.mjs +46 -0
- package/dist/schemas/draft-2019-09-meta-content.mjs +15 -0
- package/dist/schemas/draft-2019-09-meta-core.mjs +52 -0
- package/dist/schemas/draft-2019-09-meta-format.mjs +11 -0
- package/dist/schemas/draft-2019-09-meta-meta-data.mjs +31 -0
- package/dist/schemas/draft-2019-09-meta-validation.mjs +80 -0
- package/dist/schemas/draft-2019-09-schema.mjs +39 -0
- package/dist/schemas/draft-2020-12-meta-applicator.mjs +45 -0
- package/dist/schemas/draft-2020-12-meta-content.mjs +15 -0
- package/dist/schemas/draft-2020-12-meta-core.mjs +46 -0
- package/dist/schemas/draft-2020-12-meta-format-annotation.mjs +11 -0
- package/dist/schemas/draft-2020-12-meta-format-assertion.mjs +11 -0
- package/dist/schemas/draft-2020-12-meta-meta-data.mjs +31 -0
- package/dist/schemas/draft-2020-12-meta-unevaluated.mjs +14 -0
- package/dist/schemas/draft-2020-12-meta-validation.mjs +80 -0
- package/dist/schemas/draft-2020-12-schema.mjs +55 -0
- package/dist/utils/array.mjs +54 -0
- package/dist/utils/base64.mjs +21 -0
- package/dist/utils/clone.mjs +42 -0
- package/dist/utils/constants.mjs +16 -0
- package/dist/utils/date.mjs +19 -0
- package/dist/utils/hostname.mjs +73 -0
- package/dist/utils/json.mjs +34 -0
- package/dist/utils/properties.mjs +11 -0
- package/dist/utils/schema-regex.mjs +49 -0
- package/dist/utils/symbols.mjs +5 -0
- package/dist/utils/time.mjs +42 -0
- package/dist/utils/unicode.mjs +12 -0
- package/dist/utils/uri.mjs +12 -0
- package/dist/utils/what-is.mjs +23 -0
- package/dist/validation/array.mjs +57 -0
- package/dist/validation/combinators.mjs +62 -0
- package/dist/validation/numeric.mjs +38 -0
- package/dist/validation/object.mjs +109 -0
- package/dist/validation/ref.mjs +49 -0
- package/dist/validation/shared.mjs +97 -0
- package/dist/validation/string.mjs +88 -0
- package/dist/validation/type.mjs +32 -0
- package/dist/z-schema-base.d.mts +85 -0
- package/dist/z-schema-base.mjs +230 -0
- package/dist/z-schema-options.d.mts +35 -0
- package/dist/z-schema-options.mjs +55 -0
- package/dist/z-schema-reader.d.mts +6 -0
- package/dist/z-schema-reader.mjs +10 -0
- package/dist/z-schema-versions.mjs +67 -0
- package/dist/z-schema.d.mts +193 -0
- package/dist/z-schema.mjs +300 -0
- package/package.json +49 -64
- package/src/index.ts +3 -3
- package/src/schema-compiler.ts +30 -10
- package/src/schema-validator.ts +1 -1
- package/src/utils/schema-regex.ts +13 -2
- package/src/z-schema-base.ts +1 -1
- package/src/z-schema-versions.ts +1 -2
- package/src/z-schema.ts +0 -1
- package/umd/ZSchema.js +5934 -8110
- package/umd/ZSchema.min.js +2 -1
- package/dist/errors.js +0 -72
- package/dist/format-validators.js +0 -392
- package/dist/index.js +0 -5
- package/dist/json-schema-versions.js +0 -8
- package/dist/json-schema.js +0 -84
- package/dist/json-validation.js +0 -728
- package/dist/package.json +0 -3
- package/dist/report.js +0 -265
- package/dist/schema-cache.js +0 -211
- package/dist/schema-compiler.js +0 -415
- package/dist/schema-validator.js +0 -721
- package/dist/schemas/draft-04-schema.json +0 -149
- package/dist/schemas/draft-06-schema.json +0 -155
- package/dist/schemas/draft-07-schema.json +0 -172
- package/dist/schemas/draft-2019-09-meta-applicator.json +0 -52
- package/dist/schemas/draft-2019-09-meta-content.json +0 -12
- package/dist/schemas/draft-2019-09-meta-core.json +0 -53
- package/dist/schemas/draft-2019-09-meta-format.json +0 -10
- package/dist/schemas/draft-2019-09-meta-meta-data.json +0 -32
- package/dist/schemas/draft-2019-09-meta-validation.json +0 -94
- package/dist/schemas/draft-2019-09-schema.json +0 -41
- package/dist/schemas/draft-2020-12-meta-applicator.json +0 -44
- package/dist/schemas/draft-2020-12-meta-content.json +0 -12
- package/dist/schemas/draft-2020-12-meta-core.json +0 -47
- package/dist/schemas/draft-2020-12-meta-format-annotation.json +0 -10
- package/dist/schemas/draft-2020-12-meta-format-assertion.json +0 -10
- package/dist/schemas/draft-2020-12-meta-meta-data.json +0 -32
- package/dist/schemas/draft-2020-12-meta-unevaluated.json +0 -11
- package/dist/schemas/draft-2020-12-meta-validation.json +0 -94
- package/dist/schemas/draft-2020-12-schema.json +0 -57
- package/dist/types/errors.d.ts +0 -64
- package/dist/types/format-validators.d.ts +0 -11
- package/dist/types/index.d.ts +0 -14
- package/dist/types/json-schema-versions.d.ts +0 -142
- package/dist/types/json-schema.d.ts +0 -66
- package/dist/types/json-validation.d.ts +0 -6
- package/dist/types/report.d.ts +0 -94
- package/dist/types/schema-cache.d.ts +0 -27
- package/dist/types/schema-compiler.d.ts +0 -31
- package/dist/types/schema-validator.d.ts +0 -10
- package/dist/types/utils/array.d.ts +0 -9
- package/dist/types/utils/base64.d.ts +0 -2
- package/dist/types/utils/clone.d.ts +0 -2
- package/dist/types/utils/constants.d.ts +0 -19
- package/dist/types/utils/date.d.ts +0 -1
- package/dist/types/utils/hostname.d.ts +0 -2
- package/dist/types/utils/json.d.ts +0 -9
- package/dist/types/utils/properties.d.ts +0 -1
- package/dist/types/utils/schema-regex.d.ts +0 -10
- package/dist/types/utils/symbols.d.ts +0 -2
- package/dist/types/utils/time.d.ts +0 -12
- package/dist/types/utils/unicode.d.ts +0 -5
- package/dist/types/utils/uri.d.ts +0 -4
- package/dist/types/utils/what-is.d.ts +0 -4
- package/dist/types/validation/array.d.ts +0 -12
- package/dist/types/validation/combinators.d.ts +0 -10
- package/dist/types/validation/numeric.d.ts +0 -8
- package/dist/types/validation/object.d.ts +0 -13
- package/dist/types/validation/ref.d.ts +0 -11
- package/dist/types/validation/shared.d.ts +0 -26
- package/dist/types/validation/string.d.ts +0 -9
- package/dist/types/validation/type.d.ts +0 -6
- package/dist/types/z-schema-base.d.ts +0 -87
- package/dist/types/z-schema-options.d.ts +0 -35
- package/dist/types/z-schema-reader.d.ts +0 -4
- package/dist/types/z-schema-versions.d.ts +0 -1
- package/dist/types/z-schema.d.ts +0 -191
- package/dist/utils/array.js +0 -69
- package/dist/utils/base64.js +0 -29
- package/dist/utils/clone.js +0 -59
- package/dist/utils/constants.js +0 -19
- package/dist/utils/date.js +0 -21
- package/dist/utils/hostname.js +0 -146
- package/dist/utils/json.js +0 -70
- package/dist/utils/properties.js +0 -10
- package/dist/utils/schema-regex.js +0 -52
- package/dist/utils/symbols.js +0 -2
- package/dist/utils/time.js +0 -50
- package/dist/utils/unicode.js +0 -12
- package/dist/utils/uri.js +0 -15
- package/dist/utils/what-is.js +0 -32
- package/dist/validation/array.js +0 -127
- package/dist/validation/combinators.js +0 -106
- package/dist/validation/numeric.js +0 -97
- package/dist/validation/object.js +0 -237
- package/dist/validation/ref.js +0 -70
- package/dist/validation/shared.js +0 -136
- package/dist/validation/string.js +0 -170
- package/dist/validation/type.js +0 -55
- package/dist/z-schema-base.js +0 -286
- package/dist/z-schema-options.js +0 -99
- package/dist/z-schema-reader.js +0 -7
- package/dist/z-schema-versions.js +0 -110
- package/dist/z-schema.js +0 -287
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { getRemotePath, isAbsoluteUri } from "./utils/uri.mjs";
|
|
2
|
+
import { isObject } from "./utils/what-is.mjs";
|
|
3
|
+
//#region src/json-schema.ts
|
|
4
|
+
/**
|
|
5
|
+
* Keywords whose values are not JSON Schema sub-schemas and must not be
|
|
6
|
+
* traversed during schema walking (id collection, reference collection, etc.).
|
|
7
|
+
*/
|
|
8
|
+
const NON_SCHEMA_KEYWORDS = [
|
|
9
|
+
"enum",
|
|
10
|
+
"const",
|
|
11
|
+
"default",
|
|
12
|
+
"examples"
|
|
13
|
+
];
|
|
14
|
+
/** Returns true if the key is an internal z-schema property (prefixed with `__$`). */
|
|
15
|
+
const isInternalKey = (key) => key.startsWith("__$");
|
|
16
|
+
const getId = (schema) => {
|
|
17
|
+
if (typeof schema.$schema === "string" && schema.$schema.includes("draft-04")) return schema.id;
|
|
18
|
+
return schema.$id ?? schema.id;
|
|
19
|
+
};
|
|
20
|
+
const findId = (schema, id, targetBaseUri, currentBaseUri, maxDepth = 100, _depth = 0) => {
|
|
21
|
+
if (typeof schema !== "object" || schema === null) return;
|
|
22
|
+
if (!id) return schema;
|
|
23
|
+
if (_depth >= maxDepth) throw new Error(`Maximum recursion depth (${maxDepth}) exceeded in findId. If your schema is deeply nested and valid, increase the maxRecursionDepth option.`);
|
|
24
|
+
const baseUri = currentBaseUri ?? targetBaseUri;
|
|
25
|
+
const schemaId = getId(schema);
|
|
26
|
+
let nextBaseUri = baseUri;
|
|
27
|
+
if (schemaId) {
|
|
28
|
+
if (isAbsoluteUri(schemaId)) nextBaseUri = getRemotePath(schemaId);
|
|
29
|
+
else if (baseUri && isAbsoluteUri(baseUri)) try {
|
|
30
|
+
nextBaseUri = getRemotePath(new URL(schemaId, baseUri).toString());
|
|
31
|
+
} catch {}
|
|
32
|
+
}
|
|
33
|
+
if (!targetBaseUri || nextBaseUri === targetBaseUri) {
|
|
34
|
+
if (schemaId && (schemaId === id || schemaId[0] === "#" && schemaId.substring(1) === id)) return schema;
|
|
35
|
+
if (schema.$anchor === id || schema.$dynamicAnchor === id) return schema;
|
|
36
|
+
}
|
|
37
|
+
let result;
|
|
38
|
+
if (Array.isArray(schema)) for (let i = 0; i < schema.length; i++) {
|
|
39
|
+
result = findId(schema[i], id, targetBaseUri, nextBaseUri, maxDepth, _depth + 1);
|
|
40
|
+
if (result) return result;
|
|
41
|
+
}
|
|
42
|
+
if (isObject(schema)) {
|
|
43
|
+
const keys = Object.keys(schema);
|
|
44
|
+
for (let i = keys.length - 1; i >= 0; i--) {
|
|
45
|
+
const k = keys[i];
|
|
46
|
+
if (isInternalKey(k) || NON_SCHEMA_KEYWORDS.includes(k)) continue;
|
|
47
|
+
result = findId(schema[k], id, targetBaseUri, nextBaseUri, maxDepth, _depth + 1);
|
|
48
|
+
if (result) return result;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
//#endregion
|
|
53
|
+
export { NON_SCHEMA_KEYWORDS, findId, getId, isInternalKey };
|
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
import { isObject, whatIs } from "./utils/what-is.mjs";
|
|
2
|
+
import { getId } from "./json-schema.mjs";
|
|
3
|
+
import { Report } from "./report.mjs";
|
|
4
|
+
import { compileSchemaRegex } from "./utils/schema-regex.mjs";
|
|
5
|
+
import { VALIDATION_VOCAB_KEYWORDS, getCachedValidationResult, isValidationVocabularyEnabled } from "./validation/shared.mjs";
|
|
6
|
+
import { additionalItemsValidator, containsValidator, itemsValidator, maxContainsValidator, maxItemsValidator, minContainsValidator, minItemsValidator, prefixItemsValidator, uniqueItemsValidator } from "./validation/array.mjs";
|
|
7
|
+
import { allOfValidator, anyOfValidator, elseValidator, ifValidator, notValidator, oneOfValidator, thenValidator } from "./validation/combinators.mjs";
|
|
8
|
+
import { exclusiveMaximumValidator, exclusiveMinimumValidator, maximumValidator, minimumValidator, multipleOfValidator } from "./validation/numeric.mjs";
|
|
9
|
+
import { additionalPropertiesValidator, dependenciesValidator, dependentRequiredValidator, dependentSchemasValidator, maxPropertiesValidator, minPropertiesValidator, patternPropertiesValidator, propertiesValidator, propertyNamesValidator, requiredValidator } from "./validation/object.mjs";
|
|
10
|
+
import { resolveDynamicRef, resolveRecursiveRef } from "./validation/ref.mjs";
|
|
11
|
+
import { contentEncodingValidator, contentMediaTypeValidator, formatValidator, maxLengthValidator, minLengthValidator, patternValidator } from "./validation/string.mjs";
|
|
12
|
+
import { constValidator, enumValidator, typeValidator } from "./validation/type.mjs";
|
|
13
|
+
//#region src/json-validation.ts
|
|
14
|
+
function collectEvaluated(args) {
|
|
15
|
+
const { report, currentSchema, json, mode, depth } = args;
|
|
16
|
+
if (!currentSchema || typeof currentSchema === "boolean") return /* @__PURE__ */ new Set();
|
|
17
|
+
if (depth > (this.options.maxRecursionDepth ?? 100)) {
|
|
18
|
+
report.addError("COLLECT_EVALUATED_DEPTH_EXCEEDED", [depth]);
|
|
19
|
+
return /* @__PURE__ */ new Set();
|
|
20
|
+
}
|
|
21
|
+
const evaluated = /* @__PURE__ */ new Set();
|
|
22
|
+
const merge = (other) => {
|
|
23
|
+
if (other === "all") return true;
|
|
24
|
+
for (const v of other) evaluated.add(v);
|
|
25
|
+
return false;
|
|
26
|
+
};
|
|
27
|
+
const recurse = (subSchema) => {
|
|
28
|
+
if (mode === "items") return collectEvaluated.call(this, {
|
|
29
|
+
report,
|
|
30
|
+
currentSchema: subSchema,
|
|
31
|
+
json,
|
|
32
|
+
mode: "items",
|
|
33
|
+
jsonArr: args.jsonArr,
|
|
34
|
+
depth: depth + 1
|
|
35
|
+
});
|
|
36
|
+
return collectEvaluated.call(this, {
|
|
37
|
+
report,
|
|
38
|
+
currentSchema: subSchema,
|
|
39
|
+
json,
|
|
40
|
+
mode: "properties",
|
|
41
|
+
jsonData: args.jsonData,
|
|
42
|
+
depth: depth + 1
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
if (mode === "items") {
|
|
46
|
+
const jsonArr = args.jsonArr;
|
|
47
|
+
if (Array.isArray(currentSchema.prefixItems)) {
|
|
48
|
+
const len = Math.min(currentSchema.prefixItems.length, jsonArr.length);
|
|
49
|
+
for (let i = 0; i < len; i++) evaluated.add(i);
|
|
50
|
+
}
|
|
51
|
+
if (currentSchema.items !== void 0) {
|
|
52
|
+
if (Array.isArray(currentSchema.items)) {
|
|
53
|
+
const len = Math.min(currentSchema.items.length, jsonArr.length);
|
|
54
|
+
for (let i = 0; i < len; i++) evaluated.add(i);
|
|
55
|
+
} else if (currentSchema.items !== false) return "all";
|
|
56
|
+
}
|
|
57
|
+
if (currentSchema.additionalItems !== void 0 && currentSchema.additionalItems !== false && Array.isArray(currentSchema.items)) return "all";
|
|
58
|
+
if (currentSchema.contains !== void 0) for (let i = 0; i < jsonArr.length; i++) {
|
|
59
|
+
let passed = getCachedValidationResult(report, currentSchema.contains, jsonArr[i]);
|
|
60
|
+
if (passed === void 0) {
|
|
61
|
+
const subReport = new Report(report);
|
|
62
|
+
validate.call(this, subReport, currentSchema.contains, jsonArr[i]);
|
|
63
|
+
passed = subReport.errors.length === 0;
|
|
64
|
+
}
|
|
65
|
+
if (passed) evaluated.add(i);
|
|
66
|
+
}
|
|
67
|
+
if (currentSchema.unevaluatedItems === true) return "all";
|
|
68
|
+
} else {
|
|
69
|
+
const jsonData = args.jsonData;
|
|
70
|
+
if (isObject(currentSchema.properties)) {
|
|
71
|
+
for (const key of Object.keys(currentSchema.properties)) if (Object.hasOwn(jsonData, key)) evaluated.add(key);
|
|
72
|
+
}
|
|
73
|
+
if (isObject(currentSchema.patternProperties)) for (const pattern of Object.keys(currentSchema.patternProperties)) {
|
|
74
|
+
const result = compileSchemaRegex(pattern);
|
|
75
|
+
if (result.ok) {
|
|
76
|
+
for (const key of Object.keys(jsonData)) if (result.value.test(key)) evaluated.add(key);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (currentSchema.additionalProperties !== void 0) {
|
|
80
|
+
const propKeys = isObject(currentSchema.properties) ? Object.keys(currentSchema.properties) : [];
|
|
81
|
+
const patternRegexes = [];
|
|
82
|
+
if (isObject(currentSchema.patternProperties)) for (const pattern of Object.keys(currentSchema.patternProperties)) {
|
|
83
|
+
const result = compileSchemaRegex(pattern);
|
|
84
|
+
if (result.ok) patternRegexes.push(result.value);
|
|
85
|
+
}
|
|
86
|
+
for (const key of Object.keys(jsonData)) {
|
|
87
|
+
if (propKeys.includes(key)) continue;
|
|
88
|
+
if (patternRegexes.some((re) => re.test(key))) continue;
|
|
89
|
+
evaluated.add(key);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (isObject(currentSchema.dependentSchemas)) {
|
|
93
|
+
for (const [depKey, depSchema] of Object.entries(currentSchema.dependentSchemas)) if (Object.hasOwn(jsonData, depKey)) {
|
|
94
|
+
if (merge(recurse(depSchema))) return "all";
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (currentSchema.unevaluatedProperties === true) return "all";
|
|
98
|
+
}
|
|
99
|
+
if (Array.isArray(currentSchema.allOf)) {
|
|
100
|
+
for (const subSchema of currentSchema.allOf) if (merge(recurse(subSchema))) return "all";
|
|
101
|
+
}
|
|
102
|
+
if (Array.isArray(currentSchema.anyOf)) for (const subSchema of currentSchema.anyOf) {
|
|
103
|
+
let passed = getCachedValidationResult(report, subSchema, json);
|
|
104
|
+
if (passed === void 0) {
|
|
105
|
+
const subReport = new Report(report);
|
|
106
|
+
validate.call(this, subReport, subSchema, json);
|
|
107
|
+
passed = subReport.errors.length === 0;
|
|
108
|
+
}
|
|
109
|
+
if (passed) {
|
|
110
|
+
if (merge(recurse(subSchema))) return "all";
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (Array.isArray(currentSchema.oneOf)) for (const subSchema of currentSchema.oneOf) {
|
|
114
|
+
let passed = getCachedValidationResult(report, subSchema, json);
|
|
115
|
+
if (passed === void 0) {
|
|
116
|
+
const subReport = new Report(report);
|
|
117
|
+
validate.call(this, subReport, subSchema, json);
|
|
118
|
+
passed = subReport.errors.length === 0;
|
|
119
|
+
}
|
|
120
|
+
if (passed) {
|
|
121
|
+
if (merge(recurse(subSchema))) return "all";
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (currentSchema.if !== void 0) {
|
|
125
|
+
let condPassed = getCachedValidationResult(report, currentSchema.if, json);
|
|
126
|
+
if (condPassed === void 0) {
|
|
127
|
+
const condReport = new Report(report);
|
|
128
|
+
validate.call(this, condReport, currentSchema.if, json);
|
|
129
|
+
condPassed = condReport.errors.length === 0;
|
|
130
|
+
}
|
|
131
|
+
if (condPassed) {
|
|
132
|
+
if (merge(recurse(currentSchema.if))) return "all";
|
|
133
|
+
if (currentSchema.then !== void 0) {
|
|
134
|
+
if (merge(recurse(currentSchema.then))) return "all";
|
|
135
|
+
}
|
|
136
|
+
} else if (currentSchema.else !== void 0) {
|
|
137
|
+
if (merge(recurse(currentSchema.else))) return "all";
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (currentSchema.__$refResolved && currentSchema.__$refResolved !== currentSchema) {
|
|
141
|
+
if (merge(recurse(currentSchema.__$refResolved))) return "all";
|
|
142
|
+
}
|
|
143
|
+
const recursiveTarget = resolveRecursiveRef(currentSchema, report.__$recursiveAnchorStack);
|
|
144
|
+
if (recursiveTarget && recursiveTarget !== currentSchema) {
|
|
145
|
+
if (merge(recurse(recursiveTarget))) return "all";
|
|
146
|
+
}
|
|
147
|
+
const dynamicTarget = resolveDynamicRef(currentSchema, report.__$dynamicScopeStack);
|
|
148
|
+
if (dynamicTarget && dynamicTarget !== currentSchema) {
|
|
149
|
+
if (merge(recurse(dynamicTarget))) return "all";
|
|
150
|
+
}
|
|
151
|
+
return evaluated;
|
|
152
|
+
}
|
|
153
|
+
function unevaluatedItemsValidator(report, schema, json) {
|
|
154
|
+
if (!Array.isArray(json)) return;
|
|
155
|
+
if (schema.unevaluatedItems === true) return;
|
|
156
|
+
const unevalSchema = schema.unevaluatedItems;
|
|
157
|
+
if (unevalSchema === void 0) return;
|
|
158
|
+
if (json.length === 0) return;
|
|
159
|
+
const evaluatedItems = collectEvaluated.call(this, {
|
|
160
|
+
report,
|
|
161
|
+
currentSchema: schema,
|
|
162
|
+
json,
|
|
163
|
+
mode: "items",
|
|
164
|
+
jsonArr: json,
|
|
165
|
+
depth: 0
|
|
166
|
+
});
|
|
167
|
+
if (evaluatedItems === "all") return;
|
|
168
|
+
const unevaluatedIndices = [];
|
|
169
|
+
for (let i = 0; i < json.length; i++) if (!evaluatedItems.has(i)) unevaluatedIndices.push(i);
|
|
170
|
+
if (unevaluatedIndices.length === 0) return;
|
|
171
|
+
if (unevalSchema === false) report.addError("ARRAY_UNEVALUATED_ITEMS", void 0, void 0, schema, "unevaluatedItems");
|
|
172
|
+
else for (const idx of unevaluatedIndices) {
|
|
173
|
+
const subReport = new Report(report);
|
|
174
|
+
validate.call(this, subReport, unevalSchema, json[idx]);
|
|
175
|
+
if (subReport.errors.length > 0) {
|
|
176
|
+
report.addError("ARRAY_UNEVALUATED_ITEMS", void 0, void 0, schema, "unevaluatedItems");
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function unevaluatedPropertiesValidator(report, schema, json) {
|
|
182
|
+
if (!isObject(json)) return;
|
|
183
|
+
if (schema.unevaluatedProperties === true) return;
|
|
184
|
+
const unevalSchema = schema.unevaluatedProperties;
|
|
185
|
+
if (unevalSchema === void 0) return;
|
|
186
|
+
const allKeys = Object.keys(json);
|
|
187
|
+
if (allKeys.length === 0) return;
|
|
188
|
+
const evaluatedProperties = collectEvaluated.call(this, {
|
|
189
|
+
report,
|
|
190
|
+
currentSchema: schema,
|
|
191
|
+
json,
|
|
192
|
+
mode: "properties",
|
|
193
|
+
jsonData: json,
|
|
194
|
+
depth: 0
|
|
195
|
+
});
|
|
196
|
+
if (evaluatedProperties === "all") return;
|
|
197
|
+
const unevaluatedKeys = allKeys.filter((key) => !evaluatedProperties.has(key));
|
|
198
|
+
if (unevaluatedKeys.length === 0) return;
|
|
199
|
+
if (unevalSchema === false) report.addError("OBJECT_UNEVALUATED_PROPERTIES", [unevaluatedKeys.join(", ")], void 0, schema, "unevaluatedProperties");
|
|
200
|
+
else for (const key of unevaluatedKeys) {
|
|
201
|
+
const subReport = new Report(report);
|
|
202
|
+
validate.call(this, subReport, unevalSchema, json[key]);
|
|
203
|
+
if (subReport.errors.length > 0) report.addError("OBJECT_UNEVALUATED_PROPERTIES", [key], void 0, schema, "unevaluatedProperties");
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function definitionsValidator() {}
|
|
207
|
+
const JsonValidators = {
|
|
208
|
+
id: () => {},
|
|
209
|
+
$id: () => {},
|
|
210
|
+
$ref: () => {},
|
|
211
|
+
$schema: () => {},
|
|
212
|
+
$dynamicAnchor: () => {},
|
|
213
|
+
$dynamicRef: () => {},
|
|
214
|
+
$anchor: () => {},
|
|
215
|
+
$defs: () => {},
|
|
216
|
+
$vocabulary: () => {},
|
|
217
|
+
$recursiveAnchor: () => {},
|
|
218
|
+
$recursiveRef: () => {},
|
|
219
|
+
examples: () => {},
|
|
220
|
+
title: () => {},
|
|
221
|
+
description: () => {},
|
|
222
|
+
default: () => {},
|
|
223
|
+
type: typeValidator,
|
|
224
|
+
enum: enumValidator,
|
|
225
|
+
const: constValidator,
|
|
226
|
+
multipleOf: multipleOfValidator,
|
|
227
|
+
maximum: maximumValidator,
|
|
228
|
+
exclusiveMaximum: exclusiveMaximumValidator,
|
|
229
|
+
minimum: minimumValidator,
|
|
230
|
+
exclusiveMinimum: exclusiveMinimumValidator,
|
|
231
|
+
maxLength: maxLengthValidator,
|
|
232
|
+
minLength: minLengthValidator,
|
|
233
|
+
pattern: patternValidator,
|
|
234
|
+
format: formatValidator,
|
|
235
|
+
contentEncoding: contentEncodingValidator,
|
|
236
|
+
contentMediaType: contentMediaTypeValidator,
|
|
237
|
+
additionalItems: additionalItemsValidator,
|
|
238
|
+
items: itemsValidator,
|
|
239
|
+
prefixItems: prefixItemsValidator,
|
|
240
|
+
maxItems: maxItemsValidator,
|
|
241
|
+
minItems: minItemsValidator,
|
|
242
|
+
uniqueItems: uniqueItemsValidator,
|
|
243
|
+
contains: containsValidator,
|
|
244
|
+
maxContains: maxContainsValidator,
|
|
245
|
+
minContains: minContainsValidator,
|
|
246
|
+
unevaluatedItems: unevaluatedItemsValidator,
|
|
247
|
+
maxProperties: maxPropertiesValidator,
|
|
248
|
+
minProperties: minPropertiesValidator,
|
|
249
|
+
required: requiredValidator,
|
|
250
|
+
additionalProperties: additionalPropertiesValidator,
|
|
251
|
+
patternProperties: patternPropertiesValidator,
|
|
252
|
+
properties: propertiesValidator,
|
|
253
|
+
dependencies: dependenciesValidator,
|
|
254
|
+
dependentSchemas: dependentSchemasValidator,
|
|
255
|
+
dependentRequired: dependentRequiredValidator,
|
|
256
|
+
propertyNames: propertyNamesValidator,
|
|
257
|
+
unevaluatedProperties: unevaluatedPropertiesValidator,
|
|
258
|
+
allOf: allOfValidator,
|
|
259
|
+
anyOf: anyOfValidator,
|
|
260
|
+
oneOf: oneOfValidator,
|
|
261
|
+
not: notValidator,
|
|
262
|
+
if: ifValidator,
|
|
263
|
+
then: thenValidator,
|
|
264
|
+
else: elseValidator,
|
|
265
|
+
definitions: definitionsValidator
|
|
266
|
+
};
|
|
267
|
+
const recurseArray = function(report, schema, json) {
|
|
268
|
+
const schemaUri = typeof schema.$schema === "string" ? schema.$schema : void 0;
|
|
269
|
+
const prefixItems = (schemaUri === "https://json-schema.org/draft/2020-12/schema" || !schemaUri && this.options.version === "draft2020-12") && Array.isArray(schema.prefixItems) ? schema.prefixItems : void 0;
|
|
270
|
+
if (prefixItems) {
|
|
271
|
+
for (let idx = 0; idx < json.length; idx++) if (idx < prefixItems.length) {
|
|
272
|
+
report.path.push(idx);
|
|
273
|
+
validate.call(this, report, prefixItems[idx], json[idx]);
|
|
274
|
+
report.path.pop();
|
|
275
|
+
} else if (schema.items !== void 0 && !Array.isArray(schema.items)) {
|
|
276
|
+
report.path.push(idx);
|
|
277
|
+
report.schemaPath.push("items");
|
|
278
|
+
validate.call(this, report, schema.items, json[idx]);
|
|
279
|
+
report.schemaPath.pop();
|
|
280
|
+
report.path.pop();
|
|
281
|
+
}
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
if (Array.isArray(schema.items)) {
|
|
285
|
+
for (let idx = 0; idx < json.length; idx++) if (idx < schema.items.length) {
|
|
286
|
+
report.path.push(idx);
|
|
287
|
+
validate.call(this, report, schema.items[idx], json[idx]);
|
|
288
|
+
report.path.pop();
|
|
289
|
+
} else if (typeof schema.additionalItems === "object") {
|
|
290
|
+
report.path.push(idx);
|
|
291
|
+
validate.call(this, report, schema.additionalItems, json[idx]);
|
|
292
|
+
report.path.pop();
|
|
293
|
+
}
|
|
294
|
+
} else if (typeof schema.items === "object" || typeof schema.items === "boolean") for (let idx = 0; idx < json.length; idx++) {
|
|
295
|
+
report.path.push(idx);
|
|
296
|
+
report.schemaPath.push("items");
|
|
297
|
+
validate.call(this, report, schema.items, json[idx]);
|
|
298
|
+
report.schemaPath.pop();
|
|
299
|
+
report.path.pop();
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
const recurseObject = function(report, schema, json) {
|
|
303
|
+
let additionalProperties = schema.additionalProperties;
|
|
304
|
+
if (additionalProperties === true || additionalProperties === void 0) additionalProperties = {};
|
|
305
|
+
const p = schema.properties ? Object.keys(schema.properties) : [];
|
|
306
|
+
const pp = schema.patternProperties ? Object.keys(schema.patternProperties) : [];
|
|
307
|
+
const keys = Object.keys(json);
|
|
308
|
+
for (const m of keys) {
|
|
309
|
+
const propertyValue = json[m];
|
|
310
|
+
const s = [];
|
|
311
|
+
if (p.includes(m)) s.push(schema.properties[m]);
|
|
312
|
+
for (const regexString of pp) {
|
|
313
|
+
const result = compileSchemaRegex(regexString);
|
|
314
|
+
if (result.ok && result.value.test(m) === true) s.push(schema.patternProperties[regexString]);
|
|
315
|
+
}
|
|
316
|
+
if (s.length === 0 && additionalProperties !== false) s.push(additionalProperties);
|
|
317
|
+
for (const schema_s of s) {
|
|
318
|
+
report.path.push(m);
|
|
319
|
+
if (p.includes(m)) {
|
|
320
|
+
report.schemaPath.push("properties");
|
|
321
|
+
report.schemaPath.push(m);
|
|
322
|
+
} else report.schemaPath.push("additionalProperties");
|
|
323
|
+
validate.call(this, report, schema_s, propertyValue);
|
|
324
|
+
report.path.pop();
|
|
325
|
+
report.schemaPath.pop();
|
|
326
|
+
if (p.includes(m)) report.schemaPath.pop();
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
function validate(report, schema, json) {
|
|
331
|
+
report.commonErrorMessage = "JSON_OBJECT_VALIDATION_FAILED";
|
|
332
|
+
if (schema === true) return true;
|
|
333
|
+
if (schema === false) {
|
|
334
|
+
report.addError("SCHEMA_IS_FALSE", [], void 0, schema);
|
|
335
|
+
return false;
|
|
336
|
+
}
|
|
337
|
+
if (!isObject(schema)) {
|
|
338
|
+
report.addError("SCHEMA_NOT_AN_OBJECT", [whatIs(schema)], void 0, schema);
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
let keys = Object.keys(schema);
|
|
342
|
+
if (keys.length === 0) return true;
|
|
343
|
+
let isRoot = false;
|
|
344
|
+
if (!report.rootSchema) {
|
|
345
|
+
report.rootSchema = schema;
|
|
346
|
+
isRoot = true;
|
|
347
|
+
}
|
|
348
|
+
const recursiveAnchorStack = report.__$recursiveAnchorStack;
|
|
349
|
+
const dynamicScopeStack = report.__$dynamicScopeStack;
|
|
350
|
+
let pushedRecursiveAnchor = false;
|
|
351
|
+
let pushedDynamicScope = false;
|
|
352
|
+
const schemaId = getId(schema);
|
|
353
|
+
const dynamicScopeEntry = schema.__$resourceRoot || (isRoot || typeof schemaId === "string" ? schema : void 0);
|
|
354
|
+
if (dynamicScopeEntry && dynamicScopeStack[dynamicScopeStack.length - 1] !== dynamicScopeEntry) {
|
|
355
|
+
dynamicScopeStack.push(dynamicScopeEntry);
|
|
356
|
+
pushedDynamicScope = true;
|
|
357
|
+
}
|
|
358
|
+
if (schema.$recursiveAnchor === true) {
|
|
359
|
+
recursiveAnchorStack.push(schema);
|
|
360
|
+
pushedRecursiveAnchor = true;
|
|
361
|
+
}
|
|
362
|
+
if (schema.$ref !== void 0) if (this.options.version === "draft2019-09" || this.options.version === "draft2020-12") {
|
|
363
|
+
if (!schema.__$refResolved) report.addError("REF_UNRESOLVED", [schema.$ref], void 0, schema);
|
|
364
|
+
else validate.call(this, report, schema.__$refResolved, json);
|
|
365
|
+
keys = keys.filter((key) => key !== "$ref");
|
|
366
|
+
} else {
|
|
367
|
+
let maxRefs = 99;
|
|
368
|
+
while (schema.$ref && maxRefs > 0) {
|
|
369
|
+
if (!schema.__$refResolved) {
|
|
370
|
+
report.addError("REF_UNRESOLVED", [schema.$ref], void 0, schema);
|
|
371
|
+
break;
|
|
372
|
+
} else if (schema.__$refResolved === schema) break;
|
|
373
|
+
else {
|
|
374
|
+
schema = schema.__$refResolved;
|
|
375
|
+
keys = Object.keys(schema);
|
|
376
|
+
}
|
|
377
|
+
maxRefs--;
|
|
378
|
+
}
|
|
379
|
+
if (maxRefs === 0) throw new Error("Circular dependency by $ref references!");
|
|
380
|
+
report.schemaPath = [];
|
|
381
|
+
}
|
|
382
|
+
if (schema.$recursiveRef !== void 0) {
|
|
383
|
+
if (this.options.version === "draft2019-09" || this.options.version === "draft2020-12") {
|
|
384
|
+
const recursiveRefTarget = resolveRecursiveRef(schema, recursiveAnchorStack);
|
|
385
|
+
if (!recursiveRefTarget) report.addError("REF_UNRESOLVED", [schema.$recursiveRef], void 0, schema);
|
|
386
|
+
else validate.call(this, report, recursiveRefTarget, json);
|
|
387
|
+
keys = keys.filter((key) => key !== "$recursiveRef");
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
if (schema.$dynamicRef !== void 0) {
|
|
391
|
+
if (this.options.version === "draft2020-12") {
|
|
392
|
+
const dynamicRefTarget = resolveDynamicRef(schema, dynamicScopeStack);
|
|
393
|
+
if (typeof dynamicRefTarget === "undefined") report.addError("REF_UNRESOLVED", [schema.$dynamicRef], void 0, schema);
|
|
394
|
+
else validate.call(this, report, dynamicRefTarget, json);
|
|
395
|
+
keys = keys.filter((key) => key !== "$dynamicRef");
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
const validationVocabularyEnabled = isValidationVocabularyEnabled(schema, report, this.options.version);
|
|
399
|
+
if (!validationVocabularyEnabled) keys = keys.filter((key) => !VALIDATION_VOCAB_KEYWORDS.has(key));
|
|
400
|
+
if (validationVocabularyEnabled && schema.type) {
|
|
401
|
+
keys.splice(keys.indexOf("type"), 1);
|
|
402
|
+
report.schemaPath.push("type");
|
|
403
|
+
JsonValidators.type.call(this, report, schema, json);
|
|
404
|
+
report.schemaPath.pop();
|
|
405
|
+
if (report.errors.length && this.options.breakOnFirstError) {
|
|
406
|
+
if (pushedRecursiveAnchor) recursiveAnchorStack.pop();
|
|
407
|
+
if (pushedDynamicScope) dynamicScopeStack.pop();
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
const deferredUnevaluatedKeys = [];
|
|
412
|
+
for (const key of keys) {
|
|
413
|
+
if (key === "unevaluatedItems" || key === "unevaluatedProperties") {
|
|
414
|
+
deferredUnevaluatedKeys.push(key);
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
const validator = JsonValidators[key];
|
|
418
|
+
if (validator) {
|
|
419
|
+
validator.call(this, report, schema, json);
|
|
420
|
+
if (report.errors.length && this.options.breakOnFirstError) break;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
if (deferredUnevaluatedKeys.length > 0 && !(report.errors.length > 0 && this.options.breakOnFirstError)) for (const key of deferredUnevaluatedKeys) {
|
|
424
|
+
const validator = JsonValidators[key];
|
|
425
|
+
if (validator) {
|
|
426
|
+
validator.call(this, report, schema, json);
|
|
427
|
+
if (report.errors.length && this.options.breakOnFirstError) break;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
if (report.errors.length === 0 || this.options.breakOnFirstError === false) {
|
|
431
|
+
if (Array.isArray(json)) recurseArray.call(this, report, schema, json);
|
|
432
|
+
else if (isObject(json)) recurseObject.call(this, report, schema, json);
|
|
433
|
+
}
|
|
434
|
+
if (typeof this.options.customValidator === "function") this.options.customValidator.call(this, report, schema, json);
|
|
435
|
+
if (pushedRecursiveAnchor) recursiveAnchorStack.pop();
|
|
436
|
+
if (pushedDynamicScope) dynamicScopeStack.pop();
|
|
437
|
+
if (isRoot) report.rootSchema = void 0;
|
|
438
|
+
return report.errors.length === 0;
|
|
439
|
+
}
|
|
440
|
+
//#endregion
|
|
441
|
+
export { validate };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { ZSchemaOptions } from "./z-schema-options.mjs";
|
|
2
|
+
import { ErrorCode, ErrorParam } from "./errors.mjs";
|
|
3
|
+
import { ValidateCallback, ValidateOptions } from "./z-schema-base.mjs";
|
|
4
|
+
import { JsonSchema, JsonSchemaAll, JsonSchemaInternal } from "./json-schema-versions.mjs";
|
|
5
|
+
|
|
6
|
+
//#region src/report.d.ts
|
|
7
|
+
interface SchemaErrorDetail {
|
|
8
|
+
/**
|
|
9
|
+
* Example: "Expected type string but found type array"
|
|
10
|
+
*/
|
|
11
|
+
message: string;
|
|
12
|
+
/**
|
|
13
|
+
* An error identifier that can be used to format a custom error message.
|
|
14
|
+
* Example: "INVALID_TYPE"
|
|
15
|
+
*/
|
|
16
|
+
code: string;
|
|
17
|
+
/**
|
|
18
|
+
* Format parameters that can be used to format a custom error message.
|
|
19
|
+
* Example: ["string","array"]
|
|
20
|
+
*/
|
|
21
|
+
params: ErrorParam[];
|
|
22
|
+
/**
|
|
23
|
+
* A JSON path indicating the location of the error.
|
|
24
|
+
* Example: "#/projects/1"
|
|
25
|
+
*/
|
|
26
|
+
path: string | Array<string | number>;
|
|
27
|
+
/**
|
|
28
|
+
* A JSON path indicating the location in the schema where the constraint is defined.
|
|
29
|
+
* Example: ["properties", "name", "type"]
|
|
30
|
+
*/
|
|
31
|
+
schemaPath?: Array<string | number>;
|
|
32
|
+
/**
|
|
33
|
+
* The schema rule description, which is included for certain errors where
|
|
34
|
+
* this information is useful (e.g. to describe a constraint).
|
|
35
|
+
*/
|
|
36
|
+
title?: string;
|
|
37
|
+
description?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Returns details for sub-schemas that failed to match. For example, if the schema
|
|
40
|
+
* uses the "oneOf" constraint to accept several alternative possibilities, each
|
|
41
|
+
* alternative will have its own inner detail object explaining why it failed to match.
|
|
42
|
+
*/
|
|
43
|
+
inner?: SchemaErrorDetail[];
|
|
44
|
+
schemaId?: string;
|
|
45
|
+
/**
|
|
46
|
+
* The schema keyword that caused this validation error.
|
|
47
|
+
* Example: "required", "type", "minLength"
|
|
48
|
+
*/
|
|
49
|
+
keyword?: keyof JsonSchemaAll;
|
|
50
|
+
}
|
|
51
|
+
interface ReportOptions {
|
|
52
|
+
maxErrors?: number;
|
|
53
|
+
}
|
|
54
|
+
type TaskResult = unknown;
|
|
55
|
+
type TaskFn = (...args: unknown[]) => TaskResult;
|
|
56
|
+
type TaskFnArgs = Parameters<TaskFn>;
|
|
57
|
+
type TaskProcessFn = (result: ReturnType<TaskFn>) => void;
|
|
58
|
+
type AsyncTask = [TaskFn, TaskFnArgs, TaskProcessFn];
|
|
59
|
+
declare class Report {
|
|
60
|
+
asyncTasks: AsyncTask[];
|
|
61
|
+
commonErrorMessage?: string;
|
|
62
|
+
__$recursiveAnchorStack: JsonSchemaInternal[];
|
|
63
|
+
__$dynamicScopeStack: JsonSchemaInternal[];
|
|
64
|
+
__validationResultCache: Map<unknown, Map<unknown, boolean>>;
|
|
65
|
+
errors: SchemaErrorDetail[];
|
|
66
|
+
json?: unknown;
|
|
67
|
+
path: Array<number | string>;
|
|
68
|
+
schemaPath: Array<number | string>;
|
|
69
|
+
rootSchema?: JsonSchemaInternal;
|
|
70
|
+
parentReport?: Report;
|
|
71
|
+
options: ZSchemaOptions;
|
|
72
|
+
reportOptions: ReportOptions;
|
|
73
|
+
validateOptions: ValidateOptions;
|
|
74
|
+
constructor(zschemaOptions: ZSchemaOptions, validateOptions?: ValidateOptions);
|
|
75
|
+
constructor(parentReport: Report, validateOptions?: ValidateOptions);
|
|
76
|
+
constructor(parentReport: Report, reportOptions: ReportOptions, validateOptions?: ValidateOptions);
|
|
77
|
+
isValid(): boolean;
|
|
78
|
+
addAsyncTask<FV, FN extends (...args: any[]) => FV>(fn: FN, args: Parameters<FN>, asyncTaskResultProcessFn: (result: ReturnType<FN>) => void): void;
|
|
79
|
+
/**
|
|
80
|
+
* Like {@link addAsyncTask}, but automatically saves the current `path` and
|
|
81
|
+
* restores it around `processFn`. This eliminates the manual
|
|
82
|
+
* path-save/restore boilerplate that every async-aware validator would
|
|
83
|
+
* otherwise need.
|
|
84
|
+
*/
|
|
85
|
+
addAsyncTaskWithPath(fn: (...args: any[]) => any, args: any[], processFn: (result: any) => void): void;
|
|
86
|
+
getAncestor(id: string): Report | undefined;
|
|
87
|
+
processAsyncTasks(timeout: number | undefined, callback: ValidateCallback): void;
|
|
88
|
+
getPath(returnPathAsString?: boolean): string | (string | number)[];
|
|
89
|
+
getSchemaPath(): Array<string | number>;
|
|
90
|
+
getSchemaId(): string | undefined;
|
|
91
|
+
hasError(errCode: string, errParams: Array<any>): boolean;
|
|
92
|
+
addError(errCode: ErrorCode, errParams?: ErrorParam[], subReports?: Report | Report[], schema?: JsonSchema | boolean, keyword?: keyof JsonSchemaAll): void;
|
|
93
|
+
getJson(): unknown;
|
|
94
|
+
addCustomError(errorCode: ErrorCode, errorMessage: string, params?: ErrorParam[], subReports?: Report | Report[], schema?: JsonSchema | boolean, keyword?: keyof JsonSchemaAll): void;
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
export { Report, SchemaErrorDetail };
|