z-schema 6.0.2 → 7.0.0-beta.1

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.
Files changed (47) hide show
  1. package/README.md +154 -134
  2. package/bin/z-schema +128 -124
  3. package/dist/Errors.js +50 -0
  4. package/dist/FormatValidators.js +136 -0
  5. package/{src → dist}/JsonValidation.js +184 -213
  6. package/dist/Report.js +220 -0
  7. package/{src → dist}/SchemaCache.js +67 -82
  8. package/{src → dist}/SchemaCompilation.js +89 -129
  9. package/dist/SchemaValidation.js +631 -0
  10. package/{src → dist}/Utils.js +96 -104
  11. package/dist/ZSchema-umd-min.js +1 -0
  12. package/dist/ZSchema-umd.js +13791 -0
  13. package/dist/ZSchema.cjs +13785 -0
  14. package/dist/ZSchema.js +366 -0
  15. package/dist/schemas/hyper-schema.json +156 -0
  16. package/dist/schemas/schema.json +151 -0
  17. package/dist/types/Errors.d.ts +44 -0
  18. package/dist/types/FormatValidators.d.ts +12 -0
  19. package/dist/types/JsonValidation.d.ts +37 -0
  20. package/dist/types/Report.d.ts +87 -0
  21. package/dist/types/SchemaCache.d.ts +26 -0
  22. package/dist/types/SchemaCompilation.d.ts +1 -0
  23. package/dist/types/SchemaValidation.d.ts +6 -0
  24. package/dist/types/Utils.d.ts +64 -0
  25. package/dist/types/ZSchema.d.ts +97 -0
  26. package/package.json +54 -43
  27. package/src/Errors.ts +56 -0
  28. package/src/FormatValidators.ts +136 -0
  29. package/src/JsonValidation.ts +624 -0
  30. package/src/Report.ts +337 -0
  31. package/src/SchemaCache.ts +189 -0
  32. package/src/SchemaCompilation.ts +293 -0
  33. package/src/SchemaValidation.ts +629 -0
  34. package/src/Utils.ts +286 -0
  35. package/src/ZSchema.ts +469 -0
  36. package/src/schemas/_ +0 -0
  37. package/dist/ZSchema-browser-min.js +0 -2
  38. package/dist/ZSchema-browser-min.js.map +0 -1
  39. package/dist/ZSchema-browser-test.js +0 -32247
  40. package/dist/ZSchema-browser.js +0 -12745
  41. package/index.d.ts +0 -175
  42. package/src/Errors.js +0 -60
  43. package/src/FormatValidators.js +0 -129
  44. package/src/Polyfills.js +0 -16
  45. package/src/Report.js +0 -299
  46. package/src/SchemaValidation.js +0 -619
  47. package/src/ZSchema.js +0 -409
package/bin/z-schema CHANGED
@@ -3,45 +3,52 @@
3
3
  // set default exitCode for node 0.10
4
4
  process.exitCode = 0;
5
5
 
6
- var fs = require("fs");
7
- var path = require("path");
8
- var program = require("commander");
9
- var request = require("https").request;
10
- var package = require("./../package.json");
11
- var ZSchema = require("./../src/ZSchema");
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import { program } from 'commander';
9
+ import { request } from 'https';
10
+ import pkg from '../package.json' with { type: 'json' };
11
+ import ZSchema from '../dist/ZSchema.js';
12
12
 
13
13
  program
14
- .version(package.version)
15
- .usage("[options] <schema> <json1?> <json2?> <json3?>")
16
- .option("--asyncTimeout <n>", "default timeout for all async tasks", parseInt)
17
- .option("--forceAdditional", "force additionalProperties and additionalItems to be defined on \"object\" and \"array\" types")
18
- .option("--assumeAdditional", "assume additionalProperties and additionalItems are defined as \"false\" where appropriate")
19
- .option("--forceItems", "force items to be defined on \"array\" types")
20
- .option("--forceMinItems", "force minItems to be defined on \"array\" types")
21
- .option("--forceMaxItems", "force maxItems to be defined on \"array\" types")
22
- .option("--forceMinLength", "force minLength to be defined on \"string\" types")
23
- .option("--forceMaxLength", "force maxLength to be defined on \"string\" types")
24
- .option("--forceProperties", "force properties or patternProperties to be defined on \"object\" types")
25
- .option("--ignoreUnresolvableReferences", "ignore references that cannot be resolved (remote schemas)")
26
- .option("--noExtraKeywords", "disallow usage of keywords that this validator can't handle")
27
- .option("--noTypeless", "disallow usage of schema's without \"type\" defined")
28
- .option("--noEmptyStrings", "disallow zero length strings in validated objects")
29
- .option("--noEmptyArrays", "disallow zero length arrays in validated objects")
30
- .option("--strictUris", "forces \"uri\" format to be in fully rfc3986 compliant")
31
- .option("--strictMode", "turn on some of the above")
32
- .option("--reportPathAsArray", "report error paths as an array of path segments to get to the offending node")
33
- .option("--breakOnFirstError", "stops validation as soon as an error is found, true by default but can be turned off")
34
- .option("--pedanticCheck", "check if schema follow best practices and common sence")
35
- .option("--ignoreUnknownFormats", "ignore unknown formats (do not report them as an error)")
14
+ .version(pkg.version)
15
+ .usage('[options] <schema> <json1?> <json2?> <json3?>')
16
+ .option('--asyncTimeout <n>', 'default timeout for all async tasks', parseInt)
17
+ .option(
18
+ '--forceAdditional',
19
+ 'force additionalProperties and additionalItems to be defined on "object" and "array" types'
20
+ )
21
+ .option(
22
+ '--assumeAdditional',
23
+ 'assume additionalProperties and additionalItems are defined as "false" where appropriate'
24
+ )
25
+ .option('--forceItems', 'force items to be defined on "array" types')
26
+ .option('--forceMinItems', 'force minItems to be defined on "array" types')
27
+ .option('--forceMaxItems', 'force maxItems to be defined on "array" types')
28
+ .option('--forceMinLength', 'force minLength to be defined on "string" types')
29
+ .option('--forceMaxLength', 'force maxLength to be defined on "string" types')
30
+ .option('--forceProperties', 'force properties or patternProperties to be defined on "object" types')
31
+ .option('--ignoreUnresolvableReferences', 'ignore references that cannot be resolved (remote schemas)')
32
+ .option('--noExtraKeywords', "disallow usage of keywords that this validator can't handle")
33
+ .option('--noTypeless', 'disallow usage of schema\'s without "type" defined')
34
+ .option('--noEmptyStrings', 'disallow zero length strings in validated objects')
35
+ .option('--noEmptyArrays', 'disallow zero length arrays in validated objects')
36
+ .option('--strictUris', 'forces "uri" format to be in fully rfc3986 compliant')
37
+ .option('--strictMode', 'turn on some of the above')
38
+ .option('--reportPathAsArray', 'report error paths as an array of path segments to get to the offending node')
39
+ .option('--breakOnFirstError', 'stops validation as soon as an error is found, true by default but can be turned off')
40
+ .option('--pedanticCheck', 'check if schema follow best practices and common sence')
41
+ .option('--ignoreUnknownFormats', 'ignore unknown formats (do not report them as an error)')
42
+ .allowExcessArguments()
36
43
  .parse(process.argv);
37
-
38
- var options = {};
44
+
45
+ var options = {};
39
46
  var defaultOptions = ZSchema.getDefaultOptions();
40
47
 
41
48
  for (var key in defaultOptions) {
42
- if (program[key]) {
43
- options[key] = program[key];
44
- }
49
+ if (program[key]) {
50
+ options[key] = program[key];
51
+ }
45
52
  }
46
53
 
47
54
  if (!program.args.length) {
@@ -49,20 +56,20 @@ if (!program.args.length) {
49
56
  }
50
57
 
51
58
  function readJson(fileName) {
52
- var ret;
53
- try {
54
- ret = fs.readFileSync(fileName, { encoding: "utf8" });
55
- } catch (e) {
56
- console.error(e);
57
- throw new Error("Couldn't read the file: " + fileName);
58
- }
59
- try {
60
- ret = JSON.parse(ret);
61
- } catch (e) {
62
- console.error(e);
63
- throw new Error("Couldn't parse the file as JSON: " + fileName);
64
- }
65
- return ret;
59
+ var ret;
60
+ try {
61
+ ret = fs.readFileSync(fileName, { encoding: 'utf8' });
62
+ } catch (e) {
63
+ console.error(e);
64
+ throw new Error("Couldn't read the file: " + fileName);
65
+ }
66
+ try {
67
+ ret = JSON.parse(ret);
68
+ } catch (e) {
69
+ console.error(e);
70
+ throw new Error("Couldn't parse the file as JSON: " + fileName);
71
+ }
72
+ return ret;
66
73
  }
67
74
 
68
75
  var validator = new ZSchema(options);
@@ -70,100 +77,97 @@ var schemaFilePath = program.args.shift();
70
77
  var schema = readJson(schemaFilePath);
71
78
 
72
79
  function validateWithAutomaticDownloads(filePath, data, schema, callback) {
80
+ var lastResult;
73
81
 
74
- var lastResult;
82
+ function finish() {
83
+ callback(validator.getLastErrors(), lastResult);
84
+ }
75
85
 
76
- function finish() {
77
- callback(validator.getLastErrors(), lastResult);
86
+ function validate() {
87
+ if (data !== undefined) {
88
+ lastResult = validator.validate(data, schema);
89
+ } else {
90
+ lastResult = validator.validateSchema(schema);
78
91
  }
79
92
 
80
- function validate() {
93
+ // console.log(lastResult);
94
+ // console.log(JSON.stringify(validator.getLastErrors(), null, 4));
81
95
 
82
- if (data !== undefined) {
83
- lastResult = validator.validate(data, schema);
84
- } else {
85
- lastResult = validator.validateSchema(schema);
86
- }
87
-
88
- // console.log(lastResult);
89
- // console.log(JSON.stringify(validator.getLastErrors(), null, 4));
90
-
91
- var missingReferences = validator.getMissingRemoteReferences();
92
- if (missingReferences.length > 0) {
93
- var finished = 0;
94
- missingReferences.forEach(function (url) {
95
- var urlString = "request: " + url + " - ";
96
-
97
- if (url.match(/^https?:/)) {
98
- request(url, function (response) {
99
- var body = "";
100
- response.on("data", function (chunk) { data += chunk; });
101
- response.on("end", function () {
102
-
103
- console.log(urlString + response.statusCode);
104
-
105
- validator.setRemoteReference(url, JSON.parse(body));
106
- finished++;
107
- if (finished === missingReferences.length) {
108
- validate();
109
- }
110
- });
111
- }).on("error", function (error) {
112
- console.error(urlString);
113
- console.error(error);
114
- process.exit(1);
115
- });
116
- } else {
117
- // FUTURE: maybe else if (isFile(url)) later
118
- var referencePath = path.resolve(process.cwd(), path.dirname(filePath), url);
119
- var reference = readJson(referencePath);
120
- validator.setRemoteReference(url, reference);
121
- finished++;
122
- if (finished === missingReferences.length) {
123
- validate();
124
- }
125
- }
96
+ var missingReferences = validator.getMissingRemoteReferences();
97
+ if (missingReferences.length > 0) {
98
+ var finished = 0;
99
+ missingReferences.forEach(function (url) {
100
+ var urlString = 'request: ' + url + ' - ';
101
+
102
+ if (url.match(/^https?:/)) {
103
+ request(url, function (response) {
104
+ var body = '';
105
+ response.on('data', function (chunk) {
106
+ data += chunk;
107
+ });
108
+ response.on('end', function () {
109
+ console.log(urlString + response.statusCode);
110
+
111
+ validator.setRemoteReference(url, JSON.parse(body));
112
+ finished++;
113
+ if (finished === missingReferences.length) {
114
+ validate();
115
+ }
126
116
  });
117
+ }).on('error', function (error) {
118
+ console.error(urlString);
119
+ console.error(error);
120
+ process.exit(1);
121
+ });
127
122
  } else {
128
- finish();
123
+ // FUTURE: maybe else if (isFile(url)) later
124
+ var referencePath = path.resolve(process.cwd(), path.dirname(filePath), url);
125
+ var reference = readJson(referencePath);
126
+ validator.setRemoteReference(url, reference);
127
+ finished++;
128
+ if (finished === missingReferences.length) {
129
+ validate();
130
+ }
129
131
  }
130
-
132
+ });
133
+ } else {
134
+ finish();
131
135
  }
136
+ }
132
137
 
133
- validate();
134
-
138
+ validate();
135
139
  }
136
140
 
137
141
  var i = 0;
138
142
  function validateJsons() {
139
- if (program.args.length === 0) {
140
- process.exit(process.exitCode);
141
- return;
143
+ if (program.args.length === 0) {
144
+ process.exit(process.exitCode);
145
+ return;
146
+ }
147
+ i++;
148
+
149
+ var filePath = program.args.shift();
150
+ var json = readJson(filePath);
151
+ validateWithAutomaticDownloads(filePath, json, schema, function (errs, isValid) {
152
+ if (!isValid) {
153
+ console.log(JSON.stringify(validator.getLastErrors(), null, 4));
154
+ console.log('json #' + i + ' validation failed');
155
+ process.exitCode = 1;
156
+ } else {
157
+ console.log('json #' + i + ' validation passed');
142
158
  }
143
- i++;
144
-
145
- var filePath = program.args.shift();
146
- var json = readJson(filePath);
147
- validateWithAutomaticDownloads(filePath, json, schema, function (errs, isValid) {
148
- if (!isValid) {
149
- console.log(JSON.stringify(validator.getLastErrors(), null, 4));
150
- console.log("json #" + i + " validation failed");
151
- process.exitCode = 1;
152
- } else {
153
- console.log("json #" + i + " validation passed");
154
- }
155
- validateJsons();
156
- });
159
+ validateJsons();
160
+ });
157
161
  }
158
162
 
159
163
  // validate schema
160
164
  validateWithAutomaticDownloads(schemaFilePath, undefined, schema, function (errs, isValid) {
161
- if (!isValid) {
162
- console.log(JSON.stringify(validator.getLastErrors(), null, 4));
163
- console.log("schema validation failed");
164
- process.exit(1);
165
- } else {
166
- console.log("schema validation passed");
167
- validateJsons();
168
- }
165
+ if (!isValid) {
166
+ console.log(JSON.stringify(validator.getLastErrors(), null, 4));
167
+ console.log('schema validation failed');
168
+ process.exit(1);
169
+ } else {
170
+ console.log('schema validation passed');
171
+ validateJsons();
172
+ }
169
173
  });
package/dist/Errors.js ADDED
@@ -0,0 +1,50 @@
1
+ export const Errors = {
2
+ INVALID_TYPE: 'Expected type {0} but found type {1}',
3
+ INVALID_FORMAT: "Object didn't pass validation for format {0}: {1}",
4
+ ENUM_MISMATCH: 'No enum match for: {0}',
5
+ ENUM_CASE_MISMATCH: 'Enum does not match case for: {0}',
6
+ ANY_OF_MISSING: "Data does not match any schemas from 'anyOf'",
7
+ ONE_OF_MISSING: "Data does not match any schemas from 'oneOf'",
8
+ ONE_OF_MULTIPLE: "Data is valid against more than one schema from 'oneOf'",
9
+ NOT_PASSED: "Data matches schema from 'not'",
10
+ // Array errors
11
+ ARRAY_LENGTH_SHORT: 'Array is too short ({0}), minimum {1}',
12
+ ARRAY_LENGTH_LONG: 'Array is too long ({0}), maximum {1}',
13
+ ARRAY_UNIQUE: 'Array items are not unique (indexes {0} and {1})',
14
+ ARRAY_ADDITIONAL_ITEMS: 'Additional items not allowed',
15
+ // Numeric errors
16
+ MULTIPLE_OF: 'Value {0} is not a multiple of {1}',
17
+ MINIMUM: 'Value {0} is less than minimum {1}',
18
+ MINIMUM_EXCLUSIVE: 'Value {0} is equal or less than exclusive minimum {1}',
19
+ MAXIMUM: 'Value {0} is greater than maximum {1}',
20
+ MAXIMUM_EXCLUSIVE: 'Value {0} is equal or greater than exclusive maximum {1}',
21
+ // Object errors
22
+ OBJECT_PROPERTIES_MINIMUM: 'Too few properties defined ({0}), minimum {1}',
23
+ OBJECT_PROPERTIES_MAXIMUM: 'Too many properties defined ({0}), maximum {1}',
24
+ OBJECT_MISSING_REQUIRED_PROPERTY: 'Missing required property: {0}',
25
+ OBJECT_ADDITIONAL_PROPERTIES: 'Additional properties not allowed: {0}',
26
+ OBJECT_DEPENDENCY_KEY: 'Dependency failed - key must exist: {0} (due to key: {1})',
27
+ // String errors
28
+ MIN_LENGTH: 'String is too short ({0} chars), minimum {1}',
29
+ MAX_LENGTH: 'String is too long ({0} chars), maximum {1}',
30
+ PATTERN: 'String does not match pattern {0}: {1}',
31
+ // Schema validation errors
32
+ KEYWORD_TYPE_EXPECTED: "Keyword '{0}' is expected to be of type '{1}'",
33
+ KEYWORD_UNDEFINED_STRICT: "Keyword '{0}' must be defined in strict mode",
34
+ KEYWORD_UNEXPECTED: "Keyword '{0}' is not expected to appear in the schema",
35
+ KEYWORD_MUST_BE: "Keyword '{0}' must be {1}",
36
+ KEYWORD_DEPENDENCY: "Keyword '{0}' requires keyword '{1}'",
37
+ KEYWORD_PATTERN: "Keyword '{0}' is not a valid RegExp pattern: {1}",
38
+ KEYWORD_VALUE_TYPE: "Each element of keyword '{0}' array must be a '{1}'",
39
+ UNKNOWN_FORMAT: "There is no validation function for format '{0}'",
40
+ CUSTOM_MODE_FORCE_PROPERTIES: '{0} must define at least one property if present',
41
+ // Remote errors
42
+ REF_UNRESOLVED: 'Reference has not been resolved during compilation: {0}',
43
+ UNRESOLVABLE_REFERENCE: 'Reference could not be resolved: {0}',
44
+ SCHEMA_NOT_REACHABLE: 'Validator was not able to read schema with uri: {0}',
45
+ SCHEMA_TYPE_EXPECTED: "Schema is expected to be of type 'object'",
46
+ SCHEMA_NOT_AN_OBJECT: 'Schema is not an object: {0}',
47
+ ASYNC_TIMEOUT: '{0} asynchronous task(s) have timed out after {1} ms',
48
+ PARENT_SCHEMA_VALIDATION_FAILED: 'Schema failed to validate against its parent schema, see inner errors for details.',
49
+ REMOTE_NOT_VALID: "Remote reference didn't compile successfully: {0}",
50
+ };
@@ -0,0 +1,136 @@
1
+ import validator from 'validator';
2
+ export const FormatValidators = {
3
+ date: function (date) {
4
+ if (typeof date !== 'string') {
5
+ return true;
6
+ }
7
+ // full-date from http://tools.ietf.org/html/rfc3339#section-5.6
8
+ const matches = /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/.exec(date);
9
+ if (matches === null) {
10
+ return false;
11
+ }
12
+ // var year = matches[1];
13
+ // var month = matches[2];
14
+ // var day = matches[3];
15
+ if (matches[2] < '01' || matches[2] > '12' || matches[3] < '01' || matches[3] > '31') {
16
+ return false;
17
+ }
18
+ return true;
19
+ },
20
+ 'date-time': function (dateTime) {
21
+ if (typeof dateTime !== 'string') {
22
+ return true;
23
+ }
24
+ // date-time from http://tools.ietf.org/html/rfc3339#section-5.6
25
+ const s = dateTime.toLowerCase().split('t');
26
+ if (!FormatValidators.date(s[0])) {
27
+ return false;
28
+ }
29
+ const matches = /^([0-9]{2}):([0-9]{2}):([0-9]{2})(.[0-9]+)?(z|([+-][0-9]{2}:[0-9]{2}))$/.exec(s[1]);
30
+ if (matches === null) {
31
+ return false;
32
+ }
33
+ // var hour = matches[1];
34
+ // var minute = matches[2];
35
+ // var second = matches[3];
36
+ // var fraction = matches[4];
37
+ // var timezone = matches[5];
38
+ if (matches[1] > '23' || matches[2] > '59' || matches[3] > '59') {
39
+ return false;
40
+ }
41
+ return true;
42
+ },
43
+ email: function (email) {
44
+ if (typeof email !== 'string') {
45
+ return true;
46
+ }
47
+ return validator.isEmail(email, { require_tld: true });
48
+ },
49
+ hostname: function (hostname) {
50
+ if (typeof hostname !== 'string') {
51
+ return true;
52
+ }
53
+ /*
54
+ http://json-schema.org/latest/json-schema-validation.html#anchor114
55
+ A string instance is valid against this attribute if it is a valid
56
+ representation for an Internet host name, as defined by RFC 1034, section 3.1 [RFC1034].
57
+
58
+ http://tools.ietf.org/html/rfc1034#section-3.5
59
+
60
+ <digit> ::= any one of the ten digits 0 through 9
61
+ var digit = /[0-9]/;
62
+
63
+ <letter> ::= any one of the 52 alphabetic characters A through Z in upper case and a through z in lower case
64
+ var letter = /[a-zA-Z]/;
65
+
66
+ <let-dig> ::= <letter> | <digit>
67
+ var letDig = /[0-9a-zA-Z]/;
68
+
69
+ <let-dig-hyp> ::= <let-dig> | "-"
70
+ var letDigHyp = /[-0-9a-zA-Z]/;
71
+
72
+ <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
73
+ var ldhStr = /[-0-9a-zA-Z]+/;
74
+
75
+ <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
76
+ var label = /[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?/;
77
+
78
+ <subdomain> ::= <label> | <subdomain> "." <label>
79
+ var subdomain = /^[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?(\.[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?)*$/;
80
+
81
+ <domain> ::= <subdomain> | " "
82
+ var domain = null;
83
+ */
84
+ const valid = /^[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?(\.[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?)*$/.test(hostname);
85
+ if (valid) {
86
+ // the sum of all label octets and label lengths is limited to 255.
87
+ if (hostname.length > 255) {
88
+ return false;
89
+ }
90
+ // Each node has a label, which is zero to 63 octets in length
91
+ const labels = hostname.split('.');
92
+ for (let i = 0; i < labels.length; i++) {
93
+ if (labels[i].length > 63) {
94
+ return false;
95
+ }
96
+ }
97
+ }
98
+ return valid;
99
+ },
100
+ 'host-name': function (hostname) {
101
+ return FormatValidators.hostname.call(this, hostname);
102
+ },
103
+ ipv4: function (ipv4) {
104
+ if (typeof ipv4 !== 'string') {
105
+ return true;
106
+ }
107
+ return validator.isIP(ipv4, 4);
108
+ },
109
+ ipv6: function (ipv6) {
110
+ if (typeof ipv6 !== 'string') {
111
+ return true;
112
+ }
113
+ return validator.isIP(ipv6, 6);
114
+ },
115
+ regex: function (str) {
116
+ try {
117
+ RegExp(str);
118
+ return true;
119
+ }
120
+ catch (_e) {
121
+ return false;
122
+ }
123
+ },
124
+ uri: function (...args) {
125
+ if (this.options.strictUris) {
126
+ return FormatValidators['strict-uri'].apply(this, args);
127
+ }
128
+ const [uri] = args;
129
+ // https://github.com/zaggino/z-schema/issues/18
130
+ // RegExp from http://tools.ietf.org/html/rfc3986#appendix-B
131
+ return typeof uri !== 'string' || RegExp('^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?').test(uri);
132
+ },
133
+ 'strict-uri': function (uri) {
134
+ return typeof uri !== 'string' || validator.isURL(uri);
135
+ },
136
+ };