UNPKG

monaco-editor

Version:
446 lines • 19.4 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ 'use strict'; import * as Json from './../../jsonc-parser/main.js'; import URI from './../../vscode-uri/index.js'; import * as Strings from '../utils/strings.js'; import * as Parser from '../parser/jsonParser.js'; import * as nls from './../../../fillers/vscode-nls.js'; var localize = nls.loadMessageBundle(); var FilePatternAssociation = /** @class */ (function () { function FilePatternAssociation(pattern) { try { this.patternRegExp = new RegExp(Strings.convertSimple2RegExpPattern(pattern) + '$'); } catch (e) { // invalid pattern this.patternRegExp = null; } this.schemas = []; } FilePatternAssociation.prototype.addSchema = function (id) { this.schemas.push(id); }; FilePatternAssociation.prototype.matchesPattern = function (fileName) { return this.patternRegExp && this.patternRegExp.test(fileName); }; FilePatternAssociation.prototype.getSchemas = function () { return this.schemas; }; return FilePatternAssociation; }()); var SchemaHandle = /** @class */ (function () { function SchemaHandle(service, url, unresolvedSchemaContent) { this.service = service; this.url = url; if (unresolvedSchemaContent) { this.unresolvedSchema = this.service.promise.resolve(new UnresolvedSchema(unresolvedSchemaContent)); } } SchemaHandle.prototype.getUnresolvedSchema = function () { if (!this.unresolvedSchema) { this.unresolvedSchema = this.service.loadSchema(this.url); } return this.unresolvedSchema; }; SchemaHandle.prototype.getResolvedSchema = function () { var _this = this; if (!this.resolvedSchema) { this.resolvedSchema = this.getUnresolvedSchema().then(function (unresolved) { return _this.service.resolveSchemaContent(unresolved, _this.url); }); } return this.resolvedSchema; }; SchemaHandle.prototype.clearSchema = function () { this.resolvedSchema = null; this.unresolvedSchema = null; }; return SchemaHandle; }()); var UnresolvedSchema = /** @class */ (function () { function UnresolvedSchema(schema, errors) { if (errors === void 0) { errors = []; } this.schema = schema; this.errors = errors; } return UnresolvedSchema; }()); export { UnresolvedSchema }; var ResolvedSchema = /** @class */ (function () { function ResolvedSchema(schema, errors) { if (errors === void 0) { errors = []; } this.schema = schema; this.errors = errors; } ResolvedSchema.prototype.getSection = function (path) { return Parser.asSchema(this.getSectionRecursive(path, this.schema)); }; ResolvedSchema.prototype.getSectionRecursive = function (path, schema) { var _this = this; if (!schema || typeof schema === 'boolean' || path.length === 0) { return schema; } var next = path.shift(); if (schema.properties && typeof schema.properties[next]) { return this.getSectionRecursive(path, schema.properties[next]); } else if (schema.patternProperties) { Object.keys(schema.patternProperties).forEach(function (pattern) { var regex = new RegExp(pattern); if (regex.test(next)) { return _this.getSectionRecursive(path, schema.patternProperties[pattern]); } }); } else if (typeof schema.additionalProperties === 'object') { return this.getSectionRecursive(path, schema.additionalProperties); } else if (next.match('[0-9]+')) { if (Array.isArray(schema.items)) { var index = parseInt(next, 10); if (!isNaN(index) && schema.items[index]) { return this.getSectionRecursive(path, schema.items[index]); } } else if (schema.items) { return this.getSectionRecursive(path, schema.items); } } return null; }; return ResolvedSchema; }()); export { ResolvedSchema }; var JSONSchemaService = /** @class */ (function () { function JSONSchemaService(requestService, contextService, promiseConstructor) { this.contextService = contextService; this.requestService = requestService; this.promiseConstructor = promiseConstructor || Promise; this.callOnDispose = []; this.contributionSchemas = {}; this.contributionAssociations = {}; this.schemasById = {}; this.filePatternAssociations = []; this.filePatternAssociationById = {}; this.registeredSchemasIds = {}; } JSONSchemaService.prototype.getRegisteredSchemaIds = function (filter) { return Object.keys(this.registeredSchemasIds).filter(function (id) { var scheme = URI.parse(id).scheme; return scheme !== 'schemaservice' && (!filter || filter(scheme)); }); }; Object.defineProperty(JSONSchemaService.prototype, "promise", { get: function () { return this.promiseConstructor; }, enumerable: true, configurable: true }); JSONSchemaService.prototype.dispose = function () { while (this.callOnDispose.length > 0) { this.callOnDispose.pop()(); } }; JSONSchemaService.prototype.onResourceChange = function (uri) { uri = this.normalizeId(uri); var schemaFile = this.schemasById[uri]; if (schemaFile) { schemaFile.clearSchema(); return true; } return false; }; JSONSchemaService.prototype.normalizeId = function (id) { // remove trailing '#', normalize drive capitalization return URI.parse(id).toString(); }; JSONSchemaService.prototype.setSchemaContributions = function (schemaContributions) { var _this = this; if (schemaContributions.schemas) { var schemas = schemaContributions.schemas; for (var id in schemas) { var normalizedId = this.normalizeId(id); this.contributionSchemas[normalizedId] = this.addSchemaHandle(normalizedId, schemas[id]); } } if (schemaContributions.schemaAssociations) { var schemaAssociations = schemaContributions.schemaAssociations; for (var pattern in schemaAssociations) { var associations = schemaAssociations[pattern]; this.contributionAssociations[pattern] = associations; var fpa = this.getOrAddFilePatternAssociation(pattern); associations.forEach(function (schemaId) { var id = _this.normalizeId(schemaId); fpa.addSchema(id); }); } } }; JSONSchemaService.prototype.addSchemaHandle = function (id, unresolvedSchemaContent) { var schemaHandle = new SchemaHandle(this, id, unresolvedSchemaContent); this.schemasById[id] = schemaHandle; return schemaHandle; }; JSONSchemaService.prototype.getOrAddSchemaHandle = function (id, unresolvedSchemaContent) { return this.schemasById[id] || this.addSchemaHandle(id, unresolvedSchemaContent); }; JSONSchemaService.prototype.getOrAddFilePatternAssociation = function (pattern) { var fpa = this.filePatternAssociationById[pattern]; if (!fpa) { fpa = new FilePatternAssociation(pattern); this.filePatternAssociationById[pattern] = fpa; this.filePatternAssociations.push(fpa); } return fpa; }; JSONSchemaService.prototype.registerExternalSchema = function (uri, filePatterns, unresolvedSchemaContent) { var _this = this; if (filePatterns === void 0) { filePatterns = null; } var id = this.normalizeId(uri); this.registeredSchemasIds[id] = true; if (filePatterns) { filePatterns.forEach(function (pattern) { _this.getOrAddFilePatternAssociation(pattern).addSchema(id); }); } return unresolvedSchemaContent ? this.addSchemaHandle(id, unresolvedSchemaContent) : this.getOrAddSchemaHandle(id); }; JSONSchemaService.prototype.clearExternalSchemas = function () { var _this = this; this.schemasById = {}; this.filePatternAssociations = []; this.filePatternAssociationById = {}; this.registeredSchemasIds = {}; for (var id in this.contributionSchemas) { this.schemasById[id] = this.contributionSchemas[id]; this.registeredSchemasIds[id] = true; } for (var pattern in this.contributionAssociations) { var fpa = this.getOrAddFilePatternAssociation(pattern); this.contributionAssociations[pattern].forEach(function (schemaId) { var id = _this.normalizeId(schemaId); fpa.addSchema(id); }); } }; JSONSchemaService.prototype.getResolvedSchema = function (schemaId) { var id = this.normalizeId(schemaId); var schemaHandle = this.schemasById[id]; if (schemaHandle) { return schemaHandle.getResolvedSchema(); } return this.promise.resolve(null); }; JSONSchemaService.prototype.loadSchema = function (url) { if (!this.requestService) { var errorMessage = localize('json.schema.norequestservice', 'Unable to load schema from \'{0}\'. No schema request service available', toDisplayString(url)); return this.promise.resolve(new UnresolvedSchema({}, [errorMessage])); } return this.requestService(url).then(function (content) { if (!content) { var errorMessage = localize('json.schema.nocontent', 'Unable to load schema from \'{0}\': No content.', toDisplayString(url)); return new UnresolvedSchema({}, [errorMessage]); } var schemaContent = {}; var jsonErrors = []; schemaContent = Json.parse(content, jsonErrors); var errors = jsonErrors.length ? [localize('json.schema.invalidFormat', 'Unable to parse content from \'{0}\': Parse error at offset {1}.', toDisplayString(url), jsonErrors[0].offset)] : []; return new UnresolvedSchema(schemaContent, errors); }, function (error) { var errorMessage = localize('json.schema.unabletoload', 'Unable to load schema from \'{0}\': {1}', toDisplayString(url), error.toString()); return new UnresolvedSchema({}, [errorMessage]); }); }; JSONSchemaService.prototype.resolveSchemaContent = function (schemaToResolve, schemaURL) { var _this = this; var resolveErrors = schemaToResolve.errors.slice(0); var schema = schemaToResolve.schema; var contextService = this.contextService; var findSection = function (schema, path) { if (!path) { return schema; } var current = schema; if (path[0] === '/') { path = path.substr(1); } path.split('/').some(function (part) { current = current[part]; return !current; }); return current; }; var merge = function (target, sourceRoot, sourceURI, path) { var section = findSection(sourceRoot, path); if (section) { for (var key in section) { if (section.hasOwnProperty(key) && !target.hasOwnProperty(key)) { target[key] = section[key]; } } } else { resolveErrors.push(localize('json.schema.invalidref', '$ref \'{0}\' in \'{1}\' can not be resolved.', path, sourceURI)); } }; var resolveExternalLink = function (node, uri, linkPath, parentSchemaURL) { if (contextService && !/^\w+:\/\/.*/.test(uri)) { uri = contextService.resolveRelativePath(uri, parentSchemaURL); } uri = _this.normalizeId(uri); return _this.getOrAddSchemaHandle(uri).getUnresolvedSchema().then(function (unresolvedSchema) { if (unresolvedSchema.errors.length) { var loc = linkPath ? uri + '#' + linkPath : uri; resolveErrors.push(localize('json.schema.problemloadingref', 'Problems loading reference \'{0}\': {1}', loc, unresolvedSchema.errors[0])); } merge(node, unresolvedSchema.schema, uri, linkPath); return resolveRefs(node, unresolvedSchema.schema, uri); }); }; var resolveRefs = function (node, parentSchema, parentSchemaURL) { if (!node || typeof node !== 'object') { return Promise.resolve(null); } var toWalk = [node]; var seen = []; var openPromises = []; var collectEntries = function () { var entries = []; for (var _i = 0; _i < arguments.length; _i++) { entries[_i] = arguments[_i]; } for (var _a = 0, entries_1 = entries; _a < entries_1.length; _a++) { var entry = entries_1[_a]; if (typeof entry === 'object') { toWalk.push(entry); } } }; var collectMapEntries = function () { var maps = []; for (var _i = 0; _i < arguments.length; _i++) { maps[_i] = arguments[_i]; } for (var _a = 0, maps_1 = maps; _a < maps_1.length; _a++) { var map = maps_1[_a]; if (typeof map === 'object') { for (var key in map) { var entry = map[key]; if (typeof entry === 'object') { toWalk.push(entry); } } } } }; var collectArrayEntries = function () { var arrays = []; for (var _i = 0; _i < arguments.length; _i++) { arrays[_i] = arguments[_i]; } for (var _a = 0, arrays_1 = arrays; _a < arrays_1.length; _a++) { var array = arrays_1[_a]; if (Array.isArray(array)) { for (var _b = 0, array_1 = array; _b < array_1.length; _b++) { var entry = array_1[_b]; if (typeof entry === 'object') { toWalk.push(entry); } } } } }; var handleRef = function (next) { while (next.$ref) { var segments = next.$ref.split('#', 2); delete next.$ref; if (segments[0].length > 0) { openPromises.push(resolveExternalLink(next, segments[0], segments[1], parentSchemaURL)); return; } else { merge(next, parentSchema, parentSchemaURL, segments[1]); // can set next.$ref again } } collectEntries(next.items, next.additionalProperties, next.not, next.contains, next.propertyNames, next.if, next.then, next.else); collectMapEntries(next.definitions, next.properties, next.patternProperties, next.dependencies); collectArrayEntries(next.anyOf, next.allOf, next.oneOf, next.items); }; while (toWalk.length) { var next = toWalk.pop(); if (seen.indexOf(next) >= 0) { continue; } seen.push(next); handleRef(next); } return _this.promise.all(openPromises); }; return resolveRefs(schema, schema, schemaURL).then(function (_) { return new ResolvedSchema(schema, resolveErrors); }); }; JSONSchemaService.prototype.getSchemaForResource = function (resource, document) { // first use $schema if present if (document && document.root && document.root.type === 'object') { var schemaProperties = document.root.properties.filter(function (p) { return (p.keyNode.value === '$schema') && p.valueNode && p.valueNode.type === 'string'; }); if (schemaProperties.length > 0) { var schemeId = Parser.getNodeValue(schemaProperties[0].valueNode); if (schemeId && Strings.startsWith(schemeId, '.') && this.contextService) { schemeId = this.contextService.resolveRelativePath(schemeId, resource); } if (schemeId) { var id = this.normalizeId(schemeId); return this.getOrAddSchemaHandle(id).getResolvedSchema(); } } } var seen = Object.create(null); var schemas = []; for (var _i = 0, _a = this.filePatternAssociations; _i < _a.length; _i++) { var entry = _a[_i]; if (entry.matchesPattern(resource)) { for (var _b = 0, _c = entry.getSchemas(); _b < _c.length; _b++) { var schemaId = _c[_b]; if (!seen[schemaId]) { schemas.push(schemaId); seen[schemaId] = true; } } } } if (schemas.length > 0) { return this.createCombinedSchema(resource, schemas).getResolvedSchema(); } return this.promise.resolve(null); }; JSONSchemaService.prototype.createCombinedSchema = function (resource, schemaIds) { if (schemaIds.length === 1) { return this.getOrAddSchemaHandle(schemaIds[0]); } else { var combinedSchemaId = 'schemaservice://combinedSchema/' + encodeURIComponent(resource); var combinedSchema = { allOf: schemaIds.map(function (schemaId) { return ({ $ref: schemaId }); }) }; return this.addSchemaHandle(combinedSchemaId, combinedSchema); } }; return JSONSchemaService; }()); export { JSONSchemaService }; function toDisplayString(url) { try { var uri = URI.parse(url); if (uri.scheme === 'file') { return uri.fsPath; } } catch (e) { // ignore } return url; } //# sourceMappingURL=jsonSchemaService.js.map