@flow-scanner/lightning-flow-scanner-core 6.17.3 → 6.18.0
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 +247 -224
- package/index.d.ts +4 -3
- package/index.js +14 -0
- package/main/config/RuleRegistry.js +2 -0
- package/main/interfaces/IRuleDefinition.d.ts +1 -0
- package/main/interfaces/IRulesConfig.d.ts +33 -0
- package/main/interfaces/IRulesConfig.js +41 -3
- package/main/libs/FixFlows.d.ts +4 -0
- package/main/libs/FixFlows.js +89 -30
- package/main/libs/GetRuleDefinitions.js +30 -0
- package/main/models/Flow.d.ts +1 -0
- package/main/models/Flow.js +28 -2
- package/main/models/RuleCommon.d.ts +1 -1
- package/main/models/RuleInfo.d.ts +1 -2
- package/main/models/RuleInfo.js +0 -1
- package/main/rules/MissingStartReference.d.ts +7 -0
- package/main/rules/MissingStartReference.js +76 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
- [Configure Rules](#configure-rules)
|
|
40
40
|
- [Define Exceptions](#define-exceptions)
|
|
41
41
|
- [Exclude Flows](#exclude-flows)
|
|
42
|
-
- [Scan
|
|
42
|
+
- [Scan Options](#scan-options)
|
|
43
43
|
- **[Installation](#installation)**
|
|
44
44
|
- [Distributions](#distributions)
|
|
45
45
|
- [CICD Templates](#cicd-templates)
|
|
@@ -55,221 +55,225 @@
|
|
|
55
55
|
|
|
56
56
|
> Want to help improve this project? See our [Contributing Guidelines](https://github.com/Flow-Scanner/lightning-flow-scanner?tab=contributing-ov-file)
|
|
57
57
|
|
|
58
|
-
<!-- START GENERATED_RULES -->
|
|
59
|
-
|
|
60
|
-
---
|
|
61
|
-
|
|
62
|
-
### Problems
|
|
63
|
-
|
|
64
|
-
These rules detect anti-patterns and unsafe practices in your Flows that could break functionality, compromise security, or cause deployment failures.
|
|
65
|
-
|
|
66
|
-
#### DML Statement In A Loop
|
|
67
|
-
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
|
-
|
|
69
|
-
**Rule ID:** `dml-in-loop`
|
|
70
|
-
**Class Name:** _[DMLStatementInLoop](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/DMLStatementInLoop.ts)_
|
|
71
|
-
**Severity:** 🔴 *Error*
|
|
72
|
-
|
|
73
|
-
#### Hardcoded Salesforce Id
|
|
74
|
-
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.
|
|
75
|
-
|
|
76
|
-
**Rule ID:** `hardcoded-id`
|
|
77
|
-
**Class Name:** _[HardcodedId](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/HardcodedId.ts)_
|
|
78
|
-
**Severity:** 🔴 *Error*
|
|
79
|
-
|
|
80
|
-
#### Hardcoded Salesforce Url
|
|
81
|
-
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.
|
|
82
|
-
|
|
83
|
-
**Rule ID:** `hardcoded-url`
|
|
84
|
-
**Class Name:** _[HardcodedUrl](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/HardcodedUrl.ts)_
|
|
85
|
-
**Severity:** 🔴 *Error*
|
|
86
|
-
|
|
87
|
-
#### Hardcoded Secret 
|
|
88
|
-
Avoid hardcoding secrets, API keys, tokens, or credentials in Flows. These should be stored securely in Named Credentials, Custom Settings, Custom Metadata, or external secret management systems.
|
|
89
|
-
|
|
90
|
-
**Rule ID:** `hardcoded-secret`
|
|
91
|
-
**Class Name:** _[HardcodedSecret](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/HardcodedSecret.ts)_
|
|
92
|
-
**Severity:** 🔴 *Error*
|
|
93
|
-
|
|
94
|
-
#### Process Builder
|
|
95
|
-
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.
|
|
96
|
-
|
|
97
|
-
**Rule ID:** `process-builder-usage`
|
|
98
|
-
**Class Name:** _[ProcessBuilder](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/ProcessBuilder.ts)_
|
|
99
|
-
**Severity:** 🔴 *Error*
|
|
100
|
-
|
|
101
|
-
#### SOQL Query In A Loop
|
|
102
|
-
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.
|
|
103
|
-
|
|
104
|
-
**Rule ID:** `soql-in-loop`
|
|
105
|
-
**Class Name:** _[SOQLQueryInLoop](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/SOQLQueryInLoop.ts)_
|
|
106
|
-
**Severity:** 🔴 *Error*
|
|
107
|
-
|
|
108
|
-
#### Unsafe Running Context
|
|
109
|
-
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.
|
|
110
|
-
|
|
111
|
-
**Rule ID:** `unsafe-running-context`
|
|
112
|
-
**Class Name:** _[UnsafeRunningContext](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/UnsafeRunningContext.ts)_
|
|
113
|
-
**Severity:** 🔴 *Error*
|
|
114
|
-
|
|
115
|
-
#### Duplicate DML Operation
|
|
116
|
-
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.
|
|
117
|
-
|
|
118
|
-
**Rule ID:** `duplicate-dml`
|
|
119
|
-
**Class Name:** _[DuplicateDMLOperation](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/DuplicateDMLOperation.ts)_
|
|
120
|
-
**Severity:** 🟡 *Warning*
|
|
121
|
-
|
|
122
|
-
#### Missing Fault Path
|
|
123
|
-
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.
|
|
124
|
-
|
|
125
|
-
**Rule ID:** `missing-fault-path`
|
|
126
|
-
**Class Name:** _[MissingFaultPath](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/MissingFaultPath.ts)_
|
|
127
|
-
**Severity:** 🟡 *Warning*
|
|
128
|
-
|
|
129
|
-
#### Missing Null Handler
|
|
130
|
-
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.
|
|
131
|
-
|
|
132
|
-
**Rule ID:** `missing-null-handler`
|
|
133
|
-
**Class Name:** _[MissingNullHandler](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/MissingNullHandler.ts)_
|
|
134
|
-
**Severity:** 🟡 *Warning*
|
|
135
|
-
|
|
136
|
-
#### Recursive After Update
|
|
137
|
-
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.
|
|
138
|
-
|
|
139
|
-
**Rule ID:** `recursive-record-update`
|
|
140
|
-
**Class Name:** _[RecursiveAfterUpdate](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/RecursiveAfterUpdate.ts)_
|
|
141
|
-
**Severity:** 🟡 *Warning*
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
### Suggestions
|
|
146
|
-
|
|
147
|
-
These rules highlight areas where Flows can be improved. Following them increases reliability and long-term maintainability.
|
|
148
|
-
|
|
149
|
-
#### Action Call In A Loop
|
|
150
|
-
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.
|
|
151
|
-
|
|
152
|
-
**Rule ID:** `action-call-in-loop`
|
|
153
|
-
**Class Name:** _[ActionCallsInLoop](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/ActionCallsInLoop.ts)_
|
|
154
|
-
**Severity:** 🟡 *Warning*
|
|
155
|
-
|
|
156
|
-
#### Get Record All Fields
|
|
157
|
-
Avoid using Get Records to retrieve all fields unless necessary. This improves performance, reduces processing time, and limits exposure of unnecessary data.
|
|
158
|
-
|
|
159
|
-
**Rule ID:** `get-record-all-fields`
|
|
160
|
-
**Class Name:** _[GetRecordAllFields](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/GetRecordAllFields.ts)_
|
|
161
|
-
**Severity:** 🟡 *Warning*
|
|
162
|
-
|
|
163
|
-
#### Inactive Flow
|
|
164
|
-
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.
|
|
165
|
-
|
|
166
|
-
**Rule ID:** `inactive-flow`
|
|
167
|
-
**Class Name:** _[InactiveFlow](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/InactiveFlow.ts)_
|
|
168
|
-
**Severity:** 🟡 *Warning*
|
|
169
|
-
|
|
170
|
-
#### Invalid API Version
|
|
171
|
-
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.
|
|
172
|
-
|
|
173
|
-
**Rule ID:** `invalid-api-version`
|
|
174
|
-
**Class Name:** _[APIVersion](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/APIVersion.ts)_
|
|
175
|
-
**Severity:** 🟡 *Warning*
|
|
176
|
-
|
|
177
|
-
#### Missing Filter Record Trigger 
|
|
178
|
-
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.
|
|
179
|
-
|
|
180
|
-
**Rule ID:** `missing-record-trigger-filter`
|
|
181
|
-
**Class Name:** _[MissingFilterRecordTrigger](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/MissingFilterRecordTrigger.ts)_
|
|
182
|
-
**Severity:** 🟡 *Warning*
|
|
183
|
-
|
|
184
|
-
#### Same Record Field Updates
|
|
185
|
-
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
|
|
186
|
-
|
|
187
|
-
**Rule ID:** `same-record-field-updates`
|
|
188
|
-
**Class Name:** _[SameRecordFieldUpdates](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/SameRecordFieldUpdates.ts)_
|
|
189
|
-
**Severity:** 🟡 *Warning*
|
|
190
|
-
|
|
191
|
-
#### Excessive Cyclomatic Complexity
|
|
192
|
-
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.
|
|
193
|
-
|
|
194
|
-
**Rule ID:** `excessive-cyclomatic-complexity`
|
|
195
|
-
**Class Name:** _[CyclomaticComplexity](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/CyclomaticComplexity.ts)_
|
|
196
|
-
**Severity:** 🔵 *Note*
|
|
197
|
-
|
|
198
|
-
#### Missing Trigger Order
|
|
199
|
-
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.
|
|
200
|
-
|
|
201
|
-
**Rule ID:** `unspecified-trigger-order`
|
|
202
|
-
**Class Name:** _[TriggerOrder](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/TriggerOrder.ts)_
|
|
203
|
-
**Severity:** 🔵 *Note*
|
|
204
|
-
|
|
205
|
-
#### Record ID as String 
|
|
206
|
-
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.
|
|
207
|
-
|
|
208
|
-
**Rule ID:** `record-id-as-string`
|
|
209
|
-
**Class Name:** _[RecordIdAsString](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/RecordIdAsString.ts)_
|
|
210
|
-
**Severity:** 🔵 *Note*
|
|
211
|
-
|
|
212
|
-
#### Transform Instead of Loop 
|
|
213
|
-
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.
|
|
214
|
-
|
|
215
|
-
**Rule ID:** `transform-instead-of-loop`
|
|
216
|
-
**Class Name:** _[TransformInsteadOfLoop](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/TransformInsteadOfLoop.ts)_
|
|
217
|
-
**Severity:** 🔵 *Note*
|
|
218
|
-
|
|
219
|
-
---
|
|
220
|
-
|
|
221
|
-
### Layout
|
|
222
|
-
|
|
223
|
-
Focused on naming, documentation, and organization, these rules ensure Flows remain clear, easy to understand, and maintainable as automations grow.
|
|
224
|
-
|
|
225
|
-
#### Flow Naming Convention
|
|
226
|
-
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.
|
|
227
|
-
|
|
228
|
-
**Rule ID:** `invalid-naming-convention`
|
|
229
|
-
**Class Name:** _[FlowName](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/FlowName.ts)_
|
|
230
|
-
**Severity:** 🔴 *Error*
|
|
231
|
-
|
|
232
|
-
#### Missing Flow Description
|
|
233
|
-
Flow descriptions are essential for documentation and maintainability. Include a description for each Flow, explaining its purpose and where it's used.
|
|
234
|
-
|
|
235
|
-
**Rule ID:** `missing-flow-description`
|
|
236
|
-
**Class Name:** _[FlowDescription](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/FlowDescription.ts)_
|
|
237
|
-
**Severity:** 🔴 *Error*
|
|
238
|
-
|
|
239
|
-
#### Missing Metadata Description 
|
|
240
|
-
Elements and metadata without a description reduce clarity and maintainability. Adding descriptions improves readability and makes your automation easier to understand.
|
|
241
|
-
|
|
242
|
-
**Rule ID:** `missing-metadata-description`
|
|
243
|
-
**Class Name:** _[MissingMetadataDescription](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/MissingMetadataDescription.ts)_
|
|
244
|
-
**Severity:** 🟡 *Warning*
|
|
245
|
-
|
|
246
|
-
#### Unclear API Name
|
|
247
|
-
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.
|
|
248
|
-
|
|
249
|
-
**Rule ID:** `unclear-api-naming`
|
|
250
|
-
**Class Name:** _[CopyAPIName](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/CopyAPIName.ts)_
|
|
251
|
-
**Severity:** 🟡 *Warning*
|
|
252
|
-
|
|
253
|
-
#### Unreachable Element
|
|
254
|
-
Unconnected elements never execute and add unnecessary clutter. Remove or connect unused Flow elements to keep Flows clean and efficient.
|
|
255
|
-
|
|
256
|
-
**Rule ID:** `unreachable-element`
|
|
257
|
-
**Class Name:** _[UnconnectedElement](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/UnconnectedElement.ts)_
|
|
258
|
-
**Severity:** 🟡 *Warning*
|
|
259
|
-
|
|
260
|
-
#### Unused Variable
|
|
261
|
-
Unused variables are never referenced and add unnecessary clutter. Remove them to keep Flows efficient and easy to maintain.
|
|
262
|
-
|
|
263
|
-
**Rule ID:** `unused-variable`
|
|
264
|
-
**Class Name:** _[UnusedVariable](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/UnusedVariable.ts)_
|
|
265
|
-
**Severity:** 🟡 *Warning*
|
|
266
|
-
|
|
267
|
-
#### Missing Auto Layout
|
|
268
|
-
Auto-Layout automatically arranges and aligns Flow elements, keeping the canvas organized and easier to maintain. Enabling it saves time and improves readability.
|
|
269
|
-
|
|
270
|
-
**Rule ID:** `missing-auto-layout`
|
|
271
|
-
**Class Name:** _[AutoLayout](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/AutoLayout.ts)_
|
|
272
|
-
**Severity:** 🔵 *Note*
|
|
58
|
+
<!-- START GENERATED_RULES -->
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
### Problems
|
|
63
|
+
|
|
64
|
+
These rules detect anti-patterns and unsafe practices in your Flows that could break functionality, compromise security, or cause deployment failures.
|
|
65
|
+
|
|
66
|
+
#### DML Statement In A Loop
|
|
67
|
+
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
|
+
|
|
69
|
+
**Rule ID:** `dml-in-loop`
|
|
70
|
+
**Class Name:** _[DMLStatementInLoop](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/DMLStatementInLoop.ts)_
|
|
71
|
+
**Severity:** 🔴 *Error*
|
|
72
|
+
|
|
73
|
+
#### Hardcoded Salesforce Id
|
|
74
|
+
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.
|
|
75
|
+
|
|
76
|
+
**Rule ID:** `hardcoded-id`
|
|
77
|
+
**Class Name:** _[HardcodedId](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/HardcodedId.ts)_
|
|
78
|
+
**Severity:** 🔴 *Error*
|
|
79
|
+
|
|
80
|
+
#### Hardcoded Salesforce Url
|
|
81
|
+
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.
|
|
82
|
+
|
|
83
|
+
**Rule ID:** `hardcoded-url`
|
|
84
|
+
**Class Name:** _[HardcodedUrl](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/HardcodedUrl.ts)_
|
|
85
|
+
**Severity:** 🔴 *Error*
|
|
86
|
+
|
|
87
|
+
#### Hardcoded Secret 
|
|
88
|
+
Avoid hardcoding secrets, API keys, tokens, or credentials in Flows. These should be stored securely in Named Credentials, Custom Settings, Custom Metadata, or external secret management systems.
|
|
89
|
+
|
|
90
|
+
**Rule ID:** `hardcoded-secret`
|
|
91
|
+
**Class Name:** _[HardcodedSecret](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/HardcodedSecret.ts)_
|
|
92
|
+
**Severity:** 🔴 *Error*
|
|
93
|
+
|
|
94
|
+
#### Process Builder
|
|
95
|
+
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.
|
|
96
|
+
|
|
97
|
+
**Rule ID:** `process-builder-usage`
|
|
98
|
+
**Class Name:** _[ProcessBuilder](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/ProcessBuilder.ts)_
|
|
99
|
+
**Severity:** 🔴 *Error*
|
|
100
|
+
|
|
101
|
+
#### SOQL Query In A Loop
|
|
102
|
+
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.
|
|
103
|
+
|
|
104
|
+
**Rule ID:** `soql-in-loop`
|
|
105
|
+
**Class Name:** _[SOQLQueryInLoop](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/SOQLQueryInLoop.ts)_
|
|
106
|
+
**Severity:** 🔴 *Error*
|
|
107
|
+
|
|
108
|
+
#### Unsafe Running Context
|
|
109
|
+
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.
|
|
110
|
+
|
|
111
|
+
**Rule ID:** `unsafe-running-context`
|
|
112
|
+
**Class Name:** _[UnsafeRunningContext](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/UnsafeRunningContext.ts)_
|
|
113
|
+
**Severity:** 🔴 *Error*
|
|
114
|
+
|
|
115
|
+
#### Duplicate DML Operation
|
|
116
|
+
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.
|
|
117
|
+
|
|
118
|
+
**Rule ID:** `duplicate-dml`
|
|
119
|
+
**Class Name:** _[DuplicateDMLOperation](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/DuplicateDMLOperation.ts)_
|
|
120
|
+
**Severity:** 🟡 *Warning*
|
|
121
|
+
|
|
122
|
+
#### Missing Fault Path
|
|
123
|
+
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.
|
|
124
|
+
|
|
125
|
+
**Rule ID:** `missing-fault-path`
|
|
126
|
+
**Class Name:** _[MissingFaultPath](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/MissingFaultPath.ts)_
|
|
127
|
+
**Severity:** 🟡 *Warning*
|
|
128
|
+
|
|
129
|
+
#### Missing Null Handler
|
|
130
|
+
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.
|
|
131
|
+
|
|
132
|
+
**Rule ID:** `missing-null-handler`
|
|
133
|
+
**Class Name:** _[MissingNullHandler](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/MissingNullHandler.ts)_
|
|
134
|
+
**Severity:** 🟡 *Warning*
|
|
135
|
+
|
|
136
|
+
#### Recursive After Update
|
|
137
|
+
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.
|
|
138
|
+
|
|
139
|
+
**Rule ID:** `recursive-record-update`
|
|
140
|
+
**Class Name:** _[RecursiveAfterUpdate](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/RecursiveAfterUpdate.ts)_
|
|
141
|
+
**Severity:** 🟡 *Warning*
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
### Suggestions
|
|
146
|
+
|
|
147
|
+
These rules highlight areas where Flows can be improved. Following them increases reliability and long-term maintainability.
|
|
148
|
+
|
|
149
|
+
#### Action Call In A Loop
|
|
150
|
+
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.
|
|
151
|
+
|
|
152
|
+
**Rule ID:** `action-call-in-loop`
|
|
153
|
+
**Class Name:** _[ActionCallsInLoop](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/ActionCallsInLoop.ts)_
|
|
154
|
+
**Severity:** 🟡 *Warning*
|
|
155
|
+
|
|
156
|
+
#### Get Record All Fields
|
|
157
|
+
Avoid using Get Records to retrieve all fields unless necessary. This improves performance, reduces processing time, and limits exposure of unnecessary data.
|
|
158
|
+
|
|
159
|
+
**Rule ID:** `get-record-all-fields`
|
|
160
|
+
**Class Name:** _[GetRecordAllFields](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/GetRecordAllFields.ts)_
|
|
161
|
+
**Severity:** 🟡 *Warning*
|
|
162
|
+
|
|
163
|
+
#### Inactive Flow
|
|
164
|
+
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.
|
|
165
|
+
|
|
166
|
+
**Rule ID:** `inactive-flow`
|
|
167
|
+
**Class Name:** _[InactiveFlow](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/InactiveFlow.ts)_
|
|
168
|
+
**Severity:** 🟡 *Warning*
|
|
169
|
+
|
|
170
|
+
#### Invalid API Version
|
|
171
|
+
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.
|
|
172
|
+
|
|
173
|
+
**Rule ID:** `invalid-api-version`
|
|
174
|
+
**Class Name:** _[APIVersion](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/APIVersion.ts)_
|
|
175
|
+
**Severity:** 🟡 *Warning*
|
|
176
|
+
|
|
177
|
+
#### Missing Filter Record Trigger 
|
|
178
|
+
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.
|
|
179
|
+
|
|
180
|
+
**Rule ID:** `missing-record-trigger-filter`
|
|
181
|
+
**Class Name:** _[MissingFilterRecordTrigger](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/MissingFilterRecordTrigger.ts)_
|
|
182
|
+
**Severity:** 🟡 *Warning*
|
|
183
|
+
|
|
184
|
+
#### Same Record Field Updates
|
|
185
|
+
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
|
|
186
|
+
|
|
187
|
+
**Rule ID:** `same-record-field-updates`
|
|
188
|
+
**Class Name:** _[SameRecordFieldUpdates](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/SameRecordFieldUpdates.ts)_
|
|
189
|
+
**Severity:** 🟡 *Warning*
|
|
190
|
+
|
|
191
|
+
#### Excessive Cyclomatic Complexity
|
|
192
|
+
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.
|
|
193
|
+
|
|
194
|
+
**Rule ID:** `excessive-cyclomatic-complexity`
|
|
195
|
+
**Class Name:** _[CyclomaticComplexity](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/CyclomaticComplexity.ts)_
|
|
196
|
+
**Severity:** 🔵 *Note*
|
|
197
|
+
|
|
198
|
+
#### Missing Trigger Order
|
|
199
|
+
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.
|
|
200
|
+
|
|
201
|
+
**Rule ID:** `unspecified-trigger-order`
|
|
202
|
+
**Class Name:** _[TriggerOrder](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/TriggerOrder.ts)_
|
|
203
|
+
**Severity:** 🔵 *Note*
|
|
204
|
+
|
|
205
|
+
#### Record ID as String 
|
|
206
|
+
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.
|
|
207
|
+
|
|
208
|
+
**Rule ID:** `record-id-as-string`
|
|
209
|
+
**Class Name:** _[RecordIdAsString](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/RecordIdAsString.ts)_
|
|
210
|
+
**Severity:** 🔵 *Note*
|
|
211
|
+
|
|
212
|
+
#### Transform Instead of Loop 
|
|
213
|
+
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.
|
|
214
|
+
|
|
215
|
+
**Rule ID:** `transform-instead-of-loop`
|
|
216
|
+
**Class Name:** _[TransformInsteadOfLoop](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/TransformInsteadOfLoop.ts)_
|
|
217
|
+
**Severity:** 🔵 *Note*
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
### Layout
|
|
222
|
+
|
|
223
|
+
Focused on naming, documentation, and organization, these rules ensure Flows remain clear, easy to understand, and maintainable as automations grow.
|
|
224
|
+
|
|
225
|
+
#### Flow Naming Convention
|
|
226
|
+
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.
|
|
227
|
+
|
|
228
|
+
**Rule ID:** `invalid-naming-convention`
|
|
229
|
+
**Class Name:** _[FlowName](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/FlowName.ts)_
|
|
230
|
+
**Severity:** 🔴 *Error*
|
|
231
|
+
|
|
232
|
+
#### Missing Flow Description
|
|
233
|
+
Flow descriptions are essential for documentation and maintainability. Include a description for each Flow, explaining its purpose and where it's used.
|
|
234
|
+
|
|
235
|
+
**Rule ID:** `missing-flow-description`
|
|
236
|
+
**Class Name:** _[FlowDescription](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/FlowDescription.ts)_
|
|
237
|
+
**Severity:** 🔴 *Error*
|
|
238
|
+
|
|
239
|
+
#### Missing Metadata Description 
|
|
240
|
+
Elements and metadata without a description reduce clarity and maintainability. Adding descriptions improves readability and makes your automation easier to understand.
|
|
241
|
+
|
|
242
|
+
**Rule ID:** `missing-metadata-description`
|
|
243
|
+
**Class Name:** _[MissingMetadataDescription](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/MissingMetadataDescription.ts)_
|
|
244
|
+
**Severity:** 🟡 *Warning*
|
|
245
|
+
|
|
246
|
+
#### Unclear API Name
|
|
247
|
+
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.
|
|
248
|
+
|
|
249
|
+
**Rule ID:** `unclear-api-naming`
|
|
250
|
+
**Class Name:** _[CopyAPIName](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/CopyAPIName.ts)_
|
|
251
|
+
**Severity:** 🟡 *Warning*
|
|
252
|
+
|
|
253
|
+
#### Unreachable Element
|
|
254
|
+
Unconnected elements never execute and add unnecessary clutter. Remove or connect unused Flow elements to keep Flows clean and efficient.
|
|
255
|
+
|
|
256
|
+
**Rule ID:** `unreachable-element`
|
|
257
|
+
**Class Name:** _[UnconnectedElement](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/UnconnectedElement.ts)_
|
|
258
|
+
**Severity:** 🟡 *Warning*
|
|
259
|
+
|
|
260
|
+
#### Unused Variable
|
|
261
|
+
Unused variables are never referenced and add unnecessary clutter. Remove them to keep Flows efficient and easy to maintain.
|
|
262
|
+
|
|
263
|
+
**Rule ID:** `unused-variable`
|
|
264
|
+
**Class Name:** _[UnusedVariable](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/UnusedVariable.ts)_
|
|
265
|
+
**Severity:** 🟡 *Warning*
|
|
266
|
+
|
|
267
|
+
#### Missing Auto Layout
|
|
268
|
+
Auto-Layout automatically arranges and aligns Flow elements, keeping the canvas organized and easier to maintain. Enabling it saves time and improves readability.
|
|
269
|
+
|
|
270
|
+
**Rule ID:** `missing-auto-layout`
|
|
271
|
+
**Class Name:** _[AutoLayout](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/AutoLayout.ts)_
|
|
272
|
+
**Severity:** 🔵 *Note*
|
|
273
|
+
|
|
274
|
+
#### System (subcategory)
|
|
275
|
+
|
|
276
|
+
System rules are a subset of Layout rules that detect structural issues normally prevented by the Flow Builder UI. See [System Rules Documentation](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/docs/system-rules.md) for the full list.
|
|
273
277
|
<!-- END GENERATED_RULES -->
|
|
274
278
|
|
|
275
279
|
---
|
|
@@ -281,20 +285,26 @@ It is recommend to configure and define:
|
|
|
281
285
|
- The severity of violating any specific rule.
|
|
282
286
|
- Expressions used for rules, such as REGEX patterns and comparison operators.
|
|
283
287
|
- Any known exceptions that should be ignored during scanning.
|
|
288
|
+
- (Optional) Implement filters based on a severity **threshold** or **rule categories**.
|
|
289
|
+
|
|
290
|
+
Most distributions automatically load configuration from:
|
|
291
|
+
- `.flow-scanner.yml`
|
|
292
|
+
- `.flow-scanner.json`
|
|
293
|
+
- `package.json` → `"flowScanner"` key
|
|
284
294
|
|
|
285
295
|
```json
|
|
286
296
|
{
|
|
287
297
|
"rules": {
|
|
288
|
-
//
|
|
298
|
+
// rule customizations (severity, expression, enabled, ...)
|
|
289
299
|
},
|
|
290
300
|
"exceptions": {
|
|
291
|
-
//
|
|
292
|
-
}
|
|
301
|
+
// flow → rule → result suppressions
|
|
302
|
+
},
|
|
303
|
+
"threshold": "error", // only consider errors
|
|
304
|
+
"categories": ["problem", "layout"] // only run rules from these categories
|
|
293
305
|
}
|
|
294
306
|
```
|
|
295
307
|
|
|
296
|
-
Most Lightning Flow Scanner distributions automatically resolve configurations from `.flow-scanner.yml`, `.flow-scanner.json`, or `package.json` → `flowScanner`.
|
|
297
|
-
|
|
298
308
|
### Configure Rules
|
|
299
309
|
|
|
300
310
|
By default, all default rules are executed. You can customize individual rules and override the rules to be executed without having to specify every rule. Below is a breakdown of the available attributes of rule configuration:
|
|
@@ -315,7 +325,7 @@ By default, all default rules are executed. You can customize individual rules a
|
|
|
315
325
|
|
|
316
326
|
#### Configure Severity
|
|
317
327
|
|
|
318
|
-
|
|
328
|
+
Available values for severity are `error`, `warning` and `note`. If no severity is provided, a default value is applied. Configure the severity per rule as demonstrated below:
|
|
319
329
|
|
|
320
330
|
```json
|
|
321
331
|
{
|
|
@@ -444,7 +454,19 @@ Exclude specific flows by their unique API names, regardless of their location.
|
|
|
444
454
|
|
|
445
455
|
**Environment compatibility**: works in **all environments** including Node.js and browser/web distributions, as it operates on parsed flow data rather than file system paths.
|
|
446
456
|
|
|
447
|
-
### Scan
|
|
457
|
+
### Scan Options
|
|
458
|
+
|
|
459
|
+
#### Severity Threshold
|
|
460
|
+
Only report on violations at or above a chosen severity level:
|
|
461
|
+
```json
|
|
462
|
+
{ "threshold": "error" }
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
#### Filter by category
|
|
466
|
+
Restrict the scan to specific categories of rules:
|
|
467
|
+
```json
|
|
468
|
+
{ "categories": ["problem", "layout"] }
|
|
469
|
+
```
|
|
448
470
|
|
|
449
471
|
#### Beta Mode
|
|
450
472
|
|
|
@@ -469,9 +491,10 @@ By default, Lightning Flow Scanner runs **all** default rules and merges any cus
|
|
|
469
491
|
|----------------------------------------------------------------|-----------------------------------------------|---------------------------------------------------------------------------------------------------------|
|
|
470
492
|
| **[Salesforce CLI Plugin](https://www.npmjs.com/package/lightning-flow-scanner)** | Local development, scratch orgs, CI/CD | `sf plugins install lightning-flow-scanner` |
|
|
471
493
|
| **[VS Code Extension](https://open-vsx.org/extension/ForceConfigControl/lightning-flow-scanner-vsx)** | Real-time scanning inside VS Code | `code --install-extension ForceConfigControl.lightning-flow-scanner-vsx` |
|
|
472
|
-
| **[Salesforce App
|
|
494
|
+
| **[Salesforce App](https://github.com/Flow-Scanner/lightning-flow-scanner-app)** | Run scans directly inside a Salesforce org | `sf package install --package 04tgK0000008CLlQAM` |
|
|
473
495
|
| **[GitHub Action](https://github.com/marketplace/actions/lightning-flow-scan)** | Native PR checks | `uses: Flow-Scanner/lightning-flow-scanner@main` |
|
|
474
496
|
| **[Core Library](https://www.npmjs.com/package/@flow-scanner/lightning-flow-scanner-core)** (Node.js + Browser) | Custom tools, scripts, extensions, web apps | `npm install -g @flow-scanner/lightning-flow-scanner-core` |
|
|
497
|
+
| **[Regex Scanner](https://www.npmjs.com/package/@flow-scanner/regex-scanner)** | Regex-based scanning | `npm install -g @flow-scanner/regex-scanner`
|
|
475
498
|
|
|
476
499
|
**Privacy:** Zero user data collected. All processing is client-side. → See our [Security Policy](https://github.com/Flow-Scanner/lightning-flow-scanner?tab=security-ov-file).
|
|
477
500
|
|
package/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { IRuleDefinition } from "./main/interfaces/IRuleDefinition";
|
|
2
|
-
import type { IRulesConfig } from "./main/interfaces/IRulesConfig";
|
|
2
|
+
import type { IRulesConfig, RuleCategory, Severity, Threshold } from "./main/interfaces/IRulesConfig";
|
|
3
|
+
import { SEVERITY_ORDER, meetsThreshold, countThresholdViolations, filterByThreshold } from "./main/interfaces/IRulesConfig";
|
|
3
4
|
import type { FlatViolation } from "./main/models/FlatViolation";
|
|
4
5
|
import { Compiler } from "./main/libs/Compiler";
|
|
5
6
|
import { exportDetails } from "./main/libs/ExportDetails";
|
|
@@ -22,5 +23,5 @@ import { Violation } from "./main/models/Violation";
|
|
|
22
23
|
import { DEFAULT_ICONS, ASCII_ICONS, type NodeIconConfig } from "./main/config/NodeIcons";
|
|
23
24
|
import { DEFAULT_VARIABLE_ICONS, ASCII_VARIABLE_ICONS, type VariableIconConfig } from "./main/config/VariableIcons";
|
|
24
25
|
import { exportDiagram, type DiagramOptions } from "./main/libs/ExportDiagram";
|
|
25
|
-
export { Compiler, exportDetails, exportDiagram, exportSarif, fix, Flow, FlowAttribute, FlowElement, FlowNode, FlowResource, FlowType, FlowVariable, getRules, parse, ParsedFlow, Violation, RuleResult, scan, ScanResult, DEFAULT_ICONS, ASCII_ICONS, DEFAULT_VARIABLE_ICONS, ASCII_VARIABLE_ICONS, };
|
|
26
|
-
export type { FlatViolation, IRuleDefinition, IRulesConfig, NodeIconConfig, DiagramOptions, VariableIconConfig };
|
|
26
|
+
export { Compiler, exportDetails, exportDiagram, exportSarif, fix, Flow, FlowAttribute, FlowElement, FlowNode, FlowResource, FlowType, FlowVariable, getRules, parse, ParsedFlow, Violation, RuleResult, scan, ScanResult, DEFAULT_ICONS, ASCII_ICONS, DEFAULT_VARIABLE_ICONS, ASCII_VARIABLE_ICONS, SEVERITY_ORDER, meetsThreshold, countThresholdViolations, filterByThreshold, };
|
|
27
|
+
export type { FlatViolation, IRuleDefinition, IRulesConfig, RuleCategory, Severity, Threshold, NodeIconConfig, DiagramOptions, VariableIconConfig };
|
package/index.js
CHANGED
|
@@ -52,12 +52,19 @@ _export(exports, {
|
|
|
52
52
|
get RuleResult () {
|
|
53
53
|
return _RuleResult.RuleResult;
|
|
54
54
|
},
|
|
55
|
+
get // Threshold utilities
|
|
56
|
+
SEVERITY_ORDER () {
|
|
57
|
+
return _IRulesConfig.SEVERITY_ORDER;
|
|
58
|
+
},
|
|
55
59
|
get ScanResult () {
|
|
56
60
|
return _ScanResult.ScanResult;
|
|
57
61
|
},
|
|
58
62
|
get Violation () {
|
|
59
63
|
return _Violation.Violation;
|
|
60
64
|
},
|
|
65
|
+
get countThresholdViolations () {
|
|
66
|
+
return _IRulesConfig.countThresholdViolations;
|
|
67
|
+
},
|
|
61
68
|
get exportDetails () {
|
|
62
69
|
return _ExportDetails.exportDetails;
|
|
63
70
|
},
|
|
@@ -67,12 +74,18 @@ _export(exports, {
|
|
|
67
74
|
get exportSarif () {
|
|
68
75
|
return _ExportSarif.exportSarif;
|
|
69
76
|
},
|
|
77
|
+
get filterByThreshold () {
|
|
78
|
+
return _IRulesConfig.filterByThreshold;
|
|
79
|
+
},
|
|
70
80
|
get fix () {
|
|
71
81
|
return _FixFlows.fix;
|
|
72
82
|
},
|
|
73
83
|
get getRules () {
|
|
74
84
|
return _GetRuleDefinitions.getRules;
|
|
75
85
|
},
|
|
86
|
+
get meetsThreshold () {
|
|
87
|
+
return _IRulesConfig.meetsThreshold;
|
|
88
|
+
},
|
|
76
89
|
get parse () {
|
|
77
90
|
return _ParseFlows.parse;
|
|
78
91
|
},
|
|
@@ -80,6 +93,7 @@ _export(exports, {
|
|
|
80
93
|
return _ScanFlows.scan;
|
|
81
94
|
}
|
|
82
95
|
});
|
|
96
|
+
const _IRulesConfig = require("./main/interfaces/IRulesConfig");
|
|
83
97
|
const _Compiler = require("./main/libs/Compiler");
|
|
84
98
|
const _ExportDetails = require("./main/libs/ExportDetails");
|
|
85
99
|
const _ExportSarif = require("./main/libs/ExportSarif");
|
|
@@ -34,6 +34,7 @@ const _UnsafeRunningContext = require("../rules/UnsafeRunningContext");
|
|
|
34
34
|
const _UnusedVariable = require("../rules/UnusedVariable");
|
|
35
35
|
const _MissingMetadataDescription = require("../rules/MissingMetadataDescription");
|
|
36
36
|
const _MissingRecordTriggerFilter = require("../rules/MissingRecordTriggerFilter");
|
|
37
|
+
const _MissingStartReference = require("../rules/MissingStartReference");
|
|
37
38
|
const _TransformInsteadOfLoop = require("../rules/TransformInsteadOfLoop");
|
|
38
39
|
const _RecordIdAsString = require("../rules/RecordIdAsString");
|
|
39
40
|
function _define_property(obj, key, value) {
|
|
@@ -201,6 +202,7 @@ registry.register("unsafe-running-context", _UnsafeRunningContext.UnsafeRunningC
|
|
|
201
202
|
registry.register("unused-variable", _UnusedVariable.UnusedVariable, "UnusedVariable");
|
|
202
203
|
registry.register("missing-metadata-description", _MissingMetadataDescription.MissingMetadataDescription, "MissingMetadataDescription", true);
|
|
203
204
|
registry.register("missing-record-trigger-filter", _MissingRecordTriggerFilter.MissingRecordTriggerFilter, "MissingFilterRecordTrigger", true);
|
|
205
|
+
registry.register("missing-start-reference", _MissingStartReference.MissingStartReference, "MissingStartReference", true);
|
|
204
206
|
registry.register("transform-instead-of-loop", _TransformInsteadOfLoop.TransformInsteadOfLoop, "TransformInsteadOfLoop", true);
|
|
205
207
|
registry.register("record-id-as-string", _RecordIdAsString.RecordIdAsString, "RecordIdAsString", true);
|
|
206
208
|
registry.register("hardcoded-secret", _HardcodedSecret.HardcodedSecret, "HardcodedSecret", true);
|
|
@@ -4,12 +4,45 @@ export declare enum DetailLevel {
|
|
|
4
4
|
ENRICHED = "enriched",
|
|
5
5
|
SIMPLE = "simple"
|
|
6
6
|
}
|
|
7
|
+
export type RuleCategory = 'problem' | 'suggestion' | 'layout';
|
|
8
|
+
export type Severity = 'error' | 'warning' | 'note';
|
|
9
|
+
export type Threshold = Severity | 'never';
|
|
10
|
+
/** Severity levels ordered from most to least severe */
|
|
11
|
+
export declare const SEVERITY_ORDER: Severity[];
|
|
7
12
|
export interface IRulesConfig {
|
|
8
13
|
betaMode?: boolean;
|
|
9
14
|
betamode?: boolean;
|
|
15
|
+
systemRules?: boolean;
|
|
16
|
+
categories?: RuleCategory[];
|
|
17
|
+
threshold?: Threshold;
|
|
10
18
|
detailLevel?: 'enriched' | 'simple' | DetailLevel;
|
|
11
19
|
exceptions?: IExceptions;
|
|
12
20
|
rules?: IRuleOptions;
|
|
13
21
|
ruleMode?: "merged" | "isolated";
|
|
14
22
|
ignoreFlows?: string[];
|
|
15
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Check if a severity meets or exceeds the threshold.
|
|
26
|
+
* @param severity - The severity to check
|
|
27
|
+
* @param threshold - The threshold to compare against
|
|
28
|
+
* @returns true if severity >= threshold (more severe or equal)
|
|
29
|
+
*/
|
|
30
|
+
export declare function meetsThreshold(severity: string | undefined, threshold: Threshold): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Count violations that meet or exceed the threshold.
|
|
33
|
+
* @param results - Array of results with severity property
|
|
34
|
+
* @param threshold - The threshold to compare against
|
|
35
|
+
* @returns Number of violations meeting the threshold
|
|
36
|
+
*/
|
|
37
|
+
export declare function countThresholdViolations(results: Array<{
|
|
38
|
+
severity?: string;
|
|
39
|
+
}>, threshold: Threshold): number;
|
|
40
|
+
/**
|
|
41
|
+
* Filter results to only include those meeting the threshold.
|
|
42
|
+
* @param results - Array of results with severity property
|
|
43
|
+
* @param threshold - The threshold to filter by
|
|
44
|
+
* @returns Filtered array of results meeting the threshold ('never' returns all)
|
|
45
|
+
*/
|
|
46
|
+
export declare function filterByThreshold<T extends {
|
|
47
|
+
severity?: string;
|
|
48
|
+
}>(results: T[], threshold: Threshold): T[];
|
|
@@ -2,10 +2,27 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", {
|
|
3
3
|
value: true
|
|
4
4
|
});
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get DetailLevel () {
|
|
8
13
|
return DetailLevel;
|
|
14
|
+
},
|
|
15
|
+
get SEVERITY_ORDER () {
|
|
16
|
+
return SEVERITY_ORDER;
|
|
17
|
+
},
|
|
18
|
+
get countThresholdViolations () {
|
|
19
|
+
return countThresholdViolations;
|
|
20
|
+
},
|
|
21
|
+
get filterByThreshold () {
|
|
22
|
+
return filterByThreshold;
|
|
23
|
+
},
|
|
24
|
+
get meetsThreshold () {
|
|
25
|
+
return meetsThreshold;
|
|
9
26
|
}
|
|
10
27
|
});
|
|
11
28
|
var DetailLevel = /*#__PURE__*/ function(DetailLevel) {
|
|
@@ -13,3 +30,24 @@ var DetailLevel = /*#__PURE__*/ function(DetailLevel) {
|
|
|
13
30
|
DetailLevel["SIMPLE"] = "simple";
|
|
14
31
|
return DetailLevel;
|
|
15
32
|
}({});
|
|
33
|
+
const SEVERITY_ORDER = [
|
|
34
|
+
'error',
|
|
35
|
+
'warning',
|
|
36
|
+
'note'
|
|
37
|
+
];
|
|
38
|
+
function meetsThreshold(severity, threshold) {
|
|
39
|
+
if (threshold === 'never') return false;
|
|
40
|
+
const sev = severity || 'warning';
|
|
41
|
+
const sevIndex = SEVERITY_ORDER.indexOf(sev);
|
|
42
|
+
const thresholdIndex = SEVERITY_ORDER.indexOf(threshold);
|
|
43
|
+
// Lower index = more severe, so severity meets threshold if sevIndex <= thresholdIndex
|
|
44
|
+
return sevIndex >= 0 && sevIndex <= thresholdIndex;
|
|
45
|
+
}
|
|
46
|
+
function countThresholdViolations(results, threshold) {
|
|
47
|
+
if (threshold === 'never') return 0;
|
|
48
|
+
return results.filter((r)=>meetsThreshold(r.severity, threshold)).length;
|
|
49
|
+
}
|
|
50
|
+
function filterByThreshold(results, threshold) {
|
|
51
|
+
if (threshold === 'never') return results;
|
|
52
|
+
return results.filter((r)=>meetsThreshold(r.severity, threshold));
|
|
53
|
+
}
|
package/main/libs/FixFlows.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import * as core from "../internals/internals";
|
|
2
2
|
export declare function fix(results: core.ScanResult[]): core.ScanResult[];
|
|
3
|
+
/**
|
|
4
|
+
* @deprecated Use fix() instead which modifies flows in place.
|
|
5
|
+
* Kept for backward compatibility.
|
|
6
|
+
*/
|
|
3
7
|
export declare function FixFlows(flow: core.Flow, ruleResults: core.RuleResult[]): core.Flow;
|
package/main/libs/FixFlows.js
CHANGED
|
@@ -17,7 +17,6 @@ _export(exports, {
|
|
|
17
17
|
}
|
|
18
18
|
});
|
|
19
19
|
const _internals = /*#__PURE__*/ _interop_require_wildcard(require("../internals/internals"));
|
|
20
|
-
const _BuildFlow = require("./BuildFlow");
|
|
21
20
|
function _getRequireWildcardCache(nodeInterop) {
|
|
22
21
|
if (typeof WeakMap !== "function") return null;
|
|
23
22
|
var cacheBabelInterop = new WeakMap();
|
|
@@ -63,45 +62,105 @@ function fix(results) {
|
|
|
63
62
|
const newResults = [];
|
|
64
63
|
for (const result of results){
|
|
65
64
|
if (!result.ruleResults || result.ruleResults.length === 0) continue;
|
|
66
|
-
const fixables = result.ruleResults.filter((r)=>r.ruleName === "UnusedVariable" && r.occurs || r.ruleName === "UnconnectedElement" && r.occurs);
|
|
65
|
+
const fixables = result.ruleResults.filter((r)=>r.ruleName === "UnusedVariable" && r.occurs || r.ruleName === "UnconnectedElement" && r.occurs || r.ruleName === "AutoLayout" && r.occurs);
|
|
67
66
|
if (fixables.length === 0) continue;
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
if (
|
|
71
|
-
result.flow
|
|
72
|
-
newResults.push(result);
|
|
67
|
+
// Handle AutoLayout fix separately (modifies metadata, not elements)
|
|
68
|
+
const autoLayoutFix = fixables.find((r)=>r.ruleName === "AutoLayout");
|
|
69
|
+
if (autoLayoutFix) {
|
|
70
|
+
applyAutoLayoutFix(result.flow);
|
|
73
71
|
}
|
|
72
|
+
// Handle element-based fixes (UnusedVariable, UnconnectedElement)
|
|
73
|
+
// These modify xmldata in place to preserve element order and formatting
|
|
74
|
+
const elementFixables = fixables.filter((r)=>r.ruleName !== "AutoLayout");
|
|
75
|
+
if (elementFixables.length > 0) {
|
|
76
|
+
applyElementFixes(result.flow, elementFixables);
|
|
77
|
+
}
|
|
78
|
+
newResults.push(result);
|
|
74
79
|
}
|
|
75
80
|
return newResults;
|
|
76
81
|
}
|
|
77
|
-
function
|
|
78
|
-
|
|
82
|
+
function applyAutoLayoutFix(flow) {
|
|
83
|
+
if (!flow.xmldata) return;
|
|
84
|
+
// Ensure processMetadataValues is an array
|
|
85
|
+
if (!flow.xmldata.processMetadataValues) {
|
|
86
|
+
flow.xmldata.processMetadataValues = [];
|
|
87
|
+
} else if (!Array.isArray(flow.xmldata.processMetadataValues)) {
|
|
88
|
+
flow.xmldata.processMetadataValues = [
|
|
89
|
+
flow.xmldata.processMetadataValues
|
|
90
|
+
];
|
|
91
|
+
}
|
|
92
|
+
// Find existing CanvasMode entry
|
|
93
|
+
const canvasModeIndex = flow.xmldata.processMetadataValues.findIndex((mdv)=>mdv.name === "CanvasMode");
|
|
94
|
+
const autoLayoutValue = {
|
|
95
|
+
name: "CanvasMode",
|
|
96
|
+
value: {
|
|
97
|
+
stringValue: "AUTO_LAYOUT_CANVAS"
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
if (canvasModeIndex >= 0) {
|
|
101
|
+
// Update existing entry
|
|
102
|
+
flow.xmldata.processMetadataValues[canvasModeIndex] = autoLayoutValue;
|
|
103
|
+
} else {
|
|
104
|
+
// Add new entry
|
|
105
|
+
flow.xmldata.processMetadataValues.push(autoLayoutValue);
|
|
106
|
+
}
|
|
107
|
+
// Update the flow's processMetadataValues property
|
|
108
|
+
flow.processMetadataValues = flow.xmldata.processMetadataValues;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Apply element-based fixes (UnusedVariable, UnconnectedElement) by modifying xmldata in place.
|
|
112
|
+
* This preserves element order and formatting from the original file.
|
|
113
|
+
*/ function applyElementFixes(flow, ruleResults) {
|
|
114
|
+
var _unusedVariableRes_details, _unconnectedElementsRes_details;
|
|
115
|
+
if (!flow.xmldata) return;
|
|
79
116
|
const unusedVariableRes = ruleResults.find((r)=>r.ruleName === "UnusedVariable");
|
|
80
117
|
var _unusedVariableRes_details_map;
|
|
81
118
|
const unusedVariableNames = new Set((_unusedVariableRes_details_map = unusedVariableRes === null || unusedVariableRes === void 0 ? void 0 : (_unusedVariableRes_details = unusedVariableRes.details) === null || _unusedVariableRes_details === void 0 ? void 0 : _unusedVariableRes_details.map((d)=>d.name)) !== null && _unusedVariableRes_details_map !== void 0 ? _unusedVariableRes_details_map : []);
|
|
82
119
|
const unconnectedElementsRes = ruleResults.find((r)=>r.ruleName === "UnconnectedElement");
|
|
83
120
|
var _unconnectedElementsRes_details_map;
|
|
84
121
|
const unconnectedElementNames = new Set((_unconnectedElementsRes_details_map = unconnectedElementsRes === null || unconnectedElementsRes === void 0 ? void 0 : (_unconnectedElementsRes_details = unconnectedElementsRes.details) === null || _unconnectedElementsRes_details === void 0 ? void 0 : _unconnectedElementsRes_details.map((d)=>d.name)) !== null && _unconnectedElementsRes_details_map !== void 0 ? _unconnectedElementsRes_details_map : []);
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
122
|
+
// Remove unused variables from xmldata
|
|
123
|
+
if (unusedVariableNames.size > 0) {
|
|
124
|
+
for (const varTag of _internals.Flow.VARIABLE_TAGS){
|
|
125
|
+
removeElementsByName(flow.xmldata, varTag, unusedVariableNames);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Remove unconnected elements from xmldata
|
|
129
|
+
if (unconnectedElementNames.size > 0) {
|
|
130
|
+
for (const nodeTag of _internals.Flow.NODE_TAGS){
|
|
131
|
+
removeElementsByName(flow.xmldata, nodeTag, unconnectedElementNames);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Update the flow's elements array to match the modified xmldata
|
|
135
|
+
flow.preProcessNodes();
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Remove elements from xmldata by name.
|
|
139
|
+
* Handles both single element and array cases.
|
|
140
|
+
*/ function removeElementsByName(xmldata, tagName, namesToRemove) {
|
|
141
|
+
const elements = xmldata[tagName];
|
|
142
|
+
if (!elements) return;
|
|
143
|
+
if (Array.isArray(elements)) {
|
|
144
|
+
const filtered = elements.filter((el)=>!namesToRemove.has(el === null || el === void 0 ? void 0 : el.name));
|
|
145
|
+
if (filtered.length === 0) {
|
|
146
|
+
delete xmldata[tagName];
|
|
147
|
+
} else if (filtered.length === 1) {
|
|
148
|
+
// Keep as single element if only one remains (matches original format)
|
|
149
|
+
xmldata[tagName] = filtered[0];
|
|
150
|
+
} else {
|
|
151
|
+
xmldata[tagName] = filtered;
|
|
103
152
|
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
153
|
+
} else if (typeof elements === 'object' && elements !== null) {
|
|
154
|
+
// Single element case
|
|
155
|
+
if (namesToRemove.has(elements.name)) {
|
|
156
|
+
delete xmldata[tagName];
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function FixFlows(flow, ruleResults) {
|
|
161
|
+
// Create a shallow clone of xmldata to avoid modifying the original
|
|
162
|
+
const clonedXmldata = JSON.parse(JSON.stringify(flow.xmldata));
|
|
163
|
+
const clonedFlow = new _internals.Flow(flow.fsPath, clonedXmldata);
|
|
164
|
+
applyElementFixes(clonedFlow, ruleResults);
|
|
165
|
+
return clonedFlow;
|
|
107
166
|
}
|
|
@@ -19,6 +19,8 @@ _export(exports, {
|
|
|
19
19
|
const _RuleRegistry = require("../config/RuleRegistry");
|
|
20
20
|
function GetRuleDefinitions(ruleConfig, options) {
|
|
21
21
|
const includeBeta = (options === null || options === void 0 ? void 0 : options.betaMode) === true || (options === null || options === void 0 ? void 0 : options.betamode) === true;
|
|
22
|
+
const includeSystem = (options === null || options === void 0 ? void 0 : options.systemRules) !== false; // defaults to true
|
|
23
|
+
const categories = options === null || options === void 0 ? void 0 : options.categories; // undefined means all categories
|
|
22
24
|
const rulesMode = (options === null || options === void 0 ? void 0 : options.ruleMode) || "merged";
|
|
23
25
|
const selectedRules = [];
|
|
24
26
|
const ruleIds = _RuleRegistry.ruleRegistry.getAllRuleIds(includeBeta);
|
|
@@ -31,6 +33,10 @@ function GetRuleDefinitions(ruleConfig, options) {
|
|
|
31
33
|
const config = ruleConfig.get(key);
|
|
32
34
|
if ((config === null || config === void 0 ? void 0 : config.enabled) === false) continue;
|
|
33
35
|
const rule = _RuleRegistry.ruleRegistry.createInstance(entry.ruleId); // Always use ruleId to instantiate
|
|
36
|
+
// Skip system rules if disabled
|
|
37
|
+
if (rule.category === 'system' && !includeSystem) continue;
|
|
38
|
+
// Skip rules not in selected categories (if categories filter is specified)
|
|
39
|
+
if (!isCategoryIncluded(rule.category, categories, includeSystem)) continue;
|
|
34
40
|
if (config === null || config === void 0 ? void 0 : config.severity) {
|
|
35
41
|
rule.severity = config.severity;
|
|
36
42
|
}
|
|
@@ -41,6 +47,10 @@ function GetRuleDefinitions(ruleConfig, options) {
|
|
|
41
47
|
// MERGED MODE (default)
|
|
42
48
|
for (const ruleId of ruleIds){
|
|
43
49
|
const rule = _RuleRegistry.ruleRegistry.createInstance(ruleId);
|
|
50
|
+
// Skip system rules if disabled
|
|
51
|
+
if (rule.category === 'system' && !includeSystem) continue;
|
|
52
|
+
// Skip rules not in selected categories (if categories filter is specified)
|
|
53
|
+
if (!isCategoryIncluded(rule.category, categories, includeSystem)) continue;
|
|
44
54
|
var _ruleConfig_get;
|
|
45
55
|
// Try to find config by ruleId first, then fall back to legacy name
|
|
46
56
|
const config = (_ruleConfig_get = ruleConfig === null || ruleConfig === void 0 ? void 0 : ruleConfig.get(rule.ruleId)) !== null && _ruleConfig_get !== void 0 ? _ruleConfig_get : ruleConfig === null || ruleConfig === void 0 ? void 0 : ruleConfig.get(rule.name) // rule.name is the legacy camelCase name (e.g. "ActionCallsInLoop")
|
|
@@ -53,6 +63,26 @@ function GetRuleDefinitions(ruleConfig, options) {
|
|
|
53
63
|
}
|
|
54
64
|
return selectedRules;
|
|
55
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Check if a rule's category should be included based on the categories filter.
|
|
68
|
+
* - If no categories filter is specified, all categories are included
|
|
69
|
+
* - System rules are handled separately via includeSystem flag
|
|
70
|
+
* - Rules with matching category are included
|
|
71
|
+
* - Category matching is case-insensitive
|
|
72
|
+
*/ function isCategoryIncluded(ruleCategory, categories, includeSystem) {
|
|
73
|
+
// System category is controlled by systemRules flag, not categories filter
|
|
74
|
+
if (ruleCategory === 'system') {
|
|
75
|
+
return includeSystem;
|
|
76
|
+
}
|
|
77
|
+
// If no categories filter specified, include all non-system categories
|
|
78
|
+
if (!categories || categories.length === 0) {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
// Normalize categories to lowercase for case-insensitive matching
|
|
82
|
+
const normalizedCategories = categories.map((c)=>c.toLowerCase());
|
|
83
|
+
// Check if rule's category is in the allowed list (case-insensitive)
|
|
84
|
+
return normalizedCategories.includes(ruleCategory === null || ruleCategory === void 0 ? void 0 : ruleCategory.toLowerCase());
|
|
85
|
+
}
|
|
56
86
|
function getRules(ruleNames, options) {
|
|
57
87
|
return _RuleRegistry.ruleRegistry.getRulesByNames(ruleNames, options);
|
|
58
88
|
}
|
package/main/models/Flow.d.ts
CHANGED
package/main/models/Flow.js
CHANGED
|
@@ -259,16 +259,42 @@ let Flow = class Flow {
|
|
|
259
259
|
};
|
|
260
260
|
const builder = new _fastxmlparser.XMLBuilder(builderOptions);
|
|
261
261
|
const xmldataWithNs = _object_spread({}, this.xmldata);
|
|
262
|
+
// Always ensure the base xmlns is present
|
|
262
263
|
if (!xmldataWithNs["@_xmlns"]) {
|
|
263
264
|
xmldataWithNs["@_xmlns"] = flowXmlNamespace;
|
|
264
265
|
}
|
|
265
|
-
|
|
266
|
+
// Only add xmlns:xsi if the content actually uses xsi: attributes
|
|
267
|
+
// Don't add it unconditionally to avoid unnecessary diffs
|
|
268
|
+
if (!xmldataWithNs["@_xmlns:xsi"] && this.hasXsiAttributes(xmldataWithNs)) {
|
|
266
269
|
xmldataWithNs["@_xmlns:xsi"] = "http://www.w3.org/2001/XMLSchema-instance";
|
|
267
270
|
}
|
|
268
271
|
const rootObj = {
|
|
269
272
|
Flow: xmldataWithNs
|
|
270
273
|
};
|
|
271
|
-
|
|
274
|
+
const xmlContent = builder.build(rootObj);
|
|
275
|
+
// Add XML declaration if not present
|
|
276
|
+
const xmlDeclaration = '<?xml version="1.0" encoding="UTF-8"?>\n';
|
|
277
|
+
if (!xmlContent.startsWith('<?xml')) {
|
|
278
|
+
return xmlDeclaration + xmlContent;
|
|
279
|
+
}
|
|
280
|
+
return xmlContent;
|
|
281
|
+
}
|
|
282
|
+
hasXsiAttributes(obj) {
|
|
283
|
+
if (obj === null || obj === undefined) {
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
if (typeof obj !== 'object') {
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
for (const key of Object.keys(obj)){
|
|
290
|
+
if (key.includes(':xsi') || key.includes('xsi:')) {
|
|
291
|
+
return true;
|
|
292
|
+
}
|
|
293
|
+
if (this.hasXsiAttributes(obj[key])) {
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return false;
|
|
272
298
|
}
|
|
273
299
|
constructor(path, data){
|
|
274
300
|
// Flow elements (excludes legacy start nodes)
|
|
@@ -1,7 +1,7 @@
|
|
|
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
|
+
category?: 'problem' | 'suggestion' | 'layout' | 'system';
|
|
5
5
|
description: string;
|
|
6
6
|
summary: string;
|
|
7
7
|
docRefs: Array<{
|
|
@@ -29,9 +29,8 @@ export declare class RuleInfo {
|
|
|
29
29
|
label: string;
|
|
30
30
|
/**
|
|
31
31
|
* The category for the rule.
|
|
32
|
-
* 'problem' | 'suggestion' | 'layout'
|
|
33
32
|
*/
|
|
34
|
-
category: 'problem' | 'suggestion' | 'layout';
|
|
33
|
+
category: 'problem' | 'suggestion' | 'layout' | 'system';
|
|
35
34
|
/**
|
|
36
35
|
* Stable public identifier used for config, suppression, and reporting.
|
|
37
36
|
*/
|
package/main/models/RuleInfo.js
CHANGED
|
@@ -38,7 +38,6 @@ let RuleInfo = class RuleInfo {
|
|
|
38
38
|
*/ _define_property(this, "label", void 0);
|
|
39
39
|
/**
|
|
40
40
|
* The category for the rule.
|
|
41
|
-
* 'problem' | 'suggestion' | 'layout'
|
|
42
41
|
*/ _define_property(this, "category", void 0);
|
|
43
42
|
/**
|
|
44
43
|
* Stable public identifier used for config, suppression, and reporting.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as core from "../internals/internals";
|
|
2
|
+
import { RuleCommon } from "../models/RuleCommon";
|
|
3
|
+
import { IRuleDefinition } from "../internals/internals";
|
|
4
|
+
export declare class MissingStartReference extends RuleCommon implements IRuleDefinition {
|
|
5
|
+
constructor();
|
|
6
|
+
protected check(flow: core.Flow, _options: object | undefined, _suppressions: Set<string>): core.Violation[];
|
|
7
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "MissingStartReference", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return MissingStartReference;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _internals = /*#__PURE__*/ _interop_require_wildcard(require("../internals/internals"));
|
|
12
|
+
const _RuleCommon = require("../models/RuleCommon");
|
|
13
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
14
|
+
if (typeof WeakMap !== "function") return null;
|
|
15
|
+
var cacheBabelInterop = new WeakMap();
|
|
16
|
+
var cacheNodeInterop = new WeakMap();
|
|
17
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
18
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
19
|
+
})(nodeInterop);
|
|
20
|
+
}
|
|
21
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
22
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
23
|
+
return obj;
|
|
24
|
+
}
|
|
25
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
26
|
+
return {
|
|
27
|
+
default: obj
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
31
|
+
if (cache && cache.has(obj)) {
|
|
32
|
+
return cache.get(obj);
|
|
33
|
+
}
|
|
34
|
+
var newObj = {
|
|
35
|
+
__proto__: null
|
|
36
|
+
};
|
|
37
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
38
|
+
for(var key in obj){
|
|
39
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
40
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
41
|
+
if (desc && (desc.get || desc.set)) {
|
|
42
|
+
Object.defineProperty(newObj, key, desc);
|
|
43
|
+
} else {
|
|
44
|
+
newObj[key] = obj[key];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
newObj.default = obj;
|
|
49
|
+
if (cache) {
|
|
50
|
+
cache.set(obj, newObj);
|
|
51
|
+
}
|
|
52
|
+
return newObj;
|
|
53
|
+
}
|
|
54
|
+
let MissingStartReference = class MissingStartReference extends _RuleCommon.RuleCommon {
|
|
55
|
+
check(flow, _options, _suppressions) {
|
|
56
|
+
const violations = [];
|
|
57
|
+
if (!flow.startNode) {
|
|
58
|
+
violations.push(new _internals.Violation(new _internals.FlowAttribute("undefined", "startNode", "startNode")));
|
|
59
|
+
}
|
|
60
|
+
return violations;
|
|
61
|
+
}
|
|
62
|
+
constructor(){
|
|
63
|
+
super({
|
|
64
|
+
ruleId: "missing-start-reference",
|
|
65
|
+
category: "system",
|
|
66
|
+
name: "MissingStartReference",
|
|
67
|
+
label: "Missing Start Reference",
|
|
68
|
+
description: "When a flow has no start reference.",
|
|
69
|
+
summary: "Ensure flow has a start reference node",
|
|
70
|
+
supportedTypes: _internals.FlowType.allTypes(),
|
|
71
|
+
docRefs: []
|
|
72
|
+
}, {
|
|
73
|
+
severity: "error"
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
};
|
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.
|
|
4
|
+
"version": "6.18.0",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|