eslint-plugin-sfmc 1.0.2 → 2.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 +57 -0
- package/docs/rules/amp/function-arity.md +8 -0
- package/docs/rules/amp/no-unknown-function.md +42 -3
- package/docs/rules/amp/require-variable-declaration.md +11 -1
- package/docs/rules/ssjs/cache-loop-length.md +6 -5
- package/docs/rules/ssjs/no-deprecated-function.md +1 -1
- package/docs/rules/ssjs/no-property-call.md +8 -2
- package/docs/rules/ssjs/no-switch-default.md +1 -1
- package/docs/rules/ssjs/no-treatascontent-injection.md +1 -1
- package/docs/rules/ssjs/no-unknown-function.md +40 -7
- package/docs/rules/ssjs/no-unsupported-syntax.md +7 -10
- package/docs/rules/ssjs/prefer-parsejson-safe-arg.md +1 -1
- package/docs/rules/ssjs/require-hasownproperty.md +6 -5
- package/package.json +6 -3
- package/src/index.js +175 -0
- package/src/rules/amp/function-arity.js +102 -1
- package/src/rules/amp/no-deprecated-function.js +12 -30
- package/src/rules/amp/no-unknown-function.js +31 -3
- package/src/rules/amp/require-variable-declaration.js +12 -1
- package/src/rules/ssjs/cache-loop-length.js +17 -23
- package/src/rules/ssjs/no-property-call.js +18 -10
- package/src/rules/ssjs/no-unknown-function.js +49 -1
- package/src/rules/ssjs/no-unsupported-syntax.js +26 -43
- package/src/rules/ssjs/require-hasownproperty.js +51 -30
package/README.md
CHANGED
|
@@ -25,8 +25,41 @@ export default [
|
|
|
25
25
|
];
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
## VS Code Setup
|
|
29
|
+
|
|
30
|
+
To see `eslint(sfmc/...)` diagnostics in VS Code for `.amp`, `.ssjs`, and `.html` files you need the [VS Code ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) to validate the custom SFMC language IDs.
|
|
31
|
+
|
|
32
|
+
**Option A — Install `vscode-sfmc-language`** (recommended)
|
|
33
|
+
|
|
34
|
+
The [SFMC Language Service extension](https://marketplace.visualstudio.com/items?itemName=joernberkefeld.sfmc-language) contributes the SFMC language IDs **and** automatically configures `eslint.validate` for you. No manual settings required.
|
|
35
|
+
|
|
36
|
+
**Option B — Manual configuration**
|
|
37
|
+
|
|
38
|
+
Add the following to your `.vscode/settings.json`:
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"eslint.validate": [
|
|
43
|
+
"javascript",
|
|
44
|
+
"javascriptreact",
|
|
45
|
+
"typescript",
|
|
46
|
+
"typescriptreact",
|
|
47
|
+
"html",
|
|
48
|
+
"vue",
|
|
49
|
+
"markdown",
|
|
50
|
+
"ampscript",
|
|
51
|
+
"ssjs",
|
|
52
|
+
"sfmc"
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
> **Why `eslint.validate` and not `eslint.probe`?** `eslint.probe` silently skips files for language IDs that the ESLint extension does not natively recognise. `eslint.validate` forces the extension to process those files regardless of language ID.
|
|
58
|
+
|
|
28
59
|
## Configs
|
|
29
60
|
|
|
61
|
+
### Marketing Cloud Engagement (default)
|
|
62
|
+
|
|
30
63
|
| Config | Files | What it does |
|
|
31
64
|
| -------------------------- | ---------------------------- | --------------------------------------------------------- |
|
|
32
65
|
| `sfmc.configs.ampscript` | `**/*.ampscript`, `**/*.amp` | AMPscript rules only (recommended severity) |
|
|
@@ -37,6 +70,30 @@ export default [
|
|
|
37
70
|
|
|
38
71
|
`recommended`, `embedded`, and `strict` are arrays — spread them with `...`.
|
|
39
72
|
|
|
73
|
+
### Marketing Cloud Next
|
|
74
|
+
|
|
75
|
+
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.
|
|
76
|
+
|
|
77
|
+
| Config | Files | What it does |
|
|
78
|
+
| -------------------------------- | ---------------------------- | ----------------------------------------------------------------------------------------- |
|
|
79
|
+
| `sfmc.configs['ampscript-next']` | `**/*.ampscript`, `**/*.amp` | AMPscript rules + flags functions unsupported in MCN (single config object) |
|
|
80
|
+
| `sfmc.configs['ssjs-next']` | `**/*.ssjs` | Flags all SSJS API calls as MCN-unsupported; all other SSJS quality rules disabled |
|
|
81
|
+
| `sfmc.configs['recommended-next']` | Both of the above | AMPscript MCN-aware + SSJS flagged for standalone files |
|
|
82
|
+
| `sfmc.configs['embedded-next']` | `**/*.html` | AMPscript MCN-aware + SSJS flagged for HTML-embedded code |
|
|
83
|
+
| `sfmc.configs['strict-next']` | All of the above + HTML | All AMPscript rules at `error` severity + MCN flag; SSJS fully flagged |
|
|
84
|
+
|
|
85
|
+
`recommended-next`, `embedded-next`, and `strict-next` are arrays — spread them with `...`.
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
// eslint.config.js — targeting Marketing Cloud Next
|
|
89
|
+
import sfmc from 'eslint-plugin-sfmc';
|
|
90
|
+
|
|
91
|
+
export default [
|
|
92
|
+
...sfmc.configs['recommended-next'],
|
|
93
|
+
...sfmc.configs['embedded-next'],
|
|
94
|
+
];
|
|
95
|
+
```
|
|
96
|
+
|
|
40
97
|
## AMPscript Rules (`amp-*`)
|
|
41
98
|
|
|
42
99
|
| Rule | Default | Description |
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
AMPscript functions have fixed required and optional argument counts documented in the Salesforce catalog. Calling a function with too few arguments causes a runtime error. Calling it with too many can silently truncate or fail. This rule validates every call against the known min/max argument counts.
|
|
14
14
|
|
|
15
|
+
Several AMPscript functions are variadic: their trailing arguments repeat in fixed-size groups (for example `Concat` repeats a single value, while the DataExtension `UpdateData`/`UpsertData` family repeats column/value pairs). For these functions the catalog carries a `repeat` model describing where the repeating block starts, how many arguments form one group, and — for the Update/Upsert family — which earlier argument dictates how many search pairs precede the update pairs. This rule additionally reports `incompleteGroup` when the trailing arguments do not form complete groups.
|
|
16
|
+
|
|
15
17
|
## Settings
|
|
16
18
|
|
|
17
19
|
| Setting | Values | Default |
|
|
@@ -32,6 +34,9 @@ This rule has no configuration options.
|
|
|
32
34
|
|
|
33
35
|
/* Format accepts at most 3 arguments */
|
|
34
36
|
set @val = Format(@num, "0.00", "en-US", "extra")
|
|
37
|
+
|
|
38
|
+
/* UpdateData: one search pair, then an incomplete update group (odd trailing args) */
|
|
39
|
+
UpdateData("MyDE", 1, "Key", @key, "Col", @v, "Orphan")
|
|
35
40
|
]%%
|
|
36
41
|
```
|
|
37
42
|
|
|
@@ -42,6 +47,9 @@ This rule has no configuration options.
|
|
|
42
47
|
var @val
|
|
43
48
|
set @val = Lookup("MyDE", "Value", "Key", @key)
|
|
44
49
|
set @val = Format(@num, "0.00", "en-US")
|
|
50
|
+
|
|
51
|
+
/* UpdateData: one search pair + one update pair (complete groups) */
|
|
52
|
+
UpdateData("MyDE", 1, "Key", @key, "Col", @v)
|
|
45
53
|
]%%
|
|
46
54
|
```
|
|
47
55
|
|
|
@@ -5,22 +5,30 @@
|
|
|
5
5
|
| | |
|
|
6
6
|
|---|---|
|
|
7
7
|
| **Type** | `problem` |
|
|
8
|
-
| **Default severity** | `error` in `recommended` and `
|
|
8
|
+
| **Default severity** | `error` in `recommended`, `strict`, and all `-next` configs |
|
|
9
9
|
| **Fixable** | — |
|
|
10
10
|
|
|
11
11
|
## Why This Rule Exists
|
|
12
12
|
|
|
13
13
|
AMPscript does not support user-defined functions. Every function call must match a name in Salesforce's published catalog. Calling an unknown name causes a runtime error (or is silently ignored depending on the execution context), making the code unreliable. This rule catches typos and invented names before deployment.
|
|
14
14
|
|
|
15
|
+
When targeting **Marketing Cloud Next**, only a subset of AMPscript functions are supported. Use the `target: 'next'` option to flag functions that cannot run in MCN.
|
|
16
|
+
|
|
15
17
|
## Settings
|
|
16
18
|
|
|
17
19
|
| Setting | Values | Default |
|
|
18
20
|
|---------|--------|---------|
|
|
19
21
|
| severity | `"error"` \| `"warn"` \| `"off"` | `"error"` |
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
### Options
|
|
24
|
+
|
|
25
|
+
| Option | Type | Default | Description |
|
|
26
|
+
|--------|------|---------|-------------|
|
|
27
|
+
| `target` | `'engagement'` \| `'next'` | — | Target platform. Set to `'next'` to additionally flag AMPscript functions not available in Marketing Cloud Next (API v67.0+). |
|
|
28
|
+
|
|
29
|
+
## Examples
|
|
22
30
|
|
|
23
|
-
###
|
|
31
|
+
### Standard usage (Marketing Cloud Engagement)
|
|
24
32
|
|
|
25
33
|
**Not allowed:**
|
|
26
34
|
|
|
@@ -40,6 +48,37 @@ This rule has no configuration options.
|
|
|
40
48
|
]%%
|
|
41
49
|
```
|
|
42
50
|
|
|
51
|
+
### MCN target
|
|
52
|
+
|
|
53
|
+
Configure the rule with `target: 'next'` to flag functions unsupported in Marketing Cloud Next:
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
// eslint.config.js
|
|
57
|
+
rules: {
|
|
58
|
+
'sfmc/amp-no-unknown-function': ['error', { target: 'next' }]
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Or use the built-in `recommended-next` / `strict-next` / `embedded-next` configs which apply this automatically.
|
|
63
|
+
|
|
64
|
+
**Not allowed (with `target: 'next'`):**
|
|
65
|
+
|
|
66
|
+
```ampscript
|
|
67
|
+
%%[
|
|
68
|
+
/* InsertDE is not supported in Marketing Cloud Next */
|
|
69
|
+
InsertDE("MyDE", "Col", "Value")
|
|
70
|
+
]%%
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Allowed (with `target: 'next'`):**
|
|
74
|
+
|
|
75
|
+
```ampscript
|
|
76
|
+
%%[
|
|
77
|
+
/* UpsertDE is supported in Marketing Cloud Next */
|
|
78
|
+
UpsertDE("MyDE", 1, "Key", @key, "Col", "Value")
|
|
79
|
+
]%%
|
|
80
|
+
```
|
|
81
|
+
|
|
43
82
|
## When to Disable
|
|
44
83
|
|
|
45
84
|
Only disable this rule if you are intentionally using a proprietary or undocumented SFMC extension that is not in the public catalog.
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|---|---|
|
|
7
7
|
| **Type** | `suggestion` |
|
|
8
8
|
| **Default severity** | `off` by default |
|
|
9
|
-
| **Fixable** |
|
|
9
|
+
| **Fixable** | **Auto-fix** (`eslint --fix`) |
|
|
10
10
|
|
|
11
11
|
## Why This Rule Exists
|
|
12
12
|
|
|
@@ -41,6 +41,16 @@ This rule has no configuration options.
|
|
|
41
41
|
]%%
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
+
## Fix
|
|
45
|
+
|
|
46
|
+
This rule provides an **auto-fix**. Applied by:
|
|
47
|
+
|
|
48
|
+
- `eslint --fix` on the command line
|
|
49
|
+
- **Fix this issue** / **Fix all auto-fixable problems** in VS Code (requires the [ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint))
|
|
50
|
+
- On save via `editor.codeActionsOnSave: { "source.fixAll.eslint": "explicit" }`
|
|
51
|
+
|
|
52
|
+
What the auto-fix does: inserts `var @variableName` on the line immediately before the first `set` that uses an undeclared `@variable`. Only the first occurrence of each variable receives a fix in a single `--fix` pass to avoid duplicate `var` lines.
|
|
53
|
+
|
|
44
54
|
## When to Disable
|
|
45
55
|
|
|
46
56
|
This rule is off by default because undeclared `set` is valid AMPscript. Enable it for teams that want to enforce a strict declaration-first style.
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|---|---|
|
|
7
7
|
| **Type** | `suggestion` |
|
|
8
8
|
| **Default severity** | `warn` in `recommended`; `error` in `strict` |
|
|
9
|
-
| **Fixable** | **
|
|
9
|
+
| **Fixable** | **Auto-fix** (`eslint --fix`) |
|
|
10
10
|
|
|
11
11
|
## Why This Rule Exists
|
|
12
12
|
|
|
@@ -44,12 +44,13 @@ for (var i = 0, _len = items.length; i < _len; i++) {
|
|
|
44
44
|
|
|
45
45
|
## Fix
|
|
46
46
|
|
|
47
|
-
This rule provides
|
|
47
|
+
This rule provides an **auto-fix**. Applied by:
|
|
48
48
|
|
|
49
|
-
-
|
|
50
|
-
-
|
|
49
|
+
- `eslint --fix` on the command line
|
|
50
|
+
- **Fix this issue** / **Fix all auto-fixable problems** in VS Code (requires the [ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint))
|
|
51
|
+
- On save via `editor.codeActionsOnSave: { "source.fixAll.eslint": "explicit" }`
|
|
51
52
|
|
|
52
|
-
What the
|
|
53
|
+
What the auto-fix does: appends `, _len = arr.length` to the last declarator in the `for` loop initialiser and replaces `arr.length` in the test condition with `_len`. The fix is only applied when the loop `init` is a `var` declaration (the typical case). Loops with other init forms (for example `for (i = 0; i < arr.length; i++)`) are still reported but not auto-fixed.
|
|
53
54
|
|
|
54
55
|
## When to Disable
|
|
55
56
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ssjs-no-property-call
|
|
1
|
+
# `sfmc/ssjs-no-property-call`
|
|
2
2
|
|
|
3
3
|
Flags `Platform.Request` and `Platform.Response` members that are **properties**, not functions.
|
|
4
4
|
Calling them with parentheses `()` is a runtime error — they must be accessed without parentheses.
|
|
@@ -6,7 +6,7 @@ Calling them with parentheses `()` is a runtime error — they must be accessed
|
|
|
6
6
|
The rule is fixable:
|
|
7
7
|
|
|
8
8
|
- **No-arg calls** (`Property()`) → removes the `()` on both `Request` and `Response` properties.
|
|
9
|
-
- **Single-arg calls on `Platform.Response.*`** (`ContentType("text/html")`) → rewrites to an assignment (`= value`),
|
|
9
|
+
- **Single-arg calls on `Platform.Response.*`** (`ContentType("text/html")`) → rewrites to an assignment (`= value`), including when the call appears in a comma (`SequenceExpression`) expression.
|
|
10
10
|
- **Any-arg calls on `Platform.Request.*`** → reported as an error with no auto-fix, because `Request` properties are read-only.
|
|
11
11
|
|
|
12
12
|
## Properties affected
|
|
@@ -64,6 +64,12 @@ Platform.Response.ContentType = "application/json";
|
|
|
64
64
|
Platform.Response.CharacterSet = "UTF-8";
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
+
Auto-fix also applies inside comma expressions:
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
Platform.Response.CharacterSet = "UTF-8", Platform.Response.Write("ok");
|
|
71
|
+
```
|
|
72
|
+
|
|
67
73
|
### ❌ Incorrect — attempting to set a read-only `Platform.Request` property (no fix)
|
|
68
74
|
|
|
69
75
|
```js
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
# ssjs-no-unknown-function
|
|
1
|
+
# `sfmc/ssjs-no-unknown-function`
|
|
2
2
|
|
|
3
3
|
Flags calls to SFMC API methods that do not exist in the catalog. This single rule replaces the seven narrow `no-unknown-*` rules from earlier versions of the plugin.
|
|
4
4
|
|
|
5
|
+
When targeting **Marketing Cloud Next**, SSJS is not supported at all. Set `target: 'next'` to flag every SSJS API call as an error, signalling that the SSJS block must be removed or rewritten in AMPscript.
|
|
6
|
+
|
|
5
7
|
## Covered namespaces
|
|
6
8
|
|
|
7
9
|
| Namespace | Example |
|
|
@@ -15,9 +17,17 @@ Flags calls to SFMC API methods that do not exist in the catalog. This single ru
|
|
|
15
17
|
| Core Library instance methods | `de.Rows.Retrieve()` (tracked from `DataExtension.Init(…)`) |
|
|
16
18
|
| WSProxy instance methods | `api.retrieve(…)` (tracked from `new Script.Util.WSProxy()`) |
|
|
17
19
|
|
|
20
|
+
## Options
|
|
21
|
+
|
|
22
|
+
| Option | Type | Default | Description |
|
|
23
|
+
|--------|------|---------|-------------|
|
|
24
|
+
| `target` | `'engagement'` \| `'next'` | — | Target platform. Set to `'next'` to flag every SSJS API call (all of `Platform.*`, `HTTP.*`, Core Library, and WSProxy) as unsupported in Marketing Cloud Next. |
|
|
25
|
+
|
|
18
26
|
## Examples
|
|
19
27
|
|
|
20
|
-
###
|
|
28
|
+
### Standard usage (Marketing Cloud Engagement)
|
|
29
|
+
|
|
30
|
+
#### ❌ Incorrect
|
|
21
31
|
|
|
22
32
|
```js
|
|
23
33
|
// Typo in Platform.Function method name
|
|
@@ -32,7 +42,7 @@ var de = DataExtension.Init('CustomerData');
|
|
|
32
42
|
de.ExportRows();
|
|
33
43
|
```
|
|
34
44
|
|
|
35
|
-
|
|
45
|
+
#### ✅ Correct
|
|
36
46
|
|
|
37
47
|
```js
|
|
38
48
|
Platform.Function.LookupRows('MyDE', 'Status', 'Active');
|
|
@@ -44,14 +54,37 @@ var de = DataExtension.Init('CustomerData');
|
|
|
44
54
|
de.Rows.Retrieve();
|
|
45
55
|
```
|
|
46
56
|
|
|
57
|
+
### MCN target (`target: 'next'`)
|
|
58
|
+
|
|
59
|
+
SSJS is not supported in Marketing Cloud Next. Configuring `target: 'next'` flags every SFMC API call within SSJS files, indicating they must be rewritten or removed.
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
// eslint.config.js
|
|
63
|
+
rules: {
|
|
64
|
+
'sfmc/ssjs-no-unknown-function': ['error', { target: 'next' }]
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Or use the built-in `recommended-next` / `strict-next` / `embedded-next` configs which apply this automatically (and disable all other SSJS quality rules, since the entire SSJS block must be migrated).
|
|
69
|
+
|
|
70
|
+
#### ❌ Flagged (with `target: 'next'`)
|
|
71
|
+
|
|
72
|
+
```js
|
|
73
|
+
// All SFMC API calls are flagged — SSJS is not available in MCN
|
|
74
|
+
Platform.Function.LookupRows('MyDE', 'Status', 'Active');
|
|
75
|
+
|
|
76
|
+
var de = DataExtension.Init('CustomerData');
|
|
77
|
+
de.Rows.Retrieve();
|
|
78
|
+
```
|
|
79
|
+
|
|
47
80
|
## When to use
|
|
48
81
|
|
|
49
|
-
Enable this rule to catch typos, outdated method names, and unsupported API calls before
|
|
50
|
-
they cause runtime failures.
|
|
82
|
+
Enable this rule to catch typos, outdated method names, and unsupported API calls before they cause runtime failures. Use `target: 'next'` when migrating content to Marketing Cloud Next.
|
|
51
83
|
|
|
52
84
|
## Rule details
|
|
53
85
|
|
|
54
86
|
- **Type:** `problem`
|
|
55
87
|
- **Fixable:** No
|
|
56
|
-
- **Recommended:** Yes
|
|
57
|
-
- **Strict:** Yes
|
|
88
|
+
- **Recommended:** Yes (`engagement` mode)
|
|
89
|
+
- **Strict:** Yes (`engagement` mode)
|
|
90
|
+
- **`recommended-next` / `strict-next` / `embedded-next`:** Yes (`next` mode — all other SSJS rules disabled)
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|---|---|
|
|
7
7
|
| **Type** | `problem` |
|
|
8
8
|
| **Default severity** | `error` in `recommended` and `strict` |
|
|
9
|
-
| **Fixable** | **Auto-fix** for `let`/`const
|
|
9
|
+
| **Fixable** | **Auto-fix** for `let`/`const`, `??`, and direct object `return` |
|
|
10
10
|
|
|
11
11
|
## Why This Rule Exists
|
|
12
12
|
|
|
@@ -49,22 +49,19 @@ var value = (obj && obj.prop !== null && obj.prop !== undefined) ? obj.prop : "d
|
|
|
49
49
|
|
|
50
50
|
## Fix
|
|
51
51
|
|
|
52
|
-
**
|
|
52
|
+
This rule provides **auto-fix** for selected features. Applied by:
|
|
53
53
|
|
|
54
54
|
- `eslint --fix` on the command line
|
|
55
55
|
- **Fix this issue** / **Fix all auto-fixable problems** in VS Code (requires the [ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint))
|
|
56
56
|
- On save via `editor.codeActionsOnSave: { "source.fixAll.eslint": "explicit" }`
|
|
57
57
|
|
|
58
|
-
What the auto-fix does:
|
|
58
|
+
What the auto-fix does:
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
- **`let` / `const` declarations** — replaces the keyword with `var`, leaving the rest of the declaration unchanged.
|
|
61
|
+
- **Nullish coalescing (`??`)** — replaces `??` with `||`. Note that `||` has different semantics — it also treats `0`, `""`, and `false` as falsy, unlike `??` which only replaces `null` and `undefined`.
|
|
62
|
+
- **Direct object literal `return`** — rewrites `return { … }` to assign the object to a temporary `var _result` and then `return _result`.
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
- Click the **lightbulb** / press `Ctrl+.` on the flagged code in VS Code (requires the ESLint extension)
|
|
65
|
-
- `eslint --fix` does **not** apply suggestions (`--fix-type suggestion` filters fixable rules by rule category, it does **not** apply `hasSuggestions` suggestions)
|
|
66
|
-
|
|
67
|
-
What the suggestion does: replaces `??` with `||`. Note that `||` has different semantics — it also treats `0`, `""`, and `false` as falsy, unlike `??` which only replaces `null` and `undefined`.
|
|
64
|
+
Other unsupported features (arrow functions, template literals, classes, etc.) have no auto-fix.
|
|
68
65
|
|
|
69
66
|
## Configuration Example
|
|
70
67
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|---|---|
|
|
7
7
|
| **Type** | `suggestion` |
|
|
8
8
|
| **Default severity** | `warn` in `recommended`; `error` in `strict` |
|
|
9
|
-
| **Fixable** | **
|
|
9
|
+
| **Fixable** | **Auto-fix** (`eslint --fix`) |
|
|
10
10
|
|
|
11
11
|
## Why This Rule Exists
|
|
12
12
|
|
|
@@ -42,12 +42,13 @@ for (var key in myObject) {
|
|
|
42
42
|
|
|
43
43
|
## Fix
|
|
44
44
|
|
|
45
|
-
This rule provides
|
|
45
|
+
This rule provides an **auto-fix**. Applied by:
|
|
46
46
|
|
|
47
|
-
-
|
|
48
|
-
-
|
|
47
|
+
- `eslint --fix` on the command line
|
|
48
|
+
- **Fix this issue** / **Fix all auto-fixable problems** in VS Code (requires the [ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint))
|
|
49
|
+
- On save via `editor.codeActionsOnSave: { "source.fixAll.eslint": "explicit" }`
|
|
49
50
|
|
|
50
|
-
What the
|
|
51
|
+
What the auto-fix does: wraps the entire loop body in an `if (obj.hasOwnProperty(key)) { … }` guard. When the body is already a block statement, the existing content is preserved inside the new `if`; when it is a single statement, a new block is created around it.
|
|
51
52
|
|
|
52
53
|
## When to Disable
|
|
53
54
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-sfmc",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "ESLint plugin for Salesforce Marketing Cloud  AMPscript and Server-Side JavaScript (SSJS)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"sfmc"
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"ampscript-data": "^
|
|
35
|
+
"ampscript-data": "^2.0.0",
|
|
36
36
|
"ampscript-parser": "^0.1.3",
|
|
37
37
|
"ssjs-data": "^0.4.0"
|
|
38
38
|
},
|
|
@@ -40,7 +40,10 @@
|
|
|
40
40
|
"eslint": ">=9.0.0"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
|
-
"test": "node --test tests/rules.test.js",
|
|
43
|
+
"test": "node --test tests/rules.test.js && node --test tests/fixtures.test.mjs && node --test tests/autofix-manual.test.mjs",
|
|
44
|
+
"test:autofix-manual": "node --test tests/autofix-manual.test.mjs",
|
|
45
|
+
"test:fixtures": "node --test tests/fixtures.test.mjs",
|
|
46
|
+
"test:fixtures:update": "node --test tests/fixtures.test.mjs -- --update-snapshots",
|
|
44
47
|
"lint": "eslint .",
|
|
45
48
|
"lint:fix": "eslint --fix .",
|
|
46
49
|
"prepare": "husky || true",
|
package/src/index.js
CHANGED
|
@@ -121,6 +121,34 @@ const plugin = {
|
|
|
121
121
|
configs: {},
|
|
122
122
|
};
|
|
123
123
|
|
|
124
|
+
// ── MCN SSJS rule set (all SSJS rules off except ssjs-no-unknown-function) ────
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* SSJS rules for MCN targets.
|
|
128
|
+
* All quality rules are disabled — only the presence of SSJS is flagged,
|
|
129
|
+
* because SSJS as a whole must be deleted when targeting Marketing Cloud Next.
|
|
130
|
+
*/
|
|
131
|
+
const ssjsMcnRules = {
|
|
132
|
+
'sfmc/ssjs-no-unknown-function': ['error', { target: 'next' }],
|
|
133
|
+
'sfmc/ssjs-require-platform-load': 'off',
|
|
134
|
+
'sfmc/ssjs-no-unsupported-syntax': 'off',
|
|
135
|
+
'sfmc/ssjs-no-deprecated-function': 'off',
|
|
136
|
+
'sfmc/ssjs-no-property-call': 'off',
|
|
137
|
+
'sfmc/ssjs-platform-function-arity': 'off',
|
|
138
|
+
'sfmc/ssjs-cache-loop-length': 'off',
|
|
139
|
+
'sfmc/ssjs-require-hasownproperty': 'off',
|
|
140
|
+
'sfmc/ssjs-require-platform-load-order': 'off',
|
|
141
|
+
'sfmc/ssjs-no-hardcoded-credentials': 'off',
|
|
142
|
+
'sfmc/ssjs-prefer-platform-load-version': 'off',
|
|
143
|
+
'sfmc/ssjs-no-unavailable-method': 'off',
|
|
144
|
+
'sfmc/ssjs-prefer-parsejson-safe-arg': 'off',
|
|
145
|
+
'sfmc/ssjs-no-switch-default': 'off',
|
|
146
|
+
'sfmc/ssjs-no-treatascontent-injection': 'off',
|
|
147
|
+
'sfmc/ssjs-arg-types': 'off',
|
|
148
|
+
'sfmc/ssjs-core-method-arity': 'off',
|
|
149
|
+
'no-cond-assign': 'off',
|
|
150
|
+
};
|
|
151
|
+
|
|
124
152
|
// ── AMPscript rule sets ───────────────────────────────────────────────────────
|
|
125
153
|
|
|
126
154
|
const ampRecommendedRules = {
|
|
@@ -340,6 +368,153 @@ Object.assign(plugin.configs, {
|
|
|
340
368
|
rules: { ...ssjsStrictRules },
|
|
341
369
|
},
|
|
342
370
|
],
|
|
371
|
+
|
|
372
|
+
// ── Marketing Cloud Next configs ──────────────────────────────────────────
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* AMPscript-only MCN config. Flags functions not supported in MCN.
|
|
376
|
+
* No SSJS portion (AMPscript-only config).
|
|
377
|
+
*/
|
|
378
|
+
'ampscript-next': {
|
|
379
|
+
name: 'sfmc/ampscript-next',
|
|
380
|
+
plugins: { sfmc: plugin },
|
|
381
|
+
languageOptions: { parser: ampscriptParser },
|
|
382
|
+
files: ['**/*.ampscript', '**/*.amp'],
|
|
383
|
+
rules: {
|
|
384
|
+
...ampRecommendedRules,
|
|
385
|
+
'sfmc/amp-no-unknown-function': ['error', { target: 'next' }],
|
|
386
|
+
},
|
|
387
|
+
},
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* SSJS-only MCN config. Flags all SSJS API calls; disables all other SSJS rules.
|
|
391
|
+
*/
|
|
392
|
+
'ssjs-next': {
|
|
393
|
+
name: 'sfmc/ssjs-next',
|
|
394
|
+
plugins: { sfmc: plugin },
|
|
395
|
+
files: ['**/*.ssjs'],
|
|
396
|
+
languageOptions: {
|
|
397
|
+
ecmaVersion: 5,
|
|
398
|
+
sourceType: 'script',
|
|
399
|
+
globals: SSJS_GLOBALS_MAP,
|
|
400
|
+
},
|
|
401
|
+
rules: { ...ssjsMcnRules },
|
|
402
|
+
},
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Recommended MCN config: both AMPscript and SSJS for standalone files.
|
|
406
|
+
* AMPscript portion flags MCN-unsupported functions; SSJS portion flags all SSJS as unsupported.
|
|
407
|
+
*/
|
|
408
|
+
'recommended-next': [
|
|
409
|
+
{
|
|
410
|
+
name: 'sfmc/recommended-next-ampscript',
|
|
411
|
+
plugins: { sfmc: plugin },
|
|
412
|
+
languageOptions: { parser: ampscriptParser },
|
|
413
|
+
files: ['**/*.ampscript', '**/*.amp'],
|
|
414
|
+
rules: {
|
|
415
|
+
...ampRecommendedRules,
|
|
416
|
+
'sfmc/amp-no-unknown-function': ['error', { target: 'next' }],
|
|
417
|
+
},
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
name: 'sfmc/recommended-next-ssjs',
|
|
421
|
+
plugins: { sfmc: plugin },
|
|
422
|
+
files: ['**/*.ssjs'],
|
|
423
|
+
languageOptions: {
|
|
424
|
+
ecmaVersion: 5,
|
|
425
|
+
sourceType: 'script',
|
|
426
|
+
globals: SSJS_GLOBALS_MAP,
|
|
427
|
+
},
|
|
428
|
+
rules: { ...ssjsMcnRules },
|
|
429
|
+
},
|
|
430
|
+
],
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* MCN config for AMPscript and SSJS embedded in HTML files.
|
|
434
|
+
*/
|
|
435
|
+
'embedded-next': [
|
|
436
|
+
{
|
|
437
|
+
name: 'sfmc/embedded-next-processor',
|
|
438
|
+
plugins: { sfmc: plugin },
|
|
439
|
+
files: ['**/*.html'],
|
|
440
|
+
processor: 'sfmc/sfmc',
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
name: 'sfmc/embedded-next-ampscript-rules',
|
|
444
|
+
plugins: { sfmc: plugin },
|
|
445
|
+
languageOptions: { parser: ampscriptParser },
|
|
446
|
+
files: ['**/*.html/*.amp'],
|
|
447
|
+
rules: {
|
|
448
|
+
...ampRecommendedRules,
|
|
449
|
+
'sfmc/amp-no-unknown-function': ['error', { target: 'next' }],
|
|
450
|
+
},
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
name: 'sfmc/embedded-next-ssjs-rules',
|
|
454
|
+
plugins: { sfmc: plugin },
|
|
455
|
+
files: ['**/*.html/*.js'],
|
|
456
|
+
languageOptions: {
|
|
457
|
+
ecmaVersion: 5,
|
|
458
|
+
sourceType: 'script',
|
|
459
|
+
globals: SSJS_GLOBALS_MAP,
|
|
460
|
+
},
|
|
461
|
+
rules: { ...ssjsMcnRules },
|
|
462
|
+
},
|
|
463
|
+
],
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Strict MCN config: all rules at error severity for standalone + embedded.
|
|
467
|
+
*/
|
|
468
|
+
'strict-next': [
|
|
469
|
+
{
|
|
470
|
+
name: 'sfmc/strict-next-ampscript',
|
|
471
|
+
plugins: { sfmc: plugin },
|
|
472
|
+
languageOptions: { parser: ampscriptParser },
|
|
473
|
+
files: ['**/*.ampscript', '**/*.amp'],
|
|
474
|
+
rules: {
|
|
475
|
+
...ampStrictRules,
|
|
476
|
+
'sfmc/amp-no-unknown-function': ['error', { target: 'next' }],
|
|
477
|
+
},
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
name: 'sfmc/strict-next-ssjs',
|
|
481
|
+
plugins: { sfmc: plugin },
|
|
482
|
+
files: ['**/*.ssjs'],
|
|
483
|
+
languageOptions: {
|
|
484
|
+
ecmaVersion: 5,
|
|
485
|
+
sourceType: 'script',
|
|
486
|
+
globals: SSJS_GLOBALS_MAP,
|
|
487
|
+
},
|
|
488
|
+
rules: { ...ssjsMcnRules },
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
name: 'sfmc/strict-next-embedded-processor',
|
|
492
|
+
plugins: { sfmc: plugin },
|
|
493
|
+
files: ['**/*.html'],
|
|
494
|
+
processor: 'sfmc/sfmc',
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
name: 'sfmc/strict-next-embedded-ampscript-rules',
|
|
498
|
+
plugins: { sfmc: plugin },
|
|
499
|
+
languageOptions: { parser: ampscriptParser },
|
|
500
|
+
files: ['**/*.html/*.amp'],
|
|
501
|
+
rules: {
|
|
502
|
+
...ampStrictRules,
|
|
503
|
+
'sfmc/amp-no-unknown-function': ['error', { target: 'next' }],
|
|
504
|
+
},
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
name: 'sfmc/strict-next-embedded-ssjs-rules',
|
|
508
|
+
plugins: { sfmc: plugin },
|
|
509
|
+
files: ['**/*.html/*.js'],
|
|
510
|
+
languageOptions: {
|
|
511
|
+
ecmaVersion: 5,
|
|
512
|
+
sourceType: 'script',
|
|
513
|
+
globals: SSJS_GLOBALS_MAP,
|
|
514
|
+
},
|
|
515
|
+
rules: { ...ssjsMcnRules },
|
|
516
|
+
},
|
|
517
|
+
],
|
|
343
518
|
});
|
|
344
519
|
|
|
345
520
|
export default plugin;
|