@theia/core
Version:
Theia is a cloud & desktop IDE framework implemented in TypeScript.
359 lines • 18.3 kB
JavaScript
"use strict";
// *****************************************************************************
// Copyright (C) 2018 Ericsson 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
// *****************************************************************************
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PreferenceServiceImpl = exports.PreferenceProviderProvider = exports.PreferenceService = exports.PreferenceChangeImpl = exports.PreferenceScope = void 0;
/* eslint-disable @typescript-eslint/no-explicit-any */
const inversify_1 = require("inversify");
const common_1 = require("../../common");
const promise_util_1 = require("../../common/promise-util");
const preference_provider_1 = require("./preference-provider");
const preference_contribution_1 = require("./preference-contribution");
const uri_1 = require("../../common/uri");
const preference_scope_1 = require("./preference-scope");
Object.defineProperty(exports, "PreferenceScope", { enumerable: true, get: function () { return preference_scope_1.PreferenceScope; } });
const preference_configurations_1 = require("./preference-configurations");
const json_1 = require("@phosphor/coreutils/lib/json");
const preference_language_override_service_1 = require("./preference-language-override-service");
class PreferenceChangeImpl {
constructor(change) {
this.change = (0, common_1.deepFreeze)(change);
}
get preferenceName() {
return this.change.preferenceName;
}
get newValue() {
return this.change.newValue;
}
get oldValue() {
return this.change.oldValue;
}
get scope() {
return this.change.scope;
}
get domain() {
return this.change.domain;
}
// TODO add tests
affects(resourceUri) {
const resourcePath = resourceUri && new uri_1.default(resourceUri).path;
const domain = this.change.domain;
return !resourcePath || !domain || domain.some(uri => new uri_1.default(uri).path.relativity(resourcePath) >= 0);
}
}
exports.PreferenceChangeImpl = PreferenceChangeImpl;
exports.PreferenceService = Symbol('PreferenceService');
/**
* We cannot load providers directly in the case if they depend on `PreferenceService` somehow.
* It allows to load them lazily after DI is configured.
*/
exports.PreferenceProviderProvider = Symbol('PreferenceProviderProvider');
let PreferenceServiceImpl = class PreferenceServiceImpl {
constructor() {
this.onPreferenceChangedEmitter = new common_1.Emitter();
this.onPreferenceChanged = this.onPreferenceChangedEmitter.event;
this.onPreferencesChangedEmitter = new common_1.Emitter();
this.onPreferencesChanged = this.onPreferencesChangedEmitter.event;
this.toDispose = new common_1.DisposableCollection(this.onPreferenceChangedEmitter, this.onPreferencesChangedEmitter);
this.preferenceProviders = new Map();
this._ready = new promise_util_1.Deferred();
this._isReady = false;
}
async initializeProviders() {
try {
for (const scope of preference_scope_1.PreferenceScope.getScopes()) {
const provider = this.providerProvider(scope);
this.preferenceProviders.set(scope, provider);
this.toDispose.push(provider.onDidPreferencesChanged(changes => this.reconcilePreferences(changes)));
await provider.ready;
}
this._ready.resolve();
this._isReady = true;
}
catch (e) {
this._ready.reject(e);
}
}
init() {
this.toDispose.push(common_1.Disposable.create(() => this._ready.reject(new Error('preference service is disposed'))));
this.initializeProviders();
}
dispose() {
this.toDispose.dispose();
}
get ready() {
return this._ready.promise;
}
get isReady() {
return this._isReady;
}
reconcilePreferences(changes) {
const changesToEmit = {};
const acceptChange = (change) => this.getAffectedPreferenceNames(change, preferenceName => changesToEmit[preferenceName] = new PreferenceChangeImpl({ ...change, preferenceName }));
for (const preferenceName of Object.keys(changes)) {
let change = changes[preferenceName];
if (change.newValue === undefined) {
const overridden = this.overriddenPreferenceName(change.preferenceName);
if (overridden) {
change = {
...change, newValue: this.doGet(overridden.preferenceName)
};
}
}
if (this.schema.isValidInScope(preferenceName, preference_scope_1.PreferenceScope.Folder)) {
acceptChange(change);
continue;
}
for (const scope of preference_scope_1.PreferenceScope.getReversedScopes()) {
if (this.schema.isValidInScope(preferenceName, scope)) {
const provider = this.getProvider(scope);
if (provider) {
const value = provider.get(preferenceName);
if (scope > change.scope && value !== undefined) {
// preference defined in a more specific scope
break;
}
else if (scope === change.scope && change.newValue !== undefined) {
// preference is changed into something other than `undefined`
acceptChange(change);
}
else if (scope < change.scope && change.newValue === undefined && value !== undefined) {
// preference is changed to `undefined`, use the value from a more general scope
change = {
...change,
newValue: value,
scope
};
acceptChange(change);
}
}
}
else if (change.newValue === undefined && change.scope === preference_scope_1.PreferenceScope.Default) {
// preference is removed
acceptChange(change);
break;
}
}
}
// emit the changes
const changedPreferenceNames = Object.keys(changesToEmit);
if (changedPreferenceNames.length > 0) {
this.onPreferencesChangedEmitter.fire(changesToEmit);
}
changedPreferenceNames.forEach(preferenceName => this.onPreferenceChangedEmitter.fire(changesToEmit[preferenceName]));
}
getAffectedPreferenceNames(change, accept) {
accept(change.preferenceName);
for (const overridePreferenceName of this.schema.getOverridePreferenceNames(change.preferenceName)) {
if (!this.doHas(overridePreferenceName)) {
accept(overridePreferenceName);
}
}
}
getProvider(scope) {
return this.preferenceProviders.get(scope);
}
has(preferenceName, resourceUri) {
return this.get(preferenceName, undefined, resourceUri) !== undefined;
}
get(preferenceName, defaultValue, resourceUri) {
return this.resolve(preferenceName, defaultValue, resourceUri).value;
}
resolve(preferenceName, defaultValue, resourceUri) {
const { value, configUri } = this.doResolve(preferenceName, defaultValue, resourceUri);
if (value === undefined) {
const overridden = this.overriddenPreferenceName(preferenceName);
if (overridden) {
return this.doResolve(overridden.preferenceName, defaultValue, resourceUri);
}
}
return { value, configUri };
}
async set(preferenceName, value, scope, resourceUri) {
const resolvedScope = scope !== null && scope !== void 0 ? scope : (!resourceUri ? preference_scope_1.PreferenceScope.Workspace : preference_scope_1.PreferenceScope.Folder);
if (resolvedScope === preference_scope_1.PreferenceScope.Folder && !resourceUri) {
throw new Error('Unable to write to Folder Settings because no resource is provided.');
}
const provider = this.getProvider(resolvedScope);
if (provider && await provider.setPreference(preferenceName, value, resourceUri)) {
return;
}
throw new Error(`Unable to write to ${preference_scope_1.PreferenceScope[resolvedScope]} Settings.`);
}
getBoolean(preferenceName, defaultValue, resourceUri) {
const value = resourceUri ? this.get(preferenceName, defaultValue, resourceUri) : this.get(preferenceName, defaultValue);
// eslint-disable-next-line no-null/no-null
return value !== null && value !== undefined ? !!value : defaultValue;
}
getString(preferenceName, defaultValue, resourceUri) {
const value = resourceUri ? this.get(preferenceName, defaultValue, resourceUri) : this.get(preferenceName, defaultValue);
// eslint-disable-next-line no-null/no-null
if (value === null || value === undefined) {
return defaultValue;
}
return value.toString();
}
getNumber(preferenceName, defaultValue, resourceUri) {
const value = resourceUri ? this.get(preferenceName, defaultValue, resourceUri) : this.get(preferenceName, defaultValue);
// eslint-disable-next-line no-null/no-null
if (value === null || value === undefined) {
return defaultValue;
}
if (typeof value === 'number') {
return value;
}
return Number(value);
}
inspect(preferenceName, resourceUri, forceLanguageOverride) {
var _a, _b;
const defaultValue = this.inspectInScope(preferenceName, preference_scope_1.PreferenceScope.Default, resourceUri, forceLanguageOverride);
const globalValue = this.inspectInScope(preferenceName, preference_scope_1.PreferenceScope.User, resourceUri, forceLanguageOverride);
const workspaceValue = this.inspectInScope(preferenceName, preference_scope_1.PreferenceScope.Workspace, resourceUri, forceLanguageOverride);
const workspaceFolderValue = this.inspectInScope(preferenceName, preference_scope_1.PreferenceScope.Folder, resourceUri, forceLanguageOverride);
const valueApplied = (_b = (_a = workspaceFolderValue !== null && workspaceFolderValue !== void 0 ? workspaceFolderValue : workspaceValue) !== null && _a !== void 0 ? _a : globalValue) !== null && _b !== void 0 ? _b : defaultValue;
return { preferenceName, defaultValue, globalValue, workspaceValue, workspaceFolderValue, value: valueApplied };
}
inspectInScope(preferenceName, scope, resourceUri, forceLanguageOverride) {
const value = this.doInspectInScope(preferenceName, scope, resourceUri);
if (value === undefined && !forceLanguageOverride) {
const overridden = this.overriddenPreferenceName(preferenceName);
if (overridden) {
return this.doInspectInScope(overridden.preferenceName, scope, resourceUri);
}
}
return value;
}
getScopedValueFromInspection(inspection, scope) {
switch (scope) {
case preference_scope_1.PreferenceScope.Default:
return inspection.defaultValue;
case preference_scope_1.PreferenceScope.User:
return inspection.globalValue;
case preference_scope_1.PreferenceScope.Workspace:
return inspection.workspaceValue;
case preference_scope_1.PreferenceScope.Folder:
return inspection.workspaceFolderValue;
}
(0, common_1.unreachable)(scope, 'Not all PreferenceScope enum variants handled.');
}
async updateValue(preferenceName, value, resourceUri) {
const inspection = this.inspect(preferenceName, resourceUri);
if (inspection) {
const scopesToChange = this.getScopesToChange(inspection, value);
const isDeletion = value === undefined
|| (scopesToChange.length === 1 && scopesToChange[0] === preference_scope_1.PreferenceScope.User && json_1.JSONExt.deepEqual(value, inspection.defaultValue));
const effectiveValue = isDeletion ? undefined : value;
await Promise.all(scopesToChange.map(scope => this.set(preferenceName, effectiveValue, scope, resourceUri)));
}
}
getScopesToChange(inspection, intendedValue) {
var _a;
if (json_1.JSONExt.deepEqual(inspection.value, intendedValue)) {
return [];
}
// Scopes in ascending order of scope breadth.
const allScopes = preference_scope_1.PreferenceScope.getReversedScopes();
// Get rid of Default scope. We can't set anything there.
allScopes.pop();
const isScopeDefined = (scope) => this.getScopedValueFromInspection(inspection, scope) !== undefined;
if (intendedValue === undefined) {
return allScopes.filter(isScopeDefined);
}
return [(_a = allScopes.find(isScopeDefined)) !== null && _a !== void 0 ? _a : preference_scope_1.PreferenceScope.User];
}
overridePreferenceName(options) {
return this.preferenceOverrideService.overridePreferenceName(options);
}
overriddenPreferenceName(preferenceName) {
return this.preferenceOverrideService.overriddenPreferenceName(preferenceName);
}
doHas(preferenceName, resourceUri) {
return this.doGet(preferenceName, undefined, resourceUri) !== undefined;
}
doInspectInScope(preferenceName, scope, resourceUri) {
const provider = this.getProvider(scope);
return provider && provider.get(preferenceName, resourceUri);
}
doGet(preferenceName, defaultValue, resourceUri) {
return this.doResolve(preferenceName, defaultValue, resourceUri).value;
}
doResolve(preferenceName, defaultValue, resourceUri) {
const result = {};
for (const scope of preference_scope_1.PreferenceScope.getScopes()) {
if (this.schema.isValidInScope(preferenceName, scope)) {
const provider = this.getProvider(scope);
if (provider === null || provider === void 0 ? void 0 : provider.canHandleScope(scope)) {
const { configUri, value } = provider.resolve(preferenceName, resourceUri);
if (value !== undefined) {
result.configUri = configUri;
result.value = preference_provider_1.PreferenceProvider.merge(result.value, value);
}
}
}
}
return {
configUri: result.configUri,
value: result.value !== undefined ? (0, common_1.deepFreeze)(result.value) : defaultValue
};
}
getConfigUri(scope, resourceUri, sectionName = this.configurations.getConfigName()) {
const provider = this.getProvider(scope);
if (!provider || !this.configurations.isAnyConfig(sectionName)) {
return undefined;
}
const configUri = provider.getConfigUri(resourceUri, sectionName);
if (configUri) {
return configUri;
}
return provider.getContainingConfigUri && provider.getContainingConfigUri(resourceUri, sectionName);
}
};
__decorate([
(0, inversify_1.inject)(preference_contribution_1.PreferenceSchemaProvider),
__metadata("design:type", preference_contribution_1.PreferenceSchemaProvider)
], PreferenceServiceImpl.prototype, "schema", void 0);
__decorate([
(0, inversify_1.inject)(exports.PreferenceProviderProvider),
__metadata("design:type", Function)
], PreferenceServiceImpl.prototype, "providerProvider", void 0);
__decorate([
(0, inversify_1.inject)(preference_configurations_1.PreferenceConfigurations),
__metadata("design:type", preference_configurations_1.PreferenceConfigurations)
], PreferenceServiceImpl.prototype, "configurations", void 0);
__decorate([
(0, inversify_1.inject)(preference_language_override_service_1.PreferenceLanguageOverrideService),
__metadata("design:type", preference_language_override_service_1.PreferenceLanguageOverrideService)
], PreferenceServiceImpl.prototype, "preferenceOverrideService", void 0);
__decorate([
(0, inversify_1.postConstruct)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], PreferenceServiceImpl.prototype, "init", null);
PreferenceServiceImpl = __decorate([
(0, inversify_1.injectable)()
], PreferenceServiceImpl);
exports.PreferenceServiceImpl = PreferenceServiceImpl;
//# sourceMappingURL=preference-service.js.map