@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
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ErrorHandlerTypeCoverageRule = void 0;
|
|
4
|
+
const BaseRule_1 = require("../base/BaseRule");
|
|
5
|
+
/**
|
|
6
|
+
* ERR-002: Error Handler Type Coverage
|
|
7
|
+
*
|
|
8
|
+
* SAPI error handlers should cover the standard APIKit error types
|
|
9
|
+
* (BAD_REQUEST, NOT_FOUND, METHOD_NOT_ALLOWED, NOT_ACCEPTABLE,
|
|
10
|
+
* UNSUPPORTED_MEDIA_TYPE) when an APIKit router is present.
|
|
11
|
+
*
|
|
12
|
+
* Inspired by real-world accelerator patterns where both Salesforce and
|
|
13
|
+
* NetSuite SAPIs consistently cover these types for proper HTTP status
|
|
14
|
+
* code mapping.
|
|
15
|
+
*/
|
|
16
|
+
class ErrorHandlerTypeCoverageRule extends BaseRule_1.BaseRule {
|
|
17
|
+
id = 'ERR-002';
|
|
18
|
+
name = 'Error Handler Type Coverage';
|
|
19
|
+
description = 'Error handlers in APIKit projects should cover standard APIKit error types';
|
|
20
|
+
severity = 'warning';
|
|
21
|
+
category = 'error-handling';
|
|
22
|
+
issueType = 'bug';
|
|
23
|
+
/**
|
|
24
|
+
* Minimum set of APIKit error types that a well-structured SAPI should handle.
|
|
25
|
+
* These correspond to standard HTTP status codes that APIKit can generate.
|
|
26
|
+
*/
|
|
27
|
+
REQUIRED_APIKIT_TYPES = [
|
|
28
|
+
'APIKIT:BAD_REQUEST',
|
|
29
|
+
'APIKIT:NOT_FOUND',
|
|
30
|
+
'APIKIT:METHOD_NOT_ALLOWED',
|
|
31
|
+
'APIKIT:NOT_ACCEPTABLE',
|
|
32
|
+
'APIKIT:UNSUPPORTED_MEDIA_TYPE',
|
|
33
|
+
];
|
|
34
|
+
validate(doc, context) {
|
|
35
|
+
const issues = [];
|
|
36
|
+
// Only apply when project has an APIKit router
|
|
37
|
+
if (context.projectContext && !context.projectContext.hasApikitRouter) {
|
|
38
|
+
return issues;
|
|
39
|
+
}
|
|
40
|
+
// Find named (global) error handlers — these are the ones that should
|
|
41
|
+
// have comprehensive coverage
|
|
42
|
+
const errorHandlers = this.select('//mule:error-handler[@name]', doc);
|
|
43
|
+
for (const handler of errorHandlers) {
|
|
44
|
+
const handlerName = this.getAttribute(handler, 'name') ?? 'unnamed';
|
|
45
|
+
// Collect all error types handled in this error-handler
|
|
46
|
+
const handledTypes = new Set();
|
|
47
|
+
const onErrorBlocks = [
|
|
48
|
+
...this.select('.//mule:on-error-continue[@type]', handler),
|
|
49
|
+
...this.select('.//mule:on-error-propagate[@type]', handler),
|
|
50
|
+
];
|
|
51
|
+
for (const block of onErrorBlocks) {
|
|
52
|
+
const typeAttr = this.getAttribute(block, 'type') ?? '';
|
|
53
|
+
// Types can be comma-separated (e.g., "SALESFORCE:CONNECTIVITY, HTTP:CONNECTIVITY")
|
|
54
|
+
for (const t of typeAttr.split(',')) {
|
|
55
|
+
handledTypes.add(t.trim().toUpperCase());
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Check which required types are missing
|
|
59
|
+
const missingTypes = this.REQUIRED_APIKIT_TYPES.filter((t) => !handledTypes.has(t));
|
|
60
|
+
if (missingTypes.length > 0) {
|
|
61
|
+
issues.push(this.createIssue(handler, `Error handler "${handlerName}" is missing coverage for: ${missingTypes.join(', ')}`, {
|
|
62
|
+
suggestion: 'Add on-error-propagate blocks for each APIKit error type to return correct HTTP status codes (400, 404, 405, 406, 415)',
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return issues;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.ErrorHandlerTypeCoverageRule = ErrorHandlerTypeCoverageRule;
|
|
70
|
+
//# sourceMappingURL=ErrorHandlerTypeCoverageRule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ErrorHandlerTypeCoverageRule.js","sourceRoot":"","sources":["../../../../src/rules/error-handling/ErrorHandlerTypeCoverageRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;;;;;;GAUG;AACH,MAAa,4BAA6B,SAAQ,mBAAQ;IACxD,EAAE,GAAG,SAAS,CAAC;IACf,IAAI,GAAG,6BAA6B,CAAC;IACrC,WAAW,GAAG,4EAA4E,CAAC;IAC3F,QAAQ,GAAG,SAAkB,CAAC;IAC9B,QAAQ,GAAG,gBAAyB,CAAC;IACrC,SAAS,GAAc,KAAK,CAAC;IAE7B;;;OAGG;IACc,qBAAqB,GAAG;QACvC,oBAAoB;QACpB,kBAAkB;QAClB,2BAA2B;QAC3B,uBAAuB;QACvB,+BAA+B;KAChC,CAAC;IAEF,QAAQ,CAAC,GAAa,EAAE,OAA0B;QAChD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,+CAA+C;QAC/C,IAAI,OAAO,CAAC,cAAc,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,eAAe,EAAE,CAAC;YACtE,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,sEAAsE;QACtE,8BAA8B;QAC9B,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;QAEtE,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE,CAAC;YACpC,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,SAAS,CAAC;YAEpE,wDAAwD;YACxD,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;YAEvC,MAAM,aAAa,GAAG;gBACpB,GAAG,IAAI,CAAC,MAAM,CAAC,kCAAkC,EAAE,OAAmB,CAAC;gBACvE,GAAG,IAAI,CAAC,MAAM,CAAC,mCAAmC,EAAE,OAAmB,CAAC;aACzE,CAAC;YAEF,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;gBAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;gBACxD,oFAAoF;gBACpF,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;oBACpC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;gBAC3C,CAAC;YACH,CAAC;YAED,yCAAyC;YACzC,MAAM,YAAY,GAAG,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAEpF,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC5B,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,OAAO,EACP,kBAAkB,WAAW,8BAA8B,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EACpF;oBACE,UAAU,EACR,wHAAwH;iBAC3H,CACF,CACF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAtED,oEAsEC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ValidationContext, Issue, IssueType } from '../../types';
|
|
2
|
+
import { BaseRule } from '../base/BaseRule';
|
|
3
|
+
/**
|
|
4
|
+
* ERR-003: Error Response Structure
|
|
5
|
+
*
|
|
6
|
+
* Error responses should include both a correlationId and a message field
|
|
7
|
+
* for effective debugging and traceability. Real-world accelerator projects
|
|
8
|
+
* consistently use a JSON envelope like:
|
|
9
|
+
* { correlationId: "...", error: "...", message: "..." }
|
|
10
|
+
*
|
|
11
|
+
* This rule checks that ee:set-payload elements inside error handlers
|
|
12
|
+
* contain both correlationId and message in their DataWeave body.
|
|
13
|
+
*/
|
|
14
|
+
export declare class ErrorResponseStructureRule extends BaseRule {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
severity: "info";
|
|
19
|
+
category: "error-handling";
|
|
20
|
+
issueType: IssueType;
|
|
21
|
+
validate(doc: Document, _context: ValidationContext): Issue[];
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=ErrorResponseStructureRule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ErrorResponseStructureRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/error-handling/ErrorResponseStructureRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C;;;;;;;;;;GAUG;AACH,qBAAa,0BAA2B,SAAQ,QAAQ;IACtD,EAAE,SAAa;IACf,IAAI,SAA8B;IAClC,WAAW,SAAqE;IAChF,QAAQ,EAAG,MAAM,CAAU;IAC3B,QAAQ,EAAG,gBAAgB,CAAU;IACrC,SAAS,EAAE,SAAS,CAAS;IAE7B,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;CAyE9D"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ErrorResponseStructureRule = void 0;
|
|
4
|
+
const BaseRule_1 = require("../base/BaseRule");
|
|
5
|
+
const XPathHelper_1 = require("../../core/XPathHelper");
|
|
6
|
+
/**
|
|
7
|
+
* ERR-003: Error Response Structure
|
|
8
|
+
*
|
|
9
|
+
* Error responses should include both a correlationId and a message field
|
|
10
|
+
* for effective debugging and traceability. Real-world accelerator projects
|
|
11
|
+
* consistently use a JSON envelope like:
|
|
12
|
+
* { correlationId: "...", error: "...", message: "..." }
|
|
13
|
+
*
|
|
14
|
+
* This rule checks that ee:set-payload elements inside error handlers
|
|
15
|
+
* contain both correlationId and message in their DataWeave body.
|
|
16
|
+
*/
|
|
17
|
+
class ErrorResponseStructureRule extends BaseRule_1.BaseRule {
|
|
18
|
+
id = 'ERR-003';
|
|
19
|
+
name = 'Error Response Structure';
|
|
20
|
+
description = 'Error responses should include correlationId and message fields';
|
|
21
|
+
severity = 'info';
|
|
22
|
+
category = 'error-handling';
|
|
23
|
+
issueType = 'bug';
|
|
24
|
+
validate(doc, _context) {
|
|
25
|
+
const issues = [];
|
|
26
|
+
// Find on-error blocks that contain ee:set-payload (i.e., they build an error response)
|
|
27
|
+
const onErrorBlocks = [
|
|
28
|
+
...this.select('//mule:on-error-continue', doc),
|
|
29
|
+
...this.select('//mule:on-error-propagate', doc),
|
|
30
|
+
];
|
|
31
|
+
for (const block of onErrorBlocks) {
|
|
32
|
+
// Find ee:set-payload within this error block
|
|
33
|
+
const setPayloads = this.select('.//*[local-name()="set-payload" and namespace-uri()="http://www.mulesoft.org/schema/mule/ee/core"]', block);
|
|
34
|
+
if (setPayloads.length === 0) {
|
|
35
|
+
continue; // No payload transformation — skip (might be logging-only)
|
|
36
|
+
}
|
|
37
|
+
for (const sp of setPayloads) {
|
|
38
|
+
const content = (0, XPathHelper_1.getTextContent)(sp).toLowerCase();
|
|
39
|
+
// Also check resource attribute — if present, we can't inspect inline
|
|
40
|
+
const resourceAttr = this.getAttribute(sp, 'resource');
|
|
41
|
+
if (resourceAttr) {
|
|
42
|
+
continue; // External DWL — inspected by MULE-007 (CorrelationIdRule)
|
|
43
|
+
}
|
|
44
|
+
// Skip non-DataWeave content (e.g., static strings)
|
|
45
|
+
if (!content.includes('dw 2.0') && !content.includes('---')) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const hasCorrelationId = content.includes('correlationid');
|
|
49
|
+
const hasMessage = content.includes('message') || content.includes('detaileddescription');
|
|
50
|
+
if (!hasCorrelationId && !hasMessage) {
|
|
51
|
+
issues.push(this.createIssue(sp, 'Error response payload is missing both correlationId and message fields', {
|
|
52
|
+
suggestion: 'Include correlationId and message in the error response for traceability: { correlationId: vars.correlationId, message: error.detailedDescription }',
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
else if (!hasCorrelationId) {
|
|
56
|
+
issues.push(this.createIssue(sp, 'Error response payload is missing correlationId field', {
|
|
57
|
+
severity: 'info',
|
|
58
|
+
suggestion: 'Add correlationId to the error response: correlationId: vars.correlationId default ""',
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
else if (!hasMessage) {
|
|
62
|
+
issues.push(this.createIssue(sp, 'Error response payload is missing a message or description field', {
|
|
63
|
+
severity: 'info',
|
|
64
|
+
suggestion: 'Add a message field: message: error.detailedDescription default ""',
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return issues;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.ErrorResponseStructureRule = ErrorResponseStructureRule;
|
|
73
|
+
//# sourceMappingURL=ErrorResponseStructureRule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ErrorResponseStructureRule.js","sourceRoot":"","sources":["../../../../src/rules/error-handling/ErrorResponseStructureRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAC5C,wDAAwD;AAExD;;;;;;;;;;GAUG;AACH,MAAa,0BAA2B,SAAQ,mBAAQ;IACtD,EAAE,GAAG,SAAS,CAAC;IACf,IAAI,GAAG,0BAA0B,CAAC;IAClC,WAAW,GAAG,iEAAiE,CAAC;IAChF,QAAQ,GAAG,MAAe,CAAC;IAC3B,QAAQ,GAAG,gBAAyB,CAAC;IACrC,SAAS,GAAc,KAAK,CAAC;IAE7B,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,wFAAwF;QACxF,MAAM,aAAa,GAAG;YACpB,GAAG,IAAI,CAAC,MAAM,CAAC,0BAA0B,EAAE,GAAG,CAAC;YAC/C,GAAG,IAAI,CAAC,MAAM,CAAC,2BAA2B,EAAE,GAAG,CAAC;SACjD,CAAC;QAEF,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;YAClC,8CAA8C;YAC9C,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAC7B,oGAAoG,EACpG,KAAK,CACN,CAAC;YAEF,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC7B,SAAS,CAAC,2DAA2D;YACvE,CAAC;YAED,KAAK,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;gBAC7B,MAAM,OAAO,GAAG,IAAA,4BAAc,EAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;gBAEjD,sEAAsE;gBACtE,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;gBACvD,IAAI,YAAY,EAAE,CAAC;oBACjB,SAAS,CAAC,2DAA2D;gBACvE,CAAC;gBAED,oDAAoD;gBACpD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC5D,SAAS;gBACX,CAAC;gBAED,MAAM,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;gBAC3D,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC;gBAE1F,IAAI,CAAC,gBAAgB,IAAI,CAAC,UAAU,EAAE,CAAC;oBACrC,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,EAAE,EACF,yEAAyE,EACzE;wBACE,UAAU,EACR,qJAAqJ;qBACxJ,CACF,CACF,CAAC;gBACJ,CAAC;qBAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;oBAC7B,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,uDAAuD,EAAE;wBAC5E,QAAQ,EAAE,MAAM;wBAChB,UAAU,EACR,uFAAuF;qBAC1F,CAAC,CACH,CAAC;gBACJ,CAAC;qBAAM,IAAI,CAAC,UAAU,EAAE,CAAC;oBACvB,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,EAAE,EACF,kEAAkE,EAClE;wBACE,QAAQ,EAAE,MAAM;wBAChB,UAAU,EAAE,oEAAoE;qBACjF,CACF,CACF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAjFD,gEAiFC"}
|
|
@@ -3,8 +3,13 @@ import { BaseRule } from '../base/BaseRule';
|
|
|
3
3
|
/**
|
|
4
4
|
* MULE-009: Generic Error Type
|
|
5
5
|
*
|
|
6
|
-
* Avoid catching type="ANY" in error handlers
|
|
7
|
-
*
|
|
6
|
+
* Avoid catching type="ANY" in error handlers — unless it is the LAST
|
|
7
|
+
* on-error block in the error-handler, where it serves as a catch-all
|
|
8
|
+
* fallback (the accelerator pattern maps this to HTTP 500).
|
|
9
|
+
*
|
|
10
|
+
* Enhanced: only flag type="ANY" when it is NOT the last sibling in
|
|
11
|
+
* its parent error-handler, since a catch-all as the final block is
|
|
12
|
+
* an accepted MuleSoft best practice.
|
|
8
13
|
*/
|
|
9
14
|
export declare class GenericErrorRule extends BaseRule {
|
|
10
15
|
id: string;
|
|
@@ -16,8 +21,15 @@ export declare class GenericErrorRule extends BaseRule {
|
|
|
16
21
|
private readonly GENERIC_TYPES;
|
|
17
22
|
validate(doc: Document, _context: ValidationContext): Issue[];
|
|
18
23
|
/**
|
|
19
|
-
* Check if handler uses generic error type
|
|
24
|
+
* Check if handler uses generic error type.
|
|
25
|
+
* Skip if this handler is the LAST on-error block in its parent
|
|
26
|
+
* error-handler (catch-all fallback is an accepted pattern).
|
|
20
27
|
*/
|
|
21
28
|
private checkGenericType;
|
|
29
|
+
/**
|
|
30
|
+
* Returns true if the given on-error node is the last on-error child
|
|
31
|
+
* of its parent error-handler element.
|
|
32
|
+
*/
|
|
33
|
+
private isLastOnErrorBlock;
|
|
22
34
|
}
|
|
23
35
|
//# sourceMappingURL=GenericErrorRule.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GenericErrorRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/error-handling/GenericErrorRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C
|
|
1
|
+
{"version":3,"file":"GenericErrorRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/error-handling/GenericErrorRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;;GAUG;AACH,qBAAa,gBAAiB,SAAQ,QAAQ;IAC5C,EAAE,SAAc;IAChB,IAAI,SAAwB;IAC5B,WAAW,SAA+D;IAC1E,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,gBAAgB,CAAU;IACrC,SAAS,EAAE,SAAS,CAAS;IAG7B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAuB;IAErD,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;IAsB7D;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IA2BxB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;CAuB3B"}
|
|
@@ -5,8 +5,13 @@ const BaseRule_1 = require("../base/BaseRule");
|
|
|
5
5
|
/**
|
|
6
6
|
* MULE-009: Generic Error Type
|
|
7
7
|
*
|
|
8
|
-
* Avoid catching type="ANY" in error handlers
|
|
9
|
-
*
|
|
8
|
+
* Avoid catching type="ANY" in error handlers — unless it is the LAST
|
|
9
|
+
* on-error block in the error-handler, where it serves as a catch-all
|
|
10
|
+
* fallback (the accelerator pattern maps this to HTTP 500).
|
|
11
|
+
*
|
|
12
|
+
* Enhanced: only flag type="ANY" when it is NOT the last sibling in
|
|
13
|
+
* its parent error-handler, since a catch-all as the final block is
|
|
14
|
+
* an accepted MuleSoft best practice.
|
|
10
15
|
*/
|
|
11
16
|
class GenericErrorRule extends BaseRule_1.BaseRule {
|
|
12
17
|
id = 'MULE-009';
|
|
@@ -19,30 +24,65 @@ class GenericErrorRule extends BaseRule_1.BaseRule {
|
|
|
19
24
|
GENERIC_TYPES = ['ANY', 'MULE:ANY'];
|
|
20
25
|
validate(doc, _context) {
|
|
21
26
|
const issues = [];
|
|
22
|
-
// Find on-error-continue with type
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
// Find all on-error-continue and on-error-propagate with type attribute
|
|
28
|
+
const allHandlers = [
|
|
29
|
+
...this.select('//mule:on-error-continue[@type]', doc).map((h) => ({
|
|
30
|
+
node: h,
|
|
31
|
+
type: 'on-error-continue',
|
|
32
|
+
})),
|
|
33
|
+
...this.select('//mule:on-error-propagate[@type]', doc).map((h) => ({
|
|
34
|
+
node: h,
|
|
35
|
+
type: 'on-error-propagate',
|
|
36
|
+
})),
|
|
37
|
+
];
|
|
38
|
+
for (const handler of allHandlers) {
|
|
39
|
+
this.checkGenericType(handler.node, handler.type, issues);
|
|
31
40
|
}
|
|
32
41
|
return issues;
|
|
33
42
|
}
|
|
34
43
|
/**
|
|
35
|
-
* Check if handler uses generic error type
|
|
44
|
+
* Check if handler uses generic error type.
|
|
45
|
+
* Skip if this handler is the LAST on-error block in its parent
|
|
46
|
+
* error-handler (catch-all fallback is an accepted pattern).
|
|
36
47
|
*/
|
|
37
48
|
checkGenericType(handler, handlerType, issues) {
|
|
38
49
|
const errorType = this.getAttribute(handler, 'type');
|
|
39
|
-
if (errorType
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
50
|
+
if (!errorType || !this.GENERIC_TYPES.includes(errorType.toUpperCase())) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
// Check if this is the last on-error sibling in its parent error-handler
|
|
54
|
+
if (this.isLastOnErrorBlock(handler)) {
|
|
55
|
+
return; // Catch-all as last block is fine
|
|
56
|
+
}
|
|
57
|
+
const docName = this.getDocName(handler);
|
|
58
|
+
const displayName = docName ? `"${docName}"` : '';
|
|
59
|
+
issues.push(this.createIssue(handler, `${handlerType} ${displayName} uses generic type="${errorType}" but is not the last error handler — move it to the end or use specific types`, {
|
|
60
|
+
suggestion: 'If this is a catch-all, place it as the last on-error block. Otherwise, catch specific error types (e.g., HTTP:CONNECTIVITY, DB:CONNECTIVITY)',
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Returns true if the given on-error node is the last on-error child
|
|
65
|
+
* of its parent error-handler element.
|
|
66
|
+
*/
|
|
67
|
+
isLastOnErrorBlock(handler) {
|
|
68
|
+
const parent = handler.parentNode;
|
|
69
|
+
if (!parent) {
|
|
70
|
+
return true; // No parent, can't determine position — assume last
|
|
71
|
+
}
|
|
72
|
+
// Collect on-error siblings (continue and propagate)
|
|
73
|
+
const siblings = parent.childNodes;
|
|
74
|
+
let lastOnError = null;
|
|
75
|
+
for (let i = 0; i < siblings.length; i++) {
|
|
76
|
+
const sibling = siblings[i];
|
|
77
|
+
if (sibling.nodeType === 1 /* ELEMENT_NODE */) {
|
|
78
|
+
const el = sibling;
|
|
79
|
+
const localName = el.localName ?? el.tagName ?? '';
|
|
80
|
+
if (localName === 'on-error-continue' || localName === 'on-error-propagate') {
|
|
81
|
+
lastOnError = sibling;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
45
84
|
}
|
|
85
|
+
return lastOnError === handler;
|
|
46
86
|
}
|
|
47
87
|
}
|
|
48
88
|
exports.GenericErrorRule = GenericErrorRule;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GenericErrorRule.js","sourceRoot":"","sources":["../../../../src/rules/error-handling/GenericErrorRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C
|
|
1
|
+
{"version":3,"file":"GenericErrorRule.js","sourceRoot":"","sources":["../../../../src/rules/error-handling/GenericErrorRule.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,18 +1,29 @@
|
|
|
1
1
|
import { ValidationContext, Issue, IssueType } from '../../types';
|
|
2
|
-
import {
|
|
2
|
+
import { ProjectRule } from '../base/ProjectRule';
|
|
3
3
|
/**
|
|
4
4
|
* MULE-001: Global Error Handler Exists
|
|
5
5
|
*
|
|
6
|
-
* Every Mule project should have a global error handler
|
|
7
|
-
*
|
|
6
|
+
* Every Mule project should have a global error handler: either a dedicated
|
|
7
|
+
* file (default: global-error-handler.xml) OR any XML file in the project
|
|
8
|
+
* that contains a named <error-handler> element.
|
|
9
|
+
*
|
|
10
|
+
* This is a ProjectRule — it runs once per scan (not per file). It scans all
|
|
11
|
+
* XML files in the Mule source directory looking for a named error-handler
|
|
12
|
+
* definition. If none is found and the expected file doesn't exist, it reports
|
|
13
|
+
* a single project-level issue.
|
|
8
14
|
*/
|
|
9
|
-
export declare class GlobalErrorHandlerRule extends
|
|
15
|
+
export declare class GlobalErrorHandlerRule extends ProjectRule {
|
|
10
16
|
id: string;
|
|
11
17
|
name: string;
|
|
12
18
|
description: string;
|
|
13
19
|
severity: "warning";
|
|
14
20
|
category: "error-handling";
|
|
15
21
|
issueType: IssueType;
|
|
16
|
-
|
|
22
|
+
protected validateProject(context: ValidationContext): Issue[];
|
|
23
|
+
/**
|
|
24
|
+
* Recursively scan a directory for XML files containing a named
|
|
25
|
+
* <error-handler> or <error-handler ref="..."> element.
|
|
26
|
+
*/
|
|
27
|
+
private scanForErrorHandler;
|
|
17
28
|
}
|
|
18
29
|
//# sourceMappingURL=GlobalErrorHandlerRule.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GlobalErrorHandlerRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/error-handling/GlobalErrorHandlerRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"GlobalErrorHandlerRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/error-handling/GlobalErrorHandlerRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAKlD;;;;;;;;;;;GAWG;AACH,qBAAa,sBAAuB,SAAQ,WAAW;IACrD,EAAE,SAAc;IAChB,IAAI,SAAiC;IACrC,WAAW,SACgF;IAC3F,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,gBAAgB,CAAU;IACrC,SAAS,EAAE,SAAS,CAAS;IAE7B,SAAS,CAAC,eAAe,CAAC,OAAO,EAAE,iBAAiB,GAAG,KAAK,EAAE;IAqC9D;;;OAGG;IACH,OAAO,CAAC,mBAAmB;CA8B5B"}
|
|
@@ -34,44 +34,87 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.GlobalErrorHandlerRule = void 0;
|
|
37
|
-
const
|
|
37
|
+
const ProjectRule_1 = require("../base/ProjectRule");
|
|
38
38
|
const FileScanner_1 = require("../../core/FileScanner");
|
|
39
39
|
const path = __importStar(require("path"));
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
40
41
|
/**
|
|
41
42
|
* MULE-001: Global Error Handler Exists
|
|
42
43
|
*
|
|
43
|
-
* Every Mule project should have a global error handler
|
|
44
|
-
*
|
|
44
|
+
* Every Mule project should have a global error handler: either a dedicated
|
|
45
|
+
* file (default: global-error-handler.xml) OR any XML file in the project
|
|
46
|
+
* that contains a named <error-handler> element.
|
|
47
|
+
*
|
|
48
|
+
* This is a ProjectRule — it runs once per scan (not per file). It scans all
|
|
49
|
+
* XML files in the Mule source directory looking for a named error-handler
|
|
50
|
+
* definition. If none is found and the expected file doesn't exist, it reports
|
|
51
|
+
* a single project-level issue.
|
|
45
52
|
*/
|
|
46
|
-
class GlobalErrorHandlerRule extends
|
|
53
|
+
class GlobalErrorHandlerRule extends ProjectRule_1.ProjectRule {
|
|
47
54
|
id = 'MULE-001';
|
|
48
55
|
name = 'Global Error Handler Exists';
|
|
49
56
|
description = 'Project should have a global error handler configuration for consistent error handling';
|
|
50
57
|
severity = 'warning';
|
|
51
58
|
category = 'error-handling';
|
|
52
59
|
issueType = 'bug';
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
// Get configurable file path
|
|
60
|
+
validateProject(context) {
|
|
61
|
+
// Get configurable expected file path
|
|
56
62
|
const expectedFile = this.getOption(context, 'filePath', 'src/main/mule/global-error-handler.xml');
|
|
57
63
|
const fullPath = path.join(context.projectRoot, expectedFile);
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
64
|
+
// 1. If the dedicated global error handler file exists, the project
|
|
65
|
+
// satisfies the rule.
|
|
66
|
+
if ((0, FileScanner_1.fileExists)(fullPath)) {
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
// 2. Scan all XML files in src/main/mule for a named <error-handler>
|
|
70
|
+
// element or an <error-handler ref="..."> reference.
|
|
71
|
+
const muleDir = path.join(context.projectRoot, 'src/main/mule');
|
|
72
|
+
if (fs.existsSync(muleDir)) {
|
|
73
|
+
const hasErrorHandler = this.scanForErrorHandler(muleDir);
|
|
74
|
+
if (hasErrorHandler) {
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return [
|
|
79
|
+
this.createProjectIssue(`Global error handler configuration not found. Expected "${expectedFile}" or a named <error-handler> element in any Mule XML file.`, {
|
|
80
|
+
suggestion: 'Create a global-error-handler.xml file with a named <error-handler> element, or add an <error-handler name="..."> to an existing configuration file',
|
|
81
|
+
}),
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Recursively scan a directory for XML files containing a named
|
|
86
|
+
* <error-handler> or <error-handler ref="..."> element.
|
|
87
|
+
*/
|
|
88
|
+
scanForErrorHandler(dir) {
|
|
89
|
+
try {
|
|
90
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
91
|
+
for (const entry of entries) {
|
|
92
|
+
const fullPath = path.join(dir, entry.name);
|
|
93
|
+
if (entry.isDirectory()) {
|
|
94
|
+
if (this.scanForErrorHandler(fullPath)) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else if (entry.name.endsWith('.xml')) {
|
|
99
|
+
try {
|
|
100
|
+
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
101
|
+
// Quick string check before full parse — avoids parsing every file
|
|
102
|
+
if (content.includes('error-handler') &&
|
|
103
|
+
(/<error-handler\s[^>]*name\s*=/.test(content) ||
|
|
104
|
+
/<error-handler\s[^>]*ref\s*=/.test(content))) {
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Unreadable file, skip
|
|
110
|
+
}
|
|
71
111
|
}
|
|
72
112
|
}
|
|
73
113
|
}
|
|
74
|
-
|
|
114
|
+
catch {
|
|
115
|
+
// Unreadable directory
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
75
118
|
}
|
|
76
119
|
}
|
|
77
120
|
exports.GlobalErrorHandlerRule = GlobalErrorHandlerRule;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GlobalErrorHandlerRule.js","sourceRoot":"","sources":["../../../../src/rules/error-handling/GlobalErrorHandlerRule.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA
|
|
1
|
+
{"version":3,"file":"GlobalErrorHandlerRule.js","sourceRoot":"","sources":["../../../../src/rules/error-handling/GlobalErrorHandlerRule.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,qDAAkD;AAClD,wDAAoD;AACpD,2CAA6B;AAC7B,uCAAyB;AAEzB;;;;;;;;;;;GAWG;AACH,MAAa,sBAAuB,SAAQ,yBAAW;IACrD,EAAE,GAAG,UAAU,CAAC;IAChB,IAAI,GAAG,6BAA6B,CAAC;IACrC,WAAW,GACT,wFAAwF,CAAC;IAC3F,QAAQ,GAAG,SAAkB,CAAC;IAC9B,QAAQ,GAAG,gBAAyB,CAAC;IACrC,SAAS,GAAc,KAAK,CAAC;IAEnB,eAAe,CAAC,OAA0B;QAClD,sCAAsC;QACtC,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CACjC,OAAO,EACP,UAAU,EACV,wCAAwC,CACzC,CAAC;QAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;QAE9D,oEAAoE;QACpE,yBAAyB;QACzB,IAAI,IAAA,wBAAU,EAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,qEAAqE;QACrE,wDAAwD;QACxD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC;QAChE,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3B,MAAM,eAAe,GAAG,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;YAC1D,IAAI,eAAe,EAAE,CAAC;gBACpB,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;QAED,OAAO;YACL,IAAI,CAAC,kBAAkB,CACrB,2DAA2D,YAAY,4DAA4D,EACnI;gBACE,UAAU,EACR,qJAAqJ;aACxJ,CACF;SACF,CAAC;IACJ,CAAC;IAED;;;OAGG;IACK,mBAAmB,CAAC,GAAW;QACrC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAC7D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC5C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;oBACxB,IAAI,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,EAAE,CAAC;wBACvC,OAAO,IAAI,CAAC;oBACd,CAAC;gBACH,CAAC;qBAAM,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;oBACvC,IAAI,CAAC;wBACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;wBACnD,mEAAmE;wBACnE,IACE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;4BACjC,CAAC,+BAA+B,CAAC,IAAI,CAAC,OAAO,CAAC;gCAC5C,8BAA8B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAC/C,CAAC;4BACD,OAAO,IAAI,CAAC;wBACd,CAAC;oBACH,CAAC;oBAAC,MAAM,CAAC;wBACP,wBAAwB;oBAC1B,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,uBAAuB;QACzB,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAhFD,wDAgFC"}
|
|
@@ -5,6 +5,11 @@ import { BaseRule } from '../base/BaseRule';
|
|
|
5
5
|
*
|
|
6
6
|
* Error handlers should set an httpStatus variable for proper API responses.
|
|
7
7
|
* This ensures clients receive appropriate HTTP status codes.
|
|
8
|
+
*
|
|
9
|
+
* This rule only applies to projects that are HTTP-exposed (i.e., have at
|
|
10
|
+
* least one http:listener or apikit:router). When the LintEngine provides
|
|
11
|
+
* context.projectContext, projects without HTTP entry points skip this check
|
|
12
|
+
* to avoid false positives on event-driven or batch Mule applications.
|
|
8
13
|
*/
|
|
9
14
|
export declare class HttpStatusRule extends BaseRule {
|
|
10
15
|
id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HttpStatusRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/error-handling/HttpStatusRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C
|
|
1
|
+
{"version":3,"file":"HttpStatusRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/error-handling/HttpStatusRule.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,cAAe,SAAQ,QAAQ;IAC1C,EAAE,SAAc;IAChB,IAAI,SAAkC;IACtC,WAAW,SAAiF;IAC5F,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,gBAAgB,CAAU;IACrC,SAAS,EAAE,SAAS,CAAS;IAE7B,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,GAAG,KAAK,EAAE;IAwD5D;;OAEG;IACH,OAAO,CAAC,cAAc;CAUvB"}
|
|
@@ -7,6 +7,11 @@ const BaseRule_1 = require("../base/BaseRule");
|
|
|
7
7
|
*
|
|
8
8
|
* Error handlers should set an httpStatus variable for proper API responses.
|
|
9
9
|
* This ensures clients receive appropriate HTTP status codes.
|
|
10
|
+
*
|
|
11
|
+
* This rule only applies to projects that are HTTP-exposed (i.e., have at
|
|
12
|
+
* least one http:listener or apikit:router). When the LintEngine provides
|
|
13
|
+
* context.projectContext, projects without HTTP entry points skip this check
|
|
14
|
+
* to avoid false positives on event-driven or batch Mule applications.
|
|
10
15
|
*/
|
|
11
16
|
class HttpStatusRule extends BaseRule_1.BaseRule {
|
|
12
17
|
id = 'MULE-005';
|
|
@@ -17,6 +22,16 @@ class HttpStatusRule extends BaseRule_1.BaseRule {
|
|
|
17
22
|
issueType = 'bug';
|
|
18
23
|
validate(doc, context) {
|
|
19
24
|
const issues = [];
|
|
25
|
+
// Skip this rule for non-HTTP projects.
|
|
26
|
+
// When projectContext is available (project-wide scan), check whether
|
|
27
|
+
// the project has any HTTP listeners or APIkit routers. If not, the
|
|
28
|
+
// httpStatus variable is irrelevant (e.g. batch or event-driven apps).
|
|
29
|
+
if (context.projectContext) {
|
|
30
|
+
const { hasHttpListener, hasApikitRouter } = context.projectContext;
|
|
31
|
+
if (!hasHttpListener && !hasApikitRouter) {
|
|
32
|
+
return issues;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
20
35
|
// Variable name to look for
|
|
21
36
|
const variableName = this.getOption(context, 'variableName', 'httpStatus');
|
|
22
37
|
// Find error handlers
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HttpStatusRule.js","sourceRoot":"","sources":["../../../../src/rules/error-handling/HttpStatusRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C
|
|
1
|
+
{"version":3,"file":"HttpStatusRule.js","sourceRoot":"","sources":["../../../../src/rules/error-handling/HttpStatusRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;;;;;;GAUG;AACH,MAAa,cAAe,SAAQ,mBAAQ;IAC1C,EAAE,GAAG,UAAU,CAAC;IAChB,IAAI,GAAG,8BAA8B,CAAC;IACtC,WAAW,GAAG,6EAA6E,CAAC;IAC5F,QAAQ,GAAG,SAAkB,CAAC;IAC9B,QAAQ,GAAG,gBAAyB,CAAC;IACrC,SAAS,GAAc,KAAK,CAAC;IAE7B,QAAQ,CAAC,GAAa,EAAE,OAA0B;QAChD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,wCAAwC;QACxC,sEAAsE;QACtE,qEAAqE;QACrE,uEAAuE;QACvE,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;YAC3B,MAAM,EAAE,eAAe,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC;YACpE,IAAI,CAAC,eAAe,IAAI,CAAC,eAAe,EAAE,CAAC;gBACzC,OAAO,MAAM,CAAC;YAChB,CAAC;QACH,CAAC;QAED,4BAA4B;QAC5B,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;QAE3E,sBAAsB;QACtB,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,sBAAsB,EAAE,GAAG,CAAC,CAAC;QAE/D,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE,CAAC;YACpC,mDAAmD;YACnD,MAAM,WAAW,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;YACnD,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;YAChD,MAAM,WAAW,GAAG,WAAW,IAAI,UAAU,IAAI,SAAS,CAAC;YAE3D,2DAA2D;YAC3D,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAC/B,uCAAuC,YAAY,IAAI,EACvD,OAAO,CACR,CAAC;YAEF,IAAI,CAAC,aAAa,EAAE,CAAC;gBACnB,qDAAqD;gBACrD,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,CACjC,qCAAqC,YAAY,IAAI,EACrD,OAAO,CACR,CAAC;gBAEF,IAAI,CAAC,eAAe,EAAE,CAAC;oBACrB,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,OAAO,EACP,qBAAqB,WAAW,iBAAiB,YAAY,YAAY,EACzE;wBACE,UAAU,EAAE,mCAAmC,YAAY,+DAA+D;qBAC3H,CACF,CACF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACK,cAAc,CAAC,IAAU;QAC/B,IAAI,OAAO,GAAgB,IAAI,CAAC,UAAU,CAAC;QAC3C,OAAO,OAAO,EAAE,CAAC;YACf,IAAI,OAAO,CAAC,QAAQ,KAAK,MAAM,IAAI,OAAO,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;gBACpE,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC5C,CAAC;YACD,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC;QAC/B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AA7ED,wCA6EC"}
|
|
@@ -5,6 +5,10 @@ import { BaseRule } from '../base/BaseRule';
|
|
|
5
5
|
*
|
|
6
6
|
* Complex operations (DB calls, HTTP requests) should use Try scope
|
|
7
7
|
* for granular error isolation and handling.
|
|
8
|
+
*
|
|
9
|
+
* Enhanced to also check sub-flows containing http:request without
|
|
10
|
+
* Try scope — sub-flows are often called from multiple places and
|
|
11
|
+
* should handle their own errors for isolation.
|
|
8
12
|
*/
|
|
9
13
|
export declare class TryScopeRule extends BaseRule {
|
|
10
14
|
id: string;
|
|
@@ -14,5 +18,6 @@ export declare class TryScopeRule extends BaseRule {
|
|
|
14
18
|
category: "error-handling";
|
|
15
19
|
issueType: IssueType;
|
|
16
20
|
validate(doc: Document, _context: ValidationContext): Issue[];
|
|
21
|
+
private countRiskyOperations;
|
|
17
22
|
}
|
|
18
23
|
//# sourceMappingURL=TryScopeRule.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TryScopeRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/error-handling/TryScopeRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C
|
|
1
|
+
{"version":3,"file":"TryScopeRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/error-handling/TryScopeRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;GASG;AACH,qBAAa,YAAa,SAAQ,QAAQ;IACxC,EAAE,SAAa;IACf,IAAI,SAA6B;IACjC,WAAW,SAAiE;IAC5E,QAAQ,EAAG,MAAM,CAAU;IAC3B,QAAQ,EAAG,gBAAgB,CAAU;IACrC,SAAS,EAAE,SAAS,CAAS;IAE7B,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;IA8D7D,OAAO,CAAC,oBAAoB;CAe7B"}
|