@n8n/eslint-plugin-community-nodes 0.3.0 → 0.5.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 (114) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/README.md +60 -0
  3. package/dist/plugin.d.ts +144 -28
  4. package/dist/plugin.d.ts.map +1 -1
  5. package/dist/plugin.js +28 -25
  6. package/dist/plugin.js.map +1 -1
  7. package/dist/rules/credential-documentation-url.d.ts +7 -0
  8. package/dist/rules/credential-documentation-url.d.ts.map +1 -0
  9. package/dist/rules/credential-documentation-url.js +100 -0
  10. package/dist/rules/credential-documentation-url.js.map +1 -0
  11. package/dist/rules/credential-password-field.d.ts +1 -2
  12. package/dist/rules/credential-password-field.d.ts.map +1 -1
  13. package/dist/rules/credential-password-field.js +25 -14
  14. package/dist/rules/credential-password-field.js.map +1 -1
  15. package/dist/rules/credential-test-required.d.ts +1 -2
  16. package/dist/rules/credential-test-required.d.ts.map +1 -1
  17. package/dist/rules/credential-test-required.js +43 -5
  18. package/dist/rules/credential-test-required.js.map +1 -1
  19. package/dist/rules/icon-validation.d.ts +1 -2
  20. package/dist/rules/icon-validation.d.ts.map +1 -1
  21. package/dist/rules/icon-validation.js +81 -15
  22. package/dist/rules/icon-validation.js.map +1 -1
  23. package/dist/rules/index.d.ts +9 -5
  24. package/dist/rules/index.d.ts.map +1 -1
  25. package/dist/rules/index.js +7 -5
  26. package/dist/rules/index.js.map +1 -1
  27. package/dist/rules/no-credential-reuse.d.ts +1 -2
  28. package/dist/rules/no-credential-reuse.d.ts.map +1 -1
  29. package/dist/rules/no-credential-reuse.js +33 -4
  30. package/dist/rules/no-credential-reuse.js.map +1 -1
  31. package/dist/rules/no-deprecated-workflow-functions.d.ts +1 -2
  32. package/dist/rules/no-deprecated-workflow-functions.d.ts.map +1 -1
  33. package/dist/rules/no-deprecated-workflow-functions.js +38 -10
  34. package/dist/rules/no-deprecated-workflow-functions.js.map +1 -1
  35. package/dist/rules/no-restricted-globals.d.ts +2 -2
  36. package/dist/rules/no-restricted-globals.d.ts.map +1 -1
  37. package/dist/rules/no-restricted-globals.js +5 -3
  38. package/dist/rules/no-restricted-globals.js.map +1 -1
  39. package/dist/rules/no-restricted-imports.d.ts +1 -2
  40. package/dist/rules/no-restricted-imports.d.ts.map +1 -1
  41. package/dist/rules/no-restricted-imports.js +3 -3
  42. package/dist/rules/no-restricted-imports.js.map +1 -1
  43. package/dist/rules/node-usable-as-tool.d.ts +1 -2
  44. package/dist/rules/node-usable-as-tool.d.ts.map +1 -1
  45. package/dist/rules/node-usable-as-tool.js +6 -5
  46. package/dist/rules/node-usable-as-tool.js.map +1 -1
  47. package/dist/rules/package-name-convention.d.ts +1 -2
  48. package/dist/rules/package-name-convention.d.ts.map +1 -1
  49. package/dist/rules/package-name-convention.js +38 -2
  50. package/dist/rules/package-name-convention.js.map +1 -1
  51. package/dist/rules/resource-operation-pattern.d.ts +1 -2
  52. package/dist/rules/resource-operation-pattern.d.ts.map +1 -1
  53. package/dist/rules/resource-operation-pattern.js +9 -7
  54. package/dist/rules/resource-operation-pattern.js.map +1 -1
  55. package/dist/utils/ast-utils.d.ts +2 -1
  56. package/dist/utils/ast-utils.d.ts.map +1 -1
  57. package/dist/utils/ast-utils.js +37 -19
  58. package/dist/utils/ast-utils.js.map +1 -1
  59. package/dist/utils/file-utils.d.ts +14 -0
  60. package/dist/utils/file-utils.d.ts.map +1 -1
  61. package/dist/utils/file-utils.js +85 -18
  62. package/dist/utils/file-utils.js.map +1 -1
  63. package/dist/utils/index.d.ts +1 -0
  64. package/dist/utils/index.d.ts.map +1 -1
  65. package/dist/utils/index.js +1 -0
  66. package/dist/utils/index.js.map +1 -1
  67. package/dist/utils/rule-creator.d.ts +3 -0
  68. package/dist/utils/rule-creator.d.ts.map +1 -0
  69. package/dist/utils/rule-creator.js +5 -0
  70. package/dist/utils/rule-creator.js.map +1 -0
  71. package/docs/rules/credential-documentation-url.md +94 -0
  72. package/docs/rules/credential-password-field.md +45 -0
  73. package/docs/rules/credential-test-required.md +58 -0
  74. package/docs/rules/icon-validation.md +67 -0
  75. package/docs/rules/no-credential-reuse.md +82 -0
  76. package/docs/rules/no-deprecated-workflow-functions.md +61 -0
  77. package/docs/rules/no-restricted-globals.md +44 -0
  78. package/docs/rules/no-restricted-imports.md +47 -0
  79. package/docs/rules/node-usable-as-tool.md +43 -0
  80. package/docs/rules/package-name-convention.md +52 -0
  81. package/docs/rules/resource-operation-pattern.md +84 -0
  82. package/eslint.config.mjs +27 -0
  83. package/package.json +25 -4
  84. package/src/plugin.ts +30 -26
  85. package/src/rules/credential-documentation-url.test.ts +306 -0
  86. package/src/rules/credential-documentation-url.ts +129 -0
  87. package/src/rules/credential-password-field.test.ts +1 -0
  88. package/src/rules/credential-password-field.ts +34 -16
  89. package/src/rules/credential-test-required.test.ts +84 -57
  90. package/src/rules/credential-test-required.ts +51 -5
  91. package/src/rules/icon-validation.test.ts +97 -14
  92. package/src/rules/icon-validation.ts +95 -14
  93. package/src/rules/index.ts +8 -5
  94. package/src/rules/no-credential-reuse.test.ts +306 -58
  95. package/src/rules/no-credential-reuse.ts +43 -3
  96. package/src/rules/no-deprecated-workflow-functions.test.ts +70 -0
  97. package/src/rules/no-deprecated-workflow-functions.ts +44 -10
  98. package/src/rules/no-restricted-globals.test.ts +1 -0
  99. package/src/rules/no-restricted-globals.ts +6 -3
  100. package/src/rules/no-restricted-imports.test.ts +1 -0
  101. package/src/rules/no-restricted-imports.ts +8 -3
  102. package/src/rules/node-usable-as-tool.test.ts +1 -0
  103. package/src/rules/node-usable-as-tool.ts +8 -6
  104. package/src/rules/package-name-convention.test.ts +82 -5
  105. package/src/rules/package-name-convention.ts +46 -2
  106. package/src/rules/resource-operation-pattern.test.ts +1 -0
  107. package/src/rules/resource-operation-pattern.ts +13 -6
  108. package/src/utils/ast-utils.ts +47 -19
  109. package/src/utils/file-utils.ts +108 -18
  110. package/src/utils/index.ts +1 -0
  111. package/src/utils/rule-creator.ts +6 -0
  112. package/tsconfig.build.json +4 -0
  113. package/tsconfig.eslint.json +5 -0
  114. package/tsconfig.json +1 -2
@@ -1,16 +1,18 @@
1
- import { ESLintUtils } from '@typescript-eslint/utils';
2
- import { isCredentialTypeClass, findClassProperty, hasArrayLiteralValue, isFileType, getStringLiteralValue, findPackageJson, areAllCredentialUsagesTestedByNodes, } from '../utils/index.js';
3
1
  import { dirname } from 'node:path';
4
- export const CredentialTestRequiredRule = ESLintUtils.RuleCreator.withoutDocs({
2
+ import { isCredentialTypeClass, findClassProperty, hasArrayLiteralValue, isFileType, getStringLiteralValue, findPackageJson, areAllCredentialUsagesTestedByNodes, createRule, } from '../utils/index.js';
3
+ export const CredentialTestRequiredRule = createRule({
4
+ name: 'credential-test-required',
5
5
  meta: {
6
6
  type: 'problem',
7
7
  docs: {
8
8
  description: 'Ensure credentials have a credential test',
9
9
  },
10
10
  messages: {
11
+ addTemplate: 'Add basic credential test template',
11
12
  missingCredentialTest: 'Credential class "{{ className }}" must have a test property or be tested by a node via testedBy',
12
13
  },
13
14
  schema: [],
15
+ hasSuggestions: true,
14
16
  },
15
17
  defaultOptions: [],
16
18
  create(context) {
@@ -53,27 +55,63 @@ export const CredentialTestRequiredRule = ESLintUtils.RuleCreator.withoutDocs({
53
55
  }
54
56
  const pkgDir = getPackageDir();
55
57
  if (!pkgDir) {
58
+ const suggestions = [];
59
+ const testProperty = createCredentialTestTemplate();
60
+ suggestions.push({
61
+ messageId: 'addTemplate',
62
+ fix(fixer) {
63
+ const classBody = node.body.body;
64
+ const lastProperty = classBody[classBody.length - 1];
65
+ if (lastProperty) {
66
+ return fixer.insertTextAfter(lastProperty, `\n\n${testProperty}`);
67
+ }
68
+ return null;
69
+ },
70
+ });
56
71
  context.report({
57
72
  node,
58
73
  messageId: 'missingCredentialTest',
59
74
  data: {
60
- className: node.id?.name || 'Unknown',
75
+ className: node.id?.name ?? 'Unknown',
61
76
  },
77
+ suggest: suggestions,
62
78
  });
63
79
  return;
64
80
  }
65
81
  const allUsagesTestedByNodes = areAllCredentialUsagesTestedByNodes(credentialName, pkgDir);
66
82
  if (!allUsagesTestedByNodes) {
83
+ const suggestions = [];
84
+ const testProperty = createCredentialTestTemplate();
85
+ suggestions.push({
86
+ messageId: 'addTemplate',
87
+ fix(fixer) {
88
+ const classBody = node.body.body;
89
+ const lastProperty = classBody[classBody.length - 1];
90
+ if (lastProperty) {
91
+ return fixer.insertTextAfter(lastProperty, `\n\n${testProperty}`);
92
+ }
93
+ return null;
94
+ },
95
+ });
67
96
  context.report({
68
97
  node,
69
98
  messageId: 'missingCredentialTest',
70
99
  data: {
71
- className: node.id?.name || 'Unknown',
100
+ className: node.id?.name ?? 'Unknown',
72
101
  },
102
+ suggest: suggestions,
73
103
  });
74
104
  }
75
105
  },
76
106
  };
77
107
  },
78
108
  });
109
+ function createCredentialTestTemplate() {
110
+ return `\ttest: ICredentialTestRequest = {
111
+ \t\trequest: {
112
+ \t\t\tmethod: 'GET',
113
+ \t\t\turl: '={{$credentials.server}}/test', // Replace with actual endpoint
114
+ \t\t},
115
+ \t};`;
116
+ }
79
117
  //# sourceMappingURL=credential-test-required.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"credential-test-required.js","sourceRoot":"","sources":["../../src/rules/credential-test-required.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"credential-test-required.js","sourceRoot":"","sources":["../../src/rules/credential-test-required.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,2 @@
1
- import { ESLintUtils } from '@typescript-eslint/utils';
2
- export declare const IconValidationRule: ESLintUtils.RuleModule<"iconFileNotFound" | "iconNotSvg" | "lightDarkSame" | "invalidIconPath" | "missingIcon", [], unknown, ESLintUtils.RuleListener>;
1
+ export declare const IconValidationRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"iconFileNotFound" | "iconNotSvg" | "lightDarkSame" | "invalidIconPath" | "missingIcon" | "addPlaceholder" | "addFileProtocol" | "changeExtension" | "similarIcon", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
3
2
  //# sourceMappingURL=icon-validation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"icon-validation.d.ts","sourceRoot":"","sources":["../../src/rules/icon-validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAY,MAAM,0BAA0B,CAAC;AAYjE,eAAO,MAAM,kBAAkB,wJAiJ7B,CAAC"}
1
+ {"version":3,"file":"icon-validation.d.ts","sourceRoot":"","sources":["../../src/rules/icon-validation.ts"],"names":[],"mappings":"AA4BA,eAAO,MAAM,kBAAkB,qSAkN7B,CAAC"}
@@ -1,20 +1,27 @@
1
- import { ESLintUtils, TSESTree } from '@typescript-eslint/utils';
1
+ import { TSESTree } from '@typescript-eslint/utils';
2
2
  import { dirname } from 'node:path';
3
- import { isNodeTypeClass, isCredentialTypeClass, findClassProperty, findObjectProperty, getStringLiteralValue, validateIconPath, isFileType, } from '../utils/index.js';
4
- export const IconValidationRule = ESLintUtils.RuleCreator.withoutDocs({
3
+ import { isNodeTypeClass, isCredentialTypeClass, findClassProperty, findObjectProperty, getStringLiteralValue, validateIconPath, findSimilarSvgFiles, isFileType, createRule, } from '../utils/index.js';
4
+ const messages = {
5
+ iconFileNotFound: 'Icon file "{{ iconPath }}" does not exist',
6
+ iconNotSvg: 'Icon file "{{ iconPath }}" must be an SVG file (end with .svg)',
7
+ lightDarkSame: 'Light and dark icons cannot be the same file. Both point to "{{ iconPath }}"',
8
+ invalidIconPath: 'Icon path "{{ iconPath }}" must use file: protocol and be a string',
9
+ missingIcon: 'Node/Credential class must have an icon property defined',
10
+ addPlaceholder: 'Add icon property with placeholder',
11
+ addFileProtocol: "Add 'file:' protocol to icon path",
12
+ changeExtension: "Change icon extension to '.svg'",
13
+ similarIcon: "Use existing icon '{{ suggestedName }}'",
14
+ };
15
+ export const IconValidationRule = createRule({
16
+ name: 'icon-validation',
5
17
  meta: {
6
18
  type: 'problem',
7
19
  docs: {
8
20
  description: 'Validate node and credential icon files exist, are SVG format, and light/dark icons are different',
9
21
  },
10
- messages: {
11
- iconFileNotFound: 'Icon file "{{ iconPath }}" does not exist',
12
- iconNotSvg: 'Icon file "{{ iconPath }}" must be an SVG file (end with .svg)',
13
- lightDarkSame: 'Light and dark icons cannot be the same file. Both point to "{{ iconPath }}"',
14
- invalidIconPath: 'Icon path "{{ iconPath }}" must use file: protocol and be a string',
15
- missingIcon: 'Node/Credential class must have an icon property defined',
16
- },
22
+ messages,
17
23
  schema: [],
24
+ hasSuggestions: true,
18
25
  },
19
26
  defaultOptions: [],
20
27
  create(context) {
@@ -27,46 +34,79 @@ export const IconValidationRule = ESLintUtils.RuleCreator.withoutDocs({
27
34
  context.report({
28
35
  node,
29
36
  messageId: 'invalidIconPath',
30
- data: { iconPath: iconPath || '' },
37
+ data: { iconPath: iconPath ?? '' },
31
38
  });
32
39
  return false;
33
40
  }
34
41
  const currentDir = dirname(context.filename);
35
42
  const validation = validateIconPath(iconPath, currentDir);
36
43
  if (!validation.isFile) {
44
+ const suggestions = [];
45
+ if (!iconPath.startsWith('file:')) {
46
+ suggestions.push({
47
+ messageId: 'addFileProtocol',
48
+ fix(fixer) {
49
+ return fixer.replaceText(node, `"file:${iconPath}"`);
50
+ },
51
+ });
52
+ }
37
53
  context.report({
38
54
  node,
39
55
  messageId: 'invalidIconPath',
40
56
  data: { iconPath },
57
+ suggest: suggestions,
41
58
  });
42
59
  return false;
43
60
  }
44
61
  if (!validation.isSvg) {
45
62
  const relativePath = iconPath.replace(/^file:/, '');
63
+ const suggestions = [];
64
+ const pathWithoutExt = relativePath.replace(/\.[^/.]+$/, '');
65
+ const svgPath = `${pathWithoutExt}.svg`;
66
+ suggestions.push({
67
+ messageId: 'changeExtension',
68
+ fix(fixer) {
69
+ return fixer.replaceText(node, `"file:${svgPath}"`);
70
+ },
71
+ });
46
72
  context.report({
47
73
  node,
48
74
  messageId: 'iconNotSvg',
49
75
  data: { iconPath: relativePath },
76
+ suggest: suggestions,
50
77
  });
51
78
  return false;
52
79
  }
53
80
  if (!validation.exists) {
54
81
  const relativePath = iconPath.replace(/^file:/, '');
82
+ const suggestions = [];
83
+ // Find similar SVG files in the same directory
84
+ const similarFiles = findSimilarSvgFiles(relativePath, currentDir);
85
+ for (const similarFile of similarFiles) {
86
+ suggestions.push({
87
+ messageId: 'similarIcon',
88
+ data: { suggestedName: similarFile },
89
+ fix(fixer) {
90
+ return fixer.replaceText(node, `"file:${similarFile}"`);
91
+ },
92
+ });
93
+ }
55
94
  context.report({
56
95
  node,
57
96
  messageId: 'iconFileNotFound',
58
97
  data: { iconPath: relativePath },
98
+ suggest: suggestions,
59
99
  });
60
100
  return false;
61
101
  }
62
102
  return true;
63
103
  };
64
104
  const validateIconValue = (iconValue) => {
65
- if (iconValue.type === 'Literal') {
105
+ if (iconValue.type === TSESTree.AST_NODE_TYPES.Literal) {
66
106
  const iconPath = getStringLiteralValue(iconValue);
67
107
  validateIcon(iconPath, iconValue);
68
108
  }
69
- else if (iconValue.type === 'ObjectExpression') {
109
+ else if (iconValue.type === TSESTree.AST_NODE_TYPES.ObjectExpression) {
70
110
  const lightProperty = findObjectProperty(iconValue, 'light');
71
111
  const darkProperty = findObjectProperty(iconValue, 'dark');
72
112
  const lightPath = lightProperty ? getStringLiteralValue(lightProperty.value) : null;
@@ -96,18 +136,31 @@ export const IconValidationRule = ESLintUtils.RuleCreator.withoutDocs({
96
136
  if (isNodeClass) {
97
137
  const descriptionProperty = findClassProperty(node, 'description');
98
138
  if (!descriptionProperty?.value ||
99
- descriptionProperty.value.type !== 'ObjectExpression') {
139
+ descriptionProperty.value.type !== TSESTree.AST_NODE_TYPES.ObjectExpression) {
100
140
  context.report({
101
141
  node,
102
142
  messageId: 'missingIcon',
103
143
  });
104
144
  return;
105
145
  }
106
- const iconProperty = findObjectProperty(descriptionProperty.value, 'icon');
146
+ const descriptionValue = descriptionProperty.value;
147
+ const iconProperty = findObjectProperty(descriptionValue, 'icon');
107
148
  if (!iconProperty) {
149
+ const suggestions = [];
150
+ suggestions.push({
151
+ messageId: 'addPlaceholder',
152
+ fix(fixer) {
153
+ const lastProperty = descriptionValue.properties[descriptionValue.properties.length - 1];
154
+ if (lastProperty) {
155
+ return fixer.insertTextAfter(lastProperty, ',\n\t\ticon: "file:./icon.svg"');
156
+ }
157
+ return null;
158
+ },
159
+ });
108
160
  context.report({
109
161
  node,
110
162
  messageId: 'missingIcon',
163
+ suggest: suggestions,
111
164
  });
112
165
  return;
113
166
  }
@@ -116,9 +169,22 @@ export const IconValidationRule = ESLintUtils.RuleCreator.withoutDocs({
116
169
  else if (isCredentialClass) {
117
170
  const iconProperty = findClassProperty(node, 'icon');
118
171
  if (!iconProperty?.value) {
172
+ const suggestions = [];
173
+ suggestions.push({
174
+ messageId: 'addPlaceholder',
175
+ fix(fixer) {
176
+ const classBody = node.body.body;
177
+ const lastProperty = classBody[classBody.length - 1];
178
+ if (lastProperty) {
179
+ return fixer.insertTextAfter(lastProperty, '\n\n\ticon = "file:./icon.svg";');
180
+ }
181
+ return null;
182
+ },
183
+ });
119
184
  context.report({
120
185
  node,
121
186
  messageId: 'missingIcon',
187
+ suggest: suggestions,
122
188
  });
123
189
  return;
124
190
  }
@@ -1 +1 @@
1
- {"version":3,"file":"icon-validation.js","sourceRoot":"","sources":["../../src/rules/icon-validation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"icon-validation.js","sourceRoot":"","sources":["../../src/rules/icon-validation.ts"],"names":[],"mappings":"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"}
@@ -2,12 +2,16 @@ export declare const rules: {
2
2
  'no-restricted-globals': import("@typescript-eslint/utils/ts-eslint").RuleModule<"restrictedGlobal", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
3
3
  'no-restricted-imports': import("@typescript-eslint/utils/ts-eslint").RuleModule<"restrictedImport" | "restrictedRequire" | "restrictedDynamicImport", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
4
4
  'credential-password-field': import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingPasswordOption", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
5
- 'no-deprecated-workflow-functions': import("@typescript-eslint/utils/ts-eslint").RuleModule<"deprecatedRequestFunction" | "deprecatedFunction" | "deprecatedType" | "deprecatedWithoutReplacement", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
5
+ 'no-deprecated-workflow-functions': import("@typescript-eslint/utils/ts-eslint").RuleModule<"deprecatedRequestFunction" | "deprecatedFunction" | "deprecatedType" | "deprecatedWithoutReplacement" | "suggestReplaceFunction" | "suggestReplaceType", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
6
6
  'node-usable-as-tool': import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingUsableAsTool", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
7
- 'package-name-convention': import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidPackageName", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
8
- 'credential-test-required': import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingCredentialTest", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
9
- 'no-credential-reuse': import("@typescript-eslint/utils/ts-eslint").RuleModule<"credentialNotInPackage", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
10
- 'icon-validation': import("@typescript-eslint/utils/ts-eslint").RuleModule<"iconFileNotFound" | "iconNotSvg" | "lightDarkSame" | "invalidIconPath" | "missingIcon", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
7
+ 'package-name-convention': import("@typescript-eslint/utils/ts-eslint").RuleModule<"renameTo" | "invalidPackageName", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
8
+ 'credential-test-required': import("@typescript-eslint/utils/ts-eslint").RuleModule<"addTemplate" | "missingCredentialTest", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
9
+ 'no-credential-reuse': import("@typescript-eslint/utils/ts-eslint").RuleModule<"didYouMean" | "useAvailable" | "credentialNotInPackage", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
10
+ 'icon-validation': import("@typescript-eslint/utils/ts-eslint").RuleModule<"iconFileNotFound" | "iconNotSvg" | "lightDarkSame" | "invalidIconPath" | "missingIcon" | "addPlaceholder" | "addFileProtocol" | "changeExtension" | "similarIcon", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
11
11
  'resource-operation-pattern': import("@typescript-eslint/utils/ts-eslint").RuleModule<"tooManyOperationsWithoutResources", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
12
+ 'credential-documentation-url': import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidDocumentationUrl", [{
13
+ allowUrls?: boolean;
14
+ allowSlugs?: boolean;
15
+ }], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
12
16
  };
13
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,KAAK;;;;;;;;;;;CAWuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;CAYuB,CAAC"}
@@ -1,12 +1,13 @@
1
- import { NoRestrictedGlobalsRule } from './no-restricted-globals.js';
2
- import { NoRestrictedImportsRule } from './no-restricted-imports.js';
1
+ import { CredentialDocumentationUrlRule } from './credential-documentation-url.js';
3
2
  import { CredentialPasswordFieldRule } from './credential-password-field.js';
3
+ import { CredentialTestRequiredRule } from './credential-test-required.js';
4
+ import { IconValidationRule } from './icon-validation.js';
5
+ import { NoCredentialReuseRule } from './no-credential-reuse.js';
4
6
  import { NoDeprecatedWorkflowFunctionsRule } from './no-deprecated-workflow-functions.js';
7
+ import { NoRestrictedGlobalsRule } from './no-restricted-globals.js';
8
+ import { NoRestrictedImportsRule } from './no-restricted-imports.js';
5
9
  import { NodeUsableAsToolRule } from './node-usable-as-tool.js';
6
10
  import { PackageNameConventionRule } from './package-name-convention.js';
7
- import { CredentialTestRequiredRule } from './credential-test-required.js';
8
- import { NoCredentialReuseRule } from './no-credential-reuse.js';
9
- import { IconValidationRule } from './icon-validation.js';
10
11
  import { ResourceOperationPatternRule } from './resource-operation-pattern.js';
11
12
  export const rules = {
12
13
  'no-restricted-globals': NoRestrictedGlobalsRule,
@@ -19,5 +20,6 @@ export const rules = {
19
20
  'no-credential-reuse': NoCredentialReuseRule,
20
21
  'icon-validation': IconValidationRule,
21
22
  'resource-operation-pattern': ResourceOperationPatternRule,
23
+ 'credential-documentation-url': CredentialDocumentationUrlRule,
22
24
  };
23
25
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAC;AAC7E,OAAO,EAAE,iCAAiC,EAAE,MAAM,uCAAuC,CAAC;AAC1F,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,4BAA4B,EAAE,MAAM,iCAAiC,CAAC;AAE/E,MAAM,CAAC,MAAM,KAAK,GAAG;IACpB,uBAAuB,EAAE,uBAAuB;IAChD,uBAAuB,EAAE,uBAAuB;IAChD,2BAA2B,EAAE,2BAA2B;IACxD,kCAAkC,EAAE,iCAAiC;IACrE,qBAAqB,EAAE,oBAAoB;IAC3C,yBAAyB,EAAE,yBAAyB;IACpD,0BAA0B,EAAE,0BAA0B;IACtD,qBAAqB,EAAE,qBAAqB;IAC5C,iBAAiB,EAAE,kBAAkB;IACrC,4BAA4B,EAAE,4BAA4B;CAClB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,8BAA8B,EAAE,MAAM,mCAAmC,CAAC;AACnF,OAAO,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAC;AAC7E,OAAO,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,iCAAiC,EAAE,MAAM,uCAAuC,CAAC;AAC1F,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAAE,4BAA4B,EAAE,MAAM,iCAAiC,CAAC;AAE/E,MAAM,CAAC,MAAM,KAAK,GAAG;IACpB,uBAAuB,EAAE,uBAAuB;IAChD,uBAAuB,EAAE,uBAAuB;IAChD,2BAA2B,EAAE,2BAA2B;IACxD,kCAAkC,EAAE,iCAAiC;IACrE,qBAAqB,EAAE,oBAAoB;IAC3C,yBAAyB,EAAE,yBAAyB;IACpD,0BAA0B,EAAE,0BAA0B;IACtD,qBAAqB,EAAE,qBAAqB;IAC5C,iBAAiB,EAAE,kBAAkB;IACrC,4BAA4B,EAAE,4BAA4B;IAC1D,8BAA8B,EAAE,8BAA8B;CACtB,CAAC"}
@@ -1,3 +1,2 @@
1
- import { ESLintUtils } from '@typescript-eslint/utils';
2
- export declare const NoCredentialReuseRule: ESLintUtils.RuleModule<"credentialNotInPackage", [], unknown, ESLintUtils.RuleListener>;
1
+ export declare const NoCredentialReuseRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"didYouMean" | "useAvailable" | "credentialNotInPackage", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
3
2
  //# sourceMappingURL=no-credential-reuse.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"no-credential-reuse.d.ts","sourceRoot":"","sources":["../../src/rules/no-credential-reuse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAWvD,eAAO,MAAM,qBAAqB,yFAqEhC,CAAC"}
1
+ {"version":3,"file":"no-credential-reuse.d.ts","sourceRoot":"","sources":["../../src/rules/no-credential-reuse.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,qBAAqB,2LAyGhC,CAAC"}
@@ -1,15 +1,19 @@
1
- import { ESLintUtils } from '@typescript-eslint/utils';
2
- import { isNodeTypeClass, findClassProperty, findArrayLiteralProperty, extractCredentialNameFromArray, findPackageJson, readPackageJsonCredentials, isFileType, } from '../utils/index.js';
3
- export const NoCredentialReuseRule = ESLintUtils.RuleCreator.withoutDocs({
1
+ import { TSESTree } from '@typescript-eslint/types';
2
+ import { isNodeTypeClass, findClassProperty, findArrayLiteralProperty, extractCredentialNameFromArray, findPackageJson, readPackageJsonCredentials, isFileType, findSimilarStrings, createRule, } from '../utils/index.js';
3
+ export const NoCredentialReuseRule = createRule({
4
+ name: 'no-credential-reuse',
4
5
  meta: {
5
6
  type: 'problem',
6
7
  docs: {
7
8
  description: 'Prevent credential re-use security issues by ensuring nodes only reference credentials from the same package',
8
9
  },
9
10
  messages: {
11
+ didYouMean: "Did you mean '{{ suggestedName }}'?",
12
+ useAvailable: "Use available credential '{{ suggestedName }}'",
10
13
  credentialNotInPackage: 'SECURITY: Node references credential "{{ credentialName }}" which is not defined in this package. This creates a security risk as it attempts to reuse credentials from other packages. Nodes can only use credentials from the same package as listed in package.json n8n.credentials field.',
11
14
  },
12
15
  schema: [],
16
+ hasSuggestions: true,
13
17
  },
14
18
  defaultOptions: [],
15
19
  create(context) {
@@ -35,7 +39,8 @@ export const NoCredentialReuseRule = ESLintUtils.RuleCreator.withoutDocs({
35
39
  return;
36
40
  }
37
41
  const descriptionProperty = findClassProperty(node, 'description');
38
- if (!descriptionProperty?.value || descriptionProperty.value.type !== 'ObjectExpression') {
42
+ if (!descriptionProperty?.value ||
43
+ descriptionProperty.value.type !== TSESTree.AST_NODE_TYPES.ObjectExpression) {
39
44
  return;
40
45
  }
41
46
  const credentialsArray = findArrayLiteralProperty(descriptionProperty.value, 'credentials');
@@ -46,12 +51,36 @@ export const NoCredentialReuseRule = ESLintUtils.RuleCreator.withoutDocs({
46
51
  credentialsArray.elements.forEach((element) => {
47
52
  const credentialInfo = extractCredentialNameFromArray(element);
48
53
  if (credentialInfo && !allowedCredentials.has(credentialInfo.name)) {
54
+ const similarCredentials = findSimilarStrings(credentialInfo.name, allowedCredentials);
55
+ const suggestions = [];
56
+ for (const similarName of similarCredentials) {
57
+ suggestions.push({
58
+ messageId: 'didYouMean',
59
+ data: { suggestedName: similarName },
60
+ fix(fixer) {
61
+ return fixer.replaceText(credentialInfo.node, `"${similarName}"`);
62
+ },
63
+ });
64
+ }
65
+ if (suggestions.length === 0 && allowedCredentials.size > 0) {
66
+ const availableCredentials = Array.from(allowedCredentials).slice(0, 3);
67
+ for (const availableName of availableCredentials) {
68
+ suggestions.push({
69
+ messageId: 'useAvailable',
70
+ data: { suggestedName: availableName },
71
+ fix(fixer) {
72
+ return fixer.replaceText(credentialInfo.node, `"${availableName}"`);
73
+ },
74
+ });
75
+ }
76
+ }
49
77
  context.report({
50
78
  node: credentialInfo.node,
51
79
  messageId: 'credentialNotInPackage',
52
80
  data: {
53
81
  credentialName: credentialInfo.name,
54
82
  },
83
+ suggest: suggestions,
55
84
  });
56
85
  }
57
86
  });
@@ -1 +1 @@
1
- {"version":3,"file":"no-credential-reuse.js","sourceRoot":"","sources":["../../src/rules/no-credential-reuse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EACN,eAAe,EACf,iBAAiB,EACjB,wBAAwB,EACxB,8BAA8B,EAC9B,eAAe,EACf,0BAA0B,EAC1B,UAAU,GACV,MAAM,mBAAmB,CAAC;AAE3B,MAAM,CAAC,MAAM,qBAAqB,GAAG,WAAW,CAAC,WAAW,CAAC,WAAW,CAAC;IACxE,IAAI,EAAE;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACL,WAAW,EACV,8GAA8G;SAC/G;QACD,QAAQ,EAAE;YACT,sBAAsB,EACrB,+RAA+R;SAChS;QACD,MAAM,EAAE,EAAE;KACV;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACb,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,CAAC;YAC/C,OAAO,EAAE,CAAC;QACX,CAAC;QAED,IAAI,kBAAkB,GAAuB,IAAI,CAAC;QAElD,MAAM,sBAAsB,GAAG,GAAgB,EAAE;YAChD,IAAI,kBAAkB,KAAK,IAAI,EAAE,CAAC;gBACjC,OAAO,kBAAkB,CAAC;YAC3B,CAAC;YAED,MAAM,eAAe,GAAG,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAC1D,IAAI,CAAC,eAAe,EAAE,CAAC;gBACtB,kBAAkB,GAAG,IAAI,GAAG,EAAE,CAAC;gBAC/B,OAAO,kBAAkB,CAAC;YAC3B,CAAC;YAED,kBAAkB,GAAG,0BAA0B,CAAC,eAAe,CAAC,CAAC;YACjE,OAAO,kBAAkB,CAAC;QAC3B,CAAC,CAAC;QAEF,OAAO;YACN,gBAAgB,CAAC,IAAI;gBACpB,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC5B,OAAO;gBACR,CAAC;gBAED,MAAM,mBAAmB,GAAG,iBAAiB,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;gBACnE,IAAI,CAAC,mBAAmB,EAAE,KAAK,IAAI,mBAAmB,CAAC,KAAK,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;oBAC1F,OAAO;gBACR,CAAC;gBAED,MAAM,gBAAgB,GAAG,wBAAwB,CAAC,mBAAmB,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;gBAC5F,IAAI,CAAC,gBAAgB,EAAE,CAAC;oBACvB,OAAO;gBACR,CAAC;gBAED,MAAM,kBAAkB,GAAG,sBAAsB,EAAE,CAAC;gBAEpD,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;oBAC7C,MAAM,cAAc,GAAG,8BAA8B,CAAC,OAAO,CAAC,CAAC;oBAC/D,IAAI,cAAc,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;wBACpE,OAAO,CAAC,MAAM,CAAC;4BACd,IAAI,EAAE,cAAc,CAAC,IAAI;4BACzB,SAAS,EAAE,wBAAwB;4BACnC,IAAI,EAAE;gCACL,cAAc,EAAE,cAAc,CAAC,IAAI;6BACnC;yBACD,CAAC,CAAC;oBACJ,CAAC;gBACF,CAAC,CAAC,CAAC;YACJ,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC,CAAC"}
1
+ {"version":3,"file":"no-credential-reuse.js","sourceRoot":"","sources":["../../src/rules/no-credential-reuse.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,2 @@
1
- import { ESLintUtils } from '@typescript-eslint/utils';
2
- export declare const NoDeprecatedWorkflowFunctionsRule: ESLintUtils.RuleModule<"deprecatedRequestFunction" | "deprecatedFunction" | "deprecatedType" | "deprecatedWithoutReplacement", [], unknown, ESLintUtils.RuleListener>;
1
+ export declare const NoDeprecatedWorkflowFunctionsRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"deprecatedRequestFunction" | "deprecatedFunction" | "deprecatedType" | "deprecatedWithoutReplacement" | "suggestReplaceFunction" | "suggestReplaceType", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
3
2
  //# sourceMappingURL=no-deprecated-workflow-functions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"no-deprecated-workflow-functions.d.ts","sourceRoot":"","sources":["../../src/rules/no-deprecated-workflow-functions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAY,MAAM,0BAA0B,CAAC;AAuBjE,eAAO,MAAM,iCAAiC,uKA8G5C,CAAC"}
1
+ {"version":3,"file":"no-deprecated-workflow-functions.d.ts","sourceRoot":"","sources":["../../src/rules/no-deprecated-workflow-functions.ts"],"names":[],"mappings":"AA0BA,eAAO,MAAM,iCAAiC,2RA6I5C,CAAC"}
@@ -1,4 +1,5 @@
1
- import { ESLintUtils, TSESTree } from '@typescript-eslint/utils';
1
+ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
2
+ import { createRule } from '../utils/index.js';
2
3
  const DEPRECATED_FUNCTIONS = {
3
4
  request: 'httpRequest',
4
5
  requestWithAuthentication: 'httpRequestWithAuthentication',
@@ -16,7 +17,8 @@ function isDeprecatedFunctionName(name) {
16
17
  function isDeprecatedTypeName(name) {
17
18
  return name in DEPRECATED_TYPES;
18
19
  }
19
- export const NoDeprecatedWorkflowFunctionsRule = ESLintUtils.RuleCreator.withoutDocs({
20
+ export const NoDeprecatedWorkflowFunctionsRule = createRule({
21
+ name: 'no-deprecated-workflow-functions',
20
22
  meta: {
21
23
  type: 'problem',
22
24
  docs: {
@@ -27,8 +29,11 @@ export const NoDeprecatedWorkflowFunctionsRule = ESLintUtils.RuleCreator.without
27
29
  deprecatedFunction: "'{{ functionName }}' is deprecated and should be avoided. {{ message }}",
28
30
  deprecatedType: "'{{ typeName }}' is deprecated. Use '{{ replacement }}' instead.",
29
31
  deprecatedWithoutReplacement: "'{{ functionName }}' is deprecated and should be removed or replaced with alternative implementation.",
32
+ suggestReplaceFunction: "Replace '{{ functionName }}' with '{{ replacement }}'",
33
+ suggestReplaceType: "Replace '{{ typeName }}' with '{{ replacement }}'",
30
34
  },
31
35
  schema: [],
36
+ hasSuggestions: true,
32
37
  },
33
38
  defaultOptions: [],
34
39
  create(context) {
@@ -37,14 +42,16 @@ export const NoDeprecatedWorkflowFunctionsRule = ESLintUtils.RuleCreator.without
37
42
  ImportDeclaration(node) {
38
43
  if (node.source.value === 'n8n-workflow') {
39
44
  node.specifiers.forEach((specifier) => {
40
- if (specifier.type === 'ImportSpecifier' && specifier.imported.type === 'Identifier') {
45
+ if (specifier.type === AST_NODE_TYPES.ImportSpecifier &&
46
+ specifier.imported.type === AST_NODE_TYPES.Identifier) {
41
47
  n8nWorkflowTypes.add(specifier.local.name);
42
48
  }
43
49
  });
44
50
  }
45
51
  },
46
52
  MemberExpression(node) {
47
- if (node.property.type === 'Identifier' && isDeprecatedFunctionName(node.property.name)) {
53
+ if (node.property.type === AST_NODE_TYPES.Identifier &&
54
+ isDeprecatedFunctionName(node.property.name)) {
48
55
  if (!isThisHelpersAccess(node)) {
49
56
  return;
50
57
  }
@@ -62,6 +69,13 @@ export const NoDeprecatedWorkflowFunctionsRule = ESLintUtils.RuleCreator.without
62
69
  replacement,
63
70
  message: getDeprecationMessage(functionName),
64
71
  },
72
+ suggest: [
73
+ {
74
+ messageId: 'suggestReplaceFunction',
75
+ data: { functionName, replacement },
76
+ fix: (fixer) => fixer.replaceText(node.property, replacement),
77
+ },
78
+ ],
65
79
  });
66
80
  }
67
81
  else {
@@ -76,7 +90,7 @@ export const NoDeprecatedWorkflowFunctionsRule = ESLintUtils.RuleCreator.without
76
90
  }
77
91
  },
78
92
  TSTypeReference(node) {
79
- if (node.typeName.type === 'Identifier' &&
93
+ if (node.typeName.type === AST_NODE_TYPES.Identifier &&
80
94
  isDeprecatedTypeName(node.typeName.name) &&
81
95
  n8nWorkflowTypes.has(node.typeName.name)) {
82
96
  const typeName = node.typeName.name;
@@ -88,15 +102,22 @@ export const NoDeprecatedWorkflowFunctionsRule = ESLintUtils.RuleCreator.without
88
102
  typeName,
89
103
  replacement,
90
104
  },
105
+ suggest: [
106
+ {
107
+ messageId: 'suggestReplaceType',
108
+ data: { typeName, replacement },
109
+ fix: (fixer) => fixer.replaceText(node.typeName, replacement),
110
+ },
111
+ ],
91
112
  });
92
113
  }
93
114
  },
94
115
  ImportSpecifier(node) {
95
116
  // Check if this import is from n8n-workflow by looking at the parent ImportDeclaration
96
117
  const importDeclaration = node.parent;
97
- if (importDeclaration?.type === 'ImportDeclaration' &&
118
+ if (importDeclaration?.type === AST_NODE_TYPES.ImportDeclaration &&
98
119
  importDeclaration.source.value === 'n8n-workflow' &&
99
- node.imported.type === 'Identifier' &&
120
+ node.imported.type === AST_NODE_TYPES.Identifier &&
100
121
  isDeprecatedTypeName(node.imported.name)) {
101
122
  const typeName = node.imported.name;
102
123
  const replacement = DEPRECATED_TYPES[typeName];
@@ -107,6 +128,13 @@ export const NoDeprecatedWorkflowFunctionsRule = ESLintUtils.RuleCreator.without
107
128
  typeName,
108
129
  replacement,
109
130
  },
131
+ suggest: [
132
+ {
133
+ messageId: 'suggestReplaceType',
134
+ data: { typeName, replacement },
135
+ fix: (fixer) => fixer.replaceText(node.imported, replacement),
136
+ },
137
+ ],
110
138
  });
111
139
  }
112
140
  },
@@ -117,10 +145,10 @@ export const NoDeprecatedWorkflowFunctionsRule = ESLintUtils.RuleCreator.without
117
145
  * Check if the MemberExpression follows the this.helpers.* pattern
118
146
  */
119
147
  function isThisHelpersAccess(node) {
120
- if (node.object?.type === 'MemberExpression') {
148
+ if (node.object?.type === AST_NODE_TYPES.MemberExpression) {
121
149
  const outerObject = node.object;
122
- return (outerObject.object?.type === 'ThisExpression' &&
123
- outerObject.property?.type === 'Identifier' &&
150
+ return (outerObject.object?.type === AST_NODE_TYPES.ThisExpression &&
151
+ outerObject.property?.type === AST_NODE_TYPES.Identifier &&
124
152
  outerObject.property.name === 'helpers');
125
153
  }
126
154
  return false;