eslint-plugin-sfmc 1.0.2 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -0
- package/docs/rules/amp/no-unknown-function.md +42 -3
- package/docs/rules/ssjs/no-deprecated-function.md +1 -1
- package/docs/rules/ssjs/no-property-call.md +1 -1
- package/docs/rules/ssjs/no-switch-default.md +1 -1
- package/docs/rules/ssjs/no-treatascontent-injection.md +1 -1
- package/docs/rules/ssjs/no-unknown-function.md +40 -7
- package/docs/rules/ssjs/prefer-parsejson-safe-arg.md +1 -1
- package/package.json +5 -3
- package/src/index.js +175 -0
- package/src/rules/amp/no-unknown-function.js +31 -3
- package/src/rules/ssjs/no-unknown-function.js +49 -1
package/README.md
CHANGED
|
@@ -25,8 +25,41 @@ export default [
|
|
|
25
25
|
];
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
## VS Code Setup
|
|
29
|
+
|
|
30
|
+
To see `eslint(sfmc/...)` diagnostics in VS Code for `.amp`, `.ssjs`, and `.html` files you need the [VS Code ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) to validate the custom SFMC language IDs.
|
|
31
|
+
|
|
32
|
+
**Option A — Install `vscode-sfmc-language`** (recommended)
|
|
33
|
+
|
|
34
|
+
The [SFMC Language Service extension](https://marketplace.visualstudio.com/items?itemName=joernberkefeld.sfmc-language) contributes the SFMC language IDs **and** automatically configures `eslint.validate` for you. No manual settings required.
|
|
35
|
+
|
|
36
|
+
**Option B — Manual configuration**
|
|
37
|
+
|
|
38
|
+
Add the following to your `.vscode/settings.json`:
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"eslint.validate": [
|
|
43
|
+
"javascript",
|
|
44
|
+
"javascriptreact",
|
|
45
|
+
"typescript",
|
|
46
|
+
"typescriptreact",
|
|
47
|
+
"html",
|
|
48
|
+
"vue",
|
|
49
|
+
"markdown",
|
|
50
|
+
"ampscript",
|
|
51
|
+
"ssjs",
|
|
52
|
+
"sfmc"
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
> **Why `eslint.validate` and not `eslint.probe`?** `eslint.probe` silently skips files for language IDs that the ESLint extension does not natively recognise. `eslint.validate` forces the extension to process those files regardless of language ID.
|
|
58
|
+
|
|
28
59
|
## Configs
|
|
29
60
|
|
|
61
|
+
### Marketing Cloud Engagement (default)
|
|
62
|
+
|
|
30
63
|
| Config | Files | What it does |
|
|
31
64
|
| -------------------------- | ---------------------------- | --------------------------------------------------------- |
|
|
32
65
|
| `sfmc.configs.ampscript` | `**/*.ampscript`, `**/*.amp` | AMPscript rules only (recommended severity) |
|
|
@@ -37,6 +70,30 @@ export default [
|
|
|
37
70
|
|
|
38
71
|
`recommended`, `embedded`, and `strict` are arrays — spread them with `...`.
|
|
39
72
|
|
|
73
|
+
### Marketing Cloud Next
|
|
74
|
+
|
|
75
|
+
Use the `-next` config variants when targeting **Marketing Cloud Next (MCN)**. MCN supports only a subset of AMPscript functions and does **not** support SSJS at all.
|
|
76
|
+
|
|
77
|
+
| Config | Files | What it does |
|
|
78
|
+
| -------------------------------- | ---------------------------- | ----------------------------------------------------------------------------------------- |
|
|
79
|
+
| `sfmc.configs['ampscript-next']` | `**/*.ampscript`, `**/*.amp` | AMPscript rules + flags functions unsupported in MCN (single config object) |
|
|
80
|
+
| `sfmc.configs['ssjs-next']` | `**/*.ssjs` | Flags all SSJS API calls as MCN-unsupported; all other SSJS quality rules disabled |
|
|
81
|
+
| `sfmc.configs['recommended-next']` | Both of the above | AMPscript MCN-aware + SSJS flagged for standalone files |
|
|
82
|
+
| `sfmc.configs['embedded-next']` | `**/*.html` | AMPscript MCN-aware + SSJS flagged for HTML-embedded code |
|
|
83
|
+
| `sfmc.configs['strict-next']` | All of the above + HTML | All AMPscript rules at `error` severity + MCN flag; SSJS fully flagged |
|
|
84
|
+
|
|
85
|
+
`recommended-next`, `embedded-next`, and `strict-next` are arrays — spread them with `...`.
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
// eslint.config.js — targeting Marketing Cloud Next
|
|
89
|
+
import sfmc from 'eslint-plugin-sfmc';
|
|
90
|
+
|
|
91
|
+
export default [
|
|
92
|
+
...sfmc.configs['recommended-next'],
|
|
93
|
+
...sfmc.configs['embedded-next'],
|
|
94
|
+
];
|
|
95
|
+
```
|
|
96
|
+
|
|
40
97
|
## AMPscript Rules (`amp-*`)
|
|
41
98
|
|
|
42
99
|
| Rule | Default | Description |
|
|
@@ -5,22 +5,30 @@
|
|
|
5
5
|
| | |
|
|
6
6
|
|---|---|
|
|
7
7
|
| **Type** | `problem` |
|
|
8
|
-
| **Default severity** | `error` in `recommended` and `
|
|
8
|
+
| **Default severity** | `error` in `recommended`, `strict`, and all `-next` configs |
|
|
9
9
|
| **Fixable** | — |
|
|
10
10
|
|
|
11
11
|
## Why This Rule Exists
|
|
12
12
|
|
|
13
13
|
AMPscript does not support user-defined functions. Every function call must match a name in Salesforce's published catalog. Calling an unknown name causes a runtime error (or is silently ignored depending on the execution context), making the code unreliable. This rule catches typos and invented names before deployment.
|
|
14
14
|
|
|
15
|
+
When targeting **Marketing Cloud Next**, only a subset of AMPscript functions are supported. Use the `target: 'next'` option to flag functions that cannot run in MCN.
|
|
16
|
+
|
|
15
17
|
## Settings
|
|
16
18
|
|
|
17
19
|
| Setting | Values | Default |
|
|
18
20
|
|---------|--------|---------|
|
|
19
21
|
| severity | `"error"` \| `"warn"` \| `"off"` | `"error"` |
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
### Options
|
|
24
|
+
|
|
25
|
+
| Option | Type | Default | Description |
|
|
26
|
+
|--------|------|---------|-------------|
|
|
27
|
+
| `target` | `'engagement'` \| `'next'` | — | Target platform. Set to `'next'` to additionally flag AMPscript functions not available in Marketing Cloud Next (API v67.0+). |
|
|
28
|
+
|
|
29
|
+
## Examples
|
|
22
30
|
|
|
23
|
-
###
|
|
31
|
+
### Standard usage (Marketing Cloud Engagement)
|
|
24
32
|
|
|
25
33
|
**Not allowed:**
|
|
26
34
|
|
|
@@ -40,6 +48,37 @@ This rule has no configuration options.
|
|
|
40
48
|
]%%
|
|
41
49
|
```
|
|
42
50
|
|
|
51
|
+
### MCN target
|
|
52
|
+
|
|
53
|
+
Configure the rule with `target: 'next'` to flag functions unsupported in Marketing Cloud Next:
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
// eslint.config.js
|
|
57
|
+
rules: {
|
|
58
|
+
'sfmc/amp-no-unknown-function': ['error', { target: 'next' }]
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Or use the built-in `recommended-next` / `strict-next` / `embedded-next` configs which apply this automatically.
|
|
63
|
+
|
|
64
|
+
**Not allowed (with `target: 'next'`):**
|
|
65
|
+
|
|
66
|
+
```ampscript
|
|
67
|
+
%%[
|
|
68
|
+
/* InsertDE is not supported in Marketing Cloud Next */
|
|
69
|
+
InsertDE("MyDE", "Col", "Value")
|
|
70
|
+
]%%
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Allowed (with `target: 'next'`):**
|
|
74
|
+
|
|
75
|
+
```ampscript
|
|
76
|
+
%%[
|
|
77
|
+
/* UpsertDE is supported in Marketing Cloud Next */
|
|
78
|
+
UpsertDE("MyDE", 1, "Key", @key, "Col", "Value")
|
|
79
|
+
]%%
|
|
80
|
+
```
|
|
81
|
+
|
|
43
82
|
## When to Disable
|
|
44
83
|
|
|
45
84
|
Only disable this rule if you are intentionally using a proprietary or undocumented SFMC extension that is not in the public catalog.
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
# ssjs-no-unknown-function
|
|
1
|
+
# `sfmc/ssjs-no-unknown-function`
|
|
2
2
|
|
|
3
3
|
Flags calls to SFMC API methods that do not exist in the catalog. This single rule replaces the seven narrow `no-unknown-*` rules from earlier versions of the plugin.
|
|
4
4
|
|
|
5
|
+
When targeting **Marketing Cloud Next**, SSJS is not supported at all. Set `target: 'next'` to flag every SSJS API call as an error, signalling that the SSJS block must be removed or rewritten in AMPscript.
|
|
6
|
+
|
|
5
7
|
## Covered namespaces
|
|
6
8
|
|
|
7
9
|
| Namespace | Example |
|
|
@@ -15,9 +17,17 @@ Flags calls to SFMC API methods that do not exist in the catalog. This single ru
|
|
|
15
17
|
| Core Library instance methods | `de.Rows.Retrieve()` (tracked from `DataExtension.Init(…)`) |
|
|
16
18
|
| WSProxy instance methods | `api.retrieve(…)` (tracked from `new Script.Util.WSProxy()`) |
|
|
17
19
|
|
|
20
|
+
## Options
|
|
21
|
+
|
|
22
|
+
| Option | Type | Default | Description |
|
|
23
|
+
|--------|------|---------|-------------|
|
|
24
|
+
| `target` | `'engagement'` \| `'next'` | — | Target platform. Set to `'next'` to flag every SSJS API call (all of `Platform.*`, `HTTP.*`, Core Library, and WSProxy) as unsupported in Marketing Cloud Next. |
|
|
25
|
+
|
|
18
26
|
## Examples
|
|
19
27
|
|
|
20
|
-
###
|
|
28
|
+
### Standard usage (Marketing Cloud Engagement)
|
|
29
|
+
|
|
30
|
+
#### ❌ Incorrect
|
|
21
31
|
|
|
22
32
|
```js
|
|
23
33
|
// Typo in Platform.Function method name
|
|
@@ -32,7 +42,7 @@ var de = DataExtension.Init('CustomerData');
|
|
|
32
42
|
de.ExportRows();
|
|
33
43
|
```
|
|
34
44
|
|
|
35
|
-
|
|
45
|
+
#### ✅ Correct
|
|
36
46
|
|
|
37
47
|
```js
|
|
38
48
|
Platform.Function.LookupRows('MyDE', 'Status', 'Active');
|
|
@@ -44,14 +54,37 @@ var de = DataExtension.Init('CustomerData');
|
|
|
44
54
|
de.Rows.Retrieve();
|
|
45
55
|
```
|
|
46
56
|
|
|
57
|
+
### MCN target (`target: 'next'`)
|
|
58
|
+
|
|
59
|
+
SSJS is not supported in Marketing Cloud Next. Configuring `target: 'next'` flags every SFMC API call within SSJS files, indicating they must be rewritten or removed.
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
// eslint.config.js
|
|
63
|
+
rules: {
|
|
64
|
+
'sfmc/ssjs-no-unknown-function': ['error', { target: 'next' }]
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Or use the built-in `recommended-next` / `strict-next` / `embedded-next` configs which apply this automatically (and disable all other SSJS quality rules, since the entire SSJS block must be migrated).
|
|
69
|
+
|
|
70
|
+
#### ❌ Flagged (with `target: 'next'`)
|
|
71
|
+
|
|
72
|
+
```js
|
|
73
|
+
// All SFMC API calls are flagged — SSJS is not available in MCN
|
|
74
|
+
Platform.Function.LookupRows('MyDE', 'Status', 'Active');
|
|
75
|
+
|
|
76
|
+
var de = DataExtension.Init('CustomerData');
|
|
77
|
+
de.Rows.Retrieve();
|
|
78
|
+
```
|
|
79
|
+
|
|
47
80
|
## When to use
|
|
48
81
|
|
|
49
|
-
Enable this rule to catch typos, outdated method names, and unsupported API calls before
|
|
50
|
-
they cause runtime failures.
|
|
82
|
+
Enable this rule to catch typos, outdated method names, and unsupported API calls before they cause runtime failures. Use `target: 'next'` when migrating content to Marketing Cloud Next.
|
|
51
83
|
|
|
52
84
|
## Rule details
|
|
53
85
|
|
|
54
86
|
- **Type:** `problem`
|
|
55
87
|
- **Fixable:** No
|
|
56
|
-
- **Recommended:** Yes
|
|
57
|
-
- **Strict:** Yes
|
|
88
|
+
- **Recommended:** Yes (`engagement` mode)
|
|
89
|
+
- **Strict:** Yes (`engagement` mode)
|
|
90
|
+
- **`recommended-next` / `strict-next` / `embedded-next`:** Yes (`next` mode — all other SSJS rules disabled)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-sfmc",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "ESLint plugin for Salesforce Marketing Cloud  AMPscript and Server-Side JavaScript (SSJS)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"sfmc"
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"ampscript-data": "^0.
|
|
35
|
+
"ampscript-data": "^1.0.0",
|
|
36
36
|
"ampscript-parser": "^0.1.3",
|
|
37
37
|
"ssjs-data": "^0.4.0"
|
|
38
38
|
},
|
|
@@ -40,7 +40,9 @@
|
|
|
40
40
|
"eslint": ">=9.0.0"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
|
-
"test": "node --test tests/rules.test.js",
|
|
43
|
+
"test": "node --test tests/rules.test.js && node --test tests/fixtures.test.mjs",
|
|
44
|
+
"test:fixtures": "node --test tests/fixtures.test.mjs",
|
|
45
|
+
"test:fixtures:update": "node --test tests/fixtures.test.mjs -- --update-snapshots",
|
|
44
46
|
"lint": "eslint .",
|
|
45
47
|
"lint:fix": "eslint --fix .",
|
|
46
48
|
"prepare": "husky || true",
|
package/src/index.js
CHANGED
|
@@ -121,6 +121,34 @@ const plugin = {
|
|
|
121
121
|
configs: {},
|
|
122
122
|
};
|
|
123
123
|
|
|
124
|
+
// ── MCN SSJS rule set (all SSJS rules off except ssjs-no-unknown-function) ────
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* SSJS rules for MCN targets.
|
|
128
|
+
* All quality rules are disabled — only the presence of SSJS is flagged,
|
|
129
|
+
* because SSJS as a whole must be deleted when targeting Marketing Cloud Next.
|
|
130
|
+
*/
|
|
131
|
+
const ssjsMcnRules = {
|
|
132
|
+
'sfmc/ssjs-no-unknown-function': ['error', { target: 'next' }],
|
|
133
|
+
'sfmc/ssjs-require-platform-load': 'off',
|
|
134
|
+
'sfmc/ssjs-no-unsupported-syntax': 'off',
|
|
135
|
+
'sfmc/ssjs-no-deprecated-function': 'off',
|
|
136
|
+
'sfmc/ssjs-no-property-call': 'off',
|
|
137
|
+
'sfmc/ssjs-platform-function-arity': 'off',
|
|
138
|
+
'sfmc/ssjs-cache-loop-length': 'off',
|
|
139
|
+
'sfmc/ssjs-require-hasownproperty': 'off',
|
|
140
|
+
'sfmc/ssjs-require-platform-load-order': 'off',
|
|
141
|
+
'sfmc/ssjs-no-hardcoded-credentials': 'off',
|
|
142
|
+
'sfmc/ssjs-prefer-platform-load-version': 'off',
|
|
143
|
+
'sfmc/ssjs-no-unavailable-method': 'off',
|
|
144
|
+
'sfmc/ssjs-prefer-parsejson-safe-arg': 'off',
|
|
145
|
+
'sfmc/ssjs-no-switch-default': 'off',
|
|
146
|
+
'sfmc/ssjs-no-treatascontent-injection': 'off',
|
|
147
|
+
'sfmc/ssjs-arg-types': 'off',
|
|
148
|
+
'sfmc/ssjs-core-method-arity': 'off',
|
|
149
|
+
'no-cond-assign': 'off',
|
|
150
|
+
};
|
|
151
|
+
|
|
124
152
|
// ── AMPscript rule sets ───────────────────────────────────────────────────────
|
|
125
153
|
|
|
126
154
|
const ampRecommendedRules = {
|
|
@@ -340,6 +368,153 @@ Object.assign(plugin.configs, {
|
|
|
340
368
|
rules: { ...ssjsStrictRules },
|
|
341
369
|
},
|
|
342
370
|
],
|
|
371
|
+
|
|
372
|
+
// ── Marketing Cloud Next configs ──────────────────────────────────────────
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* AMPscript-only MCN config. Flags functions not supported in MCN.
|
|
376
|
+
* No SSJS portion (AMPscript-only config).
|
|
377
|
+
*/
|
|
378
|
+
'ampscript-next': {
|
|
379
|
+
name: 'sfmc/ampscript-next',
|
|
380
|
+
plugins: { sfmc: plugin },
|
|
381
|
+
languageOptions: { parser: ampscriptParser },
|
|
382
|
+
files: ['**/*.ampscript', '**/*.amp'],
|
|
383
|
+
rules: {
|
|
384
|
+
...ampRecommendedRules,
|
|
385
|
+
'sfmc/amp-no-unknown-function': ['error', { target: 'next' }],
|
|
386
|
+
},
|
|
387
|
+
},
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* SSJS-only MCN config. Flags all SSJS API calls; disables all other SSJS rules.
|
|
391
|
+
*/
|
|
392
|
+
'ssjs-next': {
|
|
393
|
+
name: 'sfmc/ssjs-next',
|
|
394
|
+
plugins: { sfmc: plugin },
|
|
395
|
+
files: ['**/*.ssjs'],
|
|
396
|
+
languageOptions: {
|
|
397
|
+
ecmaVersion: 5,
|
|
398
|
+
sourceType: 'script',
|
|
399
|
+
globals: SSJS_GLOBALS_MAP,
|
|
400
|
+
},
|
|
401
|
+
rules: { ...ssjsMcnRules },
|
|
402
|
+
},
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Recommended MCN config: both AMPscript and SSJS for standalone files.
|
|
406
|
+
* AMPscript portion flags MCN-unsupported functions; SSJS portion flags all SSJS as unsupported.
|
|
407
|
+
*/
|
|
408
|
+
'recommended-next': [
|
|
409
|
+
{
|
|
410
|
+
name: 'sfmc/recommended-next-ampscript',
|
|
411
|
+
plugins: { sfmc: plugin },
|
|
412
|
+
languageOptions: { parser: ampscriptParser },
|
|
413
|
+
files: ['**/*.ampscript', '**/*.amp'],
|
|
414
|
+
rules: {
|
|
415
|
+
...ampRecommendedRules,
|
|
416
|
+
'sfmc/amp-no-unknown-function': ['error', { target: 'next' }],
|
|
417
|
+
},
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
name: 'sfmc/recommended-next-ssjs',
|
|
421
|
+
plugins: { sfmc: plugin },
|
|
422
|
+
files: ['**/*.ssjs'],
|
|
423
|
+
languageOptions: {
|
|
424
|
+
ecmaVersion: 5,
|
|
425
|
+
sourceType: 'script',
|
|
426
|
+
globals: SSJS_GLOBALS_MAP,
|
|
427
|
+
},
|
|
428
|
+
rules: { ...ssjsMcnRules },
|
|
429
|
+
},
|
|
430
|
+
],
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* MCN config for AMPscript and SSJS embedded in HTML files.
|
|
434
|
+
*/
|
|
435
|
+
'embedded-next': [
|
|
436
|
+
{
|
|
437
|
+
name: 'sfmc/embedded-next-processor',
|
|
438
|
+
plugins: { sfmc: plugin },
|
|
439
|
+
files: ['**/*.html'],
|
|
440
|
+
processor: 'sfmc/sfmc',
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
name: 'sfmc/embedded-next-ampscript-rules',
|
|
444
|
+
plugins: { sfmc: plugin },
|
|
445
|
+
languageOptions: { parser: ampscriptParser },
|
|
446
|
+
files: ['**/*.html/*.amp'],
|
|
447
|
+
rules: {
|
|
448
|
+
...ampRecommendedRules,
|
|
449
|
+
'sfmc/amp-no-unknown-function': ['error', { target: 'next' }],
|
|
450
|
+
},
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
name: 'sfmc/embedded-next-ssjs-rules',
|
|
454
|
+
plugins: { sfmc: plugin },
|
|
455
|
+
files: ['**/*.html/*.js'],
|
|
456
|
+
languageOptions: {
|
|
457
|
+
ecmaVersion: 5,
|
|
458
|
+
sourceType: 'script',
|
|
459
|
+
globals: SSJS_GLOBALS_MAP,
|
|
460
|
+
},
|
|
461
|
+
rules: { ...ssjsMcnRules },
|
|
462
|
+
},
|
|
463
|
+
],
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Strict MCN config: all rules at error severity for standalone + embedded.
|
|
467
|
+
*/
|
|
468
|
+
'strict-next': [
|
|
469
|
+
{
|
|
470
|
+
name: 'sfmc/strict-next-ampscript',
|
|
471
|
+
plugins: { sfmc: plugin },
|
|
472
|
+
languageOptions: { parser: ampscriptParser },
|
|
473
|
+
files: ['**/*.ampscript', '**/*.amp'],
|
|
474
|
+
rules: {
|
|
475
|
+
...ampStrictRules,
|
|
476
|
+
'sfmc/amp-no-unknown-function': ['error', { target: 'next' }],
|
|
477
|
+
},
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
name: 'sfmc/strict-next-ssjs',
|
|
481
|
+
plugins: { sfmc: plugin },
|
|
482
|
+
files: ['**/*.ssjs'],
|
|
483
|
+
languageOptions: {
|
|
484
|
+
ecmaVersion: 5,
|
|
485
|
+
sourceType: 'script',
|
|
486
|
+
globals: SSJS_GLOBALS_MAP,
|
|
487
|
+
},
|
|
488
|
+
rules: { ...ssjsMcnRules },
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
name: 'sfmc/strict-next-embedded-processor',
|
|
492
|
+
plugins: { sfmc: plugin },
|
|
493
|
+
files: ['**/*.html'],
|
|
494
|
+
processor: 'sfmc/sfmc',
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
name: 'sfmc/strict-next-embedded-ampscript-rules',
|
|
498
|
+
plugins: { sfmc: plugin },
|
|
499
|
+
languageOptions: { parser: ampscriptParser },
|
|
500
|
+
files: ['**/*.html/*.amp'],
|
|
501
|
+
rules: {
|
|
502
|
+
...ampStrictRules,
|
|
503
|
+
'sfmc/amp-no-unknown-function': ['error', { target: 'next' }],
|
|
504
|
+
},
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
name: 'sfmc/strict-next-embedded-ssjs-rules',
|
|
508
|
+
plugins: { sfmc: plugin },
|
|
509
|
+
files: ['**/*.html/*.js'],
|
|
510
|
+
languageOptions: {
|
|
511
|
+
ecmaVersion: 5,
|
|
512
|
+
sourceType: 'script',
|
|
513
|
+
globals: SSJS_GLOBALS_MAP,
|
|
514
|
+
},
|
|
515
|
+
rules: { ...ssjsMcnRules },
|
|
516
|
+
},
|
|
517
|
+
],
|
|
343
518
|
});
|
|
344
519
|
|
|
345
520
|
export default plugin;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { functionNames } from 'ampscript-data';
|
|
1
|
+
import { functionNames, isMcnSupported } from 'ampscript-data';
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
4
|
meta: {
|
|
@@ -11,19 +11,47 @@ export default {
|
|
|
11
11
|
messages: {
|
|
12
12
|
unknownFunction:
|
|
13
13
|
"'{{name}}' is not a recognized AMPscript function. AMPscript does not support custom functions.",
|
|
14
|
+
notSupportedInMcn: "'{{name}}' is not supported in Marketing Cloud Next.",
|
|
14
15
|
},
|
|
15
|
-
schema: [
|
|
16
|
+
schema: [
|
|
17
|
+
{
|
|
18
|
+
type: 'object',
|
|
19
|
+
properties: {
|
|
20
|
+
target: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
enum: ['engagement', 'next'],
|
|
23
|
+
description:
|
|
24
|
+
"Target platform. Set to 'next' to additionally flag functions not available in Marketing Cloud Next.",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
additionalProperties: false,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
16
30
|
},
|
|
17
31
|
|
|
18
32
|
create(context) {
|
|
33
|
+
const options = context.options[0] ?? {};
|
|
34
|
+
const targetNext = options.target === 'next';
|
|
35
|
+
|
|
19
36
|
return {
|
|
20
37
|
FunctionCall(node) {
|
|
21
|
-
|
|
38
|
+
const lower = node.name.toLowerCase();
|
|
39
|
+
|
|
40
|
+
if (!functionNames.has(lower)) {
|
|
22
41
|
context.report({
|
|
23
42
|
node,
|
|
24
43
|
messageId: 'unknownFunction',
|
|
25
44
|
data: { name: node.name },
|
|
26
45
|
});
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (targetNext && !isMcnSupported(lower)) {
|
|
50
|
+
context.report({
|
|
51
|
+
node,
|
|
52
|
+
messageId: 'notSupportedInMcn',
|
|
53
|
+
data: { name: node.name },
|
|
54
|
+
});
|
|
27
55
|
}
|
|
28
56
|
},
|
|
29
57
|
};
|
|
@@ -49,11 +49,29 @@ export default {
|
|
|
49
49
|
unknownCoreMethod:
|
|
50
50
|
"'{{method}}' is not a known method of {{objectType}}. Available methods: {{available}}.",
|
|
51
51
|
unknownWsproxyMethod: "'{{name}}' is not a recognized WSProxy method.",
|
|
52
|
+
ssjsNotSupportedInMcn:
|
|
53
|
+
'SSJS is not supported in Marketing Cloud Next. Use AMPscript instead.',
|
|
52
54
|
},
|
|
53
|
-
schema: [
|
|
55
|
+
schema: [
|
|
56
|
+
{
|
|
57
|
+
type: 'object',
|
|
58
|
+
properties: {
|
|
59
|
+
target: {
|
|
60
|
+
type: 'string',
|
|
61
|
+
enum: ['engagement', 'next'],
|
|
62
|
+
description:
|
|
63
|
+
"Target platform. Set to 'next' to flag all SSJS API calls as unsupported in Marketing Cloud Next.",
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
additionalProperties: false,
|
|
67
|
+
},
|
|
68
|
+
],
|
|
54
69
|
},
|
|
55
70
|
|
|
56
71
|
create(context) {
|
|
72
|
+
const options = context.options[0] ?? {};
|
|
73
|
+
const targetNext = options.target === 'next';
|
|
74
|
+
|
|
57
75
|
// Track variable name → Core Library type name (assigned via TypeName.Init())
|
|
58
76
|
const coreVariables = new Map();
|
|
59
77
|
// Track variable names assigned via new Script.Util.WSProxy()
|
|
@@ -100,6 +118,36 @@ export default {
|
|
|
100
118
|
|
|
101
119
|
const methodName = property.name;
|
|
102
120
|
|
|
121
|
+
// ── MCN target: flag all SSJS API calls as unsupported ────────
|
|
122
|
+
if (targetNext) {
|
|
123
|
+
// Only report on Platform.<NS>.<method>(), HTTP.<method>(),
|
|
124
|
+
// Core Library instance calls, or WSProxy calls — not bare JS.
|
|
125
|
+
const isPlatformCall =
|
|
126
|
+
callee.object.type === 'MemberExpression' &&
|
|
127
|
+
callee.object.object.type === 'Identifier' &&
|
|
128
|
+
callee.object.object.name === 'Platform';
|
|
129
|
+
const isHttpCall =
|
|
130
|
+
callee.object.type === 'Identifier' && callee.object.name === 'HTTP';
|
|
131
|
+
|
|
132
|
+
// Traverse the object chain to find the root identifier
|
|
133
|
+
// (handles de.Rows.Retrieve() where root is `de`)
|
|
134
|
+
let rootNode = callee.object;
|
|
135
|
+
while (rootNode.type === 'MemberExpression') {
|
|
136
|
+
rootNode = rootNode.object;
|
|
137
|
+
}
|
|
138
|
+
const isInstanceCall =
|
|
139
|
+
rootNode.type === 'Identifier' &&
|
|
140
|
+
(coreVariables.has(rootNode.name) || wsproxyVariables.has(rootNode.name));
|
|
141
|
+
|
|
142
|
+
if (isPlatformCall || isHttpCall || isInstanceCall) {
|
|
143
|
+
context.report({
|
|
144
|
+
node: property,
|
|
145
|
+
messageId: 'ssjsNotSupportedInMcn',
|
|
146
|
+
});
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
103
151
|
// ── Platform.<NS>.<method>() ──────────────────────────────────
|
|
104
152
|
if (
|
|
105
153
|
callee.object.type === 'MemberExpression' &&
|