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
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jörn Berkefeld
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# eslint-plugin-sfmc
|
|
2
|
+
|
|
3
|
+
Unified ESLint plugin for **Salesforce Marketing Cloud** — linting rules for both **AMPscript** and **Server-Side JavaScript (SSJS)**.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install eslint-plugin-sfmc --save-dev
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires ESLint 9+ (flat config).
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
// eslint.config.js
|
|
17
|
+
import sfmc from 'eslint-plugin-sfmc';
|
|
18
|
+
|
|
19
|
+
export default [
|
|
20
|
+
// Lint standalone .ampscript/.amp and .ssjs files
|
|
21
|
+
...sfmc.configs.recommended,
|
|
22
|
+
|
|
23
|
+
// Lint AMPscript + SSJS embedded in .html files
|
|
24
|
+
...sfmc.configs.embedded,
|
|
25
|
+
];
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Configs
|
|
29
|
+
|
|
30
|
+
| Config | Files | What it does |
|
|
31
|
+
| -------------------------- | ---------------------------- | --------------------------------------------------------- |
|
|
32
|
+
| `sfmc.configs.ampscript` | `**/*.ampscript`, `**/*.amp` | AMPscript rules only (recommended severity) |
|
|
33
|
+
| `sfmc.configs.ssjs` | `**/*.ssjs` | SSJS rules only (recommended severity) |
|
|
34
|
+
| `sfmc.configs.recommended` | Both of the above | All rules at recommended severity for standalone files |
|
|
35
|
+
| `sfmc.configs.embedded` | `**/*.html` | Combined processor extracts both languages from HTML |
|
|
36
|
+
| `sfmc.configs.strict` | All of the above + HTML | All rules at `error` severity for standalone and embedded |
|
|
37
|
+
|
|
38
|
+
`recommended`, `embedded`, and `strict` are arrays — spread them with `...`.
|
|
39
|
+
|
|
40
|
+
## AMPscript Rules (`amp-*`)
|
|
41
|
+
|
|
42
|
+
| Rule | Default | Description |
|
|
43
|
+
| --------------------------------------- | ------- | --------------------------------------------------- |
|
|
44
|
+
| [`sfmc/amp-no-unknown-function`](docs/rules/amp/no-unknown-function.md) | `error` | Disallow calls to unknown AMPscript functions |
|
|
45
|
+
| [`sfmc/amp-function-arity`](docs/rules/amp/function-arity.md) | `error` | Enforce correct argument counts |
|
|
46
|
+
| [`sfmc/amp-set-requires-target`](docs/rules/amp/set-requires-target.md) | `error` | Require `set` to have a target variable |
|
|
47
|
+
| [`sfmc/amp-no-smart-quotes`](docs/rules/amp/no-smart-quotes.md) | `error` | Disallow smart/curly quotes in strings |
|
|
48
|
+
| [`sfmc/amp-no-var-redeclaration`](docs/rules/amp/no-var-redeclaration.md) | `warn` | Disallow re-declaring a variable with `var` |
|
|
49
|
+
| [`sfmc/amp-no-empty-block`](docs/rules/amp/no-empty-block.md) | `warn` | Disallow empty `%%[ ]%%` blocks |
|
|
50
|
+
| [`sfmc/amp-no-loop-counter-assign`](docs/rules/amp/no-loop-counter-assign.md) | `warn` | Disallow assigning to the `for` loop counter |
|
|
51
|
+
| [`sfmc/amp-no-inline-statement`](docs/rules/amp/no-inline-statement.md) | `warn` | Disallow statements inside inline expressions |
|
|
52
|
+
| [`sfmc/amp-no-deprecated-function`](docs/rules/amp/no-deprecated-function.md) | `warn` | Flag deprecated functions and suggest replacements |
|
|
53
|
+
| [`sfmc/amp-naming-convention`](docs/rules/amp/naming-convention.md) | `warn` | Enforce variable naming convention |
|
|
54
|
+
| [`sfmc/amp-no-empty-then`](docs/rules/amp/no-empty-then.md) | `warn` | Disallow IF with empty THEN branch |
|
|
55
|
+
| [`sfmc/amp-require-rowcount-check`](docs/rules/amp/require-rowcount-check.md) | `warn` | Require RowCount check before FOR on LookupRows |
|
|
56
|
+
| [`sfmc/amp-no-html-comment`](docs/rules/amp/no-html-comment.md) | `warn` | Disallow HTML comments inside AMPscript blocks |
|
|
57
|
+
| [`sfmc/amp-no-js-line-comment`](docs/rules/amp/no-js-line-comment.md) | `warn` | Disallow JS-style `//` line comments in AMPscript |
|
|
58
|
+
| [`sfmc/amp-no-nested-script-tag`](docs/rules/amp/no-nested-script-tag.md) | `error` | Disallow `<script>` tags nested inside AMPscript script tags |
|
|
59
|
+
| [`sfmc/amp-no-nested-ampscript-delimiter`](docs/rules/amp/no-nested-ampscript-delimiter.md) | `error` | Disallow AMPscript delimiters nested inside AMPscript blocks |
|
|
60
|
+
| [`sfmc/amp-prefer-attribute-value`](docs/rules/amp/prefer-attribute-value.md) | off | Prefer `AttributeValue()` over bare personalization |
|
|
61
|
+
| [`sfmc/amp-require-variable-declaration`](docs/rules/amp/require-variable-declaration.md) | off | Require `var` before `set` |
|
|
62
|
+
| [`sfmc/amp-no-email-excluded-function`](docs/rules/amp/no-email-excluded-function.md) | off | Flag functions unavailable in email context |
|
|
63
|
+
|
|
64
|
+
## SSJS Rules (`ssjs-*`)
|
|
65
|
+
|
|
66
|
+
| Rule | Default | Description |
|
|
67
|
+
| ---------------------------------------- | ------- | ---------------------------------------------------- |
|
|
68
|
+
| [`sfmc/ssjs-require-platform-load`](docs/rules/ssjs/require-platform-load.md) | `error` | Require `Platform.Load("core")` before Core usage |
|
|
69
|
+
| [`sfmc/ssjs-no-unsupported-syntax`](docs/rules/ssjs/no-unsupported-syntax.md) | `error` | Flag ES6+ syntax not supported by SFMC |
|
|
70
|
+
| [`sfmc/ssjs-no-unknown-platform-function`](docs/rules/ssjs/no-unknown-platform-function.md) | `error` | Disallow unknown `Platform.Function.*` methods |
|
|
71
|
+
| [`sfmc/ssjs-platform-function-arity`](docs/rules/ssjs/platform-function-arity.md) | `error` | Enforce correct arity for `Platform.Function.*` |
|
|
72
|
+
| [`sfmc/ssjs-no-unknown-http-method`](docs/rules/ssjs/no-unknown-http-method.md) | `error` | Disallow unknown `HTTP.*` methods |
|
|
73
|
+
| [`sfmc/ssjs-no-unknown-platform-variable`](docs/rules/ssjs/no-unknown-platform-variable.md) | `error` | Disallow unknown `Platform.Variable.*` methods |
|
|
74
|
+
| [`sfmc/ssjs-no-unknown-platform-response`](docs/rules/ssjs/no-unknown-platform-response.md) | `error` | Disallow unknown `Platform.Response.*` methods |
|
|
75
|
+
| [`sfmc/ssjs-no-unknown-platform-request`](docs/rules/ssjs/no-unknown-platform-request.md) | `error` | Disallow unknown `Platform.Request.*` methods |
|
|
76
|
+
| [`sfmc/ssjs-require-platform-load-order`](docs/rules/ssjs/require-platform-load-order.md) | `error` | Require `Platform.Load()` before Core usage in order |
|
|
77
|
+
| [`sfmc/ssjs-no-hardcoded-credentials`](docs/rules/ssjs/no-hardcoded-credentials.md) | `error` | Flag hardcoded keys in encryption calls |
|
|
78
|
+
| [`sfmc/ssjs-no-unknown-platform-client-browser`](docs/rules/ssjs/no-unknown-platform-client-browser.md) | `error` | Disallow unknown `Platform.ClientBrowser.*` methods |
|
|
79
|
+
| [`sfmc/ssjs-no-unknown-core-method`](docs/rules/ssjs/no-unknown-core-method.md) | `warn` | Disallow unknown methods on Core library objects |
|
|
80
|
+
| [`sfmc/ssjs-no-unknown-wsproxy-method`](docs/rules/ssjs/no-unknown-wsproxy-method.md) | `warn` | Disallow unknown WSProxy methods |
|
|
81
|
+
| [`sfmc/ssjs-cache-loop-length`](docs/rules/ssjs/cache-loop-length.md) | `warn` | Require caching `.length` in for-loops |
|
|
82
|
+
| [`sfmc/ssjs-require-hasownproperty`](docs/rules/ssjs/require-hasownproperty.md) | `warn` | Require `hasOwnProperty` guard in for-in loops |
|
|
83
|
+
| [`sfmc/ssjs-prefer-platform-load-version`](docs/rules/ssjs/prefer-platform-load-version.md) | `warn` | Enforce a minimum `Platform.Load` version string |
|
|
84
|
+
| [`sfmc/ssjs-no-unavailable-method`](docs/rules/ssjs/no-unavailable-method.md) | `warn` | Flag Array/String methods unavailable or broken in SFMC's ES3 engine |
|
|
85
|
+
| [`sfmc/ssjs-prefer-parsejson-safe-arg`](docs/rules/ssjs/prefer-parsejson-safe-arg.md) | `warn` | Require string coercion on `ParseJSON` argument |
|
|
86
|
+
| [`sfmc/ssjs-no-switch-default`](docs/rules/ssjs/no-switch-default.md) | `warn` | Disallow `default` clause in `switch` statements |
|
|
87
|
+
| [`sfmc/ssjs-no-treatascontent-injection`](docs/rules/ssjs/no-treatascontent-injection.md) | `warn` | Flag dynamic string concatenation in `TreatAsContent` calls |
|
|
88
|
+
|
|
89
|
+
## Processors
|
|
90
|
+
|
|
91
|
+
| Processor | Purpose |
|
|
92
|
+
| ---------------- | ------------------------------------------------------------- |
|
|
93
|
+
| `sfmc/ampscript` | Extract `%%[ ]%%`, `%%= =%%`, `<script language="ampscript">` |
|
|
94
|
+
| `sfmc/ssjs` | Extract `<script runat="server">` (non-ampscript) |
|
|
95
|
+
| `sfmc/sfmc` | Combined: extracts both AMPscript and SSJS from HTML |
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
## License
|
|
99
|
+
|
|
100
|
+
MIT
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# `sfmc/amp-function-arity`
|
|
2
|
+
|
|
3
|
+
> Enforce correct argument counts for known AMPscript functions.
|
|
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 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
|
+
|
|
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
|
+
/* Lookup requires at least 4 arguments */
|
|
30
|
+
var @val
|
|
31
|
+
set @val = Lookup("MyDE", "Value")
|
|
32
|
+
|
|
33
|
+
/* Format accepts at most 3 arguments */
|
|
34
|
+
set @val = Format(@num, "0.00", "en-US", "extra")
|
|
35
|
+
]%%
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Allowed:**
|
|
39
|
+
|
|
40
|
+
```ampscript
|
|
41
|
+
%%[
|
|
42
|
+
var @val
|
|
43
|
+
set @val = Lookup("MyDE", "Value", "Key", @key)
|
|
44
|
+
set @val = Format(@num, "0.00", "en-US")
|
|
45
|
+
]%%
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## When to Disable
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
// eslint.config.js
|
|
52
|
+
rules: { 'sfmc/amp-function-arity': 'off' }
|
|
53
|
+
```
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# `sfmc/amp-naming-convention`
|
|
2
|
+
|
|
3
|
+
> Enforce a consistent naming convention for `@variable` names.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `suggestion` |
|
|
8
|
+
| **Default severity** | `off` by default; `warn` when explicitly enabled |
|
|
9
|
+
| **Fixable** | — |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
13
|
+
AMPscript variable names are case-insensitive at runtime, but inconsistent casing (`@myVar` vs `@MyVar` vs `@MYVAR` for the same variable) causes confusion during code reviews and maintenance. Enforcing a single convention across a codebase makes intent clearer and reduces the risk of typos that create an unintended second variable reference.
|
|
14
|
+
|
|
15
|
+
## Settings
|
|
16
|
+
|
|
17
|
+
| Setting | Values | Default |
|
|
18
|
+
|---------|--------|---------|
|
|
19
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"off"` |
|
|
20
|
+
| `format` | `"camelCase"` \| `"PascalCase"` | `"camelCase"` |
|
|
21
|
+
|
|
22
|
+
### Under `"camelCase"` (default)
|
|
23
|
+
|
|
24
|
+
**Not allowed:**
|
|
25
|
+
|
|
26
|
+
```ampscript
|
|
27
|
+
%%[
|
|
28
|
+
var @FirstName
|
|
29
|
+
var @LAST_NAME
|
|
30
|
+
]%%
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Allowed:**
|
|
34
|
+
|
|
35
|
+
```ampscript
|
|
36
|
+
%%[
|
|
37
|
+
var @firstName
|
|
38
|
+
var @lastName
|
|
39
|
+
]%%
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Under `"PascalCase"`
|
|
43
|
+
|
|
44
|
+
**Not allowed:**
|
|
45
|
+
|
|
46
|
+
```ampscript
|
|
47
|
+
%%[
|
|
48
|
+
var @firstName
|
|
49
|
+
var @last_name
|
|
50
|
+
]%%
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Allowed:**
|
|
54
|
+
|
|
55
|
+
```ampscript
|
|
56
|
+
%%[
|
|
57
|
+
var @FirstName
|
|
58
|
+
var @LastName
|
|
59
|
+
]%%
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Configuration Example
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
// eslint.config.js
|
|
66
|
+
rules: {
|
|
67
|
+
'sfmc/amp-naming-convention': ['warn', { format: 'PascalCase' }]
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## When to Disable
|
|
72
|
+
|
|
73
|
+
```js
|
|
74
|
+
// eslint.config.js
|
|
75
|
+
rules: { 'sfmc/amp-naming-convention': 'off' }
|
|
76
|
+
```
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# `sfmc/amp-no-deprecated-function`
|
|
2
|
+
|
|
3
|
+
> Flag deprecated AMPscript functions and suggest their modern replacements.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `suggestion` |
|
|
8
|
+
| **Default severity** | `warn` in `recommended`; `error` in `strict` |
|
|
9
|
+
| **Fixable** | **Auto-fix** for 1:1 replacements; **Suggestion** for ambiguous replacements |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
13
|
+
Salesforce has deprecated several AMPscript functions in favour of newer equivalents. The old functions (e.g. `InsertDE`, `UpdateDE`, `DeleteDE`, `LookupValue`) remain functional for backward compatibility but may be removed in a future platform update. `ContentArea` is a Classic-only function with no equivalent in Content Builder — callers must choose between `ContentBlockByKey` or `ContentBlockByName` depending on their setup.
|
|
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 = LookupValue("MyDE", "Email", "SubKey", @key)
|
|
31
|
+
|
|
32
|
+
var @html
|
|
33
|
+
set @html = ContentArea(42)
|
|
34
|
+
]%%
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Allowed:**
|
|
38
|
+
|
|
39
|
+
```ampscript
|
|
40
|
+
%%[
|
|
41
|
+
var @rows
|
|
42
|
+
set @rows = Lookup("MyDE", "Email", "SubKey", @key)
|
|
43
|
+
|
|
44
|
+
/* Choose one depending on your setup: */
|
|
45
|
+
var @html
|
|
46
|
+
set @html = ContentBlockByKey("my-block-key")
|
|
47
|
+
/* or */
|
|
48
|
+
set @html = ContentBlockByName("My Block Name")
|
|
49
|
+
]%%
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Fix
|
|
53
|
+
|
|
54
|
+
This rule provides two types of fix depending on the deprecated function:
|
|
55
|
+
|
|
56
|
+
**Auto-fix** (for 1:1 replacements such as `InsertDE → InsertData`, `LookupValue → Lookup`, etc.). Applied by:
|
|
57
|
+
|
|
58
|
+
- `eslint --fix` on the command line (because `meta.type` is `"suggestion"`, you can also target it specifically with `--fix-type suggestion`)
|
|
59
|
+
- **Fix this issue** / **Fix all auto-fixable problems** in VS Code (requires the [ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint))
|
|
60
|
+
- On save via `editor.codeActionsOnSave: { "source.fixAll.eslint": "explicit" }`
|
|
61
|
+
|
|
62
|
+
What the auto-fix does: replaces only the function name token, leaving all arguments intact.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
**Suggestion** (for `ContentArea`, which maps to either `ContentBlockByKey` or `ContentBlockByName`). Applied by:
|
|
67
|
+
|
|
68
|
+
- Click the **lightbulb** / press `Ctrl+.` on the flagged code in VS Code (requires the ESLint extension)
|
|
69
|
+
- `eslint --fix` does **not** apply suggestions (`--fix-type suggestion` filters fixable rules by rule category, it does **not** apply `hasSuggestions` suggestions)
|
|
70
|
+
|
|
71
|
+
What the suggestion does: offers two separate options — replace `ContentArea` with `ContentBlockByKey` or with `ContentBlockByName`.
|
|
72
|
+
|
|
73
|
+
## When to Disable
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
// eslint.config.js
|
|
77
|
+
rules: { 'sfmc/amp-no-deprecated-function': 'off' }
|
|
78
|
+
```
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# `sfmc/amp-no-email-excluded-function`
|
|
2
|
+
|
|
3
|
+
> Disallow AMPscript functions that are not available in the email execution context.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `problem` |
|
|
8
|
+
| **Default severity** | `off` by default |
|
|
9
|
+
| **Fixable** | — |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
13
|
+
Several AMPscript functions — including `InsertData`, `UpdateData`, `DeleteData`, `UpsertData`, `Redirect`, `HTTPGet`, and others — are only available in CloudPage and landing-page contexts. Calling them inside an email causes a runtime error, silently fails, or aborts the send. This rule flags those calls when the file is identified as an email template.
|
|
14
|
+
|
|
15
|
+
## Settings
|
|
16
|
+
|
|
17
|
+
| Setting | Values | Default |
|
|
18
|
+
|---------|--------|---------|
|
|
19
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"off"` |
|
|
20
|
+
| `context` | `"email"` \| `"cloudpage"` \| `"auto"` | `"email"` |
|
|
21
|
+
|
|
22
|
+
### Under `"email"` (default)
|
|
23
|
+
|
|
24
|
+
Flags every call to an email-excluded function regardless of the filename.
|
|
25
|
+
|
|
26
|
+
**Not allowed:**
|
|
27
|
+
|
|
28
|
+
```ampscript
|
|
29
|
+
%%[
|
|
30
|
+
InsertData("MyDE", "Email", @email)
|
|
31
|
+
Redirect("https://example.com")
|
|
32
|
+
]%%
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Allowed:**
|
|
36
|
+
|
|
37
|
+
```ampscript
|
|
38
|
+
%%[
|
|
39
|
+
InsertDE("MyDE", "Email", @email)
|
|
40
|
+
]%%
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
> Note: `InsertDE` is itself deprecated — see [`amp-no-deprecated-function`](no-deprecated-function.md).
|
|
44
|
+
|
|
45
|
+
### Under `"cloudpage"`
|
|
46
|
+
|
|
47
|
+
Disables all checks. Use this setting for files that are exclusively used as CloudPages.
|
|
48
|
+
|
|
49
|
+
### Under `"auto"`
|
|
50
|
+
|
|
51
|
+
Skips checking for files whose name or path contains `cloudpage` or `landing`, or whose extension is `.html`. Otherwise behaves like `"email"`.
|
|
52
|
+
|
|
53
|
+
## Configuration Example
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
// eslint.config.js
|
|
57
|
+
rules: {
|
|
58
|
+
'sfmc/amp-no-email-excluded-function': ['warn', { context: 'auto' }]
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## When to Disable
|
|
63
|
+
|
|
64
|
+
This rule is off by default because many projects contain both email and CloudPage AMPscript. Enable it with `"context": "auto"` for mixed-use projects, or with `"context": "email"` for email-only repositories.
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
// eslint.config.js
|
|
68
|
+
rules: { 'sfmc/amp-no-email-excluded-function': 'off' }
|
|
69
|
+
```
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# `sfmc/amp-no-empty-block`
|
|
2
|
+
|
|
3
|
+
> Disallow empty AMPscript blocks that produce no output or side effects.
|
|
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
|
+
An empty `%%[ ]%%` block (one that contains no statements other than comments) does nothing. Such blocks are typically leftovers from deleted code or copy-paste errors. While harmless at runtime, they add noise to templates and can cause confusion during maintenance.
|
|
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
|
+
]%%
|
|
30
|
+
|
|
31
|
+
%%[
|
|
32
|
+
/* TODO: add logic here */
|
|
33
|
+
]%%
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Allowed:**
|
|
37
|
+
|
|
38
|
+
```ampscript
|
|
39
|
+
%%[
|
|
40
|
+
var @name
|
|
41
|
+
set @name = "Alice"
|
|
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: removes the entire `%%[ ]%%` block from the source.
|
|
53
|
+
|
|
54
|
+
## When to Disable
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
// eslint.config.js
|
|
58
|
+
rules: { 'sfmc/amp-no-empty-block': 'off' }
|
|
59
|
+
```
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# `sfmc/amp-no-empty-then`
|
|
2
|
+
|
|
3
|
+
> Disallow `IF` statements with an empty `THEN` branch.
|
|
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
|
+
An `IF condition THEN … ELSE … ENDIF` where the `THEN` branch is empty is almost always a logic error. The most common cause is an inverted condition — the developer wrote the consequent code in the `ELSE` branch and left `THEN` empty, or accidentally deleted the `THEN` body during editing. The code either does nothing when the condition is true, or produces the wrong output.
|
|
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
|
+
if @isActive == 1 then
|
|
30
|
+
else
|
|
31
|
+
set @msg = "Inactive"
|
|
32
|
+
endif
|
|
33
|
+
]%%
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Allowed:**
|
|
37
|
+
|
|
38
|
+
```ampscript
|
|
39
|
+
%%[
|
|
40
|
+
if @isActive == 1 then
|
|
41
|
+
set @msg = "Active"
|
|
42
|
+
else
|
|
43
|
+
set @msg = "Inactive"
|
|
44
|
+
endif
|
|
45
|
+
]%%
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```ampscript
|
|
49
|
+
%%[
|
|
50
|
+
/* Empty THEN with no ELSE is still flagged — use a positive condition instead */
|
|
51
|
+
if @isActive != 1 then
|
|
52
|
+
set @msg = "Inactive"
|
|
53
|
+
endif
|
|
54
|
+
]%%
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## When to Disable
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
// eslint.config.js
|
|
61
|
+
rules: { 'sfmc/amp-no-empty-then': 'off' }
|
|
62
|
+
```
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# `sfmc/amp-no-html-comment`
|
|
2
|
+
|
|
3
|
+
> Disallow HTML comment syntax (`<!-- ... -->`) 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 has no HTML comment syntax. HTML comments (`<!-- -->`) inside AMPscript blocks are silently ignored by the SFMC compiler, but they break language servers, formatters (Prettier), and ESLint — including causing crashes in ESLint's `spaced-comment` rule.
|
|
14
|
+
|
|
15
|
+
Two common variants are caught:
|
|
16
|
+
|
|
17
|
+
- `<!--/* comment */-->` — an AMPscript `/* */` block comment unnecessarily wrapped in HTML comment markers.
|
|
18
|
+
- `<!-- comment -->` — a plain HTML comment used where an AMPscript comment should be.
|
|
19
|
+
|
|
20
|
+
## Settings
|
|
21
|
+
|
|
22
|
+
| Setting | Values | Default |
|
|
23
|
+
|---------|--------|---------|
|
|
24
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"warn"` |
|
|
25
|
+
|
|
26
|
+
This rule has no configuration options.
|
|
27
|
+
|
|
28
|
+
### Examples
|
|
29
|
+
|
|
30
|
+
**Not allowed:**
|
|
31
|
+
|
|
32
|
+
```ampscript
|
|
33
|
+
%%[
|
|
34
|
+
<!--/* OPCO specific Language */-->
|
|
35
|
+
set @Opco = AttributeValue("OwningEntity__c")
|
|
36
|
+
]%%
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```ampscript
|
|
40
|
+
%%[
|
|
41
|
+
<!-- some section header -->
|
|
42
|
+
set @x = 1
|
|
43
|
+
]%%
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Allowed:**
|
|
47
|
+
|
|
48
|
+
```ampscript
|
|
49
|
+
%%[
|
|
50
|
+
/* OPCO specific Language */
|
|
51
|
+
set @Opco = AttributeValue("OwningEntity__c")
|
|
52
|
+
]%%
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Fix
|
|
56
|
+
|
|
57
|
+
This rule provides an **auto-fix**:
|
|
58
|
+
|
|
59
|
+
- `<!--/* ... */-->` → `/* ... */` (HTML wrapper is stripped, inner block comment is kept as-is)
|
|
60
|
+
- `<!-- ... -->` → `/* ... */` (entire construct is replaced with an AMPscript block comment)
|
|
61
|
+
|
|
62
|
+
## When to Disable
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
// eslint.config.js
|
|
66
|
+
rules: { 'sfmc/amp-no-html-comment': 'off' }
|
|
67
|
+
```
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# `sfmc/amp-no-inline-statement`
|
|
2
|
+
|
|
3
|
+
> Disallow control-flow statements inside inline expressions (`%%=…=%%`).
|
|
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
|
+
Inline expressions (`%%=…=%%`) are designed to output a single value. Placing `IF`, `FOR`, `SET`, or `VAR` statements inside them is not supported by the AMPscript parser and causes a parse or runtime error. These constructs belong in block AMPscript (`%%[…]%%`).
|
|
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
|
+
%%=IF(@x == 1) THEN "yes" ELSE "no" ENDIF=%%
|
|
29
|
+
|
|
30
|
+
%%=SET @name = "Alice"=%%
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Allowed:**
|
|
34
|
+
|
|
35
|
+
```ampscript
|
|
36
|
+
%%[
|
|
37
|
+
if @x == 1 then
|
|
38
|
+
set @out = "yes"
|
|
39
|
+
else
|
|
40
|
+
set @out = "no"
|
|
41
|
+
endif
|
|
42
|
+
]%%
|
|
43
|
+
%%=v(@out)=%%
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## When to Disable
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
// eslint.config.js
|
|
50
|
+
rules: { 'sfmc/amp-no-inline-statement': 'off' }
|
|
51
|
+
```
|