Skip to content

Commit cc6e83f

Browse files
committed
update core and readme
1 parent 3bd3452 commit cc6e83f

File tree

6 files changed

+95
-41
lines changed

6 files changed

+95
-41
lines changed

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ __*Identify potential issues and improvements in Salesforce Flows*__
2424
- [Configuration](#configuration)
2525
- [Defining the severity per rule](#defining-the-severity-per-rule)
2626
- [Specifying an exception](#specifying-an-exception)
27+
- [Configuring an expression](#configuring-an-expression)
2728

2829
## Installation
2930

@@ -80,9 +81,11 @@ sfdx flow:scan --config path/to/.flow-scanner.json
8081

8182
| Rule | Id | Description |
8283
|--------------|:-----:|:-----------|
84+
| **Old API version** | APIVersion | Newer API components may cause older versions of Flows to start behaving incorrectly due to differences in the underlying mechanics. The Api Version has been available as an attribute on the Flow since API v50.0 and it is recommended to limit variation and to update them on a regular basis. |
8385
| **DML statements in a loop** | DMLStatementInLoop | To avoid hitting Apex governor limits, we recommend grouping all of your database changes together at the end of the flow, whether those changes create, update, or delete records. |
8486
| **Duplicate DML operations** | DuplicateDMLOperations | If the flow commits changes to the database or performs actions between two screens, don't let users navigate back between screen. Otherwise, the flow may perform duplicate database operations. |
8587
| **Hardcoded Ids** | HardcodedIds | IDs are org-specific, so don’t hard-code IDs. Instead, pass them into variables when the flow starts. You can do so, for example, by using merge fields in URL parameters or by using a Get Records element. |
88+
| **Flow naming conventions** | FlowName | Readability of a flow is very important. Setting a naming convention for the Flow Name will improve the findability/searchability and overall consistency. It is recommended to at least provide a domain and a short description of the actions undertaken in the flow, in example Service_OrderFulfillment. |
8689
| **Missing flow description** | MissingFlowDescription | Descriptions are useful for documentation purposes. It is recommended to provide information about where it is used and what it will do. |
8790
| **Missing error handlers** | MissingFaultPath | Sometimes a flow doesn’t perform an operation that you configured it to do. By default, the flow shows an error message to the user and emails the admin who created the flow. However, you can control that behavior. |
8891
| **Missing null handlers** | MissingNullHandler | If a Get Records operation does not find any data it will return null. Use a decision element on the operation result variable to validate that the result is not null. |
@@ -146,3 +149,23 @@ Specifying exceptions can be done by flow, rule and result(s), as shown in the f
146149
}
147150
}
148151
```
152+
### Configuring an expression
153+
154+
Some rules have additional attributes to configure, such as the expression, that will overwrite default values. These can be configured in the same way as severity as shown in the following example.
155+
156+
```json
157+
{
158+
"rules": {
159+
"APIVersion":
160+
{
161+
"severity": "error",
162+
"expression": "===58"
163+
},
164+
"FlowName":
165+
{
166+
"severity": "error",
167+
"expression": "[A-Za-z0-9]"
168+
}
169+
}
170+
}
171+
```

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"cosmiconfig": "^8.1.3",
1414
"fs-extra": "^11.1.1",
1515
"glob": "^7.1.7",
16-
"lightning-flow-scanner-core": "^2.6.0",
16+
"lightning-flow-scanner-core": "2.15.0",
1717
"tslib": "^1",
1818
"xml2js": "^0.4.23"
1919
},

src/commands/flow/scan.ts

Lines changed: 57 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import { Violation } from "../../models/Violation";
1010
import * as c from "chalk";
1111
import { exec } from "child_process";
1212
import { cosmiconfig } from "cosmiconfig";
13+
import { FlowElement } from "lightning-flow-scanner-core/out/main/models/FlowElement";
14+
import { FlowVariable } from "lightning-flow-scanner-core/out/main/models/FlowVariable";
1315

1416
Messages.importMessagesDirectory(__dirname);
1517

@@ -47,7 +49,7 @@ export default class scan extends SfdxCommand {
4749
failon: flags.enum({
4850
char: "f",
4951
description: "Thresold failure level (error, warning, note, or never) defining when the command return code will be 1",
50-
options: ["error","warning","note","never"],
52+
options: ["error", "warning", "note", "never"],
5153
default: "error"
5254
}),
5355
retrieve: flags.boolean({
@@ -114,22 +116,31 @@ export default class scan extends SfdxCommand {
114116
const errorLevelsNumber = {};
115117
for (const scanResult of scanResults) {
116118
for (const ruleResult of scanResult.ruleResults) {
117-
errorLevelsNumber[ruleResult.severity] = (errorLevelsNumber[ruleResult.severity]|| 0) + 1
118-
if (ruleResult.details && ruleResult.details.length > 0) {
119+
errorLevelsNumber[ruleResult.severity] = (errorLevelsNumber[ruleResult.severity] || 0) + 1
120+
121+
if (ruleResult.type === 'pattern' && ruleResult.details && ruleResult.details.length > 0) {
119122
for (const result of ruleResult.details) {
120-
errors.push(
121-
new Violation(
122-
scanResult.flow.label[0],
123-
ruleResult.ruleName,
124-
ruleResult.ruleDescription,
125-
ruleResult.severity,
126-
{
127-
name: result.name,
128-
type: result.subtype,
129-
}
130-
)
131-
);
123+
errors.push(new Violation(
124+
scanResult.flow.label[0],
125+
ruleResult.ruleName,
126+
ruleResult.ruleDescription,
127+
ruleResult.severity,
128+
ruleResult.type,
129+
{
130+
name: (result as (FlowElement | FlowVariable)).name,
131+
type: (result as (FlowElement | FlowVariable)).subtype,
132+
}
133+
));
132134
}
135+
} else if (ruleResult.type === 'flow' && ruleResult.details) {
136+
errors.push(new Violation(
137+
scanResult.flow.label[0],
138+
ruleResult.ruleName,
139+
ruleResult.ruleDescription,
140+
ruleResult.severity,
141+
ruleResult.type,
142+
ruleResult.details
143+
))
133144
} else {
134145
if (!ruleResult.details && ruleResult.occurs) {
135146
errors.push(
@@ -138,9 +149,10 @@ export default class scan extends SfdxCommand {
138149
ruleResult.ruleName,
139150
ruleResult.ruleDescription,
140151
ruleResult.severity,
152+
ruleResult.type
141153
)
142154
);
143-
155+
144156
}
145157
}
146158
}
@@ -160,8 +172,13 @@ export default class scan extends SfdxCommand {
160172
this.ux.log('');
161173
for (const lintResult of lintResultFlow) {
162174
this.ux.log(`${c.yellow(lintResult.severity.toUpperCase() + ' ' + c.bold(lintResult.ruleName))}`);
175+
163176
if (lintResult.details) {
164-
this.ux.log(c.italic(`Details: ${c.yellow(lintResult.details.name)}, ${c.yellow(lintResult.details.type)}`));
177+
if (lintResult.type === 'pattern') {
178+
this.ux.log(c.italic(`Details: ${c.yellow(lintResult.details.name)}, ${c.yellow(lintResult.details.type)}`));
179+
} else {
180+
this.ux.log(c.italic(`Details: ${c.yellow(lintResult.details)}, ${c.yellow(lintResult.ruleName)}`));
181+
}
165182
}
166183
this.ux.log(c.italic(lintResult.description))
167184
this.ux.log('');
@@ -173,36 +190,42 @@ export default class scan extends SfdxCommand {
173190
// Get status depending on found errors & warnings
174191
let status = 0;
175192
if (this.failOn === 'never') {
176-
status = 0 ;
193+
status = 0;
177194
}
178195
else {
179-
if (this.failOn === "error" && (errorLevelsNumber["error"] || 0) > 0){
180-
status = 1;
181-
}
182-
else if (this.failOn === 'warning' &&
183-
((errorLevelsNumber["error"] || 0) > 0)
184-
|| ((errorLevelsNumber["warning"] || 0) > 0)) {
185-
status = 1;
186-
}
187-
else if (this.failOn === 'note' &&
188-
((errorLevelsNumber["error"] || 0) > 0)
189-
|| ((errorLevelsNumber["warning"] || 0) > 0)
190-
|| ((errorLevelsNumber["note"] || 0) > 0)) {
191-
status = 1;
192-
}
196+
if (this.failOn === "error" && (errorLevelsNumber["error"] || 0) > 0) {
197+
status = 1;
198+
}
199+
else if (this.failOn === 'warning' &&
200+
((errorLevelsNumber["error"] || 0) > 0)
201+
|| ((errorLevelsNumber["warning"] || 0) > 0)) {
202+
status = 1;
203+
}
204+
else if (this.failOn === 'note' &&
205+
((errorLevelsNumber["error"] || 0) > 0)
206+
|| ((errorLevelsNumber["warning"] || 0) > 0)
207+
|| ((errorLevelsNumber["note"] || 0) > 0)) {
208+
status = 1;
209+
}
193210
}
194211

195212
// Build summary message
196213
const flowsNumber = scanResults.length;
197214
const errornr = errors.length;
215+
const messageunformatted =
216+
"A total of " +
217+
errors.length +
218+
" errors have been found in " +
219+
flowsNumber +
220+
" flows.";
198221
const message =
199222
"A total of " +
200223
c.bold(errors.length) +
201224
" errors have been found in " +
202225
c.bold(flowsNumber) +
203226
" flows.";
204-
const summary = { flowsNumber:flowsNumber, errors: errornr, message, errorLevelsDetails: errorLevelsNumber };
205-
this.ux.styledHeader(summary.message);
227+
const summary = { flowsNumber: flowsNumber, errors: errornr, 'message' : messageunformatted, errorLevelsDetails: errorLevelsNumber };
228+
this.ux.styledHeader(message);
206229

207230
// Set status code = 1 if there are errors, that will make cli exit with code 1 when not in --json mode
208231
return { summary, status: status, results: errors };

src/libs/ParseFlows.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ export async function ParseFlows(selectedUris: any) {
1111
const parsedContent: { Flow: Flow } = await new XMLParser().execute(await fs.readFile(path.normalize(uri)));
1212
parsedFlows.push(new Flow(
1313
{
14+
'path': uri,
1415
interviewLabel: parsedContent.Flow.interviewLabel,
1516
label: parsedContent.Flow.label,
1617
processMetadataValues: parsedContent.Flow.processMetadataValues,
1718
processType: parsedContent.Flow.processType,
1819
start: parsedContent.Flow.start,
1920
status: parsedContent.Flow.status,
20-
uri: uri,
2121
xmldata: parsedContent
2222
}));
2323
} catch (e) {

src/models/Violation.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ export class Violation {
33
public ruleName: string;
44
public description: string;
55
public details;
6+
public type: string;
67
public severity: string;
78

8-
constructor(flowName: string, ruleName: string, description: string, severity: string, details?) {
9+
constructor(flowName: string, ruleName: string, description: string, severity: string, type: string, details?) {
910
this.flowName = flowName;
1011
this.ruleName = ruleName;
1112
this.description = description;
1213
this.severity = severity;
14+
this.type = type;
1315
this.details = details;
1416
}
1517
}

yarn.lock

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,11 @@
507507
version "16.0.0"
508508
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.0.0.tgz#067a6c49dc7a5c2412a505628e26902ae967bf6f"
509509

510+
"@types/node@^20.4.5":
511+
version "20.4.5"
512+
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.5.tgz#9dc0a5cb1ccce4f7a731660935ab70b9c00a5d69"
513+
integrity sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==
514+
510515
"@types/sinon@*":
511516
version "10.0.2"
512517
resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-10.0.2.tgz#f360d2f189c0fd433d14aeb97b9d705d7e4cc0e4"
@@ -2619,12 +2624,13 @@ levn@^0.4.1:
26192624
prelude-ls "^1.2.1"
26202625
type-check "~0.4.0"
26212626

2622-
lightning-flow-scanner-core@^2.5.0:
2623-
version "2.6.0"
2624-
resolved "https://registry.yarnpkg.com/lightning-flow-scanner-core/-/lightning-flow-scanner-core-2.6.0.tgz#b74d52c0fa2d84405a5d0917c5499e0654793644"
2625-
integrity sha512-ClXrBBwgo6+HDm3z1TEHUgk4XqQD/STnOgkmWAMQO7dzNg1e+L+kNFh0OuWaezVxqt0ca5ydmg21RfuubJibUA==
2627+
lightning-flow-scanner-core@2.15.0:
2628+
version "2.15.0"
2629+
resolved "https://registry.yarnpkg.com/lightning-flow-scanner-core/-/lightning-flow-scanner-core-2.15.0.tgz#8af5cd58ce63f6bb2555b7b887a769fc8ad5c464"
2630+
integrity sha512-8mKACTwpHUTfkgCMeZm33K12ZdeFoR+3K+Pcm4xh8Zqh8Y0ekbU5v86GBORYrVvrOAb4liPc4pF+tVTHvZfNOw==
26262631
dependencies:
26272632
"@types/chai" "^4.2.21"
2633+
"@types/node" "^20.4.5"
26282634
chai "^4.3.4"
26292635
global "^4.4.0"
26302636
logging "^3.3.0"

0 commit comments

Comments
 (0)