z-schema 7.0.0 → 7.0.5
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/README.md +7 -2
- package/bin/z-schema +0 -0
- package/cjs/index.d.ts +2 -0
- package/cjs/index.js +260 -256
- package/dist/SchemaCache.js +1 -2
- package/dist/ZSchema.js +4 -0
- package/dist/types/ZSchema.d.ts +2 -0
- package/package.json +3 -2
- package/src/SchemaCache.ts +1 -2
- package/src/ZSchema.ts +5 -0
- package/umd/ZSchema.js +260 -256
- package/umd/ZSchema.min.js +1 -1
package/README.md
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
# z-schema validator
|
|
1
|
+
# z-schema - a JSON Schema validator
|
|
2
2
|
|
|
3
|
-
[](https://
|
|
3
|
+
[](https://www.npmjs.com/package/z-schema)
|
|
4
4
|
|
|
5
5
|
[](https://coveralls.io/r/zaggino/z-schema)
|
|
6
6
|
|
|
7
7
|
## Topics
|
|
8
8
|
|
|
9
|
+
- [What](#what)
|
|
9
10
|
- [Usage](#usage)
|
|
10
11
|
- [Features](#features)
|
|
11
12
|
- [Options](#options)
|
|
@@ -13,6 +14,10 @@
|
|
|
13
14
|
- [Contributing](#contributing)
|
|
14
15
|
- [Contributors](#contributors)
|
|
15
16
|
|
|
17
|
+
## What
|
|
18
|
+
|
|
19
|
+
What is a JSON Schema? Find here: [https://json-schema.org/](https://json-schema.org/)
|
|
20
|
+
|
|
16
21
|
## Usage
|
|
17
22
|
|
|
18
23
|
Validator will try to perform sync validation when possible for speed, but supports async callbacks when they are necessary.
|
package/bin/z-schema
CHANGED
|
File without changes
|
package/cjs/index.d.ts
CHANGED
|
@@ -189,6 +189,8 @@ declare class ZSchema {
|
|
|
189
189
|
private validateOptions;
|
|
190
190
|
options: ZSchemaOptions;
|
|
191
191
|
constructor(options?: ZSchemaOptions);
|
|
192
|
+
/** Used by SchemaCache to break circular dependency with SchemaCompilation */
|
|
193
|
+
_compileSchema(report: Report, schema: unknown): boolean;
|
|
192
194
|
/**
|
|
193
195
|
* @param schema - JSON object representing schema
|
|
194
196
|
* @returns {boolean} true if schema is valid.
|
package/cjs/index.js
CHANGED
|
@@ -11972,257 +11972,6 @@ function requireLodash_isequal () {
|
|
|
11972
11972
|
var lodash_isequalExports = requireLodash_isequal();
|
|
11973
11973
|
var isequal = /*@__PURE__*/getDefaultExportFromCjs(lodash_isequalExports);
|
|
11974
11974
|
|
|
11975
|
-
function mergeReference(scope, ref) {
|
|
11976
|
-
if (isAbsoluteUri(ref)) {
|
|
11977
|
-
return ref;
|
|
11978
|
-
}
|
|
11979
|
-
let joinedScope = scope.join('');
|
|
11980
|
-
const isScopeAbsolute = isAbsoluteUri(joinedScope);
|
|
11981
|
-
const isScopeRelative = isRelativeUri(joinedScope);
|
|
11982
|
-
const isRefRelative = isRelativeUri(ref);
|
|
11983
|
-
let toRemove;
|
|
11984
|
-
if (isScopeAbsolute && isRefRelative) {
|
|
11985
|
-
toRemove = joinedScope.match(/\/[^/]*$/);
|
|
11986
|
-
if (toRemove) {
|
|
11987
|
-
joinedScope = joinedScope.slice(0, toRemove.index + 1);
|
|
11988
|
-
}
|
|
11989
|
-
}
|
|
11990
|
-
else if (isScopeRelative && isRefRelative) {
|
|
11991
|
-
joinedScope = '';
|
|
11992
|
-
}
|
|
11993
|
-
else {
|
|
11994
|
-
toRemove = joinedScope.match(/[^#/]+$/);
|
|
11995
|
-
if (toRemove) {
|
|
11996
|
-
joinedScope = joinedScope.slice(0, toRemove.index);
|
|
11997
|
-
}
|
|
11998
|
-
}
|
|
11999
|
-
let res = joinedScope + ref;
|
|
12000
|
-
res = res.replace(/##/, '#');
|
|
12001
|
-
return res;
|
|
12002
|
-
}
|
|
12003
|
-
function collectReferences(obj, results, scope, path) {
|
|
12004
|
-
results = results || [];
|
|
12005
|
-
scope = scope || [];
|
|
12006
|
-
path = path || [];
|
|
12007
|
-
if (typeof obj !== 'object' || obj === null) {
|
|
12008
|
-
return results;
|
|
12009
|
-
}
|
|
12010
|
-
if (typeof obj.id === 'string') {
|
|
12011
|
-
scope.push(obj.id);
|
|
12012
|
-
}
|
|
12013
|
-
if (typeof obj.$ref === 'string' && typeof obj.__$refResolved === 'undefined') {
|
|
12014
|
-
results.push({
|
|
12015
|
-
ref: mergeReference(scope, obj.$ref),
|
|
12016
|
-
key: '$ref',
|
|
12017
|
-
obj: obj,
|
|
12018
|
-
path: path.slice(0),
|
|
12019
|
-
});
|
|
12020
|
-
}
|
|
12021
|
-
if (typeof obj.$schema === 'string' && typeof obj.__$schemaResolved === 'undefined') {
|
|
12022
|
-
results.push({
|
|
12023
|
-
ref: mergeReference(scope, obj.$schema),
|
|
12024
|
-
key: '$schema',
|
|
12025
|
-
obj: obj,
|
|
12026
|
-
path: path.slice(0),
|
|
12027
|
-
});
|
|
12028
|
-
}
|
|
12029
|
-
let idx;
|
|
12030
|
-
if (Array.isArray(obj)) {
|
|
12031
|
-
idx = obj.length;
|
|
12032
|
-
while (idx--) {
|
|
12033
|
-
path.push(idx.toString());
|
|
12034
|
-
collectReferences(obj[idx], results, scope, path);
|
|
12035
|
-
path.pop();
|
|
12036
|
-
}
|
|
12037
|
-
}
|
|
12038
|
-
else {
|
|
12039
|
-
const keys = Object.keys(obj);
|
|
12040
|
-
idx = keys.length;
|
|
12041
|
-
while (idx--) {
|
|
12042
|
-
// do not recurse through resolved references and other z-schema props
|
|
12043
|
-
if (keys[idx].indexOf('__$') === 0) {
|
|
12044
|
-
continue;
|
|
12045
|
-
}
|
|
12046
|
-
path.push(keys[idx]);
|
|
12047
|
-
collectReferences(obj[keys[idx]], results, scope, path);
|
|
12048
|
-
path.pop();
|
|
12049
|
-
}
|
|
12050
|
-
}
|
|
12051
|
-
if (typeof obj.id === 'string') {
|
|
12052
|
-
scope.pop();
|
|
12053
|
-
}
|
|
12054
|
-
return results;
|
|
12055
|
-
}
|
|
12056
|
-
const compileArrayOfSchemasLoop = function (mainReport, arr) {
|
|
12057
|
-
let idx = arr.length, compiledCount = 0;
|
|
12058
|
-
while (idx--) {
|
|
12059
|
-
// try to compile each schema separately
|
|
12060
|
-
const report = new Report(mainReport);
|
|
12061
|
-
const isValid = compileSchema.call(this, report, arr[idx]);
|
|
12062
|
-
if (isValid) {
|
|
12063
|
-
compiledCount++;
|
|
12064
|
-
}
|
|
12065
|
-
// copy errors to report
|
|
12066
|
-
mainReport.errors = mainReport.errors.concat(report.errors);
|
|
12067
|
-
}
|
|
12068
|
-
return compiledCount;
|
|
12069
|
-
};
|
|
12070
|
-
function findId$1(arr, id) {
|
|
12071
|
-
let idx = arr.length;
|
|
12072
|
-
while (idx--) {
|
|
12073
|
-
if (arr[idx].id === id) {
|
|
12074
|
-
return arr[idx];
|
|
12075
|
-
}
|
|
12076
|
-
}
|
|
12077
|
-
return null;
|
|
12078
|
-
}
|
|
12079
|
-
const compileArrayOfSchemas = function (report, arr) {
|
|
12080
|
-
let compiled = 0, lastLoopCompiled;
|
|
12081
|
-
do {
|
|
12082
|
-
// remove all UNRESOLVABLE_REFERENCE errors before compiling array again
|
|
12083
|
-
let idx = report.errors.length;
|
|
12084
|
-
while (idx--) {
|
|
12085
|
-
if (report.errors[idx].code === 'UNRESOLVABLE_REFERENCE') {
|
|
12086
|
-
report.errors.splice(idx, 1);
|
|
12087
|
-
}
|
|
12088
|
-
}
|
|
12089
|
-
// remember how many were compiled in the last loop
|
|
12090
|
-
lastLoopCompiled = compiled;
|
|
12091
|
-
// count how many are compiled now
|
|
12092
|
-
compiled = compileArrayOfSchemasLoop.call(this, report, arr);
|
|
12093
|
-
// fix __$missingReferences if possible
|
|
12094
|
-
idx = arr.length;
|
|
12095
|
-
while (idx--) {
|
|
12096
|
-
const sch = arr[idx];
|
|
12097
|
-
if (sch.__$missingReferences) {
|
|
12098
|
-
let idx2 = sch.__$missingReferences.length;
|
|
12099
|
-
while (idx2--) {
|
|
12100
|
-
const refObj = sch.__$missingReferences[idx2];
|
|
12101
|
-
const response = findId$1(arr, refObj.ref);
|
|
12102
|
-
if (response) {
|
|
12103
|
-
// this might create circular references
|
|
12104
|
-
refObj.obj['__' + refObj.key + 'Resolved'] = response;
|
|
12105
|
-
// it's resolved now so delete it
|
|
12106
|
-
sch.__$missingReferences.splice(idx2, 1);
|
|
12107
|
-
}
|
|
12108
|
-
}
|
|
12109
|
-
if (sch.__$missingReferences.length === 0) {
|
|
12110
|
-
delete sch.__$missingReferences;
|
|
12111
|
-
}
|
|
12112
|
-
}
|
|
12113
|
-
}
|
|
12114
|
-
// keep repeating if not all compiled and at least one more was compiled in the last loop
|
|
12115
|
-
} while (compiled !== arr.length && compiled !== lastLoopCompiled);
|
|
12116
|
-
return report.isValid();
|
|
12117
|
-
};
|
|
12118
|
-
function compileSchema(report, schema) {
|
|
12119
|
-
report.commonErrorMessage = 'SCHEMA_COMPILATION_FAILED';
|
|
12120
|
-
// if schema is a string, assume it's a uri
|
|
12121
|
-
if (typeof schema === 'string') {
|
|
12122
|
-
const loadedSchema = getSchemaByUri.call(this, report, schema);
|
|
12123
|
-
if (!loadedSchema) {
|
|
12124
|
-
report.addError('SCHEMA_NOT_REACHABLE', [schema]);
|
|
12125
|
-
return false;
|
|
12126
|
-
}
|
|
12127
|
-
schema = loadedSchema;
|
|
12128
|
-
}
|
|
12129
|
-
// if schema is an array, assume it's an array of schemas
|
|
12130
|
-
if (Array.isArray(schema)) {
|
|
12131
|
-
return compileArrayOfSchemas.call(this, report, schema);
|
|
12132
|
-
}
|
|
12133
|
-
// if we have an id than it should be cached already (if this instance has compiled it)
|
|
12134
|
-
if (schema.__$compiled && schema.id && checkCacheForUri.call(this, schema.id) === false) {
|
|
12135
|
-
schema.__$compiled = undefined;
|
|
12136
|
-
}
|
|
12137
|
-
// do not re-compile schemas
|
|
12138
|
-
if (schema.__$compiled) {
|
|
12139
|
-
return true;
|
|
12140
|
-
}
|
|
12141
|
-
if (schema.id && typeof schema.id === 'string') {
|
|
12142
|
-
// add this to our schemaCache (before compilation in case we have references including id)
|
|
12143
|
-
cacheSchemaByUri.call(this, schema.id, schema);
|
|
12144
|
-
}
|
|
12145
|
-
// this method can be called recursively, so we need to remember our root
|
|
12146
|
-
let isRoot = false;
|
|
12147
|
-
if (!report.rootSchema) {
|
|
12148
|
-
report.rootSchema = schema;
|
|
12149
|
-
isRoot = true;
|
|
12150
|
-
}
|
|
12151
|
-
// delete all __$missingReferences from previous compilation attempts
|
|
12152
|
-
const isValidExceptReferences = report.isValid();
|
|
12153
|
-
delete schema.__$missingReferences;
|
|
12154
|
-
// collect all references that need to be resolved - $ref and $schema
|
|
12155
|
-
const refs = collectReferences.call(this, schema);
|
|
12156
|
-
let idx = refs.length;
|
|
12157
|
-
while (idx--) {
|
|
12158
|
-
// resolve all the collected references into __xxxResolved pointer
|
|
12159
|
-
const refObj = refs[idx];
|
|
12160
|
-
let response = getSchemaByUri.call(this, report, refObj.ref, schema);
|
|
12161
|
-
// we can try to use custom schemaReader if available
|
|
12162
|
-
if (!response) {
|
|
12163
|
-
const schemaReader = this.getSchemaReader();
|
|
12164
|
-
if (schemaReader) {
|
|
12165
|
-
// it's supposed to return a valid schema
|
|
12166
|
-
const s = schemaReader(refObj.ref);
|
|
12167
|
-
if (s) {
|
|
12168
|
-
// it needs to have the id
|
|
12169
|
-
s.id = refObj.ref;
|
|
12170
|
-
// try to compile the schema
|
|
12171
|
-
const subreport = new Report(report);
|
|
12172
|
-
if (!compileSchema.call(this, subreport, s)) {
|
|
12173
|
-
// copy errors to report
|
|
12174
|
-
report.errors = report.errors.concat(subreport.errors);
|
|
12175
|
-
}
|
|
12176
|
-
else {
|
|
12177
|
-
response = getSchemaByUri.call(this, report, refObj.ref, schema);
|
|
12178
|
-
}
|
|
12179
|
-
}
|
|
12180
|
-
}
|
|
12181
|
-
}
|
|
12182
|
-
if (!response) {
|
|
12183
|
-
const hasNotValid = report.hasError('REMOTE_NOT_VALID', [refObj.ref]);
|
|
12184
|
-
const isAbsolute = isAbsoluteUri(refObj.ref);
|
|
12185
|
-
let isDownloaded = false;
|
|
12186
|
-
const ignoreUnresolvableRemotes = this.options.ignoreUnresolvableReferences === true;
|
|
12187
|
-
if (isAbsolute) {
|
|
12188
|
-
// we shouldn't add UNRESOLVABLE_REFERENCE for schemas we already have downloaded
|
|
12189
|
-
// and set through setRemoteReference method
|
|
12190
|
-
isDownloaded = checkCacheForUri.call(this, refObj.ref);
|
|
12191
|
-
}
|
|
12192
|
-
if (hasNotValid) ;
|
|
12193
|
-
else if (ignoreUnresolvableRemotes && isAbsolute) ;
|
|
12194
|
-
else if (isDownloaded) ;
|
|
12195
|
-
else {
|
|
12196
|
-
Array.prototype.push.apply(report.path, refObj.path);
|
|
12197
|
-
report.addError('UNRESOLVABLE_REFERENCE', [refObj.ref]);
|
|
12198
|
-
report.path = report.path.slice(0, -refObj.path.length);
|
|
12199
|
-
// pusblish unresolved references out
|
|
12200
|
-
if (isValidExceptReferences) {
|
|
12201
|
-
schema.__$missingReferences = schema.__$missingReferences || [];
|
|
12202
|
-
schema.__$missingReferences.push(refObj);
|
|
12203
|
-
}
|
|
12204
|
-
}
|
|
12205
|
-
}
|
|
12206
|
-
// this might create circular references
|
|
12207
|
-
refObj.obj['__' + refObj.key + 'Resolved'] = response;
|
|
12208
|
-
}
|
|
12209
|
-
const isValid = report.isValid();
|
|
12210
|
-
if (isValid) {
|
|
12211
|
-
schema.__$compiled = true;
|
|
12212
|
-
}
|
|
12213
|
-
else {
|
|
12214
|
-
if (schema.id && typeof schema.id === 'string') {
|
|
12215
|
-
// remove this schema from schemaCache because it failed to compile
|
|
12216
|
-
removeFromCacheByUri.call(this, schema.id);
|
|
12217
|
-
}
|
|
12218
|
-
}
|
|
12219
|
-
// we don't need the root pointer anymore
|
|
12220
|
-
if (isRoot) {
|
|
12221
|
-
report.rootSchema = undefined;
|
|
12222
|
-
}
|
|
12223
|
-
return isValid;
|
|
12224
|
-
}
|
|
12225
|
-
|
|
12226
11975
|
const SchemaValidators = {
|
|
12227
11976
|
$ref: function (report, schema) {
|
|
12228
11977
|
// http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07
|
|
@@ -12868,7 +12617,7 @@ function getQueryPath(uri) {
|
|
|
12868
12617
|
// if (res && res[0] === "/") { res = res.slice(1); }
|
|
12869
12618
|
return res;
|
|
12870
12619
|
}
|
|
12871
|
-
function findId(schema, id) {
|
|
12620
|
+
function findId$1(schema, id) {
|
|
12872
12621
|
// process only arrays and objects
|
|
12873
12622
|
if (typeof schema !== 'object' || schema === null) {
|
|
12874
12623
|
return;
|
|
@@ -12886,7 +12635,7 @@ function findId(schema, id) {
|
|
|
12886
12635
|
if (Array.isArray(schema)) {
|
|
12887
12636
|
idx = schema.length;
|
|
12888
12637
|
while (idx--) {
|
|
12889
|
-
result = findId(schema[idx], id);
|
|
12638
|
+
result = findId$1(schema[idx], id);
|
|
12890
12639
|
if (result) {
|
|
12891
12640
|
return result;
|
|
12892
12641
|
}
|
|
@@ -12900,7 +12649,7 @@ function findId(schema, id) {
|
|
|
12900
12649
|
if (k.indexOf('__$') === 0) {
|
|
12901
12650
|
continue;
|
|
12902
12651
|
}
|
|
12903
|
-
result = findId(schema[k], id);
|
|
12652
|
+
result = findId$1(schema[k], id);
|
|
12904
12653
|
if (result) {
|
|
12905
12654
|
return result;
|
|
12906
12655
|
}
|
|
@@ -12980,7 +12729,7 @@ function getSchemaByUri(report, uri, root) {
|
|
|
12980
12729
|
}
|
|
12981
12730
|
else {
|
|
12982
12731
|
remoteReport = new Report(report);
|
|
12983
|
-
if (
|
|
12732
|
+
if (this._compileSchema(remoteReport, result)) {
|
|
12984
12733
|
const savedOptions = this.options;
|
|
12985
12734
|
try {
|
|
12986
12735
|
// If custom validationOptions were provided to setRemoteReference(),
|
|
@@ -13009,7 +12758,7 @@ function getSchemaByUri(report, uri, root) {
|
|
|
13009
12758
|
const key = decodeJSONPointer(parts[idx]);
|
|
13010
12759
|
if (idx === 0) {
|
|
13011
12760
|
// it's an id
|
|
13012
|
-
result = findId(result, key);
|
|
12761
|
+
result = findId$1(result, key);
|
|
13013
12762
|
}
|
|
13014
12763
|
else {
|
|
13015
12764
|
// it's a path behind id
|
|
@@ -13020,6 +12769,257 @@ function getSchemaByUri(report, uri, root) {
|
|
|
13020
12769
|
return result;
|
|
13021
12770
|
}
|
|
13022
12771
|
|
|
12772
|
+
function mergeReference(scope, ref) {
|
|
12773
|
+
if (isAbsoluteUri(ref)) {
|
|
12774
|
+
return ref;
|
|
12775
|
+
}
|
|
12776
|
+
let joinedScope = scope.join('');
|
|
12777
|
+
const isScopeAbsolute = isAbsoluteUri(joinedScope);
|
|
12778
|
+
const isScopeRelative = isRelativeUri(joinedScope);
|
|
12779
|
+
const isRefRelative = isRelativeUri(ref);
|
|
12780
|
+
let toRemove;
|
|
12781
|
+
if (isScopeAbsolute && isRefRelative) {
|
|
12782
|
+
toRemove = joinedScope.match(/\/[^/]*$/);
|
|
12783
|
+
if (toRemove) {
|
|
12784
|
+
joinedScope = joinedScope.slice(0, toRemove.index + 1);
|
|
12785
|
+
}
|
|
12786
|
+
}
|
|
12787
|
+
else if (isScopeRelative && isRefRelative) {
|
|
12788
|
+
joinedScope = '';
|
|
12789
|
+
}
|
|
12790
|
+
else {
|
|
12791
|
+
toRemove = joinedScope.match(/[^#/]+$/);
|
|
12792
|
+
if (toRemove) {
|
|
12793
|
+
joinedScope = joinedScope.slice(0, toRemove.index);
|
|
12794
|
+
}
|
|
12795
|
+
}
|
|
12796
|
+
let res = joinedScope + ref;
|
|
12797
|
+
res = res.replace(/##/, '#');
|
|
12798
|
+
return res;
|
|
12799
|
+
}
|
|
12800
|
+
function collectReferences(obj, results, scope, path) {
|
|
12801
|
+
results = results || [];
|
|
12802
|
+
scope = scope || [];
|
|
12803
|
+
path = path || [];
|
|
12804
|
+
if (typeof obj !== 'object' || obj === null) {
|
|
12805
|
+
return results;
|
|
12806
|
+
}
|
|
12807
|
+
if (typeof obj.id === 'string') {
|
|
12808
|
+
scope.push(obj.id);
|
|
12809
|
+
}
|
|
12810
|
+
if (typeof obj.$ref === 'string' && typeof obj.__$refResolved === 'undefined') {
|
|
12811
|
+
results.push({
|
|
12812
|
+
ref: mergeReference(scope, obj.$ref),
|
|
12813
|
+
key: '$ref',
|
|
12814
|
+
obj: obj,
|
|
12815
|
+
path: path.slice(0),
|
|
12816
|
+
});
|
|
12817
|
+
}
|
|
12818
|
+
if (typeof obj.$schema === 'string' && typeof obj.__$schemaResolved === 'undefined') {
|
|
12819
|
+
results.push({
|
|
12820
|
+
ref: mergeReference(scope, obj.$schema),
|
|
12821
|
+
key: '$schema',
|
|
12822
|
+
obj: obj,
|
|
12823
|
+
path: path.slice(0),
|
|
12824
|
+
});
|
|
12825
|
+
}
|
|
12826
|
+
let idx;
|
|
12827
|
+
if (Array.isArray(obj)) {
|
|
12828
|
+
idx = obj.length;
|
|
12829
|
+
while (idx--) {
|
|
12830
|
+
path.push(idx.toString());
|
|
12831
|
+
collectReferences(obj[idx], results, scope, path);
|
|
12832
|
+
path.pop();
|
|
12833
|
+
}
|
|
12834
|
+
}
|
|
12835
|
+
else {
|
|
12836
|
+
const keys = Object.keys(obj);
|
|
12837
|
+
idx = keys.length;
|
|
12838
|
+
while (idx--) {
|
|
12839
|
+
// do not recurse through resolved references and other z-schema props
|
|
12840
|
+
if (keys[idx].indexOf('__$') === 0) {
|
|
12841
|
+
continue;
|
|
12842
|
+
}
|
|
12843
|
+
path.push(keys[idx]);
|
|
12844
|
+
collectReferences(obj[keys[idx]], results, scope, path);
|
|
12845
|
+
path.pop();
|
|
12846
|
+
}
|
|
12847
|
+
}
|
|
12848
|
+
if (typeof obj.id === 'string') {
|
|
12849
|
+
scope.pop();
|
|
12850
|
+
}
|
|
12851
|
+
return results;
|
|
12852
|
+
}
|
|
12853
|
+
const compileArrayOfSchemasLoop = function (mainReport, arr) {
|
|
12854
|
+
let idx = arr.length, compiledCount = 0;
|
|
12855
|
+
while (idx--) {
|
|
12856
|
+
// try to compile each schema separately
|
|
12857
|
+
const report = new Report(mainReport);
|
|
12858
|
+
const isValid = compileSchema.call(this, report, arr[idx]);
|
|
12859
|
+
if (isValid) {
|
|
12860
|
+
compiledCount++;
|
|
12861
|
+
}
|
|
12862
|
+
// copy errors to report
|
|
12863
|
+
mainReport.errors = mainReport.errors.concat(report.errors);
|
|
12864
|
+
}
|
|
12865
|
+
return compiledCount;
|
|
12866
|
+
};
|
|
12867
|
+
function findId(arr, id) {
|
|
12868
|
+
let idx = arr.length;
|
|
12869
|
+
while (idx--) {
|
|
12870
|
+
if (arr[idx].id === id) {
|
|
12871
|
+
return arr[idx];
|
|
12872
|
+
}
|
|
12873
|
+
}
|
|
12874
|
+
return null;
|
|
12875
|
+
}
|
|
12876
|
+
const compileArrayOfSchemas = function (report, arr) {
|
|
12877
|
+
let compiled = 0, lastLoopCompiled;
|
|
12878
|
+
do {
|
|
12879
|
+
// remove all UNRESOLVABLE_REFERENCE errors before compiling array again
|
|
12880
|
+
let idx = report.errors.length;
|
|
12881
|
+
while (idx--) {
|
|
12882
|
+
if (report.errors[idx].code === 'UNRESOLVABLE_REFERENCE') {
|
|
12883
|
+
report.errors.splice(idx, 1);
|
|
12884
|
+
}
|
|
12885
|
+
}
|
|
12886
|
+
// remember how many were compiled in the last loop
|
|
12887
|
+
lastLoopCompiled = compiled;
|
|
12888
|
+
// count how many are compiled now
|
|
12889
|
+
compiled = compileArrayOfSchemasLoop.call(this, report, arr);
|
|
12890
|
+
// fix __$missingReferences if possible
|
|
12891
|
+
idx = arr.length;
|
|
12892
|
+
while (idx--) {
|
|
12893
|
+
const sch = arr[idx];
|
|
12894
|
+
if (sch.__$missingReferences) {
|
|
12895
|
+
let idx2 = sch.__$missingReferences.length;
|
|
12896
|
+
while (idx2--) {
|
|
12897
|
+
const refObj = sch.__$missingReferences[idx2];
|
|
12898
|
+
const response = findId(arr, refObj.ref);
|
|
12899
|
+
if (response) {
|
|
12900
|
+
// this might create circular references
|
|
12901
|
+
refObj.obj['__' + refObj.key + 'Resolved'] = response;
|
|
12902
|
+
// it's resolved now so delete it
|
|
12903
|
+
sch.__$missingReferences.splice(idx2, 1);
|
|
12904
|
+
}
|
|
12905
|
+
}
|
|
12906
|
+
if (sch.__$missingReferences.length === 0) {
|
|
12907
|
+
delete sch.__$missingReferences;
|
|
12908
|
+
}
|
|
12909
|
+
}
|
|
12910
|
+
}
|
|
12911
|
+
// keep repeating if not all compiled and at least one more was compiled in the last loop
|
|
12912
|
+
} while (compiled !== arr.length && compiled !== lastLoopCompiled);
|
|
12913
|
+
return report.isValid();
|
|
12914
|
+
};
|
|
12915
|
+
function compileSchema(report, schema) {
|
|
12916
|
+
report.commonErrorMessage = 'SCHEMA_COMPILATION_FAILED';
|
|
12917
|
+
// if schema is a string, assume it's a uri
|
|
12918
|
+
if (typeof schema === 'string') {
|
|
12919
|
+
const loadedSchema = getSchemaByUri.call(this, report, schema);
|
|
12920
|
+
if (!loadedSchema) {
|
|
12921
|
+
report.addError('SCHEMA_NOT_REACHABLE', [schema]);
|
|
12922
|
+
return false;
|
|
12923
|
+
}
|
|
12924
|
+
schema = loadedSchema;
|
|
12925
|
+
}
|
|
12926
|
+
// if schema is an array, assume it's an array of schemas
|
|
12927
|
+
if (Array.isArray(schema)) {
|
|
12928
|
+
return compileArrayOfSchemas.call(this, report, schema);
|
|
12929
|
+
}
|
|
12930
|
+
// if we have an id than it should be cached already (if this instance has compiled it)
|
|
12931
|
+
if (schema.__$compiled && schema.id && checkCacheForUri.call(this, schema.id) === false) {
|
|
12932
|
+
schema.__$compiled = undefined;
|
|
12933
|
+
}
|
|
12934
|
+
// do not re-compile schemas
|
|
12935
|
+
if (schema.__$compiled) {
|
|
12936
|
+
return true;
|
|
12937
|
+
}
|
|
12938
|
+
if (schema.id && typeof schema.id === 'string') {
|
|
12939
|
+
// add this to our schemaCache (before compilation in case we have references including id)
|
|
12940
|
+
cacheSchemaByUri.call(this, schema.id, schema);
|
|
12941
|
+
}
|
|
12942
|
+
// this method can be called recursively, so we need to remember our root
|
|
12943
|
+
let isRoot = false;
|
|
12944
|
+
if (!report.rootSchema) {
|
|
12945
|
+
report.rootSchema = schema;
|
|
12946
|
+
isRoot = true;
|
|
12947
|
+
}
|
|
12948
|
+
// delete all __$missingReferences from previous compilation attempts
|
|
12949
|
+
const isValidExceptReferences = report.isValid();
|
|
12950
|
+
delete schema.__$missingReferences;
|
|
12951
|
+
// collect all references that need to be resolved - $ref and $schema
|
|
12952
|
+
const refs = collectReferences.call(this, schema);
|
|
12953
|
+
let idx = refs.length;
|
|
12954
|
+
while (idx--) {
|
|
12955
|
+
// resolve all the collected references into __xxxResolved pointer
|
|
12956
|
+
const refObj = refs[idx];
|
|
12957
|
+
let response = getSchemaByUri.call(this, report, refObj.ref, schema);
|
|
12958
|
+
// we can try to use custom schemaReader if available
|
|
12959
|
+
if (!response) {
|
|
12960
|
+
const schemaReader = this.getSchemaReader();
|
|
12961
|
+
if (schemaReader) {
|
|
12962
|
+
// it's supposed to return a valid schema
|
|
12963
|
+
const s = schemaReader(refObj.ref);
|
|
12964
|
+
if (s) {
|
|
12965
|
+
// it needs to have the id
|
|
12966
|
+
s.id = refObj.ref;
|
|
12967
|
+
// try to compile the schema
|
|
12968
|
+
const subreport = new Report(report);
|
|
12969
|
+
if (!compileSchema.call(this, subreport, s)) {
|
|
12970
|
+
// copy errors to report
|
|
12971
|
+
report.errors = report.errors.concat(subreport.errors);
|
|
12972
|
+
}
|
|
12973
|
+
else {
|
|
12974
|
+
response = getSchemaByUri.call(this, report, refObj.ref, schema);
|
|
12975
|
+
}
|
|
12976
|
+
}
|
|
12977
|
+
}
|
|
12978
|
+
}
|
|
12979
|
+
if (!response) {
|
|
12980
|
+
const hasNotValid = report.hasError('REMOTE_NOT_VALID', [refObj.ref]);
|
|
12981
|
+
const isAbsolute = isAbsoluteUri(refObj.ref);
|
|
12982
|
+
let isDownloaded = false;
|
|
12983
|
+
const ignoreUnresolvableRemotes = this.options.ignoreUnresolvableReferences === true;
|
|
12984
|
+
if (isAbsolute) {
|
|
12985
|
+
// we shouldn't add UNRESOLVABLE_REFERENCE for schemas we already have downloaded
|
|
12986
|
+
// and set through setRemoteReference method
|
|
12987
|
+
isDownloaded = checkCacheForUri.call(this, refObj.ref);
|
|
12988
|
+
}
|
|
12989
|
+
if (hasNotValid) ;
|
|
12990
|
+
else if (ignoreUnresolvableRemotes && isAbsolute) ;
|
|
12991
|
+
else if (isDownloaded) ;
|
|
12992
|
+
else {
|
|
12993
|
+
Array.prototype.push.apply(report.path, refObj.path);
|
|
12994
|
+
report.addError('UNRESOLVABLE_REFERENCE', [refObj.ref]);
|
|
12995
|
+
report.path = report.path.slice(0, -refObj.path.length);
|
|
12996
|
+
// pusblish unresolved references out
|
|
12997
|
+
if (isValidExceptReferences) {
|
|
12998
|
+
schema.__$missingReferences = schema.__$missingReferences || [];
|
|
12999
|
+
schema.__$missingReferences.push(refObj);
|
|
13000
|
+
}
|
|
13001
|
+
}
|
|
13002
|
+
}
|
|
13003
|
+
// this might create circular references
|
|
13004
|
+
refObj.obj['__' + refObj.key + 'Resolved'] = response;
|
|
13005
|
+
}
|
|
13006
|
+
const isValid = report.isValid();
|
|
13007
|
+
if (isValid) {
|
|
13008
|
+
schema.__$compiled = true;
|
|
13009
|
+
}
|
|
13010
|
+
else {
|
|
13011
|
+
if (schema.id && typeof schema.id === 'string') {
|
|
13012
|
+
// remove this schema from schemaCache because it failed to compile
|
|
13013
|
+
removeFromCacheByUri.call(this, schema.id);
|
|
13014
|
+
}
|
|
13015
|
+
}
|
|
13016
|
+
// we don't need the root pointer anymore
|
|
13017
|
+
if (isRoot) {
|
|
13018
|
+
report.rootSchema = undefined;
|
|
13019
|
+
}
|
|
13020
|
+
return isValid;
|
|
13021
|
+
}
|
|
13022
|
+
|
|
13023
13023
|
var id$1 = "http://json-schema.org/draft-04/schema#";
|
|
13024
13024
|
var $schema$1 = "http://json-schema.org/draft-04/schema#";
|
|
13025
13025
|
var description = "Core schema meta-schema";
|
|
@@ -13561,6 +13561,10 @@ class ZSchema {
|
|
|
13561
13561
|
this.setRemoteReference('http://json-schema.org/draft-04/schema', Draft4Schema, metaschemaOptions);
|
|
13562
13562
|
this.setRemoteReference('http://json-schema.org/draft-04/hyper-schema', Draft4HyperSchema, metaschemaOptions);
|
|
13563
13563
|
}
|
|
13564
|
+
/** Used by SchemaCache to break circular dependency with SchemaCompilation */
|
|
13565
|
+
_compileSchema(report, schema) {
|
|
13566
|
+
return compileSchema.call(this, report, schema);
|
|
13567
|
+
}
|
|
13564
13568
|
/**
|
|
13565
13569
|
* @param schema - JSON object representing schema
|
|
13566
13570
|
* @returns {boolean} true if schema is valid.
|
package/dist/SchemaCache.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import isequal from 'lodash.isequal';
|
|
2
2
|
import { Report } from './Report.js';
|
|
3
|
-
import { compileSchema } from './SchemaCompilation.js';
|
|
4
3
|
import * as SchemaValidation from './SchemaValidation.js';
|
|
5
4
|
import * as Utils from './Utils.js';
|
|
6
5
|
function decodeJSONPointer(str) {
|
|
@@ -132,7 +131,7 @@ export function getSchemaByUri(report, uri, root) {
|
|
|
132
131
|
}
|
|
133
132
|
else {
|
|
134
133
|
remoteReport = new Report(report);
|
|
135
|
-
if (
|
|
134
|
+
if (this._compileSchema(remoteReport, result)) {
|
|
136
135
|
const savedOptions = this.options;
|
|
137
136
|
try {
|
|
138
137
|
// If custom validationOptions were provided to setRemoteReference(),
|
package/dist/ZSchema.js
CHANGED
|
@@ -143,6 +143,10 @@ export class ZSchema {
|
|
|
143
143
|
this.setRemoteReference('http://json-schema.org/draft-04/schema', Draft4Schema, metaschemaOptions);
|
|
144
144
|
this.setRemoteReference('http://json-schema.org/draft-04/hyper-schema', Draft4HyperSchema, metaschemaOptions);
|
|
145
145
|
}
|
|
146
|
+
/** Used by SchemaCache to break circular dependency with SchemaCompilation */
|
|
147
|
+
_compileSchema(report, schema) {
|
|
148
|
+
return SchemaCompilation.compileSchema.call(this, report, schema);
|
|
149
|
+
}
|
|
146
150
|
/**
|
|
147
151
|
* @param schema - JSON object representing schema
|
|
148
152
|
* @returns {boolean} true if schema is valid.
|
package/dist/types/ZSchema.d.ts
CHANGED
|
@@ -60,6 +60,8 @@ export declare class ZSchema {
|
|
|
60
60
|
private validateOptions;
|
|
61
61
|
options: ZSchemaOptions;
|
|
62
62
|
constructor(options?: ZSchemaOptions);
|
|
63
|
+
/** Used by SchemaCache to break circular dependency with SchemaCompilation */
|
|
64
|
+
_compileSchema(report: Report, schema: unknown): boolean;
|
|
63
65
|
/**
|
|
64
66
|
* @param schema - JSON object representing schema
|
|
65
67
|
* @returns {boolean} true if schema is valid.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "z-schema",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.5",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=22.0.0"
|
|
6
6
|
},
|
|
@@ -67,7 +67,8 @@
|
|
|
67
67
|
"test": "vitest run",
|
|
68
68
|
"test:browsers": "vitest run --project browsers --silent=true",
|
|
69
69
|
"test:node": "vitest run --project node --silent=true",
|
|
70
|
-
"test:sample": "npx vitest run --silent=false --hideSkippedTests --project node -t \"invalid definition\""
|
|
70
|
+
"test:sample": "npx vitest run --silent=false --hideSkippedTests --project node -t \"invalid definition\"",
|
|
71
|
+
"release:commit": "node -e \"const v=process.argv[1]; if(!v) throw new Error('Usage: npm run release:empty-commit -- <version>'); require('child_process').execSync(`git commit --allow-empty -m \\\"chore: release ${v}\\\" -m \\\"Release-As: ${v}\\\"`, {stdio:'inherit'});\" --"
|
|
71
72
|
},
|
|
72
73
|
"dependencies": {
|
|
73
74
|
"lodash.get": "^4.4.2",
|
package/src/SchemaCache.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import isequal from 'lodash.isequal';
|
|
2
2
|
import { Report } from './Report.js';
|
|
3
|
-
import { compileSchema } from './SchemaCompilation.js';
|
|
4
3
|
import * as SchemaValidation from './SchemaValidation.js';
|
|
5
4
|
import * as Utils from './Utils.js';
|
|
6
5
|
|
|
@@ -146,7 +145,7 @@ export function getSchemaByUri(report, uri, root) {
|
|
|
146
145
|
remoteReport = anscestorReport;
|
|
147
146
|
} else {
|
|
148
147
|
remoteReport = new Report(report);
|
|
149
|
-
if (
|
|
148
|
+
if (this._compileSchema(remoteReport, result)) {
|
|
150
149
|
const savedOptions = this.options;
|
|
151
150
|
try {
|
|
152
151
|
// If custom validationOptions were provided to setRemoteReference(),
|