From df8b106642a2c5b8ee6160d3b0ade2dcd785127d Mon Sep 17 00:00:00 2001 From: Jag Jayaprakash Date: Mon, 16 Sep 2024 10:32:07 -0700 Subject: [PATCH 01/16] NEW (Extension) @W-15640497@ Delta runs on SFGE - Phase 1 --- package.json | 3 +- src/deltarun/delta-run-service.ts | 35 ++++++ src/extension.ts | 110 +++++++++++++----- .../suite/deltarun/delta-run-service.test.ts | 98 ++++++++++++++++ src/test/suite/extension.test.ts | 6 +- yarn.lock | 60 +++++++++- 6 files changed, 276 insertions(+), 36 deletions(-) create mode 100644 src/deltarun/delta-run-service.ts create mode 100644 src/test/suite/deltarun/delta-run-service.test.ts diff --git a/package.json b/package.json index 66563d7..9664146 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "cross-spawn": "^7.0.3", "glob": "^8.0.3", "globby": "^11.0.0", + "proxyquire": "^2.1.3", "semver": "^7.5.4" }, "devDependencies": { @@ -186,7 +187,7 @@ }, { "command": "sfca.runDfa", - "when": "false" + "when": "true" }, { "command": "sfca.removeDiagnosticsOnActiveFile", diff --git a/src/deltarun/delta-run-service.ts b/src/deltarun/delta-run-service.ts new file mode 100644 index 0000000..719934e --- /dev/null +++ b/src/deltarun/delta-run-service.ts @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024, Salesforce, Inc. + * All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ +import * as fs from 'fs'; + +export function getDeltaRunTarget(sfgecachepath:string, savedFilesCache:Set): string[] { + // Read and parse the JSON file at sfgecachepath + const fileContent = fs.readFileSync(sfgecachepath, 'utf-8'); + const parsedData = JSON.parse(fileContent) as CacheData; + + const matchingEntries: string[] = []; + + // Iterate over each file entry in the data + parsedData.data.forEach((entry: { filename: string, entries: string[] }) => { + // Check if the filename is in the savedFilesCache + if (savedFilesCache.has(entry.filename)) { + // If it matches, add the individual entries to the result array + matchingEntries.push(...entry.entries); + } + }); + + return matchingEntries; +} + +interface CacheEntry { + filename: string; + entries: string[]; +} + +interface CacheData { + data: CacheEntry[]; +} \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index 08559a5..2e6ad77 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -20,7 +20,8 @@ import { CoreExtensionService, TelemetryService } from './lib/core-extension-ser import * as Constants from './lib/constants'; import * as path from 'path'; import { SIGKILL } from 'constants'; -import * as ApexGuruFunctions from './apexguru/apex-guru-service' +import * as ApexGuruFunctions from './apexguru/apex-guru-service'; +import * as DeltaRunFunctions from './deltarun/delta-run-service'; import * as os from 'os'; import * as fs from 'fs'; @@ -42,6 +43,9 @@ let outputChannel: vscode.LogOutputChannel; let sfgeCachePath: string = null; +// Create a Set to store saved file paths +const savedFilesCache: Set = new Set(); + /** * This method is invoked when the extension is first activated (this is currently configured to be when a sfdx project is loaded). * The activation trigger can be changed by changing activationEvents in package.json @@ -113,36 +117,15 @@ export async function activate(context: vscode.ExtensionContext): Promise { if (await _shouldProceedWithDfaRun(context)) { - await vscode.window.withProgress({ - location: vscode.ProgressLocation.Window, - title: messages.graphEngine.spinnerText, - cancellable: true - }, async (progress, token) => { - token.onCancellationRequested(async () => { - await _stopExistingDfaRun(context); - }); - customCancellationToken = new vscode.CancellationTokenSource(); - customCancellationToken.token.onCancellationRequested(async () => { - customCancellationToken?.dispose(); - customCancellationToken = null; - await vscode.window.showInformationMessage(messages.graphEngine.noViolationsFound); - return; - }); - const methodLevelTarget: string = await targeting.getSelectedMethod(); - // Pull out the file from the target and use it to identify the project directory. - const currentFile: string = methodLevelTarget.substring(0, methodLevelTarget.lastIndexOf('#')); - const projectDir: string = targeting.getProjectDir(currentFile); - - return _runAndDisplayDfa(context, { - commandName: Constants.COMMAND_RUN_DFA_ON_SELECTED_METHOD - }, customCancellationToken, methodLevelTarget, projectDir); - }); + const methodLevelTarget: string[] = [await targeting.getSelectedMethod()]; + await runMethodLevelDfa(context, methodLevelTarget); } }); sfgeCachePath = path.join(createTempDirectory(), 'sfca-graph-engine-cache.json'); const runDfaOnWorkspaceCmd = vscode.commands.registerCommand(Constants.COMMAND_RUN_DFA, async () => { await _runDfa(context); + savedFilesCache.clear(); }); context.subscriptions.push(runOnActiveFile, runOnSelected, runDfaOnSelectedMethodCmd, runDfaOnWorkspaceCmd, removeDiagnosticsOnActiveFile, removeDiagnosticsOnSelectedFile, removeDiagnosticsInRange); @@ -166,12 +149,44 @@ export async function activate(context: vscode.ExtensionContext): Promise { + const filePath = document.uri.fsPath; + savedFilesCache.add(filePath); + }); + context.subscriptions.push(documentSaveListener); TelemetryService.sendExtensionActivationEvent(extensionHrStart); outputChannel.appendLine(`Extension sfdx-code-analyzer-vscode activated.`); return Promise.resolve(context); } +async function runMethodLevelDfa(context: vscode.ExtensionContext, methodLevelTarget: string[]) { + await vscode.window.withProgress({ + location: vscode.ProgressLocation.Window, + title: messages.graphEngine.spinnerText, + cancellable: true + }, async (progress, token) => { + token.onCancellationRequested(async () => { + await _stopExistingDfaRun(context); + }); + customCancellationToken = new vscode.CancellationTokenSource(); + customCancellationToken.token.onCancellationRequested(async () => { + customCancellationToken?.dispose(); + customCancellationToken = null; + await vscode.window.showInformationMessage(messages.graphEngine.noViolationsFound); + return; + }); + // Pull out the file from the target and use it to identify the project directory. + const currentFile: string = methodLevelTarget[0].substring(0, methodLevelTarget.lastIndexOf('#')); + const projectDir: string = targeting.getProjectDir(currentFile); + + return _runAndDisplayDfa(context, { + commandName: Constants.COMMAND_RUN_DFA_ON_SELECTED_METHOD + }, customCancellationToken, methodLevelTarget, projectDir); + }); +} + export function createTempDirectory(): string { const tempFolderPrefix = path.join(os.tmpdir(), Constants.EXTENSION_PACK_ID); try { @@ -194,10 +209,15 @@ async function _runDfa(context: vscode.ExtensionContext) { ); // Default to "Yes" if no choice is made - const rerunFailedOnly = choice == '***Yes***'; - if (rerunFailedOnly) { + const rerunChangedOnly = choice == '***Yes***'; + if (rerunChangedOnly) { // Do nothing for now. This will be implemented as part of W-15639759 - return; + const deltaRunTargets = DeltaRunFunctions.getDeltaRunTarget(sfgeCachePath, savedFilesCache); + if (deltaRunTargets.length == 0) { + void vscode.window.showInformationMessage('***No local changes found that would change the outcome of previous SFGE full run.***'); + return + } + await runDfaOnSelectMethods(context, deltaRunTargets); } else { void vscode.window.showWarningMessage('***A full run of the graph engine will happen in the background. You can cancel this by clicking on the status progress.***'); await runDfaOnWorkspace(context); @@ -207,6 +227,31 @@ async function _runDfa(context: vscode.ExtensionContext) { } } +async function runDfaOnSelectMethods(context: vscode.ExtensionContext, selectedMethods: string[]) { + await vscode.window.withProgress({ + location: vscode.ProgressLocation.Window, + title: messages.graphEngine.spinnerText, + cancellable: true + }, async (progress, token) => { + token.onCancellationRequested(async () => { + await _stopExistingDfaRun(context); + }); + customCancellationToken = new vscode.CancellationTokenSource(); + customCancellationToken.token.onCancellationRequested(async () => { + customCancellationToken?.dispose(); + customCancellationToken = null; + await vscode.window.showInformationMessage(messages.graphEngine.noViolationsFound); + return; + }); + + // We only have one project loaded on VSCode at once. So, projectDir should have only one entry and we use + // the root directory of that project as the projectDir argument to run DFA. + return _runAndDisplayDfa(context, { + commandName: Constants.COMMAND_RUN_DFA + }, customCancellationToken, selectedMethods, targeting.getProjectDir(), sfgeCachePath); + }); +} + async function runDfaOnWorkspace(context: vscode.ExtensionContext) { await vscode.window.withProgress({ location: vscode.ProgressLocation.Window, @@ -228,7 +273,7 @@ async function runDfaOnWorkspace(context: vscode.ExtensionContext) { // the root directory of that project as the projectDir argument to run DFA. return _runAndDisplayDfa(context, { commandName: Constants.COMMAND_RUN_DFA - }, customCancellationToken, null, targeting.getProjectDir()); + }, customCancellationToken, null, targeting.getProjectDir(), sfgeCachePath); }); } @@ -371,14 +416,16 @@ export async function _runAndDisplayPathless(selections: vscode.Uri[], runInfo: * @param runInfo A collection of services and information used to properly run the command * @param runInfo.commandName The specific command being run */ -export async function _runAndDisplayDfa(context:vscode.ExtensionContext ,runInfo: RunInfo, cancelToken: vscode.CancellationTokenSource, methodLevelTarget: string, projectDir: string): Promise { +export async function _runAndDisplayDfa(context:vscode.ExtensionContext ,runInfo: RunInfo, + cancelToken: vscode.CancellationTokenSource, methodLevelTarget: string[], projectDir: string, + cacheFilePath?: string): Promise { const { commandName } = runInfo; const startTime = Date.now(); try { await verifyPluginInstallation(); - const results = await new ScanRunner().runDfa([methodLevelTarget], projectDir, context, sfgeCachePath); + const results = await new ScanRunner().runDfa(methodLevelTarget, projectDir, context, cacheFilePath); if (results.length > 0) { const panel = vscode.window.createWebviewPanel( 'dfaResults', @@ -479,6 +526,7 @@ async function summarizeResultsAsToast(targets: string[], results: RuleResult[]) // This method is called when your extension is deactivated export function deactivate() { TelemetryService.dispose(); + savedFilesCache.clear(); } export function _isValidFileForAnalysis(documentUri: vscode.Uri) { diff --git a/src/test/suite/deltarun/delta-run-service.test.ts b/src/test/suite/deltarun/delta-run-service.test.ts new file mode 100644 index 0000000..c897ac0 --- /dev/null +++ b/src/test/suite/deltarun/delta-run-service.test.ts @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2024, Salesforce, Inc. + * All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ + +import {expect} from 'chai'; +import Sinon = require('sinon'); +import proxyquire from 'proxyquire'; + +// You can import and use all API from the 'vscode' module +// as well as import your extension to test it +import * as vscode from 'vscode'; + +suite('Delta Run Test Suite', () => { + suite('#getDeltaRunTarget', () => { + let readFileSyncStub: Sinon.SinonStub; + let getDeltaRunTarget: Function; + + // Set up stubs and mock the fs module + setup(() => { + readFileSyncStub = Sinon.stub(); + + // Load the module with the mocked fs dependency + const mockedModule = proxyquire('../../../deltarun/delta-run-service', { + fs: { + readFileSync: readFileSyncStub + } + }); + + // Get the function from the module + getDeltaRunTarget = mockedModule.getDeltaRunTarget; + }); + + teardown(() => { + Sinon.restore(); + }); + + test('Returns matching entries when files in cache match JSON data', () => { + // Setup the mock return value for readFileSync + const sfgecachepath = '/path/to/sfgecache.json'; + const savedFilesCache = new Set([ + '/some/user/path/HelloWorld.cls' + ]); + + const jsonData = `{ + "data": [ + { + "entries": ["/some/user/path/HelloWorld.cls#getProducts", "/some/user/path/HelloWorld.cls#getSimilarProducts"], + "filename": "/some/user/path/HelloWorld.cls" + } + ] + }`; + + readFileSyncStub.withArgs(sfgecachepath, 'utf-8').returns(jsonData); + + // Test + const result = getDeltaRunTarget(sfgecachepath, savedFilesCache); + + // Assertions + expect(result).to.deep.equal([ + '/some/user/path/HelloWorld.cls#getProducts', + '/some/user/path/HelloWorld.cls#getSimilarProducts' + ]); + + Sinon.assert.calledOnce(readFileSyncStub); + }); + + test('Returns an empty array when no matching files are found in cache', () => { + // ===== SETUP ===== + const sfgecachepath = '/path/to/sfgecache.json'; + const savedFilesCache = new Set([ + '/some/user/path/HelloWorld.cls' + ]); + + const jsonData = `{ + "data": [ + { + "filename": "/some/user/path/NotHelloWorld.cls", + "entries": ["/some/user/path/NotHelloWorld.cls#getProducts"] + } + ] + }`; + + // Stub the file read to return the JSON data + readFileSyncStub.withArgs(sfgecachepath, 'utf-8').returns(jsonData); + + // ===== TEST ===== + const result = getDeltaRunTarget(sfgecachepath, savedFilesCache); + + // ===== ASSERTIONS ===== + expect(result).to.deep.equal([]); + + Sinon.assert.calledOnce(readFileSyncStub); + }); + }); +}); diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts index 752bf26..9f7ee9f 100644 --- a/src/test/suite/extension.test.ts +++ b/src/test/suite/extension.test.ts @@ -11,7 +11,7 @@ import {SfCli} from '../../lib/sf-cli'; import Sinon = require('sinon'); import { _runAndDisplayPathless, _runAndDisplayDfa, _clearDiagnostics, _shouldProceedWithDfaRun, _stopExistingDfaRun, _isValidFileForAnalysis, verifyPluginInstallation, _clearDiagnosticsForSelectedFiles, _removeDiagnosticsInRange, RunInfo } from '../../extension'; import {messages} from '../../lib/messages'; -import {CoreExtensionService, TelemetryService} from '../../lib/core-extension-service'; +import {TelemetryService} from '../../lib/core-extension-service'; import * as Constants from '../../lib/constants'; import * as targeting from '../../lib/targeting'; @@ -238,7 +238,7 @@ suite('Extension Test Suite', () => { // Attempt to run the appropriate extension command. await _runAndDisplayDfa(null, { commandName: fakeTelemetryName - }, null, 'someMethod', 'some/project/dir'); + }, null, ['someMethod'], 'some/project/dir'); // ===== ASSERTIONS ===== Sinon.assert.callCount(errorSpy, 1); @@ -263,7 +263,7 @@ suite('Extension Test Suite', () => { try { await _runAndDisplayDfa(null, { commandName: fakeTelemetryName - }, null, 'someMethod', 'some/project/dir'); + }, null, ['someMethod'], 'some/project/dir'); } catch (e) { err = e; } diff --git a/yarn.lock b/yarn.lock index 0c38833..3affff1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1765,6 +1765,14 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" +fill-keys@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/fill-keys/-/fill-keys-1.0.2.tgz#9a8fa36f4e8ad634e3bf6b4f3c8882551452eb20" + integrity sha512-tcgI872xXjwFF4xgQmLxi76GnwJG3g/3isB1l4/G5Z4zrbddGpBjqZCO9oEAcB5wX0Hj/5iQB3toxfO7in1hHA== + dependencies: + is-object "~1.0.1" + merge-descriptors "~1.0.0" + fill-range@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" @@ -2012,7 +2020,7 @@ hasha@^5.0.0: is-stream "^2.0.0" type-fest "^0.8.0" -hasown@^2.0.0: +hasown@^2.0.0, hasown@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== @@ -2134,6 +2142,13 @@ is-ci@^2.0.0: dependencies: ci-info "^2.0.0" +is-core-module@^2.13.0: + version "2.15.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" + integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== + dependencies: + hasown "^2.0.2" + is-docker@^2.0.0, is-docker@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" @@ -2166,6 +2181,11 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-object@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" + integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA== + is-path-inside@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" @@ -2571,6 +2591,11 @@ mdurl@^1.0.1: resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g== +merge-descriptors@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== + merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" @@ -2661,6 +2686,11 @@ mocha@^10.1.0: yargs-parser "^20.2.9" yargs-unparser "^2.0.0" +module-not-found-error@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/module-not-found-error/-/module-not-found-error-1.0.1.tgz#cf8b4ff4f29640674d6cdd02b0e3bc523c2bbdc0" + integrity sha512-pEk4ECWQXV6z2zjhRZUongnLJNUeGQJ3w6OQ5ctGwD+i5o93qjRQUk2Rt6VdNeu3sEP0AB4LcfvdebpxBRVr4g== + ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -2945,6 +2975,11 @@ path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + path-to-regexp@^6.2.1: version "6.2.2" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.2.tgz#324377a83e5049cbecadc5554d6a63a9a4866b36" @@ -3017,6 +3052,15 @@ process-on-spawn@^1.0.0: dependencies: fromentries "^1.2.0" +proxyquire@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/proxyquire/-/proxyquire-2.1.3.tgz#2049a7eefa10a9a953346a18e54aab2b4268df39" + integrity sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg== + dependencies: + fill-keys "^1.0.2" + module-not-found-error "^1.0.1" + resolve "^1.11.1" + pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -3122,6 +3166,15 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== +resolve@^1.11.1: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + restore-cursor@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-4.0.0.tgz#519560a4318975096def6e609d44100edaa4ccb9" @@ -3387,6 +3440,11 @@ supports-color@^8.1.1: dependencies: has-flag "^4.0.0" +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + tar-fs@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" From e3119aea972fb3bb6ae708d0a98c281a20968cfc Mon Sep 17 00:00:00 2001 From: Jag Jayaprakash Date: Mon, 16 Sep 2024 11:22:55 -0700 Subject: [PATCH 02/16] NEW (Extension) @W-15640497@ By default the command doesn't appear --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9664146..48f2157 100644 --- a/package.json +++ b/package.json @@ -187,7 +187,7 @@ }, { "command": "sfca.runDfa", - "when": "true" + "when": "false" }, { "command": "sfca.removeDiagnosticsOnActiveFile", From e8de54baf8621692c6d8cc53856fb2e04546391d Mon Sep 17 00:00:00 2001 From: Jag Jayaprakash Date: Mon, 16 Sep 2024 13:32:07 -0700 Subject: [PATCH 03/16] NEW (Extension) @W-15640497@ Increase test timeouts --- src/test/suite/extension.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts index 9f7ee9f..e146bb4 100644 --- a/src/test/suite/extension.test.ts +++ b/src/test/suite/extension.test.ts @@ -58,7 +58,7 @@ suite('Extension Test Suite', () => { // ===== SETUP ===== // Set the timeout to a frankly absurd value, just to make sure Github Actions // can finish it in time. - this.timeout(90000); + this.timeout(180000); // Open a file in the editor. const fileUri: vscode.Uri = vscode.Uri.file(path.join(codeFixturesPath, 'folder-a', 'MyClassA1.cls')); const doc = await vscode.workspace.openTextDocument(fileUri); @@ -89,7 +89,7 @@ suite('Extension Test Suite', () => { // ===== SETUP ===== // Set the timeout to a frankly absurd value, just to make sure Github Actions // can finish it in time. - this.timeout(60000); + this.timeout(180000); // Get the URI for a single file. const targetUri: vscode.Uri = vscode.Uri.file(path.join(codeFixturesPath, 'folder-a', 'MyClassA1.cls')); @@ -119,7 +119,7 @@ suite('Extension Test Suite', () => { // ===== SETUP ===== // Set the timeout to a frankly absurd value, just to make sure Github Actions // can finish it in time. - this.timeout(60000); + this.timeout(180000); // Get the URIs for two separate files. const targetUri1: vscode.Uri = vscode.Uri.file(path.join(codeFixturesPath, 'folder-a', 'MyClassA1.cls')); const targetUri2: vscode.Uri = vscode.Uri.file(path.join(codeFixturesPath, 'folder-a', 'MyClassA2.cls')); From ee3c7824d24e684b145ad91055f6e71afc5b0726 Mon Sep 17 00:00:00 2001 From: Jag Jayaprakash Date: Mon, 16 Sep 2024 14:02:02 -0700 Subject: [PATCH 04/16] NEW (Extension) @W-15640497@ Increase test timeouts - 2 --- src/test/suite/scanner.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/suite/scanner.test.ts b/src/test/suite/scanner.test.ts index 2ccee4e..9327e17 100644 --- a/src/test/suite/scanner.test.ts +++ b/src/test/suite/scanner.test.ts @@ -612,7 +612,7 @@ suite('ScanRunner', () => { let context: vscode.ExtensionContext; suiteSetup(async function () { - this.timeout(10000); + this.timeout(60000); // Activate the extension. context = await ext.activate(); }); From ee4ecb2bb79eb2399c0d52e35973140c571b1e80 Mon Sep 17 00:00:00 2001 From: Jag Jayaprakash Date: Wed, 18 Sep 2024 08:32:07 -0700 Subject: [PATCH 05/16] fix review comments --- package.json | 2 +- src/extension.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 48f2157..cc8e001 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,6 @@ "cross-spawn": "^7.0.3", "glob": "^8.0.3", "globby": "^11.0.0", - "proxyquire": "^2.1.3", "semver": "^7.5.4" }, "devDependencies": { @@ -58,6 +57,7 @@ "mocha": "^10.1.0", "nyc": "^15.1.0", "ovsx": "^0.8.3", + "proxyquire": "^2.1.3", "sinon": "^15.1.0", "ts-node": "^10.9.1", "typescript": "^4.9.3" diff --git a/src/extension.ts b/src/extension.ts index 2e6ad77..4d17ff7 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -211,7 +211,6 @@ async function _runDfa(context: vscode.ExtensionContext) { // Default to "Yes" if no choice is made const rerunChangedOnly = choice == '***Yes***'; if (rerunChangedOnly) { - // Do nothing for now. This will be implemented as part of W-15639759 const deltaRunTargets = DeltaRunFunctions.getDeltaRunTarget(sfgeCachePath, savedFilesCache); if (deltaRunTargets.length == 0) { void vscode.window.showInformationMessage('***No local changes found that would change the outcome of previous SFGE full run.***'); From cccc7285157d4c4dd4898497bc08310837fe752b Mon Sep 17 00:00:00 2001 From: Jag Jayaprakash Date: Thu, 19 Sep 2024 15:29:36 -0700 Subject: [PATCH 06/16] revert timeouts to old value --- src/test/suite/extension.test.ts | 6 +++--- src/test/suite/scanner.test.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts index e146bb4..9f7ee9f 100644 --- a/src/test/suite/extension.test.ts +++ b/src/test/suite/extension.test.ts @@ -58,7 +58,7 @@ suite('Extension Test Suite', () => { // ===== SETUP ===== // Set the timeout to a frankly absurd value, just to make sure Github Actions // can finish it in time. - this.timeout(180000); + this.timeout(90000); // Open a file in the editor. const fileUri: vscode.Uri = vscode.Uri.file(path.join(codeFixturesPath, 'folder-a', 'MyClassA1.cls')); const doc = await vscode.workspace.openTextDocument(fileUri); @@ -89,7 +89,7 @@ suite('Extension Test Suite', () => { // ===== SETUP ===== // Set the timeout to a frankly absurd value, just to make sure Github Actions // can finish it in time. - this.timeout(180000); + this.timeout(60000); // Get the URI for a single file. const targetUri: vscode.Uri = vscode.Uri.file(path.join(codeFixturesPath, 'folder-a', 'MyClassA1.cls')); @@ -119,7 +119,7 @@ suite('Extension Test Suite', () => { // ===== SETUP ===== // Set the timeout to a frankly absurd value, just to make sure Github Actions // can finish it in time. - this.timeout(180000); + this.timeout(60000); // Get the URIs for two separate files. const targetUri1: vscode.Uri = vscode.Uri.file(path.join(codeFixturesPath, 'folder-a', 'MyClassA1.cls')); const targetUri2: vscode.Uri = vscode.Uri.file(path.join(codeFixturesPath, 'folder-a', 'MyClassA2.cls')); diff --git a/src/test/suite/scanner.test.ts b/src/test/suite/scanner.test.ts index 9327e17..2ccee4e 100644 --- a/src/test/suite/scanner.test.ts +++ b/src/test/suite/scanner.test.ts @@ -612,7 +612,7 @@ suite('ScanRunner', () => { let context: vscode.ExtensionContext; suiteSetup(async function () { - this.timeout(60000); + this.timeout(10000); // Activate the extension. context = await ext.activate(); }); From 10f23e0a942fc2f773dd4143ae9cd8fe013166bc Mon Sep 17 00:00:00 2001 From: Jag Jayaprakash Date: Fri, 20 Sep 2024 12:16:43 -0700 Subject: [PATCH 07/16] NEW (Extension) @W-15640497@ Make Delta runs a user visible setting --- package.json | 7 ++++++- src/extension.ts | 14 +++++++++----- src/lib/settings.ts | 4 ++++ src/test/suite/settings.test.ts | 15 +++++++++++++++ 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index bdee6eb..13a0948 100644 --- a/package.json +++ b/package.json @@ -168,6 +168,11 @@ "type": "boolean", "default": false, "description": "Discover critical problems and performance issues in your Apex code with ApexGuru, which analyzes your Apex files for you. This feature is in a closed pilot; contact your account representative to learn more." + }, + "codeAnalyzer.deltaRuns.enabled": { + "type": "boolean", + "default": false, + "description": "***Enable delta run of Salesforce Graph Engine***" } } }, @@ -187,7 +192,7 @@ }, { "command": "sfca.runDfa", - "when": "false" + "when": "true" }, { "command": "sfca.removeDiagnosticsOnActiveFile", diff --git a/src/extension.ts b/src/extension.ts index 4d17ff7..31fcf78 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -123,11 +123,7 @@ export async function activate(context: vscode.ExtensionContext): Promise { - await _runDfa(context); - savedFilesCache.clear(); - }); - context.subscriptions.push(runOnActiveFile, runOnSelected, runDfaOnSelectedMethodCmd, runDfaOnWorkspaceCmd, removeDiagnosticsOnActiveFile, removeDiagnosticsOnSelectedFile, removeDiagnosticsInRange); + context.subscriptions.push(runOnActiveFile, runOnSelected, runDfaOnSelectedMethodCmd, removeDiagnosticsOnActiveFile, removeDiagnosticsOnSelectedFile, removeDiagnosticsInRange); if (apexGuruEnabled) { const runApexGuruOnSelectedFile = vscode.commands.registerCommand(Constants.COMMAND_RUN_APEX_GURU_ON_FILE, async (selection: vscode.Uri, multiSelect?: vscode.Uri[]) => { @@ -150,6 +146,14 @@ export async function activate(context: vscode.ExtensionContext): Promise { + await _runDfa(context); + savedFilesCache.clear(); + }); + context.subscriptions.push(runDfaOnWorkspaceCmd); + } + const documentSaveListener = vscode.workspace.onDidSaveTextDocument(document => { const filePath = document.uri.fsPath; savedFilesCache.add(filePath); diff --git a/src/lib/settings.ts b/src/lib/settings.ts index 9370a5f..497698b 100644 --- a/src/lib/settings.ts +++ b/src/lib/settings.ts @@ -53,4 +53,8 @@ export class SettingsManager { public static getApexGuruEnabled(): boolean { return vscode.workspace.getConfiguration('codeAnalyzer.apexGuru').get('enabled'); } + + public static getSfgeDeltaRunsEnabled(): boolean { + return vscode.workspace.getConfiguration('codeAnalyzer.deltaRuns').get('enabled'); + } } \ No newline at end of file diff --git a/src/test/suite/settings.test.ts b/src/test/suite/settings.test.ts index 4717732..3fda319 100644 --- a/src/test/suite/settings.test.ts +++ b/src/test/suite/settings.test.ts @@ -185,4 +185,19 @@ suite('SettingsManager Test Suite', () => { expect(result).to.equal(mockAnalyzeOnSaveEnabled); expect(getConfigurationStub.calledOnceWith('codeAnalyzer.apexGuru')).to.be.true; }); + + test('getSfgeDeltaRunsEnabled should return the delta runs enabled setting', () => { + // ===== SETUP ===== + const mockAnalyzeOnSaveEnabled = true; + getConfigurationStub.withArgs('codeAnalyzer.deltaRuns').returns({ + get: Sinon.stub().returns(mockAnalyzeOnSaveEnabled) + }); + + // ===== TEST ===== + const result = SettingsManager.getSfgeDeltaRunsEnabled(); + + // ===== ASSERTIONS ===== + expect(result).to.equal(mockAnalyzeOnSaveEnabled); + expect(getConfigurationStub.calledOnceWith('codeAnalyzer.deltaRuns')).to.be.true; + }); }); \ No newline at end of file From 7dda44a427ca5f12cbc9c110a379102205dae13d Mon Sep 17 00:00:00 2001 From: svc-cli-bot Date: Tue, 24 Sep 2024 11:10:13 -0600 Subject: [PATCH 08/16] Updating SHA256.md after 1.2.0 release --- SHA256.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SHA256.md b/SHA256.md index 877997e..6c31060 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. - f668893331860e3b8bc89357c4bfe2cac9840ee05acd1b0d67de5a8c37518b87 ./extensions/sfdx-code-analyzer-vscode-1.1.0.vsix + 146d022eebef24a355b117ad38713ac53a006f8e74cae178c6364a302878d3bc ./extensions/sfdx-code-analyzer-vscode-1.2.0.vsix 4. Change the filename extension for the file that you downloaded from .zip to .vsix. From bb6e7ffaef9324cf29b4a326179bc34761d109dd Mon Sep 17 00:00:00 2001 From: Jagadeeswaran Jayaprakash <58611665+jag-j@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:03:36 -0700 Subject: [PATCH 09/16] FIX (Extension) @W-16733527@ Additional telemetry for apex guru (#139) --- src/apexguru/apex-guru-service.ts | 9 +- src/extension.ts | 11 +- src/lib/constants.ts | 1 + src/lib/fixer.ts | 12 +- .../suite/apexguru/apex-guru-service.test.ts | 136 ++++++++++++++++++ src/test/suite/fixer.test.ts | 8 +- 6 files changed, 164 insertions(+), 13 deletions(-) diff --git a/src/apexguru/apex-guru-service.ts b/src/apexguru/apex-guru-service.ts index 4553c4a..8f63641 100644 --- a/src/apexguru/apex-guru-service.ts +++ b/src/apexguru/apex-guru-service.ts @@ -57,7 +57,9 @@ export async function runApexGuruOnFile(selection: vscode.Uri, runInfo: RunInfo) new DiagnosticManager().displayDiagnostics([selection.fsPath], [ruleResult], diagnosticCollection); TelemetryService.sendCommandEvent(Constants.TELEM_SUCCESSFUL_APEX_GURU_FILE_ANALYSIS, { executedCommand: commandName, - duration: (Date.now() - startTime).toString() + duration: (Date.now() - startTime).toString(), + violationsCount: ruleResult.violations.length.toString(), + violationsWithSuggestedCodeCount: getViolationsWithSuggestions(ruleResult).toString() }); void vscode.window.showInformationMessage(messages.apexGuru.finishedScan(ruleResult.violations.length)); }); @@ -68,6 +70,11 @@ export async function runApexGuruOnFile(selection: vscode.Uri, runInfo: RunInfo) } } +export function getViolationsWithSuggestions(ruleResult: RuleResult): number { + // Filter violations that have a non-empty suggestedCode and get count + return ruleResult.violations.filter(violation => (violation as ApexGuruViolation).suggestedCode?.trim() !== '').length; +} + export async function pollAndGetApexGuruResponse(connection: Connection, requestId: string, maxWaitTimeInSeconds: number, retryIntervalInMillis: number): Promise { let queryResponse: ApexGuruQueryResponse; let lastErrorMessage = ''; diff --git a/src/extension.ts b/src/extension.ts index 31fcf78..7dc3cca 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -143,7 +143,16 @@ export async function activate(context: vscode.ExtensionContext): Promise { + const edit = new vscode.WorkspaceEdit(); + edit.insert(document.uri, position, suggestedCode); + await vscode.workspace.applyEdit(edit); + TelemetryService.sendCommandEvent(Constants.TELEM_SUCCESSFUL_APEX_GURU_FILE_ANALYSIS, { + executedCommand: Constants.COMMAND_INCLUDE_APEX_GURU_SUGGESTIONS, + lines: suggestedCode.split('\n').length.toString() + }); + }) + context.subscriptions.push(runApexGuruOnSelectedFile, runApexGuruOnCurrentFile, insertApexGuruSuggestions); } if (SettingsManager.getSfgeDeltaRunsEnabled()) { diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 6dc6977..6d94694 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -19,6 +19,7 @@ export const COMMAND_REMOVE_DIAGNOSTICS_ON_SELECTED_FILE = 'sfca.removeDiagnosti export const COMMAND_DIAGNOSTICS_IN_RANGE = 'sfca.removeDiagnosticsInRange'; export const COMMAND_RUN_APEX_GURU_ON_FILE = 'sfca.runApexGuruAnalysisOnSelectedFile'; export const COMMAND_RUN_APEX_GURU_ON_ACTIVE_FILE = 'sfca.runApexGuruAnalysisOnCurrentFile'; +export const COMMAND_INCLUDE_APEX_GURU_SUGGESTIONS = 'sfca.includeApexGuruSuggestions'; // telemetry event keys export const TELEM_SUCCESSFUL_STATIC_ANALYSIS = 'sfdx__codeanalyzer_static_run_complete'; diff --git a/src/lib/fixer.ts b/src/lib/fixer.ts index bf00e09..c15b287 100644 --- a/src/lib/fixer.ts +++ b/src/lib/fixer.ts @@ -111,14 +111,14 @@ export class _ApexGuruFixGenerator extends FixGenerator { const action = new vscode.CodeAction(messages.fixer.fixWithApexGuruSuggestions, vscode.CodeActionKind.QuickFix); action.diagnostics = [this.diagnostic]; - - const edit = new vscode.WorkspaceEdit(); const range = this.diagnostic.range; // Assuming the range is the location of the existing code in the document const diagnosticStartLine = new vscode.Position(range.start.line, range.start.character); - edit.insert(document.uri, diagnosticStartLine, suggestedCode + '\n'); - - // Assign the edit to the action - action.edit = edit; + + action.command = { + title: 'Apply ApexGuru Fix', + command: Constants.COMMAND_INCLUDE_APEX_GURU_SUGGESTIONS, + arguments: [document, diagnosticStartLine, suggestedCode + '\n'] + } return action; } diff --git a/src/test/suite/apexguru/apex-guru-service.test.ts b/src/test/suite/apexguru/apex-guru-service.test.ts index f27a873..792abc0 100644 --- a/src/test/suite/apexguru/apex-guru-service.test.ts +++ b/src/test/suite/apexguru/apex-guru-service.test.ts @@ -371,4 +371,140 @@ suite('Apex Guru Test Suite', () => { expect(connectionStub.request.callCount).to.be.greaterThan(0); }); }); + suite('#getViolationsWithSuggestions', () => { + test('Returns 0 when there are no violations', () => { + // ===== SETUP ===== + const ruleResult: RuleResult = { + engine: 'fake_engine', + fileName: 'test.cls', + violations: [] + }; + // ===== TEST ===== + const result = ApexGuruFunctions.getViolationsWithSuggestions(ruleResult); + // ===== ASSERTIONS ===== + expect(result).to.equal(0); + }); + + test('Returns 0 when there are violations but no suggestions', () => { + // ===== SETUP ===== + const ruleResult: RuleResult = { + engine: 'fake_engine', + fileName: 'test.cls', + violations: [ + { + ruleName: 'BestPractices', + message: 'Avoid using System.debug', + severity: 1, + category: 'BestPractices', + line: 10, + column: 1, + currentCode: 'System.debug();', + suggestedCode: '', // No suggested code + url: 'TestFile.cls' + } as ApexGuruViolation + ] + }; + // ===== TEST ===== + const result = ApexGuruFunctions.getViolationsWithSuggestions(ruleResult); + // ===== ASSERTIONS ===== + expect(result).to.equal(0); + }); + + test('Returns correct count when there are violations with suggestions', () => { + // ===== SETUP ===== + const ruleResult: RuleResult = { + engine: 'fake_engine', + fileName: 'test.cls', + violations: [ + { + ruleName: 'BestPractices', + message: 'Avoid using System.debug', + severity: 1, + category: 'BestPractices', + line: 10, + column: 1, + currentCode: 'System.debug();', + suggestedCode: 'System.out.println("Hello World");', + url: 'TestFile.cls' + } as ApexGuruViolation + ] + }; + // ===== TEST ===== + const result = ApexGuruFunctions.getViolationsWithSuggestions(ruleResult); + // ===== ASSERTIONS ===== + expect(result).to.equal(1); + }); + + test('Returns correct count when multiple violations have suggestions', () => { + // ===== SETUP ===== + const ruleResult: RuleResult = { + engine: 'fake_engine', + fileName: 'test.cls', + violations: [ + { + ruleName: 'BestPractices', + message: 'Avoid using System.debug', + severity: 1, + category: 'BestPractices', + line: 10, + column: 1, + currentCode: 'System.debug();', + suggestedCode: 'System.out.println("Hello World");', + url: 'TestFile.cls' + } as ApexGuruViolation, + { + ruleName: 'CodeQuality', + message: 'Improve variable naming', + severity: 1, + category: 'CodeQuality', + line: 12, + column: 2, + currentCode: 'int x;', + suggestedCode: 'int userCount;', + url: 'TestFile.cls' + } as ApexGuruViolation + ] + }; + // ===== TEST ===== + const result = ApexGuruFunctions.getViolationsWithSuggestions(ruleResult); + // ===== ASSERTIONS ===== + expect(result).to.equal(2); + }); + + test('Ignores violations without suggestedCode', () => { + // ===== SETUP ===== + const ruleResult: RuleResult = { + engine: 'fake_engine', + fileName: 'test.cls', + violations: [ + { + ruleName: 'BestPractices', + message: 'Avoid using System.debug', + severity: 1, + category: 'BestPractices', + line: 10, + column: 1, + currentCode: 'System.debug();', + suggestedCode: 'System.out.println("Hello World");', + url: 'TestFile.cls' + } as ApexGuruViolation, + { + ruleName: 'CodeQuality', + message: 'Improve variable naming', + severity: 1, + category: 'CodeQuality', + line: 12, + column: 2, + currentCode: 'int x;', + suggestedCode: '', // No suggestion for this violation + url: 'TestFile.cls' + } as ApexGuruViolation + ] + }; + // ===== TEST ===== + const result = ApexGuruFunctions.getViolationsWithSuggestions(ruleResult); + // ===== ASSERTIONS ===== + expect(result).to.equal(1); + }); + }); }); diff --git a/src/test/suite/fixer.test.ts b/src/test/suite/fixer.test.ts index f962f05..8262aee 100644 --- a/src/test/suite/fixer.test.ts +++ b/src/test/suite/fixer.test.ts @@ -7,6 +7,7 @@ import * as vscode from 'vscode'; import {expect} from 'chai'; import path = require('path'); +import * as Constants from '../../lib/constants'; import {_NoOpFixGenerator, _PmdFixGenerator, _ApexGuruFixGenerator} from '../../lib/fixer'; suite('fixer.ts', () => { @@ -529,9 +530,7 @@ suite('fixer.ts', () => { // Validate results. expect(fixes).to.have.lengthOf(1, 'One fix should be offered'); - const fix = fixes[0].edit.get(fileUri)[0]; - expect(fix.newText).to.equal('apex guru suggested code\n', 'The suppression code should match the suggestion'); - expect(fix.range.start.line).to.equal(7, 'The suppression should be added at the diagnostic line'); + expect(fixes[0].command.command).to.equal(Constants.COMMAND_INCLUDE_APEX_GURU_SUGGESTIONS); }); test('Should not generate a suppression fix if line is already processed', async () => { @@ -604,8 +603,7 @@ suite('fixer.ts', () => { const fix = fixGenerator.generateApexGuruSuppresssion(doc); // Validate results. - expect(fix.edit.get(fileUri)[0].newText).to.equal('apex guru suggested code\n', 'The suppression code should match the suggestion'); - expect(fix.edit.get(fileUri)[0].range.start.line).to.equal(7, 'The suppression should be added at the diagnostic line'); + expect(fix.command.command).to.equal(Constants.COMMAND_INCLUDE_APEX_GURU_SUGGESTIONS); }); }); }); From 87e7da8f069f504b1947163b9f862469662f8794 Mon Sep 17 00:00:00 2001 From: Jagadeeswaran Jayaprakash <58611665+jag-j@users.noreply.github.com> Date: Wed, 9 Oct 2024 14:37:04 -0700 Subject: [PATCH 10/16] NEW (Extension) @W-16812379@ Add production heartbeat test (in progress) (#141) --- .github/workflows/production-heartbeat.yml | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/production-heartbeat.yml diff --git a/.github/workflows/production-heartbeat.yml b/.github/workflows/production-heartbeat.yml new file mode 100644 index 0000000..788f1d5 --- /dev/null +++ b/.github/workflows/production-heartbeat.yml @@ -0,0 +1,38 @@ +name: production-heartbeat +on: + workflow_dispatch: # As per documentation, the colon is necessary even though no config is required. + schedule: + # Cron syntax is "minute[0-59] hour[0-23] date[1-31] month[1-12] day[0-6]". '*' is 'any value', and multiple values + # can be specified with comma-separated lists. All times are UTC. + # So this expression means "run at 45 minutes past 1, 5, and 9 AM/PM UTC". The hours were chosen so that + # the jobs run only close to business hours of Central Time. + # Days were chosen to run only from Monday through Friday. + - cron: '45 13,17,21 * * 1,2,3,4,5' +jobs: + production-heartbeat: + strategy: + # By default, if any job in a matrix fails, all other jobs are immediately cancelled. This makes the jobs run to completion instead. + fail-fast: false + matrix: + os: [{vm: ubuntu-latest, exe: .sh}, {vm: windows-2019, exe: .cmd}] + node: ['lts/*'] + runs-on: ${{ matrix.os.vm }} + timeout-minutes: 60 + steps: + # === Setup. We need to get the code, set up nodejs, and create the results directory. === + - uses: actions/checkout@v4 + with: + ref: 'release' + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '11' + - run: mkdir smoke-test-results + + - name: Say Hello World + id: say_hello_world + shell: bash + run: echo "Hello World" From b17e3ccc84370e65fe2bac0de86972ae580bd641 Mon Sep 17 00:00:00 2001 From: Jagadeeswaran Jayaprakash <58611665+jag-j@users.noreply.github.com> Date: Tue, 15 Oct 2024 12:31:00 -0700 Subject: [PATCH 11/16] NEW (Extension) @W-16812379@ Add production heartbeat test (#142) --- .github/workflows/production-heartbeat.yml | 157 ++++++++++++++++++--- 1 file changed, 139 insertions(+), 18 deletions(-) diff --git a/.github/workflows/production-heartbeat.yml b/.github/workflows/production-heartbeat.yml index 788f1d5..15c0711 100644 --- a/.github/workflows/production-heartbeat.yml +++ b/.github/workflows/production-heartbeat.yml @@ -11,28 +11,149 @@ on: jobs: production-heartbeat: strategy: - # By default, if any job in a matrix fails, all other jobs are immediately cancelled. This makes the jobs run to completion instead. fail-fast: false matrix: - os: [{vm: ubuntu-latest, exe: .sh}, {vm: windows-2019, exe: .cmd}] + os: [{vm: ubuntu-latest}, {vm: windows-2019}, {vm: macos-latest}] node: ['lts/*'] runs-on: ${{ matrix.os.vm }} timeout-minutes: 60 steps: - # === Setup. We need to get the code, set up nodejs, and create the results directory. === - - uses: actions/checkout@v4 - with: - ref: 'release' - - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node }} - - uses: actions/setup-java@v4 - with: - distribution: 'temurin' - java-version: '11' - - run: mkdir smoke-test-results - - - name: Say Hello World - id: say_hello_world + # 1 Install VS Code and Extension on Ubuntu + - name: Install VS Code on Ubuntu + if: runner.os == 'Linux' + run: | + sudo apt update + sudo apt install wget gpg -y + wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > packages.microsoft.gpg + sudo install -o root -g root -m 644 packages.microsoft.gpg /usr/share/keyrings/ + sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main" > /etc/apt/sources.list.d/vscode.list' + sudo apt update + sudo apt install code -y + + - name: Install Salesforce Code Analyzer Extension on Ubuntu + if: runner.os == 'Linux' + run: | + code --install-extension salesforce.sfdx-code-analyzer-vscode + + - name: Verify Extension Installation on Ubuntu + if: runner.os == 'Linux' + run: | + if code --list-extensions | grep -q 'salesforce.sfdx-code-analyzer-vscode'; then + echo "Extension installed successfully" + else + echo "::error Extension installation failed" && exit 1 + fi + + # 2 Install VS Code and Extension on Windows + # We use chocolatey to install vscode since it gives a reliable path for the location of code.exe + # We have also seen Windows to be flaky, so adding addition echo statements. + - name: Install VS Code on Windows + if: runner.os == 'Windows' + run: | + Write-Host "Installing Chocolatey..." + Set-ExecutionPolicy Bypass -Scope Process -Force; + [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; + iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) + Write-Host "Installing Visual Studio Code using Chocolatey..." + choco install vscode -y + + - name: Install Salesforce Code Analyzer Extension on Windows + if: runner.os == 'Windows' + run: | + echo "Installing Code Analyzer Extension..." + "/c/Program Files/Microsoft VS Code/bin/code" --install-extension salesforce.sfdx-code-analyzer-vscode + echo "Installing Code Analyzer Complete" + + echo "Waiting for 10 seconds..." + sleep 10 + + echo "Listing installed extensions..." + "/c/Program Files/Microsoft VS Code/bin/code" --list-extensions + shell: bash + + - name: Verify Extension on Windows + if: runner.os == 'Windows' + run: | + echo "Waiting for 10 seconds..." + sleep 10 + + echo "Listing installed extensions..." + extensions=$("/c/Program Files/Microsoft VS Code/bin/code" --list-extensions) + + echo "$extensions" + + if echo "$extensions" | grep -q 'salesforce.sfdx-code-analyzer-vscode'; then + echo "Extension 'salesforce.sfdx-code-analyzer-vscode' is installed successfully" + else + echo "::error Extension 'salesforce.sfdx-code-analyzer-vscode' is NOT installed" + exit 1 + fi + shell: bash + + # 3 Install VS Code and Extension on macOS + - name: Install VS Code on macOS + if: runner.os == 'macOS' + run: | + brew install --cask visual-studio-code + + - name: Install Salesforce Code Analyzer Extension on macOS + if: runner.os == 'macOS' + run: | + code --install-extension salesforce.sfdx-code-analyzer-vscode + + - name: Verify Extension Installation on macOS + if: runner.os == 'macOS' + run: | + if code --list-extensions | grep -q 'salesforce.sfdx-code-analyzer-vscode'; then + echo "Extension installed successfully" + else + echo "::error Extension installation failed" && exit 1 + fi + + # === Report any problems === + - name: Report problems + # There are problems if any step failed or was skipped. + # Note that the `join()` call omits null values, so if any steps were skipped, they won't have a corresponding + # value in the string. + if: ${{ failure() || cancelled() }} shell: bash - run: echo "Hello World" + env: + # If we're here because steps failed or were skipped, then that's a critical problem. Otherwise it's a normal one. + # We can't use the `failure()` or `cancelled()` convenience methods outside of the `if` condition, hence the + # `contains()` calls. + IS_CRITICAL: ${{ contains(join(steps.*.outcome), 'failure') || contains(join(steps.*.outcome), 'skipped') }} + # A link to this run, so the PagerDuty assignee can quickly get here. + RUN_LINK: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} + + run: | + + if [[ ${{ env.IS_CRITICAL }} == true ]]; then + ALERT_SEV="critical" + ALERT_SUMMARY="Production heartbeat script failed on ${{ runner.os }}" + else + # Leaving the else part here to help with running end-to-end sanity test with real alerts being created. + ALERT_SEV="info" + ALERT_SUMMARY="Production heartbeat script succeeded with retries on ${{ runner.os }}" + fi + # Define a helper function to create our POST request's data, to sidestep issues with nested quotations. + generate_post_data() { + # This is known as a HereDoc, and it lets us declare multi-line input ending when the specified limit string, + # in this case EOF, is encountered. + cat < Date: Tue, 15 Oct 2024 13:22:06 -0700 Subject: [PATCH 12/16] CHANGE (Extension) @W-16812379@ Add pager to alert to smoke test failure (#143) --- .github/workflows/daily-smoke-test.yml | 41 ++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/.github/workflows/daily-smoke-test.yml b/.github/workflows/daily-smoke-test.yml index d29d670..278f148 100644 --- a/.github/workflows/daily-smoke-test.yml +++ b/.github/workflows/daily-smoke-test.yml @@ -28,4 +28,45 @@ jobs: create-vsix-artifact: name: 'Upload VSIX as artifact' uses: ./.github/workflows/create-vsix-artifact.yml + # Step 4: Report any problems + report-problems: + name: 'Report problems' + runs-on: ubuntu-latest + needs: [build-scanner-tarball, smoke-test, create-vsix-artifact] + if: ${{ failure() || cancelled() }} + steps: + - name: Report problems + shell: bash + env: + IS_CRITICAL: ${{ contains(join(steps.*.outcome), 'failure') || contains(join(steps.*.outcome), 'skipped') }} + RUN_LINK: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} + run: | + if [[ ${{ env.IS_CRITICAL }} == true ]]; then + ALERT_SEV="critical" + ALERT_SUMMARY="Production heartbeat script failed on ${{ runner.os }}" + else + ALERT_SEV="info" + ALERT_SUMMARY="Production heartbeat script succeeded with retries on ${{ runner.os }}" + fi + + generate_post_data() { + cat < Date: Wed, 16 Oct 2024 08:33:54 -0700 Subject: [PATCH 13/16] FIX (Extension) @W-16812379@ Fix pager alert script (#144) --- .github/workflows/daily-smoke-test.yml | 37 +++++++++++++------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/.github/workflows/daily-smoke-test.yml b/.github/workflows/daily-smoke-test.yml index 278f148..35edf6a 100644 --- a/.github/workflows/daily-smoke-test.yml +++ b/.github/workflows/daily-smoke-test.yml @@ -43,30 +43,29 @@ jobs: run: | if [[ ${{ env.IS_CRITICAL }} == true ]]; then ALERT_SEV="critical" - ALERT_SUMMARY="Production heartbeat script failed on ${{ runner.os }}" + ALERT_SUMMARY="Daily smoke test failed on ${{ runner.os }}" else ALERT_SEV="info" - ALERT_SUMMARY="Production heartbeat script succeeded with retries on ${{ runner.os }}" + ALERT_SUMMARY="Daily smoke test succeeded with retries on ${{ runner.os }}" fi - + generate_post_data() { cat < Date: Wed, 16 Oct 2024 09:34:26 -0700 Subject: [PATCH 14/16] FIX (Extension) @W-16944796@ Fix the ApexGuru violations url to point to ApexGuru antipatterns site (#145) --- src/apexguru/apex-guru-service.ts | 2 +- src/test/suite/apexguru/apex-guru-service.test.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/apexguru/apex-guru-service.ts b/src/apexguru/apex-guru-service.ts index 8f63641..7b2ff1e 100644 --- a/src/apexguru/apex-guru-service.ts +++ b/src/apexguru/apex-guru-service.ts @@ -154,7 +154,7 @@ export function transformStringToRuleResult(fileName: string, jsonString: string column: 1, currentCode: Buffer.from(encodedCodeBefore, 'base64').toString('utf8'), suggestedCode: Buffer.from(encodedCodeAfter, 'base64').toString('utf8'), - url: fileName + url: 'https://help.salesforce.com/s/articleView?id=sf.apexguru_antipatterns.htm&type=5' }; ruleResult.violations.push(violation); diff --git a/src/test/suite/apexguru/apex-guru-service.test.ts b/src/test/suite/apexguru/apex-guru-service.test.ts index 792abc0..1b3d6c2 100644 --- a/src/test/suite/apexguru/apex-guru-service.test.ts +++ b/src/test/suite/apexguru/apex-guru-service.test.ts @@ -179,7 +179,7 @@ suite('Apex Guru Test Suite', () => { column: 1, currentCode: 'System.out.println("Old Hello World");', suggestedCode: 'System.out.println("New Hello World");', - url: "TestFile.cls" + url: "https://help.salesforce.com/s/articleView?id=sf.apexguru_antipatterns.htm&type=5" }] }); }); @@ -210,7 +210,7 @@ suite('Apex Guru Test Suite', () => { column: 1, currentCode: 'System.out.println("Old Hello World");', suggestedCode: 'System.out.println("New Hello World");', - url: "TestFile.cls" + url: "https://help.salesforce.com/s/articleView?id=sf.apexguru_antipatterns.htm&type=5" }] }); }); @@ -236,7 +236,7 @@ suite('Apex Guru Test Suite', () => { category: 'BestPractices', line: 10, column: 1, - url: "TestFile.cls", + url: "https://help.salesforce.com/s/articleView?id=sf.apexguru_antipatterns.htm&type=5", currentCode: '', suggestedCode: '', }] From 45c2fffb971ed2e9a200ad6ddace92854cae709d Mon Sep 17 00:00:00 2001 From: Jagadeeswaran Jayaprakash <58611665+jag-j@users.noreply.github.com> Date: Wed, 16 Oct 2024 12:30:41 -0700 Subject: [PATCH 15/16] FIX (Extension) @W-16993912@ Implement Doc Review suggestions + fix partial runs setting bug (#146) --- package.json | 8 ++++---- src/extension.ts | 17 ++++++++++------- src/lib/messages.ts | 1 + src/lib/settings.ts | 4 ++-- src/test/suite/settings.test.ts | 6 +++--- 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index abef372..fac39f8 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ }, { "command": "sfca.runDfa", - "title": "***SFDX: Run Graph-Engine Based Analysis***" + "title": "SFDX: Scan Project with Graph Engine Path-Based Analysis" }, { "command": "sfca.runApexGuruAnalysisOnSelectedFile", @@ -169,10 +169,10 @@ "default": false, "description": "Discover critical problems and performance issues in your Apex code with ApexGuru, which analyzes your Apex files for you. This feature is in a closed pilot; contact your account representative to learn more." }, - "codeAnalyzer.deltaRuns.enabled": { + "codeAnalyzer.partialGraphEngineScans.enabled": { "type": "boolean", "default": false, - "description": "***Enable delta run of Salesforce Graph Engine***" + "description": "Enables partial Salesforce Graph Engine scans on only the code you've modified since the initial full scan. (Beta)" } } }, @@ -192,7 +192,7 @@ }, { "command": "sfca.runDfa", - "when": "true" + "when": "sfca.partialRunsEnabled" }, { "command": "sfca.removeDiagnosticsOnActiveFile", diff --git a/src/extension.ts b/src/extension.ts index 7dc3cca..9109a8b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -155,7 +155,8 @@ export async function activate(context: vscode.ExtensionContext): Promise { await _runDfa(context); savedFilesCache.clear(); @@ -212,26 +213,28 @@ export function createTempDirectory(): string { async function _runDfa(context: vscode.ExtensionContext) { if (violationsCacheExists()) { + const partialScanText = 'Partial scan: Scan only the code that you changed since the previous scan.'; + const fullScanText = 'Full scan: Scan all the code in this project again.'; const choice = await vscode.window.showQuickPick( - ['***Yes***', '***No***'], + [partialScanText, fullScanText], { - placeHolder: '***We identified a previous Salesforce Graph Engine run. Do you want to only run the previously failed violations from that run?***', + placeHolder: 'You previously scanned this code using Salesforce Graph Engine. What kind of scan do you want to run now?', canPickMany: false, ignoreFocusOut: true } ); // Default to "Yes" if no choice is made - const rerunChangedOnly = choice == '***Yes***'; + const rerunChangedOnly = choice == partialScanText; if (rerunChangedOnly) { const deltaRunTargets = DeltaRunFunctions.getDeltaRunTarget(sfgeCachePath, savedFilesCache); if (deltaRunTargets.length == 0) { - void vscode.window.showInformationMessage('***No local changes found that would change the outcome of previous SFGE full run.***'); + void vscode.window.showInformationMessage("Your local changes didn't change the outcome of the previous full Salesforce Graph Engine scan."); return } await runDfaOnSelectMethods(context, deltaRunTargets); } else { - void vscode.window.showWarningMessage('***A full run of the graph engine will happen in the background. You can cancel this by clicking on the status progress.***'); + void vscode.window.showWarningMessage('A full Salesforce Graph Engine scan is running in the background. You can cancel it by clicking the progress bar.'); await runDfaOnWorkspace(context); } } else { @@ -252,7 +255,7 @@ async function runDfaOnSelectMethods(context: vscode.ExtensionContext, selectedM customCancellationToken.token.onCancellationRequested(async () => { customCancellationToken?.dispose(); customCancellationToken = null; - await vscode.window.showInformationMessage(messages.graphEngine.noViolationsFound); + await vscode.window.showInformationMessage(messages.graphEngine.noViolationsFoundForPartialRuns); return; }); diff --git a/src/lib/messages.ts b/src/lib/messages.ts index 41dee99..1993a0d 100644 --- a/src/lib/messages.ts +++ b/src/lib/messages.ts @@ -30,6 +30,7 @@ export const messages = { }, graphEngine: { noViolationsFound: "Scan was completed. No violations found.", + noViolationsFoundForPartialRuns: "Partial Salesforce Graph Engine scan of the changed code completed, and no violations found. IMPORTANT: You might still have violations in the code that you haven't changed since the previous full scan.", resultsTab: "Graph Engine Results", spinnerText: 'Running Graph Engine analysis...', statusBarName: "Graph Engine Analysis", diff --git a/src/lib/settings.ts b/src/lib/settings.ts index 497698b..9e4010f 100644 --- a/src/lib/settings.ts +++ b/src/lib/settings.ts @@ -54,7 +54,7 @@ export class SettingsManager { return vscode.workspace.getConfiguration('codeAnalyzer.apexGuru').get('enabled'); } - public static getSfgeDeltaRunsEnabled(): boolean { - return vscode.workspace.getConfiguration('codeAnalyzer.deltaRuns').get('enabled'); + public static getSfgePartialSfgeRunsEnabled(): boolean { + return vscode.workspace.getConfiguration('codeAnalyzer.partialGraphEngineScans').get('enabled'); } } \ No newline at end of file diff --git a/src/test/suite/settings.test.ts b/src/test/suite/settings.test.ts index 3fda319..2f1e897 100644 --- a/src/test/suite/settings.test.ts +++ b/src/test/suite/settings.test.ts @@ -189,15 +189,15 @@ suite('SettingsManager Test Suite', () => { test('getSfgeDeltaRunsEnabled should return the delta runs enabled setting', () => { // ===== SETUP ===== const mockAnalyzeOnSaveEnabled = true; - getConfigurationStub.withArgs('codeAnalyzer.deltaRuns').returns({ + getConfigurationStub.withArgs('codeAnalyzer.partialGraphEngineScans').returns({ get: Sinon.stub().returns(mockAnalyzeOnSaveEnabled) }); // ===== TEST ===== - const result = SettingsManager.getSfgeDeltaRunsEnabled(); + const result = SettingsManager.getSfgePartialSfgeRunsEnabled(); // ===== ASSERTIONS ===== expect(result).to.equal(mockAnalyzeOnSaveEnabled); - expect(getConfigurationStub.calledOnceWith('codeAnalyzer.deltaRuns')).to.be.true; + expect(getConfigurationStub.calledOnceWith('codeAnalyzer.partialGraphEngineScans')).to.be.true; }); }); \ No newline at end of file From 460d63e861cf645e8a85940687f495377ad392de Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 12:10:30 +0000 Subject: [PATCH 16/16] Preparing for v1.3.0 release. --- package.json | 2 +- yarn.lock | 443 +++++++++++++++++++++++++-------------------------- 2 files changed, 216 insertions(+), 229 deletions(-) diff --git a/package.json b/package.json index fac39f8..77748ad 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "color": "#ECECEC", "theme": "light" }, - "version": "1.2.0", + "version": "1.3.0", "publisher": "salesforce", "license": "BSD-3-Clause", "engines": { diff --git a/yarn.lock b/yarn.lock index e2e1bf2..99071da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10,13 +10,6 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@azure/abort-controller@^1.0.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-1.1.0.tgz#788ee78457a55af8a1ad342acb182383d2119249" - integrity sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw== - dependencies: - tslib "^2.2.0" - "@azure/abort-controller@^2.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-2.1.2.tgz#42fe0ccab23841d9905812c58f1082d27784566d" @@ -24,13 +17,13 @@ dependencies: tslib "^2.6.2" -"@azure/core-auth@^1.4.0", "@azure/core-auth@^1.5.0", "@azure/core-auth@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@azure/core-auth/-/core-auth-1.8.0.tgz#281b4a6d3309c3e7b15bcd967f01d4c79ae4a1d6" - integrity sha512-YvFMowkXzLbXNM11yZtVLhUCmuG0ex7JKOH366ipjmHBhL3vpDcPAeWF+jf0X+jVXwFqo3UhsWUq4kH0ZPdu/g== +"@azure/core-auth@^1.4.0", "@azure/core-auth@^1.8.0", "@azure/core-auth@^1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@azure/core-auth/-/core-auth-1.9.0.tgz#ac725b03fabe3c892371065ee9e2041bee0fd1ac" + integrity sha512-FPwHpZywuyasDSLMqJ6fhbOK3TqUdviZNF8OqRGA4W5Ewib2lEEZ+pBsYcBa88B2NGO/SEnYPGhyBqNlE8ilSw== dependencies: "@azure/abort-controller" "^2.0.0" - "@azure/core-util" "^1.1.0" + "@azure/core-util" "^1.11.0" tslib "^2.6.2" "@azure/core-client@^1.9.2": @@ -46,7 +39,7 @@ "@azure/logger" "^1.0.0" tslib "^2.6.2" -"@azure/core-rest-pipeline@^1.1.0", "@azure/core-rest-pipeline@^1.9.1": +"@azure/core-rest-pipeline@^1.17.0", "@azure/core-rest-pipeline@^1.9.1": version "1.17.0" resolved "https://registry.yarnpkg.com/@azure/core-rest-pipeline/-/core-rest-pipeline-1.17.0.tgz#55dafa1093553c549ed6d8dbca69aa505c7b3aa3" integrity sha512-62Vv8nC+uPId3j86XJ0WI+sBf0jlqTqPUFCBNrGtlaUeQUIXWV/D8GE5A1d+Qx8H7OQojn2WguC8kChD6v0shA== @@ -61,34 +54,34 @@ tslib "^2.6.2" "@azure/core-tracing@^1.0.0", "@azure/core-tracing@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@azure/core-tracing/-/core-tracing-1.1.2.tgz#065dab4e093fb61899988a1cdbc827d9ad90b4ee" - integrity sha512-dawW9ifvWAWmUm9/h+/UQ2jrdvjCJ7VJEuCJ6XVNudzcOwm53BFZH4Q845vjfgoUAM8ZxokvVNxNxAITc502YA== + version "1.2.0" + resolved "https://registry.yarnpkg.com/@azure/core-tracing/-/core-tracing-1.2.0.tgz#7be5d53c3522d639cf19042cbcdb19f71bc35ab2" + integrity sha512-UKTiEJPkWcESPYJz3X5uKRYyOcJD+4nYph+KpfdPRnQJVrZfk0KJgdnaAWKfhsBBtAf/D58Az4AvCJEmWgIBAg== dependencies: tslib "^2.6.2" -"@azure/core-util@^1.1.0", "@azure/core-util@^1.3.0", "@azure/core-util@^1.6.1", "@azure/core-util@^1.9.0": - version "1.10.0" - resolved "https://registry.yarnpkg.com/@azure/core-util/-/core-util-1.10.0.tgz#cf3163382d40343972848c914869864df5d44bdb" - integrity sha512-dqLWQsh9Nro1YQU+405POVtXnwrIVqPyfUzc4zXCbThTg7+vNNaiMkwbX9AMXKyoFYFClxmB3s25ZFr3+jZkww== +"@azure/core-util@^1.11.0", "@azure/core-util@^1.6.1", "@azure/core-util@^1.9.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@azure/core-util/-/core-util-1.11.0.tgz#f530fc67e738aea872fbdd1cc8416e70219fada7" + integrity sha512-DxOSLua+NdpWoSqULhjDyAZTXFdP/LKkqtYuxxz1SCN289zk3OG8UOpnCQAz/tygyACBtWp/BoO72ptK7msY8g== dependencies: "@azure/abort-controller" "^2.0.0" tslib "^2.6.2" "@azure/identity@^4.1.0": - version "4.4.1" - resolved "https://registry.yarnpkg.com/@azure/identity/-/identity-4.4.1.tgz#490fa2ad26786229afa36411892bb53dfa3478d3" - integrity sha512-DwnG4cKFEM7S3T+9u05NstXU/HN0dk45kPOinUyNKsn5VWwpXd9sbPKEg6kgJzGbm1lMuhx9o31PVbCtM5sfBA== + version "4.5.0" + resolved "https://registry.yarnpkg.com/@azure/identity/-/identity-4.5.0.tgz#93ce3757bf761a08cfd05f56ef181435e05b9e1c" + integrity sha512-EknvVmtBuSIic47xkOqyNabAme0RYTw52BTMz8eBgU1ysTyMrD1uOoM+JdS0J/4Yfp98IBT3osqq3BfwSaNaGQ== dependencies: - "@azure/abort-controller" "^1.0.0" - "@azure/core-auth" "^1.5.0" + "@azure/abort-controller" "^2.0.0" + "@azure/core-auth" "^1.9.0" "@azure/core-client" "^1.9.2" - "@azure/core-rest-pipeline" "^1.1.0" + "@azure/core-rest-pipeline" "^1.17.0" "@azure/core-tracing" "^1.0.0" - "@azure/core-util" "^1.3.0" + "@azure/core-util" "^1.11.0" "@azure/logger" "^1.0.0" - "@azure/msal-browser" "^3.14.0" - "@azure/msal-node" "^2.9.2" + "@azure/msal-browser" "^3.26.1" + "@azure/msal-node" "^2.15.0" events "^3.0.0" jws "^4.0.0" open "^8.0.0" @@ -102,10 +95,10 @@ dependencies: tslib "^2.6.2" -"@azure/msal-browser@^3.14.0": - version "3.24.0" - resolved "https://registry.yarnpkg.com/@azure/msal-browser/-/msal-browser-3.24.0.tgz#3208047672d0b0c943b0bef5f995d510d6582ae4" - integrity sha512-JGNV9hTYAa7lsum9IMIibn2kKczAojNihGo1hi7pG0kNrcKej530Fl6jxwM05A44/6I079CSn6WxYxbVhKUmWg== +"@azure/msal-browser@^3.26.1": + version "3.26.1" + resolved "https://registry.yarnpkg.com/@azure/msal-browser/-/msal-browser-3.26.1.tgz#2f4368d7997682db30dca52e32fcac363fa0efad" + integrity sha512-y78sr9g61aCAH9fcLO1um+oHFXc1/5Ap88RIsUSuzkm0BHzFnN+PXGaQeuM1h5Qf5dTnWNOd6JqkskkMPAhh7Q== dependencies: "@azure/msal-common" "14.15.0" @@ -114,166 +107,165 @@ resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-14.15.0.tgz#0e27ac0bb88fe100f4f8d1605b64d5c268636a55" integrity sha512-ImAQHxmpMneJ/4S8BRFhjt1MZ3bppmpRPYYNyzeQPeFN288YKbb8TmmISQEbtfkQ1BPASvYZU5doIZOPBAqENQ== -"@azure/msal-node@^2.9.2": - version "2.14.0" - resolved "https://registry.yarnpkg.com/@azure/msal-node/-/msal-node-2.14.0.tgz#7881895d41b03d8b9b38a29550ba3bbb15f73b3c" - integrity sha512-rrfzIpG3Q1rHjVYZmHAEDidWAZZ2cgkxlIcMQ8dHebRISaZ2KCV33Q8Vs+uaV6lxweROabNxKFlR2lIKagZqYg== +"@azure/msal-node@^2.15.0": + version "2.15.0" + resolved "https://registry.yarnpkg.com/@azure/msal-node/-/msal-node-2.15.0.tgz#50bf8e692a6656027c073a75d877a8a478aafdfd" + integrity sha512-gVPW8YLz92ZeCibQH2QUw96odJoiM3k/ZPH3f2HxptozmH6+OnyyvKXo/Egg39HAM230akarQKHf0W74UHlh0Q== dependencies: "@azure/msal-common" "14.15.0" jsonwebtoken "^9.0.0" uuid "^8.3.0" -"@babel/code-frame@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" - integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== +"@babel/code-frame@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.25.9.tgz#895b6c7e04a7271a0cbfd575d2e8131751914cc7" + integrity sha512-z88xeGxnzehn2sqZ8UdGQEvYErF1odv2CftxInpSYJt6uHuPe9YjahKZITGs3l5LeI9d2ROG+obuDAoSlqbNfQ== dependencies: - "@babel/highlight" "^7.24.7" + "@babel/highlight" "^7.25.9" picocolors "^1.0.0" -"@babel/compat-data@^7.25.2": - version "7.25.4" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.4.tgz#7d2a80ce229890edcf4cc259d4d696cb4dae2fcb" - integrity sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ== +"@babel/compat-data@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.9.tgz#24b01c5db6a3ebf85661b4fb4a946a9bccc72ac8" + integrity sha512-yD+hEuJ/+wAJ4Ox2/rpNv5HIuPG82x3ZlQvYVn8iYCprdxzE7P1udpGF1jyjQVBU4dgznN+k2h103vxZ7NdPyw== "@babel/core@^7.7.5": - version "7.25.2" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.2.tgz#ed8eec275118d7613e77a352894cd12ded8eba77" - integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA== + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.9.tgz#855a4cddcec4158f3f7afadacdab2a7de8af7434" + integrity sha512-WYvQviPw+Qyib0v92AwNIrdLISTp7RfDkM7bPqBvpbnhY4wq8HvHBZREVdYDXk98C8BkOIVnHAY3yvj7AVISxQ== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.25.0" - "@babel/helper-compilation-targets" "^7.25.2" - "@babel/helper-module-transforms" "^7.25.2" - "@babel/helpers" "^7.25.0" - "@babel/parser" "^7.25.0" - "@babel/template" "^7.25.0" - "@babel/traverse" "^7.25.2" - "@babel/types" "^7.25.2" + "@babel/code-frame" "^7.25.9" + "@babel/generator" "^7.25.9" + "@babel/helper-compilation-targets" "^7.25.9" + "@babel/helper-module-transforms" "^7.25.9" + "@babel/helpers" "^7.25.9" + "@babel/parser" "^7.25.9" + "@babel/template" "^7.25.9" + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.25.0", "@babel/generator@^7.25.6": - version "7.25.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.6.tgz#0df1ad8cb32fe4d2b01d8bf437f153d19342a87c" - integrity sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw== +"@babel/generator@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.9.tgz#c7e828ebe0c2baba103b712924699c9e8a6e32f0" + integrity sha512-omlUGkr5EaoIJrhLf9CJ0TvjBRpd9+AXRG//0GEQ9THSo8wPiTlbpy1/Ow8ZTrbXpjd9FHXfbFQx32I04ht0FA== dependencies: - "@babel/types" "^7.25.6" + "@babel/types" "^7.25.9" "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^2.5.1" + jsesc "^3.0.2" -"@babel/helper-compilation-targets@^7.25.2": - version "7.25.2" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz#e1d9410a90974a3a5a66e84ff55ef62e3c02d06c" - integrity sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw== +"@babel/helper-compilation-targets@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz#55af025ce365be3cdc0c1c1e56c6af617ce88875" + integrity sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ== dependencies: - "@babel/compat-data" "^7.25.2" - "@babel/helper-validator-option" "^7.24.8" - browserslist "^4.23.1" + "@babel/compat-data" "^7.25.9" + "@babel/helper-validator-option" "^7.25.9" + browserslist "^4.24.0" lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-module-imports@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b" - integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA== - dependencies: - "@babel/traverse" "^7.24.7" - "@babel/types" "^7.24.7" - -"@babel/helper-module-transforms@^7.25.2": - version "7.25.2" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz#ee713c29768100f2776edf04d4eb23b8d27a66e6" - integrity sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ== - dependencies: - "@babel/helper-module-imports" "^7.24.7" - "@babel/helper-simple-access" "^7.24.7" - "@babel/helper-validator-identifier" "^7.24.7" - "@babel/traverse" "^7.25.2" - -"@babel/helper-simple-access@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3" - integrity sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg== - dependencies: - "@babel/traverse" "^7.24.7" - "@babel/types" "^7.24.7" - -"@babel/helper-string-parser@^7.24.8": - version "7.24.8" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" - integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== - -"@babel/helper-validator-identifier@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" - integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== - -"@babel/helper-validator-option@^7.24.8": - version "7.24.8" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d" - integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q== - -"@babel/helpers@^7.25.0": - version "7.25.6" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.6.tgz#57ee60141829ba2e102f30711ffe3afab357cc60" - integrity sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q== - dependencies: - "@babel/template" "^7.25.0" - "@babel/types" "^7.25.6" - -"@babel/highlight@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" - integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== - dependencies: - "@babel/helper-validator-identifier" "^7.24.7" +"@babel/helper-module-imports@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz#e7f8d20602ebdbf9ebbea0a0751fb0f2a4141715" + integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw== + dependencies: + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/helper-module-transforms@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.9.tgz#12e4fb2969197ef6d78ea8a2f24375ce85b425fb" + integrity sha512-TvLZY/F3+GvdRYFZFyxMvnsKi+4oJdgZzU3BoGN9Uc2d9C6zfNwJcKKhjqLAhK8i46mv93jsO74fDh3ih6rpHA== + dependencies: + "@babel/helper-module-imports" "^7.25.9" + "@babel/helper-simple-access" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@babel/traverse" "^7.25.9" + +"@babel/helper-simple-access@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.25.9.tgz#6d51783299884a2c74618d6ef0f86820ec2e7739" + integrity sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q== + dependencies: + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/helper-string-parser@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" + integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== + +"@babel/helper-validator-identifier@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" + integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== + +"@babel/helper-validator-option@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72" + integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw== + +"@babel/helpers@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.9.tgz#9e26aa6fbefdbca4f8c8a1d66dc6f1c00ddadb0a" + integrity sha512-oKWp3+usOJSzDZOucZUAMayhPz/xVjzymyDzUN8dk0Wd3RWMlGLXi07UCQ/CgQVb8LvXx3XBajJH4XGgkt7H7g== + dependencies: + "@babel/template" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/highlight@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.25.9.tgz#8141ce68fc73757946f983b343f1231f4691acc6" + integrity sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw== + dependencies: + "@babel/helper-validator-identifier" "^7.25.9" chalk "^2.4.2" js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.25.0", "@babel/parser@^7.25.6": - version "7.25.6" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.6.tgz#85660c5ef388cbbf6e3d2a694ee97a38f18afe2f" - integrity sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q== +"@babel/parser@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.9.tgz#8fcaa079ac7458facfddc5cd705cc8005e4d3817" + integrity sha512-aI3jjAAO1fh7vY/pBGsn1i9LDbRP43+asrRlkPuTXW5yHXtd1NgTEMudbBoDDxrf1daEEfPJqR+JBMakzrR4Dg== dependencies: - "@babel/types" "^7.25.6" + "@babel/types" "^7.25.9" -"@babel/template@^7.25.0": - version "7.25.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.0.tgz#e733dc3134b4fede528c15bc95e89cb98c52592a" - integrity sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q== +"@babel/template@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.9.tgz#ecb62d81a8a6f5dc5fe8abfc3901fc52ddf15016" + integrity sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg== dependencies: - "@babel/code-frame" "^7.24.7" - "@babel/parser" "^7.25.0" - "@babel/types" "^7.25.0" + "@babel/code-frame" "^7.25.9" + "@babel/parser" "^7.25.9" + "@babel/types" "^7.25.9" -"@babel/traverse@^7.24.7", "@babel/traverse@^7.25.2": - version "7.25.6" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.6.tgz#04fad980e444f182ecf1520504941940a90fea41" - integrity sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ== +"@babel/traverse@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.9.tgz#a50f8fe49e7f69f53de5bea7e413cd35c5e13c84" + integrity sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw== dependencies: - "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.25.6" - "@babel/parser" "^7.25.6" - "@babel/template" "^7.25.0" - "@babel/types" "^7.25.6" + "@babel/code-frame" "^7.25.9" + "@babel/generator" "^7.25.9" + "@babel/parser" "^7.25.9" + "@babel/template" "^7.25.9" + "@babel/types" "^7.25.9" debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.6": - version "7.25.6" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.6.tgz#893942ddb858f32ae7a004ec9d3a76b3463ef8e6" - integrity sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw== +"@babel/types@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.9.tgz#620f35ea1f4233df529ec9a2668d2db26574deee" + integrity sha512-OwS2CM5KocvQ/k7dFJa8i5bNGJP0hXWfVCfDkqRFP1IreH1JDC7wG6eCYCi0+McbfT8OR/kNqsI0UU0xP9H6PQ== dependencies: - "@babel/helper-string-parser" "^7.24.8" - "@babel/helper-validator-identifier" "^7.24.7" - to-fast-properties "^2.0.0" + "@babel/helper-string-parser" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" "@cspotcode/source-map-support@^0.8.0": version "0.8.1" @@ -593,9 +585,9 @@ integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== "@types/chai@^4.3.5": - version "4.3.19" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.19.tgz#14519f437361d41e84102ed3fbc922ddace3e228" - integrity sha512-2hHHvQBVE2FiSK4eN0Br6snX9MtolHaTo/batnLjlGRhoQzlCL61iVpxoqO7SfFyOw+P/pwv+0zNHzKoGWz9Cw== + version "4.3.20" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.20.tgz#cb291577ed342ca92600430841a00329ba05cecc" + integrity sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ== "@types/cross-spawn@^6.0.2": version "6.0.6" @@ -623,21 +615,21 @@ integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== "@types/mocha@^10.0.1": - version "10.0.8" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.8.tgz#a7eff5816e070c3b4d803f1d3cd780c4e42934a1" - integrity sha512-HfMcUmy9hTMJh66VNcmeC9iVErIZJli2bszuXc6julh5YGuRb/W5OnkHjwLNYdFlMis0sY3If5SEAp+PktdJjw== + version "10.0.9" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.9.tgz#101e9da88d2c02e5ac8952982c23b224524d662a" + integrity sha512-sicdRoWtYevwxjOHNMPTl3vSfJM6oyW8o1wXeI7uww6b6xHg8eBznQDNSGBCDJmsE8UMxP05JgZRtsKbTqt//Q== "@types/node@*": - version "22.6.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.6.1.tgz#e531a45f4d78f14a8468cb9cdc29dc9602afc7ac" - integrity sha512-V48tCfcKb/e6cVUigLAaJDAILdMP0fUW6BidkPK4GpGjXcfbnoHasCZDwz3N3yVt5we2RHm4XTQCpv0KJz9zqw== + version "22.7.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.9.tgz#2bf2797b5e84702d8262ea2cf843c3c3c880d0e9" + integrity sha512-jrTfRC7FM6nChvU7X2KqcrgquofrWLFDeYC1hKfwNWomVvrn7JIksqf344WN2X/y8xrgqBd2dJATZV4GbatBfg== dependencies: undici-types "~6.19.2" "@types/node@16.x": - version "16.18.108" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.108.tgz#b794e2b2a85b4c12935ea7d0f18641be68b352f9" - integrity sha512-fj42LD82fSv6yN9C6Q4dzS+hujHj+pTv0IpRR3kI20fnYeS0ytBpjFO9OjmDowSPPt4lNKN46JLaKbCyP+BW2A== + version "16.18.115" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.115.tgz#0bb385c4b1a1a996d6bf9d79e5ae786ce03cae51" + integrity sha512-NF5ajYn+dq0tRfswdyp8Df75h7D9z+L8TCIwrXoh46ZLK6KZVXkRhf/luXaZytvm/keUo9vU4m1Bg39St91a5w== "@types/semver@^7.3.12": version "7.5.8" @@ -657,9 +649,9 @@ integrity sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ== "@types/vscode@^1.74.0": - version "1.93.0" - resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.93.0.tgz#1cd7573e0272aef9c357bafc635b6177c154013e" - integrity sha512-kUK6jAHSR5zY8ps42xuW89NLcBpw1kOabah7yv38J8MyiYuOHxLQBi0e7zeXbQgVefDy/mZZetqEFC+Fl5eIEQ== + version "1.94.0" + resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.94.0.tgz#ccd2111b6ecaba6ad4da19c2d524828fa73ae250" + integrity sha512-UyQOIUT0pb14XSqJskYnRwD2aG0QrPVefIfrW1djR+/J4KeFQ0i1+hjZoaAmeNf3Z2jleK+R2hv+EboG/m8ruw== "@typescript-eslint/eslint-plugin@^5.45.0": version "5.62.0" @@ -866,9 +858,9 @@ acorn-walk@^8.1.1: acorn "^8.11.0" acorn@^8.11.0, acorn@^8.4.1, acorn@^8.9.0: - version "8.12.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" - integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + version "8.13.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.13.0.tgz#2a30d670818ad16ddd6a35d3842dacec9e5d7ca3" + integrity sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w== agent-base@^7.0.2, agent-base@^7.1.0: version "7.1.1" @@ -1049,15 +1041,15 @@ browser-stdout@^1.3.1: resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== -browserslist@^4.23.1: - version "4.23.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800" - integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA== +browserslist@^4.24.0: + version "4.24.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.2.tgz#f5845bc91069dbd55ee89faf9822e1d885d16580" + integrity sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg== dependencies: - caniuse-lite "^1.0.30001646" - electron-to-chromium "^1.5.4" + caniuse-lite "^1.0.30001669" + electron-to-chromium "^1.5.41" node-releases "^2.0.18" - update-browserslist-db "^1.1.0" + update-browserslist-db "^1.1.1" buffer-crc32@~0.2.3: version "0.2.13" @@ -1121,10 +1113,10 @@ camelcase@^6.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001646: - version "1.0.30001663" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001663.tgz#1529a723505e429fdfd49532e9fc42273ba7fed7" - integrity sha512-o9C3X27GLKbLeTYZ6HBOLU1tsAcBZsLis28wrVzddShCS16RujjHp9GDHKZqrB3meE0YjhawvMFsGb/igqiPzA== +caniuse-lite@^1.0.30001669: + version "1.0.30001669" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz#fda8f1d29a8bfdc42de0c170d7f34a9cf19ed7a3" + integrity sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w== chai@^4.3.7: version "4.5.0" @@ -1491,10 +1483,10 @@ ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer "^5.0.1" -electron-to-chromium@^1.5.4: - version "1.5.28" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.28.tgz#aee074e202c6ee8a0030a9c2ef0b3fe9f967d576" - integrity sha512-VufdJl+rzaKZoYVUijN13QcXVF5dWPZANeFTLNy+OSpHdDL5ynXTF35+60RSBbaQYB1ae723lQXHCrf4pyLsMw== +electron-to-chromium@^1.5.41: + version "1.5.45" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.45.tgz#fa592ce6a88b44d23acbc7453a2feab98996e6c9" + integrity sha512-vOzZS6uZwhhbkZbcRyiy99Wg+pYFV5hk+5YaECvx0+Z31NR3Tt5zS6dze2OepT6PCTzVzT0dIJItti+uAW5zmw== emoji-regex@^10.2.1: version "10.4.0" @@ -1521,7 +1513,7 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" -entities@^4.2.0, entities@^4.4.0, entities@^4.5.0: +entities@^4.2.0, entities@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== @@ -1578,7 +1570,7 @@ esbuild@^0.23.0: "@esbuild/win32-ia32" "0.23.1" "@esbuild/win32-x64" "0.23.1" -escalade@^3.1.1, escalade@^3.1.2: +escalade@^3.1.1, escalade@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== @@ -1831,9 +1823,9 @@ foreground-child@^2.0.0: signal-exit "^3.0.2" form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + version "4.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.1.tgz#ba1076daaaa5bfd7e99c1a6cb02aa0a5cff90d48" + integrity sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" @@ -2311,10 +2303,10 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +jsesc@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" + integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== json-buffer@3.0.1: version "3.0.1" @@ -2721,9 +2713,9 @@ nise@^5.1.4: path-to-regexp "^6.2.1" node-abi@^3.3.0: - version "3.68.0" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.68.0.tgz#8f37fb02ecf4f43ebe694090dcb52e0c4cc4ba25" - integrity sha512-7vbj10trelExNjFSBm5kTvZXXa7pZyKWx9RCKIyqe6I9Ev3IzGpQoqBP3a+cOdxY+pWj6VkP28n/2wWysBHD/A== + version "3.71.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.71.0.tgz#52d84bbcd8575efb71468fbaa1f9a49b2c242038" + integrity sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw== dependencies: semver "^7.3.5" @@ -2927,11 +2919,11 @@ parse-semver@^1.1.1: semver "^5.1.0" parse5-htmlparser2-tree-adapter@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz#23c2cc233bcf09bb7beba8b8a69d46b08c62c2f1" - integrity sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g== + version "7.1.0" + resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz#b5a806548ed893a43e24ccb42fbb78069311e81b" + integrity sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g== dependencies: - domhandler "^5.0.2" + domhandler "^5.0.3" parse5 "^7.0.0" parse5-parser-stream@^7.1.2: @@ -2942,11 +2934,11 @@ parse5-parser-stream@^7.1.2: parse5 "^7.0.0" parse5@^7.0.0, parse5@^7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" - integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== + version "7.2.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.2.0.tgz#8a0591ce9b7c5e2027173ab737d4d3fc3d826fab" + integrity sha512-ZkDsAOcxsUMZ4Lz5fVciOehNcJ+Gb8gTzcA4yl3wnc273BAybYWrQ+Ks/OjCjSEpjvQkDSeZbybK9qj2VHHdGA== dependencies: - entities "^4.4.0" + entities "^4.5.0" path-exists@^4.0.0: version "4.0.0" @@ -2988,10 +2980,10 @@ pend@~1.2.0: resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== -picocolors@^1.0.0, picocolors@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" - integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== +picocolors@^1.0.0, picocolors@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" @@ -3473,11 +3465,6 @@ tmp@^0.2.1: resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -3510,9 +3497,9 @@ tslib@^1.8.1: integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== tslib@^2.2.0, tslib@^2.6.2: - version "2.7.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" - integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== + version "2.8.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.0.tgz#d124c86c3c05a40a91e6fdea4021bd31d377971b" + integrity sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA== tsutils@^3.21.0: version "3.21.0" @@ -3597,17 +3584,17 @@ undici-types@~6.19.2: integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== undici@^6.19.5: - version "6.19.8" - resolved "https://registry.yarnpkg.com/undici/-/undici-6.19.8.tgz#002d7c8a28f8cc3a44ff33c3d4be4d85e15d40e1" - integrity sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g== + version "6.20.1" + resolved "https://registry.yarnpkg.com/undici/-/undici-6.20.1.tgz#fbb87b1e2b69d963ff2d5410a40ffb4c9e81b621" + integrity sha512-AjQF1QsmqfJys+LXfGTNum+qw4S88CojRInG/6t31W/1fk6G59s92bnAvGz5Cmur+kQv2SURXEvvudLmbrE8QA== -update-browserslist-db@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" - integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== +update-browserslist-db@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" + integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== dependencies: - escalade "^3.1.2" - picocolors "^1.0.1" + escalade "^3.2.0" + picocolors "^1.1.0" uri-js@^4.2.2: version "4.4.1"