UNPKG

@theia/core

Version:

Theia is a cloud & desktop IDE framework implemented in TypeScript.

128 lines (112 loc) 4.84 kB
// ***************************************************************************** // Copyright (C) 2018 TypeFox and others. // // This program and the accompanying materials are made available under the // terms of the Eclipse Public License v. 2.0 which is available at // http://www.eclipse.org/legal/epl-2.0. // // This Source Code may also be made available under the following Secondary // Licenses when the conditions for such availability set forth in the Eclipse // Public License v. 2.0 are satisfied: GNU General Public License, version 2 // with the GNU Classpath Exception which is available at // https://www.gnu.org/software/classpath/license.html. // // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 // ***************************************************************************** import { injectable, inject, named } from 'inversify'; import { ContributionProvider } from '../common/contribution-provider'; import { FrontendApplicationContribution } from './frontend-application-contribution'; import { MaybePromise } from '../common'; import { Endpoint } from './endpoint'; import { timeout, Deferred } from '../common/promise-util'; import { RequestContext, RequestService } from '@theia/request'; export interface JsonSchemaConfiguration { fileMatch: string | string[]; url: string; } export interface JsonSchemaRegisterContext { registerSchema(config: JsonSchemaConfiguration): void; } export const JsonSchemaContribution = Symbol('JsonSchemaContribution'); export interface JsonSchemaContribution { registerSchemas(store: JsonSchemaRegisterContext): MaybePromise<void> } @injectable() export class JsonSchemaStore implements FrontendApplicationContribution { @inject(ContributionProvider) @named(JsonSchemaContribution) protected readonly contributions: ContributionProvider<JsonSchemaContribution>; protected readonly _schemas = new Deferred<JsonSchemaConfiguration[]>(); get schemas(): Promise<JsonSchemaConfiguration[]> { return this._schemas.promise; } onStart(): void { const pendingRegistrations = []; const schemas: JsonSchemaConfiguration[] = []; const freeze = () => { Object.freeze(schemas); this._schemas.resolve(schemas); }; const registerTimeout = this.getRegisterTimeout(); const frozenErrorCode = 'JsonSchemaRegisterContext.frozen'; const context: JsonSchemaRegisterContext = { registerSchema: schema => { if (Object.isFrozen(schemas)) { throw new Error(frozenErrorCode); } schemas.push(schema); } }; for (const contribution of this.contributions.getContributions()) { const result = contribution.registerSchemas(context); if (result) { pendingRegistrations.push(result.then(() => { }, e => { if (e instanceof Error && e.message === frozenErrorCode) { console.error(`${contribution.constructor.name}.registerSchemas is taking more than ${registerTimeout.toFixed(1)} ms, new schemas are ignored.`); } else { console.error(e); } })); } } if (pendingRegistrations.length) { let pending = Promise.all(pendingRegistrations).then(() => { }); if (registerTimeout) { pending = Promise.race([pending, timeout(registerTimeout)]); } pending.then(freeze); } else { freeze(); } } protected getRegisterTimeout(): number { return 500; } } @injectable() export class DefaultJsonSchemaContribution implements JsonSchemaContribution { @inject(RequestService) protected readonly requestService: RequestService; protected readonly jsonSchemaUrl = `${new Endpoint().httpScheme}//schemastore.org/api/json/catalog.json`; async registerSchemas(context: JsonSchemaRegisterContext): Promise<void> { const response = await this.requestService.request({ url: this.jsonSchemaUrl }); const schemas = RequestContext.asJson<{ schemas: DefaultJsonSchemaContribution.SchemaData[] }>(response).schemas; for (const s of schemas) { if (s.fileMatch) { context.registerSchema({ fileMatch: s.fileMatch, url: s.url }); } } } } export namespace DefaultJsonSchemaContribution { export interface SchemaData { name: string; description: string; fileMatch?: string[]; url: string; // eslint-disable-next-line @typescript-eslint/no-explicit-any schema: any; } }