eslint-plugin-sfmc 2.6.0 → 3.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.
Files changed (43) hide show
  1. package/README.md +72 -63
  2. package/docs/rules/hbs/helper-arity.md +55 -0
  3. package/docs/rules/hbs/helper-too-new-for-target.md +62 -0
  4. package/docs/rules/hbs/no-unknown-binding.md +49 -0
  5. package/docs/rules/hbs/no-unknown-helper.md +60 -0
  6. package/docs/rules/hbs/no-unsupported-construct.md +65 -0
  7. package/package.json +14 -12
  8. package/src/ampscript-parser.js +1 -1
  9. package/src/ampscript-processor.js +22 -16
  10. package/src/handlebars-parser.js +195 -0
  11. package/src/index.js +90 -11
  12. package/src/processor.js +76 -16
  13. package/src/rules/amp/{arg-types.js → argument-types.js} +16 -12
  14. package/src/rules/amp/function-arity.js +9 -9
  15. package/src/rules/amp/no-inline-statement.js +5 -5
  16. package/src/rules/amp/no-loop-counter-assign.js +7 -7
  17. package/src/rules/amp/no-nested-ampscript-delimiter.js +1 -1
  18. package/src/rules/amp/no-smart-quotes.js +18 -18
  19. package/src/rules/amp/no-unknown-function.js +16 -3
  20. package/src/rules/amp/prefer-attribute-value.js +7 -10
  21. package/src/rules/amp/require-rowcount-check.js +12 -15
  22. package/src/rules/amp/require-variable-declaration.js +3 -3
  23. package/src/rules/hbs/_shared.js +116 -0
  24. package/src/rules/hbs/helper-arity.js +97 -0
  25. package/src/rules/hbs/helper-too-new-for-target.js +94 -0
  26. package/src/rules/hbs/no-unknown-binding.js +74 -0
  27. package/src/rules/hbs/no-unknown-helper.js +79 -0
  28. package/src/rules/hbs/no-unsupported-construct.js +70 -0
  29. package/src/rules/ssjs/cache-loop-length.js +14 -17
  30. package/src/rules/ssjs/no-deprecated-function.js +8 -8
  31. package/src/rules/ssjs/no-hardcoded-credentials.js +3 -6
  32. package/src/rules/ssjs/no-property-call.js +6 -9
  33. package/src/rules/ssjs/no-treatascontent-injection.js +6 -13
  34. package/src/rules/ssjs/no-unavailable-method.js +22 -22
  35. package/src/rules/ssjs/no-unknown-function.js +16 -12
  36. package/src/rules/ssjs/no-unsupported-syntax.js +5 -5
  37. package/src/rules/ssjs/{prefer-parsejson-safe-arg.js → prefer-parsejson-safe-argument.js} +13 -21
  38. package/src/rules/ssjs/require-hasownproperty.js +54 -42
  39. package/src/rules/ssjs/require-platform-load-order.js +1 -1
  40. package/src/rules/ssjs/require-platform-load.js +6 -6
  41. package/src/rules/ssjs/{ssjs-arg-types.js → ssjs-argument-types.js} +59 -46
  42. package/src/rules/ssjs/ssjs-core-method-arity.js +19 -15
  43. /package/src/rules/amp/{no-var-redeclaration.js → no-variable-redeclaration.js} +0 -0
@@ -27,17 +27,17 @@ export default {
27
27
  ForInStatement(node) {
28
28
  const body = node.body;
29
29
 
30
- const stmts = body.type === 'BlockStatement' ? body.body : [body];
30
+ const statements = body.type === 'BlockStatement' ? body.body : [body];
31
31
 
32
- if (stmts.length === 0) {
32
+ if (statements.length === 0) {
33
33
  return;
34
34
  }
35
35
 
36
- const hasGuard = stmts.some((stmt) => containsHasOwnProperty(stmt));
36
+ const hasGuard = statements.some((statement) => containsHasOwnProperty(statement));
37
37
 
38
38
  if (!hasGuard) {
39
39
  const keyName = getKeyName(node.left);
40
- const objText = context.sourceCode.getText(node.right);
40
+ const objectText = context.sourceCode.getText(node.right);
41
41
 
42
42
  if (!keyName) {
43
43
  context.report({
@@ -52,43 +52,49 @@ export default {
52
52
  messageId: 'missingGuard',
53
53
  fix(fixer) {
54
54
  const sourceCode = context.sourceCode;
55
- const innerStmts = body.type === 'BlockStatement' ? body.body : [body];
55
+ const innerStatements =
56
+ body.type === 'BlockStatement' ? body.body : [body];
56
57
 
57
58
  // Single-line loops keep compact output to avoid reformatting
58
59
  // code the author intentionally wrote on one line.
59
60
  const isSingleLine = node.loc.start.line === node.loc.end.line;
60
61
  if (isSingleLine) {
61
- const compactBody = innerStmts
62
- .map((stmt) => sourceCode.getText(stmt))
62
+ const compactBody = innerStatements
63
+ .map((statement) => sourceCode.getText(statement))
63
64
  .join(' ');
64
65
  return fixer.replaceText(
65
66
  body,
66
- `{ if (${objText}.hasOwnProperty(${keyName})) { ${compactBody} } }`,
67
+ `{ if (${objectText}.hasOwnProperty(${keyName})) { ${compactBody} } }`,
67
68
  );
68
69
  }
69
70
 
70
71
  // Multi-line loops: emit a properly-indented guard block.
71
72
  const loopLine = sourceCode.lines[node.loc.start.line - 1] ?? '';
72
73
  const baseIndent = (loopLine.match(/^[\t ]*/) ?? [''])[0];
73
- const firstStmt = innerStmts[0];
74
- const firstStmtLine = firstStmt
75
- ? (sourceCode.lines[firstStmt.loc.start.line - 1] ?? '')
74
+ const firstStatement = innerStatements[0];
75
+ const firstStatementLine = firstStatement
76
+ ? (sourceCode.lines[firstStatement.loc.start.line - 1] ?? '')
76
77
  : '';
77
- const firstStmtIndent = (firstStmtLine.match(/^[\t ]*/) ?? [''])[0];
78
+ const firstStatementIndent = (firstStatementLine.match(/^[\t ]*/) ?? [
79
+ '',
80
+ ])[0];
78
81
  const unit =
79
- firstStmtIndent.length > baseIndent.length
80
- ? firstStmtIndent.slice(baseIndent.length)
81
- : ' ';
82
+ firstStatementIndent.length > baseIndent.length
83
+ ? firstStatementIndent.slice(baseIndent.length)
84
+ : ' '.repeat(4);
82
85
  const guardIndent = baseIndent + unit;
83
- const stmtIndent = guardIndent + unit;
86
+ const statementIndent = guardIndent + unit;
84
87
 
85
- const guardedBody = innerStmts
86
- .map((stmt) => `${stmtIndent}${sourceCode.getText(stmt)}`)
88
+ const guardedBody = innerStatements
89
+ .map(
90
+ (statement) =>
91
+ `${statementIndent}${sourceCode.getText(statement)}`,
92
+ )
87
93
  .join('\n');
88
94
 
89
95
  return fixer.replaceText(
90
96
  body,
91
- `{\n${guardIndent}if (${objText}.hasOwnProperty(${keyName})) {\n${guardedBody}\n${guardIndent}}\n${baseIndent}}`,
97
+ `{\n${guardIndent}if (${objectText}.hasOwnProperty(${keyName})) {\n${guardedBody}\n${guardIndent}}\n${baseIndent}}`,
92
98
  );
93
99
  },
94
100
  });
@@ -99,53 +105,59 @@ export default {
99
105
  };
100
106
 
101
107
  function containsHasOwnProperty(node) {
102
- if (!node) {
108
+ let current = node;
109
+
110
+ // Unwrap pass-through single-child nodes iteratively to avoid tail recursion.
111
+ while (current && current.type === 'ExpressionStatement') {
112
+ current = current.expression;
113
+ }
114
+
115
+ if (!current) {
103
116
  return false;
104
117
  }
105
118
 
106
- if (node.type === 'IfStatement' && node.test && hasOwnPropertyTest(node.test)) {
119
+ if (current.type === 'IfStatement' && current.test && hasOwnPropertyTest(current.test)) {
107
120
  return true;
108
121
  }
109
122
 
110
- if (node.type === 'IfStatement') {
123
+ if (current.type === 'IfStatement') {
111
124
  return (
112
- hasOwnPropertyTest(node.test) ||
113
- containsHasOwnProperty(node.consequent) ||
114
- containsHasOwnProperty(node.alternate)
125
+ hasOwnPropertyTest(current.test) ||
126
+ containsHasOwnProperty(current.consequent) ||
127
+ containsHasOwnProperty(current.alternate)
115
128
  );
116
129
  }
117
130
 
118
- if (node.type === 'BlockStatement') {
119
- return node.body.some((child) => containsHasOwnProperty(child));
120
- }
121
-
122
- if (node.type === 'ExpressionStatement') {
123
- return containsHasOwnProperty(node.expression);
131
+ if (current.type === 'BlockStatement') {
132
+ return current.body.some((child) => containsHasOwnProperty(child));
124
133
  }
125
134
 
126
135
  return false;
127
136
  }
128
137
 
129
138
  function hasOwnPropertyTest(node) {
130
- if (!node) {
139
+ let current = node;
140
+
141
+ // Unwrap negations / unary wrappers iteratively to avoid tail recursion.
142
+ while (current && current.type === 'UnaryExpression') {
143
+ current = current.argument;
144
+ }
145
+
146
+ if (!current) {
131
147
  return false;
132
148
  }
133
149
 
134
150
  if (
135
- node.type === 'CallExpression' &&
136
- node.callee.type === 'MemberExpression' &&
137
- node.callee.property.type === 'Identifier' &&
138
- node.callee.property.name === 'hasOwnProperty'
151
+ current.type === 'CallExpression' &&
152
+ current.callee.type === 'MemberExpression' &&
153
+ current.callee.property.type === 'Identifier' &&
154
+ current.callee.property.name === 'hasOwnProperty'
139
155
  ) {
140
156
  return true;
141
157
  }
142
158
 
143
- if (node.type === 'LogicalExpression') {
144
- return hasOwnPropertyTest(node.left) || hasOwnPropertyTest(node.right);
145
- }
146
-
147
- if (node.type === 'UnaryExpression') {
148
- return hasOwnPropertyTest(node.argument);
159
+ if (current.type === 'LogicalExpression') {
160
+ return hasOwnPropertyTest(current.left) || hasOwnPropertyTest(current.right);
149
161
  }
150
162
 
151
163
  return false;
@@ -8,7 +8,7 @@
8
8
 
9
9
  import { coreObjectNames } from 'ssjs-data';
10
10
 
11
- const TOP_LEVEL_CORE_NAMES = new Set([...coreObjectNames].map((n) => n.split('.')[0]));
11
+ const TOP_LEVEL_CORE_NAMES = new Set([...coreObjectNames].map((n) => n.split('.', 1)[0]));
12
12
 
13
13
  export default {
14
14
  meta: {
@@ -12,11 +12,11 @@
12
12
 
13
13
  import { coreObjectNames, SSJS_GLOBALS } from 'ssjs-data';
14
14
 
15
- const TOP_LEVEL_CORE_NAMES = new Set([...coreObjectNames].map((n) => n.split('.')[0]));
15
+ const TOP_LEVEL_CORE_NAMES = new Set([...coreObjectNames].map((n) => n.split('.', 1)[0]));
16
16
 
17
17
  // Globals that resolve at runtime only after Platform.Load("core", ...) has been called.
18
18
  // E.g. Now(), Write(), GUID(), Base64Encode(), Attribute.GetValue(), DateTime.Parse(), …
19
- const REQUIRES_CORE_LOAD_GLOBALS = new Set(
19
+ const CORE_LOAD_DEPENDENT_GLOBALS = new Set(
20
20
  SSJS_GLOBALS.filter((g) => g.requiresCoreLoad).map((g) => g.name.toLowerCase()),
21
21
  );
22
22
 
@@ -55,7 +55,7 @@ export default {
55
55
 
56
56
  'Program:exit'() {
57
57
  if (!hasPlatformLoad) {
58
- for (const [i, { node, name }] of pendingReports.entries()) {
58
+ for (const [index, { node, name }] of pendingReports.entries()) {
59
59
  context.report({
60
60
  node,
61
61
  messageId: 'missingLoad',
@@ -63,7 +63,7 @@ export default {
63
63
  // Only attach the fix to the first violation to prevent
64
64
  // ESLint from inserting the statement multiple times.
65
65
  fix:
66
- i === 0
66
+ index === 0
67
67
  ? (fixer) =>
68
68
  fixer.insertTextBeforeRange(
69
69
  [0, 0],
@@ -105,7 +105,7 @@ function getCoreObjectUsage(node) {
105
105
 
106
106
  // Bare call: Now(), Write(), GUID(), Base64Encode(), Redirect(), …
107
107
  if (callee.type === 'Identifier') {
108
- if (REQUIRES_CORE_LOAD_GLOBALS.has(callee.name.toLowerCase())) {
108
+ if (CORE_LOAD_DEPENDENT_GLOBALS.has(callee.name.toLowerCase())) {
109
109
  return callee.name;
110
110
  }
111
111
  return null;
@@ -135,7 +135,7 @@ function getCoreObjectUsage(node) {
135
135
  }
136
136
 
137
137
  // requiresCoreLoad globals used as object: Attribute.GetValue(…), DateTime.Parse(…), …
138
- if (REQUIRES_CORE_LOAD_GLOBALS.has(objectName.toLowerCase())) {
138
+ if (CORE_LOAD_DEPENDENT_GLOBALS.has(objectName.toLowerCase())) {
139
139
  return `${objectName}.${callee.property.name}`;
140
140
  }
141
141
  }
@@ -61,34 +61,34 @@ export default {
61
61
  },
62
62
 
63
63
  create(context) {
64
- const coreVars = new Map(); // varName → className (Core Library instances)
65
- const wsproxyVars = new Set(); // varNames assigned new Script.Util.WSProxy()
64
+ const coreVariables = new Map(); // varName → className (Core Library instances)
65
+ const wsproxyVariables = new Set(); // varNames assigned new Script.Util.WSProxy()
66
66
 
67
- function checkArgs(entry, args, callName) {
67
+ function checkArguments(entry, arguments_, callName) {
68
68
  if (!entry || !entry.params || entry.params.length === 0) {
69
69
  return;
70
70
  }
71
- for (const [i, arg] of args.entries()) {
72
- const param = entry.params[i];
73
- if (!param) {
71
+ for (const [index, argument] of arguments_.entries()) {
72
+ const parameter = entry.params[index];
73
+ if (!parameter) {
74
74
  break;
75
75
  } // beyond declared params — arity rule handles this
76
- if (!param.type || param.type === 'any') {
76
+ if (!parameter.type || parameter.type === 'any') {
77
77
  continue;
78
78
  }
79
- const actual = inferArgType(arg);
79
+ const actual = inferArgumentType(argument);
80
80
  if (actual === null) {
81
81
  continue;
82
82
  } // unknown type (variable/call) — skip
83
- if (!isTypeCompatible(actual, param.type)) {
83
+ if (!isTypeCompatible(actual, parameter.type)) {
84
84
  context.report({
85
- node: arg,
85
+ node: argument,
86
86
  messageId: 'typeMismatch',
87
87
  data: {
88
- pos: String(i + 1),
89
- param: param.name,
88
+ pos: String(index + 1),
89
+ param: parameter.name,
90
90
  call: callName,
91
- expected: param.type,
91
+ expected: parameter.type,
92
92
  actual,
93
93
  },
94
94
  });
@@ -98,17 +98,21 @@ export default {
98
98
 
99
99
  return {
100
100
  VariableDeclaration(node) {
101
- for (const decl of node.declarations) {
102
- if (!decl.init || !decl.id || decl.id.type !== 'Identifier') {
101
+ for (const declaration of node.declarations) {
102
+ if (
103
+ !declaration.init ||
104
+ !declaration.id ||
105
+ declaration.id.type !== 'Identifier'
106
+ ) {
103
107
  continue;
104
108
  }
105
- if (isWSProxyConstructor(decl.init)) {
106
- wsproxyVars.add(decl.id.name);
109
+ if (isWSProxyConstructor(declaration.init)) {
110
+ wsproxyVariables.add(declaration.id.name);
107
111
  continue;
108
112
  }
109
- const coreType = getCoreInitType(decl.init);
113
+ const coreType = getCoreInitType(declaration.init);
110
114
  if (coreType) {
111
- coreVars.set(decl.id.name, coreType);
115
+ coreVariables.set(declaration.id.name, coreType);
112
116
  }
113
117
  }
114
118
  },
@@ -118,12 +122,12 @@ export default {
118
122
  return;
119
123
  }
120
124
  if (isWSProxyConstructor(node.right)) {
121
- wsproxyVars.add(node.left.name);
125
+ wsproxyVariables.add(node.left.name);
122
126
  return;
123
127
  }
124
128
  const coreType = getCoreInitType(node.right);
125
129
  if (coreType) {
126
- coreVars.set(node.left.name, coreType);
130
+ coreVariables.set(node.left.name, coreType);
127
131
  }
128
132
  },
129
133
 
@@ -134,7 +138,7 @@ export default {
134
138
  if (callee.type === 'Identifier') {
135
139
  const entry = ssjsGlobalsLookup.get(callee.name.toLowerCase());
136
140
  if (entry) {
137
- checkArgs(entry, node.arguments, callee.name);
141
+ checkArguments(entry, node.arguments, callee.name);
138
142
  }
139
143
  return;
140
144
  }
@@ -159,7 +163,7 @@ export default {
159
163
  if (lookup) {
160
164
  const entry = lookup.get(methodName.toLowerCase());
161
165
  if (entry) {
162
- checkArgs(
166
+ checkArguments(
163
167
  entry,
164
168
  node.arguments,
165
169
  `Platform.${callee.object.property.name}.${methodName}`,
@@ -170,48 +174,52 @@ export default {
170
174
  }
171
175
 
172
176
  if (callee.object.type === 'Identifier') {
173
- const objName = callee.object.name;
174
- const objLower = objName.toLowerCase();
177
+ const objectName = callee.object.name;
178
+ const objectLower = objectName.toLowerCase();
175
179
 
176
180
  // Static top-level: HTTP.Post(...), HTTPHeader.SetValue(...), Attribute.GetValue(...)
177
- const topLookup = TOPLEVEL_LOOKUPS.get(objLower);
181
+ const topLookup = TOPLEVEL_LOOKUPS.get(objectLower);
178
182
  if (topLookup) {
179
183
  const entry = topLookup.get(methodName.toLowerCase());
180
184
  if (entry) {
181
- checkArgs(entry, node.arguments, `${objName}.${methodName}`);
185
+ checkArguments(entry, node.arguments, `${objectName}.${methodName}`);
182
186
  }
183
187
  return;
184
188
  }
185
189
 
186
190
  // WSProxy instance method: proxy.Retrieve(...)
187
- if (wsproxyVars.has(objName)) {
191
+ if (wsproxyVariables.has(objectName)) {
188
192
  const entry = wsproxyMethodLookup.get(methodName.toLowerCase());
189
193
  if (entry) {
190
- checkArgs(entry, node.arguments, `WSProxy.${methodName}`);
194
+ checkArguments(entry, node.arguments, `WSProxy.${methodName}`);
191
195
  }
192
196
  return;
193
197
  }
194
198
 
195
199
  // Core Library instance method: de.Add(...)
196
- const coreType = coreVars.get(objName);
200
+ const coreType = coreVariables.get(objectName);
197
201
  if (coreType) {
198
202
  const classLookup = coreMethodArityLookup.get(coreType.toLowerCase());
199
203
  if (classLookup) {
200
204
  const entry = classLookup.get(methodName.toLowerCase());
201
205
  if (entry) {
202
- checkArgs(entry, node.arguments, `${coreType}.${methodName}`);
206
+ checkArguments(entry, node.arguments, `${coreType}.${methodName}`);
203
207
  }
204
208
  }
205
209
  return;
206
210
  }
207
211
 
208
212
  // Static Core Library single-name: DataExtension.Init(...), BounceEvent.Retrieve(...)
209
- if (coreObjectNames.has(objName)) {
210
- const classLookup = coreMethodArityLookup.get(objLower);
213
+ if (coreObjectNames.has(objectName)) {
214
+ const classLookup = coreMethodArityLookup.get(objectLower);
211
215
  if (classLookup) {
212
216
  const entry = classLookup.get(methodName.toLowerCase());
213
217
  if (entry) {
214
- checkArgs(entry, node.arguments, `${objName}.${methodName}`);
218
+ checkArguments(
219
+ entry,
220
+ node.arguments,
221
+ `${objectName}.${methodName}`,
222
+ );
215
223
  }
216
224
  }
217
225
  }
@@ -225,7 +233,7 @@ export default {
225
233
  if (classLookup) {
226
234
  const entry = classLookup.get(methodName.toLowerCase());
227
235
  if (entry) {
228
- checkArgs(entry, node.arguments, `${objectPath}.${methodName}`);
236
+ checkArguments(entry, node.arguments, `${objectPath}.${methodName}`);
229
237
  }
230
238
  }
231
239
  }
@@ -266,13 +274,13 @@ function getMemberPath(node) {
266
274
  return node.name;
267
275
  }
268
276
  if (node.type === 'MemberExpression' && node.property.type === 'Identifier') {
269
- const obj = getMemberPath(node.object);
270
- return obj ? `${obj}.${node.property.name}` : null;
277
+ const object = getMemberPath(node.object);
278
+ return object ? `${object}.${node.property.name}` : null;
271
279
  }
272
280
  return null;
273
281
  }
274
282
 
275
- function inferArgType(node) {
283
+ function inferArgumentType(node) {
276
284
  if (!node || node.type === 'SpreadElement') {
277
285
  return null;
278
286
  }
@@ -294,14 +302,22 @@ function inferArgType(node) {
294
302
  return 'string';
295
303
  }
296
304
  if (node.type === 'ArrayExpression') {
297
- const elems = node.elements.filter(Boolean);
298
- if (elems.length === 0) {
305
+ const elements = node.elements.filter(Boolean);
306
+ if (elements.length === 0) {
299
307
  return 'array';
300
308
  }
301
- if (elems.every((e) => e.type === 'Literal' && typeof e.value === 'string')) {
309
+ if (
310
+ elements.every(
311
+ (element) => element.type === 'Literal' && typeof element.value === 'string',
312
+ )
313
+ ) {
302
314
  return 'string[]';
303
315
  }
304
- if (elems.every((e) => e.type === 'Literal' && typeof e.value === 'number')) {
316
+ if (
317
+ elements.every(
318
+ (element) => element.type === 'Literal' && typeof element.value === 'number',
319
+ )
320
+ ) {
305
321
  return 'number[]';
306
322
  }
307
323
  return 'array';
@@ -321,10 +337,7 @@ function isTypeCompatible(actual, expected) {
321
337
  return true;
322
338
  }
323
339
  // 'array' is compatible with typed array variants
324
- if (allowed.includes('array') && (actual === 'string[]' || actual === 'number[]')) {
325
- return true;
326
- }
327
- return false;
340
+ return Boolean(allowed.includes('array') && (actual === 'string[]' || actual === 'number[]'));
328
341
  }
329
342
 
330
343
  function isWSProxyConstructor(node) {
@@ -28,13 +28,13 @@ export default {
28
28
  },
29
29
 
30
30
  create(context) {
31
- const coreVars = new Map(); // varName → className
31
+ const coreVariables = new Map(); // varName → className
32
32
 
33
- function checkArity(entry, args, callName, reportNode) {
33
+ function checkArity(entry, arguments_, callName, reportNode) {
34
34
  if (!entry) {
35
35
  return;
36
36
  }
37
- const actual = args.length;
37
+ const actual = arguments_.length;
38
38
  if (actual < entry.minArgs) {
39
39
  context.report({
40
40
  node: reportNode,
@@ -52,13 +52,17 @@ export default {
52
52
 
53
53
  return {
54
54
  VariableDeclaration(node) {
55
- for (const decl of node.declarations) {
56
- if (!decl.init || !decl.id || decl.id.type !== 'Identifier') {
55
+ for (const declaration of node.declarations) {
56
+ if (
57
+ !declaration.init ||
58
+ !declaration.id ||
59
+ declaration.id.type !== 'Identifier'
60
+ ) {
57
61
  continue;
58
62
  }
59
- const coreType = getCoreInitType(decl.init);
63
+ const coreType = getCoreInitType(declaration.init);
60
64
  if (coreType) {
61
- coreVars.set(decl.id.name, coreType);
65
+ coreVariables.set(declaration.id.name, coreType);
62
66
  }
63
67
  }
64
68
  },
@@ -69,7 +73,7 @@ export default {
69
73
  }
70
74
  const coreType = getCoreInitType(node.right);
71
75
  if (coreType) {
72
- coreVars.set(node.left.name, coreType);
76
+ coreVariables.set(node.left.name, coreType);
73
77
  }
74
78
  },
75
79
 
@@ -84,10 +88,10 @@ export default {
84
88
  const methodName = callee.property.name;
85
89
 
86
90
  if (callee.object.type === 'Identifier') {
87
- const objName = callee.object.name;
91
+ const objectName = callee.object.name;
88
92
 
89
93
  // Core Library instance method: de.Add(...)
90
- const coreType = coreVars.get(objName);
94
+ const coreType = coreVariables.get(objectName);
91
95
  if (coreType) {
92
96
  const classLookup = coreMethodArityLookup.get(coreType.toLowerCase());
93
97
  if (classLookup) {
@@ -103,14 +107,14 @@ export default {
103
107
  }
104
108
 
105
109
  // Static single-name: DataExtension.Init(...), BounceEvent.Retrieve(...)
106
- if (coreObjectNames.has(objName)) {
107
- const classLookup = coreMethodArityLookup.get(objName.toLowerCase());
110
+ if (coreObjectNames.has(objectName)) {
111
+ const classLookup = coreMethodArityLookup.get(objectName.toLowerCase());
108
112
  if (classLookup) {
109
113
  const entry = classLookup.get(methodName.toLowerCase());
110
114
  checkArity(
111
115
  entry,
112
116
  node.arguments,
113
- `${objName}.${methodName}`,
117
+ `${objectName}.${methodName}`,
114
118
  callee.property,
115
119
  );
116
120
  }
@@ -169,8 +173,8 @@ function getMemberPath(node) {
169
173
  return node.name;
170
174
  }
171
175
  if (node.type === 'MemberExpression' && node.property.type === 'Identifier') {
172
- const obj = getMemberPath(node.object);
173
- return obj ? `${obj}.${node.property.name}` : null;
176
+ const object = getMemberPath(node.object);
177
+ return object ? `${object}.${node.property.name}` : null;
174
178
  }
175
179
  return null;
176
180
  }