Skip to content

Commit 2ba9d3c

Browse files
CHANGE: @W-17970149@: Some more refactoring to remove remaining global state (#189)
1 parent 20fdbd4 commit 2ba9d3c

17 files changed

+778
-789
lines changed

.vscodeignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ templates/**
1919
**/*.ts
2020
**/.vscode-test.*
2121
**/eslint.config.mjs
22-
**/tsconfig.json
22+
**/tsconfig.json
23+
**/jest.config.mjs

src/extension.ts

+184-587
Large diffs are not rendered by default.

src/modelBasedFixers/apex-pmd-violations-fixer.ts src/lib/agentforce/agentforce-violations-fixer.ts

+18-23
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,24 @@
66
*/
77

88
import * as vscode from 'vscode';
9-
import * as Constants from '../lib/constants';
9+
import * as Constants from '../constants';
1010
import * as PromptConstants from './prompt-constants';
11-
import {LLMServiceInterface, ServiceProvider, ServiceType} from '@salesforce/vscode-service-provider';
12-
import { PromptBuilder } from './prompt-formatter';
13-
import { messages } from '../lib/messages';
14-
import { randomUUID } from 'crypto';
15-
16-
export class ApexPmdViolationsFixer implements vscode.CodeActionProvider {
17-
static readonly providedCodeActionKinds = [vscode.CodeActionKind.QuickFix];
18-
provideCodeActions(
19-
document: vscode.TextDocument,
20-
range: vscode.Range,
21-
context: vscode.CodeActionContext,
22-
_token: vscode.CancellationToken
23-
): vscode.CodeAction[] {
11+
import { PromptBuilder } from './prompt-builder';
12+
import { messages } from '../messages';
13+
import {CodeActionKind} from "vscode";
14+
import {LLMService} from "../external-services/llm-service";
15+
16+
export class AgentforceViolationsFixer implements vscode.CodeActionProvider {
17+
static readonly providedCodeActionKinds: CodeActionKind[] = [vscode.CodeActionKind.QuickFix];
18+
19+
private readonly llmService: LLMService;
20+
21+
constructor(llmService: LLMService) {
22+
this.llmService = llmService;
23+
}
24+
25+
provideCodeActions(document: vscode.TextDocument, range: vscode.Range, context: vscode.CodeActionContext,
26+
_token: vscode.CancellationToken): vscode.CodeAction[] {
2427
const codeActions: vscode.CodeAction[] = [];
2528

2629
// Throw out diagnostics that aren't ours, or are for the wrong line.
@@ -74,11 +77,8 @@ export class ApexPmdViolationsFixer implements vscode.CodeActionProvider {
7477
const [document, diagnostic] = codeAction.command.arguments as [vscode.TextDocument, vscode.Diagnostic];
7578
const prompt = this.generatePrompt(document, diagnostic);
7679

77-
// Get the LLM service instance
78-
const llmService: LLMServiceInterface = await ServiceProvider.getService(ServiceType.LLMService, Constants.EXTENSION_ID);
79-
8080
// Call the LLM service with the generated prompt
81-
const llmResponse = await llmService.callLLM(prompt, getUniqueId());
81+
const llmResponse = await this.llmService.callLLM(prompt);
8282
const codeSnippet = this.extractCodeFromResponse(llmResponse);
8383

8484
const updatedFileContent = this.replaceCodeInFile(document.getText(), codeSnippet.trim(), diagnostic.range.start.line + 1, diagnostic.range.end.line + 1, document);
@@ -274,8 +274,3 @@ export class ApexPmdViolationsFixer implements vscode.CodeActionProvider {
274274
diagnosticCollection.set(uri, updatedDiagnostics);
275275
}
276276
}
277-
278-
export function getUniqueId(): string {
279-
return randomUUID();
280-
}
281-
File renamed without changes.

src/apexguru/apex-guru-service.ts src/lib/apexguru/apex-guru-service.ts

+8-13
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@
77

88
import * as vscode from 'vscode';
99
import * as fspromises from 'fs/promises';
10-
import {Connection, CoreExtensionService} from '../lib/core-extension-service';
11-
import * as Constants from '../lib/constants';
12-
import {messages} from '../lib/messages';
13-
import {DiagnosticConvertible, DiagnosticManagerImpl} from '../lib/diagnostics';
14-
import {RunInfo} from '../extension';
15-
import {TelemetryService} from "../lib/external-services/telemetry-service";
16-
import {Logger} from "../lib/logger";
10+
import {Connection, CoreExtensionService} from '../core-extension-service';
11+
import * as Constants from '../constants';
12+
import {messages} from '../messages';
13+
import {DiagnosticConvertible, DiagnosticManager} from '../diagnostics';
14+
import {TelemetryService} from "../external-services/telemetry-service";
15+
import {Logger} from "../logger";
1716

1817
export async function isApexGuruEnabledInOrg(logger: Logger): Promise<boolean> {
1918
try {
@@ -33,11 +32,7 @@ export async function isApexGuruEnabledInOrg(logger: Logger): Promise<boolean> {
3332
}
3433
}
3534

36-
export async function runApexGuruOnFile(selection: vscode.Uri, runInfo: RunInfo, telemetryService: TelemetryService, logger: Logger) {
37-
const {
38-
diagnosticCollection,
39-
commandName
40-
} = runInfo;
35+
export async function runApexGuruOnFile(selection: vscode.Uri, commandName: string, diagnosticManager: DiagnosticManager, telemetryService: TelemetryService, logger: Logger) {
4136
const startTime = Date.now();
4237
try {
4338
await vscode.window.withProgress({
@@ -54,7 +49,7 @@ export async function runApexGuruOnFile(selection: vscode.Uri, runInfo: RunInfo,
5449

5550
const convertibles: DiagnosticConvertible[] = transformStringToDiagnosticConvertibles(selection.fsPath, decodedReport);
5651
// TODO: For testability, the diagnostic manager should probably be passed in, not instantiated here.
57-
new DiagnosticManagerImpl(diagnosticCollection).displayAsDiagnostics([selection.fsPath], convertibles);
52+
diagnosticManager.displayAsDiagnostics([selection.fsPath], convertibles);
5853
telemetryService.sendCommandEvent(Constants.TELEM_SUCCESSFUL_APEX_GURU_FILE_ANALYSIS, {
5954
executedCommand: commandName,
6055
duration: (Date.now() - startTime).toString(),

src/lib/code-analyzer-runner.ts

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
2+
import {Displayable, ProgressNotification, UxDisplay} from "./display";
3+
import {Logger} from "./logger";
4+
import {DiagnosticConvertible, DiagnosticManager} from "./diagnostics";
5+
import vscode from "vscode";
6+
import {messages} from "./messages";
7+
import {TelemetryService} from "./external-services/telemetry-service";
8+
import {SettingsManager} from "./settings";
9+
import {CliScannerV5Strategy} from "./scanner-strategies/v5-scanner";
10+
import {CliScannerV4Strategy} from "./scanner-strategies/v4-scanner";
11+
import {ScannerAction, ScannerDependencies} from "./actions/scanner-action";
12+
import * as Constants from './constants';
13+
14+
export class CodeAnalyzerRunner {
15+
private readonly diagnosticManager: DiagnosticManager;
16+
private readonly settingsManager: SettingsManager;
17+
private readonly telemetryService: TelemetryService;
18+
private readonly logger: Logger;
19+
20+
constructor(diagnosticManager: DiagnosticManager, settingsManager: SettingsManager, telemetryService: TelemetryService, logger: Logger) {
21+
this.diagnosticManager = diagnosticManager;
22+
this.settingsManager = settingsManager;
23+
this.telemetryService = telemetryService;
24+
this.logger = logger;
25+
}
26+
27+
/**
28+
* Runs the scanner against the specified file and displays the results.
29+
* @param commandName The command being run
30+
* @param targets The files/folders to run against
31+
*/
32+
async runAndDisplay(commandName: string, targets: string[]): Promise<void> {
33+
const startTime = Date.now();
34+
try {
35+
return await vscode.window.withProgress({
36+
location: vscode.ProgressLocation.Notification
37+
}, async (progress) => {
38+
const display: UxDisplay = new UxDisplay(new VSCodeDisplayable((notif: ProgressNotification) => progress.report(notif), this.logger));
39+
const scannerStrategy = this.settingsManager.getCodeAnalyzerV5Enabled()
40+
? new CliScannerV5Strategy({
41+
tags: this.settingsManager.getCodeAnalyzerTags()
42+
})
43+
: new CliScannerV4Strategy({
44+
engines: this.settingsManager.getEnginesToRun(),
45+
pmdCustomConfigFile: this.settingsManager.getPmdCustomConfigFile(),
46+
rulesCategory: this.settingsManager.getRulesCategory(),
47+
normalizeSeverity: this.settingsManager.getNormalizeSeverityEnabled()
48+
});
49+
const actionDependencies: ScannerDependencies = {
50+
scannerStrategy: scannerStrategy,
51+
display: display,
52+
diagnosticManager: this.diagnosticManager,
53+
telemetryService: this.telemetryService
54+
};
55+
const scannerAction = new ScannerAction(commandName, actionDependencies);
56+
await scannerAction.runScanner(targets);
57+
});
58+
} catch (e) {
59+
const errMsg = e instanceof Error ? e.message : e as string;
60+
this.telemetryService.sendException(Constants.TELEM_FAILED_STATIC_ANALYSIS, errMsg, {
61+
executedCommand: commandName,
62+
duration: (Date.now() - startTime).toString()
63+
});
64+
// This has to be a floating promise, since the command won't complete until
65+
// the error is dismissed.
66+
vscode.window.showErrorMessage(messages.error.analysisFailedGenerator(errMsg));
67+
this.logger.error(errMsg);
68+
}
69+
}
70+
}
71+
72+
class VSCodeDisplayable implements Displayable {
73+
private readonly progressCallback: (notif: ProgressNotification) => void;
74+
private readonly logger: Logger;
75+
76+
public constructor(progressCallback: (notif: ProgressNotification) => void, logger: Logger) {
77+
this.progressCallback = progressCallback;
78+
this.logger = logger;
79+
}
80+
81+
public progress(notification: ProgressNotification): void {
82+
this.progressCallback(notification);
83+
}
84+
85+
/**
86+
* Display a Toast summarizing the results of a non-DFA scan, i.e. how many files were scanned, how many had violations, and how many violations were found.
87+
* @param allTargets The files that were scanned. This may be a superset of the files that actually had violations.
88+
* @param results The results of a scan.
89+
*/
90+
public async results(allTargets: string[], results: DiagnosticConvertible[]): Promise<void> {
91+
const uniqueFiles: Set<string> = new Set();
92+
for (const result of results) {
93+
uniqueFiles.add(result.locations[result.primaryLocationIndex].file);
94+
}
95+
await vscode.window.showInformationMessage(messages.info.finishedScan(allTargets.length, uniqueFiles.size, results.length));
96+
}
97+
98+
public log(msg: string): void {
99+
this.logger.log(msg);
100+
}
101+
}
File renamed without changes.

0 commit comments

Comments
 (0)