src/vs/workbench/services/extensions/common/extensions.ts

753 LOC · 531 covered · 222 uncovered · 47 ranges · 2117 concepts · 14 introducers · 1165 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 > /*--------------------------------------------------------------------------------------------- extensions.ts ×23
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 { Event } from '../../../../base/common/event.js';
7 > import { Disposable, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
8 > import { raceTimeout } from '../../../../base/common/async.js';
9 > import Severity from '../../../../base/common/severity.js';
10 > import { URI } from '../../../../base/common/uri.js';
11 > import { IMessagePassingProtocol } from '../../../../base/parts/ipc/common/ipc.js';
12 > import { IAssignmentService } from '../../../../platform/assignment/common/assignment.js';
13 > import { getExtensionId, getGalleryExtensionId } from '../../../../platform/extensionManagement/common/extensionManagementUtil.js';
14 > import { ImplicitActivationEvents } from '../../../../platform/extensionManagement/common/implicitActivationEvents.js';
15 > import { ExtensionIdentifier, ExtensionIdentifierMap, ExtensionIdentifierSet, ExtensionType, IExtension, IExtensionContributions, IExtensionDescription, TargetPlatform } from '../../../../platform/extensions/common/extensions.js';
16 > import { ApiProposalName } from '../../../../platform/extensions/common/extensionsApiProposals.js';
17 > import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
18 > import { IV8Profile } from '../../../../platform/profiling/common/profiling.js';
19 > import { ExtensionHostKind } from './extensionHostKind.js';
20 > import { IExtensionDescriptionDelta, IExtensionDescriptionSnapshot } from './extensionHostProtocol.js';
21 > import { ExtensionRunningLocation } from './extensionRunningLocation.js';
22 > import { IExtensionPoint } from './extensionsRegistry.js';
23 >
24 > export const nullExtensionDescription = Object.freeze<IExtensionDescription>({
25 > identifier: new ExtensionIdentifier('nullExtensionDescription'),
26 > name: 'Null Extension Description',
27 > version: '0.0.0',
28 > publisher: 'vscode',
29 > engines: { vscode: '' },
30 > extensionLocation: URI.parse('void:location'),
31 > isBuiltin: false,
32 > targetPlatform: TargetPlatform.UNDEFINED,
33 > isUserBuiltin: false,
34 > isUnderDevelopment: false,
35 > preRelease: false,
36 > });
37 >
38 > export type WebWorkerExtHostConfigValue = boolean | 'auto';
39 > export const webWorkerExtHostConfig = 'extensions.webWorker';
40 >
41 > export const IExtensionService = createDecorator<IExtensionService>('extensionService');
42 >
43 > export interface IMessage {
44 > type: Severity;
45 > message: string;
46 > extensionId: ExtensionIdentifier;
47 > extensionPointId: string;
48 > }
49 >
50 > export interface IExtensionsStatus {
51 > id: ExtensionIdentifier;
52 > messages: IMessage[];
53 > activationStarted: boolean;
54 > activationTimes: ActivationTimes | undefined;
55 > runtimeErrors: Error[];
56 > runningLocation: ExtensionRunningLocation | null;
57 > }
58 >
59 > export class MissingExtensionDependency {
60 > constructor(readonly dependency: string) { }
61 > }
62 >
63 > /**
64 > * e.g.
65 > * ```
66 > * {
67 > * startTime: 1511954813493000,
68 > * endTime: 1511954835590000,
69 > * deltas: [ 100, 1500, 123456, 1500, 100000 ],
70 > * ids: [ 'idle', 'self', 'extension1', 'self', 'idle' ]
71 > * }
72 > * ```
73 > */
74 > export interface IExtensionHostProfile {
75 > /**
76 > * Profiling start timestamp in microseconds.
77 > */
78 > startTime: number;
79 > /**
80 > * Profiling end timestamp in microseconds.
81 > */
82 > endTime: number;
83 > /**
84 > * Duration of segment in microseconds.
85 > */
86 > deltas: number[];
87 > /**
88 > * Segment identifier: extension id or one of the four known strings.
89 > */
90 > ids: ProfileSegmentId[];
91 >
92 > /**
93 > * Get the information as a .cpuprofile.
94 > */
95 > data: IV8Profile;
96 >
97 > /**
98 > * Get the aggregated time per segmentId
99 > */
100 > getAggregatedTimes(): Map<ProfileSegmentId, number>;
101 > }
102 >
103 > export const enum ExtensionHostStartup {
104 > /**
105 > * The extension host should be launched immediately and doesn't require a `$startExtensionHost` call.
106 > */
107 > EagerAutoStart = 1,
108 > /**
109 > * The extension host should be launched immediately and needs a `$startExtensionHost` call.
110 > */
111 > EagerManualStart = 2,
112 > /**
113 > * The extension host should be launched lazily and only when it has extensions it needs to host. It doesn't require a `$startExtensionHost` call.
114 > */
115 > LazyAutoStart = 3,
116 > }
117 >
118 > export interface IExtensionInspectInfo {
119 > readonly port: number;
120 > readonly host: string;
121 > readonly devtoolsUrl?: string;
122 > readonly devtoolsLabel?: string;
123 > }
124 >
125 > export interface IExtensionHost {
126 > readonly pid: number | null;
127 > readonly runningLocation: ExtensionRunningLocation;
128 > readonly remoteAuthority: string | null;
129 > readonly startup: ExtensionHostStartup;
130 > /**
131 > * A collection of extensions which includes information about which
132 > * extension will execute or is executing on this extension host.
133 > * **NOTE**: this will reflect extensions correctly only after `start()` resolves.
134 > */
135 > readonly extensions: ExtensionHostExtensions | null;
136 > readonly onExit: Event<[number, string | null]>;
137 >
138 > start(): Promise<IMessagePassingProtocol>;
139 > getInspectPort(): IExtensionInspectInfo | undefined;
140 > enableInspectPort(): Promise<boolean>;
141 > disconnect?(): Promise<void>;
142 > dispose(): void;
143 > }
144 >
145 > export class ExtensionHostExtensions {
146 > private _versionId: number;
147 > private _allExtensions: IExtensionDescription[];
148 > private _myExtensions: ExtensionIdentifier[];
149 > private _myActivationEvents: Set<string> | null;
150 >
151 > public get versionId(): number {
152 return this._versionId;
153 }
155 > public get allExtensions(): IExtensionDescription[] {
156 return this._allExtensions;
157 }
159 > public get myExtensions(): ExtensionIdentifier[] {
160 return this._myExtensions;
161 }
163 > constructor(versionId: number, allExtensions: readonly IExtensionDescription[], myExtensions: ExtensionIdentifier[]) {
164 this._versionId = versionId;
165 this._allExtensions = allExtensions.slice(0);
166 this._myExtensions = myExtensions.slice(0);
167 this._myActivationEvents = null;
168 }
170 > toSnapshot(): IExtensionDescriptionSnapshot {
171 return {
172 versionId: this._versionId,
173 allExtensions: this._allExtensions,
174 myExtensions: this._myExtensions,
175 activationEvents: ImplicitActivationEvents.createActivationEventsMap(this._allExtensions)
176 };
177 }
179 > public set(versionId: number, allExtensions: IExtensionDescription[], myExtensions: ExtensionIdentifier[]): IExtensionDescriptionDelta {
180 if (this._versionId > versionId) {
181 throw new Error(`ExtensionHostExtensions: invalid versionId ${versionId} (current: ${this._versionId})`);
182 }
183 const toRemove: ExtensionIdentifier[] = [];
184 const toAdd: IExtensionDescription[] = [];
185 const myToRemove: ExtensionIdentifier[] = [];
186 const myToAdd: ExtensionIdentifier[] = [];
187
188 const oldExtensionsMap = extensionDescriptionArrayToMap(this._allExtensions);
189 const newExtensionsMap = extensionDescriptionArrayToMap(allExtensions);
190 const extensionsAreTheSame = (a: IExtensionDescription, b: IExtensionDescription) => {
191 return (
192 (a.extensionLocation.toString() === b.extensionLocation.toString())
193 || (a.isBuiltin === b.isBuiltin)
194 || (a.isUserBuiltin === b.isUserBuiltin)
195 || (a.isUnderDevelopment === b.isUnderDevelopment)
196 );
197 };
198
199 for (const oldExtension of this._allExtensions) {
200 const newExtension = newExtensionsMap.get(oldExtension.identifier);
201 if (!newExtension) {
202 toRemove.push(oldExtension.identifier);
203 oldExtensionsMap.delete(oldExtension.identifier);
204 continue;
205 }
206 if (!extensionsAreTheSame(oldExtension, newExtension)) {
207 // The new extension is different than the old one
208 // (e.g. maybe it executes in a different location)
209 toRemove.push(oldExtension.identifier);
210 oldExtensionsMap.delete(oldExtension.identifier);
211 continue;
212 }
213 }
214 for (const newExtension of allExtensions) {
215 const oldExtension = oldExtensionsMap.get(newExtension.identifier);
216 if (!oldExtension) {
217 toAdd.push(newExtension);
218 continue;
219 }
220 if (!extensionsAreTheSame(oldExtension, newExtension)) {
221 // The new extension is different than the old one
222 // (e.g. maybe it executes in a different location)
223 toRemove.push(oldExtension.identifier);
224 oldExtensionsMap.delete(oldExtension.identifier);
225 continue;
226 }
227 }
228
229 const myOldExtensionsSet = new ExtensionIdentifierSet(this._myExtensions);
230 const myNewExtensionsSet = new ExtensionIdentifierSet(myExtensions);
231 for (const oldExtensionId of this._myExtensions) {
232 if (!myNewExtensionsSet.has(oldExtensionId)) {
233 myToRemove.push(oldExtensionId);
234 }
235 }
236 for (const newExtensionId of myExtensions) {
237 if (!myOldExtensionsSet.has(newExtensionId)) {
238 myToAdd.push(newExtensionId);
239 }
240 }
241
242 const addActivationEvents = ImplicitActivationEvents.createActivationEventsMap(toAdd);
243 const delta = { versionId, toRemove, toAdd, addActivationEvents, myToRemove, myToAdd };
244 this.delta(delta);
245 return delta;
246 }
248 > public delta(extensionsDelta: IExtensionDescriptionDelta): IExtensionDescriptionDelta | null {
249 if (this._versionId >= extensionsDelta.versionId) {
250 // ignore older deltas
251 return null;
252 }
253
254 const { toRemove, toAdd, myToRemove, myToAdd } = extensionsDelta;
255 // First handle removals
256 const toRemoveSet = new ExtensionIdentifierSet(toRemove);
257 const myToRemoveSet = new ExtensionIdentifierSet(myToRemove);
258 for (let i = 0; i < this._allExtensions.length; i++) {
259 if (toRemoveSet.has(this._allExtensions[i].identifier)) {
260 this._allExtensions.splice(i, 1);
261 i--;
262 }
263 }
264 for (let i = 0; i < this._myExtensions.length; i++) {
265 if (myToRemoveSet.has(this._myExtensions[i])) {
266 this._myExtensions.splice(i, 1);
267 i--;
268 }
269 }
270 // Then handle additions
271 for (const extension of toAdd) {
272 this._allExtensions.push(extension);
273 }
274 for (const extensionId of myToAdd) {
275 this._myExtensions.push(extensionId);
276 }
277
278 // clear cached activation events
279 this._myActivationEvents = null;
280
281 return extensionsDelta;
282 }
284 > public containsExtension(extensionId: ExtensionIdentifier): boolean {
285 for (const myExtensionId of this._myExtensions) {
286 if (ExtensionIdentifier.equals(myExtensionId, extensionId)) {
287 return true;
288 }
289 }
290 return false;
291 }
293 > public containsActivationEvent(activationEvent: string): boolean {
294 if (!this._myActivationEvents) {
295 this._myActivationEvents = this._readMyActivationEvents();
296 }
297 return this._myActivationEvents.has(activationEvent);
298 }
300 > private _readMyActivationEvents(): Set<string> {
301 const result = new Set<string>();
302
303 for (const extensionDescription of this._allExtensions) {
304 if (!this.containsExtension(extensionDescription.identifier)) {
305 continue;
306 }
307
308 const activationEvents = ImplicitActivationEvents.readActivationEvents(extensionDescription);
309 for (const activationEvent of activationEvents) {
310 result.add(activationEvent);
311 }
312 }
313
314 return result;
315 }
317 >
318 function extensionDescriptionArrayToMap(extensions: IExtensionDescription[]): ExtensionIdentifierMap<IExtensionDescription> {
319 const result = new ExtensionIdentifierMap<IExtensionDescription>();
320 for (const extension of extensions) {
321 result.set(extension.identifier, extension);
322 }
323 return result;
324 }
326 > export function isProposedApiEnabled(extension: IExtensionDescription, proposal: ApiProposalName): boolean {
327 > if (!extension.enabledApiProposals) { extensions.ts ×2
328 > return false; extensions.ts ×1
329 > }
330 > let enabled = extension.enabledApiProposals.includes(proposal); extensions.ts ×3
331 > if (!enabled && _proposedApiEnabledResolver?.(extension, proposal)) { extensions.ts ×2
332 > // an experiment can grant proposed API access to extension/proposal combinations extensions.ts ×1
333 > // that have not declared the proposal via their `enabledApiProposals`-property
334 > enabled = true;
335 > }
336 > if (!enabled) { extensions.ts ×3
337 > reportDisabledProposedApiUsage(extension, proposal); extensions.ts ×2
338 > }
339 > return enabled; extensions.ts ×3
340 > }
342 > export interface IProposedApiUsage {
343 > /**
344 > * The identifier of the extension that attempted to use the proposal.
345 > */
346 > readonly extensionId: string;
347 > /**
348 > * The name of the API proposal that the extension is not allowed to use.
349 > */
350 > readonly proposalName: ApiProposalName;
351 > }
352 >
353 > type ProposedApiUsageReporter = (usage: IProposedApiUsage) => void;
354 >
355 > let _proposedApiUsageReporter: ProposedApiUsageReporter | undefined;
356 > const _reportedProposedApiUsages = new Set<string>();
357 >
358 > /**
359 > * Registers a reporter that is invoked whenever an extension attempts to use a proposed API
360 > * that it has not declared via its `enabledApiProposals`-property. This is used to gather
361 > * telemetry about extensions that rely on proposed API they are not entitled to use.
362 > *
363 > * Each unique extension/proposal combination is reported at most once per session in order to
364 > * avoid flooding telemetry from the (potentially hot) call sites of {@link isProposedApiEnabled}.
365 > */
366 > export function setProposedApiUsageReporter(reporter: ProposedApiUsageReporter): IDisposable {
367 _proposedApiUsageReporter = reporter;
368 return toDisposable(() => {
369 if (_proposedApiUsageReporter === reporter) {
370 _proposedApiUsageReporter = undefined;
371 }
372 });
373 }
375 > function reportDisabledProposedApiUsage(extension: IExtensionDescription, proposal: ApiProposalName): void { extensions.ts ×2
376 > const reporter = _proposedApiUsageReporter;
377 > if (!reporter) {
378 > return;
379 > }
380 const key = `${ExtensionIdentifier.toKey(extension.identifier)}/${proposal}`;
381 if (_reportedProposedApiUsages.has(key)) {
382 return;
383 }
384 _reportedProposedApiUsages.add(key);
385 reporter({ extensionId: extension.identifier.value, proposalName: proposal });
386 }
388 > type ProposedApiEnabledResolver = (extension: IExtensionDescription, proposal: ApiProposalName) => boolean;
389 >
390 > let _proposedApiEnabledResolver: ProposedApiEnabledResolver | undefined;
391 >
392 > /**
393 > * The name of the experiment ("treatment") that can grant proposed API access to
394 > * extension/proposal combinations that have not declared the proposal themselves.
395 > */
396 > export const enabledApiProposalsFallbackExperimentName = 'extensionEnabledApiProposalsFallback';
397 >
398 > /**
399 > * Experiment value that explicitly blocks all proposals reaching the fallback.
400 > */
401 > export const enabledApiProposalsFallbackNone = 'none';
402 >
403 > /**
404 > * Resolves the value of the {@link enabledApiProposalsFallbackExperimentName}-experiment, or
405 > * `undefined` when it does not apply (non-`stable` quality) or cannot be read in time.
406 > */
407 export async function resolveEnabledApiProposalsFallbackExperiment(assignmentService: IAssignmentService, quality: string | undefined): Promise<string | undefined> {
408 if (quality !== 'stable') {
409 return undefined;
410 }
411 try {
412 // This runs while building the ext host init data (whose promise has no error handling) and
413 // the assignment service can block on its initial network fetch, so cap the wait and swallow
414 // errors: falling back to `undefined` keeps today's behavior and the value is read from the
415 // cache on the next start.
416 return await raceTimeout(assignmentService.getTreatment<string>(enabledApiProposalsFallbackExperimentName), 5000);
417 } catch {
418 return undefined;
419 }
420 }
422 > /**
423 > * Enables the {@link enabledApiProposalsFallbackExperimentName}-experiment which can grant proposed
424 > * API access to extension/proposal combinations that have not declared the proposal via their
425 > * `enabledApiProposals`-property. It only takes effect on `stable` builds.
426 > *
427 > * Note that the experiment only applies to extensions that already declare at least one proposal:
428 > * an extension with no `enabledApiProposals` at all is never granted access.
429 > *
430 > * @param value A comma-separated list of `publisher.extension:proposalName` entries. Any combination
431 > * that appears here will have {@link isProposedApiEnabled} return `true` even when the extension has
432 > * not declared that particular proposal. When unset, all proposals are allowed;
433 > * {@link enabledApiProposalsFallbackNone} blocks all proposals that reach the fallback.
434 > * @param quality The product quality. The experiment only takes effect when this is `stable`.
435 > */
436 > export function setEnabledApiProposalsFallbackExperiment(value: string | undefined, quality: string | undefined): IDisposable {
437 > if (quality !== 'stable') { extensions.ts ×4
438 > return Disposable.None; extensions.ts ×1
439 > }
441 > const allowed = new Set<string>();
442 > if (value !== undefined && value !== enabledApiProposalsFallbackNone) { extensions.ts ×4
443 > for (const entry of value.split(',')) { extensions.ts ×2
444 > const trimmed = entry.trim();
445 > const idx = trimmed.indexOf(':');
446 > if (idx <= 0 || idx === trimmed.length - 1) {
447 continue;
448 }
449 > const extensionId = ExtensionIdentifier.toKey(trimmed.slice(0, idx)); extensions.ts ×2
450 > const proposal = trimmed.slice(idx + 1);
451 > allowed.add(`${extensionId}:${proposal}`);
452 > }
453 > }
455 > const resolver: ProposedApiEnabledResolver = value === undefined
456 > ? () => true extensions.ts ×1
457 > : (extension, proposal) => allowed.has(`${ExtensionIdentifier.toKey(extension.identifier)}:${proposal}`); extensions.ts ×1
458 > _proposedApiEnabledResolver = resolver; extensions.ts ×4
459 > return toDisposable(() => {
460 > if (_proposedApiEnabledResolver === resolver) { extensions.ts ×3
461 > _proposedApiEnabledResolver = undefined;
462 > }
463 > }); extensions.ts ×4
464 > }
466 > export function checkProposedApiEnabled(extension: IExtensionDescription, proposal: ApiProposalName): void {
467 > if (!isProposedApiEnabled(extension, proposal)) { extHostChatAgents2.ts ×98
468 throw new Error(`Extension '${extension.identifier.value}' CANNOT use API proposal: ${proposal}.\nIts package.json#enabledApiProposals-property declares: ${extension.enabledApiProposals?.join(', ') ?? '[]'} but NOT ${proposal}.\n The missing proposal MUST be added and you must start in extension development mode or use the following command line switch: --enable-proposed-api ${extension.identifier.value}`);
469 }
472 >
473 > /**
474 > * Extension id or one of the four known program states.
475 > */
476 > export type ProfileSegmentId = string | 'idle' | 'program' | 'gc' | 'self';
477 >
478 > export interface ExtensionActivationReason {
479 > readonly startup: boolean;
480 > readonly extensionId: ExtensionIdentifier;
481 > readonly activationEvent: string;
482 > }
483 >
484 > export class ActivationTimes {
485 > constructor(
486 public readonly codeLoadingTime: number,
487 public readonly activateCallTime: number,
488 public readonly activateResolvedTime: number,
489 public readonly activationReason: ExtensionActivationReason
490 ) {
491 }
493 >
494 > export class ExtensionPointContribution<T> {
495 > readonly description: IExtensionDescription;
496 > readonly value: T;
497 >
498 > constructor(description: IExtensionDescription, value: T) {
499 this.description = description;
500 this.value = value;
501 }
503 >
504 > export interface IWillActivateEvent {
505 > readonly event: string;
506 > readonly activation: Promise<void>;
507 > readonly activationKind: ActivationKind;
508 > }
509 >
510 > export interface IResponsiveStateChangeEvent {
511 > extensionHostKind: ExtensionHostKind;
512 > isResponsive: boolean;
513 > /**
514 > * Return the inspect port or `0`. `0` means inspection is not possible.
515 > */
516 > getInspectListener(tryEnableInspector: boolean): Promise<IExtensionInspectInfo | undefined>;
517 > }
518 >
519 > export const enum ActivationKind {
520 > Normal = 0,
521 > Immediate = 1
522 > }
523 >
524 > export interface WillStopExtensionHostsEvent {
525 >
526 > /**
527 > * A human readable reason for stopping the extension hosts
528 > * that e.g. can be shown in a confirmation dialog to the
529 > * user.
530 > */
531 > readonly reason: string;
532 >
533 > /**
534 > * A flag to indicate if the operation was triggered automatically
535 > */
536 > readonly auto: boolean;
537 >
538 > /**
539 > * Allows to veto the stopping of extension hosts. The veto can be a long running
540 > * operation.
541 > *
542 > * @param reason a human readable reason for vetoing the extension host stop in case
543 > * where the resolved `value: true`.
544 > */
545 > veto(value: boolean | Promise<boolean>, reason: string): void;
546 > }
547 >
548 > export interface IExtensionService {
549 > readonly _serviceBrand: undefined;
550 >
551 > /**
552 > * An event emitted when extensions are registered after their extension points got handled.
553 > *
554 > * This event will also fire on startup to signal the installed extensions.
555 > *
556 > * @returns the extensions that got registered
557 > */
558 > readonly onDidRegisterExtensions: Event<void>;
559 >
560 > /**
561 > * @event
562 > * Fired when extensions status changes.
563 > * The event contains the ids of the extensions that have changed.
564 > */
565 > readonly onDidChangeExtensionsStatus: Event<ExtensionIdentifier[]>;
566 >
567 > /**
568 > * Fired when the available extensions change (i.e. when extensions are added or removed).
569 > */
570 > readonly onDidChangeExtensions: Event<{ readonly added: readonly IExtensionDescription[]; readonly removed: readonly IExtensionDescription[] }>;
571 >
572 > /**
573 > * All registered extensions.
574 > * - List will be empty initially during workbench startup and will be filled with extensions as they are registered
575 > * - Listen to `onDidChangeExtensions` event for any changes to the extensions list. It will change as extensions get registered or de-reigstered.
576 > * - Listen to `onDidRegisterExtensions` event or wait for `whenInstalledExtensionsRegistered` promise to get the initial list of registered extensions.
577 > */
578 > readonly extensions: readonly IExtensionDescription[];
579 >
580 > /**
581 > * An event that is fired when activation happens.
582 > */
583 > readonly onWillActivateByEvent: Event<IWillActivateEvent>;
584 >
585 > /**
586 > * An event that is fired when an extension host changes its
587 > * responsive-state.
588 > */
589 > readonly onDidChangeResponsiveChange: Event<IResponsiveStateChangeEvent>;
590 >
591 > /**
592 > * Fired before stop of extension hosts happens. Allows listeners to veto against the
593 > * stop to prevent it from happening.
594 > */
595 > readonly onWillStop: Event<WillStopExtensionHostsEvent>;
596 >
597 > /**
598 > * Send an activation event and activate interested extensions.
599 > *
600 > * This will wait for the normal startup of the extension host(s).
601 > *
602 > * In extraordinary circumstances, if the activation event needs to activate
603 > * one or more extensions before the normal startup is finished, then you can use
604 > * `ActivationKind.Immediate`. Please do not use this flag unless really necessary
605 > * and you understand all consequences.
606 > */
607 > activateByEvent(activationEvent: string, activationKind?: ActivationKind): Promise<void>;
608 >
609 > /**
610 > * Send an activation ID and activate interested extensions.
611 > *
612 > */
613 > activateById(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void>;
614 >
615 > /**
616 > * Determine if `activateByEvent(activationEvent)` has resolved already.
617 > *
618 > * i.e. the activation event is finished and all interested extensions are already active.
619 > */
620 > activationEventIsDone(activationEvent: string): boolean;
621 >
622 > /**
623 > * An promise that resolves when the installed extensions are registered after
624 > * their extension points got handled.
625 > */
626 > whenInstalledExtensionsRegistered(): Promise<boolean>;
627 >
628 > /**
629 > * Return a specific extension
630 > * @param id An extension id
631 > */
632 > getExtension(id: string): Promise<IExtensionDescription | undefined>;
633 >
634 > /**
635 > * Returns `true` if the given extension can be added. Otherwise `false`.
636 > * @param extension An extension
637 > */
638 > canAddExtension(extension: IExtensionDescription): boolean;
639 >
640 > /**
641 > * Returns `true` if the given extension can be removed. Otherwise `false`.
642 > * @param extension An extension
643 > */
644 > canRemoveExtension(extension: IExtensionDescription): boolean;
645 >
646 > /**
647 > * Read all contributions to an extension point.
648 > */
649 > readExtensionPointContributions<T extends IExtensionContributions[keyof IExtensionContributions]>(extPoint: IExtensionPoint<T>): Promise<ExtensionPointContribution<T>[]>;
650 >
651 > /**
652 > * Get information about extensions status.
653 > */
654 > getExtensionsStatus(): { [id: string]: IExtensionsStatus };
655 >
656 > /**
657 > * Return the inspect ports (if inspection is possible) for extension hosts of kind `extensionHostKind`.
658 > */
659 > getInspectPorts(extensionHostKind: ExtensionHostKind, tryEnableInspector: boolean): Promise<IExtensionInspectInfo[]>;
660 >
661 > /**
662 > * Stops the extension hosts.
663 > *
664 > * @param reason a human readable reason for stopping the extension hosts. This maybe
665 > * can be presented to the user when showing dialogs.
666 > *
667 > * @param auto indicates if the operation was triggered by an automatic action
668 > *
669 > * @returns a promise that resolves to `true` if the extension hosts were stopped, `false`
670 > * if the operation was vetoed by listeners of the `onWillStop` event.
671 > */
672 > stopExtensionHosts(reason: string, auto?: boolean): Promise<boolean>;
673 >
674 > /**
675 > * Starts the extension hosts. If updates are provided, the extension hosts are started with the given updates.
676 > */
677 > startExtensionHosts(updates?: { readonly toAdd: readonly IExtension[]; readonly toRemove: readonly string[] }): Promise<void>;
678 >
679 > /**
680 > * Modify the environment of the remote extension host
681 > * @param env New properties for the remote extension host
682 > */
683 > setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void>;
684 > }
685 >
686 > export interface IInternalExtensionService {
687 > _activateById(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void>;
688 > _onWillActivateExtension(extensionId: ExtensionIdentifier): void;
689 > _onDidActivateExtension(extensionId: ExtensionIdentifier, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationReason: ExtensionActivationReason): void;
690 > _onDidActivateExtensionError(extensionId: ExtensionIdentifier, error: Error): void;
691 > _onExtensionRuntimeError(extensionId: ExtensionIdentifier, err: Error): void;
692 > }
693 >
694 > export interface ProfileSession {
695 > stop(): Promise<IExtensionHostProfile>;
696 > }
697 >
698 > export function toExtension(extensionDescription: IExtensionDescription): IExtension {
699 return {
700 type: extensionDescription.isBuiltin ? ExtensionType.System : ExtensionType.User,
701 isBuiltin: extensionDescription.isBuiltin || extensionDescription.isUserBuiltin,
702 identifier: { id: getGalleryExtensionId(extensionDescription.publisher, extensionDescription.name), uuid: extensionDescription.uuid },
703 manifest: extensionDescription,
704 location: extensionDescription.extensionLocation,
705 targetPlatform: extensionDescription.targetPlatform,
706 validations: [],
707 isValid: true,
708 preRelease: extensionDescription.preRelease,
709 publisherDisplayName: extensionDescription.publisherDisplayName,
710 };
711 }
713 > export function toExtensionDescription(extension: IExtension, isUnderDevelopment?: boolean): IExtensionDescription {
714 const id = getExtensionId(extension.manifest.publisher, extension.manifest.name);
715 return {
716 id,
717 identifier: new ExtensionIdentifier(id),
718 isBuiltin: extension.type === ExtensionType.System,
719 isUserBuiltin: extension.type === ExtensionType.User && extension.isBuiltin,
720 isUnderDevelopment: !!isUnderDevelopment,
721 extensionLocation: extension.location,
722 uuid: extension.identifier.uuid,
723 targetPlatform: extension.targetPlatform,
724 publisherDisplayName: extension.publisherDisplayName,
725 preRelease: extension.preRelease,
726 ...extension.manifest
727 };
728 }
730 >
731 > export class NullExtensionService implements IExtensionService {
732 > declare readonly _serviceBrand: undefined; extensions.ts ×1
733 > readonly onDidRegisterExtensions: Event<void> = Event.None;
734 > readonly onDidChangeExtensionsStatus: Event<ExtensionIdentifier[]> = Event.None;
735 > onDidChangeExtensions = Event.None;
736 > readonly onWillActivateByEvent: Event<IWillActivateEvent> = Event.None;
737 > readonly onDidChangeResponsiveChange: Event<IResponsiveStateChangeEvent> = Event.None;
738 > readonly onWillStop: Event<WillStopExtensionHostsEvent> = Event.None;
739 > readonly extensions = [];
740 > activateByEvent(_activationEvent: string): Promise<void> { return Promise.resolve(undefined); } extensions.ts ×23
741 > activateById(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void> { return Promise.resolve(undefined); }
742 > activationEventIsDone(_activationEvent: string): boolean { return false; }
743 > whenInstalledExtensionsRegistered(): Promise<boolean> { return Promise.resolve(true); }
744 > getExtension() { return Promise.resolve(undefined); }
745 > readExtensionPointContributions<T>(_extPoint: IExtensionPoint<T>): Promise<ExtensionPointContribution<T>[]> { return Promise.resolve(Object.create(null)); }
746 > getExtensionsStatus(): { [id: string]: IExtensionsStatus } { return Object.create(null); }
747 > getInspectPorts(_extensionHostKind: ExtensionHostKind, _tryEnableInspector: boolean): Promise<IExtensionInspectInfo[]> { return Promise.resolve([]); }
748 > async stopExtensionHosts(): Promise<boolean> { return true; }
749 > async startExtensionHosts(): Promise<void> { }
750 > async setRemoteEnvironment(_env: { [key: string]: string | null }): Promise<void> { }
751 > canAddExtension(): boolean { return false; }
752 > canRemoveExtension(): boolean { return false; }
753 > }