@sfdxy/mule-lint 1.4.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 (206) hide show
  1. package/README.md +413 -0
  2. package/dist/bin/mule-lint.d.ts +3 -0
  3. package/dist/bin/mule-lint.d.ts.map +1 -0
  4. package/dist/bin/mule-lint.js +123 -0
  5. package/dist/bin/mule-lint.js.map +1 -0
  6. package/dist/src/core/ComplexityCalculator.d.ts +42 -0
  7. package/dist/src/core/ComplexityCalculator.d.ts.map +1 -0
  8. package/dist/src/core/ComplexityCalculator.js +123 -0
  9. package/dist/src/core/ComplexityCalculator.js.map +1 -0
  10. package/dist/src/core/FileScanner.d.ts +58 -0
  11. package/dist/src/core/FileScanner.d.ts.map +1 -0
  12. package/dist/src/core/FileScanner.js +161 -0
  13. package/dist/src/core/FileScanner.js.map +1 -0
  14. package/dist/src/core/XPathHelper.d.ts +81 -0
  15. package/dist/src/core/XPathHelper.d.ts.map +1 -0
  16. package/dist/src/core/XPathHelper.js +229 -0
  17. package/dist/src/core/XPathHelper.js.map +1 -0
  18. package/dist/src/core/XmlParser.d.ts +38 -0
  19. package/dist/src/core/XmlParser.d.ts.map +1 -0
  20. package/dist/src/core/XmlParser.js +131 -0
  21. package/dist/src/core/XmlParser.js.map +1 -0
  22. package/dist/src/core/YamlParser.d.ts +30 -0
  23. package/dist/src/core/YamlParser.d.ts.map +1 -0
  24. package/dist/src/core/YamlParser.js +120 -0
  25. package/dist/src/core/YamlParser.js.map +1 -0
  26. package/dist/src/core/index.d.ts +4 -0
  27. package/dist/src/core/index.d.ts.map +1 -0
  28. package/dist/src/core/index.js +21 -0
  29. package/dist/src/core/index.js.map +1 -0
  30. package/dist/src/engine/LintEngine.d.ts +60 -0
  31. package/dist/src/engine/LintEngine.d.ts.map +1 -0
  32. package/dist/src/engine/LintEngine.js +271 -0
  33. package/dist/src/engine/LintEngine.js.map +1 -0
  34. package/dist/src/engine/index.d.ts +2 -0
  35. package/dist/src/engine/index.d.ts.map +1 -0
  36. package/dist/src/engine/index.js +18 -0
  37. package/dist/src/engine/index.js.map +1 -0
  38. package/dist/src/formatters/JsonFormatter.d.ts +18 -0
  39. package/dist/src/formatters/JsonFormatter.d.ts.map +1 -0
  40. package/dist/src/formatters/JsonFormatter.js +45 -0
  41. package/dist/src/formatters/JsonFormatter.js.map +1 -0
  42. package/dist/src/formatters/SarifFormatter.d.ts +8 -0
  43. package/dist/src/formatters/SarifFormatter.d.ts.map +1 -0
  44. package/dist/src/formatters/SarifFormatter.js +115 -0
  45. package/dist/src/formatters/SarifFormatter.js.map +1 -0
  46. package/dist/src/formatters/TableFormatter.d.ts +10 -0
  47. package/dist/src/formatters/TableFormatter.d.ts.map +1 -0
  48. package/dist/src/formatters/TableFormatter.js +100 -0
  49. package/dist/src/formatters/TableFormatter.js.map +1 -0
  50. package/dist/src/formatters/index.d.ts +10 -0
  51. package/dist/src/formatters/index.d.ts.map +1 -0
  52. package/dist/src/formatters/index.js +42 -0
  53. package/dist/src/formatters/index.js.map +1 -0
  54. package/dist/src/index.d.ts +6 -0
  55. package/dist/src/index.d.ts.map +1 -0
  56. package/dist/src/index.js +28 -0
  57. package/dist/src/index.js.map +1 -0
  58. package/dist/src/rules/api-led/ApiLedRules.d.ts +42 -0
  59. package/dist/src/rules/api-led/ApiLedRules.d.ts.map +1 -0
  60. package/dist/src/rules/api-led/ApiLedRules.js +95 -0
  61. package/dist/src/rules/api-led/ApiLedRules.js.map +1 -0
  62. package/dist/src/rules/base/BaseRule.d.ts +89 -0
  63. package/dist/src/rules/base/BaseRule.d.ts.map +1 -0
  64. package/dist/src/rules/base/BaseRule.js +137 -0
  65. package/dist/src/rules/base/BaseRule.js.map +1 -0
  66. package/dist/src/rules/complexity/FlowComplexityRule.d.ts +18 -0
  67. package/dist/src/rules/complexity/FlowComplexityRule.d.ts.map +1 -0
  68. package/dist/src/rules/complexity/FlowComplexityRule.js +58 -0
  69. package/dist/src/rules/complexity/FlowComplexityRule.js.map +1 -0
  70. package/dist/src/rules/dataweave/DataWeaveRules.d.ts +45 -0
  71. package/dist/src/rules/dataweave/DataWeaveRules.d.ts.map +1 -0
  72. package/dist/src/rules/dataweave/DataWeaveRules.js +168 -0
  73. package/dist/src/rules/dataweave/DataWeaveRules.js.map +1 -0
  74. package/dist/src/rules/documentation/FlowDescriptionRule.d.ts +16 -0
  75. package/dist/src/rules/documentation/FlowDescriptionRule.d.ts.map +1 -0
  76. package/dist/src/rules/documentation/FlowDescriptionRule.js +33 -0
  77. package/dist/src/rules/documentation/FlowDescriptionRule.js.map +1 -0
  78. package/dist/src/rules/documentation/MissingDocNameRule.d.ts +17 -0
  79. package/dist/src/rules/documentation/MissingDocNameRule.d.ts.map +1 -0
  80. package/dist/src/rules/documentation/MissingDocNameRule.js +44 -0
  81. package/dist/src/rules/documentation/MissingDocNameRule.js.map +1 -0
  82. package/dist/src/rules/error-handling/CorrelationIdRule.d.ts +26 -0
  83. package/dist/src/rules/error-handling/CorrelationIdRule.d.ts.map +1 -0
  84. package/dist/src/rules/error-handling/CorrelationIdRule.js +86 -0
  85. package/dist/src/rules/error-handling/CorrelationIdRule.js.map +1 -0
  86. package/dist/src/rules/error-handling/GenericErrorRule.d.ts +22 -0
  87. package/dist/src/rules/error-handling/GenericErrorRule.d.ts.map +1 -0
  88. package/dist/src/rules/error-handling/GenericErrorRule.js +51 -0
  89. package/dist/src/rules/error-handling/GenericErrorRule.js.map +1 -0
  90. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.d.ts +17 -0
  91. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.d.ts.map +1 -0
  92. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.js +77 -0
  93. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.js.map +1 -0
  94. package/dist/src/rules/error-handling/HttpStatusRule.d.ts +21 -0
  95. package/dist/src/rules/error-handling/HttpStatusRule.d.ts.map +1 -0
  96. package/dist/src/rules/error-handling/HttpStatusRule.js +57 -0
  97. package/dist/src/rules/error-handling/HttpStatusRule.js.map +1 -0
  98. package/dist/src/rules/error-handling/MissingErrorHandlerRule.d.ts +17 -0
  99. package/dist/src/rules/error-handling/MissingErrorHandlerRule.d.ts.map +1 -0
  100. package/dist/src/rules/error-handling/MissingErrorHandlerRule.js +51 -0
  101. package/dist/src/rules/error-handling/MissingErrorHandlerRule.js.map +1 -0
  102. package/dist/src/rules/experimental/ExperimentalRules.d.ts +43 -0
  103. package/dist/src/rules/experimental/ExperimentalRules.d.ts.map +1 -0
  104. package/dist/src/rules/experimental/ExperimentalRules.js +92 -0
  105. package/dist/src/rules/experimental/ExperimentalRules.js.map +1 -0
  106. package/dist/src/rules/http/HttpContentTypeRule.d.ts +17 -0
  107. package/dist/src/rules/http/HttpContentTypeRule.d.ts.map +1 -0
  108. package/dist/src/rules/http/HttpContentTypeRule.js +50 -0
  109. package/dist/src/rules/http/HttpContentTypeRule.js.map +1 -0
  110. package/dist/src/rules/http/HttpTimeoutRule.d.ts +16 -0
  111. package/dist/src/rules/http/HttpTimeoutRule.d.ts.map +1 -0
  112. package/dist/src/rules/http/HttpTimeoutRule.js +33 -0
  113. package/dist/src/rules/http/HttpTimeoutRule.js.map +1 -0
  114. package/dist/src/rules/http/HttpUserAgentRule.d.ts +17 -0
  115. package/dist/src/rules/http/HttpUserAgentRule.d.ts.map +1 -0
  116. package/dist/src/rules/http/HttpUserAgentRule.js +48 -0
  117. package/dist/src/rules/http/HttpUserAgentRule.js.map +1 -0
  118. package/dist/src/rules/index.d.ts +45 -0
  119. package/dist/src/rules/index.d.ts.map +1 -0
  120. package/dist/src/rules/index.js +205 -0
  121. package/dist/src/rules/index.js.map +1 -0
  122. package/dist/src/rules/logging/LoggerCategoryRule.d.ts +21 -0
  123. package/dist/src/rules/logging/LoggerCategoryRule.d.ts.map +1 -0
  124. package/dist/src/rules/logging/LoggerCategoryRule.js +61 -0
  125. package/dist/src/rules/logging/LoggerCategoryRule.js.map +1 -0
  126. package/dist/src/rules/logging/LoggerInUntilSuccessfulRule.d.ts +16 -0
  127. package/dist/src/rules/logging/LoggerInUntilSuccessfulRule.d.ts.map +1 -0
  128. package/dist/src/rules/logging/LoggerInUntilSuccessfulRule.js +29 -0
  129. package/dist/src/rules/logging/LoggerInUntilSuccessfulRule.js.map +1 -0
  130. package/dist/src/rules/logging/LoggerPayloadRule.d.ts +17 -0
  131. package/dist/src/rules/logging/LoggerPayloadRule.d.ts.map +1 -0
  132. package/dist/src/rules/logging/LoggerPayloadRule.js +39 -0
  133. package/dist/src/rules/logging/LoggerPayloadRule.js.map +1 -0
  134. package/dist/src/rules/naming/FlowCasingRule.d.ts +18 -0
  135. package/dist/src/rules/naming/FlowCasingRule.d.ts.map +1 -0
  136. package/dist/src/rules/naming/FlowCasingRule.js +40 -0
  137. package/dist/src/rules/naming/FlowCasingRule.js.map +1 -0
  138. package/dist/src/rules/naming/FlowNamingRule.d.ts +17 -0
  139. package/dist/src/rules/naming/FlowNamingRule.d.ts.map +1 -0
  140. package/dist/src/rules/naming/FlowNamingRule.js +60 -0
  141. package/dist/src/rules/naming/FlowNamingRule.js.map +1 -0
  142. package/dist/src/rules/naming/VariableNamingRule.d.ts +18 -0
  143. package/dist/src/rules/naming/VariableNamingRule.d.ts.map +1 -0
  144. package/dist/src/rules/naming/VariableNamingRule.js +39 -0
  145. package/dist/src/rules/naming/VariableNamingRule.js.map +1 -0
  146. package/dist/src/rules/performance/AsyncErrorHandlerRule.d.ts +16 -0
  147. package/dist/src/rules/performance/AsyncErrorHandlerRule.d.ts.map +1 -0
  148. package/dist/src/rules/performance/AsyncErrorHandlerRule.js +34 -0
  149. package/dist/src/rules/performance/AsyncErrorHandlerRule.js.map +1 -0
  150. package/dist/src/rules/performance/LargeChoiceBlockRule.d.ts +16 -0
  151. package/dist/src/rules/performance/LargeChoiceBlockRule.d.ts.map +1 -0
  152. package/dist/src/rules/performance/LargeChoiceBlockRule.js +32 -0
  153. package/dist/src/rules/performance/LargeChoiceBlockRule.js.map +1 -0
  154. package/dist/src/rules/performance/ScatterGatherRoutesRule.d.ts +16 -0
  155. package/dist/src/rules/performance/ScatterGatherRoutesRule.d.ts.map +1 -0
  156. package/dist/src/rules/performance/ScatterGatherRoutesRule.js +32 -0
  157. package/dist/src/rules/performance/ScatterGatherRoutesRule.js.map +1 -0
  158. package/dist/src/rules/security/HardcodedCredentialsRule.d.ts +19 -0
  159. package/dist/src/rules/security/HardcodedCredentialsRule.d.ts.map +1 -0
  160. package/dist/src/rules/security/HardcodedCredentialsRule.js +66 -0
  161. package/dist/src/rules/security/HardcodedCredentialsRule.js.map +1 -0
  162. package/dist/src/rules/security/HardcodedHttpRule.d.ts +33 -0
  163. package/dist/src/rules/security/HardcodedHttpRule.d.ts.map +1 -0
  164. package/dist/src/rules/security/HardcodedHttpRule.js +108 -0
  165. package/dist/src/rules/security/HardcodedHttpRule.js.map +1 -0
  166. package/dist/src/rules/security/InsecureTlsRule.d.ts +16 -0
  167. package/dist/src/rules/security/InsecureTlsRule.d.ts.map +1 -0
  168. package/dist/src/rules/security/InsecureTlsRule.js +36 -0
  169. package/dist/src/rules/security/InsecureTlsRule.js.map +1 -0
  170. package/dist/src/rules/standards/ChoiceAntiPatternRule.d.ts +17 -0
  171. package/dist/src/rules/standards/ChoiceAntiPatternRule.d.ts.map +1 -0
  172. package/dist/src/rules/standards/ChoiceAntiPatternRule.js +43 -0
  173. package/dist/src/rules/standards/ChoiceAntiPatternRule.js.map +1 -0
  174. package/dist/src/rules/standards/DeprecatedComponentRule.d.ts +17 -0
  175. package/dist/src/rules/standards/DeprecatedComponentRule.d.ts.map +1 -0
  176. package/dist/src/rules/standards/DeprecatedComponentRule.js +37 -0
  177. package/dist/src/rules/standards/DeprecatedComponentRule.js.map +1 -0
  178. package/dist/src/rules/standards/DwlStandardsRule.d.ts +22 -0
  179. package/dist/src/rules/standards/DwlStandardsRule.d.ts.map +1 -0
  180. package/dist/src/rules/standards/DwlStandardsRule.js +90 -0
  181. package/dist/src/rules/standards/DwlStandardsRule.js.map +1 -0
  182. package/dist/src/rules/structure/StructureRules.d.ts +45 -0
  183. package/dist/src/rules/structure/StructureRules.d.ts.map +1 -0
  184. package/dist/src/rules/structure/StructureRules.js +163 -0
  185. package/dist/src/rules/structure/StructureRules.js.map +1 -0
  186. package/dist/src/rules/yaml/YamlRules.d.ts +46 -0
  187. package/dist/src/rules/yaml/YamlRules.d.ts.map +1 -0
  188. package/dist/src/rules/yaml/YamlRules.js +226 -0
  189. package/dist/src/rules/yaml/YamlRules.js.map +1 -0
  190. package/dist/src/types/Config.d.ts +50 -0
  191. package/dist/src/types/Config.d.ts.map +1 -0
  192. package/dist/src/types/Config.js +18 -0
  193. package/dist/src/types/Config.js.map +1 -0
  194. package/dist/src/types/Report.d.ts +47 -0
  195. package/dist/src/types/Report.d.ts.map +1 -0
  196. package/dist/src/types/Report.js +3 -0
  197. package/dist/src/types/Report.js.map +1 -0
  198. package/dist/src/types/Rule.d.ts +76 -0
  199. package/dist/src/types/Rule.d.ts.map +1 -0
  200. package/dist/src/types/Rule.js +3 -0
  201. package/dist/src/types/Rule.js.map +1 -0
  202. package/dist/src/types/index.d.ts +4 -0
  203. package/dist/src/types/index.d.ts.map +1 -0
  204. package/dist/src/types/index.js +21 -0
  205. package/dist/src/types/index.js.map +1 -0
  206. package/package.json +70 -0
package/README.md ADDED
@@ -0,0 +1,413 @@
1
+ # Mule-Lint
2
+
3
+ <p align="center">
4
+ <strong>Enterprise-grade static analysis tool for MuleSoft applications</strong>
5
+ </p>
6
+
7
+ <p align="center">
8
+ <a href="#installation">Installation</a> •
9
+ <a href="#quick-start">Quick Start</a> •
10
+ <a href="#rules">Rules</a> •
11
+ <a href="#output-formats">Output</a> •
12
+ <a href="#configuration">Configuration</a> •
13
+ <a href="#extending">Extending</a>
14
+ </p>
15
+
16
+ ---
17
+
18
+ ## Overview
19
+
20
+ **Mule-Lint** is a TypeScript-based linting tool designed to enforce best practices and standards for MuleSoft applications. It provides:
21
+
22
+ - ✅ **10+ Built-in Rules** covering error handling, naming conventions, security, and logging
23
+ - ✅ **Multiple Output Formats** - Table (human), JSON (scripts), SARIF (AI agents/VS Code)
24
+ - ✅ **CI/CD Ready** - Exit codes and machine-readable output
25
+ - ✅ **TypeScript** - Fully typed for VS Code extension integration
26
+ - ✅ **Extensible** - Add custom rules for your organization
27
+
28
+ ### Architecture
29
+
30
+ ```mermaid
31
+ flowchart TB
32
+ subgraph CLI["CLI Layer"]
33
+ A[mule-lint command]
34
+ end
35
+
36
+ subgraph Engine["LintEngine"]
37
+ B[FileScanner] --> C[XmlParser]
38
+ C --> D[Rule Executor]
39
+ end
40
+
41
+ subgraph Rules["Rules - Strategy Pattern"]
42
+ D --> E[MULE-001]
43
+ D --> F[MULE-002]
44
+ D --> G[...]
45
+ D --> H[MULE-010]
46
+ end
47
+
48
+ subgraph Output["Formatters"]
49
+ I[Table]
50
+ J[JSON]
51
+ K[SARIF]
52
+ end
53
+
54
+ A --> B
55
+ D --> I
56
+ D --> J
57
+ D --> K
58
+ ```
59
+
60
+ ### Data Flow
61
+
62
+ ```mermaid
63
+ flowchart LR
64
+ A["XML Files"] --> B["Parse DOM"]
65
+ B --> C["Execute Rules"]
66
+ C --> D["Collect Issues"]
67
+ D --> E["Format Output"]
68
+ E --> F["Table / JSON / SARIF"]
69
+ ```
70
+
71
+
72
+ ---
73
+
74
+ ## Installation
75
+
76
+ ```bash
77
+ # Global installation
78
+ npm install -g mule-lint
79
+
80
+ # Or as a dev dependency
81
+ npm install --save-dev mule-lint
82
+ ```
83
+
84
+ ---
85
+
86
+ ## Quick Start
87
+
88
+ ```bash
89
+ # Scan a directory
90
+ mule-lint ./src/main/mule
91
+
92
+ # Scan a single file
93
+ mule-lint ./src/main/mule/implementation.xml
94
+
95
+ # Output as JSON
96
+ mule-lint ./src/main/mule -f json
97
+
98
+ # Output as SARIF (for AI agents/VS Code)
99
+ mule-lint ./src/main/mule -f sarif > report.sarif
100
+
101
+ # Write to file
102
+ mule-lint ./src/main/mule -o report.txt
103
+
104
+ # Fail on warnings (for CI/CD)
105
+ mule-lint ./src/main/mule --fail-on-warning
106
+ ```
107
+
108
+ ### CLI Options
109
+
110
+ | Option | Description |
111
+ |--------|-------------|
112
+ | `-f, --format <type>` | Output format: `table`, `json`, `sarif` (default: `table`) |
113
+ | `-o, --output <file>` | Write output to file instead of stdout |
114
+ | `-c, --config <file>` | Path to configuration file |
115
+ | `-q, --quiet` | Show only errors (suppress warnings and info) |
116
+ | `-e, --experimental` | **Enable experimental rules (opt-in)** |
117
+ | `--fail-on-warning` | Exit with error code if warnings found |
118
+ | `-v, --verbose` | Show verbose output |
119
+
120
+ ### Examples
121
+
122
+ ```bash
123
+ # Basic scan
124
+ mule-lint .
125
+
126
+ # Scan with experimental rules
127
+ mule-lint . --experimental
128
+
129
+ # Output SARIF for VS Code
130
+ mule-lint src/main/mule -f sarif -o results.sarif
131
+ ```
132
+
133
+ ---
134
+
135
+ ## Rules
136
+
137
+ ### Core Rules (MVP)
138
+
139
+ | ID | Name | Severity | Category | Description |
140
+ |----|------|----------|----------|-------------|
141
+ | MULE-001 | Global Error Handler | Error | Error Handling | Project should have global error handler |
142
+ | MULE-002 | Flow Naming | Warning | Naming | Flows end with `-flow`, sub-flows with `-subflow` |
143
+ | MULE-003 | Missing Error Handler | Error | Error Handling | Flows should have error handlers |
144
+ | MULE-004 | Hardcoded URLs | Error | Security | Use property placeholders for URLs |
145
+ | MULE-005 | HTTP Status Check | Warning | Error Handling | Error handlers should set httpStatus |
146
+ | MULE-006 | Logger Category | Warning | Logging | Loggers should have category attribute |
147
+ | MULE-007 | Correlation ID | Warning | Error Handling | Error handlers should reference correlationId |
148
+ | MULE-008 | Choice Anti-Pattern | Warning | Standards | Avoid raise-error in otherwise |
149
+ | MULE-009 | Generic Error Type | Warning | Error Handling | Avoid catching type="ANY" |
150
+ | MULE-010 | DWL Standards | Info | Standards | Standard DataWeave files should exist |
151
+
152
+ ### Extended Rules
153
+
154
+ | ID | Name | Severity | Category | Description |
155
+ |----|------|----------|----------|-------------|
156
+ | MULE-101 | Flow Casing | Warning | Naming | kebab-case for flows |
157
+ | MULE-102 | Variable Naming | Warning | Naming | camelCase for variables |
158
+ | MULE-201 | Hardcoded Credentials | Error | Security | Use `${secure::}` |
159
+ | MULE-202 | Insecure TLS | Error | Security | No insecure="true" |
160
+ | MULE-301 | Logger Payload | Warning | Logging | Don't log entire payload |
161
+ | MULE-303 | Logger in Retry | Warning | Logging | Avoid loggers in until-successful |
162
+ | MULE-401 | HTTP User-Agent | Warning | HTTP | Include User-Agent |
163
+ | MULE-402 | HTTP Content-Type | Warning | HTTP | POST/PUT needs Content-Type |
164
+ | MULE-403 | HTTP Timeout | Warning | HTTP | Set responseTimeout |
165
+ | MULE-501 | Scatter-Gather | Info | Performance | Limit parallel routes |
166
+ | MULE-502 | Async Error | Warning | Performance | Async needs error handling |
167
+ | MULE-503 | Large Choice | Warning | Performance | Max 7 when clauses |
168
+ | MULE-601 | Flow Description | Info | Documentation | Add doc:description |
169
+ | MULE-604 | Missing doc:name | Warning | Documentation | Key components need doc:name |
170
+ | MULE-701 | Deprecated | Warning | Standards | Detect deprecated elements |
171
+ | MULE-801 | Flow Complexity | Warning | Complexity | Cyclomatic complexity threshold |
172
+ | MULE-802 | Project Structure | Warning | Structure | Validate folder structure |
173
+ | MULE-803 | Global Config | Warning | Structure | global.xml should exist |
174
+ | MULE-804 | Monolithic XML | Warning | Structure | Split large XML files |
175
+
176
+ ### DataWeave & API-Led Rules
177
+
178
+ | ID | Name | Severity | Category | Description |
179
+ |----|------|----------|----------|-------------|
180
+ | DW-001 | External DWL | Warning | DataWeave | Externalize complex transforms |
181
+ | DW-002 | DWL Naming | Info | DataWeave | kebab-case for .dwl files |
182
+ | DW-003 | DWL Modules | Info | DataWeave | Use common modules |
183
+ | API-001 | Experience Layer | Info | API-Led | Experience API patterns |
184
+ | API-002 | Process Layer | Info | API-Led | Process layer orchestration |
185
+ | API-003 | System Layer | Info | API-Led | System layer connections |
186
+
187
+ ### Experimental Rules
188
+
189
+ | ID | Name | Severity | Category | Description |
190
+ |----|------|----------|----------|-------------|
191
+ | EXP-001 | Flow Ref Depth | Info | Experimental | Limit flow-ref chains |
192
+ | EXP-002 | Config Naming | Info | Experimental | Connector config naming |
193
+ | EXP-003 | MUnit Coverage | Info | Experimental | Check for MUnit tests |
194
+ | YAML-001 | Env Files | Warning | Standards | Environment YAML files |
195
+ | YAML-003 | Property Naming | Info | Standards | Property key format |
196
+ | YAML-004 | Plaintext Secrets | Error | Security | Encrypted secrets |
197
+
198
+ **Total: 41 rules** across 13 categories.
199
+
200
+ See [Rules Catalog](docs/rules-catalog.md) for detailed documentation.
201
+
202
+
203
+
204
+ ---
205
+
206
+ ## Output Formats
207
+
208
+ ### Table (Default)
209
+
210
+ Human-readable colorized output:
211
+
212
+ ```
213
+ Mule-Lint Report
214
+ Scanned 5 files in 123ms
215
+
216
+ src/main/mule/impl.xml
217
+ 45:0 error Flow "getOrders" is missing an error handler (MULE-003)
218
+ 67:0 warning Logger is missing 'category' attribute (MULE-006)
219
+
220
+ Summary:
221
+ Errors: 1
222
+ Warnings: 1
223
+ Infos: 0
224
+ ```
225
+
226
+ ### JSON
227
+
228
+ Machine-readable for scripting:
229
+
230
+ ```json
231
+ [
232
+ {
233
+ "filePath": "/path/to/impl.xml",
234
+ "line": 45,
235
+ "message": "Flow \"getOrders\" is missing an error handler",
236
+ "ruleId": "MULE-003",
237
+ "severity": "error"
238
+ }
239
+ ]
240
+ ```
241
+
242
+ ### SARIF (For AI Agents)
243
+
244
+ [SARIF 2.1.0](https://sarifweb.azurewebsites.net/) format for VS Code, GitHub, and AI agents:
245
+
246
+ ```json
247
+ {
248
+ "$schema": "https://json.schemastore.org/sarif-2.1.0.json",
249
+ "version": "2.1.0",
250
+ "runs": [{
251
+ "tool": {
252
+ "driver": {
253
+ "name": "mule-lint",
254
+ "version": "1.0.0"
255
+ }
256
+ },
257
+ "results": [...]
258
+ }]
259
+ }
260
+ ```
261
+
262
+ ---
263
+
264
+ ## Configuration
265
+
266
+ Create a `.mulelintrc.json` file in your project root:
267
+
268
+ ```json
269
+ {
270
+ "rules": {
271
+ "MULE-001": { "enabled": true },
272
+ "MULE-002": {
273
+ "enabled": true,
274
+ "options": {
275
+ "flowSuffix": "-flow",
276
+ "subflowSuffix": "-subflow",
277
+ "excludePatterns": ["*-api-main"]
278
+ }
279
+ },
280
+ "MULE-006": {
281
+ "enabled": true,
282
+ "severity": "error",
283
+ "options": {
284
+ "requiredPrefix": "com.myorg"
285
+ }
286
+ }
287
+ },
288
+ "include": ["src/main/mule/**/*.xml"],
289
+ "exclude": ["**/test/**", "**/*.munit.xml"],
290
+ "failOnWarning": false
291
+ }
292
+ ```
293
+
294
+ ---
295
+
296
+ ## Using as a Library
297
+
298
+ Import directly into your TypeScript/JavaScript projects:
299
+
300
+ ```typescript
301
+ import { LintEngine, ALL_RULES, formatSarif } from 'mule-lint';
302
+
303
+ // Create engine with all rules
304
+ const engine = new LintEngine({
305
+ rules: ALL_RULES,
306
+ config: {
307
+ include: ['src/main/mule/**/*.xml'],
308
+ },
309
+ });
310
+
311
+ // Scan a project
312
+ const report = await engine.scan('./my-mule-project');
313
+ console.log(formatSarif(report));
314
+
315
+ // Scan content directly (useful for VS Code extensions)
316
+ const issues = engine.scanContent(xmlContent, 'file.xml');
317
+ ```
318
+
319
+ ---
320
+
321
+ ## Extending
322
+
323
+ ### Adding Custom Rules
324
+
325
+ See [Extending Guide](docs/extending.md) for detailed instructions on creating custom rules.
326
+
327
+ ```typescript
328
+ import { BaseRule, ValidationContext, Issue } from 'mule-lint';
329
+
330
+ export class MyCustomRule extends BaseRule {
331
+ id = 'CUSTOM-001';
332
+ name = 'My Custom Rule';
333
+ description = 'Enforces my organization standards';
334
+ severity = 'warning' as const;
335
+ category = 'standards' as const;
336
+
337
+ validate(doc: Document, context: ValidationContext): Issue[] {
338
+ // Your validation logic using XPath
339
+ const flows = this.select('//mule:flow', doc);
340
+ // ...
341
+ }
342
+ }
343
+ ```
344
+
345
+ ---
346
+
347
+ ## Project Inspiration
348
+
349
+ This project is inspired by and builds upon the ideas from:
350
+
351
+ - **[mule-lint/mule-lint](https://github.com/mule-lint/mule-lint)** - The original Groovy-based MuleSoft linting tool with DSL-based rule definitions
352
+
353
+ While the original project uses Groovy and a custom DSL, this TypeScript implementation was created to:
354
+ - Enable easier VS Code extension integration
355
+ - Provide better AI agent compatibility via SARIF output
356
+ - Leverage the modern npm ecosystem
357
+ - Offer simpler CI/CD integration
358
+
359
+ ---
360
+
361
+ ## Documentation
362
+
363
+ | Document | Description |
364
+ |----------|-------------|
365
+ | [Architecture](docs/architecture.md) | System design and data flow |
366
+ | [Rules Catalog](docs/rules-catalog.md) | Complete list of all rules |
367
+ | [Extending](docs/extending.md) | How to add custom rules |
368
+ | [Naming Conventions](docs/naming-conventions.md) | Code style guide |
369
+
370
+ ---
371
+
372
+ ## Development
373
+
374
+ ```bash
375
+ # Install dependencies
376
+ npm install
377
+
378
+ # Build
379
+ npm run build
380
+
381
+ # Run tests
382
+ npm test
383
+
384
+ # Lint
385
+ npm run lint
386
+ ```
387
+
388
+ ---
389
+
390
+ ## Credits
391
+
392
+ <table>
393
+ <tr>
394
+ <td align="center">
395
+ <strong>Built with AI Assistance</strong><br>
396
+ This project was developed with the assistance of:<br><br>
397
+ 🚀 <strong>Antigravity</strong> (Google DeepMind)<br>
398
+ 🤖 <strong>GitHub Copilot</strong>
399
+ </td>
400
+ </tr>
401
+ </table>
402
+
403
+ ---
404
+
405
+ ## Contributing
406
+
407
+ Contributions are welcome! Please read the [Contributing Guide](CONTRIBUTING.md) for details.
408
+
409
+ ---
410
+
411
+ ## License
412
+
413
+ MIT © 2024
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=mule-lint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mule-lint.d.ts","sourceRoot":"","sources":["../../bin/mule-lint.ts"],"names":[],"mappings":""}
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ const commander_1 = require("commander");
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const LintEngine_1 = require("../src/engine/LintEngine");
41
+ const rules_1 = require("../src/rules");
42
+ const formatters_1 = require("../src/formatters");
43
+ const program = new commander_1.Command();
44
+ program
45
+ .name('mule-lint')
46
+ .description('Static analysis tool for MuleSoft applications')
47
+ .version('1.0.0')
48
+ .argument('<path>', 'Path to scan (directory or file)')
49
+ .option('-f, --format <type>', 'Output format: table, json, sarif', 'table')
50
+ .option('-o, --output <file>', 'Write output to file instead of stdout')
51
+ .option('-c, --config <file>', 'Path to configuration file')
52
+ .option('-q, --quiet', 'Show only errors (suppress warnings and info)')
53
+ .option('--fail-on-warning', 'Exit with error code if warnings found')
54
+ .option('-e, --experimental', 'Enable experimental rules (opt-in)')
55
+ .option('-v, --verbose', 'Show verbose output')
56
+ .action(async (targetPath, options) => {
57
+ try {
58
+ await runLint(targetPath, options);
59
+ }
60
+ catch (error) {
61
+ const message = error instanceof Error ? error.message : String(error);
62
+ console.error(`Error: ${message}`);
63
+ process.exit(2);
64
+ }
65
+ });
66
+ async function runLint(targetPath, options) {
67
+ const absolutePath = path.resolve(targetPath);
68
+ // Validate path exists
69
+ if (!fs.existsSync(absolutePath)) {
70
+ throw new Error(`Path does not exist: ${absolutePath}`);
71
+ }
72
+ // Load configuration if specified
73
+ let config = {};
74
+ if (options.config) {
75
+ const configPath = path.resolve(options.config);
76
+ if (!fs.existsSync(configPath)) {
77
+ throw new Error(`Config file not found: ${configPath}`);
78
+ }
79
+ const configContent = fs.readFileSync(configPath, 'utf-8');
80
+ config = JSON.parse(configContent);
81
+ }
82
+ // Filter rules based on keys (experimental is opt-in)
83
+ const effectiveRules = options.experimental
84
+ ? rules_1.ALL_RULES
85
+ : rules_1.ALL_RULES.filter(rule => rule.category !== 'experimental');
86
+ if (options.verbose) {
87
+ console.log(`Loaded ${effectiveRules.length} rules (Experimental: ${options.experimental ? 'ON' : 'OFF'})`);
88
+ }
89
+ // Create engine
90
+ const engine = new LintEngine_1.LintEngine({
91
+ rules: effectiveRules,
92
+ config,
93
+ verbose: options.verbose,
94
+ });
95
+ // Run scan
96
+ const report = await engine.scan(absolutePath);
97
+ // Filter if quiet mode
98
+ if (options.quiet) {
99
+ for (const file of report.files) {
100
+ file.issues = file.issues.filter(issue => issue.severity === 'error');
101
+ }
102
+ report.summary.bySeverity.warning = 0;
103
+ report.summary.bySeverity.info = 0;
104
+ }
105
+ // Format output
106
+ const formatterType = options.format;
107
+ const output = (0, formatters_1.format)(report, formatterType);
108
+ // Write output
109
+ if (options.output) {
110
+ const outputPath = path.resolve(options.output);
111
+ fs.writeFileSync(outputPath, output, 'utf-8');
112
+ console.log(`Report written to: ${outputPath}`);
113
+ }
114
+ else {
115
+ console.log(output);
116
+ }
117
+ // Exit code
118
+ const exitCode = (0, formatters_1.getExitCode)(report, options.failOnWarning);
119
+ process.exit(exitCode);
120
+ }
121
+ // Run the CLI
122
+ program.parse();
123
+ //# sourceMappingURL=mule-lint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mule-lint.js","sourceRoot":"","sources":["../../bin/mule-lint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Calculates cyclomatic complexity for Mule flows
3
+ *
4
+ * Complexity = 1 + (number of decision points)
5
+ *
6
+ * Decision points in Mule XML:
7
+ * - <choice> with N <when> clauses = N decision points
8
+ * - <until-successful> = 1 decision point
9
+ * - <foreach> = 1 decision point
10
+ * - <scatter-gather> = 1 decision point (parallel execution)
11
+ * - <try> = 1 decision point
12
+ */
13
+ export declare class ComplexityCalculator {
14
+ /**
15
+ * Calculate cyclomatic complexity for a flow element
16
+ */
17
+ static calculateFlowComplexity(flowNode: Node): ComplexityResult;
18
+ /**
19
+ * Get complexity rating
20
+ */
21
+ static getRating(complexity: number): ComplexityRating;
22
+ /**
23
+ * Helper to select nodes using XPath with Mule namespace
24
+ */
25
+ private static selectNodes;
26
+ /**
27
+ * Get the line number for a node
28
+ */
29
+ static getNodeLine(node: Node): number;
30
+ }
31
+ export interface ComplexityResult {
32
+ complexity: number;
33
+ details: ComplexityDetail[];
34
+ rating: ComplexityRating;
35
+ }
36
+ export interface ComplexityDetail {
37
+ type: string;
38
+ count: number;
39
+ contribution: number;
40
+ }
41
+ export type ComplexityRating = 'low' | 'moderate' | 'high';
42
+ //# sourceMappingURL=ComplexityCalculator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ComplexityCalculator.d.ts","sourceRoot":"","sources":["../../../src/core/ComplexityCalculator.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,qBAAa,oBAAoB;IAC7B;;OAEG;IACH,MAAM,CAAC,uBAAuB,CAAC,QAAQ,EAAE,IAAI,GAAG,gBAAgB;IA6EhE;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB;IAMtD;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;IAa1B;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM;CAGzC;AAED,MAAM,WAAW,gBAAgB;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,MAAM,EAAE,gBAAgB,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,UAAU,GAAG,MAAM,CAAC"}