From 5bc40b8e5df48e909283c32db1fed472e47357e7 Mon Sep 17 00:00:00 2001 From: Ruben Date: Mon, 6 May 2024 10:12:56 +0200 Subject: [PATCH 1/3] implement compiler traversal in unconnected eleents --- src/main/rules/UnconnectedElement.ts | 82 +++++++--------------------- 1 file changed, 21 insertions(+), 61 deletions(-) diff --git a/src/main/rules/UnconnectedElement.ts b/src/main/rules/UnconnectedElement.ts index 1309724..e69b7d8 100644 --- a/src/main/rules/UnconnectedElement.ts +++ b/src/main/rules/UnconnectedElement.ts @@ -17,75 +17,35 @@ export class UnconnectedElement extends RuleCommon implements core.IRuleDefiniti public execute(flow: core.Flow): core.RuleResult { + const connectedElements: Set = new Set(); + + // Callback function to log connected elements + const logConnected = (element: core.FlowNode) => { + connectedElements.add(element.name); + }; + + // Get Traversable Nodes const flowElements: core.FlowNode[] = flow.elements.filter(node => node instanceof core.FlowNode) as core.FlowNode[]; - let indexesToProcess = [this.findStart(flowElements)]; - const processedElementIndexes: number[] = []; - const unconnectedElementIndexes: number[] = []; - if (indexesToProcess[0] && indexesToProcess[0] === -1 && !flow.startElementReference) { - throw 'Can not find starting element'; - } - if (indexesToProcess[0] && indexesToProcess[0] === -1 && flow.startElementReference) { - indexesToProcess = [ - flowElements.findIndex(n => { - return n.name == flow.startElementReference[0]; - }) - ]; - } - do { - indexesToProcess = indexesToProcess.filter(index => !processedElementIndexes.includes(index)); - if (indexesToProcess.length > 0) { - for (const [index, element] of flowElements.entries()) { - if (indexesToProcess.includes(index)) { - const references: string[] = []; - if (element.connectors && element.connectors.length > 0) { - for (const connector of element.connectors) { - if (connector.reference) { - references.push(connector.reference); - } - } - } - if (references.length > 0) { - const elementsByReferences = flowElements.filter(anElement => references.includes(anElement.name)); - for (const nextElement of elementsByReferences) { - const nextIndex = flowElements.findIndex(anElement => nextElement.name === anElement.name); - if (!processedElementIndexes.includes(nextIndex)) { - indexesToProcess.push(nextIndex); - } - } - } - processedElementIndexes.push(index); - } - } - } else { - for (const index of flowElements.keys()) { - if (!processedElementIndexes.includes(index)) { - unconnectedElementIndexes.push(index); - } - } - } - } while ((processedElementIndexes.length + unconnectedElementIndexes.length) < flowElements.length); - const processedElements = []; - const unconnectedElements = []; - for (const [index, element] of flowElements.entries()) { - if (processedElementIndexes.includes(index)) { - processedElements.push(element); - } else if (unconnectedElementIndexes.includes(index)) { - unconnectedElements.push(element); - } - } - let results = []; - for (const det of unconnectedElements) { - results.push(new core.ResultDetails(det)); + // Find start of Flow + const startIndex = this.findStart(flowElements); + + // Start traversal from the start node + if (startIndex !== -1) { + new core.Compiler().traverseFlow(flow, flowElements[startIndex].name, logConnected); } + + const unconnectedElements: core.FlowNode[] = flowElements.filter(element => !connectedElements.has(element.name)); + + // Create result details + const results = unconnectedElements.map(det => new core.ResultDetails(det)); + return new core.RuleResult(this, results); } - private findStart(nodes: core.FlowElement[]) { + private findStart(nodes: core.FlowNode[]) { return nodes.findIndex(n => { return n.subtype === 'start'; }); } - - } From 3ee28d2a9f86b95143051d16dced609d15b91880 Mon Sep 17 00:00:00 2001 From: Ruben Date: Mon, 6 May 2024 13:25:54 +0200 Subject: [PATCH 2/3] rm unused class --- src/main/libs/Keys.ts | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 src/main/libs/Keys.ts diff --git a/src/main/libs/Keys.ts b/src/main/libs/Keys.ts deleted file mode 100644 index cf3d8c2..0000000 --- a/src/main/libs/Keys.ts +++ /dev/null @@ -1,4 +0,0 @@ -export function keys(m: Map | { [P in K]: any }): K[] { - if (m instanceof Map) return Array.from(m.keys()) - return Object.keys(m) as K[] -} \ No newline at end of file From 57ec94dcd7699a5275411f6603016e73ce786744 Mon Sep 17 00:00:00 2001 From: Ruben Date: Mon, 6 May 2024 15:55:20 +0200 Subject: [PATCH 3/3] add errormessage on rule failure --- package.json | 2 +- src/main/libs/ScanFlows.ts | 57 ++++++++++++++++++--------------- src/main/models/RuleResult.ts | 6 +++- tests/Config.test.ts | 11 +++++++ tests/testfiles/flawedflow.json | 7 ++++ 5 files changed, 56 insertions(+), 27 deletions(-) create mode 100644 tests/testfiles/flawedflow.json diff --git a/package.json b/package.json index 6743ffe..dfe5dd2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lightning-flow-scanner-core", - "version": "3.9.0", + "version": "3.10.0", "main": "out/**", "types": "index.d.ts", "scripts": { diff --git a/src/main/libs/ScanFlows.ts b/src/main/libs/ScanFlows.ts index 68053c2..3192037 100644 --- a/src/main/libs/ScanFlows.ts +++ b/src/main/libs/ScanFlows.ts @@ -1,8 +1,10 @@ -import { GetRuleDefinitions } from './GetRuleDefinitions'; -import * as core from '../../main/internals/internals'; - -export function ScanFlows(flows: core.Flow[], ruleOptions?: core.IRulesConfig): core.ScanResult[] { +import { GetRuleDefinitions } from "./GetRuleDefinitions"; +import * as core from "../../main/internals/internals"; +export function ScanFlows( + flows: core.Flow[], + ruleOptions?: core.IRulesConfig +): core.ScanResult[] { const flowResults: core.ScanResult[] = []; let selectedRules: core.IRuleDefinition[] = []; @@ -17,34 +19,39 @@ export function ScanFlows(flows: core.Flow[], ruleOptions?: core.IRulesConfig): } for (const flow of flows) { - - try { - const ruleResults: core.RuleResult[] = []; - for (const rule of selectedRules) { + const ruleResults: core.RuleResult[] = []; + for (const rule of selectedRules) { + try { if (rule.supportedTypes.includes(flow.type[0])) { - try { - let config = undefined; - - if (ruleOptions && ruleOptions['rules'] && ruleOptions['rules'][rule.name]) { - config = ruleOptions['rules'][rule.name]; - } - const result = (config && Object.keys(config).length > 0) ? rule.execute(flow, config) : rule.execute(flow); - if (result.severity !== rule.severity) { - result.severity = rule.severity; - } - ruleResults.push(result); - } catch (error) { - throw new error("Something went wrong while executing " + rule.name + " in the Flow: '" + flow.name + "'"); + let config = undefined; + if ( + ruleOptions && + ruleOptions["rules"] && + ruleOptions["rules"][rule.name] + ) { + config = ruleOptions["rules"][rule.name]; } + const result = + config && Object.keys(config).length > 0 + ? rule.execute(flow, config) + : rule.execute(flow); + if (result.severity !== rule.severity) { + result.severity = rule.severity; + } + ruleResults.push(result); } else { ruleResults.push(new core.RuleResult(rule, [])); } + } catch (error) { + let message = + "Something went wrong while executing " + + rule.name + + " in the Flow: '" + + flow.name; + ruleResults.push(new core.RuleResult(rule, [], message)); } - flowResults.push(new core.ScanResult(flow, ruleResults)); - } - catch (error) { - console.log(error.message) } + flowResults.push(new core.ScanResult(flow, ruleResults)); } return flowResults; diff --git a/src/main/models/RuleResult.ts b/src/main/models/RuleResult.ts index 6275497..b4081f3 100644 --- a/src/main/models/RuleResult.ts +++ b/src/main/models/RuleResult.ts @@ -8,8 +8,9 @@ export class RuleResult { public ruleDefinition: IRuleDefinition; public severity: string; public details: ResultDetails[] = []; + public errorMessage: string; - constructor(info: IRuleDefinition, details: ResultDetails[]) { + constructor(info: IRuleDefinition, details: ResultDetails[], errorMessage?:string) { this.ruleDefinition = info; this.ruleName = info.name; this.severity = info.severity ? info.severity : 'error'; @@ -18,6 +19,9 @@ export class RuleResult { if(details.length > 0){ this.occurs = true; } + if(errorMessage){ + this.errorMessage = errorMessage; + } } } diff --git a/tests/Config.test.ts b/tests/Config.test.ts index c0c7f94..bb1e77e 100644 --- a/tests/Config.test.ts +++ b/tests/Config.test.ts @@ -3,6 +3,7 @@ import 'mocha'; import * as core from '../src' import unconnectedElement from './testfiles/UnconnectedElement.json'; import Hidenav from './testfiles/hidenav.json'; +import flawed from './testfiles/flawedflow.json'; describe('Rule Configurations ', () => { @@ -17,6 +18,16 @@ describe('Rule Configurations ', () => { const rules = core.getRules(); expect(results[0].ruleResults.length).to.equal(rules.length); }); + + it(' should return errormessage when file seems corrupt', () => { + flow2 = new core.Flow({ + path: './testfiles/flawed.flow-meta.xml', + xmldata: flawed, + }); + const results: core.ScanResult[] = core.scan([flow2], undefined); + expect(results[0].ruleResults[0].errorMessage); + }); + it(' should use default when no rules are specified', () => { flow2 = new core.Flow({ diff --git a/tests/testfiles/flawedflow.json b/tests/testfiles/flawedflow.json new file mode 100644 index 0000000..f497d38 --- /dev/null +++ b/tests/testfiles/flawedflow.json @@ -0,0 +1,7 @@ +{ + "Flow": { + "$": { + "xmlns": "http://soap.sforce.com/2006/04/metadata" + } + } +} \ No newline at end of file