massive update, probably broken
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-json / node_modules / vscode-json-languageservice / lib / umd / services / jsonSchemaService.js
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", "minimatch", "vscode-nls"], 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     var Json = require("jsonc-parser");
18     var vscode_uri_1 = require("vscode-uri");
19     var Strings = require("../utils/strings");
20     var Parser = require("../parser/jsonParser");
21     var minimatch_1 = require("minimatch");
22     var nls = require("vscode-nls");
23     var localize = nls.loadMessageBundle();
24     var BANG = '!';
25     var PATH_SEP = '/';
26     var FilePatternAssociation = /** @class */ (function () {
27         function FilePatternAssociation(pattern, uris) {
28             this.minimatchWrappers = [];
29             try {
30                 for (var _i = 0, pattern_1 = pattern; _i < pattern_1.length; _i++) {
31                     var patternString = pattern_1[_i];
32                     var 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.minimatchWrappers.push({
41                             minimatch: new minimatch_1.Minimatch("**/" + patternString),
42                             include: include,
43                         });
44                     }
45                 }
46                 ;
47                 this.uris = uris;
48             }
49             catch (e) {
50                 this.minimatchWrappers.length = 0;
51                 this.uris = [];
52             }
53         }
54         FilePatternAssociation.prototype.matchesPattern = function (fileName) {
55             var match = false;
56             for (var _i = 0, _a = this.minimatchWrappers; _i < _a.length; _i++) {
57                 var _b = _a[_i], minimatch = _b.minimatch, include = _b.include;
58                 if (minimatch.match(fileName)) {
59                     match = include;
60                 }
61             }
62             return match;
63         };
64         FilePatternAssociation.prototype.getURIs = function () {
65             return this.uris;
66         };
67         return FilePatternAssociation;
68     }());
69     var SchemaHandle = /** @class */ (function () {
70         function SchemaHandle(service, url, unresolvedSchemaContent) {
71             this.service = service;
72             this.url = url;
73             this.dependencies = {};
74             if (unresolvedSchemaContent) {
75                 this.unresolvedSchema = this.service.promise.resolve(new UnresolvedSchema(unresolvedSchemaContent));
76             }
77         }
78         SchemaHandle.prototype.getUnresolvedSchema = function () {
79             if (!this.unresolvedSchema) {
80                 this.unresolvedSchema = this.service.loadSchema(this.url);
81             }
82             return this.unresolvedSchema;
83         };
84         SchemaHandle.prototype.getResolvedSchema = function () {
85             var _this = this;
86             if (!this.resolvedSchema) {
87                 this.resolvedSchema = this.getUnresolvedSchema().then(function (unresolved) {
88                     return _this.service.resolveSchemaContent(unresolved, _this.url, _this.dependencies);
89                 });
90             }
91             return this.resolvedSchema;
92         };
93         SchemaHandle.prototype.clearSchema = function () {
94             this.resolvedSchema = undefined;
95             this.unresolvedSchema = undefined;
96             this.dependencies = {};
97         };
98         return SchemaHandle;
99     }());
100     var UnresolvedSchema = /** @class */ (function () {
101         function UnresolvedSchema(schema, errors) {
102             if (errors === void 0) { errors = []; }
103             this.schema = schema;
104             this.errors = errors;
105         }
106         return UnresolvedSchema;
107     }());
108     exports.UnresolvedSchema = UnresolvedSchema;
109     var ResolvedSchema = /** @class */ (function () {
110         function ResolvedSchema(schema, errors) {
111             if (errors === void 0) { errors = []; }
112             this.schema = schema;
113             this.errors = errors;
114         }
115         ResolvedSchema.prototype.getSection = function (path) {
116             var schemaRef = this.getSectionRecursive(path, this.schema);
117             if (schemaRef) {
118                 return Parser.asSchema(schemaRef);
119             }
120             return undefined;
121         };
122         ResolvedSchema.prototype.getSectionRecursive = function (path, schema) {
123             if (!schema || typeof schema === 'boolean' || path.length === 0) {
124                 return schema;
125             }
126             var next = path.shift();
127             if (schema.properties && typeof schema.properties[next]) {
128                 return this.getSectionRecursive(path, schema.properties[next]);
129             }
130             else if (schema.patternProperties) {
131                 for (var _i = 0, _a = Object.keys(schema.patternProperties); _i < _a.length; _i++) {
132                     var pattern = _a[_i];
133                     var regex = Strings.extendedRegExp(pattern);
134                     if (regex.test(next)) {
135                         return this.getSectionRecursive(path, schema.patternProperties[pattern]);
136                     }
137                 }
138             }
139             else if (typeof schema.additionalProperties === 'object') {
140                 return this.getSectionRecursive(path, schema.additionalProperties);
141             }
142             else if (next.match('[0-9]+')) {
143                 if (Array.isArray(schema.items)) {
144                     var index = parseInt(next, 10);
145                     if (!isNaN(index) && schema.items[index]) {
146                         return this.getSectionRecursive(path, schema.items[index]);
147                     }
148                 }
149                 else if (schema.items) {
150                     return this.getSectionRecursive(path, schema.items);
151                 }
152             }
153             return undefined;
154         };
155         return ResolvedSchema;
156     }());
157     exports.ResolvedSchema = ResolvedSchema;
158     var JSONSchemaService = /** @class */ (function () {
159         function JSONSchemaService(requestService, contextService, promiseConstructor) {
160             this.contextService = contextService;
161             this.requestService = requestService;
162             this.promiseConstructor = promiseConstructor || Promise;
163             this.callOnDispose = [];
164             this.contributionSchemas = {};
165             this.contributionAssociations = [];
166             this.schemasById = {};
167             this.filePatternAssociations = [];
168             this.registeredSchemasIds = {};
169         }
170         JSONSchemaService.prototype.getRegisteredSchemaIds = function (filter) {
171             return Object.keys(this.registeredSchemasIds).filter(function (id) {
172                 var scheme = vscode_uri_1.URI.parse(id).scheme;
173                 return scheme !== 'schemaservice' && (!filter || filter(scheme));
174             });
175         };
176         Object.defineProperty(JSONSchemaService.prototype, "promise", {
177             get: function () {
178                 return this.promiseConstructor;
179             },
180             enumerable: false,
181             configurable: true
182         });
183         JSONSchemaService.prototype.dispose = function () {
184             while (this.callOnDispose.length > 0) {
185                 this.callOnDispose.pop()();
186             }
187         };
188         JSONSchemaService.prototype.onResourceChange = function (uri) {
189             var _this = this;
190             var hasChanges = false;
191             uri = normalizeId(uri);
192             var toWalk = [uri];
193             var all = Object.keys(this.schemasById).map(function (key) { return _this.schemasById[key]; });
194             while (toWalk.length) {
195                 var curr = toWalk.pop();
196                 for (var i = 0; i < all.length; i++) {
197                     var handle = all[i];
198                     if (handle && (handle.url === curr || handle.dependencies[curr])) {
199                         if (handle.url !== curr) {
200                             toWalk.push(handle.url);
201                         }
202                         handle.clearSchema();
203                         all[i] = undefined;
204                         hasChanges = true;
205                     }
206                 }
207             }
208             return hasChanges;
209         };
210         JSONSchemaService.prototype.setSchemaContributions = function (schemaContributions) {
211             if (schemaContributions.schemas) {
212                 var schemas = schemaContributions.schemas;
213                 for (var id in schemas) {
214                     var normalizedId = normalizeId(id);
215                     this.contributionSchemas[normalizedId] = this.addSchemaHandle(normalizedId, schemas[id]);
216                 }
217             }
218             if (Array.isArray(schemaContributions.schemaAssociations)) {
219                 var schemaAssociations = schemaContributions.schemaAssociations;
220                 for (var _i = 0, schemaAssociations_1 = schemaAssociations; _i < schemaAssociations_1.length; _i++) {
221                     var schemaAssociation = schemaAssociations_1[_i];
222                     var uris = schemaAssociation.uris.map(normalizeId);
223                     var association = this.addFilePatternAssociation(schemaAssociation.pattern, uris);
224                     this.contributionAssociations.push(association);
225                 }
226             }
227         };
228         JSONSchemaService.prototype.addSchemaHandle = function (id, unresolvedSchemaContent) {
229             var schemaHandle = new SchemaHandle(this, id, unresolvedSchemaContent);
230             this.schemasById[id] = schemaHandle;
231             return schemaHandle;
232         };
233         JSONSchemaService.prototype.getOrAddSchemaHandle = function (id, unresolvedSchemaContent) {
234             return this.schemasById[id] || this.addSchemaHandle(id, unresolvedSchemaContent);
235         };
236         JSONSchemaService.prototype.addFilePatternAssociation = function (pattern, uris) {
237             var fpa = new FilePatternAssociation(pattern, uris);
238             this.filePatternAssociations.push(fpa);
239             return fpa;
240         };
241         JSONSchemaService.prototype.registerExternalSchema = function (uri, filePatterns, unresolvedSchemaContent) {
242             var id = normalizeId(uri);
243             this.registeredSchemasIds[id] = true;
244             this.cachedSchemaForResource = undefined;
245             if (filePatterns) {
246                 this.addFilePatternAssociation(filePatterns, [uri]);
247             }
248             return unresolvedSchemaContent ? this.addSchemaHandle(id, unresolvedSchemaContent) : this.getOrAddSchemaHandle(id);
249         };
250         JSONSchemaService.prototype.clearExternalSchemas = function () {
251             this.schemasById = {};
252             this.filePatternAssociations = [];
253             this.registeredSchemasIds = {};
254             this.cachedSchemaForResource = undefined;
255             for (var id in this.contributionSchemas) {
256                 this.schemasById[id] = this.contributionSchemas[id];
257                 this.registeredSchemasIds[id] = true;
258             }
259             for (var _i = 0, _a = this.contributionAssociations; _i < _a.length; _i++) {
260                 var contributionAssociation = _a[_i];
261                 this.filePatternAssociations.push(contributionAssociation);
262             }
263         };
264         JSONSchemaService.prototype.getResolvedSchema = function (schemaId) {
265             var id = normalizeId(schemaId);
266             var schemaHandle = this.schemasById[id];
267             if (schemaHandle) {
268                 return schemaHandle.getResolvedSchema();
269             }
270             return this.promise.resolve(undefined);
271         };
272         JSONSchemaService.prototype.loadSchema = function (url) {
273             if (!this.requestService) {
274                 var errorMessage = localize('json.schema.norequestservice', 'Unable to load schema from \'{0}\'. No schema request service available', toDisplayString(url));
275                 return this.promise.resolve(new UnresolvedSchema({}, [errorMessage]));
276             }
277             return this.requestService(url).then(function (content) {
278                 if (!content) {
279                     var errorMessage = localize('json.schema.nocontent', 'Unable to load schema from \'{0}\': No content.', toDisplayString(url));
280                     return new UnresolvedSchema({}, [errorMessage]);
281                 }
282                 var schemaContent = {};
283                 var jsonErrors = [];
284                 schemaContent = Json.parse(content, jsonErrors);
285                 var errors = jsonErrors.length ? [localize('json.schema.invalidFormat', 'Unable to parse content from \'{0}\': Parse error at offset {1}.', toDisplayString(url), jsonErrors[0].offset)] : [];
286                 return new UnresolvedSchema(schemaContent, errors);
287             }, function (error) {
288                 var errorMessage = error.toString();
289                 var 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         JSONSchemaService.prototype.resolveSchemaContent = function (schemaToResolve, schemaURL, dependencies) {
301             var _this = this;
302             var resolveErrors = schemaToResolve.errors.slice(0);
303             var schema = schemaToResolve.schema;
304             if (schema.$schema) {
305                 var id = normalizeId(schema.$schema);
306                 if (id === 'http://json-schema.org/draft-03/schema') {
307                     return this.promise.resolve(new ResolvedSchema({}, [localize('json.schema.draft03.notsupported', "Draft-03 schemas are not supported.")]));
308                 }
309                 else if (id === 'https://json-schema.org/draft/2019-09/schema') {
310                     resolveErrors.push(localize('json.schema.draft201909.notsupported', "Draft 2019-09 schemas are not yet fully supported."));
311                 }
312             }
313             var contextService = this.contextService;
314             var findSection = function (schema, path) {
315                 if (!path) {
316                     return schema;
317                 }
318                 var current = schema;
319                 if (path[0] === '/') {
320                     path = path.substr(1);
321                 }
322                 path.split('/').some(function (part) {
323                     part = part.replace(/~1/g, '/').replace(/~0/g, '~');
324                     current = current[part];
325                     return !current;
326                 });
327                 return current;
328             };
329             var merge = function (target, sourceRoot, sourceURI, refSegment) {
330                 var path = refSegment ? decodeURIComponent(refSegment) : undefined;
331                 var section = findSection(sourceRoot, path);
332                 if (section) {
333                     for (var key in section) {
334                         if (section.hasOwnProperty(key) && !target.hasOwnProperty(key)) {
335                             target[key] = section[key];
336                         }
337                     }
338                 }
339                 else {
340                     resolveErrors.push(localize('json.schema.invalidref', '$ref \'{0}\' in \'{1}\' can not be resolved.', path, sourceURI));
341                 }
342             };
343             var resolveExternalLink = function (node, uri, refSegment, parentSchemaURL, parentSchemaDependencies) {
344                 if (contextService && !/^\w+:\/\/.*/.test(uri)) {
345                     uri = contextService.resolveRelativePath(uri, parentSchemaURL);
346                 }
347                 uri = normalizeId(uri);
348                 var referencedHandle = _this.getOrAddSchemaHandle(uri);
349                 return referencedHandle.getUnresolvedSchema().then(function (unresolvedSchema) {
350                     parentSchemaDependencies[uri] = true;
351                     if (unresolvedSchema.errors.length) {
352                         var loc = refSegment ? uri + '#' + refSegment : uri;
353                         resolveErrors.push(localize('json.schema.problemloadingref', 'Problems loading reference \'{0}\': {1}', loc, unresolvedSchema.errors[0]));
354                     }
355                     merge(node, unresolvedSchema.schema, uri, refSegment);
356                     return resolveRefs(node, unresolvedSchema.schema, uri, referencedHandle.dependencies);
357                 });
358             };
359             var resolveRefs = function (node, parentSchema, parentSchemaURL, parentSchemaDependencies) {
360                 if (!node || typeof node !== 'object') {
361                     return Promise.resolve(null);
362                 }
363                 var toWalk = [node];
364                 var seen = [];
365                 var openPromises = [];
366                 var collectEntries = function () {
367                     var entries = [];
368                     for (var _i = 0; _i < arguments.length; _i++) {
369                         entries[_i] = arguments[_i];
370                     }
371                     for (var _a = 0, entries_1 = entries; _a < entries_1.length; _a++) {
372                         var entry = entries_1[_a];
373                         if (typeof entry === 'object') {
374                             toWalk.push(entry);
375                         }
376                     }
377                 };
378                 var collectMapEntries = function () {
379                     var maps = [];
380                     for (var _i = 0; _i < arguments.length; _i++) {
381                         maps[_i] = arguments[_i];
382                     }
383                     for (var _a = 0, maps_1 = maps; _a < maps_1.length; _a++) {
384                         var map = maps_1[_a];
385                         if (typeof map === 'object') {
386                             for (var k in map) {
387                                 var key = k;
388                                 var entry = map[key];
389                                 if (typeof entry === 'object') {
390                                     toWalk.push(entry);
391                                 }
392                             }
393                         }
394                     }
395                 };
396                 var collectArrayEntries = function () {
397                     var arrays = [];
398                     for (var _i = 0; _i < arguments.length; _i++) {
399                         arrays[_i] = arguments[_i];
400                     }
401                     for (var _a = 0, arrays_1 = arrays; _a < arrays_1.length; _a++) {
402                         var array = arrays_1[_a];
403                         if (Array.isArray(array)) {
404                             for (var _b = 0, array_1 = array; _b < array_1.length; _b++) {
405                                 var entry = array_1[_b];
406                                 if (typeof entry === 'object') {
407                                     toWalk.push(entry);
408                                 }
409                             }
410                         }
411                     }
412                 };
413                 var handleRef = function (next) {
414                     var seenRefs = [];
415                     while (next.$ref) {
416                         var ref = next.$ref;
417                         var segments = ref.split('#', 2);
418                         delete next.$ref;
419                         if (segments[0].length > 0) {
420                             openPromises.push(resolveExternalLink(next, segments[0], segments[1], parentSchemaURL, parentSchemaDependencies));
421                             return;
422                         }
423                         else {
424                             if (seenRefs.indexOf(ref) === -1) {
425                                 merge(next, parentSchema, parentSchemaURL, segments[1]); // can set next.$ref again, use seenRefs to avoid circle
426                                 seenRefs.push(ref);
427                             }
428                         }
429                     }
430                     collectEntries(next.items, next.additionalItems, next.additionalProperties, next.not, next.contains, next.propertyNames, next.if, next.then, next.else);
431                     collectMapEntries(next.definitions, next.properties, next.patternProperties, next.dependencies);
432                     collectArrayEntries(next.anyOf, next.allOf, next.oneOf, next.items);
433                 };
434                 while (toWalk.length) {
435                     var next = toWalk.pop();
436                     if (seen.indexOf(next) >= 0) {
437                         continue;
438                     }
439                     seen.push(next);
440                     handleRef(next);
441                 }
442                 return _this.promise.all(openPromises);
443             };
444             return resolveRefs(schema, schema, schemaURL, dependencies).then(function (_) { return new ResolvedSchema(schema, resolveErrors); });
445         };
446         JSONSchemaService.prototype.getSchemaForResource = function (resource, document) {
447             // first use $schema if present
448             if (document && document.root && document.root.type === 'object') {
449                 var schemaProperties = document.root.properties.filter(function (p) { return (p.keyNode.value === '$schema') && p.valueNode && p.valueNode.type === 'string'; });
450                 if (schemaProperties.length > 0) {
451                     var valueNode = schemaProperties[0].valueNode;
452                     if (valueNode && valueNode.type === 'string') {
453                         var schemeId = Parser.getNodeValue(valueNode);
454                         if (schemeId && Strings.startsWith(schemeId, '.') && this.contextService) {
455                             schemeId = this.contextService.resolveRelativePath(schemeId, resource);
456                         }
457                         if (schemeId) {
458                             var id = normalizeId(schemeId);
459                             return this.getOrAddSchemaHandle(id).getResolvedSchema();
460                         }
461                     }
462                 }
463             }
464             if (this.cachedSchemaForResource && this.cachedSchemaForResource.resource === resource) {
465                 return this.cachedSchemaForResource.resolvedSchema;
466             }
467             var seen = Object.create(null);
468             var schemas = [];
469             var normalizedResource = normalizeResourceForMatching(resource);
470             for (var _i = 0, _a = this.filePatternAssociations; _i < _a.length; _i++) {
471                 var entry = _a[_i];
472                 if (entry.matchesPattern(normalizedResource)) {
473                     for (var _b = 0, _c = entry.getURIs(); _b < _c.length; _b++) {
474                         var schemaId = _c[_b];
475                         if (!seen[schemaId]) {
476                             schemas.push(schemaId);
477                             seen[schemaId] = true;
478                         }
479                     }
480                 }
481             }
482             var resolvedSchema = schemas.length > 0 ? this.createCombinedSchema(resource, schemas).getResolvedSchema() : this.promise.resolve(undefined);
483             this.cachedSchemaForResource = { resource: resource, resolvedSchema: resolvedSchema };
484             return resolvedSchema;
485         };
486         JSONSchemaService.prototype.createCombinedSchema = function (resource, schemaIds) {
487             if (schemaIds.length === 1) {
488                 return this.getOrAddSchemaHandle(schemaIds[0]);
489             }
490             else {
491                 var combinedSchemaId = 'schemaservice://combinedSchema/' + encodeURIComponent(resource);
492                 var combinedSchema = {
493                     allOf: schemaIds.map(function (schemaId) { return ({ $ref: schemaId }); })
494                 };
495                 return this.addSchemaHandle(combinedSchemaId, combinedSchema);
496             }
497         };
498         JSONSchemaService.prototype.getMatchingSchemas = function (document, jsonDocument, schema) {
499             if (schema) {
500                 var id = schema.id || ('schemaservice://untitled/matchingSchemas/' + idCounter++);
501                 return this.resolveSchemaContent(new UnresolvedSchema(schema), id, {}).then(function (resolvedSchema) {
502                     return jsonDocument.getMatchingSchemas(resolvedSchema.schema).filter(function (s) { return !s.inverted; });
503                 });
504             }
505             return this.getSchemaForResource(document.uri, jsonDocument).then(function (schema) {
506                 if (schema) {
507                     return jsonDocument.getMatchingSchemas(schema.schema).filter(function (s) { return !s.inverted; });
508                 }
509                 return [];
510             });
511         };
512         return JSONSchemaService;
513     }());
514     exports.JSONSchemaService = JSONSchemaService;
515     var idCounter = 0;
516     function normalizeId(id) {
517         // remove trailing '#', normalize drive capitalization
518         try {
519             return vscode_uri_1.URI.parse(id).toString();
520         }
521         catch (e) {
522             return id;
523         }
524     }
525     function normalizeResourceForMatching(resource) {
526         // remove queries and fragments, normalize drive capitalization
527         try {
528             return vscode_uri_1.URI.parse(resource).with({ fragment: null, query: null }).toString();
529         }
530         catch (e) {
531             return resource;
532         }
533     }
534     function toDisplayString(url) {
535         try {
536             var uri = vscode_uri_1.URI.parse(url);
537             if (uri.scheme === 'file') {
538                 return uri.fsPath;
539             }
540         }
541         catch (e) {
542             // ignore
543         }
544         return url;
545     }
546 });