@theia/plugin-utils 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/README.md +30 -0
- package/lib/common/constants.d.ts +12 -0
- package/lib/common/constants.d.ts.map +1 -0
- package/lib/common/constants.js +30 -0
- package/lib/common/constants.js.map +1 -0
- package/lib/common/constants.spec.d.ts +2 -0
- package/lib/common/constants.spec.d.ts.map +1 -0
- package/lib/common/constants.spec.js +33 -0
- package/lib/common/constants.spec.js.map +1 -0
- package/lib/common/contribution-types.d.ts +648 -0
- package/lib/common/contribution-types.d.ts.map +1 -0
- package/lib/common/contribution-types.js +30 -0
- package/lib/common/contribution-types.js.map +1 -0
- package/lib/common/manifest-types.d.ts +105 -0
- package/lib/common/manifest-types.d.ts.map +1 -0
- package/lib/common/manifest-types.js +31 -0
- package/lib/common/manifest-types.js.map +1 -0
- package/lib/common/manifest-types.spec.d.ts +2 -0
- package/lib/common/manifest-types.spec.d.ts.map +1 -0
- package/lib/common/manifest-types.spec.js +35 -0
- package/lib/common/manifest-types.spec.js.map +1 -0
- package/lib/common/package-nls.d.ts +24 -0
- package/lib/common/package-nls.d.ts.map +1 -0
- package/lib/common/package-nls.js +82 -0
- package/lib/common/package-nls.js.map +1 -0
- package/lib/common/package-nls.spec.d.ts +2 -0
- package/lib/common/package-nls.spec.d.ts.map +1 -0
- package/lib/common/package-nls.spec.js +98 -0
- package/lib/common/package-nls.spec.js.map +1 -0
- package/lib/common/plugin-activation-events.d.ts +7 -0
- package/lib/common/plugin-activation-events.d.ts.map +1 -0
- package/lib/common/plugin-activation-events.js +95 -0
- package/lib/common/plugin-activation-events.js.map +1 -0
- package/lib/common/plugin-activation-events.spec.d.ts +2 -0
- package/lib/common/plugin-activation-events.spec.d.ts.map +1 -0
- package/lib/common/plugin-activation-events.spec.js +89 -0
- package/lib/common/plugin-activation-events.spec.js.map +1 -0
- package/lib/common/plugin-manifest.d.ts +10 -0
- package/lib/common/plugin-manifest.d.ts.map +1 -0
- package/lib/common/plugin-manifest.js +35 -0
- package/lib/common/plugin-manifest.js.map +1 -0
- package/lib/common/plugin-manifest.spec.d.ts +2 -0
- package/lib/common/plugin-manifest.spec.d.ts.map +1 -0
- package/lib/common/plugin-manifest.spec.js +83 -0
- package/lib/common/plugin-manifest.spec.js.map +1 -0
- package/lib/common/plugin-model.d.ts +33 -0
- package/lib/common/plugin-model.d.ts.map +1 -0
- package/lib/common/plugin-model.js +166 -0
- package/lib/common/plugin-model.js.map +1 -0
- package/lib/common/plugin-model.spec.d.ts +2 -0
- package/lib/common/plugin-model.spec.d.ts.map +1 -0
- package/lib/common/plugin-model.spec.js +204 -0
- package/lib/common/plugin-model.spec.js.map +1 -0
- package/lib/common/protocol-shims.d.ts +128 -0
- package/lib/common/protocol-shims.d.ts.map +1 -0
- package/lib/common/protocol-shims.js +29 -0
- package/lib/common/protocol-shims.js.map +1 -0
- package/lib/common/test-helpers.d.ts +5 -0
- package/lib/common/test-helpers.d.ts.map +1 -0
- package/lib/common/test-helpers.js +41 -0
- package/lib/common/test-helpers.js.map +1 -0
- package/lib/common/utils.d.ts +20 -0
- package/lib/common/utils.d.ts.map +1 -0
- package/lib/common/utils.js +74 -0
- package/lib/common/utils.js.map +1 -0
- package/lib/common/utils.spec.d.ts +2 -0
- package/lib/common/utils.spec.d.ts.map +1 -0
- package/lib/common/utils.spec.js +77 -0
- package/lib/common/utils.spec.js.map +1 -0
- package/lib/node/normalize-contributions.d.ts +54 -0
- package/lib/node/normalize-contributions.d.ts.map +1 -0
- package/lib/node/normalize-contributions.js +985 -0
- package/lib/node/normalize-contributions.js.map +1 -0
- package/lib/node/normalize-contributions.spec.d.ts +2 -0
- package/lib/node/normalize-contributions.spec.d.ts.map +1 -0
- package/lib/node/normalize-contributions.spec.js +850 -0
- package/lib/node/normalize-contributions.spec.js.map +1 -0
- package/lib/node/package-nls.d.ts +3 -0
- package/lib/node/package-nls.d.ts.map +1 -0
- package/lib/node/package-nls.js +45 -0
- package/lib/node/package-nls.js.map +1 -0
- package/lib/node/plugin-manifest.d.ts +6 -0
- package/lib/node/plugin-manifest.d.ts.map +1 -0
- package/lib/node/plugin-manifest.js +26 -0
- package/lib/node/plugin-manifest.js.map +1 -0
- package/lib/node/plugin-model.d.ts +5 -0
- package/lib/node/plugin-model.d.ts.map +1 -0
- package/lib/node/plugin-model.js +36 -0
- package/lib/node/plugin-model.js.map +1 -0
- package/lib/node/read-grammars.d.ts +10 -0
- package/lib/node/read-grammars.d.ts.map +1 -0
- package/lib/node/read-grammars.js +83 -0
- package/lib/node/read-grammars.js.map +1 -0
- package/lib/node/read-grammars.spec.d.ts +2 -0
- package/lib/node/read-grammars.spec.d.ts.map +1 -0
- package/lib/node/read-grammars.spec.js +109 -0
- package/lib/node/read-grammars.spec.js.map +1 -0
- package/package.json +42 -0
- package/src/common/constants.spec.ts +34 -0
- package/src/common/constants.ts +35 -0
- package/src/common/contribution-types.ts +677 -0
- package/src/common/manifest-types.spec.ts +36 -0
- package/src/common/manifest-types.ts +126 -0
- package/src/common/package-nls.spec.ts +122 -0
- package/src/common/package-nls.ts +95 -0
- package/src/common/plugin-activation-events.spec.ts +104 -0
- package/src/common/plugin-activation-events.ts +102 -0
- package/src/common/plugin-manifest.spec.ts +94 -0
- package/src/common/plugin-manifest.ts +44 -0
- package/src/common/plugin-model.spec.ts +246 -0
- package/src/common/plugin-model.ts +194 -0
- package/src/common/protocol-shims.ts +148 -0
- package/src/common/test-helpers.ts +44 -0
- package/src/common/utils.spec.ts +86 -0
- package/src/common/utils.ts +81 -0
- package/src/node/normalize-contributions.spec.ts +931 -0
- package/src/node/normalize-contributions.ts +1098 -0
- package/src/node/package-nls.ts +45 -0
- package/src/node/plugin-manifest.ts +30 -0
- package/src/node/plugin-model.ts +33 -0
- package/src/node/read-grammars.spec.ts +128 -0
- package/src/node/read-grammars.ts +97 -0
|
@@ -0,0 +1,1098 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2015-2021 Red Hat, Inc.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
/* eslint-disable @theia/localization-check */
|
|
18
|
+
|
|
19
|
+
import { promises as fs } from 'fs';
|
|
20
|
+
import * as path from 'path';
|
|
21
|
+
import * as jsoncparser from 'jsonc-parser';
|
|
22
|
+
import { deepClone, isColorDefaults, isENOENT, isObject, isStringArray } from '../common/utils';
|
|
23
|
+
import {
|
|
24
|
+
ICON_NAME_SEGMENT,
|
|
25
|
+
type ColorDefinition,
|
|
26
|
+
type IJSONSchema,
|
|
27
|
+
type JsonType,
|
|
28
|
+
type JSONValue,
|
|
29
|
+
type PreferenceDataProperty,
|
|
30
|
+
type PreferenceSchema,
|
|
31
|
+
PreferenceScope,
|
|
32
|
+
type TaskDefinition,
|
|
33
|
+
} from '../common/protocol-shims';
|
|
34
|
+
import {
|
|
35
|
+
CustomEditorPriority,
|
|
36
|
+
type AutoClosingPair,
|
|
37
|
+
type AutoClosingPairConditional,
|
|
38
|
+
type CharacterPair,
|
|
39
|
+
type CommentRule,
|
|
40
|
+
type FoldingRules,
|
|
41
|
+
type IconUrl,
|
|
42
|
+
type IConfigurationNode,
|
|
43
|
+
type IndentationRules,
|
|
44
|
+
type NormalizeContributionsContext,
|
|
45
|
+
type NormalizedCommand,
|
|
46
|
+
type NormalizedCustomEditor,
|
|
47
|
+
type NormalizedIcon,
|
|
48
|
+
type NormalizedIconTheme,
|
|
49
|
+
type NormalizedKeybinding,
|
|
50
|
+
type NormalizedLanguage,
|
|
51
|
+
type NormalizedLanguageConfiguration,
|
|
52
|
+
type NormalizedLocalization,
|
|
53
|
+
type NormalizedPluginContribution,
|
|
54
|
+
type NormalizedSnippet,
|
|
55
|
+
type NormalizedSubmenu,
|
|
56
|
+
type NormalizedTerminalProfile,
|
|
57
|
+
type NormalizedTheme,
|
|
58
|
+
type NormalizedTranslation,
|
|
59
|
+
type NormalizedViewContainer,
|
|
60
|
+
type NormalizedViewWelcome,
|
|
61
|
+
type PluginUiTheme,
|
|
62
|
+
type RawCommand,
|
|
63
|
+
type RawCustomEditor,
|
|
64
|
+
type RawDebugger,
|
|
65
|
+
type RawKeybinding,
|
|
66
|
+
type RawLanguage,
|
|
67
|
+
type RawLocalization,
|
|
68
|
+
type RawMenu,
|
|
69
|
+
type RawSubmenu,
|
|
70
|
+
type RawTaskDefinition,
|
|
71
|
+
type RawTranslation,
|
|
72
|
+
type RawView,
|
|
73
|
+
type RawViewContainer,
|
|
74
|
+
type RawViewWelcome,
|
|
75
|
+
type ViewsByLocation,
|
|
76
|
+
type WalkthroughContribution,
|
|
77
|
+
type WalkthroughStepContribution,
|
|
78
|
+
type WalkthroughStepMedia,
|
|
79
|
+
type PluginPackageWalkthroughStepMedia,
|
|
80
|
+
} from '../common/contribution-types';
|
|
81
|
+
import { rawContributes, type PluginManifest } from '../common/manifest-types';
|
|
82
|
+
import { UNPUBLISHED } from '../common/constants';
|
|
83
|
+
|
|
84
|
+
function isPluginUiTheme(value: unknown): value is PluginUiTheme {
|
|
85
|
+
return value === 'vs' || value === 'vs-dark' || value === 'hc-black';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export const colorIdPattern = '^\\w+[.\\w+]*$';
|
|
89
|
+
export const iconIdPattern = `^${ICON_NAME_SEGMENT}(-${ICON_NAME_SEGMENT})+$`;
|
|
90
|
+
|
|
91
|
+
/** Maps the view container locations used by VS Code extensions to the Theia shell locations. */
|
|
92
|
+
export const VIEW_CONTAINER_LOCATION_ALIASES: Record<string, string> = {
|
|
93
|
+
activitybar: 'left',
|
|
94
|
+
panel: 'bottom',
|
|
95
|
+
secondarySidebar: 'right',
|
|
96
|
+
auxiliarybar: 'right'
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Mirrors VS Code's `ConfigurationRegistry.getDefaultValue(type)`: plugins expect typed-but-defaultless properties to read as a type-based default.
|
|
101
|
+
*/
|
|
102
|
+
export function deriveDefaultForType(type: JsonType | JsonType[] | undefined): JSONValue {
|
|
103
|
+
const t = Array.isArray(type) ? type[0] : type;
|
|
104
|
+
switch (t) {
|
|
105
|
+
case 'boolean': return false;
|
|
106
|
+
case 'integer':
|
|
107
|
+
case 'number': return 0;
|
|
108
|
+
case 'string': return '';
|
|
109
|
+
case 'array': return [];
|
|
110
|
+
case 'object': return {};
|
|
111
|
+
// eslint-disable-next-line no-null/no-null
|
|
112
|
+
default: return null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function getScope(monacoScope: string | undefined): { scope: PreferenceScope | undefined; overridable: boolean } {
|
|
117
|
+
switch (monacoScope) {
|
|
118
|
+
case 'machine-overridable':
|
|
119
|
+
case 'window':
|
|
120
|
+
case 'resource':
|
|
121
|
+
return { scope: PreferenceScope.Folder, overridable: false };
|
|
122
|
+
case 'language-overridable':
|
|
123
|
+
return { scope: PreferenceScope.Folder, overridable: true };
|
|
124
|
+
case 'application':
|
|
125
|
+
case 'machine':
|
|
126
|
+
return { scope: PreferenceScope.User, overridable: false };
|
|
127
|
+
}
|
|
128
|
+
return { scope: undefined, overridable: false };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function getFileExtension(filePath: string): string {
|
|
132
|
+
const index = filePath.lastIndexOf('.');
|
|
133
|
+
return index === -1 ? '' : filePath.substring(index + 1);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function isCharacterPair(something: unknown): something is CharacterPair {
|
|
137
|
+
return isStringArray(something) && something.length === 2;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function isRawLocalization(entry: unknown): entry is RawLocalization {
|
|
141
|
+
return isObject(entry) && typeof entry.languageId === 'string';
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function toCustomEditorPriority(priority: string | undefined): CustomEditorPriority {
|
|
145
|
+
if (priority === CustomEditorPriority.option || priority === CustomEditorPriority.builtin) {
|
|
146
|
+
return priority;
|
|
147
|
+
}
|
|
148
|
+
return CustomEditorPriority.default;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async function readJson(ctx: NormalizeContributionsContext, filePath: string): Promise<unknown | undefined> {
|
|
152
|
+
if (ctx.readJsonFile) {
|
|
153
|
+
return ctx.readJsonFile(filePath);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
const content = await fs.readFile(filePath, { encoding: 'utf8' });
|
|
158
|
+
return content ? jsoncparser.parse(content, undefined, { disallowComments: false }) : undefined;
|
|
159
|
+
} catch (e) {
|
|
160
|
+
if (!isENOENT(e)) {
|
|
161
|
+
throw e;
|
|
162
|
+
}
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export async function normalizeContributions<TContrib extends object>(
|
|
168
|
+
ctx: NormalizeContributionsContext,
|
|
169
|
+
contributions: TContrib
|
|
170
|
+
): Promise<TContrib> {
|
|
171
|
+
const output = contributions as TContrib & NormalizedPluginContribution;
|
|
172
|
+
const rawPlugin = ctx.plugin;
|
|
173
|
+
const contributes = rawContributes(rawPlugin);
|
|
174
|
+
const readConfigurationFn = ctx.readConfiguration ?? readConfiguration;
|
|
175
|
+
const readSubmenusFn = ctx.readSubmenus ?? ((submenus, plugin) => readSubmenus(ctx, submenus, plugin));
|
|
176
|
+
const readCustomEditorsFn = ctx.readCustomEditors ?? readCustomEditors;
|
|
177
|
+
const readViewsContainersFn = ctx.readViewsContainers ?? ((containers, plugin) => readViewsContainers(ctx, containers, plugin));
|
|
178
|
+
const readViewsFn = ctx.readViews ?? readViews;
|
|
179
|
+
const readViewsWelcomeFn = ctx.readViewsWelcome ?? readViewsWelcome;
|
|
180
|
+
const readCommandFn = ctx.readCommand ?? ((command, plugin) => readCommand(ctx, command, plugin));
|
|
181
|
+
const readMenusFn = ctx.readMenus ?? readMenus;
|
|
182
|
+
const readKeybindingFn = ctx.readKeybinding ?? readKeybinding;
|
|
183
|
+
const readDebuggersFn = ctx.readDebuggers ?? readDebuggers;
|
|
184
|
+
const readTaskDefinitionFn = ctx.readTaskDefinition ?? ((pluginName, definition) => readTaskDefinition(pluginName, definition, ctx));
|
|
185
|
+
const readSnippetsFn = ctx.readSnippets ?? (plugin => readSnippets(ctx, plugin));
|
|
186
|
+
const readThemesFn = ctx.readThemes ?? (plugin => readThemes(ctx, plugin));
|
|
187
|
+
const readIconsFn = ctx.readIcons ?? (plugin => readIcons(ctx, plugin));
|
|
188
|
+
const readIconThemesFn = ctx.readIconThemes ?? (plugin => readIconThemes(ctx, plugin));
|
|
189
|
+
const readColorsFn = ctx.readColors ?? (plugin => readColors(ctx, plugin));
|
|
190
|
+
const readTerminalsFn = ctx.readTerminals ?? readTerminals;
|
|
191
|
+
const readLocalizationsFn = ctx.readLocalizations ?? (plugin => readLocalizations(plugin, ctx));
|
|
192
|
+
const readWalkthroughsFn = ctx.readWalkthroughs ?? (plugin => readWalkthroughs(plugin, ctx));
|
|
193
|
+
const readLanguagesFn = ctx.readLanguages ?? ((languages, plugin) => readLanguages(ctx, languages, plugin));
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
if (contributes.configuration) {
|
|
197
|
+
const configurations = Array.isArray(contributes.configuration) ? contributes.configuration : [contributes.configuration];
|
|
198
|
+
const hasMultipleConfigs = configurations.length > 1;
|
|
199
|
+
output.configuration = [];
|
|
200
|
+
for (const c of configurations) {
|
|
201
|
+
const config = readConfigurationFn(c as IConfigurationNode, rawPlugin.packagePath);
|
|
202
|
+
if (config) {
|
|
203
|
+
Object.values(config.properties).forEach(property => {
|
|
204
|
+
if (hasMultipleConfigs) {
|
|
205
|
+
property.owner = rawPlugin.displayName;
|
|
206
|
+
property.group = config.title;
|
|
207
|
+
} else {
|
|
208
|
+
property.owner = config.title;
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
output.configuration.push(config);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
} catch (err) {
|
|
216
|
+
ctx.onError('configuration', err, contributes.configuration);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
output.problemMatchers = contributes.problemMatchers;
|
|
220
|
+
output.problemPatterns = contributes.problemPatterns;
|
|
221
|
+
output.resourceLabelFormatters = contributes.resourceLabelFormatters;
|
|
222
|
+
output.authentication = contributes.authentication;
|
|
223
|
+
output.notebooks = contributes.notebooks;
|
|
224
|
+
output.notebookRenderer = contributes.notebookRenderer;
|
|
225
|
+
output.notebookPreload = contributes.notebookPreload;
|
|
226
|
+
|
|
227
|
+
const configurationDefaults = contributes.configurationDefaults;
|
|
228
|
+
output.configurationDefaults = isObject(configurationDefaults) ? configurationDefaults : undefined;
|
|
229
|
+
|
|
230
|
+
try {
|
|
231
|
+
if (contributes.submenus) {
|
|
232
|
+
output.submenus = readSubmenusFn(contributes.submenus, rawPlugin);
|
|
233
|
+
}
|
|
234
|
+
} catch (err) {
|
|
235
|
+
ctx.onError('submenus', err, contributes.submenus);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
try {
|
|
239
|
+
if (contributes.customEditors) {
|
|
240
|
+
output.customEditors = readCustomEditorsFn(contributes.customEditors);
|
|
241
|
+
}
|
|
242
|
+
} catch (err) {
|
|
243
|
+
ctx.onError('customEditors', err, contributes.customEditors);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
try {
|
|
247
|
+
if (contributes.viewsContainers) {
|
|
248
|
+
const viewsContainers: { [location: string]: NormalizedViewContainer[] } = {};
|
|
249
|
+
for (const location of Object.keys(contributes.viewsContainers)) {
|
|
250
|
+
const containers = readViewsContainersFn(contributes.viewsContainers[location], rawPlugin);
|
|
251
|
+
const loc = VIEW_CONTAINER_LOCATION_ALIASES[location] ?? location;
|
|
252
|
+
const existing = viewsContainers[loc];
|
|
253
|
+
viewsContainers[loc] = existing ? existing.concat(containers) : containers;
|
|
254
|
+
}
|
|
255
|
+
output.viewsContainers = viewsContainers;
|
|
256
|
+
}
|
|
257
|
+
} catch (err) {
|
|
258
|
+
ctx.onError('viewsContainers', err, contributes.viewsContainers);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
if (contributes.views) {
|
|
263
|
+
const views: { [location: string]: RawView[] } = {};
|
|
264
|
+
for (const location of Object.keys(contributes.views)) {
|
|
265
|
+
views[location] = readViewsFn(contributes.views[location]);
|
|
266
|
+
}
|
|
267
|
+
output.views = views;
|
|
268
|
+
}
|
|
269
|
+
} catch (err) {
|
|
270
|
+
ctx.onError('views', err, contributes.views);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
if (contributes.viewsWelcome) {
|
|
275
|
+
output.viewsWelcome = readViewsWelcomeFn(
|
|
276
|
+
contributes.viewsWelcome,
|
|
277
|
+
contributes.views
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
} catch (err) {
|
|
281
|
+
ctx.onError('viewsWelcome', err, contributes.viewsWelcome);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
try {
|
|
285
|
+
const pluginCommands = contributes.commands;
|
|
286
|
+
if (pluginCommands) {
|
|
287
|
+
const commands = Array.isArray(pluginCommands) ? pluginCommands : [pluginCommands];
|
|
288
|
+
output.commands = commands.map(command => readCommandFn(command, rawPlugin));
|
|
289
|
+
}
|
|
290
|
+
} catch (err) {
|
|
291
|
+
ctx.onError('commands', err, contributes.commands);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
try {
|
|
295
|
+
if (contributes.menus) {
|
|
296
|
+
const menus: { [location: string]: RawMenu[] } = {};
|
|
297
|
+
for (const location of Object.keys(contributes.menus)) {
|
|
298
|
+
menus[location] = readMenusFn(contributes.menus[location]);
|
|
299
|
+
}
|
|
300
|
+
output.menus = menus;
|
|
301
|
+
}
|
|
302
|
+
} catch (err) {
|
|
303
|
+
ctx.onError('menus', err, contributes.menus);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
try {
|
|
307
|
+
if (contributes.keybindings) {
|
|
308
|
+
const rawKeybindings = Array.isArray(contributes.keybindings) ? contributes.keybindings : [contributes.keybindings];
|
|
309
|
+
output.keybindings = rawKeybindings.map(rawKeybinding => readKeybindingFn(rawKeybinding));
|
|
310
|
+
}
|
|
311
|
+
} catch (err) {
|
|
312
|
+
ctx.onError('keybindings', err, contributes.keybindings);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
try {
|
|
316
|
+
if (contributes.debuggers) {
|
|
317
|
+
output.debuggers = readDebuggersFn(contributes.debuggers);
|
|
318
|
+
}
|
|
319
|
+
} catch (err) {
|
|
320
|
+
ctx.onError('debuggers', err, contributes.debuggers);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
try {
|
|
324
|
+
if (contributes.taskDefinitions) {
|
|
325
|
+
output.taskDefinitions = contributes.taskDefinitions.map(definitionContribution =>
|
|
326
|
+
readTaskDefinitionFn(rawPlugin.name, definitionContribution)
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
} catch (err) {
|
|
330
|
+
ctx.onError('taskDefinitions', err, contributes.taskDefinitions);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
try {
|
|
334
|
+
output.snippets = readSnippetsFn(rawPlugin);
|
|
335
|
+
} catch (err) {
|
|
336
|
+
ctx.onError('snippets', err, contributes.snippets);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
try {
|
|
340
|
+
output.themes = readThemesFn(rawPlugin);
|
|
341
|
+
} catch (err) {
|
|
342
|
+
ctx.onError('themes', err, contributes.themes);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
try {
|
|
346
|
+
output.icons = readIconsFn(rawPlugin);
|
|
347
|
+
} catch (err) {
|
|
348
|
+
ctx.onError('icons', err, contributes.icons);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
try {
|
|
352
|
+
output.iconThemes = readIconThemesFn(rawPlugin);
|
|
353
|
+
} catch (err) {
|
|
354
|
+
ctx.onError('iconThemes', err, contributes.iconThemes);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
try {
|
|
358
|
+
output.colors = readColorsFn(rawPlugin);
|
|
359
|
+
} catch (err) {
|
|
360
|
+
ctx.onError('colors', err, contributes.colors);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
try {
|
|
364
|
+
output.terminalProfiles = readTerminalsFn(rawPlugin);
|
|
365
|
+
} catch (err) {
|
|
366
|
+
ctx.onError('terminals', err, contributes.terminal);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
try {
|
|
370
|
+
output.localizations = readLocalizationsFn(rawPlugin);
|
|
371
|
+
} catch (err) {
|
|
372
|
+
ctx.onError('localizations', err, contributes.localizations);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
try {
|
|
376
|
+
output.walkthroughs = readWalkthroughsFn(rawPlugin);
|
|
377
|
+
} catch (err) {
|
|
378
|
+
ctx.onError('walkthroughs', err, contributes.walkthroughs);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const [languagesResult, grammarsResult] = await Promise.allSettled([
|
|
382
|
+
contributes.languages ? readLanguagesFn(contributes.languages, rawPlugin) : undefined,
|
|
383
|
+
contributes.grammars && ctx.readGrammars
|
|
384
|
+
? ctx.readGrammars(contributes.grammars, rawPlugin.packagePath)
|
|
385
|
+
: undefined
|
|
386
|
+
]);
|
|
387
|
+
|
|
388
|
+
if (contributes.languages) {
|
|
389
|
+
if (languagesResult.status === 'fulfilled') {
|
|
390
|
+
output.languages = languagesResult.value;
|
|
391
|
+
} else {
|
|
392
|
+
ctx.onError('languages', languagesResult.reason, contributes.languages);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (contributes.grammars) {
|
|
397
|
+
if (grammarsResult.status === 'fulfilled') {
|
|
398
|
+
output.grammars = grammarsResult.value;
|
|
399
|
+
} else {
|
|
400
|
+
ctx.onError('grammars', grammarsResult.reason, contributes.grammars);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Drop keys with `undefined`
|
|
405
|
+
for (const key of Object.keys(output) as (keyof NormalizedPluginContribution)[]) {
|
|
406
|
+
if (output[key] === undefined) {
|
|
407
|
+
delete output[key];
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return output;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
export function readTerminals(pck: PluginManifest): NormalizedTerminalProfile[] | undefined {
|
|
415
|
+
const terminal = rawContributes(pck).terminal;
|
|
416
|
+
if (!terminal?.profiles) {
|
|
417
|
+
return undefined;
|
|
418
|
+
}
|
|
419
|
+
return terminal.profiles.filter((profile): profile is NormalizedTerminalProfile =>
|
|
420
|
+
!!(profile.id && profile.title)
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
export function readLocalizations(
|
|
425
|
+
pck: PluginManifest,
|
|
426
|
+
ctx?: NormalizeContributionsContext
|
|
427
|
+
): NormalizedLocalization[] | undefined {
|
|
428
|
+
const localizations = rawContributes(pck).localizations;
|
|
429
|
+
if (!Array.isArray(localizations)) {
|
|
430
|
+
return undefined;
|
|
431
|
+
}
|
|
432
|
+
const readLocalizationFn = ctx?.readLocalization ?? ((entry, pluginPath) => readLocalization(entry, pluginPath, ctx));
|
|
433
|
+
return localizations
|
|
434
|
+
.filter(isRawLocalization)
|
|
435
|
+
.map(entry => readLocalizationFn(entry, pck.packagePath));
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
export function readLocalization(
|
|
439
|
+
{ languageId, languageName, localizedLanguageName, translations, minimalTranslations }: RawLocalization,
|
|
440
|
+
pluginPath: string,
|
|
441
|
+
ctx?: Pick<NormalizeContributionsContext, 'readTranslation'>
|
|
442
|
+
): NormalizedLocalization {
|
|
443
|
+
const readTranslationFn = ctx?.readTranslation ?? readTranslation;
|
|
444
|
+
const local: NormalizedLocalization = {
|
|
445
|
+
languageId,
|
|
446
|
+
languageName,
|
|
447
|
+
localizedLanguageName,
|
|
448
|
+
minimalTranslations,
|
|
449
|
+
translations: []
|
|
450
|
+
};
|
|
451
|
+
if (Array.isArray(translations)) {
|
|
452
|
+
local.translations = translations.map(entry => readTranslationFn(entry, pluginPath));
|
|
453
|
+
}
|
|
454
|
+
return local;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export function readTranslation(packageTranslation: RawTranslation, _pluginPath: string): NormalizedTranslation {
|
|
458
|
+
return {
|
|
459
|
+
id: packageTranslation.id,
|
|
460
|
+
path: packageTranslation.path
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
export function readWalkthroughs(
|
|
465
|
+
pck: PluginManifest,
|
|
466
|
+
ctx: Pick<NormalizeContributionsContext, 'resolveUrl' | 'onWarn'>
|
|
467
|
+
): WalkthroughContribution[] | undefined {
|
|
468
|
+
const walkthroughs = rawContributes(pck).walkthroughs;
|
|
469
|
+
if (!walkthroughs) {
|
|
470
|
+
return undefined;
|
|
471
|
+
}
|
|
472
|
+
const pluginId = `${(pck.publisher ?? UNPUBLISHED).toLowerCase()}.${pck.name.toLowerCase()}`;
|
|
473
|
+
// `PluginModel` does not carry the extension icon, so it travels with the walkthroughs that show it.
|
|
474
|
+
const pluginIcon = pck.icon ? ctx.resolveUrl(pck.icon) : undefined;
|
|
475
|
+
const result: WalkthroughContribution[] = [];
|
|
476
|
+
for (const walkthrough of walkthroughs) {
|
|
477
|
+
if (typeof walkthrough.id !== 'string' || !walkthrough.id) {
|
|
478
|
+
ctx.onWarn(`'contributes.walkthroughs.id' of '${pluginId}' must be defined and non-empty`);
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
if (typeof walkthrough.title !== 'string' || !walkthrough.title) {
|
|
482
|
+
ctx.onWarn(`'contributes.walkthroughs.title' of '${pluginId}.${walkthrough.id}' must be defined and non-empty`);
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
if (!Array.isArray(walkthrough.steps)) {
|
|
486
|
+
ctx.onWarn(`'contributes.walkthroughs.steps' of '${pluginId}.${walkthrough.id}' must be an array`);
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
const steps: WalkthroughStepContribution[] = [];
|
|
490
|
+
for (const step of walkthrough.steps) {
|
|
491
|
+
if (typeof step.id !== 'string' || !step.id) {
|
|
492
|
+
ctx.onWarn(`'contributes.walkthroughs.steps.id' of '${pluginId}.${walkthrough.id}' must be defined and non-empty`);
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
if (typeof step.title !== 'string' || !step.title) {
|
|
496
|
+
ctx.onWarn(`'contributes.walkthroughs.steps.title' of '${pluginId}.${walkthrough.id}.${step.id}' must be defined and non-empty`);
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
steps.push({
|
|
500
|
+
id: step.id,
|
|
501
|
+
title: step.title,
|
|
502
|
+
description: step.description || '',
|
|
503
|
+
media: resolveWalkthroughMedia(ctx, step.media),
|
|
504
|
+
completionEvents: step.completionEvents,
|
|
505
|
+
when: step.when
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
result.push({
|
|
509
|
+
id: walkthrough.id,
|
|
510
|
+
title: walkthrough.title,
|
|
511
|
+
description: walkthrough.description || '',
|
|
512
|
+
steps,
|
|
513
|
+
when: walkthrough.when,
|
|
514
|
+
icon: walkthrough.icon,
|
|
515
|
+
pluginId,
|
|
516
|
+
pluginIcon
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
return result.length > 0 ? result : undefined;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function resolveWalkthroughMedia(
|
|
523
|
+
ctx: Pick<NormalizeContributionsContext, 'resolveUrl'>,
|
|
524
|
+
media?: PluginPackageWalkthroughStepMedia
|
|
525
|
+
): WalkthroughStepMedia | undefined {
|
|
526
|
+
if (!media) {
|
|
527
|
+
return undefined;
|
|
528
|
+
}
|
|
529
|
+
if ('markdown' in media) {
|
|
530
|
+
return { markdown: ctx.resolveUrl(media.markdown) };
|
|
531
|
+
}
|
|
532
|
+
const altText = 'altText' in media ? media.altText as string : undefined;
|
|
533
|
+
if ('svg' in media) {
|
|
534
|
+
return { svg: ctx.resolveUrl(media.svg), ...(altText !== undefined && { altText }) };
|
|
535
|
+
}
|
|
536
|
+
if ('image' in media) {
|
|
537
|
+
if (typeof media.image === 'string') {
|
|
538
|
+
return { image: ctx.resolveUrl(media.image), ...(altText !== undefined && { altText }) };
|
|
539
|
+
}
|
|
540
|
+
// Only `dark` and `light` are mandatory; the high contrast variants fall back to them.
|
|
541
|
+
const dark = ctx.resolveUrl(media.image.dark);
|
|
542
|
+
const light = ctx.resolveUrl(media.image.light);
|
|
543
|
+
return {
|
|
544
|
+
image: {
|
|
545
|
+
dark,
|
|
546
|
+
light,
|
|
547
|
+
hc: media.image.hc ? ctx.resolveUrl(media.image.hc) : dark,
|
|
548
|
+
hcLight: media.image.hcLight ? ctx.resolveUrl(media.image.hcLight) : light
|
|
549
|
+
},
|
|
550
|
+
...(altText !== undefined && { altText })
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
return undefined;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
export function readCommand(ctx: NormalizeContributionsContext, command: RawCommand, pck: PluginManifest): NormalizedCommand {
|
|
557
|
+
const { themeIcon, iconUrl } = (ctx.transformIconUrl
|
|
558
|
+
? ctx.transformIconUrl(pck, command.icon)
|
|
559
|
+
: transformIconUrl(ctx, pck, command.icon)) ?? {};
|
|
560
|
+
return {
|
|
561
|
+
command: command.command,
|
|
562
|
+
title: command.title,
|
|
563
|
+
shortTitle: command.shortTitle,
|
|
564
|
+
originalTitle: command.original,
|
|
565
|
+
category: command.category,
|
|
566
|
+
iconUrl,
|
|
567
|
+
themeIcon,
|
|
568
|
+
enablement: command.enablement
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
export function transformIconUrl(
|
|
573
|
+
ctx: Pick<NormalizeContributionsContext, 'resolveUrl'>,
|
|
574
|
+
_plugin: PluginManifest,
|
|
575
|
+
original?: IconUrl
|
|
576
|
+
): { iconUrl?: IconUrl; themeIcon?: string } | undefined {
|
|
577
|
+
if (original) {
|
|
578
|
+
if (typeof original === 'string') {
|
|
579
|
+
if (original.startsWith('$(')) {
|
|
580
|
+
return { themeIcon: original };
|
|
581
|
+
}
|
|
582
|
+
return { iconUrl: ctx.resolveUrl(original) };
|
|
583
|
+
}
|
|
584
|
+
return {
|
|
585
|
+
iconUrl: {
|
|
586
|
+
light: ctx.resolveUrl(original.light),
|
|
587
|
+
dark: ctx.resolveUrl(original.dark)
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
return undefined;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
export function readColors(ctx: NormalizeContributionsContext, pck: PluginManifest): ColorDefinition[] | undefined {
|
|
595
|
+
const colors = rawContributes(pck).colors;
|
|
596
|
+
if (!Array.isArray(colors)) {
|
|
597
|
+
return undefined;
|
|
598
|
+
}
|
|
599
|
+
const result: ColorDefinition[] = [];
|
|
600
|
+
for (const contribution of colors) {
|
|
601
|
+
if (!isObject(contribution)) {
|
|
602
|
+
continue;
|
|
603
|
+
}
|
|
604
|
+
if (typeof contribution.id !== 'string' || contribution.id.length === 0) {
|
|
605
|
+
ctx.onWarn("'configuration.colors.id' must be defined and can not be empty");
|
|
606
|
+
continue;
|
|
607
|
+
}
|
|
608
|
+
if (!contribution.id.match(colorIdPattern)) {
|
|
609
|
+
ctx.onWarn("'configuration.colors.id' must follow the word[.word]*");
|
|
610
|
+
continue;
|
|
611
|
+
}
|
|
612
|
+
if (typeof contribution.description !== 'string' || contribution.description.length === 0) {
|
|
613
|
+
ctx.onWarn("'configuration.colors.description' must be defined and can not be empty");
|
|
614
|
+
continue;
|
|
615
|
+
}
|
|
616
|
+
const defaults = contribution.defaults;
|
|
617
|
+
if (!isColorDefaults(defaults)) {
|
|
618
|
+
ctx.onWarn("'configuration.colors.defaults' must be defined and must contain 'light', 'dark' and 'highContrast'");
|
|
619
|
+
continue;
|
|
620
|
+
}
|
|
621
|
+
result.push({
|
|
622
|
+
id: contribution.id,
|
|
623
|
+
description: contribution.description,
|
|
624
|
+
defaults: {
|
|
625
|
+
light: defaults.light,
|
|
626
|
+
dark: defaults.dark,
|
|
627
|
+
hc: defaults.highContrast
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
return result;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
export function readThemes(ctx: NormalizeContributionsContext, pck: PluginManifest): NormalizedTheme[] | undefined {
|
|
635
|
+
const themes = rawContributes(pck).themes;
|
|
636
|
+
if (!Array.isArray(themes)) {
|
|
637
|
+
return undefined;
|
|
638
|
+
}
|
|
639
|
+
const result: NormalizedTheme[] = [];
|
|
640
|
+
for (const contribution of themes) {
|
|
641
|
+
if (!isObject(contribution)) {
|
|
642
|
+
continue;
|
|
643
|
+
}
|
|
644
|
+
if (typeof contribution.path === 'string' && contribution.path) {
|
|
645
|
+
result.push({
|
|
646
|
+
id: typeof contribution.id === 'string' ? contribution.id : undefined,
|
|
647
|
+
uri: ctx.resolveUri(pck, contribution.path),
|
|
648
|
+
description: typeof contribution.description === 'string' ? contribution.description : undefined,
|
|
649
|
+
label: typeof contribution.label === 'string' ? contribution.label : undefined,
|
|
650
|
+
uiTheme: isPluginUiTheme(contribution.uiTheme) ? contribution.uiTheme : undefined,
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
return result;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
export function readIconThemes(ctx: NormalizeContributionsContext, pck: PluginManifest): NormalizedIconTheme[] | undefined {
|
|
658
|
+
const iconThemes = rawContributes(pck).iconThemes;
|
|
659
|
+
if (!Array.isArray(iconThemes)) {
|
|
660
|
+
return undefined;
|
|
661
|
+
}
|
|
662
|
+
const result: NormalizedIconTheme[] = [];
|
|
663
|
+
for (const contribution of iconThemes) {
|
|
664
|
+
if (!isObject(contribution)) {
|
|
665
|
+
continue;
|
|
666
|
+
}
|
|
667
|
+
if (typeof contribution.id !== 'string' || !contribution.id) {
|
|
668
|
+
ctx.onWarn(`Expected string in \`contributes.iconThemes.id\`. Provided value: ${String(contribution.id)}`);
|
|
669
|
+
continue;
|
|
670
|
+
}
|
|
671
|
+
if (typeof contribution.path !== 'string' || !contribution.path) {
|
|
672
|
+
ctx.onWarn(`Expected string in \`contributes.iconThemes.path\`. Provided value: ${String(contribution.path)}`);
|
|
673
|
+
continue;
|
|
674
|
+
}
|
|
675
|
+
result.push({
|
|
676
|
+
id: contribution.id,
|
|
677
|
+
uri: ctx.resolveUri(pck, contribution.path),
|
|
678
|
+
description: typeof contribution.description === 'string' ? contribution.description : undefined,
|
|
679
|
+
label: typeof contribution.label === 'string' ? contribution.label : undefined,
|
|
680
|
+
uiTheme: isPluginUiTheme(contribution.uiTheme) ? contribution.uiTheme : undefined,
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
return result;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
export function readIcons(ctx: NormalizeContributionsContext, pck: PluginManifest): NormalizedIcon[] | undefined {
|
|
687
|
+
const icons = rawContributes(pck).icons;
|
|
688
|
+
if (!isObject(icons)) {
|
|
689
|
+
return undefined;
|
|
690
|
+
}
|
|
691
|
+
const result: NormalizedIcon[] = [];
|
|
692
|
+
for (const id in icons) {
|
|
693
|
+
if (!Object.prototype.hasOwnProperty.call(icons, id)) {
|
|
694
|
+
continue;
|
|
695
|
+
}
|
|
696
|
+
if (!id.match(iconIdPattern)) {
|
|
697
|
+
ctx.onWarn(
|
|
698
|
+
'\'configuration.icons\' keys represent the icon id and can only contain letter, digits and minuses. ' +
|
|
699
|
+
'They need to consist of at least two segments in the form `component-iconname`. ' +
|
|
700
|
+
`extension: ${pck.name} icon id: ${id}`
|
|
701
|
+
);
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
const iconContribution = icons[id];
|
|
705
|
+
if (!isObject(iconContribution) || typeof iconContribution.description !== 'string' || iconContribution.description.length === 0) {
|
|
706
|
+
ctx.onWarn(`configuration.icons.description must be defined and can not be empty, extension: ${pck.name} icon id: ${id}`);
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
const defaultIcon = iconContribution.default;
|
|
711
|
+
if (typeof defaultIcon === 'string') {
|
|
712
|
+
result.push({
|
|
713
|
+
id,
|
|
714
|
+
extensionId: `${pck.publisher}.${pck.name}`,
|
|
715
|
+
description: iconContribution.description,
|
|
716
|
+
defaults: { id: defaultIcon }
|
|
717
|
+
});
|
|
718
|
+
} else if (isObject(defaultIcon) && typeof defaultIcon.fontPath === 'string' && typeof defaultIcon.fontCharacter === 'string') {
|
|
719
|
+
const format = getFileExtension(defaultIcon.fontPath);
|
|
720
|
+
if (['woff', 'woff2', 'ttf'].indexOf(format) === -1) {
|
|
721
|
+
ctx.onWarn(`Expected \`contributes.icons.default.fontPath\` to have file extension 'woff', woff2' or 'ttf', is '${format}'.`);
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
const iconFontLocation = ctx.resolveUri(pck, defaultIcon.fontPath);
|
|
726
|
+
result.push({
|
|
727
|
+
id,
|
|
728
|
+
extensionId: `${pck.publisher}.${pck.name}`,
|
|
729
|
+
description: iconContribution.description,
|
|
730
|
+
defaults: {
|
|
731
|
+
fontCharacter: defaultIcon.fontCharacter,
|
|
732
|
+
location: iconFontLocation
|
|
733
|
+
}
|
|
734
|
+
});
|
|
735
|
+
} else {
|
|
736
|
+
ctx.onWarn(
|
|
737
|
+
"'configuration.icons.default' must be either a reference to the id of an other theme icon (string) " +
|
|
738
|
+
'or a icon definition (object) with properties `fontPath` and `fontCharacter`.'
|
|
739
|
+
);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
return result;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
export function readSnippets(ctx: NormalizeContributionsContext, pck: PluginManifest): NormalizedSnippet[] | undefined {
|
|
746
|
+
const snippets = rawContributes(pck).snippets;
|
|
747
|
+
if (!Array.isArray(snippets)) {
|
|
748
|
+
return undefined;
|
|
749
|
+
}
|
|
750
|
+
const result: NormalizedSnippet[] = [];
|
|
751
|
+
for (const contribution of snippets) {
|
|
752
|
+
if (!isObject(contribution)) {
|
|
753
|
+
continue;
|
|
754
|
+
}
|
|
755
|
+
if (typeof contribution.path === 'string' && contribution.path) {
|
|
756
|
+
result.push({
|
|
757
|
+
language: typeof contribution.language === 'string' ? contribution.language : undefined,
|
|
758
|
+
source: pck.displayName || pck.name,
|
|
759
|
+
uri: ctx.resolveUri(pck, contribution.path)
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
return result;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
export function readConfiguration(rawConfiguration: IConfigurationNode, _pluginPath: string): PreferenceSchema | undefined {
|
|
767
|
+
const { scope, overridable } = getScope(rawConfiguration.scope);
|
|
768
|
+
const schema: PreferenceSchema = {
|
|
769
|
+
scope,
|
|
770
|
+
defaultOverridable: overridable,
|
|
771
|
+
title: rawConfiguration.title,
|
|
772
|
+
properties: {}
|
|
773
|
+
};
|
|
774
|
+
|
|
775
|
+
if (rawConfiguration.properties) {
|
|
776
|
+
for (const [key, property] of Object.entries(rawConfiguration.properties)) {
|
|
777
|
+
const scopeInfo = getScope(property.scope);
|
|
778
|
+
const schemaProperty: PreferenceDataProperty = {
|
|
779
|
+
...property,
|
|
780
|
+
scope: scopeInfo.scope,
|
|
781
|
+
overridable: scopeInfo.overridable,
|
|
782
|
+
default: property.default !== undefined ? property.default : deriveDefaultForType(property.type)
|
|
783
|
+
};
|
|
784
|
+
|
|
785
|
+
schema.properties[key] = schemaProperty;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
return schema;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
export function readKeybinding(rawKeybinding: RawKeybinding): NormalizedKeybinding {
|
|
792
|
+
return {
|
|
793
|
+
keybinding: rawKeybinding.key,
|
|
794
|
+
command: rawKeybinding.command,
|
|
795
|
+
when: rawKeybinding.when,
|
|
796
|
+
mac: rawKeybinding.mac,
|
|
797
|
+
linux: rawKeybinding.linux,
|
|
798
|
+
win: rawKeybinding.win,
|
|
799
|
+
args: rawKeybinding.args
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
export function readCustomEditors(rawCustomEditors: readonly RawCustomEditor[]): NormalizedCustomEditor[] {
|
|
804
|
+
return rawCustomEditors.map(rawCustomEditor => readCustomEditor(rawCustomEditor));
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
export function readCustomEditor(rawCustomEditor: RawCustomEditor): NormalizedCustomEditor {
|
|
808
|
+
return {
|
|
809
|
+
viewType: rawCustomEditor.viewType,
|
|
810
|
+
displayName: rawCustomEditor.displayName,
|
|
811
|
+
selector: rawCustomEditor.selector || [],
|
|
812
|
+
priority: toCustomEditorPriority(rawCustomEditor.priority)
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
export function readViewsContainers(
|
|
817
|
+
ctx: NormalizeContributionsContext,
|
|
818
|
+
rawViewsContainers: readonly RawViewContainer[],
|
|
819
|
+
pck: PluginManifest
|
|
820
|
+
): NormalizedViewContainer[] {
|
|
821
|
+
return rawViewsContainers
|
|
822
|
+
.map(rawViewContainer => readViewContainer(ctx, rawViewContainer, pck))
|
|
823
|
+
.filter((container): container is NormalizedViewContainer => container !== undefined);
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
export function readViewContainer(
|
|
827
|
+
ctx: NormalizeContributionsContext,
|
|
828
|
+
rawViewContainer: RawViewContainer,
|
|
829
|
+
pck: PluginManifest
|
|
830
|
+
): NormalizedViewContainer | undefined {
|
|
831
|
+
const icon = rawViewContainer.icon;
|
|
832
|
+
if (typeof icon !== 'string') {
|
|
833
|
+
ctx.onError('viewsContainers', 'view container icon must be defined and must be a string', rawViewContainer);
|
|
834
|
+
return undefined;
|
|
835
|
+
}
|
|
836
|
+
const themeIcon = icon.startsWith('$(') ? icon : undefined;
|
|
837
|
+
const iconUrl = ctx.resolveUrl(icon);
|
|
838
|
+
return {
|
|
839
|
+
id: rawViewContainer.id,
|
|
840
|
+
title: rawViewContainer.title,
|
|
841
|
+
iconUrl,
|
|
842
|
+
themeIcon,
|
|
843
|
+
when: rawViewContainer.when,
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
export function readViews(rawViews: readonly RawView[]): RawView[] {
|
|
848
|
+
return rawViews.map(rawView => readView(rawView));
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
export function readView(rawView: RawView): RawView {
|
|
852
|
+
return {
|
|
853
|
+
id: rawView.id,
|
|
854
|
+
name: rawView.name,
|
|
855
|
+
when: rawView.when,
|
|
856
|
+
type: rawView.type
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
export function readViewsWelcome(rawViewsWelcome: readonly RawViewWelcome[], rowViews: ViewsByLocation | undefined): NormalizedViewWelcome[] {
|
|
861
|
+
return rawViewsWelcome.map(rawViewWelcome => readViewWelcome(rawViewWelcome, extractPluginViewsIds(rowViews)));
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
export function readViewWelcome(rawViewWelcome: RawViewWelcome, pluginViewsIds: string[]): NormalizedViewWelcome {
|
|
865
|
+
return {
|
|
866
|
+
view: rawViewWelcome.view,
|
|
867
|
+
content: rawViewWelcome.contents,
|
|
868
|
+
when: rawViewWelcome.when,
|
|
869
|
+
enablement: rawViewWelcome.enablement,
|
|
870
|
+
order: pluginViewsIds.findIndex(v => v === rawViewWelcome.view) > -1 ? 0 : 1
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
export function extractPluginViewsIds(views: ViewsByLocation | undefined): string[] {
|
|
875
|
+
const pluginViewsIds: string[] = [];
|
|
876
|
+
if (views) {
|
|
877
|
+
for (const location of Object.keys(views)) {
|
|
878
|
+
const viewsIds = views[location]
|
|
879
|
+
.filter(isObject)
|
|
880
|
+
.map(view => view.id)
|
|
881
|
+
.filter((id): id is string => typeof id === 'string');
|
|
882
|
+
pluginViewsIds.push(...viewsIds);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
return pluginViewsIds;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
export function readMenus(rawMenus: readonly RawMenu[]): RawMenu[] {
|
|
889
|
+
return rawMenus.map(rawMenu => readMenu(rawMenu));
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
export function readMenu(rawMenu: RawMenu): RawMenu {
|
|
893
|
+
return {
|
|
894
|
+
command: rawMenu.command,
|
|
895
|
+
submenu: rawMenu.submenu,
|
|
896
|
+
alt: rawMenu.alt,
|
|
897
|
+
group: rawMenu.group,
|
|
898
|
+
when: rawMenu.when
|
|
899
|
+
};
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
export async function readLanguages(ctx: NormalizeContributionsContext, rawLanguages: readonly RawLanguage[], plugin: PluginManifest): Promise<NormalizedLanguage[]> {
|
|
903
|
+
return Promise.all(rawLanguages.map(language => readLanguage(ctx, language, plugin)));
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
export function readSubmenus(ctx: NormalizeContributionsContext, rawSubmenus: readonly RawSubmenu[], plugin: PluginManifest): NormalizedSubmenu[] {
|
|
907
|
+
return rawSubmenus.map(submenu => readSubmenu(ctx, submenu, plugin));
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
export function readSubmenu(ctx: NormalizeContributionsContext, rawSubmenu: RawSubmenu, plugin: PluginManifest): NormalizedSubmenu {
|
|
911
|
+
const icon = ctx.transformIconUrl
|
|
912
|
+
? ctx.transformIconUrl(plugin, rawSubmenu.icon)
|
|
913
|
+
: transformIconUrl(ctx, plugin, rawSubmenu.icon);
|
|
914
|
+
return {
|
|
915
|
+
icon: icon?.iconUrl ?? icon?.themeIcon,
|
|
916
|
+
id: rawSubmenu.id,
|
|
917
|
+
label: rawSubmenu.label
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
export async function readLanguage(ctx: NormalizeContributionsContext, rawLang: RawLanguage, plugin: PluginManifest): Promise<NormalizedLanguage> {
|
|
922
|
+
const icon = ctx.transformIconUrl
|
|
923
|
+
? ctx.transformIconUrl(plugin, rawLang.icon)
|
|
924
|
+
: transformIconUrl(ctx, plugin, rawLang.icon);
|
|
925
|
+
const result: NormalizedLanguage = {
|
|
926
|
+
id: rawLang.id,
|
|
927
|
+
aliases: rawLang.aliases,
|
|
928
|
+
extensions: rawLang.extensions,
|
|
929
|
+
filenamePatterns: rawLang.filenamePatterns,
|
|
930
|
+
filenames: rawLang.filenames,
|
|
931
|
+
firstLine: rawLang.firstLine,
|
|
932
|
+
mimetypes: rawLang.mimetypes,
|
|
933
|
+
icon: icon?.iconUrl ?? icon?.themeIcon
|
|
934
|
+
};
|
|
935
|
+
if (typeof rawLang.configuration === 'string') {
|
|
936
|
+
const rawConfiguration = await readJson(ctx, path.resolve(plugin.packagePath, rawLang.configuration));
|
|
937
|
+
if (isObject(rawConfiguration)) {
|
|
938
|
+
const configuration: NormalizedLanguageConfiguration = {
|
|
939
|
+
brackets: Array.isArray(rawConfiguration.brackets)
|
|
940
|
+
? rawConfiguration.brackets.filter(isCharacterPair)
|
|
941
|
+
: undefined,
|
|
942
|
+
comments: rawConfiguration.comments as CommentRule | undefined,
|
|
943
|
+
folding: rawConfiguration.folding as FoldingRules | undefined,
|
|
944
|
+
wordPattern: typeof rawConfiguration.wordPattern === 'string' ? rawConfiguration.wordPattern : undefined,
|
|
945
|
+
autoClosingPairs: extractValidAutoClosingPairs(ctx, rawLang.id, rawConfiguration),
|
|
946
|
+
indentationRules: rawConfiguration.indentationRules as IndentationRules | undefined,
|
|
947
|
+
surroundingPairs: extractValidSurroundingPairs(ctx, rawLang.id, rawConfiguration),
|
|
948
|
+
onEnterRules: Array.isArray(rawConfiguration.onEnterRules) ? rawConfiguration.onEnterRules as NormalizedLanguageConfiguration['onEnterRules'] : undefined,
|
|
949
|
+
};
|
|
950
|
+
result.configuration = configuration;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
return result;
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
export function readDebuggers(rawDebuggers: readonly RawDebugger[]): RawDebugger[] {
|
|
957
|
+
return rawDebuggers.map(rawDebug => readDebugger(rawDebug));
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
export function readDebugger(rawDebugger: RawDebugger): RawDebugger {
|
|
961
|
+
return {
|
|
962
|
+
type: rawDebugger.type,
|
|
963
|
+
label: rawDebugger.label,
|
|
964
|
+
languages: rawDebugger.languages,
|
|
965
|
+
enableBreakpointsFor: rawDebugger.enableBreakpointsFor,
|
|
966
|
+
variables: rawDebugger.variables,
|
|
967
|
+
adapterExecutableCommand: rawDebugger.adapterExecutableCommand,
|
|
968
|
+
configurationSnippets: rawDebugger.configurationSnippets,
|
|
969
|
+
win: rawDebugger.win,
|
|
970
|
+
winx86: rawDebugger.winx86,
|
|
971
|
+
windows: rawDebugger.windows,
|
|
972
|
+
osx: rawDebugger.osx,
|
|
973
|
+
linux: rawDebugger.linux,
|
|
974
|
+
program: rawDebugger.program,
|
|
975
|
+
args: rawDebugger.args,
|
|
976
|
+
runtime: rawDebugger.runtime,
|
|
977
|
+
runtimeArgs: rawDebugger.runtimeArgs,
|
|
978
|
+
configurationAttributes: rawDebugger.configurationAttributes
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
export function readTaskDefinition(
|
|
983
|
+
pluginName: string,
|
|
984
|
+
definitionContribution: RawTaskDefinition,
|
|
985
|
+
ctx?: Pick<NormalizeContributionsContext, 'toSchema'>
|
|
986
|
+
): TaskDefinition {
|
|
987
|
+
const propertyKeys = definitionContribution.properties && isObject(definitionContribution.properties)
|
|
988
|
+
? Object.keys(definitionContribution.properties)
|
|
989
|
+
: [];
|
|
990
|
+
const schema = (ctx?.toSchema ?? toSchema)(definitionContribution);
|
|
991
|
+
return {
|
|
992
|
+
taskType: definitionContribution.type,
|
|
993
|
+
source: pluginName,
|
|
994
|
+
properties: {
|
|
995
|
+
required: definitionContribution.required,
|
|
996
|
+
all: propertyKeys,
|
|
997
|
+
schema
|
|
998
|
+
}
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
export function toSchema(definition: RawTaskDefinition): IJSONSchema {
|
|
1003
|
+
const reconciliation: IJSONSchema = { ...(definition as IJSONSchema), type: 'object' };
|
|
1004
|
+
const schema = deepClone(reconciliation);
|
|
1005
|
+
if (schema.properties === undefined) {
|
|
1006
|
+
// eslint-disable-next-line no-null/no-null
|
|
1007
|
+
schema.properties = Object.create(null);
|
|
1008
|
+
}
|
|
1009
|
+
schema.type = 'object';
|
|
1010
|
+
schema.properties!.type = { type: 'string', const: definition.type as string };
|
|
1011
|
+
return schema;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
function extractValidAutoClosingPairs(ctx: NormalizeContributionsContext, langId: string, configuration: Record<string, unknown>): AutoClosingPairConditional[] | undefined {
|
|
1015
|
+
const source = configuration.autoClosingPairs;
|
|
1016
|
+
if (typeof source === 'undefined') {
|
|
1017
|
+
return undefined;
|
|
1018
|
+
}
|
|
1019
|
+
if (!Array.isArray(source)) {
|
|
1020
|
+
ctx.onWarn(`[${langId}]: language configuration: expected \`autoClosingPairs\` to be an array.`);
|
|
1021
|
+
return undefined;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
let result: AutoClosingPairConditional[] | undefined = undefined;
|
|
1025
|
+
for (let i = 0, len = source.length; i < len; i++) {
|
|
1026
|
+
const pair = source[i];
|
|
1027
|
+
if (Array.isArray(pair)) {
|
|
1028
|
+
if (!isCharacterPair(pair)) {
|
|
1029
|
+
ctx.onWarn(`[${langId}]: language configuration: expected \`autoClosingPairs[${i}]\` to be an array of two strings or an object.`);
|
|
1030
|
+
continue;
|
|
1031
|
+
}
|
|
1032
|
+
result = result || [];
|
|
1033
|
+
result.push({ open: pair[0], close: pair[1] });
|
|
1034
|
+
} else {
|
|
1035
|
+
if (!isObject(pair)) {
|
|
1036
|
+
ctx.onWarn(`[${langId}]: language configuration: expected \`autoClosingPairs[${i}]\` to be an array of two strings or an object.`);
|
|
1037
|
+
continue;
|
|
1038
|
+
}
|
|
1039
|
+
if (typeof pair.open !== 'string') {
|
|
1040
|
+
ctx.onWarn(`[${langId}]: language configuration: expected \`autoClosingPairs[${i}].open\` to be a string.`);
|
|
1041
|
+
continue;
|
|
1042
|
+
}
|
|
1043
|
+
if (typeof pair.close !== 'string') {
|
|
1044
|
+
ctx.onWarn(`[${langId}]: language configuration: expected \`autoClosingPairs[${i}].close\` to be a string.`);
|
|
1045
|
+
continue;
|
|
1046
|
+
}
|
|
1047
|
+
if (typeof pair.notIn !== 'undefined') {
|
|
1048
|
+
if (!isStringArray(pair.notIn)) {
|
|
1049
|
+
ctx.onWarn(`[${langId}]: language configuration: expected \`autoClosingPairs[${i}].notIn\` to be a string array.`);
|
|
1050
|
+
continue;
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
result = result || [];
|
|
1054
|
+
result.push({ open: pair.open, close: pair.close, notIn: pair.notIn });
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
return result;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
function extractValidSurroundingPairs(ctx: NormalizeContributionsContext, langId: string, configuration: Record<string, unknown>): AutoClosingPair[] | undefined {
|
|
1061
|
+
const source = configuration.surroundingPairs;
|
|
1062
|
+
if (typeof source === 'undefined') {
|
|
1063
|
+
return undefined;
|
|
1064
|
+
}
|
|
1065
|
+
if (!Array.isArray(source)) {
|
|
1066
|
+
ctx.onWarn(`[${langId}]: language configuration: expected \`surroundingPairs\` to be an array.`);
|
|
1067
|
+
return undefined;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
let result: AutoClosingPair[] | undefined = undefined;
|
|
1071
|
+
for (let i = 0, len = source.length; i < len; i++) {
|
|
1072
|
+
const pair = source[i];
|
|
1073
|
+
if (Array.isArray(pair)) {
|
|
1074
|
+
if (!isCharacterPair(pair)) {
|
|
1075
|
+
ctx.onWarn(`[${langId}]: language configuration: expected \`surroundingPairs[${i}]\` to be an array of two strings or an object.`);
|
|
1076
|
+
continue;
|
|
1077
|
+
}
|
|
1078
|
+
result = result || [];
|
|
1079
|
+
result.push({ open: pair[0], close: pair[1] });
|
|
1080
|
+
} else {
|
|
1081
|
+
if (!isObject(pair)) {
|
|
1082
|
+
ctx.onWarn(`[${langId}]: language configuration: expected \`surroundingPairs[${i}]\` to be an array of two strings or an object.`);
|
|
1083
|
+
continue;
|
|
1084
|
+
}
|
|
1085
|
+
if (typeof pair.open !== 'string') {
|
|
1086
|
+
ctx.onWarn(`[${langId}]: language configuration: expected \`surroundingPairs[${i}].open\` to be a string.`);
|
|
1087
|
+
continue;
|
|
1088
|
+
}
|
|
1089
|
+
if (typeof pair.close !== 'string') {
|
|
1090
|
+
ctx.onWarn(`[${langId}]: language configuration: expected \`surroundingPairs[${i}].close\` to be a string.`);
|
|
1091
|
+
continue;
|
|
1092
|
+
}
|
|
1093
|
+
result = result || [];
|
|
1094
|
+
result.push({ open: pair.open, close: pair.close });
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
return result;
|
|
1098
|
+
}
|