@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.
- package/README.md +128 -73
- package/dist/package.json +1 -1
- package/dist/src/core/XPathHelper.d.ts.map +1 -1
- package/dist/src/core/XPathHelper.js +8 -0
- package/dist/src/core/XPathHelper.js.map +1 -1
- package/dist/src/engine/LintEngine.d.ts +32 -0
- package/dist/src/engine/LintEngine.d.ts.map +1 -1
- package/dist/src/engine/LintEngine.js +166 -15
- package/dist/src/engine/LintEngine.js.map +1 -1
- package/dist/src/rules/api-led/ApikitConsoleProductionRule.d.ts +22 -0
- package/dist/src/rules/api-led/ApikitConsoleProductionRule.d.ts.map +1 -0
- package/dist/src/rules/api-led/ApikitConsoleProductionRule.js +43 -0
- package/dist/src/rules/api-led/ApikitConsoleProductionRule.js.map +1 -0
- package/dist/src/rules/api-led/ApikitMainFlowStructureRule.d.ts +24 -0
- package/dist/src/rules/api-led/ApikitMainFlowStructureRule.d.ts.map +1 -0
- package/dist/src/rules/api-led/ApikitMainFlowStructureRule.js +53 -0
- package/dist/src/rules/api-led/ApikitMainFlowStructureRule.js.map +1 -0
- package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.d.ts +25 -0
- package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.d.ts.map +1 -0
- package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.js +59 -0
- package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.js.map +1 -0
- package/dist/src/rules/connector/EventListenerNullGuardRule.d.ts +24 -0
- package/dist/src/rules/connector/EventListenerNullGuardRule.d.ts.map +1 -0
- package/dist/src/rules/connector/EventListenerNullGuardRule.js +58 -0
- package/dist/src/rules/connector/EventListenerNullGuardRule.js.map +1 -0
- package/dist/src/rules/connector/ReplayChannelConfigRule.d.ts +23 -0
- package/dist/src/rules/connector/ReplayChannelConfigRule.d.ts.map +1 -0
- package/dist/src/rules/connector/ReplayChannelConfigRule.js +52 -0
- package/dist/src/rules/connector/ReplayChannelConfigRule.js.map +1 -0
- package/dist/src/rules/dataweave/DataWeaveRules.d.ts +17 -4
- package/dist/src/rules/dataweave/DataWeaveRules.d.ts.map +1 -1
- package/dist/src/rules/dataweave/DataWeaveRules.js +36 -20
- package/dist/src/rules/dataweave/DataWeaveRules.js.map +1 -1
- package/dist/src/rules/dataweave/DuplicateTransformLogicRule.d.ts +25 -0
- package/dist/src/rules/dataweave/DuplicateTransformLogicRule.d.ts.map +1 -0
- package/dist/src/rules/dataweave/DuplicateTransformLogicRule.js +63 -0
- package/dist/src/rules/dataweave/DuplicateTransformLogicRule.js.map +1 -0
- package/dist/src/rules/error-handling/CatchAllLastRule.d.ts +24 -0
- package/dist/src/rules/error-handling/CatchAllLastRule.d.ts.map +1 -0
- package/dist/src/rules/error-handling/CatchAllLastRule.js +65 -0
- package/dist/src/rules/error-handling/CatchAllLastRule.js.map +1 -0
- package/dist/src/rules/error-handling/CorrelationIdRule.d.ts +22 -1
- package/dist/src/rules/error-handling/CorrelationIdRule.d.ts.map +1 -1
- package/dist/src/rules/error-handling/CorrelationIdRule.js +107 -6
- package/dist/src/rules/error-handling/CorrelationIdRule.js.map +1 -1
- package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.d.ts +28 -0
- package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.d.ts.map +1 -0
- package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.js +70 -0
- package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.js.map +1 -0
- package/dist/src/rules/error-handling/ErrorResponseStructureRule.d.ts +23 -0
- package/dist/src/rules/error-handling/ErrorResponseStructureRule.d.ts.map +1 -0
- package/dist/src/rules/error-handling/ErrorResponseStructureRule.js +73 -0
- package/dist/src/rules/error-handling/ErrorResponseStructureRule.js.map +1 -0
- package/dist/src/rules/error-handling/GenericErrorRule.d.ts +15 -3
- package/dist/src/rules/error-handling/GenericErrorRule.d.ts.map +1 -1
- package/dist/src/rules/error-handling/GenericErrorRule.js +58 -18
- package/dist/src/rules/error-handling/GenericErrorRule.js.map +1 -1
- package/dist/src/rules/error-handling/GlobalErrorHandlerRule.d.ts +16 -5
- package/dist/src/rules/error-handling/GlobalErrorHandlerRule.d.ts.map +1 -1
- package/dist/src/rules/error-handling/GlobalErrorHandlerRule.js +64 -21
- package/dist/src/rules/error-handling/GlobalErrorHandlerRule.js.map +1 -1
- package/dist/src/rules/error-handling/HttpStatusRule.d.ts +5 -0
- package/dist/src/rules/error-handling/HttpStatusRule.d.ts.map +1 -1
- package/dist/src/rules/error-handling/HttpStatusRule.js +15 -0
- package/dist/src/rules/error-handling/HttpStatusRule.js.map +1 -1
- package/dist/src/rules/error-handling/TryScopeRule.d.ts +5 -0
- package/dist/src/rules/error-handling/TryScopeRule.d.ts.map +1 -1
- package/dist/src/rules/error-handling/TryScopeRule.js +30 -7
- package/dist/src/rules/error-handling/TryScopeRule.js.map +1 -1
- package/dist/src/rules/http/ConnectionIdleTimeoutRule.d.ts +27 -0
- package/dist/src/rules/http/ConnectionIdleTimeoutRule.d.ts.map +1 -0
- package/dist/src/rules/http/ConnectionIdleTimeoutRule.js +46 -0
- package/dist/src/rules/http/ConnectionIdleTimeoutRule.js.map +1 -0
- package/dist/src/rules/http/HttpContentTypeRule.d.ts +28 -1
- package/dist/src/rules/http/HttpContentTypeRule.d.ts.map +1 -1
- package/dist/src/rules/http/HttpContentTypeRule.js +68 -7
- package/dist/src/rules/http/HttpContentTypeRule.js.map +1 -1
- package/dist/src/rules/index.d.ts +1 -1
- package/dist/src/rules/index.d.ts.map +1 -1
- package/dist/src/rules/index.js +50 -8
- package/dist/src/rules/index.js.map +1 -1
- package/dist/src/rules/logging/LoggerPayloadRule.d.ts +15 -0
- package/dist/src/rules/logging/LoggerPayloadRule.d.ts.map +1 -1
- package/dist/src/rules/logging/LoggerPayloadRule.js +48 -4
- package/dist/src/rules/logging/LoggerPayloadRule.js.map +1 -1
- package/dist/src/rules/operations/FlowRefTargetExistsRule.d.ts +23 -0
- package/dist/src/rules/operations/FlowRefTargetExistsRule.d.ts.map +1 -0
- package/dist/src/rules/operations/FlowRefTargetExistsRule.js +58 -0
- package/dist/src/rules/operations/FlowRefTargetExistsRule.js.map +1 -0
- package/dist/src/rules/operations/UnusedFlowRule.d.ts +26 -1
- package/dist/src/rules/operations/UnusedFlowRule.d.ts.map +1 -1
- package/dist/src/rules/operations/UnusedFlowRule.js +96 -16
- package/dist/src/rules/operations/UnusedFlowRule.js.map +1 -1
- package/dist/src/rules/operations/UnusedVariableRule.d.ts +31 -0
- package/dist/src/rules/operations/UnusedVariableRule.d.ts.map +1 -0
- package/dist/src/rules/operations/UnusedVariableRule.js +103 -0
- package/dist/src/rules/operations/UnusedVariableRule.js.map +1 -0
- package/dist/src/rules/performance/ConnectionPoolingRule.d.ts +5 -0
- package/dist/src/rules/performance/ConnectionPoolingRule.d.ts.map +1 -1
- package/dist/src/rules/performance/ConnectionPoolingRule.js +18 -5
- package/dist/src/rules/performance/ConnectionPoolingRule.js.map +1 -1
- package/dist/src/rules/performance/ListenerReconnectForeverRule.d.ts +28 -0
- package/dist/src/rules/performance/ListenerReconnectForeverRule.d.ts.map +1 -0
- package/dist/src/rules/performance/ListenerReconnectForeverRule.js +56 -0
- package/dist/src/rules/performance/ListenerReconnectForeverRule.js.map +1 -0
- package/dist/src/rules/performance/ReconnectionStrategyRule.d.ts +10 -0
- package/dist/src/rules/performance/ReconnectionStrategyRule.d.ts.map +1 -1
- package/dist/src/rules/performance/ReconnectionStrategyRule.js +47 -14
- package/dist/src/rules/performance/ReconnectionStrategyRule.js.map +1 -1
- package/dist/src/rules/security/ConnectorCredentialsSecuredRule.d.ts +36 -0
- package/dist/src/rules/security/ConnectorCredentialsSecuredRule.d.ts.map +1 -0
- package/dist/src/rules/security/ConnectorCredentialsSecuredRule.js +124 -0
- package/dist/src/rules/security/ConnectorCredentialsSecuredRule.js.map +1 -0
- package/dist/src/rules/security/HardcodedCredentialsRule.d.ts +4 -0
- package/dist/src/rules/security/HardcodedCredentialsRule.d.ts.map +1 -1
- package/dist/src/rules/security/HardcodedCredentialsRule.js +15 -0
- package/dist/src/rules/security/HardcodedCredentialsRule.js.map +1 -1
- package/dist/src/rules/security/SecurePropertiesEncryptionRule.d.ts +25 -0
- package/dist/src/rules/security/SecurePropertiesEncryptionRule.d.ts.map +1 -0
- package/dist/src/rules/security/SecurePropertiesEncryptionRule.js +59 -0
- package/dist/src/rules/security/SecurePropertiesEncryptionRule.js.map +1 -0
- package/dist/src/rules/security/SecurePropertiesKeyRule.d.ts +23 -0
- package/dist/src/rules/security/SecurePropertiesKeyRule.d.ts.map +1 -0
- package/dist/src/rules/security/SecurePropertiesKeyRule.js +45 -0
- package/dist/src/rules/security/SecurePropertiesKeyRule.js.map +1 -0
- package/dist/src/rules/security/TlsKeystorePasswordRule.d.ts +25 -0
- package/dist/src/rules/security/TlsKeystorePasswordRule.d.ts.map +1 -0
- package/dist/src/rules/security/TlsKeystorePasswordRule.js +63 -0
- package/dist/src/rules/security/TlsKeystorePasswordRule.js.map +1 -0
- package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.d.ts +26 -0
- package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.d.ts.map +1 -0
- package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.js +61 -0
- package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.js.map +1 -0
- package/dist/src/rules/standards/ConfigPropertiesOrderingRule.d.ts +34 -0
- package/dist/src/rules/standards/ConfigPropertiesOrderingRule.d.ts.map +1 -0
- package/dist/src/rules/standards/ConfigPropertiesOrderingRule.js +76 -0
- package/dist/src/rules/standards/ConfigPropertiesOrderingRule.js.map +1 -0
- package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.d.ts +25 -0
- package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.d.ts.map +1 -0
- package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.js +111 -0
- package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.js.map +1 -0
- package/dist/src/rules/structure/StructureRules.d.ts +8 -1
- package/dist/src/rules/structure/StructureRules.d.ts.map +1 -1
- package/dist/src/rules/structure/StructureRules.js +11 -7
- package/dist/src/rules/structure/StructureRules.js.map +1 -1
- package/dist/src/rules/yaml/YamlRules.d.ts +6 -2
- package/dist/src/rules/yaml/YamlRules.d.ts.map +1 -1
- package/dist/src/rules/yaml/YamlRules.js +15 -11
- package/dist/src/rules/yaml/YamlRules.js.map +1 -1
- package/dist/src/types/Rule.d.ts +35 -0
- package/dist/src/types/Rule.d.ts.map +1 -1
- package/docs/best-practices/rules-catalog.md +444 -42
- package/docs/linter/architecture.md +119 -64
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/logo.svg" alt="Mule-Lint" width="600" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://www.npmjs.com/package/@sfdxy/mule-lint"><img src="https://img.shields.io/npm/v/@sfdxy/mule-lint?style=flat-square&color=34d399" alt="npm version" /></a>
|
|
7
|
+
<a href="https://github.com/Avinava/mule-lint/actions"><img src="https://img.shields.io/github/actions/workflow/status/Avinava/mule-lint/ci.yml?style=flat-square&color=38bdf8" alt="CI" /></a>
|
|
8
|
+
<a href="https://github.com/Avinava/mule-lint/blob/master/LICENSE"><img src="https://img.shields.io/npm/l/@sfdxy/mule-lint?style=flat-square&color=818cf8" alt="License" /></a>
|
|
9
|
+
<a href="https://www.npmjs.com/package/@sfdxy/mule-lint"><img src="https://img.shields.io/npm/dm/@sfdxy/mule-lint?style=flat-square&color=fbbf24" alt="Downloads" /></a>
|
|
10
|
+
</p>
|
|
2
11
|
|
|
3
12
|
<p align="center">
|
|
4
13
|
<strong>Enterprise-grade static analysis tool for MuleSoft applications</strong>
|
|
@@ -19,12 +28,14 @@
|
|
|
19
28
|
|
|
20
29
|
**Mule-Lint** is a TypeScript-based linting tool designed to enforce best practices and standards for MuleSoft applications. It provides:
|
|
21
30
|
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
31
|
+
- **82 Built-in Rules** covering error handling, security, naming, logging, performance, API-led, connectors, and more
|
|
32
|
+
- **Multiple Output Formats** - Table, JSON, SARIF, HTML, CSV <!-- id: 4 -->
|
|
33
|
+
- **CI/CD Ready** - Exit codes and machine-readable output
|
|
34
|
+
- **442 Unit Tests** - Comprehensive test coverage for reliability
|
|
35
|
+
- **TypeScript** - Fully typed for VS Code extension integration
|
|
36
|
+
- **Extensible** - Add custom rules for your organization
|
|
37
|
+
- **Document Cache** - Parsed XML documents cached to eliminate redundant parsing
|
|
38
|
+
- **Project Layer Detection** - Automatic SAPI/PAPI/EAPI/library/batch classification
|
|
28
39
|
|
|
29
40
|
### Architecture
|
|
30
41
|
|
|
@@ -35,15 +46,18 @@ flowchart TB
|
|
|
35
46
|
end
|
|
36
47
|
|
|
37
48
|
subgraph Engine["LintEngine"]
|
|
38
|
-
B[FileScanner] --> C[XmlParser]
|
|
49
|
+
B[FileScanner] --> C[XmlParser + Document Cache]
|
|
39
50
|
C --> D[Rule Executor]
|
|
51
|
+
B --> PreScan[Pre-Scan: allFlowRefs, allFlowNames, projectLayer]
|
|
52
|
+
PreScan --> D
|
|
40
53
|
end
|
|
41
54
|
|
|
42
55
|
subgraph Rules["Rules - Strategy Pattern"]
|
|
43
|
-
D --> E[
|
|
44
|
-
D --> F[
|
|
45
|
-
|
|
46
|
-
|
|
56
|
+
D --> E[Per-File Rules]
|
|
57
|
+
D --> F[Project Rules]
|
|
58
|
+
E --> G[MULE-001..804]
|
|
59
|
+
E --> H[SEC, ERR, API, DW, ...]
|
|
60
|
+
F --> I2[YAML, HYG, CFG, ...]
|
|
47
61
|
end
|
|
48
62
|
|
|
49
63
|
subgraph Output["Formatters"]
|
|
@@ -72,11 +86,12 @@ flowchart TB
|
|
|
72
86
|
|
|
73
87
|
```mermaid
|
|
74
88
|
flowchart LR
|
|
75
|
-
A["XML Files"] --> B["
|
|
76
|
-
B --> C["
|
|
77
|
-
C --> D["
|
|
78
|
-
D --> E["
|
|
79
|
-
E --> F["
|
|
89
|
+
A["XML Files"] --> B["Pre-Scan (flow-refs, flow-names, project layer)"]
|
|
90
|
+
B --> C["Parse DOM (cached)"]
|
|
91
|
+
C --> D["Execute Rules"]
|
|
92
|
+
D --> E["Collect Issues"]
|
|
93
|
+
E --> F["Format Output"]
|
|
94
|
+
F --> G["Table / JSON / SARIF / HTML / CSV"]
|
|
80
95
|
```
|
|
81
96
|
|
|
82
97
|
---
|
|
@@ -273,55 +288,55 @@ npx @sfdxy/mule-lint src/main/mule -f sarif -o results.sarif
|
|
|
273
288
|
|
|
274
289
|
### Core Rules (MVP)
|
|
275
290
|
|
|
276
|
-
| ID | Name | Severity | Category | Description
|
|
277
|
-
| -------- | --------------------- | -------- | -------------- |
|
|
278
|
-
| MULE-001 | Global Error Handler |
|
|
279
|
-
| MULE-002 | Flow Naming | Warning | Naming | Flows end with `-flow`, sub-flows with `-subflow`
|
|
280
|
-
| MULE-003 | Missing Error Handler | Error | Error Handling | Flows should have error handlers
|
|
281
|
-
| MULE-004 | Hardcoded URLs | Error | Security | Use property placeholders for URLs
|
|
282
|
-
| MULE-005 | HTTP Status Check | Warning | Error Handling | Error handlers should set httpStatus
|
|
283
|
-
| MULE-006 | Logger Category | Warning | Logging | Loggers should have category attribute
|
|
284
|
-
| MULE-007 | Correlation ID | Warning | Error Handling | Error handlers should reference correlationId
|
|
285
|
-
| MULE-008 | Choice Anti-Pattern | Warning | Standards | Avoid raise-error in otherwise
|
|
286
|
-
| MULE-009 | Generic Error Type | Warning | Error Handling | Avoid catching type="ANY"
|
|
287
|
-
| MULE-010 | DWL Standards | Info | Standards | Standard DataWeave files should exist
|
|
291
|
+
| ID | Name | Severity | Category | Description |
|
|
292
|
+
| -------- | --------------------- | -------- | -------------- | -------------------------------------------------------------------- |
|
|
293
|
+
| MULE-001 | Global Error Handler | Warning | Error Handling | Any flow file should have a global error handler |
|
|
294
|
+
| MULE-002 | Flow Naming | Warning | Naming | Flows end with `-flow`, sub-flows with `-subflow` |
|
|
295
|
+
| MULE-003 | Missing Error Handler | Error | Error Handling | Flows should have error handlers |
|
|
296
|
+
| MULE-004 | Hardcoded URLs | Error | Security | Use property placeholders for URLs |
|
|
297
|
+
| MULE-005 | HTTP Status Check | Warning | Error Handling | Error handlers should set httpStatus (skipped for non-HTTP projects) |
|
|
298
|
+
| MULE-006 | Logger Category | Warning | Logging | Loggers should have category attribute |
|
|
299
|
+
| MULE-007 | Correlation ID | Warning | Error Handling | Error handlers should reference correlationId (checks DWL files too) |
|
|
300
|
+
| MULE-008 | Choice Anti-Pattern | Warning | Standards | Avoid raise-error in otherwise |
|
|
301
|
+
| MULE-009 | Generic Error Type | Warning | Error Handling | Avoid catching type="ANY" |
|
|
302
|
+
| MULE-010 | DWL Standards | Info | Standards | Standard DataWeave files should exist |
|
|
288
303
|
|
|
289
304
|
### Extended Rules
|
|
290
305
|
|
|
291
|
-
| ID | Name | Severity | Category | Description
|
|
292
|
-
| -------- | --------------------- | -------- | ------------- |
|
|
293
|
-
| MULE-101 | Flow Casing | Warning | Naming | kebab-case for flows
|
|
294
|
-
| MULE-102 | Variable Naming | Warning | Naming | camelCase for variables
|
|
295
|
-
| MULE-201 | Hardcoded Credentials | Error | Security | Use `${secure::}`
|
|
296
|
-
| MULE-202 | Insecure TLS | Error | Security | No insecure="true"
|
|
297
|
-
| MULE-301 | Logger Payload | Warning | Logging | Don't log entire payload
|
|
298
|
-
| MULE-303 | Logger in Retry | Warning | Logging | Avoid loggers in until-successful
|
|
299
|
-
| MULE-401 | HTTP User-Agent | Warning | HTTP | Include User-Agent
|
|
300
|
-
| MULE-402 | HTTP Content-Type | Warning | HTTP | POST/PUT needs Content-Type
|
|
301
|
-
| MULE-403 | HTTP Timeout | Warning | HTTP | Set responseTimeout
|
|
302
|
-
| MULE-501 | Scatter-Gather | Info | Performance | Limit parallel routes
|
|
303
|
-
| MULE-502 | Async Error | Warning | Performance | Async needs error handling
|
|
304
|
-
| MULE-503 | Large Choice | Warning | Performance | Max 7 when clauses
|
|
305
|
-
| MULE-601 | Flow Description | Info | Documentation | Add doc:description
|
|
306
|
-
| MULE-604 | Missing doc:name | Warning | Documentation | Key components need doc:name
|
|
307
|
-
| MULE-701 | Deprecated | Warning | Standards | Detect deprecated elements
|
|
308
|
-
| MULE-801 | Flow Complexity | Warning | Complexity | Cyclomatic complexity threshold
|
|
309
|
-
| MULE-802 | Project Structure | Warning | Structure | Validate folder structure
|
|
310
|
-
| MULE-803 | Global Config | Warning | Structure | global.xml should exist
|
|
311
|
-
| MULE-804 | Monolithic XML | Warning | Structure | Split large XML files
|
|
306
|
+
| ID | Name | Severity | Category | Description |
|
|
307
|
+
| -------- | --------------------- | -------- | ------------- | --------------------------------------------------------- |
|
|
308
|
+
| MULE-101 | Flow Casing | Warning | Naming | kebab-case for flows |
|
|
309
|
+
| MULE-102 | Variable Naming | Warning | Naming | camelCase for variables |
|
|
310
|
+
| MULE-201 | Hardcoded Credentials | Error | Security | Use `${secure::}` |
|
|
311
|
+
| MULE-202 | Insecure TLS | Error | Security | No insecure="true" |
|
|
312
|
+
| MULE-301 | Logger Payload | Warning | Logging | Don't log entire payload |
|
|
313
|
+
| MULE-303 | Logger in Retry | Warning | Logging | Avoid loggers in until-successful |
|
|
314
|
+
| MULE-401 | HTTP User-Agent | Warning | HTTP | Include User-Agent |
|
|
315
|
+
| MULE-402 | HTTP Content-Type | Warning | HTTP | POST/PUT needs Content-Type (static, CDATA, or inline DW) |
|
|
316
|
+
| MULE-403 | HTTP Timeout | Warning | HTTP | Set responseTimeout |
|
|
317
|
+
| MULE-501 | Scatter-Gather | Info | Performance | Limit parallel routes |
|
|
318
|
+
| MULE-502 | Async Error | Warning | Performance | Async needs error handling |
|
|
319
|
+
| MULE-503 | Large Choice | Warning | Performance | Max 7 when clauses |
|
|
320
|
+
| MULE-601 | Flow Description | Info | Documentation | Add doc:description |
|
|
321
|
+
| MULE-604 | Missing doc:name | Warning | Documentation | Key components need doc:name |
|
|
322
|
+
| MULE-701 | Deprecated | Warning | Standards | Detect deprecated elements |
|
|
323
|
+
| MULE-801 | Flow Complexity | Warning | Complexity | Cyclomatic complexity threshold |
|
|
324
|
+
| MULE-802 | Project Structure | Warning | Structure | Validate folder structure |
|
|
325
|
+
| MULE-803 | Global Config | Warning | Structure | global.xml should exist |
|
|
326
|
+
| MULE-804 | Monolithic XML | Warning | Structure | Split large XML files |
|
|
312
327
|
|
|
313
328
|
### DataWeave & API-Led Rules
|
|
314
329
|
|
|
315
|
-
| ID | Name | Severity | Category | Description
|
|
316
|
-
| ------- | ----------------- | -------- | --------- |
|
|
317
|
-
| DW-001 | External DWL | Warning | DataWeave | Externalize complex transforms
|
|
318
|
-
| DW-002 | DWL Naming | Info | DataWeave | kebab-case for .dwl files
|
|
319
|
-
| DW-003 | DWL Modules | Info | DataWeave | Use common modules
|
|
320
|
-
| DW-004 | Java 17 DW Errors | Error | DataWeave | Java 17 compatible error handling
|
|
321
|
-
| API-001 | Experience Layer | Info | API-Led | Experience API patterns
|
|
322
|
-
| API-002 | Process Layer | Info | API-Led | Process layer orchestration
|
|
323
|
-
| API-003 | System Layer | Info | API-Led | System layer connections
|
|
324
|
-
| API-004 | Single SAPI | Warning | API-Led | Single system per SAPI
|
|
330
|
+
| ID | Name | Severity | Category | Description |
|
|
331
|
+
| ------- | ----------------- | -------- | --------- | ---------------------------------------------------- |
|
|
332
|
+
| DW-001 | External DWL | Warning | DataWeave | Externalize complex transforms |
|
|
333
|
+
| DW-002 | DWL Naming | Info | DataWeave | kebab-case for .dwl files (configurable exemptPaths) |
|
|
334
|
+
| DW-003 | DWL Modules | Info | DataWeave | Use common modules |
|
|
335
|
+
| DW-004 | Java 17 DW Errors | Error | DataWeave | Java 17 compatible error handling |
|
|
336
|
+
| API-001 | Experience Layer | Info | API-Led | Experience API patterns |
|
|
337
|
+
| API-002 | Process Layer | Info | API-Led | Process layer orchestration |
|
|
338
|
+
| API-003 | System Layer | Info | API-Led | System layer connections |
|
|
339
|
+
| API-004 | Single SAPI | Warning | API-Led | Single system per SAPI |
|
|
325
340
|
|
|
326
341
|
### Experimental Rules
|
|
327
342
|
|
|
@@ -346,20 +361,60 @@ npx @sfdxy/mule-lint src/main/mule -f sarif -o results.sarif
|
|
|
346
361
|
| ERR-001 | Try Scope | Info | Error Handling | Complex operations should use Try scope |
|
|
347
362
|
| PERF-002 | Connection Pooling | Warning | Performance | DB/HTTP should configure connection pools |
|
|
348
363
|
|
|
364
|
+
### Security & Integrity Rules (v1.21)
|
|
365
|
+
|
|
366
|
+
| ID | Name | Severity | Category | Description |
|
|
367
|
+
| ------- | ---------------------------- | -------- | --------- | ------------------------------------------------------- |
|
|
368
|
+
| SEC-007 | Connector Credentials | Error | Security | Connector configs must use secure property placeholders |
|
|
369
|
+
| SEC-008 | Secure Properties Key | Error | Security | Secure properties file must use externalized key |
|
|
370
|
+
| SEC-009 | TLS Keystore Password | Error | Security | TLS keystore passwords must use secure properties |
|
|
371
|
+
| SEC-010 | Secure Properties Encryption | Warning | Security | Secure properties must use strong encryption algorithm |
|
|
372
|
+
| HYG-004 | Flow-Ref Target Exists | Error | Standards | Flow-ref must point to an existing flow/sub-flow |
|
|
373
|
+
|
|
374
|
+
### Error Handling & Resilience Rules (v1.21)
|
|
375
|
+
|
|
376
|
+
| ID | Name | Severity | Category | Description |
|
|
377
|
+
| ------- | -------------------------- | -------- | -------------- | ----------------------------------------------------------- |
|
|
378
|
+
| ERR-002 | Error Type Coverage | Warning | Error Handling | APIKit flows should handle common HTTP error types |
|
|
379
|
+
| ERR-003 | Error Response Structure | Warning | Error Handling | Error handlers should set both httpStatus and response body |
|
|
380
|
+
| ERR-004 | Catch-All Must Be Last | Error | Error Handling | type="ANY" on-error must be the last handler block |
|
|
381
|
+
| RES-002 | Listener Reconnect Forever | Warning | Performance | Listener connectors should use reconnect-forever strategy |
|
|
382
|
+
| CFG-001 | Config Properties Ordering | Info | Standards | Config properties should follow a consistent ordering |
|
|
383
|
+
|
|
384
|
+
### API-Led & Connector Rules (v1.21)
|
|
385
|
+
|
|
386
|
+
| ID | Name | Severity | Category | Description |
|
|
387
|
+
| -------- | ----------------------- | -------- | --------- | ------------------------------------------------------- |
|
|
388
|
+
| API-006 | APIKit Main Flow | Warning | API-Led | APIKit main flow should follow standard structure |
|
|
389
|
+
| API-007 | APIKit Status Code Var | Warning | API-Led | APIKit routes should set httpStatus variable |
|
|
390
|
+
| API-008 | APIKit Console Prod | Warning | API-Led | APIKit console should be disabled in production |
|
|
391
|
+
| SF-001 | Replay Channel Config | Warning | Connector | Salesforce replay channel should have proper config |
|
|
392
|
+
| HTTP-004 | Connection Idle Timeout | Warning | HTTP | HTTP request configs should set connection idle timeout |
|
|
393
|
+
|
|
394
|
+
### Code Hygiene Rules (v1.21)
|
|
395
|
+
|
|
396
|
+
| ID | Name | Severity | Category | Description |
|
|
397
|
+
| ------- | ---------------------------- | -------- | --------- | ---------------------------------------------------------- |
|
|
398
|
+
| DW-005 | Duplicate Transform Logic | Warning | DataWeave | Detect duplicated DataWeave transform expressions |
|
|
399
|
+
| HYG-005 | Unused Variable | Warning | Standards | Detect set-variable values never referenced in the project |
|
|
400
|
+
| CFG-002 | Missing Env Properties | Warning | Standards | Properties referenced in XML should exist in YAML configs |
|
|
401
|
+
| STD-001 | APIKit Route Var Consistency | Info | Standards | APIKit route variable names should be consistent |
|
|
402
|
+
| SF-002 | Event Listener Null Guard | Warning | Connector | Event listeners should guard against null payloads |
|
|
403
|
+
|
|
349
404
|
### Operations & Resilience Rules
|
|
350
405
|
|
|
351
|
-
| ID | Name | Severity | Category | Description
|
|
352
|
-
| ------- | ---------------------- | -------- | ------------- |
|
|
353
|
-
| RES-001 | Reconnection Strategy | Warning | Performance | Connectors should have reconnection strategies
|
|
354
|
-
| OPS-001 | Auto-Discovery | Info | Standards | APIs should have auto-discovery for API Manager
|
|
355
|
-
| OPS-002 | HTTP Port Placeholder | Warning | Standards | HTTP ports should use property placeholders
|
|
356
|
-
| OPS-003 | Externalized Cron | Warning | Standards | Cron expressions should use placeholders
|
|
357
|
-
| SEC-006 | Encryption Key in Logs | Error | Security | Detect sensitive data in log messages
|
|
358
|
-
| HYG-001 | Excessive Loggers | Warning | Logging | Flows should not have too many loggers
|
|
359
|
-
| HYG-002 | Commented Code | Info | Standards | Detect commented-out code blocks
|
|
360
|
-
| HYG-003 | Unused Flow | Warning | Standards | Detect flows/sub-flows never referenced
|
|
361
|
-
| API-005 | APIKit Validation | Info | Standards | APIs should use APIKit for interfaces
|
|
362
|
-
| DOC-001 | Display Name | Info | Documentation | Key components should have meaningful names
|
|
406
|
+
| ID | Name | Severity | Category | Description |
|
|
407
|
+
| ------- | ---------------------- | -------- | ------------- | ---------------------------------------------------- |
|
|
408
|
+
| RES-001 | Reconnection Strategy | Warning | Performance | Connectors should have reconnection strategies |
|
|
409
|
+
| OPS-001 | Auto-Discovery | Info | Standards | APIs should have auto-discovery for API Manager |
|
|
410
|
+
| OPS-002 | HTTP Port Placeholder | Warning | Standards | HTTP ports should use property placeholders |
|
|
411
|
+
| OPS-003 | Externalized Cron | Warning | Standards | Cron expressions should use placeholders |
|
|
412
|
+
| SEC-006 | Encryption Key in Logs | Error | Security | Detect sensitive data in log messages |
|
|
413
|
+
| HYG-001 | Excessive Loggers | Warning | Logging | Flows should not have too many loggers |
|
|
414
|
+
| HYG-002 | Commented Code | Info | Standards | Detect commented-out code blocks |
|
|
415
|
+
| HYG-003 | Unused Flow | Warning | Standards | Detect flows/sub-flows never referenced (cross-file) |
|
|
416
|
+
| API-005 | APIKit Validation | Info | Standards | APIs should use APIKit for interfaces |
|
|
417
|
+
| DOC-001 | Display Name | Info | Documentation | Key components should have meaningful names |
|
|
363
418
|
|
|
364
419
|
### Project Governance Rules
|
|
365
420
|
|
|
@@ -368,7 +423,7 @@ npx @sfdxy/mule-lint src/main/mule -f sarif -o results.sarif
|
|
|
368
423
|
| PROJ-001 | POM Validation | Error | Structure | Validates pom.xml existence and plugins |
|
|
369
424
|
| PROJ-002 | Git Hygiene | Warning | Structure | Validates .gitignore existence and entries |
|
|
370
425
|
|
|
371
|
-
**Total:
|
|
426
|
+
**Total: 82 rules** across 16 categories.
|
|
372
427
|
|
|
373
428
|
See [Rules Catalog](docs/best-practices/rules-catalog.md) for detailed documentation.
|
|
374
429
|
|
package/dist/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"XPathHelper.d.ts","sourceRoot":"","sources":["../../../src/core/XPathHelper.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"XPathHelper.d.ts","sourceRoot":"","sources":["../../../src/core/XPathHelper.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAyElD,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,UAAW,SAAQ,IAAI;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA0B;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAE3C,OAAO;IAIP;;OAEG;WACW,WAAW,IAAI,WAAW;IAOxC;;OAEG;WACW,KAAK,IAAI,IAAI;IAI3B;;;;;OAKG;IACI,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,EAAE;IAaxE;;;;;OAKG;IACI,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI;IAK5E;;;;;OAKG;IACI,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI;IAShF;;;;;OAKG;IACI,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,GAAG,OAAO;IAIpE;;;;;OAKG;IACI,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,GAAG,MAAM;CAGnE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQxE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAEhD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAE9D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGlE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE/C;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAEjD"}
|
|
@@ -91,6 +91,14 @@ exports.MULE_NAMESPACES = {
|
|
|
91
91
|
sockets: 'http://www.mulesoft.org/schema/mule/sockets',
|
|
92
92
|
// Web Service Consumer
|
|
93
93
|
wsc: 'http://www.mulesoft.org/schema/mule/wsc',
|
|
94
|
+
// NetSuite
|
|
95
|
+
netsuite: 'http://www.mulesoft.org/schema/mule/netsuite',
|
|
96
|
+
// SAP
|
|
97
|
+
sap: 'http://www.mulesoft.org/schema/mule/sap',
|
|
98
|
+
// Anypoint MQ
|
|
99
|
+
'anypoint-mq': 'http://www.mulesoft.org/schema/mule/anypoint-mq',
|
|
100
|
+
// OAuth
|
|
101
|
+
oauth: 'http://www.mulesoft.org/schema/mule/oauth',
|
|
94
102
|
};
|
|
95
103
|
/**
|
|
96
104
|
* Helper class for namespace-aware XPath queries on Mule XML documents
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"XPathHelper.js","sourceRoot":"","sources":["../../../src/core/XPathHelper.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"XPathHelper.js","sourceRoot":"","sources":["../../../src/core/XPathHelper.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,6 +19,12 @@ export declare class LintEngine {
|
|
|
19
19
|
private rules;
|
|
20
20
|
private config;
|
|
21
21
|
private verbose;
|
|
22
|
+
/**
|
|
23
|
+
* Cache of parsed XML documents keyed by absolute file path.
|
|
24
|
+
* Populated during preScanFiles() and reused in processFile()
|
|
25
|
+
* to avoid parsing every XML file twice.
|
|
26
|
+
*/
|
|
27
|
+
private documentCache;
|
|
22
28
|
constructor(options: EngineOptions);
|
|
23
29
|
/**
|
|
24
30
|
* Scan a directory or file and return lint report
|
|
@@ -64,5 +70,31 @@ export declare class LintEngine {
|
|
|
64
70
|
* Collect metrics from a parsed XML document
|
|
65
71
|
*/
|
|
66
72
|
private collectFileMetrics;
|
|
73
|
+
/**
|
|
74
|
+
* Pre-scan all XML files to build cross-file context:
|
|
75
|
+
* - allFlowRefs: union of all <flow-ref name="..."> targets across files
|
|
76
|
+
* - allFlowNames: union of all <flow>/<sub-flow> name attributes across files
|
|
77
|
+
* - projectContext: whether the project has HTTP listeners / APIkit routers
|
|
78
|
+
*
|
|
79
|
+
* Parsed documents are cached in this.documentCache so that processFile()
|
|
80
|
+
* can reuse them instead of re-parsing.
|
|
81
|
+
*
|
|
82
|
+
* This runs before the main per-file rule execution so that rules can use
|
|
83
|
+
* the aggregated information (e.g. HYG-003 cross-file unused flow detection,
|
|
84
|
+
* HYG-004 cross-file flow-ref target validation,
|
|
85
|
+
* MULE-005 HTTP-only project detection).
|
|
86
|
+
*/
|
|
87
|
+
private preScanFiles;
|
|
88
|
+
/**
|
|
89
|
+
* Detect the API-led connectivity layer of the project.
|
|
90
|
+
*
|
|
91
|
+
* Heuristics (in priority order):
|
|
92
|
+
* 1. Directory/project name contains `-sapi`, `-papi`, `-eapi`
|
|
93
|
+
* 2. Flow names contain `sapi`, `papi`, `eapi` patterns
|
|
94
|
+
* 3. No HTTP listener + batch jobs → batch
|
|
95
|
+
* 4. No flows at all → library
|
|
96
|
+
* 5. Otherwise → unknown
|
|
97
|
+
*/
|
|
98
|
+
private detectProjectLayer;
|
|
67
99
|
}
|
|
68
100
|
//# sourceMappingURL=LintEngine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LintEngine.d.ts","sourceRoot":"","sources":["../../../src/engine/LintEngine.ts"],"names":[],"mappings":"AAGA,OAAO,
|
|
1
|
+
{"version":3,"file":"LintEngine.d.ts","sourceRoot":"","sources":["../../../src/engine/LintEngine.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,IAAI,EACJ,KAAK,EAMN,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,UAAU,EAAkB,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAA2C,MAAM,iBAAiB,CAAC;AAQtF;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,+BAA+B;IAC/B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,8CAA8C;IAC9C,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC7B,sBAAsB;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,OAAO,CAAU;IAEzB;;;;OAIG;IACH,OAAO,CAAC,aAAa,CAAoC;gBAE7C,OAAO,EAAE,aAAa;IAMlC;;OAEG;IACU,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAoI1D;;OAEG;IACH,OAAO,CAAC,eAAe;IAgBvB;;OAEG;IACI,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,EAAE;IAmB9D;;OAEG;IACI,eAAe,IAAI,IAAI,EAAE;IAOhC;;OAEG;IACH,OAAO,CAAC,WAAW;IAqEnB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAuDhB;;OAEG;IACH,OAAO,CAAC,aAAa;IAerB;;OAEG;IACH,OAAO,CAAC,YAAY;IAgCpB;;OAEG;IACH,OAAO,CAAC,eAAe;IA+BvB;;OAEG;IACH,OAAO,CAAC,GAAG;IAOX;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAI1B;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,YAAY;IAgFpB;;;;;;;;;OASG;IACH,OAAO,CAAC,kBAAkB;CA2C3B"}
|
|
@@ -54,6 +54,12 @@ class LintEngine {
|
|
|
54
54
|
rules;
|
|
55
55
|
config;
|
|
56
56
|
verbose;
|
|
57
|
+
/**
|
|
58
|
+
* Cache of parsed XML documents keyed by absolute file path.
|
|
59
|
+
* Populated during preScanFiles() and reused in processFile()
|
|
60
|
+
* to avoid parsing every XML file twice.
|
|
61
|
+
*/
|
|
62
|
+
documentCache = new Map();
|
|
57
63
|
constructor(options) {
|
|
58
64
|
this.rules = options.rules;
|
|
59
65
|
this.config = { ...Config_1.DEFAULT_CONFIG, ...options.config };
|
|
@@ -88,6 +94,10 @@ class LintEngine {
|
|
|
88
94
|
exclude: this.config.exclude,
|
|
89
95
|
});
|
|
90
96
|
this.log(`Found ${files.length} files to scan`);
|
|
97
|
+
// Pre-scan: collect cross-file context before rule execution
|
|
98
|
+
const { allFlowRefs, allFlowNames, projectContext } = isStandalone
|
|
99
|
+
? { allFlowRefs: undefined, allFlowNames: undefined, projectContext: undefined }
|
|
100
|
+
: this.preScanFiles(files);
|
|
91
101
|
// Process each file and collect metrics
|
|
92
102
|
const fileResults = [];
|
|
93
103
|
const metricsAggregator = {
|
|
@@ -108,7 +118,7 @@ class LintEngine {
|
|
|
108
118
|
flowComplexityData: [],
|
|
109
119
|
};
|
|
110
120
|
for (const file of files) {
|
|
111
|
-
const result = this.processFile(file, projectRoot, isStandalone, metricsAggregator);
|
|
121
|
+
const result = this.processFile(file, projectRoot, isStandalone, metricsAggregator, allFlowRefs, allFlowNames, projectContext);
|
|
112
122
|
fileResults.push(result);
|
|
113
123
|
}
|
|
114
124
|
// Run Project Rules (only once per scan, if not standalone)
|
|
@@ -148,6 +158,8 @@ class LintEngine {
|
|
|
148
158
|
const summary = this.buildSummary(fileResults);
|
|
149
159
|
this.log(`Scan complete in ${durationMs}ms`);
|
|
150
160
|
this.log(`Found ${summary.bySeverity.error} errors, ${summary.bySeverity.warning} warnings`);
|
|
161
|
+
// Release cached documents to free memory
|
|
162
|
+
this.documentCache.clear();
|
|
151
163
|
// Build initial report with base metrics
|
|
152
164
|
const baseReport = {
|
|
153
165
|
projectRoot,
|
|
@@ -210,24 +222,34 @@ class LintEngine {
|
|
|
210
222
|
/**
|
|
211
223
|
* Process a single file
|
|
212
224
|
*/
|
|
213
|
-
processFile(file, projectRoot, isStandalone = false, metricsAggregator) {
|
|
225
|
+
processFile(file, projectRoot, isStandalone = false, metricsAggregator, allFlowRefs, allFlowNames, projectContext) {
|
|
214
226
|
this.log(` Processing: ${file.relativePath}`);
|
|
215
227
|
try {
|
|
216
|
-
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
228
|
+
// Try to use the cached document from preScanFiles() first
|
|
229
|
+
const cachedDoc = this.documentCache.get(file.absolutePath);
|
|
230
|
+
let doc;
|
|
231
|
+
if (cachedDoc) {
|
|
232
|
+
doc = cachedDoc;
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
// Cache miss (standalone mode or non-XML processed first time)
|
|
236
|
+
const content = (0, FileScanner_1.readFileContent)(file.absolutePath);
|
|
237
|
+
const parseResult = (0, XmlParser_1.parseXml)(content, file.relativePath);
|
|
238
|
+
if (!parseResult.success || !parseResult.document) {
|
|
239
|
+
return {
|
|
240
|
+
filePath: file.absolutePath,
|
|
241
|
+
relativePath: file.relativePath,
|
|
242
|
+
issues: [],
|
|
243
|
+
parsed: false,
|
|
244
|
+
parseError: parseResult.error,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
doc = parseResult.document;
|
|
226
248
|
}
|
|
227
|
-
const issues = this.runRules(
|
|
249
|
+
const issues = this.runRules(doc, file.absolutePath, projectRoot, isStandalone, allFlowRefs, allFlowNames, projectContext);
|
|
228
250
|
// Collect metrics from parsed document
|
|
229
251
|
if (metricsAggregator) {
|
|
230
|
-
this.collectFileMetrics(
|
|
252
|
+
this.collectFileMetrics(doc, file.relativePath, metricsAggregator);
|
|
231
253
|
}
|
|
232
254
|
return {
|
|
233
255
|
filePath: file.absolutePath,
|
|
@@ -250,7 +272,7 @@ class LintEngine {
|
|
|
250
272
|
/**
|
|
251
273
|
* Run all enabled rules against a document
|
|
252
274
|
*/
|
|
253
|
-
runRules(doc, filePath, projectRoot, isStandalone = false) {
|
|
275
|
+
runRules(doc, filePath, projectRoot, isStandalone = false, allFlowRefs, allFlowNames, projectContext) {
|
|
254
276
|
const issues = [];
|
|
255
277
|
const enabledRules = this.getEnabledRules();
|
|
256
278
|
for (const rule of enabledRules) {
|
|
@@ -258,12 +280,19 @@ class LintEngine {
|
|
|
258
280
|
if (isStandalone && rule.category === 'structure') {
|
|
259
281
|
continue;
|
|
260
282
|
}
|
|
283
|
+
// Skip ProjectRule instances — they are handled separately in runProjectRules()
|
|
284
|
+
if (rule instanceof ProjectRule_1.ProjectRule) {
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
261
287
|
try {
|
|
262
288
|
const context = {
|
|
263
289
|
filePath,
|
|
264
290
|
relativePath: path.relative(projectRoot, filePath),
|
|
265
291
|
projectRoot,
|
|
266
292
|
config: this.getRuleConfig(rule.id),
|
|
293
|
+
allFlowRefs,
|
|
294
|
+
allFlowNames,
|
|
295
|
+
projectContext,
|
|
267
296
|
};
|
|
268
297
|
const ruleIssues = rule.validate(doc, context);
|
|
269
298
|
// Apply severity override from config
|
|
@@ -371,6 +400,128 @@ class LintEngine {
|
|
|
371
400
|
collectFileMetrics(doc, relativePath, metrics) {
|
|
372
401
|
(0, MetricsCollector_1.collectFileMetrics)(doc, relativePath, metrics);
|
|
373
402
|
}
|
|
403
|
+
/**
|
|
404
|
+
* Pre-scan all XML files to build cross-file context:
|
|
405
|
+
* - allFlowRefs: union of all <flow-ref name="..."> targets across files
|
|
406
|
+
* - allFlowNames: union of all <flow>/<sub-flow> name attributes across files
|
|
407
|
+
* - projectContext: whether the project has HTTP listeners / APIkit routers
|
|
408
|
+
*
|
|
409
|
+
* Parsed documents are cached in this.documentCache so that processFile()
|
|
410
|
+
* can reuse them instead of re-parsing.
|
|
411
|
+
*
|
|
412
|
+
* This runs before the main per-file rule execution so that rules can use
|
|
413
|
+
* the aggregated information (e.g. HYG-003 cross-file unused flow detection,
|
|
414
|
+
* HYG-004 cross-file flow-ref target validation,
|
|
415
|
+
* MULE-005 HTTP-only project detection).
|
|
416
|
+
*/
|
|
417
|
+
preScanFiles(files) {
|
|
418
|
+
const allFlowRefs = new Set();
|
|
419
|
+
const allFlowNames = new Set();
|
|
420
|
+
const projectContext = {
|
|
421
|
+
hasHttpListener: false,
|
|
422
|
+
hasApikitRouter: false,
|
|
423
|
+
};
|
|
424
|
+
// Clear the cache at the start of each scan
|
|
425
|
+
this.documentCache.clear();
|
|
426
|
+
for (const file of files) {
|
|
427
|
+
// Only process XML files
|
|
428
|
+
if (!file.absolutePath.endsWith('.xml')) {
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
try {
|
|
432
|
+
const content = (0, FileScanner_1.readFileContent)(file.absolutePath);
|
|
433
|
+
const parseResult = (0, XmlParser_1.parseXml)(content, file.relativePath);
|
|
434
|
+
if (!parseResult.success || !parseResult.document) {
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
const doc = parseResult.document;
|
|
438
|
+
// Cache the parsed document for reuse in processFile()
|
|
439
|
+
this.documentCache.set(file.absolutePath, doc);
|
|
440
|
+
// Collect flow-ref targets
|
|
441
|
+
const allElements = doc.getElementsByTagName('*');
|
|
442
|
+
for (let i = 0; i < allElements.length; i++) {
|
|
443
|
+
const el = allElements[i];
|
|
444
|
+
const localName = el.localName ?? el.nodeName.split(':').pop() ?? '';
|
|
445
|
+
if (localName === 'flow-ref') {
|
|
446
|
+
const name = el.getAttribute('name');
|
|
447
|
+
if (name) {
|
|
448
|
+
allFlowRefs.add(name);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
// Collect flow/sub-flow definitions
|
|
452
|
+
if (localName === 'flow' || localName === 'sub-flow') {
|
|
453
|
+
const name = el.getAttribute('name');
|
|
454
|
+
if (name) {
|
|
455
|
+
allFlowNames.add(name);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
// Detect HTTP listener
|
|
459
|
+
if (localName === 'listener') {
|
|
460
|
+
projectContext.hasHttpListener = true;
|
|
461
|
+
}
|
|
462
|
+
// Detect APIkit router or console
|
|
463
|
+
if (localName === 'router' || localName === 'console') {
|
|
464
|
+
// Check namespace to be sure it's apikit
|
|
465
|
+
const nodeName = el.nodeName;
|
|
466
|
+
if (nodeName.includes('apikit:')) {
|
|
467
|
+
projectContext.hasApikitRouter = true;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
catch {
|
|
473
|
+
// Ignore unreadable files during pre-scan
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
// Detect project layer from directory name, flow names, and content
|
|
477
|
+
projectContext.projectLayer = this.detectProjectLayer(files, allFlowNames, projectContext);
|
|
478
|
+
return { allFlowRefs, allFlowNames, projectContext };
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Detect the API-led connectivity layer of the project.
|
|
482
|
+
*
|
|
483
|
+
* Heuristics (in priority order):
|
|
484
|
+
* 1. Directory/project name contains `-sapi`, `-papi`, `-eapi`
|
|
485
|
+
* 2. Flow names contain `sapi`, `papi`, `eapi` patterns
|
|
486
|
+
* 3. No HTTP listener + batch jobs → batch
|
|
487
|
+
* 4. No flows at all → library
|
|
488
|
+
* 5. Otherwise → unknown
|
|
489
|
+
*/
|
|
490
|
+
detectProjectLayer(files, allFlowNames, projectContext) {
|
|
491
|
+
// Check project directory name
|
|
492
|
+
const projectDir = files.length > 0
|
|
493
|
+
? path.basename(path.resolve(files[0].absolutePath, '..', '..', '..', '..'))
|
|
494
|
+
: '';
|
|
495
|
+
const dirLower = projectDir.toLowerCase();
|
|
496
|
+
if (dirLower.includes('-sapi') || dirLower.includes('_sapi') || dirLower.endsWith('sapi')) {
|
|
497
|
+
return 'sapi';
|
|
498
|
+
}
|
|
499
|
+
if (dirLower.includes('-papi') || dirLower.includes('_papi') || dirLower.endsWith('papi')) {
|
|
500
|
+
return 'papi';
|
|
501
|
+
}
|
|
502
|
+
if (dirLower.includes('-eapi') || dirLower.includes('_eapi') || dirLower.endsWith('eapi')) {
|
|
503
|
+
return 'eapi';
|
|
504
|
+
}
|
|
505
|
+
// Check flow names for layer hints
|
|
506
|
+
const flowNamesArray = [...allFlowNames].map((n) => n.toLowerCase());
|
|
507
|
+
const hasSapiFlow = flowNamesArray.some((n) => n.includes('sapi') || n.includes('system-api'));
|
|
508
|
+
const hasPapiFlow = flowNamesArray.some((n) => n.includes('papi') || n.includes('process-api'));
|
|
509
|
+
const hasEapiFlow = flowNamesArray.some((n) => n.includes('eapi') || n.includes('experience-api'));
|
|
510
|
+
if (hasSapiFlow && !hasPapiFlow && !hasEapiFlow)
|
|
511
|
+
return 'sapi';
|
|
512
|
+
if (hasPapiFlow && !hasSapiFlow && !hasEapiFlow)
|
|
513
|
+
return 'papi';
|
|
514
|
+
if (hasEapiFlow && !hasSapiFlow && !hasPapiFlow)
|
|
515
|
+
return 'eapi';
|
|
516
|
+
// No flows → library
|
|
517
|
+
if (allFlowNames.size === 0)
|
|
518
|
+
return 'library';
|
|
519
|
+
// Has batch jobs but no HTTP listener → batch
|
|
520
|
+
const hasBatch = flowNamesArray.some((n) => n.includes('batch'));
|
|
521
|
+
if (hasBatch && !projectContext.hasHttpListener)
|
|
522
|
+
return 'batch';
|
|
523
|
+
return 'unknown';
|
|
524
|
+
}
|
|
374
525
|
}
|
|
375
526
|
exports.LintEngine = LintEngine;
|
|
376
527
|
//# sourceMappingURL=LintEngine.js.map
|