Skip to content

Commit cf29f50

Browse files
authored
Error Handling Improvements (#82)
* implement compiler traversal in unconnected elements * add errormessage on rule failure
1 parent c692d62 commit cf29f50

File tree

7 files changed

+77
-92
lines changed

7 files changed

+77
-92
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "lightning-flow-scanner-core",
3-
"version": "3.9.0",
3+
"version": "3.10.0",
44
"main": "out/**",
55
"types": "index.d.ts",
66
"scripts": {

src/main/libs/Keys.ts

Lines changed: 0 additions & 4 deletions
This file was deleted.

src/main/libs/ScanFlows.ts

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import { GetRuleDefinitions } from './GetRuleDefinitions';
2-
import * as core from '../../main/internals/internals';
3-
4-
export function ScanFlows(flows: core.Flow[], ruleOptions?: core.IRulesConfig): core.ScanResult[] {
1+
import { GetRuleDefinitions } from "./GetRuleDefinitions";
2+
import * as core from "../../main/internals/internals";
53

4+
export function ScanFlows(
5+
flows: core.Flow[],
6+
ruleOptions?: core.IRulesConfig
7+
): core.ScanResult[] {
68
const flowResults: core.ScanResult[] = [];
79

810
let selectedRules: core.IRuleDefinition[] = [];
@@ -17,34 +19,39 @@ export function ScanFlows(flows: core.Flow[], ruleOptions?: core.IRulesConfig):
1719
}
1820

1921
for (const flow of flows) {
20-
21-
try {
22-
const ruleResults: core.RuleResult[] = [];
23-
for (const rule of selectedRules) {
22+
const ruleResults: core.RuleResult[] = [];
23+
for (const rule of selectedRules) {
24+
try {
2425
if (rule.supportedTypes.includes(flow.type[0])) {
25-
try {
26-
let config = undefined;
27-
28-
if (ruleOptions && ruleOptions['rules'] && ruleOptions['rules'][rule.name]) {
29-
config = ruleOptions['rules'][rule.name];
30-
}
31-
const result = (config && Object.keys(config).length > 0) ? rule.execute(flow, config) : rule.execute(flow);
32-
if (result.severity !== rule.severity) {
33-
result.severity = rule.severity;
34-
}
35-
ruleResults.push(result);
36-
} catch (error) {
37-
throw new error("Something went wrong while executing " + rule.name + " in the Flow: '" + flow.name + "'");
26+
let config = undefined;
27+
if (
28+
ruleOptions &&
29+
ruleOptions["rules"] &&
30+
ruleOptions["rules"][rule.name]
31+
) {
32+
config = ruleOptions["rules"][rule.name];
3833
}
34+
const result =
35+
config && Object.keys(config).length > 0
36+
? rule.execute(flow, config)
37+
: rule.execute(flow);
38+
if (result.severity !== rule.severity) {
39+
result.severity = rule.severity;
40+
}
41+
ruleResults.push(result);
3942
} else {
4043
ruleResults.push(new core.RuleResult(rule, []));
4144
}
45+
} catch (error) {
46+
let message =
47+
"Something went wrong while executing " +
48+
rule.name +
49+
" in the Flow: '" +
50+
flow.name;
51+
ruleResults.push(new core.RuleResult(rule, [], message));
4252
}
43-
flowResults.push(new core.ScanResult(flow, ruleResults));
44-
}
45-
catch (error) {
46-
console.log(error.message)
4753
}
54+
flowResults.push(new core.ScanResult(flow, ruleResults));
4855
}
4956

5057
return flowResults;

src/main/models/RuleResult.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ export class RuleResult {
88
public ruleDefinition: IRuleDefinition;
99
public severity: string;
1010
public details: ResultDetails[] = [];
11+
public errorMessage: string;
1112

12-
constructor(info: IRuleDefinition, details: ResultDetails[]) {
13+
constructor(info: IRuleDefinition, details: ResultDetails[], errorMessage?:string) {
1314
this.ruleDefinition = info;
1415
this.ruleName = info.name;
1516
this.severity = info.severity ? info.severity : 'error';
@@ -18,6 +19,9 @@ export class RuleResult {
1819
if(details.length > 0){
1920
this.occurs = true;
2021
}
22+
if(errorMessage){
23+
this.errorMessage = errorMessage;
24+
}
2125
}
2226

2327
}

src/main/rules/UnconnectedElement.ts

Lines changed: 21 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -17,75 +17,35 @@ export class UnconnectedElement extends RuleCommon implements core.IRuleDefiniti
1717

1818
public execute(flow: core.Flow): core.RuleResult {
1919

20+
const connectedElements: Set<string> = new Set<string>();
21+
22+
// Callback function to log connected elements
23+
const logConnected = (element: core.FlowNode) => {
24+
connectedElements.add(element.name);
25+
};
26+
27+
// Get Traversable Nodes
2028
const flowElements: core.FlowNode[] = flow.elements.filter(node => node instanceof core.FlowNode) as core.FlowNode[];
21-
let indexesToProcess = [this.findStart(flowElements)];
22-
const processedElementIndexes: number[] = [];
23-
const unconnectedElementIndexes: number[] = [];
24-
if (indexesToProcess[0] && indexesToProcess[0] === -1 && !flow.startElementReference) {
25-
throw 'Can not find starting element';
26-
}
27-
if (indexesToProcess[0] && indexesToProcess[0] === -1 && flow.startElementReference) {
28-
indexesToProcess = [
29-
flowElements.findIndex(n => {
30-
return n.name == flow.startElementReference[0];
31-
})
32-
];
33-
}
34-
do {
35-
indexesToProcess = indexesToProcess.filter(index => !processedElementIndexes.includes(index));
36-
if (indexesToProcess.length > 0) {
37-
for (const [index, element] of flowElements.entries()) {
38-
if (indexesToProcess.includes(index)) {
39-
const references: string[] = [];
40-
if (element.connectors && element.connectors.length > 0) {
41-
for (const connector of element.connectors) {
42-
if (connector.reference) {
43-
references.push(connector.reference);
44-
}
45-
}
46-
}
47-
if (references.length > 0) {
48-
const elementsByReferences = flowElements.filter(anElement => references.includes(anElement.name));
49-
for (const nextElement of elementsByReferences) {
50-
const nextIndex = flowElements.findIndex(anElement => nextElement.name === anElement.name);
51-
if (!processedElementIndexes.includes(nextIndex)) {
52-
indexesToProcess.push(nextIndex);
53-
}
54-
}
55-
}
56-
processedElementIndexes.push(index);
57-
}
58-
}
59-
} else {
60-
for (const index of flowElements.keys()) {
61-
if (!processedElementIndexes.includes(index)) {
62-
unconnectedElementIndexes.push(index);
63-
}
64-
}
65-
}
66-
} while ((processedElementIndexes.length + unconnectedElementIndexes.length) < flowElements.length);
6729

68-
const processedElements = [];
69-
const unconnectedElements = [];
70-
for (const [index, element] of flowElements.entries()) {
71-
if (processedElementIndexes.includes(index)) {
72-
processedElements.push(element);
73-
} else if (unconnectedElementIndexes.includes(index)) {
74-
unconnectedElements.push(element);
75-
}
76-
}
77-
let results = [];
78-
for (const det of unconnectedElements) {
79-
results.push(new core.ResultDetails(det));
30+
// Find start of Flow
31+
const startIndex = this.findStart(flowElements);
32+
33+
// Start traversal from the start node
34+
if (startIndex !== -1) {
35+
new core.Compiler().traverseFlow(flow, flowElements[startIndex].name, logConnected);
8036
}
37+
38+
const unconnectedElements: core.FlowNode[] = flowElements.filter(element => !connectedElements.has(element.name));
39+
40+
// Create result details
41+
const results = unconnectedElements.map(det => new core.ResultDetails(det));
42+
8143
return new core.RuleResult(this, results);
8244
}
8345

84-
private findStart(nodes: core.FlowElement[]) {
46+
private findStart(nodes: core.FlowNode[]) {
8547
return nodes.findIndex(n => {
8648
return n.subtype === 'start';
8749
});
8850
}
89-
90-
9151
}

tests/Config.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'mocha';
33
import * as core from '../src'
44
import unconnectedElement from './testfiles/UnconnectedElement.json';
55
import Hidenav from './testfiles/hidenav.json';
6+
import flawed from './testfiles/flawedflow.json';
67

78
describe('Rule Configurations ', () => {
89

@@ -17,6 +18,16 @@ describe('Rule Configurations ', () => {
1718
const rules = core.getRules();
1819
expect(results[0].ruleResults.length).to.equal(rules.length);
1920
});
21+
22+
it(' should return errormessage when file seems corrupt', () => {
23+
flow2 = new core.Flow({
24+
path: './testfiles/flawed.flow-meta.xml',
25+
xmldata: flawed,
26+
});
27+
const results: core.ScanResult[] = core.scan([flow2], undefined);
28+
expect(results[0].ruleResults[0].errorMessage);
29+
});
30+
2031

2132
it(' should use default when no rules are specified', () => {
2233
flow2 = new core.Flow({

tests/testfiles/flawedflow.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"Flow": {
3+
"$": {
4+
"xmlns": "http://soap.sforce.com/2006/04/metadata"
5+
}
6+
}
7+
}

0 commit comments

Comments
 (0)