@sfdxy/mule-lint 1.20.0 → 1.22.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 (156) hide show
  1. package/README.md +63 -17
  2. package/dist/package.json +1 -1
  3. package/dist/src/core/XPathHelper.d.ts.map +1 -1
  4. package/dist/src/core/XPathHelper.js +8 -0
  5. package/dist/src/core/XPathHelper.js.map +1 -1
  6. package/dist/src/engine/LintEngine.d.ts +22 -0
  7. package/dist/src/engine/LintEngine.d.ts.map +1 -1
  8. package/dist/src/engine/LintEngine.js +105 -18
  9. package/dist/src/engine/LintEngine.js.map +1 -1
  10. package/dist/src/mcp/prompts/index.d.ts +1 -1
  11. package/dist/src/mcp/prompts/index.d.ts.map +1 -1
  12. package/dist/src/mcp/prompts/index.js +62 -1
  13. package/dist/src/mcp/prompts/index.js.map +1 -1
  14. package/dist/src/mcp/resources/index.js +114 -16
  15. package/dist/src/mcp/resources/index.js.map +1 -1
  16. package/dist/src/mcp/tools/getRuleDetails.d.ts.map +1 -1
  17. package/dist/src/mcp/tools/getRuleDetails.js +30 -1
  18. package/dist/src/mcp/tools/getRuleDetails.js.map +1 -1
  19. package/dist/src/rules/api-led/ApikitConsoleProductionRule.d.ts +22 -0
  20. package/dist/src/rules/api-led/ApikitConsoleProductionRule.d.ts.map +1 -0
  21. package/dist/src/rules/api-led/ApikitConsoleProductionRule.js +43 -0
  22. package/dist/src/rules/api-led/ApikitConsoleProductionRule.js.map +1 -0
  23. package/dist/src/rules/api-led/ApikitMainFlowStructureRule.d.ts +24 -0
  24. package/dist/src/rules/api-led/ApikitMainFlowStructureRule.d.ts.map +1 -0
  25. package/dist/src/rules/api-led/ApikitMainFlowStructureRule.js +53 -0
  26. package/dist/src/rules/api-led/ApikitMainFlowStructureRule.js.map +1 -0
  27. package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.d.ts +25 -0
  28. package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.d.ts.map +1 -0
  29. package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.js +59 -0
  30. package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.js.map +1 -0
  31. package/dist/src/rules/connector/EventListenerNullGuardRule.d.ts +24 -0
  32. package/dist/src/rules/connector/EventListenerNullGuardRule.d.ts.map +1 -0
  33. package/dist/src/rules/connector/EventListenerNullGuardRule.js +58 -0
  34. package/dist/src/rules/connector/EventListenerNullGuardRule.js.map +1 -0
  35. package/dist/src/rules/connector/ReplayChannelConfigRule.d.ts +23 -0
  36. package/dist/src/rules/connector/ReplayChannelConfigRule.d.ts.map +1 -0
  37. package/dist/src/rules/connector/ReplayChannelConfigRule.js +52 -0
  38. package/dist/src/rules/connector/ReplayChannelConfigRule.js.map +1 -0
  39. package/dist/src/rules/dataweave/DataWeaveRules.d.ts +11 -4
  40. package/dist/src/rules/dataweave/DataWeaveRules.d.ts.map +1 -1
  41. package/dist/src/rules/dataweave/DataWeaveRules.js +20 -20
  42. package/dist/src/rules/dataweave/DataWeaveRules.js.map +1 -1
  43. package/dist/src/rules/dataweave/DuplicateTransformLogicRule.d.ts +25 -0
  44. package/dist/src/rules/dataweave/DuplicateTransformLogicRule.d.ts.map +1 -0
  45. package/dist/src/rules/dataweave/DuplicateTransformLogicRule.js +63 -0
  46. package/dist/src/rules/dataweave/DuplicateTransformLogicRule.js.map +1 -0
  47. package/dist/src/rules/error-handling/CatchAllLastRule.d.ts +24 -0
  48. package/dist/src/rules/error-handling/CatchAllLastRule.d.ts.map +1 -0
  49. package/dist/src/rules/error-handling/CatchAllLastRule.js +65 -0
  50. package/dist/src/rules/error-handling/CatchAllLastRule.js.map +1 -0
  51. package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.d.ts +28 -0
  52. package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.d.ts.map +1 -0
  53. package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.js +70 -0
  54. package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.js.map +1 -0
  55. package/dist/src/rules/error-handling/ErrorResponseStructureRule.d.ts +23 -0
  56. package/dist/src/rules/error-handling/ErrorResponseStructureRule.d.ts.map +1 -0
  57. package/dist/src/rules/error-handling/ErrorResponseStructureRule.js +73 -0
  58. package/dist/src/rules/error-handling/ErrorResponseStructureRule.js.map +1 -0
  59. package/dist/src/rules/error-handling/GenericErrorRule.d.ts +15 -3
  60. package/dist/src/rules/error-handling/GenericErrorRule.d.ts.map +1 -1
  61. package/dist/src/rules/error-handling/GenericErrorRule.js +58 -18
  62. package/dist/src/rules/error-handling/GenericErrorRule.js.map +1 -1
  63. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.d.ts +14 -15
  64. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.d.ts.map +1 -1
  65. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.js +59 -38
  66. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.js.map +1 -1
  67. package/dist/src/rules/error-handling/TryScopeRule.d.ts +5 -0
  68. package/dist/src/rules/error-handling/TryScopeRule.d.ts.map +1 -1
  69. package/dist/src/rules/error-handling/TryScopeRule.js +30 -7
  70. package/dist/src/rules/error-handling/TryScopeRule.js.map +1 -1
  71. package/dist/src/rules/http/ConnectionIdleTimeoutRule.d.ts +27 -0
  72. package/dist/src/rules/http/ConnectionIdleTimeoutRule.d.ts.map +1 -0
  73. package/dist/src/rules/http/ConnectionIdleTimeoutRule.js +46 -0
  74. package/dist/src/rules/http/ConnectionIdleTimeoutRule.js.map +1 -0
  75. package/dist/src/rules/index.d.ts +1 -1
  76. package/dist/src/rules/index.d.ts.map +1 -1
  77. package/dist/src/rules/index.js +50 -8
  78. package/dist/src/rules/index.js.map +1 -1
  79. package/dist/src/rules/logging/LoggerPayloadRule.d.ts +15 -0
  80. package/dist/src/rules/logging/LoggerPayloadRule.d.ts.map +1 -1
  81. package/dist/src/rules/logging/LoggerPayloadRule.js +48 -4
  82. package/dist/src/rules/logging/LoggerPayloadRule.js.map +1 -1
  83. package/dist/src/rules/operations/FlowRefTargetExistsRule.d.ts +23 -0
  84. package/dist/src/rules/operations/FlowRefTargetExistsRule.d.ts.map +1 -0
  85. package/dist/src/rules/operations/FlowRefTargetExistsRule.js +58 -0
  86. package/dist/src/rules/operations/FlowRefTargetExistsRule.js.map +1 -0
  87. package/dist/src/rules/operations/UnusedFlowRule.d.ts +20 -0
  88. package/dist/src/rules/operations/UnusedFlowRule.d.ts.map +1 -1
  89. package/dist/src/rules/operations/UnusedFlowRule.js +73 -7
  90. package/dist/src/rules/operations/UnusedFlowRule.js.map +1 -1
  91. package/dist/src/rules/operations/UnusedVariableRule.d.ts +31 -0
  92. package/dist/src/rules/operations/UnusedVariableRule.d.ts.map +1 -0
  93. package/dist/src/rules/operations/UnusedVariableRule.js +103 -0
  94. package/dist/src/rules/operations/UnusedVariableRule.js.map +1 -0
  95. package/dist/src/rules/performance/ListenerReconnectForeverRule.d.ts +28 -0
  96. package/dist/src/rules/performance/ListenerReconnectForeverRule.d.ts.map +1 -0
  97. package/dist/src/rules/performance/ListenerReconnectForeverRule.js +56 -0
  98. package/dist/src/rules/performance/ListenerReconnectForeverRule.js.map +1 -0
  99. package/dist/src/rules/performance/ReconnectionStrategyRule.d.ts +7 -4
  100. package/dist/src/rules/performance/ReconnectionStrategyRule.d.ts.map +1 -1
  101. package/dist/src/rules/performance/ReconnectionStrategyRule.js +44 -24
  102. package/dist/src/rules/performance/ReconnectionStrategyRule.js.map +1 -1
  103. package/dist/src/rules/security/ConnectorCredentialsSecuredRule.d.ts +36 -0
  104. package/dist/src/rules/security/ConnectorCredentialsSecuredRule.d.ts.map +1 -0
  105. package/dist/src/rules/security/ConnectorCredentialsSecuredRule.js +124 -0
  106. package/dist/src/rules/security/ConnectorCredentialsSecuredRule.js.map +1 -0
  107. package/dist/src/rules/security/HardcodedCredentialsRule.d.ts +4 -0
  108. package/dist/src/rules/security/HardcodedCredentialsRule.d.ts.map +1 -1
  109. package/dist/src/rules/security/HardcodedCredentialsRule.js +15 -0
  110. package/dist/src/rules/security/HardcodedCredentialsRule.js.map +1 -1
  111. package/dist/src/rules/security/SecurePropertiesEncryptionRule.d.ts +25 -0
  112. package/dist/src/rules/security/SecurePropertiesEncryptionRule.d.ts.map +1 -0
  113. package/dist/src/rules/security/SecurePropertiesEncryptionRule.js +59 -0
  114. package/dist/src/rules/security/SecurePropertiesEncryptionRule.js.map +1 -0
  115. package/dist/src/rules/security/SecurePropertiesKeyRule.d.ts +23 -0
  116. package/dist/src/rules/security/SecurePropertiesKeyRule.d.ts.map +1 -0
  117. package/dist/src/rules/security/SecurePropertiesKeyRule.js +45 -0
  118. package/dist/src/rules/security/SecurePropertiesKeyRule.js.map +1 -0
  119. package/dist/src/rules/security/TlsKeystorePasswordRule.d.ts +25 -0
  120. package/dist/src/rules/security/TlsKeystorePasswordRule.d.ts.map +1 -0
  121. package/dist/src/rules/security/TlsKeystorePasswordRule.js +63 -0
  122. package/dist/src/rules/security/TlsKeystorePasswordRule.js.map +1 -0
  123. package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.d.ts +26 -0
  124. package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.d.ts.map +1 -0
  125. package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.js +61 -0
  126. package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.js.map +1 -0
  127. package/dist/src/rules/standards/ConfigPropertiesOrderingRule.d.ts +34 -0
  128. package/dist/src/rules/standards/ConfigPropertiesOrderingRule.d.ts.map +1 -0
  129. package/dist/src/rules/standards/ConfigPropertiesOrderingRule.js +76 -0
  130. package/dist/src/rules/standards/ConfigPropertiesOrderingRule.js.map +1 -0
  131. package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.d.ts +25 -0
  132. package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.d.ts.map +1 -0
  133. package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.js +111 -0
  134. package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.js.map +1 -0
  135. package/dist/src/rules/yaml/YamlRules.d.ts +6 -2
  136. package/dist/src/rules/yaml/YamlRules.d.ts.map +1 -1
  137. package/dist/src/rules/yaml/YamlRules.js +15 -11
  138. package/dist/src/rules/yaml/YamlRules.js.map +1 -1
  139. package/dist/src/types/Rule.d.ts +13 -0
  140. package/dist/src/types/Rule.d.ts.map +1 -1
  141. package/docs/README.md +87 -27
  142. package/docs/best-practices/ci-cd.md +135 -0
  143. package/docs/best-practices/connector-patterns.md +253 -0
  144. package/docs/best-practices/dataweave-patterns.md +370 -0
  145. package/docs/best-practices/deployment-2026.md +171 -0
  146. package/docs/best-practices/error-handling.md +277 -0
  147. package/docs/best-practices/event-driven-patterns.md +424 -0
  148. package/docs/best-practices/logging.md +163 -0
  149. package/docs/best-practices/mulesoft-best-practices.md +72 -865
  150. package/docs/best-practices/performance.md +273 -0
  151. package/docs/best-practices/rules-catalog.md +337 -29
  152. package/docs/best-practices/security.md +181 -0
  153. package/docs/best-practices/testing.md +190 -0
  154. package/docs/best-practices/variable-contracts.md +191 -0
  155. package/docs/linter/architecture.md +119 -64
  156. package/package.json +1 -1
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ErrorResponseStructureRule = void 0;
4
+ const BaseRule_1 = require("../base/BaseRule");
5
+ const XPathHelper_1 = require("../../core/XPathHelper");
6
+ /**
7
+ * ERR-003: Error Response Structure
8
+ *
9
+ * Error responses should include both a correlationId and a message field
10
+ * for effective debugging and traceability. Real-world accelerator projects
11
+ * consistently use a JSON envelope like:
12
+ * { correlationId: "...", error: "...", message: "..." }
13
+ *
14
+ * This rule checks that ee:set-payload elements inside error handlers
15
+ * contain both correlationId and message in their DataWeave body.
16
+ */
17
+ class ErrorResponseStructureRule extends BaseRule_1.BaseRule {
18
+ id = 'ERR-003';
19
+ name = 'Error Response Structure';
20
+ description = 'Error responses should include correlationId and message fields';
21
+ severity = 'info';
22
+ category = 'error-handling';
23
+ issueType = 'bug';
24
+ validate(doc, _context) {
25
+ const issues = [];
26
+ // Find on-error blocks that contain ee:set-payload (i.e., they build an error response)
27
+ const onErrorBlocks = [
28
+ ...this.select('//mule:on-error-continue', doc),
29
+ ...this.select('//mule:on-error-propagate', doc),
30
+ ];
31
+ for (const block of onErrorBlocks) {
32
+ // Find ee:set-payload within this error block
33
+ const setPayloads = this.select('.//*[local-name()="set-payload" and namespace-uri()="http://www.mulesoft.org/schema/mule/ee/core"]', block);
34
+ if (setPayloads.length === 0) {
35
+ continue; // No payload transformation — skip (might be logging-only)
36
+ }
37
+ for (const sp of setPayloads) {
38
+ const content = (0, XPathHelper_1.getTextContent)(sp).toLowerCase();
39
+ // Also check resource attribute — if present, we can't inspect inline
40
+ const resourceAttr = this.getAttribute(sp, 'resource');
41
+ if (resourceAttr) {
42
+ continue; // External DWL — inspected by MULE-007 (CorrelationIdRule)
43
+ }
44
+ // Skip non-DataWeave content (e.g., static strings)
45
+ if (!content.includes('dw 2.0') && !content.includes('---')) {
46
+ continue;
47
+ }
48
+ const hasCorrelationId = content.includes('correlationid');
49
+ const hasMessage = content.includes('message') || content.includes('detaileddescription');
50
+ if (!hasCorrelationId && !hasMessage) {
51
+ issues.push(this.createIssue(sp, 'Error response payload is missing both correlationId and message fields', {
52
+ suggestion: 'Include correlationId and message in the error response for traceability: { correlationId: vars.correlationId, message: error.detailedDescription }',
53
+ }));
54
+ }
55
+ else if (!hasCorrelationId) {
56
+ issues.push(this.createIssue(sp, 'Error response payload is missing correlationId field', {
57
+ severity: 'info',
58
+ suggestion: 'Add correlationId to the error response: correlationId: vars.correlationId default ""',
59
+ }));
60
+ }
61
+ else if (!hasMessage) {
62
+ issues.push(this.createIssue(sp, 'Error response payload is missing a message or description field', {
63
+ severity: 'info',
64
+ suggestion: 'Add a message field: message: error.detailedDescription default ""',
65
+ }));
66
+ }
67
+ }
68
+ }
69
+ return issues;
70
+ }
71
+ }
72
+ exports.ErrorResponseStructureRule = ErrorResponseStructureRule;
73
+ //# sourceMappingURL=ErrorResponseStructureRule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ErrorResponseStructureRule.js","sourceRoot":"","sources":["../../../../src/rules/error-handling/ErrorResponseStructureRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAC5C,wDAAwD;AAExD;;;;;;;;;;GAUG;AACH,MAAa,0BAA2B,SAAQ,mBAAQ;IACtD,EAAE,GAAG,SAAS,CAAC;IACf,IAAI,GAAG,0BAA0B,CAAC;IAClC,WAAW,GAAG,iEAAiE,CAAC;IAChF,QAAQ,GAAG,MAAe,CAAC;IAC3B,QAAQ,GAAG,gBAAyB,CAAC;IACrC,SAAS,GAAc,KAAK,CAAC;IAE7B,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,wFAAwF;QACxF,MAAM,aAAa,GAAG;YACpB,GAAG,IAAI,CAAC,MAAM,CAAC,0BAA0B,EAAE,GAAG,CAAC;YAC/C,GAAG,IAAI,CAAC,MAAM,CAAC,2BAA2B,EAAE,GAAG,CAAC;SACjD,CAAC;QAEF,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;YAClC,8CAA8C;YAC9C,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAC7B,oGAAoG,EACpG,KAAK,CACN,CAAC;YAEF,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC7B,SAAS,CAAC,2DAA2D;YACvE,CAAC;YAED,KAAK,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;gBAC7B,MAAM,OAAO,GAAG,IAAA,4BAAc,EAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;gBAEjD,sEAAsE;gBACtE,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;gBACvD,IAAI,YAAY,EAAE,CAAC;oBACjB,SAAS,CAAC,2DAA2D;gBACvE,CAAC;gBAED,oDAAoD;gBACpD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC5D,SAAS;gBACX,CAAC;gBAED,MAAM,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;gBAC3D,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC;gBAE1F,IAAI,CAAC,gBAAgB,IAAI,CAAC,UAAU,EAAE,CAAC;oBACrC,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,EAAE,EACF,yEAAyE,EACzE;wBACE,UAAU,EACR,qJAAqJ;qBACxJ,CACF,CACF,CAAC;gBACJ,CAAC;qBAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;oBAC7B,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,uDAAuD,EAAE;wBAC5E,QAAQ,EAAE,MAAM;wBAChB,UAAU,EACR,uFAAuF;qBAC1F,CAAC,CACH,CAAC;gBACJ,CAAC;qBAAM,IAAI,CAAC,UAAU,EAAE,CAAC;oBACvB,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,EAAE,EACF,kEAAkE,EAClE;wBACE,QAAQ,EAAE,MAAM;wBAChB,UAAU,EAAE,oEAAoE;qBACjF,CACF,CACF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAjFD,gEAiFC"}
@@ -3,8 +3,13 @@ import { BaseRule } from '../base/BaseRule';
3
3
  /**
4
4
  * MULE-009: Generic Error Type
5
5
  *
6
- * Avoid catching type="ANY" in error handlers.
7
- * Be specific about error types to handle them appropriately.
6
+ * Avoid catching type="ANY" in error handlers — unless it is the LAST
7
+ * on-error block in the error-handler, where it serves as a catch-all
8
+ * fallback (the accelerator pattern maps this to HTTP 500).
9
+ *
10
+ * Enhanced: only flag type="ANY" when it is NOT the last sibling in
11
+ * its parent error-handler, since a catch-all as the final block is
12
+ * an accepted MuleSoft best practice.
8
13
  */
9
14
  export declare class GenericErrorRule extends BaseRule {
10
15
  id: string;
@@ -16,8 +21,15 @@ export declare class GenericErrorRule extends BaseRule {
16
21
  private readonly GENERIC_TYPES;
17
22
  validate(doc: Document, _context: ValidationContext): Issue[];
18
23
  /**
19
- * Check if handler uses generic error type
24
+ * Check if handler uses generic error type.
25
+ * Skip if this handler is the LAST on-error block in its parent
26
+ * error-handler (catch-all fallback is an accepted pattern).
20
27
  */
21
28
  private checkGenericType;
29
+ /**
30
+ * Returns true if the given on-error node is the last on-error child
31
+ * of its parent error-handler element.
32
+ */
33
+ private isLastOnErrorBlock;
22
34
  }
23
35
  //# sourceMappingURL=GenericErrorRule.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"GenericErrorRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/error-handling/GenericErrorRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;GAKG;AACH,qBAAa,gBAAiB,SAAQ,QAAQ;IAC5C,EAAE,SAAc;IAChB,IAAI,SAAwB;IAC5B,WAAW,SAA+D;IAC1E,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,gBAAgB,CAAU;IACrC,SAAS,EAAE,SAAS,CAAS;IAG7B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAuB;IAErD,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;IAoB7D;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAmBzB"}
1
+ {"version":3,"file":"GenericErrorRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/error-handling/GenericErrorRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;;GAUG;AACH,qBAAa,gBAAiB,SAAQ,QAAQ;IAC5C,EAAE,SAAc;IAChB,IAAI,SAAwB;IAC5B,WAAW,SAA+D;IAC1E,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,gBAAgB,CAAU;IACrC,SAAS,EAAE,SAAS,CAAS;IAG7B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAuB;IAErD,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;IAsB7D;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IA2BxB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;CAuB3B"}
@@ -5,8 +5,13 @@ const BaseRule_1 = require("../base/BaseRule");
5
5
  /**
6
6
  * MULE-009: Generic Error Type
7
7
  *
8
- * Avoid catching type="ANY" in error handlers.
9
- * Be specific about error types to handle them appropriately.
8
+ * Avoid catching type="ANY" in error handlers — unless it is the LAST
9
+ * on-error block in the error-handler, where it serves as a catch-all
10
+ * fallback (the accelerator pattern maps this to HTTP 500).
11
+ *
12
+ * Enhanced: only flag type="ANY" when it is NOT the last sibling in
13
+ * its parent error-handler, since a catch-all as the final block is
14
+ * an accepted MuleSoft best practice.
10
15
  */
11
16
  class GenericErrorRule extends BaseRule_1.BaseRule {
12
17
  id = 'MULE-009';
@@ -19,30 +24,65 @@ class GenericErrorRule extends BaseRule_1.BaseRule {
19
24
  GENERIC_TYPES = ['ANY', 'MULE:ANY'];
20
25
  validate(doc, _context) {
21
26
  const issues = [];
22
- // Find on-error-continue with type="ANY"
23
- const onErrorContinue = this.select('//mule:on-error-continue[@type]', doc);
24
- for (const handler of onErrorContinue) {
25
- this.checkGenericType(handler, 'on-error-continue', issues);
26
- }
27
- // Find on-error-propagate with type="ANY"
28
- const onErrorPropagate = this.select('//mule:on-error-propagate[@type]', doc);
29
- for (const handler of onErrorPropagate) {
30
- this.checkGenericType(handler, 'on-error-propagate', issues);
27
+ // Find all on-error-continue and on-error-propagate with type attribute
28
+ const allHandlers = [
29
+ ...this.select('//mule:on-error-continue[@type]', doc).map((h) => ({
30
+ node: h,
31
+ type: 'on-error-continue',
32
+ })),
33
+ ...this.select('//mule:on-error-propagate[@type]', doc).map((h) => ({
34
+ node: h,
35
+ type: 'on-error-propagate',
36
+ })),
37
+ ];
38
+ for (const handler of allHandlers) {
39
+ this.checkGenericType(handler.node, handler.type, issues);
31
40
  }
32
41
  return issues;
33
42
  }
34
43
  /**
35
- * Check if handler uses generic error type
44
+ * Check if handler uses generic error type.
45
+ * Skip if this handler is the LAST on-error block in its parent
46
+ * error-handler (catch-all fallback is an accepted pattern).
36
47
  */
37
48
  checkGenericType(handler, handlerType, issues) {
38
49
  const errorType = this.getAttribute(handler, 'type');
39
- if (errorType && this.GENERIC_TYPES.includes(errorType.toUpperCase())) {
40
- const docName = this.getDocName(handler);
41
- const displayName = docName ? `"${docName}"` : '';
42
- issues.push(this.createIssue(handler, `${handlerType} ${displayName} uses generic type="${errorType}"`, {
43
- suggestion: 'Catch specific error types (e.g., HTTP:CONNECTIVITY, DB:CONNECTIVITY, VALIDATION:INVALID_JSON) for better error handling',
44
- }));
50
+ if (!errorType || !this.GENERIC_TYPES.includes(errorType.toUpperCase())) {
51
+ return;
52
+ }
53
+ // Check if this is the last on-error sibling in its parent error-handler
54
+ if (this.isLastOnErrorBlock(handler)) {
55
+ return; // Catch-all as last block is fine
56
+ }
57
+ const docName = this.getDocName(handler);
58
+ const displayName = docName ? `"${docName}"` : '';
59
+ issues.push(this.createIssue(handler, `${handlerType} ${displayName} uses generic type="${errorType}" but is not the last error handler — move it to the end or use specific types`, {
60
+ suggestion: 'If this is a catch-all, place it as the last on-error block. Otherwise, catch specific error types (e.g., HTTP:CONNECTIVITY, DB:CONNECTIVITY)',
61
+ }));
62
+ }
63
+ /**
64
+ * Returns true if the given on-error node is the last on-error child
65
+ * of its parent error-handler element.
66
+ */
67
+ isLastOnErrorBlock(handler) {
68
+ const parent = handler.parentNode;
69
+ if (!parent) {
70
+ return true; // No parent, can't determine position — assume last
71
+ }
72
+ // Collect on-error siblings (continue and propagate)
73
+ const siblings = parent.childNodes;
74
+ let lastOnError = null;
75
+ for (let i = 0; i < siblings.length; i++) {
76
+ const sibling = siblings[i];
77
+ if (sibling.nodeType === 1 /* ELEMENT_NODE */) {
78
+ const el = sibling;
79
+ const localName = el.localName ?? el.tagName ?? '';
80
+ if (localName === 'on-error-continue' || localName === 'on-error-propagate') {
81
+ lastOnError = sibling;
82
+ }
83
+ }
45
84
  }
85
+ return lastOnError === handler;
46
86
  }
47
87
  }
48
88
  exports.GenericErrorRule = GenericErrorRule;
@@ -1 +1 @@
1
- {"version":3,"file":"GenericErrorRule.js","sourceRoot":"","sources":["../../../../src/rules/error-handling/GenericErrorRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;GAKG;AACH,MAAa,gBAAiB,SAAQ,mBAAQ;IAC5C,EAAE,GAAG,UAAU,CAAC;IAChB,IAAI,GAAG,oBAAoB,CAAC;IAC5B,WAAW,GAAG,2DAA2D,CAAC;IAC1E,QAAQ,GAAG,SAAkB,CAAC;IAC9B,QAAQ,GAAG,gBAAyB,CAAC;IACrC,SAAS,GAAc,KAAK,CAAC;IAE7B,wBAAwB;IACP,aAAa,GAAG,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IAErD,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,yCAAyC;QACzC,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,CAAC,iCAAiC,EAAE,GAAG,CAAC,CAAC;QAE5E,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;YACtC,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,mBAAmB,EAAE,MAAM,CAAC,CAAC;QAC9D,CAAC;QAED,0CAA0C;QAC1C,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;QAE9E,KAAK,MAAM,OAAO,IAAI,gBAAgB,EAAE,CAAC;YACvC,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,oBAAoB,EAAE,MAAM,CAAC,CAAC;QAC/D,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACK,gBAAgB,CAAC,OAAa,EAAE,WAAmB,EAAE,MAAe;QAC1E,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAErD,IAAI,SAAS,IAAI,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;YACtE,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACzC,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YAElD,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,OAAO,EACP,GAAG,WAAW,IAAI,WAAW,uBAAuB,SAAS,GAAG,EAChE;gBACE,UAAU,EACR,0HAA0H;aAC7H,CACF,CACF,CAAC;QACJ,CAAC;IACH,CAAC;CACF;AArDD,4CAqDC"}
1
+ {"version":3,"file":"GenericErrorRule.js","sourceRoot":"","sources":["../../../../src/rules/error-handling/GenericErrorRule.ts"],"names":[],"mappings":"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"}
@@ -1,30 +1,29 @@
1
1
  import { ValidationContext, Issue, IssueType } from '../../types';
2
- import { BaseRule } from '../base/BaseRule';
2
+ import { ProjectRule } from '../base/ProjectRule';
3
3
  /**
4
4
  * MULE-001: Global Error Handler Exists
5
5
  *
6
6
  * Every Mule project should have a global error handler: either a dedicated
7
- * file (default: global-error-handler.xml) OR any scanned XML file that
8
- * contains a named <error-handler> element.
7
+ * file (default: global-error-handler.xml) OR any XML file in the project
8
+ * that contains a named <error-handler> element.
9
9
  *
10
- * The rule fires on every scanned XML file that:
11
- * 1. Contains at least one <flow> or <sub-flow> (is a flow file), AND
12
- * 2. Does not itself define an <error-handler> element
13
- *
14
- * If neither the expected file exists NOR any named <error-handler> has been
15
- * found in the current document, an issue is raised.
16
- *
17
- * Note: the old guard `context.relativePath.includes('global')` has been
18
- * removed. Restricting reports to only "global" files hid the rule for
19
- * projects that did not follow that naming convention.
10
+ * This is a ProjectRule it runs once per scan (not per file). It scans all
11
+ * XML files in the Mule source directory looking for a named error-handler
12
+ * definition. If none is found and the expected file doesn't exist, it reports
13
+ * a single project-level issue.
20
14
  */
21
- export declare class GlobalErrorHandlerRule extends BaseRule {
15
+ export declare class GlobalErrorHandlerRule extends ProjectRule {
22
16
  id: string;
23
17
  name: string;
24
18
  description: string;
25
19
  severity: "warning";
26
20
  category: "error-handling";
27
21
  issueType: IssueType;
28
- validate(doc: Document, context: ValidationContext): Issue[];
22
+ protected validateProject(context: ValidationContext): Issue[];
23
+ /**
24
+ * Recursively scan a directory for XML files containing a named
25
+ * <error-handler> or <error-handler ref="..."> element.
26
+ */
27
+ private scanForErrorHandler;
29
28
  }
30
29
  //# sourceMappingURL=GlobalErrorHandlerRule.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"GlobalErrorHandlerRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/error-handling/GlobalErrorHandlerRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAI5C;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,sBAAuB,SAAQ,QAAQ;IAClD,EAAE,SAAc;IAChB,IAAI,SAAiC;IACrC,WAAW,SACgF;IAC3F,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,gBAAgB,CAAU;IACrC,SAAS,EAAE,SAAS,CAAS;IAE7B,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,GAAG,KAAK,EAAE;CAoD7D"}
1
+ {"version":3,"file":"GlobalErrorHandlerRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/error-handling/GlobalErrorHandlerRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAKlD;;;;;;;;;;;GAWG;AACH,qBAAa,sBAAuB,SAAQ,WAAW;IACrD,EAAE,SAAc;IAChB,IAAI,SAAiC;IACrC,WAAW,SACgF;IAC3F,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,gBAAgB,CAAU;IACrC,SAAS,EAAE,SAAS,CAAS;IAE7B,SAAS,CAAC,eAAe,CAAC,OAAO,EAAE,iBAAiB,GAAG,KAAK,EAAE;IAqC9D;;;OAGG;IACH,OAAO,CAAC,mBAAmB;CA8B5B"}
@@ -34,66 +34,87 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.GlobalErrorHandlerRule = void 0;
37
- const BaseRule_1 = require("../base/BaseRule");
37
+ const ProjectRule_1 = require("../base/ProjectRule");
38
38
  const FileScanner_1 = require("../../core/FileScanner");
39
39
  const path = __importStar(require("path"));
40
+ const fs = __importStar(require("fs"));
40
41
  /**
41
42
  * MULE-001: Global Error Handler Exists
42
43
  *
43
44
  * Every Mule project should have a global error handler: either a dedicated
44
- * file (default: global-error-handler.xml) OR any scanned XML file that
45
- * contains a named <error-handler> element.
45
+ * file (default: global-error-handler.xml) OR any XML file in the project
46
+ * that contains a named <error-handler> element.
46
47
  *
47
- * The rule fires on every scanned XML file that:
48
- * 1. Contains at least one <flow> or <sub-flow> (is a flow file), AND
49
- * 2. Does not itself define an <error-handler> element
50
- *
51
- * If neither the expected file exists NOR any named <error-handler> has been
52
- * found in the current document, an issue is raised.
53
- *
54
- * Note: the old guard `context.relativePath.includes('global')` has been
55
- * removed. Restricting reports to only "global" files hid the rule for
56
- * projects that did not follow that naming convention.
48
+ * This is a ProjectRule it runs once per scan (not per file). It scans all
49
+ * XML files in the Mule source directory looking for a named error-handler
50
+ * definition. If none is found and the expected file doesn't exist, it reports
51
+ * a single project-level issue.
57
52
  */
58
- class GlobalErrorHandlerRule extends BaseRule_1.BaseRule {
53
+ class GlobalErrorHandlerRule extends ProjectRule_1.ProjectRule {
59
54
  id = 'MULE-001';
60
55
  name = 'Global Error Handler Exists';
61
56
  description = 'Project should have a global error handler configuration for consistent error handling';
62
57
  severity = 'warning';
63
58
  category = 'error-handling';
64
59
  issueType = 'bug';
65
- validate(doc, context) {
66
- const issues = [];
60
+ validateProject(context) {
67
61
  // Get configurable expected file path
68
62
  const expectedFile = this.getOption(context, 'filePath', 'src/main/mule/global-error-handler.xml');
69
63
  const fullPath = path.join(context.projectRoot, expectedFile);
70
- // If the dedicated global error handler file exists, the project satisfies
71
- // the rule regardless of what is in the current file.
64
+ // 1. If the dedicated global error handler file exists, the project
65
+ // satisfies the rule.
72
66
  if ((0, FileScanner_1.fileExists)(fullPath)) {
73
- return issues;
67
+ return [];
74
68
  }
75
- // The expected file does not exist. Check whether the current document
76
- // itself provides a global error handler via:
77
- // (a) a named <error-handler> element, OR
78
- // (b) a flow that references an error handler by ref attribute
79
- const hasNamedErrorHandler = this.exists('//*[local-name()="error-handler"][@name]', doc);
80
- if (hasNamedErrorHandler) {
81
- return issues;
69
+ // 2. Scan all XML files in src/main/mule for a named <error-handler>
70
+ // element or an <error-handler ref="..."> reference.
71
+ const muleDir = path.join(context.projectRoot, 'src/main/mule');
72
+ if (fs.existsSync(muleDir)) {
73
+ const hasErrorHandler = this.scanForErrorHandler(muleDir);
74
+ if (hasErrorHandler) {
75
+ return [];
76
+ }
82
77
  }
83
- const hasErrorHandlerRef = this.exists('//*[local-name()="error-handler"][@ref]', doc);
84
- if (hasErrorHandlerRef) {
85
- return issues;
78
+ return [
79
+ this.createProjectIssue(`Global error handler configuration not found. Expected "${expectedFile}" or a named <error-handler> element in any Mule XML file.`, {
80
+ suggestion: 'Create a global-error-handler.xml file with a named <error-handler> element, or add an <error-handler name="..."> to an existing configuration file',
81
+ }),
82
+ ];
83
+ }
84
+ /**
85
+ * Recursively scan a directory for XML files containing a named
86
+ * <error-handler> or <error-handler ref="..."> element.
87
+ */
88
+ scanForErrorHandler(dir) {
89
+ try {
90
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
91
+ for (const entry of entries) {
92
+ const fullPath = path.join(dir, entry.name);
93
+ if (entry.isDirectory()) {
94
+ if (this.scanForErrorHandler(fullPath)) {
95
+ return true;
96
+ }
97
+ }
98
+ else if (entry.name.endsWith('.xml')) {
99
+ try {
100
+ const content = fs.readFileSync(fullPath, 'utf-8');
101
+ // Quick string check before full parse — avoids parsing every file
102
+ if (content.includes('error-handler') &&
103
+ (/<error-handler\s[^>]*name\s*=/.test(content) ||
104
+ /<error-handler\s[^>]*ref\s*=/.test(content))) {
105
+ return true;
106
+ }
107
+ }
108
+ catch {
109
+ // Unreadable file, skip
110
+ }
111
+ }
112
+ }
86
113
  }
87
- // Only report for files that actually contain flows / sub-flows so that
88
- // pure configuration files (e.g. global.xml without flows) are excluded.
89
- const hasFlows = this.exists('//*[local-name()="flow" or local-name()="sub-flow"]', doc);
90
- if (!hasFlows) {
91
- return issues;
114
+ catch {
115
+ // Unreadable directory
92
116
  }
93
- issues.push(this.createFileIssue(`Global error handler configuration not found. Expected "${expectedFile}" or a named <error-handler> element in any flow file.`, {
94
- suggestion: 'Create a global-error-handler.xml file with a named <error-handler> element, or add an <error-handler name="..."> to an existing configuration file',
95
- }));
96
- return issues;
117
+ return false;
97
118
  }
98
119
  }
99
120
  exports.GlobalErrorHandlerRule = GlobalErrorHandlerRule;
@@ -1 +1 @@
1
- {"version":3,"file":"GlobalErrorHandlerRule.js","sourceRoot":"","sources":["../../../../src/rules/error-handling/GlobalErrorHandlerRule.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,+CAA4C;AAC5C,wDAAoD;AACpD,2CAA6B;AAE7B;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAa,sBAAuB,SAAQ,mBAAQ;IAClD,EAAE,GAAG,UAAU,CAAC;IAChB,IAAI,GAAG,6BAA6B,CAAC;IACrC,WAAW,GACT,wFAAwF,CAAC;IAC3F,QAAQ,GAAG,SAAkB,CAAC;IAC9B,QAAQ,GAAG,gBAAyB,CAAC;IACrC,SAAS,GAAc,KAAK,CAAC;IAE7B,QAAQ,CAAC,GAAa,EAAE,OAA0B;QAChD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,sCAAsC;QACtC,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CACjC,OAAO,EACP,UAAU,EACV,wCAAwC,CACzC,CAAC;QAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;QAE9D,2EAA2E;QAC3E,sDAAsD;QACtD,IAAI,IAAA,wBAAU,EAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,wEAAwE;QACxE,8CAA8C;QAC9C,4CAA4C;QAC5C,iEAAiE;QACjE,MAAM,oBAAoB,GAAG,IAAI,CAAC,MAAM,CAAC,0CAA0C,EAAE,GAAG,CAAC,CAAC;QAC1F,IAAI,oBAAoB,EAAE,CAAC;YACzB,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,kBAAkB,GAAG,IAAI,CAAC,MAAM,CAAC,yCAAyC,EAAE,GAAG,CAAC,CAAC;QACvF,IAAI,kBAAkB,EAAE,CAAC;YACvB,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,wEAAwE;QACxE,yEAAyE;QACzE,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,qDAAqD,EAAE,GAAG,CAAC,CAAC;QAEzF,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,eAAe,CAClB,2DAA2D,YAAY,wDAAwD,EAC/H;YACE,UAAU,EACR,qJAAqJ;SACxJ,CACF,CACF,CAAC;QAEF,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AA7DD,wDA6DC"}
1
+ {"version":3,"file":"GlobalErrorHandlerRule.js","sourceRoot":"","sources":["../../../../src/rules/error-handling/GlobalErrorHandlerRule.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,qDAAkD;AAClD,wDAAoD;AACpD,2CAA6B;AAC7B,uCAAyB;AAEzB;;;;;;;;;;;GAWG;AACH,MAAa,sBAAuB,SAAQ,yBAAW;IACrD,EAAE,GAAG,UAAU,CAAC;IAChB,IAAI,GAAG,6BAA6B,CAAC;IACrC,WAAW,GACT,wFAAwF,CAAC;IAC3F,QAAQ,GAAG,SAAkB,CAAC;IAC9B,QAAQ,GAAG,gBAAyB,CAAC;IACrC,SAAS,GAAc,KAAK,CAAC;IAEnB,eAAe,CAAC,OAA0B;QAClD,sCAAsC;QACtC,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CACjC,OAAO,EACP,UAAU,EACV,wCAAwC,CACzC,CAAC;QAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;QAE9D,oEAAoE;QACpE,yBAAyB;QACzB,IAAI,IAAA,wBAAU,EAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,qEAAqE;QACrE,wDAAwD;QACxD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC;QAChE,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3B,MAAM,eAAe,GAAG,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;YAC1D,IAAI,eAAe,EAAE,CAAC;gBACpB,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;QAED,OAAO;YACL,IAAI,CAAC,kBAAkB,CACrB,2DAA2D,YAAY,4DAA4D,EACnI;gBACE,UAAU,EACR,qJAAqJ;aACxJ,CACF;SACF,CAAC;IACJ,CAAC;IAED;;;OAGG;IACK,mBAAmB,CAAC,GAAW;QACrC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAC7D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC5C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;oBACxB,IAAI,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,EAAE,CAAC;wBACvC,OAAO,IAAI,CAAC;oBACd,CAAC;gBACH,CAAC;qBAAM,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;oBACvC,IAAI,CAAC;wBACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;wBACnD,mEAAmE;wBACnE,IACE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;4BACjC,CAAC,+BAA+B,CAAC,IAAI,CAAC,OAAO,CAAC;gCAC5C,8BAA8B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAC/C,CAAC;4BACD,OAAO,IAAI,CAAC;wBACd,CAAC;oBACH,CAAC;oBAAC,MAAM,CAAC;wBACP,wBAAwB;oBAC1B,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,uBAAuB;QACzB,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAhFD,wDAgFC"}
@@ -5,6 +5,10 @@ import { BaseRule } from '../base/BaseRule';
5
5
  *
6
6
  * Complex operations (DB calls, HTTP requests) should use Try scope
7
7
  * for granular error isolation and handling.
8
+ *
9
+ * Enhanced to also check sub-flows containing http:request without
10
+ * Try scope — sub-flows are often called from multiple places and
11
+ * should handle their own errors for isolation.
8
12
  */
9
13
  export declare class TryScopeRule extends BaseRule {
10
14
  id: string;
@@ -14,5 +18,6 @@ export declare class TryScopeRule extends BaseRule {
14
18
  category: "error-handling";
15
19
  issueType: IssueType;
16
20
  validate(doc: Document, _context: ValidationContext): Issue[];
21
+ private countRiskyOperations;
17
22
  }
18
23
  //# sourceMappingURL=TryScopeRule.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TryScopeRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/error-handling/TryScopeRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;GAKG;AACH,qBAAa,YAAa,SAAQ,QAAQ;IACxC,EAAE,SAAa;IACf,IAAI,SAA6B;IACjC,WAAW,SAAiE;IAC5E,QAAQ,EAAG,MAAM,CAAU;IAC3B,QAAQ,EAAG,gBAAgB,CAAU;IACrC,SAAS,EAAE,SAAS,CAAS;IAE7B,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;CAyC9D"}
1
+ {"version":3,"file":"TryScopeRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/error-handling/TryScopeRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;GASG;AACH,qBAAa,YAAa,SAAQ,QAAQ;IACxC,EAAE,SAAa;IACf,IAAI,SAA6B;IACjC,WAAW,SAAiE;IAC5E,QAAQ,EAAG,MAAM,CAAU;IAC3B,QAAQ,EAAG,gBAAgB,CAAU;IACrC,SAAS,EAAE,SAAS,CAAS;IAE7B,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;IA8D7D,OAAO,CAAC,oBAAoB;CAe7B"}
@@ -7,6 +7,10 @@ const BaseRule_1 = require("../base/BaseRule");
7
7
  *
8
8
  * Complex operations (DB calls, HTTP requests) should use Try scope
9
9
  * for granular error isolation and handling.
10
+ *
11
+ * Enhanced to also check sub-flows containing http:request without
12
+ * Try scope — sub-flows are often called from multiple places and
13
+ * should handle their own errors for isolation.
10
14
  */
11
15
  class TryScopeRule extends BaseRule_1.BaseRule {
12
16
  id = 'ERR-001';
@@ -17,26 +21,45 @@ class TryScopeRule extends BaseRule_1.BaseRule {
17
21
  issueType = 'bug';
18
22
  validate(doc, _context) {
19
23
  const issues = [];
20
- // Find flows with multiple risky operations
21
- const flows = this.select('//*[local-name()="flow"]', doc);
24
+ // Find flows and sub-flows with risky operations
25
+ const flows = this.select('//mule:flow', doc);
26
+ const subFlows = this.select('//mule:sub-flow', doc);
22
27
  for (const flow of flows) {
23
28
  const flowElement = flow;
24
29
  const flowName = flowElement.getAttribute('name') ?? 'unnamed';
25
30
  // Count risky operations (DB, HTTP, external calls)
26
- const dbOperations = this.select('.//*[namespace-uri()="http://www.mulesoft.org/schema/mule/db"]', flow);
27
- const httpRequests = this.select('.//*[local-name()="request" and namespace-uri()="http://www.mulesoft.org/schema/mule/http"]', flow);
28
- const externalCalls = [...dbOperations, ...httpRequests];
31
+ const riskyOps = this.countRiskyOperations(flow);
29
32
  // Check if Try scope exists
30
33
  const tryScopes = this.select('.//*[local-name()="try"]', flow);
31
34
  // If multiple external calls but no Try scope
32
- if (externalCalls.length >= 2 && tryScopes.length === 0) {
33
- issues.push(this.createIssue(flow, `Flow "${flowName}" has ${externalCalls.length} external calls without Try scope isolation`, {
35
+ if (riskyOps >= 2 && tryScopes.length === 0) {
36
+ issues.push(this.createIssue(flow, `Flow "${flowName}" has ${String(riskyOps)} external calls without Try scope isolation`, {
34
37
  suggestion: 'Wrap risky operations in Try scope for granular error handling and isolation',
35
38
  }));
36
39
  }
37
40
  }
41
+ // Sub-flows with http:request should also use Try scope
42
+ for (const subFlow of subFlows) {
43
+ const subFlowElement = subFlow;
44
+ const subFlowName = subFlowElement.getAttribute('name') ?? 'unnamed';
45
+ const httpRequests = this.select('.//*[local-name()="request" and namespace-uri()="http://www.mulesoft.org/schema/mule/http"]', subFlow);
46
+ if (httpRequests.length > 0) {
47
+ const tryScopes = this.select('.//*[local-name()="try"]', subFlow);
48
+ if (tryScopes.length === 0) {
49
+ issues.push(this.createIssue(subFlow, `Sub-flow "${subFlowName}" contains http:request without Try scope — errors will propagate to all callers`, {
50
+ suggestion: 'Wrap the http:request in a Try scope within the sub-flow for isolated error handling',
51
+ }));
52
+ }
53
+ }
54
+ }
38
55
  return issues;
39
56
  }
57
+ countRiskyOperations(node) {
58
+ const dbOps = this.select('.//*[namespace-uri()="http://www.mulesoft.org/schema/mule/db"]', node);
59
+ const httpReqs = this.select('.//*[local-name()="request" and namespace-uri()="http://www.mulesoft.org/schema/mule/http"]', node);
60
+ const wsConsumers = this.select('.//*[local-name()="consume" and namespace-uri()="http://www.mulesoft.org/schema/mule/wsc"]', node);
61
+ return dbOps.length + httpReqs.length + wsConsumers.length;
62
+ }
40
63
  }
41
64
  exports.TryScopeRule = TryScopeRule;
42
65
  //# sourceMappingURL=TryScopeRule.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TryScopeRule.js","sourceRoot":"","sources":["../../../../src/rules/error-handling/TryScopeRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;GAKG;AACH,MAAa,YAAa,SAAQ,mBAAQ;IACxC,EAAE,GAAG,SAAS,CAAC;IACf,IAAI,GAAG,yBAAyB,CAAC;IACjC,WAAW,GAAG,6DAA6D,CAAC;IAC5E,QAAQ,GAAG,MAAe,CAAC;IAC3B,QAAQ,GAAG,gBAAyB,CAAC;IACrC,SAAS,GAAc,KAAK,CAAC;IAE7B,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,4CAA4C;QAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,0BAA0B,EAAE,GAAG,CAAC,CAAC;QAE3D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,WAAW,GAAG,IAAe,CAAC;YACpC,MAAM,QAAQ,GAAG,WAAW,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC;YAE/D,oDAAoD;YACpD,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAC9B,gEAAgE,EAChE,IAAI,CACL,CAAC;YACF,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAC9B,6FAA6F,EAC7F,IAAI,CACL,CAAC;YACF,MAAM,aAAa,GAAG,CAAC,GAAG,YAAY,EAAE,GAAG,YAAY,CAAC,CAAC;YAEzD,4BAA4B;YAC5B,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,0BAA0B,EAAE,IAAI,CAAC,CAAC;YAEhE,8CAA8C;YAC9C,IAAI,aAAa,CAAC,MAAM,IAAI,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxD,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,IAAI,EACJ,SAAS,QAAQ,SAAS,aAAa,CAAC,MAAM,6CAA6C,EAC3F;oBACE,UAAU,EACR,8EAA8E;iBACjF,CACF,CACF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAjDD,oCAiDC"}
1
+ {"version":3,"file":"TryScopeRule.js","sourceRoot":"","sources":["../../../../src/rules/error-handling/TryScopeRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;;;;;GASG;AACH,MAAa,YAAa,SAAQ,mBAAQ;IACxC,EAAE,GAAG,SAAS,CAAC;IACf,IAAI,GAAG,yBAAyB,CAAC;IACjC,WAAW,GAAG,6DAA6D,CAAC;IAC5E,QAAQ,GAAG,MAAe,CAAC;IAC3B,QAAQ,GAAG,gBAAyB,CAAC;IACrC,SAAS,GAAc,KAAK,CAAC;IAE7B,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,iDAAiD;QACjD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;QAErD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,WAAW,GAAG,IAAe,CAAC;YACpC,MAAM,QAAQ,GAAG,WAAW,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC;YAE/D,oDAAoD;YACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC;YAEjD,4BAA4B;YAC5B,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,0BAA0B,EAAE,IAAI,CAAC,CAAC;YAEhE,8CAA8C;YAC9C,IAAI,QAAQ,IAAI,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5C,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,IAAI,EACJ,SAAS,QAAQ,SAAS,MAAM,CAAC,QAAQ,CAAC,6CAA6C,EACvF;oBACE,UAAU,EACR,8EAA8E;iBACjF,CACF,CACF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,wDAAwD;QACxD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,cAAc,GAAG,OAAkB,CAAC;YAC1C,MAAM,WAAW,GAAG,cAAc,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC;YAErE,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAC9B,6FAA6F,EAC7F,OAAO,CACR,CAAC;YAEF,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC5B,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,0BAA0B,EAAE,OAAO,CAAC,CAAC;gBACnE,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC3B,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,OAAO,EACP,aAAa,WAAW,kFAAkF,EAC1G;wBACE,UAAU,EACR,sFAAsF;qBACzF,CACF,CACF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,oBAAoB,CAAC,IAAU;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CACvB,gEAAgE,EAChE,IAAI,CACL,CAAC;QACF,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAC1B,6FAA6F,EAC7F,IAAI,CACL,CAAC;QACF,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAC7B,4FAA4F,EAC5F,IAAI,CACL,CAAC;QACF,OAAO,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC;IAC7D,CAAC;CACF;AArFD,oCAqFC"}
@@ -0,0 +1,27 @@
1
+ import { ValidationContext, Issue } from '../../types';
2
+ import { BaseRule } from '../base/BaseRule';
3
+ /**
4
+ * HTTP-004: Connection Idle Timeout
5
+ *
6
+ * HTTP request-connection elements should configure an idle timeout
7
+ * to prevent stale connections from accumulating in the pool.
8
+ * Without idle timeout, connections may linger and consume resources
9
+ * even when not actively in use.
10
+ *
11
+ * Accelerator pattern:
12
+ * <http:request-connection>
13
+ * <http:client-socket-properties>
14
+ * <sockets:tcp-client-socket-properties connectionTimeout="10000"
15
+ * clientTimeout="30000"/>
16
+ * </http:client-socket-properties>
17
+ * </http:request-connection>
18
+ */
19
+ export declare class ConnectionIdleTimeoutRule extends BaseRule {
20
+ id: string;
21
+ name: string;
22
+ description: string;
23
+ severity: "info";
24
+ category: "http";
25
+ validate(doc: Document, _context: ValidationContext): Issue[];
26
+ }
27
+ //# sourceMappingURL=ConnectionIdleTimeoutRule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConnectionIdleTimeoutRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/http/ConnectionIdleTimeoutRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,yBAA0B,SAAQ,QAAQ;IACrD,EAAE,SAAc;IAChB,IAAI,SAA6B;IACjC,WAAW,SACkF;IAC7F,QAAQ,EAAG,MAAM,CAAU;IAC3B,QAAQ,EAAG,MAAM,CAAU;IAE3B,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;CAiC9D"}
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConnectionIdleTimeoutRule = void 0;
4
+ const BaseRule_1 = require("../base/BaseRule");
5
+ /**
6
+ * HTTP-004: Connection Idle Timeout
7
+ *
8
+ * HTTP request-connection elements should configure an idle timeout
9
+ * to prevent stale connections from accumulating in the pool.
10
+ * Without idle timeout, connections may linger and consume resources
11
+ * even when not actively in use.
12
+ *
13
+ * Accelerator pattern:
14
+ * <http:request-connection>
15
+ * <http:client-socket-properties>
16
+ * <sockets:tcp-client-socket-properties connectionTimeout="10000"
17
+ * clientTimeout="30000"/>
18
+ * </http:client-socket-properties>
19
+ * </http:request-connection>
20
+ */
21
+ class ConnectionIdleTimeoutRule extends BaseRule_1.BaseRule {
22
+ id = 'HTTP-004';
23
+ name = 'Connection Idle Timeout';
24
+ description = 'HTTP request configs should configure connection/idle timeouts to prevent resource leaks';
25
+ severity = 'info';
26
+ category = 'http';
27
+ validate(doc, _context) {
28
+ const issues = [];
29
+ // Find HTTP request-config elements
30
+ const requestConfigs = this.select('//*[local-name()="request-config"]', doc);
31
+ for (const config of requestConfigs) {
32
+ const configName = this.getNameAttribute(config) ?? 'HTTP Request Config';
33
+ // Check for useSendBuffer, connectionIdleTimeout, or socket properties
34
+ const hasIdleTimeout = this.getAttribute(config, 'connectionIdleTimeout') !== null;
35
+ const hasSocketProps = this.exists('.//*[local-name()="tcp-client-socket-properties" or local-name()="client-socket-properties"]', config);
36
+ if (!hasIdleTimeout && !hasSocketProps) {
37
+ issues.push(this.createIssue(config, `HTTP request config "${configName}" has no connection idle timeout or socket properties configured`, {
38
+ suggestion: 'Add connectionIdleTimeout="30000" on the config, or configure <http:client-socket-properties> with tcp-client-socket-properties for fine-grained control',
39
+ }));
40
+ }
41
+ }
42
+ return issues;
43
+ }
44
+ }
45
+ exports.ConnectionIdleTimeoutRule = ConnectionIdleTimeoutRule;
46
+ //# sourceMappingURL=ConnectionIdleTimeoutRule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConnectionIdleTimeoutRule.js","sourceRoot":"","sources":["../../../../src/rules/http/ConnectionIdleTimeoutRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;;;;;;;;;;;GAeG;AACH,MAAa,yBAA0B,SAAQ,mBAAQ;IACrD,EAAE,GAAG,UAAU,CAAC;IAChB,IAAI,GAAG,yBAAyB,CAAC;IACjC,WAAW,GACT,0FAA0F,CAAC;IAC7F,QAAQ,GAAG,MAAe,CAAC;IAC3B,QAAQ,GAAG,MAAe,CAAC;IAE3B,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,oCAAoC;QACpC,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC,oCAAoC,EAAE,GAAG,CAAC,CAAC;QAE9E,KAAK,MAAM,MAAM,IAAI,cAAc,EAAE,CAAC;YACpC,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,IAAI,qBAAqB,CAAC;YAE1E,uEAAuE;YACvE,MAAM,cAAc,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,uBAAuB,CAAC,KAAK,IAAI,CAAC;YAEnF,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAChC,8FAA8F,EAC9F,MAAM,CACP,CAAC;YAEF,IAAI,CAAC,cAAc,IAAI,CAAC,cAAc,EAAE,CAAC;gBACvC,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,MAAM,EACN,wBAAwB,UAAU,kEAAkE,EACpG;oBACE,UAAU,EACR,0JAA0J;iBAC7J,CACF,CACF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAzCD,8DAyCC"}
@@ -28,7 +28,7 @@ export { AsyncErrorHandlerRule } from './performance/AsyncErrorHandlerRule';
28
28
  export { LargeChoiceBlockRule } from './performance/LargeChoiceBlockRule';
29
29
  /**
30
30
  * All available rules - instantiated and ready to use
31
- * Total: 56 rules (including operations, resilience, and hygiene rules)
31
+ * Total: 82 rules (including operations, resilience, hygiene, API-led, connector, and code quality rules)
32
32
  */
33
33
  export declare const ALL_RULES: Rule[];
34
34
  /**