eslint-plugin-sfmc 1.0.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -0
- package/docs/rules/amp/function-arity.md +8 -0
- package/docs/rules/amp/no-unknown-function.md +42 -3
- package/docs/rules/amp/require-variable-declaration.md +11 -1
- package/docs/rules/ssjs/cache-loop-length.md +6 -5
- package/docs/rules/ssjs/no-deprecated-function.md +1 -1
- package/docs/rules/ssjs/no-property-call.md +8 -2
- package/docs/rules/ssjs/no-switch-default.md +1 -1
- package/docs/rules/ssjs/no-treatascontent-injection.md +1 -1
- package/docs/rules/ssjs/no-unknown-function.md +40 -7
- package/docs/rules/ssjs/no-unsupported-syntax.md +7 -10
- package/docs/rules/ssjs/prefer-parsejson-safe-arg.md +1 -1
- package/docs/rules/ssjs/require-hasownproperty.md +6 -5
- package/package.json +6 -3
- package/src/index.js +175 -0
- package/src/rules/amp/function-arity.js +102 -1
- package/src/rules/amp/no-deprecated-function.js +12 -30
- package/src/rules/amp/no-unknown-function.js +31 -3
- package/src/rules/amp/require-variable-declaration.js +12 -1
- package/src/rules/ssjs/cache-loop-length.js +17 -23
- package/src/rules/ssjs/no-property-call.js +18 -10
- package/src/rules/ssjs/no-unknown-function.js +49 -1
- package/src/rules/ssjs/no-unsupported-syntax.js +26 -43
- package/src/rules/ssjs/require-hasownproperty.js +51 -30
|
@@ -4,22 +4,20 @@
|
|
|
4
4
|
* In for-in loops, require a hasOwnProperty guard to avoid iterating
|
|
5
5
|
* over inherited properties (like _type) that SSJS objects may have.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* Auto-fix: wraps the existing loop body in an
|
|
8
8
|
* `if (obj.hasOwnProperty(key)) { ... }` guard.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
export default {
|
|
12
12
|
meta: {
|
|
13
13
|
type: 'suggestion',
|
|
14
|
-
|
|
14
|
+
fixable: 'code',
|
|
15
15
|
docs: {
|
|
16
16
|
description: 'Require hasOwnProperty guard in for-in loops',
|
|
17
17
|
},
|
|
18
18
|
messages: {
|
|
19
19
|
missingGuard:
|
|
20
20
|
'Add a hasOwnProperty check inside for-in loops to avoid iterating over inherited properties.',
|
|
21
|
-
suggestAddGuard:
|
|
22
|
-
'Wrap the loop body in an `if ({{obj}}.hasOwnProperty({{key}})) { ... }` guard',
|
|
23
21
|
},
|
|
24
22
|
schema: [],
|
|
25
23
|
},
|
|
@@ -41,35 +39,58 @@ export default {
|
|
|
41
39
|
const keyName = getKeyName(node.left);
|
|
42
40
|
const objText = context.sourceCode.getText(node.right);
|
|
43
41
|
|
|
42
|
+
if (!keyName) {
|
|
43
|
+
context.report({
|
|
44
|
+
node,
|
|
45
|
+
messageId: 'missingGuard',
|
|
46
|
+
});
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
44
50
|
context.report({
|
|
45
51
|
node,
|
|
46
52
|
messageId: 'missingGuard',
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
53
|
+
fix(fixer) {
|
|
54
|
+
const sourceCode = context.sourceCode;
|
|
55
|
+
const innerStmts = body.type === 'BlockStatement' ? body.body : [body];
|
|
56
|
+
|
|
57
|
+
// Single-line loops keep compact output to avoid reformatting
|
|
58
|
+
// code the author intentionally wrote on one line.
|
|
59
|
+
const isSingleLine = node.loc.start.line === node.loc.end.line;
|
|
60
|
+
if (isSingleLine) {
|
|
61
|
+
const compactBody = innerStmts
|
|
62
|
+
.map((stmt) => sourceCode.getText(stmt))
|
|
63
|
+
.join(' ');
|
|
64
|
+
return fixer.replaceText(
|
|
65
|
+
body,
|
|
66
|
+
`{ if (${objText}.hasOwnProperty(${keyName})) { ${compactBody} } }`,
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Multi-line loops: emit a properly-indented guard block.
|
|
71
|
+
const loopLine = sourceCode.lines[node.loc.start.line - 1] ?? '';
|
|
72
|
+
const baseIndent = (loopLine.match(/^[\t ]*/) ?? [''])[0];
|
|
73
|
+
const firstStmt = innerStmts[0];
|
|
74
|
+
const firstStmtLine = firstStmt
|
|
75
|
+
? (sourceCode.lines[firstStmt.loc.start.line - 1] ?? '')
|
|
76
|
+
: '';
|
|
77
|
+
const firstStmtIndent = (firstStmtLine.match(/^[\t ]*/) ?? [''])[0];
|
|
78
|
+
const unit =
|
|
79
|
+
firstStmtIndent.length > baseIndent.length
|
|
80
|
+
? firstStmtIndent.slice(baseIndent.length)
|
|
81
|
+
: ' ';
|
|
82
|
+
const guardIndent = baseIndent + unit;
|
|
83
|
+
const stmtIndent = guardIndent + unit;
|
|
84
|
+
|
|
85
|
+
const guardedBody = innerStmts
|
|
86
|
+
.map((stmt) => `${stmtIndent}${sourceCode.getText(stmt)}`)
|
|
87
|
+
.join('\n');
|
|
88
|
+
|
|
89
|
+
return fixer.replaceText(
|
|
90
|
+
body,
|
|
91
|
+
`{\n${guardIndent}if (${objText}.hasOwnProperty(${keyName})) {\n${guardedBody}\n${guardIndent}}\n${baseIndent}}`,
|
|
92
|
+
);
|
|
93
|
+
},
|
|
73
94
|
});
|
|
74
95
|
}
|
|
75
96
|
},
|