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

248 lines
6.8 KiB
Markdown

# 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
```yaml
# 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
```bash
npm install --save-dev eslint-plugin-my-custom
```
### Step 2: Create or update `eslint.config.js` (flat config)
```javascript
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`
```yaml
engines:
eslint:
eslint_config_file: "eslint.config.js"
```
### Step 4: Validate and run
```bash
# 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
```javascript
// 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
```javascript
module.exports = [
{
rules: {
'@lwc/lwc/no-restricted-browser-globals-during-ssr': 'error',
'@lwc/lwc/no-unsupported-ssr-properties': 'error'
}
}
];
```
### TypeScript strict rules
```javascript
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:
```yaml
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`:
```yaml
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:
```yaml
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
```javascript
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
```javascript
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
```javascript
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"` |