@theia/plugin-ext 1.75.0-next.25 → 1.75.0-next.28
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/lib/common/errors.d.ts +1 -14
- package/lib/common/errors.d.ts.map +1 -1
- package/lib/common/errors.js +3 -16
- package/lib/common/errors.js.map +1 -1
- package/lib/common/plugin-protocol.d.ts +44 -719
- package/lib/common/plugin-protocol.d.ts.map +1 -1
- package/lib/common/plugin-protocol.js +11 -34
- package/lib/common/plugin-protocol.js.map +1 -1
- package/lib/hosted/browser/worker/plugin-manifest-loader.d.ts.map +1 -1
- package/lib/hosted/browser/worker/plugin-manifest-loader.js +5 -36
- package/lib/hosted/browser/worker/plugin-manifest-loader.js.map +1 -1
- package/lib/hosted/browser/worker/worker-main.js +2 -1
- package/lib/hosted/browser/worker/worker-main.js.map +1 -1
- package/lib/hosted/node/hosted-plugin-localization-service.d.ts.map +1 -1
- package/lib/hosted/node/hosted-plugin-localization-service.js +4 -68
- package/lib/hosted/node/hosted-plugin-localization-service.js.map +1 -1
- package/lib/hosted/node/plugin-host-rpc.d.ts.map +1 -1
- package/lib/hosted/node/plugin-host-rpc.js +2 -2
- package/lib/hosted/node/plugin-host-rpc.js.map +1 -1
- package/lib/hosted/node/plugin-reader.d.ts.map +1 -1
- package/lib/hosted/node/plugin-reader.js +4 -3
- package/lib/hosted/node/plugin-reader.js.map +1 -1
- package/lib/hosted/node/scanners/grammars-reader.d.ts +3 -2
- package/lib/hosted/node/scanners/grammars-reader.d.ts.map +1 -1
- package/lib/hosted/node/scanners/grammars-reader.js +5 -23
- package/lib/hosted/node/scanners/grammars-reader.js.map +1 -1
- package/lib/hosted/node/scanners/scanner-theia.d.ts +37 -72
- package/lib/hosted/node/scanners/scanner-theia.d.ts.map +1 -1
- package/lib/hosted/node/scanners/scanner-theia.js +114 -854
- package/lib/hosted/node/scanners/scanner-theia.js.map +1 -1
- package/lib/hosted/node/scanners/scanner-theia.spec.js +4 -4
- package/lib/hosted/node/scanners/scanner-theia.spec.js.map +1 -1
- package/lib/main/browser/plugin-contribution-handler.js +1 -1
- package/lib/main/browser/plugin-contribution-handler.js.map +1 -1
- package/lib/main/browser/plugin-icon-service.d.ts.map +1 -1
- package/lib/main/browser/plugin-icon-service.js +2 -1
- package/lib/main/browser/plugin-icon-service.js.map +1 -1
- package/lib/main/browser/plugin-icon-theme-service.d.ts.map +1 -1
- package/lib/main/browser/plugin-icon-theme-service.js +2 -1
- package/lib/main/browser/plugin-icon-theme-service.js.map +1 -1
- package/lib/main/browser/plugin-shared-style.d.ts.map +1 -1
- package/lib/main/browser/plugin-shared-style.js +2 -1
- package/lib/main/browser/plugin-shared-style.js.map +1 -1
- package/package.json +31 -30
- package/src/common/errors.ts +1 -25
- package/src/common/plugin-protocol.ts +194 -719
- package/src/hosted/browser/worker/plugin-manifest-loader.ts +8 -41
- package/src/hosted/browser/worker/worker-main.ts +2 -1
- package/src/hosted/node/hosted-plugin-localization-service.ts +3 -82
- package/src/hosted/node/plugin-host-rpc.ts +3 -3
- package/src/hosted/node/plugin-reader.ts +4 -3
- package/src/hosted/node/scanners/grammars-reader.ts +14 -23
- package/src/hosted/node/scanners/scanner-theia.spec.ts +4 -4
- package/src/hosted/node/scanners/scanner-theia.ts +200 -972
- package/src/main/browser/plugin-contribution-handler.ts +1 -1
- package/src/main/browser/plugin-icon-service.ts +2 -1
- package/src/main/browser/plugin-icon-theme-service.ts +2 -1
- package/src/main/browser/plugin-shared-style.ts +2 -1
- package/lib/hosted/node/plugin-activation-events.d.ts +0 -7
- package/lib/hosted/node/plugin-activation-events.d.ts.map +0 -1
- package/lib/hosted/node/plugin-activation-events.js +0 -95
- package/lib/hosted/node/plugin-activation-events.js.map +0 -1
- package/lib/hosted/node/plugin-manifest-loader.d.ts +0 -3
- package/lib/hosted/node/plugin-manifest-loader.d.ts.map +0 -1
- package/lib/hosted/node/plugin-manifest-loader.js +0 -34
- package/lib/hosted/node/plugin-manifest-loader.js.map +0 -1
- package/lib/main/node/errors.spec.d.ts +0 -2
- package/lib/main/node/errors.spec.d.ts.map +0 -1
- package/lib/main/node/errors.spec.js +0 -36
- package/lib/main/node/errors.spec.js.map +0 -1
- package/src/hosted/node/plugin-activation-events.ts +0 -112
- package/src/hosted/node/plugin-manifest-loader.ts +0 -32
- package/src/main/node/errors.spec.ts +0 -37
|
@@ -18,155 +18,104 @@
|
|
|
18
18
|
|
|
19
19
|
import { inject, injectable, unmanaged, named } from '@theia/core/shared/inversify';
|
|
20
20
|
import {
|
|
21
|
-
|
|
22
|
-
AutoClosingPairConditional,
|
|
23
|
-
buildFrontendModuleName,
|
|
21
|
+
CustomEditor,
|
|
24
22
|
DebuggerContribution,
|
|
25
|
-
IconThemeContribution,
|
|
26
23
|
IconContribution,
|
|
24
|
+
IconThemeContribution,
|
|
27
25
|
IconUrl,
|
|
28
26
|
Keybinding,
|
|
29
|
-
LanguageConfiguration,
|
|
30
27
|
LanguageContribution,
|
|
28
|
+
Localization,
|
|
31
29
|
Menu,
|
|
32
30
|
PluginCommand,
|
|
33
31
|
PluginContribution,
|
|
34
32
|
PluginEngine,
|
|
33
|
+
PluginEntryPoint,
|
|
35
34
|
PluginLifecycle,
|
|
36
35
|
PluginModel,
|
|
37
36
|
PluginPackage,
|
|
38
37
|
PluginPackageCommand,
|
|
38
|
+
PluginPackageCustomEditor,
|
|
39
39
|
PluginPackageDebuggersContribution,
|
|
40
40
|
PluginPackageKeybinding,
|
|
41
41
|
PluginPackageLanguageContribution,
|
|
42
|
-
|
|
42
|
+
PluginPackageLocalization,
|
|
43
43
|
PluginPackageMenu,
|
|
44
44
|
PluginPackageSubmenu,
|
|
45
|
+
PluginPackageTranslation,
|
|
45
46
|
PluginPackageView,
|
|
46
47
|
PluginPackageViewContainer,
|
|
47
48
|
PluginPackageViewWelcome,
|
|
48
49
|
PluginScanner,
|
|
49
50
|
PluginTaskDefinitionContribution,
|
|
51
|
+
PluginIdentifiers,
|
|
50
52
|
SnippetContribution,
|
|
51
53
|
Submenu,
|
|
54
|
+
TerminalProfile,
|
|
52
55
|
ThemeContribution,
|
|
56
|
+
Translation,
|
|
53
57
|
View,
|
|
54
58
|
ViewContainer,
|
|
55
59
|
ViewWelcome,
|
|
56
|
-
PluginPackageCustomEditor,
|
|
57
|
-
CustomEditor,
|
|
58
|
-
CustomEditorPriority,
|
|
59
|
-
PluginPackageLocalization,
|
|
60
|
-
Localization,
|
|
61
|
-
PluginPackageTranslation,
|
|
62
|
-
Translation,
|
|
63
|
-
PluginIdentifiers,
|
|
64
|
-
TerminalProfile,
|
|
65
|
-
PluginIconContribution,
|
|
66
|
-
PluginEntryPoint,
|
|
67
|
-
PluginPackageContribution,
|
|
68
60
|
WalkthroughContribution,
|
|
69
|
-
WalkthroughStepContribution,
|
|
70
|
-
PluginPackageWalkthroughStepMedia,
|
|
71
|
-
WalkthroughStepMedia
|
|
72
61
|
} from '../../../common/plugin-protocol';
|
|
73
|
-
import { promises as fs
|
|
62
|
+
import { promises as fs } from 'fs';
|
|
74
63
|
import * as path from 'path';
|
|
75
|
-
import { isObject, isStringArray } from '@theia/core/lib/common/types';
|
|
76
|
-
import { GrammarsReader } from './grammars-reader';
|
|
77
|
-
import { CharacterPair } from '../../../common/plugin-api-rpc';
|
|
78
|
-
import { isENOENT } from '../../../common/errors';
|
|
79
64
|
import * as jsoncparser from 'jsonc-parser';
|
|
80
|
-
import {
|
|
81
|
-
import {
|
|
82
|
-
import { deepClone } from '@theia/core/lib/common/objects';
|
|
83
|
-
import { PreferenceSchema, PreferenceDataProperty } from '@theia/core/lib/common/preferences/preference-schema';
|
|
84
|
-
import { TaskDefinition } from '@theia/task/lib/common/task-protocol';
|
|
85
|
-
import { ColorDefinition } from '@theia/core/lib/common/color';
|
|
86
|
-
import { CSSIcon } from '@theia/core/lib/common/markdown-rendering/icon-utilities';
|
|
65
|
+
import { GrammarsReader } from './grammars-reader';
|
|
66
|
+
import { isENOENT } from '@theia/plugin-utils/lib/common/utils';
|
|
87
67
|
import { PluginUriFactory } from './plugin-uri-factory';
|
|
88
|
-
import { PreferenceScope } from '@theia/core/lib/common/preferences/preference-scope';
|
|
89
68
|
import { ILogger } from '@theia/core';
|
|
69
|
+
import { IJSONSchema } from '@theia/core/lib/common/json-schema';
|
|
70
|
+
import { PreferenceSchema } from '@theia/core/lib/common/preferences/preference-schema';
|
|
71
|
+
import { PreferenceScope } from '@theia/core/lib/common/preferences/preference-scope';
|
|
72
|
+
import { TaskDefinition } from '@theia/task/lib/common/task-protocol';
|
|
73
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
74
|
+
import {
|
|
75
|
+
extractPluginViewsIds as extractPluginViewsIdsShared,
|
|
76
|
+
getScope as getScopeShared,
|
|
77
|
+
normalizeContributions,
|
|
78
|
+
readColors as readColorsShared,
|
|
79
|
+
readCommand as readCommandShared,
|
|
80
|
+
readConfiguration as readConfigurationShared,
|
|
81
|
+
readCustomEditor as readCustomEditorShared,
|
|
82
|
+
readDebugger as readDebuggerShared,
|
|
83
|
+
readIcons as readIconsShared,
|
|
84
|
+
readIconThemes as readIconThemesShared,
|
|
85
|
+
readKeybinding as readKeybindingShared,
|
|
86
|
+
readLanguage as readLanguageShared,
|
|
87
|
+
readMenu as readMenuShared,
|
|
88
|
+
readSnippets as readSnippetsShared,
|
|
89
|
+
readSubmenu as readSubmenuShared,
|
|
90
|
+
readTaskDefinition as readTaskDefinitionShared,
|
|
91
|
+
readLocalization as readLocalizationShared,
|
|
92
|
+
readLocalizations as readLocalizationsShared,
|
|
93
|
+
readTerminals as readTerminalsShared,
|
|
94
|
+
readThemes as readThemesShared,
|
|
95
|
+
readTranslation as readTranslationShared,
|
|
96
|
+
readWalkthroughs as readWalkthroughsShared,
|
|
97
|
+
readView as readViewShared,
|
|
98
|
+
readViewContainer as readViewContainerShared,
|
|
99
|
+
readViewWelcome as readViewWelcomeShared,
|
|
100
|
+
toSchema as toSchemaShared,
|
|
101
|
+
transformIconUrl as transformIconUrlShared,
|
|
102
|
+
} from '@theia/plugin-utils/lib/node/normalize-contributions';
|
|
103
|
+
import type {
|
|
104
|
+
IConfigurationNode,
|
|
105
|
+
NormalizeContributionsContext,
|
|
106
|
+
} from '@theia/plugin-utils/lib/common/contribution-types';
|
|
107
|
+
import type { ColorDefinition } from '@theia/plugin-utils/lib/common/protocol-shims';
|
|
108
|
+
import {
|
|
109
|
+
applyTrustExtraction as applyTrustExtractionShared,
|
|
110
|
+
buildEntryPointForTheia as buildEntryPointForTheiaShared,
|
|
111
|
+
buildLifecycle,
|
|
112
|
+
buildModelForTheia as buildModelForTheiaShared,
|
|
113
|
+
toPluginUrl as toPluginUrlShared
|
|
114
|
+
} from '@theia/plugin-utils/lib/common/plugin-model';
|
|
115
|
+
import { getPluginRootFileUrl as getPluginRootFileUrlShared } from '@theia/plugin-utils/lib/node/plugin-model';
|
|
90
116
|
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
/** Maps the view container locations used by VS Code extensions to the Theia shell locations. */
|
|
95
|
-
const VIEW_CONTAINER_LOCATION_ALIASES: Record<string, string> = {
|
|
96
|
-
activitybar: 'left',
|
|
97
|
-
panel: 'bottom',
|
|
98
|
-
secondarySidebar: 'right',
|
|
99
|
-
auxiliarybar: 'right'
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
function getFileExtension(filePath: string): string {
|
|
103
|
-
const index = filePath.lastIndexOf('.');
|
|
104
|
-
return index === -1 ? '' : filePath.substring(index + 1);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Mirrors VS Code's `ConfigurationRegistry.getDefaultValue(type)`: plugins expect typed-but-defaultless properties to read as a type-based default, not `undefined`.
|
|
109
|
-
*/
|
|
110
|
-
function deriveDefaultForType(type: JsonType | JsonType[] | undefined): JSONValue {
|
|
111
|
-
const t = Array.isArray(type) ? type[0] : type;
|
|
112
|
-
switch (t) {
|
|
113
|
-
case 'boolean': return false;
|
|
114
|
-
case 'integer':
|
|
115
|
-
case 'number': return 0;
|
|
116
|
-
case 'string': return '';
|
|
117
|
-
case 'array': return [];
|
|
118
|
-
case 'object': return {};
|
|
119
|
-
default: return null;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
type PluginPackageWithContributes = PluginPackage & { contributes: PluginPackageContribution };
|
|
124
|
-
|
|
125
|
-
type ScopeString = 'machine-overridable' | 'window' | 'resource' | 'language-overridable' | 'application' | 'machine';
|
|
126
|
-
|
|
127
|
-
type EditPresentationTypes = 'multilineText' | 'singleLineText';
|
|
128
|
-
export interface IConfigurationPropertySchema extends IJSONSchema {
|
|
129
|
-
|
|
130
|
-
scope?: ScopeString;
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* When `false` this property is excluded from the registry. Default is to include.
|
|
134
|
-
*/
|
|
135
|
-
included?: boolean;
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* List of tags associated to the property.
|
|
139
|
-
* - A tag can be used for filtering
|
|
140
|
-
* - Use `experimental` tag for marking the setting as experimental.
|
|
141
|
-
* - Use `onExP` tag for marking that the default of the setting can be changed by running experiments.
|
|
142
|
-
*/
|
|
143
|
-
tags?: string[];
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* When specified, controls the presentation format of string settings.
|
|
147
|
-
* Otherwise, the presentation format defaults to `singleline`.
|
|
148
|
-
*/
|
|
149
|
-
editPresentation?: EditPresentationTypes;
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* When specified, gives an order number for the setting
|
|
153
|
-
* within the settings editor. Otherwise, the setting is placed at the end.
|
|
154
|
-
*/
|
|
155
|
-
order?: number;
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
export interface IExtensionInfo {
|
|
160
|
-
id: string;
|
|
161
|
-
displayName?: string;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
export interface IConfigurationNode {
|
|
165
|
-
title?: string;
|
|
166
|
-
description?: string;
|
|
167
|
-
properties?: Record<string, IConfigurationPropertySchema>;
|
|
168
|
-
scope?: ScopeString;
|
|
169
|
-
}
|
|
117
|
+
/** Async-local contribution ctx — safe for concurrent scans on the singleton scanner. */
|
|
118
|
+
const contributionCtxStorage = new AsyncLocalStorage<NormalizeContributionsContext<PluginPackage>>();
|
|
170
119
|
|
|
171
120
|
@injectable()
|
|
172
121
|
export abstract class AbstractPluginScanner implements PluginScanner {
|
|
@@ -188,34 +137,23 @@ export abstract class AbstractPluginScanner implements PluginScanner {
|
|
|
188
137
|
|
|
189
138
|
getModel(plugin: PluginPackage): PluginModel {
|
|
190
139
|
const publisher = plugin.publisher ?? PluginIdentifiers.UNPUBLISHED;
|
|
191
|
-
const result
|
|
192
|
-
|
|
193
|
-
packageUri: this.pluginUriFactory.createUri(plugin).toString(),
|
|
194
|
-
// see id definition: https://github.com/microsoft/vscode/blob/15916055fe0cb9411a5f36119b3b012458fe0a1d/src/vs/platform/extensions/common/extensions.ts#L167-L169
|
|
195
|
-
id: `${publisher.toLowerCase()}.${plugin.name.toLowerCase()}`,
|
|
196
|
-
name: plugin.name,
|
|
140
|
+
const result = buildModelForTheiaShared({
|
|
141
|
+
...plugin,
|
|
197
142
|
publisher,
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
entryPoint: this.getEntryPoint(plugin),
|
|
207
|
-
licenseUrl: this.getLicenseUrl(plugin),
|
|
208
|
-
readmeUrl: this.getReadmeUrl(plugin)
|
|
209
|
-
};
|
|
143
|
+
packageUri: this.pluginUriFactory.createUri(plugin).toString(),
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
result.engine.type = this._apiType;
|
|
147
|
+
result.engine.version = plugin.engines[this._apiType] ?? '*';
|
|
148
|
+
result.entryPoint = this.getEntryPoint(plugin);
|
|
149
|
+
result.licenseUrl = this.getLicenseUrl(plugin);
|
|
150
|
+
result.readmeUrl = this.getReadmeUrl(plugin);
|
|
210
151
|
this.applyTrustExtraction(plugin, result);
|
|
211
152
|
return result;
|
|
212
153
|
}
|
|
213
154
|
|
|
214
155
|
protected applyTrustExtraction(plugin: PluginPackage, result: PluginModel): void {
|
|
215
|
-
|
|
216
|
-
if (untrustedWorkspacesSupport !== undefined) {
|
|
217
|
-
result.untrustedWorkspacesSupport = untrustedWorkspacesSupport;
|
|
218
|
-
}
|
|
156
|
+
applyTrustExtractionShared(plugin, result);
|
|
219
157
|
}
|
|
220
158
|
|
|
221
159
|
protected getReadmeUrl(plugin: PluginPackage): string | undefined {
|
|
@@ -227,32 +165,16 @@ export abstract class AbstractPluginScanner implements PluginScanner {
|
|
|
227
165
|
}
|
|
228
166
|
|
|
229
167
|
protected getPluginRootFileUrl(plugin: PluginPackage, names: string[]): string | undefined {
|
|
230
|
-
|
|
231
|
-
try {
|
|
232
|
-
const dir = readdirSync(plugin.packagePath, { withFileTypes: true });
|
|
233
|
-
for (const dirent of dir) {
|
|
234
|
-
if (dirent.isFile() && nameSet.has(dirent.name.toLowerCase())) {
|
|
235
|
-
return PluginPackage.toPluginUrl(plugin, dirent.name);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
} catch {
|
|
239
|
-
return undefined;
|
|
240
|
-
}
|
|
168
|
+
return getPluginRootFileUrlShared(plugin, names);
|
|
241
169
|
}
|
|
242
170
|
|
|
243
171
|
protected abstract getEntryPoint(plugin: PluginPackage): PluginEntryPoint;
|
|
244
172
|
|
|
245
173
|
getLifecycle(plugin: PluginPackage): PluginLifecycle {
|
|
246
|
-
const result
|
|
247
|
-
startMethod: 'start',
|
|
248
|
-
stopMethod: 'stop',
|
|
249
|
-
frontendModuleName: buildFrontendModuleName(plugin),
|
|
250
|
-
};
|
|
251
|
-
|
|
174
|
+
const result = buildLifecycle(plugin, 'theiaPlugin');
|
|
252
175
|
if (this._backendInitPath) {
|
|
253
176
|
result.backendInitPath = path.join(__dirname, this._backendInitPath);
|
|
254
177
|
}
|
|
255
|
-
|
|
256
178
|
return result;
|
|
257
179
|
}
|
|
258
180
|
|
|
@@ -274,10 +196,10 @@ export abstract class AbstractPluginScanner implements PluginScanner {
|
|
|
274
196
|
return contributions;
|
|
275
197
|
}
|
|
276
198
|
|
|
277
|
-
return this.readContributions(rawPlugin
|
|
199
|
+
return this.readContributions(rawPlugin, contributions);
|
|
278
200
|
}
|
|
279
201
|
|
|
280
|
-
protected async readContributions(rawPlugin:
|
|
202
|
+
protected async readContributions(rawPlugin: PluginPackage, contributions: PluginContribution): Promise<PluginContribution> {
|
|
281
203
|
return contributions;
|
|
282
204
|
}
|
|
283
205
|
|
|
@@ -293,915 +215,221 @@ export class TheiaPluginScanner extends AbstractPluginScanner {
|
|
|
293
215
|
protected readonly logger: ILogger;
|
|
294
216
|
|
|
295
217
|
protected getEntryPoint(plugin: PluginPackage): PluginEntryPoint {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
218
|
+
return buildEntryPointForTheiaShared(plugin);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
static getScope(monacoScope: string | undefined): { scope: PreferenceScope | undefined; overridable: boolean } {
|
|
222
|
+
return getScopeShared(monacoScope);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
protected override async readContributions(rawPlugin: PluginPackage, contributions: PluginContribution): Promise<PluginContribution> {
|
|
226
|
+
const ctx = this.contributionCtx(rawPlugin);
|
|
227
|
+
return contributionCtxStorage.run(ctx, () => normalizeContributions(ctx, contributions));
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
protected contributionCtx(pck: PluginPackage): NormalizeContributionsContext<PluginPackage> {
|
|
231
|
+
const active = contributionCtxStorage.getStore();
|
|
232
|
+
if (active?.plugin === pck) {
|
|
233
|
+
return active;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const ctx: NormalizeContributionsContext<PluginPackage> = {
|
|
237
|
+
plugin: pck,
|
|
238
|
+
resolveUrl: relativePath => this.toPluginUrl(pck, relativePath),
|
|
239
|
+
resolveUri: (_plugin, relativePath) => this.pluginUriFactory.createUri(pck, relativePath).toString(),
|
|
240
|
+
onError: (type, err, detail) => this.logger.error(`Could not read '${pck.name}' contribution '${type}'.`, detail, err),
|
|
241
|
+
onWarn: msg => this.logger.warn(msg),
|
|
242
|
+
readJsonFile: filePath => this.readJson(filePath),
|
|
243
|
+
// Route through protected methods so Inversify/subclass overrides still apply.
|
|
244
|
+
transformIconUrl: (plugin, original) => this.transformIconUrl(plugin, original),
|
|
245
|
+
readLocalization: (entry, pluginPath) => this.readLocalization(entry, pluginPath),
|
|
246
|
+
readTranslation: (entry, pluginPath) => this.readTranslation(entry, pluginPath),
|
|
247
|
+
toSchema: definition => this.toSchema(definition),
|
|
248
|
+
readConfiguration: this.readConfiguration.bind(this),
|
|
249
|
+
readCustomEditors: this.readCustomEditors.bind(this),
|
|
250
|
+
readViews: this.readViews.bind(this),
|
|
251
|
+
readKeybinding: this.readKeybinding.bind(this),
|
|
252
|
+
readDebuggers: this.readDebuggers.bind(this),
|
|
253
|
+
readSubmenus: (submenus, plugin) => this.readSubmenus(submenus, plugin),
|
|
254
|
+
readViewsContainers: (containers, plugin) => this.readViewsContainers(containers, plugin),
|
|
255
|
+
readViewsWelcome: (welcome, views) => this.readViewsWelcome(welcome, views),
|
|
256
|
+
readCommand: (command, plugin) => this.readCommand(command, plugin),
|
|
257
|
+
readMenus: menus => this.readMenus(menus),
|
|
258
|
+
readTaskDefinition: (pluginName, definition) => this.readTaskDefinition(pluginName, definition),
|
|
259
|
+
readSnippets: plugin => this.readSnippets(plugin),
|
|
260
|
+
readThemes: plugin => this.readThemes(plugin),
|
|
261
|
+
readIcons: plugin => this.readIcons(plugin),
|
|
262
|
+
readIconThemes: plugin => this.readIconThemes(plugin),
|
|
263
|
+
readColors: plugin => this.readColors(plugin),
|
|
264
|
+
readTerminals: plugin => this.readTerminals(plugin),
|
|
265
|
+
readLocalizations: plugin => this.readLocalizations(plugin),
|
|
266
|
+
readWalkthroughs: plugin => this.readWalkthroughs(plugin),
|
|
267
|
+
readLanguages: (languages, plugin) => this.readLanguages(languages, plugin),
|
|
299
268
|
};
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
static getScope(monacoScope: string | undefined): { scope: PreferenceScope | undefined, overridable: boolean } {
|
|
307
|
-
switch (monacoScope) {
|
|
308
|
-
case 'machine-overridable':
|
|
309
|
-
case 'window':
|
|
310
|
-
case 'resource':
|
|
311
|
-
return { scope: PreferenceScope.Folder, overridable: false };
|
|
312
|
-
case 'language-overridable':
|
|
313
|
-
return { scope: PreferenceScope.Folder, overridable: true };
|
|
314
|
-
case 'application':
|
|
315
|
-
case 'machine':
|
|
316
|
-
return { scope: PreferenceScope.User, overridable: false };
|
|
317
|
-
}
|
|
318
|
-
return { scope: undefined, overridable: false };
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
protected override async readContributions(rawPlugin: PluginPackageWithContributes, contributions: PluginContribution): Promise<PluginContribution> {
|
|
322
|
-
try {
|
|
323
|
-
if (rawPlugin.contributes.configuration) {
|
|
324
|
-
const configurations = Array.isArray(rawPlugin.contributes.configuration) ? rawPlugin.contributes.configuration : [rawPlugin.contributes.configuration];
|
|
325
|
-
const hasMultipleConfigs = configurations.length > 1;
|
|
326
|
-
contributions.configuration = [];
|
|
327
|
-
for (const c of configurations) {
|
|
328
|
-
const config = this.readConfiguration(c, rawPlugin.packagePath);
|
|
329
|
-
if (config) {
|
|
330
|
-
Object.values(config.properties).forEach(property => {
|
|
331
|
-
if (hasMultipleConfigs) {
|
|
332
|
-
// If there are multiple configuration contributions, we need to distinguish them by their title in the settings UI.
|
|
333
|
-
// They are placed directly under the plugin's name in the settings UI.
|
|
334
|
-
property.owner = rawPlugin.displayName;
|
|
335
|
-
property.group = config.title;
|
|
336
|
-
} else {
|
|
337
|
-
// If there's only one configuration contribution, we display the title in the settings UI.
|
|
338
|
-
property.owner = config.title;
|
|
339
|
-
}
|
|
340
|
-
});
|
|
341
|
-
contributions.configuration.push(config);
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
} catch (err) {
|
|
346
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'configuration'.`, rawPlugin.contributes.configuration, err);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
const configurationDefaults = rawPlugin.contributes.configurationDefaults;
|
|
350
|
-
contributions.configurationDefaults = isObject(configurationDefaults) ? configurationDefaults : undefined;
|
|
351
|
-
|
|
352
|
-
try {
|
|
353
|
-
if (rawPlugin.contributes.submenus) {
|
|
354
|
-
contributions.submenus = this.readSubmenus(rawPlugin.contributes.submenus, rawPlugin);
|
|
355
|
-
}
|
|
356
|
-
} catch (err) {
|
|
357
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'submenus'.`, rawPlugin.contributes.submenus, err);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
try {
|
|
361
|
-
if (rawPlugin.contributes.customEditors) {
|
|
362
|
-
const customEditors = this.readCustomEditors(rawPlugin.contributes.customEditors);
|
|
363
|
-
contributions.customEditors = customEditors;
|
|
364
|
-
}
|
|
365
|
-
} catch (err) {
|
|
366
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'customEditors'.`, rawPlugin.contributes.customEditors, err);
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
try {
|
|
370
|
-
if (rawPlugin.contributes.viewsContainers) {
|
|
371
|
-
const viewsContainers = rawPlugin.contributes.viewsContainers;
|
|
372
|
-
contributions.viewsContainers = {};
|
|
373
|
-
|
|
374
|
-
for (const location of Object.keys(viewsContainers)) {
|
|
375
|
-
const containers = this.readViewsContainers(viewsContainers[location], rawPlugin);
|
|
376
|
-
const loc = VIEW_CONTAINER_LOCATION_ALIASES[location] ?? location;
|
|
377
|
-
if (contributions.viewsContainers[loc]) {
|
|
378
|
-
contributions.viewsContainers[loc] = contributions.viewsContainers[loc].concat(containers);
|
|
379
|
-
} else {
|
|
380
|
-
contributions.viewsContainers[loc] = containers;
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
} catch (err) {
|
|
385
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'viewsContainers'.`, rawPlugin.contributes.viewsContainers, err);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
try {
|
|
389
|
-
if (rawPlugin.contributes.views) {
|
|
390
|
-
contributions.views = {};
|
|
391
|
-
|
|
392
|
-
for (const location of Object.keys(rawPlugin.contributes.views)) {
|
|
393
|
-
const views = this.readViews(rawPlugin.contributes.views[location]);
|
|
394
|
-
contributions.views[location] = views;
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
} catch (err) {
|
|
398
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'views'.`, rawPlugin.contributes.views, err);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
try {
|
|
402
|
-
if (rawPlugin.contributes.viewsWelcome) {
|
|
403
|
-
contributions.viewsWelcome = this.readViewsWelcome(rawPlugin.contributes!.viewsWelcome, rawPlugin.contributes.views);
|
|
404
|
-
}
|
|
405
|
-
} catch (err) {
|
|
406
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'viewsWelcome'.`, rawPlugin.contributes.viewsWelcome, err);
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
try {
|
|
410
|
-
const pluginCommands = rawPlugin.contributes.commands;
|
|
411
|
-
if (pluginCommands) {
|
|
412
|
-
const commands = Array.isArray(pluginCommands) ? pluginCommands : [pluginCommands];
|
|
413
|
-
contributions.commands = commands.map(command => this.readCommand(command, rawPlugin));
|
|
414
|
-
}
|
|
415
|
-
} catch (err) {
|
|
416
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'commands'.`, rawPlugin.contributes!.commands, err);
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
try {
|
|
420
|
-
if (rawPlugin.contributes.menus) {
|
|
421
|
-
contributions.menus = {};
|
|
422
|
-
|
|
423
|
-
for (const location of Object.keys(rawPlugin.contributes.menus)) {
|
|
424
|
-
const menus = this.readMenus(rawPlugin.contributes.menus[location]);
|
|
425
|
-
contributions.menus[location] = menus;
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
} catch (err) {
|
|
429
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'menus'.`, rawPlugin.contributes.menus, err);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
try {
|
|
433
|
-
if (rawPlugin.contributes.keybindings) {
|
|
434
|
-
const rawKeybindings = Array.isArray(rawPlugin.contributes.keybindings) ? rawPlugin.contributes.keybindings : [rawPlugin.contributes.keybindings];
|
|
435
|
-
contributions.keybindings = rawKeybindings.map(rawKeybinding => this.readKeybinding(rawKeybinding));
|
|
436
|
-
}
|
|
437
|
-
} catch (err) {
|
|
438
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'keybindings'.`, rawPlugin.contributes.keybindings, err);
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
try {
|
|
442
|
-
if (rawPlugin.contributes.debuggers) {
|
|
443
|
-
const debuggers = this.readDebuggers(rawPlugin.contributes.debuggers);
|
|
444
|
-
contributions.debuggers = debuggers;
|
|
445
|
-
}
|
|
446
|
-
} catch (err) {
|
|
447
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'debuggers'.`, rawPlugin.contributes.debuggers, err);
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
try {
|
|
451
|
-
if (rawPlugin.contributes.taskDefinitions) {
|
|
452
|
-
const definitions = rawPlugin.contributes.taskDefinitions!;
|
|
453
|
-
contributions.taskDefinitions = definitions.map(definitionContribution => this.readTaskDefinition(rawPlugin.name, definitionContribution));
|
|
454
|
-
}
|
|
455
|
-
} catch (err) {
|
|
456
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'taskDefinitions'.`, rawPlugin.contributes.taskDefinitions, err);
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
try {
|
|
460
|
-
contributions.problemMatchers = rawPlugin.contributes.problemMatchers;
|
|
461
|
-
} catch (err) {
|
|
462
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'problemMatchers'.`, rawPlugin.contributes.problemMatchers, err);
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
try {
|
|
466
|
-
contributions.problemPatterns = rawPlugin.contributes.problemPatterns;
|
|
467
|
-
} catch (err) {
|
|
468
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'problemPatterns'.`, rawPlugin.contributes.problemPatterns, err);
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
try {
|
|
472
|
-
contributions.resourceLabelFormatters = rawPlugin.contributes.resourceLabelFormatters;
|
|
473
|
-
} catch (err) {
|
|
474
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'resourceLabelFormatters'.`, rawPlugin.contributes.resourceLabelFormatters, err);
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
try {
|
|
478
|
-
contributions.authentication = rawPlugin.contributes.authentication;
|
|
479
|
-
} catch (err) {
|
|
480
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'authentication'.`, rawPlugin.contributes.authentication, err);
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
try {
|
|
484
|
-
contributions.notebooks = rawPlugin.contributes.notebooks;
|
|
485
|
-
} catch (err) {
|
|
486
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'notebooks'.`, rawPlugin.contributes.notebooks, err);
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
try {
|
|
490
|
-
contributions.notebookRenderer = rawPlugin.contributes.notebookRenderer;
|
|
491
|
-
} catch (err) {
|
|
492
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'notebook-renderer'.`, rawPlugin.contributes.notebookRenderer, err);
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
try {
|
|
496
|
-
contributions.notebookPreload = rawPlugin.contributes.notebookPreload;
|
|
497
|
-
} catch (err) {
|
|
498
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'notebooks-preload'.`, rawPlugin.contributes.notebookPreload, err);
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
try {
|
|
502
|
-
contributions.snippets = this.readSnippets(rawPlugin);
|
|
503
|
-
} catch (err) {
|
|
504
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'snippets'.`, rawPlugin.contributes!.snippets, err);
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
try {
|
|
508
|
-
contributions.themes = this.readThemes(rawPlugin);
|
|
509
|
-
} catch (err) {
|
|
510
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'themes'.`, rawPlugin.contributes.themes, err);
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
try {
|
|
514
|
-
contributions.icons = this.readIcons(rawPlugin);
|
|
515
|
-
} catch (err) {
|
|
516
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'icons'.`, rawPlugin.contributes.icons, err);
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
try {
|
|
520
|
-
contributions.iconThemes = this.readIconThemes(rawPlugin);
|
|
521
|
-
} catch (err) {
|
|
522
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'iconThemes'.`, rawPlugin.contributes.iconThemes, err);
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
try {
|
|
526
|
-
contributions.colors = this.readColors(rawPlugin);
|
|
527
|
-
} catch (err) {
|
|
528
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'colors'.`, rawPlugin.contributes.colors, err);
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
try {
|
|
532
|
-
contributions.terminalProfiles = this.readTerminals(rawPlugin);
|
|
533
|
-
} catch (err) {
|
|
534
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'terminals'.`, rawPlugin.contributes.terminal, err);
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
try {
|
|
538
|
-
contributions.localizations = this.readLocalizations(rawPlugin);
|
|
539
|
-
} catch (err) {
|
|
540
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'localizations'.`, rawPlugin.contributes.localizations, err);
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
const [languagesResult, grammarsResult] = await Promise.allSettled([
|
|
544
|
-
rawPlugin.contributes.languages ? this.readLanguages(rawPlugin.contributes.languages, rawPlugin) : undefined,
|
|
545
|
-
rawPlugin.contributes.grammars ? this.grammarsReader.readGrammars(rawPlugin.contributes.grammars, rawPlugin.packagePath) : undefined
|
|
546
|
-
]);
|
|
547
|
-
|
|
548
|
-
if (rawPlugin.contributes.languages) {
|
|
549
|
-
if (languagesResult.status === 'fulfilled') {
|
|
550
|
-
contributions.languages = languagesResult.value;
|
|
551
|
-
} else {
|
|
552
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'languages'.`, rawPlugin.contributes.languages, languagesResult.reason);
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
if (rawPlugin.contributes.grammars) {
|
|
557
|
-
if (grammarsResult.status === 'fulfilled') {
|
|
558
|
-
contributions.grammars = grammarsResult.value;
|
|
559
|
-
} else {
|
|
560
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'grammars'.`, rawPlugin.contributes.grammars, grammarsResult.reason);
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
try {
|
|
565
|
-
contributions.walkthroughs = this.readWalkthroughs(rawPlugin);
|
|
566
|
-
} catch (err) {
|
|
567
|
-
this.logger.error(`Could not read '${rawPlugin.name}' contribution 'walkthroughs'.`, rawPlugin.contributes.walkthroughs, err);
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
return contributions;
|
|
269
|
+
ctx.readGrammars = (grammars, pluginPath) => this.grammarsReader.readGrammars(
|
|
270
|
+
grammars,
|
|
271
|
+
pluginPath,
|
|
272
|
+
ctx
|
|
273
|
+
);
|
|
274
|
+
return ctx;
|
|
571
275
|
}
|
|
572
276
|
|
|
573
277
|
protected readTerminals(pck: PluginPackage): TerminalProfile[] | undefined {
|
|
574
|
-
|
|
575
|
-
return undefined;
|
|
576
|
-
}
|
|
577
|
-
return pck.contributes.terminal.profiles.filter(profile => profile.id && profile.title);
|
|
278
|
+
return readTerminalsShared(pck);
|
|
578
279
|
}
|
|
579
280
|
|
|
580
281
|
protected readLocalizations(pck: PluginPackage): Localization[] | undefined {
|
|
581
|
-
|
|
582
|
-
return undefined;
|
|
583
|
-
}
|
|
584
|
-
return pck.contributes.localizations.map(e => this.readLocalization(e, pck.packagePath));
|
|
282
|
+
return readLocalizationsShared(pck, this.contributionCtx(pck));
|
|
585
283
|
}
|
|
586
284
|
|
|
587
|
-
protected readLocalization(
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
localizedLanguageName,
|
|
592
|
-
translations: []
|
|
593
|
-
};
|
|
594
|
-
local.translations = translations.map(e => this.readTranslation(e, pluginPath));
|
|
595
|
-
return local;
|
|
285
|
+
protected readLocalization(entry: PluginPackageLocalization, pluginPath: string): Localization {
|
|
286
|
+
return readLocalizationShared(entry, pluginPath, {
|
|
287
|
+
readTranslation: (translation, translationPath) => this.readTranslation(translation, translationPath),
|
|
288
|
+
});
|
|
596
289
|
}
|
|
597
290
|
|
|
598
291
|
protected readTranslation(packageTranslation: PluginPackageTranslation, pluginPath: string): Translation {
|
|
599
|
-
|
|
600
|
-
id: packageTranslation.id,
|
|
601
|
-
path: packageTranslation.path
|
|
602
|
-
};
|
|
603
|
-
return translation;
|
|
292
|
+
return readTranslationShared(packageTranslation, pluginPath);
|
|
604
293
|
}
|
|
605
294
|
|
|
606
295
|
protected readWalkthroughs(pck: PluginPackage): WalkthroughContribution[] | undefined {
|
|
607
|
-
|
|
608
|
-
return undefined;
|
|
609
|
-
}
|
|
610
|
-
const pluginId = PluginIdentifiers.componentsToUnversionedId({ publisher: pck.publisher, name: pck.name, version: pck.version });
|
|
611
|
-
// `PluginModel` does not carry the extension icon, so it travels with the walkthroughs that show it.
|
|
612
|
-
const pluginIcon = pck.icon ? this.toPluginUrl(pck, pck.icon) : undefined;
|
|
613
|
-
const result: WalkthroughContribution[] = [];
|
|
614
|
-
for (const walkthrough of pck.contributes.walkthroughs) {
|
|
615
|
-
if (typeof walkthrough.id !== 'string' || !walkthrough.id) {
|
|
616
|
-
this.logger.error(`'contributes.walkthroughs.id' of '${pluginId}' must be defined and non-empty`);
|
|
617
|
-
continue;
|
|
618
|
-
}
|
|
619
|
-
if (typeof walkthrough.title !== 'string' || !walkthrough.title) {
|
|
620
|
-
this.logger.error(`'contributes.walkthroughs.title' of '${pluginId}.${walkthrough.id}' must be defined and non-empty`);
|
|
621
|
-
continue;
|
|
622
|
-
}
|
|
623
|
-
if (!Array.isArray(walkthrough.steps)) {
|
|
624
|
-
this.logger.error(`'contributes.walkthroughs.steps' of '${pluginId}.${walkthrough.id}' must be an array`);
|
|
625
|
-
continue;
|
|
626
|
-
}
|
|
627
|
-
const steps: WalkthroughStepContribution[] = [];
|
|
628
|
-
for (const step of walkthrough.steps) {
|
|
629
|
-
if (typeof step.id !== 'string' || !step.id) {
|
|
630
|
-
this.logger.error(`'contributes.walkthroughs.steps.id' of '${pluginId}.${walkthrough.id}' must be defined and non-empty`);
|
|
631
|
-
continue;
|
|
632
|
-
}
|
|
633
|
-
if (typeof step.title !== 'string' || !step.title) {
|
|
634
|
-
this.logger.error(`'contributes.walkthroughs.steps.title' of '${pluginId}.${walkthrough.id}.${step.id}' must be defined and non-empty`);
|
|
635
|
-
continue;
|
|
636
|
-
}
|
|
637
|
-
steps.push({
|
|
638
|
-
id: step.id,
|
|
639
|
-
title: step.title,
|
|
640
|
-
description: step.description || '',
|
|
641
|
-
media: this.resolveWalkthroughMedia(pck, step.media),
|
|
642
|
-
completionEvents: step.completionEvents,
|
|
643
|
-
when: step.when
|
|
644
|
-
});
|
|
645
|
-
}
|
|
646
|
-
result.push({
|
|
647
|
-
id: walkthrough.id,
|
|
648
|
-
title: walkthrough.title,
|
|
649
|
-
description: walkthrough.description || '',
|
|
650
|
-
steps,
|
|
651
|
-
when: walkthrough.when,
|
|
652
|
-
icon: walkthrough.icon,
|
|
653
|
-
pluginId,
|
|
654
|
-
pluginIcon
|
|
655
|
-
});
|
|
656
|
-
}
|
|
657
|
-
return result.length > 0 ? result : undefined;
|
|
296
|
+
return readWalkthroughsShared(pck, this.contributionCtx(pck));
|
|
658
297
|
}
|
|
659
298
|
|
|
660
|
-
protected
|
|
661
|
-
|
|
662
|
-
return undefined;
|
|
663
|
-
}
|
|
664
|
-
if ('markdown' in media) {
|
|
665
|
-
return { markdown: this.toPluginUrl(pck, media.markdown) };
|
|
666
|
-
}
|
|
667
|
-
const altText = 'altText' in media ? media.altText as string : undefined;
|
|
668
|
-
if ('svg' in media) {
|
|
669
|
-
return { svg: this.toPluginUrl(pck, media.svg), ...(altText !== undefined && { altText }) };
|
|
670
|
-
}
|
|
671
|
-
if ('image' in media) {
|
|
672
|
-
if (typeof media.image === 'string') {
|
|
673
|
-
return { image: this.toPluginUrl(pck, media.image), ...(altText !== undefined && { altText }) };
|
|
674
|
-
}
|
|
675
|
-
// Only `dark` and `light` are mandatory; the high contrast variants fall back to them.
|
|
676
|
-
const dark = this.toPluginUrl(pck, media.image.dark);
|
|
677
|
-
const light = this.toPluginUrl(pck, media.image.light);
|
|
678
|
-
return {
|
|
679
|
-
image: {
|
|
680
|
-
dark,
|
|
681
|
-
light,
|
|
682
|
-
hc: media.image.hc ? this.toPluginUrl(pck, media.image.hc) : dark,
|
|
683
|
-
hcLight: media.image.hcLight ? this.toPluginUrl(pck, media.image.hcLight) : light
|
|
684
|
-
},
|
|
685
|
-
...(altText !== undefined && { altText })
|
|
686
|
-
};
|
|
687
|
-
}
|
|
688
|
-
return undefined;
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
protected readCommand({ command, title, shortTitle, original, category, icon, enablement }: PluginPackageCommand, pck: PluginPackage): PluginCommand {
|
|
692
|
-
const { themeIcon, iconUrl } = this.transformIconUrl(pck, icon) ?? {};
|
|
693
|
-
return { command, title, shortTitle, originalTitle: original, category, iconUrl, themeIcon, enablement };
|
|
299
|
+
protected readCommand(command: PluginPackageCommand, pck: PluginPackage): PluginCommand {
|
|
300
|
+
return readCommandShared(this.contributionCtx(pck), command, pck);
|
|
694
301
|
}
|
|
695
302
|
|
|
696
303
|
protected transformIconUrl(plugin: PluginPackage, original?: IconUrl): { iconUrl?: IconUrl; themeIcon?: string } | undefined {
|
|
697
|
-
|
|
698
|
-
if (typeof original === 'string') {
|
|
699
|
-
if (original.startsWith('$(')) {
|
|
700
|
-
return { themeIcon: original };
|
|
701
|
-
} else {
|
|
702
|
-
return { iconUrl: this.toPluginUrl(plugin, original) };
|
|
703
|
-
}
|
|
704
|
-
} else {
|
|
705
|
-
return {
|
|
706
|
-
iconUrl: {
|
|
707
|
-
light: this.toPluginUrl(plugin, original.light),
|
|
708
|
-
dark: this.toPluginUrl(plugin, original.dark)
|
|
709
|
-
}
|
|
710
|
-
};
|
|
711
|
-
}
|
|
712
|
-
}
|
|
304
|
+
return transformIconUrlShared(this.contributionCtx(plugin), plugin, original);
|
|
713
305
|
}
|
|
714
306
|
|
|
715
307
|
protected toPluginUrl(pck: PluginPackage, relativePath: string): string {
|
|
716
|
-
return
|
|
308
|
+
return toPluginUrlShared(pck, relativePath);
|
|
717
309
|
}
|
|
718
310
|
|
|
719
311
|
protected readColors(pck: PluginPackage): ColorDefinition[] | undefined {
|
|
720
|
-
|
|
721
|
-
return undefined;
|
|
722
|
-
}
|
|
723
|
-
const result: ColorDefinition[] = [];
|
|
724
|
-
for (const contribution of pck.contributes.colors) {
|
|
725
|
-
if (typeof contribution.id !== 'string' || contribution.id.length === 0) {
|
|
726
|
-
this.logger.error("'configuration.colors.id' must be defined and can not be empty");
|
|
727
|
-
continue;
|
|
728
|
-
}
|
|
729
|
-
if (!contribution.id.match(colorIdPattern)) {
|
|
730
|
-
this.logger.error("'configuration.colors.id' must follow the word[.word]*");
|
|
731
|
-
continue;
|
|
732
|
-
}
|
|
733
|
-
if (typeof contribution.description !== 'string' || contribution.id.length === 0) {
|
|
734
|
-
this.logger.error("'configuration.colors.description' must be defined and can not be empty");
|
|
735
|
-
continue;
|
|
736
|
-
}
|
|
737
|
-
const defaults = contribution.defaults;
|
|
738
|
-
if (!defaults || typeof defaults !== 'object' || typeof defaults.light !== 'string' || typeof defaults.dark !== 'string' || typeof defaults.highContrast !== 'string') {
|
|
739
|
-
this.logger.error("'configuration.colors.defaults' must be defined and must contain 'light', 'dark' and 'highContrast'");
|
|
740
|
-
continue;
|
|
741
|
-
}
|
|
742
|
-
result.push({
|
|
743
|
-
id: contribution.id,
|
|
744
|
-
description: contribution.description,
|
|
745
|
-
defaults: {
|
|
746
|
-
light: defaults.light,
|
|
747
|
-
dark: defaults.dark,
|
|
748
|
-
hc: defaults.highContrast
|
|
749
|
-
}
|
|
750
|
-
});
|
|
751
|
-
}
|
|
752
|
-
return result;
|
|
312
|
+
return readColorsShared(this.contributionCtx(pck), pck);
|
|
753
313
|
}
|
|
754
314
|
|
|
755
315
|
protected readThemes(pck: PluginPackage): ThemeContribution[] | undefined {
|
|
756
|
-
|
|
757
|
-
return undefined;
|
|
758
|
-
}
|
|
759
|
-
const result: ThemeContribution[] = [];
|
|
760
|
-
for (const contribution of pck.contributes.themes) {
|
|
761
|
-
if (contribution.path) {
|
|
762
|
-
result.push({
|
|
763
|
-
id: contribution.id,
|
|
764
|
-
uri: this.pluginUriFactory.createUri(pck, contribution.path).toString(),
|
|
765
|
-
description: contribution.description,
|
|
766
|
-
label: contribution.label,
|
|
767
|
-
uiTheme: contribution.uiTheme
|
|
768
|
-
});
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
return result;
|
|
316
|
+
return readThemesShared(this.contributionCtx(pck), pck);
|
|
772
317
|
}
|
|
773
318
|
|
|
774
319
|
protected readIconThemes(pck: PluginPackage): IconThemeContribution[] | undefined {
|
|
775
|
-
|
|
776
|
-
return undefined;
|
|
777
|
-
}
|
|
778
|
-
const result: IconThemeContribution[] = [];
|
|
779
|
-
for (const contribution of pck.contributes.iconThemes) {
|
|
780
|
-
if (typeof contribution.id !== 'string') {
|
|
781
|
-
this.logger.error('Expected string in `contributes.iconThemes.id`. Provided value:', contribution.id);
|
|
782
|
-
continue;
|
|
783
|
-
}
|
|
784
|
-
if (typeof contribution.path !== 'string') {
|
|
785
|
-
this.logger.error('Expected string in `contributes.iconThemes.path`. Provided value:', contribution.path);
|
|
786
|
-
continue;
|
|
787
|
-
}
|
|
788
|
-
result.push({
|
|
789
|
-
id: contribution.id,
|
|
790
|
-
uri: this.pluginUriFactory.createUri(pck, contribution.path).toString(),
|
|
791
|
-
description: contribution.description,
|
|
792
|
-
label: contribution.label,
|
|
793
|
-
uiTheme: contribution.uiTheme
|
|
794
|
-
});
|
|
795
|
-
}
|
|
796
|
-
return result;
|
|
320
|
+
return readIconThemesShared(this.contributionCtx(pck), pck);
|
|
797
321
|
}
|
|
798
322
|
|
|
799
323
|
protected readIcons(pck: PluginPackage): IconContribution[] | undefined {
|
|
800
|
-
|
|
801
|
-
return undefined;
|
|
802
|
-
}
|
|
803
|
-
const result: IconContribution[] = [];
|
|
804
|
-
const iconEntries = <PluginIconContribution>(<unknown>pck.contributes.icons);
|
|
805
|
-
for (const id in iconEntries) {
|
|
806
|
-
if (pck.contributes.icons.hasOwnProperty(id)) {
|
|
807
|
-
if (!id.match(iconIdPattern)) {
|
|
808
|
-
this.logger.error("'configuration.icons' keys represent the icon id and can only contain letter, digits and minuses. " +
|
|
809
|
-
'They need to consist of at least two segments in the form `component-iconname`.', 'extension: ', pck.name, 'icon id: ', id);
|
|
810
|
-
return;
|
|
811
|
-
}
|
|
812
|
-
const iconContribution = iconEntries[id];
|
|
813
|
-
if (typeof iconContribution.description !== 'string' || iconContribution.description['length'] === 0) {
|
|
814
|
-
this.logger.error('configuration.icons.description must be defined and can not be empty, ', 'extension: ', pck.name, 'icon id: ', id);
|
|
815
|
-
return;
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
const defaultIcon = iconContribution.default;
|
|
819
|
-
if (typeof defaultIcon === 'string') {
|
|
820
|
-
result.push({
|
|
821
|
-
id,
|
|
822
|
-
extensionId: pck.publisher + '.' + pck.name,
|
|
823
|
-
description: iconContribution.description,
|
|
824
|
-
defaults: { id: defaultIcon }
|
|
825
|
-
});
|
|
826
|
-
} else if (typeof defaultIcon === 'object' && typeof defaultIcon.fontPath === 'string' && typeof defaultIcon.fontCharacter === 'string') {
|
|
827
|
-
const format = getFileExtension(defaultIcon.fontPath);
|
|
828
|
-
if (['woff', 'woff2', 'ttf'].indexOf(format) === -1) {
|
|
829
|
-
this.logger.warn("Expected `contributes.icons.default.fontPath` to have file extension 'woff', woff2' or 'ttf', is '{0}'.", format);
|
|
830
|
-
return;
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
const iconFontLocation = this.pluginUriFactory.createUri(pck, defaultIcon.fontPath).toString();
|
|
834
|
-
result.push({
|
|
835
|
-
id,
|
|
836
|
-
extensionId: pck.publisher + '.' + pck.name,
|
|
837
|
-
description: iconContribution.description,
|
|
838
|
-
defaults: {
|
|
839
|
-
fontCharacter: defaultIcon.fontCharacter,
|
|
840
|
-
location: iconFontLocation
|
|
841
|
-
}
|
|
842
|
-
});
|
|
843
|
-
} else {
|
|
844
|
-
this.logger.error("'configuration.icons.default' must be either a reference to the id of an other theme icon (string) or a icon definition (object) with ",
|
|
845
|
-
'properties `fontPath` and `fontCharacter`.');
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
return result;
|
|
324
|
+
return readIconsShared(this.contributionCtx(pck), pck);
|
|
850
325
|
}
|
|
851
326
|
|
|
852
327
|
protected readSnippets(pck: PluginPackage): SnippetContribution[] | undefined {
|
|
853
|
-
|
|
854
|
-
return undefined;
|
|
855
|
-
}
|
|
856
|
-
const result: SnippetContribution[] = [];
|
|
857
|
-
for (const contribution of pck.contributes.snippets) {
|
|
858
|
-
if (contribution.path) {
|
|
859
|
-
result.push({
|
|
860
|
-
language: contribution.language,
|
|
861
|
-
source: pck.displayName || pck.name,
|
|
862
|
-
uri: this.pluginUriFactory.createUri(pck, contribution.path).toString()
|
|
863
|
-
});
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
return result;
|
|
328
|
+
return readSnippetsShared(this.contributionCtx(pck), pck);
|
|
867
329
|
}
|
|
868
330
|
|
|
869
|
-
protected
|
|
870
|
-
|
|
871
|
-
return content ? jsoncparser.parse(content, undefined, { disallowComments: false }) : undefined;
|
|
872
|
-
}
|
|
873
|
-
protected async readFile(filePath: string): Promise<string> {
|
|
874
|
-
try {
|
|
875
|
-
const content = await fs.readFile(filePath, { encoding: 'utf8' });
|
|
876
|
-
return content;
|
|
877
|
-
} catch (e) {
|
|
878
|
-
if (!isENOENT(e)) {
|
|
879
|
-
this.logger.error(e);
|
|
880
|
-
}
|
|
881
|
-
return '';
|
|
882
|
-
}
|
|
331
|
+
protected readConfiguration(rawConfiguration: IConfigurationNode, pluginPath: string): PreferenceSchema | undefined {
|
|
332
|
+
return readConfigurationShared(rawConfiguration, pluginPath);
|
|
883
333
|
}
|
|
884
334
|
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
const { scope, overridable } = TheiaPluginScanner.getScope(rawConfiguration.scope);
|
|
888
|
-
const schema: PreferenceSchema = {
|
|
889
|
-
scope,
|
|
890
|
-
defaultOverridable: overridable,
|
|
891
|
-
title: rawConfiguration.title,
|
|
892
|
-
properties: {}
|
|
893
|
-
};
|
|
894
|
-
|
|
895
|
-
if (rawConfiguration.properties) {
|
|
896
|
-
for (const [key, property] of Object.entries(rawConfiguration.properties)) {
|
|
897
|
-
const scopeInfo = TheiaPluginScanner.getScope(property.scope);
|
|
898
|
-
const schemaProperty: PreferenceDataProperty = {
|
|
899
|
-
...property,
|
|
900
|
-
scope: scopeInfo.scope,
|
|
901
|
-
overridable: scopeInfo.overridable,
|
|
902
|
-
default: property.default !== undefined ? property.default : deriveDefaultForType(property.type)
|
|
903
|
-
};
|
|
904
|
-
|
|
905
|
-
schema.properties[key] = schemaProperty;
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
return schema;
|
|
335
|
+
protected readKeybinding(rawKeybinding: PluginPackageKeybinding): Keybinding {
|
|
336
|
+
return readKeybindingShared(rawKeybinding);
|
|
909
337
|
}
|
|
910
338
|
|
|
911
|
-
|
|
912
|
-
return {
|
|
913
|
-
keybinding: rawKeybinding.key,
|
|
914
|
-
command: rawKeybinding.command,
|
|
915
|
-
when: rawKeybinding.when,
|
|
916
|
-
mac: rawKeybinding.mac,
|
|
917
|
-
linux: rawKeybinding.linux,
|
|
918
|
-
win: rawKeybinding.win,
|
|
919
|
-
args: rawKeybinding.args
|
|
920
|
-
};
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
private readCustomEditors(rawCustomEditors: PluginPackageCustomEditor[]): CustomEditor[] {
|
|
339
|
+
protected readCustomEditors(rawCustomEditors: PluginPackageCustomEditor[]): CustomEditor[] {
|
|
924
340
|
return rawCustomEditors.map(rawCustomEditor => this.readCustomEditor(rawCustomEditor));
|
|
925
341
|
}
|
|
926
342
|
|
|
927
|
-
|
|
928
|
-
return
|
|
929
|
-
viewType: rawCustomEditor.viewType,
|
|
930
|
-
displayName: rawCustomEditor.displayName,
|
|
931
|
-
selector: rawCustomEditor.selector || [],
|
|
932
|
-
priority: rawCustomEditor.priority || CustomEditorPriority.default
|
|
933
|
-
};
|
|
343
|
+
protected readCustomEditor(rawCustomEditor: PluginPackageCustomEditor): CustomEditor {
|
|
344
|
+
return readCustomEditorShared(rawCustomEditor);
|
|
934
345
|
}
|
|
935
346
|
|
|
936
|
-
|
|
937
|
-
return rawViewsContainers
|
|
347
|
+
protected readViewsContainers(rawViewsContainers: readonly PluginPackageViewContainer[], pck: PluginPackage): ViewContainer[] {
|
|
348
|
+
return rawViewsContainers
|
|
349
|
+
.map(rawViewContainer => this.readViewContainer(rawViewContainer, pck))
|
|
350
|
+
.filter((container): container is ViewContainer => container !== undefined);
|
|
938
351
|
}
|
|
939
352
|
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
const iconUrl = this.toPluginUrl(pck, rawViewContainer.icon);
|
|
943
|
-
return {
|
|
944
|
-
id: rawViewContainer.id,
|
|
945
|
-
title: rawViewContainer.title,
|
|
946
|
-
iconUrl,
|
|
947
|
-
themeIcon,
|
|
948
|
-
when: rawViewContainer.when,
|
|
949
|
-
};
|
|
353
|
+
protected readViewContainer(rawViewContainer: PluginPackageViewContainer, pck: PluginPackage): ViewContainer | undefined {
|
|
354
|
+
return readViewContainerShared(this.contributionCtx(pck), rawViewContainer, pck);
|
|
950
355
|
}
|
|
951
356
|
|
|
952
|
-
|
|
357
|
+
protected readViews(rawViews: PluginPackageView[]): View[] {
|
|
953
358
|
return rawViews.map(rawView => this.readView(rawView));
|
|
954
359
|
}
|
|
955
360
|
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
id: rawView.id,
|
|
959
|
-
name: rawView.name,
|
|
960
|
-
when: rawView.when,
|
|
961
|
-
type: rawView.type
|
|
962
|
-
};
|
|
963
|
-
|
|
964
|
-
return result;
|
|
361
|
+
protected readView(rawView: PluginPackageView): View {
|
|
362
|
+
return readViewShared(rawView);
|
|
965
363
|
}
|
|
966
364
|
|
|
967
|
-
|
|
365
|
+
protected readViewsWelcome(rawViewsWelcome: readonly PluginPackageViewWelcome[], rowViews: { [location: string]: readonly PluginPackageView[]; } | undefined): ViewWelcome[] {
|
|
968
366
|
return rawViewsWelcome.map(rawViewWelcome => this.readViewWelcome(rawViewWelcome, this.extractPluginViewsIds(rowViews)));
|
|
969
367
|
}
|
|
970
368
|
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
view: rawViewWelcome.view,
|
|
974
|
-
content: rawViewWelcome.contents,
|
|
975
|
-
when: rawViewWelcome.when,
|
|
976
|
-
enablement: rawViewWelcome.enablement,
|
|
977
|
-
// if the plugin contributes Welcome view to its own view - it will be ordered first
|
|
978
|
-
order: pluginViewsIds.findIndex(v => v === rawViewWelcome.view) > -1 ? 0 : 1
|
|
979
|
-
};
|
|
980
|
-
|
|
981
|
-
return result;
|
|
369
|
+
protected readViewWelcome(rawViewWelcome: PluginPackageViewWelcome, pluginViewsIds: string[]): ViewWelcome {
|
|
370
|
+
return readViewWelcomeShared(rawViewWelcome, pluginViewsIds);
|
|
982
371
|
}
|
|
983
372
|
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
if (views) {
|
|
987
|
-
for (const location of Object.keys(views)) {
|
|
988
|
-
const viewsIds = views[location].map(view => view.id);
|
|
989
|
-
pluginViewsIds.push(...viewsIds);
|
|
990
|
-
};
|
|
991
|
-
}
|
|
992
|
-
return pluginViewsIds;
|
|
373
|
+
protected extractPluginViewsIds(views: { [location: string]: readonly PluginPackageView[] } | undefined): string[] {
|
|
374
|
+
return extractPluginViewsIdsShared(views);
|
|
993
375
|
}
|
|
994
376
|
|
|
995
|
-
|
|
377
|
+
protected readMenus(rawMenus: readonly PluginPackageMenu[]): Menu[] {
|
|
996
378
|
return rawMenus.map(rawMenu => this.readMenu(rawMenu));
|
|
997
379
|
}
|
|
998
380
|
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
command: rawMenu.command,
|
|
1002
|
-
submenu: rawMenu.submenu,
|
|
1003
|
-
alt: rawMenu.alt,
|
|
1004
|
-
group: rawMenu.group,
|
|
1005
|
-
when: rawMenu.when
|
|
1006
|
-
};
|
|
1007
|
-
return result;
|
|
381
|
+
protected readMenu(rawMenu: PluginPackageMenu): Menu {
|
|
382
|
+
return readMenuShared(rawMenu);
|
|
1008
383
|
}
|
|
1009
384
|
|
|
1010
|
-
|
|
385
|
+
protected async readLanguages(rawLanguages: readonly PluginPackageLanguageContribution[], plugin: PluginPackage): Promise<LanguageContribution[]> {
|
|
1011
386
|
return Promise.all(rawLanguages.map(language => this.readLanguage(language, plugin)));
|
|
1012
387
|
}
|
|
1013
388
|
|
|
1014
|
-
|
|
389
|
+
protected readSubmenus(rawSubmenus: readonly PluginPackageSubmenu[], plugin: PluginPackage): Submenu[] {
|
|
1015
390
|
return rawSubmenus.map(submenu => this.readSubmenu(submenu, plugin));
|
|
1016
391
|
}
|
|
1017
392
|
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
return {
|
|
1021
|
-
icon: icon?.iconUrl ?? icon?.themeIcon,
|
|
1022
|
-
id: rawSubmenu.id,
|
|
1023
|
-
label: rawSubmenu.label
|
|
1024
|
-
};
|
|
1025
|
-
|
|
393
|
+
protected readSubmenu(rawSubmenu: PluginPackageSubmenu, plugin: PluginPackage): Submenu {
|
|
394
|
+
return readSubmenuShared(this.contributionCtx(plugin), rawSubmenu, plugin);
|
|
1026
395
|
}
|
|
1027
396
|
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
const icon = this.transformIconUrl(plugin, rawLang.icon);
|
|
1031
|
-
const result: LanguageContribution = {
|
|
1032
|
-
id: rawLang.id,
|
|
1033
|
-
aliases: rawLang.aliases,
|
|
1034
|
-
extensions: rawLang.extensions,
|
|
1035
|
-
filenamePatterns: rawLang.filenamePatterns,
|
|
1036
|
-
filenames: rawLang.filenames,
|
|
1037
|
-
firstLine: rawLang.firstLine,
|
|
1038
|
-
mimetypes: rawLang.mimetypes,
|
|
1039
|
-
icon: icon?.iconUrl ?? icon?.themeIcon
|
|
1040
|
-
};
|
|
1041
|
-
if (rawLang.configuration) {
|
|
1042
|
-
const rawConfiguration = await this.readJson<PluginPackageLanguageContributionConfiguration>(path.resolve(plugin.packagePath, rawLang.configuration));
|
|
1043
|
-
if (rawConfiguration) {
|
|
1044
|
-
const configuration: LanguageConfiguration = {
|
|
1045
|
-
brackets: rawConfiguration.brackets,
|
|
1046
|
-
comments: rawConfiguration.comments,
|
|
1047
|
-
folding: rawConfiguration.folding,
|
|
1048
|
-
wordPattern: rawConfiguration.wordPattern,
|
|
1049
|
-
autoClosingPairs: this.extractValidAutoClosingPairs(rawLang.id, rawConfiguration),
|
|
1050
|
-
indentationRules: rawConfiguration.indentationRules,
|
|
1051
|
-
surroundingPairs: this.extractValidSurroundingPairs(rawLang.id, rawConfiguration),
|
|
1052
|
-
onEnterRules: rawConfiguration.onEnterRules,
|
|
1053
|
-
};
|
|
1054
|
-
result.configuration = configuration;
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
return result;
|
|
1058
|
-
|
|
397
|
+
protected async readLanguage(rawLang: PluginPackageLanguageContribution, plugin: PluginPackage): Promise<LanguageContribution> {
|
|
398
|
+
return readLanguageShared(this.contributionCtx(plugin), rawLang, plugin);
|
|
1059
399
|
}
|
|
1060
400
|
|
|
1061
|
-
|
|
1062
|
-
return rawDebuggers.map(
|
|
401
|
+
protected readDebuggers(rawDebuggers: PluginPackageDebuggersContribution[]): DebuggerContribution[] {
|
|
402
|
+
return rawDebuggers.map(rawDebugger => this.readDebugger(rawDebugger));
|
|
1063
403
|
}
|
|
1064
404
|
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
type: rawDebugger.type,
|
|
1068
|
-
label: rawDebugger.label,
|
|
1069
|
-
languages: rawDebugger.languages,
|
|
1070
|
-
enableBreakpointsFor: rawDebugger.enableBreakpointsFor,
|
|
1071
|
-
variables: rawDebugger.variables,
|
|
1072
|
-
adapterExecutableCommand: rawDebugger.adapterExecutableCommand,
|
|
1073
|
-
configurationSnippets: rawDebugger.configurationSnippets,
|
|
1074
|
-
win: rawDebugger.win,
|
|
1075
|
-
winx86: rawDebugger.winx86,
|
|
1076
|
-
windows: rawDebugger.windows,
|
|
1077
|
-
osx: rawDebugger.osx,
|
|
1078
|
-
linux: rawDebugger.linux,
|
|
1079
|
-
program: rawDebugger.program,
|
|
1080
|
-
args: rawDebugger.args,
|
|
1081
|
-
runtime: rawDebugger.runtime,
|
|
1082
|
-
runtimeArgs: rawDebugger.runtimeArgs,
|
|
1083
|
-
configurationAttributes: rawDebugger.configurationAttributes
|
|
1084
|
-
};
|
|
1085
|
-
|
|
1086
|
-
return result;
|
|
405
|
+
protected readDebugger(rawDebugger: PluginPackageDebuggersContribution): DebuggerContribution {
|
|
406
|
+
return readDebuggerShared(rawDebugger);
|
|
1087
407
|
}
|
|
1088
408
|
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
taskType: definitionContribution.type,
|
|
1094
|
-
source: pluginName,
|
|
1095
|
-
properties: {
|
|
1096
|
-
required: definitionContribution.required || [],
|
|
1097
|
-
all: propertyKeys,
|
|
1098
|
-
schema
|
|
1099
|
-
}
|
|
1100
|
-
};
|
|
409
|
+
protected readTaskDefinition(pluginName: string, definitionContribution: PluginTaskDefinitionContribution): TaskDefinition {
|
|
410
|
+
return readTaskDefinitionShared(pluginName, definitionContribution, {
|
|
411
|
+
toSchema: definition => this.toSchema(definition)
|
|
412
|
+
});
|
|
1101
413
|
}
|
|
1102
414
|
|
|
1103
415
|
protected toSchema(definition: PluginTaskDefinitionContribution): IJSONSchema {
|
|
1104
|
-
|
|
1105
|
-
const schema = deepClone(reconciliation);
|
|
1106
|
-
if (schema.properties === undefined) {
|
|
1107
|
-
schema.properties = Object.create(null);
|
|
1108
|
-
}
|
|
1109
|
-
schema.type = 'object';
|
|
1110
|
-
schema.properties!.type = { type: 'string', const: definition.type };
|
|
1111
|
-
return schema;
|
|
416
|
+
return toSchemaShared(definition);
|
|
1112
417
|
}
|
|
1113
418
|
|
|
1114
|
-
|
|
1115
|
-
const
|
|
1116
|
-
|
|
1117
|
-
return undefined;
|
|
1118
|
-
}
|
|
1119
|
-
if (!Array.isArray(source)) {
|
|
1120
|
-
this.logger.warn(`[${langId}]: language configuration: expected \`autoClosingPairs\` to be an array.`);
|
|
1121
|
-
return undefined;
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
let result: AutoClosingPairConditional[] | undefined = undefined;
|
|
1125
|
-
for (let i = 0, len = source.length; i < len; i++) {
|
|
1126
|
-
const pair = source[i];
|
|
1127
|
-
if (Array.isArray(pair)) {
|
|
1128
|
-
if (!isCharacterPair(pair)) {
|
|
1129
|
-
this.logger.warn(`[${langId}]: language configuration: expected \`autoClosingPairs[${i}]\` to be an array of two strings or an object.`);
|
|
1130
|
-
continue;
|
|
1131
|
-
}
|
|
1132
|
-
result = result || [];
|
|
1133
|
-
result.push({ open: pair[0], close: pair[1] });
|
|
1134
|
-
} else {
|
|
1135
|
-
if (!isObject(pair)) {
|
|
1136
|
-
this.logger.warn(`[${langId}]: language configuration: expected \`autoClosingPairs[${i}]\` to be an array of two strings or an object.`);
|
|
1137
|
-
continue;
|
|
1138
|
-
}
|
|
1139
|
-
if (typeof pair.open !== 'string') {
|
|
1140
|
-
this.logger.warn(`[${langId}]: language configuration: expected \`autoClosingPairs[${i}].open\` to be a string.`);
|
|
1141
|
-
continue;
|
|
1142
|
-
}
|
|
1143
|
-
if (typeof pair.close !== 'string') {
|
|
1144
|
-
this.logger.warn(`[${langId}]: language configuration: expected \`autoClosingPairs[${i}].close\` to be a string.`);
|
|
1145
|
-
continue;
|
|
1146
|
-
}
|
|
1147
|
-
if (typeof pair.notIn !== 'undefined') {
|
|
1148
|
-
if (!isStringArray(pair.notIn)) {
|
|
1149
|
-
this.logger.warn(`[${langId}]: language configuration: expected \`autoClosingPairs[${i}].notIn\` to be a string array.`);
|
|
1150
|
-
continue;
|
|
1151
|
-
}
|
|
1152
|
-
}
|
|
1153
|
-
result = result || [];
|
|
1154
|
-
result.push({ open: pair.open, close: pair.close, notIn: pair.notIn });
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
return result;
|
|
419
|
+
protected async readJson<T>(filePath: string): Promise<T | undefined> {
|
|
420
|
+
const content = await this.readFile(filePath);
|
|
421
|
+
return content ? jsoncparser.parse(content, undefined, { disallowComments: false }) : undefined;
|
|
1158
422
|
}
|
|
1159
423
|
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
return
|
|
1164
|
-
}
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
return undefined;
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
|
-
let result: AutoClosingPair[] | undefined = undefined;
|
|
1171
|
-
for (let i = 0, len = source.length; i < len; i++) {
|
|
1172
|
-
const pair = source[i];
|
|
1173
|
-
if (Array.isArray(pair)) {
|
|
1174
|
-
if (!isCharacterPair(pair)) {
|
|
1175
|
-
this.logger.warn(`[${langId}]: language configuration: expected \`surroundingPairs[${i}]\` to be an array of two strings or an object.`);
|
|
1176
|
-
continue;
|
|
1177
|
-
}
|
|
1178
|
-
result = result || [];
|
|
1179
|
-
result.push({ open: pair[0], close: pair[1] });
|
|
1180
|
-
} else {
|
|
1181
|
-
if (!isObject(pair)) {
|
|
1182
|
-
this.logger.warn(`[${langId}]: language configuration: expected \`surroundingPairs[${i}]\` to be an array of two strings or an object.`);
|
|
1183
|
-
continue;
|
|
1184
|
-
}
|
|
1185
|
-
if (typeof pair.open !== 'string') {
|
|
1186
|
-
this.logger.warn(`[${langId}]: language configuration: expected \`surroundingPairs[${i}].open\` to be a string.`);
|
|
1187
|
-
continue;
|
|
1188
|
-
}
|
|
1189
|
-
if (typeof pair.close !== 'string') {
|
|
1190
|
-
this.logger.warn(`[${langId}]: language configuration: expected \`surroundingPairs[${i}].close\` to be a string.`);
|
|
1191
|
-
continue;
|
|
1192
|
-
}
|
|
1193
|
-
result = result || [];
|
|
1194
|
-
result.push({ open: pair.open, close: pair.close });
|
|
424
|
+
protected async readFile(filePath: string): Promise<string> {
|
|
425
|
+
try {
|
|
426
|
+
const content = await fs.readFile(filePath, { encoding: 'utf8' });
|
|
427
|
+
return content;
|
|
428
|
+
} catch (e) {
|
|
429
|
+
if (!isENOENT(e)) {
|
|
430
|
+
this.logger.error(e);
|
|
1195
431
|
}
|
|
432
|
+
return '';
|
|
1196
433
|
}
|
|
1197
|
-
return result;
|
|
1198
434
|
}
|
|
1199
|
-
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
function isCharacterPair(something: CharacterPair): boolean {
|
|
1203
|
-
return (
|
|
1204
|
-
isStringArray(something)
|
|
1205
|
-
&& something.length === 2
|
|
1206
|
-
);
|
|
1207
435
|
}
|