src/vs/platform/extensionManagement/common/extensionsScannerService.ts

1109 LOC · 784 covered · 325 uncovered · 195 ranges · 49 concepts · 34 introducers · 30 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.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the filesrc/vs/platform/extensionManagement/common/extensionManagementUtil.ts · 212 LOCcommon/extensionManageme…src/vs/platform/extensionManagement/common/extensionsProfileScannerService.ts · 410 LOCcommon/extensionsProfile…src/vs/platform/extensionManagement/node/extensionsProfileScannerService.ts · 24 LOCnode/extensionsProfileSc…src/vs/platform/extensions/common/extensionValidator.ts · 391 LOCcommon/extensionValidato…src/vs/platform/extensions/common/extensions.ts · 570 LOCcommon/extensions.tssrc/vs/platform/files/common/fileService.ts · 1491 LOCcommon/fileService.tsextensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions scan all extensions prefers matching user extension over system extension|occurrence=1, extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions scan all extensions picks user extension with newer version over system extension|occurrence=1 · 0 introduced LOCextensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions scan picks latest version when multiple versions exist|occurrence=1 · 0 introduced LOCextensionsScannerService…extensionsScannerService.ts ×4 · 13 introduced LOCextensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions scan all extensions uses system version when autoUpdate is disabled (non-stable quality)|occurrence=1 · 0 introduced LOCextensionsScannerService…extensionsScannerService.ts ×1 · 6 introduced LOCextensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan all user extensions with default nls replacements|occurrence=1 · 0 introduced LOCextensionsScannerService…extensionsScannerService.ts ×4 · 9 introduced LOCextensionsScannerService…extensionsScannerService.ts ×12 · 65 introduced LOCextensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan extension falls back to default nls replacements|occurrence=1 · 0 introduced LOCextensionsScannerService…extensionsScannerService.ts ×1 · 2 introduced LOCextensionsScannerService…extensionsScannerService.ts ×9 · 21 introduced LOCextensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan all user extensions with different versions|occurrence=1 · 0 introduced LOCextensionsScannerService…extensionsScannerService.ts ×1 · 2 introduced LOCextensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan all user extensions include invalid extensions|occurrence=1 · 0 introduced LOCextensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan all user extensions exclude invalid extensions|occurrence=1 · 0 introduced LOCextensionsScannerService…extensionsScannerService.ts ×2 · 11 introduced LOCextensionsScannerService…extensionsScannerService.ts ×5 · 17 introduced LOCextensionsScannerService…extensionsScannerService.ts ×5 · 21 introduced LOCextensionsScannerService…extensionsScannerService.ts ×3 · 3 introduced LOCextensionsScannerService…extensionsScannerService.ts ×6 · 12 introduced LOCextensionsScannerService…extensionsScannerService.ts ×1 · 2 introduced LOCextensionsScannerService…extensionsScannerService.ts ×5 · 9 introduced LOCextensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions system extension has autoUpdate set to false when quality is not stable|occurrence=1, extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions system extension has autoUpdate set to false when not in autoUpdateBuiltinExtensions|occurrence=1, +1 · 0 introduced LOCextensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan system extension|occurrence=1 · 0 introduced LOCextensionsScannerService…extensionsScannerService.ts ×1 · 2 introduced LOCextensionsScannerService…extensionsScannerService.ts ×3 · 4 introduced LOCextensionsScannerService…extensionsScannerService.ts ×1 · 2 introduced LOCextensionsScannerService…extensionsScannerService.ts ×7 · 27 introduced LOCextensionsScannerService…extensionsScannerService.ts ×4 · 9 introduced LOCextensionsScannerService…extensionsScannerService.ts ×3 · 3 introduced LOCextensionsScannerService…extensionsScannerService.ts ×2 · 4 introduced LOCextensionsScannerService…extensionsScannerService.ts ×1 · 2 introduced LOCextensionsScannerService…extensionsScannerService.ts ×7 · 41 introduced LOCextensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan all user extensions include all versions|occurrence=1 · 0 introduced LOCextensionsScannerService…extensionsScannerService.ts ×2 · 6 introduced LOCextensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan user extensions|occurrence=1 · 0 introduced LOCextensionsScannerService…extensionsScannerService.ts ×1 · 4 introduced LOCextensionsScannerService…extensionsScannerService.ts ×1 · 6 introduced LOCextensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan existing extension|occurrence=1 · 0 introduced LOCextensionsScannerService…extensionsScannerService.ts ×3 · 6 introduced LOCextensionsScannerService…extensionsScannerService.ts ×6 · 17 introduced LOCextensionsScannerService…extensionsScannerService.ts ×4 · 5 introduced LOCextensionsScannerService…extensionsScannerService.ts ×2 · 3 introduced LOCextensionsScannerService…extensionsScannerService.ts ×2 · 3 introduced LOCextensionsScannerService…extensionsScannerService.ts ×30 · 214 introduced LOCextensionsScannerService…extensionsScannerService.test|title=ExtensionScannerInput compare inputs - location|occurrence=1, extensionsScannerService.test|title=ExtensionScannerInput compare inputs - application location|occurrence=1 · 0 introduced LOCextensionsScannerService…extensionsScannerService.test|title=ExtensionScannerInput compare inputs - profile|occurrence=1 · 0 introduced LOCextensionsScannerService…extensionsScannerService.ts ×6 · 26 introduced LOCextensionsScannerService…extensionsScannerService.ts ×50 · 322 introduced LOCextensionsScannerService…extensionsScannerService.test|title=ExtensionScannerInput compare inputs - application location|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=ExtensionScannerInput compare inputs - application location|occurrence=1extensionsScannerService…extensionsScannerService.test|title=ExtensionScannerInput compare inputs - extension type|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=ExtensionScannerInput compare inputs - extension type|occurrence=1extensionsScannerService…extensionsScannerService.test|title=ExtensionScannerInput compare inputs - location|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=ExtensionScannerInput compare inputs - location|occurrence=1extensionsScannerService…extensionsScannerService.test|title=ExtensionScannerInput compare inputs - profile|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=ExtensionScannerInput compare inputs - profile|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions scan all extensions picks user extension with newer version over system extension|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions scan all extensions picks user extension with newer version over system extension|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions scan all extensions prefers matching user extension over system extension|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions scan all extensions prefers matching user extension over system extension|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions scan all extensions uses system version when autoUpdate is disabled (non-stable quality)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions scan all extensions uses system version when autoUpdate is disabled (non-stable quality)|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions scan picks latest version when multiple versions exist|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions scan picks latest version when multiple versions exist|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions scan user extension is excluded when autoUpdate is disabled (non-stable quality)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions scan user extension is excluded when autoUpdate is disabled (non-stable quality)|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions scan user extension not in autoUpdateBuiltinExtensions is not filtered|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions scan user extension not in autoUpdateBuiltinExtensions is not filtered|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions scan user extension with different version is included when forceAutoUpdate is enabled|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions scan user extension with different version is included when forceAutoUpdate is enabled|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions scan user extension with matching product version is included|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions scan user extension with matching product version is included|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions system extension has autoUpdate set to false when not in autoUpdateBuiltinExtensions|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions system extension has autoUpdate set to false when not in autoUpdateBuiltinExtensions|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions system extension has autoUpdate set to false when quality is not stable|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions system extension has autoUpdate set to false when quality is not stable|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions system extension has autoUpdate set to true when in autoUpdateBuiltinExtensions and quality is stable|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test auto update builtin extensions system extension has autoUpdate set to true when in autoUpdateBuiltinExtensions and quality is stable|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan all user extensions exclude invalid extensions|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test scan all user extensions exclude invalid extensions|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan all user extensions include all versions|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test scan all user extensions include all versions|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan all user extensions include invalid extensions|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test scan all user extensions include invalid extensions|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan all user extensions with default nls replacements|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test scan all user extensions with default nls replacements|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan all user extensions with different versions and higher version is not compatible|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test scan all user extensions with different versions and higher version is not compatible|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan all user extensions with different versions|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test scan all user extensions with different versions|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan existing extension|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test scan existing extension|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan extension falls back to default nls replacements|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test scan extension falls back to default nls replacements|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan extension with en nls replacements|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test scan extension with en nls replacements|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan multiple extensions|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test scan multiple extensions|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan single extension with manifest metadata retains manifest metadata|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test scan single extension with manifest metadata retains manifest metadata|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan single extension|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test scan single extension|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan system extensions include additional builtin extensions|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test scan system extensions include additional builtin extensions|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan system extension|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test scan system extension|occurrence=1extensionsScannerService…extensionsScannerService.test|title=NativeExtensionsScanerService Test scan user extensions|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/extensionManagement/test/node/extensionsScannerService.test|title=NativeExtensionsScanerService Test scan user extensions|occurrence=1extensionsScannerService…Focused file · src/vs/platform/extensionManagement/common/extensionsScannerService.ts · 1109 LOCcommon/extensionsScanner…

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 > /*--------------------------------------------------------------------------------------------- extensionsScannerService.ts ×50
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 { coalesce } from '../../../base/common/arrays.js';
7 > import { ThrottledDelayer } from '../../../base/common/async.js';
8 > import * as objects from '../../../base/common/objects.js';
9 > import { VSBuffer } from '../../../base/common/buffer.js';
10 > import { getErrorMessage } from '../../../base/common/errors.js';
11 > import { getNodeType, parse, ParseError } from '../../../base/common/json.js';
12 > import { getParseErrorMessage } from '../../../base/common/jsonErrorMessages.js';
13 > import { Disposable } from '../../../base/common/lifecycle.js';
14 > import { FileAccess, Schemas } from '../../../base/common/network.js';
15 > import * as path from '../../../base/common/path.js';
16 > import * as platform from '../../../base/common/platform.js';
17 > import { basename, isEqual, joinPath } from '../../../base/common/resources.js';
18 > import * as semver from '../../../base/common/semver/semver.js';
19 > import Severity from '../../../base/common/severity.js';
20 > import { URI } from '../../../base/common/uri.js';
21 > import { localize } from '../../../nls.js';
22 > import { IEnvironmentService } from '../../environment/common/environment.js';
23 > import { IProductVersion, Metadata } from './extensionManagement.js';
24 > import { areSameExtensions, computeTargetPlatform, getExtensionId, getGalleryExtensionId } from './extensionManagementUtil.js';
25 > import { ExtensionType, ExtensionIdentifier, IExtensionManifest, TargetPlatform, IExtensionIdentifier, IRelaxedExtensionManifest, UNDEFINED_PUBLISHER, IExtensionDescription, BUILTIN_MANIFEST_CACHE_FILE, USER_MANIFEST_CACHE_FILE, ExtensionIdentifierMap, parseEnabledApiProposalNames } from '../../extensions/common/extensions.js';
26 > import { validateExtensionManifest } from '../../extensions/common/extensionValidator.js';
27 > import { FileOperationResult, IFileService, toFileOperationResult } from '../../files/common/files.js';
28 > import { createDecorator, IInstantiationService } from '../../instantiation/common/instantiation.js';
29 > import { ILogService } from '../../log/common/log.js';
30 > import { IProductService } from '../../product/common/productService.js';
31 > import { Emitter, Event } from '../../../base/common/event.js';
32 > import { revive } from '../../../base/common/marshalling.js';
33 > import { ExtensionsProfileScanningError, ExtensionsProfileScanningErrorCode, IExtensionsProfileScannerService, IProfileExtensionsScanOptions, IScannedProfileExtension } from './extensionsProfileScannerService.js';
34 > import { IUserDataProfile, IUserDataProfilesService } from '../../userDataProfile/common/userDataProfile.js';
35 > import { IUriIdentityService } from '../../uriIdentity/common/uriIdentity.js';
36 > import { localizeManifest } from './extensionNls.js';
37 >
38 > export type ManifestMetadata = Partial<{
39 > targetPlatform: TargetPlatform;
40 > installedTimestamp: number;
41 > size: number;
42 > }>;
43 >
44 > export type IScannedExtensionManifest = IRelaxedExtensionManifest & { __metadata?: ManifestMetadata };
45 >
46 > interface IRelaxedScannedExtension {
47 > type: ExtensionType;
48 > isBuiltin: boolean;
49 > identifier: IExtensionIdentifier;
50 > manifest: IRelaxedExtensionManifest;
51 > location: URI;
52 > targetPlatform: TargetPlatform;
53 > publisherDisplayName?: string;
54 > metadata: Metadata | undefined;
55 > isValid: boolean;
56 > validations: readonly [Severity, string][];
57 > preRelease: boolean;
58 > forceAutoUpdate: boolean;
59 > }
60 >
61 > export type IScannedExtension = Readonly<IRelaxedScannedExtension> & { manifest: IExtensionManifest };
62 >
63 > export interface Translations {
64 > [id: string]: string;
65 > }
66 >
67 > export namespace Translations {
68 > export function equals(a: Translations, b: Translations): boolean {
69 > if (a === b) { extensionsScannerService.ts ×6
70 return true;
71 }
72 > const aKeys = Object.keys(a); extensionsScannerService.ts ×6
73 > const bKeys: Set<string> = new Set<string>();
74 > for (const key of Object.keys(b)) {
75 bKeys.add(key);
76 }
77 > if (aKeys.length !== bKeys.size) { extensionsScannerService.ts ×6
78 return false;
79 }
81 > for (const key of aKeys) {
82 if (a[key] !== b[key]) {
83 return false;
84 }
85 bKeys.delete(key);
86 }
87 > return bKeys.size === 0; extensionsScannerService.ts ×6
88 > }
90 >
91 > interface MessageBag {
92 > [key: string]: string | { message: string; comment: string[] };
93 > }
94 >
95 > interface TranslationBundle {
96 > contents: {
97 > package: MessageBag;
98 > };
99 > }
100 >
101 > interface LocalizedMessages {
102 > values: MessageBag | undefined;
103 > default: URI | null;
104 > }
105 >
106 > interface IBuiltInExtensionControl {
107 > [name: string]: 'marketplace' | 'disabled' | string;
108 > }
109 >
110 > function getProductBuiltInExtensionsEnabledWithAutoUpdates(productService: IProductService, environmentService: IEnvironmentService): Set<string> { extensionsScannerService.ts ×30
111 > const result = new Set<string>();
112 > for (const id of productService.builtInExtensionsEnabledWithAutoUpdates) {
113 > const toLowerCaseId = id.toLowerCase(); extensionsScannerService.ts ×2
114 > if (environmentService.skipBuiltinExtensions?.some(skipId => skipId.toLowerCase() === toLowerCaseId)) {
115 continue;
116 }
117 > result.add(toLowerCaseId); extensionsScannerService.ts ×2
118 > }
119 > return result; extensionsScannerService.ts ×30
120 > }
122 > export type SystemExtensionsScanOptions = {
123 > readonly checkControlFile?: boolean;
124 > readonly language?: string;
125 > };
126 >
127 > export type UserExtensionsScanOptions = {
128 > readonly profileLocation: URI;
129 > readonly includeInvalid?: boolean;
130 > readonly language?: string;
131 > readonly useCache?: boolean;
132 > readonly productVersion?: IProductVersion;
133 > };
134 >
135 > export type ScanOptions = {
136 > readonly includeInvalid?: boolean;
137 > readonly language?: string;
138 > };
139 >
140 > export const IExtensionsScannerService = createDecorator<IExtensionsScannerService>('IExtensionsScannerService');
141 > export interface IExtensionsScannerService {
142 > readonly _serviceBrand: undefined;
143 >
144 > readonly systemExtensionsLocation: URI;
145 > readonly userExtensionsLocation: URI;
146 > readonly onDidChangeCache: Event<ExtensionType>;
147 >
148 > scanAllExtensions(systemScanOptions: SystemExtensionsScanOptions, userScanOptions: UserExtensionsScanOptions): Promise<IScannedExtension[]>;
149 > scanSystemExtensions(scanOptions: SystemExtensionsScanOptions): Promise<IScannedExtension[]>;
150 > scanUserExtensions(scanOptions: UserExtensionsScanOptions): Promise<IScannedExtension[]>;
151 > scanAllUserExtensions(): Promise<IScannedExtension[]>;
152 >
153 > scanExtensionsUnderDevelopment(existingExtensions: IScannedExtension[], scanOptions: ScanOptions): Promise<IScannedExtension[]>;
154 > scanExistingExtension(extensionLocation: URI, extensionType: ExtensionType, scanOptions: ScanOptions): Promise<IScannedExtension | null>;
155 > scanMultipleExtensions(extensionLocations: URI[], extensionType: ExtensionType, scanOptions: ScanOptions): Promise<IScannedExtension[]>;
156 > scanOneOrMultipleExtensions(extensionLocation: URI, extensionType: ExtensionType, scanOptions: ScanOptions): Promise<IScannedExtension[]>;
157 >
158 > updateManifestMetadata(extensionLocation: URI, metadata: ManifestMetadata): Promise<void>;
159 > initializeDefaultProfileExtensions(): Promise<void>;
160 > }
161 >
162 > export abstract class AbstractExtensionsScannerService extends Disposable implements IExtensionsScannerService {
163 >
164 > readonly _serviceBrand: undefined;
165 >
166 > protected abstract getTranslations(language: string): Promise<Translations>;
167 >
168 > private readonly _onDidChangeCache = this._register(new Emitter<ExtensionType>());
169 > readonly onDidChangeCache = this._onDidChangeCache.event;
170 >
171 > private readonly systemExtensionsCachedScanner: CachedExtensionsScanner;
172 > private readonly userExtensionsCachedScanner: CachedExtensionsScanner;
173 > private readonly extensionsScanner: ExtensionsScanner;
174 >
175 > constructor(
176 > readonly systemExtensionsLocation: URI, extensionsScannerService.ts ×30
177 > readonly userExtensionsLocation: URI,
178 > private readonly extensionsControlLocation: URI,
179 > currentProfile: IUserDataProfile,
180 > @IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService,
181 > @IExtensionsProfileScannerService protected readonly extensionsProfileScannerService: IExtensionsProfileScannerService,
182 > @IFileService protected readonly fileService: IFileService,
183 > @ILogService protected readonly logService: ILogService,
184 > @IEnvironmentService private readonly environmentService: IEnvironmentService,
185 > @IProductService private readonly productService: IProductService,
186 > @IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
187 > @IInstantiationService private readonly instantiationService: IInstantiationService,
188 > ) {
189 > super();
190 >
191 > this.systemExtensionsCachedScanner = this._register(this.instantiationService.createInstance(CachedExtensionsScanner, currentProfile));
192 > this.userExtensionsCachedScanner = this._register(this.instantiationService.createInstance(CachedExtensionsScanner, currentProfile));
193 > this.extensionsScanner = this._register(this.instantiationService.createInstance(ExtensionsScanner));
194 >
195 > this._register(this.systemExtensionsCachedScanner.onDidChangeCache(() => this._onDidChangeCache.fire(ExtensionType.System)));
196 > this._register(this.userExtensionsCachedScanner.onDidChangeCache(() => this._onDidChangeCache.fire(ExtensionType.User)));
197 > }
199 > private _targetPlatformPromise: Promise<TargetPlatform> | undefined;
200 > private getTargetPlatform(): Promise<TargetPlatform> {
201 > if (!this._targetPlatformPromise) { extensionsScannerService.ts ×7
202 > this._targetPlatformPromise = computeTargetPlatform(this.fileService, this.logService);
203 > }
204 > return this._targetPlatformPromise;
205 > }
207 > async scanAllExtensions(systemScanOptions: SystemExtensionsScanOptions, userScanOptions: UserExtensionsScanOptions): Promise<IScannedExtension[]> {
208 > const [system, user] = await Promise.all([ extensionsScannerService.ts ×1
209 > this.scanSystemExtensions(systemScanOptions),
210 > this.scanUserExtensions(userScanOptions),
211 > ]);
212 > return this.dedupExtensions(system, user, [], await this.getTargetPlatform(), true);
213 > }
215 > async scanSystemExtensions(scanOptions: SystemExtensionsScanOptions): Promise<IScannedExtension[]> {
216 > const promises: Promise<IRelaxedScannedExtension[]>[] = []; extensionsScannerService.ts ×7
217 > promises.push(this.scanDefaultSystemExtensions(scanOptions.language));
218 > promises.push(this.scanDevSystemExtensions(scanOptions.language, !!scanOptions.checkControlFile));
219 > const [defaultSystemExtensions, devSystemExtensions] = await Promise.all(promises);
220 > let allSystemExtensions = [...defaultSystemExtensions, ...devSystemExtensions];
221 >
222 > if (this.environmentService.skipBuiltinExtensions?.length) {
223 const skipSet = new Set(this.environmentService.skipBuiltinExtensions.map(id => id.toLowerCase()));
224 allSystemExtensions = allSystemExtensions.filter(ext => !skipSet.has(ext.identifier.id.toLowerCase()));
225 }
227 > return this.applyScanOptions(allSystemExtensions, ExtensionType.System, { pickLatest: false });
228 > }
230 > async scanUserExtensions(scanOptions: UserExtensionsScanOptions): Promise<IScannedExtension[]> {
231 > this.logService.trace('Started scanning user extensions', scanOptions.profileLocation); extensionsScannerService.ts ×12
232 > const profileScanOptions: IProfileExtensionsScanOptions | undefined = this.uriIdentityService.extUri.isEqual(scanOptions.profileLocation, this.userDataProfilesService.defaultProfile.extensionsResource) ? { bailOutWhenFileNotFound: true } : undefined;
233 > const extensionsScannerInput = await this.createExtensionScannerInput(scanOptions.profileLocation, true, ExtensionType.User, scanOptions.language, true, profileScanOptions, scanOptions.productVersion ?? this.getProductVersion());
234 > const extensionsScanner = scanOptions.useCache && !extensionsScannerInput.devMode ? this.userExtensionsCachedScanner : this.extensionsScanner;
235 > let extensions: IRelaxedScannedExtension[];
236 > try {
237 > extensions = await extensionsScanner.scanExtensions(extensionsScannerInput);
238 > } catch (error) {
239 > if (error instanceof ExtensionsProfileScanningError && error.code === ExtensionsProfileScanningErrorCode.ERROR_PROFILE_NOT_FOUND) {
240 > await this.doInitializeDefaultProfileExtensions();
241 > extensions = await extensionsScanner.scanExtensions(extensionsScannerInput);
242 > } else {
243 throw error;
244 }
246 > extensions = await this.applyScanOptions(extensions, ExtensionType.User, { includeInvalid: scanOptions.includeInvalid, pickLatest: true });
247 > this.logService.trace('Scanned user extensions:', extensions.length);
248 > return extensions;
249 > }
251 > async scanAllUserExtensions(scanOptions: { includeAllVersions?: boolean; includeInvalid: boolean } = { includeInvalid: true, includeAllVersions: true }): Promise<IScannedExtension[]> {
252 > const extensionsScannerInput = await this.createExtensionScannerInput(this.userExtensionsLocation, false, ExtensionType.User, undefined, true, undefined, this.getProductVersion()); extensionsScannerService.ts ×1
253 > const extensions = await this.extensionsScanner.scanExtensions(extensionsScannerInput);
254 > return this.applyScanOptions(extensions, ExtensionType.User, { includeAllVersions: scanOptions.includeAllVersions, includeInvalid: scanOptions.includeInvalid });
255 > }
257 > async scanExtensionsUnderDevelopment(existingExtensions: IScannedExtension[], scanOptions: ScanOptions): Promise<IScannedExtension[]> {
258 if (this.environmentService.isExtensionDevelopment && this.environmentService.extensionDevelopmentLocationURI) {
259 const extensions = (await Promise.all(this.environmentService.extensionDevelopmentLocationURI.filter(extLoc => extLoc.scheme === Schemas.file)
260 .map(async extensionDevelopmentLocationURI => {
261 const input = await this.createExtensionScannerInput(extensionDevelopmentLocationURI, false, ExtensionType.User, scanOptions.language, false /* do not validate */, undefined, this.getProductVersion());
262 const extensions = await this.extensionsScanner.scanOneOrMultipleExtensions(input);
263 return extensions.map(extension => {
264 // Override the extension type from the existing extensions
265 extension.type = existingExtensions.find(e => areSameExtensions(e.identifier, extension.identifier))?.type ?? extension.type;
266 // Validate the extension
267 return this.extensionsScanner.validate(extension, input);
268 });
269 })))
270 .flat();
271 return this.applyScanOptions(extensions, 'development', { includeInvalid: scanOptions.includeInvalid, pickLatest: true });
272 }
273 return [];
274 }
276 > async scanExistingExtension(extensionLocation: URI, extensionType: ExtensionType, scanOptions: ScanOptions): Promise<IScannedExtension | null> {
277 > const extensionsScannerInput = await this.createExtensionScannerInput(extensionLocation, false, extensionType, scanOptions.language, true, undefined, this.getProductVersion()); extensionsScannerService.ts ×3
278 > const extension = await this.extensionsScanner.scanExtension(extensionsScannerInput);
279 > if (!extension) {
280 return null;
281 }
282 > if (!scanOptions.includeInvalid && !extension.isValid) { extensionsScannerService.ts ×3
283 return null;
284 }
285 > return extension; extensionsScannerService.ts ×3
286 > }
288 > async scanOneOrMultipleExtensions(extensionLocation: URI, extensionType: ExtensionType, scanOptions: ScanOptions): Promise<IScannedExtension[]> {
289 > const extensionsScannerInput = await this.createExtensionScannerInput(extensionLocation, false, extensionType, scanOptions.language, true, undefined, this.getProductVersion()); extensionsScannerService.ts ×5
290 > const extensions = await this.extensionsScanner.scanOneOrMultipleExtensions(extensionsScannerInput);
291 > return this.applyScanOptions(extensions, extensionType, { includeInvalid: scanOptions.includeInvalid, pickLatest: true });
292 > }
294 > async scanMultipleExtensions(extensionLocations: URI[], extensionType: ExtensionType, scanOptions: ScanOptions): Promise<IScannedExtension[]> {
295 const extensions: IRelaxedScannedExtension[] = [];
296 await Promise.all(extensionLocations.map(async extensionLocation => {
297 const scannedExtensions = await this.scanOneOrMultipleExtensions(extensionLocation, extensionType, scanOptions);
298 extensions.push(...scannedExtensions);
299 }));
300 return this.applyScanOptions(extensions, extensionType, { includeInvalid: scanOptions.includeInvalid, pickLatest: true });
301 }
303 > async updateManifestMetadata(extensionLocation: URI, metaData: ManifestMetadata): Promise<void> {
304 const manifestLocation = joinPath(extensionLocation, 'package.json');
305 const content = (await this.fileService.readFile(manifestLocation)).value.toString();
306 const manifest: IScannedExtensionManifest = JSON.parse(content);
307 manifest.__metadata = { ...manifest.__metadata, ...metaData };
308
309 await this.fileService.writeFile(joinPath(extensionLocation, 'package.json'), VSBuffer.fromString(JSON.stringify(manifest, null, '\t')));
310 }
312 > async initializeDefaultProfileExtensions(): Promise<void> {
313 try {
314 await this.extensionsProfileScannerService.scanProfileExtensions(this.userDataProfilesService.defaultProfile.extensionsResource, { bailOutWhenFileNotFound: true });
315 } catch (error) {
316 if (error instanceof ExtensionsProfileScanningError && error.code === ExtensionsProfileScanningErrorCode.ERROR_PROFILE_NOT_FOUND) {
317 await this.doInitializeDefaultProfileExtensions();
318 } else {
319 throw error;
320 }
321 }
322 }
324 > private initializeDefaultProfileExtensionsPromise: Promise<void> | undefined = undefined;
325 > private async doInitializeDefaultProfileExtensions(): Promise<void> {
326 > if (!this.initializeDefaultProfileExtensionsPromise) { extensionsScannerService.ts ×12
327 > this.initializeDefaultProfileExtensionsPromise = (async () => {
328 > try {
329 > this.logService.info('Started initializing default profile extensions in extensions installation folder.', this.userExtensionsLocation.toString());
330 > const userExtensions = await this.scanAllUserExtensions({ includeInvalid: true });
331 > if (userExtensions.length) {
332 > await this.extensionsProfileScannerService.addExtensionsToProfile(userExtensions.map(e => [e, e.metadata]), this.userDataProfilesService.defaultProfile.extensionsResource); extensionsScannerService.ts ×4
335 > await this.fileService.createFile(this.userDataProfilesService.defaultProfile.extensionsResource, VSBuffer.fromString(JSON.stringify([])));
336 > } catch (error) {
337 if (toFileOperationResult(error) !== FileOperationResult.FILE_NOT_FOUND) {
338 this.logService.warn('Failed to create default profile extensions manifest in extensions installation folder.', this.userExtensionsLocation.toString(), getErrorMessage(error));
339 }
340 }
342 > this.logService.info('Completed initializing default profile extensions in extensions installation folder.', this.userExtensionsLocation.toString()); extensionsScannerService.ts ×12
343 > } catch (error) {
344 this.logService.error(error);
346 > this.initializeDefaultProfileExtensionsPromise = undefined;
347 > }
348 > })();
349 > }
350 > return this.initializeDefaultProfileExtensionsPromise;
351 > }
353 > private async applyScanOptions(extensions: IRelaxedScannedExtension[], type: ExtensionType | 'development', scanOptions: { includeAllVersions?: boolean; includeInvalid?: boolean; pickLatest?: boolean } = {}): Promise<IRelaxedScannedExtension[]> {
354 > if (!scanOptions.includeAllVersions) { extensionsScannerService.ts ×4
355 > extensions = this.dedupExtensions(type === ExtensionType.System ? extensions : undefined, type === ExtensionType.User ? extensions : undefined, type === 'development' ? extensions : undefined, await this.getTargetPlatform(), !!scanOptions.pickLatest); extensionsScannerService.ts ×7
356 > }
357 > if (!scanOptions.includeInvalid) { extensionsScannerService.ts ×4
358 > extensions = extensions.filter(extension => extension.isValid); extensionsScannerService.ts ×1
359 > }
360 > return extensions.sort((a, b) => { extensionsScannerService.ts ×4
361 > const aLastSegment = path.basename(a.location.fsPath); extensionsScannerService.ts ×2
362 > const bLastSegment = path.basename(b.location.fsPath);
363 > if (aLastSegment < bLastSegment) {
364 return -1;
365 }
366 > if (aLastSegment > bLastSegment) { extensionsScannerService.ts ×2
367 > return 1;
368 > }
369 return 0;
371 > }
373 > private dedupExtensions(system: IScannedExtension[] | undefined, user: IScannedExtension[] | undefined, development: IScannedExtension[] | undefined, targetPlatform: TargetPlatform, pickLatest: boolean): IScannedExtension[] {
374 > const pick = (existing: IScannedExtension, extension: IScannedExtension, isDevelopment: boolean): boolean => { extensionsScannerService.ts ×7
375 > if (!isDevelopment && !(existing.isBuiltin || extension.isBuiltin)) { extensionsScannerService.ts ×3
376 > if (existing.metadata?.isApplicationScoped && !extension.metadata?.isApplicationScoped) { extensionsScannerService.ts ×3
377 return false;
378 }
379 > if (!existing.metadata?.isApplicationScoped && extension.metadata?.isApplicationScoped) { extensionsScannerService.ts ×3
380 return true;
381 }
383 > if (existing.isValid && !extension.isValid) { extensionsScannerService.ts ×3
384 > return false; extensionsScannerService.ts ×1
385 > }
386 > if (existing.isValid === extension.isValid) { extensionsScannerService.ts ×4
387 > if (pickLatest && semver.gt(existing.manifest.version, extension.manifest.version)) {
388 this.logService.debug(`Skipping extension ${extension.location.path} with lower version ${extension.manifest.version} in favour of ${existing.location.path} with version ${existing.manifest.version}`);
389 return false;
390 }
391 > if (semver.eq(existing.manifest.version, extension.manifest.version)) { extensionsScannerService.ts ×4
392 if (existing.type === ExtensionType.System) {
393 this.logService.debug(`Skipping extension ${extension.location.path} in favour of system extension ${existing.location.path} with same version`);
394 return false;
395 }
396 if (existing.targetPlatform === targetPlatform) {
397 this.logService.debug(`Skipping extension ${extension.location.path} from different target platform ${extension.targetPlatform}`);
398 return false;
399 }
400 }
402 > if (isDevelopment) {
403 this.logService.warn(`Overwriting user extension ${existing.location.path} with ${extension.location.path}.`);
405 > this.logService.debug(`Overwriting user extension ${existing.location.path} with ${extension.location.path}.`);
406 > }
407 > return true;
409 > const result = new ExtensionIdentifierMap<IScannedExtension>(); extensionsScannerService.ts ×7
410 > system?.forEach((extension) => {
411 > const existing = result.get(extension.identifier.id); extensionsScannerService.ts ×7
412 > if (!existing || pick(existing, extension, false)) {
413 > result.set(extension.identifier.id, extension);
414 > }
416 > const productBuiltInExtensionsEnabledWithAutoUpdates = getProductBuiltInExtensionsEnabledWithAutoUpdates(this.productService, this.environmentService);
417 > user?.forEach((extension) => {
418 > const existing = result.get(extension.identifier.id); extensionsScannerService.ts ×3
419 > if (!existing && system && extension.type === ExtensionType.System) {
420 this.logService.debug(`Skipping obsolete system extension ${extension.location.path}.`);
421 return;
422 }
423 > if (productBuiltInExtensionsEnabledWithAutoUpdates.has(extension.identifier.id.toLowerCase()) && !extension.forceAutoUpdate) { extensionsScannerService.ts ×3
424 > this.logService.info(`Skipping user installed builtin extension ${extension.identifier.id} with version ${extension.manifest.version} because it is not allowed to in the current product quality ${this.productService.quality}`); extensionsScannerService.ts ×4
425 > return;
426 > }
427 > if (!existing || pick(existing, extension, false)) { extensionsScannerService.ts ×3
428 > result.set(extension.identifier.id, extension); extensionsScannerService.ts ×1
429 > }
431 > development?.forEach(extension => {
432 const existing = result.get(extension.identifier.id);
433 if (!existing || pick(existing, extension, true)) {
434 result.set(extension.identifier.id, extension);
435 }
436 result.set(extension.identifier.id, extension);
438 > return [...result.values()];
439 > }
441 > private async scanDefaultSystemExtensions(language: string | undefined): Promise<IRelaxedScannedExtension[]> {
442 > this.logService.trace('Started scanning system extensions'); extensionsScannerService.ts ×7
443 > const extensionsScannerInput = await this.createExtensionScannerInput(this.systemExtensionsLocation, false, ExtensionType.System, language, true, undefined, this.getProductVersion());
444 > const extensionsScanner = extensionsScannerInput.devMode ? this.extensionsScanner : this.systemExtensionsCachedScanner;
445 > const result = await extensionsScanner.scanExtensions(extensionsScannerInput);
446 > this.logService.trace('Scanned system extensions:', result.length);
447 > return result;
448 > }
450 > private async scanDevSystemExtensions(language: string | undefined, checkControlFile: boolean): Promise<IRelaxedScannedExtension[]> {
451 > const devSystemExtensionsList = this.environmentService.isBuilt ? [] : this.productService.builtInExtensions; extensionsScannerService.ts ×7
452 > if (!devSystemExtensionsList?.length) {
454 > }
456 > this.logService.trace('Started scanning dev system extensions');
457 > const builtinExtensionControl = checkControlFile ? await this.getBuiltInExtensionControl() : {};
458 > const devSystemExtensionsLocations: URI[] = []; extensionsScannerService.ts ×7
459 > const devSystemExtensionsLocation = URI.file(path.normalize(path.join(FileAccess.asFileUri('').fsPath, '..', '.build', 'builtInExtensions')));
460 > for (const extension of devSystemExtensionsList) {
461 > const controlState = builtinExtensionControl[extension.name] || 'marketplace'; extensionsScannerService.ts ×5
462 > switch (controlState) {
463 > case 'disabled':
464 > break;
465 > case 'marketplace':
466 devSystemExtensionsLocations.push(joinPath(devSystemExtensionsLocation, extension.name));
467 break;
469 > devSystemExtensionsLocations.push(URI.file(controlState));
470 > break;
471 > }
472 > }
473 > const result = await Promise.all(devSystemExtensionsLocations.map(async location => this.extensionsScanner.scanExtension((await this.createExtensionScannerInput(location, false, ExtensionType.System, language, true, undefined, this.getProductVersion())))));
474 > this.logService.trace('Scanned dev system extensions:', result.length);
475 > return coalesce(result);
478 > private async getBuiltInExtensionControl(): Promise<IBuiltInExtensionControl> {
480 > const content = await this.fileService.readFile(this.extensionsControlLocation);
481 > return JSON.parse(content.value.toString());
482 > } catch (error) {
483 return {};
484 }
487 > private async createExtensionScannerInput(location: URI, profile: boolean, type: ExtensionType, language: string | undefined, validate: boolean, profileScanOptions: IProfileExtensionsScanOptions | undefined, productVersion: IProductVersion): Promise<ExtensionScannerInput> {
488 > const translations = await this.getTranslations(language ?? platform.language); extensionsScannerService.ts ×30
489 > const mtime = await this.getMtime(location);
490 > const applicationExtensionsLocation = profile && !this.uriIdentityService.extUri.isEqual(location, this.userDataProfilesService.defaultProfile.extensionsResource) ? this.userDataProfilesService.defaultProfile.extensionsResource : undefined;
491 > const applicationExtensionsLocationMtime = applicationExtensionsLocation ? await this.getMtime(applicationExtensionsLocation) : undefined;
492 > return new ExtensionScannerInput(
493 > location,
494 > mtime,
495 > applicationExtensionsLocation,
496 > applicationExtensionsLocationMtime,
497 > profile,
498 > profileScanOptions,
499 > type,
500 > validate,
501 > productVersion.version,
502 > productVersion.date,
503 > this.productService.commit,
504 > !this.environmentService.isBuilt,
505 > language,
506 > translations,
507 > );
508 > }
510 > private async getMtime(location: URI): Promise<number | undefined> {
512 > const stat = await this.fileService.stat(location);
513 > if (typeof stat.mtime === 'number') {
514 > return stat.mtime;
515 > }
516 > } catch (err) {
517 > // That's ok... extensionsScannerService.ts ×12
518 > }
519 > return undefined;
522 > private getProductVersion(): IProductVersion {
524 > version: this.productService.version,
525 > date: this.productService.date,
526 > };
527 > }
529 > }
530 >
531 > export class ExtensionScannerInput {
532 >
533 > constructor(
534 > public readonly location: URI,
535 > public readonly mtime: number | undefined,
536 > public readonly applicationExtensionslocation: URI | undefined,
537 > public readonly applicationExtensionslocationMtime: number | undefined,
538 > public readonly profile: boolean,
539 > public readonly profileScanOptions: IProfileExtensionsScanOptions | undefined,
540 > public readonly type: ExtensionType,
541 > public readonly validate: boolean,
542 > public readonly productVersion: string,
543 > public readonly productDate: string | undefined,
544 > public readonly productCommit: string | undefined,
545 > public readonly devMode: boolean,
546 > public readonly language: string | undefined,
547 > public readonly translations: Translations
548 > ) {
549 > // Keep empty!! (JSON.parse)
550 > }
551 >
552 > public static createNlsConfiguration(input: ExtensionScannerInput): NlsConfiguration {
554 > language: input.language,
555 > pseudo: input.language === 'pseudo',
556 > devMode: input.devMode,
557 > translations: input.translations
558 > };
559 > }
561 > public static equals(a: ExtensionScannerInput, b: ExtensionScannerInput): boolean {
563 > isEqual(a.location, b.location)
564 > && a.mtime === b.mtime
565 > && isEqual(a.applicationExtensionslocation, b.applicationExtensionslocation)
566 > && a.applicationExtensionslocationMtime === b.applicationExtensionslocationMtime
567 > && a.profile === b.profile
568 > && objects.equals(a.profileScanOptions, b.profileScanOptions)
569 > && a.type === b.type
570 > && a.validate === b.validate
571 > && a.productVersion === b.productVersion
572 > && a.productDate === b.productDate
573 > && a.productCommit === b.productCommit
574 > && a.devMode === b.devMode
575 > && a.language === b.language
576 > && Translations.equals(a.translations, b.translations)
577 > );
578 > }
580 >
581 > type NlsConfiguration = {
582 > language: string | undefined;
583 > pseudo: boolean;
584 > devMode: boolean;
585 > translations: Translations;
586 > };
587 >
588 > class ExtensionsScanner extends Disposable {
589 >
590 > private readonly productQuality: string | undefined;
591 > private readonly productBuiltInExtensionsEnabledWithAutoUpdates: Set<string>;
592 >
593 > constructor(
594 > @IExtensionsProfileScannerService protected readonly extensionsProfileScannerService: IExtensionsProfileScannerService, extensionsScannerService.ts ×30
595 > @IUriIdentityService protected readonly uriIdentityService: IUriIdentityService,
596 > @IFileService protected readonly fileService: IFileService,
597 > @IProductService productService: IProductService,
598 > @IEnvironmentService environmentService: IEnvironmentService,
599 > @ILogService protected readonly logService: ILogService
600 > ) {
601 > super();
602 > this.productQuality = productService.quality;
603 > this.productBuiltInExtensionsEnabledWithAutoUpdates = getProductBuiltInExtensionsEnabledWithAutoUpdates(productService, environmentService);
604 > }
606 > async scanExtensions(input: ExtensionScannerInput): Promise<IRelaxedScannedExtension[]> {
607 > return input.profile extensionsScannerService.ts ×6
608 > ? this.scanExtensionsFromProfile(input) extensionsScannerService.ts ×12
609 > : this.scanExtensionsFromLocation(input); extensionsScannerService.ts ×6
610 > }
612 > private async scanExtensionsFromLocation(input: ExtensionScannerInput): Promise<IRelaxedScannedExtension[]> {
613 > const stat = await this.fileService.resolve(input.location); extensionsScannerService.ts ×6
614 > if (!stat.children?.length) {
615 return [];
616 }
617 > const extensions = await Promise.all<IRelaxedScannedExtension | null>( extensionsScannerService.ts ×6
618 > stat.children.map(async c => {
619 > if (!c.isDirectory) {
620 return null;
621 }
622 > // Do not consider user extension folder starting with `.` extensionsScannerService.ts ×6
623 > if (input.type === ExtensionType.User && basename(c.resource).indexOf('.') === 0) {
624 return null;
625 }
626 > const extensionScannerInput = new ExtensionScannerInput(c.resource, input.mtime, input.applicationExtensionslocation, input.applicationExtensionslocationMtime, input.profile, input.profileScanOptions, input.type, input.validate, input.productVersion, input.productDate, input.productCommit, input.devMode, input.language, input.translations); extensionsScannerService.ts ×6
627 > return this.scanExtension(extensionScannerInput);
628 > }));
629 > return coalesce(extensions)
630 > // Sort: Make sure extensions are in the same order always. Helps cache invalidation even if the order changes.
631 > .sort((a, b) => a.location.path < b.location.path ? -1 : 1);
632 > }
634 > private async scanExtensionsFromProfile(input: ExtensionScannerInput): Promise<IRelaxedScannedExtension[]> {
635 > let profileExtensions = await this.scanExtensionsFromProfileResource(input.location, () => true, input); extensionsScannerService.ts ×12
636 > if (input.applicationExtensionslocation && !this.uriIdentityService.extUri.isEqual(input.location, input.applicationExtensionslocation)) {
637 profileExtensions = profileExtensions.filter(e => !e.metadata?.isApplicationScoped);
638 const applicationExtensions = await this.scanExtensionsFromProfileResource(input.applicationExtensionslocation, (e) => !!e.metadata?.isBuiltin || !!e.metadata?.isApplicationScoped, input);
639 profileExtensions.push(...applicationExtensions);
640 }
641 > return profileExtensions; extensionsScannerService.ts ×12
642 > }
644 > private async scanExtensionsFromProfileResource(profileResource: URI, filter: (extensionInfo: IScannedProfileExtension) => boolean, input: ExtensionScannerInput): Promise<IRelaxedScannedExtension[]> {
645 > const scannedProfileExtensions = await this.extensionsProfileScannerService.scanProfileExtensions(profileResource, input.profileScanOptions); extensionsScannerService.ts ×12
646 > if (!scannedProfileExtensions.length) {
648 > }
649 > const extensions = await Promise.all<IRelaxedScannedExtension | null>( extensionsScannerService.ts ×4
650 > scannedProfileExtensions.map(async extensionInfo => {
651 > if (filter(extensionInfo)) {
652 > const extensionScannerInput = new ExtensionScannerInput(extensionInfo.location, input.mtime, input.applicationExtensionslocation, input.applicationExtensionslocationMtime, input.profile, input.profileScanOptions, input.type, input.validate, input.productVersion, input.productDate, input.productCommit, input.devMode, input.language, input.translations);
653 > return this.scanExtension(extensionScannerInput, extensionInfo);
654 > }
655 return null;
657 > return coalesce(extensions);
660 > async scanOneOrMultipleExtensions(input: ExtensionScannerInput): Promise<IRelaxedScannedExtension[]> {
662 > if (await this.fileService.exists(joinPath(input.location, 'package.json'))) {
663 > const extension = await this.scanExtension(input); extensionsScannerService.ts ×1
664 > return extension ? [extension] : [];
666 > return await this.scanExtensions(input); extensionsScannerService.ts ×1
667 > }
668 > } catch (error) { extensionsScannerService.ts ×5
669 this.logService.error(`Error scanning extensions at ${input.location.path}:`, getErrorMessage(error));
670 return [];
671 }
674 > async scanExtension(input: ExtensionScannerInput): Promise<IRelaxedScannedExtension | null>;
675 > async scanExtension(input: ExtensionScannerInput, scannedProfileExtension: IScannedProfileExtension): Promise<IRelaxedScannedExtension>;
676 > async scanExtension(input: ExtensionScannerInput, scannedProfileExtension?: IScannedProfileExtension): Promise<IRelaxedScannedExtension | null> {
677 > const validations: [Severity, string][] = []; extensionsScannerService.ts ×30
678 > let isValid = true;
679 > let manifest: IScannedExtensionManifest;
680 > try {
681 > manifest = await this.scanExtensionManifest(input.location);
682 > } catch (e) {
683 if (scannedProfileExtension) {
684 validations.push([Severity.Error, getErrorMessage(e)]);
685 isValid = false;
686 const [publisher, name] = scannedProfileExtension.identifier.id.split('.');
687 manifest = {
688 name,
689 publisher,
690 version: scannedProfileExtension.version,
691 engines: { vscode: '' }
692 };
693 } else {
694 if (input.type !== ExtensionType.System) {
695 this.logService.error(e);
696 }
697 return null;
698 }
699 }
701 > // allow publisher to be undefined to make the initial extension authoring experience smoother
702 > if (!manifest.publisher) {
703 manifest.publisher = UNDEFINED_PUBLISHER;
704 }
706 > let metadata: Metadata | undefined;
707 > if (scannedProfileExtension) {
708 > metadata = { extensionsScannerService.ts ×4
709 > ...scannedProfileExtension.metadata,
710 > size: manifest.__metadata?.size,
711 > };
712 > } else if (manifest.__metadata) { extensionsScannerService.ts ×30
713 > metadata = { extensionsScannerService.ts ×1
714 > installedTimestamp: manifest.__metadata.installedTimestamp,
715 > size: manifest.__metadata.size,
716 > targetPlatform: manifest.__metadata.targetPlatform,
717 > };
718 > }
720 > delete manifest.__metadata;
721 > const id = getGalleryExtensionId(manifest.publisher, manifest.name);
722 > const identifier = metadata?.id ? { id, uuid: metadata.id } : { id };
723 > const type = metadata?.isSystem ? ExtensionType.System : input.type;
724 > const isBuiltin = type === ExtensionType.System || !!metadata?.isBuiltin;
725 > try {
726 > manifest = await this.translateManifest(input.location, manifest, ExtensionScannerInput.createNlsConfiguration(input));
727 > } catch (error) {
728 this.logService.warn('Failed to translate manifest', getErrorMessage(error));
729 }
730 > let extension: IRelaxedScannedExtension = { extensionsScannerService.ts ×30
731 > type,
732 > identifier,
733 > manifest,
734 > location: input.location,
735 > isBuiltin,
736 > targetPlatform: metadata?.targetPlatform ?? TargetPlatform.UNDEFINED,
737 > publisherDisplayName: metadata?.publisherDisplayName,
738 > metadata,
739 > isValid,
740 > validations,
741 > preRelease: !!metadata?.preRelease,
742 > forceAutoUpdate: this.productBuiltInExtensionsEnabledWithAutoUpdates.has(id.toLowerCase()) && this.productQuality === 'stable',
743 > };
744 > if (input.validate) {
745 > extension = this.validate(extension, input);
746 > }
747 > if (manifest.enabledApiProposals) {
748 manifest.originalEnabledApiProposals = manifest.enabledApiProposals;
749 manifest.enabledApiProposals = parseEnabledApiProposalNames([...manifest.enabledApiProposals]);
750 }
751 > return extension; extensionsScannerService.ts ×30
752 > }
754 > validate(extension: IRelaxedScannedExtension, input: ExtensionScannerInput): IRelaxedScannedExtension {
755 > let isValid = extension.isValid; extensionsScannerService.ts ×30
756 > const validations = validateExtensionManifest(input.productVersion, input.productDate, input.location, extension.manifest, extension.isBuiltin);
757 > for (const [severity, message] of validations) {
758 > if (severity === Severity.Error) { extensionsScannerService.ts ×2
759 > isValid = false;
760 > this.logService.error(this.formatMessage(input.location, message));
761 > }
762 > }
763 > extension.isValid = isValid; extensionsScannerService.ts ×30
764 > extension.validations = [...extension.validations, ...validations];
765 > return extension;
766 > }
768 > private async scanExtensionManifest(extensionLocation: URI): Promise<IScannedExtensionManifest> {
769 > const manifestLocation = joinPath(extensionLocation, 'package.json'); extensionsScannerService.ts ×30
770 > let content;
771 > try {
772 > content = (await this.fileService.readFile(manifestLocation)).value.toString();
773 > } catch (error) {
774 if (toFileOperationResult(error) !== FileOperationResult.FILE_NOT_FOUND) {
775 this.logService.error(this.formatMessage(extensionLocation, localize('fileReadFail', "Cannot read file {0}: {1}.", manifestLocation.path, error.message)));
776 }
777 throw error;
778 }
779 > let manifest: IScannedExtensionManifest; extensionsScannerService.ts ×30
780 > try {
781 > manifest = JSON.parse(content);
782 > } catch (err) {
783 // invalid JSON, let's get good errors
784 const errors: ParseError[] = [];
785 parse(content, errors);
786 for (const e of errors) {
787 this.logService.error(this.formatMessage(extensionLocation, localize('jsonParseFail', "Failed to parse {0}: [{1}, {2}] {3}.", manifestLocation.path, e.offset, e.length, getParseErrorMessage(e.error))));
788 }
789 throw err;
790 }
791 > if (getNodeType(manifest) !== 'object') { extensionsScannerService.ts ×30
792 const errorMessage = this.formatMessage(extensionLocation, localize('jsonParseInvalidType', "Invalid manifest file {0}: Not a JSON object.", manifestLocation.path));
793 this.logService.error(errorMessage);
794 throw new Error(errorMessage);
795 }
796 > return manifest; extensionsScannerService.ts ×30
797 > }
799 > private async translateManifest(extensionLocation: URI, extensionManifest: IExtensionManifest, nlsConfiguration: NlsConfiguration): Promise<IExtensionManifest> {
800 > const localizedMessages = await this.getLocalizedMessages(extensionLocation, extensionManifest, nlsConfiguration); extensionsScannerService.ts ×30
801 > if (localizedMessages) {
803 > const errors: ParseError[] = [];
804 > // resolveOriginalMessageBundle returns null if localizedMessages.default === undefined;
805 > const defaults = await this.resolveOriginalMessageBundle(localizedMessages.default, errors);
806 > if (errors.length > 0) {
807 errors.forEach((error) => {
808 this.logService.error(this.formatMessage(extensionLocation, localize('jsonsParseReportErrors', "Failed to parse {0}: {1}.", localizedMessages.default?.path, getParseErrorMessage(error.error))));
809 });
810 return extensionManifest;
811 > } else if (getNodeType(localizedMessages) !== 'object') { extensionsScannerService.ts ×6
812 this.logService.error(this.formatMessage(extensionLocation, localize('jsonInvalidFormat', "Invalid format {0}: JSON object expected.", localizedMessages.default?.path)));
813 return extensionManifest;
814 }
815 > const localized = localizedMessages.values || Object.create(null); extensionsScannerService.ts ×6
816 > return localizeManifest(this.logService, extensionManifest, localized, defaults);
817 > } catch (error) {
818 /*Ignore Error*/
819 }
821 > return extensionManifest; extensionsScannerService.ts ×2
824 > private async getLocalizedMessages(extensionLocation: URI, extensionManifest: IExtensionManifest, nlsConfiguration: NlsConfiguration): Promise<LocalizedMessages | undefined> {
825 > const defaultPackageNLS = joinPath(extensionLocation, 'package.nls.json'); extensionsScannerService.ts ×30
826 > const reportErrors = (localized: URI | null, errors: ParseError[]): void => {
827 errors.forEach((error) => {
828 this.logService.error(this.formatMessage(extensionLocation, localize('jsonsParseReportErrors', "Failed to parse {0}: {1}.", localized?.path, getParseErrorMessage(error.error))));
829 });
830 };
831 > const reportInvalidFormat = (localized: URI | null): void => { extensionsScannerService.ts ×30
832 this.logService.error(this.formatMessage(extensionLocation, localize('jsonInvalidFormat', "Invalid format {0}: JSON object expected.", localized?.path)));
833 };
835 > const translationId = `${extensionManifest.publisher}.${extensionManifest.name}`;
836 > const translationPath = nlsConfiguration.translations[translationId];
837 >
838 > if (translationPath) {
840 > const translationResource = URI.file(translationPath);
841 > const content = (await this.fileService.readFile(translationResource)).value.toString();
842 > const errors: ParseError[] = [];
843 > const translationBundle: TranslationBundle = parse(content, errors);
844 > if (errors.length > 0) {
845 reportErrors(translationResource, errors);
846 return { values: undefined, default: defaultPackageNLS };
847 > } else if (getNodeType(translationBundle) !== 'object') { extensionsScannerService.ts ×5
848 reportInvalidFormat(translationResource);
849 return { values: undefined, default: defaultPackageNLS };
851 > const values = translationBundle.contents ? translationBundle.contents.package : undefined;
852 > return { values: values, default: defaultPackageNLS };
853 > }
854 > } catch (error) {
855 return { values: undefined, default: defaultPackageNLS };
856 }
858 > const exists = await this.fileService.exists(defaultPackageNLS); extensionsScannerService.ts ×2
859 > if (!exists) {
860 > return undefined; extensionsScannerService.ts ×2
861 > }
862 > let messageBundle; extensionsScannerService.ts ×9
863 > try {
864 > messageBundle = await this.findMessageBundles(extensionLocation, nlsConfiguration);
865 > } catch (error) {
866 return undefined;
867 }
868 > if (!messageBundle.localized) { extensionsScannerService.ts ×9
869 return { values: undefined, default: messageBundle.original };
870 }
872 > const messageBundleContent = (await this.fileService.readFile(messageBundle.localized)).value.toString();
873 > const errors: ParseError[] = [];
874 > const messages: MessageBag = parse(messageBundleContent, errors);
875 > if (errors.length > 0) {
876 reportErrors(messageBundle.localized, errors);
877 return { values: undefined, default: messageBundle.original };
878 > } else if (getNodeType(messages) !== 'object') { extensionsScannerService.ts ×9
879 reportInvalidFormat(messageBundle.localized);
880 return { values: undefined, default: messageBundle.original };
881 }
882 > return { values: messages, default: messageBundle.original }; extensionsScannerService.ts ×9
883 > } catch (error) {
884 return { values: undefined, default: messageBundle.original };
885 }
889 > /**
890 > * Parses original message bundle, returns null if the original message bundle is null.
891 > */
892 > private async resolveOriginalMessageBundle(originalMessageBundle: URI | null, errors: ParseError[]): Promise<{ [key: string]: string } | undefined> {
893 > if (originalMessageBundle) { extensionsScannerService.ts ×6
895 > const originalBundleContent = (await this.fileService.readFile(originalMessageBundle)).value.toString();
896 > return parse(originalBundleContent, errors);
897 > } catch (error) {
898 /* Ignore Error */
899 }
904 > /**
905 > * Finds localized message bundle and the original (unlocalized) one.
906 > * If the localized file is not present, returns null for the original and marks original as localized.
907 > */
908 > private findMessageBundles(extensionLocation: URI, nlsConfiguration: NlsConfiguration): Promise<{ localized: URI; original: URI | null }> {
909 > return new Promise<{ localized: URI; original: URI | null }>((c, e) => { extensionsScannerService.ts ×9
910 > const loop = (locale: string): void => {
911 const toCheck = joinPath(extensionLocation, `package.nls.${locale}.json`);
912 this.fileService.exists(toCheck).then(exists => {
913 if (exists) {
914 c({ localized: toCheck, original: joinPath(extensionLocation, 'package.nls.json') });
915 }
916 const index = locale.lastIndexOf('-');
917 if (index === -1) {
918 c({ localized: joinPath(extensionLocation, 'package.nls.json'), original: null });
919 } else {
920 locale = locale.substring(0, index);
921 loop(locale);
922 }
923 });
924 };
925 > if (nlsConfiguration.devMode || nlsConfiguration.pseudo || !nlsConfiguration.language) { extensionsScannerService.ts ×9
926 > return c({ localized: joinPath(extensionLocation, 'package.nls.json'), original: null });
927 > }
928 loop(nlsConfiguration.language);
930 > }
932 > private formatMessage(extensionLocation: URI, message: string): string {
933 > return `[${extensionLocation.path}]: ${message}`; extensionsScannerService.ts ×2
934 > }
936 > }
937 >
938 > interface IExtensionCacheData {
939 > input: ExtensionScannerInput;
940 > result: IRelaxedScannedExtension[];
941 > }
942 >
943 > class CachedExtensionsScanner extends ExtensionsScanner {
944 >
945 > private input: ExtensionScannerInput | undefined;
946 > private readonly cacheValidatorThrottler: ThrottledDelayer<void> = this._register(new ThrottledDelayer(3000));
947 >
948 > private readonly _onDidChangeCache = this._register(new Emitter<void>());
949 > readonly onDidChangeCache = this._onDidChangeCache.event;
950 >
951 > constructor(
952 > private readonly currentProfile: IUserDataProfile, extensionsScannerService.ts ×30
953 > @IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService,
954 > @IExtensionsProfileScannerService extensionsProfileScannerService: IExtensionsProfileScannerService,
955 > @IUriIdentityService uriIdentityService: IUriIdentityService,
956 > @IFileService fileService: IFileService,
957 > @IProductService productService: IProductService,
958 > @IEnvironmentService environmentService: IEnvironmentService,
959 > @ILogService logService: ILogService
960 > ) {
961 > super(extensionsProfileScannerService, uriIdentityService, fileService, productService, environmentService, logService);
962 > }
964 > override async scanExtensions(input: ExtensionScannerInput): Promise<IRelaxedScannedExtension[]> {
965 const cacheFile = this.getCacheFile(input);
966 const cacheContents = await this.readExtensionCache(cacheFile);
967 this.input = input;
968 if (cacheContents && cacheContents.input && ExtensionScannerInput.equals(cacheContents.input, this.input)) {
969 this.logService.debug('Using cached extensions scan result', input.type === ExtensionType.System ? 'system' : 'user', input.location.toString());
970 this.cacheValidatorThrottler.trigger(() => this.validateCache());
971 return cacheContents.result.map((extension) => {
972 // revive URI object
973 extension.location = URI.revive(extension.location);
974 return extension;
975 });
976 }
977 const result = await super.scanExtensions(input);
978 await this.writeExtensionCache(cacheFile, { input, result });
979 return result;
980 }
982 > private async readExtensionCache(cacheFile: URI): Promise<IExtensionCacheData | null> {
983 try {
984 const cacheRawContents = await this.fileService.readFile(cacheFile);
985 const extensionCacheData: IExtensionCacheData = JSON.parse(cacheRawContents.value.toString());
986 return { result: extensionCacheData.result, input: revive(extensionCacheData.input) };
987 } catch (error) {
988 if (toFileOperationResult(error) !== FileOperationResult.FILE_NOT_FOUND) {
989 this.logService.debug('Error while reading the extension cache file:', cacheFile.path, getErrorMessage(error));
990 }
991 }
992 return null;
993 }
995 > private async writeExtensionCache(cacheFile: URI, cacheContents: IExtensionCacheData): Promise<void> {
996 try {
997 await this.fileService.writeFile(cacheFile, VSBuffer.fromString(JSON.stringify(cacheContents)));
998 } catch (error) {
999 this.logService.debug('Error while writing the extension cache file:', cacheFile.path, getErrorMessage(error));
1000 }
1001 }
1003 > private async validateCache(): Promise<void> {
1004 if (!this.input) {
1005 // Input has been unset by the time we get here, so skip validation
1006 return;
1007 }
1008
1009 const cacheFile = this.getCacheFile(this.input);
1010 const cacheContents = await this.readExtensionCache(cacheFile);
1011 if (!cacheContents) {
1012 // Cache has been deleted by someone else, which is perfectly fine...
1013 return;
1014 }
1015
1016 const actual = cacheContents.result;
1017 const expected = JSON.parse(JSON.stringify(await super.scanExtensions(this.input)));
1018 if (objects.equals(expected, actual)) {
1019 // Cache is valid and running with it is perfectly fine...
1020 return;
1021 }
1022
1023 try {
1024 this.logService.info('Invalidating Cache', actual, expected);
1025 // Cache is invalid, delete it
1026 await this.fileService.del(cacheFile);
1027 this._onDidChangeCache.fire();
1028 } catch (error) {
1029 this.logService.error(error);
1030 }
1031 }
1033 > private getCacheFile(input: ExtensionScannerInput): URI {
1034 const profile = this.getProfile(input);
1035 return this.uriIdentityService.extUri.joinPath(profile.cacheHome, input.type === ExtensionType.System ? BUILTIN_MANIFEST_CACHE_FILE : USER_MANIFEST_CACHE_FILE);
1036 }
1038 > private getProfile(input: ExtensionScannerInput): IUserDataProfile {
1039 if (input.type === ExtensionType.System) {
1040 return this.userDataProfilesService.defaultProfile;
1041 }
1042 if (!input.profile) {
1043 return this.userDataProfilesService.defaultProfile;
1044 }
1045 if (this.uriIdentityService.extUri.isEqual(input.location, this.currentProfile.extensionsResource)) {
1046 return this.currentProfile;
1047 }
1048 return this.userDataProfilesService.profiles.find(p => this.uriIdentityService.extUri.isEqual(input.location, p.extensionsResource)) ?? this.currentProfile;
1049 }
1051 > }
1052 >
1053 > export function toExtensionDescription(extension: IScannedExtension, isUnderDevelopment: boolean): IExtensionDescription {
1054 const id = getExtensionId(extension.manifest.publisher, extension.manifest.name);
1055 return {
1056 id,
1057 identifier: new ExtensionIdentifier(id),
1058 isBuiltin: extension.type === ExtensionType.System,
1059 isUserBuiltin: extension.type === ExtensionType.User && extension.isBuiltin,
1060 isUnderDevelopment,
1061 extensionLocation: extension.location,
1062 uuid: extension.identifier.uuid,
1063 targetPlatform: extension.targetPlatform,
1064 publisherDisplayName: extension.publisherDisplayName,
1065 preRelease: extension.preRelease,
1066 ...extension.manifest,
1067 };
1068 }
1070 > export class NativeExtensionsScannerService extends AbstractExtensionsScannerService implements IExtensionsScannerService {
1071 >
1072 > private readonly translationsPromise: Promise<Translations>;
1073 >
1074 > constructor(
1075 systemExtensionsLocation: URI,
1076 userExtensionsLocation: URI,
1077 userHome: URI,
1078 currentProfile: IUserDataProfile,
1079 userDataProfilesService: IUserDataProfilesService,
1080 extensionsProfileScannerService: IExtensionsProfileScannerService,
1081 fileService: IFileService,
1082 logService: ILogService,
1083 environmentService: IEnvironmentService,
1084 productService: IProductService,
1085 uriIdentityService: IUriIdentityService,
1086 instantiationService: IInstantiationService,
1087 ) {
1088 super(
1089 systemExtensionsLocation,
1090 userExtensionsLocation,
1091 joinPath(userHome, '.vscode-oss-dev', 'extensions', 'control.json'),
1092 currentProfile,
1093 userDataProfilesService, extensionsProfileScannerService, fileService, logService, environmentService, productService, uriIdentityService, instantiationService);
1094 this.translationsPromise = (async () => {
1095 if (platform.translationsConfigFile) {
1096 try {
1097 const content = await this.fileService.readFile(URI.file(platform.translationsConfigFile));
1098 return JSON.parse(content.value.toString());
1099 } catch (err) { /* Ignore Error */ }
1100 }
1101 return Object.create(null);
1102 })();
1103 }
1105 > protected getTranslations(language: string): Promise<Translations> {
1106 return this.translationsPromise;
1107 }
1109 > }