Skip to content

Commit

Permalink
fix: prefer flow parametic polymorphism on constructor
Browse files Browse the repository at this point in the history
  • Loading branch information
junners committed Feb 13, 2025
1 parent b28e238 commit c74ef13
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 35 deletions.
7 changes: 1 addition & 6 deletions src/main/libs/ParseFlows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,10 @@ export async function parse(selectedUris: string[]): Promise<ParsedFlow[]> {
for (const uri of selectedUris) {
try {
const normalizedURI = p.normalize(uri);
const fsPath = p.resolve(normalizedURI);
let flowName = p.basename(p.basename(fsPath), p.extname(fsPath));
if (flowName.includes(".")) {
flowName = flowName.split(".")[0];
}
const content = await fs.readFileSync(normalizedURI);
const xmlString = content.toString();
const flowObj = convert(xmlString, { format: "object" });
parseResults.push(new ParsedFlow(uri, new Flow(flowName, flowObj)));
parseResults.push(new ParsedFlow(uri, new Flow(uri, flowObj)));
} catch (e) {
parseResults.push(new ParsedFlow(uri, undefined, e.errorMessage));
}
Expand Down
24 changes: 19 additions & 5 deletions src/main/models/Flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,24 @@ import { FlowNode } from "./FlowNode";
import { FlowMetadata } from "./FlowMetadata";
import { FlowElement } from "./FlowElement";
import { FlowVariable } from "./FlowVariable";
import * as p from "path";
import { FlowResource } from "./FlowResource";
import { XMLSerializedAsObject } from "xmlbuilder2/lib/interfaces";
import { create } from "xmlbuilder2";

export class Flow {
public label: string;
public xmldata;
public name: string;
public name?: string;
public interviewLabel?: string;
public processType?;
public processMetadataValues?;
public type?;
public start?;
public startElementReference?;
public status?;
public fsPath;
public root?;
public elements?: FlowElement[];
public startReference;
public triggerOrder?: number;
Expand Down Expand Up @@ -60,11 +65,20 @@ export class Flow {
"waits",
];

constructor(flowName: string, data?: { Flow: Flow }) {
this.name = flowName;
constructor(path?: string, data?: unknown);
constructor(path: string, data?: unknown) {
if (path) {
this.fsPath = p.resolve(path);
let flowName = p.basename(p.basename(this.fsPath), p.extname(this.fsPath));
if (flowName.includes(".")) {
flowName = flowName.split(".")[0];
}
this.name = flowName;
}
if (data) {
if (data.Flow) {
this.xmldata = data.Flow;
const hasFlowElement = !!data && typeof data === "object" && "Flow" in data;
if (hasFlowElement) {
this.xmldata = (data as XMLSerializedAsObject).Flow;
} else this.xmldata = data;
this.preProcessNodes();
}
Expand Down
20 changes: 9 additions & 11 deletions src/main/rules/CyclomaticComplexity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,19 @@ export class CyclomaticComplexity extends RuleCommon implements core.IRuleDefini
});
}

public execute(flow: core.Flow, options?: { threshold: string }): core.RuleResult {
// Set Threshold
let threshold = 0;
private defaultThreshold: number = 25;

if (options && options.threshold) {
threshold = +options.threshold;
} else {
threshold = 25;
}
public execute(flow: core.Flow, options?: { threshold: number }): core.RuleResult {
// Set Threshold
const threshold = options?.threshold ?? this.defaultThreshold;

// Calculate Cyclomatic Complexity based on the number of decision rules and loops, adding the number of decisions plus 1.
let cyclomaticComplexity = 1;

const flowDecisions = flow.elements.filter((node) => node.subtype === "decisions");
const flowLoops = flow.elements.filter((node) => node.subtype === "loops");
const flowDecisions = flow?.elements?.filter(
(node) => node.subtype === "decisions"
) as core.FlowElement[];
const flowLoops = flow?.elements?.filter((node) => node.subtype === "loops");

for (const decision of flowDecisions) {
const rules = decision.element["rules"];
Expand All @@ -47,7 +45,7 @@ export class CyclomaticComplexity extends RuleCommon implements core.IRuleDefini
if (cyclomaticComplexity > threshold) {
results.push(
new core.ResultDetails(
new core.FlowAttribute("" + cyclomaticComplexity, "CyclomaticComplexity", ">" + threshold)
new core.FlowAttribute(`${cyclomaticComplexity}`, "CyclomaticComplexity", `>${threshold}`)
)
);
}
Expand Down
5 changes: 3 additions & 2 deletions tests/UnconnectedElement.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as core from "../src";
import * as path from "path";

import { parse } from "../src/main/libs/ParseFlows";
import { ParsedFlow } from "../src/main/models/ParsedFlow";

import { UnconnectedElement } from "../src/main/rules/UnconnectedElement";
Expand All @@ -15,7 +16,7 @@ describe("UnconnectedElement", () => {
__dirname,
"./xmlfiles/Unconnected_Element.flow-meta.xml"
);
const parsed: ParsedFlow = (await core.parse([connectedElementTestFile])).pop() as ParsedFlow;
const parsed: ParsedFlow = (await parse([connectedElementTestFile])).pop() as ParsedFlow;
const ruleResult: core.RuleResult = unconnectedElementRule.execute(parsed.flow as core.Flow);
expect(ruleResult.occurs).toBe(true);
expect(ruleResult.details).not.toHaveLength(0);
Expand All @@ -29,7 +30,7 @@ describe("UnconnectedElement", () => {
__dirname,
"./xmlfiles/Unconnected_Element_Async.flow-meta.xml"
);
const parsed: ParsedFlow = (await core.parse([connectedElementTestFile])).pop() as ParsedFlow;
const parsed: ParsedFlow = (await parse([connectedElementTestFile])).pop() as ParsedFlow;
const ruleResult: core.RuleResult = unconnectedElementRule.execute(parsed.flow as core.Flow);
expect(ruleResult.occurs).toBe(true);
ruleResult.details.forEach((ruleDetail) => {
Expand Down
7 changes: 4 additions & 3 deletions tests/UnsafeRunningContext.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as core from "../src";
import * as path from "path";

import { parse } from "../src/main/libs/ParseFlows";
import { ParsedFlow } from "../src/main/models/ParsedFlow";

import { describe, it, expect } from "@jest/globals";
Expand All @@ -14,7 +15,7 @@ describe("UnsafeRunningContext", () => {
__dirname,
"./xmlfiles/Unsafe_Running_Context.flow-meta.xml"
);
const parsed: ParsedFlow = (await core.parse([unsafeContextTestFile])).pop() as ParsedFlow;
const parsed: ParsedFlow = (await parse([unsafeContextTestFile])).pop() as ParsedFlow;
const ruleResult: core.RuleResult = unsafeRunningContext.execute(parsed.flow as core.Flow);
expect(ruleResult.occurs).toBe(true);
expect(ruleResult.details).not.toHaveLength(0);
Expand All @@ -26,7 +27,7 @@ describe("UnsafeRunningContext", () => {
__dirname,
"./xmlfiles/Unsafe_Running_Context_WithSharing.flow-meta.xml"
);
const parsed: ParsedFlow = (await core.parse([unsafeContextTestFile])).pop() as ParsedFlow;
const parsed: ParsedFlow = (await parse([unsafeContextTestFile])).pop() as ParsedFlow;
const ruleResult: core.RuleResult = unsafeRunningContext.execute(parsed.flow as core.Flow);
expect(ruleResult.occurs).toBe(false);
expect(ruleResult.details).toHaveLength(0);
Expand All @@ -37,7 +38,7 @@ describe("UnsafeRunningContext", () => {
__dirname,
"./xmlfiles/Unsafe_Running_Context_Default.flow-meta.xml"
);
const parsed: ParsedFlow = (await core.parse([unsafeContextTestFile])).pop() as ParsedFlow;
const parsed: ParsedFlow = (await parse([unsafeContextTestFile])).pop() as ParsedFlow;
const ruleResult: core.RuleResult = unsafeRunningContext.execute(parsed.flow as core.Flow);
expect(ruleResult.occurs).toBe(false);
expect(ruleResult.details).toHaveLength(0);
Expand Down
15 changes: 7 additions & 8 deletions tests/models/Flow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe("Flow Model", () => {
});

it("should print as xml when correct parameters", () => {
const sut: Flow = new Flow("flow A");
const sut: Flow = new Flow();
sut.xmldata = {
"@xmlns": "http://soap.sforce.com/2006/04/metadata",
"@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
Expand All @@ -27,15 +27,14 @@ describe("Flow Model", () => {
picklistObject: "Task",
},
};
// todo fix test !
// const out = sut.toXMLString();
// expect(out).toBeTruthy();
// expect(out).toMatch('<displayField xsi:nil="true"/>');
// expect(out).toMatch('<object xsi:nil="true"/>');
const out = sut.toXMLString();
expect(out).toBeTruthy();
expect(out).toMatch('<displayField xsi:nil="true"/>');
expect(out).toMatch('<object xsi:nil="true"/>');
});

it("should never throw an exception for toXMLString", () => {
const sut: Flow = new Flow("flow B");
const sut: Flow = new Flow();
sut.xmldata = { test: "test" };
jest.spyOn(xmlbuilder, "create").mockReturnValue({
root: () => ({
Expand Down Expand Up @@ -63,7 +62,7 @@ describe("Flow Model", () => {
};

it("should throw an exception for bad document", async () => {
const sut: Flow = new Flow("flow C");
const sut: Flow = new Flow();
const errors = getError(sut["generateDoc"]);
expect(errors).toBeTruthy();
expect(errors).not.toBeInstanceOf(NoErrorThrownError);
Expand Down

0 comments on commit c74ef13

Please sign in to comment.