UNPKG

18.3 kBJavaScriptView Raw
1"use strict";
2// *****************************************************************************
3// Copyright (C) 2018 Ericsson and others.
4//
5// This program and the accompanying materials are made available under the
6// terms of the Eclipse Public License v. 2.0 which is available at
7// http://www.eclipse.org/legal/epl-2.0.
8//
9// This Source Code may also be made available under the following Secondary
10// Licenses when the conditions for such availability set forth in the Eclipse
11// Public License v. 2.0 are satisfied: GNU General Public License, version 2
12// with the GNU Classpath Exception which is available at
13// https://www.gnu.org/software/classpath/license.html.
14//
15// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16// *****************************************************************************
17var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
18 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
19 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
20 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;
21 return c > 3 && r && Object.defineProperty(target, key, r), r;
22};
23var __metadata = (this && this.__metadata) || function (k, v) {
24 if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
25};
26Object.defineProperty(exports, "__esModule", { value: true });
27exports.PreferenceServiceImpl = exports.PreferenceProviderProvider = exports.PreferenceService = exports.PreferenceChangeImpl = exports.PreferenceScope = void 0;
28/* eslint-disable @typescript-eslint/no-explicit-any */
29const inversify_1 = require("inversify");
30const common_1 = require("../../common");
31const promise_util_1 = require("../../common/promise-util");
32const preference_provider_1 = require("./preference-provider");
33const preference_contribution_1 = require("./preference-contribution");
34const uri_1 = require("../../common/uri");
35const preference_scope_1 = require("./preference-scope");
36Object.defineProperty(exports, "PreferenceScope", { enumerable: true, get: function () { return preference_scope_1.PreferenceScope; } });
37const preference_configurations_1 = require("./preference-configurations");
38const json_1 = require("@phosphor/coreutils/lib/json");
39const preference_language_override_service_1 = require("./preference-language-override-service");
40class PreferenceChangeImpl {
41 constructor(change) {
42 this.change = (0, common_1.deepFreeze)(change);
43 }
44 get preferenceName() {
45 return this.change.preferenceName;
46 }
47 get newValue() {
48 return this.change.newValue;
49 }
50 get oldValue() {
51 return this.change.oldValue;
52 }
53 get scope() {
54 return this.change.scope;
55 }
56 get domain() {
57 return this.change.domain;
58 }
59 // TODO add tests
60 affects(resourceUri) {
61 const resourcePath = resourceUri && new uri_1.default(resourceUri).path;
62 const domain = this.change.domain;
63 return !resourcePath || !domain || domain.some(uri => new uri_1.default(uri).path.relativity(resourcePath) >= 0);
64 }
65}
66exports.PreferenceChangeImpl = PreferenceChangeImpl;
67exports.PreferenceService = Symbol('PreferenceService');
68/**
69 * We cannot load providers directly in the case if they depend on `PreferenceService` somehow.
70 * It allows to load them lazily after DI is configured.
71 */
72exports.PreferenceProviderProvider = Symbol('PreferenceProviderProvider');
73let PreferenceServiceImpl = class PreferenceServiceImpl {
74 constructor() {
75 this.onPreferenceChangedEmitter = new common_1.Emitter();
76 this.onPreferenceChanged = this.onPreferenceChangedEmitter.event;
77 this.onPreferencesChangedEmitter = new common_1.Emitter();
78 this.onPreferencesChanged = this.onPreferencesChangedEmitter.event;
79 this.toDispose = new common_1.DisposableCollection(this.onPreferenceChangedEmitter, this.onPreferencesChangedEmitter);
80 this.preferenceProviders = new Map();
81 this._ready = new promise_util_1.Deferred();
82 this._isReady = false;
83 }
84 async initializeProviders() {
85 try {
86 for (const scope of preference_scope_1.PreferenceScope.getScopes()) {
87 const provider = this.providerProvider(scope);
88 this.preferenceProviders.set(scope, provider);
89 this.toDispose.push(provider.onDidPreferencesChanged(changes => this.reconcilePreferences(changes)));
90 await provider.ready;
91 }
92 this._ready.resolve();
93 this._isReady = true;
94 }
95 catch (e) {
96 this._ready.reject(e);
97 }
98 }
99 init() {
100 this.toDispose.push(common_1.Disposable.create(() => this._ready.reject(new Error('preference service is disposed'))));
101 this.initializeProviders();
102 }
103 dispose() {
104 this.toDispose.dispose();
105 }
106 get ready() {
107 return this._ready.promise;
108 }
109 get isReady() {
110 return this._isReady;
111 }
112 reconcilePreferences(changes) {
113 const changesToEmit = {};
114 const acceptChange = (change) => this.getAffectedPreferenceNames(change, preferenceName => changesToEmit[preferenceName] = new PreferenceChangeImpl({ ...change, preferenceName }));
115 for (const preferenceName of Object.keys(changes)) {
116 let change = changes[preferenceName];
117 if (change.newValue === undefined) {
118 const overridden = this.overriddenPreferenceName(change.preferenceName);
119 if (overridden) {
120 change = {
121 ...change, newValue: this.doGet(overridden.preferenceName)
122 };
123 }
124 }
125 if (this.schema.isValidInScope(preferenceName, preference_scope_1.PreferenceScope.Folder)) {
126 acceptChange(change);
127 continue;
128 }
129 for (const scope of preference_scope_1.PreferenceScope.getReversedScopes()) {
130 if (this.schema.isValidInScope(preferenceName, scope)) {
131 const provider = this.getProvider(scope);
132 if (provider) {
133 const value = provider.get(preferenceName);
134 if (scope > change.scope && value !== undefined) {
135 // preference defined in a more specific scope
136 break;
137 }
138 else if (scope === change.scope && change.newValue !== undefined) {
139 // preference is changed into something other than `undefined`
140 acceptChange(change);
141 }
142 else if (scope < change.scope && change.newValue === undefined && value !== undefined) {
143 // preference is changed to `undefined`, use the value from a more general scope
144 change = {
145 ...change,
146 newValue: value,
147 scope
148 };
149 acceptChange(change);
150 }
151 }
152 }
153 else if (change.newValue === undefined && change.scope === preference_scope_1.PreferenceScope.Default) {
154 // preference is removed
155 acceptChange(change);
156 break;
157 }
158 }
159 }
160 // emit the changes
161 const changedPreferenceNames = Object.keys(changesToEmit);
162 if (changedPreferenceNames.length > 0) {
163 this.onPreferencesChangedEmitter.fire(changesToEmit);
164 }
165 changedPreferenceNames.forEach(preferenceName => this.onPreferenceChangedEmitter.fire(changesToEmit[preferenceName]));
166 }
167 getAffectedPreferenceNames(change, accept) {
168 accept(change.preferenceName);
169 for (const overridePreferenceName of this.schema.getOverridePreferenceNames(change.preferenceName)) {
170 if (!this.doHas(overridePreferenceName)) {
171 accept(overridePreferenceName);
172 }
173 }
174 }
175 getProvider(scope) {
176 return this.preferenceProviders.get(scope);
177 }
178 has(preferenceName, resourceUri) {
179 return this.get(preferenceName, undefined, resourceUri) !== undefined;
180 }
181 get(preferenceName, defaultValue, resourceUri) {
182 return this.resolve(preferenceName, defaultValue, resourceUri).value;
183 }
184 resolve(preferenceName, defaultValue, resourceUri) {
185 const { value, configUri } = this.doResolve(preferenceName, defaultValue, resourceUri);
186 if (value === undefined) {
187 const overridden = this.overriddenPreferenceName(preferenceName);
188 if (overridden) {
189 return this.doResolve(overridden.preferenceName, defaultValue, resourceUri);
190 }
191 }
192 return { value, configUri };
193 }
194 async set(preferenceName, value, scope, resourceUri) {
195 const resolvedScope = scope !== null && scope !== void 0 ? scope : (!resourceUri ? preference_scope_1.PreferenceScope.Workspace : preference_scope_1.PreferenceScope.Folder);
196 if (resolvedScope === preference_scope_1.PreferenceScope.Folder && !resourceUri) {
197 throw new Error('Unable to write to Folder Settings because no resource is provided.');
198 }
199 const provider = this.getProvider(resolvedScope);
200 if (provider && await provider.setPreference(preferenceName, value, resourceUri)) {
201 return;
202 }
203 throw new Error(`Unable to write to ${preference_scope_1.PreferenceScope[resolvedScope]} Settings.`);
204 }
205 getBoolean(preferenceName, defaultValue, resourceUri) {
206 const value = resourceUri ? this.get(preferenceName, defaultValue, resourceUri) : this.get(preferenceName, defaultValue);
207 // eslint-disable-next-line no-null/no-null
208 return value !== null && value !== undefined ? !!value : defaultValue;
209 }
210 getString(preferenceName, defaultValue, resourceUri) {
211 const value = resourceUri ? this.get(preferenceName, defaultValue, resourceUri) : this.get(preferenceName, defaultValue);
212 // eslint-disable-next-line no-null/no-null
213 if (value === null || value === undefined) {
214 return defaultValue;
215 }
216 return value.toString();
217 }
218 getNumber(preferenceName, defaultValue, resourceUri) {
219 const value = resourceUri ? this.get(preferenceName, defaultValue, resourceUri) : this.get(preferenceName, defaultValue);
220 // eslint-disable-next-line no-null/no-null
221 if (value === null || value === undefined) {
222 return defaultValue;
223 }
224 if (typeof value === 'number') {
225 return value;
226 }
227 return Number(value);
228 }
229 inspect(preferenceName, resourceUri, forceLanguageOverride) {
230 var _a, _b;
231 const defaultValue = this.inspectInScope(preferenceName, preference_scope_1.PreferenceScope.Default, resourceUri, forceLanguageOverride);
232 const globalValue = this.inspectInScope(preferenceName, preference_scope_1.PreferenceScope.User, resourceUri, forceLanguageOverride);
233 const workspaceValue = this.inspectInScope(preferenceName, preference_scope_1.PreferenceScope.Workspace, resourceUri, forceLanguageOverride);
234 const workspaceFolderValue = this.inspectInScope(preferenceName, preference_scope_1.PreferenceScope.Folder, resourceUri, forceLanguageOverride);
235 const valueApplied = (_b = (_a = workspaceFolderValue !== null && workspaceFolderValue !== void 0 ? workspaceFolderValue : workspaceValue) !== null && _a !== void 0 ? _a : globalValue) !== null && _b !== void 0 ? _b : defaultValue;
236 return { preferenceName, defaultValue, globalValue, workspaceValue, workspaceFolderValue, value: valueApplied };
237 }
238 inspectInScope(preferenceName, scope, resourceUri, forceLanguageOverride) {
239 const value = this.doInspectInScope(preferenceName, scope, resourceUri);
240 if (value === undefined && !forceLanguageOverride) {
241 const overridden = this.overriddenPreferenceName(preferenceName);
242 if (overridden) {
243 return this.doInspectInScope(overridden.preferenceName, scope, resourceUri);
244 }
245 }
246 return value;
247 }
248 getScopedValueFromInspection(inspection, scope) {
249 switch (scope) {
250 case preference_scope_1.PreferenceScope.Default:
251 return inspection.defaultValue;
252 case preference_scope_1.PreferenceScope.User:
253 return inspection.globalValue;
254 case preference_scope_1.PreferenceScope.Workspace:
255 return inspection.workspaceValue;
256 case preference_scope_1.PreferenceScope.Folder:
257 return inspection.workspaceFolderValue;
258 }
259 (0, common_1.unreachable)(scope, 'Not all PreferenceScope enum variants handled.');
260 }
261 async updateValue(preferenceName, value, resourceUri) {
262 const inspection = this.inspect(preferenceName, resourceUri);
263 if (inspection) {
264 const scopesToChange = this.getScopesToChange(inspection, value);
265 const isDeletion = value === undefined
266 || (scopesToChange.length === 1 && scopesToChange[0] === preference_scope_1.PreferenceScope.User && json_1.JSONExt.deepEqual(value, inspection.defaultValue));
267 const effectiveValue = isDeletion ? undefined : value;
268 await Promise.all(scopesToChange.map(scope => this.set(preferenceName, effectiveValue, scope, resourceUri)));
269 }
270 }
271 getScopesToChange(inspection, intendedValue) {
272 var _a;
273 if (json_1.JSONExt.deepEqual(inspection.value, intendedValue)) {
274 return [];
275 }
276 // Scopes in ascending order of scope breadth.
277 const allScopes = preference_scope_1.PreferenceScope.getReversedScopes();
278 // Get rid of Default scope. We can't set anything there.
279 allScopes.pop();
280 const isScopeDefined = (scope) => this.getScopedValueFromInspection(inspection, scope) !== undefined;
281 if (intendedValue === undefined) {
282 return allScopes.filter(isScopeDefined);
283 }
284 return [(_a = allScopes.find(isScopeDefined)) !== null && _a !== void 0 ? _a : preference_scope_1.PreferenceScope.User];
285 }
286 overridePreferenceName(options) {
287 return this.preferenceOverrideService.overridePreferenceName(options);
288 }
289 overriddenPreferenceName(preferenceName) {
290 return this.preferenceOverrideService.overriddenPreferenceName(preferenceName);
291 }
292 doHas(preferenceName, resourceUri) {
293 return this.doGet(preferenceName, undefined, resourceUri) !== undefined;
294 }
295 doInspectInScope(preferenceName, scope, resourceUri) {
296 const provider = this.getProvider(scope);
297 return provider && provider.get(preferenceName, resourceUri);
298 }
299 doGet(preferenceName, defaultValue, resourceUri) {
300 return this.doResolve(preferenceName, defaultValue, resourceUri).value;
301 }
302 doResolve(preferenceName, defaultValue, resourceUri) {
303 const result = {};
304 for (const scope of preference_scope_1.PreferenceScope.getScopes()) {
305 if (this.schema.isValidInScope(preferenceName, scope)) {
306 const provider = this.getProvider(scope);
307 if (provider === null || provider === void 0 ? void 0 : provider.canHandleScope(scope)) {
308 const { configUri, value } = provider.resolve(preferenceName, resourceUri);
309 if (value !== undefined) {
310 result.configUri = configUri;
311 result.value = preference_provider_1.PreferenceProvider.merge(result.value, value);
312 }
313 }
314 }
315 }
316 return {
317 configUri: result.configUri,
318 value: result.value !== undefined ? (0, common_1.deepFreeze)(result.value) : defaultValue
319 };
320 }
321 getConfigUri(scope, resourceUri, sectionName = this.configurations.getConfigName()) {
322 const provider = this.getProvider(scope);
323 if (!provider || !this.configurations.isAnyConfig(sectionName)) {
324 return undefined;
325 }
326 const configUri = provider.getConfigUri(resourceUri, sectionName);
327 if (configUri) {
328 return configUri;
329 }
330 return provider.getContainingConfigUri && provider.getContainingConfigUri(resourceUri, sectionName);
331 }
332};
333__decorate([
334 (0, inversify_1.inject)(preference_contribution_1.PreferenceSchemaProvider),
335 __metadata("design:type", preference_contribution_1.PreferenceSchemaProvider)
336], PreferenceServiceImpl.prototype, "schema", void 0);
337__decorate([
338 (0, inversify_1.inject)(exports.PreferenceProviderProvider),
339 __metadata("design:type", Function)
340], PreferenceServiceImpl.prototype, "providerProvider", void 0);
341__decorate([
342 (0, inversify_1.inject)(preference_configurations_1.PreferenceConfigurations),
343 __metadata("design:type", preference_configurations_1.PreferenceConfigurations)
344], PreferenceServiceImpl.prototype, "configurations", void 0);
345__decorate([
346 (0, inversify_1.inject)(preference_language_override_service_1.PreferenceLanguageOverrideService),
347 __metadata("design:type", preference_language_override_service_1.PreferenceLanguageOverrideService)
348], PreferenceServiceImpl.prototype, "preferenceOverrideService", void 0);
349__decorate([
350 (0, inversify_1.postConstruct)(),
351 __metadata("design:type", Function),
352 __metadata("design:paramtypes", []),
353 __metadata("design:returntype", void 0)
354], PreferenceServiceImpl.prototype, "init", null);
355PreferenceServiceImpl = __decorate([
356 (0, inversify_1.injectable)()
357], PreferenceServiceImpl);
358exports.PreferenceServiceImpl = PreferenceServiceImpl;
359//# sourceMappingURL=preference-service.js.map
\No newline at end of file