@sfdxy/mule-lint 1.20.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 +63 -17
- 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 +22 -0
- package/dist/src/engine/LintEngine.d.ts.map +1 -1
- package/dist/src/engine/LintEngine.js +105 -18
- 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 +11 -4
- package/dist/src/rules/dataweave/DataWeaveRules.d.ts.map +1 -1
- package/dist/src/rules/dataweave/DataWeaveRules.js +20 -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/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 +14 -15
- package/dist/src/rules/error-handling/GlobalErrorHandlerRule.d.ts.map +1 -1
- package/dist/src/rules/error-handling/GlobalErrorHandlerRule.js +59 -38
- package/dist/src/rules/error-handling/GlobalErrorHandlerRule.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/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 +20 -0
- package/dist/src/rules/operations/UnusedFlowRule.d.ts.map +1 -1
- package/dist/src/rules/operations/UnusedFlowRule.js +73 -7
- 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/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 +7 -4
- package/dist/src/rules/performance/ReconnectionStrategyRule.d.ts.map +1 -1
- package/dist/src/rules/performance/ReconnectionStrategyRule.js +44 -24
- 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/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 +13 -0
- package/dist/src/types/Rule.d.ts.map +1 -1
- package/docs/best-practices/rules-catalog.md +337 -29
- package/docs/linter/architecture.md +119 -64
- package/package.json +1 -1
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ApikitMainFlowStructureRule = void 0;
|
|
4
|
+
const BaseRule_1 = require("../base/BaseRule");
|
|
5
|
+
/**
|
|
6
|
+
* API-006: APIKit Main Flow Structure
|
|
7
|
+
*
|
|
8
|
+
* The main flow in an APIKit project should follow the standard pattern:
|
|
9
|
+
* <http:listener> → <apikit:router>
|
|
10
|
+
*
|
|
11
|
+
* The main flow should not contain business logic — it should only
|
|
12
|
+
* receive requests and delegate to APIKit-generated implementation flows.
|
|
13
|
+
* This is the pattern used in all accelerator projects.
|
|
14
|
+
*/
|
|
15
|
+
class ApikitMainFlowStructureRule extends BaseRule_1.BaseRule {
|
|
16
|
+
id = 'API-006';
|
|
17
|
+
name = 'APIKit Main Flow Structure';
|
|
18
|
+
description = 'APIKit main flow should contain only listener and router, no business logic';
|
|
19
|
+
severity = 'warning';
|
|
20
|
+
category = 'api-led';
|
|
21
|
+
issueType = 'code-smell';
|
|
22
|
+
/** Max number of direct child elements (excluding error-handler) allowed in main flow */
|
|
23
|
+
MAX_MAIN_FLOW_CHILDREN = 4;
|
|
24
|
+
validate(doc, _context) {
|
|
25
|
+
const issues = [];
|
|
26
|
+
// Find flows that look like APIKit main flows
|
|
27
|
+
const flows = this.select('//mule:flow', doc);
|
|
28
|
+
for (const flow of flows) {
|
|
29
|
+
const flowName = this.getAttribute(flow, 'name') ?? '';
|
|
30
|
+
// Detect main flow: typically *-main or contains apikit:router
|
|
31
|
+
const hasRouter = this.exists('.//*[local-name()="router"]', flow);
|
|
32
|
+
if (!hasRouter) {
|
|
33
|
+
continue; // Not an APIKit main flow
|
|
34
|
+
}
|
|
35
|
+
const isMainFlow = flowName.endsWith('-main') ||
|
|
36
|
+
flowName.includes('-api-main') ||
|
|
37
|
+
flowName.includes('api-main');
|
|
38
|
+
if (!isMainFlow && !hasRouter) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
// Count child elements (excluding error-handler and comments)
|
|
42
|
+
const children = this.select('./*[not(local-name()="error-handler") and not(local-name()="description")]', flow);
|
|
43
|
+
if (children.length > this.MAX_MAIN_FLOW_CHILDREN) {
|
|
44
|
+
issues.push(this.createIssue(flow, `APIKit main flow "${flowName}" has ${children.length} operations — should contain only listener and router`, {
|
|
45
|
+
suggestion: 'Move business logic to APIKit implementation flows (e.g., get:\\resource:config). The main flow should only receive and route.',
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return issues;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.ApikitMainFlowStructureRule = ApikitMainFlowStructureRule;
|
|
53
|
+
//# sourceMappingURL=ApikitMainFlowStructureRule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApikitMainFlowStructureRule.js","sourceRoot":"","sources":["../../../../src/rules/api-led/ApikitMainFlowStructureRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;;;;;GASG;AACH,MAAa,2BAA4B,SAAQ,mBAAQ;IACvD,EAAE,GAAG,SAAS,CAAC;IACf,IAAI,GAAG,4BAA4B,CAAC;IACpC,WAAW,GAAG,6EAA6E,CAAC;IAC5F,QAAQ,GAAG,SAAkB,CAAC;IAC9B,QAAQ,GAAG,SAAkB,CAAC;IAC9B,SAAS,GAAc,YAAY,CAAC;IAEpC,yFAAyF;IACxE,sBAAsB,GAAG,CAAC,CAAC;IAE5C,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,8CAA8C;QAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QAE9C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;YAEvD,+DAA+D;YAC/D,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,6BAA6B,EAAE,IAAI,CAAC,CAAC;YAEnE,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,SAAS,CAAC,0BAA0B;YACtC,CAAC;YAED,MAAM,UAAU,GACd,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAC1B,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC;gBAC9B,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;YAEhC,IAAI,CAAC,UAAU,IAAI,CAAC,SAAS,EAAE,CAAC;gBAC9B,SAAS;YACX,CAAC;YAED,8DAA8D;YAC9D,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAC1B,4EAA4E,EAC5E,IAAgB,CACjB,CAAC;YAEF,IAAI,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,sBAAsB,EAAE,CAAC;gBAClD,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,IAAI,EACJ,qBAAqB,QAAQ,SAAS,QAAQ,CAAC,MAAM,uDAAuD,EAC5G;oBACE,UAAU,EACR,gIAAgI;iBACnI,CACF,CACF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AA1DD,kEA0DC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ValidationContext, Issue, IssueType } from '../../types';
|
|
2
|
+
import { BaseRule } from '../base/BaseRule';
|
|
3
|
+
/**
|
|
4
|
+
* API-007: APIKit httpStatus Variable
|
|
5
|
+
*
|
|
6
|
+
* APIKit implementation flows should set the httpStatus variable so the
|
|
7
|
+
* HTTP listener can return the correct status code. The accelerator
|
|
8
|
+
* pattern uses ee:set-variable with variableName="httpStatus" in both
|
|
9
|
+
* success paths and error handlers.
|
|
10
|
+
*
|
|
11
|
+
* Common values: 200 (GET), 201 (POST/create), 204 (DELETE/no content)
|
|
12
|
+
*/
|
|
13
|
+
export declare class ApikitStatusCodeVariableRule extends BaseRule {
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
description: string;
|
|
17
|
+
severity: "info";
|
|
18
|
+
category: "api-led";
|
|
19
|
+
issueType: IssueType;
|
|
20
|
+
/** Pattern that matches APIKit-generated flow names like get:\resource:config */
|
|
21
|
+
private readonly APIKIT_FLOW_PATTERN;
|
|
22
|
+
validate(doc: Document, _context: ValidationContext): Issue[];
|
|
23
|
+
private getExpectedStatusCode;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=ApikitStatusCodeVariableRule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApikitStatusCodeVariableRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/api-led/ApikitStatusCodeVariableRule.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,4BAA6B,SAAQ,QAAQ;IACxD,EAAE,SAAa;IACf,IAAI,SAAiC;IACrC,WAAW,SAC+E;IAC1F,QAAQ,EAAG,MAAM,CAAU;IAC3B,QAAQ,EAAG,SAAS,CAAU;IAC9B,SAAS,EAAE,SAAS,CAAgB;IAEpC,iFAAiF;IACjF,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAkD;IAEtF,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;IAkC7D,OAAO,CAAC,qBAAqB;CAU9B"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ApikitStatusCodeVariableRule = void 0;
|
|
4
|
+
const BaseRule_1 = require("../base/BaseRule");
|
|
5
|
+
/**
|
|
6
|
+
* API-007: APIKit httpStatus Variable
|
|
7
|
+
*
|
|
8
|
+
* APIKit implementation flows should set the httpStatus variable so the
|
|
9
|
+
* HTTP listener can return the correct status code. The accelerator
|
|
10
|
+
* pattern uses ee:set-variable with variableName="httpStatus" in both
|
|
11
|
+
* success paths and error handlers.
|
|
12
|
+
*
|
|
13
|
+
* Common values: 200 (GET), 201 (POST/create), 204 (DELETE/no content)
|
|
14
|
+
*/
|
|
15
|
+
class ApikitStatusCodeVariableRule extends BaseRule_1.BaseRule {
|
|
16
|
+
id = 'API-007';
|
|
17
|
+
name = 'APIKit Status Code Variable';
|
|
18
|
+
description = 'APIKit implementation flows should set httpStatus variable for correct response codes';
|
|
19
|
+
severity = 'info';
|
|
20
|
+
category = 'api-led';
|
|
21
|
+
issueType = 'code-smell';
|
|
22
|
+
/** Pattern that matches APIKit-generated flow names like get:\resource:config */
|
|
23
|
+
APIKIT_FLOW_PATTERN = /^(get|post|put|patch|delete|head|options):\\/;
|
|
24
|
+
validate(doc, _context) {
|
|
25
|
+
const issues = [];
|
|
26
|
+
const flows = this.select('//mule:flow', doc);
|
|
27
|
+
for (const flow of flows) {
|
|
28
|
+
const flowName = this.getAttribute(flow, 'name') ?? '';
|
|
29
|
+
// Only check APIKit implementation flows
|
|
30
|
+
if (!this.APIKIT_FLOW_PATTERN.test(flowName)) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
// Check if httpStatus is set anywhere in the flow
|
|
34
|
+
const setsHttpStatus = this.exists('.//*[local-name()="set-variable" and @variableName="httpStatus"]', flow) ||
|
|
35
|
+
this.exists('.//*[local-name()="set-variable" and @variableName="httpStatus"]', flow);
|
|
36
|
+
if (!setsHttpStatus) {
|
|
37
|
+
// Determine expected status code from HTTP method
|
|
38
|
+
const method = flowName.split(':')[0].toUpperCase();
|
|
39
|
+
const expectedCode = this.getExpectedStatusCode(method);
|
|
40
|
+
issues.push(this.createIssue(flow, `APIKit flow "${flowName}" does not set httpStatus variable`, {
|
|
41
|
+
suggestion: `Add <set-variable variableName="httpStatus" value="${expectedCode}"/> for ${method} operations`,
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return issues;
|
|
46
|
+
}
|
|
47
|
+
getExpectedStatusCode(method) {
|
|
48
|
+
switch (method) {
|
|
49
|
+
case 'POST':
|
|
50
|
+
return '201';
|
|
51
|
+
case 'DELETE':
|
|
52
|
+
return '204';
|
|
53
|
+
default:
|
|
54
|
+
return '200';
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.ApikitStatusCodeVariableRule = ApikitStatusCodeVariableRule;
|
|
59
|
+
//# sourceMappingURL=ApikitStatusCodeVariableRule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApikitStatusCodeVariableRule.js","sourceRoot":"","sources":["../../../../src/rules/api-led/ApikitStatusCodeVariableRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;;;;;GASG;AACH,MAAa,4BAA6B,SAAQ,mBAAQ;IACxD,EAAE,GAAG,SAAS,CAAC;IACf,IAAI,GAAG,6BAA6B,CAAC;IACrC,WAAW,GACT,uFAAuF,CAAC;IAC1F,QAAQ,GAAG,MAAe,CAAC;IAC3B,QAAQ,GAAG,SAAkB,CAAC;IAC9B,SAAS,GAAc,YAAY,CAAC;IAEpC,iFAAiF;IAChE,mBAAmB,GAAG,8CAA8C,CAAC;IAEtF,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QAE9C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;YAEvD,yCAAyC;YACzC,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC7C,SAAS;YACX,CAAC;YAED,kDAAkD;YAClD,MAAM,cAAc,GAClB,IAAI,CAAC,MAAM,CAAC,kEAAkE,EAAE,IAAI,CAAC;gBACrF,IAAI,CAAC,MAAM,CAAC,kEAAkE,EAAE,IAAI,CAAC,CAAC;YAExF,IAAI,CAAC,cAAc,EAAE,CAAC;gBACpB,kDAAkD;gBAClD,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;gBACpD,MAAM,YAAY,GAAG,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC;gBAExD,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,gBAAgB,QAAQ,oCAAoC,EAAE;oBACnF,UAAU,EAAE,sDAAsD,YAAY,WAAW,MAAM,aAAa;iBAC7G,CAAC,CACH,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,qBAAqB,CAAC,MAAc;QAC1C,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,MAAM;gBACT,OAAO,KAAK,CAAC;YACf,KAAK,QAAQ;gBACX,OAAO,KAAK,CAAC;YACf;gBACE,OAAO,KAAK,CAAC;QACjB,CAAC;IACH,CAAC;CACF;AAxDD,oEAwDC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ValidationContext, Issue, IssueType } from '../../types';
|
|
2
|
+
import { BaseRule } from '../base/BaseRule';
|
|
3
|
+
/**
|
|
4
|
+
* SF-002: Event Listener Null Guard
|
|
5
|
+
*
|
|
6
|
+
* Salesforce CDC (Change Data Capture) and Platform Event listeners receive
|
|
7
|
+
* events where fields can be null (e.g., unchanged fields in CDC events
|
|
8
|
+
* come through as null). Flows processing these events should include
|
|
9
|
+
* null-safety checks to avoid NullPointerExceptions.
|
|
10
|
+
*
|
|
11
|
+
* This rule flags flows with Salesforce event listeners (subscribe-channel,
|
|
12
|
+
* replay-channel) that contain DataWeave transforms accessing payload fields
|
|
13
|
+
* without null-safety operators (?., default, !isEmpty, etc.).
|
|
14
|
+
*/
|
|
15
|
+
export declare class EventListenerNullGuardRule extends BaseRule {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
description: string;
|
|
19
|
+
severity: "info";
|
|
20
|
+
category: "operations";
|
|
21
|
+
issueType: IssueType;
|
|
22
|
+
validate(doc: Document, _context: ValidationContext): Issue[];
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=EventListenerNullGuardRule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventListenerNullGuardRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/connector/EventListenerNullGuardRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;;;GAWG;AACH,qBAAa,0BAA2B,SAAQ,QAAQ;IACtD,EAAE,SAAY;IACd,IAAI,SAA+B;IACnC,WAAW,SAC4F;IACvG,QAAQ,EAAG,MAAM,CAAU;IAC3B,QAAQ,EAAG,YAAY,CAAU;IACjC,SAAS,EAAE,SAAS,CAAS;IAE7B,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;CAoD9D"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EventListenerNullGuardRule = void 0;
|
|
4
|
+
const BaseRule_1 = require("../base/BaseRule");
|
|
5
|
+
/**
|
|
6
|
+
* SF-002: Event Listener Null Guard
|
|
7
|
+
*
|
|
8
|
+
* Salesforce CDC (Change Data Capture) and Platform Event listeners receive
|
|
9
|
+
* events where fields can be null (e.g., unchanged fields in CDC events
|
|
10
|
+
* come through as null). Flows processing these events should include
|
|
11
|
+
* null-safety checks to avoid NullPointerExceptions.
|
|
12
|
+
*
|
|
13
|
+
* This rule flags flows with Salesforce event listeners (subscribe-channel,
|
|
14
|
+
* replay-channel) that contain DataWeave transforms accessing payload fields
|
|
15
|
+
* without null-safety operators (?., default, !isEmpty, etc.).
|
|
16
|
+
*/
|
|
17
|
+
class EventListenerNullGuardRule extends BaseRule_1.BaseRule {
|
|
18
|
+
id = 'SF-002';
|
|
19
|
+
name = 'Event Listener Null Guard';
|
|
20
|
+
description = 'Salesforce CDC/Platform Event listeners should include null-safety checks for event payload fields';
|
|
21
|
+
severity = 'info';
|
|
22
|
+
category = 'operations';
|
|
23
|
+
issueType = 'bug';
|
|
24
|
+
validate(doc, _context) {
|
|
25
|
+
const issues = [];
|
|
26
|
+
const flows = this.select('//mule:flow', doc);
|
|
27
|
+
for (const flow of flows) {
|
|
28
|
+
const flowName = this.getAttribute(flow, 'name') ?? '';
|
|
29
|
+
// Check if this flow has a Salesforce event source (CDC or Platform Event)
|
|
30
|
+
const hasSfListener = this.exists('.//*[local-name()="subscribe-channel" or local-name()="replay-channel" or local-name()="subscribe-topic" or local-name()="replay-topic"]', flow);
|
|
31
|
+
if (!hasSfListener) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
// Find DataWeave transforms in this flow
|
|
35
|
+
const transforms = this.select('.//*[local-name()="transform"]', flow);
|
|
36
|
+
for (const transform of transforms) {
|
|
37
|
+
const transformText = transform.textContent ?? '';
|
|
38
|
+
// Check if the transform accesses payload fields directly without null guards
|
|
39
|
+
// Look for patterns like: payload.fieldName (without ?.)
|
|
40
|
+
const hasDirectAccess = /payload\.\w+/.test(transformText);
|
|
41
|
+
const hasNullSafety = /payload\?\.\w+/.test(transformText) ||
|
|
42
|
+
/default\s/.test(transformText) ||
|
|
43
|
+
/isEmpty/.test(transformText) ||
|
|
44
|
+
/if\s*\(/.test(transformText) ||
|
|
45
|
+
/unless/.test(transformText) ||
|
|
46
|
+
/payload\s+default/.test(transformText);
|
|
47
|
+
if (hasDirectAccess && !hasNullSafety) {
|
|
48
|
+
issues.push(this.createIssue(transform, `DataWeave transform in CDC/event flow "${flowName}" accesses payload fields without null-safety checks`, {
|
|
49
|
+
suggestion: 'Use null-safe navigation (payload?.field), default operators, or isEmpty checks when processing CDC event payloads — unchanged fields arrive as null',
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return issues;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.EventListenerNullGuardRule = EventListenerNullGuardRule;
|
|
58
|
+
//# sourceMappingURL=EventListenerNullGuardRule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventListenerNullGuardRule.js","sourceRoot":"","sources":["../../../../src/rules/connector/EventListenerNullGuardRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;;;;;;;GAWG;AACH,MAAa,0BAA2B,SAAQ,mBAAQ;IACtD,EAAE,GAAG,QAAQ,CAAC;IACd,IAAI,GAAG,2BAA2B,CAAC;IACnC,WAAW,GACT,oGAAoG,CAAC;IACvG,QAAQ,GAAG,MAAe,CAAC;IAC3B,QAAQ,GAAG,YAAqB,CAAC;IACjC,SAAS,GAAc,KAAK,CAAC;IAE7B,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QAE9C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;YAEvD,2EAA2E;YAC3E,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAC/B,0IAA0I,EAC1I,IAAI,CACL,CAAC;YAEF,IAAI,CAAC,aAAa,EAAE,CAAC;gBACnB,SAAS;YACX,CAAC;YAED,yCAAyC;YACzC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,gCAAgC,EAAE,IAAI,CAAC,CAAC;YAEvE,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;gBACnC,MAAM,aAAa,GAAG,SAAS,CAAC,WAAW,IAAI,EAAE,CAAC;gBAElD,8EAA8E;gBAC9E,yDAAyD;gBACzD,MAAM,eAAe,GAAG,cAAc,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;gBAC3D,MAAM,aAAa,GACjB,gBAAgB,CAAC,IAAI,CAAC,aAAa,CAAC;oBACpC,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC;oBAC/B,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC;oBAC7B,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC;oBAC7B,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC;oBAC5B,mBAAmB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;gBAE1C,IAAI,eAAe,IAAI,CAAC,aAAa,EAAE,CAAC;oBACtC,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,SAAS,EACT,0CAA0C,QAAQ,sDAAsD,EACxG;wBACE,UAAU,EACR,sJAAsJ;qBACzJ,CACF,CACF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AA7DD,gEA6DC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ValidationContext, Issue, IssueType } from '../../types';
|
|
2
|
+
import { BaseRule } from '../base/BaseRule';
|
|
3
|
+
/**
|
|
4
|
+
* SF-001: Salesforce Replay Channel Config
|
|
5
|
+
*
|
|
6
|
+
* Salesforce CDC (Change Data Capture) and Platform Event listeners should
|
|
7
|
+
* configure replay channel settings for message reliability. Without proper
|
|
8
|
+
* replay configuration, events can be lost if the application is restarted
|
|
9
|
+
* or temporarily disconnected.
|
|
10
|
+
*
|
|
11
|
+
* Looks for salesforce:replay-channel or similar replay configurations
|
|
12
|
+
* on Salesforce subscriber/listener elements.
|
|
13
|
+
*/
|
|
14
|
+
export declare class ReplayChannelConfigRule extends BaseRule {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
severity: "warning";
|
|
19
|
+
category: "operations";
|
|
20
|
+
issueType: IssueType;
|
|
21
|
+
validate(doc: Document, _context: ValidationContext): Issue[];
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=ReplayChannelConfigRule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReplayChannelConfigRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/connector/ReplayChannelConfigRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;;GAUG;AACH,qBAAa,uBAAwB,SAAQ,QAAQ;IACnD,EAAE,SAAY;IACd,IAAI,SAAsC;IAC1C,WAAW,SACiF;IAC5F,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,YAAY,CAAU;IACjC,SAAS,EAAE,SAAS,CAAS;IAE7B,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;CAmD9D"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ReplayChannelConfigRule = void 0;
|
|
4
|
+
const BaseRule_1 = require("../base/BaseRule");
|
|
5
|
+
/**
|
|
6
|
+
* SF-001: Salesforce Replay Channel Config
|
|
7
|
+
*
|
|
8
|
+
* Salesforce CDC (Change Data Capture) and Platform Event listeners should
|
|
9
|
+
* configure replay channel settings for message reliability. Without proper
|
|
10
|
+
* replay configuration, events can be lost if the application is restarted
|
|
11
|
+
* or temporarily disconnected.
|
|
12
|
+
*
|
|
13
|
+
* Looks for salesforce:replay-channel or similar replay configurations
|
|
14
|
+
* on Salesforce subscriber/listener elements.
|
|
15
|
+
*/
|
|
16
|
+
class ReplayChannelConfigRule extends BaseRule_1.BaseRule {
|
|
17
|
+
id = 'SF-001';
|
|
18
|
+
name = 'Salesforce Replay Channel Config';
|
|
19
|
+
description = 'Salesforce CDC/Platform Event listeners should configure replay channel for reliability';
|
|
20
|
+
severity = 'warning';
|
|
21
|
+
category = 'operations';
|
|
22
|
+
issueType = 'bug';
|
|
23
|
+
validate(doc, _context) {
|
|
24
|
+
const issues = [];
|
|
25
|
+
// Find Salesforce subscribe elements (CDC/Platform Events)
|
|
26
|
+
const subscribers = [
|
|
27
|
+
...this.select('//*[local-name()="subscribe-channel" or local-name()="subscribe-topic"]', doc),
|
|
28
|
+
...this.select('//*[local-name()="replay-channel" or local-name()="replay-topic"]', doc),
|
|
29
|
+
];
|
|
30
|
+
// If we find replay-channel/replay-topic, that means replay IS configured — good
|
|
31
|
+
const hasReplayConfig = this.exists('//*[local-name()="replay-channel" or local-name()="replay-topic"]', doc);
|
|
32
|
+
// Find plain subscribe elements without replay
|
|
33
|
+
const plainSubscribers = this.select('//*[local-name()="subscribe-channel" or local-name()="subscribe-topic"]', doc);
|
|
34
|
+
if (plainSubscribers.length > 0 && !hasReplayConfig) {
|
|
35
|
+
for (const sub of plainSubscribers) {
|
|
36
|
+
const streamingChannel = this.getAttribute(sub, 'streamingChannel') ??
|
|
37
|
+
this.getAttribute(sub, 'channel') ??
|
|
38
|
+
'unknown';
|
|
39
|
+
issues.push(this.createIssue(sub, `Salesforce subscriber for "${streamingChannel}" has no replay channel configuration`, {
|
|
40
|
+
suggestion: 'Use salesforce:replay-channel instead of subscribe-channel, or configure Object Store-backed replay for CDC/Platform Event reliability',
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Also check for replay-channel that might be missing resumeFromLastReplay
|
|
45
|
+
if (subscribers.length === 0) {
|
|
46
|
+
return issues; // No Salesforce streaming elements in this file
|
|
47
|
+
}
|
|
48
|
+
return issues;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.ReplayChannelConfigRule = ReplayChannelConfigRule;
|
|
52
|
+
//# sourceMappingURL=ReplayChannelConfigRule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReplayChannelConfigRule.js","sourceRoot":"","sources":["../../../../src/rules/connector/ReplayChannelConfigRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;;;;;;GAUG;AACH,MAAa,uBAAwB,SAAQ,mBAAQ;IACnD,EAAE,GAAG,QAAQ,CAAC;IACd,IAAI,GAAG,kCAAkC,CAAC;IAC1C,WAAW,GACT,yFAAyF,CAAC;IAC5F,QAAQ,GAAG,SAAkB,CAAC;IAC9B,QAAQ,GAAG,YAAqB,CAAC;IACjC,SAAS,GAAc,KAAK,CAAC;IAE7B,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,2DAA2D;QAC3D,MAAM,WAAW,GAAG;YAClB,GAAG,IAAI,CAAC,MAAM,CACZ,yEAAyE,EACzE,GAAG,CACJ;YACD,GAAG,IAAI,CAAC,MAAM,CAAC,mEAAmE,EAAE,GAAG,CAAC;SACzF,CAAC;QAEF,iFAAiF;QACjF,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,CACjC,mEAAmE,EACnE,GAAG,CACJ,CAAC;QAEF,+CAA+C;QAC/C,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAClC,yEAAyE,EACzE,GAAG,CACJ,CAAC;QAEF,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;YACpD,KAAK,MAAM,GAAG,IAAI,gBAAgB,EAAE,CAAC;gBACnC,MAAM,gBAAgB,GACpB,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,kBAAkB,CAAC;oBAC1C,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,SAAS,CAAC;oBACjC,SAAS,CAAC;gBAEZ,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,GAAG,EACH,8BAA8B,gBAAgB,uCAAuC,EACrF;oBACE,UAAU,EACR,wIAAwI;iBAC3I,CACF,CACF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,2EAA2E;QAC3E,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,MAAM,CAAC,CAAC,gDAAgD;QACjE,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AA5DD,0DA4DC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ValidationContext, Issue } from '../../types';
|
|
2
2
|
import { BaseRule } from '../base/BaseRule';
|
|
3
|
+
import { ProjectRule } from '../base/ProjectRule';
|
|
3
4
|
/**
|
|
4
5
|
* DW-001: External DWL for Complex Transforms
|
|
5
6
|
*
|
|
@@ -24,14 +25,17 @@ export declare class ExternalDwlRule extends BaseRule {
|
|
|
24
25
|
* exactly match the filename, and hyphens are not valid in DataWeave identifiers.
|
|
25
26
|
* Use the `exemptPaths` option to exclude module directories from this rule, or
|
|
26
27
|
* set `convention: "camelCase"` for projects that use DW modules extensively.
|
|
28
|
+
*
|
|
29
|
+
* This is a ProjectRule — it runs once per scan to avoid producing
|
|
30
|
+
* N identical issues (one per XML file).
|
|
27
31
|
*/
|
|
28
|
-
export declare class DwlNamingRule extends
|
|
32
|
+
export declare class DwlNamingRule extends ProjectRule {
|
|
29
33
|
id: string;
|
|
30
34
|
name: string;
|
|
31
35
|
description: string;
|
|
32
36
|
severity: "info";
|
|
33
37
|
category: "dataweave";
|
|
34
|
-
|
|
38
|
+
protected validateProject(context: ValidationContext): Issue[];
|
|
35
39
|
private isValidDwlName;
|
|
36
40
|
/**
|
|
37
41
|
* Convert a filename to the target convention
|
|
@@ -43,14 +47,17 @@ export declare class DwlNamingRule extends BaseRule {
|
|
|
43
47
|
* DW-003: DWL Modules Usage
|
|
44
48
|
*
|
|
45
49
|
* Common DataWeave functions should be in reusable modules.
|
|
50
|
+
*
|
|
51
|
+
* This is a ProjectRule — it runs once per scan to avoid producing
|
|
52
|
+
* N identical issues (one per XML file).
|
|
46
53
|
*/
|
|
47
|
-
export declare class DwlModulesRule extends
|
|
54
|
+
export declare class DwlModulesRule extends ProjectRule {
|
|
48
55
|
id: string;
|
|
49
56
|
name: string;
|
|
50
57
|
description: string;
|
|
51
58
|
severity: "info";
|
|
52
59
|
category: "dataweave";
|
|
53
|
-
|
|
60
|
+
protected validateProject(context: ValidationContext): Issue[];
|
|
54
61
|
private hasFile;
|
|
55
62
|
}
|
|
56
63
|
//# sourceMappingURL=DataWeaveRules.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataWeaveRules.d.ts","sourceRoot":"","sources":["../../../../src/rules/dataweave/DataWeaveRules.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"DataWeaveRules.d.ts","sourceRoot":"","sources":["../../../../src/rules/dataweave/DataWeaveRules.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD;;;;GAIG;AACH,qBAAa,eAAgB,SAAQ,QAAQ;IAC3C,EAAE,SAAY;IACd,IAAI,SAAyC;IAC7C,WAAW,SAA4D;IACvE,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,WAAW,CAAU;IAEhC,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,GAAG,KAAK,EAAE;CA+B7D;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,aAAc,SAAQ,WAAW;IAC5C,EAAE,SAAY;IACd,IAAI,SAAqB;IACzB,WAAW,SAC8E;IACzF,QAAQ,EAAG,MAAM,CAAU;IAC3B,QAAQ,EAAG,WAAW,CAAU;IAEhC,SAAS,CAAC,eAAe,CAAC,OAAO,EAAE,iBAAiB,GAAG,KAAK,EAAE;IA8C9D,OAAO,CAAC,cAAc;IAStB;;OAEG;IACH,OAAO,CAAC,YAAY;IAiBpB,OAAO,CAAC,YAAY;CAiBrB;AAED;;;;;;;GAOG;AACH,qBAAa,cAAe,SAAQ,WAAW;IAC7C,EAAE,SAAY;IACd,IAAI,SAAiB;IACrB,WAAW,SAAkD;IAC7D,QAAQ,EAAG,MAAM,CAAU;IAC3B,QAAQ,EAAG,WAAW,CAAU;IAEhC,SAAS,CAAC,eAAe,CAAC,OAAO,EAAE,iBAAiB,GAAG,KAAK,EAAE;IAqB9D,OAAO,CAAC,OAAO;CAQhB"}
|
|
@@ -37,6 +37,7 @@ exports.DwlModulesRule = exports.DwlNamingRule = exports.ExternalDwlRule = void
|
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
39
|
const BaseRule_1 = require("../base/BaseRule");
|
|
40
|
+
const ProjectRule_1 = require("../base/ProjectRule");
|
|
40
41
|
/**
|
|
41
42
|
* DW-001: External DWL for Complex Transforms
|
|
42
43
|
*
|
|
@@ -81,14 +82,17 @@ exports.ExternalDwlRule = ExternalDwlRule;
|
|
|
81
82
|
* exactly match the filename, and hyphens are not valid in DataWeave identifiers.
|
|
82
83
|
* Use the `exemptPaths` option to exclude module directories from this rule, or
|
|
83
84
|
* set `convention: "camelCase"` for projects that use DW modules extensively.
|
|
85
|
+
*
|
|
86
|
+
* This is a ProjectRule — it runs once per scan to avoid producing
|
|
87
|
+
* N identical issues (one per XML file).
|
|
84
88
|
*/
|
|
85
|
-
class DwlNamingRule extends
|
|
89
|
+
class DwlNamingRule extends ProjectRule_1.ProjectRule {
|
|
86
90
|
id = 'DW-002';
|
|
87
91
|
name = 'DWL File Naming';
|
|
88
92
|
description = 'DataWeave files should follow consistent naming conventions (kebab-case recommended)';
|
|
89
93
|
severity = 'info';
|
|
90
94
|
category = 'dataweave';
|
|
91
|
-
|
|
95
|
+
validateProject(context) {
|
|
92
96
|
const issues = [];
|
|
93
97
|
const dwlDir = path.join(context.projectRoot, 'src/main/resources/dwl');
|
|
94
98
|
if (!fs.existsSync(dwlDir)) {
|
|
@@ -115,13 +119,9 @@ class DwlNamingRule extends BaseRule_1.BaseRule {
|
|
|
115
119
|
}
|
|
116
120
|
if (!this.isValidDwlName(basename, convention)) {
|
|
117
121
|
const suggestedName = this.toConvention(basename, convention);
|
|
118
|
-
issues.push({
|
|
119
|
-
line: 1,
|
|
120
|
-
message: `DWL file "${basename}.dwl" should use ${convention} naming`,
|
|
121
|
-
ruleId: this.id,
|
|
122
|
-
severity: this.severity,
|
|
122
|
+
issues.push(this.createProjectIssue(`DWL file "${basename}.dwl" should use ${convention} naming`, {
|
|
123
123
|
suggestion: `Rename to: ${suggestedName}.dwl`,
|
|
124
|
-
});
|
|
124
|
+
}));
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
return issues;
|
|
@@ -176,31 +176,31 @@ exports.DwlNamingRule = DwlNamingRule;
|
|
|
176
176
|
* DW-003: DWL Modules Usage
|
|
177
177
|
*
|
|
178
178
|
* Common DataWeave functions should be in reusable modules.
|
|
179
|
+
*
|
|
180
|
+
* This is a ProjectRule — it runs once per scan to avoid producing
|
|
181
|
+
* N identical issues (one per XML file).
|
|
179
182
|
*/
|
|
180
|
-
class DwlModulesRule extends
|
|
183
|
+
class DwlModulesRule extends ProjectRule_1.ProjectRule {
|
|
181
184
|
id = 'DW-003';
|
|
182
185
|
name = 'DWL Modules';
|
|
183
186
|
description = 'Project should have common DataWeave modules';
|
|
184
187
|
severity = 'info';
|
|
185
188
|
category = 'dataweave';
|
|
186
|
-
|
|
187
|
-
const issues = [];
|
|
189
|
+
validateProject(context) {
|
|
188
190
|
const dwlDir = path.join(context.projectRoot, 'src/main/resources/dwl');
|
|
189
191
|
if (!fs.existsSync(dwlDir)) {
|
|
190
|
-
return
|
|
192
|
+
return [];
|
|
191
193
|
}
|
|
192
194
|
const hasCommonModule = this.hasFile(dwlDir, 'common');
|
|
193
195
|
const hasUtilsModule = this.hasFile(dwlDir, 'utils');
|
|
194
196
|
if (!hasCommonModule && !hasUtilsModule) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
suggestion: 'Create common.dwl or utils.dwl for reusable functions',
|
|
201
|
-
});
|
|
197
|
+
return [
|
|
198
|
+
this.createProjectIssue('No common/utils DWL module found', {
|
|
199
|
+
suggestion: 'Create common.dwl or utils.dwl for reusable functions',
|
|
200
|
+
}),
|
|
201
|
+
];
|
|
202
202
|
}
|
|
203
|
-
return
|
|
203
|
+
return [];
|
|
204
204
|
}
|
|
205
205
|
hasFile(dir, pattern) {
|
|
206
206
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataWeaveRules.js","sourceRoot":"","sources":["../../../../src/rules/dataweave/DataWeaveRules.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,2CAA6B;AAE7B,+CAA4C;
|
|
1
|
+
{"version":3,"file":"DataWeaveRules.js","sourceRoot":"","sources":["../../../../src/rules/dataweave/DataWeaveRules.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ValidationContext, Issue, IssueType } from '../../types';
|
|
2
|
+
import { BaseRule } from '../base/BaseRule';
|
|
3
|
+
/**
|
|
4
|
+
* DW-005: Duplicate Transform Logic
|
|
5
|
+
*
|
|
6
|
+
* Flags flows that contain multiple DataWeave transform-message blocks
|
|
7
|
+
* with identical or near-identical body content. Duplicated transforms
|
|
8
|
+
* should be extracted into reusable .dwl modules under src/main/resources/dw/.
|
|
9
|
+
*
|
|
10
|
+
* This rule checks for duplicate ee:transform → ee:message → ee:set-payload
|
|
11
|
+
* content within the same file. It compares the text content of set-payload
|
|
12
|
+
* elements and flags exact duplicates.
|
|
13
|
+
*/
|
|
14
|
+
export declare class DuplicateTransformLogicRule extends BaseRule {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
severity: "info";
|
|
19
|
+
category: "dataweave";
|
|
20
|
+
issueType: IssueType;
|
|
21
|
+
/** Minimum length of transform content to consider for duplication check */
|
|
22
|
+
private readonly MIN_CONTENT_LENGTH;
|
|
23
|
+
validate(doc: Document, _context: ValidationContext): Issue[];
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=DuplicateTransformLogicRule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DuplicateTransformLogicRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/dataweave/DuplicateTransformLogicRule.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,2BAA4B,SAAQ,QAAQ;IACvD,EAAE,SAAY;IACd,IAAI,SAA+B;IACnC,WAAW,SAC6E;IACxF,QAAQ,EAAG,MAAM,CAAU;IAC3B,QAAQ,EAAG,WAAW,CAAU;IAChC,SAAS,EAAE,SAAS,CAAgB;IAEpC,4EAA4E;IAC5E,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAM;IAEzC,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;CA0D9D"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DuplicateTransformLogicRule = void 0;
|
|
4
|
+
const BaseRule_1 = require("../base/BaseRule");
|
|
5
|
+
/**
|
|
6
|
+
* DW-005: Duplicate Transform Logic
|
|
7
|
+
*
|
|
8
|
+
* Flags flows that contain multiple DataWeave transform-message blocks
|
|
9
|
+
* with identical or near-identical body content. Duplicated transforms
|
|
10
|
+
* should be extracted into reusable .dwl modules under src/main/resources/dw/.
|
|
11
|
+
*
|
|
12
|
+
* This rule checks for duplicate ee:transform → ee:message → ee:set-payload
|
|
13
|
+
* content within the same file. It compares the text content of set-payload
|
|
14
|
+
* elements and flags exact duplicates.
|
|
15
|
+
*/
|
|
16
|
+
class DuplicateTransformLogicRule extends BaseRule_1.BaseRule {
|
|
17
|
+
id = 'DW-005';
|
|
18
|
+
name = 'Duplicate Transform Logic';
|
|
19
|
+
description = 'Duplicate DataWeave transform blocks should be extracted into reusable .dwl modules';
|
|
20
|
+
severity = 'info';
|
|
21
|
+
category = 'dataweave';
|
|
22
|
+
issueType = 'code-smell';
|
|
23
|
+
/** Minimum length of transform content to consider for duplication check */
|
|
24
|
+
MIN_CONTENT_LENGTH = 20;
|
|
25
|
+
validate(doc, _context) {
|
|
26
|
+
const issues = [];
|
|
27
|
+
// Find all ee:transform → ee:set-payload elements
|
|
28
|
+
const transforms = this.select('//*[local-name()="transform"]/*[local-name()="message"]/*[local-name()="set-payload"]', doc);
|
|
29
|
+
// Also check top-level set-payload in transforms without message wrapper
|
|
30
|
+
const directTransforms = this.select('//*[local-name()="transform"]/*[local-name()="set-payload"]', doc);
|
|
31
|
+
const allPayloads = [...transforms, ...directTransforms];
|
|
32
|
+
// Collect transform content for duplication detection
|
|
33
|
+
const contentMap = new Map();
|
|
34
|
+
for (const payload of allPayloads) {
|
|
35
|
+
const content = (payload.textContent ?? '').trim();
|
|
36
|
+
// Skip short/trivial transforms and resource references
|
|
37
|
+
if (content.length < this.MIN_CONTENT_LENGTH) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (content.startsWith('${') || content.includes('readUrl')) {
|
|
41
|
+
continue; // Already using externalized DWL
|
|
42
|
+
}
|
|
43
|
+
const normalized = content.replace(/\s+/g, ' ');
|
|
44
|
+
const nodes = contentMap.get(normalized) ?? [];
|
|
45
|
+
nodes.push(payload);
|
|
46
|
+
contentMap.set(normalized, nodes);
|
|
47
|
+
}
|
|
48
|
+
// Flag duplicates
|
|
49
|
+
for (const [, nodes] of contentMap) {
|
|
50
|
+
if (nodes.length > 1) {
|
|
51
|
+
// Only flag the second and subsequent occurrences
|
|
52
|
+
for (let i = 1; i < nodes.length; i++) {
|
|
53
|
+
issues.push(this.createIssue(nodes[i], `Duplicate DataWeave transform logic found (${nodes.length} identical blocks in file)`, {
|
|
54
|
+
suggestion: 'Extract the shared DataWeave logic into a reusable .dwl file under src/main/resources/dw/ and reference it with readUrl("classpath://dw/transform.dwl")',
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return issues;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.DuplicateTransformLogicRule = DuplicateTransformLogicRule;
|
|
63
|
+
//# sourceMappingURL=DuplicateTransformLogicRule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DuplicateTransformLogicRule.js","sourceRoot":"","sources":["../../../../src/rules/dataweave/DuplicateTransformLogicRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;;;;;;GAUG;AACH,MAAa,2BAA4B,SAAQ,mBAAQ;IACvD,EAAE,GAAG,QAAQ,CAAC;IACd,IAAI,GAAG,2BAA2B,CAAC;IACnC,WAAW,GACT,qFAAqF,CAAC;IACxF,QAAQ,GAAG,MAAe,CAAC;IAC3B,QAAQ,GAAG,WAAoB,CAAC;IAChC,SAAS,GAAc,YAAY,CAAC;IAEpC,4EAA4E;IAC3D,kBAAkB,GAAG,EAAE,CAAC;IAEzC,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,kDAAkD;QAClD,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAC5B,uFAAuF,EACvF,GAAG,CACJ,CAAC;QAEF,yEAAyE;QACzE,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAClC,6DAA6D,EAC7D,GAAG,CACJ,CAAC;QAEF,MAAM,WAAW,GAAG,CAAC,GAAG,UAAU,EAAE,GAAG,gBAAgB,CAAC,CAAC;QAEzD,sDAAsD;QACtD,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;QAE7C,KAAK,MAAM,OAAO,IAAI,WAAW,EAAE,CAAC;YAClC,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YAEnD,wDAAwD;YACxD,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBAC7C,SAAS;YACX,CAAC;YACD,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC5D,SAAS,CAAC,iCAAiC;YAC7C,CAAC;YAED,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;YAChD,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;YAC/C,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACpB,UAAU,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QACpC,CAAC;QAED,kBAAkB;QAClB,KAAK,MAAM,CAAC,EAAE,KAAK,CAAC,IAAI,UAAU,EAAE,CAAC;YACnC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,kDAAkD;gBAClD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBACtC,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,KAAK,CAAC,CAAC,CAAC,EACR,8CAA8C,KAAK,CAAC,MAAM,4BAA4B,EACtF;wBACE,UAAU,EACR,yJAAyJ;qBAC5J,CACF,CACF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAtED,kEAsEC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ValidationContext, Issue, IssueType } from '../../types';
|
|
2
|
+
import { BaseRule } from '../base/BaseRule';
|
|
3
|
+
/**
|
|
4
|
+
* ERR-004: Catch-All Must Be Last
|
|
5
|
+
*
|
|
6
|
+
* When type="ANY" (or no type attribute — implicit catch-all) is used in
|
|
7
|
+
* an error handler, it must be the last on-error block. Placing a catch-all
|
|
8
|
+
* before specific error types makes those specific handlers unreachable.
|
|
9
|
+
*
|
|
10
|
+
* Real-world pattern from accelerators: type="ANY" is always the final
|
|
11
|
+
* on-error-propagate, typically mapping to HTTP 500.
|
|
12
|
+
*/
|
|
13
|
+
export declare class CatchAllLastRule extends BaseRule {
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
description: string;
|
|
17
|
+
severity: "error";
|
|
18
|
+
category: "error-handling";
|
|
19
|
+
issueType: IssueType;
|
|
20
|
+
private readonly CATCH_ALL_TYPES;
|
|
21
|
+
validate(doc: Document, _context: ValidationContext): Issue[];
|
|
22
|
+
private findParentFlowName;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=CatchAllLastRule.d.ts.map
|