vscode-json-languageservice 5.0.0 → 5.1.1

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