vscode-json-languageservice 5.7.2 → 6.0.0-next.2
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/CHANGELOG.md +13 -0
- package/lib/esm/jsonContributions.d.ts +1 -1
- package/lib/esm/jsonLanguageService.d.ts +2 -2
- package/lib/esm/jsonLanguageService.js +13 -13
- package/lib/esm/jsonLanguageTypes.d.ts +10 -2
- package/lib/esm/jsonSchema.d.ts +71 -2
- package/lib/esm/parser/jsonParser.js +224 -93
- package/lib/esm/services/configuration.js +2 -2
- package/lib/esm/services/jsonCompletion.js +5 -5
- package/lib/esm/services/jsonDocumentSymbols.js +4 -4
- package/lib/esm/services/jsonFolding.js +1 -1
- package/lib/esm/services/jsonHover.js +2 -2
- package/lib/esm/services/jsonLinks.js +94 -3
- package/lib/esm/services/jsonSchemaService.js +639 -100
- package/lib/esm/services/jsonSelectionRanges.js +1 -1
- package/lib/esm/services/jsonValidation.js +4 -4
- package/lib/esm/services/schemas/draft-2019-09-flat.d.ts +1 -1
- package/lib/esm/services/schemas/draft-2020-12-flat.d.ts +1 -1
- package/lib/esm/services/vocabularies.js +139 -0
- package/lib/esm/utils/format.js +1 -1
- package/lib/esm/utils/sort.js +3 -3
- package/package.json +23 -20
- package/lib/umd/jsonContributions.d.ts +0 -21
- package/lib/umd/jsonContributions.js +0 -12
- package/lib/umd/jsonLanguageService.d.ts +0 -30
- package/lib/umd/jsonLanguageService.js +0 -79
- package/lib/umd/jsonLanguageTypes.d.ts +0 -305
- package/lib/umd/jsonLanguageTypes.js +0 -109
- package/lib/umd/jsonSchema.d.ts +0 -92
- package/lib/umd/jsonSchema.js +0 -12
- package/lib/umd/parser/jsonParser.js +0 -1365
- package/lib/umd/services/configuration.js +0 -536
- package/lib/umd/services/jsonCompletion.js +0 -982
- package/lib/umd/services/jsonDocumentSymbols.js +0 -285
- package/lib/umd/services/jsonFolding.js +0 -133
- package/lib/umd/services/jsonHover.js +0 -125
- package/lib/umd/services/jsonLinks.js +0 -85
- package/lib/umd/services/jsonSchemaService.js +0 -631
- package/lib/umd/services/jsonSelectionRanges.js +0 -74
- package/lib/umd/services/jsonValidation.js +0 -165
- package/lib/umd/services/schemas/draft-2019-09-flat.d.ts +0 -278
- package/lib/umd/services/schemas/draft-2019-09-flat.js +0 -314
- package/lib/umd/services/schemas/draft-2020-12-flat.d.ts +0 -276
- package/lib/umd/services/schemas/draft-2020-12-flat.js +0 -307
- package/lib/umd/utils/colors.js +0 -83
- package/lib/umd/utils/format.js +0 -33
- package/lib/umd/utils/glob.js +0 -137
- package/lib/umd/utils/json.js +0 -55
- package/lib/umd/utils/objects.js +0 -86
- package/lib/umd/utils/propertyTree.js +0 -90
- package/lib/umd/utils/sort.js +0 -384
- package/lib/umd/utils/strings.js +0 -97
|
@@ -3,16 +3,19 @@
|
|
|
3
3
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
5
|
import * as Json from 'jsonc-parser';
|
|
6
|
-
import { isNumber, equals, isBoolean, isString, isDefined, isObject } from '../utils/objects';
|
|
7
|
-
import { extendedRegExp, stringLength } from '../utils/strings';
|
|
8
|
-
import { ErrorCode, Diagnostic, DiagnosticSeverity, Range, SchemaDraft } from '../jsonLanguageTypes';
|
|
6
|
+
import { isNumber, equals, isBoolean, isString, isDefined, isObject } from '../utils/objects.js';
|
|
7
|
+
import { extendedRegExp, stringLength } from '../utils/strings.js';
|
|
8
|
+
import { ErrorCode, Diagnostic, DiagnosticSeverity, Range, SchemaDraft } from '../jsonLanguageTypes.js';
|
|
9
9
|
import { URI } from 'vscode-uri';
|
|
10
|
+
import { isKeywordEnabled, isFormatAssertionEnabled } from '../services/vocabularies.js';
|
|
10
11
|
import * as l10n from '@vscode/l10n';
|
|
11
12
|
const formats = {
|
|
12
13
|
'color-hex': { errorMessage: l10n.t('Invalid color format. Use #RGB, #RGBA, #RRGGBB or #RRGGBBAA.'), pattern: /^#([0-9A-Fa-f]{3,4}|([0-9A-Fa-f]{2}){3,4})$/ },
|
|
13
14
|
'date-time': { errorMessage: l10n.t('String is not a RFC3339 date-time.'), pattern: /^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(\.[0-9]+)?(Z|(\+|-)([01][0-9]|2[0-3]):([0-5][0-9]))$/i },
|
|
14
15
|
'date': { errorMessage: l10n.t('String is not a RFC3339 date.'), pattern: /^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/i },
|
|
15
16
|
'time': { errorMessage: l10n.t('String is not a RFC3339 time.'), pattern: /^([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(\.[0-9]+)?(Z|(\+|-)([01][0-9]|2[0-3]):([0-5][0-9]))$/i },
|
|
17
|
+
'duration': { errorMessage: l10n.t('String is not an ISO 8601 duration.'), pattern: /^P(?!$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+(\.\d+)?S)?)?$/ },
|
|
18
|
+
'uuid': { errorMessage: l10n.t('String is not a valid UUID.'), pattern: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i },
|
|
16
19
|
'email': { errorMessage: l10n.t('String is not an e-mail address.'), pattern: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}))$/ },
|
|
17
20
|
'hostname': { errorMessage: l10n.t('String is not a hostname.'), pattern: /^(?=.{1,253}\.?$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[-0-9a-z]{0,61}[0-9a-z])?)*\.?$/i },
|
|
18
21
|
'ipv4': { errorMessage: l10n.t('String is not an IPv4 address.'), pattern: /^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/ },
|
|
@@ -130,8 +133,10 @@ const schemaDraftFromId = {
|
|
|
130
133
|
'https://json-schema.org/draft/2020-12/schema': SchemaDraft.v2020_12
|
|
131
134
|
};
|
|
132
135
|
class EvaluationContext {
|
|
133
|
-
constructor(schemaDraft) {
|
|
136
|
+
constructor(schemaDraft, activeVocabularies, explicitSchemaDraft) {
|
|
134
137
|
this.schemaDraft = schemaDraft;
|
|
138
|
+
this.activeVocabularies = activeVocabularies;
|
|
139
|
+
this.explicitSchemaDraft = explicitSchemaDraft;
|
|
135
140
|
}
|
|
136
141
|
}
|
|
137
142
|
class SchemaCollector {
|
|
@@ -264,10 +269,14 @@ export class JSONDocument {
|
|
|
264
269
|
doVisit(this.root);
|
|
265
270
|
}
|
|
266
271
|
}
|
|
267
|
-
validate(textDocument, schema, severity = DiagnosticSeverity.Warning, schemaDraft) {
|
|
272
|
+
validate(textDocument, schema, severity = DiagnosticSeverity.Warning, schemaDraft, activeVocabularies) {
|
|
268
273
|
if (this.root && schema) {
|
|
269
274
|
const validationResult = new ValidationResult();
|
|
270
|
-
|
|
275
|
+
const { explicitDraft, effectiveDraft } = resolveDrafts(schema, schemaDraft);
|
|
276
|
+
const context = new EvaluationContext(effectiveDraft, activeVocabularies, explicitDraft);
|
|
277
|
+
const schemaStack = [];
|
|
278
|
+
const schemaRoots = [schema];
|
|
279
|
+
validate(this.root, schema, validationResult, NoOpSchemaCollector.instance, context, schemaStack, schemaRoots);
|
|
271
280
|
return validationResult.problems.map(p => {
|
|
272
281
|
const range = Range.create(textDocument.positionAt(p.location.offset), textDocument.positionAt(p.location.offset + p.location.length));
|
|
273
282
|
return Diagnostic.create(range, p.message, p.severity ?? severity, p.code);
|
|
@@ -275,32 +284,123 @@ export class JSONDocument {
|
|
|
275
284
|
}
|
|
276
285
|
return undefined;
|
|
277
286
|
}
|
|
278
|
-
getMatchingSchemas(schema, focusOffset = -1, exclude) {
|
|
287
|
+
getMatchingSchemas(schema, focusOffset = -1, exclude, activeVocabularies) {
|
|
279
288
|
if (this.root && schema) {
|
|
280
289
|
const matchingSchemas = new SchemaCollector(focusOffset, exclude);
|
|
281
|
-
const
|
|
282
|
-
const context = new EvaluationContext(
|
|
283
|
-
|
|
290
|
+
const { explicitDraft, effectiveDraft } = resolveDrafts(schema);
|
|
291
|
+
const context = new EvaluationContext(effectiveDraft, activeVocabularies, explicitDraft);
|
|
292
|
+
const schemaStack = [];
|
|
293
|
+
const schemaRoots = [schema];
|
|
294
|
+
validate(this.root, schema, new ValidationResult(), matchingSchemas, context, schemaStack, schemaRoots);
|
|
284
295
|
return matchingSchemas.schemas;
|
|
285
296
|
}
|
|
286
297
|
return [];
|
|
287
298
|
}
|
|
288
299
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
300
|
+
/*
|
|
301
|
+
* Resolves the schema draft versions for validation.
|
|
302
|
+
* - explicitDraft: the draft explicitly declared via $schema or passed as an override.
|
|
303
|
+
* Undefined when no $schema is present and no override is provided.
|
|
304
|
+
* - effectiveDraft: the draft used for keyword gating, defaulting to 2020-12.
|
|
305
|
+
* These are tracked separately so that behaviors like format assertion can
|
|
306
|
+
* distinguish "explicitly 2020-12" (annotation-only per spec) from
|
|
307
|
+
* "no $schema, defaulting to 2020-12" (asserts for backward compatibility).
|
|
308
|
+
*/
|
|
309
|
+
function resolveDrafts(schema, schemaDraftOverride) {
|
|
310
|
+
const explicitDraft = schemaDraftOverride ?? (schema.$schema ? getSchemaDraftFromId(schema.$schema) : undefined);
|
|
311
|
+
const effectiveDraft = explicitDraft ?? SchemaDraft.v2020_12;
|
|
312
|
+
return { explicitDraft, effectiveDraft };
|
|
295
313
|
}
|
|
296
|
-
|
|
314
|
+
// Keywords introduced in 2019-09 (not available in draft-07 and earlier)
|
|
315
|
+
const keywords201909 = new Set([
|
|
316
|
+
'dependentRequired', 'dependentSchemas',
|
|
317
|
+
'unevaluatedProperties', 'unevaluatedItems',
|
|
318
|
+
'minContains', 'maxContains'
|
|
319
|
+
]);
|
|
320
|
+
function validate(n, schema, validationResult, matchingSchemas, context, schemaStack, schemaRoots) {
|
|
297
321
|
if (!n || !matchingSchemas.include(n)) {
|
|
298
322
|
return;
|
|
299
323
|
}
|
|
300
324
|
if (n.type === 'property') {
|
|
301
|
-
return validate(n.valueNode, schema, validationResult, matchingSchemas, context);
|
|
325
|
+
return validate(n.valueNode, schema, validationResult, matchingSchemas, context, schemaStack, schemaRoots);
|
|
302
326
|
}
|
|
303
327
|
const node = n;
|
|
328
|
+
if (schema.$recursiveRef) {
|
|
329
|
+
const hasRecursiveAnchor = (s) => s.$recursiveAnchor === true;
|
|
330
|
+
const isSchemaRoot = (s) => s.$id || s.id || s.$originalId;
|
|
331
|
+
// Find nearest schema resource root
|
|
332
|
+
const currentResourceRoot = schemaStack.slice().reverse().find(isSchemaRoot);
|
|
333
|
+
// If current resource has $recursiveAnchor, find first $recursiveAnchor in stack
|
|
334
|
+
// Otherwise use current resource root or fall back to document root
|
|
335
|
+
const targetSchema = (currentResourceRoot && hasRecursiveAnchor(currentResourceRoot))
|
|
336
|
+
? schemaStack.find(hasRecursiveAnchor)
|
|
337
|
+
: currentResourceRoot ?? schemaRoots[0];
|
|
338
|
+
// Validate against the target schema (avoiding infinite loop).
|
|
339
|
+
// Fall through afterwards so sibling keywords (e.g. unevaluatedProperties)
|
|
340
|
+
// are still evaluated against this node, accumulating processedProperties.
|
|
341
|
+
if (targetSchema && targetSchema !== schema) {
|
|
342
|
+
validate(node, targetSchema, validationResult, matchingSchemas, context, schemaStack, schemaRoots);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
// Track schema document roots (schemas with $id or $originalId) if not already the root
|
|
346
|
+
const isNewRoot = (schema.$id || schema.id || schema.$originalId) && !schemaRoots.includes(schema);
|
|
347
|
+
if (isNewRoot) {
|
|
348
|
+
schemaRoots.push(schema);
|
|
349
|
+
}
|
|
350
|
+
// Push current schema to stack for $recursiveRef resolution
|
|
351
|
+
schemaStack.push(schema);
|
|
352
|
+
// 2020-12 $dynamicRef. The initial (static) target and the referenced plain-name
|
|
353
|
+
// fragment were recorded during schema resolution in $dynamicRefInfo (target and
|
|
354
|
+
// name). "Bookending": dynamic resolution applies only when that
|
|
355
|
+
// initial target is itself a $dynamicAnchor of the referenced name; then the
|
|
356
|
+
// reference resolves to the outermost matching $dynamicAnchor currently in the
|
|
357
|
+
// dynamic scope (schemaRoots, ordered outermost-first). Otherwise it behaves
|
|
358
|
+
// like a plain $ref to the initial target. This runs after the schemaRoots push
|
|
359
|
+
// so the resource that contains the $dynamicRef participates in its own
|
|
360
|
+
// dynamic-scope resolution.
|
|
361
|
+
const dynamicRefInfo = schema.$dynamicRefInfo;
|
|
362
|
+
const dynamicRefTarget = dynamicRefInfo?.target;
|
|
363
|
+
if (dynamicRefTarget !== undefined) {
|
|
364
|
+
let targetSchema = dynamicRefTarget;
|
|
365
|
+
const dynamicName = dynamicRefInfo?.name;
|
|
366
|
+
if (dynamicName !== undefined && dynamicRefTarget.$dynamicAnchor === dynamicName) {
|
|
367
|
+
for (const root of schemaRoots) {
|
|
368
|
+
const candidate = root.$anchorMaps?.dynamic.get(dynamicName);
|
|
369
|
+
if (candidate) {
|
|
370
|
+
targetSchema = candidate;
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
// Validate the instance against the referenced schema, then fall through so
|
|
376
|
+
// that any sibling keywords on this same node are validated too: per 2020-12
|
|
377
|
+
// $dynamicRef is an applicator that applies alongside its siblings (like $ref),
|
|
378
|
+
// not a redirect that replaces them. The shared cleanup below pops the stack.
|
|
379
|
+
if (targetSchema && targetSchema !== schema) {
|
|
380
|
+
validate(node, targetSchema, validationResult, matchingSchemas, context, schemaStack, schemaRoots);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
const enabled = (keyword) => {
|
|
384
|
+
// Draft-based keyword gating: keywords only exist in certain drafts.
|
|
385
|
+
// 'dependencies' was replaced by dependentRequired/dependentSchemas in 2019-09
|
|
386
|
+
if (keyword === 'dependencies') {
|
|
387
|
+
return context.schemaDraft <= SchemaDraft.v7;
|
|
388
|
+
}
|
|
389
|
+
// Keywords introduced in 2019-09 (not available in draft-07 and earlier)
|
|
390
|
+
if (keywords201909.has(keyword)) {
|
|
391
|
+
return context.schemaDraft >= SchemaDraft.v2019_09;
|
|
392
|
+
}
|
|
393
|
+
// 'prefixItems' was introduced in 2020-12
|
|
394
|
+
if (keyword === 'prefixItems') {
|
|
395
|
+
return context.schemaDraft >= SchemaDraft.v2020_12;
|
|
396
|
+
}
|
|
397
|
+
// Vocabulary-based filtering only applies for 2019-09+ (vocabulary is not a concept in older drafts)
|
|
398
|
+
if (context.schemaDraft >= SchemaDraft.v2019_09 && context.activeVocabularies) {
|
|
399
|
+
return isKeywordEnabled(keyword, context.activeVocabularies);
|
|
400
|
+
}
|
|
401
|
+
// No vocabulary info or pre-2019-09: enable all draft-appropriate keywords
|
|
402
|
+
return true;
|
|
403
|
+
};
|
|
304
404
|
_validateNode();
|
|
305
405
|
switch (node.type) {
|
|
306
406
|
case 'object':
|
|
@@ -317,11 +417,17 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
317
417
|
break;
|
|
318
418
|
}
|
|
319
419
|
matchingSchemas.add({ node: node, schema: schema });
|
|
420
|
+
// Pop schema from stack when done
|
|
421
|
+
schemaStack.pop();
|
|
422
|
+
// Pop schema root if we pushed one
|
|
423
|
+
if (isNewRoot) {
|
|
424
|
+
schemaRoots.pop();
|
|
425
|
+
}
|
|
320
426
|
function _validateNode() {
|
|
321
427
|
function matchesType(type) {
|
|
322
428
|
return node.type === type || (type === 'integer' && node.type === 'number' && node.isInteger);
|
|
323
429
|
}
|
|
324
|
-
if (Array.isArray(schema.type)) {
|
|
430
|
+
if (Array.isArray(schema.type) && enabled('type')) {
|
|
325
431
|
if (!schema.type.some(matchesType)) {
|
|
326
432
|
validationResult.problems.push({
|
|
327
433
|
location: { offset: node.offset, length: node.length },
|
|
@@ -329,7 +435,7 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
329
435
|
});
|
|
330
436
|
}
|
|
331
437
|
}
|
|
332
|
-
else if (schema.type) {
|
|
438
|
+
else if (schema.type && !Array.isArray(schema.type) && enabled('type')) {
|
|
333
439
|
if (!matchesType(schema.type)) {
|
|
334
440
|
validationResult.problems.push({
|
|
335
441
|
location: { offset: node.offset, length: node.length },
|
|
@@ -337,20 +443,20 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
337
443
|
});
|
|
338
444
|
}
|
|
339
445
|
}
|
|
340
|
-
if (Array.isArray(schema.allOf)) {
|
|
446
|
+
if (Array.isArray(schema.allOf) && enabled('allOf')) {
|
|
341
447
|
for (const subSchemaRef of schema.allOf) {
|
|
342
448
|
const subValidationResult = new ValidationResult();
|
|
343
449
|
const subMatchingSchemas = matchingSchemas.newSub();
|
|
344
|
-
validate(node, asSchema(subSchemaRef), subValidationResult, subMatchingSchemas, context);
|
|
450
|
+
validate(node, asSchema(subSchemaRef), subValidationResult, subMatchingSchemas, context, schemaStack, schemaRoots);
|
|
345
451
|
validationResult.merge(subValidationResult);
|
|
346
452
|
matchingSchemas.merge(subMatchingSchemas);
|
|
347
453
|
}
|
|
348
454
|
}
|
|
349
455
|
const notSchema = asSchema(schema.not);
|
|
350
|
-
if (notSchema) {
|
|
456
|
+
if (notSchema && enabled('not')) {
|
|
351
457
|
const subValidationResult = new ValidationResult();
|
|
352
458
|
const subMatchingSchemas = matchingSchemas.newSub();
|
|
353
|
-
validate(node, notSchema, subValidationResult, subMatchingSchemas, context);
|
|
459
|
+
validate(node, notSchema, subValidationResult, subMatchingSchemas, context, schemaStack, schemaRoots);
|
|
354
460
|
if (!subValidationResult.hasProblems()) {
|
|
355
461
|
validationResult.problems.push({
|
|
356
462
|
location: { offset: node.offset, length: node.length },
|
|
@@ -371,7 +477,7 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
371
477
|
const subSchema = asSchema(subSchemaRef);
|
|
372
478
|
const subValidationResult = new ValidationResult();
|
|
373
479
|
const subMatchingSchemas = matchingSchemas.newSub();
|
|
374
|
-
validate(node, subSchema, subValidationResult, subMatchingSchemas, context);
|
|
480
|
+
validate(node, subSchema, subValidationResult, subMatchingSchemas, context, schemaStack, schemaRoots);
|
|
375
481
|
if (!subValidationResult.hasProblems()) {
|
|
376
482
|
matches.push(subSchema);
|
|
377
483
|
}
|
|
@@ -413,16 +519,16 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
413
519
|
}
|
|
414
520
|
return matches.length;
|
|
415
521
|
};
|
|
416
|
-
if (Array.isArray(schema.anyOf)) {
|
|
522
|
+
if (Array.isArray(schema.anyOf) && enabled('anyOf')) {
|
|
417
523
|
testAlternatives(schema.anyOf, false);
|
|
418
524
|
}
|
|
419
|
-
if (Array.isArray(schema.oneOf)) {
|
|
525
|
+
if (Array.isArray(schema.oneOf) && enabled('oneOf')) {
|
|
420
526
|
testAlternatives(schema.oneOf, true);
|
|
421
527
|
}
|
|
422
528
|
const testBranch = (schema) => {
|
|
423
529
|
const subValidationResult = new ValidationResult();
|
|
424
530
|
const subMatchingSchemas = matchingSchemas.newSub();
|
|
425
|
-
validate(node, asSchema(schema), subValidationResult, subMatchingSchemas, context);
|
|
531
|
+
validate(node, asSchema(schema), subValidationResult, subMatchingSchemas, context, schemaStack, schemaRoots);
|
|
426
532
|
validationResult.merge(subValidationResult);
|
|
427
533
|
matchingSchemas.merge(subMatchingSchemas);
|
|
428
534
|
};
|
|
@@ -430,10 +536,12 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
430
536
|
const subSchema = asSchema(ifSchema);
|
|
431
537
|
const subValidationResult = new ValidationResult();
|
|
432
538
|
const subMatchingSchemas = matchingSchemas.newSub();
|
|
433
|
-
validate(node, subSchema, subValidationResult, subMatchingSchemas, context);
|
|
539
|
+
validate(node, subSchema, subValidationResult, subMatchingSchemas, context, schemaStack, schemaRoots);
|
|
434
540
|
matchingSchemas.merge(subMatchingSchemas);
|
|
435
|
-
|
|
541
|
+
// if passed: merge properties from if;
|
|
542
|
+
// otherwise don't merge properties from if, only from else
|
|
436
543
|
if (!subValidationResult.hasProblems()) {
|
|
544
|
+
validationResult.mergeProcessedProperties(subValidationResult);
|
|
437
545
|
if (thenSchema) {
|
|
438
546
|
testBranch(thenSchema);
|
|
439
547
|
}
|
|
@@ -443,10 +551,10 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
443
551
|
}
|
|
444
552
|
};
|
|
445
553
|
const ifSchema = asSchema(schema.if);
|
|
446
|
-
if (ifSchema) {
|
|
554
|
+
if (ifSchema && enabled('if')) {
|
|
447
555
|
testCondition(ifSchema, asSchema(schema.then), asSchema(schema.else));
|
|
448
556
|
}
|
|
449
|
-
if (Array.isArray(schema.enum)) {
|
|
557
|
+
if (Array.isArray(schema.enum) && enabled('enum')) {
|
|
450
558
|
const val = getNodeValue(node);
|
|
451
559
|
let enumValueMatch = false;
|
|
452
560
|
for (const e of schema.enum) {
|
|
@@ -465,7 +573,7 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
465
573
|
});
|
|
466
574
|
}
|
|
467
575
|
}
|
|
468
|
-
if (isDefined(schema.const)) {
|
|
576
|
+
if (isDefined(schema.const) && enabled('const')) {
|
|
469
577
|
const val = getNodeValue(node);
|
|
470
578
|
if (!equals(val, schema.const)) {
|
|
471
579
|
validationResult.problems.push({
|
|
@@ -514,6 +622,18 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
514
622
|
}
|
|
515
623
|
valueMap.get(schema.const).push(i);
|
|
516
624
|
}
|
|
625
|
+
else if (schema.enum && Array.isArray(schema.enum)) {
|
|
626
|
+
for (const enumValue of schema.enum) {
|
|
627
|
+
if (!constMap.has(key)) {
|
|
628
|
+
constMap.set(key, new Map());
|
|
629
|
+
}
|
|
630
|
+
const valueMap = constMap.get(key);
|
|
631
|
+
if (!valueMap.has(enumValue)) {
|
|
632
|
+
valueMap.set(enumValue, []);
|
|
633
|
+
}
|
|
634
|
+
valueMap.get(enumValue).push(i);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
517
637
|
});
|
|
518
638
|
}
|
|
519
639
|
return constMap;
|
|
@@ -566,7 +686,7 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
566
686
|
};
|
|
567
687
|
}
|
|
568
688
|
;
|
|
569
|
-
if (isNumber(schema.multipleOf)) {
|
|
689
|
+
if (isNumber(schema.multipleOf) && enabled('multipleOf')) {
|
|
570
690
|
let remainder = -1;
|
|
571
691
|
if (Number.isInteger(schema.multipleOf)) {
|
|
572
692
|
remainder = val % schema.multipleOf;
|
|
@@ -608,28 +728,28 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
608
728
|
return undefined;
|
|
609
729
|
}
|
|
610
730
|
const exclusiveMinimum = getExclusiveLimit(schema.minimum, schema.exclusiveMinimum);
|
|
611
|
-
if (isNumber(exclusiveMinimum) && val <= exclusiveMinimum) {
|
|
731
|
+
if (isNumber(exclusiveMinimum) && val <= exclusiveMinimum && enabled('exclusiveMinimum')) {
|
|
612
732
|
validationResult.problems.push({
|
|
613
733
|
location: { offset: node.offset, length: node.length },
|
|
614
734
|
message: l10n.t('Value is below the exclusive minimum of {0}.', exclusiveMinimum)
|
|
615
735
|
});
|
|
616
736
|
}
|
|
617
737
|
const exclusiveMaximum = getExclusiveLimit(schema.maximum, schema.exclusiveMaximum);
|
|
618
|
-
if (isNumber(exclusiveMaximum) && val >= exclusiveMaximum) {
|
|
738
|
+
if (isNumber(exclusiveMaximum) && val >= exclusiveMaximum && enabled('exclusiveMaximum')) {
|
|
619
739
|
validationResult.problems.push({
|
|
620
740
|
location: { offset: node.offset, length: node.length },
|
|
621
741
|
message: l10n.t('Value is above the exclusive maximum of {0}.', exclusiveMaximum)
|
|
622
742
|
});
|
|
623
743
|
}
|
|
624
744
|
const minimum = getLimit(schema.minimum, schema.exclusiveMinimum);
|
|
625
|
-
if (isNumber(minimum) && val < minimum) {
|
|
745
|
+
if (isNumber(minimum) && val < minimum && enabled('minimum')) {
|
|
626
746
|
validationResult.problems.push({
|
|
627
747
|
location: { offset: node.offset, length: node.length },
|
|
628
748
|
message: l10n.t('Value is below the minimum of {0}.', minimum)
|
|
629
749
|
});
|
|
630
750
|
}
|
|
631
751
|
const maximum = getLimit(schema.maximum, schema.exclusiveMaximum);
|
|
632
|
-
if (isNumber(maximum) && val > maximum) {
|
|
752
|
+
if (isNumber(maximum) && val > maximum && enabled('maximum')) {
|
|
633
753
|
validationResult.problems.push({
|
|
634
754
|
location: { offset: node.offset, length: node.length },
|
|
635
755
|
message: l10n.t('Value is above the maximum of {0}.', maximum)
|
|
@@ -637,19 +757,19 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
637
757
|
}
|
|
638
758
|
}
|
|
639
759
|
function _validateStringNode(node) {
|
|
640
|
-
if (isNumber(schema.minLength) && stringLength(node.value) < schema.minLength) {
|
|
760
|
+
if (isNumber(schema.minLength) && stringLength(node.value) < schema.minLength && enabled('minLength')) {
|
|
641
761
|
validationResult.problems.push({
|
|
642
762
|
location: { offset: node.offset, length: node.length },
|
|
643
763
|
message: l10n.t('String is shorter than the minimum length of {0}.', schema.minLength)
|
|
644
764
|
});
|
|
645
765
|
}
|
|
646
|
-
if (isNumber(schema.maxLength) && stringLength(node.value) > schema.maxLength) {
|
|
766
|
+
if (isNumber(schema.maxLength) && stringLength(node.value) > schema.maxLength && enabled('maxLength')) {
|
|
647
767
|
validationResult.problems.push({
|
|
648
768
|
location: { offset: node.offset, length: node.length },
|
|
649
769
|
message: l10n.t('String is longer than the maximum length of {0}.', schema.maxLength)
|
|
650
770
|
});
|
|
651
771
|
}
|
|
652
|
-
if (isString(schema.pattern)) {
|
|
772
|
+
if (isString(schema.pattern) && enabled('pattern')) {
|
|
653
773
|
const regex = extendedRegExp(schema.pattern);
|
|
654
774
|
if (regex && !(regex.test(node.value))) {
|
|
655
775
|
validationResult.problems.push({
|
|
@@ -658,7 +778,8 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
658
778
|
});
|
|
659
779
|
}
|
|
660
780
|
}
|
|
661
|
-
if (
|
|
781
|
+
// Only validate format if format-assertion vocabulary is active (not annotation-only)
|
|
782
|
+
if (schema.format && enabled('format') && isFormatAssertionEnabled(context.activeVocabularies, context.explicitSchemaDraft)) {
|
|
662
783
|
switch (schema.format) {
|
|
663
784
|
case 'uri':
|
|
664
785
|
case 'uri-reference':
|
|
@@ -688,6 +809,8 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
688
809
|
case 'date-time':
|
|
689
810
|
case 'date':
|
|
690
811
|
case 'time':
|
|
812
|
+
case 'duration':
|
|
813
|
+
case 'uuid':
|
|
691
814
|
case 'email':
|
|
692
815
|
case 'hostname':
|
|
693
816
|
case 'ipv4':
|
|
@@ -723,7 +846,7 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
723
846
|
const itemValidationResult = new ValidationResult();
|
|
724
847
|
const item = node.items[index];
|
|
725
848
|
if (item) {
|
|
726
|
-
validate(item, subSchema, itemValidationResult, matchingSchemas, context);
|
|
849
|
+
validate(item, subSchema, itemValidationResult, matchingSchemas, context, schemaStack, schemaRoots);
|
|
727
850
|
validationResult.mergePropertyMatch(itemValidationResult);
|
|
728
851
|
}
|
|
729
852
|
validationResult.processedProperties.add(String(index));
|
|
@@ -745,19 +868,19 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
745
868
|
else {
|
|
746
869
|
for (; index < node.items.length; index++) {
|
|
747
870
|
const itemValidationResult = new ValidationResult();
|
|
748
|
-
validate(node.items[index], additionalItemSchema, itemValidationResult, matchingSchemas, context);
|
|
871
|
+
validate(node.items[index], additionalItemSchema, itemValidationResult, matchingSchemas, context, schemaStack, schemaRoots);
|
|
749
872
|
validationResult.mergePropertyMatch(itemValidationResult);
|
|
750
873
|
validationResult.processedProperties.add(String(index));
|
|
751
874
|
}
|
|
752
875
|
}
|
|
753
876
|
}
|
|
754
877
|
const containsSchema = asSchema(schema.contains);
|
|
755
|
-
if (containsSchema) {
|
|
878
|
+
if (containsSchema && enabled('contains')) {
|
|
756
879
|
let containsCount = 0;
|
|
757
880
|
for (let index = 0; index < node.items.length; index++) {
|
|
758
881
|
const item = node.items[index];
|
|
759
882
|
const itemValidationResult = new ValidationResult();
|
|
760
|
-
validate(item, containsSchema, itemValidationResult, NoOpSchemaCollector.instance, context);
|
|
883
|
+
validate(item, containsSchema, itemValidationResult, NoOpSchemaCollector.instance, context, schemaStack, schemaRoots);
|
|
761
884
|
if (!itemValidationResult.hasProblems()) {
|
|
762
885
|
containsCount++;
|
|
763
886
|
if (context.schemaDraft >= SchemaDraft.v2020_12) {
|
|
@@ -771,13 +894,13 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
771
894
|
message: schema.errorMessage || l10n.t('Array does not contain required item.')
|
|
772
895
|
});
|
|
773
896
|
}
|
|
774
|
-
if (isNumber(schema.minContains) && containsCount < schema.minContains) {
|
|
897
|
+
if (isNumber(schema.minContains) && containsCount < schema.minContains && enabled('minContains')) {
|
|
775
898
|
validationResult.problems.push({
|
|
776
899
|
location: { offset: node.offset, length: node.length },
|
|
777
900
|
message: schema.errorMessage || l10n.t('Array has too few items that match the contains contraint. Expected {0} or more.', schema.minContains)
|
|
778
901
|
});
|
|
779
902
|
}
|
|
780
|
-
if (isNumber(schema.maxContains) && containsCount > schema.maxContains) {
|
|
903
|
+
if (isNumber(schema.maxContains) && containsCount > schema.maxContains && enabled('maxContains')) {
|
|
781
904
|
validationResult.problems.push({
|
|
782
905
|
location: { offset: node.offset, length: node.length },
|
|
783
906
|
message: schema.errorMessage || l10n.t('Array has too many items that match the contains contraint. Expected {0} or less.', schema.maxContains)
|
|
@@ -785,7 +908,7 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
785
908
|
}
|
|
786
909
|
}
|
|
787
910
|
const unevaluatedItems = schema.unevaluatedItems;
|
|
788
|
-
if (unevaluatedItems !== undefined) {
|
|
911
|
+
if (unevaluatedItems !== undefined && enabled('unevaluatedItems')) {
|
|
789
912
|
for (let i = 0; i < node.items.length; i++) {
|
|
790
913
|
if (!validationResult.processedProperties.has(String(i))) {
|
|
791
914
|
if (unevaluatedItems === false) {
|
|
@@ -796,7 +919,7 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
796
919
|
}
|
|
797
920
|
else {
|
|
798
921
|
const itemValidationResult = new ValidationResult();
|
|
799
|
-
validate(node.items[i], schema.unevaluatedItems, itemValidationResult, matchingSchemas, context);
|
|
922
|
+
validate(node.items[i], schema.unevaluatedItems, itemValidationResult, matchingSchemas, context, schemaStack, schemaRoots);
|
|
800
923
|
validationResult.mergePropertyMatch(itemValidationResult);
|
|
801
924
|
}
|
|
802
925
|
}
|
|
@@ -804,19 +927,19 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
804
927
|
validationResult.propertiesValueMatches++;
|
|
805
928
|
}
|
|
806
929
|
}
|
|
807
|
-
if (isNumber(schema.minItems) && node.items.length < schema.minItems) {
|
|
930
|
+
if (isNumber(schema.minItems) && node.items.length < schema.minItems && enabled('minItems')) {
|
|
808
931
|
validationResult.problems.push({
|
|
809
932
|
location: { offset: node.offset, length: node.length },
|
|
810
933
|
message: l10n.t('Array has too few items. Expected {0} or more.', schema.minItems)
|
|
811
934
|
});
|
|
812
935
|
}
|
|
813
|
-
if (isNumber(schema.maxItems) && node.items.length > schema.maxItems) {
|
|
936
|
+
if (isNumber(schema.maxItems) && node.items.length > schema.maxItems && enabled('maxItems')) {
|
|
814
937
|
validationResult.problems.push({
|
|
815
938
|
location: { offset: node.offset, length: node.length },
|
|
816
939
|
message: l10n.t('Array has too many items. Expected {0} or fewer.', schema.maxItems)
|
|
817
940
|
});
|
|
818
941
|
}
|
|
819
|
-
if (schema.uniqueItems === true) {
|
|
942
|
+
if (schema.uniqueItems === true && enabled('uniqueItems')) {
|
|
820
943
|
const values = getNodeValue(node);
|
|
821
944
|
function hasDuplicates() {
|
|
822
945
|
for (let i = 0; i < values.length - 1; i++) {
|
|
@@ -845,13 +968,11 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
845
968
|
seenKeys[key] = propertyNode.valueNode;
|
|
846
969
|
unprocessedProperties.add(key);
|
|
847
970
|
}
|
|
848
|
-
if (Array.isArray(schema.required)) {
|
|
971
|
+
if (Array.isArray(schema.required) && enabled('required')) {
|
|
849
972
|
for (const propertyName of schema.required) {
|
|
850
973
|
if (!seenKeys[propertyName]) {
|
|
851
|
-
const keyNode = node.parent && node.parent.type === 'property' && node.parent.keyNode;
|
|
852
|
-
const location = keyNode ? { offset: keyNode.offset, length: keyNode.length } : { offset: node.offset, length: 1 };
|
|
853
974
|
validationResult.problems.push({
|
|
854
|
-
location:
|
|
975
|
+
location: { offset: node.offset, length: node.length },
|
|
855
976
|
message: l10n.t('Missing property "{0}".', propertyName)
|
|
856
977
|
});
|
|
857
978
|
}
|
|
@@ -861,7 +982,7 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
861
982
|
unprocessedProperties.delete(prop);
|
|
862
983
|
validationResult.processedProperties.add(prop);
|
|
863
984
|
};
|
|
864
|
-
if (schema.properties) {
|
|
985
|
+
if (schema.properties && enabled('properties')) {
|
|
865
986
|
for (const propertyName of Object.keys(schema.properties)) {
|
|
866
987
|
propertyProcessed(propertyName);
|
|
867
988
|
const propertySchema = schema.properties[propertyName];
|
|
@@ -882,20 +1003,28 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
882
1003
|
}
|
|
883
1004
|
else {
|
|
884
1005
|
const propertyValidationResult = new ValidationResult();
|
|
885
|
-
validate(child, propertySchema, propertyValidationResult, matchingSchemas, context);
|
|
1006
|
+
validate(child, propertySchema, propertyValidationResult, matchingSchemas, context, schemaStack, schemaRoots);
|
|
886
1007
|
validationResult.mergePropertyMatch(propertyValidationResult);
|
|
887
1008
|
}
|
|
888
1009
|
}
|
|
889
1010
|
}
|
|
890
1011
|
}
|
|
891
|
-
if (schema.patternProperties) {
|
|
1012
|
+
if (schema.patternProperties && enabled('patternProperties')) {
|
|
1013
|
+
// Collect all properties matched by any pattern first
|
|
1014
|
+
// A property must be validated against all patterns it matches
|
|
1015
|
+
// Properties in `properties` can also match `patternProperties`, check all keys
|
|
1016
|
+
const allPropertyNames = Object.keys(seenKeys);
|
|
1017
|
+
const patternPropertyMatches = new Set();
|
|
892
1018
|
for (const propertyPattern of Object.keys(schema.patternProperties)) {
|
|
893
1019
|
const regex = extendedRegExp(propertyPattern);
|
|
894
1020
|
if (regex) {
|
|
895
|
-
const
|
|
896
|
-
for (const propertyName of unprocessedProperties) {
|
|
1021
|
+
for (const propertyName of allPropertyNames) {
|
|
897
1022
|
if (regex.test(propertyName)) {
|
|
898
|
-
|
|
1023
|
+
// Only mark as pattern match if not already in `properties`
|
|
1024
|
+
// for additionalProperties tracking
|
|
1025
|
+
if (unprocessedProperties.has(propertyName)) {
|
|
1026
|
+
patternPropertyMatches.add(propertyName);
|
|
1027
|
+
}
|
|
899
1028
|
const child = seenKeys[propertyName];
|
|
900
1029
|
if (child) {
|
|
901
1030
|
const propertySchema = schema.patternProperties[propertyPattern];
|
|
@@ -914,18 +1043,19 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
914
1043
|
}
|
|
915
1044
|
else {
|
|
916
1045
|
const propertyValidationResult = new ValidationResult();
|
|
917
|
-
validate(child, propertySchema, propertyValidationResult, matchingSchemas, context);
|
|
1046
|
+
validate(child, propertySchema, propertyValidationResult, matchingSchemas, context, schemaStack, schemaRoots);
|
|
918
1047
|
validationResult.mergePropertyMatch(propertyValidationResult);
|
|
919
1048
|
}
|
|
920
1049
|
}
|
|
921
1050
|
}
|
|
922
1051
|
}
|
|
923
|
-
processed.forEach(propertyProcessed);
|
|
924
1052
|
}
|
|
925
1053
|
}
|
|
1054
|
+
// Mark all matched properties as processed after all patterns have been checked
|
|
1055
|
+
patternPropertyMatches.forEach(propertyProcessed);
|
|
926
1056
|
}
|
|
927
1057
|
const additionalProperties = schema.additionalProperties;
|
|
928
|
-
if (additionalProperties !== undefined) {
|
|
1058
|
+
if (additionalProperties !== undefined && enabled('additionalProperties')) {
|
|
929
1059
|
for (const propertyName of unprocessedProperties) {
|
|
930
1060
|
propertyProcessed(propertyName);
|
|
931
1061
|
const child = seenKeys[propertyName];
|
|
@@ -939,14 +1069,32 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
939
1069
|
}
|
|
940
1070
|
else if (additionalProperties !== true) {
|
|
941
1071
|
const propertyValidationResult = new ValidationResult();
|
|
942
|
-
validate(child, additionalProperties, propertyValidationResult, matchingSchemas, context);
|
|
1072
|
+
validate(child, additionalProperties, propertyValidationResult, matchingSchemas, context, schemaStack, schemaRoots);
|
|
943
1073
|
validationResult.mergePropertyMatch(propertyValidationResult);
|
|
944
1074
|
}
|
|
945
1075
|
}
|
|
946
1076
|
}
|
|
947
1077
|
}
|
|
1078
|
+
if (schema.dependentRequired && enabled('dependentRequired')) {
|
|
1079
|
+
for (const key in schema.dependentRequired) {
|
|
1080
|
+
const prop = seenKeys[key];
|
|
1081
|
+
const propertyDeps = schema.dependentRequired[key];
|
|
1082
|
+
if (prop && Array.isArray(propertyDeps)) {
|
|
1083
|
+
_validatePropertyDependencies(key, propertyDeps);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
if (schema.dependentSchemas && enabled('dependentSchemas')) {
|
|
1088
|
+
for (const key in schema.dependentSchemas) {
|
|
1089
|
+
const prop = seenKeys[key];
|
|
1090
|
+
const propertyDeps = schema.dependentSchemas[key];
|
|
1091
|
+
if (prop) {
|
|
1092
|
+
_validatePropertyDependencies(key, propertyDeps);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
948
1096
|
const unevaluatedProperties = schema.unevaluatedProperties;
|
|
949
|
-
if (unevaluatedProperties !== undefined) {
|
|
1097
|
+
if (unevaluatedProperties !== undefined && enabled('unevaluatedProperties')) {
|
|
950
1098
|
const processed = [];
|
|
951
1099
|
for (const propertyName of unprocessedProperties) {
|
|
952
1100
|
if (!validationResult.processedProperties.has(propertyName)) {
|
|
@@ -962,7 +1110,7 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
962
1110
|
}
|
|
963
1111
|
else if (unevaluatedProperties !== true) {
|
|
964
1112
|
const propertyValidationResult = new ValidationResult();
|
|
965
|
-
validate(child, unevaluatedProperties, propertyValidationResult, matchingSchemas, context);
|
|
1113
|
+
validate(child, unevaluatedProperties, propertyValidationResult, matchingSchemas, context, schemaStack, schemaRoots);
|
|
966
1114
|
validationResult.mergePropertyMatch(propertyValidationResult);
|
|
967
1115
|
}
|
|
968
1116
|
}
|
|
@@ -970,7 +1118,7 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
970
1118
|
}
|
|
971
1119
|
processed.forEach(propertyProcessed);
|
|
972
1120
|
}
|
|
973
|
-
if (isNumber(schema.maxProperties)) {
|
|
1121
|
+
if (isNumber(schema.maxProperties) && enabled('maxProperties')) {
|
|
974
1122
|
if (node.properties.length > schema.maxProperties) {
|
|
975
1123
|
validationResult.problems.push({
|
|
976
1124
|
location: { offset: node.offset, length: node.length },
|
|
@@ -978,7 +1126,7 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
978
1126
|
});
|
|
979
1127
|
}
|
|
980
1128
|
}
|
|
981
|
-
if (isNumber(schema.minProperties)) {
|
|
1129
|
+
if (isNumber(schema.minProperties) && enabled('minProperties')) {
|
|
982
1130
|
if (node.properties.length < schema.minProperties) {
|
|
983
1131
|
validationResult.problems.push({
|
|
984
1132
|
location: { offset: node.offset, length: node.length },
|
|
@@ -986,25 +1134,7 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
986
1134
|
});
|
|
987
1135
|
}
|
|
988
1136
|
}
|
|
989
|
-
if (schema.
|
|
990
|
-
for (const key in schema.dependentRequired) {
|
|
991
|
-
const prop = seenKeys[key];
|
|
992
|
-
const propertyDeps = schema.dependentRequired[key];
|
|
993
|
-
if (prop && Array.isArray(propertyDeps)) {
|
|
994
|
-
_validatePropertyDependencies(key, propertyDeps);
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
if (schema.dependentSchemas) {
|
|
999
|
-
for (const key in schema.dependentSchemas) {
|
|
1000
|
-
const prop = seenKeys[key];
|
|
1001
|
-
const propertyDeps = schema.dependentSchemas[key];
|
|
1002
|
-
if (prop && isObject(propertyDeps)) {
|
|
1003
|
-
_validatePropertyDependencies(key, propertyDeps);
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
if (schema.dependencies) {
|
|
1137
|
+
if (schema.dependencies && enabled('dependencies')) {
|
|
1008
1138
|
for (const key in schema.dependencies) {
|
|
1009
1139
|
const prop = seenKeys[key];
|
|
1010
1140
|
if (prop) {
|
|
@@ -1013,11 +1143,11 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
1013
1143
|
}
|
|
1014
1144
|
}
|
|
1015
1145
|
const propertyNames = asSchema(schema.propertyNames);
|
|
1016
|
-
if (propertyNames) {
|
|
1146
|
+
if (propertyNames && enabled('propertyNames')) {
|
|
1017
1147
|
for (const f of node.properties) {
|
|
1018
1148
|
const key = f.keyNode;
|
|
1019
1149
|
if (key) {
|
|
1020
|
-
validate(key, propertyNames, validationResult, matchingSchemas, context);
|
|
1150
|
+
validate(key, propertyNames, validationResult, matchingSchemas, context, schemaStack, schemaRoots);
|
|
1021
1151
|
}
|
|
1022
1152
|
}
|
|
1023
1153
|
}
|
|
@@ -1039,8 +1169,9 @@ function validate(n, schema, validationResult, matchingSchemas, context) {
|
|
|
1039
1169
|
const propertySchema = asSchema(propertyDep);
|
|
1040
1170
|
if (propertySchema) {
|
|
1041
1171
|
const propertyValidationResult = new ValidationResult();
|
|
1042
|
-
validate(node, propertySchema, propertyValidationResult, matchingSchemas, context);
|
|
1172
|
+
validate(node, propertySchema, propertyValidationResult, matchingSchemas, context, schemaStack, schemaRoots);
|
|
1043
1173
|
validationResult.mergePropertyMatch(propertyValidationResult);
|
|
1174
|
+
validationResult.mergeProcessedProperties(propertyValidationResult);
|
|
1044
1175
|
}
|
|
1045
1176
|
}
|
|
1046
1177
|
}
|