z-schema 12.2.0 → 12.4.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.
Files changed (111) hide show
  1. package/README.md +2 -2
  2. package/bin/z-schema +1 -1
  3. package/cjs/{index.js → index.cjs} +838 -707
  4. package/cjs/{index.d.ts → index.d.cts} +47 -26
  5. package/dist/{errors.d.mts → errors.d.ts} +2 -2
  6. package/dist/{errors.mjs → errors.js} +1 -2
  7. package/dist/{format-validators.mjs → format-validators.js} +60 -43
  8. package/dist/{index.d.mts → index.d.ts} +9 -9
  9. package/dist/{index.mjs → index.js} +3 -3
  10. package/dist/{json-schema-versions.d.mts → json-schema-versions.d.ts} +34 -3
  11. package/dist/{json-schema.d.mts → json-schema.d.ts} +7 -7
  12. package/dist/{json-schema.mjs → json-schema.js} +6 -5
  13. package/dist/{json-validation.mjs → json-validation.js} +144 -127
  14. package/dist/{report.d.mts → report.d.ts} +8 -9
  15. package/dist/{report.mjs → report.js} +28 -31
  16. package/dist/{schema-cache.d.mts → schema-cache.d.ts} +5 -5
  17. package/dist/{schema-cache.mjs → schema-cache.js} +10 -11
  18. package/dist/{schema-compiler.d.mts → schema-compiler.d.ts} +4 -4
  19. package/dist/{schema-compiler.mjs → schema-compiler.js} +101 -79
  20. package/dist/{schema-validator.d.mts → schema-validator.d.ts} +5 -5
  21. package/dist/{schema-validator.mjs → schema-validator.js} +138 -166
  22. package/dist/utils/{array.mjs → array.js} +4 -3
  23. package/dist/utils/{base64.mjs → base64.js} +3 -2
  24. package/dist/utils/{clone.mjs → clone.js} +18 -20
  25. package/dist/utils/hostname.js +176 -0
  26. package/dist/utils/{json.mjs → json.js} +13 -8
  27. package/dist/utils/{schema-regex.mjs → schema-regex.js} +5 -5
  28. package/dist/utils/{time.mjs → time.js} +8 -8
  29. package/dist/utils/unicode.js +22 -0
  30. package/dist/utils/{what-is.mjs → what-is.js} +1 -2
  31. package/dist/validation/{array.mjs → array.js} +18 -20
  32. package/dist/validation/{combinators.mjs → combinators.js} +16 -16
  33. package/dist/validation/{numeric.mjs → numeric.js} +11 -11
  34. package/dist/validation/{object.mjs → object.js} +35 -34
  35. package/dist/validation/{ref.mjs → ref.js} +5 -5
  36. package/dist/validation/{shared.mjs → shared.js} +15 -12
  37. package/dist/validation/{string.mjs → string.js} +35 -35
  38. package/dist/validation/type.js +34 -0
  39. package/dist/{z-schema-base.d.mts → z-schema-base.d.ts} +11 -12
  40. package/dist/{z-schema-base.mjs → z-schema-base.js} +45 -40
  41. package/dist/{z-schema-options.d.mts → z-schema-options.d.ts} +3 -3
  42. package/dist/{z-schema-options.mjs → z-schema-options.js} +5 -5
  43. package/dist/{z-schema-reader.d.mts → z-schema-reader.d.ts} +1 -1
  44. package/dist/{z-schema-versions.mjs → z-schema-versions.js} +21 -21
  45. package/dist/{z-schema.d.mts → z-schema.d.ts} +5 -13
  46. package/dist/{z-schema.mjs → z-schema.js} +38 -48
  47. package/package.json +24 -25
  48. package/src/errors.ts +1 -2
  49. package/src/format-validators.ts +173 -67
  50. package/src/json-schema-versions.ts +56 -2
  51. package/src/json-schema.ts +10 -9
  52. package/src/json-validation.ts +189 -146
  53. package/src/report.ts +37 -49
  54. package/src/schema-cache.ts +13 -13
  55. package/src/schema-compiler.ts +170 -117
  56. package/src/schema-validator.ts +239 -238
  57. package/src/utils/array.ts +9 -6
  58. package/src/utils/base64.ts +13 -2
  59. package/src/utils/clone.ts +28 -30
  60. package/src/utils/date.ts +6 -3
  61. package/src/utils/hostname.ts +257 -31
  62. package/src/utils/json.ts +16 -9
  63. package/src/utils/properties.ts +2 -2
  64. package/src/utils/schema-regex.ts +4 -4
  65. package/src/utils/time.ts +8 -7
  66. package/src/utils/unicode.ts +12 -5
  67. package/src/utils/what-is.ts +1 -5
  68. package/src/validation/array.ts +24 -22
  69. package/src/validation/combinators.ts +14 -14
  70. package/src/validation/numeric.ts +14 -28
  71. package/src/validation/object.ts +32 -36
  72. package/src/validation/ref.ts +5 -6
  73. package/src/validation/shared.ts +22 -21
  74. package/src/validation/string.ts +36 -42
  75. package/src/validation/type.ts +17 -17
  76. package/src/z-schema-base.ts +49 -38
  77. package/src/z-schema-options.ts +4 -3
  78. package/src/z-schema.ts +35 -45
  79. package/umd/ZSchema.js +853 -715
  80. package/umd/ZSchema.min.js +2 -2
  81. package/umd/package.json +3 -0
  82. package/dist/utils/hostname.mjs +0 -75
  83. package/dist/utils/unicode.mjs +0 -12
  84. package/dist/validation/type.mjs +0 -32
  85. /package/dist/{format-validators.d.mts → format-validators.d.ts} +0 -0
  86. /package/dist/{json-schema-versions.mjs → json-schema-versions.js} +0 -0
  87. /package/dist/schemas/{draft-04-schema.mjs → draft-04-schema.js} +0 -0
  88. /package/dist/schemas/{draft-06-schema.mjs → draft-06-schema.js} +0 -0
  89. /package/dist/schemas/{draft-07-schema.mjs → draft-07-schema.js} +0 -0
  90. /package/dist/schemas/{draft-2019-09-meta-applicator.mjs → draft-2019-09-meta-applicator.js} +0 -0
  91. /package/dist/schemas/{draft-2019-09-meta-content.mjs → draft-2019-09-meta-content.js} +0 -0
  92. /package/dist/schemas/{draft-2019-09-meta-core.mjs → draft-2019-09-meta-core.js} +0 -0
  93. /package/dist/schemas/{draft-2019-09-meta-format.mjs → draft-2019-09-meta-format.js} +0 -0
  94. /package/dist/schemas/{draft-2019-09-meta-meta-data.mjs → draft-2019-09-meta-meta-data.js} +0 -0
  95. /package/dist/schemas/{draft-2019-09-meta-validation.mjs → draft-2019-09-meta-validation.js} +0 -0
  96. /package/dist/schemas/{draft-2019-09-schema.mjs → draft-2019-09-schema.js} +0 -0
  97. /package/dist/schemas/{draft-2020-12-meta-applicator.mjs → draft-2020-12-meta-applicator.js} +0 -0
  98. /package/dist/schemas/{draft-2020-12-meta-content.mjs → draft-2020-12-meta-content.js} +0 -0
  99. /package/dist/schemas/{draft-2020-12-meta-core.mjs → draft-2020-12-meta-core.js} +0 -0
  100. /package/dist/schemas/{draft-2020-12-meta-format-annotation.mjs → draft-2020-12-meta-format-annotation.js} +0 -0
  101. /package/dist/schemas/{draft-2020-12-meta-format-assertion.mjs → draft-2020-12-meta-format-assertion.js} +0 -0
  102. /package/dist/schemas/{draft-2020-12-meta-meta-data.mjs → draft-2020-12-meta-meta-data.js} +0 -0
  103. /package/dist/schemas/{draft-2020-12-meta-unevaluated.mjs → draft-2020-12-meta-unevaluated.js} +0 -0
  104. /package/dist/schemas/{draft-2020-12-meta-validation.mjs → draft-2020-12-meta-validation.js} +0 -0
  105. /package/dist/schemas/{draft-2020-12-schema.mjs → draft-2020-12-schema.js} +0 -0
  106. /package/dist/utils/{constants.mjs → constants.js} +0 -0
  107. /package/dist/utils/{date.mjs → date.js} +0 -0
  108. /package/dist/utils/{properties.mjs → properties.js} +0 -0
  109. /package/dist/utils/{symbols.mjs → symbols.js} +0 -0
  110. /package/dist/utils/{uri.mjs → uri.js} +0 -0
  111. /package/dist/{z-schema-reader.mjs → z-schema-reader.js} +0 -0
@@ -1,3 +1,4 @@
1
+ import type { ErrorCode } from '../errors.js';
1
2
  import type { JsonSchema, JsonSchemaAll, JsonSchemaInternal, JsonSchemaVersion } from '../json-schema-versions.js';
2
3
  // JsonSchemaAll is retained for the VALIDATION_VOCAB_KEYWORDS Set key type.
3
4
  import type { Report } from '../report.js';
@@ -9,22 +10,17 @@ import { isObject } from '../utils/what-is.js';
9
10
  // Shared types
10
11
  // ---------------------------------------------------------------------------
11
12
 
12
- export type JsonValidatorFn = (this: ZSchemaBase, report: Report, schema: JsonSchema, json: unknown) => void;
13
+ export type JsonValidatorFn = (ctx: ZSchemaBase, report: Report, schema: JsonSchema, json: unknown) => void;
13
14
 
14
15
  // ---------------------------------------------------------------------------
15
16
  // Draft / vocabulary helpers
16
17
  // ---------------------------------------------------------------------------
17
18
 
18
- export const shouldSkipValidate = function (options: ValidateOptions, errors: any) {
19
- return (
20
- options &&
21
- Array.isArray(options.includeErrors) &&
22
- options.includeErrors.length > 0 &&
23
- !errors.some(function (err: any) {
24
- return options.includeErrors!.includes(err);
25
- })
26
- );
27
- };
19
+ export const shouldSkipValidate = (options: ValidateOptions, errors: readonly ErrorCode[]) =>
20
+ options &&
21
+ Array.isArray(options.includeErrors) &&
22
+ options.includeErrors.length > 0 &&
23
+ !errors.some((err) => options.includeErrors!.includes(err));
28
24
 
29
25
  export const supportsDependentKeywords = (
30
26
  schema: JsonSchemaInternal,
@@ -89,12 +85,12 @@ export const isValidationVocabularyEnabled = (
89
85
  return true;
90
86
  }
91
87
 
92
- const vocabulary = metaSchema.$vocabulary as Record<string, boolean>;
88
+ const vocabulary = metaSchema.$vocabulary;
93
89
  const has2019 = Object.hasOwn(vocabulary, VOCAB_VALIDATION_2019_09);
94
90
  const has2020 = Object.hasOwn(vocabulary, VOCAB_VALIDATION_2020_12);
95
91
 
96
92
  if (has2019 || has2020) {
97
- return vocabulary[VOCAB_VALIDATION_2019_09] === true || vocabulary[VOCAB_VALIDATION_2020_12] === true;
93
+ return vocabulary[VOCAB_VALIDATION_2019_09] || vocabulary[VOCAB_VALIDATION_2020_12];
98
94
  }
99
95
 
100
96
  return false;
@@ -124,16 +120,16 @@ export const isFormatAssertionVocabEnabled = (
124
120
  return false; // no vocabulary info, default to annotation-only for modern drafts
125
121
  }
126
122
 
127
- const vocabulary = metaSchema.$vocabulary as Record<string, boolean>;
123
+ const vocabulary = metaSchema.$vocabulary;
128
124
 
129
125
  // For draft 2020-12, only the format-assertion vocabulary enables format as assertion
130
126
  if (Object.hasOwn(vocabulary, VOCAB_FORMAT_ASSERTION_2020_12)) {
131
- return vocabulary[VOCAB_FORMAT_ASSERTION_2020_12] === true;
127
+ return vocabulary[VOCAB_FORMAT_ASSERTION_2020_12];
132
128
  }
133
129
 
134
130
  // For draft 2019-09, check if the format vocabulary is enabled (true)
135
131
  if (Object.hasOwn(vocabulary, VOCAB_FORMAT_2019_09)) {
136
- return vocabulary[VOCAB_FORMAT_2019_09] === true;
132
+ return vocabulary[VOCAB_FORMAT_2019_09];
137
133
  }
138
134
 
139
135
  return false; // default to annotation-only for modern drafts
@@ -170,17 +166,22 @@ export function getCachedValidationResult(report: Report, schema: unknown, json:
170
166
  */
171
167
  export function deferOrRunSync(report: Report, subReports: Report[], decisionFn: () => void): void {
172
168
  const asyncTasksBefore = report.asyncTasks.length;
173
- for (const subReport of subReports) {
174
- report.asyncTasks.push(...subReport.asyncTasks);
169
+ for (let i = 0; i < subReports.length; i++) {
170
+ const tasks = subReports[i].asyncTasks;
171
+ for (let j = 0; j < tasks.length; j++) {
172
+ report.asyncTasks.push(tasks[j]);
173
+ }
175
174
  }
176
175
  const hasAsyncTasks = report.asyncTasks.length > asyncTasksBefore;
177
176
 
178
177
  if (hasAsyncTasks) {
179
178
  report.addAsyncTaskWithPath(
180
- (callback) => {
181
- setTimeout(() => callback(null), 0);
179
+ (callback: (result: unknown) => void) => {
180
+ setTimeout(() => {
181
+ callback(null);
182
+ }, 0);
182
183
  },
183
- [] as any,
184
+ [],
184
185
  () => {
185
186
  decisionFn();
186
187
  }
@@ -2,7 +2,7 @@ import type { JsonSchemaInternal } from '../json-schema-versions.js';
2
2
  import type { Report } from '../report.js';
3
3
  import type { ZSchemaBase } from '../z-schema-base.js';
4
4
 
5
- import { getFormatValidators } from '../format-validators.js';
5
+ import { resolveFormatValidator } from '../format-validators.js';
6
6
  import { decodeBase64, isValidBase64 } from '../utils/base64.js';
7
7
  import { compileSchemaRegex } from '../utils/schema-regex.js';
8
8
  import { unicodeLength } from '../utils/unicode.js';
@@ -13,9 +13,9 @@ import { isFormatAssertionVocabEnabled, shouldSkipValidate } from './shared.js';
13
13
  // minLength
14
14
  // ---------------------------------------------------------------------------
15
15
 
16
- export function minLengthValidator(this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
16
+ export function minLengthValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
17
17
  // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.2.2
18
- if (shouldSkipValidate(this.validateOptions, ['MIN_LENGTH'])) {
18
+ if (shouldSkipValidate(ctx.validateOptions, ['MIN_LENGTH'])) {
19
19
  return;
20
20
  }
21
21
  if (typeof json !== 'string') {
@@ -30,9 +30,9 @@ export function minLengthValidator(this: ZSchemaBase, report: Report, schema: Js
30
30
  // maxLength
31
31
  // ---------------------------------------------------------------------------
32
32
 
33
- export function maxLengthValidator(this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
33
+ export function maxLengthValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
34
34
  // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.1.2
35
- if (shouldSkipValidate(this.validateOptions, ['MAX_LENGTH'])) {
35
+ if (shouldSkipValidate(ctx.validateOptions, ['MAX_LENGTH'])) {
36
36
  return;
37
37
  }
38
38
  if (typeof json !== 'string') {
@@ -47,9 +47,9 @@ export function maxLengthValidator(this: ZSchemaBase, report: Report, schema: Js
47
47
  // pattern
48
48
  // ---------------------------------------------------------------------------
49
49
 
50
- export function patternValidator(this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
50
+ export function patternValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
51
51
  // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.3.2
52
- if (shouldSkipValidate(this.validateOptions, ['PATTERN'])) {
52
+ if (shouldSkipValidate(ctx.validateOptions, ['PATTERN'])) {
53
53
  return;
54
54
  }
55
55
  if (typeof json !== 'string') {
@@ -70,27 +70,24 @@ export function patternValidator(this: ZSchemaBase, report: Report, schema: Json
70
70
  // format
71
71
  // ---------------------------------------------------------------------------
72
72
 
73
- export function formatValidator(this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
73
+ export function formatValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
74
74
  // http://json-schema.org/latest/json-schema-validation.html#rfc.section.7.2
75
- if (this.options.formatAssertions === false) {
75
+ if (ctx.options.formatAssertions === false) {
76
76
  return;
77
77
  }
78
78
 
79
79
  // When formatAssertions is explicitly true, respect the meta-schema vocabulary:
80
80
  // for draft 2019-09/2020-12, format is annotation-only unless the format-assertion
81
81
  // vocabulary is enabled in the meta-schema.
82
- if (this.options.formatAssertions === true) {
83
- if (!isFormatAssertionVocabEnabled(schema, report, this.options.version)) {
84
- return;
85
- }
82
+ if (ctx.options.formatAssertions === true && !isFormatAssertionVocabEnabled(schema, report, ctx.options.version)) {
83
+ return;
86
84
  }
87
85
 
88
- const isModernDraft = this.options.version === 'draft2019-09' || this.options.version === 'draft2020-12';
86
+ const isModernDraft = ctx.options.version === 'draft2019-09' || ctx.options.version === 'draft2020-12';
89
87
 
90
- const formatValidators = getFormatValidators(this.options);
91
- const formatValidatorFn = formatValidators[schema.format!];
88
+ const formatValidatorFn = resolveFormatValidator(schema.format!, ctx.options);
92
89
  if (typeof formatValidatorFn === 'function') {
93
- if (shouldSkipValidate(this.validateOptions, ['INVALID_FORMAT'])) {
90
+ if (shouldSkipValidate(ctx.validateOptions, ['INVALID_FORMAT'])) {
94
91
  return;
95
92
  }
96
93
  if (report.hasError('INVALID_TYPE', [schema.type, whatIs(json)])) {
@@ -98,40 +95,42 @@ export function formatValidator(this: ZSchemaBase, report: Report, schema: JsonS
98
95
  }
99
96
  if (formatValidatorFn.length === 2) {
100
97
  // callback-based async
101
- report.addAsyncTaskWithPath(formatValidatorFn, [json], function (result) {
98
+ report.addAsyncTaskWithPath(formatValidatorFn, [json], (result) => {
102
99
  if (result !== true) {
103
100
  report.addError('INVALID_FORMAT', [schema.format!, JSON.stringify(json)], undefined, schema, 'format');
104
101
  }
105
102
  });
106
103
  } else {
107
- const result = formatValidatorFn.call(this, json);
104
+ const result = formatValidatorFn.call(ctx, json);
108
105
  if (result instanceof Promise) {
109
106
  // Promise-based async
110
107
  const promiseResult = result;
111
108
  report.addAsyncTaskWithPath(
112
- async (callback) => {
109
+ async (callback: (result: unknown) => void) => {
110
+ let resolved: unknown = false;
113
111
  try {
114
- const resolved = await promiseResult;
115
- callback(resolved);
116
- } catch (_error) {
117
- callback(false);
112
+ resolved = await promiseResult;
113
+ } catch {
114
+ // A rejected validator promise is treated as an invalid result (false).
118
115
  }
116
+ // Terminal callback of the async task; `return callback(...)` would trip
117
+ // no-confusing-void-expression since the callback returns void.
118
+ // oxlint-disable-next-line node/callback-return
119
+ callback(resolved);
119
120
  },
120
- [] as any,
121
- function (resolvedResult) {
121
+ [],
122
+ (resolvedResult) => {
122
123
  if (resolvedResult !== true) {
123
124
  report.addError('INVALID_FORMAT', [schema.format!, JSON.stringify(json)], undefined, schema, 'format');
124
125
  }
125
126
  }
126
127
  );
127
- } else {
128
+ } else if (!result) {
128
129
  // sync
129
- if (result !== true) {
130
- report.addError('INVALID_FORMAT', [schema.format!, JSON.stringify(json)], undefined, schema, 'format');
131
- }
130
+ report.addError('INVALID_FORMAT', [schema.format!, JSON.stringify(json)], undefined, schema, 'format');
132
131
  }
133
132
  }
134
- } else if (this.options.ignoreUnknownFormats !== true && !isModernDraft) {
133
+ } else if (ctx.options.ignoreUnknownFormats !== true && !isModernDraft) {
135
134
  report.addError('UNKNOWN_FORMAT', [schema.format!], undefined, schema, 'format');
136
135
  }
137
136
  }
@@ -140,15 +139,15 @@ export function formatValidator(this: ZSchemaBase, report: Report, schema: JsonS
140
139
  // contentEncoding
141
140
  // ---------------------------------------------------------------------------
142
141
 
143
- export function contentEncodingValidator(this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
144
- if (this.options.version !== 'draft-07') {
142
+ export function contentEncodingValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
143
+ if (ctx.options.version !== 'draft-07') {
145
144
  return;
146
145
  }
147
146
  if (typeof json !== 'string') {
148
147
  return;
149
148
  }
150
149
 
151
- const contentEncoding = schema.contentEncoding;
150
+ const { contentEncoding } = schema;
152
151
  if (contentEncoding !== 'base64') {
153
152
  return;
154
153
  }
@@ -168,20 +167,15 @@ export function contentEncodingValidator(this: ZSchemaBase, report: Report, sche
168
167
  // contentMediaType
169
168
  // ---------------------------------------------------------------------------
170
169
 
171
- export function contentMediaTypeValidator(
172
- this: ZSchemaBase,
173
- report: Report,
174
- schema: JsonSchemaInternal,
175
- json: unknown
176
- ) {
177
- if (this.options.version !== 'draft-07') {
170
+ export function contentMediaTypeValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
171
+ if (ctx.options.version !== 'draft-07') {
178
172
  return;
179
173
  }
180
174
  if (typeof json !== 'string') {
181
175
  return;
182
176
  }
183
177
 
184
- const contentMediaType = schema.contentMediaType;
178
+ const { contentMediaType } = schema;
185
179
  if (contentMediaType !== 'application/json') {
186
180
  return;
187
181
  }
@@ -10,9 +10,9 @@ import { shouldSkipValidate } from './shared.js';
10
10
  // type
11
11
  // ---------------------------------------------------------------------------
12
12
 
13
- export function typeValidator(this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
13
+ export function typeValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
14
14
  // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.5.2.2
15
- if (shouldSkipValidate(this.validateOptions, ['INVALID_TYPE'])) {
15
+ if (shouldSkipValidate(ctx.validateOptions, ['INVALID_TYPE'])) {
16
16
  return;
17
17
  }
18
18
  const jsonType = whatIs(json);
@@ -20,10 +20,8 @@ export function typeValidator(this: ZSchemaBase, report: Report, schema: JsonSch
20
20
  if (jsonType !== schema.type && (jsonType !== 'integer' || schema.type !== 'number')) {
21
21
  report.addError('INVALID_TYPE', [schema.type, jsonType], undefined, schema, 'type');
22
22
  }
23
- } else {
24
- if (!schema.type!.includes(jsonType) && (jsonType !== 'integer' || !schema.type!.includes('number'))) {
25
- report.addError('INVALID_TYPE', [JSON.stringify(schema.type), jsonType], undefined, schema, 'type');
26
- }
23
+ } else if (!schema.type!.includes(jsonType) && (jsonType !== 'integer' || !schema.type!.includes('number'))) {
24
+ report.addError('INVALID_TYPE', [JSON.stringify(schema.type), jsonType], undefined, schema, 'type');
27
25
  }
28
26
  }
29
27
 
@@ -31,25 +29,27 @@ export function typeValidator(this: ZSchemaBase, report: Report, schema: JsonSch
31
29
  // enum
32
30
  // ---------------------------------------------------------------------------
33
31
 
34
- export function enumValidator(this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
32
+ export function enumValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
35
33
  // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.5.1.2
36
- if (shouldSkipValidate(this.validateOptions, ['ENUM_CASE_MISMATCH', 'ENUM_MISMATCH'])) {
34
+ if (shouldSkipValidate(ctx.validateOptions, ['ENUM_CASE_MISMATCH', 'ENUM_MISMATCH'])) {
37
35
  return;
38
36
  }
39
- let match = false,
40
- caseInsensitiveMatch = false;
37
+ const eqOpts = { maxDepth: ctx.options.maxRecursionDepth };
38
+ const eqOptsCI = { caseInsensitiveComparison: true, maxDepth: ctx.options.maxRecursionDepth };
39
+ let caseInsensitiveMatch = false,
40
+ match = false;
41
41
  for (const enumVal of schema.enum!) {
42
- if (areEqual(json, enumVal, { maxDepth: this.options.maxRecursionDepth })) {
42
+ if (areEqual(json, enumVal, eqOpts)) {
43
43
  match = true;
44
44
  break;
45
- } else if (areEqual(json, enumVal, { caseInsensitiveComparison: true, maxDepth: this.options.maxRecursionDepth })) {
45
+ } else if (areEqual(json, enumVal, eqOptsCI)) {
46
46
  caseInsensitiveMatch = true;
47
47
  }
48
48
  }
49
49
 
50
- if (match === false) {
50
+ if (!match) {
51
51
  const error =
52
- caseInsensitiveMatch && this.options.enumCaseInsensitiveComparison ? 'ENUM_CASE_MISMATCH' : 'ENUM_MISMATCH';
52
+ caseInsensitiveMatch && ctx.options.enumCaseInsensitiveComparison ? 'ENUM_CASE_MISMATCH' : 'ENUM_MISMATCH';
53
53
  report.addError(error, [JSON.stringify(json)], undefined, schema, 'enum');
54
54
  }
55
55
  }
@@ -58,9 +58,9 @@ export function enumValidator(this: ZSchemaBase, report: Report, schema: JsonSch
58
58
  // const
59
59
  // ---------------------------------------------------------------------------
60
60
 
61
- export function constValidator(this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
61
+ export function constValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
62
62
  const constValue = schema.const;
63
- if (areEqual(json, constValue, { maxDepth: this.options.maxRecursionDepth }) === false) {
64
- report.addError('CONST', [JSON.stringify(constValue)], undefined, schema, undefined);
63
+ if (!areEqual(json, constValue, { maxDepth: ctx.options.maxRecursionDepth })) {
64
+ report.addError('CONST', [JSON.stringify(constValue)], undefined, schema);
65
65
  }
66
66
  }
@@ -1,10 +1,10 @@
1
- import type { ValidateError } from './errors.js';
1
+ import type { Errors, ValidateError } from './errors.js';
2
2
  import type { FormatValidatorFn } from './format-validators.js';
3
3
  import type { JsonSchema, JsonSchemaInternal, JsonSchemaVersion } from './json-schema-versions.js';
4
4
  import type { SchemaErrorDetail } from './report.js';
5
5
  import type { ZSchemaOptions } from './z-schema-options.js';
6
6
 
7
- import { type Errors, getValidateError } from './errors.js';
7
+ import { getValidateError } from './errors.js';
8
8
  import { getSupportedFormats } from './format-validators.js';
9
9
  import { VERSION_SCHEMA_URL_MAPPING } from './json-schema-versions.js';
10
10
  import { isInternalKey } from './json-schema.js';
@@ -26,7 +26,10 @@ export interface ValidateOptions {
26
26
  excludeErrors?: Array<keyof typeof Errors>;
27
27
  }
28
28
 
29
- export type ValidateResponse = { valid: boolean; err?: ValidateError };
29
+ export interface ValidateResponse {
30
+ valid: boolean;
31
+ err?: ValidateError;
32
+ }
30
33
 
31
34
  export type ValidateCallback = (err: ValidateResponse['err'], valid: ValidateResponse['valid']) => void;
32
35
 
@@ -62,7 +65,7 @@ export class ZSchemaBase {
62
65
  * create a circular dependency).
63
66
  */
64
67
  _jsonValidate(report: Report, schema: boolean | JsonSchemaInternal, json: unknown): boolean {
65
- return validateJson.call(this, report, schema, json);
68
+ return validateJson(this, report, schema, json);
66
69
  }
67
70
 
68
71
  getDefaultSchemaId(): string {
@@ -73,8 +76,7 @@ export class ZSchemaBase {
73
76
 
74
77
  _validate(json: unknown, schema: JsonSchema | string, options: ValidateOptions, callback: ValidateCallback): void;
75
78
  _validate(json: unknown, schema: JsonSchema | string, callback: ValidateCallback): void;
76
- _validate(json: unknown, schema: JsonSchema | string, options: ValidateOptions): true;
77
- _validate(json: unknown, schema: JsonSchema | string): true;
79
+ _validate(json: unknown, schema: JsonSchema | string, options?: ValidateOptions): true;
78
80
  _validate(
79
81
  json: unknown,
80
82
  schema: JsonSchema | string,
@@ -93,10 +95,10 @@ export class ZSchemaBase {
93
95
 
94
96
  if (typeof schema !== 'string' && typeof schema !== 'boolean' && !isObject(schema)) {
95
97
  const e = new Error(
96
- 'Invalid .validate call - schema must be a string or object but ' + whatIs(schema) + ' was passed!'
98
+ `Invalid .validate call - schema must be a string or object but ${whatIs(schema)} was passed!`
97
99
  );
98
100
  if (callback) {
99
- setTimeout(function () {
101
+ setTimeout(() => {
100
102
  callback(e, false);
101
103
  }, 0);
102
104
  return;
@@ -113,9 +115,9 @@ export class ZSchemaBase {
113
115
  const schemaName = schema;
114
116
  _schema = this.scache.getSchema(report, schemaName)!;
115
117
  if (!_schema) {
116
- const e = new Error("Schema with id '" + schemaName + "' wasn't found in the validator cache!");
118
+ const e = new Error(`Schema with id '${schemaName}' wasn't found in the validator cache!`);
117
119
  if (callback) {
118
- setTimeout(function () {
120
+ setTimeout(() => {
119
121
  callback(e, false);
120
122
  }, 0);
121
123
  return;
@@ -144,11 +146,11 @@ export class ZSchemaBase {
144
146
 
145
147
  if (options.schemaPath) {
146
148
  report.rootSchema = _schema;
147
- _schema = get(_schema, options.schemaPath);
149
+ _schema = get(_schema, options.schemaPath) as JsonSchemaInternal;
148
150
  if (!_schema) {
149
- const e = new Error("Schema path '" + options.schemaPath + "' wasn't found in the schema!");
151
+ const e = new Error(`Schema path '${options.schemaPath}' wasn't found in the schema!`);
150
152
  if (callback) {
151
- setTimeout(function () {
153
+ setTimeout(() => {
152
154
  callback(e, false);
153
155
  }, 0);
154
156
  return;
@@ -158,7 +160,7 @@ export class ZSchemaBase {
158
160
  }
159
161
 
160
162
  if (!foundError) {
161
- validateJson.call(this, report, _schema, json);
163
+ validateJson(this, report, _schema, json);
162
164
  }
163
165
 
164
166
  if (callback) {
@@ -187,13 +189,13 @@ export class ZSchemaBase {
187
189
  const report = new Report(this.options);
188
190
 
189
191
  if (Array.isArray(schemaOrArr)) {
190
- const arr = this.scache.getSchema(report, schemaOrArr)!;
192
+ const arr = this.scache.getSchema(report, schemaOrArr);
191
193
  const compiled = this.sc.compileSchema(report, arr);
192
194
  if (compiled) {
193
195
  this.sv.validateSchema(report, arr);
194
196
  }
195
197
  } else {
196
- const schema = this.scache.getSchema(report, schemaOrArr)!;
198
+ const schema = this.scache.getSchema(report, schemaOrArr);
197
199
  const compiled = this.sc.compileSchema(report, schema);
198
200
  if (compiled) {
199
201
  this.sv.validateSchema(report, schema);
@@ -256,11 +258,13 @@ export class ZSchemaBase {
256
258
  * @returns An array of unresolvable reference URIs.
257
259
  */
258
260
  getMissingReferences(err: ValidateError): string[] {
259
- if (!err) return [];
261
+ if (!err) {
262
+ return [];
263
+ }
260
264
  const details = err.details || [];
261
265
  const missingRefs: string[] = [];
262
- function collect(details: SchemaErrorDetail[]) {
263
- for (const detail of details) {
266
+ function collect(items: SchemaErrorDetail[]) {
267
+ for (const detail of items) {
264
268
  if (detail.code === 'UNRESOLVABLE_REFERENCE' || detail.code === 'SCHEMA_NOT_REACHABLE') {
265
269
  missingRefs.push(detail.params[0] as string);
266
270
  }
@@ -281,9 +285,11 @@ export class ZSchemaBase {
281
285
  getMissingRemoteReferences(err: ValidateError) {
282
286
  const missingReferences = this.getMissingReferences(err);
283
287
  const missingRemoteReferences: string[] = [];
288
+ const seen = new Set<string>();
284
289
  for (const ref of missingReferences) {
285
290
  const remoteReference = getRemotePath(ref);
286
- if (remoteReference && !missingRemoteReferences.includes(remoteReference)) {
291
+ if (remoteReference && !seen.has(remoteReference)) {
292
+ seen.add(remoteReference);
287
293
  missingRemoteReferences.push(remoteReference);
288
294
  }
289
295
  }
@@ -299,41 +305,46 @@ export class ZSchemaBase {
299
305
  getResolvedSchema(schemaId: string): JsonSchema | undefined {
300
306
  const report = new Report(this.options);
301
307
  const schema = this.scache.getSchemaByUri(report, schemaId);
302
- if (!schema) return undefined;
308
+ if (!schema) {
309
+ return undefined;
310
+ }
303
311
 
304
312
  const clonedSchema = deepClone(schema, this.options.maxRecursionDepth);
305
313
 
306
314
  const visited = new WeakSet<object>();
307
315
 
308
316
  // clean-up the schema and resolve references
309
- const cleanup = function (schema: any) {
310
- let key;
311
- const typeOf = whatIs(schema);
317
+ const cleanup = (node: unknown) => {
318
+ const typeOf = whatIs(node);
312
319
  if (typeOf !== 'object' && typeOf !== 'array') {
313
320
  return;
314
321
  }
315
322
 
316
- if (visited.has(schema)) {
323
+ if (visited.has(node as object)) {
317
324
  return;
318
325
  }
319
326
 
320
- visited.add(schema);
321
-
322
- if (schema.$ref && schema.__$refResolved) {
323
- const from = schema.__$refResolved;
324
- const to = schema;
325
- delete schema.$ref;
326
- delete schema.__$refResolved;
327
- for (key in from) {
328
- copyProp(from, to, key);
327
+ visited.add(node as object);
328
+
329
+ const schemaNode = node as JsonSchemaInternal;
330
+ if (schemaNode.$ref && schemaNode.__$refResolved) {
331
+ const from = schemaNode.__$refResolved;
332
+ const to = schemaNode;
333
+ delete schemaNode.$ref;
334
+ delete schemaNode.__$refResolved;
335
+ for (const key in from) {
336
+ if (Object.hasOwn(from, key)) {
337
+ copyProp(from, to, key);
338
+ }
329
339
  }
330
340
  }
331
- for (key in schema) {
332
- if (Object.hasOwn(schema, key)) {
341
+ const record = node as Record<string, unknown>;
342
+ for (const key in record) {
343
+ if (Object.hasOwn(record, key)) {
333
344
  if (isInternalKey(key)) {
334
- delete (schema as any)[key];
345
+ delete record[key];
335
346
  } else {
336
- cleanup((schema as any)[key]);
347
+ cleanup(record[key]);
337
348
  }
338
349
  }
339
350
  }
@@ -1,7 +1,8 @@
1
1
  import type { FormatValidatorFn } from './format-validators.js';
2
+ import type { JsonSchemaVersion } from './json-schema-versions.js';
2
3
  import type { Report } from './report.js';
3
4
 
4
- import { CURRENT_DEFAULT_SCHEMA_VERSION, type JsonSchemaVersion } from './json-schema-versions.js';
5
+ import { CURRENT_DEFAULT_SCHEMA_VERSION } from './json-schema-versions.js';
5
6
  import { shallowClone } from './utils/clone.js';
6
7
  import { DEFAULT_MAX_RECURSION_DEPTH, MAX_ASYNC_TIMEOUT } from './utils/constants.js';
7
8
 
@@ -103,7 +104,7 @@ export const normalizeOptions = (options?: ZSchemaOptions) => {
103
104
  // check that the options are correctly configured
104
105
  for (const key of keys) {
105
106
  if (defaultOptions[key] === undefined) {
106
- throw new Error('Unexpected option passed to constructor: ' + key);
107
+ throw new Error(`Unexpected option passed to constructor: ${key}`);
107
108
  }
108
109
  }
109
110
 
@@ -111,7 +112,7 @@ export const normalizeOptions = (options?: ZSchemaOptions) => {
111
112
  keys = Object.keys(defaultOptions) as Array<keyof ZSchemaOptions>;
112
113
  for (const key of keys) {
113
114
  if (options[key] === undefined) {
114
- (options as any)[key] = shallowClone(defaultOptions[key]);
115
+ (options as Record<string, unknown>)[key] = shallowClone(defaultOptions[key]);
115
116
  }
116
117
  }
117
118