agentleFS
grzmolgrzmol/vibe-force/skills/sf-code-analyzer-quality/SKILL.md

sf-code-analyzer-quality

Skill2 starsChanged 2 months agoMITView on GitHub

Salesforce Code Analyzer v5 and the rest of the local quality gate - sf code-analyzer run/rules/config with --workspace, --target, --rule-selector, --severity-threshold, --view, --output-file and --config-file, the pmd, eslint, regex, retire-js, flow, cpd and sfge (Salesforce Graph Engine) engines, code-analyzer.yml schema with rule overrides, ignores and suppressions, custom PMD rulesets and XPath rules, ESLint flat config with @salesforce/eslint-config-lwc, Prettier with prettier-plugin-apex, the 1-5 severity taxonomy and the analyzerFailSeverity gate, baseline and ratchet strategies for legacy code, SARIF output and CI annotation. Use when configuring or running static analysis, triaging violations, authoring or suppressing rules, or when running vf-check static, vf-check lint, vf-check format, vf-check analyzer, or vf-check local.

  • Installs packages

The file

We split this skill into the rules it gives an agent

3 rules. About 0 are common, 0 are distinctive, and 3 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 3

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    If Java or Python are unavailable in an environment (a lean CI image, for example), disable those engines in code-analyzer.yml rather than …

    line 30
  2. Very specific:

    Every code-analyzer command auto-discovers code-analyzer.yml or code-analyzer.yaml in the current folder.

    line 121
  3. Very specific:

    Write an XPath rule (or a Java rule packaged in a JAR) in a PMD ruleset XML file.

    line 169

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Code Analyzer and Quality Gates

When to use

  • Setting up or changing static analysis for a Salesforce project.
  • Triaging a vf-check analyzer failure, deciding fix versus suppress, or writing a suppression with a reason and a cap.
  • Authoring a custom PMD rule or a regex rule for a project convention.
  • Wiring Prettier/ESLint so vf-check format and vf-check lint are deterministic.
  • Introducing the gate to a legacy codebase without stopping delivery (baseline and ratchet).
  • Wave 2 of the vibe-force workflow: sf-quality-gate runs vf-check local and reports.
  • Org-wide debt rather than a diff: skill sf-technical-debt-audit (it turns recurring findings into regex rules authored here).

Toolchain and prerequisites

ToolInstallRequirement
Code Analyzer pluginsf plugins install code-analyzer (it is also a JIT plugin: running a code-analyzer command installs it automatically)Salesforce CLI; Node.js 20 or later if the CLI was installed via npm
pmd, cpd, sfge enginesbundled with the pluginJDK 11 or later
flow engine (Flow Scanner)bundledPython 3.10.0 or later
eslint, retire-js, regex enginesbundledNode, no extra runtime
Prettier + Apex pluginnpm i -D prettier prettier-plugin-apexNode 22 or later; JRE 17 or later only on platforms without a prebuilt native parser
LWC ESLintnpm i -D eslint @babel/core @babel/eslint-parser @salesforce/eslint-config-lwc @lwc/eslint-plugin-lwc @salesforce/eslint-plugin-lightning eslint-plugin-import eslint-plugin-jestESLint 9 for @salesforce/eslint-config-lwc 4.x and @lwc/eslint-plugin-lwc 3.x

If Java or Python are unavailable in an environment (a lean CI image, for example), disable those engines in code-analyzer.yml rather than tolerating engine errors:

engines:
  flow:
    disable_engine: true
  cpd:
    disable_engine: true

Config files live in the plugin and are referenced by the check runner; do not duplicate them per project: config/code-analyzer.yml, config/pmd/apex-ruleset.xml, config/eslint/eslint.config.mjs, config/prettier/.prettierrc.

Engines

EngineAnalyzesDetectsNotes
pmdApex, Visualforce, HTML, JavaScript, XMLsecurity, error-prone, performance, style, documentationJDK required; default languages apex and visualforce; AppExchange ruleset available via --rule-selector AppExchange
eslintJavaScript, TypeScript, LWC, Aura, CSS/SCSS (SLDS), JSXLWC rule violations, JS correctness, SLDS 2 misuse, React/JSX when enabledbundles @salesforce/eslint-config-lwc/recommended and @lwc/lwc-platform/recommended; supports ESLint 8 and 9
regexany text fileproject conventions, banned strings, trailing whitespacecustom rules need a global-modifier regex (/TODO/gi)
retire-jsbundled JavaScript, static resourcesknown-vulnerable third-party libraries
flowFlows, subflowsunsafe Flow patterns, data passed into without sharing ApexPython required
cpdmultiple languagescopy/paste duplicationJDK required; off by default in the vibe-force config
sfgeApexpath-based CRUD/FLS, sharing, null-pointer, loop-database, mass-schema-lookup issuesDeveloper Preview; JDK required; slowest engine

Severity taxonomy and the gate

SeverityNamevibe-force policy
1Criticalblocks; fix before the PR leaves wave 2
2Highblocks
3Moderateblocks (gates.analyzerFailSeverity default 3)
4Lowreported, does not block
5Inforeported, does not block

--severity-threshold makes the command exit non-zero when a violation meets or exceeds the given level; it accepts a number or its name (2 or "High"). vf-check analyzer passes gates.analyzerFailSeverity from .vibeforce/config.json.

Core patterns

1. List the rules before running them

# recommended rules for every available engine (the default selector is Recommended)
sf code-analyzer rules

# everything the pmd engine offers, with full detail
sf code-analyzer rules --rule-selector pmd --view detail

# scope to what actually applies to this codebase
sf code-analyzer rules --rule-selector all --workspace . --target force-app/**/*.cls

--rule-selector eslint is equivalent to eslint:all; append :Recommended to stay inside the recommended set. Criteria combine with : as AND and , as OR, and parentheses group; a selector containing parentheses must be double-quoted.

2. Run the same selectors

sf code-analyzer run --workspace . --rule-selector Recommended --severity-threshold 3 --view detail

# Apex-only path analysis, whole project as context, targeted files as entry points
sf code-analyzer run --workspace . --rule-selector sfge --target force-app/main/default/classes

# machine-readable plus human-readable in one pass
sf code-analyzer run --workspace . \
  --output-file .vibeforce/reports/analyzer.json \
  --output-file .vibeforce/reports/analyzer.html

--workspace is the analysis context (default .); --target narrows which files produce violations while keeping the workspace available to engines that need the whole project - Graph Engine compiles the workspace to build its call graph.

3. Generate and evolve the configuration

# write the current effective configuration, comments included, to a file
sf code-analyzer config --config-file ./code-analyzer.yml --output-file ./code-analyzer.yml

# just the recommended rules, including their unmodified default values
sf code-analyzer config --rule-selector Recommended --include-unmodified-rules

# what is configured for one rule
sf code-analyzer config --rule-selector pmd:ApexCRUDViolation

Every code-analyzer command auto-discovers code-analyzer.yml or code-analyzer.yaml in the current folder; --config-file overrides the location. Schema details: references/code-analyzer-cli.md and references/config-templates.md.

4. Override severity and tags instead of deleting rules

rules:
  pmd:
    ApexCRUDViolation:
      severity: "Critical"
      tags: ["Recommended", "Security", "VibeForceBlocking"]
    ApexDoc:
      disabled: true
  eslint:
    "@lwc/lwc/no-inner-html":
      severity: 1
  regex:
    NoTrailingWhiteSpace:
      tags: ["Suggestion"]

rules.<engine>.<rule>.severity accepts 1-5 or Critical|High|Moderate|Low|Info; tags replaces the rule's tags; disabled: true switches the rule off for every file.

5. Add a project convention as a regex rule

engines:
  regex:
    custom_rules:
      NoSeeAllData:
        regex: /@IsTest\s*\(\s*seeAllData\s*=\s*true\s*\)/gi
        file_extensions: [".cls"]
        description: "Tests must not use seeAllData=true."
        violation_message: "Replace seeAllData=true with @TestSetup-created data."
        severity: 2
        tags: ["Recommended", "VibeForce"]

The regex must carry a global modifier (/.../g or /.../gi); without it the engine errors. [unverified] The exact property names under custom_rules beyond regex and file_extensions were not enumerated on the fetched configuration pages; generate a skeleton with sf code-analyzer config --rule-selector regex --include-unmodified-rules and copy the shape it prints.

6. Add a custom PMD rule

  1. Write an XPath rule (or a Java rule packaged in a JAR) in a PMD ruleset XML file; use sf code-analyzer ast-dump to see the AST you are matching against.
  2. Register the ruleset:
engines:
  pmd:
    custom_rulesets:
      - "config/pmd/apex-ruleset.xml"
    java_classpath_entries: []
  1. Confirm registration, then run it:
sf code-analyzer rules --rule-selector pmd:Custom --view detail
sf code-analyzer run --rule-selector pmd:CheckForBadVariableNames --view detail

Code Analyzer tags every custom rule Custom and also adds a tag matching the <ruleset> name attribute with spaces removed. Custom PMD severities derive from PMD priority: 1 -> 2 (High), 2 -> 3 (Moderate), 3 -> 3 (Moderate), 4 -> 4 (Low), 5 -> 4 (Low).

7. Suppress narrowly, with a reason

In-source markers (processed by Code Analyzer v5 for any text file):

// code-analyzer-suppress-next-line eslint:no-console -- deliberate build-time diagnostic
console.log('bundle built');

Configuration-level bulk suppression:

suppressions:
  disable_suppressions: false
  "force-app/legacy/classes/":
    - rule_selector: "pmd:ApexCRUDViolation,pmd:ApexSharingViolations"
      max_suppressed_violations: 40
      reason: "Legacy module; tracked by VF-214, migrating to user mode per quarter."

Marker forms: code-analyzer-suppress, code-analyzer-suppress-line, code-analyzer-suppress-next-line, and code-analyzer-unsuppress to restore checking. A bare code-analyzer-suppress applies from that line to end of file or until an unsuppress marker, so prefer the line-scoped forms. Folder paths in suppressions must end with /. --no-suppressions ignores both marker and config suppressions, except that a suppressions.disable_suppressions setting in the config file takes precedence over the flag. PMD's own @SuppressWarnings('PMD.RuleName') annotation and // NOPMD comment still work for the PMD engine; vibe-force prefers the Code Analyzer markers because they work across every engine and are greppable.

8. Formatting and linting around the analyzer

# format check (what vf-check format runs)
npx prettier --check --config config/prettier/.prettierrc --ignore-path config/prettier/.prettierignore "force-app/**/*.{cls,trigger,js,html,css,xml,json}"

# lint LWC/Aura JS (what vf-check lint runs)
npx eslint --config config/eslint/eslint.config.mjs "force-app/**/lwc/**/*.js" "force-app/**/aura/**/*.js"

Prettier owns whitespace, ESLint owns JavaScript semantics, Code Analyzer owns Apex, metadata, and cross-language rules. Never encode formatting preferences as analyzer rules.

9. Composition of the vibe-force checks

vf-checkComposed of
formatprettier --check over changed Apex, LWC, Aura, XML, JS (--fix runs prettier --write)
linteslint over changed LWC/Aura JS
analyzersf code-analyzer run --config-file config/code-analyzer.yml --severity-threshold <gates.analyzerFailSeverity> over the changed files as --target with the package directories as --workspace
staticformat + lint + analyzer
localstatic + jest - the full no-org gate

Reports land in <project>/.vibeforce/reports/<check>-<ISO>.json with {check, startedAt, durationMs, status, gates, findings[], raw}. Exit codes: 0 pass, 1 gate failed, 2 misconfiguration or missing tool, 3 org/network error.

Anti-patterns

Anti-patternConsequenceInstead
--rule-selector eslint when you meant the recommended setruns every ESLint rule, floods the reporteslint:Recommended
--target without --workspace on Graph Engine runsGraph Engine cannot build the call graph and misses or misreports pathspass the whole project as --workspace
Deleting a rule from the ruleset to silence itloses the signal everywhere, silentlyrules.<engine>.<rule>.disabled with a comment, or a scoped suppression
Bare code-analyzer-suppress at the top of a filesuppresses to end of filecode-analyzer-suppress-next-line <selector> -- reason
Suppression without max_suppressed_violationsdebt grows invisiblyset a cap; new violations beyond it are reported normally
Running --rule-selector all in the PR gatenoisy, slow, unstable across plugin upgradesRecommended plus explicitly added rules
Turning off the whole sfge engine because it is slowloses path-based CRUD/FLS detectionkeep it in the nightly or pre-deploy run, raise java_thread_count, java_max_heap_size
auto_discover_eslint_config: true plus a conflicting local configplugin-version conflicts and engine errorspin eslint_config_file to config/eslint/eslint.config.mjs
Formatting rules enabled in both Prettier and ESLintfight each other on every savePrettier formats, ESLint lints
Using v4 syntax (sf scanner run --category Security)removed command surfacesee the migration table in references/code-analyzer-cli.md

Verification

# does the configuration resolve and are the intended rules selected?
sf code-analyzer config --config-file config/code-analyzer.yml --rule-selector Recommended
sf code-analyzer rules --config-file config/code-analyzer.yml --workspace . --view table

# the gate itself, on changed files only
node "${CLAUDE_PLUGIN_ROOT}/scripts/checks/vf-check.mjs" analyzer --changed

# the full local gate before any deploy
node "${CLAUDE_PLUGIN_ROOT}/scripts/checks/vf-check.mjs" local

# CI: SARIF for code scanning upload
sf code-analyzer run --workspace . --rule-selector Recommended \
  --severity-threshold 3 --output-file analyzer.sarif

A configuration change is proven by a before/after sf code-analyzer rules --rule-selector <rule> pair showing the new severity or tags, plus a run that exits 0 on clean code and 1 on a deliberately seeded violation.

References

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.