@flow-scanner/lightning-flow-scanner-core 6.15.0 → 6.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +140 -96
  2. package/main/interfaces/IRuleConfig.d.ts +2 -0
  3. package/main/interfaces/IRuleDefinition.d.ts +1 -0
  4. package/main/libs/ExportDetails.js +3 -1
  5. package/main/libs/ExportSarif.js +4 -4
  6. package/main/libs/RuleDocumentation.d.ts +20 -0
  7. package/main/libs/RuleDocumentation.js +41 -0
  8. package/main/libs/ScanFlows.js +8 -1
  9. package/main/models/FlatViolation.d.ts +2 -0
  10. package/main/models/RuleCommon.d.ts +2 -0
  11. package/main/models/RuleCommon.js +4 -0
  12. package/main/models/RuleInfo.d.ts +9 -0
  13. package/main/models/RuleInfo.js +7 -0
  14. package/main/models/RuleResult.d.ts +2 -0
  15. package/main/models/RuleResult.js +3 -0
  16. package/main/rules/APIVersion.js +2 -0
  17. package/main/rules/ActionCallsInLoop.js +2 -0
  18. package/main/rules/AutoLayout.js +2 -0
  19. package/main/rules/CopyAPIName.js +2 -0
  20. package/main/rules/CyclomaticComplexity.js +3 -1
  21. package/main/rules/DMLStatementInLoop.js +2 -0
  22. package/main/rules/DuplicateDMLOperation.js +2 -0
  23. package/main/rules/FlowDescription.js +3 -1
  24. package/main/rules/FlowName.js +3 -1
  25. package/main/rules/GetRecordAllFields.js +2 -0
  26. package/main/rules/HardcodedId.js +2 -0
  27. package/main/rules/HardcodedUrl.js +2 -0
  28. package/main/rules/InactiveFlow.js +2 -0
  29. package/main/rules/MissingFaultPath.js +2 -0
  30. package/main/rules/MissingMetadataDescription.js +2 -0
  31. package/main/rules/MissingNullHandler.js +2 -0
  32. package/main/rules/MissingRecordTriggerFilter.js +2 -0
  33. package/main/rules/ProcessBuilder.js +2 -0
  34. package/main/rules/RecordIdAsString.js +2 -0
  35. package/main/rules/RecursiveAfterUpdate.js +2 -0
  36. package/main/rules/SOQLQueryInLoop.js +2 -0
  37. package/main/rules/SameRecordFieldUpdates.js +2 -0
  38. package/main/rules/TransformInsteadOfLoop.js +2 -0
  39. package/main/rules/TriggerOrder.js +2 -0
  40. package/main/rules/UnconnectedElement.js +2 -0
  41. package/main/rules/UnsafeRunningContext.js +2 -0
  42. package/main/rules/UnusedVariable.js +2 -0
  43. package/package.json +1 -1
package/README.md CHANGED
@@ -32,9 +32,11 @@
32
32
  ## Table of contents
33
33
 
34
34
  - **[Default Rules](#default-rules)**
35
+ - [problems](#problems)
36
+ - [suggestions](#suggestions)
37
+ - [layout](#layout)
35
38
  - **[Configuration](#configuration)**
36
39
  - [Configure Rules](#configure-rules)
37
- - [Overwrite Expressions](#overwrite-expressions)
38
40
  - [Define Exceptions](#define-exceptions)
39
41
  - [Exclude Flows](#exclude-flows)
40
42
  - [Scan Modes](#scan-modes)
@@ -54,12 +56,7 @@
54
56
  > Want to code a new rule? → See [How to Write a Rule](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/docs/write-a-rule.md)
55
57
 
56
58
  <!-- START GENERATED_RULES -->
57
- ### Action Call In A Loop
58
- Repeatedly invoking Apex actions inside a loop can exhaust governor limits and lead to performance issues. Where possible, bulkify your logic by moving the action call outside the loop and passing a collection variable instead.
59
-
60
- **Rule ID:** `action-call-in-loop`
61
- **Class Name:** _[ActionCallsInLoop](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/ActionCallsInLoop.ts)_
62
- **Severity:** 🟡 *Warning*
59
+ ### Problems
63
60
 
64
61
  ### DML Statement In A Loop
65
62
  Executing DML operations (insert, update, delete) inside a loop is a high-risk anti-pattern that frequently causes governor limit exceptions. All database operations should be collected and executed once, outside the loop.
@@ -68,6 +65,41 @@ Executing DML operations (insert, update, delete) inside a loop is a high-risk a
68
65
  **Class Name:** _[DMLStatementInLoop](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/DMLStatementInLoop.ts)_
69
66
  **Severity:** 🔴 *Error*
70
67
 
68
+ ### Hardcoded Id
69
+ Avoid hard-coding record IDs, as they are unique to a specific org and will not work in other environments. Instead, store IDs in variables—such as merge-field URL parameters or a **Get Records** element—to make the Flow portable, maintainable, and flexible.
70
+
71
+ **Rule ID:** `hardcoded-id`
72
+ **Class Name:** _[HardcodedId](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/HardcodedId.ts)_
73
+ **Severity:** 🔴 *Error*
74
+
75
+ ### Hardcoded Url
76
+ Avoid hard-coding URLs, as they may change between environments or over time. Instead, store URLs in variables or custom settings to make the Flow adaptable, maintainable, and environment-independent.
77
+
78
+ **Rule ID:** `hardcoded-url`
79
+ **Class Name:** _[HardcodedUrl](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/HardcodedUrl.ts)_
80
+ **Severity:** 🔴 *Error*
81
+
82
+ ### Process Builder
83
+ Process Builder is retired. Continuing to use it increases maintenance overhead and risks future compatibility issues. Migrating automation to Flow reduces risk and improves maintainability.
84
+
85
+ **Rule ID:** `process-builder-usage`
86
+ **Class Name:** _[ProcessBuilder](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/ProcessBuilder.ts)_
87
+ **Severity:** 🔴 *Error*
88
+
89
+ ### SOQL Query In A Loop
90
+ Running SOQL queries inside a loop can rapidly exceed query limits and severely degrade performance. Queries should be executed once, with results reused throughout the loop.
91
+
92
+ **Rule ID:** `soql-in-loop`
93
+ **Class Name:** _[SOQLQueryInLoop](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/SOQLQueryInLoop.ts)_
94
+ **Severity:** 🔴 *Error*
95
+
96
+ ### Unsafe Running Context
97
+ Flows configured to run in System Mode without Sharing grant access to all data, bypassing user permissions. Avoid this setting to prevent security risks and protect sensitive data.
98
+
99
+ **Rule ID:** `unsafe-running-context`
100
+ **Class Name:** _[UnsafeRunningContext](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/UnsafeRunningContext.ts)_
101
+ **Severity:** 🔴 *Error*
102
+
71
103
  ### Duplicate DML Operation
72
104
  When a Flow performs database operations across multiple screens, users navigating backward can cause the same actions to run multiple times. To prevent unintended changes, either restrict backward navigation or redesign the Flow so database operations execute in a single, forward-moving step.
73
105
 
@@ -75,40 +107,44 @@ When a Flow performs database operations across multiple screens, users navigati
75
107
  **Class Name:** _[DuplicateDMLOperation](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/DuplicateDMLOperation.ts)_
76
108
  **Severity:** 🟡 *Warning*
77
109
 
78
- ### Excessive Cyclomatic Complexity
79
- High numbers of loops and decision elements increase a Flow’s cyclomatic complexity. To maintain simplicity and readability, consider using subflows or splitting a Flow into smaller, ordered Flows.
110
+ ### Missing Fault Path
111
+ Elements that can fail should include a Fault Path to handle errors gracefully. Without it, failures show generic errors to users. Fault Paths improve reliability and user experience.
80
112
 
81
- **Rule ID:** `excessive-cyclomatic-complexity`
82
- **Class Name:** _[CyclomaticComplexity](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/CyclomaticComplexity.ts)_
83
- **Severity:** 🔵 *Note*
113
+ **Rule ID:** `missing-fault-path`
114
+ **Class Name:** _[MissingFaultPath](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/MissingFaultPath.ts)_
115
+ **Severity:** 🟡 *Warning*
84
116
 
85
- ### Flow Naming Convention
86
- Using clear and consistent Flow names improves readability, discoverability, and maintainability. A good naming convention helps team members quickly understand a Flow’s purpose—for example, including a domain and brief description like Service_OrderFulfillment. Adopt a naming pattern that aligns with your organization’s standards.
117
+ ### Missing Null Handler
118
+ Get Records operations return null when no data is found. Without handling these null values, Flows can fail or produce unintended results. Adding a null check improves reliability and ensures the Flow behaves as expected.
87
119
 
88
- **Rule ID:** `invalid-naming-convention`
89
- **Class Name:** _[FlowName](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/FlowName.ts)_
90
- **Severity:** 🔴 *Error*
120
+ **Rule ID:** `missing-null-handler`
121
+ **Class Name:** _[MissingNullHandler](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/MissingNullHandler.ts)_
122
+ **Severity:** 🟡 *Warning*
91
123
 
92
- ### Get Record All Fields
93
- Avoid using Get Records to retrieve all fields unless necessary. This improves performance, reduces processing time, and limits exposure of unnecessary data.
124
+ ### Recursive After Update
125
+ After-save Flows that update the same record can trigger recursion, causing unintended behavior or performance issues. Avoid updating the triggering record in after-save Flows; use before-save Flows instead to prevent recursion.
94
126
 
95
- **Rule ID:** `get-record-all-fields`
96
- **Class Name:** _[GetRecordAllFields](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/GetRecordAllFields.ts)_
127
+ **Rule ID:** `recursive-record-update`
128
+ **Class Name:** _[RecursiveAfterUpdate](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/RecursiveAfterUpdate.ts)_
97
129
  **Severity:** 🟡 *Warning*
98
130
 
99
- ### Hardcoded Id
100
- Avoid hard-coding record IDs, as they are unique to a specific org and will not work in other environments. Instead, store IDs in variables—such as merge-field URL parameters or a **Get Records** element—to make the Flow portable, maintainable, and flexible.
101
131
 
102
- **Rule ID:** `hardcoded-id`
103
- **Class Name:** _[HardcodedId](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/HardcodedId.ts)_
104
- **Severity:** 🔴 *Error*
105
132
 
106
- ### Hardcoded Url
107
- Avoid hard-coding URLs, as they may change between environments or over time. Instead, store URLs in variables or custom settings to make the Flow adaptable, maintainable, and environment-independent.
133
+ ### Suggestions
108
134
 
109
- **Rule ID:** `hardcoded-url`
110
- **Class Name:** _[HardcodedUrl](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/HardcodedUrl.ts)_
111
- **Severity:** 🔴 *Error*
135
+ ### Action Call In A Loop
136
+ Repeatedly invoking Apex actions inside a loop can exhaust governor limits and lead to performance issues. Where possible, bulkify your logic by moving the action call outside the loop and passing a collection variable instead.
137
+
138
+ **Rule ID:** `action-call-in-loop`
139
+ **Class Name:** _[ActionCallsInLoop](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/ActionCallsInLoop.ts)_
140
+ **Severity:** 🟡 *Warning*
141
+
142
+ ### Get Record All Fields
143
+ Avoid using Get Records to retrieve all fields unless necessary. This improves performance, reduces processing time, and limits exposure of unnecessary data.
144
+
145
+ **Rule ID:** `get-record-all-fields`
146
+ **Class Name:** _[GetRecordAllFields](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/GetRecordAllFields.ts)_
147
+ **Severity:** 🟡 *Warning*
112
148
 
113
149
  ### Inactive Flow
114
150
  Inactive Flows should be deleted or archived to reduce risk. Even when inactive, they can cause unintended record changes during testing or be activated as subflows. Keeping only active, relevant Flows improves safety and maintainability.
@@ -124,20 +160,6 @@ Flows running on outdated API versions may behave inconsistently when newer plat
124
160
  **Class Name:** _[APIVersion](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/APIVersion.ts)_
125
161
  **Severity:** 🟡 *Warning*
126
162
 
127
- ### Missing Auto Layout
128
- Auto-Layout automatically arranges and aligns Flow elements, keeping the canvas organized and easier to maintain. Enabling it saves time and improves readability.
129
-
130
- **Rule ID:** `missing-auto-layout`
131
- **Class Name:** _[AutoLayout](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/AutoLayout.ts)_
132
- **Severity:** 🔵 *Note*
133
-
134
- ### Missing Fault Path
135
- Elements that can fail should include a Fault Path to handle errors gracefully. Without it, failures show generic errors to users. Fault Paths improve reliability and user experience.
136
-
137
- **Rule ID:** `missing-fault-path`
138
- **Class Name:** _[MissingFaultPath](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/MissingFaultPath.ts)_
139
- **Severity:** 🟡 *Warning*
140
-
141
163
  ### Missing Filter Record Trigger ![Beta](https://img.shields.io/badge/status-beta-yellow)
142
164
  Record-triggered Flows without filters on changed fields or entry conditions execute on every record change. Adding filters ensures the Flow runs only when needed, improving performance.
143
165
 
@@ -145,26 +167,19 @@ Record-triggered Flows without filters on changed fields or entry conditions exe
145
167
  **Class Name:** _[MissingFilterRecordTrigger](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/MissingFilterRecordTrigger.ts)_
146
168
  **Severity:** 🟡 *Warning*
147
169
 
148
- ### Missing Flow Description
149
- Flow descriptions are essential for documentation and maintainability. Include a description for each Flow, explaining its purpose and where it’s used.
150
-
151
- **Rule ID:** `missing-flow-description`
152
- **Class Name:** _[FlowDescription](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/FlowDescription.ts)_
153
- **Severity:** 🔴 *Error*
154
-
155
- ### Missing Metadata Description ![Beta](https://img.shields.io/badge/status-beta-yellow)
156
- Elements and metadata without a description reduce clarity and maintainability. Adding descriptions improves readability and makes your automation easier to understand.
170
+ ### Same Record Field Updates
171
+ Before-save Flows can safely update the triggering record directly via $Record, applying changes efficiently without extra DML operations. Using before-save updates improves performance
157
172
 
158
- **Rule ID:** `missing-metadata-description`
159
- **Class Name:** _[MissingMetadataDescription](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/MissingMetadataDescription.ts)_
173
+ **Rule ID:** `same-record-field-updates`
174
+ **Class Name:** _[SameRecordFieldUpdates](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/SameRecordFieldUpdates.ts)_
160
175
  **Severity:** 🟡 *Warning*
161
176
 
162
- ### Missing Null Handler
163
- Get Records operations return null when no data is found. Without handling these null values, Flows can fail or produce unintended results. Adding a null check improves reliability and ensures the Flow behaves as expected.
177
+ ### Excessive Cyclomatic Complexity
178
+ High numbers of loops and decision elements increase a Flow's cyclomatic complexity. To maintain simplicity and readability, consider using subflows or splitting a Flow into smaller, ordered Flows.
164
179
 
165
- **Rule ID:** `missing-null-handler`
166
- **Class Name:** _[MissingNullHandler](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/MissingNullHandler.ts)_
167
- **Severity:** 🟡 *Warning*
180
+ **Rule ID:** `excessive-cyclomatic-complexity`
181
+ **Class Name:** _[CyclomaticComplexity](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/CyclomaticComplexity.ts)_
182
+ **Severity:** 🔵 *Note*
168
183
 
169
184
  ### Missing Trigger Order
170
185
  Record-triggered Flows without a specified Trigger Order may execute in an unpredictable sequence. Setting a Trigger Order ensures your Flows run in the intended order.
@@ -173,13 +188,6 @@ Record-triggered Flows without a specified Trigger Order may execute in an unpre
173
188
  **Class Name:** _[TriggerOrder](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/TriggerOrder.ts)_
174
189
  **Severity:** 🔵 *Note*
175
190
 
176
- ### Process Builder
177
- Process Builder is retired. Continuing to use it increases maintenance overhead and risks future compatibility issues. Migrating automation to Flow reduces risk and improves maintainability.
178
-
179
- **Rule ID:** `process-builder-usage`
180
- **Class Name:** _[ProcessBuilder](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/ProcessBuilder.ts)_
181
- **Severity:** 🔴 *Error*
182
-
183
191
  ### Record ID as String ![Beta](https://img.shields.io/badge/status-beta-yellow)
184
192
  Flows that use a String variable for a record ID instead of receiving the full record introduce unnecessary complexity and additional Get Records queries. Using the complete record simplifies the Flow and improves performance.
185
193
 
@@ -187,33 +195,37 @@ Flows that use a String variable for a record ID instead of receiving the full r
187
195
  **Class Name:** _[RecordIdAsString](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/RecordIdAsString.ts)_
188
196
  **Severity:** 🔵 *Note*
189
197
 
190
- ### Recursive After Update
191
- After-save Flows that update the same record can trigger recursion, causing unintended behavior or performance issues. Avoid updating the triggering record in after-save Flows; use before-save Flows instead to prevent recursion.
198
+ ### Transform Instead of Loop ![Beta](https://img.shields.io/badge/status-beta-yellow)
199
+ Loop elements that perform direct Assignments on each item can slow down Flows. Using Transform elements allows bulk operations on collections, improving performance and reducing complexity.
192
200
 
193
- **Rule ID:** `recursive-record-update`
194
- **Class Name:** _[RecursiveAfterUpdate](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/RecursiveAfterUpdate.ts)_
195
- **Severity:** 🟡 *Warning*
201
+ **Rule ID:** `transform-instead-of-loop`
202
+ **Class Name:** _[TransformInsteadOfLoop](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/TransformInsteadOfLoop.ts)_
203
+ **Severity:** 🔵 *Note*
196
204
 
197
- ### Same Record Field Updates
198
- Before-save Flows can safely update the triggering record directly via $Record, applying changes efficiently without extra DML operations. Using before-save updates improves performance
199
205
 
200
- **Rule ID:** `same-record-field-updates`
201
- **Class Name:** _[SameRecordFieldUpdates](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/SameRecordFieldUpdates.ts)_
202
- **Severity:** 🟡 *Warning*
203
206
 
204
- ### SOQL Query In A Loop
205
- Running SOQL queries inside a loop can rapidly exceed query limits and severely degrade performance. Queries should be executed once, with results reused throughout the loop.
207
+ ### Layout
206
208
 
207
- **Rule ID:** `soql-in-loop`
208
- **Class Name:** _[SOQLQueryInLoop](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/SOQLQueryInLoop.ts)_
209
+ ### Flow Naming Convention
210
+ Using clear and consistent Flow names improves readability, discoverability, and maintainability. A good naming convention helps team members quickly understand a Flow's purpose—for example, including a domain and brief description like Service_OrderFulfillment. Adopt a naming pattern that aligns with your organization's standards.
211
+
212
+ **Rule ID:** `invalid-naming-convention`
213
+ **Class Name:** _[FlowName](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/FlowName.ts)_
209
214
  **Severity:** 🔴 *Error*
210
215
 
211
- ### Transform Instead of Loop ![Beta](https://img.shields.io/badge/status-beta-yellow)
212
- Loop elements that perform direct Assignments on each item can slow down Flows. Using Transform elements allows bulk operations on collections, improving performance and reducing complexity.
216
+ ### Missing Flow Description
217
+ Flow descriptions are essential for documentation and maintainability. Include a description for each Flow, explaining its purpose and where it's used.
213
218
 
214
- **Rule ID:** `transform-instead-of-loop`
215
- **Class Name:** _[TransformInsteadOfLoop](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/TransformInsteadOfLoop.ts)_
216
- **Severity:** 🔵 *Note*
219
+ **Rule ID:** `missing-flow-description`
220
+ **Class Name:** _[FlowDescription](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/FlowDescription.ts)_
221
+ **Severity:** 🔴 *Error*
222
+
223
+ ### Missing Metadata Description ![Beta](https://img.shields.io/badge/status-beta-yellow)
224
+ Elements and metadata without a description reduce clarity and maintainability. Adding descriptions improves readability and makes your automation easier to understand.
225
+
226
+ **Rule ID:** `missing-metadata-description`
227
+ **Class Name:** _[MissingMetadataDescription](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/MissingMetadataDescription.ts)_
228
+ **Severity:** 🟡 *Warning*
217
229
 
218
230
  ### Unclear API Name
219
231
  Elements with unclear or duplicated API names, like Copy_X_Of_Element, reduce Flow readability. Make sure to update the API name when copying elements to keep your Flow organized.
@@ -229,19 +241,19 @@ Unconnected elements never execute and add unnecessary clutter. Remove or connec
229
241
  **Class Name:** _[UnconnectedElement](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/UnconnectedElement.ts)_
230
242
  **Severity:** 🟡 *Warning*
231
243
 
232
- ### Unsafe Running Context
233
- Flows configured to run in System Mode without Sharing grant access to all data, bypassing user permissions. Avoid this setting to prevent security risks and protect sensitive data.
234
-
235
- **Rule ID:** `unsafe-running-context`
236
- **Class Name:** _[UnsafeRunningContext](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/UnsafeRunningContext.ts)_
237
- **Severity:** 🔴 *Error*
238
-
239
244
  ### Unused Variable
240
245
  Unused variables are never referenced and add unnecessary clutter. Remove them to keep Flows efficient and easy to maintain.
241
246
 
242
247
  **Rule ID:** `unused-variable`
243
248
  **Class Name:** _[UnusedVariable](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/UnusedVariable.ts)_
244
249
  **Severity:** 🟡 *Warning*
250
+
251
+ ### Missing Auto Layout
252
+ Auto-Layout automatically arranges and aligns Flow elements, keeping the canvas organized and easier to maintain. Enabling it saves time and improves readability.
253
+
254
+ **Rule ID:** `missing-auto-layout`
255
+ **Class Name:** _[AutoLayout](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/AutoLayout.ts)_
256
+ **Severity:** 🔵 *Note*
245
257
  <!-- END GENERATED_RULES -->
246
258
 
247
259
  ---
@@ -278,12 +290,15 @@ By default, all default rules are executed. You can customize individual rules a
278
290
  "severity": "<Severity>", // Override severity level
279
291
  "expression": "<Expression>", // Override rule expression
280
292
  "message": "<Message>", // Set custom message
281
- "enabled": false // Disable this rule
293
+ "messageUrl": "<URL>", // Set custom documentation URL
294
+ "enabled": false, // Disable this rule
282
295
  }
283
296
  }
284
297
  }
285
298
  ```
286
299
 
300
+ #### Configure Severity
301
+
287
302
  When the severity is not provided it will be `warning` by default. Other available values for severity are `error` and `note`. Configure the severity per rule as demonstrated below:
288
303
 
289
304
  ```json
@@ -299,7 +314,7 @@ When the severity is not provided it will be `warning` by default. Other availab
299
314
  }
300
315
  ```
301
316
 
302
- ### Overwrite Expressions
317
+ #### Override Expressions
303
318
 
304
319
  Some rules are configurable and allow overriding their default expressions. You configure these overrides the same way as severity, as shown in the examples below.
305
320
 
@@ -316,6 +331,35 @@ Some rules are configurable and allow overriding their default expressions. You
316
331
  }
317
332
  ```
318
333
 
334
+ #### Customize Messages
335
+
336
+ If not provided, `message` shows the standard rule summary and `messageUrl` links to the README; providing either overrides the default behavior.
337
+
338
+ ```json
339
+ {
340
+ "rules": {
341
+ "dml-in-loop": {
342
+ "message": "Avoid DML inside loops. Bulkify operations instead.",
343
+ "messageUrl": "https://internal.docs.company.com/salesforce/flow-dml-best-practices"
344
+ }
345
+ }
346
+ }
347
+ ```
348
+
349
+ #### Disable Rules
350
+
351
+ To disable a rule, set `"enabled": false` as shown below:
352
+
353
+ ```json
354
+ {
355
+ "rules": {
356
+ "dml-in-loop": {
357
+ "enabled": false
358
+ }
359
+ }
360
+ }
361
+ ```
362
+
319
363
  ### Define Exceptions
320
364
 
321
365
  Defining exceptions allows you to exclude specific scenarios from rule enforcement. Exceptions can be specified at the flow, rule, or result level to provide fine-grained control. Below is a breakdown of the available attributes of exception configuration:
@@ -1,4 +1,6 @@
1
1
  export interface IRuleConfig {
2
2
  enabled?: boolean;
3
3
  severity?: "error" | "warning" | "note";
4
+ message?: string;
5
+ messageUrl?: string;
4
6
  }
@@ -2,6 +2,7 @@ import { Flow, RuleResult } from "../internals/internals";
2
2
  export interface IRuleDefinition {
3
3
  ruleId: string;
4
4
  description: string;
5
+ summary: string;
5
6
  docRefs: Array<{
6
7
  label: string;
7
8
  path: string;
@@ -106,9 +106,11 @@ function exportDetails(results, includeDetails = false) {
106
106
  const exported = _object_spread_props(_object_spread({}, base), {
107
107
  flowFile,
108
108
  flowName,
109
+ ruleId: rule.ruleId,
109
110
  ruleName: rule.ruleName,
110
111
  severity: (_rule_severity = rule.severity) !== null && _rule_severity !== void 0 ? _rule_severity : "warning",
111
- message: rule.message || rule.ruleDefinition.description
112
+ message: rule.message || rule.ruleDefinition.description,
113
+ messageUrl: rule.messageUrl
112
114
  });
113
115
  // Flatten details object into top-level properties if includeDetails is true
114
116
  if (includeDetails && details) {
@@ -63,14 +63,14 @@ function exportSarif(results) {
63
63
  }
64
64
  ],
65
65
  message: {
66
- text: r.errorMessage || (r.message || r.ruleDefinition.description ? `${r.message || r.ruleDefinition.description} (${d.name})` : `${r.ruleName} in ${d.name}`)
66
+ text: r.errorMessage || (r.message || r.ruleDefinition.description ? `${r.message || r.ruleDefinition.description} (${d.name})` : `${r.ruleId} in ${d.name}`)
67
67
  },
68
68
  properties: _object_spread({
69
69
  element: d.name,
70
70
  flow: flow.name,
71
71
  type: d.type
72
72
  }, d.details),
73
- ruleId: r.ruleName
73
+ ruleId: r.ruleId
74
74
  }))),
75
75
  tool: {
76
76
  driver: {
@@ -83,9 +83,9 @@ function exportSarif(results) {
83
83
  fullDescription: {
84
84
  text: r.message || r.ruleDefinition.description || ""
85
85
  },
86
- id: r.ruleName,
86
+ id: r.ruleId,
87
87
  shortDescription: {
88
- text: r.message || r.ruleDefinition.description || r.ruleName
88
+ text: r.message || r.ruleDefinition.description || r.ruleId
89
89
  }
90
90
  })),
91
91
  version: "1.0.0"
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Converts a rule label to a documentation URL anchor.
3
+ *
4
+ * Rules:
5
+ * - Lowercase
6
+ * - Spaces → hyphens
7
+ * - Remove special characters and badges
8
+ *
9
+ * @param label - The rule display label (e.g., "DML Statement In A Loop")
10
+ * @returns The anchor slug (e.g., "dml-statement-in-a-loop")
11
+ */
12
+ export declare function labelToAnchor(label: string): string;
13
+ /**
14
+ * Generates a documentation URL for a rule.
15
+ *
16
+ * @param label - The rule display label
17
+ * @param customUrl - Optional custom URL override
18
+ * @returns The documentation URL
19
+ */
20
+ export declare function getRuleDocumentationUrl(label: string, customUrl?: string): string;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Converts a rule label to a documentation URL anchor.
3
+ *
4
+ * Rules:
5
+ * - Lowercase
6
+ * - Spaces → hyphens
7
+ * - Remove special characters and badges
8
+ *
9
+ * @param label - The rule display label (e.g., "DML Statement In A Loop")
10
+ * @returns The anchor slug (e.g., "dml-statement-in-a-loop")
11
+ */ "use strict";
12
+ Object.defineProperty(exports, "__esModule", {
13
+ value: true
14
+ });
15
+ function _export(target, all) {
16
+ for(var name in all)Object.defineProperty(target, name, {
17
+ enumerable: true,
18
+ get: Object.getOwnPropertyDescriptor(all, name).get
19
+ });
20
+ }
21
+ _export(exports, {
22
+ get getRuleDocumentationUrl () {
23
+ return getRuleDocumentationUrl;
24
+ },
25
+ get labelToAnchor () {
26
+ return labelToAnchor;
27
+ }
28
+ });
29
+ function labelToAnchor(label) {
30
+ return label.toLowerCase().replace(/\s+/g, '-') // Replace spaces with hyphens
31
+ .replace(/[^a-z0-9-]/g, '') // Remove non-alphanumeric except hyphens
32
+ .replace(/-+/g, '-') // Collapse multiple hyphens
33
+ .replace(/^-|-$/g, ''); // Trim leading/trailing hyphens
34
+ }
35
+ function getRuleDocumentationUrl(label, customUrl) {
36
+ if (customUrl) {
37
+ return customUrl;
38
+ }
39
+ const anchor = labelToAnchor(label);
40
+ return `https://flow-scanner.github.io/lightning-flow-scanner/#${anchor}`;
41
+ }
@@ -20,6 +20,7 @@ const _internals = require("../../main/internals/internals");
20
20
  const _IRulesConfig = require("../interfaces/IRulesConfig");
21
21
  const _Violation = require("../models/Violation");
22
22
  const _GetRuleDefinitions = require("./GetRuleDefinitions");
23
+ const _RuleDocumentation = require("./RuleDocumentation");
23
24
  function getRuleConfigByIdOrName(rule, rulesConfig) {
24
25
  if (!rulesConfig) return undefined;
25
26
  // Try ruleId first, then fall back to name
@@ -76,10 +77,16 @@ function ScanFlows(flows, ruleOptions) {
76
77
  const config = getRuleConfigByIdOrName(rule, ruleOptions === null || ruleOptions === void 0 ? void 0 : ruleOptions.rules);
77
78
  const suppressions = getSuppressionsForRule(rule, flow.name, ruleOptions === null || ruleOptions === void 0 ? void 0 : ruleOptions.exceptions);
78
79
  const result = config && Object.keys(config).length > 0 ? rule.execute(flow, config, suppressions) : rule.execute(flow, undefined, suppressions);
79
- // Apply custom message if provided in config
80
+ // Apply custom message if provided in config, otherwise use summary
80
81
  if (config && typeof config === 'object' && 'message' in config && typeof config.message === 'string') {
81
82
  result.message = config.message;
83
+ } else {
84
+ // Use summary if available, otherwise fallback to description
85
+ result.message = result.ruleDefinition.summary || result.ruleDefinition.description;
82
86
  }
87
+ // Apply custom messageUrl if provided in config, otherwise auto-generate from rule label
88
+ const customUrl = config && typeof config === 'object' && 'messageUrl' in config && typeof config.messageUrl === 'string' ? config.messageUrl : undefined;
89
+ result.messageUrl = (0, _RuleDocumentation.getRuleDocumentationUrl)(result.ruleDefinition.label, customUrl);
83
90
  if (result.details.length > 0) {
84
91
  let flowXml = flowXmlCache.get(flow.name);
85
92
  if (!flowXml) {
@@ -2,9 +2,11 @@ import { Violation } from "./Violation";
2
2
  export interface FlatViolation extends Omit<Violation, 'details'> {
3
3
  flowFile: string;
4
4
  flowName: string;
5
+ ruleId: string;
5
6
  ruleName: string;
6
7
  severity: string;
7
8
  message?: string;
9
+ messageUrl?: string;
8
10
  dataType?: string;
9
11
  locationX?: string;
10
12
  locationY?: string;
@@ -1,7 +1,9 @@
1
1
  import { RuleInfo } from "./RuleInfo";
2
2
  import * as core from "../internals/internals";
3
3
  export declare abstract class RuleCommon {
4
+ category?: 'problem' | 'suggestion' | 'layout';
4
5
  description: string;
6
+ summary: string;
5
7
  docRefs: Array<{
6
8
  label: string;
7
9
  path: string;
@@ -127,7 +127,9 @@ let RuleCommon = class RuleCommon {
127
127
  return undefined;
128
128
  }
129
129
  constructor(info, optional){
130
+ _define_property(this, "category", void 0);
130
131
  _define_property(this, "description", void 0);
132
+ _define_property(this, "summary", void 0);
131
133
  _define_property(this, "docRefs", []);
132
134
  _define_property(this, "isConfigurable", void 0);
133
135
  _define_property(this, "label", void 0);
@@ -136,11 +138,13 @@ let RuleCommon = class RuleCommon {
136
138
  _define_property(this, "supportedTypes", void 0);
137
139
  _define_property(this, "uri", void 0);
138
140
  _define_property(this, "ruleId", void 0);
141
+ this.category = info.category;
139
142
  this.ruleId = info.ruleId;
140
143
  this.name = info.name;
141
144
  this.supportedTypes = info.supportedTypes;
142
145
  this.label = info.label;
143
146
  this.description = info.description;
147
+ this.summary = info.summary;
144
148
  this.uri = `https://github.com/Lightning-Flow-Scanner/lightning-flow-scanner/tree/main/src/main/rules/${info.name}.ts`;
145
149
  this.docRefs = info.docRefs;
146
150
  const checkImpl = this.check;
@@ -11,6 +11,10 @@ export declare class RuleInfo {
11
11
  * A human-readable description of the rule.
12
12
  */
13
13
  description: string;
14
+ /**
15
+ * A short summary (5-10 words) used when no custom message is provided.
16
+ */
17
+ summary: string;
14
18
  /**
15
19
  * An array of documentation references related to the rule.
16
20
  */
@@ -23,6 +27,11 @@ export declare class RuleInfo {
23
27
  * This property is being displayed on sf cli and on vsce
24
28
  */
25
29
  label: string;
30
+ /**
31
+ * The category for the rule.
32
+ * 'problem' | 'suggestion' | 'layout'
33
+ */
34
+ category: 'problem' | 'suggestion' | 'layout';
26
35
  /**
27
36
  * Stable public identifier used for config, suppression, and reporting.
28
37
  */
@@ -27,6 +27,9 @@ let RuleInfo = class RuleInfo {
27
27
  * A human-readable description of the rule.
28
28
  */ _define_property(this, "description", void 0);
29
29
  /**
30
+ * A short summary (5-10 words) used when no custom message is provided.
31
+ */ _define_property(this, "summary", void 0);
32
+ /**
30
33
  * An array of documentation references related to the rule.
31
34
  */ _define_property(this, "docRefs", void 0);
32
35
  /**
@@ -34,6 +37,10 @@ let RuleInfo = class RuleInfo {
34
37
  * This property is being displayed on sf cli and on vsce
35
38
  */ _define_property(this, "label", void 0);
36
39
  /**
40
+ * The category for the rule.
41
+ * 'problem' | 'suggestion' | 'layout'
42
+ */ _define_property(this, "category", void 0);
43
+ /**
37
44
  * Stable public identifier used for config, suppression, and reporting.
38
45
  */ _define_property(this, "ruleId", void 0);
39
46
  /**
@@ -3,10 +3,12 @@ import { Violation } from "./Violation";
3
3
  export declare class RuleResult {
4
4
  occurs: boolean;
5
5
  ruleName: string;
6
+ ruleId: string;
6
7
  ruleDefinition: IRuleDefinition;
7
8
  severity: string;
8
9
  details: Violation[];
9
10
  errorMessage: string;
10
11
  message?: string;
12
+ messageUrl?: string;
11
13
  constructor(info: IRuleDefinition, details: Violation[], errorMessage?: string);
12
14
  }
@@ -25,13 +25,16 @@ let RuleResult = class RuleResult {
25
25
  constructor(info, details, errorMessage){
26
26
  _define_property(this, "occurs", void 0);
27
27
  _define_property(this, "ruleName", void 0);
28
+ _define_property(this, "ruleId", void 0);
28
29
  _define_property(this, "ruleDefinition", void 0);
29
30
  _define_property(this, "severity", void 0);
30
31
  _define_property(this, "details", []);
31
32
  _define_property(this, "errorMessage", void 0);
32
33
  _define_property(this, "message", void 0); // Custom message that overrides the default rule description
34
+ _define_property(this, "messageUrl", void 0); // URL to custom documentation (fallback to rule docs if not provided)
33
35
  this.ruleDefinition = info;
34
36
  this.ruleName = info.name;
37
+ this.ruleId = info.ruleId;
35
38
  this.severity = info.severity ? info.severity : "warning";
36
39
  this.occurs = false;
37
40
  this.details = details;
@@ -114,9 +114,11 @@ let APIVersion = class APIVersion extends _RuleCommon.RuleCommon {
114
114
  constructor(){
115
115
  super({
116
116
  ruleId: "invalid-api-version",
117
+ category: "suggestion",
117
118
  name: "APIVersion",
118
119
  label: "Invalid API Version",
119
120
  description: "Flows running on outdated API versions may behave inconsistently when newer platform features or components are used. From API version 50.0 onward, the API Version attribute explicitly controls Flow runtime behavior. Keeping Flows aligned with a supported API version helps prevent compatibility issues and ensures predictable execution.",
121
+ summary: "Outdated API versions risk compatibility issues",
120
122
  supportedTypes: _internals.FlowType.allTypes(),
121
123
  docRefs: []
122
124
  });
@@ -20,7 +20,9 @@ let ActionCallsInLoop = class ActionCallsInLoop extends _LoopRuleCommon.LoopRule
20
20
  constructor(){
21
21
  super({
22
22
  ruleId: "action-call-in-loop",
23
+ category: "suggestion",
23
24
  description: "Repeatedly invoking Apex actions inside a loop can exhaust governor limits and lead to performance issues. Where possible, bulkify your logic by moving the action call outside the loop and passing a collection variable instead.",
25
+ summary: "Action calls inside loop risk governor limits",
24
26
  docRefs: [
25
27
  {
26
28
  label: "Action Call In A Loop",
@@ -66,9 +66,11 @@ let AutoLayout = class AutoLayout extends _RuleCommon.RuleCommon {
66
66
  constructor(){
67
67
  super({
68
68
  ruleId: "missing-auto-layout",
69
+ category: "layout",
69
70
  name: "AutoLayout",
70
71
  label: "Missing Auto Layout",
71
72
  description: "Auto-Layout automatically arranges and aligns Flow elements, keeping the canvas organized and easier to maintain. Enabling it saves time and improves readability.",
73
+ summary: "Auto-Layout improves canvas organization and readability",
72
74
  supportedTypes: _internals.FlowType.allTypes(),
73
75
  docRefs: []
74
76
  }, {
@@ -60,9 +60,11 @@ let CopyAPIName = class CopyAPIName extends _RuleCommon.RuleCommon {
60
60
  constructor(){
61
61
  super({
62
62
  ruleId: "unclear-api-naming",
63
+ category: "layout",
63
64
  name: "CopyAPIName",
64
65
  label: "Unclear API Name",
65
66
  description: "Elements with unclear or duplicated API names, like Copy_X_Of_Element, reduce Flow readability. Make sure to update the API name when copying elements to keep your Flow organized.",
67
+ summary: "Duplicated API names reduce Flow readability",
66
68
  supportedTypes: _internals.FlowType.allTypes(),
67
69
  docRefs: []
68
70
  });
@@ -88,9 +88,11 @@ let CyclomaticComplexity = class CyclomaticComplexity extends _RuleCommon.RuleCo
88
88
  constructor(){
89
89
  super({
90
90
  ruleId: "excessive-cyclomatic-complexity",
91
+ category: "suggestion",
91
92
  name: "CyclomaticComplexity",
92
93
  label: "Excessive Cyclomatic Complexity",
93
- description: "High numbers of loops and decision elements increase a Flows cyclomatic complexity. To maintain simplicity and readability, consider using subflows or splitting a Flow into smaller, ordered Flows.",
94
+ description: "High numbers of loops and decision elements increase a Flow's cyclomatic complexity. To maintain simplicity and readability, consider using subflows or splitting a Flow into smaller, ordered Flows.",
95
+ summary: "Too many loops and decisions harm readability",
94
96
  supportedTypes: _internals.FlowType.backEndTypes,
95
97
  docRefs: [
96
98
  {
@@ -21,7 +21,9 @@ let DMLStatementInLoop = class DMLStatementInLoop extends _LoopRuleCommon.LoopRu
21
21
  constructor(){
22
22
  super({
23
23
  ruleId: "dml-in-loop",
24
+ category: "problem",
24
25
  description: "Executing DML operations (insert, update, delete) inside a loop is a high-risk anti-pattern that frequently causes governor limit exceptions. All database operations should be collected and executed once, outside the loop.",
26
+ summary: "DML operations inside loop risk governor limits",
25
27
  docRefs: [
26
28
  {
27
29
  label: "Flow Best Practices",
@@ -95,9 +95,11 @@ let DuplicateDMLOperation = class DuplicateDMLOperation extends _RuleCommon.Rule
95
95
  constructor(){
96
96
  super({
97
97
  ruleId: "duplicate-dml",
98
+ category: "problem",
98
99
  name: "DuplicateDMLOperation",
99
100
  label: "Duplicate DML Operation",
100
101
  description: "When a Flow performs database operations across multiple screens, users navigating backward can cause the same actions to run multiple times. To prevent unintended changes, either restrict backward navigation or redesign the Flow so database operations execute in a single, forward-moving step.",
102
+ summary: "DML across screens may execute multiple times",
101
103
  supportedTypes: _internals.FlowType.visualTypes,
102
104
  docRefs: []
103
105
  });
@@ -64,7 +64,9 @@ let FlowDescription = class FlowDescription extends _RuleCommon.RuleCommon {
64
64
  constructor(){
65
65
  super({
66
66
  ruleId: "missing-flow-description",
67
- description: "Flow descriptions are essential for documentation and maintainability. Include a description for each Flow, explaining its purpose and where it’s used.",
67
+ category: "layout",
68
+ description: "Flow descriptions are essential for documentation and maintainability. Include a description for each Flow, explaining its purpose and where it's used.",
69
+ summary: "Flow descriptions improve documentation and maintainability",
68
70
  docRefs: [],
69
71
  label: "Missing Flow Description",
70
72
  name: "FlowDescription",
@@ -67,7 +67,9 @@ let FlowName = class FlowName extends _RuleCommon.RuleCommon {
67
67
  constructor(){
68
68
  super({
69
69
  ruleId: "invalid-naming-convention",
70
- description: "Using clear and consistent Flow names improves readability, discoverability, and maintainability. A good naming convention helps team members quickly understand a Flow’s purpose—for example, including a domain and brief description like Service_OrderFulfillment. Adopt a naming pattern that aligns with your organization’s standards.",
70
+ category: "layout",
71
+ description: "Using clear and consistent Flow names improves readability, discoverability, and maintainability. A good naming convention helps team members quickly understand a Flow's purpose—for example, including a domain and brief description like Service_OrderFulfillment. Adopt a naming pattern that aligns with your organization's standards.",
72
+ summary: "Consistent naming improves Flow discoverability and maintainability",
71
73
  docRefs: [
72
74
  {
73
75
  label: "Naming your Flows is more critical than ever. By Stephen Church",
@@ -69,7 +69,9 @@ let GetRecordAllFields = class GetRecordAllFields extends _RuleCommon.RuleCommon
69
69
  constructor(){
70
70
  super({
71
71
  ruleId: "get-record-all-fields",
72
+ category: "suggestion",
72
73
  description: "Avoid using Get Records to retrieve all fields unless necessary. This improves performance, reduces processing time, and limits exposure of unnecessary data.",
74
+ summary: "Retrieving all fields harms performance and security",
73
75
  docRefs: [
74
76
  {
75
77
  label: "Get Records Stores All Fields",
@@ -60,8 +60,10 @@ let HardcodedId = class HardcodedId extends _RuleCommon.RuleCommon {
60
60
  super({
61
61
  ruleId: "hardcoded-id",
62
62
  name: "HardcodedId",
63
+ category: "problem",
63
64
  label: "Hardcoded Id",
64
65
  description: "Avoid hard-coding record IDs, as they are unique to a specific org and will not work in other environments. Instead, store IDs in variables—such as merge-field URL parameters or a **Get Records** element—to make the Flow portable, maintainable, and flexible.",
66
+ summary: "Hardcoded IDs break portability across environments",
65
67
  supportedTypes: _internals.FlowType.allTypes(),
66
68
  docRefs: [
67
69
  {
@@ -19,7 +19,9 @@ let HardcodedUrl = class HardcodedUrl extends _RuleCommon.RuleCommon {
19
19
  constructor(){
20
20
  super({
21
21
  ruleId: "hardcoded-url",
22
+ category: "problem",
22
23
  description: "Avoid hard-coding URLs, as they may change between environments or over time. Instead, store URLs in variables or custom settings to make the Flow adaptable, maintainable, and environment-independent.",
24
+ summary: "Hardcoded URLs break across different environments",
23
25
  docRefs: [
24
26
  {
25
27
  label: "The Ultimate Guide to Salesforce Flow Best Practices",
@@ -63,9 +63,11 @@ let InactiveFlow = class InactiveFlow extends _RuleCommon.RuleCommon {
63
63
  constructor(){
64
64
  super({
65
65
  ruleId: "inactive-flow",
66
+ category: "suggestion",
66
67
  name: "InactiveFlow",
67
68
  label: "Inactive Flow",
68
69
  description: "Inactive Flows should be deleted or archived to reduce risk. Even when inactive, they can cause unintended record changes during testing or be activated as subflows. Keeping only active, relevant Flows improves safety and maintainability.",
70
+ summary: "Inactive Flows should be deleted or archived",
69
71
  supportedTypes: _internals.FlowType.allTypes(),
70
72
  docRefs: []
71
73
  });
@@ -127,7 +127,9 @@ let MissingFaultPath = class MissingFaultPath extends _RuleCommon.RuleCommon {
127
127
  constructor(){
128
128
  super({
129
129
  ruleId: "missing-fault-path",
130
+ category: "problem",
130
131
  description: "Elements that can fail should include a Fault Path to handle errors gracefully. Without it, failures show generic errors to users. Fault Paths improve reliability and user experience.",
132
+ summary: "Fault Paths enable graceful error handling",
131
133
  docRefs: [
132
134
  {
133
135
  label: "Flow Best Practices",
@@ -66,7 +66,9 @@ let MissingMetadataDescription = class MissingMetadataDescription extends _RuleC
66
66
  constructor(){
67
67
  super({
68
68
  ruleId: "missing-metadata-description",
69
+ category: "layout",
69
70
  description: "Elements and metadata without a description reduce clarity and maintainability. Adding descriptions improves readability and makes your automation easier to understand.",
71
+ summary: "Element descriptions improve clarity and maintainability",
70
72
  docRefs: [],
71
73
  label: "Missing Metadata Description",
72
74
  name: "MissingMetadataDescription",
@@ -138,7 +138,9 @@ let MissingNullHandler = class MissingNullHandler extends _RuleCommon.RuleCommon
138
138
  constructor(){
139
139
  super({
140
140
  ruleId: "missing-null-handler",
141
+ category: "problem",
141
142
  description: "Get Records operations return null when no data is found. Without handling these null values, Flows can fail or produce unintended results. Adding a null check improves reliability and ensures the Flow behaves as expected.",
143
+ summary: "Null checks prevent failures from missing records",
142
144
  docRefs: [],
143
145
  label: "Missing Null Handler",
144
146
  name: "MissingNullHandler",
@@ -78,9 +78,11 @@ let MissingRecordTriggerFilter = class MissingRecordTriggerFilter extends _RuleC
78
78
  constructor(){
79
79
  super({
80
80
  ruleId: "missing-record-trigger-filter",
81
+ category: "suggestion",
81
82
  name: "MissingRecordTriggerFilter",
82
83
  label: "Missing Filter Record Trigger",
83
84
  description: "Record-triggered Flows without filters on changed fields or entry conditions execute on every record change. Adding filters ensures the Flow runs only when needed, improving performance.",
85
+ summary: "Filters ensure Flows run only when needed",
84
86
  supportedTypes: [
85
87
  _internals.FlowType.autolaunchedType
86
88
  ],
@@ -60,9 +60,11 @@ let ProcessBuilder = class ProcessBuilder extends _RuleCommon.RuleCommon {
60
60
  constructor(){
61
61
  super({
62
62
  ruleId: "process-builder-usage",
63
+ category: "problem",
63
64
  name: "ProcessBuilder",
64
65
  label: "Process Builder",
65
66
  description: "Process Builder is retired. Continuing to use it increases maintenance overhead and risks future compatibility issues. Migrating automation to Flow reduces risk and improves maintainability.",
67
+ summary: "Process Builder is retired, migrate to Flow",
66
68
  supportedTypes: _internals.FlowType.processBuilder,
67
69
  docRefs: [
68
70
  {
@@ -74,9 +74,11 @@ let RecordIdAsString = class RecordIdAsString extends _RuleCommon.RuleCommon {
74
74
  constructor(){
75
75
  super({
76
76
  ruleId: "record-id-as-string",
77
+ category: "suggestion",
77
78
  name: "RecordIdAsString",
78
79
  label: "Record ID as String",
79
80
  description: "Flows that use a String variable for a record ID instead of receiving the full record introduce unnecessary complexity and additional Get Records queries. Using the complete record simplifies the Flow and improves performance.",
81
+ summary: "String record IDs add complexity and queries",
80
82
  supportedTypes: [
81
83
  ..._internals.FlowType.visualTypes,
82
84
  _internals.FlowType.autolaunchedType
@@ -105,7 +105,9 @@ let RecursiveAfterUpdate = class RecursiveAfterUpdate extends _RuleCommon.RuleCo
105
105
  constructor(){
106
106
  super({
107
107
  ruleId: "recursive-record-update",
108
+ category: "problem",
108
109
  description: "After-save Flows that update the same record can trigger recursion, causing unintended behavior or performance issues. Avoid updating the triggering record in after-save Flows; use before-save Flows instead to prevent recursion.",
110
+ summary: "After-save updates to same record trigger recursion",
109
111
  docRefs: [
110
112
  {
111
113
  label: "Learn about same record field updates",
@@ -19,7 +19,9 @@ let SOQLQueryInLoop = class SOQLQueryInLoop extends _LoopRuleCommon.LoopRuleComm
19
19
  constructor(){
20
20
  super({
21
21
  ruleId: "soql-in-loop",
22
+ category: "problem",
22
23
  description: "Running SOQL queries inside a loop can rapidly exceed query limits and severely degrade performance. Queries should be executed once, with results reused throughout the loop.",
24
+ summary: "SOQL queries inside loop risk governor limits",
23
25
  docRefs: [
24
26
  {
25
27
  label: "Flow Best Practices",
@@ -87,9 +87,11 @@ let SameRecordFieldUpdates = class SameRecordFieldUpdates extends _RuleCommon.Ru
87
87
  constructor(){
88
88
  super({
89
89
  ruleId: "same-record-field-updates",
90
+ category: "suggestion",
90
91
  name: "SameRecordFieldUpdates",
91
92
  label: "Same Record Field Updates",
92
93
  description: "Before-save Flows can safely update the triggering record directly via $Record, applying changes efficiently without extra DML operations. Using before-save updates improves performance",
94
+ summary: "Before-save Flows can update $Record directly",
93
95
  supportedTypes: [
94
96
  ..._internals.FlowType.backEndTypes
95
97
  ],
@@ -77,9 +77,11 @@ let TransformInsteadOfLoop = class TransformInsteadOfLoop extends _RuleCommon.Ru
77
77
  constructor(){
78
78
  super({
79
79
  ruleId: "transform-instead-of-loop",
80
+ category: "suggestion",
80
81
  name: "TransformInsteadOfLoop",
81
82
  label: "Transform Instead of Loop",
82
83
  description: "Loop elements that perform direct Assignments on each item can slow down Flows. Using Transform elements allows bulk operations on collections, improving performance and reducing complexity.",
84
+ summary: "Transform elements enable faster bulk operations",
83
85
  supportedTypes: _internals.FlowType.allTypes(),
84
86
  docRefs: [
85
87
  {
@@ -69,9 +69,11 @@ let TriggerOrder = class TriggerOrder extends _RuleCommon.RuleCommon {
69
69
  constructor(){
70
70
  super({
71
71
  ruleId: "unspecified-trigger-order",
72
+ category: "suggestion",
72
73
  name: "TriggerOrder",
73
74
  label: "Missing Trigger Order",
74
75
  description: "Record-triggered Flows without a specified Trigger Order may execute in an unpredictable sequence. Setting a Trigger Order ensures your Flows run in the intended order.",
76
+ summary: "Trigger Order ensures predictable execution sequence",
75
77
  supportedTypes: [
76
78
  _internals.FlowType.autolaunchedType
77
79
  ],
@@ -62,7 +62,9 @@ let UnconnectedElement = class UnconnectedElement extends _RuleCommon.RuleCommon
62
62
  constructor(){
63
63
  super({
64
64
  ruleId: "unreachable-element",
65
+ category: "layout",
65
66
  description: "Unconnected elements never execute and add unnecessary clutter. Remove or connect unused Flow elements to keep Flows clean and efficient.",
67
+ summary: "Unconnected elements add clutter without executing",
66
68
  docRefs: [],
67
69
  label: "Unreachable Element",
68
70
  name: "UnconnectedElement",
@@ -68,9 +68,11 @@ let UnsafeRunningContext = class UnsafeRunningContext extends _RuleCommon.RuleCo
68
68
  constructor(){
69
69
  super({
70
70
  ruleId: "unsafe-running-context",
71
+ category: "problem",
71
72
  name: "UnsafeRunningContext",
72
73
  label: "Unsafe Running Context",
73
74
  description: "Flows configured to run in System Mode without Sharing grant access to all data, bypassing user permissions. Avoid this setting to prevent security risks and protect sensitive data.",
75
+ summary: "System mode without sharing creates security risks",
74
76
  supportedTypes: [
75
77
  ..._internals.FlowType.backEndTypes,
76
78
  ..._internals.FlowType.visualTypes
@@ -80,9 +80,11 @@ let UnusedVariable = class UnusedVariable extends _RuleCommon.RuleCommon {
80
80
  constructor(){
81
81
  super({
82
82
  ruleId: "unused-variable",
83
+ category: "layout",
83
84
  name: "UnusedVariable",
84
85
  label: "Unused Variable",
85
86
  description: "Unused variables are never referenced and add unnecessary clutter. Remove them to keep Flows efficient and easy to maintain.",
87
+ summary: "Unused variables add clutter and hurt maintainability",
86
88
  supportedTypes: [
87
89
  ..._internals.FlowType.backEndTypes,
88
90
  ..._internals.FlowType.visualTypes
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@flow-scanner/lightning-flow-scanner-core",
3
3
  "description": "A lightweight engine for Flow metadata in Node.js, and browser environments. Assess and enhance Salesforce Flow automations for best practices, security, governor limits, and performance issues.",
4
- "version": "6.15.0",
4
+ "version": "6.15.2",
5
5
  "main": "index.js",
6
6
  "exports": {
7
7
  ".": {