vscode-json-languageservice 4.2.1 → 5.0.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 (49) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/SECURITY.md +41 -0
  3. package/lib/esm/jsonContributions.d.ts +17 -17
  4. package/lib/esm/jsonContributions.js +1 -1
  5. package/lib/esm/jsonLanguageService.d.ts +29 -29
  6. package/lib/esm/jsonLanguageService.js +66 -66
  7. package/lib/esm/jsonLanguageTypes.d.ts +279 -278
  8. package/lib/esm/jsonLanguageTypes.js +46 -45
  9. package/lib/esm/jsonSchema.d.ts +89 -70
  10. package/lib/esm/jsonSchema.js +1 -1
  11. package/lib/esm/parser/jsonParser.js +1214 -1218
  12. package/lib/esm/services/configuration.js +528 -528
  13. package/lib/esm/services/jsonCompletion.js +918 -934
  14. package/lib/esm/services/jsonDocumentSymbols.js +267 -278
  15. package/lib/esm/services/jsonFolding.js +120 -121
  16. package/lib/esm/services/jsonHover.js +109 -112
  17. package/lib/esm/services/jsonLinks.js +72 -73
  18. package/lib/esm/services/jsonSchemaService.js +586 -605
  19. package/lib/esm/services/jsonSelectionRanges.js +61 -61
  20. package/lib/esm/services/jsonValidation.js +151 -149
  21. package/lib/esm/utils/colors.js +68 -69
  22. package/lib/esm/utils/glob.js +124 -124
  23. package/lib/esm/utils/json.js +42 -42
  24. package/lib/esm/utils/objects.js +68 -65
  25. package/lib/esm/utils/strings.js +64 -64
  26. package/lib/umd/jsonContributions.d.ts +17 -17
  27. package/lib/umd/jsonContributions.js +12 -12
  28. package/lib/umd/jsonLanguageService.d.ts +29 -29
  29. package/lib/umd/jsonLanguageService.js +90 -90
  30. package/lib/umd/jsonLanguageTypes.d.ts +279 -278
  31. package/lib/umd/jsonLanguageTypes.js +93 -92
  32. package/lib/umd/jsonSchema.d.ts +89 -70
  33. package/lib/umd/jsonSchema.js +12 -12
  34. package/lib/umd/parser/jsonParser.js +1243 -1237
  35. package/lib/umd/services/configuration.js +541 -541
  36. package/lib/umd/services/jsonCompletion.js +932 -947
  37. package/lib/umd/services/jsonDocumentSymbols.js +281 -291
  38. package/lib/umd/services/jsonFolding.js +134 -135
  39. package/lib/umd/services/jsonHover.js +123 -125
  40. package/lib/umd/services/jsonLinks.js +86 -87
  41. package/lib/umd/services/jsonSchemaService.js +602 -618
  42. package/lib/umd/services/jsonSelectionRanges.js +75 -75
  43. package/lib/umd/services/jsonValidation.js +165 -162
  44. package/lib/umd/utils/colors.js +84 -85
  45. package/lib/umd/utils/glob.js +138 -138
  46. package/lib/umd/utils/json.js +56 -56
  47. package/lib/umd/utils/objects.js +87 -83
  48. package/lib/umd/utils/strings.js +82 -82
  49. package/package.json +10 -10
@@ -1,1218 +1,1214 @@
1
- /*---------------------------------------------------------------------------------------------
2
- * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Licensed under the MIT License. See License.txt in the project root for license information.
4
- *--------------------------------------------------------------------------------------------*/
5
- var __extends = (this && this.__extends) || (function () {
6
- var extendStatics = function (d, b) {
7
- extendStatics = Object.setPrototypeOf ||
8
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
9
- function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
10
- return extendStatics(d, b);
11
- };
12
- return function (d, b) {
13
- if (typeof b !== "function" && b !== null)
14
- throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
15
- extendStatics(d, b);
16
- function __() { this.constructor = d; }
17
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
18
- };
19
- })();
20
- import * as Json from 'jsonc-parser';
21
- import { isNumber, equals, isBoolean, isString, isDefined } from '../utils/objects';
22
- import { extendedRegExp } from '../utils/strings';
23
- import { ErrorCode, Diagnostic, DiagnosticSeverity, Range } from '../jsonLanguageTypes';
24
- import * as nls from 'vscode-nls';
25
- var localize = nls.loadMessageBundle();
26
- var formats = {
27
- 'color-hex': { errorMessage: localize('colorHexFormatWarning', 'Invalid color format. Use #RGB, #RGBA, #RRGGBB or #RRGGBBAA.'), pattern: /^#([0-9A-Fa-f]{3,4}|([0-9A-Fa-f]{2}){3,4})$/ },
28
- 'date-time': { errorMessage: localize('dateTimeFormatWarning', '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 },
29
- 'date': { errorMessage: localize('dateFormatWarning', 'String is not a RFC3339 date.'), pattern: /^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/i },
30
- 'time': { errorMessage: localize('timeFormatWarning', '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 },
31
- 'email': { errorMessage: localize('emailFormatWarning', '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,}))$/ },
32
- 'hostname': { errorMessage: localize('hostnameFormatWarning', '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 },
33
- 'ipv4': { errorMessage: localize('ipv4FormatWarning', '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)$/ },
34
- 'ipv6': { errorMessage: localize('ipv6FormatWarning', 'String is not an IPv6 address.'), pattern: /^((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))$/i },
35
- };
36
- var ASTNodeImpl = /** @class */ (function () {
37
- function ASTNodeImpl(parent, offset, length) {
38
- if (length === void 0) { length = 0; }
39
- this.offset = offset;
40
- this.length = length;
41
- this.parent = parent;
42
- }
43
- Object.defineProperty(ASTNodeImpl.prototype, "children", {
44
- get: function () {
45
- return [];
46
- },
47
- enumerable: false,
48
- configurable: true
49
- });
50
- ASTNodeImpl.prototype.toString = function () {
51
- return 'type: ' + this.type + ' (' + this.offset + '/' + this.length + ')' + (this.parent ? ' parent: {' + this.parent.toString() + '}' : '');
52
- };
53
- return ASTNodeImpl;
54
- }());
55
- export { ASTNodeImpl };
56
- var NullASTNodeImpl = /** @class */ (function (_super) {
57
- __extends(NullASTNodeImpl, _super);
58
- function NullASTNodeImpl(parent, offset) {
59
- var _this = _super.call(this, parent, offset) || this;
60
- _this.type = 'null';
61
- _this.value = null;
62
- return _this;
63
- }
64
- return NullASTNodeImpl;
65
- }(ASTNodeImpl));
66
- export { NullASTNodeImpl };
67
- var BooleanASTNodeImpl = /** @class */ (function (_super) {
68
- __extends(BooleanASTNodeImpl, _super);
69
- function BooleanASTNodeImpl(parent, boolValue, offset) {
70
- var _this = _super.call(this, parent, offset) || this;
71
- _this.type = 'boolean';
72
- _this.value = boolValue;
73
- return _this;
74
- }
75
- return BooleanASTNodeImpl;
76
- }(ASTNodeImpl));
77
- export { BooleanASTNodeImpl };
78
- var ArrayASTNodeImpl = /** @class */ (function (_super) {
79
- __extends(ArrayASTNodeImpl, _super);
80
- function ArrayASTNodeImpl(parent, offset) {
81
- var _this = _super.call(this, parent, offset) || this;
82
- _this.type = 'array';
83
- _this.items = [];
84
- return _this;
85
- }
86
- Object.defineProperty(ArrayASTNodeImpl.prototype, "children", {
87
- get: function () {
88
- return this.items;
89
- },
90
- enumerable: false,
91
- configurable: true
92
- });
93
- return ArrayASTNodeImpl;
94
- }(ASTNodeImpl));
95
- export { ArrayASTNodeImpl };
96
- var NumberASTNodeImpl = /** @class */ (function (_super) {
97
- __extends(NumberASTNodeImpl, _super);
98
- function NumberASTNodeImpl(parent, offset) {
99
- var _this = _super.call(this, parent, offset) || this;
100
- _this.type = 'number';
101
- _this.isInteger = true;
102
- _this.value = Number.NaN;
103
- return _this;
104
- }
105
- return NumberASTNodeImpl;
106
- }(ASTNodeImpl));
107
- export { NumberASTNodeImpl };
108
- var StringASTNodeImpl = /** @class */ (function (_super) {
109
- __extends(StringASTNodeImpl, _super);
110
- function StringASTNodeImpl(parent, offset, length) {
111
- var _this = _super.call(this, parent, offset, length) || this;
112
- _this.type = 'string';
113
- _this.value = '';
114
- return _this;
115
- }
116
- return StringASTNodeImpl;
117
- }(ASTNodeImpl));
118
- export { StringASTNodeImpl };
119
- var PropertyASTNodeImpl = /** @class */ (function (_super) {
120
- __extends(PropertyASTNodeImpl, _super);
121
- function PropertyASTNodeImpl(parent, offset, keyNode) {
122
- var _this = _super.call(this, parent, offset) || this;
123
- _this.type = 'property';
124
- _this.colonOffset = -1;
125
- _this.keyNode = keyNode;
126
- return _this;
127
- }
128
- Object.defineProperty(PropertyASTNodeImpl.prototype, "children", {
129
- get: function () {
130
- return this.valueNode ? [this.keyNode, this.valueNode] : [this.keyNode];
131
- },
132
- enumerable: false,
133
- configurable: true
134
- });
135
- return PropertyASTNodeImpl;
136
- }(ASTNodeImpl));
137
- export { PropertyASTNodeImpl };
138
- var ObjectASTNodeImpl = /** @class */ (function (_super) {
139
- __extends(ObjectASTNodeImpl, _super);
140
- function ObjectASTNodeImpl(parent, offset) {
141
- var _this = _super.call(this, parent, offset) || this;
142
- _this.type = 'object';
143
- _this.properties = [];
144
- return _this;
145
- }
146
- Object.defineProperty(ObjectASTNodeImpl.prototype, "children", {
147
- get: function () {
148
- return this.properties;
149
- },
150
- enumerable: false,
151
- configurable: true
152
- });
153
- return ObjectASTNodeImpl;
154
- }(ASTNodeImpl));
155
- export { ObjectASTNodeImpl };
156
- export function asSchema(schema) {
157
- if (isBoolean(schema)) {
158
- return schema ? {} : { "not": {} };
159
- }
160
- return schema;
161
- }
162
- export var EnumMatch;
163
- (function (EnumMatch) {
164
- EnumMatch[EnumMatch["Key"] = 0] = "Key";
165
- EnumMatch[EnumMatch["Enum"] = 1] = "Enum";
166
- })(EnumMatch || (EnumMatch = {}));
167
- var SchemaCollector = /** @class */ (function () {
168
- function SchemaCollector(focusOffset, exclude) {
169
- if (focusOffset === void 0) { focusOffset = -1; }
170
- this.focusOffset = focusOffset;
171
- this.exclude = exclude;
172
- this.schemas = [];
173
- }
174
- SchemaCollector.prototype.add = function (schema) {
175
- this.schemas.push(schema);
176
- };
177
- SchemaCollector.prototype.merge = function (other) {
178
- Array.prototype.push.apply(this.schemas, other.schemas);
179
- };
180
- SchemaCollector.prototype.include = function (node) {
181
- return (this.focusOffset === -1 || contains(node, this.focusOffset)) && (node !== this.exclude);
182
- };
183
- SchemaCollector.prototype.newSub = function () {
184
- return new SchemaCollector(-1, this.exclude);
185
- };
186
- return SchemaCollector;
187
- }());
188
- var NoOpSchemaCollector = /** @class */ (function () {
189
- function NoOpSchemaCollector() {
190
- }
191
- Object.defineProperty(NoOpSchemaCollector.prototype, "schemas", {
192
- get: function () { return []; },
193
- enumerable: false,
194
- configurable: true
195
- });
196
- NoOpSchemaCollector.prototype.add = function (schema) { };
197
- NoOpSchemaCollector.prototype.merge = function (other) { };
198
- NoOpSchemaCollector.prototype.include = function (node) { return true; };
199
- NoOpSchemaCollector.prototype.newSub = function () { return this; };
200
- NoOpSchemaCollector.instance = new NoOpSchemaCollector();
201
- return NoOpSchemaCollector;
202
- }());
203
- var ValidationResult = /** @class */ (function () {
204
- function ValidationResult() {
205
- this.problems = [];
206
- this.propertiesMatches = 0;
207
- this.propertiesValueMatches = 0;
208
- this.primaryValueMatches = 0;
209
- this.enumValueMatch = false;
210
- this.enumValues = undefined;
211
- }
212
- ValidationResult.prototype.hasProblems = function () {
213
- return !!this.problems.length;
214
- };
215
- ValidationResult.prototype.mergeAll = function (validationResults) {
216
- for (var _i = 0, validationResults_1 = validationResults; _i < validationResults_1.length; _i++) {
217
- var validationResult = validationResults_1[_i];
218
- this.merge(validationResult);
219
- }
220
- };
221
- ValidationResult.prototype.merge = function (validationResult) {
222
- this.problems = this.problems.concat(validationResult.problems);
223
- };
224
- ValidationResult.prototype.mergeEnumValues = function (validationResult) {
225
- if (!this.enumValueMatch && !validationResult.enumValueMatch && this.enumValues && validationResult.enumValues) {
226
- this.enumValues = this.enumValues.concat(validationResult.enumValues);
227
- for (var _i = 0, _a = this.problems; _i < _a.length; _i++) {
228
- var error = _a[_i];
229
- if (error.code === ErrorCode.EnumValueMismatch) {
230
- error.message = localize('enumWarning', 'Value is not accepted. Valid values: {0}.', this.enumValues.map(function (v) { return JSON.stringify(v); }).join(', '));
231
- }
232
- }
233
- }
234
- };
235
- ValidationResult.prototype.mergePropertyMatch = function (propertyValidationResult) {
236
- this.merge(propertyValidationResult);
237
- this.propertiesMatches++;
238
- if (propertyValidationResult.enumValueMatch || !propertyValidationResult.hasProblems() && propertyValidationResult.propertiesMatches) {
239
- this.propertiesValueMatches++;
240
- }
241
- if (propertyValidationResult.enumValueMatch && propertyValidationResult.enumValues && propertyValidationResult.enumValues.length === 1) {
242
- this.primaryValueMatches++;
243
- }
244
- };
245
- ValidationResult.prototype.compare = function (other) {
246
- var hasProblems = this.hasProblems();
247
- if (hasProblems !== other.hasProblems()) {
248
- return hasProblems ? -1 : 1;
249
- }
250
- if (this.enumValueMatch !== other.enumValueMatch) {
251
- return other.enumValueMatch ? -1 : 1;
252
- }
253
- if (this.primaryValueMatches !== other.primaryValueMatches) {
254
- return this.primaryValueMatches - other.primaryValueMatches;
255
- }
256
- if (this.propertiesValueMatches !== other.propertiesValueMatches) {
257
- return this.propertiesValueMatches - other.propertiesValueMatches;
258
- }
259
- return this.propertiesMatches - other.propertiesMatches;
260
- };
261
- return ValidationResult;
262
- }());
263
- export { ValidationResult };
264
- export function newJSONDocument(root, diagnostics) {
265
- if (diagnostics === void 0) { diagnostics = []; }
266
- return new JSONDocument(root, diagnostics, []);
267
- }
268
- export function getNodeValue(node) {
269
- return Json.getNodeValue(node);
270
- }
271
- export function getNodePath(node) {
272
- return Json.getNodePath(node);
273
- }
274
- export function contains(node, offset, includeRightBound) {
275
- if (includeRightBound === void 0) { includeRightBound = false; }
276
- return offset >= node.offset && offset < (node.offset + node.length) || includeRightBound && offset === (node.offset + node.length);
277
- }
278
- var JSONDocument = /** @class */ (function () {
279
- function JSONDocument(root, syntaxErrors, comments) {
280
- if (syntaxErrors === void 0) { syntaxErrors = []; }
281
- if (comments === void 0) { comments = []; }
282
- this.root = root;
283
- this.syntaxErrors = syntaxErrors;
284
- this.comments = comments;
285
- }
286
- JSONDocument.prototype.getNodeFromOffset = function (offset, includeRightBound) {
287
- if (includeRightBound === void 0) { includeRightBound = false; }
288
- if (this.root) {
289
- return Json.findNodeAtOffset(this.root, offset, includeRightBound);
290
- }
291
- return undefined;
292
- };
293
- JSONDocument.prototype.visit = function (visitor) {
294
- if (this.root) {
295
- var doVisit_1 = function (node) {
296
- var ctn = visitor(node);
297
- var children = node.children;
298
- if (Array.isArray(children)) {
299
- for (var i = 0; i < children.length && ctn; i++) {
300
- ctn = doVisit_1(children[i]);
301
- }
302
- }
303
- return ctn;
304
- };
305
- doVisit_1(this.root);
306
- }
307
- };
308
- JSONDocument.prototype.validate = function (textDocument, schema, severity) {
309
- if (severity === void 0) { severity = DiagnosticSeverity.Warning; }
310
- if (this.root && schema) {
311
- var validationResult = new ValidationResult();
312
- validate(this.root, schema, validationResult, NoOpSchemaCollector.instance);
313
- return validationResult.problems.map(function (p) {
314
- var _a;
315
- var range = Range.create(textDocument.positionAt(p.location.offset), textDocument.positionAt(p.location.offset + p.location.length));
316
- return Diagnostic.create(range, p.message, (_a = p.severity) !== null && _a !== void 0 ? _a : severity, p.code);
317
- });
318
- }
319
- return undefined;
320
- };
321
- JSONDocument.prototype.getMatchingSchemas = function (schema, focusOffset, exclude) {
322
- if (focusOffset === void 0) { focusOffset = -1; }
323
- var matchingSchemas = new SchemaCollector(focusOffset, exclude);
324
- if (this.root && schema) {
325
- validate(this.root, schema, new ValidationResult(), matchingSchemas);
326
- }
327
- return matchingSchemas.schemas;
328
- };
329
- return JSONDocument;
330
- }());
331
- export { JSONDocument };
332
- function validate(n, schema, validationResult, matchingSchemas) {
333
- if (!n || !matchingSchemas.include(n)) {
334
- return;
335
- }
336
- var node = n;
337
- switch (node.type) {
338
- case 'object':
339
- _validateObjectNode(node, schema, validationResult, matchingSchemas);
340
- break;
341
- case 'array':
342
- _validateArrayNode(node, schema, validationResult, matchingSchemas);
343
- break;
344
- case 'string':
345
- _validateStringNode(node, schema, validationResult, matchingSchemas);
346
- break;
347
- case 'number':
348
- _validateNumberNode(node, schema, validationResult, matchingSchemas);
349
- break;
350
- case 'property':
351
- return validate(node.valueNode, schema, validationResult, matchingSchemas);
352
- }
353
- _validateNode();
354
- matchingSchemas.add({ node: node, schema: schema });
355
- function _validateNode() {
356
- function matchesType(type) {
357
- return node.type === type || (type === 'integer' && node.type === 'number' && node.isInteger);
358
- }
359
- if (Array.isArray(schema.type)) {
360
- if (!schema.type.some(matchesType)) {
361
- validationResult.problems.push({
362
- location: { offset: node.offset, length: node.length },
363
- message: schema.errorMessage || localize('typeArrayMismatchWarning', 'Incorrect type. Expected one of {0}.', schema.type.join(', '))
364
- });
365
- }
366
- }
367
- else if (schema.type) {
368
- if (!matchesType(schema.type)) {
369
- validationResult.problems.push({
370
- location: { offset: node.offset, length: node.length },
371
- message: schema.errorMessage || localize('typeMismatchWarning', 'Incorrect type. Expected "{0}".', schema.type)
372
- });
373
- }
374
- }
375
- if (Array.isArray(schema.allOf)) {
376
- for (var _i = 0, _a = schema.allOf; _i < _a.length; _i++) {
377
- var subSchemaRef = _a[_i];
378
- validate(node, asSchema(subSchemaRef), validationResult, matchingSchemas);
379
- }
380
- }
381
- var notSchema = asSchema(schema.not);
382
- if (notSchema) {
383
- var subValidationResult = new ValidationResult();
384
- var subMatchingSchemas = matchingSchemas.newSub();
385
- validate(node, notSchema, subValidationResult, subMatchingSchemas);
386
- if (!subValidationResult.hasProblems()) {
387
- validationResult.problems.push({
388
- location: { offset: node.offset, length: node.length },
389
- message: localize('notSchemaWarning', "Matches a schema that is not allowed.")
390
- });
391
- }
392
- for (var _b = 0, _c = subMatchingSchemas.schemas; _b < _c.length; _b++) {
393
- var ms = _c[_b];
394
- ms.inverted = !ms.inverted;
395
- matchingSchemas.add(ms);
396
- }
397
- }
398
- var testAlternatives = function (alternatives, maxOneMatch) {
399
- var matches = [];
400
- // remember the best match that is used for error messages
401
- var bestMatch = undefined;
402
- for (var _i = 0, alternatives_1 = alternatives; _i < alternatives_1.length; _i++) {
403
- var subSchemaRef = alternatives_1[_i];
404
- var subSchema = asSchema(subSchemaRef);
405
- var subValidationResult = new ValidationResult();
406
- var subMatchingSchemas = matchingSchemas.newSub();
407
- validate(node, subSchema, subValidationResult, subMatchingSchemas);
408
- if (!subValidationResult.hasProblems()) {
409
- matches.push(subSchema);
410
- }
411
- if (!bestMatch) {
412
- bestMatch = { schema: subSchema, validationResult: subValidationResult, matchingSchemas: subMatchingSchemas };
413
- }
414
- else {
415
- if (!maxOneMatch && !subValidationResult.hasProblems() && !bestMatch.validationResult.hasProblems()) {
416
- // no errors, both are equally good matches
417
- bestMatch.matchingSchemas.merge(subMatchingSchemas);
418
- bestMatch.validationResult.propertiesMatches += subValidationResult.propertiesMatches;
419
- bestMatch.validationResult.propertiesValueMatches += subValidationResult.propertiesValueMatches;
420
- }
421
- else {
422
- var compareResult = subValidationResult.compare(bestMatch.validationResult);
423
- if (compareResult > 0) {
424
- // our node is the best matching so far
425
- bestMatch = { schema: subSchema, validationResult: subValidationResult, matchingSchemas: subMatchingSchemas };
426
- }
427
- else if (compareResult === 0) {
428
- // there's already a best matching but we are as good
429
- bestMatch.matchingSchemas.merge(subMatchingSchemas);
430
- bestMatch.validationResult.mergeEnumValues(subValidationResult);
431
- }
432
- }
433
- }
434
- }
435
- if (matches.length > 1 && maxOneMatch) {
436
- validationResult.problems.push({
437
- location: { offset: node.offset, length: 1 },
438
- message: localize('oneOfWarning', "Matches multiple schemas when only one must validate.")
439
- });
440
- }
441
- if (bestMatch) {
442
- validationResult.merge(bestMatch.validationResult);
443
- validationResult.propertiesMatches += bestMatch.validationResult.propertiesMatches;
444
- validationResult.propertiesValueMatches += bestMatch.validationResult.propertiesValueMatches;
445
- matchingSchemas.merge(bestMatch.matchingSchemas);
446
- }
447
- return matches.length;
448
- };
449
- if (Array.isArray(schema.anyOf)) {
450
- testAlternatives(schema.anyOf, false);
451
- }
452
- if (Array.isArray(schema.oneOf)) {
453
- testAlternatives(schema.oneOf, true);
454
- }
455
- var testBranch = function (schema) {
456
- var subValidationResult = new ValidationResult();
457
- var subMatchingSchemas = matchingSchemas.newSub();
458
- validate(node, asSchema(schema), subValidationResult, subMatchingSchemas);
459
- validationResult.merge(subValidationResult);
460
- validationResult.propertiesMatches += subValidationResult.propertiesMatches;
461
- validationResult.propertiesValueMatches += subValidationResult.propertiesValueMatches;
462
- matchingSchemas.merge(subMatchingSchemas);
463
- };
464
- var testCondition = function (ifSchema, thenSchema, elseSchema) {
465
- var subSchema = asSchema(ifSchema);
466
- var subValidationResult = new ValidationResult();
467
- var subMatchingSchemas = matchingSchemas.newSub();
468
- validate(node, subSchema, subValidationResult, subMatchingSchemas);
469
- matchingSchemas.merge(subMatchingSchemas);
470
- if (!subValidationResult.hasProblems()) {
471
- if (thenSchema) {
472
- testBranch(thenSchema);
473
- }
474
- }
475
- else if (elseSchema) {
476
- testBranch(elseSchema);
477
- }
478
- };
479
- var ifSchema = asSchema(schema.if);
480
- if (ifSchema) {
481
- testCondition(ifSchema, asSchema(schema.then), asSchema(schema.else));
482
- }
483
- if (Array.isArray(schema.enum)) {
484
- var val = getNodeValue(node);
485
- var enumValueMatch = false;
486
- for (var _d = 0, _e = schema.enum; _d < _e.length; _d++) {
487
- var e = _e[_d];
488
- if (equals(val, e)) {
489
- enumValueMatch = true;
490
- break;
491
- }
492
- }
493
- validationResult.enumValues = schema.enum;
494
- validationResult.enumValueMatch = enumValueMatch;
495
- if (!enumValueMatch) {
496
- validationResult.problems.push({
497
- location: { offset: node.offset, length: node.length },
498
- code: ErrorCode.EnumValueMismatch,
499
- message: schema.errorMessage || localize('enumWarning', 'Value is not accepted. Valid values: {0}.', schema.enum.map(function (v) { return JSON.stringify(v); }).join(', '))
500
- });
501
- }
502
- }
503
- if (isDefined(schema.const)) {
504
- var val = getNodeValue(node);
505
- if (!equals(val, schema.const)) {
506
- validationResult.problems.push({
507
- location: { offset: node.offset, length: node.length },
508
- code: ErrorCode.EnumValueMismatch,
509
- message: schema.errorMessage || localize('constWarning', 'Value must be {0}.', JSON.stringify(schema.const))
510
- });
511
- validationResult.enumValueMatch = false;
512
- }
513
- else {
514
- validationResult.enumValueMatch = true;
515
- }
516
- validationResult.enumValues = [schema.const];
517
- }
518
- if (schema.deprecationMessage && node.parent) {
519
- validationResult.problems.push({
520
- location: { offset: node.parent.offset, length: node.parent.length },
521
- severity: DiagnosticSeverity.Warning,
522
- message: schema.deprecationMessage,
523
- code: ErrorCode.Deprecated
524
- });
525
- }
526
- }
527
- function _validateNumberNode(node, schema, validationResult, matchingSchemas) {
528
- var val = node.value;
529
- function normalizeFloats(float) {
530
- var _a;
531
- var parts = /^(-?\d+)(?:\.(\d+))?(?:e([-+]\d+))?$/.exec(float.toString());
532
- return parts && {
533
- value: Number(parts[1] + (parts[2] || '')),
534
- multiplier: (((_a = parts[2]) === null || _a === void 0 ? void 0 : _a.length) || 0) - (parseInt(parts[3]) || 0)
535
- };
536
- }
537
- ;
538
- if (isNumber(schema.multipleOf)) {
539
- var remainder = -1;
540
- if (Number.isInteger(schema.multipleOf)) {
541
- remainder = val % schema.multipleOf;
542
- }
543
- else {
544
- var normMultipleOf = normalizeFloats(schema.multipleOf);
545
- var normValue = normalizeFloats(val);
546
- if (normMultipleOf && normValue) {
547
- var multiplier = Math.pow(10, Math.abs(normValue.multiplier - normMultipleOf.multiplier));
548
- if (normValue.multiplier < normMultipleOf.multiplier) {
549
- normValue.value *= multiplier;
550
- }
551
- else {
552
- normMultipleOf.value *= multiplier;
553
- }
554
- remainder = normValue.value % normMultipleOf.value;
555
- }
556
- }
557
- if (remainder !== 0) {
558
- validationResult.problems.push({
559
- location: { offset: node.offset, length: node.length },
560
- message: localize('multipleOfWarning', 'Value is not divisible by {0}.', schema.multipleOf)
561
- });
562
- }
563
- }
564
- function getExclusiveLimit(limit, exclusive) {
565
- if (isNumber(exclusive)) {
566
- return exclusive;
567
- }
568
- if (isBoolean(exclusive) && exclusive) {
569
- return limit;
570
- }
571
- return undefined;
572
- }
573
- function getLimit(limit, exclusive) {
574
- if (!isBoolean(exclusive) || !exclusive) {
575
- return limit;
576
- }
577
- return undefined;
578
- }
579
- var exclusiveMinimum = getExclusiveLimit(schema.minimum, schema.exclusiveMinimum);
580
- if (isNumber(exclusiveMinimum) && val <= exclusiveMinimum) {
581
- validationResult.problems.push({
582
- location: { offset: node.offset, length: node.length },
583
- message: localize('exclusiveMinimumWarning', 'Value is below the exclusive minimum of {0}.', exclusiveMinimum)
584
- });
585
- }
586
- var exclusiveMaximum = getExclusiveLimit(schema.maximum, schema.exclusiveMaximum);
587
- if (isNumber(exclusiveMaximum) && val >= exclusiveMaximum) {
588
- validationResult.problems.push({
589
- location: { offset: node.offset, length: node.length },
590
- message: localize('exclusiveMaximumWarning', 'Value is above the exclusive maximum of {0}.', exclusiveMaximum)
591
- });
592
- }
593
- var minimum = getLimit(schema.minimum, schema.exclusiveMinimum);
594
- if (isNumber(minimum) && val < minimum) {
595
- validationResult.problems.push({
596
- location: { offset: node.offset, length: node.length },
597
- message: localize('minimumWarning', 'Value is below the minimum of {0}.', minimum)
598
- });
599
- }
600
- var maximum = getLimit(schema.maximum, schema.exclusiveMaximum);
601
- if (isNumber(maximum) && val > maximum) {
602
- validationResult.problems.push({
603
- location: { offset: node.offset, length: node.length },
604
- message: localize('maximumWarning', 'Value is above the maximum of {0}.', maximum)
605
- });
606
- }
607
- }
608
- function _validateStringNode(node, schema, validationResult, matchingSchemas) {
609
- if (isNumber(schema.minLength) && node.value.length < schema.minLength) {
610
- validationResult.problems.push({
611
- location: { offset: node.offset, length: node.length },
612
- message: localize('minLengthWarning', 'String is shorter than the minimum length of {0}.', schema.minLength)
613
- });
614
- }
615
- if (isNumber(schema.maxLength) && node.value.length > schema.maxLength) {
616
- validationResult.problems.push({
617
- location: { offset: node.offset, length: node.length },
618
- message: localize('maxLengthWarning', 'String is longer than the maximum length of {0}.', schema.maxLength)
619
- });
620
- }
621
- if (isString(schema.pattern)) {
622
- var regex = extendedRegExp(schema.pattern);
623
- if (!(regex === null || regex === void 0 ? void 0 : regex.test(node.value))) {
624
- validationResult.problems.push({
625
- location: { offset: node.offset, length: node.length },
626
- message: schema.patternErrorMessage || schema.errorMessage || localize('patternWarning', 'String does not match the pattern of "{0}".', schema.pattern)
627
- });
628
- }
629
- }
630
- if (schema.format) {
631
- switch (schema.format) {
632
- case 'uri':
633
- case 'uri-reference':
634
- {
635
- var errorMessage = void 0;
636
- if (!node.value) {
637
- errorMessage = localize('uriEmpty', 'URI expected.');
638
- }
639
- else {
640
- var match = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/.exec(node.value);
641
- if (!match) {
642
- errorMessage = localize('uriMissing', 'URI is expected.');
643
- }
644
- else if (!match[2] && schema.format === 'uri') {
645
- errorMessage = localize('uriSchemeMissing', 'URI with a scheme is expected.');
646
- }
647
- }
648
- if (errorMessage) {
649
- validationResult.problems.push({
650
- location: { offset: node.offset, length: node.length },
651
- message: schema.patternErrorMessage || schema.errorMessage || localize('uriFormatWarning', 'String is not a URI: {0}', errorMessage)
652
- });
653
- }
654
- }
655
- break;
656
- case 'color-hex':
657
- case 'date-time':
658
- case 'date':
659
- case 'time':
660
- case 'email':
661
- case 'hostname':
662
- case 'ipv4':
663
- case 'ipv6':
664
- var format = formats[schema.format];
665
- if (!node.value || !format.pattern.exec(node.value)) {
666
- validationResult.problems.push({
667
- location: { offset: node.offset, length: node.length },
668
- message: schema.patternErrorMessage || schema.errorMessage || format.errorMessage
669
- });
670
- }
671
- default:
672
- }
673
- }
674
- }
675
- function _validateArrayNode(node, schema, validationResult, matchingSchemas) {
676
- if (Array.isArray(schema.items)) {
677
- var subSchemas = schema.items;
678
- for (var index = 0; index < subSchemas.length; index++) {
679
- var subSchemaRef = subSchemas[index];
680
- var subSchema = asSchema(subSchemaRef);
681
- var itemValidationResult = new ValidationResult();
682
- var item = node.items[index];
683
- if (item) {
684
- validate(item, subSchema, itemValidationResult, matchingSchemas);
685
- validationResult.mergePropertyMatch(itemValidationResult);
686
- }
687
- else if (node.items.length >= subSchemas.length) {
688
- validationResult.propertiesValueMatches++;
689
- }
690
- }
691
- if (node.items.length > subSchemas.length) {
692
- if (typeof schema.additionalItems === 'object') {
693
- for (var i = subSchemas.length; i < node.items.length; i++) {
694
- var itemValidationResult = new ValidationResult();
695
- validate(node.items[i], schema.additionalItems, itemValidationResult, matchingSchemas);
696
- validationResult.mergePropertyMatch(itemValidationResult);
697
- }
698
- }
699
- else if (schema.additionalItems === false) {
700
- validationResult.problems.push({
701
- location: { offset: node.offset, length: node.length },
702
- message: localize('additionalItemsWarning', 'Array has too many items according to schema. Expected {0} or fewer.', subSchemas.length)
703
- });
704
- }
705
- }
706
- }
707
- else {
708
- var itemSchema = asSchema(schema.items);
709
- if (itemSchema) {
710
- for (var _i = 0, _a = node.items; _i < _a.length; _i++) {
711
- var item = _a[_i];
712
- var itemValidationResult = new ValidationResult();
713
- validate(item, itemSchema, itemValidationResult, matchingSchemas);
714
- validationResult.mergePropertyMatch(itemValidationResult);
715
- }
716
- }
717
- }
718
- var containsSchema = asSchema(schema.contains);
719
- if (containsSchema) {
720
- var doesContain = node.items.some(function (item) {
721
- var itemValidationResult = new ValidationResult();
722
- validate(item, containsSchema, itemValidationResult, NoOpSchemaCollector.instance);
723
- return !itemValidationResult.hasProblems();
724
- });
725
- if (!doesContain) {
726
- validationResult.problems.push({
727
- location: { offset: node.offset, length: node.length },
728
- message: schema.errorMessage || localize('requiredItemMissingWarning', 'Array does not contain required item.')
729
- });
730
- }
731
- }
732
- if (isNumber(schema.minItems) && node.items.length < schema.minItems) {
733
- validationResult.problems.push({
734
- location: { offset: node.offset, length: node.length },
735
- message: localize('minItemsWarning', 'Array has too few items. Expected {0} or more.', schema.minItems)
736
- });
737
- }
738
- if (isNumber(schema.maxItems) && node.items.length > schema.maxItems) {
739
- validationResult.problems.push({
740
- location: { offset: node.offset, length: node.length },
741
- message: localize('maxItemsWarning', 'Array has too many items. Expected {0} or fewer.', schema.maxItems)
742
- });
743
- }
744
- if (schema.uniqueItems === true) {
745
- var values_1 = getNodeValue(node);
746
- var duplicates = values_1.some(function (value, index) {
747
- return index !== values_1.lastIndexOf(value);
748
- });
749
- if (duplicates) {
750
- validationResult.problems.push({
751
- location: { offset: node.offset, length: node.length },
752
- message: localize('uniqueItemsWarning', 'Array has duplicate items.')
753
- });
754
- }
755
- }
756
- }
757
- function _validateObjectNode(node, schema, validationResult, matchingSchemas) {
758
- var seenKeys = Object.create(null);
759
- var unprocessedProperties = [];
760
- for (var _i = 0, _a = node.properties; _i < _a.length; _i++) {
761
- var propertyNode = _a[_i];
762
- var key = propertyNode.keyNode.value;
763
- seenKeys[key] = propertyNode.valueNode;
764
- unprocessedProperties.push(key);
765
- }
766
- if (Array.isArray(schema.required)) {
767
- for (var _b = 0, _c = schema.required; _b < _c.length; _b++) {
768
- var propertyName = _c[_b];
769
- if (!seenKeys[propertyName]) {
770
- var keyNode = node.parent && node.parent.type === 'property' && node.parent.keyNode;
771
- var location = keyNode ? { offset: keyNode.offset, length: keyNode.length } : { offset: node.offset, length: 1 };
772
- validationResult.problems.push({
773
- location: location,
774
- message: localize('MissingRequiredPropWarning', 'Missing property "{0}".', propertyName)
775
- });
776
- }
777
- }
778
- }
779
- var propertyProcessed = function (prop) {
780
- var index = unprocessedProperties.indexOf(prop);
781
- while (index >= 0) {
782
- unprocessedProperties.splice(index, 1);
783
- index = unprocessedProperties.indexOf(prop);
784
- }
785
- };
786
- if (schema.properties) {
787
- for (var _d = 0, _e = Object.keys(schema.properties); _d < _e.length; _d++) {
788
- var propertyName = _e[_d];
789
- propertyProcessed(propertyName);
790
- var propertySchema = schema.properties[propertyName];
791
- var child = seenKeys[propertyName];
792
- if (child) {
793
- if (isBoolean(propertySchema)) {
794
- if (!propertySchema) {
795
- var propertyNode = child.parent;
796
- validationResult.problems.push({
797
- location: { offset: propertyNode.keyNode.offset, length: propertyNode.keyNode.length },
798
- message: schema.errorMessage || localize('DisallowedExtraPropWarning', 'Property {0} is not allowed.', propertyName)
799
- });
800
- }
801
- else {
802
- validationResult.propertiesMatches++;
803
- validationResult.propertiesValueMatches++;
804
- }
805
- }
806
- else {
807
- var propertyValidationResult = new ValidationResult();
808
- validate(child, propertySchema, propertyValidationResult, matchingSchemas);
809
- validationResult.mergePropertyMatch(propertyValidationResult);
810
- }
811
- }
812
- }
813
- }
814
- if (schema.patternProperties) {
815
- for (var _f = 0, _g = Object.keys(schema.patternProperties); _f < _g.length; _f++) {
816
- var propertyPattern = _g[_f];
817
- var regex = extendedRegExp(propertyPattern);
818
- for (var _h = 0, _j = unprocessedProperties.slice(0); _h < _j.length; _h++) {
819
- var propertyName = _j[_h];
820
- if (regex === null || regex === void 0 ? void 0 : regex.test(propertyName)) {
821
- propertyProcessed(propertyName);
822
- var child = seenKeys[propertyName];
823
- if (child) {
824
- var propertySchema = schema.patternProperties[propertyPattern];
825
- if (isBoolean(propertySchema)) {
826
- if (!propertySchema) {
827
- var propertyNode = child.parent;
828
- validationResult.problems.push({
829
- location: { offset: propertyNode.keyNode.offset, length: propertyNode.keyNode.length },
830
- message: schema.errorMessage || localize('DisallowedExtraPropWarning', 'Property {0} is not allowed.', propertyName)
831
- });
832
- }
833
- else {
834
- validationResult.propertiesMatches++;
835
- validationResult.propertiesValueMatches++;
836
- }
837
- }
838
- else {
839
- var propertyValidationResult = new ValidationResult();
840
- validate(child, propertySchema, propertyValidationResult, matchingSchemas);
841
- validationResult.mergePropertyMatch(propertyValidationResult);
842
- }
843
- }
844
- }
845
- }
846
- }
847
- }
848
- if (typeof schema.additionalProperties === 'object') {
849
- for (var _k = 0, unprocessedProperties_1 = unprocessedProperties; _k < unprocessedProperties_1.length; _k++) {
850
- var propertyName = unprocessedProperties_1[_k];
851
- var child = seenKeys[propertyName];
852
- if (child) {
853
- var propertyValidationResult = new ValidationResult();
854
- validate(child, schema.additionalProperties, propertyValidationResult, matchingSchemas);
855
- validationResult.mergePropertyMatch(propertyValidationResult);
856
- }
857
- }
858
- }
859
- else if (schema.additionalProperties === false) {
860
- if (unprocessedProperties.length > 0) {
861
- for (var _l = 0, unprocessedProperties_2 = unprocessedProperties; _l < unprocessedProperties_2.length; _l++) {
862
- var propertyName = unprocessedProperties_2[_l];
863
- var child = seenKeys[propertyName];
864
- if (child) {
865
- var propertyNode = child.parent;
866
- validationResult.problems.push({
867
- location: { offset: propertyNode.keyNode.offset, length: propertyNode.keyNode.length },
868
- message: schema.errorMessage || localize('DisallowedExtraPropWarning', 'Property {0} is not allowed.', propertyName)
869
- });
870
- }
871
- }
872
- }
873
- }
874
- if (isNumber(schema.maxProperties)) {
875
- if (node.properties.length > schema.maxProperties) {
876
- validationResult.problems.push({
877
- location: { offset: node.offset, length: node.length },
878
- message: localize('MaxPropWarning', 'Object has more properties than limit of {0}.', schema.maxProperties)
879
- });
880
- }
881
- }
882
- if (isNumber(schema.minProperties)) {
883
- if (node.properties.length < schema.minProperties) {
884
- validationResult.problems.push({
885
- location: { offset: node.offset, length: node.length },
886
- message: localize('MinPropWarning', 'Object has fewer properties than the required number of {0}', schema.minProperties)
887
- });
888
- }
889
- }
890
- if (schema.dependencies) {
891
- for (var _m = 0, _o = Object.keys(schema.dependencies); _m < _o.length; _m++) {
892
- var key = _o[_m];
893
- var prop = seenKeys[key];
894
- if (prop) {
895
- var propertyDep = schema.dependencies[key];
896
- if (Array.isArray(propertyDep)) {
897
- for (var _p = 0, propertyDep_1 = propertyDep; _p < propertyDep_1.length; _p++) {
898
- var requiredProp = propertyDep_1[_p];
899
- if (!seenKeys[requiredProp]) {
900
- validationResult.problems.push({
901
- location: { offset: node.offset, length: node.length },
902
- message: localize('RequiredDependentPropWarning', 'Object is missing property {0} required by property {1}.', requiredProp, key)
903
- });
904
- }
905
- else {
906
- validationResult.propertiesValueMatches++;
907
- }
908
- }
909
- }
910
- else {
911
- var propertySchema = asSchema(propertyDep);
912
- if (propertySchema) {
913
- var propertyValidationResult = new ValidationResult();
914
- validate(node, propertySchema, propertyValidationResult, matchingSchemas);
915
- validationResult.mergePropertyMatch(propertyValidationResult);
916
- }
917
- }
918
- }
919
- }
920
- }
921
- var propertyNames = asSchema(schema.propertyNames);
922
- if (propertyNames) {
923
- for (var _q = 0, _r = node.properties; _q < _r.length; _q++) {
924
- var f = _r[_q];
925
- var key = f.keyNode;
926
- if (key) {
927
- validate(key, propertyNames, validationResult, NoOpSchemaCollector.instance);
928
- }
929
- }
930
- }
931
- }
932
- }
933
- export function parse(textDocument, config) {
934
- var problems = [];
935
- var lastProblemOffset = -1;
936
- var text = textDocument.getText();
937
- var scanner = Json.createScanner(text, false);
938
- var commentRanges = config && config.collectComments ? [] : undefined;
939
- function _scanNext() {
940
- while (true) {
941
- var token_1 = scanner.scan();
942
- _checkScanError();
943
- switch (token_1) {
944
- case 12 /* LineCommentTrivia */:
945
- case 13 /* BlockCommentTrivia */:
946
- if (Array.isArray(commentRanges)) {
947
- commentRanges.push(Range.create(textDocument.positionAt(scanner.getTokenOffset()), textDocument.positionAt(scanner.getTokenOffset() + scanner.getTokenLength())));
948
- }
949
- break;
950
- case 15 /* Trivia */:
951
- case 14 /* LineBreakTrivia */:
952
- break;
953
- default:
954
- return token_1;
955
- }
956
- }
957
- }
958
- function _accept(token) {
959
- if (scanner.getToken() === token) {
960
- _scanNext();
961
- return true;
962
- }
963
- return false;
964
- }
965
- function _errorAtRange(message, code, startOffset, endOffset, severity) {
966
- if (severity === void 0) { severity = DiagnosticSeverity.Error; }
967
- if (problems.length === 0 || startOffset !== lastProblemOffset) {
968
- var range = Range.create(textDocument.positionAt(startOffset), textDocument.positionAt(endOffset));
969
- problems.push(Diagnostic.create(range, message, severity, code, textDocument.languageId));
970
- lastProblemOffset = startOffset;
971
- }
972
- }
973
- function _error(message, code, node, skipUntilAfter, skipUntil) {
974
- if (node === void 0) { node = undefined; }
975
- if (skipUntilAfter === void 0) { skipUntilAfter = []; }
976
- if (skipUntil === void 0) { skipUntil = []; }
977
- var start = scanner.getTokenOffset();
978
- var end = scanner.getTokenOffset() + scanner.getTokenLength();
979
- if (start === end && start > 0) {
980
- start--;
981
- while (start > 0 && /\s/.test(text.charAt(start))) {
982
- start--;
983
- }
984
- end = start + 1;
985
- }
986
- _errorAtRange(message, code, start, end);
987
- if (node) {
988
- _finalize(node, false);
989
- }
990
- if (skipUntilAfter.length + skipUntil.length > 0) {
991
- var token_2 = scanner.getToken();
992
- while (token_2 !== 17 /* EOF */) {
993
- if (skipUntilAfter.indexOf(token_2) !== -1) {
994
- _scanNext();
995
- break;
996
- }
997
- else if (skipUntil.indexOf(token_2) !== -1) {
998
- break;
999
- }
1000
- token_2 = _scanNext();
1001
- }
1002
- }
1003
- return node;
1004
- }
1005
- function _checkScanError() {
1006
- switch (scanner.getTokenError()) {
1007
- case 4 /* InvalidUnicode */:
1008
- _error(localize('InvalidUnicode', 'Invalid unicode sequence in string.'), ErrorCode.InvalidUnicode);
1009
- return true;
1010
- case 5 /* InvalidEscapeCharacter */:
1011
- _error(localize('InvalidEscapeCharacter', 'Invalid escape character in string.'), ErrorCode.InvalidEscapeCharacter);
1012
- return true;
1013
- case 3 /* UnexpectedEndOfNumber */:
1014
- _error(localize('UnexpectedEndOfNumber', 'Unexpected end of number.'), ErrorCode.UnexpectedEndOfNumber);
1015
- return true;
1016
- case 1 /* UnexpectedEndOfComment */:
1017
- _error(localize('UnexpectedEndOfComment', 'Unexpected end of comment.'), ErrorCode.UnexpectedEndOfComment);
1018
- return true;
1019
- case 2 /* UnexpectedEndOfString */:
1020
- _error(localize('UnexpectedEndOfString', 'Unexpected end of string.'), ErrorCode.UnexpectedEndOfString);
1021
- return true;
1022
- case 6 /* InvalidCharacter */:
1023
- _error(localize('InvalidCharacter', 'Invalid characters in string. Control characters must be escaped.'), ErrorCode.InvalidCharacter);
1024
- return true;
1025
- }
1026
- return false;
1027
- }
1028
- function _finalize(node, scanNext) {
1029
- node.length = scanner.getTokenOffset() + scanner.getTokenLength() - node.offset;
1030
- if (scanNext) {
1031
- _scanNext();
1032
- }
1033
- return node;
1034
- }
1035
- function _parseArray(parent) {
1036
- if (scanner.getToken() !== 3 /* OpenBracketToken */) {
1037
- return undefined;
1038
- }
1039
- var node = new ArrayASTNodeImpl(parent, scanner.getTokenOffset());
1040
- _scanNext(); // consume OpenBracketToken
1041
- var count = 0;
1042
- var needsComma = false;
1043
- while (scanner.getToken() !== 4 /* CloseBracketToken */ && scanner.getToken() !== 17 /* EOF */) {
1044
- if (scanner.getToken() === 5 /* CommaToken */) {
1045
- if (!needsComma) {
1046
- _error(localize('ValueExpected', 'Value expected'), ErrorCode.ValueExpected);
1047
- }
1048
- var commaOffset = scanner.getTokenOffset();
1049
- _scanNext(); // consume comma
1050
- if (scanner.getToken() === 4 /* CloseBracketToken */) {
1051
- if (needsComma) {
1052
- _errorAtRange(localize('TrailingComma', 'Trailing comma'), ErrorCode.TrailingComma, commaOffset, commaOffset + 1);
1053
- }
1054
- continue;
1055
- }
1056
- }
1057
- else if (needsComma) {
1058
- _error(localize('ExpectedComma', 'Expected comma'), ErrorCode.CommaExpected);
1059
- }
1060
- var item = _parseValue(node);
1061
- if (!item) {
1062
- _error(localize('PropertyExpected', 'Value expected'), ErrorCode.ValueExpected, undefined, [], [4 /* CloseBracketToken */, 5 /* CommaToken */]);
1063
- }
1064
- else {
1065
- node.items.push(item);
1066
- }
1067
- needsComma = true;
1068
- }
1069
- if (scanner.getToken() !== 4 /* CloseBracketToken */) {
1070
- return _error(localize('ExpectedCloseBracket', 'Expected comma or closing bracket'), ErrorCode.CommaOrCloseBacketExpected, node);
1071
- }
1072
- return _finalize(node, true);
1073
- }
1074
- var keyPlaceholder = new StringASTNodeImpl(undefined, 0, 0);
1075
- function _parseProperty(parent, keysSeen) {
1076
- var node = new PropertyASTNodeImpl(parent, scanner.getTokenOffset(), keyPlaceholder);
1077
- var key = _parseString(node);
1078
- if (!key) {
1079
- if (scanner.getToken() === 16 /* Unknown */) {
1080
- // give a more helpful error message
1081
- _error(localize('DoubleQuotesExpected', 'Property keys must be doublequoted'), ErrorCode.Undefined);
1082
- var keyNode = new StringASTNodeImpl(node, scanner.getTokenOffset(), scanner.getTokenLength());
1083
- keyNode.value = scanner.getTokenValue();
1084
- key = keyNode;
1085
- _scanNext(); // consume Unknown
1086
- }
1087
- else {
1088
- return undefined;
1089
- }
1090
- }
1091
- node.keyNode = key;
1092
- var seen = keysSeen[key.value];
1093
- if (seen) {
1094
- _errorAtRange(localize('DuplicateKeyWarning', "Duplicate object key"), ErrorCode.DuplicateKey, node.keyNode.offset, node.keyNode.offset + node.keyNode.length, DiagnosticSeverity.Warning);
1095
- if (typeof seen === 'object') {
1096
- _errorAtRange(localize('DuplicateKeyWarning', "Duplicate object key"), ErrorCode.DuplicateKey, seen.keyNode.offset, seen.keyNode.offset + seen.keyNode.length, DiagnosticSeverity.Warning);
1097
- }
1098
- keysSeen[key.value] = true; // if the same key is duplicate again, avoid duplicate error reporting
1099
- }
1100
- else {
1101
- keysSeen[key.value] = node;
1102
- }
1103
- if (scanner.getToken() === 6 /* ColonToken */) {
1104
- node.colonOffset = scanner.getTokenOffset();
1105
- _scanNext(); // consume ColonToken
1106
- }
1107
- else {
1108
- _error(localize('ColonExpected', 'Colon expected'), ErrorCode.ColonExpected);
1109
- if (scanner.getToken() === 10 /* StringLiteral */ && textDocument.positionAt(key.offset + key.length).line < textDocument.positionAt(scanner.getTokenOffset()).line) {
1110
- node.length = key.length;
1111
- return node;
1112
- }
1113
- }
1114
- var value = _parseValue(node);
1115
- if (!value) {
1116
- return _error(localize('ValueExpected', 'Value expected'), ErrorCode.ValueExpected, node, [], [2 /* CloseBraceToken */, 5 /* CommaToken */]);
1117
- }
1118
- node.valueNode = value;
1119
- node.length = value.offset + value.length - node.offset;
1120
- return node;
1121
- }
1122
- function _parseObject(parent) {
1123
- if (scanner.getToken() !== 1 /* OpenBraceToken */) {
1124
- return undefined;
1125
- }
1126
- var node = new ObjectASTNodeImpl(parent, scanner.getTokenOffset());
1127
- var keysSeen = Object.create(null);
1128
- _scanNext(); // consume OpenBraceToken
1129
- var needsComma = false;
1130
- while (scanner.getToken() !== 2 /* CloseBraceToken */ && scanner.getToken() !== 17 /* EOF */) {
1131
- if (scanner.getToken() === 5 /* CommaToken */) {
1132
- if (!needsComma) {
1133
- _error(localize('PropertyExpected', 'Property expected'), ErrorCode.PropertyExpected);
1134
- }
1135
- var commaOffset = scanner.getTokenOffset();
1136
- _scanNext(); // consume comma
1137
- if (scanner.getToken() === 2 /* CloseBraceToken */) {
1138
- if (needsComma) {
1139
- _errorAtRange(localize('TrailingComma', 'Trailing comma'), ErrorCode.TrailingComma, commaOffset, commaOffset + 1);
1140
- }
1141
- continue;
1142
- }
1143
- }
1144
- else if (needsComma) {
1145
- _error(localize('ExpectedComma', 'Expected comma'), ErrorCode.CommaExpected);
1146
- }
1147
- var property = _parseProperty(node, keysSeen);
1148
- if (!property) {
1149
- _error(localize('PropertyExpected', 'Property expected'), ErrorCode.PropertyExpected, undefined, [], [2 /* CloseBraceToken */, 5 /* CommaToken */]);
1150
- }
1151
- else {
1152
- node.properties.push(property);
1153
- }
1154
- needsComma = true;
1155
- }
1156
- if (scanner.getToken() !== 2 /* CloseBraceToken */) {
1157
- return _error(localize('ExpectedCloseBrace', 'Expected comma or closing brace'), ErrorCode.CommaOrCloseBraceExpected, node);
1158
- }
1159
- return _finalize(node, true);
1160
- }
1161
- function _parseString(parent) {
1162
- if (scanner.getToken() !== 10 /* StringLiteral */) {
1163
- return undefined;
1164
- }
1165
- var node = new StringASTNodeImpl(parent, scanner.getTokenOffset());
1166
- node.value = scanner.getTokenValue();
1167
- return _finalize(node, true);
1168
- }
1169
- function _parseNumber(parent) {
1170
- if (scanner.getToken() !== 11 /* NumericLiteral */) {
1171
- return undefined;
1172
- }
1173
- var node = new NumberASTNodeImpl(parent, scanner.getTokenOffset());
1174
- if (scanner.getTokenError() === 0 /* None */) {
1175
- var tokenValue = scanner.getTokenValue();
1176
- try {
1177
- var numberValue = JSON.parse(tokenValue);
1178
- if (!isNumber(numberValue)) {
1179
- return _error(localize('InvalidNumberFormat', 'Invalid number format.'), ErrorCode.Undefined, node);
1180
- }
1181
- node.value = numberValue;
1182
- }
1183
- catch (e) {
1184
- return _error(localize('InvalidNumberFormat', 'Invalid number format.'), ErrorCode.Undefined, node);
1185
- }
1186
- node.isInteger = tokenValue.indexOf('.') === -1;
1187
- }
1188
- return _finalize(node, true);
1189
- }
1190
- function _parseLiteral(parent) {
1191
- var node;
1192
- switch (scanner.getToken()) {
1193
- case 7 /* NullKeyword */:
1194
- return _finalize(new NullASTNodeImpl(parent, scanner.getTokenOffset()), true);
1195
- case 8 /* TrueKeyword */:
1196
- return _finalize(new BooleanASTNodeImpl(parent, true, scanner.getTokenOffset()), true);
1197
- case 9 /* FalseKeyword */:
1198
- return _finalize(new BooleanASTNodeImpl(parent, false, scanner.getTokenOffset()), true);
1199
- default:
1200
- return undefined;
1201
- }
1202
- }
1203
- function _parseValue(parent) {
1204
- return _parseArray(parent) || _parseObject(parent) || _parseString(parent) || _parseNumber(parent) || _parseLiteral(parent);
1205
- }
1206
- var _root = undefined;
1207
- var token = _scanNext();
1208
- if (token !== 17 /* EOF */) {
1209
- _root = _parseValue(_root);
1210
- if (!_root) {
1211
- _error(localize('Invalid symbol', 'Expected a JSON object, array or literal.'), ErrorCode.Undefined);
1212
- }
1213
- else if (scanner.getToken() !== 17 /* EOF */) {
1214
- _error(localize('End of file expected', 'End of file expected.'), ErrorCode.Undefined);
1215
- }
1216
- }
1217
- return new JSONDocument(_root, problems, commentRanges);
1218
- }
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License. See License.txt in the project root for license information.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ import * as Json from 'jsonc-parser';
6
+ import { isNumber, equals, isBoolean, isString, isDefined, isObject } from '../utils/objects';
7
+ import { extendedRegExp } from '../utils/strings';
8
+ import { ErrorCode, Diagnostic, DiagnosticSeverity, Range } from '../jsonLanguageTypes';
9
+ import * as nls from 'vscode-nls';
10
+ const localize = nls.loadMessageBundle();
11
+ const formats = {
12
+ 'color-hex': { errorMessage: localize('colorHexFormatWarning', 'Invalid color format. Use #RGB, #RGBA, #RRGGBB or #RRGGBBAA.'), pattern: /^#([0-9A-Fa-f]{3,4}|([0-9A-Fa-f]{2}){3,4})$/ },
13
+ 'date-time': { errorMessage: localize('dateTimeFormatWarning', '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
+ 'date': { errorMessage: localize('dateFormatWarning', '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
+ 'time': { errorMessage: localize('timeFormatWarning', '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 },
16
+ 'email': { errorMessage: localize('emailFormatWarning', '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
+ 'hostname': { errorMessage: localize('hostnameFormatWarning', '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
+ 'ipv4': { errorMessage: localize('ipv4FormatWarning', '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)$/ },
19
+ 'ipv6': { errorMessage: localize('ipv6FormatWarning', 'String is not an IPv6 address.'), pattern: /^((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))$/i },
20
+ };
21
+ export class ASTNodeImpl {
22
+ constructor(parent, offset, length = 0) {
23
+ this.offset = offset;
24
+ this.length = length;
25
+ this.parent = parent;
26
+ }
27
+ get children() {
28
+ return [];
29
+ }
30
+ toString() {
31
+ return 'type: ' + this.type + ' (' + this.offset + '/' + this.length + ')' + (this.parent ? ' parent: {' + this.parent.toString() + '}' : '');
32
+ }
33
+ }
34
+ export class NullASTNodeImpl extends ASTNodeImpl {
35
+ constructor(parent, offset) {
36
+ super(parent, offset);
37
+ this.type = 'null';
38
+ this.value = null;
39
+ }
40
+ }
41
+ export class BooleanASTNodeImpl extends ASTNodeImpl {
42
+ constructor(parent, boolValue, offset) {
43
+ super(parent, offset);
44
+ this.type = 'boolean';
45
+ this.value = boolValue;
46
+ }
47
+ }
48
+ export class ArrayASTNodeImpl extends ASTNodeImpl {
49
+ constructor(parent, offset) {
50
+ super(parent, offset);
51
+ this.type = 'array';
52
+ this.items = [];
53
+ }
54
+ get children() {
55
+ return this.items;
56
+ }
57
+ }
58
+ export class NumberASTNodeImpl extends ASTNodeImpl {
59
+ constructor(parent, offset) {
60
+ super(parent, offset);
61
+ this.type = 'number';
62
+ this.isInteger = true;
63
+ this.value = Number.NaN;
64
+ }
65
+ }
66
+ export class StringASTNodeImpl extends ASTNodeImpl {
67
+ constructor(parent, offset, length) {
68
+ super(parent, offset, length);
69
+ this.type = 'string';
70
+ this.value = '';
71
+ }
72
+ }
73
+ export class PropertyASTNodeImpl extends ASTNodeImpl {
74
+ constructor(parent, offset, keyNode) {
75
+ super(parent, offset);
76
+ this.type = 'property';
77
+ this.colonOffset = -1;
78
+ this.keyNode = keyNode;
79
+ }
80
+ get children() {
81
+ return this.valueNode ? [this.keyNode, this.valueNode] : [this.keyNode];
82
+ }
83
+ }
84
+ export class ObjectASTNodeImpl extends ASTNodeImpl {
85
+ constructor(parent, offset) {
86
+ super(parent, offset);
87
+ this.type = 'object';
88
+ this.properties = [];
89
+ }
90
+ get children() {
91
+ return this.properties;
92
+ }
93
+ }
94
+ export function asSchema(schema) {
95
+ if (isBoolean(schema)) {
96
+ return schema ? {} : { "not": {} };
97
+ }
98
+ return schema;
99
+ }
100
+ export var EnumMatch;
101
+ (function (EnumMatch) {
102
+ EnumMatch[EnumMatch["Key"] = 0] = "Key";
103
+ EnumMatch[EnumMatch["Enum"] = 1] = "Enum";
104
+ })(EnumMatch || (EnumMatch = {}));
105
+ class SchemaCollector {
106
+ constructor(focusOffset = -1, exclude) {
107
+ this.focusOffset = focusOffset;
108
+ this.exclude = exclude;
109
+ this.schemas = [];
110
+ }
111
+ add(schema) {
112
+ this.schemas.push(schema);
113
+ }
114
+ merge(other) {
115
+ Array.prototype.push.apply(this.schemas, other.schemas);
116
+ }
117
+ include(node) {
118
+ return (this.focusOffset === -1 || contains(node, this.focusOffset)) && (node !== this.exclude);
119
+ }
120
+ newSub() {
121
+ return new SchemaCollector(-1, this.exclude);
122
+ }
123
+ }
124
+ class NoOpSchemaCollector {
125
+ constructor() { }
126
+ get schemas() { return []; }
127
+ add(schema) { }
128
+ merge(other) { }
129
+ include(node) { return true; }
130
+ newSub() { return this; }
131
+ }
132
+ NoOpSchemaCollector.instance = new NoOpSchemaCollector();
133
+ export class ValidationResult {
134
+ constructor() {
135
+ this.problems = [];
136
+ this.propertiesMatches = 0;
137
+ this.processedProperties = new Set();
138
+ this.propertiesValueMatches = 0;
139
+ this.primaryValueMatches = 0;
140
+ this.enumValueMatch = false;
141
+ this.enumValues = undefined;
142
+ }
143
+ hasProblems() {
144
+ return !!this.problems.length;
145
+ }
146
+ mergeAll(validationResults) {
147
+ for (const validationResult of validationResults) {
148
+ this.merge(validationResult);
149
+ }
150
+ }
151
+ merge(validationResult) {
152
+ this.problems = this.problems.concat(validationResult.problems);
153
+ }
154
+ mergeEnumValues(validationResult) {
155
+ if (!this.enumValueMatch && !validationResult.enumValueMatch && this.enumValues && validationResult.enumValues) {
156
+ this.enumValues = this.enumValues.concat(validationResult.enumValues);
157
+ for (const error of this.problems) {
158
+ if (error.code === ErrorCode.EnumValueMismatch) {
159
+ error.message = localize('enumWarning', 'Value is not accepted. Valid values: {0}.', this.enumValues.map(v => JSON.stringify(v)).join(', '));
160
+ }
161
+ }
162
+ }
163
+ }
164
+ mergePropertyMatch(propertyValidationResult) {
165
+ this.merge(propertyValidationResult);
166
+ this.propertiesMatches++;
167
+ if (propertyValidationResult.enumValueMatch || !propertyValidationResult.hasProblems() && propertyValidationResult.propertiesMatches) {
168
+ this.propertiesValueMatches++;
169
+ }
170
+ if (propertyValidationResult.enumValueMatch && propertyValidationResult.enumValues && propertyValidationResult.enumValues.length === 1) {
171
+ this.primaryValueMatches++;
172
+ }
173
+ }
174
+ mergeProcessedProperties(validationResult) {
175
+ validationResult.processedProperties.forEach(p => this.processedProperties.add(p));
176
+ }
177
+ compare(other) {
178
+ const hasProblems = this.hasProblems();
179
+ if (hasProblems !== other.hasProblems()) {
180
+ return hasProblems ? -1 : 1;
181
+ }
182
+ if (this.enumValueMatch !== other.enumValueMatch) {
183
+ return other.enumValueMatch ? -1 : 1;
184
+ }
185
+ if (this.primaryValueMatches !== other.primaryValueMatches) {
186
+ return this.primaryValueMatches - other.primaryValueMatches;
187
+ }
188
+ if (this.propertiesValueMatches !== other.propertiesValueMatches) {
189
+ return this.propertiesValueMatches - other.propertiesValueMatches;
190
+ }
191
+ return this.propertiesMatches - other.propertiesMatches;
192
+ }
193
+ }
194
+ export function newJSONDocument(root, diagnostics = []) {
195
+ return new JSONDocument(root, diagnostics, []);
196
+ }
197
+ export function getNodeValue(node) {
198
+ return Json.getNodeValue(node);
199
+ }
200
+ export function getNodePath(node) {
201
+ return Json.getNodePath(node);
202
+ }
203
+ export function contains(node, offset, includeRightBound = false) {
204
+ return offset >= node.offset && offset < (node.offset + node.length) || includeRightBound && offset === (node.offset + node.length);
205
+ }
206
+ export class JSONDocument {
207
+ constructor(root, syntaxErrors = [], comments = []) {
208
+ this.root = root;
209
+ this.syntaxErrors = syntaxErrors;
210
+ this.comments = comments;
211
+ }
212
+ getNodeFromOffset(offset, includeRightBound = false) {
213
+ if (this.root) {
214
+ return Json.findNodeAtOffset(this.root, offset, includeRightBound);
215
+ }
216
+ return undefined;
217
+ }
218
+ visit(visitor) {
219
+ if (this.root) {
220
+ const doVisit = (node) => {
221
+ let ctn = visitor(node);
222
+ const children = node.children;
223
+ if (Array.isArray(children)) {
224
+ for (let i = 0; i < children.length && ctn; i++) {
225
+ ctn = doVisit(children[i]);
226
+ }
227
+ }
228
+ return ctn;
229
+ };
230
+ doVisit(this.root);
231
+ }
232
+ }
233
+ validate(textDocument, schema, severity = DiagnosticSeverity.Warning) {
234
+ if (this.root && schema) {
235
+ const validationResult = new ValidationResult();
236
+ validate(this.root, schema, validationResult, NoOpSchemaCollector.instance);
237
+ return validationResult.problems.map(p => {
238
+ const range = Range.create(textDocument.positionAt(p.location.offset), textDocument.positionAt(p.location.offset + p.location.length));
239
+ return Diagnostic.create(range, p.message, p.severity ?? severity, p.code);
240
+ });
241
+ }
242
+ return undefined;
243
+ }
244
+ getMatchingSchemas(schema, focusOffset = -1, exclude) {
245
+ const matchingSchemas = new SchemaCollector(focusOffset, exclude);
246
+ if (this.root && schema) {
247
+ validate(this.root, schema, new ValidationResult(), matchingSchemas);
248
+ }
249
+ return matchingSchemas.schemas;
250
+ }
251
+ }
252
+ function validate(n, schema, validationResult, matchingSchemas) {
253
+ if (!n || !matchingSchemas.include(n)) {
254
+ return;
255
+ }
256
+ if (n.type === 'property') {
257
+ return validate(n.valueNode, schema, validationResult, matchingSchemas);
258
+ }
259
+ const node = n;
260
+ _validateNode();
261
+ switch (node.type) {
262
+ case 'object':
263
+ _validateObjectNode(node);
264
+ break;
265
+ case 'array':
266
+ _validateArrayNode(node);
267
+ break;
268
+ case 'string':
269
+ _validateStringNode(node);
270
+ break;
271
+ case 'number':
272
+ _validateNumberNode(node);
273
+ break;
274
+ }
275
+ matchingSchemas.add({ node: node, schema: schema });
276
+ function _validateNode() {
277
+ function matchesType(type) {
278
+ return node.type === type || (type === 'integer' && node.type === 'number' && node.isInteger);
279
+ }
280
+ if (Array.isArray(schema.type)) {
281
+ if (!schema.type.some(matchesType)) {
282
+ validationResult.problems.push({
283
+ location: { offset: node.offset, length: node.length },
284
+ message: schema.errorMessage || localize('typeArrayMismatchWarning', 'Incorrect type. Expected one of {0}.', schema.type.join(', '))
285
+ });
286
+ }
287
+ }
288
+ else if (schema.type) {
289
+ if (!matchesType(schema.type)) {
290
+ validationResult.problems.push({
291
+ location: { offset: node.offset, length: node.length },
292
+ message: schema.errorMessage || localize('typeMismatchWarning', 'Incorrect type. Expected "{0}".', schema.type)
293
+ });
294
+ }
295
+ }
296
+ if (Array.isArray(schema.allOf)) {
297
+ for (const subSchemaRef of schema.allOf) {
298
+ validate(node, asSchema(subSchemaRef), validationResult, matchingSchemas);
299
+ }
300
+ }
301
+ const notSchema = asSchema(schema.not);
302
+ if (notSchema) {
303
+ const subValidationResult = new ValidationResult();
304
+ const subMatchingSchemas = matchingSchemas.newSub();
305
+ validate(node, notSchema, subValidationResult, subMatchingSchemas);
306
+ if (!subValidationResult.hasProblems()) {
307
+ validationResult.problems.push({
308
+ location: { offset: node.offset, length: node.length },
309
+ message: localize('notSchemaWarning', "Matches a schema that is not allowed.")
310
+ });
311
+ }
312
+ for (const ms of subMatchingSchemas.schemas) {
313
+ ms.inverted = !ms.inverted;
314
+ matchingSchemas.add(ms);
315
+ }
316
+ }
317
+ const testAlternatives = (alternatives, maxOneMatch) => {
318
+ const matches = [];
319
+ // remember the best match that is used for error messages
320
+ let bestMatch = undefined;
321
+ for (const subSchemaRef of alternatives) {
322
+ const subSchema = asSchema(subSchemaRef);
323
+ const subValidationResult = new ValidationResult();
324
+ const subMatchingSchemas = matchingSchemas.newSub();
325
+ validate(node, subSchema, subValidationResult, subMatchingSchemas);
326
+ if (!subValidationResult.hasProblems()) {
327
+ matches.push(subSchema);
328
+ }
329
+ if (!bestMatch) {
330
+ bestMatch = { schema: subSchema, validationResult: subValidationResult, matchingSchemas: subMatchingSchemas };
331
+ }
332
+ else {
333
+ if (!maxOneMatch && !subValidationResult.hasProblems() && !bestMatch.validationResult.hasProblems()) {
334
+ // no errors, both are equally good matches
335
+ bestMatch.matchingSchemas.merge(subMatchingSchemas);
336
+ bestMatch.validationResult.propertiesMatches += subValidationResult.propertiesMatches;
337
+ bestMatch.validationResult.propertiesValueMatches += subValidationResult.propertiesValueMatches;
338
+ bestMatch.validationResult.mergeProcessedProperties(subValidationResult);
339
+ }
340
+ else {
341
+ const compareResult = subValidationResult.compare(bestMatch.validationResult);
342
+ if (compareResult > 0) {
343
+ // our node is the best matching so far
344
+ bestMatch = { schema: subSchema, validationResult: subValidationResult, matchingSchemas: subMatchingSchemas };
345
+ }
346
+ else if (compareResult === 0) {
347
+ // there's already a best matching but we are as good
348
+ bestMatch.matchingSchemas.merge(subMatchingSchemas);
349
+ bestMatch.validationResult.mergeEnumValues(subValidationResult);
350
+ }
351
+ }
352
+ }
353
+ }
354
+ if (matches.length > 1 && maxOneMatch) {
355
+ validationResult.problems.push({
356
+ location: { offset: node.offset, length: 1 },
357
+ message: localize('oneOfWarning', "Matches multiple schemas when only one must validate.")
358
+ });
359
+ }
360
+ if (bestMatch) {
361
+ validationResult.merge(bestMatch.validationResult);
362
+ validationResult.propertiesMatches += bestMatch.validationResult.propertiesMatches;
363
+ validationResult.propertiesValueMatches += bestMatch.validationResult.propertiesValueMatches;
364
+ validationResult.mergeProcessedProperties(bestMatch.validationResult);
365
+ matchingSchemas.merge(bestMatch.matchingSchemas);
366
+ }
367
+ return matches.length;
368
+ };
369
+ if (Array.isArray(schema.anyOf)) {
370
+ testAlternatives(schema.anyOf, false);
371
+ }
372
+ if (Array.isArray(schema.oneOf)) {
373
+ testAlternatives(schema.oneOf, true);
374
+ }
375
+ const testBranch = (schema) => {
376
+ const subValidationResult = new ValidationResult();
377
+ const subMatchingSchemas = matchingSchemas.newSub();
378
+ validate(node, asSchema(schema), subValidationResult, subMatchingSchemas);
379
+ validationResult.merge(subValidationResult);
380
+ validationResult.propertiesMatches += subValidationResult.propertiesMatches;
381
+ validationResult.propertiesValueMatches += subValidationResult.propertiesValueMatches;
382
+ validationResult.mergeProcessedProperties(subValidationResult);
383
+ matchingSchemas.merge(subMatchingSchemas);
384
+ };
385
+ const testCondition = (ifSchema, thenSchema, elseSchema) => {
386
+ const subSchema = asSchema(ifSchema);
387
+ const subValidationResult = new ValidationResult();
388
+ const subMatchingSchemas = matchingSchemas.newSub();
389
+ validate(node, subSchema, subValidationResult, subMatchingSchemas);
390
+ matchingSchemas.merge(subMatchingSchemas);
391
+ validationResult.mergeProcessedProperties(subValidationResult);
392
+ if (!subValidationResult.hasProblems()) {
393
+ if (thenSchema) {
394
+ testBranch(thenSchema);
395
+ }
396
+ }
397
+ else if (elseSchema) {
398
+ testBranch(elseSchema);
399
+ }
400
+ };
401
+ const ifSchema = asSchema(schema.if);
402
+ if (ifSchema) {
403
+ testCondition(ifSchema, asSchema(schema.then), asSchema(schema.else));
404
+ }
405
+ if (Array.isArray(schema.enum)) {
406
+ const val = getNodeValue(node);
407
+ let enumValueMatch = false;
408
+ for (const e of schema.enum) {
409
+ if (equals(val, e)) {
410
+ enumValueMatch = true;
411
+ break;
412
+ }
413
+ }
414
+ validationResult.enumValues = schema.enum;
415
+ validationResult.enumValueMatch = enumValueMatch;
416
+ if (!enumValueMatch) {
417
+ validationResult.problems.push({
418
+ location: { offset: node.offset, length: node.length },
419
+ code: ErrorCode.EnumValueMismatch,
420
+ message: schema.errorMessage || localize('enumWarning', 'Value is not accepted. Valid values: {0}.', schema.enum.map(v => JSON.stringify(v)).join(', '))
421
+ });
422
+ }
423
+ }
424
+ if (isDefined(schema.const)) {
425
+ const val = getNodeValue(node);
426
+ if (!equals(val, schema.const)) {
427
+ validationResult.problems.push({
428
+ location: { offset: node.offset, length: node.length },
429
+ code: ErrorCode.EnumValueMismatch,
430
+ message: schema.errorMessage || localize('constWarning', 'Value must be {0}.', JSON.stringify(schema.const))
431
+ });
432
+ validationResult.enumValueMatch = false;
433
+ }
434
+ else {
435
+ validationResult.enumValueMatch = true;
436
+ }
437
+ validationResult.enumValues = [schema.const];
438
+ }
439
+ let deprecationMessage = schema.deprecationMessage;
440
+ if ((deprecationMessage || schema.deprecated) && node.parent) {
441
+ deprecationMessage = deprecationMessage || localize('deprecated', 'Value is deprecated');
442
+ validationResult.problems.push({
443
+ location: { offset: node.parent.offset, length: node.parent.length },
444
+ severity: DiagnosticSeverity.Warning,
445
+ message: deprecationMessage,
446
+ code: ErrorCode.Deprecated
447
+ });
448
+ }
449
+ }
450
+ function _validateNumberNode(node) {
451
+ const val = node.value;
452
+ function normalizeFloats(float) {
453
+ const parts = /^(-?\d+)(?:\.(\d+))?(?:e([-+]\d+))?$/.exec(float.toString());
454
+ return parts && {
455
+ value: Number(parts[1] + (parts[2] || '')),
456
+ multiplier: (parts[2]?.length || 0) - (parseInt(parts[3]) || 0)
457
+ };
458
+ }
459
+ ;
460
+ if (isNumber(schema.multipleOf)) {
461
+ let remainder = -1;
462
+ if (Number.isInteger(schema.multipleOf)) {
463
+ remainder = val % schema.multipleOf;
464
+ }
465
+ else {
466
+ let normMultipleOf = normalizeFloats(schema.multipleOf);
467
+ let normValue = normalizeFloats(val);
468
+ if (normMultipleOf && normValue) {
469
+ const multiplier = 10 ** Math.abs(normValue.multiplier - normMultipleOf.multiplier);
470
+ if (normValue.multiplier < normMultipleOf.multiplier) {
471
+ normValue.value *= multiplier;
472
+ }
473
+ else {
474
+ normMultipleOf.value *= multiplier;
475
+ }
476
+ remainder = normValue.value % normMultipleOf.value;
477
+ }
478
+ }
479
+ if (remainder !== 0) {
480
+ validationResult.problems.push({
481
+ location: { offset: node.offset, length: node.length },
482
+ message: localize('multipleOfWarning', 'Value is not divisible by {0}.', schema.multipleOf)
483
+ });
484
+ }
485
+ }
486
+ function getExclusiveLimit(limit, exclusive) {
487
+ if (isNumber(exclusive)) {
488
+ return exclusive;
489
+ }
490
+ if (isBoolean(exclusive) && exclusive) {
491
+ return limit;
492
+ }
493
+ return undefined;
494
+ }
495
+ function getLimit(limit, exclusive) {
496
+ if (!isBoolean(exclusive) || !exclusive) {
497
+ return limit;
498
+ }
499
+ return undefined;
500
+ }
501
+ const exclusiveMinimum = getExclusiveLimit(schema.minimum, schema.exclusiveMinimum);
502
+ if (isNumber(exclusiveMinimum) && val <= exclusiveMinimum) {
503
+ validationResult.problems.push({
504
+ location: { offset: node.offset, length: node.length },
505
+ message: localize('exclusiveMinimumWarning', 'Value is below the exclusive minimum of {0}.', exclusiveMinimum)
506
+ });
507
+ }
508
+ const exclusiveMaximum = getExclusiveLimit(schema.maximum, schema.exclusiveMaximum);
509
+ if (isNumber(exclusiveMaximum) && val >= exclusiveMaximum) {
510
+ validationResult.problems.push({
511
+ location: { offset: node.offset, length: node.length },
512
+ message: localize('exclusiveMaximumWarning', 'Value is above the exclusive maximum of {0}.', exclusiveMaximum)
513
+ });
514
+ }
515
+ const minimum = getLimit(schema.minimum, schema.exclusiveMinimum);
516
+ if (isNumber(minimum) && val < minimum) {
517
+ validationResult.problems.push({
518
+ location: { offset: node.offset, length: node.length },
519
+ message: localize('minimumWarning', 'Value is below the minimum of {0}.', minimum)
520
+ });
521
+ }
522
+ const maximum = getLimit(schema.maximum, schema.exclusiveMaximum);
523
+ if (isNumber(maximum) && val > maximum) {
524
+ validationResult.problems.push({
525
+ location: { offset: node.offset, length: node.length },
526
+ message: localize('maximumWarning', 'Value is above the maximum of {0}.', maximum)
527
+ });
528
+ }
529
+ }
530
+ function _validateStringNode(node) {
531
+ if (isNumber(schema.minLength) && node.value.length < schema.minLength) {
532
+ validationResult.problems.push({
533
+ location: { offset: node.offset, length: node.length },
534
+ message: localize('minLengthWarning', 'String is shorter than the minimum length of {0}.', schema.minLength)
535
+ });
536
+ }
537
+ if (isNumber(schema.maxLength) && node.value.length > schema.maxLength) {
538
+ validationResult.problems.push({
539
+ location: { offset: node.offset, length: node.length },
540
+ message: localize('maxLengthWarning', 'String is longer than the maximum length of {0}.', schema.maxLength)
541
+ });
542
+ }
543
+ if (isString(schema.pattern)) {
544
+ const regex = extendedRegExp(schema.pattern);
545
+ if (!(regex?.test(node.value))) {
546
+ validationResult.problems.push({
547
+ location: { offset: node.offset, length: node.length },
548
+ message: schema.patternErrorMessage || schema.errorMessage || localize('patternWarning', 'String does not match the pattern of "{0}".', schema.pattern)
549
+ });
550
+ }
551
+ }
552
+ if (schema.format) {
553
+ switch (schema.format) {
554
+ case 'uri':
555
+ case 'uri-reference':
556
+ {
557
+ let errorMessage;
558
+ if (!node.value) {
559
+ errorMessage = localize('uriEmpty', 'URI expected.');
560
+ }
561
+ else {
562
+ const match = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/.exec(node.value);
563
+ if (!match) {
564
+ errorMessage = localize('uriMissing', 'URI is expected.');
565
+ }
566
+ else if (!match[2] && schema.format === 'uri') {
567
+ errorMessage = localize('uriSchemeMissing', 'URI with a scheme is expected.');
568
+ }
569
+ }
570
+ if (errorMessage) {
571
+ validationResult.problems.push({
572
+ location: { offset: node.offset, length: node.length },
573
+ message: schema.patternErrorMessage || schema.errorMessage || localize('uriFormatWarning', 'String is not a URI: {0}', errorMessage)
574
+ });
575
+ }
576
+ }
577
+ break;
578
+ case 'color-hex':
579
+ case 'date-time':
580
+ case 'date':
581
+ case 'time':
582
+ case 'email':
583
+ case 'hostname':
584
+ case 'ipv4':
585
+ case 'ipv6':
586
+ const format = formats[schema.format];
587
+ if (!node.value || !format.pattern.exec(node.value)) {
588
+ validationResult.problems.push({
589
+ location: { offset: node.offset, length: node.length },
590
+ message: schema.patternErrorMessage || schema.errorMessage || format.errorMessage
591
+ });
592
+ }
593
+ default:
594
+ }
595
+ }
596
+ }
597
+ function _validateArrayNode(node) {
598
+ let prefixItemsSchemas;
599
+ let additionalItemSchema;
600
+ let isSchema_2020_12 = Array.isArray(schema.prefixItems) || (schema.items !== undefined && !Array.isArray(schema.items) && schema.additionalItems === undefined);
601
+ if (isSchema_2020_12) {
602
+ prefixItemsSchemas = schema.prefixItems;
603
+ additionalItemSchema = !Array.isArray(schema.items) ? schema.items : undefined;
604
+ }
605
+ else {
606
+ prefixItemsSchemas = Array.isArray(schema.items) ? schema.items : undefined;
607
+ additionalItemSchema = !Array.isArray(schema.items) ? schema.items : schema.additionalItems;
608
+ }
609
+ let index = 0;
610
+ if (prefixItemsSchemas !== undefined) {
611
+ const max = Math.min(prefixItemsSchemas.length, node.items.length);
612
+ for (; index < max; index++) {
613
+ const subSchemaRef = prefixItemsSchemas[index];
614
+ const subSchema = asSchema(subSchemaRef);
615
+ const itemValidationResult = new ValidationResult();
616
+ const item = node.items[index];
617
+ if (item) {
618
+ validate(item, subSchema, itemValidationResult, matchingSchemas);
619
+ validationResult.mergePropertyMatch(itemValidationResult);
620
+ }
621
+ validationResult.processedProperties.add(String(index));
622
+ }
623
+ }
624
+ if (additionalItemSchema !== undefined && index < node.items.length) {
625
+ if (typeof additionalItemSchema === 'boolean') {
626
+ if (additionalItemSchema === false) {
627
+ validationResult.problems.push({
628
+ location: { offset: node.offset, length: node.length },
629
+ message: localize('additionalItemsWarning', 'Array has too many items according to schema. Expected {0} or fewer.', index)
630
+ });
631
+ }
632
+ for (; index < node.items.length; index++) {
633
+ validationResult.processedProperties.add(String(index));
634
+ validationResult.propertiesValueMatches++;
635
+ }
636
+ }
637
+ else {
638
+ for (; index < node.items.length; index++) {
639
+ const itemValidationResult = new ValidationResult();
640
+ validate(node.items[index], additionalItemSchema, itemValidationResult, matchingSchemas);
641
+ validationResult.mergePropertyMatch(itemValidationResult);
642
+ validationResult.processedProperties.add(String(index));
643
+ }
644
+ }
645
+ }
646
+ const containsSchema = asSchema(schema.contains);
647
+ if (containsSchema) {
648
+ let containsCount = 0;
649
+ for (let index = 0; index < node.items.length; index++) {
650
+ const item = node.items[index];
651
+ const itemValidationResult = new ValidationResult();
652
+ validate(item, containsSchema, itemValidationResult, NoOpSchemaCollector.instance);
653
+ if (!itemValidationResult.hasProblems()) {
654
+ containsCount++;
655
+ if (isSchema_2020_12) {
656
+ validationResult.processedProperties.add(String(index));
657
+ }
658
+ }
659
+ }
660
+ if (containsCount === 0 && !isNumber(schema.minContains)) {
661
+ validationResult.problems.push({
662
+ location: { offset: node.offset, length: node.length },
663
+ message: schema.errorMessage || localize('requiredItemMissingWarning', 'Array does not contain required item.')
664
+ });
665
+ }
666
+ if (isNumber(schema.minContains) && containsCount < schema.minContains) {
667
+ validationResult.problems.push({
668
+ location: { offset: node.offset, length: node.length },
669
+ message: localize('minContainsWarning', 'Array has too few items that match the contains contraint. Expected {0} or more.', schema.minContains)
670
+ });
671
+ }
672
+ if (isNumber(schema.maxContains) && containsCount > schema.maxContains) {
673
+ validationResult.problems.push({
674
+ location: { offset: node.offset, length: node.length },
675
+ message: localize('maxContainsWarning', 'Array has too many items that match the contains contraint. Expected {0} or less.', schema.maxContains)
676
+ });
677
+ }
678
+ }
679
+ const unevaluatedItems = schema.unevaluatedItems;
680
+ if (unevaluatedItems !== undefined) {
681
+ for (let i = 0; i < node.items.length; i++) {
682
+ if (!validationResult.processedProperties.has(String(i))) {
683
+ if (unevaluatedItems === false) {
684
+ validationResult.problems.push({
685
+ location: { offset: node.offset, length: node.length },
686
+ message: localize('unevaluatedItemsWarning', 'Item does not match any validation rule from the array.')
687
+ });
688
+ }
689
+ else {
690
+ const itemValidationResult = new ValidationResult();
691
+ validate(node.items[i], schema.additionalItems, itemValidationResult, matchingSchemas);
692
+ validationResult.mergePropertyMatch(itemValidationResult);
693
+ }
694
+ }
695
+ validationResult.processedProperties.add(String(i));
696
+ validationResult.propertiesValueMatches++;
697
+ }
698
+ }
699
+ if (isNumber(schema.minItems) && node.items.length < schema.minItems) {
700
+ validationResult.problems.push({
701
+ location: { offset: node.offset, length: node.length },
702
+ message: localize('minItemsWarning', 'Array has too few items. Expected {0} or more.', schema.minItems)
703
+ });
704
+ }
705
+ if (isNumber(schema.maxItems) && node.items.length > schema.maxItems) {
706
+ validationResult.problems.push({
707
+ location: { offset: node.offset, length: node.length },
708
+ message: localize('maxItemsWarning', 'Array has too many items. Expected {0} or fewer.', schema.maxItems)
709
+ });
710
+ }
711
+ if (schema.uniqueItems === true) {
712
+ const values = getNodeValue(node);
713
+ const duplicates = values.some((value, index) => {
714
+ return index !== values.lastIndexOf(value);
715
+ });
716
+ if (duplicates) {
717
+ validationResult.problems.push({
718
+ location: { offset: node.offset, length: node.length },
719
+ message: localize('uniqueItemsWarning', 'Array has duplicate items.')
720
+ });
721
+ }
722
+ }
723
+ }
724
+ function _validateObjectNode(node) {
725
+ const seenKeys = Object.create(null);
726
+ const unprocessedProperties = new Set();
727
+ for (const propertyNode of node.properties) {
728
+ const key = propertyNode.keyNode.value;
729
+ seenKeys[key] = propertyNode.valueNode;
730
+ unprocessedProperties.add(key);
731
+ }
732
+ if (Array.isArray(schema.required)) {
733
+ for (const propertyName of schema.required) {
734
+ if (!seenKeys[propertyName]) {
735
+ const keyNode = node.parent && node.parent.type === 'property' && node.parent.keyNode;
736
+ const location = keyNode ? { offset: keyNode.offset, length: keyNode.length } : { offset: node.offset, length: 1 };
737
+ validationResult.problems.push({
738
+ location: location,
739
+ message: localize('MissingRequiredPropWarning', 'Missing property "{0}".', propertyName)
740
+ });
741
+ }
742
+ }
743
+ }
744
+ const propertyProcessed = (prop) => {
745
+ unprocessedProperties.delete(prop);
746
+ validationResult.processedProperties.add(prop);
747
+ };
748
+ if (schema.properties) {
749
+ for (const propertyName of Object.keys(schema.properties)) {
750
+ propertyProcessed(propertyName);
751
+ const propertySchema = schema.properties[propertyName];
752
+ const child = seenKeys[propertyName];
753
+ if (child) {
754
+ if (isBoolean(propertySchema)) {
755
+ if (!propertySchema) {
756
+ const propertyNode = child.parent;
757
+ validationResult.problems.push({
758
+ location: { offset: propertyNode.keyNode.offset, length: propertyNode.keyNode.length },
759
+ message: schema.errorMessage || localize('DisallowedExtraPropWarning', 'Property {0} is not allowed.', propertyName)
760
+ });
761
+ }
762
+ else {
763
+ validationResult.propertiesMatches++;
764
+ validationResult.propertiesValueMatches++;
765
+ }
766
+ }
767
+ else {
768
+ const propertyValidationResult = new ValidationResult();
769
+ validate(child, propertySchema, propertyValidationResult, matchingSchemas);
770
+ validationResult.mergePropertyMatch(propertyValidationResult);
771
+ }
772
+ }
773
+ }
774
+ }
775
+ if (schema.patternProperties) {
776
+ for (const propertyPattern of Object.keys(schema.patternProperties)) {
777
+ const regex = extendedRegExp(propertyPattern);
778
+ if (regex) {
779
+ const processed = [];
780
+ for (const propertyName of unprocessedProperties) {
781
+ if (regex.test(propertyName)) {
782
+ processed.push(propertyName);
783
+ const child = seenKeys[propertyName];
784
+ if (child) {
785
+ const propertySchema = schema.patternProperties[propertyPattern];
786
+ if (isBoolean(propertySchema)) {
787
+ if (!propertySchema) {
788
+ const propertyNode = child.parent;
789
+ validationResult.problems.push({
790
+ location: { offset: propertyNode.keyNode.offset, length: propertyNode.keyNode.length },
791
+ message: schema.errorMessage || localize('DisallowedExtraPropWarning', 'Property {0} is not allowed.', propertyName)
792
+ });
793
+ }
794
+ else {
795
+ validationResult.propertiesMatches++;
796
+ validationResult.propertiesValueMatches++;
797
+ }
798
+ }
799
+ else {
800
+ const propertyValidationResult = new ValidationResult();
801
+ validate(child, propertySchema, propertyValidationResult, matchingSchemas);
802
+ validationResult.mergePropertyMatch(propertyValidationResult);
803
+ }
804
+ }
805
+ }
806
+ }
807
+ processed.forEach(propertyProcessed);
808
+ }
809
+ }
810
+ }
811
+ const additionalProperties = schema.additionalProperties;
812
+ if (additionalProperties !== undefined && additionalProperties !== true) {
813
+ for (const propertyName of unprocessedProperties) {
814
+ propertyProcessed(propertyName);
815
+ const child = seenKeys[propertyName];
816
+ if (child) {
817
+ if (additionalProperties === false) {
818
+ const propertyNode = child.parent;
819
+ validationResult.problems.push({
820
+ location: { offset: propertyNode.keyNode.offset, length: propertyNode.keyNode.length },
821
+ message: schema.errorMessage || localize('DisallowedExtraPropWarning', 'Property {0} is not allowed.', propertyName)
822
+ });
823
+ }
824
+ else {
825
+ const propertyValidationResult = new ValidationResult();
826
+ validate(child, additionalProperties, propertyValidationResult, matchingSchemas);
827
+ validationResult.mergePropertyMatch(propertyValidationResult);
828
+ }
829
+ }
830
+ }
831
+ }
832
+ const unevaluatedProperties = schema.unevaluatedProperties;
833
+ if (unevaluatedProperties !== undefined && unevaluatedProperties !== true) {
834
+ const processed = [];
835
+ for (const propertyName of unprocessedProperties) {
836
+ if (!validationResult.processedProperties.has(propertyName)) {
837
+ processed.push(propertyName);
838
+ const child = seenKeys[propertyName];
839
+ if (child) {
840
+ if (unevaluatedProperties === false) {
841
+ const propertyNode = child.parent;
842
+ validationResult.problems.push({
843
+ location: { offset: propertyNode.keyNode.offset, length: propertyNode.keyNode.length },
844
+ message: schema.errorMessage || localize('DisallowedExtraPropWarning', 'Property {0} is not allowed.', propertyName)
845
+ });
846
+ }
847
+ else {
848
+ const propertyValidationResult = new ValidationResult();
849
+ validate(child, unevaluatedProperties, propertyValidationResult, matchingSchemas);
850
+ validationResult.mergePropertyMatch(propertyValidationResult);
851
+ }
852
+ }
853
+ }
854
+ }
855
+ processed.forEach(propertyProcessed);
856
+ }
857
+ if (isNumber(schema.maxProperties)) {
858
+ if (node.properties.length > schema.maxProperties) {
859
+ validationResult.problems.push({
860
+ location: { offset: node.offset, length: node.length },
861
+ message: localize('MaxPropWarning', 'Object has more properties than limit of {0}.', schema.maxProperties)
862
+ });
863
+ }
864
+ }
865
+ if (isNumber(schema.minProperties)) {
866
+ if (node.properties.length < schema.minProperties) {
867
+ validationResult.problems.push({
868
+ location: { offset: node.offset, length: node.length },
869
+ message: localize('MinPropWarning', 'Object has fewer properties than the required number of {0}', schema.minProperties)
870
+ });
871
+ }
872
+ }
873
+ if (schema.dependentRequired) {
874
+ for (const key in schema.dependentRequired) {
875
+ const prop = seenKeys[key];
876
+ const propertyDeps = schema.dependentRequired[key];
877
+ if (prop && Array.isArray(propertyDeps)) {
878
+ _validatePropertyDependencies(key, propertyDeps);
879
+ }
880
+ }
881
+ }
882
+ if (schema.dependentSchemas) {
883
+ for (const key in schema.dependentSchemas) {
884
+ const prop = seenKeys[key];
885
+ const propertyDeps = schema.dependentSchemas[key];
886
+ if (prop && isObject(propertyDeps)) {
887
+ _validatePropertyDependencies(key, propertyDeps);
888
+ }
889
+ }
890
+ }
891
+ if (schema.dependencies) {
892
+ for (const key in schema.dependencies) {
893
+ const prop = seenKeys[key];
894
+ if (prop) {
895
+ _validatePropertyDependencies(key, schema.dependencies[key]);
896
+ }
897
+ }
898
+ }
899
+ const propertyNames = asSchema(schema.propertyNames);
900
+ if (propertyNames) {
901
+ for (const f of node.properties) {
902
+ const key = f.keyNode;
903
+ if (key) {
904
+ validate(key, propertyNames, validationResult, NoOpSchemaCollector.instance);
905
+ }
906
+ }
907
+ }
908
+ function _validatePropertyDependencies(key, propertyDep) {
909
+ if (Array.isArray(propertyDep)) {
910
+ for (const requiredProp of propertyDep) {
911
+ if (!seenKeys[requiredProp]) {
912
+ validationResult.problems.push({
913
+ location: { offset: node.offset, length: node.length },
914
+ message: localize('RequiredDependentPropWarning', 'Object is missing property {0} required by property {1}.', requiredProp, key)
915
+ });
916
+ }
917
+ else {
918
+ validationResult.propertiesValueMatches++;
919
+ }
920
+ }
921
+ }
922
+ else {
923
+ const propertySchema = asSchema(propertyDep);
924
+ if (propertySchema) {
925
+ const propertyValidationResult = new ValidationResult();
926
+ validate(node, propertySchema, propertyValidationResult, matchingSchemas);
927
+ validationResult.mergePropertyMatch(propertyValidationResult);
928
+ }
929
+ }
930
+ }
931
+ }
932
+ }
933
+ export function parse(textDocument, config) {
934
+ const problems = [];
935
+ let lastProblemOffset = -1;
936
+ const text = textDocument.getText();
937
+ const scanner = Json.createScanner(text, false);
938
+ const commentRanges = config && config.collectComments ? [] : undefined;
939
+ function _scanNext() {
940
+ while (true) {
941
+ const token = scanner.scan();
942
+ _checkScanError();
943
+ switch (token) {
944
+ case 12 /* LineCommentTrivia */:
945
+ case 13 /* BlockCommentTrivia */:
946
+ if (Array.isArray(commentRanges)) {
947
+ commentRanges.push(Range.create(textDocument.positionAt(scanner.getTokenOffset()), textDocument.positionAt(scanner.getTokenOffset() + scanner.getTokenLength())));
948
+ }
949
+ break;
950
+ case 15 /* Trivia */:
951
+ case 14 /* LineBreakTrivia */:
952
+ break;
953
+ default:
954
+ return token;
955
+ }
956
+ }
957
+ }
958
+ function _accept(token) {
959
+ if (scanner.getToken() === token) {
960
+ _scanNext();
961
+ return true;
962
+ }
963
+ return false;
964
+ }
965
+ function _errorAtRange(message, code, startOffset, endOffset, severity = DiagnosticSeverity.Error) {
966
+ if (problems.length === 0 || startOffset !== lastProblemOffset) {
967
+ const range = Range.create(textDocument.positionAt(startOffset), textDocument.positionAt(endOffset));
968
+ problems.push(Diagnostic.create(range, message, severity, code, textDocument.languageId));
969
+ lastProblemOffset = startOffset;
970
+ }
971
+ }
972
+ function _error(message, code, node = undefined, skipUntilAfter = [], skipUntil = []) {
973
+ let start = scanner.getTokenOffset();
974
+ let end = scanner.getTokenOffset() + scanner.getTokenLength();
975
+ if (start === end && start > 0) {
976
+ start--;
977
+ while (start > 0 && /\s/.test(text.charAt(start))) {
978
+ start--;
979
+ }
980
+ end = start + 1;
981
+ }
982
+ _errorAtRange(message, code, start, end);
983
+ if (node) {
984
+ _finalize(node, false);
985
+ }
986
+ if (skipUntilAfter.length + skipUntil.length > 0) {
987
+ let token = scanner.getToken();
988
+ while (token !== 17 /* EOF */) {
989
+ if (skipUntilAfter.indexOf(token) !== -1) {
990
+ _scanNext();
991
+ break;
992
+ }
993
+ else if (skipUntil.indexOf(token) !== -1) {
994
+ break;
995
+ }
996
+ token = _scanNext();
997
+ }
998
+ }
999
+ return node;
1000
+ }
1001
+ function _checkScanError() {
1002
+ switch (scanner.getTokenError()) {
1003
+ case 4 /* InvalidUnicode */:
1004
+ _error(localize('InvalidUnicode', 'Invalid unicode sequence in string.'), ErrorCode.InvalidUnicode);
1005
+ return true;
1006
+ case 5 /* InvalidEscapeCharacter */:
1007
+ _error(localize('InvalidEscapeCharacter', 'Invalid escape character in string.'), ErrorCode.InvalidEscapeCharacter);
1008
+ return true;
1009
+ case 3 /* UnexpectedEndOfNumber */:
1010
+ _error(localize('UnexpectedEndOfNumber', 'Unexpected end of number.'), ErrorCode.UnexpectedEndOfNumber);
1011
+ return true;
1012
+ case 1 /* UnexpectedEndOfComment */:
1013
+ _error(localize('UnexpectedEndOfComment', 'Unexpected end of comment.'), ErrorCode.UnexpectedEndOfComment);
1014
+ return true;
1015
+ case 2 /* UnexpectedEndOfString */:
1016
+ _error(localize('UnexpectedEndOfString', 'Unexpected end of string.'), ErrorCode.UnexpectedEndOfString);
1017
+ return true;
1018
+ case 6 /* InvalidCharacter */:
1019
+ _error(localize('InvalidCharacter', 'Invalid characters in string. Control characters must be escaped.'), ErrorCode.InvalidCharacter);
1020
+ return true;
1021
+ }
1022
+ return false;
1023
+ }
1024
+ function _finalize(node, scanNext) {
1025
+ node.length = scanner.getTokenOffset() + scanner.getTokenLength() - node.offset;
1026
+ if (scanNext) {
1027
+ _scanNext();
1028
+ }
1029
+ return node;
1030
+ }
1031
+ function _parseArray(parent) {
1032
+ if (scanner.getToken() !== 3 /* OpenBracketToken */) {
1033
+ return undefined;
1034
+ }
1035
+ const node = new ArrayASTNodeImpl(parent, scanner.getTokenOffset());
1036
+ _scanNext(); // consume OpenBracketToken
1037
+ const count = 0;
1038
+ let needsComma = false;
1039
+ while (scanner.getToken() !== 4 /* CloseBracketToken */ && scanner.getToken() !== 17 /* EOF */) {
1040
+ if (scanner.getToken() === 5 /* CommaToken */) {
1041
+ if (!needsComma) {
1042
+ _error(localize('ValueExpected', 'Value expected'), ErrorCode.ValueExpected);
1043
+ }
1044
+ const commaOffset = scanner.getTokenOffset();
1045
+ _scanNext(); // consume comma
1046
+ if (scanner.getToken() === 4 /* CloseBracketToken */) {
1047
+ if (needsComma) {
1048
+ _errorAtRange(localize('TrailingComma', 'Trailing comma'), ErrorCode.TrailingComma, commaOffset, commaOffset + 1);
1049
+ }
1050
+ continue;
1051
+ }
1052
+ }
1053
+ else if (needsComma) {
1054
+ _error(localize('ExpectedComma', 'Expected comma'), ErrorCode.CommaExpected);
1055
+ }
1056
+ const item = _parseValue(node);
1057
+ if (!item) {
1058
+ _error(localize('PropertyExpected', 'Value expected'), ErrorCode.ValueExpected, undefined, [], [4 /* CloseBracketToken */, 5 /* CommaToken */]);
1059
+ }
1060
+ else {
1061
+ node.items.push(item);
1062
+ }
1063
+ needsComma = true;
1064
+ }
1065
+ if (scanner.getToken() !== 4 /* CloseBracketToken */) {
1066
+ return _error(localize('ExpectedCloseBracket', 'Expected comma or closing bracket'), ErrorCode.CommaOrCloseBacketExpected, node);
1067
+ }
1068
+ return _finalize(node, true);
1069
+ }
1070
+ const keyPlaceholder = new StringASTNodeImpl(undefined, 0, 0);
1071
+ function _parseProperty(parent, keysSeen) {
1072
+ const node = new PropertyASTNodeImpl(parent, scanner.getTokenOffset(), keyPlaceholder);
1073
+ let key = _parseString(node);
1074
+ if (!key) {
1075
+ if (scanner.getToken() === 16 /* Unknown */) {
1076
+ // give a more helpful error message
1077
+ _error(localize('DoubleQuotesExpected', 'Property keys must be doublequoted'), ErrorCode.Undefined);
1078
+ const keyNode = new StringASTNodeImpl(node, scanner.getTokenOffset(), scanner.getTokenLength());
1079
+ keyNode.value = scanner.getTokenValue();
1080
+ key = keyNode;
1081
+ _scanNext(); // consume Unknown
1082
+ }
1083
+ else {
1084
+ return undefined;
1085
+ }
1086
+ }
1087
+ node.keyNode = key;
1088
+ const seen = keysSeen[key.value];
1089
+ if (seen) {
1090
+ _errorAtRange(localize('DuplicateKeyWarning', "Duplicate object key"), ErrorCode.DuplicateKey, node.keyNode.offset, node.keyNode.offset + node.keyNode.length, DiagnosticSeverity.Warning);
1091
+ if (isObject(seen)) {
1092
+ _errorAtRange(localize('DuplicateKeyWarning', "Duplicate object key"), ErrorCode.DuplicateKey, seen.keyNode.offset, seen.keyNode.offset + seen.keyNode.length, DiagnosticSeverity.Warning);
1093
+ }
1094
+ keysSeen[key.value] = true; // if the same key is duplicate again, avoid duplicate error reporting
1095
+ }
1096
+ else {
1097
+ keysSeen[key.value] = node;
1098
+ }
1099
+ if (scanner.getToken() === 6 /* ColonToken */) {
1100
+ node.colonOffset = scanner.getTokenOffset();
1101
+ _scanNext(); // consume ColonToken
1102
+ }
1103
+ else {
1104
+ _error(localize('ColonExpected', 'Colon expected'), ErrorCode.ColonExpected);
1105
+ if (scanner.getToken() === 10 /* StringLiteral */ && textDocument.positionAt(key.offset + key.length).line < textDocument.positionAt(scanner.getTokenOffset()).line) {
1106
+ node.length = key.length;
1107
+ return node;
1108
+ }
1109
+ }
1110
+ const value = _parseValue(node);
1111
+ if (!value) {
1112
+ return _error(localize('ValueExpected', 'Value expected'), ErrorCode.ValueExpected, node, [], [2 /* CloseBraceToken */, 5 /* CommaToken */]);
1113
+ }
1114
+ node.valueNode = value;
1115
+ node.length = value.offset + value.length - node.offset;
1116
+ return node;
1117
+ }
1118
+ function _parseObject(parent) {
1119
+ if (scanner.getToken() !== 1 /* OpenBraceToken */) {
1120
+ return undefined;
1121
+ }
1122
+ const node = new ObjectASTNodeImpl(parent, scanner.getTokenOffset());
1123
+ const keysSeen = Object.create(null);
1124
+ _scanNext(); // consume OpenBraceToken
1125
+ let needsComma = false;
1126
+ while (scanner.getToken() !== 2 /* CloseBraceToken */ && scanner.getToken() !== 17 /* EOF */) {
1127
+ if (scanner.getToken() === 5 /* CommaToken */) {
1128
+ if (!needsComma) {
1129
+ _error(localize('PropertyExpected', 'Property expected'), ErrorCode.PropertyExpected);
1130
+ }
1131
+ const commaOffset = scanner.getTokenOffset();
1132
+ _scanNext(); // consume comma
1133
+ if (scanner.getToken() === 2 /* CloseBraceToken */) {
1134
+ if (needsComma) {
1135
+ _errorAtRange(localize('TrailingComma', 'Trailing comma'), ErrorCode.TrailingComma, commaOffset, commaOffset + 1);
1136
+ }
1137
+ continue;
1138
+ }
1139
+ }
1140
+ else if (needsComma) {
1141
+ _error(localize('ExpectedComma', 'Expected comma'), ErrorCode.CommaExpected);
1142
+ }
1143
+ const property = _parseProperty(node, keysSeen);
1144
+ if (!property) {
1145
+ _error(localize('PropertyExpected', 'Property expected'), ErrorCode.PropertyExpected, undefined, [], [2 /* CloseBraceToken */, 5 /* CommaToken */]);
1146
+ }
1147
+ else {
1148
+ node.properties.push(property);
1149
+ }
1150
+ needsComma = true;
1151
+ }
1152
+ if (scanner.getToken() !== 2 /* CloseBraceToken */) {
1153
+ return _error(localize('ExpectedCloseBrace', 'Expected comma or closing brace'), ErrorCode.CommaOrCloseBraceExpected, node);
1154
+ }
1155
+ return _finalize(node, true);
1156
+ }
1157
+ function _parseString(parent) {
1158
+ if (scanner.getToken() !== 10 /* StringLiteral */) {
1159
+ return undefined;
1160
+ }
1161
+ const node = new StringASTNodeImpl(parent, scanner.getTokenOffset());
1162
+ node.value = scanner.getTokenValue();
1163
+ return _finalize(node, true);
1164
+ }
1165
+ function _parseNumber(parent) {
1166
+ if (scanner.getToken() !== 11 /* NumericLiteral */) {
1167
+ return undefined;
1168
+ }
1169
+ const node = new NumberASTNodeImpl(parent, scanner.getTokenOffset());
1170
+ if (scanner.getTokenError() === 0 /* None */) {
1171
+ const tokenValue = scanner.getTokenValue();
1172
+ try {
1173
+ const numberValue = JSON.parse(tokenValue);
1174
+ if (!isNumber(numberValue)) {
1175
+ return _error(localize('InvalidNumberFormat', 'Invalid number format.'), ErrorCode.Undefined, node);
1176
+ }
1177
+ node.value = numberValue;
1178
+ }
1179
+ catch (e) {
1180
+ return _error(localize('InvalidNumberFormat', 'Invalid number format.'), ErrorCode.Undefined, node);
1181
+ }
1182
+ node.isInteger = tokenValue.indexOf('.') === -1;
1183
+ }
1184
+ return _finalize(node, true);
1185
+ }
1186
+ function _parseLiteral(parent) {
1187
+ let node;
1188
+ switch (scanner.getToken()) {
1189
+ case 7 /* NullKeyword */:
1190
+ return _finalize(new NullASTNodeImpl(parent, scanner.getTokenOffset()), true);
1191
+ case 8 /* TrueKeyword */:
1192
+ return _finalize(new BooleanASTNodeImpl(parent, true, scanner.getTokenOffset()), true);
1193
+ case 9 /* FalseKeyword */:
1194
+ return _finalize(new BooleanASTNodeImpl(parent, false, scanner.getTokenOffset()), true);
1195
+ default:
1196
+ return undefined;
1197
+ }
1198
+ }
1199
+ function _parseValue(parent) {
1200
+ return _parseArray(parent) || _parseObject(parent) || _parseString(parent) || _parseNumber(parent) || _parseLiteral(parent);
1201
+ }
1202
+ let _root = undefined;
1203
+ const token = _scanNext();
1204
+ if (token !== 17 /* EOF */) {
1205
+ _root = _parseValue(_root);
1206
+ if (!_root) {
1207
+ _error(localize('Invalid symbol', 'Expected a JSON object, array or literal.'), ErrorCode.Undefined);
1208
+ }
1209
+ else if (scanner.getToken() !== 17 /* EOF */) {
1210
+ _error(localize('End of file expected', 'End of file expected.'), ErrorCode.Undefined);
1211
+ }
1212
+ }
1213
+ return new JSONDocument(_root, problems, commentRanges);
1214
+ }