From 4c2156f2ee92eb46c5e37367960040c9b61858be Mon Sep 17 00:00:00 2001 From: Nikhil Mittal Date: Tue, 28 Jul 2026 12:33:14 +0530 Subject: [PATCH 1/4] update apexguru tags --- package-lock.json | 30 +----------- .../package.json | 2 +- .../src/apexguru-rules.ts | 48 +++++++++---------- 3 files changed, 26 insertions(+), 54 deletions(-) diff --git a/package-lock.json b/package-lock.json index 739f6255..14912ba6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -618,7 +618,6 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -630,7 +629,6 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -641,7 +639,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -1749,7 +1746,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -2063,7 +2059,6 @@ "version": "0.10.2", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -2504,7 +2499,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2518,7 +2512,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2532,7 +2525,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2546,7 +2538,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2560,7 +2551,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2574,7 +2564,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2588,7 +2577,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2602,7 +2590,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2616,7 +2603,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2630,7 +2616,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2644,7 +2629,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2658,7 +2642,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2672,7 +2655,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2686,7 +2668,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2700,7 +2681,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2714,7 +2694,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2728,7 +2707,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2742,7 +2720,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2756,7 +2733,6 @@ "cpu": [ "wasm32" ], - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -2775,7 +2751,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2789,7 +2764,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2803,7 +2777,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5545,7 +5518,6 @@ }, "node_modules/fsevents": { "version": "2.3.3", - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -10732,7 +10704,7 @@ }, "packages/code-analyzer-apexguru-engine": { "name": "@salesforce/code-analyzer-apexguru-engine", - "version": "0.40.0-SNAPSHOT", + "version": "0.41.0-SNAPSHOT", "license": "BSD-3-Clause", "dependencies": { "@salesforce/code-analyzer-engine-api": "0.40.0-SNAPSHOT", diff --git a/packages/code-analyzer-apexguru-engine/package.json b/packages/code-analyzer-apexguru-engine/package.json index 2dc5d080..80e5d24a 100644 --- a/packages/code-analyzer-apexguru-engine/package.json +++ b/packages/code-analyzer-apexguru-engine/package.json @@ -1,7 +1,7 @@ { "name": "@salesforce/code-analyzer-apexguru-engine", "description": "ApexGuru Engine Package for the Salesforce Code Analyzer", - "version": "0.40.0-SNAPSHOT", + "version": "0.41.0-SNAPSHOT", "author": "The Salesforce Code Analyzer Team", "license": "BSD-3-Clause", "homepage": "https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/overview", diff --git a/packages/code-analyzer-apexguru-engine/src/apexguru-rules.ts b/packages/code-analyzer-apexguru-engine/src/apexguru-rules.ts index 91aadff9..d4d62508 100644 --- a/packages/code-analyzer-apexguru-engine/src/apexguru-rules.ts +++ b/packages/code-analyzer-apexguru-engine/src/apexguru-rules.ts @@ -1,6 +1,6 @@ -import { RuleDescription, SeverityLevel, COMMON_TAGS } from '@salesforce/code-analyzer-engine-api'; +import { RuleDescription, SeverityLevel } from '@salesforce/code-analyzer-engine-api'; export const DEV_PREVIEW_TAG: string = 'DevPreview'; @@ -18,7 +18,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SoqlInALoop', severityLevel: SeverityLevel.High, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.PERFORMANCE, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'SOQL query inside a loop causes performance issues and can hit governor limits', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_soql_in_loop.htm&type=5'] }, @@ -26,7 +26,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'DmlInALoop', severityLevel: SeverityLevel.High, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.PERFORMANCE, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'DML statement inside a loop causes performance issues and can hit governor limits', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_dml_in_loop.htm&type=5'] }, @@ -38,7 +38,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SoqlInALoopOneHop', severityLevel: SeverityLevel.High, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.PERFORMANCE, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'SOQL query reached one method-hop away inside a loop causes performance issues and can hit governor limits', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_soql_in_loop_one_hop.htm&type=5'] }, @@ -46,7 +46,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'ExpensiveMethods', severityLevel: SeverityLevel.High, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.PERFORMANCE, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'Method accounts for a large share of observed Apex CPU time and is a hotspot for performance work', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_expensive_methods.htm&type=5'] }, @@ -58,7 +58,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SoqlWithoutAWhereClauseOrLimitStatement', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.PERFORMANCE, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'SOQL query without WHERE clause or LIMIT statement can cause performance issues and heap size exceptions', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_soql_without_where_clause_or_limit_statement.htm&type=5'] }, @@ -66,7 +66,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SoqlWithWildcardFilter', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.PERFORMANCE, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'SOQL query using LIKE with leading wildcard is inefficient and cannot use indexes', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_soql_with_wildcard_filter.htm&type=5'] }, @@ -74,7 +74,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SchemaGetGlobalDescribeNotEfficient', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.PERFORMANCE, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'Using Schema.getGlobalDescribe() causes unnecessary overhead and decreases performance', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_schema_getglobaldescribe_not_efficient.htm&type=5'] }, @@ -86,7 +86,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'Soql Aggregation', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.PERFORMANCE, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'Manual aggregation in Apex instead of using SOQL aggregate functions causes performance issues', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_aggregating_in_apex.htm&type=5'] }, @@ -94,7 +94,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SoqlWithApexFilter', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.PERFORMANCE, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'Filtering records in Apex instead of using SOQL WHERE clause causes performance issues', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_soql_with_apex_filter.htm&type=5'] }, @@ -102,7 +102,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'CopyingListOrSetElementsUsingAForLoop', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.PERFORMANCE, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'Copying list or set elements using a for loop is inefficient - use addAll() instead', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_copying_elements_with_for_loop.htm&type=5'] }, @@ -110,7 +110,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'Redundant Soql', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.PERFORMANCE, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'Multiple identical SOQL queries cause unnecessary database round trips', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_redundant_soql.htm&type=5'] }, @@ -118,7 +118,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SoqlWithNegativeExpressions', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.PERFORMANCE, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'SOQL queries using negative expressions (NOT IN, !=) don\'t use indexes and cause full table scans', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_soql_with_negative_expressions.htm&type=5'] }, @@ -126,7 +126,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SObjectMapInAForLoop', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.PERFORMANCE, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'Building Map using .put() in a for loop is inefficient - use map constructor or putAll()', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_sobject_map_in_for_loop.htm&type=5'] }, @@ -134,7 +134,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SoqlWithoutPlatformCache', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.PERFORMANCE, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'Frequently executed SOQL query whose results could be served from Platform Cache to reduce database load', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_soql_without_platform_cache.htm&type=5'] }, @@ -146,7 +146,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'LimitsGetHeapsizeMethods', severityLevel: SeverityLevel.Low, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.PERFORMANCE, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'Frequent Limits.getHeapSize() calls add runtime overhead', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_limits_getheapsize_methods.htm&type=5'] }, @@ -154,7 +154,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'ExpensiveStringComparison', severityLevel: SeverityLevel.Low, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.PERFORMANCE, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'Inefficient string comparison wastes CPU time', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_expensive_string_comparison.htm&type=5'] }, @@ -162,7 +162,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'ExpensiveDebugStatements', severityLevel: SeverityLevel.Low, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.PERFORMANCE, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'Expensive System.debug() statements add runtime overhead', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_expensive_debug_statements.htm&type=5'] }, @@ -174,7 +174,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'UsingTheTestMethodKeyword', severityLevel: SeverityLevel.Low, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'The testMethod keyword is deprecated - use @isTest annotation instead', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_test_case_antipattern_using_testmethod.htm&type=5'] }, @@ -186,7 +186,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SortingInApex', severityLevel: SeverityLevel.Low, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'Sorting records in Apex wastes CPU time and can exceed governor limits - use ORDER BY in SOQL', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_sorting_in_apex.htm&type=5'] }, @@ -194,7 +194,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'BusyLoopDelay', severityLevel: SeverityLevel.Low, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'Using empty loops to delay execution wastes CPU time - use System.enqueueJob with delay parameter', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_busy_loop_delay.htm&type=5'] }, @@ -202,7 +202,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SoqlWithUnusedFields', severityLevel: SeverityLevel.Low, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'SOQL query selecting unused fields increases resource consumption unnecessarily', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_soql_with_unused_fields.htm&type=5'] }, @@ -210,7 +210,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'WritingFillerStatements', severityLevel: SeverityLevel.Low, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'Filler statements written to inflate code coverage instead of testing real behavior', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_test_case_antipattern_filler_statements.htm&type=5'] }, @@ -222,7 +222,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'apexguru-other', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.APEX], + tags: [DEV_PREVIEW_TAG], description: 'Other ApexGuru rules - covers new rules added by Salesforce that are not yet explicitly declared', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru.htm'] } From 754c3ee203ca08a9cfb675a89b27f8d4b5bbe7f2 Mon Sep 17 00:00:00 2001 From: Nikhil Mittal Date: Tue, 28 Jul 2026 12:39:36 +0530 Subject: [PATCH 2/4] test case fix --- .../test/apexguru-rules.test.ts | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/packages/code-analyzer-apexguru-engine/test/apexguru-rules.test.ts b/packages/code-analyzer-apexguru-engine/test/apexguru-rules.test.ts index ed958a28..40e799ec 100644 --- a/packages/code-analyzer-apexguru-engine/test/apexguru-rules.test.ts +++ b/packages/code-analyzer-apexguru-engine/test/apexguru-rules.test.ts @@ -1,5 +1,4 @@ import { APEXGURU_RULES, DEV_PREVIEW_TAG, isKnownRule, FALLBACK_RULE_NAME } from '../src/apexguru-rules'; -import { COMMON_TAGS } from '@salesforce/code-analyzer-engine-api'; describe('apexguru-rules', () => { @@ -64,14 +63,6 @@ describe('apexguru-rules', () => { expect(rule!.tags[0]).toBe('DevPreview'); }); - it.each(rulesWithoutFormerRecommended)('%s should retain its category tag', (ruleName) => { - const rule = APEXGURU_RULES.find(r => r.name === ruleName); - expect(rule).toBeDefined(); - const hasCategoryTag = rule!.tags.includes(COMMON_TAGS.CATEGORIES.PERFORMANCE) || - rule!.tags.includes(COMMON_TAGS.CATEGORIES.BEST_PRACTICES); - expect(hasCategoryTag).toBe(true); - }); - it.each(rulesWithoutFormerRecommended)('%s should NOT contain Recommended tag', (ruleName) => { const rule = APEXGURU_RULES.find(r => r.name === ruleName); expect(rule).toBeDefined(); @@ -96,19 +87,6 @@ describe('apexguru-rules', () => { } }); - it('every rule should have a category tag (Performance or BestPractices)', () => { - for (const rule of APEXGURU_RULES) { - const hasCategoryTag = rule.tags.includes(COMMON_TAGS.CATEGORIES.PERFORMANCE) || - rule.tags.includes(COMMON_TAGS.CATEGORIES.BEST_PRACTICES); - expect(hasCategoryTag).toBe(true); - } - }); - - it('every rule should have Apex language tag', () => { - for (const rule of APEXGURU_RULES) { - expect(rule.tags).toContain(COMMON_TAGS.LANGUAGES.APEX); - } - }); }); describe('isKnownRule', () => { From 3890dbff407953d976cdc9f858099139103b73f4 Mon Sep 17 00:00:00 2001 From: Nikhil Mittal Date: Tue, 28 Jul 2026 13:45:12 +0530 Subject: [PATCH 3/4] apexguru isolation --- package-lock.json | 2 +- .../src/apexguru-rules.ts | 48 +++++++++---------- .../test/ApexGuruEngine.test.ts | 4 +- .../test/apexguru-rules.test.ts | 14 +++--- packages/code-analyzer-core/package.json | 2 +- packages/code-analyzer-core/src/rules.ts | 29 +++++++---- .../test/rule-selection.test.ts | 42 ++++++++++++++++ packages/code-analyzer-core/test/stubs.ts | 46 ++++++++++++++++++ 8 files changed, 144 insertions(+), 43 deletions(-) diff --git a/package-lock.json b/package-lock.json index 14912ba6..803749bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10959,7 +10959,7 @@ }, "packages/code-analyzer-core": { "name": "@salesforce/code-analyzer-core", - "version": "0.50.0-SNAPSHOT", + "version": "0.51.0-SNAPSHOT", "license": "BSD-3-Clause", "dependencies": { "@salesforce/code-analyzer-engine-api": "0.40.0-SNAPSHOT", diff --git a/packages/code-analyzer-apexguru-engine/src/apexguru-rules.ts b/packages/code-analyzer-apexguru-engine/src/apexguru-rules.ts index d4d62508..c24dab68 100644 --- a/packages/code-analyzer-apexguru-engine/src/apexguru-rules.ts +++ b/packages/code-analyzer-apexguru-engine/src/apexguru-rules.ts @@ -2,7 +2,7 @@ import { RuleDescription, SeverityLevel } from '@salesforce/code-analyzer-engine-api'; -export const DEV_PREVIEW_TAG: string = 'DevPreview'; +export const DEV_PREVIEW_TAG_APEXGURU: string = 'DevPreviewApexGuru'; /** * Known ApexGuru rules with descriptions and metadata. @@ -18,7 +18,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SoqlInALoop', severityLevel: SeverityLevel.High, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'SOQL query inside a loop causes performance issues and can hit governor limits', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_soql_in_loop.htm&type=5'] }, @@ -26,7 +26,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'DmlInALoop', severityLevel: SeverityLevel.High, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'DML statement inside a loop causes performance issues and can hit governor limits', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_dml_in_loop.htm&type=5'] }, @@ -38,7 +38,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SoqlInALoopOneHop', severityLevel: SeverityLevel.High, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'SOQL query reached one method-hop away inside a loop causes performance issues and can hit governor limits', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_soql_in_loop_one_hop.htm&type=5'] }, @@ -46,7 +46,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'ExpensiveMethods', severityLevel: SeverityLevel.High, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'Method accounts for a large share of observed Apex CPU time and is a hotspot for performance work', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_expensive_methods.htm&type=5'] }, @@ -58,7 +58,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SoqlWithoutAWhereClauseOrLimitStatement', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'SOQL query without WHERE clause or LIMIT statement can cause performance issues and heap size exceptions', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_soql_without_where_clause_or_limit_statement.htm&type=5'] }, @@ -66,7 +66,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SoqlWithWildcardFilter', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'SOQL query using LIKE with leading wildcard is inefficient and cannot use indexes', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_soql_with_wildcard_filter.htm&type=5'] }, @@ -74,7 +74,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SchemaGetGlobalDescribeNotEfficient', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'Using Schema.getGlobalDescribe() causes unnecessary overhead and decreases performance', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_schema_getglobaldescribe_not_efficient.htm&type=5'] }, @@ -86,7 +86,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'Soql Aggregation', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'Manual aggregation in Apex instead of using SOQL aggregate functions causes performance issues', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_aggregating_in_apex.htm&type=5'] }, @@ -94,7 +94,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SoqlWithApexFilter', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'Filtering records in Apex instead of using SOQL WHERE clause causes performance issues', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_soql_with_apex_filter.htm&type=5'] }, @@ -102,7 +102,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'CopyingListOrSetElementsUsingAForLoop', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'Copying list or set elements using a for loop is inefficient - use addAll() instead', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_copying_elements_with_for_loop.htm&type=5'] }, @@ -110,7 +110,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'Redundant Soql', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'Multiple identical SOQL queries cause unnecessary database round trips', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_redundant_soql.htm&type=5'] }, @@ -118,7 +118,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SoqlWithNegativeExpressions', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'SOQL queries using negative expressions (NOT IN, !=) don\'t use indexes and cause full table scans', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_soql_with_negative_expressions.htm&type=5'] }, @@ -126,7 +126,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SObjectMapInAForLoop', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'Building Map using .put() in a for loop is inefficient - use map constructor or putAll()', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_sobject_map_in_for_loop.htm&type=5'] }, @@ -134,7 +134,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SoqlWithoutPlatformCache', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'Frequently executed SOQL query whose results could be served from Platform Cache to reduce database load', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_soql_without_platform_cache.htm&type=5'] }, @@ -146,7 +146,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'LimitsGetHeapsizeMethods', severityLevel: SeverityLevel.Low, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'Frequent Limits.getHeapSize() calls add runtime overhead', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_limits_getheapsize_methods.htm&type=5'] }, @@ -154,7 +154,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'ExpensiveStringComparison', severityLevel: SeverityLevel.Low, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'Inefficient string comparison wastes CPU time', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_expensive_string_comparison.htm&type=5'] }, @@ -162,7 +162,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'ExpensiveDebugStatements', severityLevel: SeverityLevel.Low, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'Expensive System.debug() statements add runtime overhead', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_expensive_debug_statements.htm&type=5'] }, @@ -174,7 +174,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'UsingTheTestMethodKeyword', severityLevel: SeverityLevel.Low, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'The testMethod keyword is deprecated - use @isTest annotation instead', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_test_case_antipattern_using_testmethod.htm&type=5'] }, @@ -186,7 +186,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SortingInApex', severityLevel: SeverityLevel.Low, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'Sorting records in Apex wastes CPU time and can exceed governor limits - use ORDER BY in SOQL', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_sorting_in_apex.htm&type=5'] }, @@ -194,7 +194,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'BusyLoopDelay', severityLevel: SeverityLevel.Low, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'Using empty loops to delay execution wastes CPU time - use System.enqueueJob with delay parameter', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_busy_loop_delay.htm&type=5'] }, @@ -202,7 +202,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'SoqlWithUnusedFields', severityLevel: SeverityLevel.Low, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'SOQL query selecting unused fields increases resource consumption unnecessarily', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_antipattern_soql_with_unused_fields.htm&type=5'] }, @@ -210,7 +210,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'WritingFillerStatements', severityLevel: SeverityLevel.Low, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'Filler statements written to inflate code coverage instead of testing real behavior', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru_test_case_antipattern_filler_statements.htm&type=5'] }, @@ -222,7 +222,7 @@ export const APEXGURU_RULES: RuleDescription[] = [ { name: 'apexguru-other', severityLevel: SeverityLevel.Moderate, - tags: [DEV_PREVIEW_TAG], + tags: [DEV_PREVIEW_TAG_APEXGURU], description: 'Other ApexGuru rules - covers new rules added by Salesforce that are not yet explicitly declared', resourceUrls: ['https://help.salesforce.com/s/articleView?id=xcloud.apexguru.htm'] } diff --git a/packages/code-analyzer-apexguru-engine/test/ApexGuruEngine.test.ts b/packages/code-analyzer-apexguru-engine/test/ApexGuruEngine.test.ts index 60fa6c9b..9c18817e 100644 --- a/packages/code-analyzer-apexguru-engine/test/ApexGuruEngine.test.ts +++ b/packages/code-analyzer-apexguru-engine/test/ApexGuruEngine.test.ts @@ -612,7 +612,7 @@ describe('ApexGuruEngine', () => { expect(rules.length).toBeGreaterThan(0); for (const rule of rules) { - expect(rule.tags).toContain('DevPreview'); + expect(rule.tags).toContain('DevPreviewApexGuru'); expect(rule.tags).not.toContain('Recommended'); } }); @@ -633,7 +633,7 @@ describe('ApexGuruEngine', () => { workingFolder: '/tmp/working' }); - const devPreviewRules = rules.filter(r => r.tags.includes('DevPreview')); + const devPreviewRules = rules.filter(r => r.tags.includes('DevPreviewApexGuru')); expect(devPreviewRules).toHaveLength(rules.length); }); diff --git a/packages/code-analyzer-apexguru-engine/test/apexguru-rules.test.ts b/packages/code-analyzer-apexguru-engine/test/apexguru-rules.test.ts index 40e799ec..bee2b8a0 100644 --- a/packages/code-analyzer-apexguru-engine/test/apexguru-rules.test.ts +++ b/packages/code-analyzer-apexguru-engine/test/apexguru-rules.test.ts @@ -1,10 +1,10 @@ -import { APEXGURU_RULES, DEV_PREVIEW_TAG, isKnownRule, FALLBACK_RULE_NAME } from '../src/apexguru-rules'; +import { APEXGURU_RULES, DEV_PREVIEW_TAG_APEXGURU, isKnownRule, FALLBACK_RULE_NAME } from '../src/apexguru-rules'; describe('apexguru-rules', () => { - describe('DEV_PREVIEW_TAG constant', () => { - it('should equal DevPreview', () => { - expect(DEV_PREVIEW_TAG).toBe('DevPreview'); + describe('DEV_PREVIEW_TAG_APEXGURU constant', () => { + it('should equal DevPreviewApexGuru', () => { + expect(DEV_PREVIEW_TAG_APEXGURU).toBe('DevPreviewApexGuru'); }); }); @@ -22,7 +22,7 @@ describe('apexguru-rules', () => { it.each(rulesWithFormerRecommended)('%s should have DevPreview as first tag', (ruleName) => { const rule = APEXGURU_RULES.find(r => r.name === ruleName); expect(rule).toBeDefined(); - expect(rule!.tags[0]).toBe('DevPreview'); + expect(rule!.tags[0]).toBe('DevPreviewApexGuru'); }); it.each(rulesWithFormerRecommended)('%s should NOT contain Recommended tag', (ruleName) => { @@ -60,7 +60,7 @@ describe('apexguru-rules', () => { it.each(rulesWithoutFormerRecommended)('%s should have DevPreview as first tag', (ruleName) => { const rule = APEXGURU_RULES.find(r => r.name === ruleName); expect(rule).toBeDefined(); - expect(rule!.tags[0]).toBe('DevPreview'); + expect(rule!.tags[0]).toBe('DevPreviewApexGuru'); }); it.each(rulesWithoutFormerRecommended)('%s should NOT contain Recommended tag', (ruleName) => { @@ -77,7 +77,7 @@ describe('apexguru-rules', () => { it('every rule should have DevPreview in its tags', () => { for (const rule of APEXGURU_RULES) { - expect(rule.tags).toContain('DevPreview'); + expect(rule.tags).toContain('DevPreviewApexGuru'); } }); diff --git a/packages/code-analyzer-core/package.json b/packages/code-analyzer-core/package.json index 68c08e22..d6531570 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.50.0-SNAPSHOT", + "version": "0.51.0-SNAPSHOT", "author": "The Salesforce Code Analyzer Team", "license": "BSD-3-Clause", "homepage": "https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/overview", diff --git a/packages/code-analyzer-core/src/rules.ts b/packages/code-analyzer-core/src/rules.ts index 85444b40..5a83bf59 100644 --- a/packages/code-analyzer-core/src/rules.ts +++ b/packages/code-analyzer-core/src/rules.ts @@ -108,14 +108,27 @@ export class RuleImpl implements Rule { matchesRuleSelector(ruleSelector: Selector): boolean { const sevNumber: number = this.getSeverityLevel().valueOf(); const sevName: string = SeverityLevel[sevNumber]; - const selectables: string[] = [ - "all", - this.getEngineName().toLowerCase(), - this.getName().toLowerCase(), - sevName.toLowerCase(), - String(sevNumber), - ...this.getTags().map(t => t.toLowerCase()) - ] + const tags: string[] = this.getTags().map(t => t.toLowerCase()); + const isDevPreviewApexGuru: boolean = tags.includes('devpreviewapexguru'); + let selectables: string[]; + if (isDevPreviewApexGuru) { + // DevPreviewApexGuru rules are opt-in: only selectable by engine name, rule name, or explicit tag. + // 'all' and severity are intentionally excluded so broad selectors (e.g. 'all', '4', 'Low') don't pull them in. + selectables = [ + this.getEngineName().toLowerCase(), + this.getName().toLowerCase(), + ...tags + ]; + } else { + selectables = [ + "all", + this.getEngineName().toLowerCase(), + this.getName().toLowerCase(), + sevName.toLowerCase(), + String(sevNumber), + ...tags + ]; + } return ruleSelector.matchesSelectables(selectables); } } diff --git a/packages/code-analyzer-core/test/rule-selection.test.ts b/packages/code-analyzer-core/test/rule-selection.test.ts index 37bdefbd..ed2db3c8 100644 --- a/packages/code-analyzer-core/test/rule-selection.test.ts +++ b/packages/code-analyzer-core/test/rule-selection.test.ts @@ -610,6 +610,48 @@ describe('Tests for selecting rules', () => { getMessage('InstructionsToIgnoreErrorAndDisableEngine', 'someEngine')); }) + describe('DevPreviewApexGuru rule selection behavior', () => { + beforeEach(async () => { + codeAnalyzer = createCodeAnalyzer(); + await codeAnalyzer.addEnginePlugin(new stubs.DevPreviewEnginePlugin()); + }); + + it('DevPreviewApexGuru rules are NOT selected by severity number selector', async () => { + const selection: RuleSelection = await codeAnalyzer.selectRules(['4']); // Low + expect(ruleNamesFor(selection, 'devPreviewEngine')).toEqual([]); + }); + + it('DevPreviewApexGuru rules are NOT selected by severity name selector', async () => { + const selection: RuleSelection = await codeAnalyzer.selectRules(['Low']); + expect(ruleNamesFor(selection, 'devPreviewEngine')).toEqual([]); + }); + + it('DevPreviewApexGuru rules are NOT selected by all', async () => { + const selection: RuleSelection = await codeAnalyzer.selectRules(['all']); + expect(ruleNamesFor(selection, 'devPreviewEngine')).toEqual([]); + }); + + it('DevPreviewApexGuru rules ARE selected by engine name', async () => { + const selection: RuleSelection = await codeAnalyzer.selectRules(['devPreviewEngine']); + expect(ruleNamesFor(selection, 'devPreviewEngine')).toEqual(['devPreviewRule1', 'devPreviewRule2']); + }); + + it('DevPreviewApexGuru rules ARE selected by rule name', async () => { + const selection: RuleSelection = await codeAnalyzer.selectRules(['devPreviewRule1']); + expect(ruleNamesFor(selection, 'devPreviewEngine')).toEqual(['devPreviewRule1']); + }); + + it('DevPreviewApexGuru rules ARE selected by DevPreviewApexGuru tag', async () => { + const selection: RuleSelection = await codeAnalyzer.selectRules(['DevPreviewApexGuru']); + expect(ruleNamesFor(selection, 'devPreviewEngine')).toEqual(['devPreviewRule1', 'devPreviewRule2']); + }); + + it('DevPreviewApexGuru rules ARE selected by other tag they carry', async () => { + const selection: RuleSelection = await codeAnalyzer.selectRules(['Performance']); + expect(ruleNamesFor(selection, 'devPreviewEngine')).toEqual(['devPreviewRule1']); + }); + }); + it('When attempting to get a rule that does not exist in the selection, then error', async () => { const selection: RuleSelection = await codeAnalyzer.selectRules([]); diff --git a/packages/code-analyzer-core/test/stubs.ts b/packages/code-analyzer-core/test/stubs.ts index 52e0296f..080c7105 100644 --- a/packages/code-analyzer-core/test/stubs.ts +++ b/packages/code-analyzer-core/test/stubs.ts @@ -601,6 +601,52 @@ class EmptyTagEngine extends engApi.Engine { } } +/** + * DevPreviewEnginePlugin - A plugin to help with testing DevPreview rule selection behavior + */ +export class DevPreviewEnginePlugin extends engApi.EnginePluginV1 { + getAvailableEngineNames(): string[] { + return ["devPreviewEngine"]; + } + + async createEngine(_engineName: string, _config: engApi.ConfigObject): Promise { + return new DevPreviewEngine(); + } +} + +class DevPreviewEngine extends engApi.Engine { + getName(): string { + return 'devPreviewEngine'; + } + + getEngineVersion(): Promise { + return Promise.resolve('1.0.0'); + } + + async describeRules(_describeOptions: engApi.DescribeOptions): Promise { + return [ + { + name: "devPreviewRule1", + severityLevel: engApi.SeverityLevel.Low, + tags: ['DevPreviewApexGuru', 'Performance'], + description: 'A DevPreview rule with Low severity', + resourceUrls: [] + }, + { + name: "devPreviewRule2", + severityLevel: engApi.SeverityLevel.High, + tags: ['DevPreviewApexGuru'], + description: 'A DevPreview rule with High severity', + resourceUrls: [] + } + ]; + } + + async runRules(_ruleNames: string[], _runOptions: engApi.RunOptions): Promise { + return { violations: [] }; + } +} + /** * FutureEnginePlugin - A plugin to help with testing forward compatibility */ From a3bec6b149846ac22996ab50bf523138d4c15428 Mon Sep 17 00:00:00 2001 From: Nikhil Mittal Date: Tue, 28 Jul 2026 14:48:29 +0530 Subject: [PATCH 4/4] apexguru test fixes --- .../test/apexguru-rules.test.ts | 35 ++++--------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/packages/code-analyzer-apexguru-engine/test/apexguru-rules.test.ts b/packages/code-analyzer-apexguru-engine/test/apexguru-rules.test.ts index bee2b8a0..3ae6b909 100644 --- a/packages/code-analyzer-apexguru-engine/test/apexguru-rules.test.ts +++ b/packages/code-analyzer-apexguru-engine/test/apexguru-rules.test.ts @@ -19,21 +19,10 @@ describe('apexguru-rules', () => { 'apexguru-other' ]; - it.each(rulesWithFormerRecommended)('%s should have DevPreview as first tag', (ruleName) => { + it.each(rulesWithFormerRecommended)('%s should have exactly [DevPreviewApexGuru] as its tags', (ruleName) => { const rule = APEXGURU_RULES.find(r => r.name === ruleName); expect(rule).toBeDefined(); - expect(rule!.tags[0]).toBe('DevPreviewApexGuru'); - }); - - it.each(rulesWithFormerRecommended)('%s should NOT contain Recommended tag', (ruleName) => { - const rule = APEXGURU_RULES.find(r => r.name === ruleName); - expect(rule).toBeDefined(); - expect(rule!.tags).not.toContain('Recommended'); - }); - - it('should have zero rules with Recommended tag across all APEXGURU_RULES', () => { - const rulesWithRecommended = APEXGURU_RULES.filter(r => r.tags.includes('Recommended')); - expect(rulesWithRecommended).toHaveLength(0); + expect(rule!.tags).toEqual(['DevPreviewApexGuru']); }); }); @@ -57,16 +46,10 @@ describe('apexguru-rules', () => { 'WritingFillerStatements' ]; - it.each(rulesWithoutFormerRecommended)('%s should have DevPreview as first tag', (ruleName) => { - const rule = APEXGURU_RULES.find(r => r.name === ruleName); - expect(rule).toBeDefined(); - expect(rule!.tags[0]).toBe('DevPreviewApexGuru'); - }); - - it.each(rulesWithoutFormerRecommended)('%s should NOT contain Recommended tag', (ruleName) => { + it.each(rulesWithoutFormerRecommended)('%s should have exactly [DevPreviewApexGuru] as its tags', (ruleName) => { const rule = APEXGURU_RULES.find(r => r.name === ruleName); expect(rule).toBeDefined(); - expect(rule!.tags).not.toContain('Recommended'); + expect(rule!.tags).toEqual(['DevPreviewApexGuru']); }); }); @@ -75,15 +58,9 @@ describe('apexguru-rules', () => { expect(APEXGURU_RULES).toHaveLength(23); }); - it('every rule should have DevPreview in its tags', () => { - for (const rule of APEXGURU_RULES) { - expect(rule.tags).toContain('DevPreviewApexGuru'); - } - }); - - it('no rule should have Recommended in its tags', () => { + it('every rule should have exactly [DevPreviewApexGuru] as its tags', () => { for (const rule of APEXGURU_RULES) { - expect(rule.tags).not.toContain('Recommended'); + expect(rule.tags).toEqual(['DevPreviewApexGuru']); } });