@flow-scanner/lightning-flow-scanner-core 6.15.0 → 6.15.1
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.
- package/README.md +203 -189
- package/main/interfaces/IRuleConfig.d.ts +2 -0
- package/main/interfaces/IRuleDefinition.d.ts +1 -0
- package/main/libs/ExportDetails.js +3 -1
- package/main/libs/ExportSarif.js +4 -4
- package/main/libs/RuleDocumentation.d.ts +20 -0
- package/main/libs/RuleDocumentation.js +41 -0
- package/main/libs/ScanFlows.js +8 -1
- package/main/models/FlatViolation.d.ts +2 -0
- package/main/models/RuleCommon.d.ts +1 -0
- package/main/models/RuleCommon.js +2 -0
- package/main/models/RuleInfo.d.ts +4 -0
- package/main/models/RuleInfo.js +3 -0
- package/main/models/RuleResult.d.ts +2 -0
- package/main/models/RuleResult.js +3 -0
- package/main/rules/APIVersion.js +1 -0
- package/main/rules/ActionCallsInLoop.js +1 -0
- package/main/rules/AutoLayout.js +1 -0
- package/main/rules/CopyAPIName.js +1 -0
- package/main/rules/CyclomaticComplexity.js +2 -1
- package/main/rules/DMLStatementInLoop.js +1 -0
- package/main/rules/DuplicateDMLOperation.js +1 -0
- package/main/rules/FlowDescription.js +2 -1
- package/main/rules/FlowName.js +2 -1
- package/main/rules/GetRecordAllFields.js +1 -0
- package/main/rules/HardcodedId.js +1 -0
- package/main/rules/HardcodedUrl.js +1 -0
- package/main/rules/InactiveFlow.js +1 -0
- package/main/rules/MissingFaultPath.js +1 -0
- package/main/rules/MissingMetadataDescription.js +1 -0
- package/main/rules/MissingNullHandler.js +1 -0
- package/main/rules/MissingRecordTriggerFilter.js +1 -0
- package/main/rules/ProcessBuilder.js +1 -0
- package/main/rules/RecordIdAsString.js +1 -0
- package/main/rules/RecursiveAfterUpdate.js +1 -0
- package/main/rules/SOQLQueryInLoop.js +1 -0
- package/main/rules/SameRecordFieldUpdates.js +1 -0
- package/main/rules/TransformInsteadOfLoop.js +1 -0
- package/main/rules/TriggerOrder.js +1 -0
- package/main/rules/UnconnectedElement.js +1 -0
- package/main/rules/UnsafeRunningContext.js +1 -0
- package/main/rules/UnusedVariable.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -53,195 +53,195 @@
|
|
|
53
53
|
|
|
54
54
|
> 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
55
|
|
|
56
|
-
<!-- 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*
|
|
63
|
-
|
|
64
|
-
### DML Statement In A Loop
|
|
65
|
-
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.
|
|
66
|
-
|
|
67
|
-
**Rule ID:** `dml-in-loop`
|
|
68
|
-
**Class Name:** _[DMLStatementInLoop](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/DMLStatementInLoop.ts)_
|
|
69
|
-
**Severity:** 🔴 *Error*
|
|
70
|
-
|
|
71
|
-
### Duplicate DML Operation
|
|
72
|
-
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
|
-
|
|
74
|
-
**Rule ID:** `duplicate-dml`
|
|
75
|
-
**Class Name:** _[DuplicateDMLOperation](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/DuplicateDMLOperation.ts)_
|
|
76
|
-
**Severity:** 🟡 *Warning*
|
|
77
|
-
|
|
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.
|
|
80
|
-
|
|
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*
|
|
84
|
-
|
|
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.
|
|
87
|
-
|
|
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*
|
|
91
|
-
|
|
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.
|
|
94
|
-
|
|
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)_
|
|
97
|
-
**Severity:** 🟡 *Warning*
|
|
98
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
108
|
-
|
|
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*
|
|
112
|
-
|
|
113
|
-
### Inactive Flow
|
|
114
|
-
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.
|
|
115
|
-
|
|
116
|
-
**Rule ID:** `inactive-flow`
|
|
117
|
-
**Class Name:** _[InactiveFlow](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/InactiveFlow.ts)_
|
|
118
|
-
**Severity:** 🟡 *Warning*
|
|
119
|
-
|
|
120
|
-
### Invalid API Version
|
|
121
|
-
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.
|
|
122
|
-
|
|
123
|
-
**Rule ID:** `invalid-api-version`
|
|
124
|
-
**Class Name:** _[APIVersion](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/APIVersion.ts)_
|
|
125
|
-
**Severity:** 🟡 *Warning*
|
|
126
|
-
|
|
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
|
-
### Missing Filter Record Trigger 
|
|
142
|
-
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
|
-
|
|
144
|
-
**Rule ID:** `missing-record-trigger-filter`
|
|
145
|
-
**Class Name:** _[MissingFilterRecordTrigger](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/MissingFilterRecordTrigger.ts)_
|
|
146
|
-
**Severity:** 🟡 *Warning*
|
|
147
|
-
|
|
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 
|
|
156
|
-
Elements and metadata without a description reduce clarity and maintainability. Adding descriptions improves readability and makes your automation easier to understand.
|
|
157
|
-
|
|
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)_
|
|
160
|
-
**Severity:** 🟡 *Warning*
|
|
161
|
-
|
|
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.
|
|
164
|
-
|
|
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*
|
|
168
|
-
|
|
169
|
-
### Missing Trigger Order
|
|
170
|
-
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.
|
|
171
|
-
|
|
172
|
-
**Rule ID:** `unspecified-trigger-order`
|
|
173
|
-
**Class Name:** _[TriggerOrder](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/TriggerOrder.ts)_
|
|
174
|
-
**Severity:** 🔵 *Note*
|
|
175
|
-
|
|
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
|
-
### Record ID as String 
|
|
184
|
-
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
|
-
|
|
186
|
-
**Rule ID:** `record-id-as-string`
|
|
187
|
-
**Class Name:** _[RecordIdAsString](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/RecordIdAsString.ts)_
|
|
188
|
-
**Severity:** 🔵 *Note*
|
|
189
|
-
|
|
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.
|
|
192
|
-
|
|
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*
|
|
196
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
206
|
-
|
|
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
|
-
**Severity:** 🔴 *Error*
|
|
210
|
-
|
|
211
|
-
### Transform Instead of Loop 
|
|
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.
|
|
213
|
-
|
|
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*
|
|
217
|
-
|
|
218
|
-
### Unclear API Name
|
|
219
|
-
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.
|
|
220
|
-
|
|
221
|
-
**Rule ID:** `unclear-api-naming`
|
|
222
|
-
**Class Name:** _[CopyAPIName](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/CopyAPIName.ts)_
|
|
223
|
-
**Severity:** 🟡 *Warning*
|
|
224
|
-
|
|
225
|
-
### Unreachable Element
|
|
226
|
-
Unconnected elements never execute and add unnecessary clutter. Remove or connect unused Flow elements to keep Flows clean and efficient.
|
|
227
|
-
|
|
228
|
-
**Rule ID:** `unreachable-element`
|
|
229
|
-
**Class Name:** _[UnconnectedElement](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/UnconnectedElement.ts)_
|
|
230
|
-
**Severity:** 🟡 *Warning*
|
|
231
|
-
|
|
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
|
-
### Unused Variable
|
|
240
|
-
Unused variables are never referenced and add unnecessary clutter. Remove them to keep Flows efficient and easy to maintain.
|
|
241
|
-
|
|
242
|
-
**Rule ID:** `unused-variable`
|
|
243
|
-
**Class Name:** _[UnusedVariable](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/UnusedVariable.ts)_
|
|
244
|
-
**Severity:** 🟡 *Warning*
|
|
56
|
+
<!-- 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*
|
|
63
|
+
|
|
64
|
+
### DML Statement In A Loop
|
|
65
|
+
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.
|
|
66
|
+
|
|
67
|
+
**Rule ID:** `dml-in-loop`
|
|
68
|
+
**Class Name:** _[DMLStatementInLoop](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/DMLStatementInLoop.ts)_
|
|
69
|
+
**Severity:** 🔴 *Error*
|
|
70
|
+
|
|
71
|
+
### Duplicate DML Operation
|
|
72
|
+
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
|
+
|
|
74
|
+
**Rule ID:** `duplicate-dml`
|
|
75
|
+
**Class Name:** _[DuplicateDMLOperation](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/DuplicateDMLOperation.ts)_
|
|
76
|
+
**Severity:** 🟡 *Warning*
|
|
77
|
+
|
|
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.
|
|
80
|
+
|
|
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*
|
|
84
|
+
|
|
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.
|
|
87
|
+
|
|
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*
|
|
91
|
+
|
|
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.
|
|
94
|
+
|
|
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)_
|
|
97
|
+
**Severity:** 🟡 *Warning*
|
|
98
|
+
|
|
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
|
+
|
|
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
|
+
|
|
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.
|
|
108
|
+
|
|
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*
|
|
112
|
+
|
|
113
|
+
### Inactive Flow
|
|
114
|
+
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.
|
|
115
|
+
|
|
116
|
+
**Rule ID:** `inactive-flow`
|
|
117
|
+
**Class Name:** _[InactiveFlow](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/InactiveFlow.ts)_
|
|
118
|
+
**Severity:** 🟡 *Warning*
|
|
119
|
+
|
|
120
|
+
### Invalid API Version
|
|
121
|
+
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.
|
|
122
|
+
|
|
123
|
+
**Rule ID:** `invalid-api-version`
|
|
124
|
+
**Class Name:** _[APIVersion](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/APIVersion.ts)_
|
|
125
|
+
**Severity:** 🟡 *Warning*
|
|
126
|
+
|
|
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
|
+
### Missing Filter Record Trigger 
|
|
142
|
+
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
|
+
|
|
144
|
+
**Rule ID:** `missing-record-trigger-filter`
|
|
145
|
+
**Class Name:** _[MissingFilterRecordTrigger](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/MissingFilterRecordTrigger.ts)_
|
|
146
|
+
**Severity:** 🟡 *Warning*
|
|
147
|
+
|
|
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 
|
|
156
|
+
Elements and metadata without a description reduce clarity and maintainability. Adding descriptions improves readability and makes your automation easier to understand.
|
|
157
|
+
|
|
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)_
|
|
160
|
+
**Severity:** 🟡 *Warning*
|
|
161
|
+
|
|
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.
|
|
164
|
+
|
|
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*
|
|
168
|
+
|
|
169
|
+
### Missing Trigger Order
|
|
170
|
+
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.
|
|
171
|
+
|
|
172
|
+
**Rule ID:** `unspecified-trigger-order`
|
|
173
|
+
**Class Name:** _[TriggerOrder](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/TriggerOrder.ts)_
|
|
174
|
+
**Severity:** 🔵 *Note*
|
|
175
|
+
|
|
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
|
+
### Record ID as String 
|
|
184
|
+
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
|
+
|
|
186
|
+
**Rule ID:** `record-id-as-string`
|
|
187
|
+
**Class Name:** _[RecordIdAsString](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/RecordIdAsString.ts)_
|
|
188
|
+
**Severity:** 🔵 *Note*
|
|
189
|
+
|
|
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.
|
|
192
|
+
|
|
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*
|
|
196
|
+
|
|
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
|
+
|
|
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
|
+
|
|
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.
|
|
206
|
+
|
|
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
|
+
**Severity:** 🔴 *Error*
|
|
210
|
+
|
|
211
|
+
### Transform Instead of Loop 
|
|
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.
|
|
213
|
+
|
|
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*
|
|
217
|
+
|
|
218
|
+
### Unclear API Name
|
|
219
|
+
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.
|
|
220
|
+
|
|
221
|
+
**Rule ID:** `unclear-api-naming`
|
|
222
|
+
**Class Name:** _[CopyAPIName](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/CopyAPIName.ts)_
|
|
223
|
+
**Severity:** 🟡 *Warning*
|
|
224
|
+
|
|
225
|
+
### Unreachable Element
|
|
226
|
+
Unconnected elements never execute and add unnecessary clutter. Remove or connect unused Flow elements to keep Flows clean and efficient.
|
|
227
|
+
|
|
228
|
+
**Rule ID:** `unreachable-element`
|
|
229
|
+
**Class Name:** _[UnconnectedElement](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/UnconnectedElement.ts)_
|
|
230
|
+
**Severity:** 🟡 *Warning*
|
|
231
|
+
|
|
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
|
+
### Unused Variable
|
|
240
|
+
Unused variables are never referenced and add unnecessary clutter. Remove them to keep Flows efficient and easy to maintain.
|
|
241
|
+
|
|
242
|
+
**Rule ID:** `unused-variable`
|
|
243
|
+
**Class Name:** _[UnusedVariable](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/UnusedVariable.ts)_
|
|
244
|
+
**Severity:** 🟡 *Warning*
|
|
245
245
|
<!-- END GENERATED_RULES -->
|
|
246
246
|
|
|
247
247
|
---
|
|
@@ -278,6 +278,7 @@ By default, all default rules are executed. You can customize individual rules a
|
|
|
278
278
|
"severity": "<Severity>", // Override severity level
|
|
279
279
|
"expression": "<Expression>", // Override rule expression
|
|
280
280
|
"message": "<Message>", // Set custom message
|
|
281
|
+
"messageUrl": "<URL>", // Set custom documentation URL
|
|
281
282
|
"enabled": false // Disable this rule
|
|
282
283
|
}
|
|
283
284
|
}
|
|
@@ -299,6 +300,19 @@ When the severity is not provided it will be `warning` by default. Other availab
|
|
|
299
300
|
}
|
|
300
301
|
```
|
|
301
302
|
|
|
303
|
+
If not provided, `message` shows the standard rule summary and `messageUrl` links to the README; providing either overrides the default behavior.
|
|
304
|
+
|
|
305
|
+
```json
|
|
306
|
+
{
|
|
307
|
+
"rules": {
|
|
308
|
+
"dml-in-loop": {
|
|
309
|
+
"message": "Avoid DML inside loops. Bulkify operations instead.",
|
|
310
|
+
"messageUrl": "https://internal.docs.company.com/salesforce/flow-dml-best-practices"
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
302
316
|
### Overwrite Expressions
|
|
303
317
|
|
|
304
318
|
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.
|
|
@@ -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) {
|
package/main/libs/ExportSarif.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
86
|
+
id: r.ruleId,
|
|
87
87
|
shortDescription: {
|
|
88
|
-
text: r.message || r.ruleDefinition.description || r.
|
|
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
|
+
}
|
package/main/libs/ScanFlows.js
CHANGED
|
@@ -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;
|
|
@@ -128,6 +128,7 @@ let RuleCommon = class RuleCommon {
|
|
|
128
128
|
}
|
|
129
129
|
constructor(info, optional){
|
|
130
130
|
_define_property(this, "description", void 0);
|
|
131
|
+
_define_property(this, "summary", void 0);
|
|
131
132
|
_define_property(this, "docRefs", []);
|
|
132
133
|
_define_property(this, "isConfigurable", void 0);
|
|
133
134
|
_define_property(this, "label", void 0);
|
|
@@ -141,6 +142,7 @@ let RuleCommon = class RuleCommon {
|
|
|
141
142
|
this.supportedTypes = info.supportedTypes;
|
|
142
143
|
this.label = info.label;
|
|
143
144
|
this.description = info.description;
|
|
145
|
+
this.summary = info.summary;
|
|
144
146
|
this.uri = `https://github.com/Lightning-Flow-Scanner/lightning-flow-scanner/tree/main/src/main/rules/${info.name}.ts`;
|
|
145
147
|
this.docRefs = info.docRefs;
|
|
146
148
|
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
|
*/
|
package/main/models/RuleInfo.js
CHANGED
|
@@ -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
|
/**
|
|
@@ -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;
|
package/main/rules/APIVersion.js
CHANGED
|
@@ -117,6 +117,7 @@ let APIVersion = class APIVersion extends _RuleCommon.RuleCommon {
|
|
|
117
117
|
name: "APIVersion",
|
|
118
118
|
label: "Invalid API Version",
|
|
119
119
|
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.",
|
|
120
|
+
summary: "Outdated API versions risk compatibility issues",
|
|
120
121
|
supportedTypes: _internals.FlowType.allTypes(),
|
|
121
122
|
docRefs: []
|
|
122
123
|
});
|
|
@@ -21,6 +21,7 @@ let ActionCallsInLoop = class ActionCallsInLoop extends _LoopRuleCommon.LoopRule
|
|
|
21
21
|
super({
|
|
22
22
|
ruleId: "action-call-in-loop",
|
|
23
23
|
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.",
|
|
24
|
+
summary: "Action calls inside loop risk governor limits",
|
|
24
25
|
docRefs: [
|
|
25
26
|
{
|
|
26
27
|
label: "Action Call In A Loop",
|
package/main/rules/AutoLayout.js
CHANGED
|
@@ -69,6 +69,7 @@ let AutoLayout = class AutoLayout extends _RuleCommon.RuleCommon {
|
|
|
69
69
|
name: "AutoLayout",
|
|
70
70
|
label: "Missing Auto Layout",
|
|
71
71
|
description: "Auto-Layout automatically arranges and aligns Flow elements, keeping the canvas organized and easier to maintain. Enabling it saves time and improves readability.",
|
|
72
|
+
summary: "Auto-Layout improves canvas organization and readability",
|
|
72
73
|
supportedTypes: _internals.FlowType.allTypes(),
|
|
73
74
|
docRefs: []
|
|
74
75
|
}, {
|
|
@@ -63,6 +63,7 @@ let CopyAPIName = class CopyAPIName extends _RuleCommon.RuleCommon {
|
|
|
63
63
|
name: "CopyAPIName",
|
|
64
64
|
label: "Unclear API Name",
|
|
65
65
|
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.",
|
|
66
|
+
summary: "Duplicated API names reduce Flow readability",
|
|
66
67
|
supportedTypes: _internals.FlowType.allTypes(),
|
|
67
68
|
docRefs: []
|
|
68
69
|
});
|
|
@@ -90,7 +90,8 @@ let CyclomaticComplexity = class CyclomaticComplexity extends _RuleCommon.RuleCo
|
|
|
90
90
|
ruleId: "excessive-cyclomatic-complexity",
|
|
91
91
|
name: "CyclomaticComplexity",
|
|
92
92
|
label: "Excessive Cyclomatic Complexity",
|
|
93
|
-
description: "High numbers of loops and decision elements increase a Flow
|
|
93
|
+
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.",
|
|
94
|
+
summary: "Too many loops and decisions harm readability",
|
|
94
95
|
supportedTypes: _internals.FlowType.backEndTypes,
|
|
95
96
|
docRefs: [
|
|
96
97
|
{
|
|
@@ -22,6 +22,7 @@ let DMLStatementInLoop = class DMLStatementInLoop extends _LoopRuleCommon.LoopRu
|
|
|
22
22
|
super({
|
|
23
23
|
ruleId: "dml-in-loop",
|
|
24
24
|
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.",
|
|
25
|
+
summary: "DML operations inside loop risk governor limits",
|
|
25
26
|
docRefs: [
|
|
26
27
|
{
|
|
27
28
|
label: "Flow Best Practices",
|
|
@@ -98,6 +98,7 @@ let DuplicateDMLOperation = class DuplicateDMLOperation extends _RuleCommon.Rule
|
|
|
98
98
|
name: "DuplicateDMLOperation",
|
|
99
99
|
label: "Duplicate DML Operation",
|
|
100
100
|
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.",
|
|
101
|
+
summary: "DML across screens may execute multiple times",
|
|
101
102
|
supportedTypes: _internals.FlowType.visualTypes,
|
|
102
103
|
docRefs: []
|
|
103
104
|
});
|
|
@@ -64,7 +64,8 @@ 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
|
|
67
|
+
description: "Flow descriptions are essential for documentation and maintainability. Include a description for each Flow, explaining its purpose and where it's used.",
|
|
68
|
+
summary: "Flow descriptions improve documentation and maintainability",
|
|
68
69
|
docRefs: [],
|
|
69
70
|
label: "Missing Flow Description",
|
|
70
71
|
name: "FlowDescription",
|
package/main/rules/FlowName.js
CHANGED
|
@@ -67,7 +67,8 @@ 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
|
|
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.",
|
|
71
|
+
summary: "Consistent naming improves Flow discoverability and maintainability",
|
|
71
72
|
docRefs: [
|
|
72
73
|
{
|
|
73
74
|
label: "Naming your Flows is more critical than ever. By Stephen Church",
|
|
@@ -70,6 +70,7 @@ let GetRecordAllFields = class GetRecordAllFields extends _RuleCommon.RuleCommon
|
|
|
70
70
|
super({
|
|
71
71
|
ruleId: "get-record-all-fields",
|
|
72
72
|
description: "Avoid using Get Records to retrieve all fields unless necessary. This improves performance, reduces processing time, and limits exposure of unnecessary data.",
|
|
73
|
+
summary: "Retrieving all fields harms performance and security",
|
|
73
74
|
docRefs: [
|
|
74
75
|
{
|
|
75
76
|
label: "Get Records Stores All Fields",
|
|
@@ -62,6 +62,7 @@ let HardcodedId = class HardcodedId extends _RuleCommon.RuleCommon {
|
|
|
62
62
|
name: "HardcodedId",
|
|
63
63
|
label: "Hardcoded Id",
|
|
64
64
|
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.",
|
|
65
|
+
summary: "Hardcoded IDs break portability across environments",
|
|
65
66
|
supportedTypes: _internals.FlowType.allTypes(),
|
|
66
67
|
docRefs: [
|
|
67
68
|
{
|
|
@@ -20,6 +20,7 @@ let HardcodedUrl = class HardcodedUrl extends _RuleCommon.RuleCommon {
|
|
|
20
20
|
super({
|
|
21
21
|
ruleId: "hardcoded-url",
|
|
22
22
|
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.",
|
|
23
|
+
summary: "Hardcoded URLs break across different environments",
|
|
23
24
|
docRefs: [
|
|
24
25
|
{
|
|
25
26
|
label: "The Ultimate Guide to Salesforce Flow Best Practices",
|
|
@@ -66,6 +66,7 @@ let InactiveFlow = class InactiveFlow extends _RuleCommon.RuleCommon {
|
|
|
66
66
|
name: "InactiveFlow",
|
|
67
67
|
label: "Inactive Flow",
|
|
68
68
|
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.",
|
|
69
|
+
summary: "Inactive Flows should be deleted or archived",
|
|
69
70
|
supportedTypes: _internals.FlowType.allTypes(),
|
|
70
71
|
docRefs: []
|
|
71
72
|
});
|
|
@@ -128,6 +128,7 @@ let MissingFaultPath = class MissingFaultPath extends _RuleCommon.RuleCommon {
|
|
|
128
128
|
super({
|
|
129
129
|
ruleId: "missing-fault-path",
|
|
130
130
|
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.",
|
|
131
|
+
summary: "Fault Paths enable graceful error handling",
|
|
131
132
|
docRefs: [
|
|
132
133
|
{
|
|
133
134
|
label: "Flow Best Practices",
|
|
@@ -67,6 +67,7 @@ let MissingMetadataDescription = class MissingMetadataDescription extends _RuleC
|
|
|
67
67
|
super({
|
|
68
68
|
ruleId: "missing-metadata-description",
|
|
69
69
|
description: "Elements and metadata without a description reduce clarity and maintainability. Adding descriptions improves readability and makes your automation easier to understand.",
|
|
70
|
+
summary: "Element descriptions improve clarity and maintainability",
|
|
70
71
|
docRefs: [],
|
|
71
72
|
label: "Missing Metadata Description",
|
|
72
73
|
name: "MissingMetadataDescription",
|
|
@@ -139,6 +139,7 @@ let MissingNullHandler = class MissingNullHandler extends _RuleCommon.RuleCommon
|
|
|
139
139
|
super({
|
|
140
140
|
ruleId: "missing-null-handler",
|
|
141
141
|
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.",
|
|
142
|
+
summary: "Null checks prevent failures from missing records",
|
|
142
143
|
docRefs: [],
|
|
143
144
|
label: "Missing Null Handler",
|
|
144
145
|
name: "MissingNullHandler",
|
|
@@ -81,6 +81,7 @@ let MissingRecordTriggerFilter = class MissingRecordTriggerFilter extends _RuleC
|
|
|
81
81
|
name: "MissingRecordTriggerFilter",
|
|
82
82
|
label: "Missing Filter Record Trigger",
|
|
83
83
|
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.",
|
|
84
|
+
summary: "Filters ensure Flows run only when needed",
|
|
84
85
|
supportedTypes: [
|
|
85
86
|
_internals.FlowType.autolaunchedType
|
|
86
87
|
],
|
|
@@ -63,6 +63,7 @@ let ProcessBuilder = class ProcessBuilder extends _RuleCommon.RuleCommon {
|
|
|
63
63
|
name: "ProcessBuilder",
|
|
64
64
|
label: "Process Builder",
|
|
65
65
|
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.",
|
|
66
|
+
summary: "Process Builder is retired, migrate to Flow",
|
|
66
67
|
supportedTypes: _internals.FlowType.processBuilder,
|
|
67
68
|
docRefs: [
|
|
68
69
|
{
|
|
@@ -77,6 +77,7 @@ let RecordIdAsString = class RecordIdAsString extends _RuleCommon.RuleCommon {
|
|
|
77
77
|
name: "RecordIdAsString",
|
|
78
78
|
label: "Record ID as String",
|
|
79
79
|
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.",
|
|
80
|
+
summary: "String record IDs add complexity and queries",
|
|
80
81
|
supportedTypes: [
|
|
81
82
|
..._internals.FlowType.visualTypes,
|
|
82
83
|
_internals.FlowType.autolaunchedType
|
|
@@ -106,6 +106,7 @@ let RecursiveAfterUpdate = class RecursiveAfterUpdate extends _RuleCommon.RuleCo
|
|
|
106
106
|
super({
|
|
107
107
|
ruleId: "recursive-record-update",
|
|
108
108
|
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.",
|
|
109
|
+
summary: "After-save updates to same record trigger recursion",
|
|
109
110
|
docRefs: [
|
|
110
111
|
{
|
|
111
112
|
label: "Learn about same record field updates",
|
|
@@ -20,6 +20,7 @@ let SOQLQueryInLoop = class SOQLQueryInLoop extends _LoopRuleCommon.LoopRuleComm
|
|
|
20
20
|
super({
|
|
21
21
|
ruleId: "soql-in-loop",
|
|
22
22
|
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.",
|
|
23
|
+
summary: "SOQL queries inside loop risk governor limits",
|
|
23
24
|
docRefs: [
|
|
24
25
|
{
|
|
25
26
|
label: "Flow Best Practices",
|
|
@@ -90,6 +90,7 @@ let SameRecordFieldUpdates = class SameRecordFieldUpdates extends _RuleCommon.Ru
|
|
|
90
90
|
name: "SameRecordFieldUpdates",
|
|
91
91
|
label: "Same Record Field Updates",
|
|
92
92
|
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",
|
|
93
|
+
summary: "Before-save Flows can update $Record directly",
|
|
93
94
|
supportedTypes: [
|
|
94
95
|
..._internals.FlowType.backEndTypes
|
|
95
96
|
],
|
|
@@ -80,6 +80,7 @@ let TransformInsteadOfLoop = class TransformInsteadOfLoop extends _RuleCommon.Ru
|
|
|
80
80
|
name: "TransformInsteadOfLoop",
|
|
81
81
|
label: "Transform Instead of Loop",
|
|
82
82
|
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.",
|
|
83
|
+
summary: "Transform elements enable faster bulk operations",
|
|
83
84
|
supportedTypes: _internals.FlowType.allTypes(),
|
|
84
85
|
docRefs: [
|
|
85
86
|
{
|
|
@@ -72,6 +72,7 @@ let TriggerOrder = class TriggerOrder extends _RuleCommon.RuleCommon {
|
|
|
72
72
|
name: "TriggerOrder",
|
|
73
73
|
label: "Missing Trigger Order",
|
|
74
74
|
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.",
|
|
75
|
+
summary: "Trigger Order ensures predictable execution sequence",
|
|
75
76
|
supportedTypes: [
|
|
76
77
|
_internals.FlowType.autolaunchedType
|
|
77
78
|
],
|
|
@@ -63,6 +63,7 @@ let UnconnectedElement = class UnconnectedElement extends _RuleCommon.RuleCommon
|
|
|
63
63
|
super({
|
|
64
64
|
ruleId: "unreachable-element",
|
|
65
65
|
description: "Unconnected elements never execute and add unnecessary clutter. Remove or connect unused Flow elements to keep Flows clean and efficient.",
|
|
66
|
+
summary: "Unconnected elements add clutter without executing",
|
|
66
67
|
docRefs: [],
|
|
67
68
|
label: "Unreachable Element",
|
|
68
69
|
name: "UnconnectedElement",
|
|
@@ -71,6 +71,7 @@ let UnsafeRunningContext = class UnsafeRunningContext extends _RuleCommon.RuleCo
|
|
|
71
71
|
name: "UnsafeRunningContext",
|
|
72
72
|
label: "Unsafe Running Context",
|
|
73
73
|
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.",
|
|
74
|
+
summary: "System mode without sharing creates security risks",
|
|
74
75
|
supportedTypes: [
|
|
75
76
|
..._internals.FlowType.backEndTypes,
|
|
76
77
|
..._internals.FlowType.visualTypes
|
|
@@ -83,6 +83,7 @@ let UnusedVariable = class UnusedVariable extends _RuleCommon.RuleCommon {
|
|
|
83
83
|
name: "UnusedVariable",
|
|
84
84
|
label: "Unused Variable",
|
|
85
85
|
description: "Unused variables are never referenced and add unnecessary clutter. Remove them to keep Flows efficient and easy to maintain.",
|
|
86
|
+
summary: "Unused variables add clutter and hurt maintainability",
|
|
86
87
|
supportedTypes: [
|
|
87
88
|
..._internals.FlowType.backEndTypes,
|
|
88
89
|
..._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.
|
|
4
|
+
"version": "6.15.1",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|