eslint-plugin-sfmc 2.6.1 → 4.0.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 +77 -65
- package/docs/rules/amp/no-mcn-unsupported.md +76 -0
- package/docs/rules/amp/no-unknown-function.md +2 -39
- package/docs/rules/hbs/helper-arity.md +55 -0
- package/docs/rules/hbs/no-mcn-unsupported.md +69 -0
- package/docs/rules/hbs/no-unknown-binding.md +49 -0
- package/docs/rules/hbs/no-unknown-helper.md +60 -0
- package/docs/rules/hbs/no-unsupported-construct.md +65 -0
- package/docs/rules/ssjs/no-mcn-unsupported.md +68 -0
- package/docs/rules/ssjs/no-unknown-function.md +4 -31
- package/package.json +14 -12
- package/src/ampscript-parser.js +1 -1
- package/src/ampscript-processor.js +22 -16
- package/src/handlebars-parser.js +195 -0
- package/src/index.js +108 -23
- package/src/processor.js +76 -16
- package/src/rules/amp/{arg-types.js → argument-types.js} +16 -12
- package/src/rules/amp/function-arity.js +9 -9
- package/src/rules/amp/no-inline-statement.js +5 -5
- package/src/rules/amp/no-loop-counter-assign.js +7 -7
- package/src/rules/amp/no-mcn-unsupported.js +102 -0
- package/src/rules/amp/no-nested-ampscript-delimiter.js +58 -66
- package/src/rules/amp/no-smart-quotes.js +41 -47
- package/src/rules/amp/no-unknown-function.js +2 -28
- package/src/rules/amp/prefer-attribute-value.js +7 -10
- package/src/rules/amp/require-rowcount-check.js +12 -15
- package/src/rules/amp/require-variable-declaration.js +3 -3
- package/src/rules/hbs/_shared.js +116 -0
- package/src/rules/hbs/helper-arity.js +97 -0
- package/src/rules/hbs/no-mcn-unsupported.js +164 -0
- package/src/rules/hbs/no-unknown-binding.js +74 -0
- package/src/rules/hbs/no-unknown-helper.js +79 -0
- package/src/rules/hbs/no-unsupported-construct.js +70 -0
- package/src/rules/ssjs/cache-loop-length.js +14 -17
- package/src/rules/ssjs/no-deprecated-function.js +8 -8
- package/src/rules/ssjs/no-hardcoded-credentials.js +3 -6
- package/src/rules/ssjs/no-mcn-unsupported.js +182 -0
- package/src/rules/ssjs/no-property-call.js +6 -9
- package/src/rules/ssjs/no-treatascontent-injection.js +6 -13
- package/src/rules/ssjs/no-unavailable-method.js +22 -22
- package/src/rules/ssjs/no-unknown-function.js +15 -59
- package/src/rules/ssjs/no-unsupported-syntax.js +5 -5
- package/src/rules/ssjs/{prefer-parsejson-safe-arg.js → prefer-parsejson-safe-argument.js} +13 -21
- package/src/rules/ssjs/require-hasownproperty.js +54 -42
- package/src/rules/ssjs/require-platform-load-order.js +1 -1
- package/src/rules/ssjs/require-platform-load.js +6 -6
- package/src/rules/ssjs/{ssjs-arg-types.js → ssjs-argument-types.js} +59 -46
- package/src/rules/ssjs/ssjs-core-method-arity.js +41 -15
- /package/src/rules/amp/{no-var-redeclaration.js → no-variable-redeclaration.js} +0 -0
package/README.md
CHANGED
|
@@ -39,18 +39,19 @@ Add the following to your `.vscode/settings.json`:
|
|
|
39
39
|
|
|
40
40
|
```json
|
|
41
41
|
{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
42
|
+
"eslint.validate": [
|
|
43
|
+
"javascript",
|
|
44
|
+
"javascriptreact",
|
|
45
|
+
"typescript",
|
|
46
|
+
"typescriptreact",
|
|
47
|
+
"html",
|
|
48
|
+
"vue",
|
|
49
|
+
"markdown",
|
|
50
|
+
"ampscript",
|
|
51
|
+
"ssjs",
|
|
52
|
+
"sfmc",
|
|
53
|
+
"handlebars"
|
|
54
|
+
]
|
|
54
55
|
}
|
|
55
56
|
```
|
|
56
57
|
|
|
@@ -72,15 +73,15 @@ Add the following to your `.vscode/settings.json`:
|
|
|
72
73
|
|
|
73
74
|
### Marketing Cloud Next
|
|
74
75
|
|
|
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
|
+
Use the `-next` config variants when targeting **Marketing Cloud Next (MCN)**. MCN supports only a subset of AMPscript functions and does **not** support SSJS at all. Handlebars is MCN's templating language, so the `embedded-next` and `strict-next` configs also lint the `{{...}}` helpers and `{!$...}` bindings extracted from HTML (see [Handlebars Rules](#handlebars-rules-hbs-)).
|
|
76
77
|
|
|
77
|
-
| Config
|
|
78
|
-
|
|
|
79
|
-
| `sfmc.configs['ampscript-next']`
|
|
80
|
-
| `sfmc.configs['ssjs-next']`
|
|
81
|
-
| `sfmc.configs['recommended-next']` | Both of the above
|
|
82
|
-
| `sfmc.configs['embedded-next']`
|
|
83
|
-
| `sfmc.configs['strict-next']`
|
|
78
|
+
| Config | Files | What it does |
|
|
79
|
+
| ---------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------- |
|
|
80
|
+
| `sfmc.configs['ampscript-next']` | `**/*.ampscript`, `**/*.amp` | AMPscript rules + flags functions unsupported in MCN (single config object) |
|
|
81
|
+
| `sfmc.configs['ssjs-next']` | `**/*.ssjs` | Flags all SSJS API calls as MCN-unsupported; all other SSJS quality rules disabled |
|
|
82
|
+
| `sfmc.configs['recommended-next']` | Both of the above | AMPscript MCN-aware + SSJS flagged for standalone files |
|
|
83
|
+
| `sfmc.configs['embedded-next']` | `**/*.html` | AMPscript MCN-aware + SSJS flagged + Handlebars rules for HTML-embedded code |
|
|
84
|
+
| `sfmc.configs['strict-next']` | All of the above + HTML | All AMPscript rules at `error` severity + MCN flag; SSJS fully flagged; Handlebars rules on |
|
|
84
85
|
|
|
85
86
|
`recommended-next`, `embedded-next`, and `strict-next` are arrays — spread them with `...`.
|
|
86
87
|
|
|
@@ -88,58 +89,69 @@ Use the `-next` config variants when targeting **Marketing Cloud Next (MCN)**. M
|
|
|
88
89
|
// eslint.config.js — targeting Marketing Cloud Next
|
|
89
90
|
import sfmc from 'eslint-plugin-sfmc';
|
|
90
91
|
|
|
91
|
-
export default [
|
|
92
|
-
...sfmc.configs['recommended-next'],
|
|
93
|
-
...sfmc.configs['embedded-next'],
|
|
94
|
-
];
|
|
92
|
+
export default [...sfmc.configs['recommended-next'], ...sfmc.configs['embedded-next']];
|
|
95
93
|
```
|
|
96
94
|
|
|
97
95
|
## AMPscript Rules (`amp-*`)
|
|
98
96
|
|
|
99
|
-
| Rule | Default
|
|
100
|
-
| ------------------------------------------------------------------------------------------- |
|
|
101
|
-
| [`sfmc/amp-no-unknown-function`](docs/rules/amp/no-unknown-function.md) | `error`
|
|
102
|
-
| [`sfmc/amp-
|
|
103
|
-
| [`sfmc/amp-
|
|
104
|
-
| [`sfmc/amp-
|
|
105
|
-
| [`sfmc/amp-
|
|
106
|
-
| [`sfmc/amp-no-
|
|
107
|
-
| [`sfmc/amp-no-
|
|
108
|
-
| [`sfmc/amp-no-
|
|
109
|
-
| [`sfmc/amp-no-
|
|
110
|
-
| [`sfmc/amp-no-
|
|
111
|
-
| [`sfmc/amp-
|
|
112
|
-
| [`sfmc/amp-
|
|
113
|
-
| [`sfmc/amp-
|
|
114
|
-
| [`sfmc/amp-
|
|
115
|
-
| [`sfmc/amp-no-
|
|
116
|
-
| [`sfmc/amp-no-
|
|
117
|
-
| [`sfmc/amp-no-nested-
|
|
118
|
-
| [`sfmc/amp-
|
|
119
|
-
| [`sfmc/amp-
|
|
120
|
-
| [`sfmc/amp-
|
|
97
|
+
| Rule | Default | Description |
|
|
98
|
+
| ------------------------------------------------------------------------------------------- | ------------------------ | ----------------------------------------------------------------------------------- |
|
|
99
|
+
| [`sfmc/amp-no-unknown-function`](docs/rules/amp/no-unknown-function.md) | `error` | Disallow calls to unknown AMPscript functions |
|
|
100
|
+
| [`sfmc/amp-no-mcn-unsupported`](docs/rules/amp/no-mcn-unsupported.md) | off (`error` in `-next`) | Flag AMPscript functions unavailable in the targeted MCN API version (`apiVersion`) |
|
|
101
|
+
| [`sfmc/amp-function-arity`](docs/rules/amp/function-arity.md) | `error` | Enforce correct argument counts |
|
|
102
|
+
| [`sfmc/amp-arg-types`](docs/rules/amp/arg-types.md) | `error` | Check that literal arguments match expected parameter types and allowed values |
|
|
103
|
+
| [`sfmc/amp-set-requires-target`](docs/rules/amp/set-requires-target.md) | `error` | Require `set` to have a target variable |
|
|
104
|
+
| [`sfmc/amp-no-smart-quotes`](docs/rules/amp/no-smart-quotes.md) | `error` | Disallow smart/curly quotes in strings |
|
|
105
|
+
| [`sfmc/amp-no-var-redeclaration`](docs/rules/amp/no-var-redeclaration.md) | `warn` | Disallow re-declaring a variable with `var` |
|
|
106
|
+
| [`sfmc/amp-no-empty-block`](docs/rules/amp/no-empty-block.md) | `warn` | Disallow empty `%%[ ]%%` blocks |
|
|
107
|
+
| [`sfmc/amp-no-loop-counter-assign`](docs/rules/amp/no-loop-counter-assign.md) | `warn` | Disallow assigning to the `for` loop counter |
|
|
108
|
+
| [`sfmc/amp-no-inline-statement`](docs/rules/amp/no-inline-statement.md) | `warn` | Disallow statements inside inline expressions |
|
|
109
|
+
| [`sfmc/amp-no-deprecated-function`](docs/rules/amp/no-deprecated-function.md) | `warn` | Flag deprecated functions and suggest replacements |
|
|
110
|
+
| [`sfmc/amp-naming-convention`](docs/rules/amp/naming-convention.md) | `warn` | Enforce variable naming convention |
|
|
111
|
+
| [`sfmc/amp-no-empty-then`](docs/rules/amp/no-empty-then.md) | `warn` | Disallow IF with empty THEN branch |
|
|
112
|
+
| [`sfmc/amp-require-rowcount-check`](docs/rules/amp/require-rowcount-check.md) | `warn` | Require RowCount check before FOR on LookupRows |
|
|
113
|
+
| [`sfmc/amp-no-html-comment`](docs/rules/amp/no-html-comment.md) | `warn` | Disallow HTML comments inside AMPscript blocks |
|
|
114
|
+
| [`sfmc/amp-no-js-line-comment`](docs/rules/amp/no-js-line-comment.md) | `warn` | Disallow JS-style `//` line comments in AMPscript |
|
|
115
|
+
| [`sfmc/amp-no-nested-script-tag`](docs/rules/amp/no-nested-script-tag.md) | `error` | Disallow `<script>` tags nested inside AMPscript script tags |
|
|
116
|
+
| [`sfmc/amp-no-nested-ampscript-delimiter`](docs/rules/amp/no-nested-ampscript-delimiter.md) | `error` | Disallow AMPscript delimiters nested inside AMPscript blocks |
|
|
117
|
+
| [`sfmc/amp-prefer-attribute-value`](docs/rules/amp/prefer-attribute-value.md) | off | Prefer `AttributeValue()` over bare personalization |
|
|
118
|
+
| [`sfmc/amp-require-variable-declaration`](docs/rules/amp/require-variable-declaration.md) | off | Require `var` before `set` |
|
|
119
|
+
| [`sfmc/amp-no-email-excluded-function`](docs/rules/amp/no-email-excluded-function.md) | off | Flag functions unavailable in email context |
|
|
121
120
|
|
|
122
121
|
## SSJS Rules (`ssjs-*`)
|
|
123
122
|
|
|
124
|
-
| Rule
|
|
125
|
-
|
|
|
126
|
-
| [`sfmc/ssjs-require-platform-load`](docs/rules/ssjs/require-platform-load.md)
|
|
127
|
-
| [`sfmc/ssjs-no-unsupported-syntax`](docs/rules/ssjs/no-unsupported-syntax.md)
|
|
128
|
-
| [`sfmc/ssjs-no-unknown-function`](docs/rules/ssjs/no-unknown-function.md)
|
|
129
|
-
| [`sfmc/ssjs-no-
|
|
130
|
-
| [`sfmc/ssjs-no-
|
|
131
|
-
| [`sfmc/ssjs-
|
|
132
|
-
| [`sfmc/ssjs-
|
|
133
|
-
| [`sfmc/ssjs-
|
|
134
|
-
| [`sfmc/ssjs-
|
|
135
|
-
| [`sfmc/ssjs-
|
|
136
|
-
| [`sfmc/ssjs-
|
|
137
|
-
| [`sfmc/ssjs-
|
|
138
|
-
| [`sfmc/ssjs-
|
|
139
|
-
| [`sfmc/ssjs-
|
|
140
|
-
| [`sfmc/ssjs-no-
|
|
141
|
-
| [`sfmc/ssjs-
|
|
142
|
-
| [`sfmc/ssjs-
|
|
123
|
+
| Rule | Default | Description |
|
|
124
|
+
| ------------------------------------------------------------------------------------------- | ------------------------ | ------------------------------------------------------------------------ |
|
|
125
|
+
| [`sfmc/ssjs-require-platform-load`](docs/rules/ssjs/require-platform-load.md) | `error` | Require `Platform.Load("core")` before Core or requiresCoreLoad globals |
|
|
126
|
+
| [`sfmc/ssjs-no-unsupported-syntax`](docs/rules/ssjs/no-unsupported-syntax.md) | `error` | Flag ES6+ syntax not supported by SFMC |
|
|
127
|
+
| [`sfmc/ssjs-no-unknown-function`](docs/rules/ssjs/no-unknown-function.md) | `error` | Disallow unknown methods on Platform.\*, HTTP, Core Library, and WSProxy |
|
|
128
|
+
| [`sfmc/ssjs-no-mcn-unsupported`](docs/rules/ssjs/no-mcn-unsupported.md) | off (`error` in `-next`) | Flag all SSJS API usage as unsupported in Marketing Cloud Next |
|
|
129
|
+
| [`sfmc/ssjs-no-deprecated-function`](docs/rules/ssjs/no-deprecated-function.md) | `error` | Flag use of deprecated SFMC SSJS APIs (e.g. ContentArea, ContentAreaObj) |
|
|
130
|
+
| [`sfmc/ssjs-no-property-call`](docs/rules/ssjs/no-property-call.md) | `error` | Disallow calling Platform.Request/Response properties as functions |
|
|
131
|
+
| [`sfmc/ssjs-platform-function-arity`](docs/rules/ssjs/platform-function-arity.md) | `error` | Enforce correct arity for `Platform.Function.*` |
|
|
132
|
+
| [`sfmc/ssjs-require-platform-load-order`](docs/rules/ssjs/require-platform-load-order.md) | `error` | Require `Platform.Load()` before Core usage in order |
|
|
133
|
+
| [`sfmc/ssjs-no-hardcoded-credentials`](docs/rules/ssjs/no-hardcoded-credentials.md) | `error` | Flag hardcoded keys in encryption calls |
|
|
134
|
+
| [`sfmc/ssjs-cache-loop-length`](docs/rules/ssjs/cache-loop-length.md) | `warn` | Require caching `.length` in for-loops |
|
|
135
|
+
| [`sfmc/ssjs-require-hasownproperty`](docs/rules/ssjs/require-hasownproperty.md) | `warn` | Require `hasOwnProperty` guard in for-in loops |
|
|
136
|
+
| [`sfmc/ssjs-prefer-platform-load-version`](docs/rules/ssjs/prefer-platform-load-version.md) | `warn` | Enforce a minimum `Platform.Load` version string |
|
|
137
|
+
| [`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 |
|
|
138
|
+
| [`sfmc/ssjs-prefer-parsejson-safe-arg`](docs/rules/ssjs/prefer-parsejson-safe-arg.md) | `warn` | Require string coercion on `ParseJSON` argument |
|
|
139
|
+
| [`sfmc/ssjs-no-switch-default`](docs/rules/ssjs/no-switch-default.md) | `warn` | Disallow `default` clause in `switch` statements |
|
|
140
|
+
| [`sfmc/ssjs-no-treatascontent-injection`](docs/rules/ssjs/no-treatascontent-injection.md) | `warn` | Flag dynamic string concatenation in `TreatAsContent` calls |
|
|
141
|
+
| [`sfmc/ssjs-core-method-arity`](docs/rules/ssjs/core-method-arity.md) | `warn` | Enforce correct argument counts for Core Library object methods |
|
|
142
|
+
| [`sfmc/ssjs-arg-types`](docs/rules/ssjs/arg-types.md) | `warn` | Check that literal arguments match expected parameter types |
|
|
143
|
+
|
|
144
|
+
## Handlebars Rules (`hbs-*`)
|
|
145
|
+
|
|
146
|
+
Handlebars is the templating language for **Marketing Cloud Next (MCN)** only. These rules are enabled at `error` severity in the `-next` configs and are `off` in the classic (Engagement) configs — in classic SFMC, `{{...}}` is plain content and must not be flagged.
|
|
147
|
+
|
|
148
|
+
| Rule | Default (`-next`) | Description |
|
|
149
|
+
| --------------------------------------------------------------------------------- | ----------------- | ------------------------------------------------------------------------------------ |
|
|
150
|
+
| [`sfmc/hbs-no-unknown-helper`](docs/rules/hbs/no-unknown-helper.md) | `error` | Disallow helper invocations that are not part of the MCN catalog |
|
|
151
|
+
| [`sfmc/hbs-no-unknown-binding`](docs/rules/hbs/no-unknown-binding.md) | `error` | Disallow unknown `{!$...}` built-in data bindings |
|
|
152
|
+
| [`sfmc/hbs-helper-arity`](docs/rules/hbs/helper-arity.md) | `error` | Enforce correct positional-argument counts for known helpers |
|
|
153
|
+
| [`sfmc/hbs-no-unsupported-construct`](docs/rules/hbs/no-unsupported-construct.md) | `error` | Disallow constructs unsupported by the MCN engine (partials, decorators, `log`) |
|
|
154
|
+
| [`sfmc/hbs-no-mcn-unsupported`](docs/rules/hbs/no-mcn-unsupported.md) | `error` | Flag helpers and bindings unavailable in the targeted MCN API version (`apiVersion`) |
|
|
143
155
|
|
|
144
156
|
## Processors
|
|
145
157
|
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# `sfmc/amp-no-mcn-unsupported`
|
|
2
|
+
|
|
3
|
+
> Disallow AMPscript functions that are not available in the targeted Marketing Cloud Next API version.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `problem` |
|
|
8
|
+
| **Default severity** | `error` in all `-next` configs; `off` otherwise |
|
|
9
|
+
| **Fixable** | — |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
13
|
+
Only a subset of AMPscript functions are available in Marketing Cloud Next (MCN), and support has been added gradually across MCN releases. This rule flags AMPscript functions that will not work in the MCN release you target:
|
|
14
|
+
|
|
15
|
+
- Functions that **Marketing Cloud Next never supported** — they only work in classic Marketing Cloud Engagement.
|
|
16
|
+
- Functions that were **added in a later MCN release** than the one you target (see the `apiVersion` option below).
|
|
17
|
+
- Functions that work in MCN AMPscript but have **no Handlebars equivalent**, so they cannot be carried over if you later migrate the content to Handlebars.
|
|
18
|
+
|
|
19
|
+
Unknown function names are handled separately by [`sfmc/amp-no-unknown-function`](no-unknown-function.md); this rule only checks functions that actually exist in AMPscript.
|
|
20
|
+
|
|
21
|
+
## Settings
|
|
22
|
+
|
|
23
|
+
| Setting | Values | Default |
|
|
24
|
+
|---------|--------|---------|
|
|
25
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"error"` in `-next` configs |
|
|
26
|
+
|
|
27
|
+
### Options
|
|
28
|
+
|
|
29
|
+
| Option | Type | Default | Description |
|
|
30
|
+
|--------|------|---------|-------------|
|
|
31
|
+
| `apiVersion` | `number` | — | The targeted Marketing Cloud Next API version (e.g. `65` = Winter '26, `67` = Summer '26). |
|
|
32
|
+
|
|
33
|
+
**What `apiVersion` does** (shared with the SSJS and Handlebars MCN rules):
|
|
34
|
+
|
|
35
|
+
- **Leave it unset** to check against _any_ MCN release: a function is flagged only if it is never supported in Marketing Cloud Next. Anything that works in some MCN release is allowed.
|
|
36
|
+
- **Set it to your target release** (for example `65`) to also flag functions that were added in a _later_ MCN release than the one you run. A function is allowed only when it is available in your target release or an earlier one.
|
|
37
|
+
|
|
38
|
+
## Examples
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
// eslint.config.js
|
|
42
|
+
rules: {
|
|
43
|
+
'sfmc/amp-no-mcn-unsupported': ['error', { apiVersion: 65 }]
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Or use the built-in `recommended-next` / `strict-next` / `embedded-next` configs, which apply this rule automatically (without an `apiVersion`, flagging only never-supported functions).
|
|
48
|
+
|
|
49
|
+
**Not allowed (with `apiVersion: 65`):**
|
|
50
|
+
|
|
51
|
+
```ampscript
|
|
52
|
+
%%[
|
|
53
|
+
/* InsertDE is never available in Marketing Cloud Next */
|
|
54
|
+
InsertDE("MyDE", "Col", "Value")
|
|
55
|
+
/* Concat was added in a later MCN release than the one targeted (65) */
|
|
56
|
+
set @x = Concat("a", "b")
|
|
57
|
+
]%%
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Allowed (with `apiVersion: 67`):**
|
|
61
|
+
|
|
62
|
+
```ampscript
|
|
63
|
+
%%[
|
|
64
|
+
/* Concat is available in this MCN release */
|
|
65
|
+
set @x = Concat("a", "b")
|
|
66
|
+
]%%
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## When to Disable
|
|
70
|
+
|
|
71
|
+
Disable this rule when you are not targeting Marketing Cloud Next (the default `engagement` configs already leave it `off`).
|
|
72
|
+
|
|
73
|
+
```js
|
|
74
|
+
// eslint.config.js
|
|
75
|
+
rules: { 'sfmc/amp-no-mcn-unsupported': 'off' }
|
|
76
|
+
```
|
|
@@ -12,7 +12,7 @@
|
|
|
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
|
-
|
|
15
|
+
This rule only reports **unknown** function names. Functions that exist in the catalog but are unavailable when targeting Marketing Cloud Next are handled by [`sfmc/amp-no-mcn-unsupported`](no-mcn-unsupported.md).
|
|
16
16
|
|
|
17
17
|
## Settings
|
|
18
18
|
|
|
@@ -20,16 +20,10 @@ When targeting **Marketing Cloud Next**, only a subset of AMPscript functions ar
|
|
|
20
20
|
|---------|--------|---------|
|
|
21
21
|
| severity | `"error"` \| `"warn"` \| `"off"` | `"error"` |
|
|
22
22
|
|
|
23
|
-
|
|
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+). |
|
|
23
|
+
This rule takes no options.
|
|
28
24
|
|
|
29
25
|
## Examples
|
|
30
26
|
|
|
31
|
-
### Standard usage (Marketing Cloud Engagement)
|
|
32
|
-
|
|
33
27
|
**Not allowed:**
|
|
34
28
|
|
|
35
29
|
```ampscript
|
|
@@ -48,37 +42,6 @@ When targeting **Marketing Cloud Next**, only a subset of AMPscript functions ar
|
|
|
48
42
|
]%%
|
|
49
43
|
```
|
|
50
44
|
|
|
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
|
-
|
|
82
45
|
## When to Disable
|
|
83
46
|
|
|
84
47
|
Only disable this rule if you are intentionally using a proprietary or undocumented SFMC extension that is not in the public catalog.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# `sfmc/hbs-helper-arity`
|
|
2
|
+
|
|
3
|
+
> Enforce correct positional-argument counts for known Marketing Cloud Next Handlebars helpers.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `problem` |
|
|
8
|
+
| **Default severity** | `error` in the `-next` configs; `off` in classic configs |
|
|
9
|
+
| **Fixable** | — |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
13
|
+
Each Marketing Cloud Next helper has a fixed set of positional parameters defined in the catalog. Calling a helper with too few required arguments, or with more arguments than it accepts, fails at render time. This rule validates every helper invocation against the helper's `params` definition.
|
|
14
|
+
|
|
15
|
+
Only **positional** arguments are checked. Helpers with a variadic trailing parameter (for example `concat`, `and`, `set`) have no upper bound. Hash (named) arguments are not counted as positional arguments. A bare `{{foo}}` mustache with no arguments is a data binding, not an invocation, and is skipped.
|
|
16
|
+
|
|
17
|
+
Handlebars only exists when targeting MCN, so this rule is enabled only in the `-next` configs.
|
|
18
|
+
|
|
19
|
+
## Settings
|
|
20
|
+
|
|
21
|
+
| Setting | Values | Default |
|
|
22
|
+
|---------|--------|---------|
|
|
23
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"error"` (in `-next` configs) |
|
|
24
|
+
|
|
25
|
+
This rule has no configuration options.
|
|
26
|
+
|
|
27
|
+
## Examples
|
|
28
|
+
|
|
29
|
+
**Not allowed:**
|
|
30
|
+
|
|
31
|
+
```handlebars
|
|
32
|
+
{{! formatDate requires a value and a format string }}
|
|
33
|
+
{{formatDate order.createdAt}}
|
|
34
|
+
|
|
35
|
+
{{! uppercase takes exactly one argument }}
|
|
36
|
+
{{uppercase firstName lastName}}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Allowed:**
|
|
40
|
+
|
|
41
|
+
```handlebars
|
|
42
|
+
{{formatDate order.createdAt "yyyy-MM-dd"}}
|
|
43
|
+
|
|
44
|
+
{{uppercase firstName}}
|
|
45
|
+
|
|
46
|
+
{{! concat is variadic — any number of arguments is fine }}
|
|
47
|
+
{{concat firstName " " lastName}}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## When to Disable
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
// eslint.config.js
|
|
54
|
+
rules: { 'sfmc/hbs-helper-arity': 'off' }
|
|
55
|
+
```
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# `sfmc/hbs-no-mcn-unsupported`
|
|
2
|
+
|
|
3
|
+
> Disallow Handlebars helpers and bindings not available in the targeted Marketing Cloud Next API version.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `problem` |
|
|
8
|
+
| **Default severity** | `error` in all `-next` configs; `off` otherwise |
|
|
9
|
+
| **Fixable** | — |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
13
|
+
Marketing Cloud Next (MCN) adds new Handlebars helpers and `{!$...}` data bindings across its releases. This rule flags helpers and bindings that will not work in the MCN release you target:
|
|
14
|
+
|
|
15
|
+
- Helpers/bindings that **Marketing Cloud Next never supported**.
|
|
16
|
+
- Helpers/bindings that were **added in a later MCN release** than the one you target (see the `apiVersion` option below).
|
|
17
|
+
|
|
18
|
+
Unknown helpers and bindings — ones that are not part of Marketing Cloud Next at all — are handled separately by [`sfmc/hbs-no-unknown-helper`](no-unknown-helper.md) and [`sfmc/hbs-no-unknown-binding`](no-unknown-binding.md); this rule only checks the release availability of helpers and bindings that MCN does provide. Handlebars constructs that MCN never supports (partials, decorators, `{{log}}`, etc.) are handled by [`sfmc/hbs-no-unsupported-construct`](no-unsupported-construct.md).
|
|
19
|
+
|
|
20
|
+
## Settings
|
|
21
|
+
|
|
22
|
+
| Setting | Values | Default |
|
|
23
|
+
|---------|--------|---------|
|
|
24
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"error"` in `-next` configs |
|
|
25
|
+
|
|
26
|
+
### Options
|
|
27
|
+
|
|
28
|
+
| Option | Type | Default | Description |
|
|
29
|
+
|--------|------|---------|-------------|
|
|
30
|
+
| `apiVersion` | `number` | — | The targeted Marketing Cloud Next API version (e.g. `65` = Winter '26, `67` = Summer '26). |
|
|
31
|
+
|
|
32
|
+
**What `apiVersion` does** (shared with the AMPscript and SSJS MCN rules):
|
|
33
|
+
|
|
34
|
+
- **Leave it unset** to check against _any_ MCN release: a helper or binding is flagged only if it is never supported in Marketing Cloud Next. Anything that works in some MCN release is allowed.
|
|
35
|
+
- **Set it to your target release** (for example `65`) to also flag helpers and bindings that were added in a _later_ MCN release than the one you run. An item is allowed only when it is available in your target release or an earlier one.
|
|
36
|
+
|
|
37
|
+
Every Handlebars helper and binding is available in some MCN release, so with no `apiVersion` set nothing is flagged. Setting `apiVersion` to an earlier release flags the helpers and bindings added after it — for example, `apiVersion: 65` flags the helpers introduced in release 67.
|
|
38
|
+
|
|
39
|
+
## Examples
|
|
40
|
+
|
|
41
|
+
```js
|
|
42
|
+
// eslint.config.js
|
|
43
|
+
rules: {
|
|
44
|
+
'sfmc/hbs-no-mcn-unsupported': ['error', { apiVersion: 65 }]
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Not allowed (with `apiVersion: 65`):**
|
|
49
|
+
|
|
50
|
+
```handlebars
|
|
51
|
+
{{! dateAdd was added in a later MCN release than the one targeted (65) }}
|
|
52
|
+
{{dateAdd order.createdAt 7 "days"}}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Allowed (with `apiVersion: 65`):**
|
|
56
|
+
|
|
57
|
+
```handlebars
|
|
58
|
+
{{! add is available in this MCN release }}
|
|
59
|
+
{{add price tax}}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## When to Disable
|
|
63
|
+
|
|
64
|
+
Disable this rule when you are not targeting Marketing Cloud Next (the default `engagement` configs already leave it `off`).
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
// eslint.config.js
|
|
68
|
+
rules: { 'sfmc/hbs-no-mcn-unsupported': 'off' }
|
|
69
|
+
```
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# `sfmc/hbs-no-unknown-binding`
|
|
2
|
+
|
|
3
|
+
> Disallow unknown `{!$...}` built-in data bindings in Marketing Cloud Next Handlebars.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `problem` |
|
|
8
|
+
| **Default severity** | `error` in the `-next` configs; `off` in classic configs |
|
|
9
|
+
| **Fixable** | — |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
13
|
+
Marketing Cloud Next exposes a fixed set of built-in data bindings written as `{!$namespace.Field}` tokens (for example `{!$Context.MessageContext}`). These `{!$...}` tokens are **not** Handlebars helper syntax — the Handlebars parser treats them as literal content — so this rule scans the raw source text with a regex pass rather than walking the AST, mirroring the `handlebars/unknown-binding` diagnostic emitted by the language server.
|
|
14
|
+
|
|
15
|
+
An unrecognized binding name is a typo or a reference to a namespace/field that MCN does not provide, and resolves to empty output at render time. The rule offers a "did you mean" suggestion when a close match exists.
|
|
16
|
+
|
|
17
|
+
Handlebars only exists when targeting MCN, so this rule is enabled only in the `-next` configs.
|
|
18
|
+
|
|
19
|
+
## Settings
|
|
20
|
+
|
|
21
|
+
| Setting | Values | Default |
|
|
22
|
+
|---------|--------|---------|
|
|
23
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"error"` (in `-next` configs) |
|
|
24
|
+
|
|
25
|
+
This rule has no configuration options.
|
|
26
|
+
|
|
27
|
+
## Examples
|
|
28
|
+
|
|
29
|
+
**Not allowed:**
|
|
30
|
+
|
|
31
|
+
```handlebars
|
|
32
|
+
{{! 'Contect' is not a known binding namespace }}
|
|
33
|
+
{!$Contect.MessageContext}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Allowed:**
|
|
37
|
+
|
|
38
|
+
```handlebars
|
|
39
|
+
{!$Context.MessageContext}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## When to Disable
|
|
43
|
+
|
|
44
|
+
Disable only if you use a binding that is available in your MCN account but missing from the bundled catalog (please report it so the catalog can be updated).
|
|
45
|
+
|
|
46
|
+
```js
|
|
47
|
+
// eslint.config.js
|
|
48
|
+
rules: { 'sfmc/hbs-no-unknown-binding': 'off' }
|
|
49
|
+
```
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# `sfmc/hbs-no-unknown-helper`
|
|
2
|
+
|
|
3
|
+
> Disallow Handlebars helper invocations that are not part of the Marketing Cloud Next catalog.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `problem` |
|
|
8
|
+
| **Default severity** | `error` in the `-next` configs; `off` in classic configs |
|
|
9
|
+
| **Fixable** | — |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
13
|
+
Marketing Cloud Next (MCN) runs a locked-down Handlebars engine that cannot register custom helpers. Every helper name must exist in the published MCN catalog. An unknown helper name is a typo or an unsupported construct that fails at render time. This rule flags any helper invocation whose name is not in the catalog and offers a "did you mean" suggestion when a close match exists.
|
|
14
|
+
|
|
15
|
+
A bare `{{foo}}` mustache with no arguments is treated as a **data binding**, not a helper invocation, and is not flagged by this rule. Helper detection applies to inline mustaches with arguments, subexpressions, and block helpers.
|
|
16
|
+
|
|
17
|
+
Handlebars only exists when targeting MCN, so this rule is enabled only in the `-next` configs. In classic (Marketing Cloud Engagement) configs it is disabled because `{{...}}` is plain content there.
|
|
18
|
+
|
|
19
|
+
## Settings
|
|
20
|
+
|
|
21
|
+
| Setting | Values | Default |
|
|
22
|
+
|---------|--------|---------|
|
|
23
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"error"` (in `-next` configs) |
|
|
24
|
+
|
|
25
|
+
This rule has no configuration options.
|
|
26
|
+
|
|
27
|
+
## Examples
|
|
28
|
+
|
|
29
|
+
**Not allowed:**
|
|
30
|
+
|
|
31
|
+
```handlebars
|
|
32
|
+
{{! 'formatDates' is not a catalog helper — did you mean 'formatDate'? }}
|
|
33
|
+
{{formatDates order.createdAt "yyyy-MM-dd"}}
|
|
34
|
+
|
|
35
|
+
{{#eachItem items}}
|
|
36
|
+
{{this.name}}
|
|
37
|
+
{{/eachItem}}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Allowed:**
|
|
41
|
+
|
|
42
|
+
```handlebars
|
|
43
|
+
{{formatDate order.createdAt "yyyy-MM-dd"}}
|
|
44
|
+
|
|
45
|
+
{{#each items}}
|
|
46
|
+
{{this.name}}
|
|
47
|
+
{{/each}}
|
|
48
|
+
|
|
49
|
+
{{! bare binding, not a helper — never flagged }}
|
|
50
|
+
{{firstName}}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## When to Disable
|
|
54
|
+
|
|
55
|
+
Disable only if you rely on a helper that is genuinely available in your MCN account but missing from the bundled catalog (please report it so the catalog can be updated).
|
|
56
|
+
|
|
57
|
+
```js
|
|
58
|
+
// eslint.config.js
|
|
59
|
+
rules: { 'sfmc/hbs-no-unknown-helper': 'off' }
|
|
60
|
+
```
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# `sfmc/hbs-no-unsupported-construct`
|
|
2
|
+
|
|
3
|
+
> Disallow Handlebars constructs unsupported by the Marketing Cloud Next engine (partials, decorators, log).
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Type** | `problem` |
|
|
8
|
+
| **Default severity** | `error` in the `-next` configs; `off` in classic configs |
|
|
9
|
+
| **Fixable** | — |
|
|
10
|
+
|
|
11
|
+
## Why This Rule Exists
|
|
12
|
+
|
|
13
|
+
The Marketing Cloud Next Handlebars engine is a locked-down subset of handlebars.js. Several standard handlebars.js constructs are not available and fail at render time:
|
|
14
|
+
|
|
15
|
+
- Partials — `{{> partialName}}`
|
|
16
|
+
- Partial blocks — `{{#> partialName}}...{{/partialName}}`
|
|
17
|
+
- Inline partials — `{{#*inline "name"}}...{{/inline}}`
|
|
18
|
+
- Decorators — `{{* decorator}}` and `{{#* decorator}}...{{/*decorator}}`
|
|
19
|
+
- The debugging helper `{{log}}`
|
|
20
|
+
|
|
21
|
+
This rule flags each of these, mirroring the `handlebars/unsupported-construct` diagnostic emitted by the language server. The full explanation for the specific construct is included in the reported message.
|
|
22
|
+
|
|
23
|
+
Handlebars only exists when targeting MCN, so this rule is enabled only in the `-next` configs.
|
|
24
|
+
|
|
25
|
+
## Settings
|
|
26
|
+
|
|
27
|
+
| Setting | Values | Default |
|
|
28
|
+
|---------|--------|---------|
|
|
29
|
+
| severity | `"error"` \| `"warn"` \| `"off"` | `"error"` (in `-next` configs) |
|
|
30
|
+
|
|
31
|
+
This rule has no configuration options.
|
|
32
|
+
|
|
33
|
+
## Examples
|
|
34
|
+
|
|
35
|
+
**Not allowed:**
|
|
36
|
+
|
|
37
|
+
```handlebars
|
|
38
|
+
{{> header}}
|
|
39
|
+
|
|
40
|
+
{{#> layout}}
|
|
41
|
+
body
|
|
42
|
+
{{/layout}}
|
|
43
|
+
|
|
44
|
+
{{log "debugging"}}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Allowed:**
|
|
48
|
+
|
|
49
|
+
```handlebars
|
|
50
|
+
{{! inline the shared markup instead of using a partial }}
|
|
51
|
+
<h1>{{title}}</h1>
|
|
52
|
+
|
|
53
|
+
{{#each items}}
|
|
54
|
+
{{this.name}}
|
|
55
|
+
{{/each}}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## When to Disable
|
|
59
|
+
|
|
60
|
+
These constructs do not run in MCN, so disabling the rule only hides a guaranteed render-time failure. Leave it enabled.
|
|
61
|
+
|
|
62
|
+
```js
|
|
63
|
+
// eslint.config.js
|
|
64
|
+
rules: { 'sfmc/hbs-no-unsupported-construct': 'off' }
|
|
65
|
+
```
|