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