eslint-plugin-sfmc 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -10
- package/docs/unicorn-compatibility.md +365 -0
- package/package.json +11 -5
- package/src/index.js +187 -0
- package/src/processor.js +20 -0
package/README.md
CHANGED
|
@@ -73,15 +73,17 @@ Add the following to your `.vscode/settings.json`:
|
|
|
73
73
|
|
|
74
74
|
### Marketing Cloud Next
|
|
75
75
|
|
|
76
|
-
Use the `-next` config variants when targeting **Marketing Cloud Next (MCN)**. MCN supports only a subset of AMPscript functions and does **not** support SSJS at all. Handlebars is MCN's templating language, so the
|
|
76
|
+
Use the `-next` config variants when targeting **Marketing Cloud Next (MCN)**. MCN supports only a subset of AMPscript functions and does **not** support SSJS at all. Handlebars is MCN's templating language, so the `-next` configs also lint the `{{...}}` helpers and `{!$...}` bindings extracted from HTML **and** standalone `.hbs` files (see [Handlebars Rules](#handlebars-rules-hbs-)).
|
|
77
77
|
|
|
78
|
-
| Config | Files
|
|
79
|
-
| ---------------------------------- |
|
|
80
|
-
| `sfmc.configs['ampscript-next']` | `**/*.ampscript`, `**/*.amp`
|
|
81
|
-
| `sfmc.configs['ssjs-next']` | `**/*.ssjs`
|
|
82
|
-
| `sfmc.configs['recommended-next']` | Both of the above
|
|
83
|
-
| `sfmc.configs['embedded-next']` | `**/*.html`
|
|
84
|
-
| `sfmc.configs['strict-next']` | All of the above + HTML
|
|
78
|
+
| Config | Files | What it does |
|
|
79
|
+
| ---------------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------- |
|
|
80
|
+
| `sfmc.configs['ampscript-next']` | `**/*.ampscript`, `**/*.amp` | AMPscript rules + flags functions unsupported in MCN (single config object) |
|
|
81
|
+
| `sfmc.configs['ssjs-next']` | `**/*.ssjs` | Flags all SSJS API calls as MCN-unsupported; all other SSJS quality rules disabled |
|
|
82
|
+
| `sfmc.configs['recommended-next']` | Both of the above + `**/*.hbs` | AMPscript MCN-aware + SSJS flagged + Handlebars rules for standalone `.hbs` files |
|
|
83
|
+
| `sfmc.configs['embedded-next']` | `**/*.html`, `**/*.hbs` | AMPscript MCN-aware + SSJS flagged + Handlebars rules for HTML-embedded code and `.hbs` |
|
|
84
|
+
| `sfmc.configs['strict-next']` | All of the above + HTML + `**/*.hbs` | All AMPscript rules at `error` severity + MCN flag; SSJS fully flagged; Handlebars rules on |
|
|
85
|
+
|
|
86
|
+
Standalone `.hbs` files (VS Code's built-in **Handlebars** language) are treated as MCN by default — Handlebars only runs on Marketing Cloud Next, so a `.hbs` file is always linted with the full Handlebars rule set. This is deliberately wired **only** into the `-next` configs; the classic `recommended` / `strict` (Engagement) configs never lint `.hbs`.
|
|
85
87
|
|
|
86
88
|
`recommended-next`, `embedded-next`, and `strict-next` are arrays — spread them with `...`.
|
|
87
89
|
|
|
@@ -143,7 +145,7 @@ export default [...sfmc.configs['recommended-next'], ...sfmc.configs['embedded-n
|
|
|
143
145
|
|
|
144
146
|
## Handlebars Rules (`hbs-*`)
|
|
145
147
|
|
|
146
|
-
Handlebars is the templating language for **Marketing Cloud Next (MCN)** only. These rules are enabled at `error` severity in the `-next` configs and are `off` in the classic (Engagement) configs — in classic SFMC, `{{...}}` is plain content and must not be flagged.
|
|
148
|
+
Handlebars is the templating language for **Marketing Cloud Next (MCN)** only. These rules are enabled at `error` severity in the `-next` configs — applied both to `{{...}}` extracted from HTML and to standalone `.hbs` files — and are `off` in the classic (Engagement) configs — in classic SFMC, `{{...}}` is plain content and must not be flagged.
|
|
147
149
|
|
|
148
150
|
| Rule | Default (`-next`) | Description |
|
|
149
151
|
| --------------------------------------------------------------------------------- | ----------------- | ------------------------------------------------------------------------------------ |
|
|
@@ -153,13 +155,60 @@ Handlebars is the templating language for **Marketing Cloud Next (MCN)** only. T
|
|
|
153
155
|
| [`sfmc/hbs-no-unsupported-construct`](docs/rules/hbs/no-unsupported-construct.md) | `error` | Disallow constructs unsupported by the MCN engine (partials, decorators, `log`) |
|
|
154
156
|
| [`sfmc/hbs-no-mcn-unsupported`](docs/rules/hbs/no-mcn-unsupported.md) | `error` | Flag helpers and bindings unavailable in the targeted MCN API version (`apiVersion`) |
|
|
155
157
|
|
|
158
|
+
## MSO / Outlook email checks
|
|
159
|
+
|
|
160
|
+
Email HTML for SFMC frequently contains **Outlook conditional comments** (`<!--[if mso]>…<![endif]-->`), MSO-only CSS, and VML fallbacks. These checks are provided by [`eslint-plugin-mso-email`](https://github.com/JoernBerkefeld/eslint-plugin-mso-email), which ships as a **bundled dependency** of `eslint-plugin-sfmc` — you do **not** load it separately.
|
|
161
|
+
|
|
162
|
+
The MSO rules are **auto-included** in the HTML-embedded configs: `embedded`, `strict`, `embedded-next`, and `strict-next`. When you lint an `.html` file with any of these, the combined `sfmc/sfmc` processor also extracts MSO conditional comments and the document body and runs the MSO rules on them — no extra processor or config to wire up, and no processor conflict.
|
|
163
|
+
|
|
164
|
+
| Rule (`mso/*`) | Default (embedded/strict) | Description |
|
|
165
|
+
| ---------------------------------- | ------------------------- | ------------------------------------------------------------- |
|
|
166
|
+
| `mso/valid-mso-condition` | `error` | Validate the `[if …]` expression syntax of MSO comments |
|
|
167
|
+
| `mso/matching-mso-endif` | `error` | Require every MSO opener to have a matching `<![endif]>` |
|
|
168
|
+
| `mso/matching-mso-endif-type` | `warn` | Require the endif comment style to match its opener |
|
|
169
|
+
| `mso/no-unknown-mso-property` | `warn` | Flag unknown `mso-*` CSS properties |
|
|
170
|
+
| `mso/vml-requires-namespace` | `warn` | Require the `v:` VML namespace declaration when VML is used |
|
|
171
|
+
| `mso/no-unknown-vml-tag` | `warn` | Flag unknown `v:*` VML tags |
|
|
172
|
+
| `mso/no-unknown-vml-attribute` | `warn` | Flag unknown attributes on VML tags |
|
|
173
|
+
| `mso/table-presentation-role` | `warn` | Require `role="presentation"` on layout tables |
|
|
174
|
+
|
|
175
|
+
Severities above are the same in `embedded`, `strict`, `embedded-next`, and `strict-next` (MSO markup is engine-agnostic — it behaves identically for Engagement and Next). For MSO rule details and options, see the [`eslint-plugin-mso-email` docs](https://github.com/JoernBerkefeld/eslint-plugin-mso-email).
|
|
176
|
+
|
|
177
|
+
## Using `eslint-plugin-unicorn` with SFMC
|
|
178
|
+
|
|
179
|
+
[`eslint-plugin-unicorn`](https://github.com/sindresorhus/eslint-plugin-unicorn) is a high-quality, widely used plugin that we **strongly recommend** — but it is built for modern JavaScript, not SFMC's **SSJS** runtime. SFMC SSJS runs on a JINT-based ES3/ES5-era engine that lacks many built-ins (`Array#includes`, `String#startsWith`, `Set`, `Map`, `Object.fromEntries`, `Math.trunc`, spread `...`, ES modules, `async`/`await`, …).
|
|
180
|
+
|
|
181
|
+
If you enable unicorn's `recommended` set on SSJS, about **46** of its 300 recommended rules would either **autofix your code to a missing built-in** (breaking it at runtime) or **forbid a required SFMC workaround**. `eslint-plugin-sfmc` offers an **optional** override config that turns off exactly those 46 rules for SSJS.
|
|
182
|
+
|
|
183
|
+
**Important — this is optional and only needed if you use unicorn.** `eslint-plugin-sfmc` does **not** depend on or load unicorn. The override configs are plain rules objects with **no** `plugins` key, so they only resolve when your own unicorn config (which registers the `unicorn` plugin) is loaded **earlier** in the flat-config array. Spread the sfmc override **after** it:
|
|
184
|
+
|
|
185
|
+
```js
|
|
186
|
+
import sfmc from 'eslint-plugin-sfmc';
|
|
187
|
+
import eslintPluginUnicorn from 'eslint-plugin-unicorn';
|
|
188
|
+
|
|
189
|
+
export default [
|
|
190
|
+
eslintPluginUnicorn.configs.recommended, // you opt in — registers the `unicorn` plugin
|
|
191
|
+
...sfmc.configs.recommended,
|
|
192
|
+
...sfmc.configs['unicorn-ssjs'], // OPTIONAL: off the 46 SFMC-incompatible unicorn rules for SSJS
|
|
193
|
+
// For SSJS embedded in HTML (<script runat="server">), also add:
|
|
194
|
+
// ...sfmc.configs['unicorn-ssjs-embedded'],
|
|
195
|
+
];
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
| Config | Files | What it does |
|
|
199
|
+
| ------------------------------------- | -------------------- | ----------------------------------------------------------------- |
|
|
200
|
+
| `sfmc.configs['unicorn-ssjs']` | `**/*.ssjs` | Turns off the 46 SFMC-incompatible unicorn rules for SSJS |
|
|
201
|
+
| `sfmc.configs['unicorn-ssjs-embedded']` | `**/*.html/*.js` | Same 46-rule override for SSJS embedded in HTML |
|
|
202
|
+
|
|
203
|
+
Only **46** of unicorn's 300 recommended rules are overridden — the other **254** stay active. If you don't use unicorn, omit these configs entirely. For the full rule-by-rule breakdown (with rationale and SFMC evidence links, pinned to unicorn v71.1.0), see [docs/unicorn-compatibility.md](docs/unicorn-compatibility.md).
|
|
204
|
+
|
|
156
205
|
## Processors
|
|
157
206
|
|
|
158
207
|
| Processor | Purpose |
|
|
159
208
|
| ---------------- | ------------------------------------------------------------- |
|
|
160
209
|
| `sfmc/ampscript` | Extract `%%[ ]%%`, `%%= =%%`, `<script language="ampscript">` |
|
|
161
210
|
| `sfmc/ssjs` | Extract `<script runat="server">` (non-ampscript) |
|
|
162
|
-
| `sfmc/sfmc` | Combined: extracts
|
|
211
|
+
| `sfmc/sfmc` | Combined: extracts AMPscript, SSJS, Handlebars, and MSO from HTML |
|
|
163
212
|
|
|
164
213
|
## License
|
|
165
214
|
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
# `eslint-plugin-unicorn` compatibility with SFMC SSJS
|
|
2
|
+
|
|
3
|
+
> **Compatibility analysis for [`eslint-plugin-unicorn@71.1.0`](https://github.com/sindresorhus/eslint-plugin-unicorn).**
|
|
4
|
+
>
|
|
5
|
+
> ⚠️ **Version warning:** This classification was done against `eslint-plugin-unicorn` **v71.1.0** (300 recommended rules). Newer versions of unicorn may add, rename, or change rules that are **not** yet classified here. Re-audit this page whenever you upgrade unicorn — a rule added in a later version could autofix SSJS into runtime-breaking code without being in the override list below.
|
|
6
|
+
|
|
7
|
+
`eslint-plugin-unicorn` is an excellent, actively maintained plugin that we **strongly recommend** — but it targets modern JavaScript engines, not the Salesforce Marketing Cloud **SSJS** runtime. SFMC SSJS runs on a JINT-based ES3/ES5-era engine that is missing many built-ins (`Array#includes`, `String#startsWith`, `Set`, `Map`, `Object.fromEntries`, `Math.trunc`, spread `...`, ES modules, `async`/`await`, …). See the SFMC evidence pages:
|
|
8
|
+
|
|
9
|
+
- **ECMAScript built-ins support** — <https://ssjs.guide/ecmascript-builtins/>
|
|
10
|
+
- **Engine limitations** — <https://ssjs.guide/engine-limitations/>
|
|
11
|
+
|
|
12
|
+
Of unicorn's **300** recommended rules (v71.1.0), **254** are safe to keep on for SSJS and **46** should be turned off. `eslint-plugin-sfmc` ships an **optional** override config (`unicorn-ssjs` / `unicorn-ssjs-embedded`) that turns off exactly those 46 for SSJS files. `eslint-plugin-sfmc` does **not** depend on or load unicorn — the override only takes effect when you have loaded unicorn yourself. See [Section 3](#section-3--how-to-apply).
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Section 1 — Rules OK as-is (254)
|
|
17
|
+
|
|
18
|
+
These recommended rules are **not** disabled by the override config. They are either genuinely SFMC-safe (readability / best-practice rules that work on the ES3/ES5 engine) or **inert** on SSJS — many target the DOM, Node.js, Promises, TypeScript, or ES modules and therefore never fire on server-side SFMC code. Each links to its official unicorn documentation.
|
|
19
|
+
|
|
20
|
+
<!-- BEGIN 254-OK-LIST -->
|
|
21
|
+
- [better-dom-traversing](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/better-dom-traversing.md)
|
|
22
|
+
- [catch-error-name](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/catch-error-name.md)
|
|
23
|
+
- [class-reference-in-static-methods](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/class-reference-in-static-methods.md)
|
|
24
|
+
- [consistent-assert](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-assert.md)
|
|
25
|
+
- [consistent-boolean-name](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-boolean-name.md)
|
|
26
|
+
- [consistent-class-member-order](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-class-member-order.md)
|
|
27
|
+
- [consistent-compound-words](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-compound-words.md)
|
|
28
|
+
- [consistent-conditional-object-spread](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-conditional-object-spread.md)
|
|
29
|
+
- [consistent-date-clone](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-date-clone.md)
|
|
30
|
+
- [consistent-empty-array-spread](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-empty-array-spread.md)
|
|
31
|
+
- [consistent-existence-index-check](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-existence-index-check.md)
|
|
32
|
+
- [consistent-export-decorator-position](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-export-decorator-position.md)
|
|
33
|
+
- [consistent-function-scoping](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-function-scoping.md)
|
|
34
|
+
- [consistent-json-file-read](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-json-file-read.md)
|
|
35
|
+
- [consistent-optional-chaining](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-optional-chaining.md)
|
|
36
|
+
- [consistent-template-literal-escape](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-template-literal-escape.md)
|
|
37
|
+
- [consistent-tuple-labels](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-tuple-labels.md)
|
|
38
|
+
- [default-export-style](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/default-export-style.md)
|
|
39
|
+
- [dom-node-dataset](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/dom-node-dataset.md)
|
|
40
|
+
- [empty-brace-spaces](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/empty-brace-spaces.md)
|
|
41
|
+
- [error-message](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/error-message.md)
|
|
42
|
+
- [escape-case](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/escape-case.md)
|
|
43
|
+
- [expiring-todo-comments](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/expiring-todo-comments.md)
|
|
44
|
+
- [explicit-length-check](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/explicit-length-check.md)
|
|
45
|
+
- [explicit-timer-delay](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/explicit-timer-delay.md)
|
|
46
|
+
- [filename-case](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/filename-case.md)
|
|
47
|
+
- [import-style](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/import-style.md)
|
|
48
|
+
- [isolated-functions](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/isolated-functions.md)
|
|
49
|
+
- [logical-assignment-operators](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/logical-assignment-operators.md)
|
|
50
|
+
- [max-nested-calls](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/max-nested-calls.md)
|
|
51
|
+
- [name-replacements](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/name-replacements.md)
|
|
52
|
+
- [new-for-builtins](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/new-for-builtins.md)
|
|
53
|
+
- [no-abusive-eslint-disable](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-abusive-eslint-disable.md)
|
|
54
|
+
- [no-accessor-recursion](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-accessor-recursion.md)
|
|
55
|
+
- [no-accidental-bitwise-operator](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-accidental-bitwise-operator.md)
|
|
56
|
+
- [no-anonymous-default-export](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-anonymous-default-export.md)
|
|
57
|
+
- [no-array-callback-reference](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-array-callback-reference.md)
|
|
58
|
+
- [no-array-concat-in-loop](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-array-concat-in-loop.md)
|
|
59
|
+
- [no-array-fill-with-reference-type](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-array-fill-with-reference-type.md)
|
|
60
|
+
- [no-array-from-fill](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-array-from-fill.md)
|
|
61
|
+
- [no-array-method-this-argument](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-array-method-this-argument.md)
|
|
62
|
+
- [no-array-reduce](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-array-reduce.md)
|
|
63
|
+
- [no-array-sort](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-array-sort.md)
|
|
64
|
+
- [no-array-sort-for-min-max](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-array-sort-for-min-max.md)
|
|
65
|
+
- [no-array-splice](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-array-splice.md)
|
|
66
|
+
- [no-async-promise-finally](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-async-promise-finally.md)
|
|
67
|
+
- [no-await-expression-member](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-await-expression-member.md)
|
|
68
|
+
- [no-await-in-promise-methods](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-await-in-promise-methods.md)
|
|
69
|
+
- [no-blob-to-file](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-blob-to-file.md)
|
|
70
|
+
- [no-boolean-sort-comparator](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-boolean-sort-comparator.md)
|
|
71
|
+
- [no-break-in-nested-loop](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-break-in-nested-loop.md)
|
|
72
|
+
- [no-canvas-to-image](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-canvas-to-image.md)
|
|
73
|
+
- [no-chained-comparison](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-chained-comparison.md)
|
|
74
|
+
- [no-collection-bracket-access](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-collection-bracket-access.md)
|
|
75
|
+
- [no-computed-property-existence-check](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-computed-property-existence-check.md)
|
|
76
|
+
- [no-confusing-array-splice](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-confusing-array-splice.md)
|
|
77
|
+
- [no-confusing-array-with](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-confusing-array-with.md)
|
|
78
|
+
- [no-console-spaces](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-console-spaces.md)
|
|
79
|
+
- [no-constant-zero-expression](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-constant-zero-expression.md)
|
|
80
|
+
- [no-declarations-before-early-exit](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-declarations-before-early-exit.md)
|
|
81
|
+
- [no-document-cookie](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-document-cookie.md)
|
|
82
|
+
- [no-double-comparison](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-double-comparison.md)
|
|
83
|
+
- [no-duplicate-if-branches](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-duplicate-if-branches.md)
|
|
84
|
+
- [no-duplicate-logical-operands](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-duplicate-logical-operands.md)
|
|
85
|
+
- [no-duplicate-loops](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-duplicate-loops.md)
|
|
86
|
+
- [no-duplicate-set-values](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-duplicate-set-values.md)
|
|
87
|
+
- [no-empty-file](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-empty-file.md)
|
|
88
|
+
- [no-error-property-assignment](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-error-property-assignment.md)
|
|
89
|
+
- [no-exports-in-scripts](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-exports-in-scripts.md)
|
|
90
|
+
- [no-for-loop](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-for-loop.md)
|
|
91
|
+
- [no-global-object-property-assignment](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-global-object-property-assignment.md)
|
|
92
|
+
- [no-immediate-mutation](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-immediate-mutation.md)
|
|
93
|
+
- [no-impossible-length-comparison](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-impossible-length-comparison.md)
|
|
94
|
+
- [no-incorrect-query-selector](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-incorrect-query-selector.md)
|
|
95
|
+
- [no-incorrect-template-string-interpolation](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-incorrect-template-string-interpolation.md)
|
|
96
|
+
- [no-invalid-argument-count](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-invalid-argument-count.md)
|
|
97
|
+
- [no-invalid-character-comparison](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-invalid-character-comparison.md)
|
|
98
|
+
- [no-invalid-fetch-options](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-invalid-fetch-options.md)
|
|
99
|
+
- [no-invalid-remove-event-listener](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-invalid-remove-event-listener.md)
|
|
100
|
+
- [no-invalid-well-known-symbol-methods](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-invalid-well-known-symbol-methods.md)
|
|
101
|
+
- [no-late-current-target-access](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-late-current-target-access.md)
|
|
102
|
+
- [no-late-event-control](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-late-event-control.md)
|
|
103
|
+
- [no-lonely-if](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-lonely-if.md)
|
|
104
|
+
- [no-loop-iterable-mutation](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-loop-iterable-mutation.md)
|
|
105
|
+
- [no-magic-array-flat-depth](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-magic-array-flat-depth.md)
|
|
106
|
+
- [no-mismatched-map-key](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-mismatched-map-key.md)
|
|
107
|
+
- [no-misrefactored-assignment](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-misrefactored-assignment.md)
|
|
108
|
+
- [no-named-default](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-named-default.md)
|
|
109
|
+
- [no-negated-array-predicate](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-negated-array-predicate.md)
|
|
110
|
+
- [no-negated-comparison](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-negated-comparison.md)
|
|
111
|
+
- [no-negated-condition](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-negated-condition.md)
|
|
112
|
+
- [no-negation-in-equality-check](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-negation-in-equality-check.md)
|
|
113
|
+
- [no-nested-ternary](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-nested-ternary.md)
|
|
114
|
+
- [no-new-array](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-new-array.md)
|
|
115
|
+
- [no-new-buffer](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-new-buffer.md)
|
|
116
|
+
- [no-non-function-verb-prefix](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-non-function-verb-prefix.md)
|
|
117
|
+
- [no-nonstandard-builtin-properties](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-nonstandard-builtin-properties.md)
|
|
118
|
+
- [no-null](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-null.md)
|
|
119
|
+
- [no-object-as-default-parameter](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-object-as-default-parameter.md)
|
|
120
|
+
- [no-object-methods-with-collections](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-object-methods-with-collections.md)
|
|
121
|
+
- [no-optional-chaining-on-undeclared-variable](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-optional-chaining-on-undeclared-variable.md)
|
|
122
|
+
- [no-process-exit](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-process-exit.md)
|
|
123
|
+
- [no-redundant-comparison](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-redundant-comparison.md)
|
|
124
|
+
- [no-return-array-push](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-return-array-push.md)
|
|
125
|
+
- [no-selector-as-dom-name](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-selector-as-dom-name.md)
|
|
126
|
+
- [no-single-promise-in-promise-methods](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-single-promise-in-promise-methods.md)
|
|
127
|
+
- [no-static-only-class](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-static-only-class.md)
|
|
128
|
+
- [no-subtraction-comparison](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-subtraction-comparison.md)
|
|
129
|
+
- [no-thenable](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-thenable.md)
|
|
130
|
+
- [no-this-assignment](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-this-assignment.md)
|
|
131
|
+
- [no-this-outside-of-class](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-this-outside-of-class.md)
|
|
132
|
+
- [no-top-level-assignment-in-function](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-top-level-assignment-in-function.md)
|
|
133
|
+
- [no-top-level-side-effects](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-top-level-side-effects.md)
|
|
134
|
+
- [no-typeof-undefined](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-typeof-undefined.md)
|
|
135
|
+
- [no-uncalled-method](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-uncalled-method.md)
|
|
136
|
+
- [no-undeclared-class-members](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-undeclared-class-members.md)
|
|
137
|
+
- [no-unnecessary-array-flat-depth](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unnecessary-array-flat-depth.md)
|
|
138
|
+
- [no-unnecessary-array-flat-map](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unnecessary-array-flat-map.md)
|
|
139
|
+
- [no-unnecessary-array-splice-count](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unnecessary-array-splice-count.md)
|
|
140
|
+
- [no-unnecessary-await](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unnecessary-await.md)
|
|
141
|
+
- [no-unnecessary-boolean-comparison](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unnecessary-boolean-comparison.md)
|
|
142
|
+
- [no-unnecessary-fetch-options](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unnecessary-fetch-options.md)
|
|
143
|
+
- [no-unnecessary-global-this](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unnecessary-global-this.md)
|
|
144
|
+
- [no-unnecessary-nested-ternary](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unnecessary-nested-ternary.md)
|
|
145
|
+
- [no-unnecessary-polyfills](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unnecessary-polyfills.md)
|
|
146
|
+
- [no-unnecessary-slice-end](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unnecessary-slice-end.md)
|
|
147
|
+
- [no-unnecessary-splice](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unnecessary-splice.md)
|
|
148
|
+
- [no-unnecessary-string-trim](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unnecessary-string-trim.md)
|
|
149
|
+
- [no-unreadable-array-destructuring](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unreadable-array-destructuring.md)
|
|
150
|
+
- [no-unreadable-for-of-expression](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unreadable-for-of-expression.md)
|
|
151
|
+
- [no-unreadable-iife](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unreadable-iife.md)
|
|
152
|
+
- [no-unreadable-object-destructuring](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unreadable-object-destructuring.md)
|
|
153
|
+
- [no-unsafe-buffer-conversion](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unsafe-buffer-conversion.md)
|
|
154
|
+
- [no-unsafe-promise-all-settled-values](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unsafe-promise-all-settled-values.md)
|
|
155
|
+
- [no-unsafe-property-key](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unsafe-property-key.md)
|
|
156
|
+
- [no-unsafe-string-replacement](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unsafe-string-replacement.md)
|
|
157
|
+
- [no-unused-array-method-return](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unused-array-method-return.md)
|
|
158
|
+
- [no-useless-boolean-cast](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-boolean-cast.md)
|
|
159
|
+
- [no-useless-coercion](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-coercion.md)
|
|
160
|
+
- [no-useless-collection-argument](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-collection-argument.md)
|
|
161
|
+
- [no-useless-compound-assignment](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-compound-assignment.md)
|
|
162
|
+
- [no-useless-concat](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-concat.md)
|
|
163
|
+
- [no-useless-continue](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-continue.md)
|
|
164
|
+
- [no-useless-delete-check](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-delete-check.md)
|
|
165
|
+
- [no-useless-else](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-else.md)
|
|
166
|
+
- [no-useless-error-capture-stack-trace](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-error-capture-stack-trace.md)
|
|
167
|
+
- [no-useless-fallback-in-spread](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-fallback-in-spread.md)
|
|
168
|
+
- [no-useless-iterator-to-array](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-iterator-to-array.md)
|
|
169
|
+
- [no-useless-length-check](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-length-check.md)
|
|
170
|
+
- [no-useless-logical-operand](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-logical-operand.md)
|
|
171
|
+
- [no-useless-override](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-override.md)
|
|
172
|
+
- [no-useless-promise-resolve-reject](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-promise-resolve-reject.md)
|
|
173
|
+
- [no-useless-recursion](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-recursion.md)
|
|
174
|
+
- [no-useless-spread](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-spread.md)
|
|
175
|
+
- [no-useless-switch-case](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-switch-case.md)
|
|
176
|
+
- [no-useless-template-literals](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-template-literals.md)
|
|
177
|
+
- [no-useless-undefined](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-undefined.md)
|
|
178
|
+
- [no-xor-as-exponentiation](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-xor-as-exponentiation.md)
|
|
179
|
+
- [no-zero-fractions](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-zero-fractions.md)
|
|
180
|
+
- [number-literal-case](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/number-literal-case.md)
|
|
181
|
+
- [numeric-separators-style](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/numeric-separators-style.md)
|
|
182
|
+
- [operator-assignment](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/operator-assignment.md)
|
|
183
|
+
- [prefer-abort-signal-any](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-abort-signal-any.md)
|
|
184
|
+
- [prefer-abort-signal-timeout](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-abort-signal-timeout.md)
|
|
185
|
+
- [prefer-add-event-listener](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-add-event-listener.md)
|
|
186
|
+
- [prefer-add-event-listener-options](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-add-event-listener-options.md)
|
|
187
|
+
- [prefer-aggregate-error](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-aggregate-error.md)
|
|
188
|
+
- [prefer-array-from-map](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-array-from-map.md)
|
|
189
|
+
- [prefer-array-from-range](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-array-from-range.md)
|
|
190
|
+
- [prefer-array-iterable-methods](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-array-iterable-methods.md)
|
|
191
|
+
- [prefer-array-slice](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-array-slice.md)
|
|
192
|
+
- [prefer-await](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-await.md)
|
|
193
|
+
- [prefer-bigint-literals](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-bigint-literals.md)
|
|
194
|
+
- [prefer-blob-reading-methods](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-blob-reading-methods.md)
|
|
195
|
+
- [prefer-block-statement-over-iife](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-block-statement-over-iife.md)
|
|
196
|
+
- [prefer-boolean-return](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-boolean-return.md)
|
|
197
|
+
- [prefer-class-fields](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-class-fields.md)
|
|
198
|
+
- [prefer-classlist-toggle](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-classlist-toggle.md)
|
|
199
|
+
- [prefer-continue](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-continue.md)
|
|
200
|
+
- [prefer-default-parameters](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-default-parameters.md)
|
|
201
|
+
- [prefer-direct-iteration](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-direct-iteration.md)
|
|
202
|
+
- [prefer-dom-node-append](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-dom-node-append.md)
|
|
203
|
+
- [prefer-dom-node-remove](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-dom-node-remove.md)
|
|
204
|
+
- [prefer-dom-node-replace-children](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-dom-node-replace-children.md)
|
|
205
|
+
- [prefer-dom-node-text-content](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-dom-node-text-content.md)
|
|
206
|
+
- [prefer-early-return](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-early-return.md)
|
|
207
|
+
- [prefer-else-if](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-else-if.md)
|
|
208
|
+
- [prefer-event-target](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-event-target.md)
|
|
209
|
+
- [prefer-flat-math-min-max](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-flat-math-min-max.md)
|
|
210
|
+
- [prefer-get-or-insert-computed](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-get-or-insert-computed.md)
|
|
211
|
+
- [prefer-global-this](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-global-this.md)
|
|
212
|
+
- [prefer-has-check](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-has-check.md)
|
|
213
|
+
- [prefer-hoisting-branch-code](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-hoisting-branch-code.md)
|
|
214
|
+
- [prefer-https](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-https.md)
|
|
215
|
+
- [prefer-identifier-import-export-specifiers](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-identifier-import-export-specifiers.md)
|
|
216
|
+
- [prefer-includes-over-repeated-comparisons](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-includes-over-repeated-comparisons.md)
|
|
217
|
+
- [prefer-iterable-in-constructor](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-iterable-in-constructor.md)
|
|
218
|
+
- [prefer-iterator-to-array](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-iterator-to-array.md)
|
|
219
|
+
- [prefer-iterator-to-array-at-end](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-iterator-to-array-at-end.md)
|
|
220
|
+
- [prefer-keyboard-event-key](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-keyboard-event-key.md)
|
|
221
|
+
- [prefer-location-assign](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-location-assign.md)
|
|
222
|
+
- [prefer-logical-operator-over-ternary](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-logical-operator-over-ternary.md)
|
|
223
|
+
- [prefer-math-abs](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-math-abs.md)
|
|
224
|
+
- [prefer-math-constants](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-math-constants.md)
|
|
225
|
+
- [prefer-math-min-max](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-math-min-max.md)
|
|
226
|
+
- [prefer-minimal-ternary](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-minimal-ternary.md)
|
|
227
|
+
- [prefer-modern-dom-apis](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-modern-dom-apis.md)
|
|
228
|
+
- [prefer-object-define-properties](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-object-define-properties.md)
|
|
229
|
+
- [prefer-object-destructuring-defaults](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-object-destructuring-defaults.md)
|
|
230
|
+
- [prefer-object-iterable-methods](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-object-iterable-methods.md)
|
|
231
|
+
- [prefer-observer-apis](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-observer-apis.md)
|
|
232
|
+
- [prefer-path2d](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-path2d.md)
|
|
233
|
+
- [prefer-private-class-fields](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-private-class-fields.md)
|
|
234
|
+
- [prefer-promise-try](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-promise-try.md)
|
|
235
|
+
- [prefer-promise-with-resolvers](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-promise-with-resolvers.md)
|
|
236
|
+
- [prefer-prototype-methods](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-prototype-methods.md)
|
|
237
|
+
- [prefer-query-selector](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-query-selector.md)
|
|
238
|
+
- [prefer-queue-microtask](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-queue-microtask.md)
|
|
239
|
+
- [prefer-regexp-test](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-regexp-test.md)
|
|
240
|
+
- [prefer-response-static-json](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-response-static-json.md)
|
|
241
|
+
- [prefer-scoped-selector](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-scoped-selector.md)
|
|
242
|
+
- [prefer-simple-condition-first](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-simple-condition-first.md)
|
|
243
|
+
- [prefer-simple-sort-comparator](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-simple-sort-comparator.md)
|
|
244
|
+
- [prefer-simplified-conditions](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-simplified-conditions.md)
|
|
245
|
+
- [prefer-single-array-predicate](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-single-array-predicate.md)
|
|
246
|
+
- [prefer-single-call](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-single-call.md)
|
|
247
|
+
- [prefer-single-object-destructuring](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-single-object-destructuring.md)
|
|
248
|
+
- [prefer-single-replace](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-single-replace.md)
|
|
249
|
+
- [prefer-smaller-scope](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-smaller-scope.md)
|
|
250
|
+
- [prefer-split-limit](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-split-limit.md)
|
|
251
|
+
- [prefer-switch](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-switch.md)
|
|
252
|
+
- [prefer-ternary](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-ternary.md)
|
|
253
|
+
- [prefer-toggle-attribute](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-toggle-attribute.md)
|
|
254
|
+
- [prefer-type-error](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-type-error.md)
|
|
255
|
+
- [prefer-type-literal-last](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-type-literal-last.md)
|
|
256
|
+
- [prefer-unary-minus](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-unary-minus.md)
|
|
257
|
+
- [prefer-unicode-code-point-escapes](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-unicode-code-point-escapes.md)
|
|
258
|
+
- [prefer-url-can-parse](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-url-can-parse.md)
|
|
259
|
+
- [prefer-url-href](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-url-href.md)
|
|
260
|
+
- [prefer-url-search-parameters](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-url-search-parameters.md)
|
|
261
|
+
- [prefer-while-loop-condition](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-while-loop-condition.md)
|
|
262
|
+
- [relative-url-style](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/relative-url-style.md)
|
|
263
|
+
- [require-array-sort-compare](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/require-array-sort-compare.md)
|
|
264
|
+
- [require-css-escape](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/require-css-escape.md)
|
|
265
|
+
- [require-module-attributes](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/require-module-attributes.md)
|
|
266
|
+
- [require-module-specifiers](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/require-module-specifiers.md)
|
|
267
|
+
- [require-number-to-fixed-digits-argument](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/require-number-to-fixed-digits-argument.md)
|
|
268
|
+
- [require-passive-events](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/require-passive-events.md)
|
|
269
|
+
- [require-proxy-trap-boolean-return](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/require-proxy-trap-boolean-return.md)
|
|
270
|
+
- [switch-case-braces](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/switch-case-braces.md)
|
|
271
|
+
- [switch-case-break-position](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/switch-case-break-position.md)
|
|
272
|
+
- [template-indent](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/template-indent.md)
|
|
273
|
+
- [text-encoding-identifier-case](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/text-encoding-identifier-case.md)
|
|
274
|
+
- [throw-new-error](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/throw-new-error.md)
|
|
275
|
+
<!-- END 254-OK-LIST -->
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Section 2 — Rules to override for SSJS (46)
|
|
280
|
+
|
|
281
|
+
These 46 recommended rules either **autofix code to a missing built-in**, **forbid a documented SFMC workaround**, or **enforce ES-module / async / ES6-only syntax** the engine cannot run. The override config sets each to `'off'` for SSJS. All 46 are confirmed `recommended` in unicorn v71.1.0.
|
|
282
|
+
|
|
283
|
+
### Group A — autofix to a missing built-in / forbid a SFMC workaround (41)
|
|
284
|
+
|
|
285
|
+
| Rule | Why it breaks SSJS | SFMC evidence |
|
|
286
|
+
|---|---|---|
|
|
287
|
+
| [`prefer-includes`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-includes.md) | Pushes `Array/String#includes()` — missing in SSJS | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
288
|
+
| [`prefer-string-starts-ends-with`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-string-starts-ends-with.md) | Pushes `String#startsWith/endsWith` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
289
|
+
| [`prefer-string-trim-start-end`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-string-trim-start-end.md) | Pushes `trimStart/trimEnd` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
290
|
+
| [`prefer-string-slice`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-string-slice.md) | Forbids `substring`, the SFMC-safe choice | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
291
|
+
| [`prefer-string-replace-all`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-string-replace-all.md) | Pushes `String#replaceAll` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
292
|
+
| [`prefer-string-repeat`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-string-repeat.md) | Pushes `String#repeat` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
293
|
+
| [`prefer-string-pad-start-end`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-string-pad-start-end.md) | Pushes `padStart/padEnd` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
294
|
+
| [`prefer-string-match-all`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-string-match-all.md) | Pushes `String#matchAll` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
295
|
+
| [`prefer-string-raw`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-string-raw.md) | Pushes `String.raw` tag — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
296
|
+
| [`prefer-code-point`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-code-point.md) | Pushes `codePointAt/fromCodePoint` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
297
|
+
| [`prefer-array-find`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-array-find.md) | Pushes `Array#find/findLast` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
298
|
+
| [`prefer-array-some`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-array-some.md) | Pushes `Array#some` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
299
|
+
| [`prefer-array-index-of`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-array-index-of.md) | Pushes `findIndex/findLastIndex` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
300
|
+
| [`prefer-array-flat`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-array-flat.md) | Pushes `Array#flat` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
301
|
+
| [`prefer-array-flat-map`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-array-flat-map.md) | Pushes `Array#flatMap` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
302
|
+
| [`prefer-array-last-methods`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-array-last-methods.md) | Pushes `.at()/findLast` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
303
|
+
| [`prefer-array-from-async`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-array-from-async.md) | Pushes `Array.fromAsync` — missing + async unsupported | [Engine limitations](https://ssjs.guide/engine-limitations/) |
|
|
304
|
+
| [`no-array-reverse`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-array-reverse.md) | Autofixes to `Array#toReversed()` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
305
|
+
| [`prefer-at`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-at.md) | Pushes `.at()` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
306
|
+
| [`prefer-negative-index`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-negative-index.md) | Pushes `.at()` — missing; forbids the `.length - i` workaround | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
307
|
+
| [`prefer-spread`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-spread.md) | Pushes spread `...` — ES6 syntax, throws on ES3 | [Engine limitations](https://ssjs.guide/engine-limitations/) |
|
|
308
|
+
| [`prefer-date-now`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-date-now.md) | Pushes `Date.now()` — missing static | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
309
|
+
| [`prefer-object-from-entries`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-object-from-entries.md) | Pushes `Object.fromEntries` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
310
|
+
| [`prefer-reflect-apply`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-reflect-apply.md) | Pushes `Reflect.apply` — `Reflect` missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
311
|
+
| [`prefer-number-properties`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-number-properties.md) | Pushes `Number.parseInt/parseFloat/isNaN/isFinite` statics — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
312
|
+
| [`prefer-number-is-safe-integer`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-number-is-safe-integer.md) | Pushes `Number.isSafeInteger` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
313
|
+
| [`prefer-number-coercion`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-number-coercion.md) | Number-static patterns unsafe on the ES3 engine | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
314
|
+
| [`prefer-global-number-constants`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-global-number-constants.md) | Pushes `Number.NaN/Number.POSITIVE_INFINITY` etc. — missing statics | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
315
|
+
| [`prefer-native-coercion-functions`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-native-coercion-functions.md) | Native coercion refs that are missing/unsafe | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
316
|
+
| [`prefer-math-trunc`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-math-trunc.md) | Pushes `Math.trunc` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
317
|
+
| [`prefer-modern-math-apis`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-modern-math-apis.md) | Pushes `Math.log10/log2/hypot` — missing; forbids `Math.log(x)/Math.LN10` and `Math.sqrt(a*a+b*b)` workarounds | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
318
|
+
| [`no-instanceof-builtins`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-instanceof-builtins.md) | Autofixes `instanceof Array` to `Array.isArray` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
319
|
+
| [`no-for-each`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-for-each.md) | Assumes `.forEach` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
320
|
+
| [`prefer-set-has`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-set-has.md) | Pushes `Set` — ES6, unsupported | [Engine limitations](https://ssjs.guide/engine-limitations/) |
|
|
321
|
+
| [`prefer-set-size`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-set-size.md) | Pushes `Set` — ES6, unsupported | [Engine limitations](https://ssjs.guide/engine-limitations/) |
|
|
322
|
+
| [`prefer-set-methods`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-set-methods.md) | Pushes `Set` methods — ES2024, unsupported | [Engine limitations](https://ssjs.guide/engine-limitations/) |
|
|
323
|
+
| [`prefer-map-from-entries`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-map-from-entries.md) | Pushes `Map` + `Object.fromEntries` — unsupported | [Engine limitations](https://ssjs.guide/engine-limitations/) |
|
|
324
|
+
| [`prefer-group-by`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-group-by.md) | Pushes `Object.groupBy/Map.groupBy` — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
325
|
+
| [`prefer-iterator-helpers`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-iterator-helpers.md) | Pushes the iterator-helper protocol — unsupported | [Engine limitations](https://ssjs.guide/engine-limitations/) |
|
|
326
|
+
| [`prefer-structured-clone`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-structured-clone.md) | Pushes `structuredClone` global — missing | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
327
|
+
| [`require-array-join-separator`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/require-array-join-separator.md) | Safe alone, but grouped here to avoid pushing modern array idioms under the strict set | [ECMAScript built-ins](https://ssjs.guide/ecmascript-builtins/) |
|
|
328
|
+
|
|
329
|
+
### Group B — forbid ES6+ syntax / ES-module / async constructs (5)
|
|
330
|
+
|
|
331
|
+
| Rule | Why it breaks SSJS | SFMC evidence |
|
|
332
|
+
|---|---|---|
|
|
333
|
+
| [`prefer-optional-catch-binding`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-optional-catch-binding.md) | Pushes `catch {}` (ES2019) — may not parse on ES3 | [Engine limitations](https://ssjs.guide/engine-limitations/) |
|
|
334
|
+
| [`prefer-module`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-module.md) | Pushes ES modules — unsupported | [Engine limitations](https://ssjs.guide/engine-limitations/) |
|
|
335
|
+
| [`prefer-node-protocol`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-node-protocol.md) | Pushes `node:` imports — no module system | [Engine limitations](https://ssjs.guide/engine-limitations/) |
|
|
336
|
+
| [`prefer-top-level-await`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-top-level-await.md) | Pushes top-level `await` — async unsupported | [Engine limitations](https://ssjs.guide/engine-limitations/) |
|
|
337
|
+
| [`prefer-export-from`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-export-from.md) | Pushes `export … from` — ES modules | [Engine limitations](https://ssjs.guide/engine-limitations/) |
|
|
338
|
+
|
|
339
|
+
> **Note:** [`prefer-regexp-test`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-regexp-test.md) stays **active** — `RegExp#test` exists in SFMC SSJS, so it is intentionally **not** in the override list.
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## Section 3 — How to apply
|
|
344
|
+
|
|
345
|
+
The override is **optional** and **SSJS-scoped**. `eslint-plugin-sfmc` never loads unicorn; the override is a plain rules object that only resolves when you have loaded your own unicorn config **earlier** in the flat-config array (that config registers the `unicorn` plugin). Spread the sfmc override **after** it:
|
|
346
|
+
|
|
347
|
+
```js
|
|
348
|
+
import sfmc from 'eslint-plugin-sfmc';
|
|
349
|
+
import eslintPluginUnicorn from 'eslint-plugin-unicorn';
|
|
350
|
+
|
|
351
|
+
export default [
|
|
352
|
+
eslintPluginUnicorn.configs.recommended, // you opt in — registers the `unicorn` plugin
|
|
353
|
+
...sfmc.configs.recommended,
|
|
354
|
+
...sfmc.configs['unicorn-ssjs'], // OPTIONAL: off the 46 SFMC-incompatible unicorn rules for SSJS
|
|
355
|
+
// For SSJS embedded in HTML, also add:
|
|
356
|
+
// ...sfmc.configs['unicorn-ssjs-embedded'],
|
|
357
|
+
];
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
| Config | Applies to |
|
|
361
|
+
|---|---|
|
|
362
|
+
| `unicorn-ssjs` | `**/*.ssjs` |
|
|
363
|
+
| `unicorn-ssjs-embedded` | `**/*.html/*.js` (SSJS extracted from `<script runat="server">`) |
|
|
364
|
+
|
|
365
|
+
If you don't use unicorn, omit these configs entirely — nothing else in `eslint-plugin-sfmc` references them.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-sfmc",
|
|
3
|
-
"version": "4.
|
|
4
|
-
"description": "ESLint plugin for Salesforce Marketing Cloud
|
|
3
|
+
"version": "4.1.0",
|
|
4
|
+
"description": "ESLint plugin for Salesforce Marketing Cloud Engagement+Next - AMPscript, Server-Side JavaScript (SSJS) and Handlebars",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"exports": {
|
|
@@ -27,15 +27,21 @@
|
|
|
27
27
|
"eslintplugin",
|
|
28
28
|
"ampscript",
|
|
29
29
|
"ssjs",
|
|
30
|
+
"handlebars",
|
|
31
|
+
"hbs",
|
|
30
32
|
"salesforce",
|
|
31
33
|
"marketing-cloud",
|
|
32
|
-
"sfmc"
|
|
34
|
+
"sfmc",
|
|
35
|
+
"marketing-cloud-next",
|
|
36
|
+
"mcn"
|
|
33
37
|
],
|
|
34
38
|
"dependencies": {
|
|
35
39
|
"@handlebars/parser": "^2.2.2",
|
|
36
40
|
"ampscript-data": "^3.0.0",
|
|
37
41
|
"ampscript-parser": "^0.2.0",
|
|
42
|
+
"eslint-plugin-mso-email": "^2.0.0",
|
|
38
43
|
"handlebars-data": "^0.3.0",
|
|
44
|
+
"mso-conditional-parser": "^2.0.1",
|
|
39
45
|
"ssjs-data": "^0.14.0"
|
|
40
46
|
},
|
|
41
47
|
"peerDependencies": {
|
|
@@ -60,9 +66,9 @@
|
|
|
60
66
|
"@eslint/js": "^10.0.1",
|
|
61
67
|
"eslint": "^10.6.0",
|
|
62
68
|
"eslint-config-prettier": "^10.1.8",
|
|
63
|
-
"eslint-plugin-jsdoc": "^63.0.
|
|
69
|
+
"eslint-plugin-jsdoc": "^63.0.12",
|
|
64
70
|
"eslint-plugin-prettier": "^5.5.6",
|
|
65
|
-
"eslint-plugin-unicorn": "^
|
|
71
|
+
"eslint-plugin-unicorn": "^71.1.0",
|
|
66
72
|
"globals": "^17.7.0",
|
|
67
73
|
"husky": "^9.1.7",
|
|
68
74
|
"lint-staged": "^17.0.8",
|
package/src/index.js
CHANGED
|
@@ -71,6 +71,16 @@ import ampscriptProcessor from './ampscript-processor.js';
|
|
|
71
71
|
import ssjsProcessor from './ssjs-processor.js';
|
|
72
72
|
import combinedProcessor from './processor.js';
|
|
73
73
|
|
|
74
|
+
// ── MSO / Outlook email plugin (auto-included in embedded/strict configs) ──────
|
|
75
|
+
|
|
76
|
+
import msoPlugin from 'eslint-plugin-mso-email';
|
|
77
|
+
import msoEslintParser from 'eslint-plugin-mso-email/mso-parser';
|
|
78
|
+
import htmlEslintParser from 'eslint-plugin-mso-email/html-parser';
|
|
79
|
+
import {
|
|
80
|
+
MSO_VIRTUAL_BASENAME,
|
|
81
|
+
DOCUMENT_VIRTUAL_BASENAME,
|
|
82
|
+
} from 'eslint-plugin-mso-email/comment-pattern';
|
|
83
|
+
|
|
74
84
|
// ── Data imports ──────────────────────────────────────────────────────────────
|
|
75
85
|
import { SSJS_GLOBALS_MAP } from 'ssjs-data';
|
|
76
86
|
|
|
@@ -291,6 +301,143 @@ const hbsOffRules = {
|
|
|
291
301
|
/** Shared languageOptions for linting virtual `.hbs` files. */
|
|
292
302
|
const hbsLanguageOptions = { parser: handlebarsParser };
|
|
293
303
|
|
|
304
|
+
/**
|
|
305
|
+
* Config block(s) for **standalone** `.hbs` files (a real Handlebars file on
|
|
306
|
+
* disk, opened under VS Code's built-in `handlebars` language id). Handlebars
|
|
307
|
+
* only runs on Marketing Cloud Next, so a `.hbs` file is always treated as MCN
|
|
308
|
+
* and the full `hbsNextRules` set applies — no processor is needed because the
|
|
309
|
+
* whole file is Handlebars and is parsed directly. This is deliberately wired
|
|
310
|
+
* only into the `-next` configs; `recommended`/`strict` (MCE) never lint `.hbs`.
|
|
311
|
+
*
|
|
312
|
+
* @param {string} configName - the owning config, used for a unique block name
|
|
313
|
+
* @returns {object[]} a single-entry array with the standalone `.hbs` config
|
|
314
|
+
*/
|
|
315
|
+
function standaloneHandlebarsConfigs(configName) {
|
|
316
|
+
return [
|
|
317
|
+
{
|
|
318
|
+
name: `sfmc/${configName}-standalone-handlebars`,
|
|
319
|
+
plugins: { sfmc: plugin },
|
|
320
|
+
languageOptions: { ...hbsLanguageOptions },
|
|
321
|
+
files: ['**/*.hbs'],
|
|
322
|
+
rules: { ...hbsNextRules },
|
|
323
|
+
},
|
|
324
|
+
];
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// ── Optional eslint-plugin-unicorn override for SSJS ──────────────────────────
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* The 46 `eslint-plugin-unicorn` recommended rules (analysed against
|
|
331
|
+
* unicorn v71.1.0) that are incompatible with the SFMC SSJS (JINT / ES3-ES5)
|
|
332
|
+
* engine — they either autofix code to a missing built-in or forbid a required
|
|
333
|
+
* SFMC workaround, or enforce ES-module / async / ES6-only syntax that the
|
|
334
|
+
* engine cannot run. Each is mapped to `'off'`.
|
|
335
|
+
*
|
|
336
|
+
* This is exposed via the optional `unicorn-ssjs` / `unicorn-ssjs-embedded`
|
|
337
|
+
* configs. eslint-plugin-sfmc does NOT depend on or load unicorn; these configs
|
|
338
|
+
* are plain rules objects (no `plugins` key) and only resolve when the user has
|
|
339
|
+
* loaded their own unicorn config earlier in the flat-config array. See
|
|
340
|
+
* docs/unicorn-compatibility.md for the full rationale and evidence links.
|
|
341
|
+
*/
|
|
342
|
+
const unicornSsjsOffRules = {
|
|
343
|
+
// Group A — autofix to a missing built-in / forbid a documented SFMC workaround
|
|
344
|
+
'unicorn/prefer-includes': 'off',
|
|
345
|
+
'unicorn/prefer-string-starts-ends-with': 'off',
|
|
346
|
+
'unicorn/prefer-string-trim-start-end': 'off',
|
|
347
|
+
'unicorn/prefer-string-slice': 'off',
|
|
348
|
+
'unicorn/prefer-string-replace-all': 'off',
|
|
349
|
+
'unicorn/prefer-string-repeat': 'off',
|
|
350
|
+
'unicorn/prefer-string-pad-start-end': 'off',
|
|
351
|
+
'unicorn/prefer-string-match-all': 'off',
|
|
352
|
+
'unicorn/prefer-string-raw': 'off',
|
|
353
|
+
'unicorn/prefer-code-point': 'off',
|
|
354
|
+
'unicorn/prefer-array-find': 'off',
|
|
355
|
+
'unicorn/prefer-array-some': 'off',
|
|
356
|
+
'unicorn/prefer-array-index-of': 'off',
|
|
357
|
+
'unicorn/prefer-array-flat': 'off',
|
|
358
|
+
'unicorn/prefer-array-flat-map': 'off',
|
|
359
|
+
'unicorn/prefer-array-last-methods': 'off',
|
|
360
|
+
'unicorn/prefer-array-from-async': 'off',
|
|
361
|
+
'unicorn/no-array-reverse': 'off',
|
|
362
|
+
'unicorn/prefer-at': 'off',
|
|
363
|
+
'unicorn/prefer-negative-index': 'off',
|
|
364
|
+
'unicorn/prefer-spread': 'off',
|
|
365
|
+
'unicorn/prefer-date-now': 'off',
|
|
366
|
+
'unicorn/prefer-object-from-entries': 'off',
|
|
367
|
+
'unicorn/prefer-reflect-apply': 'off',
|
|
368
|
+
'unicorn/prefer-number-properties': 'off',
|
|
369
|
+
'unicorn/prefer-number-is-safe-integer': 'off',
|
|
370
|
+
'unicorn/prefer-number-coercion': 'off',
|
|
371
|
+
'unicorn/prefer-global-number-constants': 'off',
|
|
372
|
+
'unicorn/prefer-native-coercion-functions': 'off',
|
|
373
|
+
'unicorn/prefer-math-trunc': 'off',
|
|
374
|
+
'unicorn/prefer-modern-math-apis': 'off',
|
|
375
|
+
'unicorn/no-instanceof-builtins': 'off',
|
|
376
|
+
'unicorn/no-for-each': 'off',
|
|
377
|
+
'unicorn/prefer-set-has': 'off',
|
|
378
|
+
'unicorn/prefer-set-size': 'off',
|
|
379
|
+
'unicorn/prefer-set-methods': 'off',
|
|
380
|
+
'unicorn/prefer-map-from-entries': 'off',
|
|
381
|
+
'unicorn/prefer-group-by': 'off',
|
|
382
|
+
'unicorn/prefer-iterator-helpers': 'off',
|
|
383
|
+
'unicorn/prefer-structured-clone': 'off',
|
|
384
|
+
'unicorn/require-array-join-separator': 'off',
|
|
385
|
+
// Group B — forbid ES6+ syntax / ES-module / async constructs
|
|
386
|
+
'unicorn/prefer-optional-catch-binding': 'off',
|
|
387
|
+
'unicorn/prefer-module': 'off',
|
|
388
|
+
'unicorn/prefer-node-protocol': 'off',
|
|
389
|
+
'unicorn/prefer-top-level-await': 'off',
|
|
390
|
+
'unicorn/prefer-export-from': 'off',
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
// ── MSO / Outlook email rule configs (auto-included, no separate plugin load) ──
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Virtual-file globs for the MSO blocks the combined processor appends.
|
|
397
|
+
* sfmc's processor only runs on `**\/*.html`, so MSO blocks are emitted as
|
|
398
|
+
* `email.html/{index}_mso-comments.mso` and `email.html/{index}_document.msohtml`.
|
|
399
|
+
*/
|
|
400
|
+
const msoVirtualFiles = [`**/*.html/*_${MSO_VIRTUAL_BASENAME}`];
|
|
401
|
+
const msoDocumentFiles = [`**/*.html/*_${DOCUMENT_VIRTUAL_BASENAME}`];
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Returns MSO's two rule-config entries (conditional-comment rules on `.mso`
|
|
405
|
+
* virtual files, document rules on `.msohtml` virtual files) wired to the MSO
|
|
406
|
+
* parsers. The `mso/html-processor` entry from eslint-plugin-mso-email is
|
|
407
|
+
* intentionally omitted — sfmc's own combined processor already emits the MSO
|
|
408
|
+
* blocks, so registering MSO's processor too would create a processor conflict.
|
|
409
|
+
*
|
|
410
|
+
* @returns {import('eslint').Linter.Config[]} MSO conditional + document rule configs.
|
|
411
|
+
*/
|
|
412
|
+
function msoRuleConfigs() {
|
|
413
|
+
return [
|
|
414
|
+
{
|
|
415
|
+
name: 'sfmc/mso-conditional-rules',
|
|
416
|
+
plugins: { mso: msoPlugin },
|
|
417
|
+
files: msoVirtualFiles,
|
|
418
|
+
languageOptions: { parser: msoEslintParser },
|
|
419
|
+
rules: {
|
|
420
|
+
'mso/valid-mso-condition': 'error',
|
|
421
|
+
'mso/matching-mso-endif': 'error',
|
|
422
|
+
'mso/matching-mso-endif-type': 'warn',
|
|
423
|
+
},
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
name: 'sfmc/mso-document-rules',
|
|
427
|
+
plugins: { mso: msoPlugin },
|
|
428
|
+
files: msoDocumentFiles,
|
|
429
|
+
languageOptions: { parser: htmlEslintParser },
|
|
430
|
+
rules: {
|
|
431
|
+
'mso/no-unknown-mso-property': 'warn',
|
|
432
|
+
'mso/vml-requires-namespace': 'warn',
|
|
433
|
+
'mso/no-unknown-vml-tag': 'warn',
|
|
434
|
+
'mso/no-unknown-vml-attribute': 'warn',
|
|
435
|
+
'mso/table-presentation-role': 'warn',
|
|
436
|
+
},
|
|
437
|
+
},
|
|
438
|
+
];
|
|
439
|
+
}
|
|
440
|
+
|
|
294
441
|
// ── Configs (defined after plugin so they can reference it) ───────────────────
|
|
295
442
|
|
|
296
443
|
plugin.configs = {
|
|
@@ -384,6 +531,8 @@ plugin.configs = {
|
|
|
384
531
|
files: ['**/*.html/*.hbs'],
|
|
385
532
|
rules: { ...hbsOffRules },
|
|
386
533
|
},
|
|
534
|
+
// MSO / Outlook conditional-comment + VML/CSS checks (auto-included).
|
|
535
|
+
...msoRuleConfigs(),
|
|
387
536
|
],
|
|
388
537
|
|
|
389
538
|
/**
|
|
@@ -440,6 +589,8 @@ plugin.configs = {
|
|
|
440
589
|
files: ['**/*.html/*.hbs'],
|
|
441
590
|
rules: { ...hbsOffRules },
|
|
442
591
|
},
|
|
592
|
+
// MSO / Outlook conditional-comment + VML/CSS checks (auto-included).
|
|
593
|
+
...msoRuleConfigs(),
|
|
443
594
|
],
|
|
444
595
|
|
|
445
596
|
// ── Marketing Cloud Next configs ──────────────────────────────────────────
|
|
@@ -500,6 +651,8 @@ plugin.configs = {
|
|
|
500
651
|
},
|
|
501
652
|
rules: { ...ssjsMcnRules },
|
|
502
653
|
},
|
|
654
|
+
// Standalone .hbs files are Handlebars templates — always MCN.
|
|
655
|
+
...standaloneHandlebarsConfigs('recommended-next'),
|
|
503
656
|
],
|
|
504
657
|
|
|
505
658
|
/**
|
|
@@ -541,6 +694,10 @@ plugin.configs = {
|
|
|
541
694
|
files: ['**/*.html/*.hbs'],
|
|
542
695
|
rules: { ...hbsNextRules },
|
|
543
696
|
},
|
|
697
|
+
// Standalone .hbs files are Handlebars templates — always MCN.
|
|
698
|
+
...standaloneHandlebarsConfigs('embedded-next'),
|
|
699
|
+
// MSO / Outlook conditional-comment + VML/CSS checks (auto-included).
|
|
700
|
+
...msoRuleConfigs(),
|
|
544
701
|
],
|
|
545
702
|
|
|
546
703
|
/**
|
|
@@ -603,7 +760,37 @@ plugin.configs = {
|
|
|
603
760
|
files: ['**/*.html/*.hbs'],
|
|
604
761
|
rules: { ...hbsNextRules },
|
|
605
762
|
},
|
|
763
|
+
// Standalone .hbs files are Handlebars templates — always MCN.
|
|
764
|
+
...standaloneHandlebarsConfigs('strict-next'),
|
|
765
|
+
// MSO / Outlook conditional-comment + VML/CSS checks (auto-included).
|
|
766
|
+
...msoRuleConfigs(),
|
|
606
767
|
],
|
|
768
|
+
|
|
769
|
+
// ── Optional eslint-plugin-unicorn override configs ───────────────────────
|
|
770
|
+
|
|
771
|
+
/**
|
|
772
|
+
* OPTIONAL: turns off the 46 unicorn recommended rules incompatible with
|
|
773
|
+
* SFMC SSJS, for standalone `.ssjs` files. Plain rules object with NO
|
|
774
|
+
* `plugins` key — eslint-plugin-sfmc does not load unicorn. Spread this
|
|
775
|
+
* AFTER your own unicorn config (which registers the `unicorn` plugin);
|
|
776
|
+
* otherwise ESLint cannot resolve the `unicorn/*` keys. If you don't use
|
|
777
|
+
* unicorn, omit this config entirely.
|
|
778
|
+
*/
|
|
779
|
+
'unicorn-ssjs': {
|
|
780
|
+
name: 'sfmc/unicorn-ssjs',
|
|
781
|
+
files: ['**/*.ssjs'],
|
|
782
|
+
rules: { ...unicornSsjsOffRules },
|
|
783
|
+
},
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* OPTIONAL: same 46-rule override for SSJS embedded in HTML
|
|
787
|
+
* (virtual `**\/*.html/*.js` files). Spread AFTER your unicorn config.
|
|
788
|
+
*/
|
|
789
|
+
'unicorn-ssjs-embedded': {
|
|
790
|
+
name: 'sfmc/unicorn-ssjs-embedded',
|
|
791
|
+
files: ['**/*.html/*.js'],
|
|
792
|
+
rules: { ...unicornSsjsOffRules },
|
|
793
|
+
},
|
|
607
794
|
};
|
|
608
795
|
|
|
609
796
|
export default plugin;
|
package/src/processor.js
CHANGED
|
@@ -13,8 +13,16 @@
|
|
|
13
13
|
* Returns extracted regions as virtual files for ESLint to lint with the
|
|
14
14
|
* appropriate parser/rules based on file extension matching.
|
|
15
15
|
* Line offsets are preserved so ESLint reports errors at correct locations.
|
|
16
|
+
*
|
|
17
|
+
* MSO / Outlook conditional-comment checks are delegated to
|
|
18
|
+
* eslint-plugin-mso-email: when the document contains MSO markup, that plugin's
|
|
19
|
+
* extractor is called and its virtual blocks are appended verbatim, so a single
|
|
20
|
+
* processor (this one) runs on every HTML file and no processor conflict arises.
|
|
16
21
|
*/
|
|
17
22
|
|
|
23
|
+
import { preprocess as msoPreprocess } from 'eslint-plugin-mso-email/processor';
|
|
24
|
+
import { MSO_COMMENT_PATTERN } from 'eslint-plugin-mso-email/comment-pattern';
|
|
25
|
+
|
|
18
26
|
const AMPSCRIPT_SCRIPT_OPEN_RE =
|
|
19
27
|
/^<script\b(?=[^>]*\brunat\s*=\s*['"]server['"])(?=[^>]*\blanguage\s*=\s*['"]ampscript['"])[^>]*>/i;
|
|
20
28
|
const SSJS_SCRIPT_OPEN_RE =
|
|
@@ -201,6 +209,18 @@ export function preprocess(text, filename) {
|
|
|
201
209
|
});
|
|
202
210
|
}
|
|
203
211
|
|
|
212
|
+
// --- Pass 4: delegate MSO / Outlook conditional-comment extraction ---
|
|
213
|
+
// Only when the document actually contains MSO markup, so plain HTML/AMPscript
|
|
214
|
+
// files don't get an extra full-document virtual block. MSO_COMMENT_PATTERN is
|
|
215
|
+
// a global regex with lastIndex state — reset before testing.
|
|
216
|
+
MSO_COMMENT_PATTERN.lastIndex = 0;
|
|
217
|
+
if (MSO_COMMENT_PATTERN.test(text)) {
|
|
218
|
+
// MSO already preserves line offsets and returns bare virtual basenames
|
|
219
|
+
// (mso-comments.mso, document.msohtml); append verbatim so ESLint routes
|
|
220
|
+
// them to eslint-plugin-mso-email's rule configs via their own globs.
|
|
221
|
+
blocks.push(...msoPreprocess(text, filename));
|
|
222
|
+
}
|
|
223
|
+
|
|
204
224
|
if (blocks.length === 0) {
|
|
205
225
|
return [text];
|
|
206
226
|
}
|