Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lightning-flow-scanner-core",
"version": "3.9.0",
"version": "3.10.0",
"main": "out/**",
"types": "index.d.ts",
"scripts": {
Expand Down
4 changes: 0 additions & 4 deletions src/main/libs/Keys.ts

This file was deleted.

57 changes: 32 additions & 25 deletions src/main/libs/ScanFlows.ts
Original file line number Diff line number Diff line change
@@ -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[] = [];
Expand All @@ -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;
Expand Down
6 changes: 5 additions & 1 deletion src/main/models/RuleResult.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -18,6 +19,9 @@ export class RuleResult {
if(details.length > 0){
this.occurs = true;
}
if(errorMessage){
this.errorMessage = errorMessage;
}
}

}
82 changes: 21 additions & 61 deletions src/main/rules/UnconnectedElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,75 +17,35 @@ export class UnconnectedElement extends RuleCommon implements core.IRuleDefiniti

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

const connectedElements: Set<string> = new Set<string>();

// 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';
});
}


}
11 changes: 11 additions & 0 deletions tests/Config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 ', () => {

Expand All @@ -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({
Expand Down
7 changes: 7 additions & 0 deletions tests/testfiles/flawedflow.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"Flow": {
"$": {
"xmlns": "http://soap.sforce.com/2006/04/metadata"
}
}
}