extensionDescriptionRegistry.ts ×37

Frontier kind: Code frontier

unlabeled · c_8db614ea5c49

43 tests · 7777 LOC · 35 files · introduces 0 tests · 139 LOC · 1 file

Introduces — evidence that enters the hierarchy at this concept

Code
37 ranges139 lines · 1 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
1097 ranges7777 lines · 35 files · Browse complete extent
All tests (intent)
43 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

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 native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

1 file ranked by introduced lines: 139 introduced LOC across 37 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/workbench/services/extensions/common/extensionDescriptionRegistry.ts 139 introduced LOC · 37 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extensionDescriptionRegistry.ts
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 { ExtensionIdentifier, ExtensionIdentifierMap, ExtensionIdentifierSet, IExtensionDescription } from '../../../../platform/extensions/common/extensions.js';
7 > import { Emitter } from '../../../../base/common/event.js';
8 > import * as path from '../../../../base/common/path.js';
9 > import { Disposable, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
10 > import { promiseWithResolvers } from '../../../../base/common/async.js';
11 >
12 > export class DeltaExtensionsResult {
13 > constructor(
14 public readonly versionId: number,
15 public readonly removedDueToLooping: IExtensionDescription[]
16 ) { }
18 >
19 > export interface IReadOnlyExtensionDescriptionRegistry {
20 > containsActivationEvent(activationEvent: string): boolean;
21 > containsExtension(extensionId: ExtensionIdentifier): boolean;
22 > getExtensionDescriptionsForActivationEvent(activationEvent: string): IExtensionDescription[];
23 > getAllExtensionDescriptions(): IExtensionDescription[];
24 > getExtensionDescription(extensionId: ExtensionIdentifier | string): IExtensionDescription | undefined;
25 > getExtensionDescriptionByUUID(uuid: string): IExtensionDescription | undefined;
26 > getExtensionDescriptionByIdOrUUID(extensionId: ExtensionIdentifier | string, uuid: string | undefined): IExtensionDescription | undefined;
27 > }
28 >
29 > export class ExtensionDescriptionRegistry extends Disposable implements IReadOnlyExtensionDescriptionRegistry {
30 >
31 > public static isHostExtension(extensionId: ExtensionIdentifier | string, myRegistry: ExtensionDescriptionRegistry, globalRegistry: ExtensionDescriptionRegistry): boolean {
32 > if (myRegistry.getExtensionDescription(extensionId)) {
33 > // I have this extension
34 > return false;
35 > }
36 const extensionDescription = globalRegistry.getExtensionDescription(extensionId);
37 if (!extensionDescription) {
39 return false;
40 }
41 > if ((extensionDescription.main || extensionDescription.browser) && extensionDescription.api === 'none') { extensionDescriptionRegistry.ts
42 return true;
43 }
44 return false;
46 >
47 > private readonly _onDidChange = this._register(new Emitter<void>());
48 > public readonly onDidChange = this._onDidChange.event;
49 >
50 > private _versionId: number = 0;
51 > private _extensionDescriptions: IExtensionDescription[];
52 > private _extensionsMap!: ExtensionIdentifierMap<IExtensionDescription>;
53 > private _extensionsArr!: IExtensionDescription[];
54 > private _activationMap!: Map<string, IExtensionDescription[]>;
55 >
56 > constructor(
57 private readonly _activationEventsReader: IActivationEventsReader,
58 extensionDescriptions: IExtensionDescription[]
62 this._initialize();
63 }
65 > private _initialize(): void {
66 // Ensure extensions are stored in the order: builtin, user, under development
67 this._extensionDescriptions.sort(extensionCmp);
90 }
91 }
93 > public set(extensionDescriptions: IExtensionDescription[]): { versionId: number } {
94 this._extensionDescriptions = extensionDescriptions;
95 this._initialize();
100 };
101 }
103 > public deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): DeltaExtensionsResult {
104 // It is possible that an extension is removed, only to be added again at a different version
105 // so we will first handle removals
118 return new DeltaExtensionsResult(this._versionId, looping);
119 }
121 > private static _findLoopingExtensions(extensionDescriptions: IExtensionDescription[]): IExtensionDescription[] {
122 const G = new class {
123
202 return nodes.map(id => descs.get(id)!);
203 }
205 > public containsActivationEvent(activationEvent: string): boolean {
206 return this._activationMap.has(activationEvent);
207 }
209 > public containsExtension(extensionId: ExtensionIdentifier): boolean {
210 return this._extensionsMap.has(extensionId);
211 }
213 > public getExtensionDescriptionsForActivationEvent(activationEvent: string): IExtensionDescription[] {
214 const extensions = this._activationMap.get(activationEvent);
215 return extensions ? extensions.slice(0) : [];
216 }
218 > public getAllExtensionDescriptions(): IExtensionDescription[] {
219 return this._extensionsArr.slice(0);
220 }
222 > public getSnapshot(): ExtensionDescriptionRegistrySnapshot {
223 return new ExtensionDescriptionRegistrySnapshot(
224 this._versionId,
226 );
227 }
229 > public getExtensionDescription(extensionId: ExtensionIdentifier | string): IExtensionDescription | undefined {
230 const extension = this._extensionsMap.get(extensionId);
231 return extension ? extension : undefined;
232 }
234 > public getExtensionDescriptionByUUID(uuid: string): IExtensionDescription | undefined {
235 for (const extensionDescription of this._extensionsArr) {
236 if (extensionDescription.uuid === uuid) {
240 return undefined;
241 }
243 > public getExtensionDescriptionByIdOrUUID(extensionId: ExtensionIdentifier | string, uuid: string | undefined): IExtensionDescription | undefined {
244 return (
245 this.getExtensionDescription(extensionId)
247 );
248 }
250 >
251 > export class ExtensionDescriptionRegistrySnapshot {
252 > constructor(
253 public readonly versionId: number,
254 public readonly extensions: readonly IExtensionDescription[]
255 ) { }
257 >
258 > export interface IActivationEventsReader {
259 > readActivationEvents(extensionDescription: IExtensionDescription): string[];
260 > }
261 >
262 > export class LockableExtensionDescriptionRegistry implements IReadOnlyExtensionDescriptionRegistry {
263 >
264 > private readonly _actual: ExtensionDescriptionRegistry;
265 > private readonly _lock = new Lock();
266 >
267 > constructor(activationEventsReader: IActivationEventsReader) {
268 this._actual = new ExtensionDescriptionRegistry(activationEventsReader, []);
269 }
271 > public async acquireLock(customerName: string): Promise<ExtensionDescriptionRegistryLock> {
272 const lock = await this._lock.acquire(customerName);
273 return new ExtensionDescriptionRegistryLock(this, lock);
274 }
276 > public deltaExtensions(acquiredLock: ExtensionDescriptionRegistryLock, toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): DeltaExtensionsResult {
277 if (!acquiredLock.isAcquiredFor(this)) {
278 throw new Error('Lock is not held');
280 return this._actual.deltaExtensions(toAdd, toRemove);
281 }
283 > public containsActivationEvent(activationEvent: string): boolean {
284 return this._actual.containsActivationEvent(activationEvent);
285 }
286 > public containsExtension(extensionId: ExtensionIdentifier): boolean { extensionDescriptionRegistry.ts
287 return this._actual.containsExtension(extensionId);
288 }
289 > public getExtensionDescriptionsForActivationEvent(activationEvent: string): IExtensionDescription[] { extensionDescriptionRegistry.ts
290 return this._actual.getExtensionDescriptionsForActivationEvent(activationEvent);
291 }
292 > public getAllExtensionDescriptions(): IExtensionDescription[] { extensionDescriptionRegistry.ts
293 return this._actual.getAllExtensionDescriptions();
294 }
295 > public getSnapshot(): ExtensionDescriptionRegistrySnapshot { extensionDescriptionRegistry.ts
296 return this._actual.getSnapshot();
297 }
298 > public getExtensionDescription(extensionId: ExtensionIdentifier | string): IExtensionDescription | undefined { extensionDescriptionRegistry.ts
299 return this._actual.getExtensionDescription(extensionId);
300 }
301 > public getExtensionDescriptionByUUID(uuid: string): IExtensionDescription | undefined { extensionDescriptionRegistry.ts
302 return this._actual.getExtensionDescriptionByUUID(uuid);
303 }
304 > public getExtensionDescriptionByIdOrUUID(extensionId: ExtensionIdentifier | string, uuid: string | undefined): IExtensionDescription | undefined { extensionDescriptionRegistry.ts
305 return this._actual.getExtensionDescriptionByIdOrUUID(extensionId, uuid);
306 }
308 >
309 > export class ExtensionDescriptionRegistryLock extends Disposable {
310 >
311 > private _isDisposed = false;
312 >
313 > constructor(
314 private readonly _registry: LockableExtensionDescriptionRegistry,
315 lock: IDisposable
318 this._register(lock);
319 }
321 > public isAcquiredFor(registry: LockableExtensionDescriptionRegistry): boolean {
322 return !this._isDisposed && this._registry === registry;
323 }
325 >
326 > class LockCustomer {
327 > public readonly promise: Promise<IDisposable>;
328 > private readonly _resolve: (value: IDisposable) => void;
329 >
330 > constructor(
331 public readonly name: string
332 ) {
335 this._resolve = withResolvers.resolve;
336 }
338 > resolve(value: IDisposable): void {
339 this._resolve(value);
340 }
342 >
343 class Lock {
344 private readonly _pendingCustomers: LockCustomer[] = [];
345 private _isLocked = false;
347 > public async acquire(customerName: string): Promise<IDisposable> {
348 const customer = new LockCustomer(customerName);
349 this._pendingCustomers.push(customer);
351 return customer.promise;
352 }
354 > private _advance(): void {
355 if (this._isLocked) {
356 // cannot advance yet
385 customer.resolve(toDisposable(releaseLock));
386 }
388 >
389 > const enum SortBucket {
390 > Builtin = 0,
391 > User = 1,
392 > Dev = 2
393 > }
394 >
395 > /**
396 > * Ensure that:
397 > * - first are builtin extensions
398 > * - second are user extensions
399 > * - third are extensions under development
400 > *
401 > * In each bucket, extensions must be sorted alphabetically by their folder name.
402 > */
403 function extensionCmp(a: IExtensionDescription, b: IExtensionDescription): number {
404 const aSortBucket = (a.isBuiltin ? SortBucket.Builtin : a.isUnderDevelopment ? SortBucket.Dev : SortBucket.User);
417 return 0;
418 }
420 function removeExtensions(arr: IExtensionDescription[], toRemove: ExtensionIdentifier[]): IExtensionDescription[] {
421 const toRemoveSet = new ExtensionIdentifierSet(toRemove);