@replikanti/flowlint-core 0.10.0 → 0.12.1

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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @replikanti/flowlint-core
2
2
 
3
- ![Coverage](https://img.shields.io/badge/coverage-86.48%25-green)
3
+ ![Coverage](https://img.shields.io/badge/coverage-86.84%25-green)
4
4
 
5
5
  Core static analysis engine for [n8n](https://n8n.io) workflows. This package contains the parser, rules engine, and default rule definitions.
6
6
 
@@ -70,6 +70,7 @@ This package includes 14 built-in rules:
70
70
  | R12 | Unhandled error path | must |
71
71
  | R13 | Webhook acknowledgment | must |
72
72
  | R14 | Retry-After compliance | should |
73
+ | R15 | Error handler set in settings | must |
73
74
 
74
75
  ## License
75
76
 
package/dist/index.d.mts CHANGED
@@ -56,6 +56,9 @@ interface RetryAfterComplianceConfig {
56
56
  suggest_exponential_backoff?: boolean;
57
57
  suggest_jitter?: boolean;
58
58
  }
59
+ interface ErrorHandlerSetInSettingsConfig {
60
+ enabled: boolean;
61
+ }
59
62
  interface RulesConfig {
60
63
  rate_limit_retry: RateLimitRetryConfig;
61
64
  error_handling: ErrorHandlingConfig;
@@ -71,6 +74,7 @@ interface RulesConfig {
71
74
  config_literals: ConfigLiteralsConfig;
72
75
  webhook_acknowledgment: WebhookAcknowledgmentConfig;
73
76
  retry_after_compliance: RetryAfterComplianceConfig;
77
+ error_handler_set_in_settings: ErrorHandlerSetInSettingsConfig;
74
78
  }
75
79
  interface FilesConfig {
76
80
  include: string[];
@@ -168,7 +172,7 @@ type RuleContext = {
168
172
  cfg: FlowLintConfig;
169
173
  nodeLines?: Record<string, number>;
170
174
  };
171
- declare function runAllRules(graph: Graph, ctx: RuleContext): Finding[];
175
+ declare function runAllRules(graph: Graph, ctx: RuleContext, extraRules?: RuleRunner[]): Finding[];
172
176
 
173
177
  interface RuleMetadata {
174
178
  id: string;
package/dist/index.d.ts CHANGED
@@ -56,6 +56,9 @@ interface RetryAfterComplianceConfig {
56
56
  suggest_exponential_backoff?: boolean;
57
57
  suggest_jitter?: boolean;
58
58
  }
59
+ interface ErrorHandlerSetInSettingsConfig {
60
+ enabled: boolean;
61
+ }
59
62
  interface RulesConfig {
60
63
  rate_limit_retry: RateLimitRetryConfig;
61
64
  error_handling: ErrorHandlingConfig;
@@ -71,6 +74,7 @@ interface RulesConfig {
71
74
  config_literals: ConfigLiteralsConfig;
72
75
  webhook_acknowledgment: WebhookAcknowledgmentConfig;
73
76
  retry_after_compliance: RetryAfterComplianceConfig;
77
+ error_handler_set_in_settings: ErrorHandlerSetInSettingsConfig;
74
78
  }
75
79
  interface FilesConfig {
76
80
  include: string[];
@@ -168,7 +172,7 @@ type RuleContext = {
168
172
  cfg: FlowLintConfig;
169
173
  nodeLines?: Record<string, number>;
170
174
  };
171
- declare function runAllRules(graph: Graph, ctx: RuleContext): Finding[];
175
+ declare function runAllRules(graph: Graph, ctx: RuleContext, extraRules?: RuleRunner[]): Finding[];
172
176
 
173
177
  interface RuleMetadata {
174
178
  id: string;
package/dist/index.js CHANGED
@@ -401,6 +401,11 @@ function findAllUpstreamNodes(graph, startNodeId) {
401
401
  }
402
402
  return visited;
403
403
  }
404
+ function isMainWorkflow(graph) {
405
+ return graph.nodes.some(
406
+ (node) => /trigger|webhook|schedule|form|\bstart\b/i.test(node.type) && !/executeworkflow/i.test(node.type) && !/manualTrigger/i.test(node.type)
407
+ );
408
+ }
404
409
  var EXAMPLES_BASE_URL = "https://github.com/Replikanti/flowlint-examples/tree/main";
405
410
  function getExampleLink(ruleId) {
406
411
  return `${EXAMPLES_BASE_URL}/${ruleId}`;
@@ -615,7 +620,8 @@ function parseN8n(doc) {
615
620
  edges,
616
621
  meta: {
617
622
  credentials: !!parsed.credentials,
618
- nodeLines: Object.fromEntries(nodeLines)
623
+ nodeLines: Object.fromEntries(nodeLines),
624
+ settings: parsed.settings
619
625
  }
620
626
  };
621
627
  }
@@ -1159,6 +1165,40 @@ var r14RetryAfterCompliance = createNodeRule(metadata14.id, metadata14.name, (no
1159
1165
  };
1160
1166
  });
1161
1167
 
1168
+ // src/rules/lib/r15-error-handler-set-in-settings.ts
1169
+ var metadata15 = {
1170
+ id: "R15",
1171
+ name: "error_handler_set_in_settings",
1172
+ severity: "must",
1173
+ description: "Ensures main workflows have an error handler workflow configured in settings",
1174
+ details: "Main workflows (triggered by webhook, schedule, form, etc.) should have settings.errorWorkflow set to receive error notifications. Sub-workflows (Execute Workflow Trigger) are excluded from this check."
1175
+ };
1176
+ function getWorkflowSettings(meta) {
1177
+ const settings = meta.settings;
1178
+ if (settings != null && typeof settings === "object" && !Array.isArray(settings)) {
1179
+ return settings;
1180
+ }
1181
+ return void 0;
1182
+ }
1183
+ function r15ErrorHandlerSetInSettings(graph, ctx) {
1184
+ const cfg = ctx.cfg.rules.error_handler_set_in_settings;
1185
+ if (!cfg?.enabled) return [];
1186
+ if (!isMainWorkflow(graph)) return [];
1187
+ const settings = getWorkflowSettings(graph.meta);
1188
+ if (settings?.errorWorkflow && typeof settings.errorWorkflow === "string" && settings.errorWorkflow.trim().length > 0) {
1189
+ return [];
1190
+ }
1191
+ return [
1192
+ {
1193
+ rule: metadata15.id,
1194
+ severity: metadata15.severity,
1195
+ path: ctx.path,
1196
+ message: "Main workflow does not have an error handler workflow configured in settings",
1197
+ raw_details: "Set settings.errorWorkflow to a valid workflow ID so that runtime errors trigger a notification workflow."
1198
+ }
1199
+ ];
1200
+ }
1201
+
1162
1202
  // src/rules/index.ts
1163
1203
  var rules = [
1164
1204
  r1Retry,
@@ -1174,10 +1214,11 @@ var rules = [
1174
1214
  r11DeprecatedNodes,
1175
1215
  r12UnhandledErrorPath,
1176
1216
  r13WebhookAcknowledgment,
1177
- r14RetryAfterCompliance
1217
+ r14RetryAfterCompliance,
1218
+ r15ErrorHandlerSetInSettings
1178
1219
  ];
1179
- function runAllRules(graph, ctx) {
1180
- return rules.flatMap((rule) => rule(graph, ctx));
1220
+ function runAllRules(graph, ctx, extraRules = []) {
1221
+ return [...rules, ...extraRules].flatMap((rule) => rule(graph, ctx));
1181
1222
  }
1182
1223
 
1183
1224
  // src/rules/metadata.ts
@@ -1195,7 +1236,8 @@ var RULES_METADATA = [
1195
1236
  metadata11,
1196
1237
  metadata12,
1197
1238
  metadata13,
1198
- metadata14
1239
+ metadata14,
1240
+ metadata15
1199
1241
  ];
1200
1242
 
1201
1243
  // src/config/default-config.ts
@@ -1263,7 +1305,8 @@ var defaultConfig = {
1263
1305
  enabled: true,
1264
1306
  suggest_exponential_backoff: true,
1265
1307
  suggest_jitter: true
1266
- }
1308
+ },
1309
+ error_handler_set_in_settings: { enabled: true }
1267
1310
  }
1268
1311
  };
1269
1312