From d5f719a146689e47e40a2785535733f9fce30c09 Mon Sep 17 00:00:00 2001 From: smartinello1 Date: Sat, 15 Nov 2025 00:56:32 +0100 Subject: [PATCH 1/5] feat: Add New Rule - MissingMetadataDescription (for Elements & Variables) #215 New Rule Implementation - MissingMetadataDescription Checks for every flow's element if has a property description filled --- assets/example-flows/.flow-scanner.yml | 2 ++ src/main/rules/MissingMetadataDescription.ts | 33 ++++++++++++++++++++ src/main/store/DefaultRuleStore.ts | 2 ++ 3 files changed, 37 insertions(+) create mode 100644 src/main/rules/MissingMetadataDescription.ts diff --git a/assets/example-flows/.flow-scanner.yml b/assets/example-flows/.flow-scanner.yml index df1b8dfd..f0a998a1 100644 --- a/assets/example-flows/.flow-scanner.yml +++ b/assets/example-flows/.flow-scanner.yml @@ -48,4 +48,6 @@ rules: severity: error UnusedVariable: severity: error + MissingMetadataDescription: + severity: warning exceptions: \ No newline at end of file diff --git a/src/main/rules/MissingMetadataDescription.ts b/src/main/rules/MissingMetadataDescription.ts new file mode 100644 index 00000000..9e947190 --- /dev/null +++ b/src/main/rules/MissingMetadataDescription.ts @@ -0,0 +1,33 @@ +import * as core from "../internals/internals"; +import { RuleCommon } from "../models/RuleCommon"; +import { IRuleDefinition } from "../interfaces/IRuleDefinition"; + +export class MissingMetadataDescription extends RuleCommon implements IRuleDefinition { + constructor() { + super({ + name: "MissingMetadataDescription", + label: "Missing Metadata Description", + description: "Every element must have a meaningful description", + supportedTypes: core.FlowType.allTypes(), + docRefs: [], + isConfigurable: false, + autoFixable: false, + }); + } + + public execute(flow: core.Flow, options?: object, suppressions: string[] = []): core.RuleResult { + return this.executeWithSuppression(flow, options, suppressions, (suppSet) => { + const results: core.ResultDetails[] = flow.elements + .filter((elem) => { + if (!elem.element["description"]) { + return elem; + } + }) + .map((elem) => { + return new core.ResultDetails(elem); + }); + + return new core.RuleResult(this, results); + }); + } +} diff --git a/src/main/store/DefaultRuleStore.ts b/src/main/store/DefaultRuleStore.ts index 9d626028..335c3c85 100644 --- a/src/main/store/DefaultRuleStore.ts +++ b/src/main/store/DefaultRuleStore.ts @@ -21,6 +21,7 @@ import { TriggerOrder } from "../rules/TriggerOrder"; import { UnconnectedElement } from "../rules/UnconnectedElement"; import { UnsafeRunningContext } from "../rules/UnsafeRunningContext"; import { UnusedVariable } from "../rules/UnusedVariable"; +import { MissingMetadataDescription } from "../rules/MissingMetadataDescription"; export const DefaultRuleStore: object = { APIVersion, @@ -45,6 +46,7 @@ export const DefaultRuleStore: object = { UnconnectedElement, UnsafeRunningContext, UnusedVariable, + MissingMetadataDescription, }; export const BetaRuleStore: object = { From e7a10c2171ae7753897373b1e314538fc5a7d347 Mon Sep 17 00:00:00 2001 From: smartinello1 Date: Sat, 15 Nov 2025 01:26:36 +0100 Subject: [PATCH 2/5] Add test and example for MissingMetadataDescription rule Introduces a sample flow XML and a Jest test to validate the MissingMetadataDescription rule. Also adds debug logging to the rule implementation for easier troubleshooting. --- ...Missing_Metadata_Description.flow-meta.xml | 78 +++++++++++++++++++ src/main/rules/MissingMetadataDescription.ts | 4 +- tests/MissingMetadataDescription.test.ts | 16 ++++ 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 assets/example-flows/force-app/main/default/flows/Missing_Metadata_Description.flow-meta.xml create mode 100644 tests/MissingMetadataDescription.test.ts diff --git a/assets/example-flows/force-app/main/default/flows/Missing_Metadata_Description.flow-meta.xml b/assets/example-flows/force-app/main/default/flows/Missing_Metadata_Description.flow-meta.xml new file mode 100644 index 00000000..b2010970 --- /dev/null +++ b/assets/example-flows/force-app/main/default/flows/Missing_Metadata_Description.flow-meta.xml @@ -0,0 +1,78 @@ + + + + create_account_manually + + 440 + 242 + FeedItem.NewTaskFromFeedItem + quickAction + CurrentTransaction + + contextId + + $User.Id + + + FeedItem.NewTaskFromFeedItem + 1 + + 58.0 + This flow demonstrates a violation of the rule "Missing Metadata Description". + Default + Missing Metadata Description {!$Flow.CurrentDateTime} + + + BuilderType + + LightningFlowBuilder + + + + CanvasMode + + AUTO_LAYOUT_CANVAS + + + + OriginBuilderType + + LightningFlowBuilder + + + AutoLaunchedFlow + + create_Test_Account + + 176 + 134 + + create_account_manually + + + Name + + Test Account + + + Account + true + + + 50 + 0 + + create_Test_Account + + + Active + + Account + SObject + false + false + false + Account + + 10 + \ No newline at end of file diff --git a/src/main/rules/MissingMetadataDescription.ts b/src/main/rules/MissingMetadataDescription.ts index 9e947190..9a104837 100644 --- a/src/main/rules/MissingMetadataDescription.ts +++ b/src/main/rules/MissingMetadataDescription.ts @@ -19,11 +19,13 @@ export class MissingMetadataDescription extends RuleCommon implements IRuleDefin return this.executeWithSuppression(flow, options, suppressions, (suppSet) => { const results: core.ResultDetails[] = flow.elements .filter((elem) => { - if (!elem.element["description"]) { + console.log("elem: ", elem); + if (elem.metaType !== "metadata" && !elem.element["description"]) { return elem; } }) .map((elem) => { + console.log("elem.map: ", elem); return new core.ResultDetails(elem); }); diff --git a/tests/MissingMetadataDescription.test.ts b/tests/MissingMetadataDescription.test.ts new file mode 100644 index 00000000..1a5b229a --- /dev/null +++ b/tests/MissingMetadataDescription.test.ts @@ -0,0 +1,16 @@ +import * as core from "../src"; +import * as path from "path"; + +import { describe, it, expect } from "@jest/globals"; + +describe("HardcodedId", () => { + const example_uri = path.join(__dirname, "../assets/example-flows/force-app/main/default/flows/Missing_Metadata_Description.flow-meta.xml"); + + it("there should be 1 results for the rule MissingMetadataDescription", async () => { + const flows = await core.parse([example_uri]); + const results: core.ScanResult[] = core.scan(flows); + const occurringResults = results[0].ruleResults.filter((rule) => rule.occurs); + expect(occurringResults).toHaveLength(1); + expect(occurringResults.filter(ruleName => ruleName.ruleName === "MissingMetadataDescription")[0].ruleName).toBe("MissingMetadataDescription"); + }); +}); From 0aef085011b4d750bd361200f28a8aed3bcbabbf Mon Sep 17 00:00:00 2001 From: smartinello1 Date: Sun, 16 Nov 2025 00:10:32 +0100 Subject: [PATCH 3/5] Add missing description fields to flow metadata Descriptions were added to actionCalls, recordCreates, and variables in several flow .flow-meta.xml files to improve metadata completeness. The rule logic in MissingMetadataDescription.ts was updated to better filter elements missing descriptions, excluding 'start' subtype and suppressed elements. --- .../main/default/flows/Hardcoded_Id.flow-meta.xml | 3 +++ .../default/flows/Missing_Error_Handler.flow-meta.xml | 1 + .../flows/Missing_Error_Handler_Fixed.flow-meta.xml | 2 ++ src/main/rules/MissingMetadataDescription.ts | 10 +++++++--- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/assets/example-flows/force-app/main/default/flows/Hardcoded_Id.flow-meta.xml b/assets/example-flows/force-app/main/default/flows/Hardcoded_Id.flow-meta.xml index f68fd5c1..cceb9e8f 100644 --- a/assets/example-flows/force-app/main/default/flows/Hardcoded_Id.flow-meta.xml +++ b/assets/example-flows/force-app/main/default/flows/Hardcoded_Id.flow-meta.xml @@ -3,6 +3,7 @@ create_account_manually + create account description 440 242 FeedItem.NewTaskFromFeedItem @@ -44,6 +45,7 @@ create_Test_Account + create Test Account description 176 134 @@ -74,6 +76,7 @@ Active Account + Account description SObject false false diff --git a/assets/example-flows/force-app/main/default/flows/Missing_Error_Handler.flow-meta.xml b/assets/example-flows/force-app/main/default/flows/Missing_Error_Handler.flow-meta.xml index 89b38585..d5d0ef8f 100644 --- a/assets/example-flows/force-app/main/default/flows/Missing_Error_Handler.flow-meta.xml +++ b/assets/example-flows/force-app/main/default/flows/Missing_Error_Handler.flow-meta.xml @@ -3,6 +3,7 @@ log_call + description 176 134 LogACall diff --git a/assets/example-flows/force-app/main/default/flows/Missing_Error_Handler_Fixed.flow-meta.xml b/assets/example-flows/force-app/main/default/flows/Missing_Error_Handler_Fixed.flow-meta.xml index dd0386be..23be6d31 100644 --- a/assets/example-flows/force-app/main/default/flows/Missing_Error_Handler_Fixed.flow-meta.xml +++ b/assets/example-flows/force-app/main/default/flows/Missing_Error_Handler_Fixed.flow-meta.xml @@ -3,6 +3,7 @@ dosomethingelse + description 440 242 NewTask @@ -20,6 +21,7 @@ log_call + description 176 134 LogACall diff --git a/src/main/rules/MissingMetadataDescription.ts b/src/main/rules/MissingMetadataDescription.ts index 9a104837..3b8a845e 100644 --- a/src/main/rules/MissingMetadataDescription.ts +++ b/src/main/rules/MissingMetadataDescription.ts @@ -19,13 +19,17 @@ export class MissingMetadataDescription extends RuleCommon implements IRuleDefin return this.executeWithSuppression(flow, options, suppressions, (suppSet) => { const results: core.ResultDetails[] = flow.elements .filter((elem) => { - console.log("elem: ", elem); - if (elem.metaType !== "metadata" && !elem.element["description"]) { + if ( + elem.metaType !== "metadata" && + !elem.element["description"] && + elem.subtype !== "start" && + !suppSet.has(elem.name) + ) { + console.log("elem: ", elem); return elem; } }) .map((elem) => { - console.log("elem.map: ", elem); return new core.ResultDetails(elem); }); From 8acc8bdf1a9fd8aa9da33d788bd3fc14ce2efef8 Mon Sep 17 00:00:00 2001 From: smartinello1 Date: Wed, 26 Nov 2025 21:55:19 +0100 Subject: [PATCH 4/5] feat: updated rule implementation Update rule implementation with new version of the framework based on: https://github.com/Flow-Scanner/lightning-flow-scanner-core/blob/main/docs/write-a-rule.md --- src/main/rules/MissingMetadataDescription.ts | 51 +++++++++++--------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/src/main/rules/MissingMetadataDescription.ts b/src/main/rules/MissingMetadataDescription.ts index 3b8a845e..f482aefc 100644 --- a/src/main/rules/MissingMetadataDescription.ts +++ b/src/main/rules/MissingMetadataDescription.ts @@ -1,39 +1,42 @@ +import { IRuleDefinition } from "../interfaces/IRuleDefinition"; import * as core from "../internals/internals"; import { RuleCommon } from "../models/RuleCommon"; -import { IRuleDefinition } from "../interfaces/IRuleDefinition"; export class MissingMetadataDescription extends RuleCommon implements IRuleDefinition { constructor() { super({ - name: "MissingMetadataDescription", - label: "Missing Metadata Description", + autoFixable: false, description: "Every element must have a meaningful description", - supportedTypes: core.FlowType.allTypes(), docRefs: [], isConfigurable: false, - autoFixable: false, + label: "Missing Metadata Description", + name: "MissingMetadataDescription", + supportedTypes: core.FlowType.allTypes(), }); } - public execute(flow: core.Flow, options?: object, suppressions: string[] = []): core.RuleResult { - return this.executeWithSuppression(flow, options, suppressions, (suppSet) => { - const results: core.ResultDetails[] = flow.elements - .filter((elem) => { - if ( - elem.metaType !== "metadata" && - !elem.element["description"] && - elem.subtype !== "start" && - !suppSet.has(elem.name) - ) { - console.log("elem: ", elem); - return elem; - } - }) - .map((elem) => { - return new core.ResultDetails(elem); - }); + protected check( + flow: core.Flow, + _options: object | undefined, + _suppression: Set + ): core.Violation[] { + const violations: core.Violation[] = []; - return new core.RuleResult(this, results); - }); + flow.elements + .filter((elem) => { + if ( + elem.metaType !== "metadata" && + !elem.element["description"] && + elem.subtype !== "start" + ) { + console.log("elem: ", elem); + return elem; + } + }) + .forEach((elem) => { + return violations.push(new core.Violation(elem)); + }); + + return violations; } } From 6aeeed0bbc732defdca80ebda9f1acbacca509f0 Mon Sep 17 00:00:00 2001 From: smartinello1 Date: Wed, 26 Nov 2025 22:06:44 +0100 Subject: [PATCH 5/5] chore: removed log --- src/main/rules/MissingMetadataDescription.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/rules/MissingMetadataDescription.ts b/src/main/rules/MissingMetadataDescription.ts index f482aefc..3aa4866d 100644 --- a/src/main/rules/MissingMetadataDescription.ts +++ b/src/main/rules/MissingMetadataDescription.ts @@ -29,7 +29,6 @@ export class MissingMetadataDescription extends RuleCommon implements IRuleDefin !elem.element["description"] && elem.subtype !== "start" ) { - console.log("elem: ", elem); return elem; } })