@n8n/eslint-plugin-community-nodes 0.21.0 → 0.23.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 (67) hide show
  1. package/.turbo/turbo-build$colon$unchecked.log +1 -1
  2. package/README.md +52 -46
  3. package/dist/plugin.d.ts +36 -0
  4. package/dist/plugin.d.ts.map +1 -1
  5. package/dist/plugin.js +12 -0
  6. package/dist/plugin.js.map +1 -1
  7. package/dist/rules/ai-node-package-json.d.ts.map +1 -1
  8. package/dist/rules/ai-node-package-json.js +4 -3
  9. package/dist/rules/ai-node-package-json.js.map +1 -1
  10. package/dist/rules/index.d.ts +6 -0
  11. package/dist/rules/index.d.ts.map +1 -1
  12. package/dist/rules/index.js +12 -0
  13. package/dist/rules/index.js.map +1 -1
  14. package/dist/rules/no-asterisk-in-option-names.d.ts +2 -0
  15. package/dist/rules/no-asterisk-in-option-names.d.ts.map +1 -0
  16. package/dist/rules/no-asterisk-in-option-names.js +90 -0
  17. package/dist/rules/no-asterisk-in-option-names.js.map +1 -0
  18. package/dist/rules/no-duplicate-param-options.d.ts +2 -0
  19. package/dist/rules/no-duplicate-param-options.d.ts.map +1 -0
  20. package/dist/rules/no-duplicate-param-options.js +97 -0
  21. package/dist/rules/no-duplicate-param-options.js.map +1 -0
  22. package/dist/rules/node-class-description-name-camelcase.d.ts +2 -0
  23. package/dist/rules/node-class-description-name-camelcase.d.ts.map +1 -0
  24. package/dist/rules/node-class-description-name-camelcase.js +92 -0
  25. package/dist/rules/node-class-description-name-camelcase.js.map +1 -0
  26. package/dist/rules/require-mit-license.d.ts +2 -0
  27. package/dist/rules/require-mit-license.d.ts.map +1 -0
  28. package/dist/rules/require-mit-license.js +57 -0
  29. package/dist/rules/require-mit-license.js.map +1 -0
  30. package/dist/rules/require-param-default.d.ts +15 -0
  31. package/dist/rules/require-param-default.d.ts.map +1 -0
  32. package/dist/rules/require-param-default.js +75 -0
  33. package/dist/rules/require-param-default.js.map +1 -0
  34. package/dist/rules/trigger-node-conventions.d.ts +2 -0
  35. package/dist/rules/trigger-node-conventions.d.ts.map +1 -0
  36. package/dist/rules/trigger-node-conventions.js +70 -0
  37. package/dist/rules/trigger-node-conventions.js.map +1 -0
  38. package/dist/rules/valid-peer-dependencies.d.ts.map +1 -1
  39. package/dist/rules/valid-peer-dependencies.js +5 -3
  40. package/dist/rules/valid-peer-dependencies.js.map +1 -1
  41. package/dist/typecheck.tsbuildinfo +1 -1
  42. package/docs/rules/no-asterisk-in-option-names.md +61 -0
  43. package/docs/rules/no-duplicate-param-options.md +46 -0
  44. package/docs/rules/node-class-description-name-camelcase.md +41 -0
  45. package/docs/rules/require-mit-license.md +38 -0
  46. package/docs/rules/require-param-default.md +60 -0
  47. package/docs/rules/trigger-node-conventions.md +49 -0
  48. package/docs/rules/valid-peer-dependencies.md +1 -1
  49. package/package.json +6 -5
  50. package/src/plugin.ts +12 -0
  51. package/src/rules/ai-node-package-json.test.ts +5 -0
  52. package/src/rules/ai-node-package-json.ts +4 -3
  53. package/src/rules/index.ts +12 -0
  54. package/src/rules/no-asterisk-in-option-names.test.ts +185 -0
  55. package/src/rules/no-asterisk-in-option-names.ts +111 -0
  56. package/src/rules/no-duplicate-param-options.test.ts +125 -0
  57. package/src/rules/no-duplicate-param-options.ts +125 -0
  58. package/src/rules/node-class-description-name-camelcase.test.ts +121 -0
  59. package/src/rules/node-class-description-name-camelcase.ts +114 -0
  60. package/src/rules/require-mit-license.test.ts +67 -0
  61. package/src/rules/require-mit-license.ts +65 -0
  62. package/src/rules/require-param-default.test.ts +227 -0
  63. package/src/rules/require-param-default.ts +89 -0
  64. package/src/rules/trigger-node-conventions.test.ts +110 -0
  65. package/src/rules/trigger-node-conventions.ts +92 -0
  66. package/src/rules/valid-peer-dependencies.test.ts +5 -0
  67. package/src/rules/valid-peer-dependencies.ts +5 -3
@@ -0,0 +1,92 @@
1
+ import { TSESTree } from '@typescript-eslint/utils';
2
+
3
+ import {
4
+ isNodeTypeClass,
5
+ findClassProperty,
6
+ findObjectProperty,
7
+ getStringLiteralValue,
8
+ isFileType,
9
+ createRule,
10
+ } from '../utils/index.js';
11
+
12
+ export const TriggerNodeConventionsRule = createRule({
13
+ name: 'trigger-node-conventions',
14
+ meta: {
15
+ type: 'problem',
16
+ docs: {
17
+ description:
18
+ 'Trigger nodes (class name ends with `Trigger`) must label themselves consistently as triggers',
19
+ },
20
+ messages: {
21
+ nameMissingSuffix: "Trigger node `description.name` '{{value}}' must end with 'Trigger'",
22
+ displayNameMissingTrigger:
23
+ "Trigger node `description.displayName` '{{value}}' must contain 'Trigger'",
24
+ inputsNotEmpty: 'Trigger node `description.inputs` must be an empty array `[]`',
25
+ },
26
+ schema: [],
27
+ },
28
+ defaultOptions: [],
29
+ create(context) {
30
+ if (!isFileType(context.filename, '.node.ts')) {
31
+ return {};
32
+ }
33
+
34
+ return {
35
+ ClassDeclaration(node) {
36
+ if (!isNodeTypeClass(node)) {
37
+ return;
38
+ }
39
+
40
+ if (!node.id?.name.endsWith('Trigger')) {
41
+ return;
42
+ }
43
+
44
+ const descriptionProperty = findClassProperty(node, 'description');
45
+ if (descriptionProperty?.value?.type !== TSESTree.AST_NODE_TYPES.ObjectExpression) {
46
+ return;
47
+ }
48
+ const description = descriptionProperty.value;
49
+
50
+ const displayNameProperty = findObjectProperty(description, 'displayName');
51
+ const displayNameValue = displayNameProperty
52
+ ? getStringLiteralValue(displayNameProperty.value)
53
+ : null;
54
+ if (
55
+ displayNameProperty &&
56
+ displayNameValue !== null &&
57
+ !displayNameValue.includes('Trigger')
58
+ ) {
59
+ context.report({
60
+ node: displayNameProperty.value,
61
+ messageId: 'displayNameMissingTrigger',
62
+ data: { value: displayNameValue },
63
+ });
64
+ }
65
+
66
+ const nameProperty = findObjectProperty(description, 'name');
67
+ const nameValue = nameProperty ? getStringLiteralValue(nameProperty.value) : null;
68
+ if (nameProperty && nameValue !== null && !nameValue.endsWith('Trigger')) {
69
+ context.report({
70
+ node: nameProperty.value,
71
+ messageId: 'nameMissingSuffix',
72
+ data: { value: nameValue },
73
+ });
74
+ }
75
+
76
+ const inputsProperty = findObjectProperty(description, 'inputs');
77
+ if (
78
+ inputsProperty &&
79
+ !(
80
+ inputsProperty.value.type === TSESTree.AST_NODE_TYPES.ArrayExpression &&
81
+ inputsProperty.value.elements.length === 0
82
+ )
83
+ ) {
84
+ context.report({
85
+ node: inputsProperty.value,
86
+ messageId: 'inputsNotEmpty',
87
+ });
88
+ }
89
+ },
90
+ };
91
+ },
92
+ });
@@ -11,6 +11,11 @@ ruleTester.run('valid-peer-dependencies', ValidPeerDependenciesRule, {
11
11
  filename: 'package.json',
12
12
  code: '{ "name": "n8n-nodes-example", "peerDependencies": { "n8n-workflow": "*" } }',
13
13
  },
14
+ {
15
+ name: 'n8n-workflow and scoped @n8n/ai-node-sdk',
16
+ filename: 'package.json',
17
+ code: '{ "name": "n8n-nodes-example", "peerDependencies": { "n8n-workflow": "*", "@n8n/ai-node-sdk": "*" } }',
18
+ },
14
19
  {
15
20
  name: 'n8n-workflow and ai-node-sdk',
16
21
  filename: 'package.json',
@@ -5,7 +5,9 @@ import { createRule, findJsonProperty } from '../utils/index.js';
5
5
 
6
6
  const REQUIRED_DEP = 'n8n-workflow';
7
7
  const REQUIRED_VERSION = '*';
8
- const ALLOWED_DEPS = new Set([REQUIRED_DEP, 'ai-node-sdk']);
8
+ // The published SDK is scoped (@n8n/ai-node-sdk); the unscoped name is kept for
9
+ // backwards compatibility, mirroring no-restricted-imports.
10
+ const ALLOWED_DEPS = new Set([REQUIRED_DEP, '@n8n/ai-node-sdk', 'ai-node-sdk']);
9
11
 
10
12
  export const ValidPeerDependenciesRule = createRule({
11
13
  name: 'valid-peer-dependencies',
@@ -13,7 +15,7 @@ export const ValidPeerDependenciesRule = createRule({
13
15
  type: 'problem',
14
16
  docs: {
15
17
  description:
16
- 'Require community node package.json peerDependencies to contain only "n8n-workflow": "*" (and optionally "ai-node-sdk")',
18
+ 'Require community node package.json peerDependencies to contain only "n8n-workflow": "*" (and optionally "@n8n/ai-node-sdk")',
17
19
  },
18
20
  fixable: 'code',
19
21
  messages: {
@@ -22,7 +24,7 @@ export const ValidPeerDependenciesRule = createRule({
22
24
  missingN8nWorkflow: `"peerDependencies" must include "${REQUIRED_DEP}": "${REQUIRED_VERSION}".`,
23
25
  pinnedN8nWorkflow: `"peerDependencies.${REQUIRED_DEP}" must be "${REQUIRED_VERSION}", got {{ value }}.`,
24
26
  forbiddenPeerDependency:
25
- '"{{ name }}" is not allowed in "peerDependencies". Only "n8n-workflow" and "ai-node-sdk" are permitted.',
27
+ '"{{ name }}" is not allowed in "peerDependencies". Only "n8n-workflow" and "@n8n/ai-node-sdk" are permitted.',
26
28
  },
27
29
  schema: [],
28
30
  },