@n8n/eslint-plugin-community-nodes 0.2.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 (92) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/LICENSE.md +88 -0
  3. package/LICENSE_EE.md +27 -0
  4. package/dist/plugin.d.ts +61 -0
  5. package/dist/plugin.d.ts.map +1 -0
  6. package/dist/plugin.js +51 -0
  7. package/dist/plugin.js.map +1 -0
  8. package/dist/rules/credential-password-field.d.ts +3 -0
  9. package/dist/rules/credential-password-field.d.ts.map +1 -0
  10. package/dist/rules/credential-password-field.js +97 -0
  11. package/dist/rules/credential-password-field.js.map +1 -0
  12. package/dist/rules/credential-test-required.d.ts +3 -0
  13. package/dist/rules/credential-test-required.d.ts.map +1 -0
  14. package/dist/rules/credential-test-required.js +79 -0
  15. package/dist/rules/credential-test-required.js.map +1 -0
  16. package/dist/rules/icon-validation.d.ts +3 -0
  17. package/dist/rules/icon-validation.d.ts.map +1 -0
  18. package/dist/rules/icon-validation.js +131 -0
  19. package/dist/rules/icon-validation.js.map +1 -0
  20. package/dist/rules/index.d.ts +13 -0
  21. package/dist/rules/index.d.ts.map +1 -0
  22. package/dist/rules/index.js +23 -0
  23. package/dist/rules/index.js.map +1 -0
  24. package/dist/rules/no-credential-reuse.d.ts +3 -0
  25. package/dist/rules/no-credential-reuse.d.ts.map +1 -0
  26. package/dist/rules/no-credential-reuse.js +62 -0
  27. package/dist/rules/no-credential-reuse.js.map +1 -0
  28. package/dist/rules/no-deprecated-workflow-functions.d.ts +3 -0
  29. package/dist/rules/no-deprecated-workflow-functions.d.ts.map +1 -0
  30. package/dist/rules/no-deprecated-workflow-functions.js +144 -0
  31. package/dist/rules/no-deprecated-workflow-functions.js.map +1 -0
  32. package/dist/rules/no-restricted-globals.d.ts +3 -0
  33. package/dist/rules/no-restricted-globals.d.ts.map +1 -0
  34. package/dist/rules/no-restricted-globals.js +58 -0
  35. package/dist/rules/no-restricted-globals.js.map +1 -0
  36. package/dist/rules/no-restricted-imports.d.ts +3 -0
  37. package/dist/rules/no-restricted-imports.d.ts.map +1 -0
  38. package/dist/rules/no-restricted-imports.js +80 -0
  39. package/dist/rules/no-restricted-imports.js.map +1 -0
  40. package/dist/rules/node-usable-as-tool.d.ts +3 -0
  41. package/dist/rules/node-usable-as-tool.d.ts.map +1 -0
  42. package/dist/rules/node-usable-as-tool.js +57 -0
  43. package/dist/rules/node-usable-as-tool.js.map +1 -0
  44. package/dist/rules/package-name-convention.d.ts +3 -0
  45. package/dist/rules/package-name-convention.d.ts.map +1 -0
  46. package/dist/rules/package-name-convention.js +52 -0
  47. package/dist/rules/package-name-convention.js.map +1 -0
  48. package/dist/rules/resource-operation-pattern.d.ts +3 -0
  49. package/dist/rules/resource-operation-pattern.d.ts.map +1 -0
  50. package/dist/rules/resource-operation-pattern.js +77 -0
  51. package/dist/rules/resource-operation-pattern.js.map +1 -0
  52. package/dist/utils/ast-utils.d.ts +25 -0
  53. package/dist/utils/ast-utils.d.ts.map +1 -0
  54. package/dist/utils/ast-utils.js +117 -0
  55. package/dist/utils/ast-utils.js.map +1 -0
  56. package/dist/utils/file-utils.d.ts +12 -0
  57. package/dist/utils/file-utils.d.ts.map +1 -0
  58. package/dist/utils/file-utils.js +154 -0
  59. package/dist/utils/file-utils.js.map +1 -0
  60. package/dist/utils/index.d.ts +3 -0
  61. package/dist/utils/index.d.ts.map +1 -0
  62. package/dist/utils/index.js +3 -0
  63. package/dist/utils/index.js.map +1 -0
  64. package/package.json +46 -0
  65. package/src/plugin.ts +55 -0
  66. package/src/rules/credential-password-field.test.ts +231 -0
  67. package/src/rules/credential-password-field.ts +123 -0
  68. package/src/rules/credential-test-required.test.ts +147 -0
  69. package/src/rules/credential-test-required.ts +99 -0
  70. package/src/rules/icon-validation.test.ts +196 -0
  71. package/src/rules/icon-validation.ts +158 -0
  72. package/src/rules/index.ts +24 -0
  73. package/src/rules/no-credential-reuse.test.ts +226 -0
  74. package/src/rules/no-credential-reuse.ts +81 -0
  75. package/src/rules/no-deprecated-workflow-functions.test.ts +117 -0
  76. package/src/rules/no-deprecated-workflow-functions.ts +166 -0
  77. package/src/rules/no-restricted-globals.test.ts +135 -0
  78. package/src/rules/no-restricted-globals.ts +71 -0
  79. package/src/rules/no-restricted-imports.test.ts +181 -0
  80. package/src/rules/no-restricted-imports.ts +86 -0
  81. package/src/rules/node-usable-as-tool.test.ts +80 -0
  82. package/src/rules/node-usable-as-tool.ts +70 -0
  83. package/src/rules/package-name-convention.test.ts +112 -0
  84. package/src/rules/package-name-convention.ts +63 -0
  85. package/src/rules/resource-operation-pattern.test.ts +216 -0
  86. package/src/rules/resource-operation-pattern.ts +97 -0
  87. package/src/utils/ast-utils.ts +179 -0
  88. package/src/utils/file-utils.ts +204 -0
  89. package/src/utils/index.ts +2 -0
  90. package/tsconfig.json +11 -0
  91. package/tsconfig.tsbuildinfo +1 -0
  92. package/vite.config.ts +4 -0
@@ -0,0 +1,23 @@
1
+ import { NoRestrictedGlobalsRule } from './no-restricted-globals.js';
2
+ import { NoRestrictedImportsRule } from './no-restricted-imports.js';
3
+ import { CredentialPasswordFieldRule } from './credential-password-field.js';
4
+ import { NoDeprecatedWorkflowFunctionsRule } from './no-deprecated-workflow-functions.js';
5
+ import { NodeUsableAsToolRule } from './node-usable-as-tool.js';
6
+ 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
+ import { ResourceOperationPatternRule } from './resource-operation-pattern.js';
11
+ export const rules = {
12
+ 'no-restricted-globals': NoRestrictedGlobalsRule,
13
+ 'no-restricted-imports': NoRestrictedImportsRule,
14
+ 'credential-password-field': CredentialPasswordFieldRule,
15
+ 'no-deprecated-workflow-functions': NoDeprecatedWorkflowFunctionsRule,
16
+ 'node-usable-as-tool': NodeUsableAsToolRule,
17
+ 'package-name-convention': PackageNameConventionRule,
18
+ 'credential-test-required': CredentialTestRequiredRule,
19
+ 'no-credential-reuse': NoCredentialReuseRule,
20
+ 'icon-validation': IconValidationRule,
21
+ 'resource-operation-pattern': ResourceOperationPatternRule,
22
+ };
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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"}
@@ -0,0 +1,3 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ export declare const NoCredentialReuseRule: ESLintUtils.RuleModule<"credentialNotInPackage", [], unknown, ESLintUtils.RuleListener>;
3
+ //# sourceMappingURL=no-credential-reuse.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,62 @@
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({
4
+ meta: {
5
+ type: 'problem',
6
+ docs: {
7
+ description: 'Prevent credential re-use security issues by ensuring nodes only reference credentials from the same package',
8
+ },
9
+ messages: {
10
+ 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
+ },
12
+ schema: [],
13
+ },
14
+ defaultOptions: [],
15
+ create(context) {
16
+ if (!isFileType(context.filename, '.node.ts')) {
17
+ return {};
18
+ }
19
+ let packageCredentials = null;
20
+ const loadPackageCredentials = () => {
21
+ if (packageCredentials !== null) {
22
+ return packageCredentials;
23
+ }
24
+ const packageJsonPath = findPackageJson(context.filename);
25
+ if (!packageJsonPath) {
26
+ packageCredentials = new Set();
27
+ return packageCredentials;
28
+ }
29
+ packageCredentials = readPackageJsonCredentials(packageJsonPath);
30
+ return packageCredentials;
31
+ };
32
+ return {
33
+ ClassDeclaration(node) {
34
+ if (!isNodeTypeClass(node)) {
35
+ return;
36
+ }
37
+ const descriptionProperty = findClassProperty(node, 'description');
38
+ if (!descriptionProperty?.value || descriptionProperty.value.type !== 'ObjectExpression') {
39
+ return;
40
+ }
41
+ const credentialsArray = findArrayLiteralProperty(descriptionProperty.value, 'credentials');
42
+ if (!credentialsArray) {
43
+ return;
44
+ }
45
+ const allowedCredentials = loadPackageCredentials();
46
+ credentialsArray.elements.forEach((element) => {
47
+ const credentialInfo = extractCredentialNameFromArray(element);
48
+ if (credentialInfo && !allowedCredentials.has(credentialInfo.name)) {
49
+ context.report({
50
+ node: credentialInfo.node,
51
+ messageId: 'credentialNotInPackage',
52
+ data: {
53
+ credentialName: credentialInfo.name,
54
+ },
55
+ });
56
+ }
57
+ });
58
+ },
59
+ };
60
+ },
61
+ });
62
+ //# sourceMappingURL=no-credential-reuse.js.map
@@ -0,0 +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"}
@@ -0,0 +1,3 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ export declare const NoDeprecatedWorkflowFunctionsRule: ESLintUtils.RuleModule<"deprecatedRequestFunction" | "deprecatedFunction" | "deprecatedType" | "deprecatedWithoutReplacement", [], unknown, ESLintUtils.RuleListener>;
3
+ //# sourceMappingURL=no-deprecated-workflow-functions.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,144 @@
1
+ import { ESLintUtils, TSESTree } from '@typescript-eslint/utils';
2
+ const DEPRECATED_FUNCTIONS = {
3
+ request: 'httpRequest',
4
+ requestWithAuthentication: 'httpRequestWithAuthentication',
5
+ requestOAuth1: 'httpRequestWithAuthentication',
6
+ requestOAuth2: 'httpRequestWithAuthentication',
7
+ copyBinaryFile: null,
8
+ prepareOutputData: null,
9
+ };
10
+ const DEPRECATED_TYPES = {
11
+ IRequestOptions: 'IHttpRequestOptions',
12
+ };
13
+ function isDeprecatedFunctionName(name) {
14
+ return name in DEPRECATED_FUNCTIONS;
15
+ }
16
+ function isDeprecatedTypeName(name) {
17
+ return name in DEPRECATED_TYPES;
18
+ }
19
+ export const NoDeprecatedWorkflowFunctionsRule = ESLintUtils.RuleCreator.withoutDocs({
20
+ meta: {
21
+ type: 'problem',
22
+ docs: {
23
+ description: 'Disallow usage of deprecated functions and types from n8n-workflow package',
24
+ },
25
+ messages: {
26
+ deprecatedRequestFunction: "'{{ functionName }}' is deprecated. Use '{{ replacement }}' instead for better authentication support and consistency.",
27
+ deprecatedFunction: "'{{ functionName }}' is deprecated and should be avoided. {{ message }}",
28
+ deprecatedType: "'{{ typeName }}' is deprecated. Use '{{ replacement }}' instead.",
29
+ deprecatedWithoutReplacement: "'{{ functionName }}' is deprecated and should be removed or replaced with alternative implementation.",
30
+ },
31
+ schema: [],
32
+ },
33
+ defaultOptions: [],
34
+ create(context) {
35
+ const n8nWorkflowTypes = new Set();
36
+ return {
37
+ ImportDeclaration(node) {
38
+ if (node.source.value === 'n8n-workflow') {
39
+ node.specifiers.forEach((specifier) => {
40
+ if (specifier.type === 'ImportSpecifier' && specifier.imported.type === 'Identifier') {
41
+ n8nWorkflowTypes.add(specifier.local.name);
42
+ }
43
+ });
44
+ }
45
+ },
46
+ MemberExpression(node) {
47
+ if (node.property.type === 'Identifier' && isDeprecatedFunctionName(node.property.name)) {
48
+ if (!isThisHelpersAccess(node)) {
49
+ return;
50
+ }
51
+ const functionName = node.property.name;
52
+ const replacement = DEPRECATED_FUNCTIONS[functionName];
53
+ if (replacement) {
54
+ const messageId = functionName.includes('request')
55
+ ? 'deprecatedRequestFunction'
56
+ : 'deprecatedFunction';
57
+ context.report({
58
+ node: node.property,
59
+ messageId,
60
+ data: {
61
+ functionName,
62
+ replacement,
63
+ message: getDeprecationMessage(functionName),
64
+ },
65
+ });
66
+ }
67
+ else {
68
+ context.report({
69
+ node: node.property,
70
+ messageId: 'deprecatedWithoutReplacement',
71
+ data: {
72
+ functionName,
73
+ },
74
+ });
75
+ }
76
+ }
77
+ },
78
+ TSTypeReference(node) {
79
+ if (node.typeName.type === 'Identifier' &&
80
+ isDeprecatedTypeName(node.typeName.name) &&
81
+ n8nWorkflowTypes.has(node.typeName.name)) {
82
+ const typeName = node.typeName.name;
83
+ const replacement = DEPRECATED_TYPES[typeName];
84
+ context.report({
85
+ node: node.typeName,
86
+ messageId: 'deprecatedType',
87
+ data: {
88
+ typeName,
89
+ replacement,
90
+ },
91
+ });
92
+ }
93
+ },
94
+ ImportSpecifier(node) {
95
+ // Check if this import is from n8n-workflow by looking at the parent ImportDeclaration
96
+ const importDeclaration = node.parent;
97
+ if (importDeclaration?.type === 'ImportDeclaration' &&
98
+ importDeclaration.source.value === 'n8n-workflow' &&
99
+ node.imported.type === 'Identifier' &&
100
+ isDeprecatedTypeName(node.imported.name)) {
101
+ const typeName = node.imported.name;
102
+ const replacement = DEPRECATED_TYPES[typeName];
103
+ context.report({
104
+ node: node.imported,
105
+ messageId: 'deprecatedType',
106
+ data: {
107
+ typeName,
108
+ replacement,
109
+ },
110
+ });
111
+ }
112
+ },
113
+ };
114
+ },
115
+ });
116
+ /**
117
+ * Check if the MemberExpression follows the this.helpers.* pattern
118
+ */
119
+ function isThisHelpersAccess(node) {
120
+ if (node.object?.type === 'MemberExpression') {
121
+ const outerObject = node.object;
122
+ return (outerObject.object?.type === 'ThisExpression' &&
123
+ outerObject.property?.type === 'Identifier' &&
124
+ outerObject.property.name === 'helpers');
125
+ }
126
+ return false;
127
+ }
128
+ function getDeprecationMessage(functionName) {
129
+ switch (functionName) {
130
+ case 'request':
131
+ return 'Use httpRequest for better type safety and consistency.';
132
+ case 'requestWithAuthentication':
133
+ case 'requestOAuth1':
134
+ case 'requestOAuth2':
135
+ return 'Use httpRequestWithAuthentication which provides unified authentication handling.';
136
+ case 'copyBinaryFile':
137
+ return 'This function has been removed. Handle binary data directly.';
138
+ case 'prepareOutputData':
139
+ return 'This function is deprecated. Return data directly from execute method.';
140
+ default:
141
+ return 'This function is deprecated and should be avoided.';
142
+ }
143
+ }
144
+ //# sourceMappingURL=no-deprecated-workflow-functions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-deprecated-workflow-functions.js","sourceRoot":"","sources":["../../src/rules/no-deprecated-workflow-functions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ export declare const NoRestrictedGlobalsRule: ESLintUtils.RuleModule<"restrictedGlobal", [], unknown, ESLintUtils.RuleListener>;
3
+ //# sourceMappingURL=no-restricted-globals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-restricted-globals.d.ts","sourceRoot":"","sources":["../../src/rules/no-restricted-globals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAiBvD,eAAO,MAAM,uBAAuB,mFAqDlC,CAAC"}
@@ -0,0 +1,58 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ const restrictedGlobals = [
3
+ 'clearInterval',
4
+ 'clearTimeout',
5
+ 'global',
6
+ 'globalThis',
7
+ 'process',
8
+ 'setInterval',
9
+ 'setTimeout',
10
+ 'setImmediate',
11
+ 'clearImmediate',
12
+ '__dirname',
13
+ '__filename',
14
+ ];
15
+ export const NoRestrictedGlobalsRule = ESLintUtils.RuleCreator.withoutDocs({
16
+ meta: {
17
+ type: 'problem',
18
+ docs: {
19
+ description: 'Disallow usage of restricted global variables in community nodes.',
20
+ },
21
+ messages: {
22
+ restrictedGlobal: "Use of restricted global '{{ name }}' is not allowed",
23
+ },
24
+ schema: [],
25
+ },
26
+ defaultOptions: [],
27
+ create(context) {
28
+ function checkReference(ref, name) {
29
+ const { parent } = ref.identifier;
30
+ // Skip property access (like console.process - we want process.exit but not obj.process)
31
+ if (parent?.type === 'MemberExpression' &&
32
+ parent.property === ref.identifier &&
33
+ !parent.computed) {
34
+ return;
35
+ }
36
+ context.report({
37
+ node: ref.identifier,
38
+ messageId: 'restrictedGlobal',
39
+ data: { name },
40
+ });
41
+ }
42
+ return {
43
+ Program() {
44
+ const globalScope = context.sourceCode.getScope(context.sourceCode.ast);
45
+ const allReferences = [
46
+ ...globalScope.variables
47
+ .filter((variable) => restrictedGlobals.includes(variable.name) && variable.defs.length === 0)
48
+ .flatMap((variable) => variable.references.map((ref) => ({ ref, name: variable.name }))),
49
+ ...globalScope.through
50
+ .filter((ref) => restrictedGlobals.includes(ref.identifier.name))
51
+ .map((ref) => ({ ref, name: ref.identifier.name })),
52
+ ];
53
+ allReferences.forEach(({ ref, name }) => checkReference(ref, name));
54
+ },
55
+ };
56
+ },
57
+ });
58
+ //# sourceMappingURL=no-restricted-globals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-restricted-globals.js","sourceRoot":"","sources":["../../src/rules/no-restricted-globals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,MAAM,iBAAiB,GAAG;IACzB,eAAe;IACf,cAAc;IACd,QAAQ;IACR,YAAY;IACZ,SAAS;IACT,aAAa;IACb,YAAY;IACZ,cAAc;IACd,gBAAgB;IAChB,WAAW;IACX,YAAY;CACZ,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG,WAAW,CAAC,WAAW,CAAC,WAAW,CAAC;IAC1E,IAAI,EAAE;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACL,WAAW,EAAE,mEAAmE;SAChF;QACD,QAAQ,EAAE;YACT,gBAAgB,EAAE,sDAAsD;SACxE;QACD,MAAM,EAAE,EAAE;KACV;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACb,SAAS,cAAc,CAAC,GAA6B,EAAE,IAAY;YAClE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,UAAU,CAAC;YAElC,yFAAyF;YACzF,IACC,MAAM,EAAE,IAAI,KAAK,kBAAkB;gBACnC,MAAM,CAAC,QAAQ,KAAK,GAAG,CAAC,UAAU;gBAClC,CAAC,MAAM,CAAC,QAAQ,EACf,CAAC;gBACF,OAAO;YACR,CAAC;YAED,OAAO,CAAC,MAAM,CAAC;gBACd,IAAI,EAAE,GAAG,CAAC,UAAU;gBACpB,SAAS,EAAE,kBAAkB;gBAC7B,IAAI,EAAE,EAAE,IAAI,EAAE;aACd,CAAC,CAAC;QACJ,CAAC;QAED,OAAO;YACN,OAAO;gBACN,MAAM,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;gBAExE,MAAM,aAAa,GAAG;oBACrB,GAAG,WAAW,CAAC,SAAS;yBACtB,MAAM,CACN,CAAC,QAAQ,EAAE,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CACrF;yBACA,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CACrB,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAChE;oBACF,GAAG,WAAW,CAAC,OAAO;yBACpB,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;yBAChE,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;iBACpD,CAAC;gBAEF,aAAa,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;YACrE,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ export declare const NoRestrictedImportsRule: ESLintUtils.RuleModule<"restrictedImport" | "restrictedRequire" | "restrictedDynamicImport", [], unknown, ESLintUtils.RuleListener>;
3
+ //# sourceMappingURL=no-restricted-imports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-restricted-imports.d.ts","sourceRoot":"","sources":["../../src/rules/no-restricted-imports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAwBvD,eAAO,MAAM,uBAAuB,qIA6DlC,CAAC"}
@@ -0,0 +1,80 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ import { getModulePath, isDirectRequireCall, isRequireMemberCall } from '../utils/index.js';
3
+ const allowedModules = [
4
+ 'n8n-workflow',
5
+ 'lodash',
6
+ 'moment',
7
+ 'p-limit',
8
+ 'luxon',
9
+ 'zod',
10
+ 'crypto',
11
+ 'node:crypto',
12
+ ];
13
+ const isModuleAllowed = (modulePath) => {
14
+ if (modulePath.startsWith('./') || modulePath.startsWith('../'))
15
+ return true;
16
+ const moduleName = modulePath.startsWith('@')
17
+ ? modulePath.split('/').slice(0, 2).join('/')
18
+ : modulePath.split('/')[0];
19
+ if (!moduleName)
20
+ return true;
21
+ return allowedModules.includes(moduleName);
22
+ };
23
+ export const NoRestrictedImportsRule = ESLintUtils.RuleCreator.withoutDocs({
24
+ meta: {
25
+ type: 'problem',
26
+ docs: {
27
+ description: 'Disallow usage of restricted imports in community nodes.',
28
+ },
29
+ messages: {
30
+ restrictedImport: "Import of '{{ modulePath }}' is not allowed. n8n Cloud does not allow community nodes with dependencies.",
31
+ restrictedRequire: "Require of '{{ modulePath }}' is not allowed. n8n Cloud does not allow community nodes with dependencies.",
32
+ restrictedDynamicImport: "Dynamic import of '{{ modulePath }}' is not allowed. n8n Cloud does not allow community nodes with dependencies.",
33
+ },
34
+ schema: [],
35
+ },
36
+ defaultOptions: [],
37
+ create(context) {
38
+ return {
39
+ ImportDeclaration(node) {
40
+ const modulePath = getModulePath(node.source);
41
+ if (modulePath && !isModuleAllowed(modulePath)) {
42
+ context.report({
43
+ node,
44
+ messageId: 'restrictedImport',
45
+ data: {
46
+ modulePath,
47
+ },
48
+ });
49
+ }
50
+ },
51
+ ImportExpression(node) {
52
+ const modulePath = getModulePath(node.source);
53
+ if (modulePath && !isModuleAllowed(modulePath)) {
54
+ context.report({
55
+ node,
56
+ messageId: 'restrictedDynamicImport',
57
+ data: {
58
+ modulePath,
59
+ },
60
+ });
61
+ }
62
+ },
63
+ CallExpression(node) {
64
+ if (isDirectRequireCall(node) || isRequireMemberCall(node)) {
65
+ const modulePath = getModulePath(node.arguments[0] ?? null);
66
+ if (modulePath && !isModuleAllowed(modulePath)) {
67
+ context.report({
68
+ node,
69
+ messageId: 'restrictedRequire',
70
+ data: {
71
+ modulePath,
72
+ },
73
+ });
74
+ }
75
+ }
76
+ },
77
+ };
78
+ },
79
+ });
80
+ //# sourceMappingURL=no-restricted-imports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-restricted-imports.js","sourceRoot":"","sources":["../../src/rules/no-restricted-imports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE5F,MAAM,cAAc,GAAG;IACtB,cAAc;IACd,QAAQ;IACR,QAAQ;IACR,SAAS;IACT,OAAO;IACP,KAAK;IACL,QAAQ;IACR,aAAa;CACb,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,UAAkB,EAAW,EAAE;IACvD,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAE7E,MAAM,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC;QAC5C,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QAC7C,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5B,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAC7B,OAAO,cAAc,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;AAC5C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG,WAAW,CAAC,WAAW,CAAC,WAAW,CAAC;IAC1E,IAAI,EAAE;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACL,WAAW,EAAE,0DAA0D;SACvE;QACD,QAAQ,EAAE;YACT,gBAAgB,EACf,0GAA0G;YAC3G,iBAAiB,EAChB,2GAA2G;YAC5G,uBAAuB,EACtB,kHAAkH;SACnH;QACD,MAAM,EAAE,EAAE;KACV;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACb,OAAO;YACN,iBAAiB,CAAC,IAAI;gBACrB,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAC9C,IAAI,UAAU,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE,CAAC;oBAChD,OAAO,CAAC,MAAM,CAAC;wBACd,IAAI;wBACJ,SAAS,EAAE,kBAAkB;wBAC7B,IAAI,EAAE;4BACL,UAAU;yBACV;qBACD,CAAC,CAAC;gBACJ,CAAC;YACF,CAAC;YAED,gBAAgB,CAAC,IAAI;gBACpB,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAC9C,IAAI,UAAU,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE,CAAC;oBAChD,OAAO,CAAC,MAAM,CAAC;wBACd,IAAI;wBACJ,SAAS,EAAE,yBAAyB;wBACpC,IAAI,EAAE;4BACL,UAAU;yBACV;qBACD,CAAC,CAAC;gBACJ,CAAC;YACF,CAAC;YAED,cAAc,CAAC,IAAI;gBAClB,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC5D,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;oBAC5D,IAAI,UAAU,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE,CAAC;wBAChD,OAAO,CAAC,MAAM,CAAC;4BACd,IAAI;4BACJ,SAAS,EAAE,mBAAmB;4BAC9B,IAAI,EAAE;gCACL,UAAU;6BACV;yBACD,CAAC,CAAC;oBACJ,CAAC;gBACF,CAAC;YACF,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ export declare const NodeUsableAsToolRule: ESLintUtils.RuleModule<"missingUsableAsTool", [], unknown, ESLintUtils.RuleListener>;
3
+ //# sourceMappingURL=node-usable-as-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-usable-as-tool.d.ts","sourceRoot":"","sources":["../../src/rules/node-usable-as-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAQvD,eAAO,MAAM,oBAAoB,sFA6D/B,CAAC"}
@@ -0,0 +1,57 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ import { isNodeTypeClass, findClassProperty, findObjectProperty, getBooleanLiteralValue, } from '../utils/index.js';
3
+ export const NodeUsableAsToolRule = ESLintUtils.RuleCreator.withoutDocs({
4
+ meta: {
5
+ type: 'problem',
6
+ docs: {
7
+ description: 'Ensure node classes have usableAsTool property',
8
+ },
9
+ messages: {
10
+ missingUsableAsTool: 'Node class should have usableAsTool property. When in doubt, set it to true.',
11
+ },
12
+ fixable: 'code',
13
+ schema: [],
14
+ },
15
+ defaultOptions: [],
16
+ create(context) {
17
+ return {
18
+ ClassDeclaration(node) {
19
+ if (!isNodeTypeClass(node)) {
20
+ return;
21
+ }
22
+ const descriptionProperty = findClassProperty(node, 'description');
23
+ if (!descriptionProperty) {
24
+ return;
25
+ }
26
+ const descriptionValue = descriptionProperty.value;
27
+ if (descriptionValue?.type !== 'ObjectExpression') {
28
+ return;
29
+ }
30
+ const usableAsToolProperty = findObjectProperty(descriptionValue, 'usableAsTool');
31
+ if (!usableAsToolProperty) {
32
+ context.report({
33
+ node,
34
+ messageId: 'missingUsableAsTool',
35
+ fix(fixer) {
36
+ if (descriptionValue?.type === 'ObjectExpression') {
37
+ const properties = descriptionValue.properties;
38
+ if (properties.length === 0) {
39
+ const openBrace = descriptionValue.range[0] + 1;
40
+ return fixer.insertTextAfterRange([openBrace, openBrace], '\n\t\tusableAsTool: true,');
41
+ }
42
+ else {
43
+ const lastProperty = properties.at(-1);
44
+ if (lastProperty) {
45
+ return fixer.insertTextAfter(lastProperty, ',\n\t\tusableAsTool: true');
46
+ }
47
+ }
48
+ }
49
+ return null;
50
+ },
51
+ });
52
+ }
53
+ },
54
+ };
55
+ },
56
+ });
57
+ //# sourceMappingURL=node-usable-as-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-usable-as-tool.js","sourceRoot":"","sources":["../../src/rules/node-usable-as-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EACN,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,GACtB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,CAAC,MAAM,oBAAoB,GAAG,WAAW,CAAC,WAAW,CAAC,WAAW,CAAC;IACvE,IAAI,EAAE;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACL,WAAW,EAAE,gDAAgD;SAC7D;QACD,QAAQ,EAAE;YACT,mBAAmB,EAClB,8EAA8E;SAC/E;QACD,OAAO,EAAE,MAAM;QACf,MAAM,EAAE,EAAE;KACV;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACb,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,CAAC;oBAC1B,OAAO;gBACR,CAAC;gBAED,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,KAAK,CAAC;gBACnD,IAAI,gBAAgB,EAAE,IAAI,KAAK,kBAAkB,EAAE,CAAC;oBACnD,OAAO;gBACR,CAAC;gBAED,MAAM,oBAAoB,GAAG,kBAAkB,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC;gBAElF,IAAI,CAAC,oBAAoB,EAAE,CAAC;oBAC3B,OAAO,CAAC,MAAM,CAAC;wBACd,IAAI;wBACJ,SAAS,EAAE,qBAAqB;wBAChC,GAAG,CAAC,KAAK;4BACR,IAAI,gBAAgB,EAAE,IAAI,KAAK,kBAAkB,EAAE,CAAC;gCACnD,MAAM,UAAU,GAAG,gBAAgB,CAAC,UAAU,CAAC;gCAC/C,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oCAC7B,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;oCACjD,OAAO,KAAK,CAAC,oBAAoB,CAChC,CAAC,SAAS,EAAE,SAAS,CAAC,EACtB,2BAA2B,CAC3B,CAAC;gCACH,CAAC;qCAAM,CAAC;oCACP,MAAM,YAAY,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;oCACvC,IAAI,YAAY,EAAE,CAAC;wCAClB,OAAO,KAAK,CAAC,eAAe,CAAC,YAAY,EAAE,2BAA2B,CAAC,CAAC;oCACzE,CAAC;gCACF,CAAC;4BACF,CAAC;4BAED,OAAO,IAAI,CAAC;wBACb,CAAC;qBACD,CAAC,CAAC;gBACJ,CAAC;YACF,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ export declare const PackageNameConventionRule: ESLintUtils.RuleModule<"invalidPackageName", [], unknown, ESLintUtils.RuleListener>;
3
+ //# sourceMappingURL=package-name-convention.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-name-convention.d.ts","sourceRoot":"","sources":["../../src/rules/package-name-convention.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA4B,MAAM,0BAA0B,CAAC;AAEjF,eAAO,MAAM,yBAAyB,qFAsDpC,CAAC"}
@@ -0,0 +1,52 @@
1
+ import { ESLintUtils, TSESTree, AST_NODE_TYPES } from '@typescript-eslint/utils';
2
+ export const PackageNameConventionRule = ESLintUtils.RuleCreator.withoutDocs({
3
+ meta: {
4
+ type: 'problem',
5
+ docs: {
6
+ description: 'Enforce correct package naming convention for n8n community nodes',
7
+ },
8
+ messages: {
9
+ invalidPackageName: 'Package name "{{ packageName }}" must follow the convention "n8n-nodes-[PACKAGE-NAME]" or "@[AUTHOR]/n8n-nodes-[PACKAGE-NAME]"',
10
+ },
11
+ schema: [],
12
+ },
13
+ defaultOptions: [],
14
+ create(context) {
15
+ if (!context.filename.endsWith('package.json')) {
16
+ return {};
17
+ }
18
+ return {
19
+ ObjectExpression(node) {
20
+ if (node.parent?.type === AST_NODE_TYPES.Property) {
21
+ return;
22
+ }
23
+ const nameProperty = node.properties.find((property) => property.type === AST_NODE_TYPES.Property &&
24
+ property.key.type === AST_NODE_TYPES.Literal &&
25
+ property.key.value === 'name');
26
+ if (!nameProperty || nameProperty.type !== AST_NODE_TYPES.Property) {
27
+ return;
28
+ }
29
+ if (nameProperty.value.type !== AST_NODE_TYPES.Literal) {
30
+ return;
31
+ }
32
+ const packageName = nameProperty.value.value;
33
+ const packageNameStr = typeof packageName === 'string' ? packageName : null;
34
+ if (!packageNameStr || !isValidPackageName(packageNameStr)) {
35
+ context.report({
36
+ node: nameProperty,
37
+ messageId: 'invalidPackageName',
38
+ data: {
39
+ packageName: packageNameStr ?? 'undefined',
40
+ },
41
+ });
42
+ }
43
+ },
44
+ };
45
+ },
46
+ });
47
+ function isValidPackageName(name) {
48
+ const unscoped = /^n8n-nodes-.+$/;
49
+ const scoped = /^@.+\/n8n-nodes-.+$/;
50
+ return unscoped.test(name) || scoped.test(name);
51
+ }
52
+ //# sourceMappingURL=package-name-convention.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-name-convention.js","sourceRoot":"","sources":["../../src/rules/package-name-convention.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAEjF,MAAM,CAAC,MAAM,yBAAyB,GAAG,WAAW,CAAC,WAAW,CAAC,WAAW,CAAC;IAC5E,IAAI,EAAE;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACL,WAAW,EAAE,mEAAmE;SAChF;QACD,QAAQ,EAAE;YACT,kBAAkB,EACjB,gIAAgI;SACjI;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,QAAQ,EAAE,CAAC;oBACnD,OAAO;gBACR,CAAC;gBAED,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CACxC,CAAC,QAAQ,EAAE,EAAE,CACZ,QAAQ,CAAC,IAAI,KAAK,cAAc,CAAC,QAAQ;oBACzC,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,cAAc,CAAC,OAAO;oBAC5C,QAAQ,CAAC,GAAG,CAAC,KAAK,KAAK,MAAM,CAC9B,CAAC;gBAEF,IAAI,CAAC,YAAY,IAAI,YAAY,CAAC,IAAI,KAAK,cAAc,CAAC,QAAQ,EAAE,CAAC;oBACpE,OAAO;gBACR,CAAC;gBAED,IAAI,YAAY,CAAC,KAAK,CAAC,IAAI,KAAK,cAAc,CAAC,OAAO,EAAE,CAAC;oBACxD,OAAO;gBACR,CAAC;gBAED,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC;gBAC7C,MAAM,cAAc,GAAG,OAAO,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;gBAE5E,IAAI,CAAC,cAAc,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC,EAAE,CAAC;oBAC5D,OAAO,CAAC,MAAM,CAAC;wBACd,IAAI,EAAE,YAAY;wBAClB,SAAS,EAAE,oBAAoB;wBAC/B,IAAI,EAAE;4BACL,WAAW,EAAE,cAAc,IAAI,WAAW;yBAC1C;qBACD,CAAC,CAAC;gBACJ,CAAC;YACF,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC,CAAC;AAEH,SAAS,kBAAkB,CAAC,IAAY;IACvC,MAAM,QAAQ,GAAG,gBAAgB,CAAC;IAClC,MAAM,MAAM,GAAG,qBAAqB,CAAC;IACrC,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACjD,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ export declare const ResourceOperationPatternRule: ESLintUtils.RuleModule<"tooManyOperationsWithoutResources", [], unknown, ESLintUtils.RuleListener>;
3
+ //# sourceMappingURL=resource-operation-pattern.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-operation-pattern.d.ts","sourceRoot":"","sources":["../../src/rules/resource-operation-pattern.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAY,MAAM,0BAA0B,CAAC;AASjE,eAAO,MAAM,4BAA4B,oGAuFvC,CAAC"}