@codingame/monaco-vscode-extension-gallery-service-override 3.2.2 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/extensionGallery.js +7 -1
- package/override/vs/platform/dialogs/common/dialogs.js +2 -0
- package/package.json +9 -9
- package/vscode/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.js +18 -16
- package/vscode/src/vs/platform/extensionManagement/common/extensionGalleryService.js +24 -23
- package/vscode/src/vs/platform/extensionManagement/common/extensionManagementIpc.js +5 -2
- package/vscode/src/vs/platform/extensionManagement/common/extensionTipsService.js +10 -0
- package/vscode/src/vs/workbench/contrib/extensions/browser/abstractRuntimeExtensionsEditor.js +33 -19
- package/vscode/src/vs/workbench/contrib/extensions/browser/configBasedRecommendations.js +1 -1
- package/vscode/src/vs/workbench/contrib/extensions/browser/deprecatedExtensionsChecker.js +8 -5
- package/vscode/src/vs/workbench/contrib/extensions/browser/exeBasedRecommendations.js +1 -1
- package/vscode/src/vs/workbench/contrib/extensions/browser/extensionEditor.js +109 -40
- package/vscode/src/vs/workbench/contrib/extensions/browser/extensionFeaturesTab.js +11 -8
- package/vscode/src/vs/workbench/contrib/extensions/browser/extensionRecommendationNotificationService.js +31 -11
- package/vscode/src/vs/workbench/contrib/extensions/browser/extensionRecommendationsService.js +35 -21
- package/vscode/src/vs/workbench/contrib/extensions/browser/extensions.contribution.js +54 -29
- package/vscode/src/vs/workbench/contrib/extensions/browser/extensionsList.js +6 -6
- package/vscode/src/vs/workbench/contrib/extensions/browser/extensionsViewer.js +11 -1
- package/vscode/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.js +18 -17
- package/vscode/src/vs/workbench/contrib/extensions/browser/extensionsViews.js +71 -31
- package/vscode/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.js +63 -20
- package/vscode/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.js +551 -134
- package/vscode/src/vs/workbench/contrib/extensions/browser/fileBasedRecommendations.js +3 -3
- package/vscode/src/vs/workbench/contrib/extensions/browser/keymapRecommendations.js +1 -1
- package/vscode/src/vs/workbench/contrib/extensions/browser/languageRecommendations.js +1 -1
- package/vscode/src/vs/workbench/contrib/extensions/browser/media/extension.css.js +1 -1
- package/vscode/src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css.js +1 -1
- package/vscode/src/vs/workbench/contrib/extensions/browser/remoteRecommendations.js +1 -1
- package/vscode/src/vs/workbench/contrib/extensions/browser/webRecommendations.js +1 -1
- package/vscode/src/vs/workbench/contrib/extensions/browser/workspaceRecommendations.js +78 -4
- package/vscode/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.js +7 -1
- package/vscode/src/vs/workbench/services/extensionManagement/browser/extensionsProfileScannerService.js +24 -0
- package/vscode/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.js +15 -8
- package/vscode/src/vs/workbench/services/extensionManagement/common/extensionManagementChannelClient.js +2 -2
- package/vscode/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.js +3 -2
- package/vscode/src/vs/workbench/services/extensionManagement/common/extensionManagementService.js +469 -57
- package/vscode/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.js +5 -2
- package/vscode/src/vs/workbench/services/extensionRecommendations/common/extensionIgnoredRecommendationsService.js +1 -0
- package/vscode/src/vs/workbench/services/extensions/browser/extensionsScannerService.js +33 -0
package/vscode/src/vs/workbench/services/extensionManagement/common/extensionManagementService.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
|
|
2
|
-
import { Event, EventMultiplexer } from 'vscode/vscode/vs/base/common/event';
|
|
2
|
+
import { Emitter, Event, EventMultiplexer } from 'vscode/vscode/vs/base/common/event';
|
|
3
3
|
import { ExtensionManagementErrorCode, EXTENSION_INSTALL_SYNC_CONTEXT, ExtensionManagementError, IExtensionGalleryService } from 'vscode/vscode/vs/platform/extensionManagement/common/extensionManagement';
|
|
4
|
-
import { IExtensionManagementServerService } from 'vscode/vscode/vs/workbench/services/extensionManagement/common/extensionManagement';
|
|
4
|
+
import { extensionsConfigurationNodeBase, IExtensionManagementServerService } from 'vscode/vscode/vs/workbench/services/extensionManagement/common/extensionManagement';
|
|
5
5
|
import { isLanguagePackExtension, getWorkspaceSupportTypeMessage } from 'vscode/vscode/vs/platform/extensions/common/extensions';
|
|
6
|
-
import {
|
|
6
|
+
import { URI } from 'vscode/vscode/vs/base/common/uri';
|
|
7
|
+
import { Disposable, DisposableStore } from 'vscode/vscode/vs/base/common/lifecycle';
|
|
7
8
|
import { IConfigurationService } from 'vscode/vscode/vs/platform/configuration/common/configuration';
|
|
8
9
|
import { CancellationToken } from 'vscode/vscode/vs/base/common/cancellation';
|
|
9
10
|
import { areSameExtensions, computeTargetPlatform } from 'vscode/vscode/vs/platform/extensionManagement/common/extensionManagementUtil';
|
|
@@ -11,24 +12,32 @@ import { localizeWithPath } from 'vscode/vscode/vs/nls';
|
|
|
11
12
|
import { IProductService } from 'vscode/vscode/vs/platform/product/common/productService';
|
|
12
13
|
import { Schemas } from 'vscode/vscode/vs/base/common/network';
|
|
13
14
|
import { IDownloadService } from 'vscode/vscode/vs/platform/download/common/download';
|
|
14
|
-
import {
|
|
15
|
+
import { coalesce } from 'vscode/vscode/vs/base/common/arrays';
|
|
15
16
|
import '../../../../../../../override/vs/platform/dialogs/common/dialogs.js';
|
|
16
|
-
import Severity from 'vscode/vscode/vs/base/common/severity';
|
|
17
|
+
import Severity$1 from 'vscode/vscode/vs/base/common/severity';
|
|
17
18
|
import { IUserDataSyncEnablementService } from 'vscode/vscode/vs/platform/userDataSync/common/userDataSync';
|
|
18
19
|
import { Promises } from 'vscode/vscode/vs/base/common/async';
|
|
19
20
|
import { IWorkspaceTrustRequestService } from 'vscode/vscode/vs/platform/workspace/common/workspaceTrust';
|
|
20
21
|
import { IExtensionManifestPropertiesService } from 'vscode/vscode/vs/workbench/services/extensions/common/extensionManifestPropertiesService';
|
|
21
22
|
import { IInstantiationService } from 'vscode/vscode/vs/platform/instantiation/common/instantiation';
|
|
22
23
|
import { ICommandService } from 'vscode/vscode/vs/platform/commands/common/commands';
|
|
23
|
-
import { isUndefined } from 'vscode/vscode/vs/base/common/types';
|
|
24
|
+
import { isString, isUndefined } from 'vscode/vscode/vs/base/common/types';
|
|
24
25
|
import { IFileService } from 'vscode/vscode/vs/platform/files/common/files';
|
|
25
26
|
import { ILogService } from 'vscode/vscode/vs/platform/log/common/log';
|
|
26
|
-
import { CancellationError } from 'vscode/vscode/vs/base/common/errors';
|
|
27
|
+
import { getErrorMessage, CancellationError } from 'vscode/vscode/vs/base/common/errors';
|
|
27
28
|
import { IUserDataProfileService } from 'vscode/vscode/vs/workbench/services/userDataProfile/common/userDataProfile';
|
|
29
|
+
import { IWorkspaceContextService } from 'vscode/vscode/vs/platform/workspace/common/workspace';
|
|
30
|
+
import { IExtensionsScannerService } from 'vscode/vscode/vs/platform/extensionManagement/common/extensionsScannerService';
|
|
31
|
+
import { IStorageService } from 'vscode/vscode/vs/platform/storage/common/storage';
|
|
32
|
+
import { IUriIdentityService } from 'vscode/vscode/vs/platform/uriIdentity/common/uriIdentity';
|
|
33
|
+
import { ITelemetryService } from 'vscode/vscode/vs/platform/telemetry/common/telemetry';
|
|
34
|
+
import { Registry } from 'vscode/vscode/vs/platform/registry/common/platform';
|
|
35
|
+
import { Extensions } from 'vscode/vscode/vs/platform/configuration/common/configurationRegistry';
|
|
28
36
|
import { IDialogService } from 'vscode/vscode/vs/platform/dialogs/common/dialogs';
|
|
29
37
|
|
|
38
|
+
var WorkspaceExtensionsManagementService_1;
|
|
30
39
|
let ExtensionManagementService = class ExtensionManagementService extends Disposable {
|
|
31
|
-
constructor(extensionManagementServerService, extensionGalleryService, userDataProfileService, configurationService, productService, downloadService, userDataSyncEnablementService, dialogService, workspaceTrustRequestService, extensionManifestPropertiesService, fileService, logService, instantiationService) {
|
|
40
|
+
constructor(extensionManagementServerService, extensionGalleryService, userDataProfileService, configurationService, productService, downloadService, userDataSyncEnablementService, dialogService, workspaceTrustRequestService, extensionManifestPropertiesService, fileService, logService, instantiationService, extensionsScannerService, telemetryService) {
|
|
32
41
|
super();
|
|
33
42
|
this.extensionManagementServerService = extensionManagementServerService;
|
|
34
43
|
this.extensionGalleryService = extensionGalleryService;
|
|
@@ -43,7 +52,38 @@ let ExtensionManagementService = class ExtensionManagementService extends Dispos
|
|
|
43
52
|
this.fileService = fileService;
|
|
44
53
|
this.logService = logService;
|
|
45
54
|
this.instantiationService = instantiationService;
|
|
55
|
+
this.extensionsScannerService = extensionsScannerService;
|
|
56
|
+
this.telemetryService = telemetryService;
|
|
57
|
+
this._onInstallExtension = this._register(( new Emitter()));
|
|
58
|
+
this._onDidInstallExtensions = this._register(( new Emitter()));
|
|
59
|
+
this._onUninstallExtension = this._register(( new Emitter()));
|
|
60
|
+
this._onDidUninstallExtension = this._register(( new Emitter()));
|
|
46
61
|
this.servers = [];
|
|
62
|
+
if (productService.quality !== 'stable') {
|
|
63
|
+
( Registry.as(Extensions.Configuration))
|
|
64
|
+
.registerConfiguration({
|
|
65
|
+
...extensionsConfigurationNodeBase,
|
|
66
|
+
properties: {
|
|
67
|
+
'extensions.experimental.supportWorkspaceExtensions': {
|
|
68
|
+
type: 'boolean',
|
|
69
|
+
description: ( localizeWithPath(
|
|
70
|
+
'vs/workbench/services/extensionManagement/common/extensionManagementService',
|
|
71
|
+
'extensions.experimental.supportWorkspaceExtensions',
|
|
72
|
+
"Enables support for workspace specific local extensions."
|
|
73
|
+
)),
|
|
74
|
+
default: false,
|
|
75
|
+
scope: 1
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
if (this.productService.quality !== 'stable' && this.configurationService.getValue('extensions.experimental.supportWorkspaceExtensions') === true) {
|
|
81
|
+
this.workspaceExtensionManagementService = this._register(this.instantiationService.createInstance(WorkspaceExtensionsManagementService));
|
|
82
|
+
this.onDidEnableExtensions = this.workspaceExtensionManagementService.onDidChangeInvalidExtensions;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
this.onDidEnableExtensions = Event.None;
|
|
86
|
+
}
|
|
47
87
|
if (this.extensionManagementServerService.localExtensionManagementServer) {
|
|
48
88
|
this.servers.push(this.extensionManagementServerService.localExtensionManagementServer);
|
|
49
89
|
}
|
|
@@ -53,32 +93,62 @@ let ExtensionManagementService = class ExtensionManagementService extends Dispos
|
|
|
53
93
|
if (this.extensionManagementServerService.webExtensionManagementServer) {
|
|
54
94
|
this.servers.push(this.extensionManagementServerService.webExtensionManagementServer);
|
|
55
95
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
this.
|
|
61
|
-
this.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
this.onDidUpdateExtensionMetadata =
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
(
|
|
78
|
-
|
|
79
|
-
|
|
96
|
+
const onInstallExtensionEventMultiplexer = this._register(( new EventMultiplexer()));
|
|
97
|
+
this._register(onInstallExtensionEventMultiplexer.add(this._onInstallExtension.event));
|
|
98
|
+
this.onInstallExtension = onInstallExtensionEventMultiplexer.event;
|
|
99
|
+
const onDidInstallExtensionsEventMultiplexer = this._register(( new EventMultiplexer()));
|
|
100
|
+
this._register(onDidInstallExtensionsEventMultiplexer.add(this._onDidInstallExtensions.event));
|
|
101
|
+
this.onDidInstallExtensions = onDidInstallExtensionsEventMultiplexer.event;
|
|
102
|
+
const onUninstallExtensionEventMultiplexer = this._register(( new EventMultiplexer()));
|
|
103
|
+
this._register(onUninstallExtensionEventMultiplexer.add(this._onUninstallExtension.event));
|
|
104
|
+
this.onUninstallExtension = onUninstallExtensionEventMultiplexer.event;
|
|
105
|
+
const onDidUninstallExtensionEventMultiplexer = this._register(( new EventMultiplexer()));
|
|
106
|
+
this._register(onDidUninstallExtensionEventMultiplexer.add(this._onDidUninstallExtension.event));
|
|
107
|
+
this.onDidUninstallExtension = onDidUninstallExtensionEventMultiplexer.event;
|
|
108
|
+
const onDidUpdateExtensionMetadaEventMultiplexer = this._register(( new EventMultiplexer()));
|
|
109
|
+
this.onDidUpdateExtensionMetadata = onDidUpdateExtensionMetadaEventMultiplexer.event;
|
|
110
|
+
const onDidChangeProfileEventMultiplexer = this._register(( new EventMultiplexer()));
|
|
111
|
+
this.onDidChangeProfile = onDidChangeProfileEventMultiplexer.event;
|
|
112
|
+
for (const server of this.servers) {
|
|
113
|
+
this._register(onInstallExtensionEventMultiplexer.add(( Event.map(
|
|
114
|
+
server.extensionManagementService.onInstallExtension,
|
|
115
|
+
e => ({ ...e, server })
|
|
116
|
+
))));
|
|
117
|
+
this._register(onDidInstallExtensionsEventMultiplexer.add(server.extensionManagementService.onDidInstallExtensions));
|
|
118
|
+
this._register(onUninstallExtensionEventMultiplexer.add(( Event.map(
|
|
119
|
+
server.extensionManagementService.onUninstallExtension,
|
|
120
|
+
e => ({ ...e, server })
|
|
121
|
+
))));
|
|
122
|
+
this._register(onDidUninstallExtensionEventMultiplexer.add(( Event.map(
|
|
123
|
+
server.extensionManagementService.onDidUninstallExtension,
|
|
124
|
+
e => ({ ...e, server })
|
|
125
|
+
))));
|
|
126
|
+
this._register(onDidUpdateExtensionMetadaEventMultiplexer.add(server.extensionManagementService.onDidUpdateExtensionMetadata));
|
|
127
|
+
this._register(onDidChangeProfileEventMultiplexer.add(( Event.map(
|
|
128
|
+
server.extensionManagementService.onDidChangeProfile,
|
|
129
|
+
e => ({ ...e, server })
|
|
130
|
+
))));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
isWorkspaceExtensionsSupported() {
|
|
134
|
+
return !!this.workspaceExtensionManagementService;
|
|
135
|
+
}
|
|
136
|
+
async getInstalled(type, profileLocation, productVersion) {
|
|
137
|
+
const result = [];
|
|
138
|
+
await Promise.all(( this.servers.map(async (server) => {
|
|
139
|
+
const installed = await server.extensionManagementService.getInstalled(type, profileLocation, productVersion);
|
|
140
|
+
if (server === this.getWorkspaceExtensionsServer()) {
|
|
141
|
+
const workspaceExtensions = await this.getInstalledWorkspaceExtensions(true);
|
|
142
|
+
installed.push(...workspaceExtensions);
|
|
143
|
+
}
|
|
144
|
+
result.push(...installed);
|
|
145
|
+
})));
|
|
146
|
+
return result;
|
|
80
147
|
}
|
|
81
148
|
async uninstall(extension, options) {
|
|
149
|
+
if (extension.isWorkspaceScoped) {
|
|
150
|
+
return this.uninstallExtensionFromWorkspace(extension);
|
|
151
|
+
}
|
|
82
152
|
const server = this.getServer(extension);
|
|
83
153
|
if (!server) {
|
|
84
154
|
return Promise.reject(`Invalid location ${( extension.location.toString())}`);
|
|
@@ -152,7 +222,7 @@ let ExtensionManagementService = class ExtensionManagementService extends Dispos
|
|
|
152
222
|
async reinstallFromGallery(extension) {
|
|
153
223
|
const server = this.getServer(extension);
|
|
154
224
|
if (server) {
|
|
155
|
-
await this.checkForWorkspaceTrust(extension.manifest);
|
|
225
|
+
await this.checkForWorkspaceTrust(extension.manifest, false);
|
|
156
226
|
return server.extensionManagementService.reinstallFromGallery(extension);
|
|
157
227
|
}
|
|
158
228
|
return Promise.reject(`Invalid location ${( extension.location.toString())}`);
|
|
@@ -191,7 +261,7 @@ let ExtensionManagementService = class ExtensionManagementService extends Dispos
|
|
|
191
261
|
async installVSIX(vsix, manifest, options) {
|
|
192
262
|
const serversToInstall = this.getServersToInstall(manifest);
|
|
193
263
|
if (serversToInstall?.length) {
|
|
194
|
-
await this.checkForWorkspaceTrust(manifest);
|
|
264
|
+
await this.checkForWorkspaceTrust(manifest, false);
|
|
195
265
|
const [local] = await Promises.settled(( serversToInstall.map(server => this.installVSIXInServer(vsix, server, options))));
|
|
196
266
|
return local;
|
|
197
267
|
}
|
|
@@ -331,6 +401,113 @@ let ExtensionManagementService = class ExtensionManagementService extends Dispos
|
|
|
331
401
|
server => server.extensionManagementService.installFromGallery(gallery, installOptions)
|
|
332
402
|
))).then(([local]) => local);
|
|
333
403
|
}
|
|
404
|
+
async getExtensions(locations) {
|
|
405
|
+
if (!this.workspaceExtensionManagementService) {
|
|
406
|
+
return [];
|
|
407
|
+
}
|
|
408
|
+
const scannedExtensions = await this.extensionsScannerService.scanMultipleExtensions(locations, 1 , { includeInvalid: true });
|
|
409
|
+
const result = [];
|
|
410
|
+
await Promise.all(( scannedExtensions.map(async (scannedExtension) => {
|
|
411
|
+
const workspaceExtension = await this.workspaceExtensionManagementService?.toLocalWorkspaceExtension(scannedExtension);
|
|
412
|
+
if (workspaceExtension) {
|
|
413
|
+
result.push({
|
|
414
|
+
identifier: workspaceExtension.identifier,
|
|
415
|
+
location: workspaceExtension.location,
|
|
416
|
+
manifest: workspaceExtension.manifest,
|
|
417
|
+
changelogUri: workspaceExtension.changelogUrl,
|
|
418
|
+
readmeUri: workspaceExtension.readmeUrl,
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
})));
|
|
422
|
+
return result;
|
|
423
|
+
}
|
|
424
|
+
async getInstalledWorkspaceExtensions(includeInvalid) {
|
|
425
|
+
return this.workspaceExtensionManagementService?.getInstalled(includeInvalid) ?? [];
|
|
426
|
+
}
|
|
427
|
+
async installResourceExtension(extension, installOptions) {
|
|
428
|
+
if (!installOptions.isWorkspaceScoped) {
|
|
429
|
+
return this.installFromLocation(extension.location);
|
|
430
|
+
}
|
|
431
|
+
if (!this.workspaceExtensionManagementService) {
|
|
432
|
+
throw new Error('Workspace Extensions are not supported');
|
|
433
|
+
}
|
|
434
|
+
this.logService.info(`Installing the extension ${extension.identifier.id} from ${( extension.location.toString())} in workspace`);
|
|
435
|
+
const server = this.getWorkspaceExtensionsServer();
|
|
436
|
+
this._onInstallExtension.fire({
|
|
437
|
+
identifier: extension.identifier,
|
|
438
|
+
source: extension.location,
|
|
439
|
+
server,
|
|
440
|
+
applicationScoped: false,
|
|
441
|
+
profileLocation: this.userDataProfileService.currentProfile.extensionsResource,
|
|
442
|
+
workspaceScoped: true
|
|
443
|
+
});
|
|
444
|
+
try {
|
|
445
|
+
await this.checkForWorkspaceTrust(extension.manifest, true);
|
|
446
|
+
const workspaceExtension = await this.workspaceExtensionManagementService.install(extension);
|
|
447
|
+
this.logService.info(`Successfully installed the extension ${workspaceExtension.identifier.id} from ${( extension.location.toString())} in the workspace`);
|
|
448
|
+
this._onDidInstallExtensions.fire([{
|
|
449
|
+
identifier: workspaceExtension.identifier,
|
|
450
|
+
source: extension.location,
|
|
451
|
+
operation: 2 ,
|
|
452
|
+
applicationScoped: false,
|
|
453
|
+
profileLocation: this.userDataProfileService.currentProfile.extensionsResource,
|
|
454
|
+
local: workspaceExtension,
|
|
455
|
+
workspaceScoped: true
|
|
456
|
+
}]);
|
|
457
|
+
return workspaceExtension;
|
|
458
|
+
}
|
|
459
|
+
catch (error) {
|
|
460
|
+
this.logService.error(`Failed to install the extension ${extension.identifier.id} from ${( extension.location.toString())} in the workspace`, getErrorMessage(error));
|
|
461
|
+
this._onDidInstallExtensions.fire([{
|
|
462
|
+
identifier: extension.identifier,
|
|
463
|
+
source: extension.location,
|
|
464
|
+
operation: 2 ,
|
|
465
|
+
applicationScoped: false,
|
|
466
|
+
profileLocation: this.userDataProfileService.currentProfile.extensionsResource,
|
|
467
|
+
error,
|
|
468
|
+
workspaceScoped: true
|
|
469
|
+
}]);
|
|
470
|
+
throw error;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
async uninstallExtensionFromWorkspace(extension) {
|
|
474
|
+
if (!extension.isWorkspaceScoped) {
|
|
475
|
+
throw new Error('The extension is not a workspace extension');
|
|
476
|
+
}
|
|
477
|
+
if (!this.workspaceExtensionManagementService) {
|
|
478
|
+
throw new Error('Workspace Extensions are not supported');
|
|
479
|
+
}
|
|
480
|
+
this.logService.info(`Uninstalling the workspace extension ${extension.identifier.id} from ${( extension.location.toString())}`);
|
|
481
|
+
const server = this.getWorkspaceExtensionsServer();
|
|
482
|
+
this._onUninstallExtension.fire({
|
|
483
|
+
identifier: extension.identifier,
|
|
484
|
+
server,
|
|
485
|
+
applicationScoped: false,
|
|
486
|
+
workspaceScoped: true
|
|
487
|
+
});
|
|
488
|
+
try {
|
|
489
|
+
await this.workspaceExtensionManagementService.uninstall(extension);
|
|
490
|
+
this.logService.info(`Successfully uninstalled the workspace extension ${extension.identifier.id} from ${( extension.location.toString())}`);
|
|
491
|
+
this.telemetryService.publicLog2('workspaceextension:uninstall');
|
|
492
|
+
this._onDidUninstallExtension.fire({
|
|
493
|
+
identifier: extension.identifier,
|
|
494
|
+
server,
|
|
495
|
+
applicationScoped: false,
|
|
496
|
+
workspaceScoped: true
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
catch (error) {
|
|
500
|
+
this.logService.error(`Failed to uninstall the workspace extension ${extension.identifier.id} from ${( extension.location.toString())}`, getErrorMessage(error));
|
|
501
|
+
this._onDidUninstallExtension.fire({
|
|
502
|
+
identifier: extension.identifier,
|
|
503
|
+
server,
|
|
504
|
+
error,
|
|
505
|
+
applicationScoped: false,
|
|
506
|
+
workspaceScoped: true
|
|
507
|
+
});
|
|
508
|
+
throw error;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
334
511
|
async validateAndGetExtensionManagementServersToInstall(gallery, installOptions) {
|
|
335
512
|
const manifest = await this.extensionGalleryService.getManifest(gallery, CancellationToken.None);
|
|
336
513
|
if (!manifest) {
|
|
@@ -362,7 +539,7 @@ let ExtensionManagementService = class ExtensionManagementService extends Dispos
|
|
|
362
539
|
throw error;
|
|
363
540
|
}
|
|
364
541
|
if (!installOptions?.context?.[EXTENSION_INSTALL_SYNC_CONTEXT]) {
|
|
365
|
-
await this.checkForWorkspaceTrust(manifest);
|
|
542
|
+
await this.checkForWorkspaceTrust(manifest, false);
|
|
366
543
|
}
|
|
367
544
|
if (!installOptions?.donotIncludePackAndDependencies) {
|
|
368
545
|
await this.checkInstallingExtensionOnWeb(gallery, manifest);
|
|
@@ -393,7 +570,7 @@ let ExtensionManagementService = class ExtensionManagementService extends Dispos
|
|
|
393
570
|
async hasToFlagExtensionsMachineScoped(extensions) {
|
|
394
571
|
if (this.isExtensionsSyncEnabled()) {
|
|
395
572
|
const { result } = await this.dialogService.prompt({
|
|
396
|
-
type: Severity.Info,
|
|
573
|
+
type: Severity$1.Info,
|
|
397
574
|
message: extensions.length === 1 ? ( localizeWithPath(
|
|
398
575
|
'vs/workbench/services/extensionManagement/common/extensionManagementService',
|
|
399
576
|
'install extension',
|
|
@@ -456,33 +633,50 @@ let ExtensionManagementService = class ExtensionManagementService extends Dispos
|
|
|
456
633
|
return Promise.resolve({ malicious: [], deprecated: {}, search: [] });
|
|
457
634
|
}
|
|
458
635
|
getServer(extension) {
|
|
636
|
+
if (extension.isWorkspaceScoped) {
|
|
637
|
+
return this.getWorkspaceExtensionsServer();
|
|
638
|
+
}
|
|
459
639
|
return this.extensionManagementServerService.getExtensionManagementServer(extension);
|
|
460
640
|
}
|
|
461
|
-
|
|
462
|
-
if (this.
|
|
641
|
+
getWorkspaceExtensionsServer() {
|
|
642
|
+
if (this.extensionManagementServerService.remoteExtensionManagementServer) {
|
|
643
|
+
return this.extensionManagementServerService.remoteExtensionManagementServer;
|
|
644
|
+
}
|
|
645
|
+
if (this.extensionManagementServerService.localExtensionManagementServer) {
|
|
646
|
+
return this.extensionManagementServerService.localExtensionManagementServer;
|
|
647
|
+
}
|
|
648
|
+
if (this.extensionManagementServerService.webExtensionManagementServer) {
|
|
649
|
+
return this.extensionManagementServerService.webExtensionManagementServer;
|
|
650
|
+
}
|
|
651
|
+
throw new Error('No extension server found');
|
|
652
|
+
}
|
|
653
|
+
async checkForWorkspaceTrust(manifest, requireTrust) {
|
|
654
|
+
if (requireTrust || this.extensionManifestPropertiesService.getExtensionUntrustedWorkspaceSupportType(manifest) === false) {
|
|
655
|
+
const buttons = [];
|
|
656
|
+
buttons.push({ label: ( localizeWithPath(
|
|
657
|
+
'vs/workbench/services/extensionManagement/common/extensionManagementService',
|
|
658
|
+
'extensionInstallWorkspaceTrustButton',
|
|
659
|
+
"Trust Workspace & Install"
|
|
660
|
+
)), type: 'ContinueWithTrust' });
|
|
661
|
+
if (!requireTrust) {
|
|
662
|
+
buttons.push({ label: ( localizeWithPath(
|
|
663
|
+
'vs/workbench/services/extensionManagement/common/extensionManagementService',
|
|
664
|
+
'extensionInstallWorkspaceTrustContinueButton',
|
|
665
|
+
"Install"
|
|
666
|
+
)), type: 'ContinueWithoutTrust' });
|
|
667
|
+
}
|
|
668
|
+
buttons.push({ label: ( localizeWithPath(
|
|
669
|
+
'vs/workbench/services/extensionManagement/common/extensionManagementService',
|
|
670
|
+
'extensionInstallWorkspaceTrustManageButton',
|
|
671
|
+
"Learn More"
|
|
672
|
+
)), type: 'Manage' });
|
|
463
673
|
const trustState = await this.workspaceTrustRequestService.requestWorkspaceTrust({
|
|
464
674
|
message: ( localizeWithPath(
|
|
465
675
|
'vs/workbench/services/extensionManagement/common/extensionManagementService',
|
|
466
676
|
'extensionInstallWorkspaceTrustMessage',
|
|
467
677
|
"Enabling this extension requires a trusted workspace."
|
|
468
678
|
)),
|
|
469
|
-
buttons
|
|
470
|
-
{ label: ( localizeWithPath(
|
|
471
|
-
'vs/workbench/services/extensionManagement/common/extensionManagementService',
|
|
472
|
-
'extensionInstallWorkspaceTrustButton',
|
|
473
|
-
"Trust Workspace & Install"
|
|
474
|
-
)), type: 'ContinueWithTrust' },
|
|
475
|
-
{ label: ( localizeWithPath(
|
|
476
|
-
'vs/workbench/services/extensionManagement/common/extensionManagementService',
|
|
477
|
-
'extensionInstallWorkspaceTrustContinueButton',
|
|
478
|
-
"Install"
|
|
479
|
-
)), type: 'ContinueWithoutTrust' },
|
|
480
|
-
{ label: ( localizeWithPath(
|
|
481
|
-
'vs/workbench/services/extensionManagement/common/extensionManagementService',
|
|
482
|
-
'extensionInstallWorkspaceTrustManageButton',
|
|
483
|
-
"Learn More"
|
|
484
|
-
)), type: 'Manage' }
|
|
485
|
-
]
|
|
679
|
+
buttons
|
|
486
680
|
});
|
|
487
681
|
if (trustState === undefined) {
|
|
488
682
|
throw new CancellationError();
|
|
@@ -574,7 +768,7 @@ let ExtensionManagementService = class ExtensionManagementService extends Dispos
|
|
|
574
768
|
];
|
|
575
769
|
}
|
|
576
770
|
await this.dialogService.prompt({
|
|
577
|
-
type: Severity.Info,
|
|
771
|
+
type: Severity$1.Info,
|
|
578
772
|
message,
|
|
579
773
|
detail,
|
|
580
774
|
buttons,
|
|
@@ -627,7 +821,225 @@ ExtensionManagementService = ( __decorate([
|
|
|
627
821
|
( __param(9, IExtensionManifestPropertiesService)),
|
|
628
822
|
( __param(10, IFileService)),
|
|
629
823
|
( __param(11, ILogService)),
|
|
630
|
-
( __param(12, IInstantiationService))
|
|
824
|
+
( __param(12, IInstantiationService)),
|
|
825
|
+
( __param(13, IExtensionsScannerService)),
|
|
826
|
+
( __param(14, ITelemetryService))
|
|
631
827
|
], ExtensionManagementService));
|
|
828
|
+
let WorkspaceExtensionsManagementService = class WorkspaceExtensionsManagementService extends Disposable {
|
|
829
|
+
static { WorkspaceExtensionsManagementService_1 = this; }
|
|
830
|
+
static { this.WORKSPACE_EXTENSIONS_KEY = 'workspaceExtensions.locations'; }
|
|
831
|
+
constructor(fileService, logService, workspaceService, extensionsScannerService, storageService, uriIdentityService, telemetryService) {
|
|
832
|
+
super();
|
|
833
|
+
this.fileService = fileService;
|
|
834
|
+
this.logService = logService;
|
|
835
|
+
this.workspaceService = workspaceService;
|
|
836
|
+
this.extensionsScannerService = extensionsScannerService;
|
|
837
|
+
this.storageService = storageService;
|
|
838
|
+
this.uriIdentityService = uriIdentityService;
|
|
839
|
+
this.telemetryService = telemetryService;
|
|
840
|
+
this._onDidChangeInvalidExtensions = this._register(( new Emitter()));
|
|
841
|
+
this.onDidChangeInvalidExtensions = this._onDidChangeInvalidExtensions.event;
|
|
842
|
+
this.extensions = [];
|
|
843
|
+
this.invalidExtensionWatchers = this._register(( new DisposableStore()));
|
|
844
|
+
this._register(Event.debounce(this.fileService.onDidFilesChange, (last, e) => {
|
|
845
|
+
(last = last ?? []).push(e);
|
|
846
|
+
return last;
|
|
847
|
+
}, 1000)(events => {
|
|
848
|
+
const changedInvalidExtensions = this.extensions.filter(extension => !extension.isValid && ( events.some(e => e.affects(extension.location))));
|
|
849
|
+
if (changedInvalidExtensions.length) {
|
|
850
|
+
this.checkExtensionsValidity(changedInvalidExtensions);
|
|
851
|
+
}
|
|
852
|
+
}));
|
|
853
|
+
this.initializePromise = this.initialize();
|
|
854
|
+
}
|
|
855
|
+
async initialize() {
|
|
856
|
+
const existingLocations = this.getWorkspaceExtensionsLocations();
|
|
857
|
+
if (!existingLocations.length) {
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
await Promise.allSettled(( existingLocations.map(async (location) => {
|
|
861
|
+
if (!this.workspaceService.isInsideWorkspace(location)) {
|
|
862
|
+
this.logService.info(`Removing the workspace extension ${( location.toString())} as it is not inside the workspace`);
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
if (!(await this.fileService.exists(location))) {
|
|
866
|
+
this.logService.info(`Removing the workspace extension ${( location.toString())} as it does not exist`);
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
try {
|
|
870
|
+
const extension = await this.scanWorkspaceExtension(location);
|
|
871
|
+
if (extension) {
|
|
872
|
+
this.extensions.push(extension);
|
|
873
|
+
}
|
|
874
|
+
else {
|
|
875
|
+
this.logService.info(`Skipping workspace extension ${( location.toString())} as it does not exist`);
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
catch (error) {
|
|
879
|
+
this.logService.error('Skipping the workspace extension', ( location.toString()), error);
|
|
880
|
+
}
|
|
881
|
+
})));
|
|
882
|
+
this.saveWorkspaceExtensions();
|
|
883
|
+
}
|
|
884
|
+
watchInvalidExtensions() {
|
|
885
|
+
this.invalidExtensionWatchers.clear();
|
|
886
|
+
for (const extension of this.extensions) {
|
|
887
|
+
if (!extension.isValid) {
|
|
888
|
+
this.invalidExtensionWatchers.add(this.fileService.watch(extension.location));
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
async checkExtensionsValidity(extensions) {
|
|
893
|
+
const validExtensions = [];
|
|
894
|
+
await Promise.all(( extensions.map(async (extension) => {
|
|
895
|
+
const newExtension = await this.scanWorkspaceExtension(extension.location);
|
|
896
|
+
if (newExtension?.isValid) {
|
|
897
|
+
validExtensions.push(newExtension);
|
|
898
|
+
}
|
|
899
|
+
})));
|
|
900
|
+
let changed = false;
|
|
901
|
+
for (const extension of validExtensions) {
|
|
902
|
+
const index = this.extensions.findIndex(e => this.uriIdentityService.extUri.isEqual(e.location, extension.location));
|
|
903
|
+
if (index !== -1) {
|
|
904
|
+
changed = true;
|
|
905
|
+
this.extensions.splice(index, 1, extension);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
if (changed) {
|
|
909
|
+
this.saveWorkspaceExtensions();
|
|
910
|
+
this._onDidChangeInvalidExtensions.fire(validExtensions);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
async getInstalled(includeInvalid) {
|
|
914
|
+
await this.initializePromise;
|
|
915
|
+
return this.extensions.filter(e => includeInvalid || e.isValid);
|
|
916
|
+
}
|
|
917
|
+
async install(extension) {
|
|
918
|
+
await this.initializePromise;
|
|
919
|
+
const workspaceExtension = await this.scanWorkspaceExtension(extension.location);
|
|
920
|
+
if (!workspaceExtension) {
|
|
921
|
+
throw new Error('Cannot install the extension as it does not exist.');
|
|
922
|
+
}
|
|
923
|
+
const existingExtensionIndex = this.extensions.findIndex(e => areSameExtensions(e.identifier, extension.identifier));
|
|
924
|
+
if (existingExtensionIndex === -1) {
|
|
925
|
+
this.extensions.push(workspaceExtension);
|
|
926
|
+
}
|
|
927
|
+
else {
|
|
928
|
+
this.extensions.splice(existingExtensionIndex, 1, workspaceExtension);
|
|
929
|
+
}
|
|
930
|
+
this.saveWorkspaceExtensions();
|
|
931
|
+
this.telemetryService.publicLog2('workspaceextension:install');
|
|
932
|
+
return workspaceExtension;
|
|
933
|
+
}
|
|
934
|
+
async uninstall(extension) {
|
|
935
|
+
await this.initializePromise;
|
|
936
|
+
const existingExtensionIndex = this.extensions.findIndex(e => areSameExtensions(e.identifier, extension.identifier));
|
|
937
|
+
if (existingExtensionIndex !== -1) {
|
|
938
|
+
this.extensions.splice(existingExtensionIndex, 1);
|
|
939
|
+
this.saveWorkspaceExtensions();
|
|
940
|
+
}
|
|
941
|
+
this.telemetryService.publicLog2('workspaceextension:uninstall');
|
|
942
|
+
}
|
|
943
|
+
getWorkspaceExtensionsLocations() {
|
|
944
|
+
const locations = [];
|
|
945
|
+
try {
|
|
946
|
+
const parsed = JSON.parse(this.storageService.get(WorkspaceExtensionsManagementService_1.WORKSPACE_EXTENSIONS_KEY, 1 , '[]'));
|
|
947
|
+
if (Array.isArray(locations)) {
|
|
948
|
+
for (const location of parsed) {
|
|
949
|
+
if (isString(location)) {
|
|
950
|
+
if (this.workspaceService.getWorkbenchState() === 2 ) {
|
|
951
|
+
locations.push(this.workspaceService.getWorkspace().folders[0].toResource(location));
|
|
952
|
+
}
|
|
953
|
+
else {
|
|
954
|
+
this.logService.warn(`Invalid value for 'extensions' in workspace storage: ${location}`);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
else {
|
|
958
|
+
locations.push(URI.revive(location));
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
else {
|
|
963
|
+
this.logService.warn(`Invalid value for 'extensions' in workspace storage: ${locations}`);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
catch (error) {
|
|
967
|
+
this.logService.warn(`Error parsing workspace extensions locations: ${getErrorMessage(error)}`);
|
|
968
|
+
}
|
|
969
|
+
return locations;
|
|
970
|
+
}
|
|
971
|
+
saveWorkspaceExtensions() {
|
|
972
|
+
const locations = ( this.extensions.map(extension => extension.location));
|
|
973
|
+
if (this.workspaceService.getWorkbenchState() === 2 ) {
|
|
974
|
+
this.storageService.store(WorkspaceExtensionsManagementService_1.WORKSPACE_EXTENSIONS_KEY, JSON.stringify(coalesce(( locations
|
|
975
|
+
.map(
|
|
976
|
+
location => this.uriIdentityService.extUri.relativePath(this.workspaceService.getWorkspace().folders[0].uri, location)
|
|
977
|
+
)))), 1 , 1 );
|
|
978
|
+
}
|
|
979
|
+
else {
|
|
980
|
+
this.storageService.store(WorkspaceExtensionsManagementService_1.WORKSPACE_EXTENSIONS_KEY, JSON.stringify(locations), 1 , 1 );
|
|
981
|
+
}
|
|
982
|
+
this.watchInvalidExtensions();
|
|
983
|
+
}
|
|
984
|
+
async scanWorkspaceExtension(location) {
|
|
985
|
+
const scannedExtension = await this.extensionsScannerService.scanExistingExtension(location, 1 , { includeInvalid: true });
|
|
986
|
+
return scannedExtension ? this.toLocalWorkspaceExtension(scannedExtension) : null;
|
|
987
|
+
}
|
|
988
|
+
async toLocalWorkspaceExtension(extension) {
|
|
989
|
+
const stat = await this.fileService.resolve(extension.location);
|
|
990
|
+
let readmeUrl;
|
|
991
|
+
let changelogUrl;
|
|
992
|
+
if (stat.children) {
|
|
993
|
+
readmeUrl = stat.children.find(({ name }) => /^readme(\.txt|\.md|)$/i.test(name))?.resource;
|
|
994
|
+
changelogUrl = stat.children.find(({ name }) => /^changelog(\.txt|\.md|)$/i.test(name))?.resource;
|
|
995
|
+
}
|
|
996
|
+
const validations = [...extension.validations];
|
|
997
|
+
let isValid = extension.isValid;
|
|
998
|
+
if (extension.manifest.main) {
|
|
999
|
+
if (!(await this.fileService.exists(this.uriIdentityService.extUri.joinPath(extension.location, extension.manifest.main)))) {
|
|
1000
|
+
isValid = false;
|
|
1001
|
+
validations.push([Severity$1.Error, ( localizeWithPath(
|
|
1002
|
+
'vs/workbench/services/extensionManagement/common/extensionManagementService',
|
|
1003
|
+
'main.notFound',
|
|
1004
|
+
"Cannot activate, becase {0} not found",
|
|
1005
|
+
extension.manifest.main
|
|
1006
|
+
))]);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
return {
|
|
1010
|
+
identifier: extension.identifier,
|
|
1011
|
+
type: extension.type,
|
|
1012
|
+
isBuiltin: extension.isBuiltin || !!extension.metadata?.isBuiltin,
|
|
1013
|
+
location: extension.location,
|
|
1014
|
+
manifest: extension.manifest,
|
|
1015
|
+
targetPlatform: extension.targetPlatform,
|
|
1016
|
+
validations,
|
|
1017
|
+
isValid,
|
|
1018
|
+
readmeUrl,
|
|
1019
|
+
changelogUrl,
|
|
1020
|
+
publisherDisplayName: extension.metadata?.publisherDisplayName || null,
|
|
1021
|
+
publisherId: extension.metadata?.publisherId || null,
|
|
1022
|
+
isApplicationScoped: !!extension.metadata?.isApplicationScoped,
|
|
1023
|
+
isMachineScoped: !!extension.metadata?.isMachineScoped,
|
|
1024
|
+
isPreReleaseVersion: !!extension.metadata?.isPreReleaseVersion,
|
|
1025
|
+
hasPreReleaseVersion: !!extension.metadata?.hasPreReleaseVersion,
|
|
1026
|
+
preRelease: !!extension.metadata?.preRelease,
|
|
1027
|
+
installedTimestamp: extension.metadata?.installedTimestamp,
|
|
1028
|
+
updated: !!extension.metadata?.updated,
|
|
1029
|
+
pinned: !!extension.metadata?.pinned,
|
|
1030
|
+
isWorkspaceScoped: true,
|
|
1031
|
+
source: 'resource'
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
};
|
|
1035
|
+
WorkspaceExtensionsManagementService = WorkspaceExtensionsManagementService_1 = ( __decorate([
|
|
1036
|
+
( __param(0, IFileService)),
|
|
1037
|
+
( __param(1, ILogService)),
|
|
1038
|
+
( __param(2, IWorkspaceContextService)),
|
|
1039
|
+
( __param(3, IExtensionsScannerService)),
|
|
1040
|
+
( __param(4, IStorageService)),
|
|
1041
|
+
( __param(5, IUriIdentityService)),
|
|
1042
|
+
( __param(6, ITelemetryService))
|
|
1043
|
+
], WorkspaceExtensionsManagementService));
|
|
632
1044
|
|
|
633
1045
|
export { ExtensionManagementService };
|
package/vscode/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.js
CHANGED
|
@@ -139,8 +139,8 @@ let WebExtensionManagementService = class WebExtensionManagementService extends
|
|
|
139
139
|
async copyExtensions(fromProfileLocation, toProfileLocation) {
|
|
140
140
|
await this.webExtensionsScannerService.copyExtensions(fromProfileLocation, toProfileLocation, e => !e.metadata?.isApplicationScoped);
|
|
141
141
|
}
|
|
142
|
-
async getCompatibleVersion(extension, sameVersion, includePreRelease) {
|
|
143
|
-
const compatibleExtension = await super.getCompatibleVersion(extension, sameVersion, includePreRelease);
|
|
142
|
+
async getCompatibleVersion(extension, sameVersion, includePreRelease, productVersion) {
|
|
143
|
+
const compatibleExtension = await super.getCompatibleVersion(extension, sameVersion, includePreRelease, productVersion);
|
|
144
144
|
if (compatibleExtension) {
|
|
145
145
|
return compatibleExtension;
|
|
146
146
|
}
|
|
@@ -213,6 +213,8 @@ function toLocalExtension(extension) {
|
|
|
213
213
|
targetPlatform: "web" ,
|
|
214
214
|
updated: !!metadata.updated,
|
|
215
215
|
pinned: !!metadata?.pinned,
|
|
216
|
+
isWorkspaceScoped: false,
|
|
217
|
+
source: metadata?.source ?? (extension.identifier.uuid ? 'gallery' : 'resource')
|
|
216
218
|
};
|
|
217
219
|
}
|
|
218
220
|
function getMetadata(options, existingExtension) {
|
|
@@ -255,6 +257,7 @@ class InstallExtensionTask extends AbstractExtensionTask {
|
|
|
255
257
|
metadata.preRelease = isBoolean(this.options.preRelease)
|
|
256
258
|
? this.options.preRelease
|
|
257
259
|
: this.options.installPreReleaseVersion || this.extension.properties.isPreReleaseVersion || metadata.preRelease;
|
|
260
|
+
metadata.source = URI.isUri(this.extension) ? 'resource' : 'gallery';
|
|
258
261
|
}
|
|
259
262
|
metadata.pinned = this.options.installGivenVersion ? true : (this.options.pinned ?? metadata.pinned);
|
|
260
263
|
this._profileLocation = metadata.isApplicationScoped ? this.userDataProfilesService.defaultProfile.extensionsResource : this.options.profileLocation;
|