@n8n/eslint-plugin-community-nodes 0.9.0 → 0.11.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 (44) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/README.md +19 -15
  3. package/dist/plugin.d.ts +24 -0
  4. package/dist/plugin.d.ts.map +1 -1
  5. package/dist/plugin.js +8 -0
  6. package/dist/plugin.js.map +1 -1
  7. package/dist/rules/cred-class-field-icon-missing.d.ts +2 -0
  8. package/dist/rules/cred-class-field-icon-missing.d.ts.map +1 -0
  9. package/dist/rules/cred-class-field-icon-missing.js +51 -0
  10. package/dist/rules/cred-class-field-icon-missing.js.map +1 -0
  11. package/dist/rules/icon-validation.d.ts +1 -1
  12. package/dist/rules/index.d.ts +5 -1
  13. package/dist/rules/index.d.ts.map +1 -1
  14. package/dist/rules/index.js +8 -0
  15. package/dist/rules/index.js.map +1 -1
  16. package/dist/rules/node-class-description-icon-missing.d.ts +2 -0
  17. package/dist/rules/node-class-description-icon-missing.d.ts.map +1 -0
  18. package/dist/rules/node-class-description-icon-missing.js +57 -0
  19. package/dist/rules/node-class-description-icon-missing.js.map +1 -0
  20. package/dist/rules/node-connection-type-literal.d.ts +2 -0
  21. package/dist/rules/node-connection-type-literal.d.ts.map +1 -0
  22. package/dist/rules/node-connection-type-literal.js +77 -0
  23. package/dist/rules/node-connection-type-literal.js.map +1 -0
  24. package/dist/rules/options-sorted-alphabetically.d.ts +2 -0
  25. package/dist/rules/options-sorted-alphabetically.d.ts.map +1 -0
  26. package/dist/rules/options-sorted-alphabetically.js +95 -0
  27. package/dist/rules/options-sorted-alphabetically.js.map +1 -0
  28. package/docs/rules/cred-class-field-icon-missing.md +47 -0
  29. package/docs/rules/node-class-description-icon-missing.md +52 -0
  30. package/docs/rules/node-connection-type-literal.md +46 -0
  31. package/docs/rules/options-sorted-alphabetically.md +63 -0
  32. package/package.json +9 -6
  33. package/src/plugin.ts +8 -0
  34. package/src/rules/cred-class-field-icon-missing.test.ts +96 -0
  35. package/src/rules/cred-class-field-icon-missing.ts +59 -0
  36. package/src/rules/index.ts +8 -0
  37. package/src/rules/node-class-description-icon-missing.test.ts +113 -0
  38. package/src/rules/node-class-description-icon-missing.ts +71 -0
  39. package/src/rules/node-connection-type-literal.test.ts +128 -0
  40. package/src/rules/node-connection-type-literal.ts +98 -0
  41. package/src/rules/options-sorted-alphabetically.test.ts +468 -0
  42. package/src/rules/options-sorted-alphabetically.ts +129 -0
  43. package/tsconfig.json +1 -1
  44. package/tsconfig.build.tsbuildinfo +0 -1
@@ -1,4 +1,4 @@
1
1
 
2
- > @n8n/eslint-plugin-community-nodes@0.9.0 build /home/runner/work/n8n/n8n/packages/@n8n/eslint-plugin-community-nodes
2
+ > @n8n/eslint-plugin-community-nodes@0.11.0 build /home/runner/work/n8n/n8n/packages/@n8n/eslint-plugin-community-nodes
3
3
  > tsc --project tsconfig.build.json
4
4
 
package/README.md CHANGED
@@ -43,20 +43,24 @@ export default [
43
43
  🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\
44
44
  💡 Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
45
45
 
46
- | Name                             | Description | 💼 | ⚠️ | 🔧 | 💡 |
47
- | :--------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------ | :--- | :--- | :- | :- |
48
- | [ai-node-package-json](docs/rules/ai-node-package-json.md) | Enforce consistency between n8n.aiNodeSdkVersion and ai-node-sdk peer dependency in community node packages | ✅ ☑️ | | | |
49
- | [credential-documentation-url](docs/rules/credential-documentation-url.md) | Enforce valid credential documentationUrl format (URL or lowercase alphanumeric slug) | ✅ ☑️ | | 🔧 | |
50
- | [credential-password-field](docs/rules/credential-password-field.md) | Ensure credential fields with sensitive names have typeOptions.password = true | ✅ ☑️ | | 🔧 | |
51
- | [credential-test-required](docs/rules/credential-test-required.md) | Ensure credentials have a credential test | ✅ ☑️ | | | 💡 |
52
- | [icon-validation](docs/rules/icon-validation.md) | Validate node and credential icon files exist, are SVG format, and light/dark icons are different | ✅ ☑️ | | | 💡 |
53
- | [no-credential-reuse](docs/rules/no-credential-reuse.md) | Prevent credential re-use security issues by ensuring nodes only reference credentials from the same package | ✅ ☑️ | | | 💡 |
54
- | [no-deprecated-workflow-functions](docs/rules/no-deprecated-workflow-functions.md) | Disallow usage of deprecated functions and types from n8n-workflow package | ✅ ☑️ | | | 💡 |
55
- | [no-http-request-with-manual-auth](docs/rules/no-http-request-with-manual-auth.md) | Disallow this.helpers.httpRequest() in functions that call this.getCredentials(). Use this.helpers.httpRequestWithAuthentication() instead. | ✅ ☑️ | | | |
56
- | [no-restricted-globals](docs/rules/no-restricted-globals.md) | Disallow usage of restricted global variables in community nodes. | ✅ | | | |
57
- | [no-restricted-imports](docs/rules/no-restricted-imports.md) | Disallow usage of restricted imports in community nodes. | ✅ | | | |
58
- | [node-usable-as-tool](docs/rules/node-usable-as-tool.md) | Ensure node classes have usableAsTool property | ✅ ☑️ | | 🔧 | |
59
- | [package-name-convention](docs/rules/package-name-convention.md) | Enforce correct package naming convention for n8n community nodes | ✅ ☑️ | | | 💡 |
60
- | [resource-operation-pattern](docs/rules/resource-operation-pattern.md) | Enforce proper resource/operation pattern for better UX in n8n nodes | | ✅ ☑️ | | |
46
+ | Name                                | Description | 💼 | ⚠️ | 🔧 | 💡 |
47
+ | :--------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------ | :--- | :--- | :- | :- |
48
+ | [ai-node-package-json](docs/rules/ai-node-package-json.md) | Enforce consistency between n8n.aiNodeSdkVersion and ai-node-sdk peer dependency in community node packages | ✅ ☑️ | | | |
49
+ | [cred-class-field-icon-missing](docs/rules/cred-class-field-icon-missing.md) | Credential class must have an `icon` property defined | ✅ ☑️ | | | 💡 |
50
+ | [credential-documentation-url](docs/rules/credential-documentation-url.md) | Enforce valid credential documentationUrl format (URL or lowercase alphanumeric slug) | ✅ ☑️ | | 🔧 | |
51
+ | [credential-password-field](docs/rules/credential-password-field.md) | Ensure credential fields with sensitive names have typeOptions.password = true | ✅ ☑️ | | 🔧 | |
52
+ | [credential-test-required](docs/rules/credential-test-required.md) | Ensure credentials have a credential test | ✅ ☑️ | | | 💡 |
53
+ | [icon-validation](docs/rules/icon-validation.md) | Validate node and credential icon files exist, are SVG format, and light/dark icons are different | ✅ ☑️ | | | 💡 |
54
+ | [no-credential-reuse](docs/rules/no-credential-reuse.md) | Prevent credential re-use security issues by ensuring nodes only reference credentials from the same package | ✅ ☑️ | | | 💡 |
55
+ | [no-deprecated-workflow-functions](docs/rules/no-deprecated-workflow-functions.md) | Disallow usage of deprecated functions and types from n8n-workflow package | ✅ ☑️ | | | 💡 |
56
+ | [no-http-request-with-manual-auth](docs/rules/no-http-request-with-manual-auth.md) | Disallow this.helpers.httpRequest() in functions that call this.getCredentials(). Use this.helpers.httpRequestWithAuthentication() instead. | ✅ ☑️ | | | |
57
+ | [no-restricted-globals](docs/rules/no-restricted-globals.md) | Disallow usage of restricted global variables in community nodes. | ✅ | | | |
58
+ | [no-restricted-imports](docs/rules/no-restricted-imports.md) | Disallow usage of restricted imports in community nodes. | ✅ | | | |
59
+ | [node-class-description-icon-missing](docs/rules/node-class-description-icon-missing.md) | Node class description must have an `icon` property defined | ✅ ☑️ | | | 💡 |
60
+ | [node-connection-type-literal](docs/rules/node-connection-type-literal.md) | Disallow string literals in node description `inputs`/`outputs` use `NodeConnectionTypes` enum instead | ✅ ☑️ | | 🔧 | |
61
+ | [node-usable-as-tool](docs/rules/node-usable-as-tool.md) | Ensure node classes have usableAsTool property | ✅ ☑️ | | 🔧 | |
62
+ | [options-sorted-alphabetically](docs/rules/options-sorted-alphabetically.md) | Enforce alphabetical ordering of options arrays in n8n node properties | | ✅ ☑️ | | |
63
+ | [package-name-convention](docs/rules/package-name-convention.md) | Enforce correct package naming convention for n8n community nodes | ✅ ☑️ | | | 💡 |
64
+ | [resource-operation-pattern](docs/rules/resource-operation-pattern.md) | Enforce proper resource/operation pattern for better UX in n8n nodes | | ✅ ☑️ | | |
61
65
 
62
66
  <!-- end auto-generated rules list -->
package/dist/plugin.d.ts CHANGED
@@ -25,8 +25,12 @@ declare const configs: {
25
25
  '@n8n/community-nodes/no-credential-reuse': "error";
26
26
  '@n8n/community-nodes/no-http-request-with-manual-auth': "error";
27
27
  '@n8n/community-nodes/icon-validation': "error";
28
+ '@n8n/community-nodes/options-sorted-alphabetically': "warn";
28
29
  '@n8n/community-nodes/resource-operation-pattern': "warn";
29
30
  '@n8n/community-nodes/credential-documentation-url': "error";
31
+ '@n8n/community-nodes/node-class-description-icon-missing': "error";
32
+ '@n8n/community-nodes/cred-class-field-icon-missing': "error";
33
+ '@n8n/community-nodes/node-connection-type-literal': "error";
30
34
  };
31
35
  };
32
36
  recommendedWithoutN8nCloudSupport: {
@@ -51,8 +55,12 @@ declare const configs: {
51
55
  '@n8n/community-nodes/no-credential-reuse': "error";
52
56
  '@n8n/community-nodes/no-http-request-with-manual-auth': "error";
53
57
  '@n8n/community-nodes/icon-validation': "error";
58
+ '@n8n/community-nodes/options-sorted-alphabetically': "warn";
54
59
  '@n8n/community-nodes/credential-documentation-url': "error";
55
60
  '@n8n/community-nodes/resource-operation-pattern': "warn";
61
+ '@n8n/community-nodes/node-class-description-icon-missing': "error";
62
+ '@n8n/community-nodes/cred-class-field-icon-missing': "error";
63
+ '@n8n/community-nodes/node-connection-type-literal': "error";
56
64
  };
57
65
  };
58
66
  };
@@ -82,8 +90,12 @@ declare const pluginWithConfigs: {
82
90
  '@n8n/community-nodes/no-credential-reuse': "error";
83
91
  '@n8n/community-nodes/no-http-request-with-manual-auth': "error";
84
92
  '@n8n/community-nodes/icon-validation': "error";
93
+ '@n8n/community-nodes/options-sorted-alphabetically': "warn";
85
94
  '@n8n/community-nodes/resource-operation-pattern': "warn";
86
95
  '@n8n/community-nodes/credential-documentation-url': "error";
96
+ '@n8n/community-nodes/node-class-description-icon-missing': "error";
97
+ '@n8n/community-nodes/cred-class-field-icon-missing': "error";
98
+ '@n8n/community-nodes/node-connection-type-literal': "error";
87
99
  };
88
100
  };
89
101
  recommendedWithoutN8nCloudSupport: {
@@ -108,8 +120,12 @@ declare const pluginWithConfigs: {
108
120
  '@n8n/community-nodes/no-credential-reuse': "error";
109
121
  '@n8n/community-nodes/no-http-request-with-manual-auth': "error";
110
122
  '@n8n/community-nodes/icon-validation': "error";
123
+ '@n8n/community-nodes/options-sorted-alphabetically': "warn";
111
124
  '@n8n/community-nodes/credential-documentation-url': "error";
112
125
  '@n8n/community-nodes/resource-operation-pattern': "warn";
126
+ '@n8n/community-nodes/node-class-description-icon-missing': "error";
127
+ '@n8n/community-nodes/cred-class-field-icon-missing': "error";
128
+ '@n8n/community-nodes/node-connection-type-literal': "error";
113
129
  };
114
130
  };
115
131
  };
@@ -146,8 +162,12 @@ declare const n8nCommunityNodesPlugin: {
146
162
  '@n8n/community-nodes/no-credential-reuse': "error";
147
163
  '@n8n/community-nodes/no-http-request-with-manual-auth': "error";
148
164
  '@n8n/community-nodes/icon-validation': "error";
165
+ '@n8n/community-nodes/options-sorted-alphabetically': "warn";
149
166
  '@n8n/community-nodes/resource-operation-pattern': "warn";
150
167
  '@n8n/community-nodes/credential-documentation-url': "error";
168
+ '@n8n/community-nodes/node-class-description-icon-missing': "error";
169
+ '@n8n/community-nodes/cred-class-field-icon-missing': "error";
170
+ '@n8n/community-nodes/node-connection-type-literal': "error";
151
171
  };
152
172
  };
153
173
  recommendedWithoutN8nCloudSupport: {
@@ -172,8 +192,12 @@ declare const n8nCommunityNodesPlugin: {
172
192
  '@n8n/community-nodes/no-credential-reuse': "error";
173
193
  '@n8n/community-nodes/no-http-request-with-manual-auth': "error";
174
194
  '@n8n/community-nodes/icon-validation': "error";
195
+ '@n8n/community-nodes/options-sorted-alphabetically': "warn";
175
196
  '@n8n/community-nodes/credential-documentation-url': "error";
176
197
  '@n8n/community-nodes/resource-operation-pattern': "warn";
198
+ '@n8n/community-nodes/node-class-description-icon-missing': "error";
199
+ '@n8n/community-nodes/cred-class-field-icon-missing': "error";
200
+ '@n8n/community-nodes/node-connection-type-literal': "error";
177
201
  };
178
202
  };
179
203
  };
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAC;AAG7C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAYzC,QAAA,MAAM,OAAO;;;;;;;;;;uBAHI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBAAtB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;CA4CE,CAAC;AAE1C,QAAA,MAAM,iBAAiB;;;;;;;;;;;2BA9CN,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAAtB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;WAAtB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;CA8CiC,CAAC;AAEzE,QAAA,MAAM,uBAAuB;;;;;;;;;;;2BAhDZ,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAAtB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;WAAtB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;CAgDU,CAAC;AAClD,eAAe,iBAAiB,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAC;AAG7C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAYzC,QAAA,MAAM,OAAO;;;;;;;;;;uBAHI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBAAtB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;CAoDE,CAAC;AAE1C,QAAA,MAAM,iBAAiB;;;;;;;;;;;2BAtDN,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAAtB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;WAAtB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;CAsDiC,CAAC;AAEzE,QAAA,MAAM,uBAAuB;;;;;;;;;;;2BAxDZ,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAAtB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;WAAtB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;CAwDU,CAAC;AAClD,eAAe,iBAAiB,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
package/dist/plugin.js CHANGED
@@ -27,8 +27,12 @@ const configs = {
27
27
  '@n8n/community-nodes/no-credential-reuse': 'error',
28
28
  '@n8n/community-nodes/no-http-request-with-manual-auth': 'error',
29
29
  '@n8n/community-nodes/icon-validation': 'error',
30
+ '@n8n/community-nodes/options-sorted-alphabetically': 'warn',
30
31
  '@n8n/community-nodes/resource-operation-pattern': 'warn',
31
32
  '@n8n/community-nodes/credential-documentation-url': 'error',
33
+ '@n8n/community-nodes/node-class-description-icon-missing': 'error',
34
+ '@n8n/community-nodes/cred-class-field-icon-missing': 'error',
35
+ '@n8n/community-nodes/node-connection-type-literal': 'error',
32
36
  },
33
37
  },
34
38
  recommendedWithoutN8nCloudSupport: {
@@ -46,8 +50,12 @@ const configs = {
46
50
  '@n8n/community-nodes/no-credential-reuse': 'error',
47
51
  '@n8n/community-nodes/no-http-request-with-manual-auth': 'error',
48
52
  '@n8n/community-nodes/icon-validation': 'error',
53
+ '@n8n/community-nodes/options-sorted-alphabetically': 'warn',
49
54
  '@n8n/community-nodes/credential-documentation-url': 'error',
50
55
  '@n8n/community-nodes/resource-operation-pattern': 'warn',
56
+ '@n8n/community-nodes/node-class-description-icon-missing': 'error',
57
+ '@n8n/community-nodes/cred-class-field-icon-missing': 'error',
58
+ '@n8n/community-nodes/node-connection-type-literal': 'error',
51
59
  },
52
60
  },
53
61
  };
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,GAAG,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,MAAM,MAAM,GAAG;IACd,IAAI,EAAE;QACL,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,SAAS,EAAE,sBAAsB;KACjC;IACD,8EAA8E;IAC9E,KAAK,EAAE,KAA+B;CACd,CAAC;AAE1B,MAAM,OAAO,GAAG;IACf,WAAW,EAAE;QACZ,OAAO,EAAE,CAAC,+BAA+B,CAAC;QAC1C,OAAO,EAAE;YACR,sBAAsB,EAAE,MAAM;SAC9B;QACD,KAAK,EAAE;YACN,2CAA2C,EAAE,OAAO;YACpD,4CAA4C,EAAE,OAAO;YACrD,4CAA4C,EAAE,OAAO;YACrD,gDAAgD,EAAE,OAAO;YACzD,uDAAuD,EAAE,OAAO;YAChE,0CAA0C,EAAE,OAAO;YACnD,8CAA8C,EAAE,OAAO;YACvD,+CAA+C,EAAE,OAAO;YACxD,0CAA0C,EAAE,OAAO;YACnD,uDAAuD,EAAE,OAAO;YAChE,sCAAsC,EAAE,OAAO;YAC/C,iDAAiD,EAAE,MAAM;YACzD,mDAAmD,EAAE,OAAO;SAC5D;KACD;IACD,iCAAiC,EAAE;QAClC,OAAO,EAAE,CAAC,+BAA+B,CAAC;QAC1C,OAAO,EAAE;YACR,sBAAsB,EAAE,MAAM;SAC9B;QACD,KAAK,EAAE;YACN,2CAA2C,EAAE,OAAO;YACpD,gDAAgD,EAAE,OAAO;YACzD,uDAAuD,EAAE,OAAO;YAChE,0CAA0C,EAAE,OAAO;YACnD,8CAA8C,EAAE,OAAO;YACvD,+CAA+C,EAAE,OAAO;YACxD,0CAA0C,EAAE,OAAO;YACnD,uDAAuD,EAAE,OAAO;YAChE,sCAAsC,EAAE,OAAO;YAC/C,mDAAmD,EAAE,OAAO;YAC5D,iDAAiD,EAAE,MAAM;SACzD;KACD;CACuC,CAAC;AAE1C,MAAM,iBAAiB,GAAG,EAAE,GAAG,MAAM,EAAE,OAAO,EAA0B,CAAC;AAEzE,MAAM,uBAAuB,GAAG,iBAAiB,CAAC;AAClD,eAAe,iBAAiB,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,GAAG,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,MAAM,MAAM,GAAG;IACd,IAAI,EAAE;QACL,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,SAAS,EAAE,sBAAsB;KACjC;IACD,8EAA8E;IAC9E,KAAK,EAAE,KAA+B;CACd,CAAC;AAE1B,MAAM,OAAO,GAAG;IACf,WAAW,EAAE;QACZ,OAAO,EAAE,CAAC,+BAA+B,CAAC;QAC1C,OAAO,EAAE;YACR,sBAAsB,EAAE,MAAM;SAC9B;QACD,KAAK,EAAE;YACN,2CAA2C,EAAE,OAAO;YACpD,4CAA4C,EAAE,OAAO;YACrD,4CAA4C,EAAE,OAAO;YACrD,gDAAgD,EAAE,OAAO;YACzD,uDAAuD,EAAE,OAAO;YAChE,0CAA0C,EAAE,OAAO;YACnD,8CAA8C,EAAE,OAAO;YACvD,+CAA+C,EAAE,OAAO;YACxD,0CAA0C,EAAE,OAAO;YACnD,uDAAuD,EAAE,OAAO;YAChE,sCAAsC,EAAE,OAAO;YAC/C,oDAAoD,EAAE,MAAM;YAC5D,iDAAiD,EAAE,MAAM;YACzD,mDAAmD,EAAE,OAAO;YAC5D,0DAA0D,EAAE,OAAO;YACnE,oDAAoD,EAAE,OAAO;YAC7D,mDAAmD,EAAE,OAAO;SAC5D;KACD;IACD,iCAAiC,EAAE;QAClC,OAAO,EAAE,CAAC,+BAA+B,CAAC;QAC1C,OAAO,EAAE;YACR,sBAAsB,EAAE,MAAM;SAC9B;QACD,KAAK,EAAE;YACN,2CAA2C,EAAE,OAAO;YACpD,gDAAgD,EAAE,OAAO;YACzD,uDAAuD,EAAE,OAAO;YAChE,0CAA0C,EAAE,OAAO;YACnD,8CAA8C,EAAE,OAAO;YACvD,+CAA+C,EAAE,OAAO;YACxD,0CAA0C,EAAE,OAAO;YACnD,uDAAuD,EAAE,OAAO;YAChE,sCAAsC,EAAE,OAAO;YAC/C,oDAAoD,EAAE,MAAM;YAC5D,mDAAmD,EAAE,OAAO;YAC5D,iDAAiD,EAAE,MAAM;YACzD,0DAA0D,EAAE,OAAO;YACnE,oDAAoD,EAAE,OAAO;YAC7D,mDAAmD,EAAE,OAAO;SAC5D;KACD;CACuC,CAAC;AAE1C,MAAM,iBAAiB,GAAG,EAAE,GAAG,MAAM,EAAE,OAAO,EAA0B,CAAC;AAEzE,MAAM,uBAAuB,GAAG,iBAAiB,CAAC;AAClD,eAAe,iBAAiB,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const CredClassFieldIconMissingRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingIcon" | "addPlaceholder", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
2
+ //# sourceMappingURL=cred-class-field-icon-missing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cred-class-field-icon-missing.d.ts","sourceRoot":"","sources":["../../src/rules/cred-class-field-icon-missing.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,6BAA6B,mKAmDxC,CAAC"}
@@ -0,0 +1,51 @@
1
+ import { isCredentialTypeClass, findClassProperty, isFileType, createRule, } from '../utils/index.js';
2
+ export const CredClassFieldIconMissingRule = createRule({
3
+ name: 'cred-class-field-icon-missing',
4
+ meta: {
5
+ type: 'problem',
6
+ docs: {
7
+ description: 'Credential class must have an `icon` property defined',
8
+ },
9
+ messages: {
10
+ missingIcon: 'Credential class is missing required `icon` property',
11
+ addPlaceholder: 'Add icon property with placeholder',
12
+ },
13
+ schema: [],
14
+ hasSuggestions: true,
15
+ },
16
+ defaultOptions: [],
17
+ create(context) {
18
+ if (!isFileType(context.filename, '.credentials.ts')) {
19
+ return {};
20
+ }
21
+ return {
22
+ ClassDeclaration(node) {
23
+ if (!isCredentialTypeClass(node)) {
24
+ return;
25
+ }
26
+ const iconProperty = findClassProperty(node, 'icon');
27
+ if (iconProperty?.value) {
28
+ return;
29
+ }
30
+ context.report({
31
+ node,
32
+ messageId: 'missingIcon',
33
+ suggest: [
34
+ {
35
+ messageId: 'addPlaceholder',
36
+ fix(fixer) {
37
+ const classBody = node.body.body;
38
+ const lastProperty = classBody[classBody.length - 1];
39
+ if (lastProperty) {
40
+ return fixer.insertTextAfter(lastProperty, '\n\n\ticon = "file:./icon.svg";');
41
+ }
42
+ return null;
43
+ },
44
+ },
45
+ ],
46
+ });
47
+ },
48
+ };
49
+ },
50
+ });
51
+ //# sourceMappingURL=cred-class-field-icon-missing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cred-class-field-icon-missing.js","sourceRoot":"","sources":["../../src/rules/cred-class-field-icon-missing.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,qBAAqB,EACrB,iBAAiB,EACjB,UAAU,EACV,UAAU,GACV,MAAM,mBAAmB,CAAC;AAE3B,MAAM,CAAC,MAAM,6BAA6B,GAAG,UAAU,CAAC;IACvD,IAAI,EAAE,+BAA+B;IACrC,IAAI,EAAE;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACL,WAAW,EAAE,uDAAuD;SACpE;QACD,QAAQ,EAAE;YACT,WAAW,EAAE,sDAAsD;YACnE,cAAc,EAAE,oCAAoC;SACpD;QACD,MAAM,EAAE,EAAE;QACV,cAAc,EAAE,IAAI;KACpB;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACb,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,iBAAiB,CAAC,EAAE,CAAC;YACtD,OAAO,EAAE,CAAC;QACX,CAAC;QAED,OAAO;YACN,gBAAgB,CAAC,IAAI;gBACpB,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC;oBAClC,OAAO;gBACR,CAAC;gBAED,MAAM,YAAY,GAAG,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;gBACrD,IAAI,YAAY,EAAE,KAAK,EAAE,CAAC;oBACzB,OAAO;gBACR,CAAC;gBAED,OAAO,CAAC,MAAM,CAAC;oBACd,IAAI;oBACJ,SAAS,EAAE,aAAa;oBACxB,OAAO,EAAE;wBACR;4BACC,SAAS,EAAE,gBAAgB;4BAC3B,GAAG,CAAC,KAAK;gCACR,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;gCACjC,MAAM,YAAY,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gCACrD,IAAI,YAAY,EAAE,CAAC;oCAClB,OAAO,KAAK,CAAC,eAAe,CAAC,YAAY,EAAE,iCAAiC,CAAC,CAAC;gCAC/E,CAAC;gCACD,OAAO,IAAI,CAAC;4BACb,CAAC;yBACD;qBACD;iBACD,CAAC,CAAC;YACJ,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC,CAAC"}
@@ -1,2 +1,2 @@
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>;
1
+ export declare const IconValidationRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingIcon" | "addPlaceholder" | "iconFileNotFound" | "iconNotSvg" | "lightDarkSame" | "invalidIconPath" | "addFileProtocol" | "changeExtension" | "similarIcon", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
2
2
  //# sourceMappingURL=icon-validation.d.ts.map
@@ -5,15 +5,19 @@ export declare const rules: {
5
5
  'credential-password-field': import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingPasswordOption", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
6
6
  '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>;
7
7
  'node-usable-as-tool': import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingUsableAsTool", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
8
+ 'options-sorted-alphabetically': import("@typescript-eslint/utils/ts-eslint").RuleModule<"optionsNotSorted", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
8
9
  'package-name-convention': import("@typescript-eslint/utils/ts-eslint").RuleModule<"renameTo" | "invalidPackageName", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
9
10
  'credential-test-required': import("@typescript-eslint/utils/ts-eslint").RuleModule<"addTemplate" | "missingCredentialTest", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
10
11
  'no-credential-reuse': import("@typescript-eslint/utils/ts-eslint").RuleModule<"didYouMean" | "useAvailable" | "credentialNotInPackage", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
11
12
  'no-http-request-with-manual-auth': import("@typescript-eslint/utils/ts-eslint").RuleModule<"useHttpRequestWithAuthentication", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
12
- '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>;
13
+ 'icon-validation': import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingIcon" | "addPlaceholder" | "iconFileNotFound" | "iconNotSvg" | "lightDarkSame" | "invalidIconPath" | "addFileProtocol" | "changeExtension" | "similarIcon", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
13
14
  'resource-operation-pattern': import("@typescript-eslint/utils/ts-eslint").RuleModule<"tooManyOperationsWithoutResources", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
14
15
  'credential-documentation-url': import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidDocumentationUrl", [{
15
16
  allowUrls?: boolean;
16
17
  allowSlugs?: boolean;
17
18
  }], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
19
+ 'node-class-description-icon-missing': import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingIcon" | "addPlaceholder", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
20
+ 'cred-class-field-icon-missing': import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingIcon" | "addPlaceholder", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
21
+ 'node-connection-type-literal': import("@typescript-eslint/utils/ts-eslint").RuleModule<"stringLiteralInInputs" | "stringLiteralInOutputs" | "unknownStringLiteralInInputs" | "unknownStringLiteralInOutputs", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
18
22
  };
19
23
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;CAcuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;CAkBuB,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { AiNodePackageJsonRule } from './ai-node-package-json.js';
2
+ import { CredClassFieldIconMissingRule } from './cred-class-field-icon-missing.js';
2
3
  import { CredentialDocumentationUrlRule } from './credential-documentation-url.js';
3
4
  import { CredentialPasswordFieldRule } from './credential-password-field.js';
4
5
  import { CredentialTestRequiredRule } from './credential-test-required.js';
@@ -8,7 +9,10 @@ import { NoDeprecatedWorkflowFunctionsRule } from './no-deprecated-workflow-func
8
9
  import { NoHttpRequestWithManualAuthRule } from './no-http-request-with-manual-auth.js';
9
10
  import { NoRestrictedGlobalsRule } from './no-restricted-globals.js';
10
11
  import { NoRestrictedImportsRule } from './no-restricted-imports.js';
12
+ import { NodeClassDescriptionIconMissingRule } from './node-class-description-icon-missing.js';
13
+ import { NodeConnectionTypeLiteralRule } from './node-connection-type-literal.js';
11
14
  import { NodeUsableAsToolRule } from './node-usable-as-tool.js';
15
+ import { OptionsSortedAlphabeticallyRule } from './options-sorted-alphabetically.js';
12
16
  import { PackageNameConventionRule } from './package-name-convention.js';
13
17
  import { ResourceOperationPatternRule } from './resource-operation-pattern.js';
14
18
  export const rules = {
@@ -18,6 +22,7 @@ export const rules = {
18
22
  'credential-password-field': CredentialPasswordFieldRule,
19
23
  'no-deprecated-workflow-functions': NoDeprecatedWorkflowFunctionsRule,
20
24
  'node-usable-as-tool': NodeUsableAsToolRule,
25
+ 'options-sorted-alphabetically': OptionsSortedAlphabeticallyRule,
21
26
  'package-name-convention': PackageNameConventionRule,
22
27
  'credential-test-required': CredentialTestRequiredRule,
23
28
  'no-credential-reuse': NoCredentialReuseRule,
@@ -25,5 +30,8 @@ export const rules = {
25
30
  'icon-validation': IconValidationRule,
26
31
  'resource-operation-pattern': ResourceOperationPatternRule,
27
32
  'credential-documentation-url': CredentialDocumentationUrlRule,
33
+ 'node-class-description-icon-missing': NodeClassDescriptionIconMissingRule,
34
+ 'cred-class-field-icon-missing': CredClassFieldIconMissingRule,
35
+ 'node-connection-type-literal': NodeConnectionTypeLiteralRule,
28
36
  };
29
37
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,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,+BAA+B,EAAE,MAAM,uCAAuC,CAAC;AACxF,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,sBAAsB,EAAE,qBAAqB;IAC7C,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,kCAAkC,EAAE,+BAA+B;IACnE,iBAAiB,EAAE,kBAAkB;IACrC,4BAA4B,EAAE,4BAA4B;IAC1D,8BAA8B,EAAE,8BAA8B;CACtB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AACnF,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,+BAA+B,EAAE,MAAM,uCAAuC,CAAC;AACxF,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,mCAAmC,EAAE,MAAM,0CAA0C,CAAC;AAC/F,OAAO,EAAE,6BAA6B,EAAE,MAAM,mCAAmC,CAAC;AAClF,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,+BAA+B,EAAE,MAAM,oCAAoC,CAAC;AACrF,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAAE,4BAA4B,EAAE,MAAM,iCAAiC,CAAC;AAE/E,MAAM,CAAC,MAAM,KAAK,GAAG;IACpB,sBAAsB,EAAE,qBAAqB;IAC7C,uBAAuB,EAAE,uBAAuB;IAChD,uBAAuB,EAAE,uBAAuB;IAChD,2BAA2B,EAAE,2BAA2B;IACxD,kCAAkC,EAAE,iCAAiC;IACrE,qBAAqB,EAAE,oBAAoB;IAC3C,+BAA+B,EAAE,+BAA+B;IAChE,yBAAyB,EAAE,yBAAyB;IACpD,0BAA0B,EAAE,0BAA0B;IACtD,qBAAqB,EAAE,qBAAqB;IAC5C,kCAAkC,EAAE,+BAA+B;IACnE,iBAAiB,EAAE,kBAAkB;IACrC,4BAA4B,EAAE,4BAA4B;IAC1D,8BAA8B,EAAE,8BAA8B;IAC9D,qCAAqC,EAAE,mCAAmC;IAC1E,+BAA+B,EAAE,6BAA6B;IAC9D,8BAA8B,EAAE,6BAA6B;CACrB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const NodeClassDescriptionIconMissingRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingIcon" | "addPlaceholder", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
2
+ //# sourceMappingURL=node-class-description-icon-missing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-class-description-icon-missing.d.ts","sourceRoot":"","sources":["../../src/rules/node-class-description-icon-missing.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,mCAAmC,mKA4D9C,CAAC"}
@@ -0,0 +1,57 @@
1
+ import { TSESTree } from '@typescript-eslint/utils';
2
+ import { isNodeTypeClass, findClassProperty, findObjectProperty, isFileType, createRule, } from '../utils/index.js';
3
+ export const NodeClassDescriptionIconMissingRule = createRule({
4
+ name: 'node-class-description-icon-missing',
5
+ meta: {
6
+ type: 'problem',
7
+ docs: {
8
+ description: 'Node class description must have an `icon` property defined',
9
+ },
10
+ messages: {
11
+ missingIcon: 'Node class description is missing required `icon` property',
12
+ addPlaceholder: 'Add icon property with placeholder',
13
+ },
14
+ schema: [],
15
+ hasSuggestions: true,
16
+ },
17
+ defaultOptions: [],
18
+ create(context) {
19
+ if (!isFileType(context.filename, '.node.ts')) {
20
+ return {};
21
+ }
22
+ return {
23
+ ClassDeclaration(node) {
24
+ if (!isNodeTypeClass(node)) {
25
+ return;
26
+ }
27
+ const descriptionProperty = findClassProperty(node, 'description');
28
+ if (!descriptionProperty?.value ||
29
+ descriptionProperty.value.type !== TSESTree.AST_NODE_TYPES.ObjectExpression) {
30
+ return;
31
+ }
32
+ const descriptionValue = descriptionProperty.value;
33
+ const iconProperty = findObjectProperty(descriptionValue, 'icon');
34
+ if (iconProperty) {
35
+ return;
36
+ }
37
+ context.report({
38
+ node,
39
+ messageId: 'missingIcon',
40
+ suggest: [
41
+ {
42
+ messageId: 'addPlaceholder',
43
+ fix(fixer) {
44
+ const lastProperty = descriptionValue.properties[descriptionValue.properties.length - 1];
45
+ if (lastProperty) {
46
+ return fixer.insertTextAfter(lastProperty, ',\n\t\ticon: "file:./icon.svg"');
47
+ }
48
+ return null;
49
+ },
50
+ },
51
+ ],
52
+ });
53
+ },
54
+ };
55
+ },
56
+ });
57
+ //# sourceMappingURL=node-class-description-icon-missing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-class-description-icon-missing.js","sourceRoot":"","sources":["../../src/rules/node-class-description-icon-missing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEpD,OAAO,EACN,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACV,UAAU,GACV,MAAM,mBAAmB,CAAC;AAE3B,MAAM,CAAC,MAAM,mCAAmC,GAAG,UAAU,CAAC;IAC7D,IAAI,EAAE,qCAAqC;IAC3C,IAAI,EAAE;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACL,WAAW,EAAE,6DAA6D;SAC1E;QACD,QAAQ,EAAE;YACT,WAAW,EAAE,4DAA4D;YACzE,cAAc,EAAE,oCAAoC;SACpD;QACD,MAAM,EAAE,EAAE;QACV,cAAc,EAAE,IAAI;KACpB;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,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,IACC,CAAC,mBAAmB,EAAE,KAAK;oBAC3B,mBAAmB,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,cAAc,CAAC,gBAAgB,EAC1E,CAAC;oBACF,OAAO;gBACR,CAAC;gBAED,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,KAAK,CAAC;gBACnD,MAAM,YAAY,GAAG,kBAAkB,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;gBAClE,IAAI,YAAY,EAAE,CAAC;oBAClB,OAAO;gBACR,CAAC;gBAED,OAAO,CAAC,MAAM,CAAC;oBACd,IAAI;oBACJ,SAAS,EAAE,aAAa;oBACxB,OAAO,EAAE;wBACR;4BACC,SAAS,EAAE,gBAAgB;4BAC3B,GAAG,CAAC,KAAK;gCACR,MAAM,YAAY,GACjB,gBAAgB,CAAC,UAAU,CAAC,gBAAgB,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gCACrE,IAAI,YAAY,EAAE,CAAC;oCAClB,OAAO,KAAK,CAAC,eAAe,CAAC,YAAY,EAAE,gCAAgC,CAAC,CAAC;gCAC9E,CAAC;gCACD,OAAO,IAAI,CAAC;4BACb,CAAC;yBACD;qBACD;iBACD,CAAC,CAAC;YACJ,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const NodeConnectionTypeLiteralRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"stringLiteralInInputs" | "stringLiteralInOutputs" | "unknownStringLiteralInInputs" | "unknownStringLiteralInOutputs", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
2
+ //# sourceMappingURL=node-connection-type-literal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-connection-type-literal.d.ts","sourceRoot":"","sources":["../../src/rules/node-connection-type-literal.ts"],"names":[],"mappings":"AAuBA,eAAO,MAAM,6BAA6B,wPA0ExC,CAAC"}
@@ -0,0 +1,77 @@
1
+ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
2
+ import { createRequire } from 'node:module';
3
+ import { isNodeTypeClass, findClassProperty, findObjectProperty, createRule, } from '../utils/index.js';
4
+ // n8n-workflow's ESM dist uses bare module specifiers that Node's native ESM
5
+ // loader cannot resolve. Loading via CJS (createRequire) sidesteps this.
6
+ const { NodeConnectionTypes } = createRequire(import.meta.url)('n8n-workflow');
7
+ // Reverse map: string value (e.g. 'main') → enum key name (e.g. 'Main').
8
+ // Derived directly from NodeConnectionTypes so it stays in sync automatically.
9
+ const VALUE_TO_ENUM_KEY = Object.fromEntries(Object.entries(NodeConnectionTypes).map(([key, value]) => [value, key]));
10
+ export const NodeConnectionTypeLiteralRule = createRule({
11
+ name: 'node-connection-type-literal',
12
+ meta: {
13
+ type: 'problem',
14
+ docs: {
15
+ description: 'Disallow string literals in node description `inputs`/`outputs` — use `NodeConnectionTypes` enum instead',
16
+ },
17
+ messages: {
18
+ stringLiteralInInputs: 'Use NodeConnectionTypes.{{enumKey}} from "n8n-workflow" instead of the string literal "{{value}}" in "inputs".',
19
+ stringLiteralInOutputs: 'Use NodeConnectionTypes.{{enumKey}} from "n8n-workflow" instead of the string literal "{{value}}" in "outputs".',
20
+ unknownStringLiteralInInputs: 'Use the NodeConnectionTypes enum from "n8n-workflow" instead of the string literal "{{value}}" in "inputs".',
21
+ unknownStringLiteralInOutputs: 'Use the NodeConnectionTypes enum from "n8n-workflow" instead of the string literal "{{value}}" in "outputs".',
22
+ },
23
+ fixable: 'code',
24
+ schema: [],
25
+ },
26
+ defaultOptions: [],
27
+ create(context) {
28
+ function checkArrayElements(elements, property) {
29
+ for (const element of elements) {
30
+ if (element?.type !== AST_NODE_TYPES.Literal)
31
+ continue;
32
+ if (typeof element.value !== 'string')
33
+ continue;
34
+ const value = element.value;
35
+ const enumKey = VALUE_TO_ENUM_KEY[value];
36
+ if (enumKey) {
37
+ context.report({
38
+ node: element,
39
+ messageId: property === 'inputs' ? 'stringLiteralInInputs' : 'stringLiteralInOutputs',
40
+ data: { value, enumKey },
41
+ fix(fixer) {
42
+ return fixer.replaceText(element, `NodeConnectionTypes.${enumKey}`);
43
+ },
44
+ });
45
+ }
46
+ else {
47
+ context.report({
48
+ node: element,
49
+ messageId: property === 'inputs'
50
+ ? 'unknownStringLiteralInInputs'
51
+ : 'unknownStringLiteralInOutputs',
52
+ data: { value },
53
+ });
54
+ }
55
+ }
56
+ }
57
+ return {
58
+ ClassDeclaration(node) {
59
+ if (!isNodeTypeClass(node))
60
+ return;
61
+ const descriptionProperty = findClassProperty(node, 'description');
62
+ if (!descriptionProperty)
63
+ return;
64
+ const descriptionValue = descriptionProperty.value;
65
+ if (descriptionValue?.type !== AST_NODE_TYPES.ObjectExpression)
66
+ return;
67
+ for (const prop of ['inputs', 'outputs']) {
68
+ const property = findObjectProperty(descriptionValue, prop);
69
+ if (property?.value.type !== AST_NODE_TYPES.ArrayExpression)
70
+ continue;
71
+ checkArrayElements(property.value.elements, prop);
72
+ }
73
+ },
74
+ };
75
+ },
76
+ });
77
+ //# sourceMappingURL=node-connection-type-literal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-connection-type-literal.js","sourceRoot":"","sources":["../../src/rules/node-connection-type-literal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EACN,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,GACV,MAAM,mBAAmB,CAAC;AAE3B,6EAA6E;AAC7E,yEAAyE;AACzE,MAAM,EAAE,mBAAmB,EAAE,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,cAAc,CAE5E,CAAC;AAEF,yEAAyE;AACzE,+EAA+E;AAC/E,MAAM,iBAAiB,GAA2B,MAAM,CAAC,WAAW,CACnE,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CACvE,CAAC;AAEF,MAAM,CAAC,MAAM,6BAA6B,GAAG,UAAU,CAAC;IACvD,IAAI,EAAE,8BAA8B;IACpC,IAAI,EAAE;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACL,WAAW,EACV,0GAA0G;SAC3G;QACD,QAAQ,EAAE;YACT,qBAAqB,EACpB,gHAAgH;YACjH,sBAAsB,EACrB,iHAAiH;YAClH,4BAA4B,EAC3B,6GAA6G;YAC9G,6BAA6B,EAC5B,8GAA8G;SAC/G;QACD,OAAO,EAAE,MAAM;QACf,MAAM,EAAE,EAAE;KACV;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACb,SAAS,kBAAkB,CAC1B,QAA8C,EAC9C,QAA8B;YAE9B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAChC,IAAI,OAAO,EAAE,IAAI,KAAK,cAAc,CAAC,OAAO;oBAAE,SAAS;gBACvD,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ;oBAAE,SAAS;gBAEhD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;gBAC5B,MAAM,OAAO,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;gBAEzC,IAAI,OAAO,EAAE,CAAC;oBACb,OAAO,CAAC,MAAM,CAAC;wBACd,IAAI,EAAE,OAAO;wBACb,SAAS,EAAE,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,wBAAwB;wBACrF,IAAI,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE;wBACxB,GAAG,CAAC,KAAK;4BACR,OAAO,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,uBAAuB,OAAO,EAAE,CAAC,CAAC;wBACrE,CAAC;qBACD,CAAC,CAAC;gBACJ,CAAC;qBAAM,CAAC;oBACP,OAAO,CAAC,MAAM,CAAC;wBACd,IAAI,EAAE,OAAO;wBACb,SAAS,EACR,QAAQ,KAAK,QAAQ;4BACpB,CAAC,CAAC,8BAA8B;4BAChC,CAAC,CAAC,+BAA+B;wBACnC,IAAI,EAAE,EAAE,KAAK,EAAE;qBACf,CAAC,CAAC;gBACJ,CAAC;YACF,CAAC;QACF,CAAC;QAED,OAAO;YACN,gBAAgB,CAAC,IAAI;gBACpB,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;oBAAE,OAAO;gBAEnC,MAAM,mBAAmB,GAAG,iBAAiB,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;gBACnE,IAAI,CAAC,mBAAmB;oBAAE,OAAO;gBAEjC,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,KAAK,CAAC;gBACnD,IAAI,gBAAgB,EAAE,IAAI,KAAK,cAAc,CAAC,gBAAgB;oBAAE,OAAO;gBAEvE,KAAK,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAU,EAAE,CAAC;oBACnD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC;oBAC5D,IAAI,QAAQ,EAAE,KAAK,CAAC,IAAI,KAAK,cAAc,CAAC,eAAe;wBAAE,SAAS;oBACtE,kBAAkB,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;gBACnD,CAAC;YACF,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const OptionsSortedAlphabeticallyRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"optionsNotSorted", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
2
+ //# sourceMappingURL=options-sorted-alphabetically.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options-sorted-alphabetically.d.ts","sourceRoot":"","sources":["../../src/rules/options-sorted-alphabetically.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,+BAA+B,qJAoH1C,CAAC"}
@@ -0,0 +1,95 @@
1
+ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
2
+ import { isNodeTypeClass, findClassProperty, findObjectProperty, getStringLiteralValue, isFileType, createRule, } from '../utils/index.js';
3
+ export const OptionsSortedAlphabeticallyRule = createRule({
4
+ name: 'options-sorted-alphabetically',
5
+ meta: {
6
+ type: 'suggestion',
7
+ docs: {
8
+ description: 'Enforce alphabetical ordering of options arrays in n8n node properties',
9
+ },
10
+ messages: {
11
+ optionsNotSorted: 'Options in "{{ displayName }}" are not sorted alphabetically. Expected order: {{ expectedOrder }}.',
12
+ },
13
+ schema: [],
14
+ },
15
+ defaultOptions: [],
16
+ create(context) {
17
+ if (!isFileType(context.filename, '.node.ts')) {
18
+ return {};
19
+ }
20
+ const analyzeNodeDescription = (descriptionValue) => {
21
+ if (!descriptionValue || descriptionValue.type !== AST_NODE_TYPES.ObjectExpression) {
22
+ return;
23
+ }
24
+ const propertiesProperty = findObjectProperty(descriptionValue, 'properties');
25
+ if (!propertiesProperty?.value ||
26
+ propertiesProperty.value.type !== AST_NODE_TYPES.ArrayExpression) {
27
+ return;
28
+ }
29
+ for (const property of propertiesProperty.value.elements) {
30
+ if (!property || property.type !== AST_NODE_TYPES.ObjectExpression) {
31
+ continue;
32
+ }
33
+ const typeProperty = findObjectProperty(property, 'type');
34
+ const type = typeProperty ? getStringLiteralValue(typeProperty.value) : null;
35
+ if (type !== 'options') {
36
+ continue;
37
+ }
38
+ const optionsProperty = findObjectProperty(property, 'options');
39
+ if (!optionsProperty?.value ||
40
+ optionsProperty.value.type !== AST_NODE_TYPES.ArrayExpression) {
41
+ continue;
42
+ }
43
+ const optionsArray = optionsProperty.value;
44
+ // Extract all option names; skip if any name is non-literal (dynamic options)
45
+ const names = [];
46
+ let hasDynamicName = false;
47
+ for (const option of optionsArray.elements) {
48
+ if (!option || option.type !== AST_NODE_TYPES.ObjectExpression) {
49
+ hasDynamicName = true;
50
+ break;
51
+ }
52
+ const nameProperty = findObjectProperty(option, 'name');
53
+ const name = nameProperty ? getStringLiteralValue(nameProperty.value) : null;
54
+ if (name === null) {
55
+ hasDynamicName = true;
56
+ break;
57
+ }
58
+ names.push(name);
59
+ }
60
+ if (hasDynamicName || names.length <= 1) {
61
+ continue;
62
+ }
63
+ const sorted = [...names].sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' }));
64
+ const isSorted = names.every((name, i) => name === sorted[i]);
65
+ if (isSorted) {
66
+ continue;
67
+ }
68
+ const displayNameProperty = findObjectProperty(property, 'displayName');
69
+ const displayName = (displayNameProperty ? getStringLiteralValue(displayNameProperty.value) : null) ??
70
+ 'unknown';
71
+ context.report({
72
+ node: optionsArray,
73
+ messageId: 'optionsNotSorted',
74
+ data: {
75
+ displayName,
76
+ expectedOrder: sorted.join(', '),
77
+ },
78
+ });
79
+ }
80
+ };
81
+ return {
82
+ ClassDeclaration(node) {
83
+ if (!isNodeTypeClass(node)) {
84
+ return;
85
+ }
86
+ const descriptionProperty = findClassProperty(node, 'description');
87
+ if (!descriptionProperty) {
88
+ return;
89
+ }
90
+ analyzeNodeDescription(descriptionProperty.value);
91
+ },
92
+ };
93
+ },
94
+ });
95
+ //# sourceMappingURL=options-sorted-alphabetically.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options-sorted-alphabetically.js","sourceRoot":"","sources":["../../src/rules/options-sorted-alphabetically.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EACN,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EACrB,UAAU,EACV,UAAU,GACV,MAAM,mBAAmB,CAAC;AAE3B,MAAM,CAAC,MAAM,+BAA+B,GAAG,UAAU,CAAC;IACzD,IAAI,EAAE,+BAA+B;IACrC,IAAI,EAAE;QACL,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACL,WAAW,EAAE,wEAAwE;SACrF;QACD,QAAQ,EAAE;YACT,gBAAgB,EACf,oGAAoG;SACrG;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,gBAA4C,EAAQ,EAAE;YACrF,IAAI,CAAC,gBAAgB,IAAI,gBAAgB,CAAC,IAAI,KAAK,cAAc,CAAC,gBAAgB,EAAE,CAAC;gBACpF,OAAO;YACR,CAAC;YAED,MAAM,kBAAkB,GAAG,kBAAkB,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAAC;YAC9E,IACC,CAAC,kBAAkB,EAAE,KAAK;gBAC1B,kBAAkB,CAAC,KAAK,CAAC,IAAI,KAAK,cAAc,CAAC,eAAe,EAC/D,CAAC;gBACF,OAAO;YACR,CAAC;YAED,KAAK,MAAM,QAAQ,IAAI,kBAAkB,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;gBAC1D,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,IAAI,KAAK,cAAc,CAAC,gBAAgB,EAAE,CAAC;oBACpE,SAAS;gBACV,CAAC;gBAED,MAAM,YAAY,GAAG,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;gBAC1D,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,qBAAqB,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;gBAE7E,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;oBACxB,SAAS;gBACV,CAAC;gBAED,MAAM,eAAe,GAAG,kBAAkB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;gBAChE,IACC,CAAC,eAAe,EAAE,KAAK;oBACvB,eAAe,CAAC,KAAK,CAAC,IAAI,KAAK,cAAc,CAAC,eAAe,EAC5D,CAAC;oBACF,SAAS;gBACV,CAAC;gBAED,MAAM,YAAY,GAAG,eAAe,CAAC,KAAK,CAAC;gBAE3C,8EAA8E;gBAC9E,MAAM,KAAK,GAAa,EAAE,CAAC;gBAC3B,IAAI,cAAc,GAAG,KAAK,CAAC;gBAE3B,KAAK,MAAM,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,CAAC;oBAC5C,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,cAAc,CAAC,gBAAgB,EAAE,CAAC;wBAChE,cAAc,GAAG,IAAI,CAAC;wBACtB,MAAM;oBACP,CAAC;oBACD,MAAM,YAAY,GAAG,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;oBACxD,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,qBAAqB,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;oBAC7E,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;wBACnB,cAAc,GAAG,IAAI,CAAC;wBACtB,MAAM;oBACP,CAAC;oBACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAClB,CAAC;gBAED,IAAI,cAAc,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;oBACzC,SAAS;gBACV,CAAC;gBAED,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACvC,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CACtD,CAAC;gBAEF,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC9D,IAAI,QAAQ,EAAE,CAAC;oBACd,SAAS;gBACV,CAAC;gBAED,MAAM,mBAAmB,GAAG,kBAAkB,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;gBACxE,MAAM,WAAW,GAChB,CAAC,mBAAmB,CAAC,CAAC,CAAC,qBAAqB,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;oBAC/E,SAAS,CAAC;gBAEX,OAAO,CAAC,MAAM,CAAC;oBACd,IAAI,EAAE,YAAY;oBAClB,SAAS,EAAE,kBAAkB;oBAC7B,IAAI,EAAE;wBACL,WAAW;wBACX,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;qBAChC;iBACD,CAAC,CAAC;YACJ,CAAC;QACF,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,CAAC;oBAC1B,OAAO;gBACR,CAAC;gBAED,sBAAsB,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;YACnD,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC,CAAC"}