@sfdxy/mule-lint 1.19.0 → 1.21.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 (154) hide show
  1. package/README.md +128 -73
  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 +32 -0
  7. package/dist/src/engine/LintEngine.d.ts.map +1 -1
  8. package/dist/src/engine/LintEngine.js +166 -15
  9. package/dist/src/engine/LintEngine.js.map +1 -1
  10. package/dist/src/rules/api-led/ApikitConsoleProductionRule.d.ts +22 -0
  11. package/dist/src/rules/api-led/ApikitConsoleProductionRule.d.ts.map +1 -0
  12. package/dist/src/rules/api-led/ApikitConsoleProductionRule.js +43 -0
  13. package/dist/src/rules/api-led/ApikitConsoleProductionRule.js.map +1 -0
  14. package/dist/src/rules/api-led/ApikitMainFlowStructureRule.d.ts +24 -0
  15. package/dist/src/rules/api-led/ApikitMainFlowStructureRule.d.ts.map +1 -0
  16. package/dist/src/rules/api-led/ApikitMainFlowStructureRule.js +53 -0
  17. package/dist/src/rules/api-led/ApikitMainFlowStructureRule.js.map +1 -0
  18. package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.d.ts +25 -0
  19. package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.d.ts.map +1 -0
  20. package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.js +59 -0
  21. package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.js.map +1 -0
  22. package/dist/src/rules/connector/EventListenerNullGuardRule.d.ts +24 -0
  23. package/dist/src/rules/connector/EventListenerNullGuardRule.d.ts.map +1 -0
  24. package/dist/src/rules/connector/EventListenerNullGuardRule.js +58 -0
  25. package/dist/src/rules/connector/EventListenerNullGuardRule.js.map +1 -0
  26. package/dist/src/rules/connector/ReplayChannelConfigRule.d.ts +23 -0
  27. package/dist/src/rules/connector/ReplayChannelConfigRule.d.ts.map +1 -0
  28. package/dist/src/rules/connector/ReplayChannelConfigRule.js +52 -0
  29. package/dist/src/rules/connector/ReplayChannelConfigRule.js.map +1 -0
  30. package/dist/src/rules/dataweave/DataWeaveRules.d.ts +17 -4
  31. package/dist/src/rules/dataweave/DataWeaveRules.d.ts.map +1 -1
  32. package/dist/src/rules/dataweave/DataWeaveRules.js +36 -20
  33. package/dist/src/rules/dataweave/DataWeaveRules.js.map +1 -1
  34. package/dist/src/rules/dataweave/DuplicateTransformLogicRule.d.ts +25 -0
  35. package/dist/src/rules/dataweave/DuplicateTransformLogicRule.d.ts.map +1 -0
  36. package/dist/src/rules/dataweave/DuplicateTransformLogicRule.js +63 -0
  37. package/dist/src/rules/dataweave/DuplicateTransformLogicRule.js.map +1 -0
  38. package/dist/src/rules/error-handling/CatchAllLastRule.d.ts +24 -0
  39. package/dist/src/rules/error-handling/CatchAllLastRule.d.ts.map +1 -0
  40. package/dist/src/rules/error-handling/CatchAllLastRule.js +65 -0
  41. package/dist/src/rules/error-handling/CatchAllLastRule.js.map +1 -0
  42. package/dist/src/rules/error-handling/CorrelationIdRule.d.ts +22 -1
  43. package/dist/src/rules/error-handling/CorrelationIdRule.d.ts.map +1 -1
  44. package/dist/src/rules/error-handling/CorrelationIdRule.js +107 -6
  45. package/dist/src/rules/error-handling/CorrelationIdRule.js.map +1 -1
  46. package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.d.ts +28 -0
  47. package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.d.ts.map +1 -0
  48. package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.js +70 -0
  49. package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.js.map +1 -0
  50. package/dist/src/rules/error-handling/ErrorResponseStructureRule.d.ts +23 -0
  51. package/dist/src/rules/error-handling/ErrorResponseStructureRule.d.ts.map +1 -0
  52. package/dist/src/rules/error-handling/ErrorResponseStructureRule.js +73 -0
  53. package/dist/src/rules/error-handling/ErrorResponseStructureRule.js.map +1 -0
  54. package/dist/src/rules/error-handling/GenericErrorRule.d.ts +15 -3
  55. package/dist/src/rules/error-handling/GenericErrorRule.d.ts.map +1 -1
  56. package/dist/src/rules/error-handling/GenericErrorRule.js +58 -18
  57. package/dist/src/rules/error-handling/GenericErrorRule.js.map +1 -1
  58. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.d.ts +16 -5
  59. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.d.ts.map +1 -1
  60. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.js +64 -21
  61. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.js.map +1 -1
  62. package/dist/src/rules/error-handling/HttpStatusRule.d.ts +5 -0
  63. package/dist/src/rules/error-handling/HttpStatusRule.d.ts.map +1 -1
  64. package/dist/src/rules/error-handling/HttpStatusRule.js +15 -0
  65. package/dist/src/rules/error-handling/HttpStatusRule.js.map +1 -1
  66. package/dist/src/rules/error-handling/TryScopeRule.d.ts +5 -0
  67. package/dist/src/rules/error-handling/TryScopeRule.d.ts.map +1 -1
  68. package/dist/src/rules/error-handling/TryScopeRule.js +30 -7
  69. package/dist/src/rules/error-handling/TryScopeRule.js.map +1 -1
  70. package/dist/src/rules/http/ConnectionIdleTimeoutRule.d.ts +27 -0
  71. package/dist/src/rules/http/ConnectionIdleTimeoutRule.d.ts.map +1 -0
  72. package/dist/src/rules/http/ConnectionIdleTimeoutRule.js +46 -0
  73. package/dist/src/rules/http/ConnectionIdleTimeoutRule.js.map +1 -0
  74. package/dist/src/rules/http/HttpContentTypeRule.d.ts +28 -1
  75. package/dist/src/rules/http/HttpContentTypeRule.d.ts.map +1 -1
  76. package/dist/src/rules/http/HttpContentTypeRule.js +68 -7
  77. package/dist/src/rules/http/HttpContentTypeRule.js.map +1 -1
  78. package/dist/src/rules/index.d.ts +1 -1
  79. package/dist/src/rules/index.d.ts.map +1 -1
  80. package/dist/src/rules/index.js +50 -8
  81. package/dist/src/rules/index.js.map +1 -1
  82. package/dist/src/rules/logging/LoggerPayloadRule.d.ts +15 -0
  83. package/dist/src/rules/logging/LoggerPayloadRule.d.ts.map +1 -1
  84. package/dist/src/rules/logging/LoggerPayloadRule.js +48 -4
  85. package/dist/src/rules/logging/LoggerPayloadRule.js.map +1 -1
  86. package/dist/src/rules/operations/FlowRefTargetExistsRule.d.ts +23 -0
  87. package/dist/src/rules/operations/FlowRefTargetExistsRule.d.ts.map +1 -0
  88. package/dist/src/rules/operations/FlowRefTargetExistsRule.js +58 -0
  89. package/dist/src/rules/operations/FlowRefTargetExistsRule.js.map +1 -0
  90. package/dist/src/rules/operations/UnusedFlowRule.d.ts +26 -1
  91. package/dist/src/rules/operations/UnusedFlowRule.d.ts.map +1 -1
  92. package/dist/src/rules/operations/UnusedFlowRule.js +96 -16
  93. package/dist/src/rules/operations/UnusedFlowRule.js.map +1 -1
  94. package/dist/src/rules/operations/UnusedVariableRule.d.ts +31 -0
  95. package/dist/src/rules/operations/UnusedVariableRule.d.ts.map +1 -0
  96. package/dist/src/rules/operations/UnusedVariableRule.js +103 -0
  97. package/dist/src/rules/operations/UnusedVariableRule.js.map +1 -0
  98. package/dist/src/rules/performance/ConnectionPoolingRule.d.ts +5 -0
  99. package/dist/src/rules/performance/ConnectionPoolingRule.d.ts.map +1 -1
  100. package/dist/src/rules/performance/ConnectionPoolingRule.js +18 -5
  101. package/dist/src/rules/performance/ConnectionPoolingRule.js.map +1 -1
  102. package/dist/src/rules/performance/ListenerReconnectForeverRule.d.ts +28 -0
  103. package/dist/src/rules/performance/ListenerReconnectForeverRule.d.ts.map +1 -0
  104. package/dist/src/rules/performance/ListenerReconnectForeverRule.js +56 -0
  105. package/dist/src/rules/performance/ListenerReconnectForeverRule.js.map +1 -0
  106. package/dist/src/rules/performance/ReconnectionStrategyRule.d.ts +10 -0
  107. package/dist/src/rules/performance/ReconnectionStrategyRule.d.ts.map +1 -1
  108. package/dist/src/rules/performance/ReconnectionStrategyRule.js +47 -14
  109. package/dist/src/rules/performance/ReconnectionStrategyRule.js.map +1 -1
  110. package/dist/src/rules/security/ConnectorCredentialsSecuredRule.d.ts +36 -0
  111. package/dist/src/rules/security/ConnectorCredentialsSecuredRule.d.ts.map +1 -0
  112. package/dist/src/rules/security/ConnectorCredentialsSecuredRule.js +124 -0
  113. package/dist/src/rules/security/ConnectorCredentialsSecuredRule.js.map +1 -0
  114. package/dist/src/rules/security/HardcodedCredentialsRule.d.ts +4 -0
  115. package/dist/src/rules/security/HardcodedCredentialsRule.d.ts.map +1 -1
  116. package/dist/src/rules/security/HardcodedCredentialsRule.js +15 -0
  117. package/dist/src/rules/security/HardcodedCredentialsRule.js.map +1 -1
  118. package/dist/src/rules/security/SecurePropertiesEncryptionRule.d.ts +25 -0
  119. package/dist/src/rules/security/SecurePropertiesEncryptionRule.d.ts.map +1 -0
  120. package/dist/src/rules/security/SecurePropertiesEncryptionRule.js +59 -0
  121. package/dist/src/rules/security/SecurePropertiesEncryptionRule.js.map +1 -0
  122. package/dist/src/rules/security/SecurePropertiesKeyRule.d.ts +23 -0
  123. package/dist/src/rules/security/SecurePropertiesKeyRule.d.ts.map +1 -0
  124. package/dist/src/rules/security/SecurePropertiesKeyRule.js +45 -0
  125. package/dist/src/rules/security/SecurePropertiesKeyRule.js.map +1 -0
  126. package/dist/src/rules/security/TlsKeystorePasswordRule.d.ts +25 -0
  127. package/dist/src/rules/security/TlsKeystorePasswordRule.d.ts.map +1 -0
  128. package/dist/src/rules/security/TlsKeystorePasswordRule.js +63 -0
  129. package/dist/src/rules/security/TlsKeystorePasswordRule.js.map +1 -0
  130. package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.d.ts +26 -0
  131. package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.d.ts.map +1 -0
  132. package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.js +61 -0
  133. package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.js.map +1 -0
  134. package/dist/src/rules/standards/ConfigPropertiesOrderingRule.d.ts +34 -0
  135. package/dist/src/rules/standards/ConfigPropertiesOrderingRule.d.ts.map +1 -0
  136. package/dist/src/rules/standards/ConfigPropertiesOrderingRule.js +76 -0
  137. package/dist/src/rules/standards/ConfigPropertiesOrderingRule.js.map +1 -0
  138. package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.d.ts +25 -0
  139. package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.d.ts.map +1 -0
  140. package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.js +111 -0
  141. package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.js.map +1 -0
  142. package/dist/src/rules/structure/StructureRules.d.ts +8 -1
  143. package/dist/src/rules/structure/StructureRules.d.ts.map +1 -1
  144. package/dist/src/rules/structure/StructureRules.js +11 -7
  145. package/dist/src/rules/structure/StructureRules.js.map +1 -1
  146. package/dist/src/rules/yaml/YamlRules.d.ts +6 -2
  147. package/dist/src/rules/yaml/YamlRules.d.ts.map +1 -1
  148. package/dist/src/rules/yaml/YamlRules.js +15 -11
  149. package/dist/src/rules/yaml/YamlRules.js.map +1 -1
  150. package/dist/src/types/Rule.d.ts +35 -0
  151. package/dist/src/types/Rule.d.ts.map +1 -1
  152. package/docs/best-practices/rules-catalog.md +444 -42
  153. package/docs/linter/architecture.md +119 -64
  154. package/package.json +1 -1
@@ -6,6 +6,14 @@ const BaseRule_1 = require("../base/BaseRule");
6
6
  * MULE-301: Logger Payload Reference
7
7
  *
8
8
  * Loggers should not directly reference #[payload] for security/performance.
9
+ * This includes:
10
+ * - Direct payload reference: #[payload]
11
+ * - DataWeave write of full payload: write(payload, 'application/json')
12
+ * - output application/json --- payload (full payload serialization)
13
+ *
14
+ * Logging the entire payload risks exposing PII/sensitive customer data
15
+ * (names, addresses, SSNs, credit cards) and can degrade performance for
16
+ * large payloads.
9
17
  */
10
18
  class LoggerPayloadRule extends BaseRule_1.BaseRule {
11
19
  id = 'MULE-301';
@@ -15,24 +23,60 @@ class LoggerPayloadRule extends BaseRule_1.BaseRule {
15
23
  category = 'logging';
16
24
  validate(doc, _context) {
17
25
  const issues = [];
18
- const loggers = this.select('//mule:logger[@message]', doc);
26
+ // Check standard logger elements with message attribute
27
+ const loggers = this.select('//*[local-name()="logger"]', doc);
19
28
  for (const logger of loggers) {
20
29
  const message = this.getAttribute(logger, 'message') ?? '';
21
- // Check for direct payload logging
22
30
  if (this.hasDirectPayloadReference(message)) {
23
31
  const docName = this.getDocName(logger) ?? 'Logger';
24
32
  issues.push(this.createIssue(logger, `Logger "${docName}" logs entire payload - security/performance risk`, {
25
- suggestion: 'Log specific fields instead: #[payload.orderId]',
33
+ suggestion: 'Log specific fields instead: #[payload.orderId] or use a masking DataWeave module',
26
34
  }));
27
35
  }
28
36
  }
37
+ // Check ee:transform set-payload inside logger contexts
38
+ // (Some projects put write(payload,...) in transform message elements)
39
+ const transforms = this.select('//*[local-name()="transform"]', doc);
40
+ for (const transform of transforms) {
41
+ // Check all text content in set-payload / set-variable / message elements
42
+ const payloadSetters = this.select('.//*[local-name()="set-payload" or local-name()="set-variable"]', transform);
43
+ for (const setter of payloadSetters) {
44
+ const content = setter.textContent ?? '';
45
+ if (this.hasPayloadSerialization(content)) {
46
+ const docName = this.getDocName(transform) ?? 'Transform';
47
+ issues.push(this.createIssue(transform, `Transform "${docName}" serializes entire payload (write(payload,...)) - PII exposure risk`, {
48
+ severity: 'warning',
49
+ suggestion: 'Serialize only specific fields or use a masking function to redact sensitive data before logging',
50
+ }));
51
+ break; // One issue per transform
52
+ }
53
+ }
54
+ }
29
55
  return issues;
30
56
  }
31
57
  hasDirectPayloadReference(message) {
32
58
  // Match #[payload] but not #[payload.something]
33
59
  return (/#\[payload\s*\]/.test(message) ||
34
60
  /#\[\s*payload\s*\]/.test(message) ||
35
- message === '#[payload]');
61
+ message === '#[payload]' ||
62
+ this.hasPayloadSerialization(message));
63
+ }
64
+ /**
65
+ * Detect DataWeave patterns that serialize the full payload:
66
+ * - write(payload, 'application/json')
67
+ * - write(payload, "application/json")
68
+ * - output application/json --- payload
69
+ */
70
+ hasPayloadSerialization(content) {
71
+ // write(payload, ...) — serializes entire payload to string
72
+ if (/write\s*\(\s*payload\s*,/.test(content)) {
73
+ return true;
74
+ }
75
+ // output ... --- payload (entire payload as output body)
76
+ if (/---\s*payload\s*$/.test(content.trim())) {
77
+ return true;
78
+ }
79
+ return false;
36
80
  }
37
81
  }
38
82
  exports.LoggerPayloadRule = LoggerPayloadRule;
@@ -1 +1 @@
1
- {"version":3,"file":"LoggerPayloadRule.js","sourceRoot":"","sources":["../../../../src/rules/logging/LoggerPayloadRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;GAIG;AACH,MAAa,iBAAkB,SAAQ,mBAAQ;IAC7C,EAAE,GAAG,UAAU,CAAC;IAChB,IAAI,GAAG,0BAA0B,CAAC;IAClC,WAAW,GAAG,gDAAgD,CAAC;IAC/D,QAAQ,GAAG,SAAkB,CAAC;IAC9B,QAAQ,GAAG,SAAkB,CAAC;IAE9B,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC;QAE5D,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC;YAE3D,mCAAmC;YACnC,IAAI,IAAI,CAAC,yBAAyB,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC;gBACpD,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,MAAM,EACN,WAAW,OAAO,mDAAmD,EACrE;oBACE,UAAU,EAAE,iDAAiD;iBAC9D,CACF,CACF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,yBAAyB,CAAC,OAAe;QAC/C,gDAAgD;QAChD,OAAO,CACL,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC;YAC/B,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC;YAClC,OAAO,KAAK,YAAY,CACzB,CAAC;IACJ,CAAC;CACF;AAzCD,8CAyCC"}
1
+ {"version":3,"file":"LoggerPayloadRule.js","sourceRoot":"","sources":["../../../../src/rules/logging/LoggerPayloadRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;;;;;;;;GAYG;AACH,MAAa,iBAAkB,SAAQ,mBAAQ;IAC7C,EAAE,GAAG,UAAU,CAAC;IAChB,IAAI,GAAG,0BAA0B,CAAC;IAClC,WAAW,GAAG,gDAAgD,CAAC;IAC/D,QAAQ,GAAG,SAAkB,CAAC;IAC9B,QAAQ,GAAG,SAAkB,CAAC;IAE9B,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,wDAAwD;QACxD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,4BAA4B,EAAE,GAAG,CAAC,CAAC;QAC/D,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC;YAE3D,IAAI,IAAI,CAAC,yBAAyB,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC;gBACpD,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,MAAM,EACN,WAAW,OAAO,mDAAmD,EACrE;oBACE,UAAU,EACR,mFAAmF;iBACtF,CACF,CACF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,wDAAwD;QACxD,uEAAuE;QACvE,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,+BAA+B,EAAE,GAAG,CAAC,CAAC;QACrE,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,0EAA0E;YAC1E,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAChC,iEAAiE,EACjE,SAAqB,CACtB,CAAC;YACF,KAAK,MAAM,MAAM,IAAI,cAAc,EAAE,CAAC;gBACpC,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC;gBACzC,IAAI,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,WAAW,CAAC;oBAC1D,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,SAAS,EACT,cAAc,OAAO,sEAAsE,EAC3F;wBACE,QAAQ,EAAE,SAAS;wBACnB,UAAU,EACR,kGAAkG;qBACrG,CACF,CACF,CAAC;oBACF,MAAM,CAAC,0BAA0B;gBACnC,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,yBAAyB,CAAC,OAAe;QAC/C,gDAAgD;QAChD,OAAO,CACL,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC;YAC/B,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC;YAClC,OAAO,KAAK,YAAY;YACxB,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,CACtC,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACK,uBAAuB,CAAC,OAAe;QAC7C,4DAA4D;QAC5D,IAAI,0BAA0B,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7C,OAAO,IAAI,CAAC;QACd,CAAC;QACD,yDAAyD;QACzD,IAAI,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YAC7C,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAzFD,8CAyFC"}
@@ -0,0 +1,23 @@
1
+ import { ValidationContext, Issue, IssueType } from '../../types';
2
+ import { BaseRule } from '../base/BaseRule';
3
+ /**
4
+ * HYG-004: Flow-Ref Target Exists
5
+ *
6
+ * Every <flow-ref name="X"/> must have a corresponding <flow name="X"/> or
7
+ * <sub-flow name="X"/> somewhere in the project. When the engine provides
8
+ * `context.allFlowRefs` we rely on the pre-scanned flow name map; otherwise
9
+ * we fall back to intra-file validation only.
10
+ *
11
+ * This rule catches broken wiring at lint time, preventing runtime
12
+ * MULE:ROUTING errors in production.
13
+ */
14
+ export declare class FlowRefTargetExistsRule extends BaseRule {
15
+ id: string;
16
+ name: string;
17
+ description: string;
18
+ severity: "error";
19
+ category: "operations";
20
+ issueType: IssueType;
21
+ validate(doc: Document, context: ValidationContext): Issue[];
22
+ }
23
+ //# sourceMappingURL=FlowRefTargetExistsRule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlowRefTargetExistsRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/operations/FlowRefTargetExistsRule.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,uBAAwB,SAAQ,QAAQ;IACnD,EAAE,SAAa;IACf,IAAI,SAA4B;IAChC,WAAW,SAAgE;IAC3E,QAAQ,EAAG,OAAO,CAAU;IAC5B,QAAQ,EAAG,YAAY,CAAU;IACjC,SAAS,EAAE,SAAS,CAAS;IAE7B,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,GAAG,KAAK,EAAE;CA0C7D"}
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FlowRefTargetExistsRule = void 0;
4
+ const BaseRule_1 = require("../base/BaseRule");
5
+ /**
6
+ * HYG-004: Flow-Ref Target Exists
7
+ *
8
+ * Every <flow-ref name="X"/> must have a corresponding <flow name="X"/> or
9
+ * <sub-flow name="X"/> somewhere in the project. When the engine provides
10
+ * `context.allFlowRefs` we rely on the pre-scanned flow name map; otherwise
11
+ * we fall back to intra-file validation only.
12
+ *
13
+ * This rule catches broken wiring at lint time, preventing runtime
14
+ * MULE:ROUTING errors in production.
15
+ */
16
+ class FlowRefTargetExistsRule extends BaseRule_1.BaseRule {
17
+ id = 'HYG-004';
18
+ name = 'Flow-Ref Target Exists';
19
+ description = 'Every flow-ref must reference an existing flow or sub-flow';
20
+ severity = 'error';
21
+ category = 'operations';
22
+ issueType = 'bug';
23
+ validate(doc, context) {
24
+ const issues = [];
25
+ // Collect all flow/sub-flow names defined in this file
26
+ const localFlowNames = new Set();
27
+ const flows = this.select('//*[local-name()="flow" or local-name()="sub-flow"]', doc);
28
+ for (const flow of flows) {
29
+ const name = this.getNameAttribute(flow);
30
+ if (name) {
31
+ localFlowNames.add(name);
32
+ }
33
+ }
34
+ // Collect all flow names across project if available
35
+ const allFlowNames = context.allFlowNames ?? localFlowNames;
36
+ // Check every flow-ref
37
+ const flowRefs = this.select('//*[local-name()="flow-ref"]', doc);
38
+ for (const ref of flowRefs) {
39
+ const targetName = this.getNameAttribute(ref);
40
+ if (!targetName) {
41
+ continue;
42
+ }
43
+ // Skip dynamic flow-refs (DataWeave expressions)
44
+ if (targetName.includes('#[') || targetName.includes('${')) {
45
+ continue;
46
+ }
47
+ if (!allFlowNames.has(targetName)) {
48
+ const docName = this.getDocName(ref) ?? targetName;
49
+ issues.push(this.createIssue(ref, `Flow-ref "${docName}" targets non-existent flow "${targetName}"`, {
50
+ suggestion: 'Verify the target flow or sub-flow exists. Check for typos or missing XML files in src/main/mule/',
51
+ }));
52
+ }
53
+ }
54
+ return issues;
55
+ }
56
+ }
57
+ exports.FlowRefTargetExistsRule = FlowRefTargetExistsRule;
58
+ //# sourceMappingURL=FlowRefTargetExistsRule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlowRefTargetExistsRule.js","sourceRoot":"","sources":["../../../../src/rules/operations/FlowRefTargetExistsRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;;;;;;GAUG;AACH,MAAa,uBAAwB,SAAQ,mBAAQ;IACnD,EAAE,GAAG,SAAS,CAAC;IACf,IAAI,GAAG,wBAAwB,CAAC;IAChC,WAAW,GAAG,4DAA4D,CAAC;IAC3E,QAAQ,GAAG,OAAgB,CAAC;IAC5B,QAAQ,GAAG,YAAqB,CAAC;IACjC,SAAS,GAAc,KAAK,CAAC;IAE7B,QAAQ,CAAC,GAAa,EAAE,OAA0B;QAChD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,uDAAuD;QACvD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;QACzC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,qDAAqD,EAAE,GAAG,CAAC,CAAC;QACtF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;YACzC,IAAI,IAAI,EAAE,CAAC;gBACT,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;QAED,qDAAqD;QACrD,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,cAAc,CAAC;QAE5D,uBAAuB;QACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;QAClE,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;YAC9C,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,SAAS;YACX,CAAC;YAED,iDAAiD;YACjD,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC3D,SAAS;YACX,CAAC;YAED,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;gBAClC,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC;gBACnD,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,aAAa,OAAO,gCAAgC,UAAU,GAAG,EAAE;oBACvF,UAAU,EACR,mGAAmG;iBACtG,CAAC,CACH,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAlDD,0DAkDC"}
@@ -4,6 +4,19 @@ import { BaseRule } from '../base/BaseRule';
4
4
  * HYG-003: Unused Flow Detection
5
5
  *
6
6
  * Detects flows that are never referenced by flow-ref.
7
+ *
8
+ * Cross-file detection: when the LintEngine provides context.allFlowRefs
9
+ * (populated during the pre-scan phase), the rule checks across all project
10
+ * files. When scanning a standalone file (allFlowRefs is undefined), only
11
+ * intra-file references are checked.
12
+ *
13
+ * The rule recognises several categories of "externally referenced" flows:
14
+ * - APIKit-generated flows: verb:\path:config (routed by apikit:router)
15
+ * - Flows with external triggers: http:listener, scheduler, vm:listener,
16
+ * salesforce:* listeners (replay-channel-listener, subscribe-channel-listener,
17
+ * replay-topic-listener, subscribe-topic-listener, modified-object-listener,
18
+ * new-object-listener)
19
+ * - Common naming conventions: *-main, *-api, api-*, *-console, *-error-handler, global*
7
20
  */
8
21
  export declare class UnusedFlowRule extends BaseRule {
9
22
  id: string;
@@ -11,7 +24,19 @@ export declare class UnusedFlowRule extends BaseRule {
11
24
  description: string;
12
25
  severity: "warning";
13
26
  category: "standards";
14
- validate(doc: Document, _context: ValidationContext): Issue[];
27
+ validate(doc: Document, context: ValidationContext): Issue[];
28
+ /**
29
+ * Check if a flow name matches the APIKit auto-generated naming convention.
30
+ * Pattern: verb:\path:config-name (e.g. "get:\orders:api-config")
31
+ * Also matches with (type) suffix: "get:\orders:api-config(application\json)"
32
+ */
33
+ private isApikitFlow;
34
+ /**
35
+ * Check if a flow has an external trigger (a source component as the first
36
+ * processor). This covers HTTP listeners, schedulers, VM listeners,
37
+ * Salesforce connectors, and any other connector listener.
38
+ */
39
+ private hasExternalTrigger;
15
40
  private isExternallyReferenced;
16
41
  }
17
42
  //# sourceMappingURL=UnusedFlowRule.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"UnusedFlowRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/operations/UnusedFlowRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,QAAQ;IAC1C,EAAE,SAAa;IACf,IAAI,SAA2B;IAC/B,WAAW,SAA6C;IACxD,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,WAAW,CAAU;IAEhC,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;IAmE7D,OAAO,CAAC,sBAAsB;CAY/B"}
1
+ {"version":3,"file":"UnusedFlowRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/operations/UnusedFlowRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,cAAe,SAAQ,QAAQ;IAC1C,EAAE,SAAa;IACf,IAAI,SAA2B;IAC/B,WAAW,SAA6C;IACxD,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,WAAW,CAAU;IAEhC,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,GAAG,KAAK,EAAE;IAwE5D;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAKpB;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAgD1B,OAAO,CAAC,sBAAsB;CAY/B"}
@@ -6,6 +6,19 @@ const BaseRule_1 = require("../base/BaseRule");
6
6
  * HYG-003: Unused Flow Detection
7
7
  *
8
8
  * Detects flows that are never referenced by flow-ref.
9
+ *
10
+ * Cross-file detection: when the LintEngine provides context.allFlowRefs
11
+ * (populated during the pre-scan phase), the rule checks across all project
12
+ * files. When scanning a standalone file (allFlowRefs is undefined), only
13
+ * intra-file references are checked.
14
+ *
15
+ * The rule recognises several categories of "externally referenced" flows:
16
+ * - APIKit-generated flows: verb:\path:config (routed by apikit:router)
17
+ * - Flows with external triggers: http:listener, scheduler, vm:listener,
18
+ * salesforce:* listeners (replay-channel-listener, subscribe-channel-listener,
19
+ * replay-topic-listener, subscribe-topic-listener, modified-object-listener,
20
+ * new-object-listener)
21
+ * - Common naming conventions: *-main, *-api, api-*, *-console, *-error-handler, global*
9
22
  */
10
23
  class UnusedFlowRule extends BaseRule_1.BaseRule {
11
24
  id = 'HYG-003';
@@ -13,18 +26,27 @@ class UnusedFlowRule extends BaseRule_1.BaseRule {
13
26
  description = 'Detects flows that are never referenced';
14
27
  severity = 'warning';
15
28
  category = 'standards';
16
- validate(doc, _context) {
29
+ validate(doc, context) {
17
30
  const issues = [];
18
31
  // Get all flow names in this document
19
32
  const flows = this.select('//*[local-name()="flow"]', doc);
20
33
  const subflows = this.select('//*[local-name()="sub-flow"]', doc);
21
- // Get all flow-ref targets
22
- const flowRefs = this.select('//*[local-name()="flow-ref"]', doc);
23
- const referencedFlows = new Set();
24
- for (const ref of flowRefs) {
25
- const name = this.getNameAttribute(ref);
26
- if (name) {
27
- referencedFlows.add(name);
34
+ // Build the set of referenced flow names.
35
+ // When context.allFlowRefs is available (project-wide pre-scan), use it.
36
+ // Fall back to intra-file refs only for standalone scans.
37
+ let referencedFlows;
38
+ if (context.allFlowRefs) {
39
+ referencedFlows = context.allFlowRefs;
40
+ }
41
+ else {
42
+ // Intra-file only (standalone scan)
43
+ const flowRefs = this.select('//*[local-name()="flow-ref"]', doc);
44
+ referencedFlows = new Set();
45
+ for (const ref of flowRefs) {
46
+ const name = this.getNameAttribute(ref);
47
+ if (name) {
48
+ referencedFlows.add(name);
49
+ }
28
50
  }
29
51
  }
30
52
  // Check sub-flows (they should always be referenced)
@@ -33,25 +55,26 @@ class UnusedFlowRule extends BaseRule_1.BaseRule {
33
55
  if (name && !referencedFlows.has(name)) {
34
56
  // Exclude common patterns that are referenced externally
35
57
  if (!this.isExternallyReferenced(name)) {
36
- issues.push(this.createIssue(subflow, `Sub-flow "${name}" is never referenced within this file`, {
58
+ issues.push(this.createIssue(subflow, `Sub-flow "${name}" is never referenced`, {
37
59
  severity: 'info',
38
60
  suggestion: 'Consider removing unused sub-flows or verify cross-file references',
39
61
  }));
40
62
  }
41
63
  }
42
64
  }
43
- // Check private flows (not triggered by HTTP/scheduler)
65
+ // Check private flows (not triggered by HTTP/scheduler/connector listeners)
44
66
  for (const flow of flows) {
45
67
  const name = this.getNameAttribute(flow);
46
68
  if (!name) {
47
69
  continue;
48
70
  }
49
- // Skip if it has an external trigger
50
- const hasHttpListener = this.exists('.//*[local-name()="listener"]', flow);
51
- const hasScheduler = this.exists('.//*[local-name()="scheduler"]', flow);
52
- const hasVmListener = this.exists('.//*[local-name()="listener" and contains(@config-ref, "vm")]', flow);
53
- if (hasHttpListener || hasScheduler || hasVmListener) {
54
- continue; // Entry point flow
71
+ // Skip APIKit-generated flows (verb:\path:config pattern)
72
+ if (this.isApikitFlow(name)) {
73
+ continue;
74
+ }
75
+ // Skip if it has an external trigger (listener / scheduler)
76
+ if (this.hasExternalTrigger(flow)) {
77
+ continue;
55
78
  }
56
79
  // Check if referenced
57
80
  if (!referencedFlows.has(name) && !this.isExternallyReferenced(name)) {
@@ -63,6 +86,63 @@ class UnusedFlowRule extends BaseRule_1.BaseRule {
63
86
  }
64
87
  return issues;
65
88
  }
89
+ /**
90
+ * Check if a flow name matches the APIKit auto-generated naming convention.
91
+ * Pattern: verb:\path:config-name (e.g. "get:\orders:api-config")
92
+ * Also matches with (type) suffix: "get:\orders:api-config(application\json)"
93
+ */
94
+ isApikitFlow(name) {
95
+ // APIKit flow names contain backslash-separated segments starting with an HTTP verb
96
+ return /^(get|post|put|patch|delete|head|options|trace):\\.+:.+$/i.test(name);
97
+ }
98
+ /**
99
+ * Check if a flow has an external trigger (a source component as the first
100
+ * processor). This covers HTTP listeners, schedulers, VM listeners,
101
+ * Salesforce connectors, and any other connector listener.
102
+ */
103
+ hasExternalTrigger(flow) {
104
+ // http:listener or any namespace listener
105
+ const hasHttpListener = this.exists('.//*[local-name()="listener"]', flow);
106
+ if (hasHttpListener) {
107
+ return true;
108
+ }
109
+ // scheduler
110
+ const hasScheduler = this.exists('.//*[local-name()="scheduler"]', flow);
111
+ if (hasScheduler) {
112
+ return true;
113
+ }
114
+ // Salesforce-specific listeners (platform events, CDC, polling)
115
+ const sfListenerPatterns = [
116
+ 'replay-channel-listener',
117
+ 'subscribe-channel-listener',
118
+ 'replay-topic-listener',
119
+ 'subscribe-topic-listener',
120
+ 'modified-object-listener',
121
+ 'new-object-listener',
122
+ ];
123
+ for (const pattern of sfListenerPatterns) {
124
+ if (this.exists(`.//*[local-name()="${pattern}"]`, flow)) {
125
+ return true;
126
+ }
127
+ }
128
+ // JMS, AMQP, Anypoint MQ, File, FTP, SFTP, Email, DB polling listeners
129
+ const otherListenerPatterns = [
130
+ 'subscriber', // jms:subscriber, amqp:subscriber
131
+ 'consume', // anypoint-mq:subscriber is actually "subscriber" but some use "consume"
132
+ 'on-new-file', // file:listener
133
+ 'on-new-or-updated-file', // sftp/ftp
134
+ 'listener-imap', // email
135
+ 'listener-pop3', // email
136
+ 'on-new-message', // anypoint-mq
137
+ 'on-table-row', // db polling
138
+ ];
139
+ for (const pattern of otherListenerPatterns) {
140
+ if (this.exists(`.//*[local-name()="${pattern}"]`, flow)) {
141
+ return true;
142
+ }
143
+ }
144
+ return false;
145
+ }
66
146
  isExternallyReferenced(name) {
67
147
  // Common patterns that are typically referenced externally
68
148
  const externalPatterns = [
@@ -1 +1 @@
1
- {"version":3,"file":"UnusedFlowRule.js","sourceRoot":"","sources":["../../../../src/rules/operations/UnusedFlowRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;GAIG;AACH,MAAa,cAAe,SAAQ,mBAAQ;IAC1C,EAAE,GAAG,SAAS,CAAC;IACf,IAAI,GAAG,uBAAuB,CAAC;IAC/B,WAAW,GAAG,yCAAyC,CAAC;IACxD,QAAQ,GAAG,SAAkB,CAAC;IAC9B,QAAQ,GAAG,WAAoB,CAAC;IAEhC,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,sCAAsC;QACtC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,0BAA0B,EAAE,GAAG,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;QAElE,2BAA2B;QAC3B,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;QAClE,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;QAE1C,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;YACxC,IAAI,IAAI,EAAE,CAAC;gBACT,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;QAED,qDAAqD;QACrD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;YAC5C,IAAI,IAAI,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvC,yDAAyD;gBACzD,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,EAAE,CAAC;oBACvC,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,aAAa,IAAI,wCAAwC,EAAE;wBACnF,QAAQ,EAAE,MAAM;wBAChB,UAAU,EAAE,oEAAoE;qBACjF,CAAC,CACH,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,wDAAwD;QACxD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;YACzC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,SAAS;YACX,CAAC;YAED,qCAAqC;YACrC,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,CAAC,+BAA+B,EAAE,IAAI,CAAC,CAAC;YAC3E,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,gCAAgC,EAAE,IAAI,CAAC,CAAC;YACzE,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAC/B,+DAA+D,EAC/D,IAAI,CACL,CAAC;YAEF,IAAI,eAAe,IAAI,YAAY,IAAI,aAAa,EAAE,CAAC;gBACrD,SAAS,CAAC,mBAAmB;YAC/B,CAAC;YAED,sBAAsB;YACtB,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrE,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,IAAI,0CAA0C,EAAE;oBAC9E,QAAQ,EAAE,MAAM;oBAChB,UAAU,EAAE,qEAAqE;iBAClF,CAAC,CACH,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,sBAAsB,CAAC,IAAY;QACzC,2DAA2D;QAC3D,MAAM,gBAAgB,GAAG;YACvB,QAAQ;YACR,OAAO;YACP,OAAO;YACP,WAAW;YACX,iBAAiB;YACjB,SAAS;SACV,CAAC;QACF,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAChE,CAAC;CACF;AAtFD,wCAsFC"}
1
+ {"version":3,"file":"UnusedFlowRule.js","sourceRoot":"","sources":["../../../../src/rules/operations/UnusedFlowRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAa,cAAe,SAAQ,mBAAQ;IAC1C,EAAE,GAAG,SAAS,CAAC;IACf,IAAI,GAAG,uBAAuB,CAAC;IAC/B,WAAW,GAAG,yCAAyC,CAAC;IACxD,QAAQ,GAAG,SAAkB,CAAC;IAC9B,QAAQ,GAAG,WAAoB,CAAC;IAEhC,QAAQ,CAAC,GAAa,EAAE,OAA0B;QAChD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,sCAAsC;QACtC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,0BAA0B,EAAE,GAAG,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;QAElE,0CAA0C;QAC1C,yEAAyE;QACzE,0DAA0D;QAC1D,IAAI,eAA4B,CAAC;QACjC,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YACxB,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC;QACxC,CAAC;aAAM,CAAC;YACN,oCAAoC;YACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;YAClE,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;YACpC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;gBAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;gBACxC,IAAI,IAAI,EAAE,CAAC;oBACT,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC5B,CAAC;YACH,CAAC;QACH,CAAC;QAED,qDAAqD;QACrD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;YAC5C,IAAI,IAAI,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvC,yDAAyD;gBACzD,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,EAAE,CAAC;oBACvC,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,aAAa,IAAI,uBAAuB,EAAE;wBAClE,QAAQ,EAAE,MAAM;wBAChB,UAAU,EAAE,oEAAoE;qBACjF,CAAC,CACH,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,4EAA4E;QAC5E,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;YACzC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,SAAS;YACX,CAAC;YAED,0DAA0D;YAC1D,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5B,SAAS;YACX,CAAC;YAED,4DAA4D;YAC5D,IAAI,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;gBAClC,SAAS;YACX,CAAC;YAED,sBAAsB;YACtB,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrE,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,IAAI,0CAA0C,EAAE;oBAC9E,QAAQ,EAAE,MAAM;oBAChB,UAAU,EAAE,qEAAqE;iBAClF,CAAC,CACH,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;OAIG;IACK,YAAY,CAAC,IAAY;QAC/B,oFAAoF;QACpF,OAAO,2DAA2D,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChF,CAAC;IAED;;;;OAIG;IACK,kBAAkB,CAAC,IAAU;QACnC,0CAA0C;QAC1C,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,CAAC,+BAA+B,EAAE,IAAI,CAAC,CAAC;QAC3E,IAAI,eAAe,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,YAAY;QACZ,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,gCAAgC,EAAE,IAAI,CAAC,CAAC;QACzE,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,gEAAgE;QAChE,MAAM,kBAAkB,GAAG;YACzB,yBAAyB;YACzB,4BAA4B;YAC5B,uBAAuB;YACvB,0BAA0B;YAC1B,0BAA0B;YAC1B,qBAAqB;SACtB,CAAC;QACF,KAAK,MAAM,OAAO,IAAI,kBAAkB,EAAE,CAAC;YACzC,IAAI,IAAI,CAAC,MAAM,CAAC,sBAAsB,OAAO,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;gBACzD,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,uEAAuE;QACvE,MAAM,qBAAqB,GAAG;YAC5B,YAAY,EAAE,kCAAkC;YAChD,SAAS,EAAE,yEAAyE;YACpF,aAAa,EAAE,gBAAgB;YAC/B,wBAAwB,EAAE,WAAW;YACrC,eAAe,EAAE,QAAQ;YACzB,eAAe,EAAE,QAAQ;YACzB,gBAAgB,EAAE,cAAc;YAChC,cAAc,EAAE,aAAa;SAC9B,CAAC;QACF,KAAK,MAAM,OAAO,IAAI,qBAAqB,EAAE,CAAC;YAC5C,IAAI,IAAI,CAAC,MAAM,CAAC,sBAAsB,OAAO,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;gBACzD,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,sBAAsB,CAAC,IAAY;QACzC,2DAA2D;QAC3D,MAAM,gBAAgB,GAAG;YACvB,QAAQ;YACR,OAAO;YACP,OAAO;YACP,WAAW;YACX,iBAAiB;YACjB,SAAS;SACV,CAAC;QACF,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAChE,CAAC;CACF;AA1JD,wCA0JC"}
@@ -0,0 +1,31 @@
1
+ import { ValidationContext, Issue, IssueType } from '../../types';
2
+ import { BaseRule } from '../base/BaseRule';
3
+ /**
4
+ * HYG-005: Unused Variable
5
+ *
6
+ * Detects variables that are set in a flow but never referenced later
7
+ * in the same flow. This is a common code smell that indicates dead code
8
+ * or incomplete refactoring.
9
+ *
10
+ * Checks for set-variable elements whose variableName is not referenced
11
+ * by any subsequent expression in the same flow via `vars.variableName`
12
+ * or `#[vars.variableName]` patterns.
13
+ *
14
+ * Note: This is a best-effort heuristic — variables consumed outside the
15
+ * flow (via flow-ref caller, for example) cannot be detected.
16
+ */
17
+ export declare class UnusedVariableRule extends BaseRule {
18
+ id: string;
19
+ name: string;
20
+ description: string;
21
+ severity: "info";
22
+ category: "operations";
23
+ issueType: IssueType;
24
+ /** Well-known variables that are always considered "used" (consumed by connectors/listeners) */
25
+ private readonly WELL_KNOWN_VARS;
26
+ validate(doc: Document, _context: ValidationContext): Issue[];
27
+ private serializeNode;
28
+ private collectTextContent;
29
+ private escapeRegex;
30
+ }
31
+ //# sourceMappingURL=UnusedVariableRule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnusedVariableRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/operations/UnusedVariableRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;;;;;GAaG;AACH,qBAAa,kBAAmB,SAAQ,QAAQ;IAC9C,EAAE,SAAa;IACf,IAAI,SAAqB;IACzB,WAAW,SAAuE;IAClF,QAAQ,EAAG,MAAM,CAAU;IAC3B,QAAQ,EAAG,YAAY,CAAU;IACjC,SAAS,EAAE,SAAS,CAAgB;IAEpC,gGAAgG;IAChG,OAAO,CAAC,QAAQ,CAAC,eAAe,CAK7B;IAEH,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;IAuD7D,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,kBAAkB;IAqB1B,OAAO,CAAC,WAAW;CAGpB"}
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UnusedVariableRule = void 0;
4
+ const BaseRule_1 = require("../base/BaseRule");
5
+ /**
6
+ * HYG-005: Unused Variable
7
+ *
8
+ * Detects variables that are set in a flow but never referenced later
9
+ * in the same flow. This is a common code smell that indicates dead code
10
+ * or incomplete refactoring.
11
+ *
12
+ * Checks for set-variable elements whose variableName is not referenced
13
+ * by any subsequent expression in the same flow via `vars.variableName`
14
+ * or `#[vars.variableName]` patterns.
15
+ *
16
+ * Note: This is a best-effort heuristic — variables consumed outside the
17
+ * flow (via flow-ref caller, for example) cannot be detected.
18
+ */
19
+ class UnusedVariableRule extends BaseRule_1.BaseRule {
20
+ id = 'HYG-005';
21
+ name = 'Unused Variable';
22
+ description = 'Variables set in a flow should be referenced within the same flow';
23
+ severity = 'info';
24
+ category = 'operations';
25
+ issueType = 'code-smell';
26
+ /** Well-known variables that are always considered "used" (consumed by connectors/listeners) */
27
+ WELL_KNOWN_VARS = new Set([
28
+ 'httpStatus',
29
+ 'outboundHeaders',
30
+ 'statusCode',
31
+ 'correlationId',
32
+ ]);
33
+ validate(doc, _context) {
34
+ const issues = [];
35
+ const flows = this.select('//mule:flow | //mule:sub-flow', doc);
36
+ for (const flow of flows) {
37
+ const flowName = this.getAttribute(flow, 'name') ?? '';
38
+ // Collect all set-variable declarations in this flow
39
+ const setVars = this.select('.//*[local-name()="set-variable"]', flow);
40
+ const variables = [];
41
+ for (const setVar of setVars) {
42
+ const varName = this.getAttribute(setVar, 'variableName');
43
+ if (varName && !this.WELL_KNOWN_VARS.has(varName)) {
44
+ variables.push({ name: varName, node: setVar });
45
+ }
46
+ }
47
+ if (variables.length === 0) {
48
+ continue;
49
+ }
50
+ // Get the full text content of the flow to search for references
51
+ const flowText = this.serializeNode(flow);
52
+ for (const { name, node } of variables) {
53
+ // Check for common reference patterns:
54
+ // vars.name, vars['name'], vars["name"], vars.name
55
+ const patterns = [`vars.${name}`, `vars['${name}']`, `vars["${name}"]`, `#[vars.${name}]`];
56
+ const isReferenced = patterns.some((pattern) => {
57
+ // Count occurrences — must appear beyond just the set-variable itself
58
+ const regex = new RegExp(this.escapeRegex(pattern), 'g');
59
+ const matches = flowText.match(regex);
60
+ return matches !== null && matches.length > 0;
61
+ });
62
+ if (!isReferenced) {
63
+ issues.push(this.createIssue(node, `Variable "${name}" is set in flow "${flowName}" but never referenced within the same flow`, {
64
+ suggestion: `Remove the unused variable or verify it is consumed by a downstream flow via flow-ref`,
65
+ }));
66
+ }
67
+ }
68
+ }
69
+ return issues;
70
+ }
71
+ serializeNode(node) {
72
+ // Get all text content and attribute values from the node subtree
73
+ const parts = [];
74
+ this.collectTextContent(node, parts);
75
+ return parts.join(' ');
76
+ }
77
+ collectTextContent(node, parts) {
78
+ if (node.nodeType === 3 /* TEXT_NODE */) {
79
+ parts.push(node.textContent ?? '');
80
+ }
81
+ else if (node.nodeType === 1 /* ELEMENT_NODE */) {
82
+ // Include attribute values (expressions live in attributes)
83
+ const element = node;
84
+ if (element.attributes) {
85
+ for (let i = 0; i < element.attributes.length; i++) {
86
+ parts.push(element.attributes[i].value);
87
+ }
88
+ }
89
+ // Recurse into children
90
+ const children = node.childNodes;
91
+ if (children) {
92
+ for (let i = 0; i < children.length; i++) {
93
+ this.collectTextContent(children[i], parts);
94
+ }
95
+ }
96
+ }
97
+ }
98
+ escapeRegex(str) {
99
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
100
+ }
101
+ }
102
+ exports.UnusedVariableRule = UnusedVariableRule;
103
+ //# sourceMappingURL=UnusedVariableRule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnusedVariableRule.js","sourceRoot":"","sources":["../../../../src/rules/operations/UnusedVariableRule.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,11 @@ import { BaseRule } from '../base/BaseRule';
5
5
  *
6
6
  * DB and HTTP connectors should configure connection pools
7
7
  * for optimal performance and resource management.
8
+ *
9
+ * Per the Mule HTTP connector XSD, `maxConnections` and `connectionIdleTimeout`
10
+ * are valid on BOTH `<http:request-config>` (older style) and on the nested
11
+ * `<http:request-connection>` child element (current XSD-correct placement).
12
+ * The rule must accept either location to avoid false positives.
8
13
  */
9
14
  export declare class ConnectionPoolingRule extends BaseRule {
10
15
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"ConnectionPoolingRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/performance/ConnectionPoolingRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;GAKG;AACH,qBAAa,qBAAsB,SAAQ,QAAQ;IACjD,EAAE,SAAc;IAChB,IAAI,SAAwB;IAC5B,WAAW,SAA0D;IACrE,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,aAAa,CAAU;IAElC,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;CA8D9D"}
1
+ {"version":3,"file":"ConnectionPoolingRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/performance/ConnectionPoolingRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;;GAUG;AACH,qBAAa,qBAAsB,SAAQ,QAAQ;IACjD,EAAE,SAAc;IAChB,IAAI,SAAwB;IAC5B,WAAW,SAA0D;IACrE,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,aAAa,CAAU;IAElC,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;CA2E9D"}
@@ -7,6 +7,11 @@ const BaseRule_1 = require("../base/BaseRule");
7
7
  *
8
8
  * DB and HTTP connectors should configure connection pools
9
9
  * for optimal performance and resource management.
10
+ *
11
+ * Per the Mule HTTP connector XSD, `maxConnections` and `connectionIdleTimeout`
12
+ * are valid on BOTH `<http:request-config>` (older style) and on the nested
13
+ * `<http:request-connection>` child element (current XSD-correct placement).
14
+ * The rule must accept either location to avoid false positives.
10
15
  */
11
16
  class ConnectionPoolingRule extends BaseRule_1.BaseRule {
12
17
  id = 'PERF-002';
@@ -21,13 +26,21 @@ class ConnectionPoolingRule extends BaseRule_1.BaseRule {
21
26
  for (const config of httpConfigs) {
22
27
  const element = config;
23
28
  const name = element.getAttribute('name') ?? 'unnamed';
24
- // Check for connection pooling attributes
25
- const hasPooling = element.hasAttribute('maxConnections') ||
26
- element.hasAttribute('connectionIdleTimeout') ||
27
- this.select('.//*[local-name()="pooling-profile"]', config).length > 0;
29
+ // Check for connection pooling attributes on the request-config element itself
30
+ const hasPoolingOnConfig = element.hasAttribute('maxConnections') || element.hasAttribute('connectionIdleTimeout');
31
+ // Also check the nested http:request-connection child element (XSD-correct placement).
32
+ // Per the Mule HTTP connector XSD, maxConnections and connectionIdleTimeout belong on
33
+ // http:request-connection, not http:request-config. Both placements must be accepted.
34
+ const connectionChild = this.selectFirst('.//*[local-name()="request-connection"]', config);
35
+ const hasPoolingOnConnection = connectionChild !== null &&
36
+ (connectionChild.hasAttribute('maxConnections') ||
37
+ connectionChild.hasAttribute('connectionIdleTimeout'));
38
+ // Also accept a pooling-profile child (db-style config)
39
+ const hasPoolingProfile = this.select('.//*[local-name()="pooling-profile"]', config).length > 0;
40
+ const hasPooling = hasPoolingOnConfig || hasPoolingOnConnection || hasPoolingProfile;
28
41
  if (!hasPooling) {
29
42
  issues.push(this.createIssue(config, `HTTP request config "${name}" has no connection pooling configured`, {
30
- suggestion: 'Add maxConnections and connectionIdleTimeout for optimal connection management',
43
+ suggestion: 'Add maxConnections and connectionIdleTimeout on <http:request-connection> for optimal connection management',
31
44
  }));
32
45
  }
33
46
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ConnectionPoolingRule.js","sourceRoot":"","sources":["../../../../src/rules/performance/ConnectionPoolingRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;GAKG;AACH,MAAa,qBAAsB,SAAQ,mBAAQ;IACjD,EAAE,GAAG,UAAU,CAAC;IAChB,IAAI,GAAG,oBAAoB,CAAC;IAC5B,WAAW,GAAG,sDAAsD,CAAC;IACrE,QAAQ,GAAG,SAAkB,CAAC;IAC9B,QAAQ,GAAG,aAAsB,CAAC;IAElC,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,oCAAoC;QACpC,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAC7B,mGAAmG,EACnG,GAAG,CACJ,CAAC;QAEF,KAAK,MAAM,MAAM,IAAI,WAAW,EAAE,CAAC;YACjC,MAAM,OAAO,GAAG,MAAiB,CAAC;YAClC,MAAM,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC;YAEvD,0CAA0C;YAC1C,MAAM,UAAU,GACd,OAAO,CAAC,YAAY,CAAC,gBAAgB,CAAC;gBACtC,OAAO,CAAC,YAAY,CAAC,uBAAuB,CAAC;gBAC7C,IAAI,CAAC,MAAM,CAAC,sCAAsC,EAAE,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;YAEzE,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,MAAM,EACN,wBAAwB,IAAI,wCAAwC,EACpE;oBACE,UAAU,EACR,gFAAgF;iBACnF,CACF,CACF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,gCAAgC;QAChC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAC3B,yFAAyF,EACzF,GAAG,CACJ,CAAC;QAEF,KAAK,MAAM,MAAM,IAAI,SAAS,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAG,MAAiB,CAAC;YAClC,MAAM,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC;YAEvD,4BAA4B;YAC5B,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,sCAAsC,EAAE,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;YAE1F,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,MAAM,EACN,oBAAoB,IAAI,wCAAwC,EAChE;oBACE,UAAU,EACR,iFAAiF;iBACpF,CACF,CACF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AArED,sDAqEC"}
1
+ {"version":3,"file":"ConnectionPoolingRule.js","sourceRoot":"","sources":["../../../../src/rules/performance/ConnectionPoolingRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;;;;;;GAUG;AACH,MAAa,qBAAsB,SAAQ,mBAAQ;IACjD,EAAE,GAAG,UAAU,CAAC;IAChB,IAAI,GAAG,oBAAoB,CAAC;IAC5B,WAAW,GAAG,sDAAsD,CAAC;IACrE,QAAQ,GAAG,SAAkB,CAAC;IAC9B,QAAQ,GAAG,aAAsB,CAAC;IAElC,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,oCAAoC;QACpC,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAC7B,mGAAmG,EACnG,GAAG,CACJ,CAAC;QAEF,KAAK,MAAM,MAAM,IAAI,WAAW,EAAE,CAAC;YACjC,MAAM,OAAO,GAAG,MAAiB,CAAC;YAClC,MAAM,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC;YAEvD,+EAA+E;YAC/E,MAAM,kBAAkB,GACtB,OAAO,CAAC,YAAY,CAAC,gBAAgB,CAAC,IAAI,OAAO,CAAC,YAAY,CAAC,uBAAuB,CAAC,CAAC;YAE1F,uFAAuF;YACvF,sFAAsF;YACtF,sFAAsF;YACtF,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,CAAC,yCAAyC,EAAE,MAAM,CAAC,CAAC;YAC5F,MAAM,sBAAsB,GAC1B,eAAe,KAAK,IAAI;gBACxB,CAAE,eAA2B,CAAC,YAAY,CAAC,gBAAgB,CAAC;oBACzD,eAA2B,CAAC,YAAY,CAAC,uBAAuB,CAAC,CAAC,CAAC;YAExE,wDAAwD;YACxD,MAAM,iBAAiB,GACrB,IAAI,CAAC,MAAM,CAAC,sCAAsC,EAAE,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;YAEzE,MAAM,UAAU,GAAG,kBAAkB,IAAI,sBAAsB,IAAI,iBAAiB,CAAC;YAErF,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,MAAM,EACN,wBAAwB,IAAI,wCAAwC,EACpE;oBACE,UAAU,EACR,6GAA6G;iBAChH,CACF,CACF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,gCAAgC;QAChC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAC3B,yFAAyF,EACzF,GAAG,CACJ,CAAC;QAEF,KAAK,MAAM,MAAM,IAAI,SAAS,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAG,MAAiB,CAAC;YAClC,MAAM,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC;YAEvD,4BAA4B;YAC5B,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,sCAAsC,EAAE,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;YAE1F,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,MAAM,EACN,oBAAoB,IAAI,wCAAwC,EAChE;oBACE,UAAU,EACR,iFAAiF;iBACpF,CACF,CACF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAlFD,sDAkFC"}