Skip to content

Commit

Permalink
Merge pull request #139 from Lightning-Flow-Scanner/fix/missing-fault…
Browse files Browse the repository at this point in the history
…-path-rule-on-fast-update

fix(RuleEngine): missing fault path rule modification resolved #134
  • Loading branch information
junners authored Nov 16, 2024
2 parents 685553a + c80c37a commit b880f77
Show file tree
Hide file tree
Showing 12 changed files with 481 additions and 242 deletions.
Binary file modified .DS_Store
Binary file not shown.
2 changes: 1 addition & 1 deletion .github/workflows/deploy-BETA.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
persist-credentials: false
- uses: actions/[email protected]
with:
node-version: 20.x
node-version: 22.x
registry-url: https://registry.npmjs.org
scope: rubenhalman
- name: Install Dependencies
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy-RELEASE.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
# Setup .npmrc file to publish to npm
- uses: actions/[email protected]
with:
node-version: 20.x
node-version: 22.x
registry-url: https://registry.npmjs.org
scope: rubenhalman
- name: Publish
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/generate-RELEASE.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
# Setup .npmrc file to publish to npm
- uses: actions/[email protected]
with:
node-version: 20.x
node-version: 22.x
registry-url: https://registry.npmjs.org
scope: rubenhalman
- name: Generate New Release Number
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: Install node
uses: actions/[email protected]
with:
node-version: 20.x
node-version: 22.x
- name: Install dependencies and link
run: npm ci && npm link
- name: Run tests
Expand Down
478 changes: 264 additions & 214 deletions package-lock.json

Large diffs are not rendered by default.

18 changes: 9 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,25 @@
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-typescript": "^12.1.1",
"@types/chai": "^5.0.0",
"@types/chai": "^5.0.1",
"@types/mocha": "^10.0.9",
"@types/node": "^22.7.7",
"chai": "^5.1.1",
"@types/node": "^22.9.0",
"chai": "^5.1.2",
"cross-env": "^7.0.3",
"eslint": "^9.13.0",
"eslint": "^9.15.0",
"husky": "^9.1.6",
"lint-staged": "^15.2.10",
"logging": "^3.3.0",
"mocha": "^10.7.3",
"mocha": "^10.8.2",
"nyc": "^17.1.0",
"prettier": "^3.3.3",
"rollup": "^4.24.0",
"rollup": "^4.27.2",
"rollup-plugin-polyfill-node": "^0.13.0",
"semantic-release": "^24.1.3",
"semantic-release": "^24.2.0",
"ts-node": "^10.9.2",
"tslib": "^2.8.0",
"tslib": "^2.8.1",
"typescript": "^5.6.3",
"typescript-eslint": "^8.10.0",
"typescript-eslint": "^8.14.0",
"uglify-js": "^3.19.3"
},
"dependencies": {
Expand Down
2 changes: 1 addition & 1 deletion src/main/libs/Compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class Compiler {
for (const elementName of elementsToVisit) {
if (!this.visitedElements.has(elementName)) {
const currentElement = flow.elements?.find(
(element) => element instanceof FlowNode && element.name === elementName
(element) => element.name === elementName
) as FlowNode;
if (currentElement) {
visitCallback(currentElement);
Expand Down
32 changes: 19 additions & 13 deletions src/main/rules/MissingFaultPath.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ import { RuleCommon } from "../models/RuleCommon";
import * as core from "../internals/internals";

export class MissingFaultPath extends RuleCommon implements core.IRuleDefinition {
protected applicableElements: string[] = [
"recordLookups",
"recordDeletes",
"recordUpdates",
"recordCreates",
"waits",
"actionCalls",
];

constructor() {
super({
name: "MissingFaultPath",
Expand All @@ -24,26 +33,23 @@ export class MissingFaultPath extends RuleCommon implements core.IRuleDefinition
const compiler = new core.Compiler();
const results: core.ResultDetails[] = [];
const elementsWhereFaultPathIsApplicable = (
flow.elements.filter(
(node) =>
node instanceof core.FlowNode &&
[
"recordLookups",
"recordDeletes",
"recordUpdates",
"recordCreates",
"waits",
"actionCalls",
].includes(node.subtype)
) as core.FlowNode[]
flow.elements.filter((node) => {
const proxyNode = node as {} as core.FlowNode;
const validSubtype = this.applicableElements.includes(proxyNode.subtype);
return validSubtype;
}) as core.FlowNode[]
).map((e) => e.name);

const isRecordBeforeSave = flow.start.triggerType === "RecordBeforeSave";

const visitCallback = (element: core.FlowNode) => {
// Check if the element should have a fault path
if (
!element.connectors.find((connector) => connector.type === "faultConnector") &&
elementsWhereFaultPathIsApplicable.includes(element.name)
) {
if (isRecordBeforeSave && element.subtype === "recordUpdates") {
return;
}
// Check if the element is part of another fault path
if (!this.isPartOfFaultHandlingFlow(element, flow)) {
results.push(new core.ResultDetails(element));
Expand Down
16 changes: 16 additions & 0 deletions tests/MissingFaultPath.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import "mocha";
import * as core from "../src";
import * as path from "path-browserify";
import { ParsedFlow } from "../src/main/models/ParsedFlow";
import { MissingFaultPath } from "../src/main/rules/MissingFaultPath";

describe("MissingFaultPath", () => {
let expect;
Expand All @@ -24,4 +26,18 @@ describe("MissingFaultPath", () => {
const occurringResults = results[0].ruleResults.filter((rule) => rule.occurs);
expect(occurringResults.length).to.equal(0);
});

it("should skip before save flows due to salesforce limitation", async () => {
const { default: rawFile } = await import(
"./jsonfiles/MissingFaultPath_BeforeSave_Bypass.json",
{
with: { type: "json" },
}
);
const parsedFile: ParsedFlow[] = rawFile as {} as ParsedFlow[];
const missingFaultPathRule = new MissingFaultPath();
const flow: core.Flow = parsedFile.pop()?.flow as core.Flow;
const scanResults: core.RuleResult = missingFaultPathRule.execute(flow);
expect(scanResults.occurs).to.be.false;
});
});
2 changes: 1 addition & 1 deletion tests/MissingNullHandler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ describe("MissingNullHandler ", () => {
expect(results[0].ruleResults[0].occurs).to.equal(true);
});

it(" should return no result when null handlers are implemented", async () => {
it("should return no result when null handlers are implemented", async () => {
let flows = await core.parse([fixed_uri]);
const ruleConfig = {
rules: {
Expand Down
167 changes: 167 additions & 0 deletions tests/jsonfiles/MissingFaultPath_BeforeSave_Bypass.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
[
{
"flow": {
"flowVariables": ["choices", "constants", "dynamicChoiceSets", "formulas", "variables"],
"flowResources": ["textTemplates", "stages"],
"flowMetadata": [
"description",
"apiVersion",
"processMetadataValues",
"processType",
"interviewLabel",
"label",
"status",
"runInMode",
"startElementReference",
"isTemplate",
"fullName",
"timeZoneSidKey",
"isAdditionalPermissionRequiredToRun",
"migratedFromWorkflowRuleName",
"triggerOrder",
"environments",
"segment"
],
"flowNodes": [
"actionCalls",
"apexPluginCalls",
"assignments",
"collectionProcessors",
"decisions",
"loops",
"orchestratedStages",
"recordCreates",
"recordDeletes",
"recordLookups",
"recordUpdates",
"recordRollbacks",
"screens",
"start",
"steps",
"subflows",
"waits"
],
"name": "Test_Flow",
"xmldata": {
"@xmlns": "http://soap.sforce.com/2006/04/metadata",
"apiVersion": "62.0",
"environments": "Default",
"interviewLabel": "Test Flow {!$Flow.CurrentDateTime}",
"label": "Test Flow",
"processMetadataValues": [
{ "name": "BuilderType", "value": { "stringValue": "LightningFlowBuilder" } },
{ "name": "CanvasMode", "value": { "stringValue": "AUTO_LAYOUT_CANVAS" } },
{ "name": "OriginBuilderType", "value": { "stringValue": "LightningFlowBuilder" } }
],
"processType": "AutoLaunchedFlow",
"recordUpdates": {
"description": "test",
"name": "Update_triggering_records",
"label": "Update triggering records",
"locationX": "176",
"locationY": "287",
"inputAssignments": { "field": "Active__c", "value": { "stringValue": "Yes" } },
"inputReference": "$Record"
},
"start": {
"locationX": "50",
"locationY": "0",
"connector": { "targetReference": "Update_triggering_records" },
"object": "Account",
"recordTriggerType": "Create",
"triggerType": "RecordBeforeSave"
},
"status": "Draft"
},
"label": "Test Flow",
"interviewLabel": "Test Flow {!$Flow.CurrentDateTime}",
"processType": "AutoLaunchedFlow",
"processMetadataValues": [
{ "name": "BuilderType", "value": { "stringValue": "LightningFlowBuilder" } },
{ "name": "CanvasMode", "value": { "stringValue": "AUTO_LAYOUT_CANVAS" } },
{ "name": "OriginBuilderType", "value": { "stringValue": "LightningFlowBuilder" } }
],
"start": {
"locationX": "50",
"locationY": "0",
"connector": { "targetReference": "Update_triggering_records" },
"object": "Account",
"recordTriggerType": "Create",
"triggerType": "RecordBeforeSave"
},
"status": "Draft",
"type": "AutoLaunchedFlow",
"elements": [
{ "element": "62.0", "subtype": "apiVersion", "metaType": "metadata" },
{ "element": "Default", "subtype": "environments", "metaType": "metadata" },
{
"element": "Test Flow {!$Flow.CurrentDateTime}",
"subtype": "interviewLabel",
"metaType": "metadata"
},
{ "element": "Test Flow", "subtype": "label", "metaType": "metadata" },
{
"element": { "name": "BuilderType", "value": { "stringValue": "LightningFlowBuilder" } },
"subtype": "processMetadataValues",
"metaType": "metadata"
},
{
"element": { "name": "CanvasMode", "value": { "stringValue": "AUTO_LAYOUT_CANVAS" } },
"subtype": "processMetadataValues",
"metaType": "metadata"
},
{
"element": {
"name": "OriginBuilderType",
"value": { "stringValue": "LightningFlowBuilder" }
},
"subtype": "processMetadataValues",
"metaType": "metadata"
},
{ "element": "AutoLaunchedFlow", "subtype": "processType", "metaType": "metadata" },
{
"element": {
"description": "test",
"name": "Update_triggering_records",
"label": "Update triggering records",
"locationX": "176",
"locationY": "287",
"inputAssignments": { "field": "Active__c", "value": { "stringValue": "Yes" } },
"inputReference": "$Record"
},
"subtype": "recordUpdates",
"metaType": "node",
"connectors": [],
"name": "Update_triggering_records",
"locationX": "176",
"locationY": "287"
},
{
"element": {
"locationX": "50",
"locationY": "0",
"connector": { "targetReference": "Update_triggering_records" },
"object": "Account",
"recordTriggerType": "Create",
"triggerType": "RecordBeforeSave"
},
"subtype": "start",
"metaType": "node",
"connectors": [
{
"element": { "targetReference": "Update_triggering_records" },
"processed": false,
"type": "connector",
"reference": "Update_triggering_records"
}
],
"name": "flowstart",
"locationX": "50",
"locationY": "0"
},
{ "element": "Draft", "subtype": "status", "metaType": "metadata" }
],
"startReference": "Update_triggering_records"
}
}
]

0 comments on commit b880f77

Please sign in to comment.