@sfdxy/mule-lint 1.19.0 → 1.20.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 +65 -56
- package/dist/package.json +1 -1
- package/dist/src/engine/LintEngine.d.ts +10 -0
- package/dist/src/engine/LintEngine.d.ts.map +1 -1
- package/dist/src/engine/LintEngine.js +68 -4
- package/dist/src/engine/LintEngine.js.map +1 -1
- package/dist/src/rules/dataweave/DataWeaveRules.d.ts +6 -0
- package/dist/src/rules/dataweave/DataWeaveRules.d.ts.map +1 -1
- package/dist/src/rules/dataweave/DataWeaveRules.js +16 -0
- package/dist/src/rules/dataweave/DataWeaveRules.js.map +1 -1
- 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/GlobalErrorHandlerRule.d.ts +14 -2
- package/dist/src/rules/error-handling/GlobalErrorHandlerRule.d.ts.map +1 -1
- package/dist/src/rules/error-handling/GlobalErrorHandlerRule.js +40 -18
- 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/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/operations/UnusedFlowRule.d.ts +6 -1
- package/dist/src/rules/operations/UnusedFlowRule.d.ts.map +1 -1
- package/dist/src/rules/operations/UnusedFlowRule.js +23 -9
- package/dist/src/rules/operations/UnusedFlowRule.js.map +1 -1
- 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/ReconnectionStrategyRule.d.ts +7 -0
- package/dist/src/rules/performance/ReconnectionStrategyRule.d.ts.map +1 -1
- package/dist/src/rules/performance/ReconnectionStrategyRule.js +15 -2
- package/dist/src/rules/performance/ReconnectionStrategyRule.js.map +1 -1
- 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/types/Rule.d.ts +22 -0
- package/dist/src/types/Rule.d.ts.map +1 -1
- package/docs/best-practices/rules-catalog.md +107 -13
- package/package.json +1 -1
|
@@ -1,6 +1,41 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.CorrelationIdRule = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
4
39
|
const BaseRule_1 = require("../base/BaseRule");
|
|
5
40
|
const XPathHelper_1 = require("../../core/XPathHelper");
|
|
6
41
|
/**
|
|
@@ -8,6 +43,13 @@ const XPathHelper_1 = require("../../core/XPathHelper");
|
|
|
8
43
|
*
|
|
9
44
|
* Error handlers should include correlation ID for traceability.
|
|
10
45
|
* This helps track errors across distributed systems.
|
|
46
|
+
*
|
|
47
|
+
* The rule checks three patterns:
|
|
48
|
+
* 1. Inline correlationId reference in the error handler XML text/attributes
|
|
49
|
+
* 2. External DWL file referenced via resource="..." attribute on ee:set-payload
|
|
50
|
+
* (the DWL file content is read from disk and inspected)
|
|
51
|
+
* 3. If a resource reference exists but the file cannot be read, the issue is
|
|
52
|
+
* downgraded to 'info' to avoid false positives on valid code
|
|
11
53
|
*/
|
|
12
54
|
class CorrelationIdRule extends BaseRule_1.BaseRule {
|
|
13
55
|
id = 'MULE-007';
|
|
@@ -27,7 +69,7 @@ class CorrelationIdRule extends BaseRule_1.BaseRule {
|
|
|
27
69
|
'requestId',
|
|
28
70
|
'request-id',
|
|
29
71
|
];
|
|
30
|
-
validate(doc,
|
|
72
|
+
validate(doc, context) {
|
|
31
73
|
const issues = [];
|
|
32
74
|
// Find error handlers
|
|
33
75
|
const errorHandlers = this.select('//mule:error-handler', doc);
|
|
@@ -35,16 +77,68 @@ class CorrelationIdRule extends BaseRule_1.BaseRule {
|
|
|
35
77
|
const handlerName = this.getNameAttribute(handler);
|
|
36
78
|
const parentFlow = this.findParentFlow(handler);
|
|
37
79
|
const contextName = handlerName ?? parentFlow ?? 'unnamed';
|
|
38
|
-
// Check
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
80
|
+
// Check inline text/attribute content first
|
|
81
|
+
if (this.containsCorrelationId(handler)) {
|
|
82
|
+
continue; // Found inline — pass
|
|
83
|
+
}
|
|
84
|
+
// Check resource= references to external DWL files
|
|
85
|
+
const resourceResult = this.checkResourceReferences(handler, context.projectRoot);
|
|
86
|
+
if (resourceResult === 'found') {
|
|
87
|
+
continue; // Found in referenced DWL file — pass
|
|
88
|
+
}
|
|
89
|
+
if (resourceResult === 'unresolvable') {
|
|
90
|
+
// Resource reference exists but file cannot be read; cannot determine
|
|
91
|
+
// whether correlationId is present. Downgrade to info to avoid false positive.
|
|
92
|
+
issues.push(this.createIssue(handler, `Error handler in "${contextName}" delegates to an external DWL file — verify correlationId is included`, {
|
|
93
|
+
severity: 'info',
|
|
94
|
+
suggestion: 'Ensure the referenced DWL resource file includes correlationId in its output',
|
|
43
95
|
}));
|
|
96
|
+
continue;
|
|
44
97
|
}
|
|
98
|
+
// No correlationId found anywhere
|
|
99
|
+
issues.push(this.createIssue(handler, `Error handler in "${contextName}" should include correlationId for traceability`, {
|
|
100
|
+
suggestion: 'Include correlationId in error response or logging for distributed tracing',
|
|
101
|
+
}));
|
|
45
102
|
}
|
|
46
103
|
return issues;
|
|
47
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Inspect resource="..." attributes on ee:set-payload (and similar) elements
|
|
107
|
+
* within the error handler.
|
|
108
|
+
*
|
|
109
|
+
* @returns
|
|
110
|
+
* 'found' — correlationId pattern detected in a referenced DWL file
|
|
111
|
+
* 'unresolvable' — resource reference exists but could not be read
|
|
112
|
+
* 'not-found' — no resource references present or none contain correlationId
|
|
113
|
+
*/
|
|
114
|
+
checkResourceReferences(handler, projectRoot) {
|
|
115
|
+
// Look for any element with a resource= attribute (covers ee:set-payload, ee:set-variable, etc.)
|
|
116
|
+
const elementsWithResource = this.select('.//*[@resource]', handler);
|
|
117
|
+
if (elementsWithResource.length === 0) {
|
|
118
|
+
return 'not-found';
|
|
119
|
+
}
|
|
120
|
+
let hasUnresolvable = false;
|
|
121
|
+
for (const el of elementsWithResource) {
|
|
122
|
+
const resourceAttr = this.getAttribute(el, 'resource') ?? '';
|
|
123
|
+
if (!resourceAttr) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
// Resolve relative to src/main/resources/ (standard Mule resource path)
|
|
127
|
+
const fullPath = path.join(projectRoot, 'src', 'main', 'resources', resourceAttr);
|
|
128
|
+
try {
|
|
129
|
+
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
130
|
+
if (this.contentContainsCorrelationId(content)) {
|
|
131
|
+
return 'found';
|
|
132
|
+
}
|
|
133
|
+
// File read successfully but no correlationId found — continue checking others
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// File not readable — mark as unresolvable but keep checking other resources
|
|
137
|
+
hasUnresolvable = true;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return hasUnresolvable ? 'unresolvable' : 'not-found';
|
|
141
|
+
}
|
|
48
142
|
/**
|
|
49
143
|
* Check if a node or its descendants contain correlation ID reference
|
|
50
144
|
*/
|
|
@@ -69,6 +163,13 @@ class CorrelationIdRule extends BaseRule_1.BaseRule {
|
|
|
69
163
|
}
|
|
70
164
|
return false;
|
|
71
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Check whether a raw file content string contains a correlationId pattern
|
|
168
|
+
*/
|
|
169
|
+
contentContainsCorrelationId(content) {
|
|
170
|
+
const lower = content.toLowerCase();
|
|
171
|
+
return this.CORRELATION_PATTERNS.some((p) => lower.includes(p.toLowerCase()));
|
|
172
|
+
}
|
|
72
173
|
/**
|
|
73
174
|
* Find the parent flow element for context
|
|
74
175
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CorrelationIdRule.js","sourceRoot":"","sources":["../../../../src/rules/error-handling/CorrelationIdRule.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CorrelationIdRule.js","sourceRoot":"","sources":["../../../../src/rules/error-handling/CorrelationIdRule.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,8 +3,20 @@ import { BaseRule } from '../base/BaseRule';
|
|
|
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 scanned XML file that
|
|
8
|
+
* contains a named <error-handler> element.
|
|
9
|
+
*
|
|
10
|
+
* The rule fires on every scanned XML file that:
|
|
11
|
+
* 1. Contains at least one <flow> or <sub-flow> (is a flow file), AND
|
|
12
|
+
* 2. Does not itself define an <error-handler> element
|
|
13
|
+
*
|
|
14
|
+
* If neither the expected file exists NOR any named <error-handler> has been
|
|
15
|
+
* found in the current document, an issue is raised.
|
|
16
|
+
*
|
|
17
|
+
* Note: the old guard `context.relativePath.includes('global')` has been
|
|
18
|
+
* removed. Restricting reports to only "global" files hid the rule for
|
|
19
|
+
* projects that did not follow that naming convention.
|
|
8
20
|
*/
|
|
9
21
|
export declare class GlobalErrorHandlerRule extends BaseRule {
|
|
10
22
|
id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GlobalErrorHandlerRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/error-handling/GlobalErrorHandlerRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAI5C
|
|
1
|
+
{"version":3,"file":"GlobalErrorHandlerRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/error-handling/GlobalErrorHandlerRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAI5C;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,sBAAuB,SAAQ,QAAQ;IAClD,EAAE,SAAc;IAChB,IAAI,SAAiC;IACrC,WAAW,SACgF;IAC3F,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,gBAAgB,CAAU;IACrC,SAAS,EAAE,SAAS,CAAS;IAE7B,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,GAAG,KAAK,EAAE;CAoD7D"}
|
|
@@ -40,8 +40,20 @@ const path = __importStar(require("path"));
|
|
|
40
40
|
/**
|
|
41
41
|
* MULE-001: Global Error Handler Exists
|
|
42
42
|
*
|
|
43
|
-
* Every Mule project should have a global error handler
|
|
44
|
-
*
|
|
43
|
+
* Every Mule project should have a global error handler: either a dedicated
|
|
44
|
+
* file (default: global-error-handler.xml) OR any scanned XML file that
|
|
45
|
+
* contains a named <error-handler> element.
|
|
46
|
+
*
|
|
47
|
+
* The rule fires on every scanned XML file that:
|
|
48
|
+
* 1. Contains at least one <flow> or <sub-flow> (is a flow file), AND
|
|
49
|
+
* 2. Does not itself define an <error-handler> element
|
|
50
|
+
*
|
|
51
|
+
* If neither the expected file exists NOR any named <error-handler> has been
|
|
52
|
+
* found in the current document, an issue is raised.
|
|
53
|
+
*
|
|
54
|
+
* Note: the old guard `context.relativePath.includes('global')` has been
|
|
55
|
+
* removed. Restricting reports to only "global" files hid the rule for
|
|
56
|
+
* projects that did not follow that naming convention.
|
|
45
57
|
*/
|
|
46
58
|
class GlobalErrorHandlerRule extends BaseRule_1.BaseRule {
|
|
47
59
|
id = 'MULE-001';
|
|
@@ -52,25 +64,35 @@ class GlobalErrorHandlerRule extends BaseRule_1.BaseRule {
|
|
|
52
64
|
issueType = 'bug';
|
|
53
65
|
validate(doc, context) {
|
|
54
66
|
const issues = [];
|
|
55
|
-
// Get configurable file path
|
|
67
|
+
// Get configurable expected file path
|
|
56
68
|
const expectedFile = this.getOption(context, 'filePath', 'src/main/mule/global-error-handler.xml');
|
|
57
69
|
const fullPath = path.join(context.projectRoot, expectedFile);
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
// If the dedicated global error handler file exists, the project satisfies
|
|
71
|
+
// the rule regardless of what is in the current file.
|
|
72
|
+
if ((0, FileScanner_1.fileExists)(fullPath)) {
|
|
73
|
+
return issues;
|
|
74
|
+
}
|
|
75
|
+
// The expected file does not exist. Check whether the current document
|
|
76
|
+
// itself provides a global error handler via:
|
|
77
|
+
// (a) a named <error-handler> element, OR
|
|
78
|
+
// (b) a flow that references an error handler by ref attribute
|
|
79
|
+
const hasNamedErrorHandler = this.exists('//*[local-name()="error-handler"][@name]', doc);
|
|
80
|
+
if (hasNamedErrorHandler) {
|
|
81
|
+
return issues;
|
|
82
|
+
}
|
|
83
|
+
const hasErrorHandlerRef = this.exists('//*[local-name()="error-handler"][@ref]', doc);
|
|
84
|
+
if (hasErrorHandlerRef) {
|
|
85
|
+
return issues;
|
|
86
|
+
}
|
|
87
|
+
// Only report for files that actually contain flows / sub-flows so that
|
|
88
|
+
// pure configuration files (e.g. global.xml without flows) are excluded.
|
|
89
|
+
const hasFlows = this.exists('//*[local-name()="flow" or local-name()="sub-flow"]', doc);
|
|
90
|
+
if (!hasFlows) {
|
|
91
|
+
return issues;
|
|
73
92
|
}
|
|
93
|
+
issues.push(this.createFileIssue(`Global error handler configuration not found. Expected "${expectedFile}" or a named <error-handler> element in any flow file.`, {
|
|
94
|
+
suggestion: 'Create a global-error-handler.xml file with a named <error-handler> element, or add an <error-handler name="..."> to an existing configuration file',
|
|
95
|
+
}));
|
|
74
96
|
return issues;
|
|
75
97
|
}
|
|
76
98
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GlobalErrorHandlerRule.js","sourceRoot":"","sources":["../../../../src/rules/error-handling/GlobalErrorHandlerRule.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,+CAA4C;AAC5C,wDAAoD;AACpD,2CAA6B;AAE7B
|
|
1
|
+
{"version":3,"file":"GlobalErrorHandlerRule.js","sourceRoot":"","sources":["../../../../src/rules/error-handling/GlobalErrorHandlerRule.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,+CAA4C;AAC5C,wDAAoD;AACpD,2CAA6B;AAE7B;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAa,sBAAuB,SAAQ,mBAAQ;IAClD,EAAE,GAAG,UAAU,CAAC;IAChB,IAAI,GAAG,6BAA6B,CAAC;IACrC,WAAW,GACT,wFAAwF,CAAC;IAC3F,QAAQ,GAAG,SAAkB,CAAC;IAC9B,QAAQ,GAAG,gBAAyB,CAAC;IACrC,SAAS,GAAc,KAAK,CAAC;IAE7B,QAAQ,CAAC,GAAa,EAAE,OAA0B;QAChD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,sCAAsC;QACtC,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CACjC,OAAO,EACP,UAAU,EACV,wCAAwC,CACzC,CAAC;QAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;QAE9D,2EAA2E;QAC3E,sDAAsD;QACtD,IAAI,IAAA,wBAAU,EAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,wEAAwE;QACxE,8CAA8C;QAC9C,4CAA4C;QAC5C,iEAAiE;QACjE,MAAM,oBAAoB,GAAG,IAAI,CAAC,MAAM,CAAC,0CAA0C,EAAE,GAAG,CAAC,CAAC;QAC1F,IAAI,oBAAoB,EAAE,CAAC;YACzB,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,kBAAkB,GAAG,IAAI,CAAC,MAAM,CAAC,yCAAyC,EAAE,GAAG,CAAC,CAAC;QACvF,IAAI,kBAAkB,EAAE,CAAC;YACvB,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,wEAAwE;QACxE,yEAAyE;QACzE,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,qDAAqD,EAAE,GAAG,CAAC,CAAC;QAEzF,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,eAAe,CAClB,2DAA2D,YAAY,wDAAwD,EAC/H;YACE,UAAU,EACR,qJAAqJ;SACxJ,CACF,CACF,CAAC;QAEF,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AA7DD,wDA6DC"}
|
|
@@ -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"}
|
|
@@ -4,6 +4,25 @@ import { BaseRule } from '../base/BaseRule';
|
|
|
4
4
|
* MULE-402: HTTP Request Content-Type
|
|
5
5
|
*
|
|
6
6
|
* POST/PUT HTTP requests should include Content-Type header.
|
|
7
|
+
*
|
|
8
|
+
* The rule detects Content-Type in three patterns:
|
|
9
|
+
*
|
|
10
|
+
* Pattern A — Static <http:header> element:
|
|
11
|
+
* <http:headers>
|
|
12
|
+
* <http:header headerName="Content-Type" value="application/json"/>
|
|
13
|
+
* </http:headers>
|
|
14
|
+
*
|
|
15
|
+
* Pattern B — CDATA DataWeave expression block:
|
|
16
|
+
* <http:headers><![CDATA[#[output application/java --- {"Content-Type": "application/json"}]]]></http:headers>
|
|
17
|
+
*
|
|
18
|
+
* Pattern C — Inline DataWeave expression on value attribute:
|
|
19
|
+
* <http:headers value='#[{"Content-Type": "application/json"}]'/>
|
|
20
|
+
*
|
|
21
|
+
* When headers are set via DataWeave (patterns B/C), the rule performs a
|
|
22
|
+
* case-insensitive text search for "content-type" within the expression body.
|
|
23
|
+
* If a DataWeave expression is present but does not contain "content-type",
|
|
24
|
+
* the issue is downgraded to 'info' severity to acknowledge the static analysis
|
|
25
|
+
* limitation of evaluating dynamic expressions.
|
|
7
26
|
*/
|
|
8
27
|
export declare class HttpContentTypeRule extends BaseRule {
|
|
9
28
|
id: string;
|
|
@@ -12,6 +31,14 @@ export declare class HttpContentTypeRule extends BaseRule {
|
|
|
12
31
|
severity: "warning";
|
|
13
32
|
category: "http";
|
|
14
33
|
validate(doc: Document, _context: ValidationContext): Issue[];
|
|
15
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Check whether a Content-Type header is present on the given http:request element.
|
|
36
|
+
*
|
|
37
|
+
* @returns
|
|
38
|
+
* 'present' — Content-Type definitively found
|
|
39
|
+
* 'dynamic-unverified' — headers set via DW expression but Content-Type not visible
|
|
40
|
+
* 'missing' — no headers element or no Content-Type anywhere
|
|
41
|
+
*/
|
|
42
|
+
private checkContentTypeHeader;
|
|
16
43
|
}
|
|
17
44
|
//# sourceMappingURL=HttpContentTypeRule.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HttpContentTypeRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/http/HttpContentTypeRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C
|
|
1
|
+
{"version":3,"file":"HttpContentTypeRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/http/HttpContentTypeRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,mBAAoB,SAAQ,QAAQ;IAC/C,EAAE,SAAc;IAChB,IAAI,SAA+B;IACnC,WAAW,SAA+D;IAC1E,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,MAAM,CAAU;IAE3B,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;IAqD7D;;;;;;;OAOG;IACH,OAAO,CAAC,sBAAsB;CAuC/B"}
|
|
@@ -6,6 +6,25 @@ const BaseRule_1 = require("../base/BaseRule");
|
|
|
6
6
|
* MULE-402: HTTP Request Content-Type
|
|
7
7
|
*
|
|
8
8
|
* POST/PUT HTTP requests should include Content-Type header.
|
|
9
|
+
*
|
|
10
|
+
* The rule detects Content-Type in three patterns:
|
|
11
|
+
*
|
|
12
|
+
* Pattern A — Static <http:header> element:
|
|
13
|
+
* <http:headers>
|
|
14
|
+
* <http:header headerName="Content-Type" value="application/json"/>
|
|
15
|
+
* </http:headers>
|
|
16
|
+
*
|
|
17
|
+
* Pattern B — CDATA DataWeave expression block:
|
|
18
|
+
* <http:headers><![CDATA[#[output application/java --- {"Content-Type": "application/json"}]]]></http:headers>
|
|
19
|
+
*
|
|
20
|
+
* Pattern C — Inline DataWeave expression on value attribute:
|
|
21
|
+
* <http:headers value='#[{"Content-Type": "application/json"}]'/>
|
|
22
|
+
*
|
|
23
|
+
* When headers are set via DataWeave (patterns B/C), the rule performs a
|
|
24
|
+
* case-insensitive text search for "content-type" within the expression body.
|
|
25
|
+
* If a DataWeave expression is present but does not contain "content-type",
|
|
26
|
+
* the issue is downgraded to 'info' severity to acknowledge the static analysis
|
|
27
|
+
* limitation of evaluating dynamic expressions.
|
|
9
28
|
*/
|
|
10
29
|
class HttpContentTypeRule extends BaseRule_1.BaseRule {
|
|
11
30
|
id = 'MULE-402';
|
|
@@ -25,26 +44,68 @@ class HttpContentTypeRule extends BaseRule_1.BaseRule {
|
|
|
25
44
|
const method = this.getAttribute(request, 'method')?.toUpperCase();
|
|
26
45
|
// Only check POST and PUT methods
|
|
27
46
|
if (method === 'POST' || method === 'PUT') {
|
|
28
|
-
const
|
|
29
|
-
if (
|
|
47
|
+
const result = this.checkContentTypeHeader(request);
|
|
48
|
+
if (result === 'missing') {
|
|
30
49
|
const docName = this.getDocName(request) ?? 'HTTP Request';
|
|
31
50
|
issues.push(this.createIssue(request, `${method} request "${docName}" is missing Content-Type header`, {
|
|
32
51
|
suggestion: 'Add header: <http:header headerName="Content-Type" value="application/json"/>',
|
|
33
52
|
}));
|
|
34
53
|
}
|
|
54
|
+
else if (result === 'dynamic-unverified') {
|
|
55
|
+
// Headers are set via a DataWeave expression but we cannot statically
|
|
56
|
+
// verify that Content-Type is included. Downgrade to info.
|
|
57
|
+
const docName = this.getDocName(request) ?? 'HTTP Request';
|
|
58
|
+
issues.push(this.createIssue(request, `${method} request "${docName}" sets headers via DataWeave expression — verify Content-Type is included`, {
|
|
59
|
+
severity: 'info',
|
|
60
|
+
suggestion: 'Ensure the DataWeave expression includes {"Content-Type": "application/json"} or equivalent',
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
// 'present' → no issue
|
|
35
64
|
}
|
|
36
65
|
}
|
|
37
66
|
return issues;
|
|
38
67
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Check whether a Content-Type header is present on the given http:request element.
|
|
70
|
+
*
|
|
71
|
+
* @returns
|
|
72
|
+
* 'present' — Content-Type definitively found
|
|
73
|
+
* 'dynamic-unverified' — headers set via DW expression but Content-Type not visible
|
|
74
|
+
* 'missing' — no headers element or no Content-Type anywhere
|
|
75
|
+
*/
|
|
76
|
+
checkContentTypeHeader(request) {
|
|
77
|
+
// Pattern A: Static <http:header headerName="Content-Type" ...>
|
|
78
|
+
const staticHeaders = this.select('.//*[local-name()="header"]', request);
|
|
79
|
+
for (const header of staticHeaders) {
|
|
42
80
|
const headerName = this.getAttribute(header, 'headerName') ?? '';
|
|
43
81
|
if (headerName.toLowerCase() === 'content-type') {
|
|
44
|
-
return
|
|
82
|
+
return 'present';
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Patterns B & C: Check <http:headers> element for DataWeave expression content
|
|
86
|
+
const headersElements = this.select('.//*[local-name()="headers"]', request);
|
|
87
|
+
let hasDynamicHeaders = false;
|
|
88
|
+
for (const headersEl of headersElements) {
|
|
89
|
+
const element = headersEl;
|
|
90
|
+
// Pattern C: value attribute containing a DataWeave expression
|
|
91
|
+
const valueAttr = element.getAttribute('value') ?? '';
|
|
92
|
+
if (valueAttr.includes('#[')) {
|
|
93
|
+
hasDynamicHeaders = true;
|
|
94
|
+
if (valueAttr.toLowerCase().includes('content-type')) {
|
|
95
|
+
return 'present';
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Pattern B: CDATA block or text content inside <http:headers>
|
|
99
|
+
const textContent = headersEl.textContent ?? '';
|
|
100
|
+
if (textContent.trim().length > 0) {
|
|
101
|
+
// Any non-empty text content in <http:headers> is treated as a DW expression
|
|
102
|
+
hasDynamicHeaders = true;
|
|
103
|
+
if (textContent.toLowerCase().includes('content-type')) {
|
|
104
|
+
return 'present';
|
|
105
|
+
}
|
|
45
106
|
}
|
|
46
107
|
}
|
|
47
|
-
return
|
|
108
|
+
return hasDynamicHeaders ? 'dynamic-unverified' : 'missing';
|
|
48
109
|
}
|
|
49
110
|
}
|
|
50
111
|
exports.HttpContentTypeRule = HttpContentTypeRule;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HttpContentTypeRule.js","sourceRoot":"","sources":["../../../../src/rules/http/HttpContentTypeRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C
|
|
1
|
+
{"version":3,"file":"HttpContentTypeRule.js","sourceRoot":"","sources":["../../../../src/rules/http/HttpContentTypeRule.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,11 @@ import { BaseRule } from '../base/BaseRule';
|
|
|
4
4
|
* HYG-003: Unused Flow Detection
|
|
5
5
|
*
|
|
6
6
|
* Detects flows that are never referenced by flow-ref.
|
|
7
|
+
*
|
|
8
|
+
* Cross-file detection: when the LintEngine provides context.allFlowRefs
|
|
9
|
+
* (populated during the pre-scan phase), the rule checks across all project
|
|
10
|
+
* files. When scanning a standalone file (allFlowRefs is undefined), only
|
|
11
|
+
* intra-file references are checked.
|
|
7
12
|
*/
|
|
8
13
|
export declare class UnusedFlowRule extends BaseRule {
|
|
9
14
|
id: string;
|
|
@@ -11,7 +16,7 @@ export declare class UnusedFlowRule extends BaseRule {
|
|
|
11
16
|
description: string;
|
|
12
17
|
severity: "warning";
|
|
13
18
|
category: "standards";
|
|
14
|
-
validate(doc: Document,
|
|
19
|
+
validate(doc: Document, context: ValidationContext): Issue[];
|
|
15
20
|
private isExternallyReferenced;
|
|
16
21
|
}
|
|
17
22
|
//# sourceMappingURL=UnusedFlowRule.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UnusedFlowRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/operations/UnusedFlowRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C
|
|
1
|
+
{"version":3,"file":"UnusedFlowRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/operations/UnusedFlowRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;GASG;AACH,qBAAa,cAAe,SAAQ,QAAQ;IAC1C,EAAE,SAAa;IACf,IAAI,SAA2B;IAC/B,WAAW,SAA6C;IACxD,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,WAAW,CAAU;IAEhC,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,GAAG,KAAK,EAAE;IA0E5D,OAAO,CAAC,sBAAsB;CAY/B"}
|
|
@@ -6,6 +6,11 @@ const BaseRule_1 = require("../base/BaseRule");
|
|
|
6
6
|
* HYG-003: Unused Flow Detection
|
|
7
7
|
*
|
|
8
8
|
* Detects flows that are never referenced by flow-ref.
|
|
9
|
+
*
|
|
10
|
+
* Cross-file detection: when the LintEngine provides context.allFlowRefs
|
|
11
|
+
* (populated during the pre-scan phase), the rule checks across all project
|
|
12
|
+
* files. When scanning a standalone file (allFlowRefs is undefined), only
|
|
13
|
+
* intra-file references are checked.
|
|
9
14
|
*/
|
|
10
15
|
class UnusedFlowRule extends BaseRule_1.BaseRule {
|
|
11
16
|
id = 'HYG-003';
|
|
@@ -13,18 +18,27 @@ class UnusedFlowRule extends BaseRule_1.BaseRule {
|
|
|
13
18
|
description = 'Detects flows that are never referenced';
|
|
14
19
|
severity = 'warning';
|
|
15
20
|
category = 'standards';
|
|
16
|
-
validate(doc,
|
|
21
|
+
validate(doc, context) {
|
|
17
22
|
const issues = [];
|
|
18
23
|
// Get all flow names in this document
|
|
19
24
|
const flows = this.select('//*[local-name()="flow"]', doc);
|
|
20
25
|
const subflows = this.select('//*[local-name()="sub-flow"]', doc);
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
// Build the set of referenced flow names.
|
|
27
|
+
// When context.allFlowRefs is available (project-wide pre-scan), use it.
|
|
28
|
+
// Fall back to intra-file refs only for standalone scans.
|
|
29
|
+
let referencedFlows;
|
|
30
|
+
if (context.allFlowRefs) {
|
|
31
|
+
referencedFlows = context.allFlowRefs;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
// Intra-file only (standalone scan)
|
|
35
|
+
const flowRefs = this.select('//*[local-name()="flow-ref"]', doc);
|
|
36
|
+
referencedFlows = new Set();
|
|
37
|
+
for (const ref of flowRefs) {
|
|
38
|
+
const name = this.getNameAttribute(ref);
|
|
39
|
+
if (name) {
|
|
40
|
+
referencedFlows.add(name);
|
|
41
|
+
}
|
|
28
42
|
}
|
|
29
43
|
}
|
|
30
44
|
// Check sub-flows (they should always be referenced)
|
|
@@ -33,7 +47,7 @@ class UnusedFlowRule extends BaseRule_1.BaseRule {
|
|
|
33
47
|
if (name && !referencedFlows.has(name)) {
|
|
34
48
|
// Exclude common patterns that are referenced externally
|
|
35
49
|
if (!this.isExternallyReferenced(name)) {
|
|
36
|
-
issues.push(this.createIssue(subflow, `Sub-flow "${name}" is never referenced
|
|
50
|
+
issues.push(this.createIssue(subflow, `Sub-flow "${name}" is never referenced`, {
|
|
37
51
|
severity: 'info',
|
|
38
52
|
suggestion: 'Consider removing unused sub-flows or verify cross-file references',
|
|
39
53
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UnusedFlowRule.js","sourceRoot":"","sources":["../../../../src/rules/operations/UnusedFlowRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C
|
|
1
|
+
{"version":3,"file":"UnusedFlowRule.js","sourceRoot":"","sources":["../../../../src/rules/operations/UnusedFlowRule.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,11 @@ import { BaseRule } from '../base/BaseRule';
|
|
|
5
5
|
*
|
|
6
6
|
* DB and HTTP connectors should configure connection pools
|
|
7
7
|
* for optimal performance and resource management.
|
|
8
|
+
*
|
|
9
|
+
* Per the Mule HTTP connector XSD, `maxConnections` and `connectionIdleTimeout`
|
|
10
|
+
* are valid on BOTH `<http:request-config>` (older style) and on the nested
|
|
11
|
+
* `<http:request-connection>` child element (current XSD-correct placement).
|
|
12
|
+
* The rule must accept either location to avoid false positives.
|
|
8
13
|
*/
|
|
9
14
|
export declare class ConnectionPoolingRule extends BaseRule {
|
|
10
15
|
id: string;
|