eslint-plugin-sfmc 0.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/LICENSE +21 -0
- package/README.md +100 -0
- package/docs/rules/amp/function-arity.md +53 -0
- package/docs/rules/amp/naming-convention.md +76 -0
- package/docs/rules/amp/no-deprecated-function.md +78 -0
- package/docs/rules/amp/no-email-excluded-function.md +69 -0
- package/docs/rules/amp/no-empty-block.md +59 -0
- package/docs/rules/amp/no-empty-then.md +62 -0
- package/docs/rules/amp/no-html-comment.md +67 -0
- package/docs/rules/amp/no-inline-statement.md +51 -0
- package/docs/rules/amp/no-js-line-comment.md +54 -0
- package/docs/rules/amp/no-loop-counter-assign.md +52 -0
- package/docs/rules/amp/no-nested-ampscript-delimiter.md +69 -0
- package/docs/rules/amp/no-nested-script-tag.md +58 -0
- package/docs/rules/amp/no-smart-quotes.md +60 -0
- package/docs/rules/amp/no-unknown-function.md +50 -0
- package/docs/rules/amp/no-var-redeclaration.md +52 -0
- package/docs/rules/amp/prefer-attribute-value.md +64 -0
- package/docs/rules/amp/require-rowcount-check.md +62 -0
- package/docs/rules/amp/require-variable-declaration.md +51 -0
- package/docs/rules/amp/set-requires-target.md +47 -0
- package/docs/rules/ssjs/cache-loop-length.md +59 -0
- package/docs/rules/ssjs/no-hardcoded-credentials.md +52 -0
- package/docs/rules/ssjs/no-switch-default.md +37 -0
- package/docs/rules/ssjs/no-treatascontent-injection.md +38 -0
- package/docs/rules/ssjs/no-unavailable-method.md +134 -0
- package/docs/rules/ssjs/no-unknown-core-method.md +46 -0
- package/docs/rules/ssjs/no-unknown-http-method.md +44 -0
- package/docs/rules/ssjs/no-unknown-platform-client-browser.md +44 -0
- package/docs/rules/ssjs/no-unknown-platform-function.md +44 -0
- package/docs/rules/ssjs/no-unknown-platform-request.md +43 -0
- package/docs/rules/ssjs/no-unknown-platform-response.md +43 -0
- package/docs/rules/ssjs/no-unknown-platform-variable.md +43 -0
- package/docs/rules/ssjs/no-unknown-wsproxy-method.md +46 -0
- package/docs/rules/ssjs/no-unsupported-syntax.md +83 -0
- package/docs/rules/ssjs/platform-function-arity.md +45 -0
- package/docs/rules/ssjs/prefer-parsejson-safe-arg.md +42 -0
- package/docs/rules/ssjs/prefer-platform-load-version.md +68 -0
- package/docs/rules/ssjs/require-hasownproperty.md +57 -0
- package/docs/rules/ssjs/require-platform-load-order.md +46 -0
- package/docs/rules/ssjs/require-platform-load.md +57 -0
- package/package.json +52 -0
- package/src/ampscript-parser.js +159 -0
- package/src/ampscript-processor.js +132 -0
- package/src/index.js +355 -0
- package/src/processor.js +147 -0
- package/src/rules/amp/function-arity.js +51 -0
- package/src/rules/amp/naming-convention.js +58 -0
- package/src/rules/amp/no-deprecated-function.js +75 -0
- package/src/rules/amp/no-email-excluded-function.js +72 -0
- package/src/rules/amp/no-empty-block.js +37 -0
- package/src/rules/amp/no-empty-then.js +34 -0
- package/src/rules/amp/no-html-comment.js +57 -0
- package/src/rules/amp/no-inline-statement.js +45 -0
- package/src/rules/amp/no-js-line-comment.js +54 -0
- package/src/rules/amp/no-loop-counter-assign.js +71 -0
- package/src/rules/amp/no-nested-ampscript-delimiter.js +102 -0
- package/src/rules/amp/no-nested-script-tag.js +65 -0
- package/src/rules/amp/no-smart-quotes.js +78 -0
- package/src/rules/amp/no-unknown-function.js +31 -0
- package/src/rules/amp/no-var-redeclaration.js +36 -0
- package/src/rules/amp/prefer-attribute-value.js +94 -0
- package/src/rules/amp/require-rowcount-check.js +116 -0
- package/src/rules/amp/require-variable-declaration.js +49 -0
- package/src/rules/amp/set-requires-target.js +27 -0
- package/src/rules/ssjs/cache-loop-length.js +92 -0
- package/src/rules/ssjs/no-hardcoded-credentials.js +66 -0
- package/src/rules/ssjs/no-switch-default.js +32 -0
- package/src/rules/ssjs/no-treatascontent-injection.js +76 -0
- package/src/rules/ssjs/no-unavailable-method.js +190 -0
- package/src/rules/ssjs/no-unknown-core-method.js +103 -0
- package/src/rules/ssjs/no-unknown-http-method.js +41 -0
- package/src/rules/ssjs/no-unknown-platform-client-browser.js +50 -0
- package/src/rules/ssjs/no-unknown-platform-function.js +49 -0
- package/src/rules/ssjs/no-unknown-platform-request.js +50 -0
- package/src/rules/ssjs/no-unknown-platform-response.js +50 -0
- package/src/rules/ssjs/no-unknown-platform-variable.js +50 -0
- package/src/rules/ssjs/no-unknown-wsproxy-method.js +71 -0
- package/src/rules/ssjs/no-unsupported-syntax.js +122 -0
- package/src/rules/ssjs/platform-function-arity.js +70 -0
- package/src/rules/ssjs/prefer-parsejson-safe-arg.js +94 -0
- package/src/rules/ssjs/prefer-platform-load-version.js +96 -0
- package/src/rules/ssjs/require-hasownproperty.js +142 -0
- package/src/rules/ssjs/require-platform-load-order.js +112 -0
- package/src/rules/ssjs/require-platform-load.js +124 -0
- package/src/ssjs-processor.js +48 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# `sfmc/amp-no-js-line-comment`
|
|
2
|
+
|
|
3
|
+
> Disallow JavaScript-style single-line comments (`// ...`) inside AMPscript regions.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `problem` |
|
|
8
|
+
| **Default severity** | `warn` in `recommended`, `error` in `strict` |
|
|
9
|
+
| **Fixable** | **Auto-fix** (`eslint --fix`) |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
13
|
+
AMPscript only supports block comments (`/* ... */`). JavaScript-style single-line comments (`// comment`) are silently ignored by the SFMC compiler, but they cause crashes in ESLint (the `spaced-comment` rule throws an unhandled error), break Prettier formatting, and can confuse the language server.
|
|
14
|
+
|
|
15
|
+
Note: `://` in URLs (e.g. `"https://example.com"`) inside string literals is not flagged because string contents are not parsed as code.
|
|
16
|
+
|
|
17
|
+
## Settings
|
|
18
|
+
|
|
19
|
+
| Setting | Values | Default |
|
|
20
|
+
|---------|--------|---------|
|
|
21
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"warn"` |
|
|
22
|
+
|
|
23
|
+
This rule has no configuration options.
|
|
24
|
+
|
|
25
|
+
### Examples
|
|
26
|
+
|
|
27
|
+
**Not allowed:**
|
|
28
|
+
|
|
29
|
+
```ampscript
|
|
30
|
+
%%[
|
|
31
|
+
// ---------------Language---------------
|
|
32
|
+
set @Opco = AttributeValue("OwningEntity__c")
|
|
33
|
+
]%%
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Allowed:**
|
|
37
|
+
|
|
38
|
+
```ampscript
|
|
39
|
+
%%[
|
|
40
|
+
/* ---------------Language--------------- */
|
|
41
|
+
set @Opco = AttributeValue("OwningEntity__c")
|
|
42
|
+
]%%
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Fix
|
|
46
|
+
|
|
47
|
+
This rule provides an **auto-fix**: `// comment text` is replaced with `/* comment text */`.
|
|
48
|
+
|
|
49
|
+
## When to Disable
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
// eslint.config.js
|
|
53
|
+
rules: { 'sfmc/amp-no-js-line-comment': 'off' }
|
|
54
|
+
```
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# `sfmc/amp-no-loop-counter-assign`
|
|
2
|
+
|
|
3
|
+
> Disallow assigning to the `for` loop counter variable inside the loop body.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `suggestion` |
|
|
8
|
+
| **Default severity** | `warn` in `recommended`; `error` in `strict` |
|
|
9
|
+
| **Fixable** | — |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
13
|
+
AMPscript documentation explicitly states that modifying the counter variable inside a `FOR … TO … DO` loop is not allowed and causes validation or runtime errors. The counter (`@i` in `FOR @i = 1 TO @n DO`) is managed by the runtime; attempting to reassign it produces undefined behavior.
|
|
14
|
+
|
|
15
|
+
## Settings
|
|
16
|
+
|
|
17
|
+
| Setting | Values | Default |
|
|
18
|
+
|---------|--------|---------|
|
|
19
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"warn"` |
|
|
20
|
+
|
|
21
|
+
This rule has no configuration options.
|
|
22
|
+
|
|
23
|
+
### Examples
|
|
24
|
+
|
|
25
|
+
**Not allowed:**
|
|
26
|
+
|
|
27
|
+
```ampscript
|
|
28
|
+
%%[
|
|
29
|
+
for @i = 1 to 10 do
|
|
30
|
+
set @i = Add(@i, 1)
|
|
31
|
+
next @i
|
|
32
|
+
]%%
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Allowed:**
|
|
36
|
+
|
|
37
|
+
```ampscript
|
|
38
|
+
%%[
|
|
39
|
+
var @step
|
|
40
|
+
for @i = 1 to 10 do
|
|
41
|
+
set @step = Add(@i, 1)
|
|
42
|
+
output(v(@step))
|
|
43
|
+
next @i
|
|
44
|
+
]%%
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## When to Disable
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
// eslint.config.js
|
|
51
|
+
rules: { 'sfmc/amp-no-loop-counter-assign': 'off' }
|
|
52
|
+
```
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# `sfmc/amp-no-nested-ampscript-delimiter`
|
|
2
|
+
|
|
3
|
+
> Disallow `%%[` or `%%=` delimiters inside an already-open AMPscript region.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `problem` |
|
|
8
|
+
| **Default severity** | `error` in `recommended` and `strict` |
|
|
9
|
+
| **Fixable** | **Auto-fix** (`eslint --fix`) |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
13
|
+
AMPscript delimiters (`%%[`, `]%%`, `%%=`, `=%%`) are used in HTML context to mark the start and end of AMPscript regions. Inside an already-open region — whether a `%%[...]%%` block, a `%%=...=%%` inline expression, or a `<script language="ampscript">` tag — these delimiters are not needed and indicate a structural mistake.
|
|
14
|
+
|
|
15
|
+
Two sub-cases:
|
|
16
|
+
|
|
17
|
+
- `%%[` or `%%=` inside a `<script language="ampscript">` block — redundant because the script tag already establishes AMPscript context for its entire body.
|
|
18
|
+
- `%%[` nested inside an already-open `%%[...]%%` block — double-opening without a corresponding close.
|
|
19
|
+
|
|
20
|
+
## Settings
|
|
21
|
+
|
|
22
|
+
| Setting | Values | Default |
|
|
23
|
+
|---------|--------|---------|
|
|
24
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"error"` |
|
|
25
|
+
|
|
26
|
+
This rule has no configuration options.
|
|
27
|
+
|
|
28
|
+
### Examples
|
|
29
|
+
|
|
30
|
+
**Not allowed — delimiter inside script tag:**
|
|
31
|
+
|
|
32
|
+
```html
|
|
33
|
+
<script runat="server" language="ampscript">
|
|
34
|
+
%%[ set @x = "redundant delimiter" ]%%
|
|
35
|
+
</script>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Not allowed — nested block delimiter:**
|
|
39
|
+
|
|
40
|
+
```ampscript
|
|
41
|
+
%%[
|
|
42
|
+
%%[ set @inner = "nested" ]%%
|
|
43
|
+
]%%
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Allowed:**
|
|
47
|
+
|
|
48
|
+
```html
|
|
49
|
+
<script runat="server" language="ampscript">
|
|
50
|
+
set @x = "no delimiter needed here"
|
|
51
|
+
</script>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```ampscript
|
|
55
|
+
%%[
|
|
56
|
+
set @x = "correct"
|
|
57
|
+
]%%
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Fix
|
|
61
|
+
|
|
62
|
+
This rule provides an **auto-fix** that removes the redundant delimiter pair (`%%[`/`]%%` or `%%=`/`=%%`), leaving only the inner code.
|
|
63
|
+
|
|
64
|
+
## When to Disable
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
// eslint.config.js
|
|
68
|
+
rules: { 'sfmc/amp-no-nested-ampscript-delimiter': 'off' }
|
|
69
|
+
```
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# `sfmc/amp-no-nested-script-tag`
|
|
2
|
+
|
|
3
|
+
> Disallow nested `<script language="ampscript">` tags inside an already-open AMPscript script block.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `problem` |
|
|
8
|
+
| **Default severity** | `error` in `recommended` and `strict` |
|
|
9
|
+
| **Fixable** | **Auto-fix** (`eslint --fix`) |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
13
|
+
Each `<script runat="server" language="ampscript">` block must be closed with `</script>` before a new one can be opened. A nested opening tag is structurally invalid and almost always indicates a missing `</script>` closing tag. The SFMC compiler may silently ignore the nested tag, leading to code that appears to work but is structured incorrectly.
|
|
14
|
+
|
|
15
|
+
## Settings
|
|
16
|
+
|
|
17
|
+
| Setting | Values | Default |
|
|
18
|
+
|---------|--------|---------|
|
|
19
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"error"` |
|
|
20
|
+
|
|
21
|
+
This rule has no configuration options.
|
|
22
|
+
|
|
23
|
+
### Examples
|
|
24
|
+
|
|
25
|
+
**Not allowed:**
|
|
26
|
+
|
|
27
|
+
```html
|
|
28
|
+
<script runat="server" language="ampscript">
|
|
29
|
+
set @a = "outer"
|
|
30
|
+
|
|
31
|
+
<script runat="server" language="ampscript">
|
|
32
|
+
set @b = "inner - this tag is nested!"
|
|
33
|
+
</script>
|
|
34
|
+
</script>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Allowed:**
|
|
38
|
+
|
|
39
|
+
```html
|
|
40
|
+
<script runat="server" language="ampscript">
|
|
41
|
+
set @a = "outer"
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<script runat="server" language="ampscript">
|
|
45
|
+
set @b = "second block - valid"
|
|
46
|
+
</script>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Fix
|
|
50
|
+
|
|
51
|
+
This rule provides an **auto-fix**: inserts `</script>` immediately before the nested opening tag, converting the nested block into a valid sequential block.
|
|
52
|
+
|
|
53
|
+
## When to Disable
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
// eslint.config.js
|
|
57
|
+
rules: { 'sfmc/amp-no-nested-script-tag': 'off' }
|
|
58
|
+
```
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# `sfmc/amp-no-smart-quotes`
|
|
2
|
+
|
|
3
|
+
> Disallow smart/curly quotes in string literals.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `problem` |
|
|
8
|
+
| **Default severity** | `error` in `recommended` and `strict` |
|
|
9
|
+
| **Fixable** | **Auto-fix** (`eslint --fix`) |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
13
|
+
AMPscript's parser only recognises straight ASCII single (`'`) and double (`"`) quotes as string delimiters. Smart (curly) quotes — such as `"`, `"`, `'`, `'` — are commonly introduced by word processors, rich-text editors, or copy-pasting from documentation. When these characters appear inside a string literal the AMPscript engine produces a parse error or treats the content as malformed, causing the email or page to fail silently or crash.
|
|
14
|
+
|
|
15
|
+
## Settings
|
|
16
|
+
|
|
17
|
+
| Setting | Values | Default |
|
|
18
|
+
|---------|--------|---------|
|
|
19
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"error"` |
|
|
20
|
+
|
|
21
|
+
This rule has no configuration options.
|
|
22
|
+
|
|
23
|
+
### Examples
|
|
24
|
+
|
|
25
|
+
**Not allowed:**
|
|
26
|
+
|
|
27
|
+
```ampscript
|
|
28
|
+
%%[
|
|
29
|
+
var @name
|
|
30
|
+
set @name = "John"
|
|
31
|
+
set @name = 'Jane'
|
|
32
|
+
]%%
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Allowed:**
|
|
36
|
+
|
|
37
|
+
```ampscript
|
|
38
|
+
%%[
|
|
39
|
+
var @name
|
|
40
|
+
set @name = "John"
|
|
41
|
+
set @name = 'Jane'
|
|
42
|
+
]%%
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Fix
|
|
46
|
+
|
|
47
|
+
This rule provides an **auto-fix**. Applied by:
|
|
48
|
+
|
|
49
|
+
- `eslint --fix` on the command line (applies ALL fixable rules regardless of `meta.type`; use `--fix-type problem` or `--fix-type suggestion` to filter by rule category)
|
|
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" }`
|
|
52
|
+
|
|
53
|
+
What the fix does: replaces every smart quote inside the string content with its ASCII equivalent (`'` for single-flavour curly quotes, `"` for double-flavour). If the replacement would introduce the existing outer delimiter, the outer quotes are switched (e.g. `"…"` becomes `'…'`). If both quote types would appear after replacement, no automatic fix is applied.
|
|
54
|
+
|
|
55
|
+
## When to Disable
|
|
56
|
+
|
|
57
|
+
```js
|
|
58
|
+
// eslint.config.js
|
|
59
|
+
rules: { 'sfmc/amp-no-smart-quotes': 'off' }
|
|
60
|
+
```
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# `sfmc/amp-no-unknown-function`
|
|
2
|
+
|
|
3
|
+
> Disallow calls to function names not in the known AMPscript catalog.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `problem` |
|
|
8
|
+
| **Default severity** | `error` in `recommended` and `strict` |
|
|
9
|
+
| **Fixable** | — |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
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
|
+
|
|
15
|
+
## Settings
|
|
16
|
+
|
|
17
|
+
| Setting | Values | Default |
|
|
18
|
+
|---------|--------|---------|
|
|
19
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"error"` |
|
|
20
|
+
|
|
21
|
+
This rule has no configuration options.
|
|
22
|
+
|
|
23
|
+
### Examples
|
|
24
|
+
|
|
25
|
+
**Not allowed:**
|
|
26
|
+
|
|
27
|
+
```ampscript
|
|
28
|
+
%%[
|
|
29
|
+
var @result
|
|
30
|
+
set @result = CustomLookup("MyDE", "Key", @key)
|
|
31
|
+
]%%
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Allowed:**
|
|
35
|
+
|
|
36
|
+
```ampscript
|
|
37
|
+
%%[
|
|
38
|
+
var @result
|
|
39
|
+
set @result = Lookup("MyDE", "Value", "Key", @key)
|
|
40
|
+
]%%
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## When to Disable
|
|
44
|
+
|
|
45
|
+
Only disable this rule if you are intentionally using a proprietary or undocumented SFMC extension that is not in the public catalog.
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
// eslint.config.js
|
|
49
|
+
rules: { 'sfmc/amp-no-unknown-function': 'off' }
|
|
50
|
+
```
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# `sfmc/amp-no-var-redeclaration`
|
|
2
|
+
|
|
3
|
+
> Disallow re-declaring a variable with `var` after it has already been declared.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `problem` |
|
|
8
|
+
| **Default severity** | `warn` in `recommended`; `error` in `strict` |
|
|
9
|
+
| **Fixable** | — |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
13
|
+
In AMPscript, re-declaring an already-declared variable with `var` silently resets its value to `null`. This is a common source of bugs when code is copy-pasted or blocks are re-ordered — the second `var @x` statement discards any value assigned in between, leading to unexpected empty output or runtime errors downstream.
|
|
14
|
+
|
|
15
|
+
## Settings
|
|
16
|
+
|
|
17
|
+
| Setting | Values | Default |
|
|
18
|
+
|---------|--------|---------|
|
|
19
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"warn"` |
|
|
20
|
+
|
|
21
|
+
This rule has no configuration options.
|
|
22
|
+
|
|
23
|
+
### Examples
|
|
24
|
+
|
|
25
|
+
**Not allowed:**
|
|
26
|
+
|
|
27
|
+
```ampscript
|
|
28
|
+
%%[
|
|
29
|
+
var @name
|
|
30
|
+
set @name = "Alice"
|
|
31
|
+
var @name
|
|
32
|
+
/* @name is now null */
|
|
33
|
+
output(concat("Hello ", @name))
|
|
34
|
+
]%%
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Allowed:**
|
|
38
|
+
|
|
39
|
+
```ampscript
|
|
40
|
+
%%[
|
|
41
|
+
var @name
|
|
42
|
+
set @name = "Alice"
|
|
43
|
+
output(concat("Hello ", @name))
|
|
44
|
+
]%%
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## When to Disable
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
// eslint.config.js
|
|
51
|
+
rules: { 'sfmc/amp-no-var-redeclaration': 'off' }
|
|
52
|
+
```
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# `sfmc/amp-prefer-attribute-value`
|
|
2
|
+
|
|
3
|
+
> Prefer `AttributeValue()` over bare personalization strings for safe attribute access.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `suggestion` |
|
|
8
|
+
| **Default severity** | `off` by default |
|
|
9
|
+
| **Fixable** | **Suggestion** (manual, via VS Code lightbulb) |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
13
|
+
Using a bare identifier such as `FirstName` in a `SET` expression or as a standalone output relies on AMPscript's implicit personalization-string lookup. If the subscriber profile does not contain that attribute the send is aborted with an error. Wrapping the reference in `AttributeValue("FirstName")` instead returns an empty string (or a default value if the second argument is provided) when the attribute is missing, preventing send failures.
|
|
14
|
+
|
|
15
|
+
## Settings
|
|
16
|
+
|
|
17
|
+
| Setting | Values | Default |
|
|
18
|
+
|---------|--------|---------|
|
|
19
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"off"` |
|
|
20
|
+
|
|
21
|
+
This rule has no configuration options.
|
|
22
|
+
|
|
23
|
+
### Examples
|
|
24
|
+
|
|
25
|
+
**Not allowed (when rule is enabled):**
|
|
26
|
+
|
|
27
|
+
```ampscript
|
|
28
|
+
%%[
|
|
29
|
+
var @greeting
|
|
30
|
+
set @greeting = concat("Hello, ", FirstName)
|
|
31
|
+
]%%
|
|
32
|
+
%%=FirstName=%%
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Allowed:**
|
|
36
|
+
|
|
37
|
+
```ampscript
|
|
38
|
+
%%[
|
|
39
|
+
var @greeting
|
|
40
|
+
set @greeting = concat("Hello, ", AttributeValue("FirstName"))
|
|
41
|
+
]%%
|
|
42
|
+
%%=AttributeValue("FirstName")=%%
|
|
43
|
+
|
|
44
|
+
/* With a default value: */
|
|
45
|
+
%%=AttributeValue("FirstName", "default", "", "Subscriber")=%%
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Fix
|
|
49
|
+
|
|
50
|
+
This rule provides a **suggestion** (not applied automatically). To apply it:
|
|
51
|
+
|
|
52
|
+
- Click the **lightbulb** / press `Ctrl+.` on the flagged code in VS Code (requires the [ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint))
|
|
53
|
+
- `eslint --fix` does **not** apply suggestions (`--fix-type suggestion` filters fixable rules by rule category, it does **not** apply `hasSuggestions` suggestions)
|
|
54
|
+
|
|
55
|
+
What the suggestion does: wraps the bare identifier (e.g. `FirstName`) in `AttributeValue("FirstName")`.
|
|
56
|
+
|
|
57
|
+
## When to Disable
|
|
58
|
+
|
|
59
|
+
This rule is off by default because bare personalization strings are valid AMPscript. Enable it only if your team wants to enforce the safer `AttributeValue()` pattern across all content.
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
// eslint.config.js
|
|
63
|
+
rules: { 'sfmc/amp-prefer-attribute-value': 'warn' }
|
|
64
|
+
```
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# `sfmc/amp-require-rowcount-check`
|
|
2
|
+
|
|
3
|
+
> Require a `RowCount > 0` check before iterating over a `LookupRows` result.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `problem` |
|
|
8
|
+
| **Default severity** | `warn` in `recommended`; `error` in `strict` |
|
|
9
|
+
| **Fixable** | — |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
13
|
+
When `LookupRows` (or `LookupOrderedRows`) returns an empty rowset and you immediately use `FOR @i = 1 TO RowCount(@rows)`, AMPscript evaluates `RowCount(@rows)` as `0`. A `FOR` loop iterating `1 TO 0` triggers a runtime error on some SFMC versions because the loop body attempts to access row index `1` from an empty set. The safe pattern is to guard the loop with `IF RowCount(@rows) > 0 THEN … ENDIF`.
|
|
14
|
+
|
|
15
|
+
## Settings
|
|
16
|
+
|
|
17
|
+
| Setting | Values | Default |
|
|
18
|
+
|---------|--------|---------|
|
|
19
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"warn"` |
|
|
20
|
+
|
|
21
|
+
This rule has no configuration options.
|
|
22
|
+
|
|
23
|
+
### Examples
|
|
24
|
+
|
|
25
|
+
**Not allowed:**
|
|
26
|
+
|
|
27
|
+
```ampscript
|
|
28
|
+
%%[
|
|
29
|
+
var @rows
|
|
30
|
+
set @rows = LookupRows("MyDE", "Status", "Active")
|
|
31
|
+
|
|
32
|
+
for @i = 1 to RowCount(@rows) do
|
|
33
|
+
var @email
|
|
34
|
+
set @email = Field(Row(@rows, @i), "Email")
|
|
35
|
+
output(v(@email))
|
|
36
|
+
next @i
|
|
37
|
+
]%%
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Allowed:**
|
|
41
|
+
|
|
42
|
+
```ampscript
|
|
43
|
+
%%[
|
|
44
|
+
var @rows
|
|
45
|
+
set @rows = LookupRows("MyDE", "Status", "Active")
|
|
46
|
+
|
|
47
|
+
if RowCount(@rows) > 0 then
|
|
48
|
+
for @i = 1 to RowCount(@rows) do
|
|
49
|
+
var @email
|
|
50
|
+
set @email = Field(Row(@rows, @i), "Email")
|
|
51
|
+
output(v(@email))
|
|
52
|
+
next @i
|
|
53
|
+
endif
|
|
54
|
+
]%%
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## When to Disable
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
// eslint.config.js
|
|
61
|
+
rules: { 'sfmc/amp-require-rowcount-check': 'off' }
|
|
62
|
+
```
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# `sfmc/amp-require-variable-declaration`
|
|
2
|
+
|
|
3
|
+
> Require variables to be declared with `var` before use in `set` statements.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `suggestion` |
|
|
8
|
+
| **Default severity** | `off` by default |
|
|
9
|
+
| **Fixable** | — |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
13
|
+
AMPscript does not technically require `var` before `set` — you can write `set @x = 1` without a prior declaration. However, the [ampscript.guide](https://ampscript.guide) best-practices documentation recommends always declaring variables with `var` first. This makes code self-documenting, helps catch variable-name typos at lint time, and mirrors the conventions used in official Salesforce examples.
|
|
14
|
+
|
|
15
|
+
System variables (those starting with `@@`) are not affected.
|
|
16
|
+
|
|
17
|
+
## Settings
|
|
18
|
+
|
|
19
|
+
| Setting | Values | Default |
|
|
20
|
+
|---------|--------|---------|
|
|
21
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"off"` |
|
|
22
|
+
|
|
23
|
+
This rule has no configuration options.
|
|
24
|
+
|
|
25
|
+
### Examples
|
|
26
|
+
|
|
27
|
+
**Not allowed (when rule is enabled):**
|
|
28
|
+
|
|
29
|
+
```ampscript
|
|
30
|
+
%%[
|
|
31
|
+
set @name = "Alice"
|
|
32
|
+
]%%
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Allowed:**
|
|
36
|
+
|
|
37
|
+
```ampscript
|
|
38
|
+
%%[
|
|
39
|
+
var @name
|
|
40
|
+
set @name = "Alice"
|
|
41
|
+
]%%
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## When to Disable
|
|
45
|
+
|
|
46
|
+
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.
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
// eslint.config.js
|
|
50
|
+
rules: { 'sfmc/amp-require-variable-declaration': 'warn' }
|
|
51
|
+
```
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# `sfmc/amp-set-requires-target`
|
|
2
|
+
|
|
3
|
+
> Require `set` statements to have a target variable.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `problem` |
|
|
8
|
+
| **Default severity** | `error` in `recommended` and `strict` |
|
|
9
|
+
| **Fixable** | — |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
13
|
+
The correct form of a `set` statement is `set @variable = expression`. A bare `set = expression` with no target is either a parse error or produces undefined runtime behavior. This always indicates a typo or incomplete code.
|
|
14
|
+
|
|
15
|
+
## Settings
|
|
16
|
+
|
|
17
|
+
| Setting | Values | Default |
|
|
18
|
+
|---------|--------|---------|
|
|
19
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"error"` |
|
|
20
|
+
|
|
21
|
+
This rule has no configuration options.
|
|
22
|
+
|
|
23
|
+
### Examples
|
|
24
|
+
|
|
25
|
+
**Not allowed:**
|
|
26
|
+
|
|
27
|
+
```ampscript
|
|
28
|
+
%%[
|
|
29
|
+
set = Lookup("MyDE", "Value", "Key", @key)
|
|
30
|
+
]%%
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Allowed:**
|
|
34
|
+
|
|
35
|
+
```ampscript
|
|
36
|
+
%%[
|
|
37
|
+
var @result
|
|
38
|
+
set @result = Lookup("MyDE", "Value", "Key", @key)
|
|
39
|
+
]%%
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## When to Disable
|
|
43
|
+
|
|
44
|
+
```js
|
|
45
|
+
// eslint.config.js
|
|
46
|
+
rules: { 'sfmc/amp-set-requires-target': 'off' }
|
|
47
|
+
```
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# `sfmc/ssjs-cache-loop-length`
|
|
2
|
+
|
|
3
|
+
> Require caching array `.length` in `for` loop conditions.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `suggestion` |
|
|
8
|
+
| **Default severity** | `warn` in `recommended`; `error` in `strict` |
|
|
9
|
+
| **Fixable** | **Suggestion** (manual, via VS Code lightbulb) |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
13
|
+
SFMC's SSJS engine (JINT) re-evaluates the loop test expression on every iteration. A condition like `i < arr.length` therefore calls the `.length` getter on every pass through the loop. For large arrays this is a measurable performance cost. The recommended pattern (per Mateusz Dąbrowski's SSJS style guide) is to cache the length in a variable in the loop initialiser:
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
for (var i = 0, _len = arr.length; i < _len; i++) { … }
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Settings
|
|
20
|
+
|
|
21
|
+
| Setting | Values | Default |
|
|
22
|
+
|---------|--------|---------|
|
|
23
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"warn"` |
|
|
24
|
+
|
|
25
|
+
This rule has no configuration options.
|
|
26
|
+
|
|
27
|
+
### Examples
|
|
28
|
+
|
|
29
|
+
**Not allowed:**
|
|
30
|
+
|
|
31
|
+
```js
|
|
32
|
+
for (var i = 0; i < items.length; i++) {
|
|
33
|
+
process(items[i]);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Allowed:**
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
for (var i = 0, _len = items.length; i < _len; i++) {
|
|
41
|
+
process(items[i]);
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Fix
|
|
46
|
+
|
|
47
|
+
This rule provides a **suggestion** (not applied automatically). To apply it:
|
|
48
|
+
|
|
49
|
+
- Click the **lightbulb** / press `Ctrl+.` on the flagged code in VS Code (requires the [ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint))
|
|
50
|
+
- `eslint --fix` does **not** apply suggestions (`--fix-type suggestion` filters fixable rules by rule category, it does **not** apply `hasSuggestions` suggestions)
|
|
51
|
+
|
|
52
|
+
What the suggestion 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 suggestion is only offered when the loop `init` is a `var` declaration (the typical case).
|
|
53
|
+
|
|
54
|
+
## When to Disable
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
// eslint.config.js
|
|
58
|
+
rules: { 'sfmc/ssjs-cache-loop-length': 'off' }
|
|
59
|
+
```
|