@n8n/eslint-plugin-community-nodes 0.23.0 → 0.25.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 (108) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/README.md +39 -52
  3. package/dist/plugin.d.ts +0 -78
  4. package/dist/plugin.d.ts.map +1 -1
  5. package/dist/plugin.js +0 -26
  6. package/dist/plugin.js.map +1 -1
  7. package/dist/rules/index.d.ts +0 -13
  8. package/dist/rules/index.d.ts.map +1 -1
  9. package/dist/rules/index.js +0 -26
  10. package/dist/rules/index.js.map +1 -1
  11. package/dist/typecheck.tsbuildinfo +1 -1
  12. package/docs/rules/no-forbidden-lifecycle-scripts.md +1 -1
  13. package/package.json +4 -4
  14. package/src/plugin.ts +0 -26
  15. package/src/rules/index.ts +0 -26
  16. package/src/rules/no-forbidden-lifecycle-scripts.test.ts +2 -2
  17. package/.turbo/turbo-build$colon$unchecked.log +0 -4
  18. package/dist/rules/cred-class-name-field-conventions.d.ts +0 -2
  19. package/dist/rules/cred-class-name-field-conventions.d.ts.map +0 -1
  20. package/dist/rules/cred-class-name-field-conventions.js +0 -89
  21. package/dist/rules/cred-class-name-field-conventions.js.map +0 -1
  22. package/dist/rules/cred-class-name-suffix.d.ts +0 -2
  23. package/dist/rules/cred-class-name-suffix.d.ts.map +0 -1
  24. package/dist/rules/cred-class-name-suffix.js +0 -53
  25. package/dist/rules/cred-class-name-suffix.js.map +0 -1
  26. package/dist/rules/cred-filename-against-convention.d.ts +0 -2
  27. package/dist/rules/cred-filename-against-convention.d.ts.map +0 -1
  28. package/dist/rules/cred-filename-against-convention.js +0 -42
  29. package/dist/rules/cred-filename-against-convention.js.map +0 -1
  30. package/dist/rules/no-asterisk-in-option-names.d.ts +0 -2
  31. package/dist/rules/no-asterisk-in-option-names.d.ts.map +0 -1
  32. package/dist/rules/no-asterisk-in-option-names.js +0 -90
  33. package/dist/rules/no-asterisk-in-option-names.js.map +0 -1
  34. package/dist/rules/no-duplicate-param-options.d.ts +0 -2
  35. package/dist/rules/no-duplicate-param-options.d.ts.map +0 -1
  36. package/dist/rules/no-duplicate-param-options.js +0 -97
  37. package/dist/rules/no-duplicate-param-options.js.map +0 -1
  38. package/dist/rules/node-class-description-name-camelcase.d.ts +0 -2
  39. package/dist/rules/node-class-description-name-camelcase.d.ts.map +0 -1
  40. package/dist/rules/node-class-description-name-camelcase.js +0 -92
  41. package/dist/rules/node-class-description-name-camelcase.js.map +0 -1
  42. package/dist/rules/node-filename-against-convention.d.ts +0 -2
  43. package/dist/rules/node-filename-against-convention.d.ts.map +0 -1
  44. package/dist/rules/node-filename-against-convention.js +0 -61
  45. package/dist/rules/node-filename-against-convention.js.map +0 -1
  46. package/dist/rules/node-operation-error-itemindex.d.ts +0 -12
  47. package/dist/rules/node-operation-error-itemindex.d.ts.map +0 -1
  48. package/dist/rules/node-operation-error-itemindex.js +0 -184
  49. package/dist/rules/node-operation-error-itemindex.js.map +0 -1
  50. package/dist/rules/options-sorted-alphabetically.d.ts +0 -2
  51. package/dist/rules/options-sorted-alphabetically.d.ts.map +0 -1
  52. package/dist/rules/options-sorted-alphabetically.js +0 -95
  53. package/dist/rules/options-sorted-alphabetically.js.map +0 -1
  54. package/dist/rules/require-community-node-keyword.d.ts +0 -2
  55. package/dist/rules/require-community-node-keyword.d.ts.map +0 -1
  56. package/dist/rules/require-community-node-keyword.js +0 -65
  57. package/dist/rules/require-community-node-keyword.js.map +0 -1
  58. package/dist/rules/require-continue-on-fail.d.ts +0 -2
  59. package/dist/rules/require-continue-on-fail.d.ts.map +0 -1
  60. package/dist/rules/require-continue-on-fail.js +0 -76
  61. package/dist/rules/require-continue-on-fail.js.map +0 -1
  62. package/dist/rules/require-mit-license.d.ts +0 -2
  63. package/dist/rules/require-mit-license.d.ts.map +0 -1
  64. package/dist/rules/require-mit-license.js +0 -57
  65. package/dist/rules/require-mit-license.js.map +0 -1
  66. package/dist/rules/require-param-default.d.ts +0 -15
  67. package/dist/rules/require-param-default.d.ts.map +0 -1
  68. package/dist/rules/require-param-default.js +0 -75
  69. package/dist/rules/require-param-default.js.map +0 -1
  70. package/docs/rules/cred-class-name-field-conventions.md +0 -38
  71. package/docs/rules/cred-class-name-suffix.md +0 -46
  72. package/docs/rules/cred-filename-against-convention.md +0 -42
  73. package/docs/rules/no-asterisk-in-option-names.md +0 -61
  74. package/docs/rules/no-duplicate-param-options.md +0 -46
  75. package/docs/rules/node-class-description-name-camelcase.md +0 -41
  76. package/docs/rules/node-filename-against-convention.md +0 -50
  77. package/docs/rules/node-operation-error-itemindex.md +0 -81
  78. package/docs/rules/options-sorted-alphabetically.md +0 -63
  79. package/docs/rules/require-community-node-keyword.md +0 -45
  80. package/docs/rules/require-continue-on-fail.md +0 -56
  81. package/docs/rules/require-mit-license.md +0 -38
  82. package/docs/rules/require-param-default.md +0 -60
  83. package/src/rules/cred-class-name-field-conventions.test.ts +0 -121
  84. package/src/rules/cred-class-name-field-conventions.ts +0 -102
  85. package/src/rules/cred-class-name-suffix.test.ts +0 -74
  86. package/src/rules/cred-class-name-suffix.ts +0 -57
  87. package/src/rules/cred-filename-against-convention.test.ts +0 -72
  88. package/src/rules/cred-filename-against-convention.ts +0 -48
  89. package/src/rules/no-asterisk-in-option-names.test.ts +0 -185
  90. package/src/rules/no-asterisk-in-option-names.ts +0 -111
  91. package/src/rules/no-duplicate-param-options.test.ts +0 -125
  92. package/src/rules/no-duplicate-param-options.ts +0 -125
  93. package/src/rules/node-class-description-name-camelcase.test.ts +0 -121
  94. package/src/rules/node-class-description-name-camelcase.ts +0 -114
  95. package/src/rules/node-filename-against-convention.test.ts +0 -115
  96. package/src/rules/node-filename-against-convention.ts +0 -76
  97. package/src/rules/node-operation-error-itemindex.test.ts +0 -280
  98. package/src/rules/node-operation-error-itemindex.ts +0 -223
  99. package/src/rules/options-sorted-alphabetically.test.ts +0 -468
  100. package/src/rules/options-sorted-alphabetically.ts +0 -129
  101. package/src/rules/require-community-node-keyword.test.ts +0 -82
  102. package/src/rules/require-community-node-keyword.ts +0 -78
  103. package/src/rules/require-continue-on-fail.test.ts +0 -129
  104. package/src/rules/require-continue-on-fail.ts +0 -88
  105. package/src/rules/require-mit-license.test.ts +0 -67
  106. package/src/rules/require-mit-license.ts +0 -65
  107. package/src/rules/require-param-default.test.ts +0 -227
  108. package/src/rules/require-param-default.ts +0 -89
@@ -1,65 +0,0 @@
1
- import { AST_NODE_TYPES } from '@typescript-eslint/utils';
2
- import { createRule, findJsonProperty } from '../utils/index.js';
3
- const REQUIRED_KEYWORD = 'n8n-community-node-package';
4
- export const RequireCommunityNodeKeywordRule = createRule({
5
- name: 'require-community-node-keyword',
6
- meta: {
7
- type: 'problem',
8
- docs: {
9
- description: 'Require the "n8n-community-node-package" keyword in community node package.json',
10
- },
11
- fixable: 'code',
12
- messages: {
13
- missingKeyword: `The "keywords" array must include "${REQUIRED_KEYWORD}". This keyword is required for n8n to discover community node packages.`,
14
- missingKeywordsArray: `The package.json must have a "keywords" array containing "${REQUIRED_KEYWORD}".`,
15
- },
16
- schema: [],
17
- },
18
- defaultOptions: [],
19
- create(context) {
20
- if (!context.filename.endsWith('package.json')) {
21
- return {};
22
- }
23
- return {
24
- ObjectExpression(node) {
25
- if (node.parent?.type !== AST_NODE_TYPES.ExpressionStatement) {
26
- return;
27
- }
28
- const keywordsProp = findJsonProperty(node, 'keywords');
29
- if (!keywordsProp) {
30
- context.report({
31
- node,
32
- messageId: 'missingKeywordsArray',
33
- fix(fixer) {
34
- const lastProp = node.properties[node.properties.length - 1];
35
- if (!lastProp) {
36
- return fixer.replaceText(node, `{ "keywords": ["${REQUIRED_KEYWORD}"] }`);
37
- }
38
- return fixer.insertTextAfter(lastProp, `, "keywords": ["${REQUIRED_KEYWORD}"]`);
39
- },
40
- });
41
- return;
42
- }
43
- if (keywordsProp.value.type !== AST_NODE_TYPES.ArrayExpression) {
44
- return;
45
- }
46
- const keywordsArray = keywordsProp.value;
47
- const hasRequiredKeyword = keywordsArray.elements.some((element) => element?.type === AST_NODE_TYPES.Literal && element.value === REQUIRED_KEYWORD);
48
- if (!hasRequiredKeyword) {
49
- context.report({
50
- node: keywordsProp,
51
- messageId: 'missingKeyword',
52
- fix(fixer) {
53
- const lastElement = keywordsArray.elements[keywordsArray.elements.length - 1];
54
- if (!lastElement) {
55
- return fixer.replaceText(keywordsArray, `["${REQUIRED_KEYWORD}"]`);
56
- }
57
- return fixer.insertTextAfter(lastElement, `, "${REQUIRED_KEYWORD}"`);
58
- },
59
- });
60
- }
61
- },
62
- };
63
- },
64
- });
65
- //# sourceMappingURL=require-community-node-keyword.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"require-community-node-keyword.js","sourceRoot":"","sources":["../../src/rules/require-community-node-keyword.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAEjE,MAAM,gBAAgB,GAAG,4BAA4B,CAAC;AAEtD,MAAM,CAAC,MAAM,+BAA+B,GAAG,UAAU,CAAC;IACzD,IAAI,EAAE,gCAAgC;IACtC,IAAI,EAAE;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACL,WAAW,EACV,iFAAiF;SAClF;QACD,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE;YACT,cAAc,EAAE,sCAAsC,gBAAgB,0EAA0E;YAChJ,oBAAoB,EAAE,6DAA6D,gBAAgB,IAAI;SACvG;QACD,MAAM,EAAE,EAAE;KACV;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACb,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YAChD,OAAO,EAAE,CAAC;QACX,CAAC;QAED,OAAO;YACN,gBAAgB,CAAC,IAA+B;gBAC/C,IAAI,IAAI,CAAC,MAAM,EAAE,IAAI,KAAK,cAAc,CAAC,mBAAmB,EAAE,CAAC;oBAC9D,OAAO;gBACR,CAAC;gBAED,MAAM,YAAY,GAAG,gBAAgB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;gBAExD,IAAI,CAAC,YAAY,EAAE,CAAC;oBACnB,OAAO,CAAC,MAAM,CAAC;wBACd,IAAI;wBACJ,SAAS,EAAE,sBAAsB;wBACjC,GAAG,CAAC,KAAK;4BACR,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;4BAC7D,IAAI,CAAC,QAAQ,EAAE,CAAC;gCACf,OAAO,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,mBAAmB,gBAAgB,MAAM,CAAC,CAAC;4BAC3E,CAAC;4BACD,OAAO,KAAK,CAAC,eAAe,CAAC,QAAQ,EAAE,mBAAmB,gBAAgB,IAAI,CAAC,CAAC;wBACjF,CAAC;qBACD,CAAC,CAAC;oBACH,OAAO;gBACR,CAAC;gBAED,IAAI,YAAY,CAAC,KAAK,CAAC,IAAI,KAAK,cAAc,CAAC,eAAe,EAAE,CAAC;oBAChE,OAAO;gBACR,CAAC;gBAED,MAAM,aAAa,GAAG,YAAY,CAAC,KAAK,CAAC;gBACzC,MAAM,kBAAkB,GAAG,aAAa,CAAC,QAAQ,CAAC,IAAI,CACrD,CAAC,OAAO,EAAE,EAAE,CACX,OAAO,EAAE,IAAI,KAAK,cAAc,CAAC,OAAO,IAAI,OAAO,CAAC,KAAK,KAAK,gBAAgB,CAC/E,CAAC;gBAEF,IAAI,CAAC,kBAAkB,EAAE,CAAC;oBACzB,OAAO,CAAC,MAAM,CAAC;wBACd,IAAI,EAAE,YAAY;wBAClB,SAAS,EAAE,gBAAgB;wBAC3B,GAAG,CAAC,KAAK;4BACR,MAAM,WAAW,GAAG,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;4BAC9E,IAAI,CAAC,WAAW,EAAE,CAAC;gCAClB,OAAO,KAAK,CAAC,WAAW,CAAC,aAAa,EAAE,KAAK,gBAAgB,IAAI,CAAC,CAAC;4BACpE,CAAC;4BACD,OAAO,KAAK,CAAC,eAAe,CAAC,WAAW,EAAE,MAAM,gBAAgB,GAAG,CAAC,CAAC;wBACtE,CAAC;qBACD,CAAC,CAAC;gBACJ,CAAC;YACF,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC,CAAC"}
@@ -1,2 +0,0 @@
1
- export declare const RequireContinueOnFailRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingContinueOnFail", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
2
- //# sourceMappingURL=require-continue-on-fail.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"require-continue-on-fail.d.ts","sourceRoot":"","sources":["../../src/rules/require-continue-on-fail.ts"],"names":[],"mappings":"AA8CA,eAAO,MAAM,yBAAyB,0JAyCpC,CAAC"}
@@ -1,76 +0,0 @@
1
- import { AST_NODE_TYPES } from '@typescript-eslint/utils';
2
- import { isNodeTypeClass } from '../utils/index.js';
3
- import { createRule } from '../utils/rule-creator.js';
4
- /** Keys that are not child AST nodes (back-references, metadata). */
5
- const NON_CHILD_KEYS = new Set(['parent', 'loc', 'range', 'start', 'end', 'tokens', 'comments']);
6
- /**
7
- * Recursively checks whether any descendant of the given AST node is a
8
- * `this.continueOnFail()` call expression.
9
- */
10
- function containsContinueOnFailCall(node) {
11
- if (node.type === AST_NODE_TYPES.CallExpression &&
12
- node.callee.type === AST_NODE_TYPES.MemberExpression &&
13
- node.callee.object.type === AST_NODE_TYPES.ThisExpression &&
14
- node.callee.property.type === AST_NODE_TYPES.Identifier &&
15
- node.callee.property.name === 'continueOnFail') {
16
- return true;
17
- }
18
- for (const key of Object.keys(node)) {
19
- if (NON_CHILD_KEYS.has(key))
20
- continue;
21
- const value = node[key];
22
- if (Array.isArray(value)) {
23
- for (const child of value) {
24
- if (child && typeof child === 'object' && 'type' in child) {
25
- if (containsContinueOnFailCall(child)) {
26
- return true;
27
- }
28
- }
29
- }
30
- }
31
- else if (value && typeof value === 'object' && 'type' in value) {
32
- if (containsContinueOnFailCall(value)) {
33
- return true;
34
- }
35
- }
36
- }
37
- return false;
38
- }
39
- export const RequireContinueOnFailRule = createRule({
40
- name: 'require-continue-on-fail',
41
- meta: {
42
- type: 'problem',
43
- docs: {
44
- description: 'Require continueOnFail() handling in execute() methods of node classes',
45
- },
46
- messages: {
47
- missingContinueOnFail: 'execute() method must handle this.continueOnFail() for proper error handling. ' +
48
- 'Wrap item processing in a try/catch and check this.continueOnFail() in the catch block.',
49
- },
50
- schema: [],
51
- },
52
- defaultOptions: [],
53
- create(context) {
54
- return {
55
- ClassDeclaration(node) {
56
- if (!isNodeTypeClass(node)) {
57
- return;
58
- }
59
- for (const member of node.body.body) {
60
- if (member.type !== AST_NODE_TYPES.MethodDefinition ||
61
- member.key.type !== AST_NODE_TYPES.Identifier ||
62
- member.key.name !== 'execute') {
63
- continue;
64
- }
65
- if (member.value.body && !containsContinueOnFailCall(member.value.body)) {
66
- context.report({
67
- node: member.key,
68
- messageId: 'missingContinueOnFail',
69
- });
70
- }
71
- }
72
- },
73
- };
74
- },
75
- });
76
- //# sourceMappingURL=require-continue-on-fail.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"require-continue-on-fail.js","sourceRoot":"","sources":["../../src/rules/require-continue-on-fail.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export declare const RequireMitLicenseRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingLicense" | "wrongLicense", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
2
- //# sourceMappingURL=require-mit-license.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"require-mit-license.d.ts","sourceRoot":"","sources":["../../src/rules/require-mit-license.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,qBAAqB,oKAyDhC,CAAC"}
@@ -1,57 +0,0 @@
1
- import { AST_NODE_TYPES } from '@typescript-eslint/utils';
2
- import { createRule, findJsonProperty, getStringLiteralValue } from '../utils/index.js';
3
- const REQUIRED_LICENSE = 'MIT';
4
- export const RequireMitLicenseRule = createRule({
5
- name: 'require-mit-license',
6
- meta: {
7
- type: 'problem',
8
- docs: {
9
- description: 'Require the "license" field in community node package.json to be "MIT"',
10
- },
11
- fixable: 'code',
12
- messages: {
13
- missingLicense: `The package.json must have a "license" field set to "${REQUIRED_LICENSE}".`,
14
- wrongLicense: `The "license" field must be "${REQUIRED_LICENSE}".`,
15
- },
16
- schema: [],
17
- },
18
- defaultOptions: [],
19
- create(context) {
20
- if (!context.filename.endsWith('package.json')) {
21
- return {};
22
- }
23
- return {
24
- ObjectExpression(node) {
25
- if (node.parent?.type !== AST_NODE_TYPES.ExpressionStatement) {
26
- return;
27
- }
28
- const licenseProp = findJsonProperty(node, 'license');
29
- if (!licenseProp) {
30
- context.report({
31
- node,
32
- messageId: 'missingLicense',
33
- fix(fixer) {
34
- const lastProp = node.properties[node.properties.length - 1];
35
- if (!lastProp) {
36
- return fixer.replaceText(node, `{ "license": "${REQUIRED_LICENSE}" }`);
37
- }
38
- return fixer.insertTextAfter(lastProp, `, "license": "${REQUIRED_LICENSE}"`);
39
- },
40
- });
41
- return;
42
- }
43
- if (getStringLiteralValue(licenseProp.value) === REQUIRED_LICENSE) {
44
- return;
45
- }
46
- context.report({
47
- node: licenseProp.value,
48
- messageId: 'wrongLicense',
49
- fix(fixer) {
50
- return fixer.replaceText(licenseProp.value, `"${REQUIRED_LICENSE}"`);
51
- },
52
- });
53
- },
54
- };
55
- },
56
- });
57
- //# sourceMappingURL=require-mit-license.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"require-mit-license.js","sourceRoot":"","sources":["../../src/rules/require-mit-license.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAExF,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAE/B,MAAM,CAAC,MAAM,qBAAqB,GAAG,UAAU,CAAC;IAC/C,IAAI,EAAE,qBAAqB;IAC3B,IAAI,EAAE;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACL,WAAW,EAAE,wEAAwE;SACrF;QACD,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE;YACT,cAAc,EAAE,wDAAwD,gBAAgB,IAAI;YAC5F,YAAY,EAAE,gCAAgC,gBAAgB,IAAI;SAClE;QACD,MAAM,EAAE,EAAE;KACV;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACb,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YAChD,OAAO,EAAE,CAAC;QACX,CAAC;QAED,OAAO;YACN,gBAAgB,CAAC,IAA+B;gBAC/C,IAAI,IAAI,CAAC,MAAM,EAAE,IAAI,KAAK,cAAc,CAAC,mBAAmB,EAAE,CAAC;oBAC9D,OAAO;gBACR,CAAC;gBAED,MAAM,WAAW,GAAG,gBAAgB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;gBAEtD,IAAI,CAAC,WAAW,EAAE,CAAC;oBAClB,OAAO,CAAC,MAAM,CAAC;wBACd,IAAI;wBACJ,SAAS,EAAE,gBAAgB;wBAC3B,GAAG,CAAC,KAAK;4BACR,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;4BAC7D,IAAI,CAAC,QAAQ,EAAE,CAAC;gCACf,OAAO,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,iBAAiB,gBAAgB,KAAK,CAAC,CAAC;4BACxE,CAAC;4BACD,OAAO,KAAK,CAAC,eAAe,CAAC,QAAQ,EAAE,iBAAiB,gBAAgB,GAAG,CAAC,CAAC;wBAC9E,CAAC;qBACD,CAAC,CAAC;oBACH,OAAO;gBACR,CAAC;gBAED,IAAI,qBAAqB,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,gBAAgB,EAAE,CAAC;oBACnE,OAAO;gBACR,CAAC;gBAED,OAAO,CAAC,MAAM,CAAC;oBACd,IAAI,EAAE,WAAW,CAAC,KAAK;oBACvB,SAAS,EAAE,cAAc;oBACzB,GAAG,CAAC,KAAK;wBACR,OAAO,KAAK,CAAC,WAAW,CAAC,WAAW,CAAC,KAAK,EAAE,IAAI,gBAAgB,GAAG,CAAC,CAAC;oBACtE,CAAC;iBACD,CAAC,CAAC;YACJ,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC,CAAC"}
@@ -1,15 +0,0 @@
1
- /**
2
- * Requires every node parameter to declare a `default` property.
3
- *
4
- * A parameter is detected structurally: an object literal inside a node's
5
- * `description` with `displayName`, `name`, and `type` all set to string
6
- * literals — the shape every `INodeProperties` entry has. This avoids
7
- * hardcoding the `NodePropertyTypes` union (which would silently go stale as
8
- * new types are added) and naturally excludes `options`-array entries, which
9
- * carry `name`/`value` but no `displayName`/`type`.
10
- *
11
- * Without a `default`, n8n cannot reliably initialise the parameter's value,
12
- * which leads to inconsistent runtime behaviour in the editor and on execution.
13
- */
14
- export declare const RequireParamDefaultRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingDefault", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
15
- //# sourceMappingURL=require-param-default.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"require-param-default.d.ts","sourceRoot":"","sources":["../../src/rules/require-param-default.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AA0BH,eAAO,MAAM,uBAAuB,mJAkDlC,CAAC"}
@@ -1,75 +0,0 @@
1
- /**
2
- * Requires every node parameter to declare a `default` property.
3
- *
4
- * A parameter is detected structurally: an object literal inside a node's
5
- * `description` with `displayName`, `name`, and `type` all set to string
6
- * literals — the shape every `INodeProperties` entry has. This avoids
7
- * hardcoding the `NodePropertyTypes` union (which would silently go stale as
8
- * new types are added) and naturally excludes `options`-array entries, which
9
- * carry `name`/`value` but no `displayName`/`type`.
10
- *
11
- * Without a `default`, n8n cannot reliably initialise the parameter's value,
12
- * which leads to inconsistent runtime behaviour in the editor and on execution.
13
- */
14
- import { simpleTraverse } from '@typescript-eslint/typescript-estree';
15
- import { AST_NODE_TYPES } from '@typescript-eslint/utils';
16
- import { createRule, findClassProperty, findObjectProperty, getStringLiteralValue, isFileType, isNodeTypeClass, } from '../utils/index.js';
17
- /** Property keys an `INodeProperties` parameter always carries as string literals. */
18
- const REQUIRED_PARAM_KEYS = ['displayName', 'name', 'type'];
19
- /** Returns true when the object literal has the shape of a node parameter. */
20
- function isNodeParameter(node) {
21
- return REQUIRED_PARAM_KEYS.every((key) => {
22
- const property = findObjectProperty(node, key);
23
- return property !== null && getStringLiteralValue(property.value) !== null;
24
- });
25
- }
26
- export const RequireParamDefaultRule = createRule({
27
- name: 'require-param-default',
28
- meta: {
29
- type: 'problem',
30
- docs: {
31
- description: 'Require every node parameter to declare a default value.',
32
- },
33
- messages: {
34
- missingDefault: "Node parameter '{{ name }}' is missing a `default` value. Add a `default` property so the parameter initialises consistently.",
35
- },
36
- schema: [],
37
- },
38
- defaultOptions: [],
39
- create(context) {
40
- if (!isFileType(context.filename, '.node.ts')) {
41
- return {};
42
- }
43
- const reportIfMissingDefault = (node) => {
44
- if (!isNodeParameter(node) || findObjectProperty(node, 'default') !== null) {
45
- return;
46
- }
47
- const nameProperty = findObjectProperty(node, 'name');
48
- context.report({
49
- node,
50
- messageId: 'missingDefault',
51
- data: { name: getStringLiteralValue(nameProperty?.value ?? null) ?? '' },
52
- });
53
- };
54
- return {
55
- // Scope to an INodeType class's `description`, then walk only that
56
- // subtree, so helper classes and object literals elsewhere in the file
57
- // (e.g. in method bodies) that share the parameter shape are ignored.
58
- ClassDeclaration(node) {
59
- if (!isNodeTypeClass(node))
60
- return;
61
- const description = findClassProperty(node, 'description');
62
- if (description?.value?.type !== AST_NODE_TYPES.ObjectExpression)
63
- return;
64
- simpleTraverse(description.value, {
65
- enter(child) {
66
- if (child.type === AST_NODE_TYPES.ObjectExpression) {
67
- reportIfMissingDefault(child);
68
- }
69
- },
70
- });
71
- },
72
- };
73
- },
74
- });
75
- //# sourceMappingURL=require-param-default.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"require-param-default.js","sourceRoot":"","sources":["../../src/rules/require-param-default.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAEtE,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EACN,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EACrB,UAAU,EACV,eAAe,GACf,MAAM,mBAAmB,CAAC;AAE3B,sFAAsF;AACtF,MAAM,mBAAmB,GAAG,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,CAAU,CAAC;AAErE,8EAA8E;AAC9E,SAAS,eAAe,CAAC,IAA+B;IACvD,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACxC,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC/C,OAAO,QAAQ,KAAK,IAAI,IAAI,qBAAqB,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;IAC5E,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,uBAAuB,GAAG,UAAU,CAAC;IACjD,IAAI,EAAE,uBAAuB;IAC7B,IAAI,EAAE;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACL,WAAW,EAAE,0DAA0D;SACvE;QACD,QAAQ,EAAE;YACT,cAAc,EACb,+HAA+H;SAChI;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,MAAM,sBAAsB,GAAG,CAAC,IAA+B,EAAQ,EAAE;YACxE,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,kBAAkB,CAAC,IAAI,EAAE,SAAS,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC5E,OAAO;YACR,CAAC;YACD,MAAM,YAAY,GAAG,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACtD,OAAO,CAAC,MAAM,CAAC;gBACd,IAAI;gBACJ,SAAS,EAAE,gBAAgB;gBAC3B,IAAI,EAAE,EAAE,IAAI,EAAE,qBAAqB,CAAC,YAAY,EAAE,KAAK,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE;aACxE,CAAC,CAAC;QACJ,CAAC,CAAC;QAEF,OAAO;YACN,mEAAmE;YACnE,uEAAuE;YACvE,sEAAsE;YACtE,gBAAgB,CAAC,IAAI;gBACpB,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;oBAAE,OAAO;gBACnC,MAAM,WAAW,GAAG,iBAAiB,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;gBAC3D,IAAI,WAAW,EAAE,KAAK,EAAE,IAAI,KAAK,cAAc,CAAC,gBAAgB;oBAAE,OAAO;gBAEzE,cAAc,CAAC,WAAW,CAAC,KAAK,EAAE;oBACjC,KAAK,CAAC,KAAK;wBACV,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,CAAC,gBAAgB,EAAE,CAAC;4BACpD,sBAAsB,CAAC,KAAK,CAAC,CAAC;wBAC/B,CAAC;oBACF,CAAC;iBACD,CAAC,CAAC;YACJ,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC,CAAC"}
@@ -1,38 +0,0 @@
1
- # Credential `name` field must end with `Api` and start with a lowercase letter (`@n8n/community-nodes/cred-class-name-field-conventions`)
2
-
3
- 💼 This rule is enabled in the following configs: ✅ `recommended`, ☑️ `recommendedWithoutN8nCloudSupport`.
4
-
5
- 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
6
-
7
- <!-- end auto-generated rule header -->
8
-
9
- ## Rule Details
10
-
11
- The `name` field of a credential class (those implementing `ICredentialType` in `*.credentials.ts` files) is the internal identifier referenced by nodes and stored in the credential registry. n8n convention requires this identifier to:
12
-
13
- - End with `Api` (e.g. `githubApi`), so credentials are easily recognisable across the codebase.
14
- - Start with a lowercase letter (camelCase), since it is an identifier value rather than a class name.
15
-
16
- Both checks are automatically fixable.
17
-
18
- ## Examples
19
-
20
- ### ❌ Incorrect
21
-
22
- ```typescript
23
- export class GithubApi implements ICredentialType {
24
- name = 'Github';
25
- displayName = 'GitHub API';
26
- properties: INodeProperties[] = [];
27
- }
28
- ```
29
-
30
- ### ✅ Correct
31
-
32
- ```typescript
33
- export class GithubApi implements ICredentialType {
34
- name = 'githubApi';
35
- displayName = 'GitHub API';
36
- properties: INodeProperties[] = [];
37
- }
38
- ```
@@ -1,46 +0,0 @@
1
- # Credential class names must be suffixed with `Api` (`@n8n/community-nodes/cred-class-name-suffix`)
2
-
3
- 💼 This rule is enabled in the following configs: ✅ `recommended`, ☑️ `recommendedWithoutN8nCloudSupport`.
4
-
5
- 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
6
-
7
- <!-- end auto-generated rule header -->
8
-
9
- ## Rule Details
10
-
11
- Credential classes (those implementing `ICredentialType` in `*.credentials.ts` files) must have a class name ending in `Api`. This is the n8n convention so credentials are easily recognisable in code, in import statements, and across the credential registry.
12
-
13
- For OAuth2 credentials extending the OAuth2 base, see the sibling rule `cred-class-oauth2-naming` which enforces the more specific `OAuth2Api` suffix.
14
-
15
- ## Opt-out
16
-
17
- For legitimate exceptions (for example credentials representing custom auth headers where the `Api` suffix would be misleading), disable the rule for the specific class with a standard ESLint comment:
18
-
19
- ```typescript
20
- // eslint-disable-next-line @n8n/community-nodes/cred-class-name-suffix
21
- export class CustomAuthHeader implements ICredentialType {
22
- // ...
23
- }
24
- ```
25
-
26
- ## Examples
27
-
28
- ### ❌ Incorrect
29
-
30
- ```typescript
31
- export class MyService implements ICredentialType {
32
- name = 'myServiceApi';
33
- displayName = 'My Service API';
34
- properties: INodeProperties[] = [];
35
- }
36
- ```
37
-
38
- ### ✅ Correct
39
-
40
- ```typescript
41
- export class MyServiceApi implements ICredentialType {
42
- name = 'myServiceApi';
43
- displayName = 'My Service API';
44
- properties: INodeProperties[] = [];
45
- }
46
- ```
@@ -1,42 +0,0 @@
1
- # Credential filename must match the credential class name (`@n8n/community-nodes/cred-filename-against-convention`)
2
-
3
- 💼 This rule is enabled in the following configs: ✅ `recommended`, ☑️ `recommendedWithoutN8nCloudSupport`.
4
-
5
- <!-- end auto-generated rule header -->
6
-
7
- ## Rule Details
8
-
9
- This rule enforces that the basename of a `*.credentials.ts` file (without the
10
- `.credentials.ts` extension) matches the name of the credential class it
11
- contains. The class name is the source of truth.
12
-
13
- Keeping filenames in sync with class names makes credentials predictable to
14
- locate and matches the convention used throughout n8n's built-in credentials.
15
-
16
- ## Examples
17
-
18
- ### Incorrect
19
-
20
- ```typescript
21
- // File: GithubApi.credentials.ts
22
- import type { ICredentialType, INodeProperties } from 'n8n-workflow';
23
-
24
- export class GitlabApi implements ICredentialType {
25
- name = 'gitlabApi';
26
- displayName = 'GitLab API';
27
- properties: INodeProperties[] = [];
28
- }
29
- ```
30
-
31
- ### Correct
32
-
33
- ```typescript
34
- // File: GithubApi.credentials.ts
35
- import type { ICredentialType, INodeProperties } from 'n8n-workflow';
36
-
37
- export class GithubApi implements ICredentialType {
38
- name = 'githubApi';
39
- displayName = 'GitHub API';
40
- properties: INodeProperties[] = [];
41
- }
42
- ```
@@ -1,61 +0,0 @@
1
- # Disallow asterisk characters in node option name values (`@n8n/community-nodes/no-asterisk-in-option-names`)
2
-
3
- ⚠️ This rule _warns_ in the following configs: ✅ `recommended`, ☑️ `recommendedWithoutN8nCloudSupport`.
4
-
5
- 💡 This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
6
-
7
- <!-- end auto-generated rule header -->
8
-
9
- ## Rule Details
10
-
11
- The `name` of each entry in an `options` array is rendered directly in the n8n
12
- editor. An asterisk (`*`) in these labels renders ambiguously — it reads like a
13
- markdown bullet or emphasis marker rather than literal text. This rule flags any
14
- option `name` containing `*` and suggests replacing it with bracketed notation
15
- such as `[All]`.
16
-
17
- The rule only inspects `name` values inside `options` arrays (including nested
18
- `collection` and `fixedCollection` options); asterisks elsewhere are not
19
- reported.
20
-
21
- ## Examples
22
-
23
- ### Incorrect
24
-
25
- ```typescript
26
- export class MyNode implements INodeType {
27
- description: INodeTypeDescription = {
28
- displayName: 'My Node',
29
- name: 'myNode',
30
- properties: [
31
- {
32
- displayName: 'Resource',
33
- name: 'resource',
34
- type: 'options',
35
- options: [{ name: '* All', value: 'all' }],
36
- default: 'all',
37
- },
38
- ],
39
- };
40
- }
41
- ```
42
-
43
- ### Correct
44
-
45
- ```typescript
46
- export class MyNode implements INodeType {
47
- description: INodeTypeDescription = {
48
- displayName: 'My Node',
49
- name: 'myNode',
50
- properties: [
51
- {
52
- displayName: 'Resource',
53
- name: 'resource',
54
- type: 'options',
55
- options: [{ name: '[All]', value: 'all' }],
56
- default: 'all',
57
- },
58
- ],
59
- };
60
- }
61
- ```
@@ -1,46 +0,0 @@
1
- # Disallow duplicate option names or values within a single node parameter (`@n8n/community-nodes/no-duplicate-param-options`)
2
-
3
- ⚠️ This rule _warns_ in the following configs: ✅ `recommended`, ☑️ `recommendedWithoutN8nCloudSupport`.
4
-
5
- <!-- end auto-generated rule header -->
6
-
7
- ## Rule Details
8
-
9
- Within an `options`- or `multiOptions`-typed node parameter, each option must
10
- have a unique `name` and a unique `value`. Duplicate names confuse users in the
11
- dropdown, and duplicate values make selections ambiguous and break value-based
12
- logic downstream.
13
-
14
- ## Examples
15
-
16
- ### Incorrect
17
-
18
- ```typescript
19
- {
20
- displayName: 'Resource',
21
- name: 'resource',
22
- type: 'options',
23
- options: [
24
- { name: 'Contact', value: 'contact' },
25
- { name: 'Contact', value: 'person' }, // duplicate name
26
- { name: 'User', value: 'contact' }, // duplicate value
27
- ],
28
- default: 'contact',
29
- }
30
- ```
31
-
32
- ### Correct
33
-
34
- ```typescript
35
- {
36
- displayName: 'Resource',
37
- name: 'resource',
38
- type: 'options',
39
- options: [
40
- { name: 'Contact', value: 'contact' },
41
- { name: 'Person', value: 'person' },
42
- { name: 'User', value: 'user' },
43
- ],
44
- default: 'contact',
45
- }
46
- ```
@@ -1,41 +0,0 @@
1
- # Node class `description.name` must be camelCase (`@n8n/community-nodes/node-class-description-name-camelcase`)
2
-
3
- 💼 This rule is enabled in the following configs: ✅ `recommended`, ☑️ `recommendedWithoutN8nCloudSupport`.
4
-
5
- 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
6
-
7
- <!-- end auto-generated rule header -->
8
-
9
- ## Rule Details
10
-
11
- The `name` field inside a node class `description` (those implementing `INodeType` or extending `Node` in `*.node.ts` files) is the internal identifier used to register and reference the node. n8n convention requires this identifier to be camelCase: it must start with a lowercase letter and contain only letters and digits, with no spaces, hyphens, underscores, or other separators.
12
-
13
- The value must match `^[a-z][a-zA-Z0-9]*$`.
14
-
15
- The rule is automatically fixable: separators are removed, each subsequent word is upper-cased, and the first character is lower-cased (e.g. `My Node` → `myNode`). Names that cannot be repaired into a valid identifier (for example, those starting with a digit) are reported without an autofix.
16
-
17
- ## Examples
18
-
19
- ### ❌ Incorrect
20
-
21
- ```typescript
22
- export class MyNode implements INodeType {
23
- description: INodeTypeDescription = {
24
- displayName: 'My Node',
25
- name: 'My Node',
26
- // ...
27
- };
28
- }
29
- ```
30
-
31
- ### ✅ Correct
32
-
33
- ```typescript
34
- export class MyNode implements INodeType {
35
- description: INodeTypeDescription = {
36
- displayName: 'My Node',
37
- name: 'myNode',
38
- // ...
39
- };
40
- }
41
- ```