Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/services/extensions/common/extensionsRegistry.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import * as nls from '../../../../nls.js';
7
import { onUnexpectedError } from '../../../../base/common/errors.js';
8
import { IJSONSchema } from '../../../../base/common/jsonSchema.js';
9
import Severity from '../../../../base/common/severity.js';
10
import { EXTENSION_IDENTIFIER_PATTERN } from '../../../../platform/extensionManagement/common/extensionManagement.js';
11
import { Extensions, IJSONContributionRegistry } from '../../../../platform/jsonschemas/common/jsonContributionRegistry.js';
12
import { Registry } from '../../../../platform/registry/common/platform.js';
13
import { IMessage } from './extensions.js';
14
import { IExtensionDescription, EXTENSION_CATEGORIES, ExtensionIdentifierSet } from '../../../../platform/extensions/common/extensions.js';
15
import { ExtensionKind } from '../../../../platform/environment/common/environment.js';
16
import { productSchemaId } from '../../../../platform/product/common/productService.js';
17
import { ImplicitActivationEvents, IActivationEventsGenerator } from '../../../../platform/extensionManagement/common/implicitActivationEvents.js';
18
import { IDisposable } from '../../../../base/common/lifecycle.js';
19
import { allApiProposals } from '../../../../platform/extensions/common/extensionsApiProposals.js';
20
21
const schemaRegistry = Registry.as<IJSONContributionRegistry>(Extensions.JSONContribution);
22
23
export class ExtensionMessageCollector {
24
25
private readonly _messageHandler: (msg: IMessage) => void;
26
private readonly _extension: IExtensionDescription;
27
private readonly _extensionPointId: string;
28
29
constructor(
30
messageHandler: (msg: IMessage) => void,
31
extension: IExtensionDescription,
32
extensionPointId: string
33
) {
34
this._messageHandler = messageHandler;
35
this._extension = extension;
36
this._extensionPointId = extensionPointId;
37
}
38
39
private _msg(type: Severity, message: string): void {
40
this._messageHandler({
41
type: type,
42
message: message,
43
extensionId: this._extension.identifier,
44
extensionPointId: this._extensionPointId
45
});
46
}
47
48
public error(message: string): void {
49
this._msg(Severity.Error, message);
50
}
51
52
public warn(message: string): void {
53
this._msg(Severity.Warning, message);
54
}
55
56
public info(message: string): void {
57
this._msg(Severity.Info, message);
58
}
59
}
60
61
export interface IExtensionPointUser<T> {
62
description: IExtensionDescription;
63
value: T;
64
collector: ExtensionMessageCollector;
65
}
66
67
export type IExtensionPointHandler<T> = (extensions: readonly IExtensionPointUser<T>[], delta: ExtensionPointUserDelta<T>) => void;
68
69
export interface IExtensionPoint<T> {
70
readonly name: string;
71
setHandler(handler: IExtensionPointHandler<T>): IDisposable;
72
readonly defaultExtensionKind: ExtensionKind[] | undefined;
73
readonly canHandleResolver?: boolean;
74
}
75
76
export class ExtensionPointUserDelta<T> {
77
78
private static _toSet<T>(arr: readonly IExtensionPointUser<T>[]): ExtensionIdentifierSet {
79
const result = new ExtensionIdentifierSet();
80
for (let i = 0, len = arr.length; i < len; i++) {
81
result.add(arr[i].description.identifier);
82
}
83
return result;
84
}
85
86
public static compute<T>(previous: readonly IExtensionPointUser<T>[] | null, current: readonly IExtensionPointUser<T>[]): ExtensionPointUserDelta<T> {
87
if (!previous || !previous.length) {
88
return new ExtensionPointUserDelta<T>(current, []);
89
}
90
if (!current || !current.length) {
91
return new ExtensionPointUserDelta<T>([], previous);
92
}
93
94
const previousSet = this._toSet(previous);
95
const currentSet = this._toSet(current);
96
97
const added = current.filter(user => !previousSet.has(user.description.identifier));
98
const removed = previous.filter(user => !currentSet.has(user.description.identifier));
99
100
return new ExtensionPointUserDelta<T>(added, removed);
101
}
102
103
constructor(
104
public readonly added: readonly IExtensionPointUser<T>[],
105
public readonly removed: readonly IExtensionPointUser<T>[],
106
) { }
107
}
108
109
export class ExtensionPoint<T> implements IExtensionPoint<T> {
110
111
public readonly name: string;
112
public readonly defaultExtensionKind: ExtensionKind[] | undefined;
113
public readonly canHandleResolver?: boolean;
114
115
private _handler: IExtensionPointHandler<T> | null;
116
private _users: IExtensionPointUser<T>[] | null;
117
private _delta: ExtensionPointUserDelta<T> | null;
118
119
constructor(name: string, defaultExtensionKind: ExtensionKind[] | undefined, canHandleResolver?: boolean) {
120
this.name = name;
121
this.defaultExtensionKind = defaultExtensionKind;
122
this.canHandleResolver = canHandleResolver;
123
this._handler = null;
124
this._users = null;
125
this._delta = null;
126
}
127
128
setHandler(handler: IExtensionPointHandler<T>): IDisposable {
129
if (this._handler !== null) {
130
throw new Error('Handler already set!');
131
}
132
this._handler = handler;
133
this._handle();
134
135
return {
136
dispose: () => {
137
this._handler = null;
138
}
139
};
140
}
141
142
acceptUsers(users: IExtensionPointUser<T>[]): void {
143
this._delta = ExtensionPointUserDelta.compute(this._users, users);
144
this._users = users;
145
this._handle();
146
}
147
148
private _handle(): void {
149
if (this._handler === null || this._users === null || this._delta === null) {
150
return;
151
}
152
153
try {
154
this._handler(this._users, this._delta);
155
} catch (err) {
156
onUnexpectedError(err);
157
}
158
}
159
}
160
161
const extensionKindSchema: IJSONSchema = {
162
type: 'string',
163
enum: [
164
'ui',
165
'workspace'
166
],
167
enumDescriptions: [
168
nls.localize('ui', "UI extension kind. In a remote window, such extensions are enabled only when available on the local machine."),
169
nls.localize('workspace', "Workspace extension kind. In a remote window, such extensions are enabled only when available on the remote."),
170
],
171
};
172
173
const schemaId = 'vscode://schemas/vscode-extensions';
174
export const schema: IJSONSchema = {
175
properties: {
176
engines: {
177
type: 'object',
178
description: nls.localize('vscode.extension.engines', "Engine compatibility."),
179
properties: {
180
'vscode': {
181
type: 'string',
182
description: nls.localize('vscode.extension.engines.vscode', 'For VS Code extensions, specifies the VS Code version that the extension is compatible with. Cannot be *. For example: ^0.10.5 indicates compatibility with a minimum VS Code version of 0.10.5.'),
183
default: '^1.22.0',
184
}
185
}
186
},
187
publisher: {
188
description: nls.localize('vscode.extension.publisher', 'The publisher of the VS Code extension.'),
189
type: 'string'
190
},
191
displayName: {
192
description: nls.localize('vscode.extension.displayName', 'The display name for the extension used in the VS Code gallery.'),
193
type: 'string'
194
},
195
categories: {
196
description: nls.localize('vscode.extension.categories', 'The categories used by the VS Code gallery to categorize the extension.'),
197
type: 'array',
198
uniqueItems: true,
199
items: {
200
oneOf: [{
201
type: 'string',
202
enum: EXTENSION_CATEGORIES,
203
},
204
{
205
type: 'string',
206
const: 'Languages',
207
deprecationMessage: nls.localize('vscode.extension.category.languages.deprecated', 'Use \'Programming Languages\' instead'),
208
}]
209
}
210
},
211
galleryBanner: {
212
type: 'object',
213
description: nls.localize('vscode.extension.galleryBanner', 'Banner used in the VS Code marketplace.'),
214
properties: {
215
color: {
216
description: nls.localize('vscode.extension.galleryBanner.color', 'The banner color on the VS Code marketplace page header.'),
217
type: 'string'
218
},
219
theme: {
220
description: nls.localize('vscode.extension.galleryBanner.theme', 'The color theme for the font used in the banner.'),
221
type: 'string',
222
enum: ['dark', 'light']
223
}
224
}
225
},
226
contributes: {
227
description: nls.localize('vscode.extension.contributes', 'All contributions of the VS Code extension represented by this package.'),
228
type: 'object',
229
properties: {
230
// extensions will fill in
231
} as any as { [key: string]: any },
232
default: {}
233
},
234
preview: {
235
type: 'boolean',
236
description: nls.localize('vscode.extension.preview', 'Sets the extension to be flagged as a Preview in the Marketplace.'),
237
},
238
enableProposedApi: {
239
type: 'boolean',
240
deprecationMessage: nls.localize('vscode.extension.enableProposedApi.deprecated', 'Use `enabledApiProposals` instead.'),
241
},
242
enabledApiProposals: {
243
markdownDescription: nls.localize('vscode.extension.enabledApiProposals', 'Enable API proposals to try them out. Only valid **during development**. Extensions **cannot be published** with this property. For more details visit: https://code.visualstudio.com/api/advanced-topics/using-proposed-api'),
244
type: 'array',
245
uniqueItems: true,
246
items: {
247
type: 'string',
248
enum: Object.keys(allApiProposals).map(proposalName => proposalName),
249
markdownEnumDescriptions: Object.values(allApiProposals).map(value => value.proposal)
250
}
251
},
252
api: {
253
markdownDescription: nls.localize('vscode.extension.api', 'Describe the API provided by this extension. For more details visit: https://code.visualstudio.com/api/advanced-topics/remote-extensions#handling-dependencies-with-remote-extensions'),
254
type: 'string',
255
enum: ['none'],
256
enumDescriptions: [
257
nls.localize('vscode.extension.api.none', "Give up entirely the ability to export any APIs. This allows other extensions that depend on this extension to run in a separate extension host process or in a remote machine.")
258
]
259
},
260
activationEvents: {
261
description: nls.localize('vscode.extension.activationEvents', 'Activation events for the VS Code extension.'),
262
type: 'array',
263
items: {
264
type: 'string',
265
defaultSnippets: [
266
{
267
label: 'onWebviewPanel',
268
description: nls.localize('vscode.extension.activationEvents.onWebviewPanel', 'An activation event emmited when a webview is loaded of a certain viewType'),
269
body: 'onWebviewPanel:viewType'
270
},
271
{
272
label: 'onLanguage',
273
description: nls.localize('vscode.extension.activationEvents.onLanguage', 'An activation event emitted whenever a file that resolves to the specified language gets opened.'),
274
body: 'onLanguage:${1:languageId}'
275
},
276
{
277
label: 'onCommand',
278
description: nls.localize('vscode.extension.activationEvents.onCommand', 'An activation event emitted whenever the specified command gets invoked.'),
279
body: 'onCommand:${2:commandId}'
280
},
281
{
282
label: 'onDebug',
283
description: nls.localize('vscode.extension.activationEvents.onDebug', 'An activation event emitted whenever a user is about to start debugging or about to setup debug configurations.'),
284
body: 'onDebug'
285
},
286
{
287
label: 'onDebugInitialConfigurations',
288
description: nls.localize('vscode.extension.activationEvents.onDebugInitialConfigurations', 'An activation event emitted whenever a "launch.json" needs to be created (and all provideDebugConfigurations methods need to be called).'),
289
body: 'onDebugInitialConfigurations'
290
},
291
{
292
label: 'onDebugDynamicConfigurations',
293
description: nls.localize('vscode.extension.activationEvents.onDebugDynamicConfigurations', 'An activation event emitted whenever a list of all debug configurations needs to be created (and all provideDebugConfigurations methods for the "dynamic" scope need to be called).'),
294
body: 'onDebugDynamicConfigurations'
295
},
296
{
297
label: 'onDebugResolve',
298
description: nls.localize('vscode.extension.activationEvents.onDebugResolve', 'An activation event emitted whenever a debug session with the specific type is about to be launched (and a corresponding resolveDebugConfiguration method needs to be called).'),
299
body: 'onDebugResolve:${6:type}'
300
},
301
{
302
label: 'onDebugAdapterProtocolTracker',
303
description: nls.localize('vscode.extension.activationEvents.onDebugAdapterProtocolTracker', 'An activation event emitted whenever a debug session with the specific type is about to be launched and a debug protocol tracker might be needed.'),
304
body: 'onDebugAdapterProtocolTracker:${6:type}'
305
},
306
{
307
label: 'workspaceContains',
308
description: nls.localize('vscode.extension.activationEvents.workspaceContains', 'An activation event emitted whenever a folder is opened that contains at least a file matching the specified glob pattern.'),
309
body: 'workspaceContains:${4:filePattern}'
310
},
311
{
312
label: 'onStartupFinished',
313
description: nls.localize('vscode.extension.activationEvents.onStartupFinished', 'An activation event emitted after the start-up finished (after all `*` activated extensions have finished activating).'),
314
body: 'onStartupFinished'
315
},
316
{
317
label: 'onTaskType',
318
description: nls.localize('vscode.extension.activationEvents.onTaskType', 'An activation event emitted whenever tasks of a certain type need to be listed or resolved.'),
319
body: 'onTaskType:${1:taskType}'
320
},
321
{
322
label: 'onFileSystem',
323
description: nls.localize('vscode.extension.activationEvents.onFileSystem', 'An activation event emitted whenever a file or folder is accessed with the given scheme.'),
324
body: 'onFileSystem:${1:scheme}'
325
},
326
{
327
label: 'onEditSession',
328
description: nls.localize('vscode.extension.activationEvents.onEditSession', 'An activation event emitted whenever an edit session is accessed with the given scheme.'),
329
body: 'onEditSession:${1:scheme}'
330
},
331
{
332
label: 'onSearch',
333
description: nls.localize('vscode.extension.activationEvents.onSearch', 'An activation event emitted whenever a search is started in the folder with the given scheme.'),
334
body: 'onSearch:${7:scheme}'
335
},
336
{
337
label: 'onView',
338
body: 'onView:${5:viewId}',
339
description: nls.localize('vscode.extension.activationEvents.onView', 'An activation event emitted whenever the specified view is expanded.'),
340
},
341
{
342
label: 'onUri',
343
body: 'onUri',
344
description: nls.localize('vscode.extension.activationEvents.onUri', 'An activation event emitted whenever a system-wide Uri directed towards this extension is open.'),
345
},
346
{
347
label: 'onOpenExternalUri',
348
body: 'onOpenExternalUri',
349
description: nls.localize('vscode.extension.activationEvents.onOpenExternalUri', 'An activation event emitted whenever a external uri (such as an http or https link) is being opened.'),
350
},
351
{
352
label: 'onCustomEditor',
353
body: 'onCustomEditor:${9:viewType}',
354
description: nls.localize('vscode.extension.activationEvents.onCustomEditor', 'An activation event emitted whenever the specified custom editor becomes visible.'),
355
},
356
{
357
label: 'onNotebook',
358
body: 'onNotebook:${1:type}',
359
description: nls.localize('vscode.extension.activationEvents.onNotebook', 'An activation event emitted whenever the specified notebook document is opened.'),
360
},
361
{
362
label: 'onAuthenticationRequest',
363
body: 'onAuthenticationRequest:${11:authenticationProviderId}',
364
description: nls.localize('vscode.extension.activationEvents.onAuthenticationRequest', 'An activation event emitted whenever sessions are requested from the specified authentication provider.')
365
},
366
{
367
label: 'onRenderer',
368
description: nls.localize('vscode.extension.activationEvents.onRenderer', 'An activation event emitted whenever a notebook output renderer is used.'),
369
body: 'onRenderer:${11:rendererId}'
370
},
371
{
372
label: 'onTerminalProfile',
373
body: 'onTerminalProfile:${1:terminalId}',
374
description: nls.localize('vscode.extension.activationEvents.onTerminalProfile', 'An activation event emitted when a specific terminal profile is launched.'),
375
},
376
{
377
label: 'onTerminalQuickFixRequest',
378
body: 'onTerminalQuickFixRequest:${1:quickFixId}',
379
description: nls.localize('vscode.extension.activationEvents.onTerminalQuickFixRequest', 'An activation event emitted when a command matches the selector associated with this ID'),
380
},
381
{
382
label: 'onWalkthrough',
383
body: 'onWalkthrough:${1:walkthroughID}',
384
description: nls.localize('vscode.extension.activationEvents.onWalkthrough', 'An activation event emitted when a specified walkthrough is opened.'),
385
},
386
{
387
label: 'onIssueReporterOpened',
388
body: 'onIssueReporterOpened',
389
description: nls.localize('vscode.extension.activationEvents.onIssueReporterOpened', 'An activation event emitted when the issue reporter is opened.'),
390
},
391
{
392
label: 'onChatParticipant',
393
body: 'onChatParticipant:${1:participantId}',
394
description: nls.localize('vscode.extension.activationEvents.onChatParticipant', 'An activation event emitted when the specified chat participant is invoked.'),
395
},
396
{
397
label: 'onLanguageModelChatProvider',
398
body: 'onLanguageModelChatProvider:${1:vendor}',
399
description: nls.localize('vscode.extension.activationEvents.onLanguageModelChatProvider', 'An activation event emitted when a chat model provider for the given vendor is requested.'),
400
},
401
{
402
label: 'onLanguageModelTool',
403
body: 'onLanguageModelTool:${1:toolId}',
404
description: nls.localize('vscode.extension.activationEvents.onLanguageModelTool', 'An activation event emitted when the specified language model tool is invoked.'),
405
},
406
{
407
label: 'onTerminal',
408
body: 'onTerminal:{1:shellType}',
409
description: nls.localize('vscode.extension.activationEvents.onTerminal', 'An activation event emitted when a terminal of the given shell type is opened.'),
410
},
411
{
412
label: 'onTerminalCompletionsRequested',
413
body: 'onTerminalCompletionsRequested',
414
description: nls.localize('vscode.extension.activationEvents.onTerminalCompletionsRequested', 'An activation event emitted when terminal completions are requested.'),
415
},
416
{
417
label: 'onTerminalShellIntegration',
418
body: 'onTerminalShellIntegration:${1:shellType}',
419
description: nls.localize('vscode.extension.activationEvents.onTerminalShellIntegration', 'An activation event emitted when terminal shell integration is activated for the given shell type.'),
420
},
421
{
422
label: 'onMcpCollection',
423
description: nls.localize('vscode.extension.activationEvents.onMcpCollection', 'An activation event emitted whenver a tool from the MCP server is requested.'),
424
body: 'onMcpCollection:${2:collectionId}',
425
},
426
{
427
label: '*',
428
description: nls.localize('vscode.extension.activationEvents.star', 'An activation event emitted on VS Code startup. To ensure a great end user experience, please use this activation event in your extension only when no other activation events combination works in your use-case.'),
429
body: '*'
430
}
431
],
432
}
433
},
434
badges: {
435
type: 'array',
436
description: nls.localize('vscode.extension.badges', 'Array of badges to display in the sidebar of the Marketplace\'s extension page.'),
437
items: {
438
type: 'object',
439
required: ['url', 'href', 'description'],
440
properties: {
441
url: {
442
type: 'string',
443
description: nls.localize('vscode.extension.badges.url', 'Badge image URL.')
444
},
445
href: {
446
type: 'string',
447
description: nls.localize('vscode.extension.badges.href', 'Badge link.')
448
},
449
description: {
450
type: 'string',
451
description: nls.localize('vscode.extension.badges.description', 'Badge description.')
452
}
453
}
454
}
455
},
456
markdown: {
457
type: 'string',
458
description: nls.localize('vscode.extension.markdown', "Controls the Markdown rendering engine used in the Marketplace. Either github (default) or standard."),
459
enum: ['github', 'standard'],
460
default: 'github'
461
},
462
qna: {
463
default: 'marketplace',
464
description: nls.localize('vscode.extension.qna', "Controls the Q&A link in the Marketplace. Set to marketplace to enable the default Marketplace Q & A site. Set to a string to provide the URL of a custom Q & A site. Set to false to disable Q & A altogether."),
465
anyOf: [
466
{
467
type: ['string', 'boolean'],
468
enum: ['marketplace', false]
469
},
470
{
471
type: 'string'
472
}
473
]
474
},
475
extensionDependencies: {
476
description: nls.localize('vscode.extension.extensionDependencies', 'Dependencies to other extensions. The identifier of an extension is always ${publisher}.${name}. For example: vscode.csharp.'),
477
type: 'array',
478
uniqueItems: true,
479
items: {
480
type: 'string',
481
pattern: EXTENSION_IDENTIFIER_PATTERN
482
}
483
},
484
extensionPack: {
485
description: nls.localize('vscode.extension.contributes.extensionPack', "A set of extensions that can be installed together. The identifier of an extension is always ${publisher}.${name}. For example: vscode.csharp."),
486
type: 'array',
487
uniqueItems: true,
488
items: {
489
type: 'string',
490
pattern: EXTENSION_IDENTIFIER_PATTERN
491
}
492
},
493
extensionKind: {
494
description: nls.localize('extensionKind', "Define the kind of an extension. `ui` extensions are installed and run on the local machine while `workspace` extensions run on the remote."),
495
type: 'array',
496
items: extensionKindSchema,
497
default: ['workspace'],
498
defaultSnippets: [
499
{
500
body: ['ui'],
501
description: nls.localize('extensionKind.ui', "Define an extension which can run only on the local machine when connected to remote window.")
502
},
503
{
504
body: ['workspace'],
505
description: nls.localize('extensionKind.workspace', "Define an extension which can run only on the remote machine when connected remote window.")
506
},
507
{
508
body: ['ui', 'workspace'],
509
description: nls.localize('extensionKind.ui-workspace', "Define an extension which can run on either side, with a preference towards running on the local machine.")
510
},
511
{
512
body: ['workspace', 'ui'],
513
description: nls.localize('extensionKind.workspace-ui', "Define an extension which can run on either side, with a preference towards running on the remote machine.")
514
},
515
{
516
body: [],
517
description: nls.localize('extensionKind.empty', "Define an extension which cannot run in a remote context, neither on the local, nor on the remote machine.")
518
}
519
]
520
},
521
capabilities: {
522
description: nls.localize('vscode.extension.capabilities', "Declare the set of supported capabilities by the extension."),
523
type: 'object',
524
properties: {
525
virtualWorkspaces: {
526
description: nls.localize('vscode.extension.capabilities.virtualWorkspaces', "Declares whether the extension should be enabled in virtual workspaces. A virtual workspace is a workspace which is not backed by any on-disk resources. When false, this extension will be automatically disabled in virtual workspaces. Default is true."),
527
type: ['boolean', 'object'],
528
defaultSnippets: [
529
{ label: 'limited', body: { supported: '${1:limited}', description: '${2}' } },
530
{ label: 'false', body: { supported: false, description: '${2}' } },
531
],
532
default: true.valueOf,
533
properties: {
534
supported: {
535
markdownDescription: nls.localize('vscode.extension.capabilities.virtualWorkspaces.supported', "Declares the level of support for virtual workspaces by the extension."),
536
type: ['string', 'boolean'],
537
enum: ['limited', true, false],
538
enumDescriptions: [
539
nls.localize('vscode.extension.capabilities.virtualWorkspaces.supported.limited', "The extension will be enabled in virtual workspaces with some functionality disabled."),
540
nls.localize('vscode.extension.capabilities.virtualWorkspaces.supported.true', "The extension will be enabled in virtual workspaces with all functionality enabled."),
541
nls.localize('vscode.extension.capabilities.virtualWorkspaces.supported.false', "The extension will not be enabled in virtual workspaces."),
542
]
543
},
544
description: {
545
type: 'string',
546
markdownDescription: nls.localize('vscode.extension.capabilities.virtualWorkspaces.description', "A description of how virtual workspaces affects the extensions behavior and why it is needed. This only applies when `supported` is not `true`."),
547
}
548
}
549
},
550
untrustedWorkspaces: {
551
description: nls.localize('vscode.extension.capabilities.untrustedWorkspaces', 'Declares how the extension should be handled in untrusted workspaces.'),
552
type: 'object',
553
required: ['supported'],
554
defaultSnippets: [
555
{ body: { supported: '${1:limited}', description: '${2}' } },
556
],
557
properties: {
558
supported: {
559
markdownDescription: nls.localize('vscode.extension.capabilities.untrustedWorkspaces.supported', "Declares the level of support for untrusted workspaces by the extension."),
560
type: ['string', 'boolean'],
561
enum: ['limited', true, false],
562
enumDescriptions: [
563
nls.localize('vscode.extension.capabilities.untrustedWorkspaces.supported.limited', "The extension will be enabled in untrusted workspaces with some functionality disabled."),
564
nls.localize('vscode.extension.capabilities.untrustedWorkspaces.supported.true', "The extension will be enabled in untrusted workspaces with all functionality enabled."),
565
nls.localize('vscode.extension.capabilities.untrustedWorkspaces.supported.false', "The extension will not be enabled in untrusted workspaces."),
566
]
567
},
568
restrictedConfigurations: {
569
description: nls.localize('vscode.extension.capabilities.untrustedWorkspaces.restrictedConfigurations', "A list of configuration keys contributed by the extension that should not use workspace values in untrusted workspaces."),
570
type: 'array',
571
items: {
572
type: 'string'
573
}
574
},
575
description: {
576
type: 'string',
577
markdownDescription: nls.localize('vscode.extension.capabilities.untrustedWorkspaces.description', "A description of how workspace trust affects the extensions behavior and why it is needed. This only applies when `supported` is not `true`."),
578
}
579
}
580
}
581
}
582
},
583
sponsor: {
584
description: nls.localize('vscode.extension.contributes.sponsor', "Specify the location from where users can sponsor your extension."),
585
type: 'object',
586
defaultSnippets: [
587
{ body: { url: '${1:https:}' } },
588
],
589
properties: {
590
'url': {
591
description: nls.localize('vscode.extension.contributes.sponsor.url', "URL from where users can sponsor your extension. It must be a valid URL with a HTTP or HTTPS protocol. Example value: https://github.com/sponsors/nvaccess"),
592
type: 'string',
593
}
594
}
595
},
596
scripts: {
597
type: 'object',
598
properties: {
599
'vscode:prepublish': {
600
description: nls.localize('vscode.extension.scripts.prepublish', 'Script executed before the package is published as a VS Code extension.'),
601
type: 'string'
602
},
603
'vscode:uninstall': {
604
description: nls.localize('vscode.extension.scripts.uninstall', 'Uninstall hook for VS Code extension. Script that gets executed when the extension is completely uninstalled from VS Code which is when VS Code is restarted (shutdown and start) after the extension is uninstalled. Only Node scripts are supported.'),
605
type: 'string'
606
}
607
}
608
},
609
icon: {
610
type: 'string',
611
description: nls.localize('vscode.extension.icon', 'The path to a 128x128 pixel icon.')
612
},
613
l10n: {
614
type: 'string',
615
description: nls.localize({
616
key: 'vscode.extension.l10n',
617
comment: [
618
'{Locked="bundle.l10n._locale_.json"}',
619
'{Locked="vscode.l10n API"}'
620
]
621
}, 'The relative path to a folder containing localization (bundle.l10n.*.json) files. Must be specified if you are using the vscode.l10n API.')
622
},
623
pricing: {
624
type: 'string',
625
markdownDescription: nls.localize('vscode.extension.pricing', 'The pricing information for the extension. Can be Free (default) or Trial. For more details visit: https://code.visualstudio.com/api/working-with-extensions/publishing-extension#extension-pricing-label'),
626
enum: ['Free', 'Trial'],
627
default: 'Free'
628
}
629
}
630
};
631
632
export type removeArray<T> = T extends Array<infer X> ? X : T;
633
634
export interface IExtensionPointDescriptor<T> {
635
extensionPoint: string;
636
deps?: IExtensionPoint<any>[];
637
jsonSchema: IJSONSchema;
638
defaultExtensionKind?: ExtensionKind[];
639
canHandleResolver?: boolean;
640
/**
641
* A function which runs before the extension point has been validated and which
642
* should collect automatic activation events from the contribution.
643
*/
644
activationEventsGenerator?: IActivationEventsGenerator<removeArray<T>>;
645
}
646
647
export class ExtensionsRegistryImpl {
648
649
private readonly _extensionPoints = new Map<string, ExtensionPoint<any>>();
650
651
public registerExtensionPoint<T>(desc: IExtensionPointDescriptor<T>): IExtensionPoint<T> {
652
if (this._extensionPoints.has(desc.extensionPoint)) {
653
throw new Error('Duplicate extension point: ' + desc.extensionPoint);
654
}
655
const result = new ExtensionPoint<T>(desc.extensionPoint, desc.defaultExtensionKind, desc.canHandleResolver);
656
this._extensionPoints.set(desc.extensionPoint, result);
657
if (desc.activationEventsGenerator) {
658
ImplicitActivationEvents.register(desc.extensionPoint, desc.activationEventsGenerator);
659
}
660
661
schema.properties!['contributes'].properties![desc.extensionPoint] = desc.jsonSchema;
662
schemaRegistry.registerSchema(schemaId, schema);
663
664
return result;
665
}
666
667
public getExtensionPoints(): ExtensionPoint<any>[] {
668
return Array.from(this._extensionPoints.values());
669
}
670
}
671
672
const PRExtensions = {
673
ExtensionsRegistry: 'ExtensionsRegistry'
674
};
675
Registry.add(PRExtensions.ExtensionsRegistry, new ExtensionsRegistryImpl());
676
export const ExtensionsRegistry: ExtensionsRegistryImpl = Registry.as(PRExtensions.ExtensionsRegistry);
677
678
schemaRegistry.registerSchema(schemaId, schema);
679
680
681
schemaRegistry.registerSchema(productSchemaId, {
682
properties: {
683
extensionEnabledApiProposals: {
684
description: nls.localize('product.extensionEnabledApiProposals', "API proposals that the respective extensions can freely use."),
685
type: 'object',
686
properties: {},
687
additionalProperties: {
688
anyOf: [{
689
type: 'array',
690
uniqueItems: true,
691
items: {
692
type: 'string',
693
enum: Object.keys(allApiProposals),
694
markdownEnumDescriptions: Object.values(allApiProposals).map(value => value.proposal)
695
}
696
}]
697
}
698
}
699
}
700
});
701
702