mirror of
https://github.com/forcedotcom/afv-library.git
synced 2026-08-01 12:20:24 +08:00
175 lines
6.9 KiB
Markdown
175 lines
6.9 KiB
Markdown
# Regex Rule Schema Reference
|
|
|
|
Custom regex rules are defined inline in `code-analyzer.yml` under `engines.regex.custom_rules`.
|
|
|
|
## Complete Schema
|
|
|
|
```yaml
|
|
engines:
|
|
regex:
|
|
custom_rules:
|
|
RuleName: # Must match: /^[A-Za-z@][A-Za-z_0-9@\-/]*$/
|
|
regex: "/pattern/flags" # REQUIRED — JavaScript regex literal format
|
|
description: "What this checks" # REQUIRED — Purpose of the rule
|
|
violation_message: "Fix this" # Optional — Message shown on violation
|
|
severity: 3 # Optional — 1=Critical, 2=High, 3=Moderate, 4=Low, 5=Info
|
|
tags: # Optional — Default: ['Recommended', 'Custom']
|
|
- "Custom"
|
|
- "Security"
|
|
file_extensions: # Optional — Default: all text files
|
|
- ".cls"
|
|
- ".trigger"
|
|
regex_ignore: "/exception/i" # Optional — Matches excluded from violations
|
|
```
|
|
|
|
## Field Details
|
|
|
|
### `regex` (Required)
|
|
|
|
JavaScript regex literal format: `/pattern/flags`
|
|
|
|
| Format | Example | Meaning |
|
|
|--------|---------|---------|
|
|
| `/pattern/g` | `/TODO/g` | Case-sensitive, global (find all matches) — **minimum required** |
|
|
| `/pattern/gi` | `/todo/gi` | Global + case-insensitive |
|
|
| `/pattern/gm` | `/^import/gm` | Global + multiline (^ matches each line start) |
|
|
|
|
**Common pitfalls:**
|
|
- **The `/g` (global) flag is REQUIRED.** Code Analyzer rejects regex patterns without at least one flag after the closing `/`. Always include `/g` (or `/gi`, `/gm`, etc.).
|
|
- Backslashes must be escaped: `\d` → write as `/\\d/`
|
|
- Dots match any character: use `/\\.cls/` not `/.cls/`
|
|
- Regex is tested against file content line by line
|
|
|
|
**Named capture groups** narrow the violation highlight to a specific portion of the match:
|
|
```yaml
|
|
# Without named group — entire match is highlighted:
|
|
regex: "/System\\.debug\\([^)]*\\)/g"
|
|
# Highlights: "System.debug('hello')" (entire expression)
|
|
|
|
# With named group — only captured portion highlighted:
|
|
regex: "/(?<target>System\\.debug)\\([^)]*\\)/g"
|
|
# Highlights: "System.debug" (just the method name)
|
|
```
|
|
|
|
Use `(?<target>...)` when the regex needs surrounding context to match correctly, but the violation should point to a narrower location. Common patterns:
|
|
|
|
```yaml
|
|
# Highlight just the hardcoded ID, not the surrounding quotes
|
|
regex: "/['\"](?<target>[0-9a-zA-Z]{15,18})['\"]/g"
|
|
|
|
# Highlight the annotation, not the whole line
|
|
regex: "/(?<target>@SuppressWarnings\\([^)]*\\))/g"
|
|
|
|
# Highlight the method call within a larger expression
|
|
regex: "/(?<target>Database\\.query)\\(/g"
|
|
```
|
|
|
|
### `description` (Required)
|
|
|
|
Brief explanation of what the rule enforces. Used in rule listings and generated messages.
|
|
|
|
### `violation_message` (Optional)
|
|
|
|
Message shown when a violation is found. If omitted, auto-generated as:
|
|
> "A match of the regular expression `<regex>` was found for rule '<RuleName>': <description>"
|
|
|
|
Good violation messages tell the user HOW to fix, not just WHAT's wrong:
|
|
- ❌ "Hardcoded ID found"
|
|
- ✅ "Replace hardcoded Salesforce ID with a Custom Label or Custom Metadata reference"
|
|
|
|
### `severity` (Optional, default: 3)
|
|
|
|
| Value | Name | Meaning |
|
|
|-------|------|---------|
|
|
| 1 | Critical | Security vulnerability, must fix before deploy |
|
|
| 2 | High | Significant quality issue, should fix |
|
|
| 3 | Moderate | Recommended improvement |
|
|
| 4 | Low | Minor style issue |
|
|
| 5 | Info | Informational, no action required |
|
|
|
|
Also accepts string names: `"Critical"`, `"High"`, `"Moderate"`, `"Low"`, `"Info"`
|
|
|
|
### `tags` (Optional, default: ['Recommended', 'Custom'])
|
|
|
|
Array of tag strings. Used for `--rule-selector` filtering. Common tags:
|
|
- `Custom` — auto-applied to user-created rules
|
|
- `Security` — security-related rules
|
|
- `BestPractices` — coding standards
|
|
- `Performance` — performance anti-patterns
|
|
- `CodeStyle` — formatting/naming rules
|
|
|
|
### `file_extensions` (Optional, default: all text files)
|
|
|
|
Array of file extensions to scan. Each must start with `.` and match: `/^([.][a-zA-Z0-9-_]+)+$/`
|
|
|
|
Common values for Salesforce:
|
|
- `.cls` — Apex classes
|
|
- `.trigger` — Apex triggers
|
|
- `.js` — JavaScript/LWC
|
|
- `.html` — LWC HTML templates
|
|
- `.xml` — Metadata files
|
|
- `.page` — Visualforce pages
|
|
- `.component` — Visualforce components
|
|
|
|
### `regex_ignore` (Optional)
|
|
|
|
A second regex pattern — matches that ALSO match this pattern are excluded. Useful for reducing false positives.
|
|
|
|
⚠️ **`regex_ignore` operates per-LINE, not per-FILE.** It only skips a match if the same line also matches the ignore pattern. It does NOT exclude entire files or classes. For example, adding `/@isTest/` only suppresses violations on lines that literally contain `@isTest` — a hardcoded ID on line 50 of a test class still flags because line 50 doesn't contain `@isTest`.
|
|
|
|
To exclude entire files, use `ignores.files` in `code-analyzer.yml`:
|
|
```yaml
|
|
ignores:
|
|
files:
|
|
- "**/*Test.cls"
|
|
- "**/test/**"
|
|
```
|
|
|
|
```yaml
|
|
# Flag System.debug everywhere EXCEPT in lines with "// OK" comment
|
|
regex: "/System\\.debug/g"
|
|
regex_ignore: "/\\/\\/ OK/"
|
|
```
|
|
|
|
## Validation Rules
|
|
|
|
| Rule | Error if violated |
|
|
|------|-------------------|
|
|
| Name matches `/^[A-Za-z@][A-Za-z_0-9@\-/]*$/` | "Invalid rule name" |
|
|
| Regex starts and ends with `/` | "Invalid regex format" |
|
|
| File extensions start with `.` | "Invalid file extension" |
|
|
| Severity is 1-5 or valid name | "Invalid severity" |
|
|
| No duplicate rule names | "Rule already exists" |
|
|
|
|
## Multiple Rules Example
|
|
|
|
```yaml
|
|
engines:
|
|
regex:
|
|
custom_rules:
|
|
NoHardcodedIds:
|
|
regex: "/['\"][0-9a-zA-Z]{15,18}['\"]/g"
|
|
description: "Detects hardcoded Salesforce record IDs"
|
|
violation_message: "Use Custom Labels or Custom Metadata instead of hardcoded IDs"
|
|
severity: 2
|
|
tags: ["Custom", "Security"]
|
|
file_extensions: [".cls", ".trigger"]
|
|
|
|
NoTodos:
|
|
regex: "/TODO|FIXME|HACK/gi"
|
|
description: "Flags TODO/FIXME/HACK comments that should be resolved"
|
|
violation_message: "Resolve or remove this TODO/FIXME/HACK before merging"
|
|
severity: 4
|
|
tags: ["Custom", "BestPractices"]
|
|
|
|
NoSuppressWarnings:
|
|
regex: "/(?<target>@SuppressWarnings\\([^)]*\\))/g"
|
|
description: "Bans @SuppressWarnings annotations — violations must be fixed, not suppressed"
|
|
violation_message: "Remove @SuppressWarnings and fix the underlying violation instead"
|
|
severity: 2
|
|
tags: ["Recommended", "Custom", "BestPractices"]
|
|
file_extensions: [".cls", ".trigger"]
|
|
```
|
|
|
|
⚠️ **Note on test-class exclusion:** The `regex_ignore` field is per-LINE only. Adding `regex_ignore: "/@isTest/i"` does NOT exclude entire test classes — it only skips lines that literally contain `@isTest`. For SOQL rules that should skip test classes, use PMD/XPath instead (which can structurally check `[not(ancestor::UserClass[ModifierNode[@Test = true()]])]`). See the "Excluding Test Classes" section in SKILL.md.
|