vscode-json-languageservice 4.2.0-next.3 → 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,605 +1,586 @@
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 { URI } from 'vscode-uri';
7
- import * as Strings from '../utils/strings';
8
- import * as Parser from '../parser/jsonParser';
9
- import * as nls from 'vscode-nls';
10
- import { createRegex } from '../utils/glob';
11
- var localize = nls.loadMessageBundle();
12
- var BANG = '!';
13
- var PATH_SEP = '/';
14
- var FilePatternAssociation = /** @class */ (function () {
15
- function FilePatternAssociation(pattern, uris) {
16
- this.globWrappers = [];
17
- try {
18
- for (var _i = 0, pattern_1 = pattern; _i < pattern_1.length; _i++) {
19
- var patternString = pattern_1[_i];
20
- var include = patternString[0] !== BANG;
21
- if (!include) {
22
- patternString = patternString.substring(1);
23
- }
24
- if (patternString.length > 0) {
25
- if (patternString[0] === PATH_SEP) {
26
- patternString = patternString.substring(1);
27
- }
28
- this.globWrappers.push({
29
- regexp: createRegex('**/' + patternString, { extended: true, globstar: true }),
30
- include: include,
31
- });
32
- }
33
- }
34
- ;
35
- this.uris = uris;
36
- }
37
- catch (e) {
38
- this.globWrappers.length = 0;
39
- this.uris = [];
40
- }
41
- }
42
- FilePatternAssociation.prototype.matchesPattern = function (fileName) {
43
- var match = false;
44
- for (var _i = 0, _a = this.globWrappers; _i < _a.length; _i++) {
45
- var _b = _a[_i], regexp = _b.regexp, include = _b.include;
46
- if (regexp.test(fileName)) {
47
- match = include;
48
- }
49
- }
50
- return match;
51
- };
52
- FilePatternAssociation.prototype.getURIs = function () {
53
- return this.uris;
54
- };
55
- return FilePatternAssociation;
56
- }());
57
- var SchemaHandle = /** @class */ (function () {
58
- function SchemaHandle(service, uri, unresolvedSchemaContent) {
59
- this.service = service;
60
- this.uri = uri;
61
- this.dependencies = new Set();
62
- this.anchors = undefined;
63
- if (unresolvedSchemaContent) {
64
- this.unresolvedSchema = this.service.promise.resolve(new UnresolvedSchema(unresolvedSchemaContent));
65
- }
66
- }
67
- SchemaHandle.prototype.getUnresolvedSchema = function () {
68
- if (!this.unresolvedSchema) {
69
- this.unresolvedSchema = this.service.loadSchema(this.uri);
70
- }
71
- return this.unresolvedSchema;
72
- };
73
- SchemaHandle.prototype.getResolvedSchema = function () {
74
- var _this = this;
75
- if (!this.resolvedSchema) {
76
- this.resolvedSchema = this.getUnresolvedSchema().then(function (unresolved) {
77
- return _this.service.resolveSchemaContent(unresolved, _this);
78
- });
79
- }
80
- return this.resolvedSchema;
81
- };
82
- SchemaHandle.prototype.clearSchema = function () {
83
- var hasChanges = !!this.unresolvedSchema;
84
- this.resolvedSchema = undefined;
85
- this.unresolvedSchema = undefined;
86
- this.dependencies.clear();
87
- this.anchors = undefined;
88
- return hasChanges;
89
- };
90
- return SchemaHandle;
91
- }());
92
- var UnresolvedSchema = /** @class */ (function () {
93
- function UnresolvedSchema(schema, errors) {
94
- if (errors === void 0) { errors = []; }
95
- this.schema = schema;
96
- this.errors = errors;
97
- }
98
- return UnresolvedSchema;
99
- }());
100
- export { UnresolvedSchema };
101
- var ResolvedSchema = /** @class */ (function () {
102
- function ResolvedSchema(schema, errors) {
103
- if (errors === void 0) { errors = []; }
104
- this.schema = schema;
105
- this.errors = errors;
106
- }
107
- ResolvedSchema.prototype.getSection = function (path) {
108
- var schemaRef = this.getSectionRecursive(path, this.schema);
109
- if (schemaRef) {
110
- return Parser.asSchema(schemaRef);
111
- }
112
- return undefined;
113
- };
114
- ResolvedSchema.prototype.getSectionRecursive = function (path, schema) {
115
- if (!schema || typeof schema === 'boolean' || path.length === 0) {
116
- return schema;
117
- }
118
- var next = path.shift();
119
- if (schema.properties && typeof schema.properties[next]) {
120
- return this.getSectionRecursive(path, schema.properties[next]);
121
- }
122
- else if (schema.patternProperties) {
123
- for (var _i = 0, _a = Object.keys(schema.patternProperties); _i < _a.length; _i++) {
124
- var pattern = _a[_i];
125
- var regex = Strings.extendedRegExp(pattern);
126
- if (regex === null || regex === void 0 ? void 0 : regex.test(next)) {
127
- return this.getSectionRecursive(path, schema.patternProperties[pattern]);
128
- }
129
- }
130
- }
131
- else if (typeof schema.additionalProperties === 'object') {
132
- return this.getSectionRecursive(path, schema.additionalProperties);
133
- }
134
- else if (next.match('[0-9]+')) {
135
- if (Array.isArray(schema.items)) {
136
- var index = parseInt(next, 10);
137
- if (!isNaN(index) && schema.items[index]) {
138
- return this.getSectionRecursive(path, schema.items[index]);
139
- }
140
- }
141
- else if (schema.items) {
142
- return this.getSectionRecursive(path, schema.items);
143
- }
144
- }
145
- return undefined;
146
- };
147
- return ResolvedSchema;
148
- }());
149
- export { ResolvedSchema };
150
- var JSONSchemaService = /** @class */ (function () {
151
- function JSONSchemaService(requestService, contextService, promiseConstructor) {
152
- this.contextService = contextService;
153
- this.requestService = requestService;
154
- this.promiseConstructor = promiseConstructor || Promise;
155
- this.callOnDispose = [];
156
- this.contributionSchemas = {};
157
- this.contributionAssociations = [];
158
- this.schemasById = {};
159
- this.filePatternAssociations = [];
160
- this.registeredSchemasIds = {};
161
- }
162
- JSONSchemaService.prototype.getRegisteredSchemaIds = function (filter) {
163
- return Object.keys(this.registeredSchemasIds).filter(function (id) {
164
- var scheme = URI.parse(id).scheme;
165
- return scheme !== 'schemaservice' && (!filter || filter(scheme));
166
- });
167
- };
168
- Object.defineProperty(JSONSchemaService.prototype, "promise", {
169
- get: function () {
170
- return this.promiseConstructor;
171
- },
172
- enumerable: false,
173
- configurable: true
174
- });
175
- JSONSchemaService.prototype.dispose = function () {
176
- while (this.callOnDispose.length > 0) {
177
- this.callOnDispose.pop()();
178
- }
179
- };
180
- JSONSchemaService.prototype.onResourceChange = function (uri) {
181
- var _this = this;
182
- // always clear this local cache when a resource changes
183
- this.cachedSchemaForResource = undefined;
184
- var hasChanges = false;
185
- uri = normalizeId(uri);
186
- var toWalk = [uri];
187
- var all = Object.keys(this.schemasById).map(function (key) { return _this.schemasById[key]; });
188
- while (toWalk.length) {
189
- var curr = toWalk.pop();
190
- for (var i = 0; i < all.length; i++) {
191
- var handle = all[i];
192
- if (handle && (handle.uri === curr || handle.dependencies.has(curr))) {
193
- if (handle.uri !== curr) {
194
- toWalk.push(handle.uri);
195
- }
196
- if (handle.clearSchema()) {
197
- hasChanges = true;
198
- }
199
- all[i] = undefined;
200
- }
201
- }
202
- }
203
- return hasChanges;
204
- };
205
- JSONSchemaService.prototype.setSchemaContributions = function (schemaContributions) {
206
- if (schemaContributions.schemas) {
207
- var schemas = schemaContributions.schemas;
208
- for (var id in schemas) {
209
- var normalizedId = normalizeId(id);
210
- this.contributionSchemas[normalizedId] = this.addSchemaHandle(normalizedId, schemas[id]);
211
- }
212
- }
213
- if (Array.isArray(schemaContributions.schemaAssociations)) {
214
- var schemaAssociations = schemaContributions.schemaAssociations;
215
- for (var _i = 0, schemaAssociations_1 = schemaAssociations; _i < schemaAssociations_1.length; _i++) {
216
- var schemaAssociation = schemaAssociations_1[_i];
217
- var uris = schemaAssociation.uris.map(normalizeId);
218
- var association = this.addFilePatternAssociation(schemaAssociation.pattern, uris);
219
- this.contributionAssociations.push(association);
220
- }
221
- }
222
- };
223
- JSONSchemaService.prototype.addSchemaHandle = function (id, unresolvedSchemaContent) {
224
- var schemaHandle = new SchemaHandle(this, id, unresolvedSchemaContent);
225
- this.schemasById[id] = schemaHandle;
226
- return schemaHandle;
227
- };
228
- JSONSchemaService.prototype.getOrAddSchemaHandle = function (id, unresolvedSchemaContent) {
229
- return this.schemasById[id] || this.addSchemaHandle(id, unresolvedSchemaContent);
230
- };
231
- JSONSchemaService.prototype.addFilePatternAssociation = function (pattern, uris) {
232
- var fpa = new FilePatternAssociation(pattern, uris);
233
- this.filePatternAssociations.push(fpa);
234
- return fpa;
235
- };
236
- JSONSchemaService.prototype.registerExternalSchema = function (uri, filePatterns, unresolvedSchemaContent) {
237
- var id = normalizeId(uri);
238
- this.registeredSchemasIds[id] = true;
239
- this.cachedSchemaForResource = undefined;
240
- if (filePatterns) {
241
- this.addFilePatternAssociation(filePatterns, [id]);
242
- }
243
- return unresolvedSchemaContent ? this.addSchemaHandle(id, unresolvedSchemaContent) : this.getOrAddSchemaHandle(id);
244
- };
245
- JSONSchemaService.prototype.clearExternalSchemas = function () {
246
- this.schemasById = {};
247
- this.filePatternAssociations = [];
248
- this.registeredSchemasIds = {};
249
- this.cachedSchemaForResource = undefined;
250
- for (var id in this.contributionSchemas) {
251
- this.schemasById[id] = this.contributionSchemas[id];
252
- this.registeredSchemasIds[id] = true;
253
- }
254
- for (var _i = 0, _a = this.contributionAssociations; _i < _a.length; _i++) {
255
- var contributionAssociation = _a[_i];
256
- this.filePatternAssociations.push(contributionAssociation);
257
- }
258
- };
259
- JSONSchemaService.prototype.getResolvedSchema = function (schemaId) {
260
- var id = normalizeId(schemaId);
261
- var schemaHandle = this.schemasById[id];
262
- if (schemaHandle) {
263
- return schemaHandle.getResolvedSchema();
264
- }
265
- return this.promise.resolve(undefined);
266
- };
267
- JSONSchemaService.prototype.loadSchema = function (url) {
268
- if (!this.requestService) {
269
- var errorMessage = localize('json.schema.norequestservice', 'Unable to load schema from \'{0}\'. No schema request service available', toDisplayString(url));
270
- return this.promise.resolve(new UnresolvedSchema({}, [errorMessage]));
271
- }
272
- return this.requestService(url).then(function (content) {
273
- if (!content) {
274
- var errorMessage = localize('json.schema.nocontent', 'Unable to load schema from \'{0}\': No content.', toDisplayString(url));
275
- return new UnresolvedSchema({}, [errorMessage]);
276
- }
277
- var schemaContent = {};
278
- var jsonErrors = [];
279
- schemaContent = Json.parse(content, jsonErrors);
280
- var errors = jsonErrors.length ? [localize('json.schema.invalidFormat', 'Unable to parse content from \'{0}\': Parse error at offset {1}.', toDisplayString(url), jsonErrors[0].offset)] : [];
281
- return new UnresolvedSchema(schemaContent, errors);
282
- }, function (error) {
283
- var errorMessage = error.toString();
284
- var errorSplit = error.toString().split('Error: ');
285
- if (errorSplit.length > 1) {
286
- // more concise error message, URL and context are attached by caller anyways
287
- errorMessage = errorSplit[1];
288
- }
289
- if (Strings.endsWith(errorMessage, '.')) {
290
- errorMessage = errorMessage.substr(0, errorMessage.length - 1);
291
- }
292
- return new UnresolvedSchema({}, [localize('json.schema.nocontent', 'Unable to load schema from \'{0}\': {1}.', toDisplayString(url), errorMessage)]);
293
- });
294
- };
295
- JSONSchemaService.prototype.resolveSchemaContent = function (schemaToResolve, handle) {
296
- var _this = this;
297
- var resolveErrors = schemaToResolve.errors.slice(0);
298
- var schema = schemaToResolve.schema;
299
- if (schema.$schema) {
300
- var id = normalizeId(schema.$schema);
301
- if (id === 'http://json-schema.org/draft-03/schema') {
302
- return this.promise.resolve(new ResolvedSchema({}, [localize('json.schema.draft03.notsupported', "Draft-03 schemas are not supported.")]));
303
- }
304
- else if (id === 'https://json-schema.org/draft/2019-09/schema') {
305
- resolveErrors.push(localize('json.schema.draft201909.notsupported', "Draft 2019-09 schemas are not yet fully supported."));
306
- }
307
- else if (id === 'https://json-schema.org/draft/2020-12/schema') {
308
- resolveErrors.push(localize('json.schema.draft202012.notsupported', "Draft 2020-12 schemas are not yet fully supported."));
309
- }
310
- }
311
- var contextService = this.contextService;
312
- var findSectionByJSONPointer = function (schema, path) {
313
- path = decodeURIComponent(path);
314
- var current = schema;
315
- if (path[0] === '/') {
316
- path = path.substring(1);
317
- }
318
- path.split('/').some(function (part) {
319
- part = part.replace(/~1/g, '/').replace(/~0/g, '~');
320
- current = current[part];
321
- return !current;
322
- });
323
- return current;
324
- };
325
- var findSchemaById = function (schema, handle, id) {
326
- if (!handle.anchors) {
327
- handle.anchors = collectAnchors(schema);
328
- }
329
- return handle.anchors.get(id);
330
- };
331
- var merge = function (target, section) {
332
- for (var key in section) {
333
- if (section.hasOwnProperty(key) && !target.hasOwnProperty(key) && key !== 'id' && key !== '$id') {
334
- target[key] = section[key];
335
- }
336
- }
337
- };
338
- var mergeRef = function (target, sourceRoot, sourceHandle, refSegment) {
339
- var section;
340
- if (refSegment === undefined) {
341
- section = sourceRoot;
342
- }
343
- else if (refSegment.charAt(0) === '/') {
344
- // A $ref to a JSON Pointer (i.e #/definitions/foo)
345
- section = findSectionByJSONPointer(sourceRoot, refSegment);
346
- }
347
- else {
348
- // A $ref to a sub-schema with an $id (i.e #hello)
349
- section = findSchemaById(sourceRoot, sourceHandle, refSegment);
350
- }
351
- if (section) {
352
- merge(target, section);
353
- }
354
- else {
355
- resolveErrors.push(localize('json.schema.invalidid', '$ref \'{0}\' in \'{1}\' can not be resolved.', refSegment, sourceHandle.uri));
356
- }
357
- };
358
- var resolveExternalLink = function (node, uri, refSegment, parentHandle) {
359
- if (contextService && !/^[A-Za-z][A-Za-z0-9+\-.+]*:\/\/.*/.test(uri)) {
360
- uri = contextService.resolveRelativePath(uri, parentHandle.uri);
361
- }
362
- uri = normalizeId(uri);
363
- var referencedHandle = _this.getOrAddSchemaHandle(uri);
364
- return referencedHandle.getUnresolvedSchema().then(function (unresolvedSchema) {
365
- parentHandle.dependencies.add(uri);
366
- if (unresolvedSchema.errors.length) {
367
- var loc = refSegment ? uri + '#' + refSegment : uri;
368
- resolveErrors.push(localize('json.schema.problemloadingref', 'Problems loading reference \'{0}\': {1}', loc, unresolvedSchema.errors[0]));
369
- }
370
- mergeRef(node, unresolvedSchema.schema, referencedHandle, refSegment);
371
- return resolveRefs(node, unresolvedSchema.schema, referencedHandle);
372
- });
373
- };
374
- var resolveRefs = function (node, parentSchema, parentHandle) {
375
- var openPromises = [];
376
- _this.traverseNodes(node, function (next) {
377
- var seenRefs = new Set();
378
- while (next.$ref) {
379
- var ref = next.$ref;
380
- var segments = ref.split('#', 2);
381
- delete next.$ref;
382
- if (segments[0].length > 0) {
383
- // This is a reference to an external schema
384
- openPromises.push(resolveExternalLink(next, segments[0], segments[1], parentHandle));
385
- return;
386
- }
387
- else {
388
- // This is a reference inside the current schema
389
- if (!seenRefs.has(ref)) {
390
- var id = segments[1];
391
- mergeRef(next, parentSchema, parentHandle, id);
392
- seenRefs.add(ref);
393
- }
394
- }
395
- }
396
- });
397
- return _this.promise.all(openPromises);
398
- };
399
- var collectAnchors = function (root) {
400
- var result = new Map();
401
- _this.traverseNodes(root, function (next) {
402
- var id = next.$id || next.id;
403
- if (typeof id === 'string' && id.charAt(0) === '#') {
404
- // delete next.$id;
405
- // delete next.id;
406
- var anchor = id.substring(1);
407
- if (result.has(anchor)) {
408
- resolveErrors.push(localize('json.schema.duplicateid', 'Duplicate id declaration: \'{0}\'', id));
409
- }
410
- else {
411
- result.set(anchor, next);
412
- }
413
- }
414
- });
415
- return result;
416
- };
417
- return resolveRefs(schema, schema, handle).then(function (_) {
418
- return new ResolvedSchema(schema, resolveErrors);
419
- });
420
- };
421
- JSONSchemaService.prototype.traverseNodes = function (root, handle) {
422
- if (!root || typeof root !== 'object') {
423
- return Promise.resolve(null);
424
- }
425
- var seen = new Set();
426
- var collectEntries = function () {
427
- var entries = [];
428
- for (var _i = 0; _i < arguments.length; _i++) {
429
- entries[_i] = arguments[_i];
430
- }
431
- for (var _a = 0, entries_1 = entries; _a < entries_1.length; _a++) {
432
- var entry = entries_1[_a];
433
- if (typeof entry === 'object') {
434
- toWalk.push(entry);
435
- }
436
- }
437
- };
438
- var collectMapEntries = function () {
439
- var maps = [];
440
- for (var _i = 0; _i < arguments.length; _i++) {
441
- maps[_i] = arguments[_i];
442
- }
443
- for (var _a = 0, maps_1 = maps; _a < maps_1.length; _a++) {
444
- var map = maps_1[_a];
445
- if (typeof map === 'object') {
446
- for (var k in map) {
447
- var key = k;
448
- var entry = map[key];
449
- if (typeof entry === 'object') {
450
- toWalk.push(entry);
451
- }
452
- }
453
- }
454
- }
455
- };
456
- var collectArrayEntries = function () {
457
- var arrays = [];
458
- for (var _i = 0; _i < arguments.length; _i++) {
459
- arrays[_i] = arguments[_i];
460
- }
461
- for (var _a = 0, arrays_1 = arrays; _a < arrays_1.length; _a++) {
462
- var array = arrays_1[_a];
463
- if (Array.isArray(array)) {
464
- for (var _b = 0, array_1 = array; _b < array_1.length; _b++) {
465
- var entry = array_1[_b];
466
- if (typeof entry === 'object') {
467
- toWalk.push(entry);
468
- }
469
- }
470
- }
471
- }
472
- };
473
- var toWalk = [root];
474
- var next = toWalk.pop();
475
- while (next) {
476
- if (!seen.has(next)) {
477
- seen.add(next);
478
- handle(next);
479
- collectEntries(next.items, next.additionalItems, next.additionalProperties, next.not, next.contains, next.propertyNames, next.if, next.then, next.else);
480
- collectMapEntries(next.definitions, next.properties, next.patternProperties, next.dependencies);
481
- collectArrayEntries(next.anyOf, next.allOf, next.oneOf, next.items);
482
- }
483
- next = toWalk.pop();
484
- }
485
- };
486
- ;
487
- JSONSchemaService.prototype.getSchemaFromProperty = function (resource, document) {
488
- var _a, _b;
489
- if (((_a = document.root) === null || _a === void 0 ? void 0 : _a.type) === 'object') {
490
- for (var _i = 0, _c = document.root.properties; _i < _c.length; _i++) {
491
- var p = _c[_i];
492
- if (p.keyNode.value === '$schema' && ((_b = p.valueNode) === null || _b === void 0 ? void 0 : _b.type) === 'string') {
493
- var schemaId = p.valueNode.value;
494
- if (this.contextService && !/^\w[\w\d+.-]*:/.test(schemaId)) { // has scheme
495
- schemaId = this.contextService.resolveRelativePath(schemaId, resource);
496
- }
497
- return schemaId;
498
- }
499
- }
500
- }
501
- return undefined;
502
- };
503
- JSONSchemaService.prototype.getAssociatedSchemas = function (resource) {
504
- var seen = Object.create(null);
505
- var schemas = [];
506
- var normalizedResource = normalizeResourceForMatching(resource);
507
- for (var _i = 0, _a = this.filePatternAssociations; _i < _a.length; _i++) {
508
- var entry = _a[_i];
509
- if (entry.matchesPattern(normalizedResource)) {
510
- for (var _b = 0, _c = entry.getURIs(); _b < _c.length; _b++) {
511
- var schemaId = _c[_b];
512
- if (!seen[schemaId]) {
513
- schemas.push(schemaId);
514
- seen[schemaId] = true;
515
- }
516
- }
517
- }
518
- }
519
- return schemas;
520
- };
521
- JSONSchemaService.prototype.getSchemaURIsForResource = function (resource, document) {
522
- var schemeId = document && this.getSchemaFromProperty(resource, document);
523
- if (schemeId) {
524
- return [schemeId];
525
- }
526
- return this.getAssociatedSchemas(resource);
527
- };
528
- JSONSchemaService.prototype.getSchemaForResource = function (resource, document) {
529
- if (document) {
530
- // first use $schema if present
531
- var schemeId = this.getSchemaFromProperty(resource, document);
532
- if (schemeId) {
533
- var id = normalizeId(schemeId);
534
- return this.getOrAddSchemaHandle(id).getResolvedSchema();
535
- }
536
- }
537
- if (this.cachedSchemaForResource && this.cachedSchemaForResource.resource === resource) {
538
- return this.cachedSchemaForResource.resolvedSchema;
539
- }
540
- var schemas = this.getAssociatedSchemas(resource);
541
- var resolvedSchema = schemas.length > 0 ? this.createCombinedSchema(resource, schemas).getResolvedSchema() : this.promise.resolve(undefined);
542
- this.cachedSchemaForResource = { resource: resource, resolvedSchema: resolvedSchema };
543
- return resolvedSchema;
544
- };
545
- JSONSchemaService.prototype.createCombinedSchema = function (resource, schemaIds) {
546
- if (schemaIds.length === 1) {
547
- return this.getOrAddSchemaHandle(schemaIds[0]);
548
- }
549
- else {
550
- var combinedSchemaId = 'schemaservice://combinedSchema/' + encodeURIComponent(resource);
551
- var combinedSchema = {
552
- allOf: schemaIds.map(function (schemaId) { return ({ $ref: schemaId }); })
553
- };
554
- return this.addSchemaHandle(combinedSchemaId, combinedSchema);
555
- }
556
- };
557
- JSONSchemaService.prototype.getMatchingSchemas = function (document, jsonDocument, schema) {
558
- if (schema) {
559
- var id = schema.id || ('schemaservice://untitled/matchingSchemas/' + idCounter++);
560
- var handle = this.addSchemaHandle(id, schema);
561
- return handle.getResolvedSchema().then(function (resolvedSchema) {
562
- return jsonDocument.getMatchingSchemas(resolvedSchema.schema).filter(function (s) { return !s.inverted; });
563
- });
564
- }
565
- return this.getSchemaForResource(document.uri, jsonDocument).then(function (schema) {
566
- if (schema) {
567
- return jsonDocument.getMatchingSchemas(schema.schema).filter(function (s) { return !s.inverted; });
568
- }
569
- return [];
570
- });
571
- };
572
- return JSONSchemaService;
573
- }());
574
- export { JSONSchemaService };
575
- var idCounter = 0;
576
- function normalizeId(id) {
577
- // remove trailing '#', normalize drive capitalization
578
- try {
579
- return URI.parse(id).toString();
580
- }
581
- catch (e) {
582
- return id;
583
- }
584
- }
585
- function normalizeResourceForMatching(resource) {
586
- // remove queries and fragments, normalize drive capitalization
587
- try {
588
- return URI.parse(resource).with({ fragment: null, query: null }).toString();
589
- }
590
- catch (e) {
591
- return resource;
592
- }
593
- }
594
- function toDisplayString(url) {
595
- try {
596
- var uri = URI.parse(url);
597
- if (uri.scheme === 'file') {
598
- return uri.fsPath;
599
- }
600
- }
601
- catch (e) {
602
- // ignore
603
- }
604
- return url;
605
- }
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 { URI } from 'vscode-uri';
7
+ import * as Strings from '../utils/strings';
8
+ import * as Parser from '../parser/jsonParser';
9
+ import * as nls from 'vscode-nls';
10
+ import { createRegex } from '../utils/glob';
11
+ import { isObject, isString } from '../utils/objects';
12
+ const localize = nls.loadMessageBundle();
13
+ const BANG = '!';
14
+ const PATH_SEP = '/';
15
+ class FilePatternAssociation {
16
+ constructor(pattern, uris) {
17
+ this.globWrappers = [];
18
+ try {
19
+ for (let patternString of pattern) {
20
+ const include = patternString[0] !== BANG;
21
+ if (!include) {
22
+ patternString = patternString.substring(1);
23
+ }
24
+ if (patternString.length > 0) {
25
+ if (patternString[0] === PATH_SEP) {
26
+ patternString = patternString.substring(1);
27
+ }
28
+ this.globWrappers.push({
29
+ regexp: createRegex('**/' + patternString, { extended: true, globstar: true }),
30
+ include: include,
31
+ });
32
+ }
33
+ }
34
+ ;
35
+ this.uris = uris;
36
+ }
37
+ catch (e) {
38
+ this.globWrappers.length = 0;
39
+ this.uris = [];
40
+ }
41
+ }
42
+ matchesPattern(fileName) {
43
+ let match = false;
44
+ for (const { regexp, include } of this.globWrappers) {
45
+ if (regexp.test(fileName)) {
46
+ match = include;
47
+ }
48
+ }
49
+ return match;
50
+ }
51
+ getURIs() {
52
+ return this.uris;
53
+ }
54
+ }
55
+ class SchemaHandle {
56
+ constructor(service, uri, unresolvedSchemaContent) {
57
+ this.service = service;
58
+ this.uri = uri;
59
+ this.dependencies = new Set();
60
+ this.anchors = undefined;
61
+ if (unresolvedSchemaContent) {
62
+ this.unresolvedSchema = this.service.promise.resolve(new UnresolvedSchema(unresolvedSchemaContent));
63
+ }
64
+ }
65
+ getUnresolvedSchema() {
66
+ if (!this.unresolvedSchema) {
67
+ this.unresolvedSchema = this.service.loadSchema(this.uri);
68
+ }
69
+ return this.unresolvedSchema;
70
+ }
71
+ getResolvedSchema() {
72
+ if (!this.resolvedSchema) {
73
+ this.resolvedSchema = this.getUnresolvedSchema().then(unresolved => {
74
+ return this.service.resolveSchemaContent(unresolved, this);
75
+ });
76
+ }
77
+ return this.resolvedSchema;
78
+ }
79
+ clearSchema() {
80
+ const hasChanges = !!this.unresolvedSchema;
81
+ this.resolvedSchema = undefined;
82
+ this.unresolvedSchema = undefined;
83
+ this.dependencies.clear();
84
+ this.anchors = undefined;
85
+ return hasChanges;
86
+ }
87
+ }
88
+ export class UnresolvedSchema {
89
+ constructor(schema, errors = []) {
90
+ this.schema = schema;
91
+ this.errors = errors;
92
+ }
93
+ }
94
+ export class ResolvedSchema {
95
+ constructor(schema, errors = [], warnings = [], schemaDraft) {
96
+ this.schema = schema;
97
+ this.errors = errors;
98
+ this.warnings = warnings;
99
+ this.schemaDraft = schemaDraft;
100
+ }
101
+ getSection(path) {
102
+ const schemaRef = this.getSectionRecursive(path, this.schema);
103
+ if (schemaRef) {
104
+ return Parser.asSchema(schemaRef);
105
+ }
106
+ return undefined;
107
+ }
108
+ getSectionRecursive(path, schema) {
109
+ if (!schema || typeof schema === 'boolean' || path.length === 0) {
110
+ return schema;
111
+ }
112
+ const next = path.shift();
113
+ if (schema.properties && typeof schema.properties[next]) {
114
+ return this.getSectionRecursive(path, schema.properties[next]);
115
+ }
116
+ else if (schema.patternProperties) {
117
+ for (const pattern of Object.keys(schema.patternProperties)) {
118
+ const regex = Strings.extendedRegExp(pattern);
119
+ if (regex?.test(next)) {
120
+ return this.getSectionRecursive(path, schema.patternProperties[pattern]);
121
+ }
122
+ }
123
+ }
124
+ else if (typeof schema.additionalProperties === 'object') {
125
+ return this.getSectionRecursive(path, schema.additionalProperties);
126
+ }
127
+ else if (next.match('[0-9]+')) {
128
+ if (Array.isArray(schema.items)) {
129
+ const index = parseInt(next, 10);
130
+ if (!isNaN(index) && schema.items[index]) {
131
+ return this.getSectionRecursive(path, schema.items[index]);
132
+ }
133
+ }
134
+ else if (schema.items) {
135
+ return this.getSectionRecursive(path, schema.items);
136
+ }
137
+ }
138
+ return undefined;
139
+ }
140
+ }
141
+ export class JSONSchemaService {
142
+ constructor(requestService, contextService, promiseConstructor) {
143
+ this.contextService = contextService;
144
+ this.requestService = requestService;
145
+ this.promiseConstructor = promiseConstructor || Promise;
146
+ this.callOnDispose = [];
147
+ this.contributionSchemas = {};
148
+ this.contributionAssociations = [];
149
+ this.schemasById = {};
150
+ this.filePatternAssociations = [];
151
+ this.registeredSchemasIds = {};
152
+ }
153
+ getRegisteredSchemaIds(filter) {
154
+ return Object.keys(this.registeredSchemasIds).filter(id => {
155
+ const scheme = URI.parse(id).scheme;
156
+ return scheme !== 'schemaservice' && (!filter || filter(scheme));
157
+ });
158
+ }
159
+ get promise() {
160
+ return this.promiseConstructor;
161
+ }
162
+ dispose() {
163
+ while (this.callOnDispose.length > 0) {
164
+ this.callOnDispose.pop()();
165
+ }
166
+ }
167
+ onResourceChange(uri) {
168
+ // always clear this local cache when a resource changes
169
+ this.cachedSchemaForResource = undefined;
170
+ let hasChanges = false;
171
+ uri = normalizeId(uri);
172
+ const toWalk = [uri];
173
+ const all = Object.keys(this.schemasById).map(key => this.schemasById[key]);
174
+ while (toWalk.length) {
175
+ const curr = toWalk.pop();
176
+ for (let i = 0; i < all.length; i++) {
177
+ const handle = all[i];
178
+ if (handle && (handle.uri === curr || handle.dependencies.has(curr))) {
179
+ if (handle.uri !== curr) {
180
+ toWalk.push(handle.uri);
181
+ }
182
+ if (handle.clearSchema()) {
183
+ hasChanges = true;
184
+ }
185
+ all[i] = undefined;
186
+ }
187
+ }
188
+ }
189
+ return hasChanges;
190
+ }
191
+ setSchemaContributions(schemaContributions) {
192
+ if (schemaContributions.schemas) {
193
+ const schemas = schemaContributions.schemas;
194
+ for (const id in schemas) {
195
+ const normalizedId = normalizeId(id);
196
+ this.contributionSchemas[normalizedId] = this.addSchemaHandle(normalizedId, schemas[id]);
197
+ }
198
+ }
199
+ if (Array.isArray(schemaContributions.schemaAssociations)) {
200
+ const schemaAssociations = schemaContributions.schemaAssociations;
201
+ for (let schemaAssociation of schemaAssociations) {
202
+ const uris = schemaAssociation.uris.map(normalizeId);
203
+ const association = this.addFilePatternAssociation(schemaAssociation.pattern, uris);
204
+ this.contributionAssociations.push(association);
205
+ }
206
+ }
207
+ }
208
+ addSchemaHandle(id, unresolvedSchemaContent) {
209
+ const schemaHandle = new SchemaHandle(this, id, unresolvedSchemaContent);
210
+ this.schemasById[id] = schemaHandle;
211
+ return schemaHandle;
212
+ }
213
+ getOrAddSchemaHandle(id, unresolvedSchemaContent) {
214
+ return this.schemasById[id] || this.addSchemaHandle(id, unresolvedSchemaContent);
215
+ }
216
+ addFilePatternAssociation(pattern, uris) {
217
+ const fpa = new FilePatternAssociation(pattern, uris);
218
+ this.filePatternAssociations.push(fpa);
219
+ return fpa;
220
+ }
221
+ registerExternalSchema(uri, filePatterns, unresolvedSchemaContent) {
222
+ const id = normalizeId(uri);
223
+ this.registeredSchemasIds[id] = true;
224
+ this.cachedSchemaForResource = undefined;
225
+ if (filePatterns) {
226
+ this.addFilePatternAssociation(filePatterns, [id]);
227
+ }
228
+ return unresolvedSchemaContent ? this.addSchemaHandle(id, unresolvedSchemaContent) : this.getOrAddSchemaHandle(id);
229
+ }
230
+ clearExternalSchemas() {
231
+ this.schemasById = {};
232
+ this.filePatternAssociations = [];
233
+ this.registeredSchemasIds = {};
234
+ this.cachedSchemaForResource = undefined;
235
+ for (const id in this.contributionSchemas) {
236
+ this.schemasById[id] = this.contributionSchemas[id];
237
+ this.registeredSchemasIds[id] = true;
238
+ }
239
+ for (const contributionAssociation of this.contributionAssociations) {
240
+ this.filePatternAssociations.push(contributionAssociation);
241
+ }
242
+ }
243
+ getResolvedSchema(schemaId) {
244
+ const id = normalizeId(schemaId);
245
+ const schemaHandle = this.schemasById[id];
246
+ if (schemaHandle) {
247
+ return schemaHandle.getResolvedSchema();
248
+ }
249
+ return this.promise.resolve(undefined);
250
+ }
251
+ loadSchema(url) {
252
+ if (!this.requestService) {
253
+ const errorMessage = localize('json.schema.norequestservice', 'Unable to load schema from \'{0}\'. No schema request service available', toDisplayString(url));
254
+ return this.promise.resolve(new UnresolvedSchema({}, [errorMessage]));
255
+ }
256
+ return this.requestService(url).then(content => {
257
+ if (!content) {
258
+ const errorMessage = localize('json.schema.nocontent', 'Unable to load schema from \'{0}\': No content.', toDisplayString(url));
259
+ return new UnresolvedSchema({}, [errorMessage]);
260
+ }
261
+ let schemaContent = {};
262
+ const jsonErrors = [];
263
+ schemaContent = Json.parse(content, jsonErrors);
264
+ const errors = jsonErrors.length ? [localize('json.schema.invalidFormat', 'Unable to parse content from \'{0}\': Parse error at offset {1}.', toDisplayString(url), jsonErrors[0].offset)] : [];
265
+ return new UnresolvedSchema(schemaContent, errors);
266
+ }, (error) => {
267
+ let errorMessage = error.toString();
268
+ const errorSplit = error.toString().split('Error: ');
269
+ if (errorSplit.length > 1) {
270
+ // more concise error message, URL and context are attached by caller anyways
271
+ errorMessage = errorSplit[1];
272
+ }
273
+ if (Strings.endsWith(errorMessage, '.')) {
274
+ errorMessage = errorMessage.substr(0, errorMessage.length - 1);
275
+ }
276
+ return new UnresolvedSchema({}, [localize('json.schema.nocontent', 'Unable to load schema from \'{0}\': {1}.', toDisplayString(url), errorMessage)]);
277
+ });
278
+ }
279
+ resolveSchemaContent(schemaToResolve, handle) {
280
+ const resolveErrors = schemaToResolve.errors.slice(0);
281
+ const schema = schemaToResolve.schema;
282
+ let schemaDraft = schema.$schema ? normalizeId(schema.$schema) : undefined;
283
+ if (schemaDraft === 'http://json-schema.org/draft-03/schema') {
284
+ return this.promise.resolve(new ResolvedSchema({}, [localize('json.schema.draft03.notsupported', "Draft-03 schemas are not supported.")], [], schemaDraft));
285
+ }
286
+ let usesUnsupportedFeatures = new Set();
287
+ const contextService = this.contextService;
288
+ const findSectionByJSONPointer = (schema, path) => {
289
+ path = decodeURIComponent(path);
290
+ let current = schema;
291
+ if (path[0] === '/') {
292
+ path = path.substring(1);
293
+ }
294
+ path.split('/').some((part) => {
295
+ part = part.replace(/~1/g, '/').replace(/~0/g, '~');
296
+ current = current[part];
297
+ return !current;
298
+ });
299
+ return current;
300
+ };
301
+ const findSchemaById = (schema, handle, id) => {
302
+ if (!handle.anchors) {
303
+ handle.anchors = collectAnchors(schema);
304
+ }
305
+ return handle.anchors.get(id);
306
+ };
307
+ const merge = (target, section) => {
308
+ for (const key in section) {
309
+ if (section.hasOwnProperty(key) && !target.hasOwnProperty(key) && key !== 'id' && key !== '$id') {
310
+ target[key] = section[key];
311
+ }
312
+ }
313
+ };
314
+ const mergeRef = (target, sourceRoot, sourceHandle, refSegment) => {
315
+ let section;
316
+ if (refSegment === undefined || refSegment.length === 0) {
317
+ section = sourceRoot;
318
+ }
319
+ else if (refSegment.charAt(0) === '/') {
320
+ // A $ref to a JSON Pointer (i.e #/definitions/foo)
321
+ section = findSectionByJSONPointer(sourceRoot, refSegment);
322
+ }
323
+ else {
324
+ // A $ref to a sub-schema with an $id (i.e #hello)
325
+ section = findSchemaById(sourceRoot, sourceHandle, refSegment);
326
+ }
327
+ if (section) {
328
+ merge(target, section);
329
+ }
330
+ else {
331
+ resolveErrors.push(localize('json.schema.invalidid', '$ref \'{0}\' in \'{1}\' can not be resolved.', refSegment, sourceHandle.uri));
332
+ }
333
+ };
334
+ const resolveExternalLink = (node, uri, refSegment, parentHandle) => {
335
+ if (contextService && !/^[A-Za-z][A-Za-z0-9+\-.+]*:\/\/.*/.test(uri)) {
336
+ uri = contextService.resolveRelativePath(uri, parentHandle.uri);
337
+ }
338
+ uri = normalizeId(uri);
339
+ const referencedHandle = this.getOrAddSchemaHandle(uri);
340
+ return referencedHandle.getUnresolvedSchema().then(unresolvedSchema => {
341
+ parentHandle.dependencies.add(uri);
342
+ if (unresolvedSchema.errors.length) {
343
+ const loc = refSegment ? uri + '#' + refSegment : uri;
344
+ resolveErrors.push(localize('json.schema.problemloadingref', 'Problems loading reference \'{0}\': {1}', loc, unresolvedSchema.errors[0]));
345
+ }
346
+ mergeRef(node, unresolvedSchema.schema, referencedHandle, refSegment);
347
+ return resolveRefs(node, unresolvedSchema.schema, referencedHandle);
348
+ });
349
+ };
350
+ const resolveRefs = (node, parentSchema, parentHandle) => {
351
+ const openPromises = [];
352
+ this.traverseNodes(node, next => {
353
+ const seenRefs = new Set();
354
+ while (next.$ref) {
355
+ const ref = next.$ref;
356
+ const segments = ref.split('#', 2);
357
+ delete next.$ref;
358
+ if (segments[0].length > 0) {
359
+ // This is a reference to an external schema
360
+ openPromises.push(resolveExternalLink(next, segments[0], segments[1], parentHandle));
361
+ return;
362
+ }
363
+ else {
364
+ // This is a reference inside the current schema
365
+ if (!seenRefs.has(ref)) {
366
+ const id = segments[1];
367
+ mergeRef(next, parentSchema, parentHandle, id);
368
+ seenRefs.add(ref);
369
+ }
370
+ }
371
+ }
372
+ if (next.$recursiveRef) {
373
+ usesUnsupportedFeatures.add('$recursiveRef');
374
+ }
375
+ if (next.$dynamicRef) {
376
+ usesUnsupportedFeatures.add('$dynamicRef');
377
+ }
378
+ });
379
+ return this.promise.all(openPromises);
380
+ };
381
+ const collectAnchors = (root) => {
382
+ const result = new Map();
383
+ this.traverseNodes(root, next => {
384
+ const id = next.$id || next.id;
385
+ const anchor = isString(id) && id.charAt(0) === '#' ? id.substring(1) : next.$anchor;
386
+ if (anchor) {
387
+ if (result.has(anchor)) {
388
+ resolveErrors.push(localize('json.schema.duplicateid', 'Duplicate anchor declaration: \'{0}\'', anchor));
389
+ }
390
+ else {
391
+ result.set(anchor, next);
392
+ }
393
+ }
394
+ if (next.$recursiveAnchor) {
395
+ usesUnsupportedFeatures.add('$recursiveAnchor');
396
+ }
397
+ if (next.$dynamicAnchor) {
398
+ usesUnsupportedFeatures.add('$dynamicAnchor');
399
+ }
400
+ });
401
+ return result;
402
+ };
403
+ return resolveRefs(schema, schema, handle).then(_ => {
404
+ let resolveWarnings = [];
405
+ if (usesUnsupportedFeatures.size) {
406
+ resolveWarnings.push(localize('json.schema.warnings', 'The schema uses meta-schema features ({0}) that are not yet supported by the validator.', Array.from(usesUnsupportedFeatures.keys()).join(', ')));
407
+ }
408
+ return new ResolvedSchema(schema, resolveErrors, resolveWarnings, schemaDraft);
409
+ });
410
+ }
411
+ traverseNodes(root, handle) {
412
+ if (!root || typeof root !== 'object') {
413
+ return Promise.resolve(null);
414
+ }
415
+ const seen = new Set();
416
+ const collectEntries = (...entries) => {
417
+ for (const entry of entries) {
418
+ if (isObject(entry)) {
419
+ toWalk.push(entry);
420
+ }
421
+ }
422
+ };
423
+ const collectMapEntries = (...maps) => {
424
+ for (const map of maps) {
425
+ if (isObject(map)) {
426
+ for (const k in map) {
427
+ const key = k;
428
+ const entry = map[key];
429
+ if (isObject(entry)) {
430
+ toWalk.push(entry);
431
+ }
432
+ }
433
+ }
434
+ }
435
+ };
436
+ const collectArrayEntries = (...arrays) => {
437
+ for (const array of arrays) {
438
+ if (Array.isArray(array)) {
439
+ for (const entry of array) {
440
+ if (isObject(entry)) {
441
+ toWalk.push(entry);
442
+ }
443
+ }
444
+ }
445
+ }
446
+ };
447
+ const collectEntryOrArrayEntries = (items) => {
448
+ if (Array.isArray(items)) {
449
+ for (const entry of items) {
450
+ if (isObject(entry)) {
451
+ toWalk.push(entry);
452
+ }
453
+ }
454
+ }
455
+ else if (isObject(items)) {
456
+ toWalk.push(items);
457
+ }
458
+ };
459
+ const toWalk = [root];
460
+ let next = toWalk.pop();
461
+ while (next) {
462
+ if (!seen.has(next)) {
463
+ seen.add(next);
464
+ handle(next);
465
+ collectEntries(next.additionalItems, next.additionalProperties, next.not, next.contains, next.propertyNames, next.if, next.then, next.else, next.unevaluatedItems, next.unevaluatedProperties);
466
+ collectMapEntries(next.definitions, next.$defs, next.properties, next.patternProperties, next.dependencies, next.dependentSchemas);
467
+ collectArrayEntries(next.anyOf, next.allOf, next.oneOf, next.prefixItems);
468
+ collectEntryOrArrayEntries(next.items);
469
+ }
470
+ next = toWalk.pop();
471
+ }
472
+ }
473
+ ;
474
+ getSchemaFromProperty(resource, document) {
475
+ if (document.root?.type === 'object') {
476
+ for (const p of document.root.properties) {
477
+ if (p.keyNode.value === '$schema' && p.valueNode?.type === 'string') {
478
+ let schemaId = p.valueNode.value;
479
+ if (this.contextService && !/^\w[\w\d+.-]*:/.test(schemaId)) { // has scheme
480
+ schemaId = this.contextService.resolveRelativePath(schemaId, resource);
481
+ }
482
+ return schemaId;
483
+ }
484
+ }
485
+ }
486
+ return undefined;
487
+ }
488
+ getAssociatedSchemas(resource) {
489
+ const seen = Object.create(null);
490
+ const schemas = [];
491
+ const normalizedResource = normalizeResourceForMatching(resource);
492
+ for (const entry of this.filePatternAssociations) {
493
+ if (entry.matchesPattern(normalizedResource)) {
494
+ for (const schemaId of entry.getURIs()) {
495
+ if (!seen[schemaId]) {
496
+ schemas.push(schemaId);
497
+ seen[schemaId] = true;
498
+ }
499
+ }
500
+ }
501
+ }
502
+ return schemas;
503
+ }
504
+ getSchemaURIsForResource(resource, document) {
505
+ let schemeId = document && this.getSchemaFromProperty(resource, document);
506
+ if (schemeId) {
507
+ return [schemeId];
508
+ }
509
+ return this.getAssociatedSchemas(resource);
510
+ }
511
+ getSchemaForResource(resource, document) {
512
+ if (document) {
513
+ // first use $schema if present
514
+ let schemeId = this.getSchemaFromProperty(resource, document);
515
+ if (schemeId) {
516
+ const id = normalizeId(schemeId);
517
+ return this.getOrAddSchemaHandle(id).getResolvedSchema();
518
+ }
519
+ }
520
+ if (this.cachedSchemaForResource && this.cachedSchemaForResource.resource === resource) {
521
+ return this.cachedSchemaForResource.resolvedSchema;
522
+ }
523
+ const schemas = this.getAssociatedSchemas(resource);
524
+ const resolvedSchema = schemas.length > 0 ? this.createCombinedSchema(resource, schemas).getResolvedSchema() : this.promise.resolve(undefined);
525
+ this.cachedSchemaForResource = { resource, resolvedSchema };
526
+ return resolvedSchema;
527
+ }
528
+ createCombinedSchema(resource, schemaIds) {
529
+ if (schemaIds.length === 1) {
530
+ return this.getOrAddSchemaHandle(schemaIds[0]);
531
+ }
532
+ else {
533
+ const combinedSchemaId = 'schemaservice://combinedSchema/' + encodeURIComponent(resource);
534
+ const combinedSchema = {
535
+ allOf: schemaIds.map(schemaId => ({ $ref: schemaId }))
536
+ };
537
+ return this.addSchemaHandle(combinedSchemaId, combinedSchema);
538
+ }
539
+ }
540
+ getMatchingSchemas(document, jsonDocument, schema) {
541
+ if (schema) {
542
+ const id = schema.id || ('schemaservice://untitled/matchingSchemas/' + idCounter++);
543
+ const handle = this.addSchemaHandle(id, schema);
544
+ return handle.getResolvedSchema().then(resolvedSchema => {
545
+ return jsonDocument.getMatchingSchemas(resolvedSchema.schema).filter(s => !s.inverted);
546
+ });
547
+ }
548
+ return this.getSchemaForResource(document.uri, jsonDocument).then(schema => {
549
+ if (schema) {
550
+ return jsonDocument.getMatchingSchemas(schema.schema).filter(s => !s.inverted);
551
+ }
552
+ return [];
553
+ });
554
+ }
555
+ }
556
+ let idCounter = 0;
557
+ function normalizeId(id) {
558
+ // remove trailing '#', normalize drive capitalization
559
+ try {
560
+ return URI.parse(id).toString(true);
561
+ }
562
+ catch (e) {
563
+ return id;
564
+ }
565
+ }
566
+ function normalizeResourceForMatching(resource) {
567
+ // remove queries and fragments, normalize drive capitalization
568
+ try {
569
+ return URI.parse(resource).with({ fragment: null, query: null }).toString(true);
570
+ }
571
+ catch (e) {
572
+ return resource;
573
+ }
574
+ }
575
+ function toDisplayString(url) {
576
+ try {
577
+ const uri = URI.parse(url);
578
+ if (uri.scheme === 'file') {
579
+ return uri.fsPath;
580
+ }
581
+ }
582
+ catch (e) {
583
+ // ignore
584
+ }
585
+ return url;
586
+ }