From 0b497adb52b93d33b50ffacdf639a7f4475512a8 Mon Sep 17 00:00:00 2001 From: Namrata Gupta Date: Tue, 3 Feb 2026 16:06:46 +0530 Subject: [PATCH 1/2] Adding changes for ignore object in config yml --- package-lock.json | 63 ++------- packages/code-analyzer-core/package.json | 4 +- .../code-analyzer-core/src/code-analyzer.ts | 87 ++++++++++-- packages/code-analyzer-core/src/config.ts | 39 +++++- packages/code-analyzer-core/src/index.ts | 1 + packages/code-analyzer-core/src/messages.ts | 16 +++ .../test/code-analyzer.test.ts | 125 ++++++++++++++++++ .../code-analyzer-core/test/config.test.ts | 88 +++++++++++- 8 files changed, 357 insertions(+), 66 deletions(-) diff --git a/package-lock.json b/package-lock.json index ab8afa25..57b94e1e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -58,7 +58,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.4.tgz", "integrity": "sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==", "license": "MIT", - "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", @@ -98,7 +97,6 @@ "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.27.5.tgz", "integrity": "sha512-HLkYQfRICudzcOtjGwkPvGc5nF1b4ljLZh1IRDj50lRZ718NAKVgQpIAUX8bfg6u/yuSKY3L7E0YzIV+OxrB8Q==", "license": "MIT", - "peer": true, "dependencies": { "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", @@ -656,7 +654,6 @@ "version": "1.7.1", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -668,7 +665,6 @@ "version": "1.7.1", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -679,7 +675,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -1697,7 +1692,6 @@ "version": "0.2.12", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -1754,7 +1748,6 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, "license": "MIT", "optional": true, "engines": { @@ -1910,7 +1903,6 @@ "resolved": "https://registry.npmjs.org/@salesforce/eslint-plugin-lightning/-/eslint-plugin-lightning-1.0.1.tgz", "integrity": "sha512-oyUVSNUA0WkkQr3BRtcAYhYotzIpqZtfMpUVMhROPN8YjDGu6CzCoC3/1i4ySIevgmH3J83KypwoqvRfoQf8Ww==", "license": "MIT", - "peer": true, "peerDependencies": { "eslint": "^7 || ^8" } @@ -1952,7 +1944,6 @@ "version": "0.10.1", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -2078,6 +2069,13 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "license": "MIT" }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "20.19.25", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.25.tgz", @@ -2139,7 +2137,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.53.0.tgz", "integrity": "sha512-eEXsVvLPu8Z4PkFibtuFJLJOTAV/nPdgtSjkGoPpddpFk3/ym2oy97jynY6ic2m6+nc5M8SE1e9v/mHKsulcJg==", "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.53.0", @@ -2168,7 +2165,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.53.0.tgz", "integrity": "sha512-npiaib8XzbjtzS2N4HlqPvlpxpmZ14FjSJrteZpPxGUaYPlvhzlzUZ4mZyABo0EFrOWnvyd0Xxroq//hKhtAWg==", "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.53.0", "@typescript-eslint/types": "8.53.0", @@ -2371,7 +2367,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2385,7 +2380,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2399,7 +2393,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2413,7 +2406,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2427,7 +2419,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2441,7 +2432,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2455,7 +2445,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2469,7 +2458,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2483,7 +2471,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2497,7 +2484,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2511,7 +2497,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2525,7 +2510,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2539,7 +2523,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2553,7 +2536,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2567,7 +2549,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2581,7 +2562,6 @@ "cpu": [ "wasm32" ], - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -2598,7 +2578,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2612,7 +2591,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2626,7 +2604,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2638,7 +2615,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3149,7 +3125,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", @@ -3974,7 +3949,6 @@ "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -4076,7 +4050,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz", "integrity": "sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==", "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.8", @@ -4161,7 +4134,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.12.1.tgz", "integrity": "sha512-Rxo7r4jSANMBkXLICJKS0gjacgyopfNAsoS0e3R9AHnjoKuQOaaPfmsDJPi8UWwygI099OV/K/JhpYRVkxD4AA==", "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/utils": "^8.0.0" }, @@ -4896,7 +4868,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -5965,7 +5936,6 @@ "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/core": "30.2.0", "@jest/types": "30.2.0", @@ -8594,7 +8564,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -8852,7 +8821,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9404,7 +9372,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -9430,6 +9397,7 @@ "@types/node": "^20.0.0", "csv-stringify": "^6.6.0", "js-yaml": "^4.1.1", + "minimatch": "^9.0.0", "semver": "^7.7.3", "xmlbuilder": "^15.1.1" }, @@ -9437,6 +9405,7 @@ "@eslint/js": "^9.39.2", "@types/jest": "^30.0.0", "@types/js-yaml": "^4.0.9", + "@types/minimatch": "^5.1.2", "@types/sarif": "^2.1.7", "@types/semver": "^7.7.1", "cross-env": "^10.1.0", @@ -9492,7 +9461,6 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -9671,7 +9639,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -9932,7 +9899,7 @@ }, "packages/code-analyzer-eslint-engine": { "name": "@salesforce/code-analyzer-eslint-engine", - "version": "0.39.0", + "version": "0.40.0-SNAPSHOT", "license": "BSD-3-Clause", "dependencies": { "@babel/preset-react": "^7.28.5", @@ -10016,7 +9983,6 @@ "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.25.9.tgz", "integrity": "sha512-5UXfgpK0j0Xr/xIdgdLEhOFxaDZ0bRPWJJchRpqOSur/3rZoPbqqki5mm0p4NE2cs28krBEiSM2MB7//afRSQQ==", "license": "MIT", - "peer": true, "dependencies": { "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", @@ -10207,7 +10173,6 @@ "resolved": "https://registry.npmjs.org/@salesforce/eslint-plugin-lightning/-/eslint-plugin-lightning-2.0.0.tgz", "integrity": "sha512-lC3GL2j6B2wAGeTFWT0h47BFg+0R7naqqlQW+ANvNSaIC/qEB+tNSRcdAZ8DRTojsI3GRdpgq3FTB1llbrFBng==", "license": "MIT", - "peer": true, "engines": { "node": ">=10.0.0" }, @@ -10232,7 +10197,6 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -10292,7 +10256,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -10612,7 +10575,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.30.1.tgz", "integrity": "sha512-v+VWphxMjn+1t48/jO4t950D6KR8JaJuNXzi33Ve6P8sEmPr5k6CEXjdGwT6+LodVnEa91EQCtwjWNUCPweo+Q==", "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.30.1", @@ -10688,7 +10650,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.30.1.tgz", "integrity": "sha512-H+vqmWwT5xoNrXqWs/fesmssOW70gxFlgcMlYcBaWNPIEWDgLa4W9nkSPmhuOgLnXq9QYgkZ31fhDyLhleCsAg==", "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.30.1", "@typescript-eslint/types": "8.30.1", @@ -10798,7 +10759,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.10.0.tgz", "integrity": "sha512-hyMWUxkBH99HpXT3p8hc7REbEZK3D+nk8vHXGgpB+XXsi0gO4PxMSP+pjfUzb67GnV9yawV9a53eUmcde1CCZA==", "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/utils": "^6.0.0 || ^7.0.0 || ^8.0.0" }, @@ -10833,7 +10793,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -11142,7 +11101,7 @@ }, "packages/code-analyzer-pmd-engine": { "name": "@salesforce/code-analyzer-pmd-engine", - "version": "0.35.0", + "version": "0.36.0-SNAPSHOT", "license": "BSD-3-Clause", "dependencies": { "@salesforce/code-analyzer-engine-api": "0.34.0", diff --git a/packages/code-analyzer-core/package.json b/packages/code-analyzer-core/package.json index 90e11207..21e981ea 100644 --- a/packages/code-analyzer-core/package.json +++ b/packages/code-analyzer-core/package.json @@ -1,7 +1,7 @@ { "name": "@salesforce/code-analyzer-core", "description": "Core Package for the Salesforce Code Analyzer", - "version": "0.42.0", + "version": "0.43.0-SNAPSHOT", "author": "The Salesforce Code Analyzer Team", "license": "BSD-3-Clause", "homepage": "https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/overview", @@ -20,6 +20,7 @@ "@types/node": "^20.0.0", "csv-stringify": "^6.6.0", "js-yaml": "^4.1.1", + "minimatch": "^9.0.0", "semver": "^7.7.3", "xmlbuilder": "^15.1.1" }, @@ -27,6 +28,7 @@ "@eslint/js": "^9.39.2", "@types/js-yaml": "^4.0.9", "@types/jest": "^30.0.0", + "@types/minimatch": "^5.1.2", "@types/sarif": "^2.1.7", "@types/semver": "^7.7.1", "cross-env": "^10.1.0", diff --git a/packages/code-analyzer-core/src/code-analyzer.ts b/packages/code-analyzer-core/src/code-analyzer.ts index ca189122..a0ed824e 100644 --- a/packages/code-analyzer-core/src/code-analyzer.ts +++ b/packages/code-analyzer-core/src/code-analyzer.ts @@ -24,7 +24,7 @@ import * as engApi from "@salesforce/code-analyzer-engine-api" import {Clock, RealClock} from '@salesforce/code-analyzer-engine-api/utils'; import {Selector, toSelector} from "./selectors"; import {EventEmitter} from "node:events"; -import {CodeAnalyzerConfig, ConfigDescription, EngineOverrides, FIELDS, RuleOverride} from "./config"; +import {CodeAnalyzerConfig, ConfigDescription, EngineOverrides, FIELDS, Ignores, RuleOverride} from "./config"; import { EngineProgressAggregator, FileSystem, @@ -36,6 +36,7 @@ import { } from "./utils"; import fs from "node:fs"; import path from 'node:path'; +import {Minimatch} from 'minimatch'; /** * Interface for workspaces @@ -157,6 +158,8 @@ export class CodeAnalyzer { * analyze the few files that you are targeting. If a targets array is not specified, then the entire list of * workspaces files and folders will be targeted. * + * Files matching patterns specified in the ignores.files configuration will be excluded from the workspace. + * * @param workspaceFilesAndFolders string array of files and/or folders to include in the workspace * @param targets optional string array of files and/or folders */ @@ -174,7 +177,11 @@ export class CodeAnalyzer { validatedTargets = (await Promise.all(targetPromises)).flat(); } - const workspace: Workspace = new WorkspaceImpl(workspaceId, validatedWorkspaceFilesAndFolders, validatedTargets); + // Get ignore patterns from config + const ignores: Ignores = this.config.getIgnores(); + const ignorePatterns: string[] = ignores.files; + + const workspace: Workspace = new WorkspaceImpl(workspaceId, validatedWorkspaceFilesAndFolders, validatedTargets, ignorePatterns); // It appears that each of the engines is calling these methods all at the same time and so if we had N engines // each creating N promises, the cache hasn't been populated, and so we are doing the work N times. If we @@ -646,8 +653,13 @@ export class CodeAnalyzer { */ class WorkspaceImpl implements Workspace { private readonly delegate: engApi.Workspace; - constructor(workspaceId: string, absWorkspaceFilesAndFolders: string[], absTargets?: string[]) { + private readonly ignorePatterns: string[]; + private cachedFilteredWorkspaceFiles?: string[]; + private cachedFilteredTargetedFiles?: string[]; + + constructor(workspaceId: string, absWorkspaceFilesAndFolders: string[], absTargets?: string[], ignorePatterns: string[] = []) { this.delegate = new engApi.Workspace(workspaceId, absWorkspaceFilesAndFolders, absTargets); + this.ignorePatterns = ignorePatterns; } getWorkspaceId(): string { @@ -662,16 +674,75 @@ class WorkspaceImpl implements Workspace { return this.delegate.getRawTargets(); } - getWorkspaceFiles(): Promise { - return this.delegate.getWorkspaceFiles(); + async getWorkspaceFiles(): Promise { + if (!this.cachedFilteredWorkspaceFiles) { + const files = await this.delegate.getWorkspaceFiles(); + this.cachedFilteredWorkspaceFiles = this.filterIgnoredFiles(files); + } + return this.cachedFilteredWorkspaceFiles; + } + + async getTargetedFiles(): Promise { + if (!this.cachedFilteredTargetedFiles) { + const files = await this.delegate.getTargetedFiles(); + this.cachedFilteredTargetedFiles = this.filterIgnoredFiles(files); + } + return this.cachedFilteredTargetedFiles; } - getTargetedFiles(): Promise { - return this.delegate.getTargetedFiles(); + /** + * Filters out files that match any of the ignore patterns. + * Patterns are matched against the file path relative to the workspace root, + * or the full path if no workspace root exists. + */ + private filterIgnoredFiles(files: string[]): string[] { + if (this.ignorePatterns.length === 0) { + return files; + } + + // Pre-compile the patterns for performance + const matchers = this.ignorePatterns.map(pattern => new Minimatch(pattern, { dot: true, matchBase: true })); + + const workspaceRoot = this.delegate.getWorkspaceRoot(); + return files.filter(file => { + // Get the path to match against - use relative path if workspace root exists + const pathToMatch = workspaceRoot ? file.slice(workspaceRoot.length + 1) : file; + + // Check if the file matches any ignore pattern + const shouldIgnore = matchers.some(matcher => matcher.match(pathToMatch)); + return !shouldIgnore; + }); } _toEngApiWorkspace(): engApi.Workspace { - return this.delegate; + // Return a workspace that applies filtering while preserving original raw values. + // We use inheritance here because: + // 1. getRawFilesAndFolders() must return original folders (not expanded/filtered files) + // 2. getWorkspaceFiles() must return filtered files + // Composition alone can't preserve both semantics. + return new FilteredEngApiWorkspace(this.delegate, this); + } +} + +/** + * Wrapper around engApi.Workspace that returns filtered file lists while preserving + * original raw files/folders. This ensures engines receive filtered files but can + * still access the original workspace structure if needed. + */ +class FilteredEngApiWorkspace extends engApi.Workspace { + private readonly workspaceImpl: WorkspaceImpl; + + constructor(delegate: engApi.Workspace, workspaceImpl: WorkspaceImpl) { + super(delegate.getWorkspaceId(), delegate.getRawFilesAndFolders(), delegate.getRawTargets()); + this.workspaceImpl = workspaceImpl; + } + + override async getWorkspaceFiles(): Promise { + return this.workspaceImpl.getWorkspaceFiles(); + } + + override async getTargetedFiles(): Promise { + return this.workspaceImpl.getTargetedFiles(); } } diff --git a/packages/code-analyzer-core/src/config.ts b/packages/code-analyzer-core/src/config.ts index a73834f2..ac4b93e2 100644 --- a/packages/code-analyzer-core/src/config.ts +++ b/packages/code-analyzer-core/src/config.ts @@ -20,7 +20,9 @@ export const FIELDS = { ENGINES: 'engines', SEVERITY: 'severity', TAGS: 'tags', - DISABLE_ENGINE: 'disable_engine' + DISABLE_ENGINE: 'disable_engine', + IGNORES: 'ignores', + FILES: 'files' } as const; /** @@ -37,12 +39,20 @@ export type RuleOverride = { tags?: string[] } +/** + * Object containing the user specified ignores configuration for files to skip during scanning + */ +export type Ignores = { + files: string[] +} + type TopLevelConfig = { config_root: string log_folder: string log_level: LogLevel rules: Record engines: Record + ignores: Ignores root_working_folder: string, // INTERNAL USE ONLY preserve_all_working_folders: boolean // INTERNAL USE ONLY custom_engine_plugin_modules: string[] // INTERNAL USE ONLY @@ -55,6 +65,7 @@ export const DEFAULT_CONFIG: TopLevelConfig = { log_level: LogLevel.Debug, rules: {}, engines: {}, + ignores: { files: [] }, root_working_folder: os.tmpdir(), // INTERNAL USE ONLY preserve_all_working_folders: false, // INTERNAL USE ONLY custom_engine_plugin_modules: [], // INTERNAL USE ONLY @@ -143,7 +154,7 @@ export class CodeAnalyzerConfig { validateAbsoluteFolder(rawConfig.config_root, FIELDS.CONFIG_ROOT); const configExtractor: engApi.ConfigValueExtractor = new engApi.ConfigValueExtractor(rawConfig, '', configRoot); configExtractor.addKeysThatBypassValidation([FIELDS.CUSTOM_ENGINE_PLUGIN_MODULES, FIELDS.PRESERVE_ALL_WORKING_FOLDERS, FIELDS.ROOT_WORKING_FOLDER]); // Hidden fields bypass validation - configExtractor.validateContainsOnlySpecifiedKeys([FIELDS.CONFIG_ROOT, FIELDS.LOG_FOLDER, FIELDS.LOG_LEVEL ,FIELDS.RULES, FIELDS.ENGINES]); + configExtractor.validateContainsOnlySpecifiedKeys([FIELDS.CONFIG_ROOT, FIELDS.LOG_FOLDER, FIELDS.LOG_LEVEL, FIELDS.RULES, FIELDS.ENGINES, FIELDS.IGNORES]); const config: TopLevelConfig = { config_root: configRoot, log_folder: configExtractor.extractFolder(FIELDS.LOG_FOLDER, DEFAULT_CONFIG.log_folder)!, @@ -154,7 +165,8 @@ export class CodeAnalyzerConfig { root_working_folder: configExtractor.extractFolder(FIELDS.ROOT_WORKING_FOLDER, DEFAULT_CONFIG.root_working_folder)!, preserve_all_working_folders: configExtractor.extractBoolean(FIELDS.PRESERVE_ALL_WORKING_FOLDERS, DEFAULT_CONFIG.preserve_all_working_folders)!, rules: extractRulesValue(configExtractor), - engines: extractEnginesValue(configExtractor) + engines: extractEnginesValue(configExtractor), + ignores: extractIgnoresValue(configExtractor) } return new CodeAnalyzerConfig(config); } @@ -195,6 +207,12 @@ export class CodeAnalyzerConfig { valueType: 'object', defaultValue: {}, wasSuppliedByUser: !deepEquals(this.config.engines, DEFAULT_CONFIG.engines) + }, + ignores: { + descriptionText: getMessage('ConfigFieldDescription_ignores'), + valueType: 'object', + defaultValue: { files: [] }, + wasSuppliedByUser: !deepEquals(this.config.ignores, DEFAULT_CONFIG.ignores) } } }; @@ -276,6 +294,14 @@ export class CodeAnalyzerConfig { public getEngineOverridesFor(engineName: string): EngineOverrides { return engApi.getValueUsingCaseInsensitiveKey(this.config.engines, engineName) as EngineOverrides || {}; } + + /** + * Returns a {@link Ignores} instance containing the user specified file patterns to ignore during scanning. + * The patterns can be file paths, folder paths, or glob patterns. + */ + public getIgnores(): Ignores { + return this.config.ignores; + } } function extractLogLevel(configExtractor: engApi.ConfigValueExtractor): LogLevel { @@ -322,6 +348,13 @@ function extractEnginesValue(configExtractor: engApi.ConfigValueExtractor): Reco return enginesExtractor.getObject() as Record; } +function extractIgnoresValue(configExtractor: engApi.ConfigValueExtractor): Ignores { + const ignoresExtractor: engApi.ConfigValueExtractor = configExtractor.extractObjectAsExtractor(FIELDS.IGNORES, DEFAULT_CONFIG.ignores); + ignoresExtractor.validateContainsOnlySpecifiedKeys([FIELDS.FILES]); + const files: string[] = ignoresExtractor.extractArray(FIELDS.FILES, engApi.ValueValidator.validateString, DEFAULT_CONFIG.ignores.files) || []; + return { files }; +} + function parseAndValidate(parseFcn: () => unknown): object { let data; try { diff --git a/packages/code-analyzer-core/src/index.ts b/packages/code-analyzer-core/src/index.ts index f1d53597..d45dec3b 100644 --- a/packages/code-analyzer-core/src/index.ts +++ b/packages/code-analyzer-core/src/index.ts @@ -6,6 +6,7 @@ export type { ConfigDescription, ConfigFieldDescription, EngineOverrides, + Ignores, RuleOverrides, RuleOverride } from "./config" diff --git a/packages/code-analyzer-core/src/messages.ts b/packages/code-analyzer-core/src/messages.ts index e16c4091..2cdf1311 100644 --- a/packages/code-analyzer-core/src/messages.ts +++ b/packages/code-analyzer-core/src/messages.ts @@ -47,6 +47,22 @@ const MESSAGE_CATALOG : MessageCatalog = { ` {property_name} is the name of a property that you would like to override.\n` + `Each engine may have its own set of properties available to help customize that particular engine's behavior.`, + ConfigFieldDescription_ignores: + `Configuration for ignoring files during scanning. Contains the following field:\n` + + ` 'files' - [Optional] An array of file paths, folder paths, or glob patterns specifying which files to skip during analysis.\n` + + ` Patterns support standard glob syntax:\n` + + ` * matches any characters within a single directory level\n` + + ` ** matches any characters across multiple directory levels\n` + + ` ? matches exactly one character\n` + + `---- [Example usage]: ---------------------\n` + + `ignores:\n` + + ` files:\n` + + ` - "src/*.cls" # All .cls files directly in src/\n` + + ` - "test/*/data.json" # data.json in any immediate subdirectory of test/\n` + + ` - "**/*.test.js" # All .test.js files anywhere\n` + + ` - "**/node_modules/**" # Anything inside any node_modules folder\n` + + `-------------------------------------------`, + GenericEngineConfigOverview: `%s ENGINE CONFIGURATION`, diff --git a/packages/code-analyzer-core/test/code-analyzer.test.ts b/packages/code-analyzer-core/test/code-analyzer.test.ts index 37feeb29..ca8a5711 100644 --- a/packages/code-analyzer-core/test/code-analyzer.test.ts +++ b/packages/code-analyzer-core/test/code-analyzer.test.ts @@ -179,6 +179,131 @@ describe("Tests for the createWorkspace method", () => { }); }); +describe("Tests for ignores configuration in createWorkspace", () => { + it("When ignores.files contains glob patterns, then matching files are excluded from workspace files", async () => { + const config = CodeAnalyzerConfig.fromObject({ + ignores: { + files: ["**/*.cls"] + } + }); + const codeAnalyzerWithIgnores = new CodeAnalyzer(config, new FakeFileSystem()); + + const workspace: Workspace = await codeAnalyzerWithIgnores.createWorkspace([SAMPLE_WORKSPACE_FOLDER]); + + const workspaceFiles = await workspace.getWorkspaceFiles(); + // All .cls files should be excluded + expect(workspaceFiles).not.toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'someFile.cls')); + expect(workspaceFiles).not.toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'sub1', 'sub3', 'someFileInSub3.cls')); + // Non-.cls files should still be included + expect(workspaceFiles).toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'sub1', 'someFileInSub1.txt')); + expect(workspaceFiles).toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'folderWithExt.cls', 'placeholder.txt')); + }); + + it("When ignores.files contains glob patterns, then matching files are excluded from targeted files", async () => { + const config = CodeAnalyzerConfig.fromObject({ + ignores: { + files: ["**/*.txt"] + } + }); + const codeAnalyzerWithIgnores = new CodeAnalyzer(config, new FakeFileSystem()); + + const workspace: Workspace = await codeAnalyzerWithIgnores.createWorkspace([SAMPLE_WORKSPACE_FOLDER]); + + const targetedFiles = await workspace.getTargetedFiles(); + // All .txt files should be excluded + expect(targetedFiles).not.toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'sub1', 'someFileInSub1.txt')); + expect(targetedFiles).not.toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'sub1', 'sub2', 'someFile1InSub2.txt')); + expect(targetedFiles).not.toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'folderWithExt.cls', 'placeholder.txt')); + // .cls files should still be included + expect(targetedFiles).toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'someFile.cls')); + expect(targetedFiles).toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'sub1', 'sub3', 'someFileInSub3.cls')); + }); + + it("When ignores.files contains specific file patterns, then only those files are excluded", async () => { + const config = CodeAnalyzerConfig.fromObject({ + ignores: { + files: ["someFile.cls"] + } + }); + const codeAnalyzerWithIgnores = new CodeAnalyzer(config, new FakeFileSystem()); + + const workspace: Workspace = await codeAnalyzerWithIgnores.createWorkspace([SAMPLE_WORKSPACE_FOLDER]); + + const workspaceFiles = await workspace.getWorkspaceFiles(); + expect(workspaceFiles).not.toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'someFile.cls')); + // Other .cls files should still be included since pattern doesn't have ** + expect(workspaceFiles).toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'sub1', 'sub3', 'someFileInSub3.cls')); + }); + + it("When ignores.files contains folder patterns, then files in matching folders are excluded", async () => { + const config = CodeAnalyzerConfig.fromObject({ + ignores: { + files: ["sub1/sub2/**"] + } + }); + const codeAnalyzerWithIgnores = new CodeAnalyzer(config, new FakeFileSystem()); + + const workspace: Workspace = await codeAnalyzerWithIgnores.createWorkspace([SAMPLE_WORKSPACE_FOLDER]); + + const workspaceFiles = await workspace.getWorkspaceFiles(); + // Files in sub2 folder should be excluded + expect(workspaceFiles).not.toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'sub1', 'sub2', 'someFile1InSub2.txt')); + expect(workspaceFiles).not.toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'sub1', 'sub2', 'someFile2InSub2.txt')); + // Files in other folders should still be included + expect(workspaceFiles).toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'sub1', 'someFileInSub1.txt')); + expect(workspaceFiles).toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'sub1', 'sub3', 'someFileInSub3.cls')); + }); + + it("When ignores.files contains multiple patterns, then all matching files are excluded", async () => { + const config = CodeAnalyzerConfig.fromObject({ + ignores: { + files: ["**/*.cls", "**/*InSub2*"] + } + }); + const codeAnalyzerWithIgnores = new CodeAnalyzer(config, new FakeFileSystem()); + + const workspace: Workspace = await codeAnalyzerWithIgnores.createWorkspace([SAMPLE_WORKSPACE_FOLDER]); + + const workspaceFiles = await workspace.getWorkspaceFiles(); + // All .cls files should be excluded + expect(workspaceFiles).not.toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'someFile.cls')); + expect(workspaceFiles).not.toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'sub1', 'sub3', 'someFileInSub3.cls')); + // Files matching *InSub2* should be excluded + expect(workspaceFiles).not.toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'sub1', 'sub2', 'someFile1InSub2.txt')); + expect(workspaceFiles).not.toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'sub1', 'sub2', 'someFile2InSub2.txt')); + // Other files should still be included + expect(workspaceFiles).toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'sub1', 'someFileInSub1.txt')); + expect(workspaceFiles).toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'folderWithExt.cls', 'placeholder.txt')); + }); + + it("When ignores.files is empty, then no files are excluded", async () => { + const config = CodeAnalyzerConfig.fromObject({ + ignores: { + files: [] + } + }); + const codeAnalyzerWithIgnores = new CodeAnalyzer(config, new FakeFileSystem()); + + const workspace: Workspace = await codeAnalyzerWithIgnores.createWorkspace([SAMPLE_WORKSPACE_FOLDER]); + + const workspaceFiles = await workspace.getWorkspaceFiles(); + // All files should be present (except those normally excluded by the engine API like node_modules and .dotfiles) + expect(workspaceFiles).toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'someFile.cls')); + expect(workspaceFiles).toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'sub1', 'someFileInSub1.txt')); + expect(workspaceFiles).toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'sub1', 'sub3', 'someFileInSub3.cls')); + }); + + it("When no ignores config is provided, then default behavior is used (no extra exclusions)", async () => { + const codeAnalyzerDefault = new CodeAnalyzer(CodeAnalyzerConfig.withDefaults(), new FakeFileSystem()); + + const workspace: Workspace = await codeAnalyzerDefault.createWorkspace([SAMPLE_WORKSPACE_FOLDER]); + + const workspaceFiles = await workspace.getWorkspaceFiles(); + expect(workspaceFiles).toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'someFile.cls')); + expect(workspaceFiles).toContain(path.join(SAMPLE_WORKSPACE_FOLDER, 'sub1', 'someFileInSub1.txt')); + }); +}); + describe("Tests for the run method of CodeAnalyzer", () => { let sampleRunOptions: RunOptions; let fileSystem: FakeFileSystem; diff --git a/packages/code-analyzer-core/test/config.test.ts b/packages/code-analyzer-core/test/config.test.ts index e39496eb..beb8cd5c 100644 --- a/packages/code-analyzer-core/test/config.test.ts +++ b/packages/code-analyzer-core/test/config.test.ts @@ -1,4 +1,4 @@ -import {CodeAnalyzerConfig, SeverityLevel} from "../src"; +import {CodeAnalyzerConfig, Ignores, SeverityLevel} from "../src"; import * as os from "node:os"; import * as path from "node:path"; import {getMessageFromCatalog, LogLevel, SHARED_MESSAGE_CATALOG} from "@salesforce/code-analyzer-engine-api"; @@ -25,6 +25,7 @@ describe("Tests for creating and accessing configuration values", () => { expect(conf.getEngineOverridesFor("stubEngine1")).toEqual({}); expect(conf.getRuleOverridesFor("stubEngine2")).toEqual({}); expect(conf.getEngineOverridesFor("stubEngine2")).toEqual({}); + expect(conf.getIgnores()).toEqual({ files: [] }); }); it("When configuration file does not exist, then throw an error", () => { @@ -177,7 +178,7 @@ describe("Tests for creating and accessing configuration values", () => { it("When top level config has an unknown key, then we error", () => { expect(() => CodeAnalyzerConfig.fromObject({doesNotExist: 3})).toThrow( getMessageFromCatalog(SHARED_MESSAGE_CATALOG,'ConfigObjectContainsInvalidKey','', 'doesNotExist', - '["config_root","engines","log_folder","log_level","rules"]')); + '["config_root","engines","ignores","log_folder","log_level","rules"]')); }); it("When engines value is not an object then we throw an error", () => { @@ -393,6 +394,12 @@ describe("Tests for creating and accessing configuration values", () => { valueType: 'object', defaultValue: {}, wasSuppliedByUser: false + }, + ignores: { + descriptionText: getMessage('ConfigFieldDescription_ignores'), + valueType: 'object', + defaultValue: { files: [] }, + wasSuppliedByUser: false } }); }); @@ -416,3 +423,80 @@ describe("Tests for creating and accessing configuration values", () => { expect(configDescription.fieldDescriptions.engines.wasSuppliedByUser).toEqual(false); }); }); + +describe("Tests for ignores configuration", () => { + it("When constructing config withDefaults then ignores has empty files array", () => { + const conf: CodeAnalyzerConfig = CodeAnalyzerConfig.withDefaults(); + const ignores: Ignores = conf.getIgnores(); + expect(ignores).toEqual({ files: [] }); + }); + + it("When constructing config with ignores.files array, then values are parsed correctly", () => { + const conf: CodeAnalyzerConfig = CodeAnalyzerConfig.fromYamlString(` +ignores: + files: + - "src/*.cls" + - "**/*.test.js" + - "**/node_modules/**" +`); + const ignores: Ignores = conf.getIgnores(); + expect(ignores.files).toEqual([ + "src/*.cls", + "**/*.test.js", + "**/node_modules/**" + ]); + }); + + it("When constructing config with empty ignores object, then files defaults to empty array", () => { + const conf: CodeAnalyzerConfig = CodeAnalyzerConfig.fromYamlString(` +ignores: {} +`); + const ignores: Ignores = conf.getIgnores(); + expect(ignores).toEqual({ files: [] }); + }); + + it("When constructing config with ignores.files as null, then files defaults to empty array", () => { + const conf: CodeAnalyzerConfig = CodeAnalyzerConfig.fromYamlString(` +ignores: + files: null +`); + const ignores: Ignores = conf.getIgnores(); + expect(ignores).toEqual({ files: [] }); + }); + + it("When ignores is not an object then we throw an error", () => { + expect(() => CodeAnalyzerConfig.fromObject({ignores: "invalid"})).toThrow( + getMessageFromCatalog(SHARED_MESSAGE_CATALOG, 'ConfigValueMustBeOfType', 'ignores', 'object', 'string')); + }); + + it("When ignores.files is not an array then we throw an error", () => { + expect(() => CodeAnalyzerConfig.fromObject({ignores: {files: "invalid"}})).toThrow( + getMessageFromCatalog(SHARED_MESSAGE_CATALOG, 'ConfigValueMustBeOfType', 'ignores.files', 'array', 'string')); + }); + + it("When ignores.files contains non-string values then we throw an error", () => { + expect(() => CodeAnalyzerConfig.fromObject({ignores: {files: ["valid", 123]}})).toThrow( + getMessageFromCatalog(SHARED_MESSAGE_CATALOG, 'ConfigValueMustBeOfType', 'ignores.files[1]', 'string', 'number')); + }); + + it("When ignores contains unknown keys then we throw an error", () => { + expect(() => CodeAnalyzerConfig.fromObject({ignores: {files: [], unknownKey: "value"}})).toThrow( + getMessageFromCatalog(SHARED_MESSAGE_CATALOG, 'ConfigObjectContainsInvalidKey', 'ignores', 'unknownKey', '["files"]')); + }); + + it("When getConfigDescription is called, then ignores field is included", () => { + const configDescription: ConfigDescription = CodeAnalyzerConfig.withDefaults().getConfigDescription(); + expect(configDescription.fieldDescriptions.ignores).toBeDefined(); + expect(configDescription.fieldDescriptions.ignores.valueType).toEqual('object'); + expect(configDescription.fieldDescriptions.ignores.defaultValue).toEqual({ files: [] }); + expect(configDescription.fieldDescriptions.ignores.wasSuppliedByUser).toEqual(false); + }); + + it("When getConfigDescription is called with ignores supplied, then wasSuppliedByUser is true", () => { + const conf: CodeAnalyzerConfig = CodeAnalyzerConfig.fromObject({ + ignores: { files: ["**/*.test.js"] } + }); + const configDescription: ConfigDescription = conf.getConfigDescription(); + expect(configDescription.fieldDescriptions.ignores.wasSuppliedByUser).toEqual(true); + }); +}); From 4210533d3caf80fe481667f0299a4c967c3ece72 Mon Sep 17 00:00:00 2001 From: Namrata Gupta Date: Thu, 5 Feb 2026 11:00:47 +0530 Subject: [PATCH 2/2] Adding changes to allow ignoring without inheriting engine-api workspace --- package-lock.json | 128 ++++++++++++++++-- packages/ENGINE-TEMPLATE/package.json | 2 +- packages/code-analyzer-core/package.json | 4 +- .../code-analyzer-core/src/code-analyzer.ts | 73 +--------- .../code-analyzer-engine-api/package.json | 5 +- .../code-analyzer-engine-api/src/workspace.ts | 33 ++++- .../code-analyzer-eslint-engine/package.json | 4 +- .../code-analyzer-eslint8-engine/package.json | 4 +- .../code-analyzer-flow-engine/package.json | 4 +- .../code-analyzer-pmd-engine/package.json | 2 +- .../code-analyzer-regex-engine/package.json | 4 +- .../package.json | 4 +- .../code-analyzer-sfge-engine/package.json | 4 +- 13 files changed, 169 insertions(+), 102 deletions(-) diff --git a/package-lock.json b/package-lock.json index 57b94e1e..62ec8c1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2069,13 +2069,6 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "license": "MIT" }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/node": { "version": "20.19.25", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.25.tgz", @@ -9390,14 +9383,13 @@ }, "packages/code-analyzer-core": { "name": "@salesforce/code-analyzer-core", - "version": "0.42.0", + "version": "0.43.0-SNAPSHOT", "license": "BSD-3-Clause", "dependencies": { "@salesforce/code-analyzer-engine-api": "0.34.0", "@types/node": "^20.0.0", "csv-stringify": "^6.6.0", "js-yaml": "^4.1.1", - "minimatch": "^9.0.0", "semver": "^7.7.3", "xmlbuilder": "^15.1.1" }, @@ -9405,7 +9397,6 @@ "@eslint/js": "^9.39.2", "@types/jest": "^30.0.0", "@types/js-yaml": "^4.0.9", - "@types/minimatch": "^5.1.2", "@types/sarif": "^2.1.7", "@types/semver": "^7.7.1", "cross-env": "^10.1.0", @@ -9457,10 +9448,23 @@ "url": "https://eslint.org/donate" } }, + "packages/code-analyzer-core/node_modules/@salesforce/code-analyzer-engine-api": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@salesforce/code-analyzer-engine-api/-/code-analyzer-engine-api-0.34.0.tgz", + "integrity": "sha512-eZo+jfpzoDxWQIrnhKH8o2NJ+poYiEdusxezYTTnfGPmuQLRipq+a2Yz8j3+2zGjvNsJ0Up8p0POIdOZqd7mZw==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/node": "^20.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, "packages/code-analyzer-core/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -9639,6 +9643,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -9649,10 +9654,11 @@ }, "packages/code-analyzer-engine-api": { "name": "@salesforce/code-analyzer-engine-api", - "version": "0.34.0", + "version": "0.35.0-SNAPSHOT", "license": "BSD-3-Clause", "dependencies": { - "@types/node": "^20.0.0" + "@types/node": "^20.0.0", + "minimatch": "^9.0.0" }, "devDependencies": { "@eslint/js": "^9.39.2", @@ -9709,7 +9715,6 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -9888,7 +9893,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -10132,6 +10136,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "packages/code-analyzer-eslint-engine/node_modules/@salesforce/code-analyzer-engine-api": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@salesforce/code-analyzer-engine-api/-/code-analyzer-engine-api-0.34.0.tgz", + "integrity": "sha512-eZo+jfpzoDxWQIrnhKH8o2NJ+poYiEdusxezYTTnfGPmuQLRipq+a2Yz8j3+2zGjvNsJ0Up8p0POIdOZqd7mZw==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/node": "^20.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, "packages/code-analyzer-eslint-engine/node_modules/@salesforce/eslint-config-lwc": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/@salesforce/eslint-config-lwc/-/eslint-config-lwc-4.1.2.tgz", @@ -10482,6 +10498,18 @@ "node": ">=20.0.0" } }, + "packages/code-analyzer-eslint8-engine/node_modules/@salesforce/code-analyzer-engine-api": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@salesforce/code-analyzer-engine-api/-/code-analyzer-engine-api-0.34.0.tgz", + "integrity": "sha512-eZo+jfpzoDxWQIrnhKH8o2NJ+poYiEdusxezYTTnfGPmuQLRipq+a2Yz8j3+2zGjvNsJ0Up8p0POIdOZqd7mZw==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/node": "^20.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, "packages/code-analyzer-eslint8-engine/node_modules/@salesforce/eslint-config-lwc": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/@salesforce/eslint-config-lwc/-/eslint-config-lwc-3.7.2.tgz", @@ -10907,6 +10935,18 @@ "url": "https://eslint.org/donate" } }, + "packages/code-analyzer-flow-engine/node_modules/@salesforce/code-analyzer-engine-api": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@salesforce/code-analyzer-engine-api/-/code-analyzer-engine-api-0.34.0.tgz", + "integrity": "sha512-eZo+jfpzoDxWQIrnhKH8o2NJ+poYiEdusxezYTTnfGPmuQLRipq+a2Yz8j3+2zGjvNsJ0Up8p0POIdOZqd7mZw==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/node": "^20.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, "packages/code-analyzer-flow-engine/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -11160,6 +11200,18 @@ "url": "https://eslint.org/donate" } }, + "packages/code-analyzer-pmd-engine/node_modules/@salesforce/code-analyzer-engine-api": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@salesforce/code-analyzer-engine-api/-/code-analyzer-engine-api-0.34.0.tgz", + "integrity": "sha512-eZo+jfpzoDxWQIrnhKH8o2NJ+poYiEdusxezYTTnfGPmuQLRipq+a2Yz8j3+2zGjvNsJ0Up8p0POIdOZqd7mZw==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/node": "^20.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, "packages/code-analyzer-pmd-engine/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -11413,6 +11465,18 @@ "url": "https://eslint.org/donate" } }, + "packages/code-analyzer-regex-engine/node_modules/@salesforce/code-analyzer-engine-api": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@salesforce/code-analyzer-engine-api/-/code-analyzer-engine-api-0.34.0.tgz", + "integrity": "sha512-eZo+jfpzoDxWQIrnhKH8o2NJ+poYiEdusxezYTTnfGPmuQLRipq+a2Yz8j3+2zGjvNsJ0Up8p0POIdOZqd7mZw==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/node": "^20.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, "packages/code-analyzer-regex-engine/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -11679,6 +11743,18 @@ "url": "https://eslint.org/donate" } }, + "packages/code-analyzer-retirejs-engine/node_modules/@salesforce/code-analyzer-engine-api": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@salesforce/code-analyzer-engine-api/-/code-analyzer-engine-api-0.34.0.tgz", + "integrity": "sha512-eZo+jfpzoDxWQIrnhKH8o2NJ+poYiEdusxezYTTnfGPmuQLRipq+a2Yz8j3+2zGjvNsJ0Up8p0POIdOZqd7mZw==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/node": "^20.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, "packages/code-analyzer-retirejs-engine/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -11944,6 +12020,18 @@ "url": "https://eslint.org/donate" } }, + "packages/code-analyzer-sfge-engine/node_modules/@salesforce/code-analyzer-engine-api": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@salesforce/code-analyzer-engine-api/-/code-analyzer-engine-api-0.34.0.tgz", + "integrity": "sha512-eZo+jfpzoDxWQIrnhKH8o2NJ+poYiEdusxezYTTnfGPmuQLRipq+a2Yz8j3+2zGjvNsJ0Up8p0POIdOZqd7mZw==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/node": "^20.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, "packages/code-analyzer-sfge-engine/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -12195,6 +12283,18 @@ "url": "https://eslint.org/donate" } }, + "packages/ENGINE-TEMPLATE/node_modules/@salesforce/code-analyzer-engine-api": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@salesforce/code-analyzer-engine-api/-/code-analyzer-engine-api-0.34.0.tgz", + "integrity": "sha512-eZo+jfpzoDxWQIrnhKH8o2NJ+poYiEdusxezYTTnfGPmuQLRipq+a2Yz8j3+2zGjvNsJ0Up8p0POIdOZqd7mZw==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/node": "^20.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, "packages/ENGINE-TEMPLATE/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", diff --git a/packages/ENGINE-TEMPLATE/package.json b/packages/ENGINE-TEMPLATE/package.json index 4dfc5bf2..4fa23b83 100644 --- a/packages/ENGINE-TEMPLATE/package.json +++ b/packages/ENGINE-TEMPLATE/package.json @@ -14,7 +14,7 @@ "types": "dist/index.d.ts", "dependencies": { "@types/node": "^20.0.0", - "@salesforce/code-analyzer-engine-api": "0.34.0" + "@salesforce/code-analyzer-engine-api": "0.35.0-SNAPSHOT" }, "devDependencies": { "@eslint/js": "^9.39.2", diff --git a/packages/code-analyzer-core/package.json b/packages/code-analyzer-core/package.json index 21e981ea..3299e29e 100644 --- a/packages/code-analyzer-core/package.json +++ b/packages/code-analyzer-core/package.json @@ -16,11 +16,10 @@ }, "types": "dist/index.d.ts", "dependencies": { - "@salesforce/code-analyzer-engine-api": "0.34.0", + "@salesforce/code-analyzer-engine-api": "0.35.0-SNAPSHOT", "@types/node": "^20.0.0", "csv-stringify": "^6.6.0", "js-yaml": "^4.1.1", - "minimatch": "^9.0.0", "semver": "^7.7.3", "xmlbuilder": "^15.1.1" }, @@ -28,7 +27,6 @@ "@eslint/js": "^9.39.2", "@types/js-yaml": "^4.0.9", "@types/jest": "^30.0.0", - "@types/minimatch": "^5.1.2", "@types/sarif": "^2.1.7", "@types/semver": "^7.7.1", "cross-env": "^10.1.0", diff --git a/packages/code-analyzer-core/src/code-analyzer.ts b/packages/code-analyzer-core/src/code-analyzer.ts index a0ed824e..04e53467 100644 --- a/packages/code-analyzer-core/src/code-analyzer.ts +++ b/packages/code-analyzer-core/src/code-analyzer.ts @@ -36,7 +36,6 @@ import { } from "./utils"; import fs from "node:fs"; import path from 'node:path'; -import {Minimatch} from 'minimatch'; /** * Interface for workspaces @@ -653,13 +652,10 @@ export class CodeAnalyzer { */ class WorkspaceImpl implements Workspace { private readonly delegate: engApi.Workspace; - private readonly ignorePatterns: string[]; - private cachedFilteredWorkspaceFiles?: string[]; - private cachedFilteredTargetedFiles?: string[]; constructor(workspaceId: string, absWorkspaceFilesAndFolders: string[], absTargets?: string[], ignorePatterns: string[] = []) { - this.delegate = new engApi.Workspace(workspaceId, absWorkspaceFilesAndFolders, absTargets); - this.ignorePatterns = ignorePatterns; + // Pass ignore patterns directly to engApi.Workspace which handles filtering internally + this.delegate = new engApi.Workspace(workspaceId, absWorkspaceFilesAndFolders, absTargets, ignorePatterns); } getWorkspaceId(): string { @@ -675,74 +671,15 @@ class WorkspaceImpl implements Workspace { } async getWorkspaceFiles(): Promise { - if (!this.cachedFilteredWorkspaceFiles) { - const files = await this.delegate.getWorkspaceFiles(); - this.cachedFilteredWorkspaceFiles = this.filterIgnoredFiles(files); - } - return this.cachedFilteredWorkspaceFiles; + return this.delegate.getWorkspaceFiles(); } async getTargetedFiles(): Promise { - if (!this.cachedFilteredTargetedFiles) { - const files = await this.delegate.getTargetedFiles(); - this.cachedFilteredTargetedFiles = this.filterIgnoredFiles(files); - } - return this.cachedFilteredTargetedFiles; - } - - /** - * Filters out files that match any of the ignore patterns. - * Patterns are matched against the file path relative to the workspace root, - * or the full path if no workspace root exists. - */ - private filterIgnoredFiles(files: string[]): string[] { - if (this.ignorePatterns.length === 0) { - return files; - } - - // Pre-compile the patterns for performance - const matchers = this.ignorePatterns.map(pattern => new Minimatch(pattern, { dot: true, matchBase: true })); - - const workspaceRoot = this.delegate.getWorkspaceRoot(); - return files.filter(file => { - // Get the path to match against - use relative path if workspace root exists - const pathToMatch = workspaceRoot ? file.slice(workspaceRoot.length + 1) : file; - - // Check if the file matches any ignore pattern - const shouldIgnore = matchers.some(matcher => matcher.match(pathToMatch)); - return !shouldIgnore; - }); + return this.delegate.getTargetedFiles(); } _toEngApiWorkspace(): engApi.Workspace { - // Return a workspace that applies filtering while preserving original raw values. - // We use inheritance here because: - // 1. getRawFilesAndFolders() must return original folders (not expanded/filtered files) - // 2. getWorkspaceFiles() must return filtered files - // Composition alone can't preserve both semantics. - return new FilteredEngApiWorkspace(this.delegate, this); - } -} - -/** - * Wrapper around engApi.Workspace that returns filtered file lists while preserving - * original raw files/folders. This ensures engines receive filtered files but can - * still access the original workspace structure if needed. - */ -class FilteredEngApiWorkspace extends engApi.Workspace { - private readonly workspaceImpl: WorkspaceImpl; - - constructor(delegate: engApi.Workspace, workspaceImpl: WorkspaceImpl) { - super(delegate.getWorkspaceId(), delegate.getRawFilesAndFolders(), delegate.getRawTargets()); - this.workspaceImpl = workspaceImpl; - } - - override async getWorkspaceFiles(): Promise { - return this.workspaceImpl.getWorkspaceFiles(); - } - - override async getTargetedFiles(): Promise { - return this.workspaceImpl.getTargetedFiles(); + return this.delegate; } } diff --git a/packages/code-analyzer-engine-api/package.json b/packages/code-analyzer-engine-api/package.json index 24a16f76..9f91ad9b 100644 --- a/packages/code-analyzer-engine-api/package.json +++ b/packages/code-analyzer-engine-api/package.json @@ -1,7 +1,7 @@ { "name": "@salesforce/code-analyzer-engine-api", "description": "Engine API Package for the Salesforce Code Analyzer", - "version": "0.34.0", + "version": "0.35.0-SNAPSHOT", "author": "The Salesforce Code Analyzer Team", "license": "BSD-3-Clause", "homepage": "https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/overview", @@ -16,7 +16,8 @@ }, "types": "dist/index.d.ts", "dependencies": { - "@types/node": "^20.0.0" + "@types/node": "^20.0.0", + "minimatch": "^9.0.0" }, "devDependencies": { "@eslint/js": "^9.39.2", diff --git a/packages/code-analyzer-engine-api/src/workspace.ts b/packages/code-analyzer-engine-api/src/workspace.ts index 3eedbf0a..7cb908f8 100644 --- a/packages/code-analyzer-engine-api/src/workspace.ts +++ b/packages/code-analyzer-engine-api/src/workspace.ts @@ -1,5 +1,6 @@ import fs from "node:fs"; import path from "node:path"; +import {Minimatch} from "minimatch"; import {calculateLongestCommonParentFolderOf} from "./utils"; const NON_DOT_FOLDERS_TO_EXCLUDE: string[] = ['node_modules']; @@ -15,6 +16,7 @@ export class Workspace { private readonly workspaceId: string; private readonly rawAbsFilesAndFolders: string[]; private readonly rawAbsTargets?: string[]; + private readonly ignorePatterns: string[]; private cachedRawFilesAndFolders?: string[]; private cachedRawTargets?: string[]; @@ -23,6 +25,7 @@ export class Workspace { private cachedTargetedFiles?: string[]; private workspaceRoot?: string | null; + private cachedIgnoreMatchers?: Minimatch[]; /** * Creates a {@link Workspace} instance associated with a specified list of files and folders. @@ -40,11 +43,13 @@ export class Workspace { * @param workspaceId Optional workspace identifier * @param absFilesAndFolders Absolute file and folder paths that make up the workspace * @param absTargets optional string array of files and/or folders + * @param ignorePatterns optional array of glob patterns for files to ignore during scanning */ - constructor(workspaceId: string, absFilesAndFolders: string[], absTargets?: string[]) { + constructor(workspaceId: string, absFilesAndFolders: string[], absTargets?: string[], ignorePatterns: string[] = []) { this.workspaceId = workspaceId; this.rawAbsFilesAndFolders = absFilesAndFolders; this.rawAbsTargets = absTargets; + this.ignorePatterns = ignorePatterns; } /** @@ -156,8 +161,34 @@ export class Workspace { * they choose to do so. */ private shouldExclude(fileOrFolder: string): boolean { + // Check user-specified ignore patterns first + if (this.matchesIgnorePattern(fileOrFolder)) { + return true; + } + // Then check built-in exclusions (node_modules, dot files, etc.) return this.isExcludeCandidate(fileOrFolder) && !this.excludeCandidateWasExplicitlyProvided(fileOrFolder); } + + /** + * Returns whether a file matches any of the user-specified ignore patterns. + * Patterns are matched against the file path relative to the workspace root. + */ + private matchesIgnorePattern(fileOrFolder: string): boolean { + if (this.ignorePatterns.length === 0) { + return false; + } + // Lazily compile matchers for performance + if (!this.cachedIgnoreMatchers) { + this.cachedIgnoreMatchers = this.ignorePatterns.map( + pattern => new Minimatch(pattern, { dot: true, matchBase: true }) + ); + } + // Get relative path for matching (without leading separator) + const relativePath = this.makeRelativeToWorkspaceRoot(fileOrFolder); + const pathToMatch = relativePath.startsWith(path.sep) ? relativePath.slice(1) : relativePath; + + return this.cachedIgnoreMatchers.some(matcher => matcher.match(pathToMatch)); + } private isExcludeCandidate(fileOrFolder: string): boolean { const relativeFileOrFolder: string = this.makeRelativeToWorkspaceRoot(fileOrFolder); if (relativeFileOrFolder.length === 0) { // folder is equal to the workspace root diff --git a/packages/code-analyzer-eslint-engine/package.json b/packages/code-analyzer-eslint-engine/package.json index d8679128..f093949f 100644 --- a/packages/code-analyzer-eslint-engine/package.json +++ b/packages/code-analyzer-eslint-engine/package.json @@ -18,8 +18,8 @@ "@lwc/eslint-plugin-lwc": "^3.3.0", "@lwc/eslint-plugin-lwc-platform": "^6.3.0", "@salesforce-ux/eslint-plugin-slds": "^1.1.0", - "@salesforce/code-analyzer-engine-api": "0.34.0", - "@salesforce/code-analyzer-eslint8-engine": "0.11.0", + "@salesforce/code-analyzer-engine-api": "0.35.0-SNAPSHOT", + "@salesforce/code-analyzer-eslint8-engine": "0.12.0-SNAPSHOT", "@salesforce/eslint-config-lwc": "^4.1.2", "@salesforce/eslint-plugin-lightning": "^2.0.0", "@types/node": "^20.0.0", diff --git a/packages/code-analyzer-eslint8-engine/package.json b/packages/code-analyzer-eslint8-engine/package.json index 8d71d9ae..57a5c347 100644 --- a/packages/code-analyzer-eslint8-engine/package.json +++ b/packages/code-analyzer-eslint8-engine/package.json @@ -1,7 +1,7 @@ { "name": "@salesforce/code-analyzer-eslint8-engine", "description": "Plugin package that adds 'eslint' (version 8) as an engine into Salesforce Code Analyzer", - "version": "0.11.0", + "version": "0.12.0-SNAPSHOT", "author": "The Salesforce Code Analyzer Team", "license": "BSD-3-Clause", "homepage": "https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/overview", @@ -18,7 +18,7 @@ "@eslint/js": "8.57.1", "@lwc/eslint-plugin-lwc": "2.2.0", "@lwc/eslint-plugin-lwc-platform": "5.2.0", - "@salesforce/code-analyzer-engine-api": "0.34.0", + "@salesforce/code-analyzer-engine-api": "0.35.0-SNAPSHOT", "@salesforce/eslint-config-lwc": "3.7.2", "@salesforce/eslint-plugin-lightning": "1.0.1", "@types/node": "^20.0.0", diff --git a/packages/code-analyzer-flow-engine/package.json b/packages/code-analyzer-flow-engine/package.json index b54b966f..5c7e28e6 100644 --- a/packages/code-analyzer-flow-engine/package.json +++ b/packages/code-analyzer-flow-engine/package.json @@ -1,7 +1,7 @@ { "name": "@salesforce/code-analyzer-flow-engine", "description": "Plugin package that adds 'Flow Scanner' as an engine into Salesforce Code Analyzer", - "version": "0.33.0", + "version": "0.34.0-SNAPSHOT", "author": "The Salesforce Code Analyzer Team", "license": "BSD-3-Clause", "homepage": "https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/overview", @@ -13,7 +13,7 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "dependencies": { - "@salesforce/code-analyzer-engine-api": "0.34.0", + "@salesforce/code-analyzer-engine-api": "0.35.0-SNAPSHOT", "@types/node": "^20.0.0", "@types/semver": "^7.7.1", "semver": "^7.7.3" diff --git a/packages/code-analyzer-pmd-engine/package.json b/packages/code-analyzer-pmd-engine/package.json index 331a98cb..2b8a47ec 100644 --- a/packages/code-analyzer-pmd-engine/package.json +++ b/packages/code-analyzer-pmd-engine/package.json @@ -13,7 +13,7 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "dependencies": { - "@salesforce/code-analyzer-engine-api": "0.34.0", + "@salesforce/code-analyzer-engine-api": "0.35.0-SNAPSHOT", "@types/node": "^20.0.0", "@types/semver": "^7.7.1", "semver": "^7.7.3" diff --git a/packages/code-analyzer-regex-engine/package.json b/packages/code-analyzer-regex-engine/package.json index f7b53cef..c9fd2982 100644 --- a/packages/code-analyzer-regex-engine/package.json +++ b/packages/code-analyzer-regex-engine/package.json @@ -1,7 +1,7 @@ { "name": "@salesforce/code-analyzer-regex-engine", "description": "Plugin package that adds 'regex' as an engine into Salesforce Code Analyzer", - "version": "0.32.0", + "version": "0.33.0-SNAPSHOT", "author": "The Salesforce Code Analyzer Team", "license": "BSD-3-Clause", "homepage": "https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/overview", @@ -13,7 +13,7 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "dependencies": { - "@salesforce/code-analyzer-engine-api": "0.34.0", + "@salesforce/code-analyzer-engine-api": "0.35.0-SNAPSHOT", "@types/node": "^20.0.0", "isbinaryfile": "^5.0.0", "p-limit": "^3.1.0" diff --git a/packages/code-analyzer-retirejs-engine/package.json b/packages/code-analyzer-retirejs-engine/package.json index 017df96d..c8bd095c 100644 --- a/packages/code-analyzer-retirejs-engine/package.json +++ b/packages/code-analyzer-retirejs-engine/package.json @@ -1,7 +1,7 @@ { "name": "@salesforce/code-analyzer-retirejs-engine", "description": "Plugin package that adds 'retire-js' as an engine into Salesforce Code Analyzer", - "version": "0.31.0", + "version": "0.32.0-SNAPSHOT", "author": "The Salesforce Code Analyzer Team", "license": "BSD-3-Clause", "homepage": "https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/overview", @@ -13,7 +13,7 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "dependencies": { - "@salesforce/code-analyzer-engine-api": "0.34.0", + "@salesforce/code-analyzer-engine-api": "0.35.0-SNAPSHOT", "@types/node": "^20.0.0", "isbinaryfile": "^5.0.0", "node-stream-zip": "^1.15.0", diff --git a/packages/code-analyzer-sfge-engine/package.json b/packages/code-analyzer-sfge-engine/package.json index bf38d219..30a2b3ef 100644 --- a/packages/code-analyzer-sfge-engine/package.json +++ b/packages/code-analyzer-sfge-engine/package.json @@ -1,7 +1,7 @@ { "name": "@salesforce/code-analyzer-sfge-engine", "description": "Plugin package that adds 'Salesforce Graph Engine' as an engine into Salesforce Code Analyzer", - "version": "0.17.0", + "version": "0.18.0-SNAPSHOT", "author": "The Salesforce Code Analyzer Team", "license": "BSD-3-Clause", "homepage": "https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/overview", @@ -13,7 +13,7 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "dependencies": { - "@salesforce/code-analyzer-engine-api": "0.34.0", + "@salesforce/code-analyzer-engine-api": "0.35.0-SNAPSHOT", "@types/node": "^20.0.0", "semver": "^7.7.3" },