@flow-scanner/lightning-flow-scanner-core 6.4.2 → 6.5.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 +51 -14
- package/index.d.ts +4 -3
- package/index.js +4 -4
- package/main/interfaces/IRulesConfig.d.ts +6 -0
- package/main/interfaces/IRulesConfig.js +11 -0
- package/main/internals/internals.d.ts +6 -5
- package/main/internals/internals.js +11 -7
- package/main/libs/GetRuleDefinitions.d.ts +1 -1
- package/main/libs/GetRuleDefinitions.js +5 -6
- package/main/libs/ScanFlows.js +29 -3
- package/main/libs/exportAsDetails.d.ts +2 -15
- package/main/libs/exportAsDetails.js +69 -26
- package/main/libs/exportAsSarif.js +19 -18
- package/main/models/FlatViolation.d.ts +7 -0
- package/main/models/Flow.d.ts +18 -10
- package/main/models/Flow.js +82 -61
- package/main/models/LoopRuleCommon.d.ts +2 -2
- package/main/models/LoopRuleCommon.js +8 -10
- package/main/models/RuleCommon.d.ts +14 -2
- package/main/models/RuleCommon.js +16 -3
- package/main/models/RuleResult.d.ts +3 -3
- package/main/models/ScanResult.d.ts +1 -1
- package/main/models/Violation.d.ts +12 -0
- package/main/models/Violation.js +101 -0
- package/main/rules/APIVersion.d.ts +3 -3
- package/main/rules/APIVersion.js +20 -24
- package/main/rules/ActionCallsInLoop.js +1 -1
- package/main/rules/AutoLayout.d.ts +1 -3
- package/main/rules/AutoLayout.js +10 -20
- package/main/rules/CopyAPIName.d.ts +1 -1
- package/main/rules/CopyAPIName.js +4 -13
- package/main/rules/CyclomaticComplexity.d.ts +4 -4
- package/main/rules/CyclomaticComplexity.js +19 -27
- package/main/rules/DuplicateDMLOperation.d.ts +2 -2
- package/main/rules/DuplicateDMLOperation.js +53 -56
- package/main/rules/FlowDescription.d.ts +1 -1
- package/main/rules/FlowDescription.js +8 -12
- package/main/rules/FlowName.d.ts +2 -2
- package/main/rules/FlowName.js +12 -18
- package/main/rules/GetRecordAllFields.d.ts +1 -1
- package/main/rules/GetRecordAllFields.js +11 -21
- package/main/rules/HardcodedId.d.ts +1 -1
- package/main/rules/HardcodedId.js +4 -15
- package/main/rules/HardcodedUrl.d.ts +2 -2
- package/main/rules/HardcodedUrl.js +4 -17
- package/main/rules/InactiveFlow.d.ts +1 -1
- package/main/rules/InactiveFlow.js +7 -10
- package/main/rules/MissingFaultPath.d.ts +1 -1
- package/main/rules/MissingFaultPath.js +22 -24
- package/main/rules/MissingNullHandler.d.ts +1 -1
- package/main/rules/MissingNullHandler.js +67 -70
- package/main/rules/ProcessBuilder.d.ts +1 -3
- package/main/rules/ProcessBuilder.js +4 -8
- package/main/rules/RecursiveAfterUpdate.d.ts +1 -1
- package/main/rules/RecursiveAfterUpdate.js +29 -31
- package/main/rules/SameRecordFieldUpdates.d.ts +1 -1
- package/main/rules/SameRecordFieldUpdates.js +15 -21
- package/main/rules/TriggerOrder.d.ts +1 -1
- package/main/rules/TriggerOrder.js +8 -13
- package/main/rules/UnconnectedElement.d.ts +1 -1
- package/main/rules/UnconnectedElement.js +12 -15
- package/main/rules/UnsafeRunningContext.d.ts +1 -1
- package/main/rules/UnsafeRunningContext.js +12 -13
- package/main/rules/UnusedVariable.d.ts +1 -1
- package/main/rules/UnusedVariable.js +23 -27
- package/main/store/DefaultRuleStore.js +2 -3
- package/package.json +6 -7
- package/main/interfaces/AutoFixable.d.ts +0 -10
- package/main/models/ResultDetails.d.ts +0 -10
- package/main/models/ResultDetails.js +0 -57
- /package/main/{interfaces/AutoFixable.js → models/FlatViolation.js} +0 -0
package/README.md
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
- [Defining Severity Levels](#defining-severity-levels)
|
|
16
16
|
- [Configuring Expressions](#configuring-expressions)
|
|
17
17
|
- [Specifying Exceptions](#specifying-exceptions)
|
|
18
|
+
- [Report Detail Level](#report-detail-level)
|
|
18
19
|
- [Include Beta Rules](#include-beta-rules)
|
|
19
20
|
- **[Usage](#Usage)**
|
|
20
21
|
- [Examples](#examples)
|
|
@@ -27,7 +28,9 @@
|
|
|
27
28
|
## Default Rules
|
|
28
29
|
|
|
29
30
|
<p>📌<strong>Tip:</strong> To link directly to a specific rule, use the full GitHub anchor link format. Example:</p>
|
|
30
|
-
<p><em><a href="https://github.com/Flow-Scanner/lightning-flow-scanner-core#unsafe-running-context">https://github.com/Flow-Scanner/lightning-flow-scanner-core#unsafe-running-context</a></em></
|
|
31
|
+
<p><em><a href="https://github.com/Flow-Scanner/lightning-flow-scanner-core#unsafe-running-context">https://github.com/Flow-Scanner/lightning-flow-scanner-core#unsafe-running-context</a></em></p>
|
|
32
|
+
|
|
33
|
+
> Want to code a new rule? → See [How to Write a Rule](docs/write-a-new-rule.md)
|
|
31
34
|
|
|
32
35
|
### Action Calls In Loop(Beta)
|
|
33
36
|
|
|
@@ -125,7 +128,7 @@ _[UnusedVariable](https://github.com/Flow-Scanner/lightning-flow-scanner-core/tr
|
|
|
125
128
|
|
|
126
129
|
## Configuration
|
|
127
130
|
|
|
128
|
-
|
|
131
|
+
Lightning Flow Scanner is plug-and-play by default, but we recommend configuring and defining:
|
|
129
132
|
|
|
130
133
|
- The rules to be executed.
|
|
131
134
|
- The severity of violating any specific rule.
|
|
@@ -201,8 +204,10 @@ Specifying exceptions allows you to exclude specific scenarios from rule enforce
|
|
|
201
204
|
"exceptions": {
|
|
202
205
|
"<FlowName>": {
|
|
203
206
|
"<RuleName>": [
|
|
204
|
-
|
|
205
|
-
"
|
|
207
|
+
// Suppress a specific result:
|
|
208
|
+
"<ResultName>",
|
|
209
|
+
// Suppress ALL results of rule:
|
|
210
|
+
"*",
|
|
206
211
|
...
|
|
207
212
|
]
|
|
208
213
|
},
|
|
@@ -224,6 +229,22 @@ _Example_
|
|
|
224
229
|
}
|
|
225
230
|
```
|
|
226
231
|
|
|
232
|
+
### Report Detail Level
|
|
233
|
+
|
|
234
|
+
Control the verbosity of violation reports via detailLevel. By default (`enriched`), outputs include element or flow-level details like variable data types, node connectors/locations, or attribute expressions for comprehensive reports. Set to `simple` for lighter output with only line and column numbers.
|
|
235
|
+
|
|
236
|
+
```json
|
|
237
|
+
{
|
|
238
|
+
"rules": {
|
|
239
|
+
...
|
|
240
|
+
},
|
|
241
|
+
"exceptions": {
|
|
242
|
+
...
|
|
243
|
+
},
|
|
244
|
+
"detailLevel": "simple"
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
227
248
|
### Include Beta Rules
|
|
228
249
|
|
|
229
250
|
New rules are introduced in Beta mode before being added to the default ruleset. To include current Beta rules, enable the optional betamode parameter in your configuration:
|
|
@@ -236,15 +257,16 @@ New rules are introduced in Beta mode before being added to the default ruleset.
|
|
|
236
257
|
"exceptions": {
|
|
237
258
|
...
|
|
238
259
|
},
|
|
239
|
-
"
|
|
260
|
+
"betaMode": true
|
|
240
261
|
}
|
|
262
|
+
|
|
241
263
|
```
|
|
242
264
|
|
|
243
265
|
---
|
|
244
266
|
|
|
245
267
|
## Usage
|
|
246
268
|
|
|
247
|
-
`lightning-flow-scanner-core`
|
|
269
|
+
Use `lightning-flow-scanner-core` as a Node.js/browser dependency or standalone UMD module.
|
|
248
270
|
|
|
249
271
|
### Examples
|
|
250
272
|
|
|
@@ -282,7 +304,7 @@ _Retrieves rule definitions used in the scanner._
|
|
|
282
304
|
|
|
283
305
|
#### [`parse(selectedUris: any): Promise<ParsedFlow[]>`](https://github.com/Flow-Scanner/lightning-flow-scanner-core/tree/main/src/main/libs/ParseFlows.ts)
|
|
284
306
|
|
|
285
|
-
_Loads Flow XML files into in-memory models._
|
|
307
|
+
_Loads Flow XML files into in-memory models.(Node.js only)_
|
|
286
308
|
|
|
287
309
|
#### [`scan(parsedFlows: ParsedFlow[], ruleOptions?: IRulesConfig): ScanResult[]`](https://github.com/Flow-Scanner/lightning-flow-scanner-core/tree/main/src/main/libs/ScanFlows.ts)
|
|
288
310
|
|
|
@@ -348,14 +370,21 @@ npm install @flow-scanner/lightning-flow-scanner-core
|
|
|
348
370
|
npm run test
|
|
349
371
|
```
|
|
350
372
|
|
|
351
|
-
5.
|
|
352
|
-
|
|
373
|
+
5. Testing the module locally(Optional):
|
|
374
|
+
|
|
375
|
+
To link the module, run:
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
npm run link
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
a. Ad-Hoc Testing with node:
|
|
353
382
|
|
|
354
383
|
```bash
|
|
355
384
|
npm run link
|
|
356
385
|
```
|
|
357
386
|
|
|
358
|
-
b.
|
|
387
|
+
b. Test in a dependent project (e.g. VSX or CLI):
|
|
359
388
|
|
|
360
389
|
```bash
|
|
361
390
|
npm link @flow-scanner/lightning-flow-scanner-core
|
|
@@ -363,10 +392,18 @@ npm install @flow-scanner/lightning-flow-scanner-core
|
|
|
363
392
|
|
|
364
393
|
Your local module will now replace any installed version and update on rebuild.
|
|
365
394
|
|
|
366
|
-
6.
|
|
395
|
+
6. Deploy Demo Flows (Optional):
|
|
367
396
|
|
|
368
|
-
```bash
|
|
369
|
-
|
|
370
|
-
```
|
|
397
|
+
```bash
|
|
398
|
+
cd assets/example-flows && sf project deploy start &&
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
Navigate to the [Demo Readme](assets\example-flows\README.md) for full details
|
|
402
|
+
|
|
403
|
+
7. Create a standalone UMD Module(Optional):
|
|
404
|
+
|
|
405
|
+
```bash
|
|
406
|
+
npm run vite:dist // creates UMD at`dist/lightning-flow-scanner-core.umd.js`.
|
|
407
|
+
```
|
|
371
408
|
|
|
372
409
|
<p><strong>Want to help improve Lightning Flow Scanner? See our <a href="https://github.com/Flow-Scanner/lightning-flow-scanner-core?tab=contributing-ov-file">Contributing Guidelines</a></strong></p>
|
package/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { IRuleDefinition } from "./main/interfaces/IRuleDefinition";
|
|
2
2
|
import type { IRulesConfig } from "./main/interfaces/IRulesConfig";
|
|
3
|
+
import type { FlatViolation } from "./main/models/FlatViolation";
|
|
3
4
|
import { Compiler } from "./main/libs/Compiler";
|
|
4
5
|
import { exportDetails } from "./main/libs/exportAsDetails";
|
|
5
6
|
import { exportSarif } from "./main/libs/exportAsSarif";
|
|
@@ -15,8 +16,8 @@ import { FlowResource } from "./main/models/FlowResource";
|
|
|
15
16
|
import { FlowType } from "./main/models/FlowType";
|
|
16
17
|
import { FlowVariable } from "./main/models/FlowVariable";
|
|
17
18
|
import { ParsedFlow } from "./main/models/ParsedFlow";
|
|
18
|
-
import { ResultDetails } from "./main/models/ResultDetails";
|
|
19
19
|
import { RuleResult } from "./main/models/RuleResult";
|
|
20
20
|
import { ScanResult } from "./main/models/ScanResult";
|
|
21
|
-
|
|
22
|
-
export
|
|
21
|
+
import { Violation } from "./main/models/Violation";
|
|
22
|
+
export { Compiler, exportDetails, exportSarif, fix, Flow, FlowAttribute, FlowElement, FlowNode, FlowResource, FlowType, FlowVariable, getBetaRules, getRules, parse, ParsedFlow, Violation, RuleResult, scan, ScanResult, };
|
|
23
|
+
export type { FlatViolation, IRuleDefinition, IRulesConfig };
|
package/index.js
CHANGED
|
@@ -36,15 +36,15 @@ _export(exports, {
|
|
|
36
36
|
get ParsedFlow () {
|
|
37
37
|
return _ParsedFlow.ParsedFlow;
|
|
38
38
|
},
|
|
39
|
-
get ResultDetails () {
|
|
40
|
-
return _ResultDetails.ResultDetails;
|
|
41
|
-
},
|
|
42
39
|
get RuleResult () {
|
|
43
40
|
return _RuleResult.RuleResult;
|
|
44
41
|
},
|
|
45
42
|
get ScanResult () {
|
|
46
43
|
return _ScanResult.ScanResult;
|
|
47
44
|
},
|
|
45
|
+
get Violation () {
|
|
46
|
+
return _Violation.Violation;
|
|
47
|
+
},
|
|
48
48
|
get exportDetails () {
|
|
49
49
|
return _exportAsDetails.exportDetails;
|
|
50
50
|
},
|
|
@@ -82,6 +82,6 @@ const _FlowResource = require("./main/models/FlowResource");
|
|
|
82
82
|
const _FlowType = require("./main/models/FlowType");
|
|
83
83
|
const _FlowVariable = require("./main/models/FlowVariable");
|
|
84
84
|
const _ParsedFlow = require("./main/models/ParsedFlow");
|
|
85
|
-
const _ResultDetails = require("./main/models/ResultDetails");
|
|
86
85
|
const _RuleResult = require("./main/models/RuleResult");
|
|
87
86
|
const _ScanResult = require("./main/models/ScanResult");
|
|
87
|
+
const _Violation = require("./main/models/Violation");
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { IExceptions } from "./IExceptions";
|
|
2
2
|
import { IRuleOptions } from "./IRuleOptions";
|
|
3
|
+
export declare enum DetailLevel {
|
|
4
|
+
ENRICHED = "enriched",
|
|
5
|
+
SIMPLE = "simple"
|
|
6
|
+
}
|
|
3
7
|
export interface IRulesConfig {
|
|
8
|
+
betaMode?: boolean;
|
|
4
9
|
betamode?: boolean;
|
|
10
|
+
detailLevel?: 'enriched' | 'simple' | DetailLevel;
|
|
5
11
|
exceptions?: IExceptions;
|
|
6
12
|
rules?: IRuleOptions;
|
|
7
13
|
}
|
|
@@ -2,3 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", {
|
|
3
3
|
value: true
|
|
4
4
|
});
|
|
5
|
+
Object.defineProperty(exports, "DetailLevel", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return DetailLevel;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
var DetailLevel = /*#__PURE__*/ function(DetailLevel) {
|
|
12
|
+
DetailLevel["ENRICHED"] = "enriched";
|
|
13
|
+
DetailLevel["SIMPLE"] = "simple";
|
|
14
|
+
return DetailLevel;
|
|
15
|
+
}({});
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import type { IRuleDefinition } from "../interfaces/IRuleDefinition";
|
|
2
2
|
import type { IRulesConfig } from "../interfaces/IRulesConfig";
|
|
3
3
|
import { Compiler } from "../libs/Compiler";
|
|
4
|
+
import { FlatViolation } from "../models/FlatViolation";
|
|
4
5
|
import { Flow } from "../models/Flow";
|
|
5
6
|
import { FlowAttribute } from "../models/FlowAttribute";
|
|
6
7
|
import { FlowElement } from "../models/FlowElement";
|
|
7
|
-
import { FlowType } from "../models/FlowType";
|
|
8
8
|
import { FlowNode } from "../models/FlowNode";
|
|
9
9
|
import { FlowResource } from "../models/FlowResource";
|
|
10
|
+
import { FlowType } from "../models/FlowType";
|
|
10
11
|
import { FlowVariable } from "../models/FlowVariable";
|
|
11
|
-
import {
|
|
12
|
+
import { ParsedFlow } from "../models/ParsedFlow";
|
|
13
|
+
import { RuleCommon } from "../models/RuleCommon";
|
|
12
14
|
import { RuleResult } from "../models/RuleResult";
|
|
13
15
|
import { ScanResult } from "../models/ScanResult";
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
export { FlowAttribute, FlowElement, FlowNode, FlowType, FlowVariable, FlowResource, Flow, Compiler, ScanResult, RuleResult, ResultDetails, RuleCommon, ParsedFlow, };
|
|
16
|
+
import { Violation } from "../models/Violation";
|
|
17
|
+
export { FlatViolation, FlowAttribute, FlowElement, FlowNode, FlowType, FlowVariable, FlowResource, Flow, Compiler, ScanResult, RuleResult, Violation, RuleCommon, ParsedFlow, };
|
|
17
18
|
export type { IRuleDefinition, IRulesConfig };
|
|
@@ -12,6 +12,9 @@ _export(exports, {
|
|
|
12
12
|
get Compiler () {
|
|
13
13
|
return _Compiler.Compiler;
|
|
14
14
|
},
|
|
15
|
+
get FlatViolation () {
|
|
16
|
+
return _FlatViolation.FlatViolation;
|
|
17
|
+
},
|
|
15
18
|
get Flow () {
|
|
16
19
|
return _Flow.Flow;
|
|
17
20
|
},
|
|
@@ -36,9 +39,6 @@ _export(exports, {
|
|
|
36
39
|
get ParsedFlow () {
|
|
37
40
|
return _ParsedFlow.ParsedFlow;
|
|
38
41
|
},
|
|
39
|
-
get ResultDetails () {
|
|
40
|
-
return _ResultDetails.ResultDetails;
|
|
41
|
-
},
|
|
42
42
|
get RuleCommon () {
|
|
43
43
|
return _RuleCommon.RuleCommon;
|
|
44
44
|
},
|
|
@@ -47,18 +47,22 @@ _export(exports, {
|
|
|
47
47
|
},
|
|
48
48
|
get ScanResult () {
|
|
49
49
|
return _ScanResult.ScanResult;
|
|
50
|
+
},
|
|
51
|
+
get Violation () {
|
|
52
|
+
return _Violation.Violation;
|
|
50
53
|
}
|
|
51
54
|
});
|
|
52
55
|
const _Compiler = require("../libs/Compiler");
|
|
56
|
+
const _FlatViolation = require("../models/FlatViolation");
|
|
53
57
|
const _Flow = require("../models/Flow");
|
|
54
58
|
const _FlowAttribute = require("../models/FlowAttribute");
|
|
55
59
|
const _FlowElement = require("../models/FlowElement");
|
|
56
|
-
const _FlowType = require("../models/FlowType");
|
|
57
60
|
const _FlowNode = require("../models/FlowNode");
|
|
58
61
|
const _FlowResource = require("../models/FlowResource");
|
|
62
|
+
const _FlowType = require("../models/FlowType");
|
|
59
63
|
const _FlowVariable = require("../models/FlowVariable");
|
|
60
|
-
const
|
|
64
|
+
const _ParsedFlow = require("../models/ParsedFlow");
|
|
65
|
+
const _RuleCommon = require("../models/RuleCommon");
|
|
61
66
|
const _RuleResult = require("../models/RuleResult");
|
|
62
67
|
const _ScanResult = require("../models/ScanResult");
|
|
63
|
-
const
|
|
64
|
-
const _ParsedFlow = require("../models/ParsedFlow");
|
|
68
|
+
const _Violation = require("../models/Violation");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IRuleDefinition } from "../interfaces/IRuleDefinition";
|
|
2
2
|
import { IRulesConfig } from "../interfaces/IRulesConfig";
|
|
3
|
+
export declare function getBetaRules(): IRuleDefinition[];
|
|
3
4
|
export declare function GetRuleDefinitions(ruleConfig?: Map<string, unknown>, options?: IRulesConfig): IRuleDefinition[];
|
|
4
5
|
export declare function getRules(ruleNames?: string[], options?: IRulesConfig): IRuleDefinition[];
|
|
5
|
-
export declare function getBetaRules(): IRuleDefinition[];
|
|
@@ -21,9 +21,12 @@ _export(exports, {
|
|
|
21
21
|
});
|
|
22
22
|
const _DefaultRuleStore = require("../store/DefaultRuleStore");
|
|
23
23
|
const _DynamicRule = require("./DynamicRule");
|
|
24
|
+
function getBetaRules() {
|
|
25
|
+
return getBetaDefinition();
|
|
26
|
+
}
|
|
24
27
|
function GetRuleDefinitions(ruleConfig, options) {
|
|
25
28
|
const selectedRules = [];
|
|
26
|
-
const includeBeta = (options === null || options === void 0 ? void 0 : options.betamode) === true;
|
|
29
|
+
const includeBeta = (options === null || options === void 0 ? void 0 : options.betaMode) === true || (options === null || options === void 0 ? void 0 : options.betamode) === true;
|
|
27
30
|
if (ruleConfig && ruleConfig instanceof Map) {
|
|
28
31
|
for (const ruleName of ruleConfig.keys()){
|
|
29
32
|
let severity = "warning";
|
|
@@ -49,8 +52,7 @@ function GetRuleDefinitions(ruleConfig, options) {
|
|
|
49
52
|
selectedRules.push(matchedRule);
|
|
50
53
|
}
|
|
51
54
|
}
|
|
52
|
-
|
|
53
|
-
if (includeBeta) {
|
|
55
|
+
if (includeBeta && _DefaultRuleStore.BetaRuleStore && typeof _DefaultRuleStore.BetaRuleStore === 'object' && !Array.isArray(_DefaultRuleStore.BetaRuleStore)) {
|
|
54
56
|
for(const betaRuleName in _DefaultRuleStore.BetaRuleStore){
|
|
55
57
|
if (!selectedRules.some((r)=>r.name === betaRuleName)) {
|
|
56
58
|
const betaRule = new _DynamicRule.DynamicRule(betaRuleName);
|
|
@@ -73,9 +75,6 @@ function getRules(ruleNames, options) {
|
|
|
73
75
|
return GetRuleDefinitions(undefined, options);
|
|
74
76
|
}
|
|
75
77
|
}
|
|
76
|
-
function getBetaRules() {
|
|
77
|
-
return getBetaDefinition();
|
|
78
|
-
}
|
|
79
78
|
function getBetaDefinition() {
|
|
80
79
|
return Object.values(_DefaultRuleStore.BetaRuleStore).map((rule)=>new rule());
|
|
81
80
|
}
|
package/main/libs/ScanFlows.js
CHANGED
|
@@ -17,6 +17,8 @@ _export(exports, {
|
|
|
17
17
|
}
|
|
18
18
|
});
|
|
19
19
|
const _internals = require("../../main/internals/internals");
|
|
20
|
+
const _IRulesConfig = require("../interfaces/IRulesConfig");
|
|
21
|
+
const _Violation = require("../models/Violation");
|
|
20
22
|
const _GetRuleDefinitions = require("./GetRuleDefinitions");
|
|
21
23
|
function scan(parsedFlows, ruleOptions) {
|
|
22
24
|
const flows = [];
|
|
@@ -26,11 +28,13 @@ function scan(parsedFlows, ruleOptions) {
|
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
const scanResults = ScanFlows(flows, ruleOptions);
|
|
29
|
-
return scanResults;
|
|
31
|
+
return scanResults;
|
|
30
32
|
}
|
|
31
33
|
function ScanFlows(flows, ruleOptions) {
|
|
32
34
|
const flowResults = [];
|
|
33
35
|
let selectedRules = [];
|
|
36
|
+
const rawMode = ruleOptions === null || ruleOptions === void 0 ? void 0 : ruleOptions.detailLevel;
|
|
37
|
+
const detailLevel = typeof rawMode === 'string' && rawMode.toLowerCase() === 'simple' ? _IRulesConfig.DetailLevel.SIMPLE : _IRulesConfig.DetailLevel.ENRICHED;
|
|
34
38
|
if ((ruleOptions === null || ruleOptions === void 0 ? void 0 : ruleOptions.rules) && Object.keys(ruleOptions.rules).length > 0) {
|
|
35
39
|
const ruleMap = new Map();
|
|
36
40
|
for (const [ruleName, config] of Object.entries(ruleOptions.rules)){
|
|
@@ -40,7 +44,9 @@ function ScanFlows(flows, ruleOptions) {
|
|
|
40
44
|
} else {
|
|
41
45
|
selectedRules = (0, _GetRuleDefinitions.GetRuleDefinitions)();
|
|
42
46
|
}
|
|
43
|
-
|
|
47
|
+
const flowXmlCache = new Map();
|
|
48
|
+
for (const flowInput of flows){
|
|
49
|
+
const flow = flowInput instanceof _internals.Flow ? flowInput : _internals.Flow.from(flowInput);
|
|
44
50
|
const ruleResults = [];
|
|
45
51
|
for (const rule of selectedRules){
|
|
46
52
|
try {
|
|
@@ -53,7 +59,6 @@ function ScanFlows(flows, ruleOptions) {
|
|
|
53
59
|
if (ruleOptions === null || ruleOptions === void 0 ? void 0 : (_ruleOptions_rules = ruleOptions.rules) === null || _ruleOptions_rules === void 0 ? void 0 : _ruleOptions_rules[rule.name]) {
|
|
54
60
|
config = ruleOptions.rules[rule.name];
|
|
55
61
|
}
|
|
56
|
-
// WILDCARD SUPPORT: "*" = suppress all
|
|
57
62
|
const rawSuppressions = ruleOptions === null || ruleOptions === void 0 ? void 0 : (_ruleOptions_exceptions = ruleOptions.exceptions) === null || _ruleOptions_exceptions === void 0 ? void 0 : (_ruleOptions_exceptions_flow_name = _ruleOptions_exceptions[flow.name]) === null || _ruleOptions_exceptions_flow_name === void 0 ? void 0 : _ruleOptions_exceptions_flow_name[rule.name];
|
|
58
63
|
const suppressions = (rawSuppressions === null || rawSuppressions === void 0 ? void 0 : rawSuppressions.includes("*")) ? [
|
|
59
64
|
"*"
|
|
@@ -62,6 +67,16 @@ function ScanFlows(flows, ruleOptions) {
|
|
|
62
67
|
if (result.severity !== rule.severity) {
|
|
63
68
|
result.severity = rule.severity;
|
|
64
69
|
}
|
|
70
|
+
if (result.details.length > 0) {
|
|
71
|
+
let flowXml = flowXmlCache.get(flow.name);
|
|
72
|
+
if (!flowXml) {
|
|
73
|
+
flowXml = flow.toXMLString();
|
|
74
|
+
flowXmlCache.set(flow.name, flowXml);
|
|
75
|
+
}
|
|
76
|
+
if (flowXml) {
|
|
77
|
+
(0, _Violation.enrichViolationsWithLineNumbers)(result.details, flowXml);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
65
80
|
ruleResults.push(result);
|
|
66
81
|
} catch (error) {
|
|
67
82
|
const message = `Something went wrong while executing ${rule.name} in the Flow: ${flow.name} with error ${error}`;
|
|
@@ -69,6 +84,17 @@ function ScanFlows(flows, ruleOptions) {
|
|
|
69
84
|
}
|
|
70
85
|
}
|
|
71
86
|
flowResults.push(new _internals.ScanResult(flow, ruleResults));
|
|
87
|
+
flowXmlCache.delete(flow.name);
|
|
88
|
+
}
|
|
89
|
+
flowXmlCache.clear();
|
|
90
|
+
if (detailLevel === _IRulesConfig.DetailLevel.SIMPLE) {
|
|
91
|
+
flowResults.forEach((scanResult)=>{
|
|
92
|
+
scanResult.ruleResults.forEach((ruleResult)=>{
|
|
93
|
+
ruleResult.details.forEach((violation)=>{
|
|
94
|
+
delete violation.details;
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
});
|
|
72
98
|
}
|
|
73
99
|
return flowResults;
|
|
74
100
|
}
|
|
@@ -1,16 +1,3 @@
|
|
|
1
|
+
import { FlatViolation } from "../models/FlatViolation";
|
|
1
2
|
import { ScanResult } from "../models/ScanResult";
|
|
2
|
-
export
|
|
3
|
-
connectsTo?: string;
|
|
4
|
-
dataType?: string;
|
|
5
|
-
expression?: string;
|
|
6
|
-
flowFile: string;
|
|
7
|
-
flowName: string;
|
|
8
|
-
locationX?: string;
|
|
9
|
-
locationY?: string;
|
|
10
|
-
metaType: string;
|
|
11
|
-
name: string;
|
|
12
|
-
ruleName: string;
|
|
13
|
-
severity: string;
|
|
14
|
-
type: string;
|
|
15
|
-
}
|
|
16
|
-
export declare function exportDetails(results: ScanResult[]): FlatViolation[];
|
|
3
|
+
export declare function exportDetails(results: ScanResult[], includeDetails?: boolean): FlatViolation[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", {
|
|
3
3
|
value: true
|
|
4
4
|
});
|
|
@@ -8,36 +8,79 @@ Object.defineProperty(exports, "exportDetails", {
|
|
|
8
8
|
return exportDetails;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
-
function
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
function _define_property(obj, key, value) {
|
|
12
|
+
if (key in obj) {
|
|
13
|
+
Object.defineProperty(obj, key, {
|
|
14
|
+
value: value,
|
|
15
|
+
enumerable: true,
|
|
16
|
+
configurable: true,
|
|
17
|
+
writable: true
|
|
18
|
+
});
|
|
19
|
+
} else {
|
|
20
|
+
obj[key] = value;
|
|
21
|
+
}
|
|
22
|
+
return obj;
|
|
23
|
+
}
|
|
24
|
+
function _object_spread(target) {
|
|
25
|
+
for(var i = 1; i < arguments.length; i++){
|
|
26
|
+
var source = arguments[i] != null ? arguments[i] : {};
|
|
27
|
+
var ownKeys = Object.keys(source);
|
|
28
|
+
if (typeof Object.getOwnPropertySymbols === "function") {
|
|
29
|
+
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
|
|
30
|
+
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
ownKeys.forEach(function(key) {
|
|
34
|
+
_define_property(target, key, source[key]);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return target;
|
|
38
|
+
}
|
|
39
|
+
function ownKeys(object, enumerableOnly) {
|
|
40
|
+
var keys = Object.keys(object);
|
|
41
|
+
if (Object.getOwnPropertySymbols) {
|
|
42
|
+
var symbols = Object.getOwnPropertySymbols(object);
|
|
43
|
+
if (enumerableOnly) {
|
|
44
|
+
symbols = symbols.filter(function(sym) {
|
|
45
|
+
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
keys.push.apply(keys, symbols);
|
|
49
|
+
}
|
|
50
|
+
return keys;
|
|
51
|
+
}
|
|
52
|
+
function _object_spread_props(target, source) {
|
|
53
|
+
source = source != null ? source : {};
|
|
54
|
+
if (Object.getOwnPropertyDescriptors) {
|
|
55
|
+
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
|
|
56
|
+
} else {
|
|
57
|
+
ownKeys(Object(source)).forEach(function(key) {
|
|
58
|
+
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return target;
|
|
62
|
+
}
|
|
63
|
+
function exportDetails(results, includeDetails = false) {
|
|
64
|
+
return results.flatMap((result)=>{
|
|
14
65
|
const flow = result.flow;
|
|
15
66
|
const flowName = flow.label || flow.name;
|
|
16
67
|
const flowFile = flow.fsPath ? flow.fsPath.replace(/\\/g, "/") : `${flow.name}.flow-meta.xml`;
|
|
17
|
-
|
|
68
|
+
return result.ruleResults.filter((rule)=>{
|
|
18
69
|
var _rule_details;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
dataType: d.dataType,
|
|
28
|
-
expression: d.expression,
|
|
70
|
+
return rule.occurs && ((_rule_details = rule.details) === null || _rule_details === void 0 ? void 0 : _rule_details.length);
|
|
71
|
+
}).flatMap((rule)=>rule.details.map((detail)=>{
|
|
72
|
+
// Exclude details by default (via Omit), add conditionally
|
|
73
|
+
const base = detail;
|
|
74
|
+
var _rule_severity;
|
|
75
|
+
const exported = _object_spread_props(_object_spread({}, base, includeDetails && detail.details ? {
|
|
76
|
+
details: detail.details
|
|
77
|
+
} : {}), {
|
|
29
78
|
flowFile,
|
|
30
79
|
flowName,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
metaType: detail.metaType,
|
|
34
|
-
name: detail.name,
|
|
35
|
-
ruleName,
|
|
36
|
-
severity,
|
|
37
|
-
type: detail.type
|
|
80
|
+
ruleName: rule.ruleDefinition.label || rule.ruleName,
|
|
81
|
+
severity: (_rule_severity = rule.severity) !== null && _rule_severity !== void 0 ? _rule_severity : "error"
|
|
38
82
|
});
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
return violations;
|
|
83
|
+
return exported;
|
|
84
|
+
}));
|
|
85
|
+
});
|
|
43
86
|
}
|
|
@@ -58,7 +58,7 @@ function exportSarif(results) {
|
|
|
58
58
|
index: 0,
|
|
59
59
|
uri
|
|
60
60
|
},
|
|
61
|
-
region: mapRegion(d
|
|
61
|
+
region: mapRegion(d)
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
],
|
|
@@ -100,26 +100,27 @@ function exportSarif(results) {
|
|
|
100
100
|
}, null, 2);
|
|
101
101
|
}
|
|
102
102
|
function getUri(flow) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
for(let i = 0; i < lines.length; i++){
|
|
113
|
-
if (lines[i].includes(`<name>${name}</name>`)) {
|
|
114
|
-
return {
|
|
115
|
-
startLine: i + 1,
|
|
116
|
-
startColumn: lines[i].indexOf(name) + 1
|
|
117
|
-
};
|
|
103
|
+
// Prefer uri (works in both browser and Node)
|
|
104
|
+
if (flow.uri) {
|
|
105
|
+
return flow.uri.replace(/\\/g, "/");
|
|
106
|
+
}
|
|
107
|
+
// Node only: fsPath is only set in Node environments
|
|
108
|
+
if (flow.fsPath) {
|
|
109
|
+
const match = flow.fsPath.match(/(?:force-app|src)\/.+$/);
|
|
110
|
+
if (match) {
|
|
111
|
+
return match[0].replace(/\\/g, "/");
|
|
118
112
|
}
|
|
113
|
+
return flow.fsPath.replace(/\\/g, "/");
|
|
119
114
|
}
|
|
115
|
+
return `flows/${flow.name}.flow-meta.xml`;
|
|
116
|
+
}
|
|
117
|
+
function mapRegion(detail) {
|
|
118
|
+
var _detail_columnNumber, _detail_lineNumber;
|
|
119
|
+
// Use pre-enriched line/column from Violation (added by enrichViolationsWithLineNumbers)
|
|
120
|
+
// Fallback if somehow missing (e.g., unenriched legacy data)
|
|
120
121
|
return {
|
|
121
|
-
|
|
122
|
-
|
|
122
|
+
startColumn: (_detail_columnNumber = detail.columnNumber) !== null && _detail_columnNumber !== void 0 ? _detail_columnNumber : 1,
|
|
123
|
+
startLine: (_detail_lineNumber = detail.lineNumber) !== null && _detail_lineNumber !== void 0 ? _detail_lineNumber : 1
|
|
123
124
|
};
|
|
124
125
|
}
|
|
125
126
|
function mapSeverity(sev) {
|
package/main/models/Flow.d.ts
CHANGED
|
@@ -1,31 +1,39 @@
|
|
|
1
1
|
import { FlowElement } from "./FlowElement";
|
|
2
2
|
export declare class Flow {
|
|
3
|
+
/**
|
|
4
|
+
* Metadata Tags of Salesforce Flow Elements
|
|
5
|
+
*/
|
|
6
|
+
static readonly FLOW_METADATA_TAGS: readonly ["description", "apiVersion", "processMetadataValues", "processType", "interviewLabel", "label", "status", "runInMode", "startElementReference", "isTemplate", "fullName", "timeZoneSidKey", "isAdditionalPermissionRequiredToRun", "migratedFromWorkflowRuleName", "triggerOrder", "environments", "segment"];
|
|
7
|
+
/**
|
|
8
|
+
* Categorized flow contents that should be used in the rule implementation
|
|
9
|
+
*/
|
|
10
|
+
static readonly FLOW_NODES: readonly ["actionCalls", "apexPluginCalls", "assignments", "collectionProcessors", "decisions", "loops", "orchestratedStages", "recordCreates", "recordDeletes", "recordLookups", "recordUpdates", "recordRollbacks", "screens", "start", "steps", "subflows", "waits", "transforms", "customErrors"];
|
|
11
|
+
static readonly FLOW_RESOURCES: readonly ["textTemplates", "stages"];
|
|
12
|
+
static readonly FLOW_VARIABLES: readonly ["choices", "constants", "dynamicChoiceSets", "formulas", "variables"];
|
|
3
13
|
/**
|
|
4
14
|
* Categorized flow contents that should be used in the rule implementation
|
|
5
15
|
*/
|
|
6
16
|
elements?: FlowElement[];
|
|
7
|
-
fsPath
|
|
17
|
+
fsPath?: string;
|
|
18
|
+
uri?: string;
|
|
8
19
|
interviewLabel?: string;
|
|
9
20
|
label: string;
|
|
10
21
|
name?: string;
|
|
11
22
|
processMetadataValues?: any;
|
|
12
|
-
processType?:
|
|
23
|
+
processType?: string;
|
|
13
24
|
root?: any;
|
|
14
25
|
start?: any;
|
|
15
|
-
startElementReference?:
|
|
16
|
-
startReference
|
|
17
|
-
status?:
|
|
26
|
+
startElementReference?: string;
|
|
27
|
+
startReference?: string;
|
|
28
|
+
status?: string;
|
|
18
29
|
triggerOrder?: number;
|
|
19
|
-
type?:
|
|
30
|
+
type?: string;
|
|
20
31
|
/**
|
|
21
32
|
* XML to JSON conversion in raw format
|
|
22
33
|
*/
|
|
23
34
|
xmldata: any;
|
|
24
|
-
private flowMetadata;
|
|
25
|
-
private flowNodes;
|
|
26
|
-
private flowResources;
|
|
27
|
-
private flowVariables;
|
|
28
35
|
constructor(path?: string, data?: unknown);
|
|
36
|
+
static from(obj: Partial<Flow>): Flow;
|
|
29
37
|
preProcessNodes(): void;
|
|
30
38
|
toXMLString(): string;
|
|
31
39
|
private findStart;
|