From 351587ea9db011b3fb89520a7f7dfab62949728c Mon Sep 17 00:00:00 2001 From: svc-cli-bot Date: Tue, 29 Apr 2025 13:16:20 -0500 Subject: [PATCH 1/3] Updating SHA256.md after 1.6.0 release --- SHA256.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SHA256.md b/SHA256.md index 839b2d95..4adecb1f 100644 --- a/SHA256.md +++ b/SHA256.md @@ -15,7 +15,7 @@ make sure that their SHA values match the values in the list below. shasum -a 256 3. Confirm that the SHA in your output matches the value in this list of SHAs. - 8dbf73cb26d6dbc695b5d0fe0f901ab7cbf1fb834640713dfb717209c224474d ./extensions/sfdx-code-analyzer-vscode-1.5.1.vsix + fc2d37a4f1c59206be01f30ff9384ec202632b7bb8d95b4776c4d75469377ff4 ./extensions/sfdx-code-analyzer-vscode-1.6.0.vsix 4. Change the filename extension for the file that you downloaded from .zip to .vsix. From 40986bf012d0b3706d0418903ff8725735201dfc Mon Sep 17 00:00:00 2001 From: Stephen Carter <123964848+stephen-carter-at-sf@users.noreply.github.com> Date: Wed, 30 Apr 2025 11:14:04 -0400 Subject: [PATCH 2/3] =?UTF-8?q?FIX:=20@W-18403733@:=20Pass=20in=20raw=20se?= =?UTF-8?q?lection=20to=20be=20scanned=20instead=20of=20expanding=E2=80=A6?= =?UTF-8?q?=20(#235)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/extension.ts | 24 ++++--- src/lib/cli-commands.ts | 28 +++++--- src/lib/code-analyzer-run-action.ts | 12 ++-- src/lib/code-analyzer.ts | 12 ++-- .../scanner-strategies/scanner-strategy.ts | 3 +- src/lib/scanner-strategies/v4-scanner.ts | 9 +-- src/lib/scanner-strategies/v5-scanner.ts | 23 ++---- src/lib/workspace.ts | 72 +++++++++++++++++++ src/test/legacy/extension.test.ts | 12 +++- .../unit/lib/code-analyzer-run-action.test.ts | 25 ++++--- src/test/unit/lib/code-analyzer.test.ts | 29 +++++--- src/test/unit/stubs.ts | 5 +- 12 files changed, 179 insertions(+), 75 deletions(-) create mode 100644 src/lib/workspace.ts diff --git a/src/extension.ts b/src/extension.ts index e1a4733e..7d9a5194 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -33,6 +33,7 @@ import {CliCommandExecutor, CliCommandExecutorImpl} from "./lib/cli-commands"; import {getErrorMessage} from "./lib/utils"; import {FileHandler, FileHandlerImpl} from "./lib/fs-utils"; import {VscodeWorkspace, VscodeWorkspaceImpl, WindowManager, WindowManagerImpl} from "./lib/vscode-api"; +import {Workspace} from "./lib/workspace"; // Object to hold the state of our extension for a specific activation context, to be returned by our activate function @@ -85,13 +86,14 @@ export async function activate(context: vscode.ExtensionContext): Promise { @@ -154,22 +158,20 @@ export async function activate(context: vscode.ExtensionContext): Promise { const selection: vscode.Uri[] = (multiSelection && multiSelection.length > 0) ? multiSelection : [singleSelection]; - // TODO: We may wish to consider moving away from this target resolution, and just passing in files and folders - // as given to us. It's possible the current style could lead to overflowing the CLI when a folder has - // many files. - const selectedFiles: string[] = await targeting.getFilesFromSelection(selection); - if (selectedFiles.length == 0) { // I have not found a way to hit this, but we should check just in case + const workspace: Workspace = await Workspace.fromTargetPaths(selection.map(uri => uri.fsPath), vscodeWorkspace, fileHandler); + if (workspace.getRawTargetPaths().length == 0) { // I have not found a way to hit this, but we should check just in case vscode.window.showWarningMessage(messages.targeting.error.noFileSelected); return; } - await codeAnalyzerRunAction.run(Constants.COMMAND_RUN_ON_SELECTED, selectedFiles); + await codeAnalyzerRunAction.run(Constants.COMMAND_RUN_ON_SELECTED, workspace); }); diff --git a/src/lib/cli-commands.ts b/src/lib/cli-commands.ts index 1b7c733e..de8e8c3c 100644 --- a/src/lib/cli-commands.ts +++ b/src/lib/cli-commands.ts @@ -96,20 +96,30 @@ export class CliCommandExecutorImpl implements CliCommandExecutor { async exec(command: string, args: string[], options: ExecOptions = {}): Promise { return new Promise((resolve) => { - const childProcess: cp.ChildProcessWithoutNullStreams = cp.spawn(command, args, { - shell: process.platform.startsWith('win'), // Use shell on Windows machines - }); - - if (options.pidHandler) { - options.pidHandler(childProcess.pid); - } - const logLevel: vscode.LogLevel = options.logLevel === undefined ? vscode.LogLevel.Trace : options.logLevel; - const output: CommandOutput = { stdout: '', stderr: '', exitCode: 0 }; + + let childProcess: cp.ChildProcessWithoutNullStreams; + try { + childProcess = cp.spawn(command, args, { + shell: process.platform.startsWith('win'), // Use shell on Windows machines + }); + } catch (err) { + this.logger.logAtLevel(vscode.LogLevel.Error, `Failed to execute the following command:\n` + + indent(`${command} ${args.map(arg => arg.includes(' ') ? `"${arg}"` : arg).join(' ')}`) + `\n\n` + + 'Error Thrown:\n' + indent(getErrorMessageWithStack(err))); + output.stderr = getErrorMessageWithStack(err); + output.exitCode = 127; + resolve(output); + } + + if (options.pidHandler) { + options.pidHandler(childProcess.pid); + } + const logLevel: vscode.LogLevel = options.logLevel === undefined ? vscode.LogLevel.Trace : options.logLevel; let combinedOut: string = ''; this.logger.logAtLevel(logLevel, `Executing with background process (${childProcess.pid}):\n` + diff --git a/src/lib/code-analyzer-run-action.ts b/src/lib/code-analyzer-run-action.ts index 61057c3f..60422fde 100644 --- a/src/lib/code-analyzer-run-action.ts +++ b/src/lib/code-analyzer-run-action.ts @@ -9,6 +9,7 @@ import {Display} from "./display"; import {getErrorMessage, getErrorMessageWithStack} from "./utils"; import {ProgressReporter, TaskWithProgressRunner} from "./progress"; import {WindowManager} from "./vscode-api"; +import {Workspace} from "./workspace"; export const UNINSTANTIABLE_ENGINE_RULE = 'UninstantiableEngineError'; @@ -35,9 +36,9 @@ export class CodeAnalyzerRunAction { /** * Runs the scanner against the specified file and displays the results. * @param commandName The command being run - * @param filesToScan The files to run against + * @param workspace The workspace to run against */ - run(commandName: string, filesToScan: string[]): Promise { + run(commandName: string, workspace: Workspace): Promise { return this.taskWithProgressRunner.runTask(async (progressReporter: ProgressReporter) => { const startTime: number = Date.now(); @@ -59,7 +60,7 @@ export class CodeAnalyzerRunAction { increment: 20 }); this.logger.log(messages.info.scanningWith(await this.codeAnalyzer.getScannerName())); - const violations: Violation[] = await this.codeAnalyzer.scan(filesToScan); + const violations: Violation[] = await this.codeAnalyzer.scan(workspace); progressReporter.reportProgress({ message: messages.scanProgressReport.processingResults, @@ -78,9 +79,10 @@ export class CodeAnalyzerRunAction { }); const diagnostics: CodeAnalyzerDiagnostic[] = violationsWithFileLocation.map(v => CodeAnalyzerDiagnostic.fromViolation(v)); - this.diagnosticManager.clearDiagnosticsForFiles(filesToScan.map(f => vscode.Uri.file(f))); + const targetedFiles: string[] = await workspace.getTargetedFiles(); + this.diagnosticManager.clearDiagnosticsForFiles(targetedFiles.map(f => vscode.Uri.file(f))); this.diagnosticManager.addDiagnostics(diagnostics); - void this.displayResults(filesToScan.length, violationsWithFileLocation); + void this.displayResults(targetedFiles.length, violationsWithFileLocation); this.telemetryService.sendCommandEvent(Constants.TELEM_SUCCESSFUL_STATIC_ANALYSIS, { commandName: commandName, diff --git a/src/lib/code-analyzer.ts b/src/lib/code-analyzer.ts index c7279bb4..32aa3332 100644 --- a/src/lib/code-analyzer.ts +++ b/src/lib/code-analyzer.ts @@ -11,8 +11,8 @@ import { RECOMMENDED_MINIMUM_REQUIRED_CODE_ANALYZER_CLI_PLUGIN_VERSION } from "./constants"; import {CliScannerStrategy} from "./scanner-strategies/scanner-strategy"; -import {VscodeWorkspace, VscodeWorkspaceImpl} from "./vscode-api"; import {FileHandler, FileHandlerImpl} from "./fs-utils"; +import {Workspace} from "./workspace"; export interface CodeAnalyzer extends CliScannerStrategy { validateEnvironment(): Promise; @@ -22,7 +22,6 @@ export class CodeAnalyzerImpl implements CodeAnalyzer { private readonly cliCommandExecutor: CliCommandExecutor; private readonly settingsManager: SettingsManager; private readonly display: Display; - private readonly vscodeWorkspace: VscodeWorkspace; private readonly fileHandler: FileHandler private cliIsInstalled: boolean = false; @@ -31,11 +30,10 @@ export class CodeAnalyzerImpl implements CodeAnalyzer { private codeAnalyzerV5?: CliScannerV5Strategy; constructor(cliCommandExecutor: CliCommandExecutor, settingsManager: SettingsManager, display: Display, - vscodeWorkspace: VscodeWorkspace = new VscodeWorkspaceImpl(), fileHandler: FileHandler = new FileHandlerImpl()) { + fileHandler: FileHandler = new FileHandlerImpl()) { this.cliCommandExecutor = cliCommandExecutor; this.settingsManager = settingsManager; this.display = display; - this.vscodeWorkspace = vscodeWorkspace; this.fileHandler = fileHandler; } @@ -87,11 +85,11 @@ export class CodeAnalyzerImpl implements CodeAnalyzer { this.display.displayWarning(messages.codeAnalyzer.usingOlderVersion(installedVersion.toString(), recommendedMinVersion.toString()) + '\n' + messages.codeAnalyzer.installLatestVersion); } - this.codeAnalyzerV5 = new CliScannerV5Strategy(installedVersion, this.cliCommandExecutor, this.settingsManager, this.vscodeWorkspace, this.fileHandler); + this.codeAnalyzerV5 = new CliScannerV5Strategy(installedVersion, this.cliCommandExecutor, this.settingsManager, this.fileHandler); } - async scan(filesToScan: string[]): Promise { - return (await this.getDelegate()).scan(filesToScan); + async scan(workspace: Workspace): Promise { + return (await this.getDelegate()).scan(workspace); } async getScannerName(): Promise { diff --git a/src/lib/scanner-strategies/scanner-strategy.ts b/src/lib/scanner-strategies/scanner-strategy.ts index 1b3b0ea7..1f450aa2 100644 --- a/src/lib/scanner-strategies/scanner-strategy.ts +++ b/src/lib/scanner-strategies/scanner-strategy.ts @@ -1,7 +1,8 @@ import {Violation} from '../diagnostics'; +import {Workspace} from "../workspace"; export interface CliScannerStrategy { - scan(filesToScan: string[]): Promise; + scan(workspace: Workspace): Promise; getScannerName(): Promise; diff --git a/src/lib/scanner-strategies/v4-scanner.ts b/src/lib/scanner-strategies/v4-scanner.ts index 93c18ae4..758b0d0e 100644 --- a/src/lib/scanner-strategies/v4-scanner.ts +++ b/src/lib/scanner-strategies/v4-scanner.ts @@ -6,6 +6,7 @@ import {SettingsManager} from "../settings"; import * as semver from 'semver'; import {CliCommandExecutor, CommandOutput} from "../cli-commands"; import {FileHandler} from "../fs-utils"; +import {Workspace} from "../workspace"; export type BaseV4Violation = { ruleName: string; @@ -66,9 +67,9 @@ export class CliScannerV4Strategy implements CliScannerStrategy { return Promise.resolve(`@salesforce/sfdx-scanner@${this.version.toString()} via CLI`); } - public async scan(filesToScan: string[]): Promise { + public async scan(workspace: Workspace): Promise { // Create the arg array. - const args: string[] = await this.createArgArray(filesToScan); + const args: string[] = await this.createArgArray(workspace); // Invoke the scanner. const executionResult: V4ExecutionResult = await this.invokeAnalyzer(args); @@ -77,7 +78,7 @@ export class CliScannerV4Strategy implements CliScannerStrategy { return this.processResults(executionResult); } - private async createArgArray(targets: string[]): Promise { + private async createArgArray(workspace: Workspace): Promise { const engines: string = this.settingsManager.getEnginesToRun(); const pmdCustomConfigFile: string | undefined = this.settingsManager.getPmdCustomConfigFile(); const rulesCategory: string | undefined = this.settingsManager.getRulesCategory(); @@ -89,7 +90,7 @@ export class CliScannerV4Strategy implements CliScannerStrategy { const args: string[] = [ 'scanner', 'run', - '--target', `${targets.join(',')}`, + '--target', `${workspace.getRawTargetPaths().join(',')}`, `--engine`, engines, `--json` ]; diff --git a/src/lib/scanner-strategies/v5-scanner.ts b/src/lib/scanner-strategies/v5-scanner.ts index dba917e1..d5b93c2d 100644 --- a/src/lib/scanner-strategies/v5-scanner.ts +++ b/src/lib/scanner-strategies/v5-scanner.ts @@ -7,7 +7,7 @@ import * as path from 'node:path'; import * as semver from 'semver'; import {SettingsManager} from "../settings"; import {CliCommandExecutor, CommandOutput} from "../cli-commands"; -import {VscodeWorkspace} from "../vscode-api"; +import {Workspace} from "../workspace"; type ResultsJson = { runDir: string; @@ -31,16 +31,14 @@ export class CliScannerV5Strategy implements CliScannerStrategy { private readonly version: semver.SemVer; private readonly cliCommandExecutor: CliCommandExecutor; private readonly settingsManager: SettingsManager; - private readonly vscodeWorkspace: VscodeWorkspace; private readonly fileHandler: FileHandler; private ruleDescriptionMap?: Map; - public constructor(version: semver.SemVer, cliCommandExecutor: CliCommandExecutor, settingsManager: SettingsManager, vscodeWorkspace: VscodeWorkspace, fileHandler: FileHandler) { + public constructor(version: semver.SemVer, cliCommandExecutor: CliCommandExecutor, settingsManager: SettingsManager, fileHandler: FileHandler) { this.version = version; this.cliCommandExecutor = cliCommandExecutor; this.settingsManager = settingsManager; - this.vscodeWorkspace = vscodeWorkspace; this.fileHandler = fileHandler; } @@ -63,25 +61,18 @@ export class CliScannerV5Strategy implements CliScannerStrategy { return this.ruleDescriptionMap; } - public async scan(filesToScan: string[]): Promise { + public async scan(workspace: Workspace): Promise { const ruleSelector: string = this.settingsManager.getCodeAnalyzerRuleSelectors(); const configFile: string = this.settingsManager.getCodeAnalyzerConfigFile(); const args: string[] = ['code-analyzer', 'run']; if (semver.gte(this.version, '5.0.0')) { - // Just in case a file is open in the editor that does not live in the current workspace, or if there - // is no workspace open at all, we still want to be able to run code analyzer without error, so we - // include the files to scan always along with any workspace folders. - const workspacePaths: string[] = [ - ...this.vscodeWorkspace.getWorkspaceFolders(), - ...filesToScan - ] - workspacePaths.forEach(p => args.push('-w', p)); - filesToScan.forEach(p => args.push('-t', p)); + workspace.getRawWorkspacePaths().forEach(p => args.push('-w', p)); + workspace.getRawTargetPaths().forEach(p => args.push('-t', p)); } else { - // Before 5.0.0 the --target flag did not exist, so we just make the workspace equal to the files to scan - filesToScan.forEach(p => args.push('-w', p)); + // Before 5.0.0 the --target flag did not exist, so we just make the workspace equal to the target paths + workspace.getRawTargetPaths().forEach(p => args.push('-w', p)); } if (ruleSelector) { diff --git a/src/lib/workspace.ts b/src/lib/workspace.ts new file mode 100644 index 00000000..3b1bb75b --- /dev/null +++ b/src/lib/workspace.ts @@ -0,0 +1,72 @@ +import * as vscode from "vscode"; +import {FileHandler} from "./fs-utils"; +import {messages} from "./messages"; +import {glob} from "glob"; +import {VscodeWorkspace} from "./vscode-api"; + +// Note, calling this Workspace since the future we might make this close and closer like what we have in Core and +// eventually replace it when we no longer depend on the CLI. +export class Workspace { + private readonly rawTargets: string[]; + private readonly vscodeWorkspace: VscodeWorkspace; + private readonly fileHandler: FileHandler; + + private constructor(rawTargets: string[], vscodeWorkspace: VscodeWorkspace, fileHandler: FileHandler) { + this.rawTargets = rawTargets; + this.vscodeWorkspace = vscodeWorkspace; + this.fileHandler = fileHandler; + } + + static async fromTargetPaths(targetedPaths: string[], vscodeWorkspace: VscodeWorkspace, fileHandler: FileHandler): Promise { + const uniqueTargetPaths: Set = new Set(); + for (const target of targetedPaths) { + if (!(await fileHandler.exists(target))) { + // This should never happen, but we should handle it gracefully regardless. + throw new Error(messages.targeting.error.nonexistentSelectedFileGenerator(target)); + } + uniqueTargetPaths.add(target); + } + return new Workspace([...uniqueTargetPaths], vscodeWorkspace, fileHandler); + } + + /** + * Unique string array of targeted files and folders as they were selected by the user + */ + getRawTargetPaths(): string[] { + return this.rawTargets; + } + + /** + * Unique array of files and folders that make up the workspace. + * + * Just in case a file is open in the editor that does not live in the current workspace, or if there + * is no workspace open at all, we still want to be able to run code analyzer without error, so we + * include the raw targeted files and folders always along with any vscode workspace folders. + */ + getRawWorkspacePaths(): string[] { + return [... new Set([ + ...this.vscodeWorkspace.getWorkspaceFolders(), + ...this.getRawTargetPaths() + ])]; + } + + /** + * String array of expanded files that make up the targeted files + * This array is derived by expanding the targeted folders recursively into their children files. + */ + async getTargetedFiles(): Promise { + const workspaceFiles: string[] = []; + for (const fileOrFolder of this.getRawTargetPaths()) { + if (await this.fileHandler.isDir(fileOrFolder)) { + // Globby wants forward-slashes, but Windows uses back-slashes, so always convert to forward slashes + const globbablePath: string = fileOrFolder.replace(/\\/g, '/'); + const globOut: string[] = await glob(`${globbablePath}/**/*`, {nodir: true}); + // Globby's results are Unix-formatted. Do a Uri.file round-trip to return the path to its expected form. + globOut.forEach(o => workspaceFiles.push(vscode.Uri.file(o).fsPath)); + } else { + workspaceFiles.push(fileOrFolder); + } + } + return workspaceFiles; + } +} diff --git a/src/test/legacy/extension.test.ts b/src/test/legacy/extension.test.ts index 11ed3806..1a1ce01c 100644 --- a/src/test/legacy/extension.test.ts +++ b/src/test/legacy/extension.test.ts @@ -28,7 +28,14 @@ import {TaskWithProgressRunner, TaskWithProgressRunnerImpl} from "../../lib/prog import {Display, VSCodeDisplay} from "../../lib/display"; import {CliCommandExecutorImpl} from "../../lib/cli-commands"; import {Logger} from "../../lib/logger"; -import {SpyWindowManager, StubSettingsManager, StubSpyCliCommandExecutor} from "../unit/stubs"; +import { + SpyWindowManager, + StubFileHandler, + StubSettingsManager, + StubSpyCliCommandExecutor, + StubVscodeWorkspace +} from "../unit/stubs"; +import {Workspace} from "../../lib/workspace"; suite('Extension Test Suite', () => { vscode.window.showInformationMessage('Start all tests.'); @@ -249,7 +256,8 @@ suite('Extension Test Suite', () => { // ===== TEST ===== // Attempt to run the appropriate extension command. // The arguments do not matter. - await codeAnalyzerRunAction.run(fakeTelemetryName, []); + const workspace: Workspace = await Workspace.fromTargetPaths([], new StubVscodeWorkspace(), new StubFileHandler()); + await codeAnalyzerRunAction.run(fakeTelemetryName, workspace); // ===== ASSERTIONS ===== diff --git a/src/test/unit/lib/code-analyzer-run-action.test.ts b/src/test/unit/lib/code-analyzer-run-action.test.ts index 5e2437c8..32d89b82 100644 --- a/src/test/unit/lib/code-analyzer-run-action.test.ts +++ b/src/test/unit/lib/code-analyzer-run-action.test.ts @@ -6,15 +6,17 @@ import { SpyLogger, SpyTelemetryService, SpyWindowManager, - StubCodeAnalyzer + StubCodeAnalyzer, StubFileHandler, StubVscodeWorkspace } from "../stubs"; import {CodeLocation, DiagnosticManager, DiagnosticManagerImpl, Violation} from "../../../lib/diagnostics"; import {FakeDiagnosticCollection} from "../vscode-stubs"; import {CodeAnalyzerRunAction, UNINSTANTIABLE_ENGINE_RULE} from "../../../lib/code-analyzer-run-action"; import {messages} from "../../../lib/messages"; import * as Constants from '../../../lib/constants'; +import {Workspace} from "../../../lib/workspace"; describe('Tests for CodeAnalyzerRunAction', () => { + let sampleWorkspace: Workspace; let taskWithProgressRunner: FakeTaskWithProgressRunner; let codeAnalyzer: StubCodeAnalyzer; let diagnosticCollection: vscode.DiagnosticCollection; @@ -25,7 +27,9 @@ describe('Tests for CodeAnalyzerRunAction', () => { let windowManager: SpyWindowManager; let codeAnalyzerRunAction: CodeAnalyzerRunAction; - beforeEach(() => { + beforeEach(async () => { + sampleWorkspace = await Workspace.fromTargetPaths(['someFile.flow-meta.xml'], new StubVscodeWorkspace(), new StubFileHandler()); + taskWithProgressRunner = new FakeTaskWithProgressRunner(); codeAnalyzer = new StubCodeAnalyzer(); diagnosticCollection = new FakeDiagnosticCollection(); @@ -48,7 +52,8 @@ describe('Tests for CodeAnalyzerRunAction', () => { createSampleViolation('F', 5, [{}]) ]; - await codeAnalyzerRunAction.run('dummyCommandName', ['someFile.cls']); + const workspace: Workspace = await Workspace.fromTargetPaths(['someFile.cls'], new StubVscodeWorkspace(), new StubFileHandler()); + await codeAnalyzerRunAction.run('dummyCommandName', workspace); expect(display.displayErrorCallHistory).toEqual([ {msg: '[engineA:ruleA] messageA', buttons: []}, @@ -73,7 +78,7 @@ describe('Tests for CodeAnalyzerRunAction', () => { createViolationWithoutLocation(engine, UNINSTANTIABLE_ENGINE_RULE, 'some setup message') ]; - await codeAnalyzerRunAction.run('dummyCommandName', ['someFile.flow-meta.xml']); + await codeAnalyzerRunAction.run('dummyCommandName', sampleWorkspace); expect(display.displayErrorCallHistory).toHaveLength(1); expect(display.displayErrorCallHistory[0].msg).toEqual(messages.error.engineUninstantiable(engine)); @@ -89,7 +94,7 @@ describe('Tests for CodeAnalyzerRunAction', () => { createViolationWithoutLocation(engine, UNINSTANTIABLE_ENGINE_RULE, 'some setup message') ]; - await codeAnalyzerRunAction.run('dummyCommandName', ['someFile.flow-meta.xml']); + await codeAnalyzerRunAction.run('dummyCommandName', sampleWorkspace); expect(display.displayErrorCallHistory).toHaveLength(1); expect(display.displayErrorCallHistory[0].msg).toEqual(messages.error.engineUninstantiable(engine)); expect(logger.errorCallHistory).toHaveLength(1); @@ -97,7 +102,7 @@ describe('Tests for CodeAnalyzerRunAction', () => { expect(display.displayErrorCallHistory[0].buttons).toHaveLength(3); display.displayErrorCallHistory[0].buttons[1].callback(); // Invoke the 2nd button should ignore the error - await codeAnalyzerRunAction.run('dummyCommandName', ['someFile.flow-meta.xml']); + await codeAnalyzerRunAction.run('dummyCommandName', sampleWorkspace); expect(display.displayErrorCallHistory).toHaveLength(1); // Should still be 1 because we ignored the error }); @@ -107,7 +112,7 @@ describe('Tests for CodeAnalyzerRunAction', () => { createViolationWithoutLocation(engine, UNINSTANTIABLE_ENGINE_RULE, 'some setup message1') ]; - await codeAnalyzerRunAction.run('dummyCommandName', ['someFile.flow-meta.xml']); + await codeAnalyzerRunAction.run('dummyCommandName', sampleWorkspace); expect(display.displayErrorCallHistory).toHaveLength(1); expect(display.displayErrorCallHistory[0].msg).toEqual(messages.error.engineUninstantiable(engine)); expect(logger.errorCallHistory).toHaveLength(1); @@ -120,7 +125,7 @@ describe('Tests for CodeAnalyzerRunAction', () => { createViolationWithoutLocation('pmd', UNINSTANTIABLE_ENGINE_RULE, 'some setup message2') ]; - await codeAnalyzerRunAction.run('dummyCommandName', ['someFile.flow-meta.xml']); + await codeAnalyzerRunAction.run('dummyCommandName', sampleWorkspace); expect(display.displayErrorCallHistory).toHaveLength(2); // Should still be 1 because we ignored the error expect(logger.errorCallHistory).toHaveLength(2); expect(logger.errorCallHistory[1].msg).toEqual('some setup message2\n\nLearn more: ' + Constants.DOCS_SETUP_LINK); @@ -132,7 +137,7 @@ describe('Tests for CodeAnalyzerRunAction', () => { createViolationWithoutLocation(engine, UNINSTANTIABLE_ENGINE_RULE, 'some setup message1') ]; - await codeAnalyzerRunAction.run('dummyCommandName', ['someFile.flow-meta.xml']); + await codeAnalyzerRunAction.run('dummyCommandName', sampleWorkspace); expect(display.displayErrorCallHistory).toHaveLength(1); expect(display.displayErrorCallHistory[0].msg).toEqual(messages.error.engineUninstantiable(engine)); expect(display.displayErrorCallHistory[0].buttons).toHaveLength(3); @@ -148,7 +153,7 @@ describe('Tests for CodeAnalyzerRunAction', () => { createViolationWithoutLocation(engine, UNINSTANTIABLE_ENGINE_RULE, 'some setup message1') ]; - await codeAnalyzerRunAction.run('dummyCommandName', ['someFile.flow-meta.xml']); + await codeAnalyzerRunAction.run('dummyCommandName', sampleWorkspace); expect(display.displayErrorCallHistory).toHaveLength(1); expect(display.displayErrorCallHistory[0].msg).toEqual(messages.error.engineUninstantiable(engine)); expect(display.displayErrorCallHistory[0].buttons).toHaveLength(3); diff --git a/src/test/unit/lib/code-analyzer.test.ts b/src/test/unit/lib/code-analyzer.test.ts index 6ed23d0d..6fe43ecb 100644 --- a/src/test/unit/lib/code-analyzer.test.ts +++ b/src/test/unit/lib/code-analyzer.test.ts @@ -4,6 +4,8 @@ import * as stubs from "../stubs"; import {messages} from "../../../lib/messages"; import {Violation} from "../../../lib/diagnostics"; import * as path from "path"; +import {Workspace} from "../../../lib/workspace"; +import {StubVscodeWorkspace} from "../stubs"; const TEST_DATA_DIR: string = path.resolve(__dirname, '..', 'test-data'); @@ -11,7 +13,6 @@ describe('Tests for the CodeAnalyzerImpl class', () => { let cliCommandExecutor: stubs.StubSpyCliCommandExecutor; let settingsManager: stubs.StubSettingsManager; let display: stubs.SpyDisplay; - let vscodeWorkspace: stubs.StubVscodeWorkspace; let fileHandler: stubs.StubFileHandler; let codeAnalyzer: CodeAnalyzer; @@ -19,9 +20,8 @@ describe('Tests for the CodeAnalyzerImpl class', () => { cliCommandExecutor = new stubs.StubSpyCliCommandExecutor(); settingsManager = new stubs.StubSettingsManager(); display = new stubs.SpyDisplay(); - vscodeWorkspace = new stubs.StubVscodeWorkspace(); fileHandler = new stubs.StubFileHandler(); - codeAnalyzer = new CodeAnalyzerImpl(cliCommandExecutor, settingsManager, display, vscodeWorkspace, fileHandler); + codeAnalyzer = new CodeAnalyzerImpl(cliCommandExecutor, settingsManager, display, fileHandler); }); describe('v5 tests', () => { @@ -75,6 +75,8 @@ describe('Tests for the CodeAnalyzerImpl class', () => { }); describe('v5 tests for the scan method', () => { + const vscodeWorkspace: stubs.StubVscodeWorkspace = new stubs.StubVscodeWorkspace(); + const expectedViolation1: Violation = { engine: "eslint", locations: [ @@ -119,7 +121,8 @@ describe('Tests for the CodeAnalyzerImpl class', () => { it('Sanity check that scan first calls validateEnvironment', async () => { cliCommandExecutor.isSfInstalledReturnValue = false; - await expect(codeAnalyzer.scan([])).rejects.toThrow(messages.error.sfMissing); + const workspace: Workspace = await Workspace.fromTargetPaths([], vscodeWorkspace, fileHandler); + await expect(codeAnalyzer.scan(workspace)).rejects.toThrow(messages.error.sfMissing); }); it('When running a scan with a beta version of v5, then confirm we call the cli and process the results correctly using only --workspace', async () => { @@ -129,8 +132,11 @@ describe('Tests for the CodeAnalyzerImpl class', () => { // Set up the file handler to point to a prepopulated results json file instead of actually calling the cli: fileHandler.createTempFileReturnValue = prePopulatedResultsJsonFile; + const workspace: Workspace = await Workspace.fromTargetPaths( + ['/my/project/dummyFile1.cls', '/my/project/dummyFile2.cls', '/my/project/subfolder'], vscodeWorkspace, fileHandler); + // Call scan - const violations: Violation[] = await codeAnalyzer.scan(['/my/project/dummyFile1.cls', '/my/project/dummyFile2.cls']); + const violations: Violation[] = await codeAnalyzer.scan(workspace); // First check that we are passing the correct arguments to the cli expect(cliCommandExecutor.execCallHistory).toHaveLength(1); @@ -139,6 +145,7 @@ describe('Tests for the CodeAnalyzerImpl class', () => { "code-analyzer", "run", "-w", "/my/project/dummyFile1.cls", "-w", "/my/project/dummyFile2.cls", + "-w", "/my/project/subfolder", // Should not be expanded to files - should stay as raw folder "-r", "Recommended", "-f", prePopulatedResultsJsonFile ]); @@ -154,7 +161,9 @@ describe('Tests for the CodeAnalyzerImpl class', () => { fileHandler.createTempFileReturnValue = prePopulatedResultsJsonFile; // Call scan - const violations: Violation[] = await codeAnalyzer.scan(['/my/project/dummyFile1.cls', '/my/project/dummyFile2.cls']); + const workspace: Workspace = await Workspace.fromTargetPaths( + ['/my/project/dummyFile1.cls', '/my/project/dummyFile2.cls'], vscodeWorkspace, fileHandler); + const violations: Violation[] = await codeAnalyzer.scan(workspace); // First check that we are passing the correct arguments to the cli expect(cliCommandExecutor.execCallHistory).toHaveLength(1); @@ -182,7 +191,10 @@ describe('Tests for the CodeAnalyzerImpl class', () => { fileHandler.createTempFileReturnValue = prePopulatedResultsJsonFile; // Call scan - const violations: Violation[] = await codeAnalyzer.scan(['/my/project/dummyFile1.cls', '/my/project/dummyFile2.cls', '/my/project/subfolder']); + const workspace: Workspace = await Workspace.fromTargetPaths( + ['/my/project/dummyFile1.cls', '/my/project/dummyFile2.cls', '/my/project/subfolder'], + vscodeWorkspace, fileHandler); + const violations: Violation[] = await codeAnalyzer.scan(workspace); // First check that we are passing the correct arguments to the cli expect(cliCommandExecutor.execCallHistory).toHaveLength(1); @@ -305,7 +317,8 @@ describe('Tests for the CodeAnalyzerImpl class', () => { describe('v4 tests for the scan method', () => { it('Sanity check that scan first calls validateEnvironment', async () => { cliCommandExecutor.isSfInstalledReturnValue = false; - await expect(codeAnalyzer.scan([])).rejects.toThrow(messages.error.sfMissing); + const workspace: Workspace = await Workspace.fromTargetPaths([], new StubVscodeWorkspace(), fileHandler); + await expect(codeAnalyzer.scan(workspace)).rejects.toThrow(messages.error.sfMissing); }); // TODO: More tests coming soon ... diff --git a/src/test/unit/stubs.ts b/src/test/unit/stubs.ts index 3072f43b..4d774789 100644 --- a/src/test/unit/stubs.ts +++ b/src/test/unit/stubs.ts @@ -15,6 +15,7 @@ import {CliCommandExecutor, CommandOutput, ExecOptions} from "../../lib/cli-comm import * as semver from "semver"; import {FileHandler} from "../../lib/fs-utils"; import {VscodeWorkspace, WindowManager} from "../../lib/vscode-api"; +import {Workspace} from "../../lib/workspace"; export class SpyTelemetryService implements TelemetryService { @@ -147,7 +148,7 @@ export class StubCodeAnalyzer implements CodeAnalyzer { scanReturnValue: Violation[] = []; - scan(_filesToScan: string[]): Promise { + scan(_workspace: Workspace): Promise { return Promise.resolve(this.scanReturnValue); } @@ -169,7 +170,7 @@ export class ThrowingCodeAnalyzer implements CodeAnalyzer { throw new Error("Error from validateEnvironment"); } - scan(_filesToScan: string[]): Promise { + scan(_workspace: Workspace): Promise { throw new Error("Error from scan"); } From e741d87f0ecf0b5fb80fd3c2314ec41b97330bd0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 30 Apr 2025 15:33:17 +0000 Subject: [PATCH 3/3] Preparing for v1.6.1 release. --- package-lock.json | 332 +++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 167 insertions(+), 167 deletions(-) diff --git a/package-lock.json b/package-lock.json index f73c3113..68d6f58a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "sfdx-code-analyzer-vscode", - "version": "1.6.0", + "version": "1.6.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "sfdx-code-analyzer-vscode", - "version": "1.6.0", + "version": "1.6.1", "license": "BSD-3-Clause", "dependencies": { "@salesforce/vscode-service-provider": "^1.4.0", @@ -194,22 +194,22 @@ } }, "node_modules/@azure/msal-browser": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.11.0.tgz", - "integrity": "sha512-0p5Ut3wORMP+975AKvaSPIO4UytgsfAvJ7RxaTx+nkP+Hpkmm93AuiMkBWKI2x9tApU/SLgIyPz/ZwLYUIWb5Q==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.11.1.tgz", + "integrity": "sha512-jPxASelqmP/0R1jZuYW8cboba95M9jpUi2ZqzgftddlAIRZA9KL/YaESuT55zu9+BIPS5Eo2kuhy3q2jjU3whg==", "dev": true, "license": "MIT", "dependencies": { - "@azure/msal-common": "15.5.1" + "@azure/msal-common": "15.5.2" }, "engines": { "node": ">=0.8.0" } }, "node_modules/@azure/msal-common": { - "version": "15.5.1", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.5.1.tgz", - "integrity": "sha512-oxK0khbc4Bg1bKQnqDr7ikULhVL2OHgSrIq0Vlh4b6+hm4r0lr6zPMQE8ZvmacJuh+ZZGKBM5iIObhF1q1QimQ==", + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.5.2.tgz", + "integrity": "sha512-+G85T6oA6i4ubzjOw4BpWd8QCG2FunYN4jaz96gw3SUd8+89vwuiqLg6mtnm/lkPC95bayD+CwuwFn9wvhQGow==", "dev": true, "license": "MIT", "engines": { @@ -217,13 +217,13 @@ } }, "node_modules/@azure/msal-node": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.5.1.tgz", - "integrity": "sha512-dkgMYM5B6tI88r/oqf5bYd93WkenQpaWwiszJDk7avVjso8cmuKRTW97dA1RMi6RhihZFLtY1VtWxU9+sW2T5g==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.5.2.tgz", + "integrity": "sha512-mt97ieL+IpD/7Hj7Q6pGTPk3dBgvhkOV1HYyH+PkOakhbOOCEb9flAteDgBfADRXBsYJZT+ZlEbPJa4IDn9HZw==", "dev": true, "license": "MIT", "dependencies": { - "@azure/msal-common": "15.5.1", + "@azure/msal-common": "15.5.2", "jsonwebtoken": "^9.0.0", "uuid": "^8.3.0" }, @@ -232,23 +232,23 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", + "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", - "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.1.tgz", + "integrity": "sha512-Q+E+rd/yBzNQhXkG+zQnF58e4zoZfBedaxwzPmicKsiK3nt8iJYrSrDbjwFFDGC4f+rPafqRaPH6TsDoSvMf7A==", "dev": true, "license": "MIT", "engines": { @@ -256,22 +256,22 @@ } }, "node_modules/@babel/core": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz", - "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.1.tgz", + "integrity": "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.10", - "@babel/helper-compilation-targets": "^7.26.5", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.10", - "@babel/parser": "^7.26.10", - "@babel/template": "^7.26.9", - "@babel/traverse": "^7.26.10", - "@babel/types": "^7.26.10", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.1", + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helpers": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/template": "^7.27.1", + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -297,14 +297,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz", - "integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.1.tgz", + "integrity": "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0", + "@babel/parser": "^7.27.1", + "@babel/types": "^7.27.1", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -314,14 +314,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.0.tgz", - "integrity": "sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.1.tgz", + "integrity": "sha512-2YaDd/Rd9E598B5+WIc8wJPmWETiiJXFYVE60oX8FDohv7rAUU3CQj+A1MgeEmcsk2+dQuEjIe/GDvig0SqL4g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.26.8", - "@babel/helper-validator-option": "^7.25.9", + "@babel/compat-data": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -358,29 +358,29 @@ "license": "ISC" }, "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.1.tgz", + "integrity": "sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -390,9 +390,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", - "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", "dev": true, "license": "MIT", "engines": { @@ -400,9 +400,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, "license": "MIT", "engines": { @@ -410,18 +410,18 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, "license": "MIT", "engines": { @@ -429,27 +429,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz", - "integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.1.tgz", + "integrity": "sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.27.0", - "@babel/types": "^7.27.0" + "@babel/template": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", - "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.1.tgz", + "integrity": "sha512-I0dZ3ZpCrJ1c04OqlNsQcKiZlsrXf/kkE4FXzID9rIOYICsAbA8mMDzhW/luRNAHdCNt7os/u8wenklZDlUVUQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.27.0" + "@babel/types": "^7.27.1" }, "bin": { "parser": "bin/babel-parser.js" @@ -514,13 +514,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", - "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -556,13 +556,13 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", - "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -682,13 +682,13 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", - "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -698,32 +698,32 @@ } }, "node_modules/@babel/template": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", - "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.1.tgz", + "integrity": "sha512-Fyo3ghWMqkHHpHQCoBs2VnYjR4iWFFjguTDEqA5WgZDOrFesVjMhMM2FSqTKSoUSDO1VQtavj8NFpdRBEvJTtg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0" + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", - "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.1.tgz", + "integrity": "sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.27.0", - "@babel/parser": "^7.27.0", - "@babel/template": "^7.27.0", - "@babel/types": "^7.27.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/template": "^7.27.1", + "@babel/types": "^7.27.1", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -742,14 +742,14 @@ } }, "node_modules/@babel/types": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", - "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", + "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -2622,9 +2622,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.15.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.2.tgz", - "integrity": "sha512-uKXqKN9beGoMdBfcaTY1ecwz6ctxuJAcUlwE55938g0ZJ8lRxwAZqRz2AJ4pzpt5dHdTPMB863UZ0ESiFUcP7A==", + "version": "22.15.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.3.tgz", + "integrity": "sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -2688,17 +2688,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.0.tgz", - "integrity": "sha512-evaQJZ/J/S4wisevDvC1KFZkPzRetH8kYZbkgcTRyql3mcKsf+ZFDV1BVWUGTCAW5pQHoqn5gK5b8kn7ou9aFQ==", + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.1.tgz", + "integrity": "sha512-oUlH4h1ABavI4F0Xnl8/fOtML/eu8nI2A1nYd+f+55XI0BLu+RIqKoCiZKNo6DtqZBEQm5aNKA20G3Z5w3R6GQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.31.0", - "@typescript-eslint/type-utils": "8.31.0", - "@typescript-eslint/utils": "8.31.0", - "@typescript-eslint/visitor-keys": "8.31.0", + "@typescript-eslint/scope-manager": "8.31.1", + "@typescript-eslint/type-utils": "8.31.1", + "@typescript-eslint/utils": "8.31.1", + "@typescript-eslint/visitor-keys": "8.31.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -2718,16 +2718,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.31.0.tgz", - "integrity": "sha512-67kYYShjBR0jNI5vsf/c3WG4u+zDnCTHTPqVMQguffaWWFs7artgwKmfwdifl+r6XyM5LYLas/dInj2T0SgJyw==", + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.31.1.tgz", + "integrity": "sha512-oU/OtYVydhXnumd0BobL9rkJg7wFJ9bFFPmSmB/bf/XWN85hlViji59ko6bSKBXyseT9V8l+CN1nwmlbiN0G7Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.31.0", - "@typescript-eslint/types": "8.31.0", - "@typescript-eslint/typescript-estree": "8.31.0", - "@typescript-eslint/visitor-keys": "8.31.0", + "@typescript-eslint/scope-manager": "8.31.1", + "@typescript-eslint/types": "8.31.1", + "@typescript-eslint/typescript-estree": "8.31.1", + "@typescript-eslint/visitor-keys": "8.31.1", "debug": "^4.3.4" }, "engines": { @@ -2743,14 +2743,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.31.0.tgz", - "integrity": "sha512-knO8UyF78Nt8O/B64i7TlGXod69ko7z6vJD9uhSlm0qkAbGeRUSudcm0+K/4CrRjrpiHfBCjMWlc08Vav1xwcw==", + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.31.1.tgz", + "integrity": "sha512-BMNLOElPxrtNQMIsFHE+3P0Yf1z0dJqV9zLdDxN/xLlWMlXK/ApEsVEKzpizg9oal8bAT5Sc7+ocal7AC1HCVw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.31.0", - "@typescript-eslint/visitor-keys": "8.31.0" + "@typescript-eslint/types": "8.31.1", + "@typescript-eslint/visitor-keys": "8.31.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2761,14 +2761,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.31.0.tgz", - "integrity": "sha512-DJ1N1GdjI7IS7uRlzJuEDCgDQix3ZVYVtgeWEyhyn4iaoitpMBX6Ndd488mXSx0xah/cONAkEaYyylDyAeHMHg==", + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.31.1.tgz", + "integrity": "sha512-fNaT/m9n0+dpSp8G/iOQ05GoHYXbxw81x+yvr7TArTuZuCA6VVKbqWYVZrV5dVagpDTtj/O8k5HBEE/p/HM5LA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.31.0", - "@typescript-eslint/utils": "8.31.0", + "@typescript-eslint/typescript-estree": "8.31.1", + "@typescript-eslint/utils": "8.31.1", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, @@ -2785,9 +2785,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.31.0.tgz", - "integrity": "sha512-Ch8oSjVyYyJxPQk8pMiP2FFGYatqXQfQIaMp+TpuuLlDachRWpUAeEu1u9B/v/8LToehUIWyiKcA/w5hUFRKuQ==", + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.31.1.tgz", + "integrity": "sha512-SfepaEFUDQYRoA70DD9GtytljBePSj17qPxFHA/h3eg6lPTqGJ5mWOtbXCk1YrVU1cTJRd14nhaXWFu0l2troQ==", "dev": true, "license": "MIT", "engines": { @@ -2799,14 +2799,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.0.tgz", - "integrity": "sha512-xLmgn4Yl46xi6aDSZ9KkyfhhtnYI15/CvHbpOy/eR5NWhK/BK8wc709KKwhAR0m4ZKRP7h07bm4BWUYOCuRpQQ==", + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.1.tgz", + "integrity": "sha512-kaA0ueLe2v7KunYOyWYtlf/QhhZb7+qh4Yw6Ni5kgukMIG+iP773tjgBiLWIXYumWCwEq3nLW+TUywEp8uEeag==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.31.0", - "@typescript-eslint/visitor-keys": "8.31.0", + "@typescript-eslint/types": "8.31.1", + "@typescript-eslint/visitor-keys": "8.31.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -2826,16 +2826,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.31.0.tgz", - "integrity": "sha512-qi6uPLt9cjTFxAb1zGNgTob4x9ur7xC6mHQJ8GwEzGMGE9tYniublmJaowOJ9V2jUzxrltTPfdG2nKlWsq0+Ww==", + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.31.1.tgz", + "integrity": "sha512-2DSI4SNfF5T4oRveQ4nUrSjUqjMND0nLq9rEkz0gfGr3tg0S5KB6DhwR+WZPCjzkZl3cH+4x2ce3EsL50FubjQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.31.0", - "@typescript-eslint/types": "8.31.0", - "@typescript-eslint/typescript-estree": "8.31.0" + "@typescript-eslint/scope-manager": "8.31.1", + "@typescript-eslint/types": "8.31.1", + "@typescript-eslint/typescript-estree": "8.31.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2850,13 +2850,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.0.tgz", - "integrity": "sha512-QcGHmlRHWOl93o64ZUMNewCdwKGU6WItOU52H0djgNmn1EOrhVudrDzXz4OycCRSCPwFCDrE2iIt5vmuUdHxuQ==", + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.1.tgz", + "integrity": "sha512-I+/rgqOVBn6f0o7NDTmAPWWC6NuqhV174lfYvAm9fUaWeiefLdux9/YI3/nLugEn9L8fcSi0XmpKi/r5u0nmpw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.31.0", + "@typescript-eslint/types": "8.31.1", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -3854,9 +3854,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001715", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001715.tgz", - "integrity": "sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw==", + "version": "1.0.30001716", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001716.tgz", + "integrity": "sha512-49/c1+x3Kwz7ZIWt+4DvK3aMJy9oYXXG6/97JKsnjdCk/6n9vVyWL8NAwVt95Lwt9eigI10Hl782kDfZUUlRXw==", "dev": true, "funding": [ { @@ -4727,9 +4727,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.142", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.142.tgz", - "integrity": "sha512-Ah2HgkTu/9RhTDNThBtzu2Wirdy4DC9b0sMT1pUhbkZQ5U/iwmE+PHZX1MpjD5IkJCc2wSghgGG/B04szAx07w==", + "version": "1.5.145", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.145.tgz", + "integrity": "sha512-pZ5EcTWRq/055MvSBgoFEyKf2i4apwfoqJbK/ak2jnFq8oHjZ+vzc3AhRcz37Xn+ZJfL58R666FLJx0YOK9yTw==", "dev": true, "license": "ISC" }, @@ -10836,9 +10836,9 @@ } }, "node_modules/ts-jest/node_modules/type-fest": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.0.tgz", - "integrity": "sha512-ABHZ2/tS2JkvH1PEjxFDTUWC8dB5OsIGZP4IFLhR293GqT5Y5qB1WwL2kMPYhQW9DVgVD8Hd7I8gjwPIf5GFkw==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.1.tgz", + "integrity": "sha512-9YvLNnORDpI+vghLU/Nf+zSv0kL47KbVJ1o3sKgoTefl6i+zebxbiDQWoe/oWWqPhIgQdRZRT1KA9sCPL810SA==", "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { @@ -10996,15 +10996,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.31.0.tgz", - "integrity": "sha512-u+93F0sB0An8WEAPtwxVhFby573E8ckdjwUUQUj9QA4v8JAvgtoDdIyYR3XFwFHq2W1KJ1AurwJCO+w+Y1ixyQ==", + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.31.1.tgz", + "integrity": "sha512-j6DsEotD/fH39qKzXTQRwYYWlt7D+0HmfpOK+DVhwJOFLcdmn92hq3mBb7HlKJHbjjI/gTOqEcc9d6JfpFf/VA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.31.0", - "@typescript-eslint/parser": "8.31.0", - "@typescript-eslint/utils": "8.31.0" + "@typescript-eslint/eslint-plugin": "8.31.1", + "@typescript-eslint/parser": "8.31.1", + "@typescript-eslint/utils": "8.31.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" diff --git a/package.json b/package.json index dd1d0618..23e857c4 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "color": "#ECECEC", "theme": "light" }, - "version": "1.6.0", + "version": "1.6.1", "publisher": "salesforce", "license": "BSD-3-Clause", "engines": {