afv-library/skills/dx-code-analyzer-custom-rule-create/references/eslint-custom-plugins.md

6.8 KiB

ESLint Custom Rules for LWC/JavaScript

Create and integrate custom ESLint rules for Lightning Web Components, JavaScript, and TypeScript through Code Analyzer.

How It Works

Code Analyzer's ESLint engine loads your project's ESLint configuration alongside its built-in rules. You can:

  • Use your own eslint.config.js with custom plugins
  • Extend or override built-in base configs (LWC, TypeScript, SLDS, React)
  • Install any npm ESLint plugin and have Code Analyzer pick it up

Configuration

# code-analyzer.yml
engines:
  eslint:
    # Point to your project's ESLint config
    eslint_config_file: "eslint.config.js"

    # Or auto-discover from workspace (searches for eslint.config.js/mjs/cjs)
    auto_discover_eslint_config: true

    # Disable base configs you don't need
    disable_javascript_base_config: false
    disable_lwc_base_config: false
    disable_typescript_base_config: false
    disable_slds_base_config: false
    disable_react_base_config: false

    # Custom file extension mapping
    file_extensions:
      javascript: [".js", ".cjs", ".mjs", ".jsx"]
      typescript: [".ts", ".tsx"]
      html: [".html", ".htm", ".cmp"]
      css: [".css", ".scss"]

Adding Custom ESLint Plugins

Step 1: Install the plugin

npm install --save-dev eslint-plugin-my-custom

Step 2: Create or update eslint.config.js (flat config)

const myPlugin = require('eslint-plugin-my-custom');

module.exports = [
    {
        plugins: {
            'my-custom': myPlugin
        },
        rules: {
            'my-custom/no-dangerous-pattern': 'error',
            'my-custom/enforce-naming': ['warn', { pattern: '^[a-z]' }]
        }
    }
];

Step 3: Reference in code-analyzer.yml

engines:
  eslint:
    eslint_config_file: "eslint.config.js"

Step 4: Validate and run

# Check that custom rules appear
sf code-analyzer rules --rule-selector eslint

# Run against targets
sf code-analyzer run --rule-selector eslint --target force-app/main/default/lwc/

Common LWC Custom Rule Patterns

Enforce component naming convention

// eslint.config.js
module.exports = [
    {
        rules: {
            '@lwc/lwc/no-unknown-wire-adapters': 'error',
            '@lwc/lwc/no-api-reassignments': 'error',
            '@lwc/lwc/no-leaky-event-listeners': 'error'
        }
    }
];

Add SSR compatibility checks

module.exports = [
    {
        rules: {
            '@lwc/lwc/no-restricted-browser-globals-during-ssr': 'error',
            '@lwc/lwc/no-unsupported-ssr-properties': 'error'
        }
    }
];

TypeScript strict rules

module.exports = [
    {
        rules: {
            '@typescript-eslint/no-explicit-any': 'error',
            '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
            '@typescript-eslint/strict-boolean-expressions': 'warn'
        }
    }
];

Disabling Base Configs

When you want full control over which rules run, disable the built-in base configs:

engines:
  eslint:
    eslint_config_file: "eslint.config.js"
    disable_javascript_base_config: true
    disable_lwc_base_config: true
    disable_typescript_base_config: true

This prevents Code Analyzer's bundled rules from running — only your custom config's rules apply. Parsers are still configured (so files parse correctly), but no built-in rules fire.

Overriding Rule Severity via Config

After ESLint rules are loaded, override severity in code-analyzer.yml:

rules:
  eslint:
    no-unused-vars:
      severity: "Low"
    my-custom/dangerous-pattern:
      severity: "Critical"
    no-console:
      disabled: true

Legacy Config Support

If your project uses .eslintrc.js (ESLint v8 format), it still works:

engines:
  eslint:
    eslint_config_file: ".eslintrc.js"
    eslint_ignore_file: ".eslintignore"    # Only needed with legacy config

Flat config (eslint.config.js) is recommended for new projects.

Plugin Requirements

For Code Analyzer to pick up custom plugin rules, each rule must have:

  • meta.docs.description — rule description
  • meta.docs.url — documentation URL

Rules without these metadata fields are silently excluded. Deprecated rules are also excluded.

Banning APIs Without a Custom Plugin

Core ESLint includes powerful "restrictor" rules that can ban specific globals, syntax patterns, or properties — no plugin installation needed. These rules are NOT active by default — you must enable them in eslint.config.js:

no-restricted-globals — ban global functions/variables

module.exports = [
    {
        files: ["**/lwc/**/*.js"],
        rules: {
            "no-restricted-globals": ["error",
                { "name": "setTimeout", "message": "Use lifecycle hooks instead of setTimeout." },
                { "name": "setInterval", "message": "Use lifecycle hooks instead of setInterval." },
                { "name": "eval", "message": "eval is forbidden for security." }
            ]
        }
    }
];

no-restricted-syntax — ban arbitrary AST patterns

module.exports = [
    {
        files: ["**/lwc/**/*.js"],
        rules: {
            "no-restricted-syntax": ["error",
                { "selector": "CallExpression[callee.name='fetch']", "message": "Use Lightning Data Service instead of fetch." },
                { "selector": "NewExpression[callee.name='XMLHttpRequest']", "message": "Use fetch or LDS." }
            ]
        }
    }
];

no-restricted-properties — ban specific object methods

module.exports = [
    {
        files: ["**/lwc/**/*.js"],
        rules: {
            "no-restricted-properties": ["error",
                { "object": "window", "property": "location", "message": "Use NavigationMixin." },
                { "object": "document", "property": "cookie", "message": "Cookies are not available in LWC." }
            ]
        }
    }
];

⚠️ These rules will NOT appear in sf code-analyzer rules output until you:

  1. Create the eslint.config.js file with the rule enabled
  2. Set engines.eslint.eslint_config_file: "eslint.config.js" in code-analyzer.yml
  3. Run sf code-analyzer rules --rule-selector eslint:no-restricted-globals to verify

They are core ESLint rules, not Code Analyzer built-ins — they require your config to activate.

When to Use ESLint vs Regex vs PMD

Need Engine
JavaScript/TypeScript code patterns ESLint
LWC component best practices ESLint (with @lwc plugin)
HTML template issues ESLint (with SLDS or custom HTML plugin)
Simple string patterns in JS/TS ESLint (Regex cannot distinguish code from comments/strings in JS)
Apex code structure PMD (ESLint doesn't parse Apex)
Metadata XML governance PMD with language="xml"