From c5946a507d5fc742f56765a0b3d231fa482c3966 Mon Sep 17 00:00:00 2001 From: Roland Grunberg Date: Tue, 10 Sep 2024 14:46:56 -0400 Subject: [PATCH] Extension IDs listed for 'unwantedRecommendations' should be ignored. - Support 'unwantedRecommendations' in .vscode/extensions.json and in the '.code-workspace' (multi-root) files Signed-off-by: Roland Grunberg --- src/vscode/impl/recommendationServiceImpl.ts | 42 +++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/vscode/impl/recommendationServiceImpl.ts b/src/vscode/impl/recommendationServiceImpl.ts index 4600069..bfa0690 100644 --- a/src/vscode/impl/recommendationServiceImpl.ts +++ b/src/vscode/impl/recommendationServiceImpl.ts @@ -9,6 +9,8 @@ import { IRecommendationService } from "../recommendationService"; import { IStorageService } from "../storageService"; import { StorageServiceImpl } from "./storageServiceImpl"; import { getInstalledExtensionName, isExtensionInstalled, promptUserUtil, installExtensionUtil } from "./vscodeUtil"; +import { existsSync } from "fs"; +import { readFile } from "./util/fsUtil"; export const filterUnique = (value: any, index: number, self: any[]): boolean => self.indexOf(value) === index; @@ -40,6 +42,23 @@ export class RecommendationServiceImpl implements IRecommendationService { return path.resolve(context.globalStorageUri.fsPath, '..', 'vscode-extension-recommender'); } + protected getExtensionConfiguration(): string | undefined { + if (workspace.workspaceFolders !== undefined) { + if (workspace.workspaceFolders.length == 1) { + const file = path.resolve(workspace.workspaceFolders[0].uri.path, '.vscode', 'extensions.json'); + if (existsSync(file)) { + return file; + } + } else { + const file = workspace.workspaceFile?.path; + if (file !== undefined && existsSync(file)) { + return file; + } + } + } + return undefined; + } + public async register(toAdd: Recommendation[]): Promise { const newSession: boolean = await this.addRecommendationsToModel(toAdd); if( newSession ) { @@ -56,6 +75,26 @@ export class RecommendationServiceImpl implements IRecommendationService { return false; } + protected async isUnwantedRecommendation(toExtension: string): Promise { + const extensionConfigFile = this.getExtensionConfiguration(); + if (extensionConfigFile !== undefined) { + try { + const jsonData = await readFile(extensionConfigFile); + if (jsonData) { + let json = JSON.parse(jsonData); + if (workspace.workspaceFile?.path !== undefined) { + json = json['extensions']; + } + const unwantedRecommendations = json['unwantedRecommendations']; + return !!unwantedRecommendations && unwantedRecommendations.length > 0 && unwantedRecommendations.includes(toExtension); + } + } catch (err) { + // continue + } + } + return false; + } + public create(extensionId: string, extensionDisplayName: string, description: string, @@ -114,7 +153,7 @@ export class RecommendationServiceImpl implements IRecommendationService { // Show a single recommendation immediately, if certain conditions are met // Specifically, if the recommender is installed, and the recommended is not installed, // and the recommended has not been timelocked in this session or ignored by user previously - if( this.ignoreRecommendations()) { + if( this.ignoreRecommendations() || await this.isUnwantedRecommendation(toExtension)) { return; } @@ -154,6 +193,7 @@ export class RecommendationServiceImpl implements IRecommendationService { const recommendedExtension: string[] = model.recommendations .map((x) => x.extensionId) .filter(filterUnique) + .filter((x) => !this.isUnwantedRecommendation(x)) .filter((x) => !isExtensionInstalled(x)); for( let i = 0; i < recommendedExtension.length; i++ ) { this.showStartupRecommendationsForSingleExtension(model, recommendedExtension[i]);