Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG][code-analyzer] ESLint Plugin Conflict in Salesforce Code Analyzer 5.0 Beta 2 #1753

Open
TimPaulaskasDS opened this issue Mar 11, 2025 · 1 comment

Comments

@TimPaulaskasDS
Copy link

TimPaulaskasDS commented Mar 11, 2025

Have you tried to resolve this issue yourself first?

Yes

Bug Description

Bug Report: ESLint Plugin Conflict in Salesforce Code Analyzer 5.0 Beta 2

Description

When attempting to run Salesforce Code Analyzer 5.0 Beta 2 with an existing .eslintrc.json configuration, the analyzer encounters a conflict between a plugin supplied by a user-defined ESLint configuration file and a plugin supplied by the base configuration.

Error Message:

Selecting rules... Error
Error (1): The eslint engine encountered a conflict between a plugin supplied by one of your ESLint configuration files and a plugin supplied by the base configuration.
To continue to use your custom config you may need to disable one or more of the provided base configurations, by setting one or more of the following fields to true in your Code Analyzer configuration:
  engines:
    eslint:
      disable_javascript_base_config: true
      disable_lwc_base_config: true
      disable_typescript_base_config: true
Alternatively, you can use continue to use the base config by disabling your custom config by setting 'eslint_config_file' to null and setting 'auto_discover_eslint_config' to false inside of your Code Analyzer configuration:
  engines:
    eslint:
      eslint_config_file: null
      auto_discover_eslint_config: false

Error thrown from ESLint.isPathIgnored(/Users/tim.paulaskas/Code/SalesforceCI/force-app/main/default/aura/AccountGroupComponentAura/AccountGroupComponentAuraController.js)': Plugin "@lwc/lwc" was conflicted between "--config » @salesforce/eslint-config-lwc/recommended » /Users/tim.paulaskas/Code/SalesforceCI/node_modules/@salesforce/eslint-config-lwc/base.js" and "BaseConfig#overrides[0]".

ESLint options used: {
  "cwd": "/Users/tim.paulaskas/.local/share/sf/node_modules/@salesforce/plugin-code-analyzer/node_modules/@salesforce/code-analyzer-eslint-engine/dist",
  "errorOnUnmatchedPattern": false,
  "reportUnusedDisableDirectives": "off",
  "baseConfig": {
    "globals": {
      "$A": "readonly",
      "$Browser": "readonly",
      "$ContentAsset": "readonly",
      "$Label": "readonly",
      "$Locale": "readonly",
      "$Resource": "readonly"
    },
    "overrides": [
      {
        "files": [
          "*.js",
          "*.cjs",
          "*.mjs"
        ],
        "extends": [
          "@salesforce/eslint-config-lwc/base",
          "plugin:@lwc/lwc-platform/recommended",
          "eslint:recommended"
        ],
        "plugins": [
          "@lwc/eslint-plugin-lwc",
          "@lwc/lwc-platform",
          "@salesforce/eslint-plugin-lightning"
        ],
        "rules": {
          "@lwc/lwc/no-api-reassignments": "error",
          "@lwc/lwc/no-async-operation": "error",
          "@lwc/lwc/no-attributes-during-construction": "error",
          "@lwc/lwc/no-document-query": "error",
          "@lwc/lwc/no-inner-html": "error",
          "@lwc/lwc/no-leading-uppercase-api-name": "error",
          "@lwc/lwc/no-template-children": "error",
          "@lwc/lwc/prefer-custom-event": "error",
          "@lwc/lwc/valid-api": [
            "error",
            {
              "disallowUnderscoreUppercaseMix": true
            }
          ],
          "@lwc/lwc/valid-graphql-wire-adapter-callback-parameters": "error",
          "@salesforce/lightning/valid-apex-method-invocation": "error",
          "@lwc/lwc-platform/valid-offline-wire": "off"
        },
        "parser": "@babel/eslint-parser",
        "parserOptions": {
          "requireConfigFile": false,
          "babelOptions": {
            "babelrc": false,
            "configFile": false,
            "parserOpts": {
              "plugins": [
                "classProperties",
                [
                  "decorators",
                  {
                    "decoratorsBeforeExport": false
                  }
                ]
              ]
            }
          }
        }
      },
      {
        "files": [
          "*.ts"
        ],
        "extends": [
          "eslint:recommended",
          "plugin:@typescript-eslint/recommended"
        ],
        "plugins": [
          "@typescript-eslint"
        ],
        "parser": "@typescript-eslint/parser",
        "parserOptions": {
          "project": true
        }
      }
    ]
  },
  "useEslintrc": false,
  "overrideConfigFile": "/Users/tim.paulaskas/Code/SalesforceCI/.eslintrc.json",
  "ignorePath": "/Users/tim.paulaskas/Code/SalesforceCI/.eslintignore"
}

Steps to Reproduce

  1. Update Salesforce Code Analyzer to version 5.0 Beta 2.
  2. Run the analyzer on a Salesforce project with an existing .eslintrc.json file.
  3. Observe the error related to plugin conflicts.

Expected Behavior

The analyzer should respect the existing ESLint configuration or provide a seamless way to disable conflicting base configurations without requiring manual intervention.

Output / Logs

sfca-2025_03_11_08_58_25_821.log

Steps To Reproduce

sf code-analyzer run --rule-selector pmd --rule-selector retire-js --rule-selector regex --workspace "./force-app//*.cls" --workspace "./force-app//.trigger" --workspace "./force-app/**/.js" --workspace "./force-app//*.ts" --workspace "./force-app//*.apex" --output-file ./code-analyzer-logs/results.html --output-file ./code-analyzer-logs/results.csv

Expected Behavior

Expected Behavior

Salesforce Code Analyzer should correctly handle ESLint configurations without conflicting with user-defined .eslintrc.json settings. The expected behavior includes:

  1. Seamless Compatibility: The analyzer should not introduce conflicts between its base configuration and user-defined ESLint settings.
  2. Automatic Resolution: If conflicts arise, the tool should either:
    • Automatically resolve them without requiring manual intervention.
    • Provide a clear and actionable message guiding users on how to resolve the conflict.
  3. Configurable Behavior: Users should have the option to:
    • Use the base ESLint configuration provided by Salesforce Code Analyzer.
    • Override specific rules without having to disable the entire base configuration.
  4. Consistent Execution: The analyzer should execute without errors when a properly configured .eslintrc.json file is present, respecting user configurations while ensuring compatibility with Salesforce best practices.

Operating System

MacOS Sonoma 15.3.1

Salesforce CLI Version

@salesforce/cli/2.78.3 darwin-arm64 node-v22.14.0

Code Analyzer Plugin (code-analyzer) Version

code-analyzer 5.0.0-beta.2 (5.0.0-beta.2)

Node Version

v22.14.0

Java Version

openjdk version "17.0.14" 2025-01-21 OpenJDK Runtime Environment Homebrew (build 17.0.14+0) OpenJDK 64-Bit Server VM Homebrew (build 17.0.14+0, mixed mode, sharing)

Python Version

Python 3.13.2

Additional Context (Screenshots, Files, etc)

.eslintrc.json

.eslintignore

**/lwc/**/*.css
**/lwc/**/*.html
**/lwc/**/*.json
**/lwc/**/*.svg
**/lwc/**/*.xml
**/aura/**/*.auradoc
**/aura/**/*.cmp
**/aura/**/*.css
**/aura/**/*.design
**/aura/**/*.evt
**/aura/**/*.json
**/aura/**/*.svg
**/aura/**/*.tokens
**/aura/**/*.xml
**/aura/**/*.app
.sfdx
createNewQuoteAuraController.js

Workaround

Workaround

I cannot use the auto discover or the specified eslint configuration or ignore files.

To avoid the plugin conflict, I have to configure code-analyzer.yml as follows:

engines:
  eslint:
    disable_engine: false
    eslint_config_file: null
    eslint_ignore_file: null
    auto_discover_eslint_config: false

Urgency

Low

@stephen-carter-at-sf
Copy link
Collaborator

stephen-carter-at-sf commented Mar 13, 2025

Hello @TimPaulaskasDS ,

In our attempt to serve both types of users

  • low-code users who simply want us to recommend a set of rules from eslint
  • pro-code users who desire to have a more advanced eslint configuration
    we are unable to avoid certain conflicts that can arise with ESLint. As we provide our own recommended eslint configurations, if a user uses the same type of plugins or slightly different parsers within their configuration, then ESLint may not be able to automatically resolve these. Therefore, we try our best to give you an error message that explains what was found.

Regarding

Seamless Compatibility: The analyzer should not introduce conflicts between its base configuration and user-defined ESLint settings.
Automatic Resolution: If conflicts arise, the tool should either:
Automatically resolve them without requiring manual intervention.

We wish not to guess at what the user wants in these circumstances. The only way to resolve automatically would be to either remove one of our recommended configurations in favor of the users configuration or remove the users configuration in favor of our recommended configuration. But different users will want different things, which is why we point users to the ability to make these decisions within their code-analyzer.yml file.

Provide a clear and actionable message guiding users on how to resolve the conflict.
We provide as much detail as we can, but ultimately this is something ESLint should probably improve upon. I suggest opening an issue against ESLint's GitHub repo asking for more guidance on resolving conflicting configurations.

Configurable Behavior: Users should have the option to:
Use the base ESLint configuration provided by Salesforce Code Analyzer.
We do provide this ability.

Override specific rules without having to disable the entire base configuration.
We do provide this ability as well. As long as you do not introduce conflicting plugins or parsers that ESLint doesn't know how to resolve, your eslint configuration files may modify and add rules/plugins which automatically resolve with the base configuration.

Alternatively, you could just look at the configuration we set by looking at the log file that we produce during a call to any code-analyzer command and just apply those settings as the basis of your own custom configuration and then disable our configuration in favor of your own with:

engines:
  eslint:
    eslint_config_file: <your_config_file>
    disable_javascript_base_config: true
    disable_lwc_base_config: true
    disable_typescript_base_config: true

You can see how we build the configuration over at: https://github.com/forcedotcom/code-analyzer-core/blob/dev/packages/code-analyzer-eslint-engine/src/base-config.ts

Consistent Execution: The analyzer should execute without errors when a properly configured .eslintrc.json file is present, respecting user configurations while ensuring compatibility with Salesforce best practices.

This suggests that we shouldn't attempt to add in our own recommended rules, but instead just choose the user's .eslintrc.json file if it exists instead. This is a valid option, but most of the time, ESLint can resolve our configuration along side the user's configuration without issue... so we chose to allow ESLint to attempt to resolve all the configurations together.

We understand that the initial setup with an existing .estlintrc.json configuration file can be a pain point, but we do believe that giving the user the choice on how to resolve the conflict is a one time pain at first setup only and gives our users the ability to have more control over how code analyzer is configured.


OK, now to help you resolve your issue... I see you have the following .eslintrc.json configuration:

{
    "extends": [
        "@salesforce/eslint-config-lwc/recommended",
        "plugin:yml/recommended"
    ],
    "overrides": [
        {
            "files": ["*.yaml", "*.yml"],
            "parser": "yaml-eslint-parser",
            "plugins": ["yml"]
        }
    ]
}

which gets set in the overall eslint config internally with:

  "overrideConfigFile": "/Users/tim.paulaskas/Code/SalesforceCI/.eslintrc.json",

And the conflict says:

Error thrown from ESLint.isPathIgnored(/Users/tim.paulaskas/Code/SalesforceCI/force-app/main/default/aura/AccountGroupComponentAura/AccountGroupComponentAuraController.js)': Plugin "@lwc/lwc" was conflicted between "--config » @salesforce/eslint-config-lwc/recommended » /Users/tim.paulaskas/Code/SalesforceCI/node_modules/@salesforce/eslint-config-lwc/base.js" and "BaseConfig#overrides[0]".

My guess is that this happening because you are specifying

    "extends": [
        "@salesforce/eslint-config-lwc/recommended",

in your config and it sees that you have locally installed the plugin over at

/Users/tim.paulaskas/Code/SalesforceCI/node_modules/@salesforce/eslint-config-lwc/base.js

which conflicts with the one already provided by the Salesforce Code Analyzer. ESLint has an outstanding issue where it doesn't know how to choose the correct node_module's package if a base config and an override config both point to the same plugin but in different node_module directories because there could be version conflicts.

Keeping in mind that Salesforce Code Analyzer doesn't just take your eslint configuration file as the list of rules to run, but instead as the additional eslint rules that can be made available for rule selection, the easiest thing to do is just to remove

        "@salesforce/eslint-config-lwc/recommended",

from your .eslintrc.json file. If you don't want to do this globally for your other tools (like VSCode etc) then just make a separate salesforce code analyzer specific eslint configuration file (maybe called .eslintrc_sfca.json) that allows you to bring in your yaml based rules still for selection which will be added to the existing base config's rules. For example create a .eslintrc_sfca.json file that looks like this:

{
    "extends": [
        "plugin:yml/recommended"
    ],
    "overrides": [
        {
            "files": ["*.yaml", "*.yml"],
            "parser": "yaml-eslint-parser",
            "plugins": ["yml"]
        }
    ]
}

and then have your code-analyzer.yml file look like this:

engines:
  eslint:
    eslint_config_file: '.eslintrc_sfca.json'
    eslint_ignore_file: '.eslintignore'
    file_extensions:
      other: ['.yaml','.yml']

and then look at the output of

sf code-analyzer rules -r eslint

to see if it has everything you want.

If you want to override a specific rule that code analyzer already brings in, then simply add in a 'rules' section with the overrides that you want. For example: https://github.com/forcedotcom/code-analyzer-core/blob/dev/packages/code-analyzer-eslint-engine/test/test-data/legacyConfigCases/workspace_HasCustomConfigModifyingExistingRules/.eslintrc.json

Please let us know if this explains/resolves your issue. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants