@flow-scanner/lightning-flow-scanner-core 6.0.4 → 6.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -18
- package/index.d.ts +2 -1
- package/index.js +4 -0
- package/main/libs/ExportSarif.d.ts +2 -0
- package/main/libs/ExportSarif.js +136 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,18 +4,23 @@
|
|
|
4
4
|
</a>
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
|
-
<p align="center"><i>
|
|
7
|
+
<p align="center"><i>UMD-compatible Flow metadata engine for Node.js & browsers—20+ rules to catch common issues.</i></p>
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Table of contens
|
|
12
|
+
|
|
13
|
+
- **[Default Rules](#default-rules)**
|
|
14
|
+
- **[Configuration](#configuration)**
|
|
11
15
|
- [Defining Severity Levels](#defining-severity-levels)
|
|
12
16
|
- [Configuring Expressions](#configuring-expressions)
|
|
13
17
|
- [Specifying Exceptions](#specifying-exceptions)
|
|
14
18
|
- [Include Beta Rules](#include-beta-rules)
|
|
15
|
-
- [Usage](#Usage)
|
|
16
|
-
- [
|
|
17
|
-
- [
|
|
18
|
-
- [
|
|
19
|
+
- **[Usage](#Usage)**
|
|
20
|
+
- [Examples](#examples)
|
|
21
|
+
- [Functions](#core-functions)
|
|
22
|
+
- **[Installation](#installation)**
|
|
23
|
+
- **[Development](#development)**
|
|
19
24
|
|
|
20
25
|
---
|
|
21
26
|
|
|
@@ -24,7 +29,7 @@
|
|
|
24
29
|
<p>📌 <strong>Tip:</strong> To link directly to a specific rule, use the full GitHub anchor link format. Example:</p>
|
|
25
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></i></p>
|
|
26
31
|
|
|
27
|
-
### Action Calls In Loop
|
|
32
|
+
### Action Calls In Loop(Beta)
|
|
28
33
|
|
|
29
34
|
_[ActionCallsInLoop](https://github.com/Flow-Scanner/lightning-flow-scanner-core/tree/main/src/main/rules/ActionCallsInLoop.ts)_ - To prevent exceeding Apex governor limits, it is advisable to consolidate and bulkify your apex calls, utilizing a single action call containing a collection variable at the end of the loop.
|
|
30
35
|
|
|
@@ -226,15 +231,39 @@ New rules are introduced in Beta mode before being added to the default ruleset.
|
|
|
226
231
|
|
|
227
232
|
## Usage
|
|
228
233
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
```
|
|
234
|
-
|
|
234
|
+
The Lightning Flow Scanner Core can be used as a dependency in Node.js and browser environments, or used as a standalone UMD module.
|
|
235
|
+
|
|
236
|
+
### Examples
|
|
237
|
+
|
|
238
|
+
```js
|
|
239
|
+
// Basic
|
|
240
|
+
import { parse, scan } from "@flow-scanner/lightning-flow-scanner-core";
|
|
241
|
+
parse("flows/*.xml").then(scan);
|
|
242
|
+
|
|
243
|
+
// Apply fixes automatically
|
|
244
|
+
import { parse, scan, fix } from "@flow-scanner/lightning-flow-scanner-core";
|
|
245
|
+
parse("flows/*.xml").then(scan).then(fix);
|
|
246
|
+
|
|
247
|
+
// Get SARIF output
|
|
248
|
+
import { parse, scan, exportSarif } from "@flow-scanner/lightning-flow-scanner-core";
|
|
249
|
+
parse("flows/*.xml")
|
|
250
|
+
.then(scan)
|
|
251
|
+
.then(exportSarif)
|
|
252
|
+
.then((sarif) => save("results.sarif", sarif));
|
|
253
|
+
|
|
254
|
+
// Browser Usage (Tooling API)
|
|
255
|
+
const { Flow, scan } = window.lightningflowscanner;
|
|
256
|
+
const metadataRes = await conn.tooling.query(`SELECT Id, FullName, Metadata FROM Flow`);
|
|
257
|
+
const results = scan(
|
|
258
|
+
metadataRes.records.map((r) => ({
|
|
259
|
+
uri: `/services/data/v60.0/tooling/sobjects/Flow/${r.Id}`,
|
|
260
|
+
flow: new Flow(r.FullName, r.Metadata),
|
|
261
|
+
})),
|
|
262
|
+
optionsForScan
|
|
263
|
+
);
|
|
235
264
|
```
|
|
236
265
|
|
|
237
|
-
###
|
|
266
|
+
### Functions
|
|
238
267
|
|
|
239
268
|
#### [`getRules(ruleNames?: string[]): IRuleDefinition[]`](https://github.com/Flow-Scanner/lightning-flow-scanner-core/tree/main/src/main/libs/GetRuleDefinitions.ts)
|
|
240
269
|
|
|
@@ -242,15 +271,33 @@ _Retrieves rule definitions used in the scanner._
|
|
|
242
271
|
|
|
243
272
|
#### [`parse(selectedUris: any): Promise<ParsedFlow[]>`](https://github.com/Flow-Scanner/lightning-flow-scanner-core/tree/main/src/main/libs/ParseFlows.ts)
|
|
244
273
|
|
|
245
|
-
|
|
274
|
+
_Loads Flow XML files into in-memory models._
|
|
246
275
|
|
|
247
276
|
#### [`scan(parsedFlows: ParsedFlow[], ruleOptions?: IRulesConfig): ScanResult[]`](https://github.com/Flow-Scanner/lightning-flow-scanner-core/tree/main/src/main/libs/ScanFlows.ts)
|
|
248
277
|
|
|
249
|
-
_Runs
|
|
278
|
+
_Runs all enabled rules and returns detailed violations._
|
|
250
279
|
|
|
251
280
|
#### [`fix(results: ScanResult[]): ScanResult[]`](https://github.com/Flow-Scanner/lightning-flow-scanner-core/tree/main/src/main/libs/FixFlows.ts)
|
|
252
281
|
|
|
253
|
-
|
|
282
|
+
_Automatically applies available fixes(removing variables and unconnected elements)._
|
|
283
|
+
|
|
284
|
+
#### [`exportSarif(results: ScanResult[]): string`](https://github.com/Flow-Scanner/lightning-flow-scanner-core/tree/main/src/main/libs/ExportSarif.ts)
|
|
285
|
+
|
|
286
|
+
_Generates SARIF output with paths and exact line numbers._
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## Installation
|
|
291
|
+
|
|
292
|
+
`lightning-flow-scanner-core` is published to **npm** only.
|
|
293
|
+
|
|
294
|
+
[](https://www.npmjs.com/package/@flow-scanner/lightning-flow-scanner-core)
|
|
295
|
+
|
|
296
|
+
**To install with npm:**
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
npm install @flow-scanner/lightning-flow-scanner-core
|
|
300
|
+
```
|
|
254
301
|
|
|
255
302
|
---
|
|
256
303
|
|
package/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { IRuleDefinition } from "./main/interfaces/IRuleDefinition";
|
|
2
2
|
import type { IRulesConfig } from "./main/interfaces/IRulesConfig";
|
|
3
3
|
import { Compiler } from "./main/libs/Compiler";
|
|
4
|
+
import { exportSarif } from "./main/libs/ExportSarif";
|
|
4
5
|
import { fix } from "./main/libs/FixFlows";
|
|
5
6
|
import { getBetaRules, getRules } from "./main/libs/GetRuleDefinitions";
|
|
6
7
|
import { parse } from "./main/libs/ParseFlows";
|
|
@@ -17,5 +18,5 @@ import { ParsedFlow } from "./main/models/ParsedFlow";
|
|
|
17
18
|
import { ResultDetails } from "./main/models/ResultDetails";
|
|
18
19
|
import { RuleResult } from "./main/models/RuleResult";
|
|
19
20
|
import { ScanResult } from "./main/models/ScanResult";
|
|
20
|
-
export { AdvancedRule, Compiler, fix, Flow, FlowAttribute, FlowElement, FlowNode, FlowResource, FlowType, FlowVariable, getBetaRules, getRules, parse, ParsedFlow, ResultDetails, RuleResult, scan, ScanResult, };
|
|
21
|
+
export { AdvancedRule, Compiler, exportSarif, fix, Flow, FlowAttribute, FlowElement, FlowNode, FlowResource, FlowType, FlowVariable, getBetaRules, getRules, parse, ParsedFlow, ResultDetails, RuleResult, scan, ScanResult, };
|
|
21
22
|
export type { IRuleDefinition, IRulesConfig };
|
package/index.js
CHANGED
|
@@ -48,6 +48,9 @@ _export(exports, {
|
|
|
48
48
|
get ScanResult () {
|
|
49
49
|
return _ScanResult.ScanResult;
|
|
50
50
|
},
|
|
51
|
+
get exportSarif () {
|
|
52
|
+
return _ExportSarif.exportSarif;
|
|
53
|
+
},
|
|
51
54
|
get fix () {
|
|
52
55
|
return _FixFlows.fix;
|
|
53
56
|
},
|
|
@@ -65,6 +68,7 @@ _export(exports, {
|
|
|
65
68
|
}
|
|
66
69
|
});
|
|
67
70
|
const _Compiler = require("./main/libs/Compiler");
|
|
71
|
+
const _ExportSarif = require("./main/libs/ExportSarif");
|
|
68
72
|
const _FixFlows = require("./main/libs/FixFlows");
|
|
69
73
|
const _GetRuleDefinitions = require("./main/libs/GetRuleDefinitions");
|
|
70
74
|
const _ParseFlows = require("./main/libs/ParseFlows");
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// src/main/libs/exportSarif.ts
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "exportSarif", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function() {
|
|
9
|
+
return exportSarif;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
function _define_property(obj, key, value) {
|
|
13
|
+
if (key in obj) {
|
|
14
|
+
Object.defineProperty(obj, key, {
|
|
15
|
+
value: value,
|
|
16
|
+
enumerable: true,
|
|
17
|
+
configurable: true,
|
|
18
|
+
writable: true
|
|
19
|
+
});
|
|
20
|
+
} else {
|
|
21
|
+
obj[key] = value;
|
|
22
|
+
}
|
|
23
|
+
return obj;
|
|
24
|
+
}
|
|
25
|
+
function _object_spread(target) {
|
|
26
|
+
for(var i = 1; i < arguments.length; i++){
|
|
27
|
+
var source = arguments[i] != null ? arguments[i] : {};
|
|
28
|
+
var ownKeys = Object.keys(source);
|
|
29
|
+
if (typeof Object.getOwnPropertySymbols === "function") {
|
|
30
|
+
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
|
|
31
|
+
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
ownKeys.forEach(function(key) {
|
|
35
|
+
_define_property(target, key, source[key]);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return target;
|
|
39
|
+
}
|
|
40
|
+
function exportSarif(results) {
|
|
41
|
+
const runs = results.map((result)=>{
|
|
42
|
+
const flow = result.flow;
|
|
43
|
+
const uri = getUri(flow);
|
|
44
|
+
return {
|
|
45
|
+
artifacts: [
|
|
46
|
+
{
|
|
47
|
+
location: {
|
|
48
|
+
uri
|
|
49
|
+
},
|
|
50
|
+
sourceLanguage: "xml"
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
results: result.ruleResults.filter((r)=>r.occurs).flatMap((r)=>r.details.map((d)=>({
|
|
54
|
+
level: mapSeverity(r.severity),
|
|
55
|
+
locations: [
|
|
56
|
+
{
|
|
57
|
+
physicalLocation: {
|
|
58
|
+
artifactLocation: {
|
|
59
|
+
index: 0,
|
|
60
|
+
uri
|
|
61
|
+
},
|
|
62
|
+
region: mapRegion(d, result.flow.toXMLString() || "")
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
message: {
|
|
67
|
+
text: r.errorMessage || `${r.ruleName} in ${d.name}`
|
|
68
|
+
},
|
|
69
|
+
properties: _object_spread({
|
|
70
|
+
element: d.name,
|
|
71
|
+
flow: flow.name,
|
|
72
|
+
type: d.type
|
|
73
|
+
}, d.details),
|
|
74
|
+
ruleId: r.ruleName
|
|
75
|
+
}))),
|
|
76
|
+
tool: {
|
|
77
|
+
driver: {
|
|
78
|
+
informationUri: "https://github.com/Flow-Scanner/lightning-flow-scanner-core",
|
|
79
|
+
name: "Lightning Flow Scanner",
|
|
80
|
+
rules: result.ruleResults.filter((r)=>r.occurs).map((r)=>({
|
|
81
|
+
defaultConfiguration: {
|
|
82
|
+
level: mapSeverity(r.severity)
|
|
83
|
+
},
|
|
84
|
+
fullDescription: {
|
|
85
|
+
text: r.ruleDefinition.description || ""
|
|
86
|
+
},
|
|
87
|
+
id: r.ruleName,
|
|
88
|
+
shortDescription: {
|
|
89
|
+
text: r.ruleDefinition.description || r.ruleName
|
|
90
|
+
}
|
|
91
|
+
})),
|
|
92
|
+
version: "1.0.0"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
return JSON.stringify({
|
|
98
|
+
$schema: "https://json.schemastore.org/sarif-2.1.0.json",
|
|
99
|
+
runs,
|
|
100
|
+
version: "2.1.0"
|
|
101
|
+
}, null, 2);
|
|
102
|
+
}
|
|
103
|
+
function getUri(flow) {
|
|
104
|
+
return flow.fsPath ? flow.fsPath.replace(/\\/g, "/") : `flows/${flow.name}.flow-meta.xml`;
|
|
105
|
+
}
|
|
106
|
+
function mapRegion(detail, rawXml = "") {
|
|
107
|
+
if (!rawXml) return {
|
|
108
|
+
startLine: 1,
|
|
109
|
+
startColumn: 1
|
|
110
|
+
};
|
|
111
|
+
const lines = rawXml.split("\n");
|
|
112
|
+
const name = detail.name;
|
|
113
|
+
for(let i = 0; i < lines.length; i++){
|
|
114
|
+
if (lines[i].includes(`<name>${name}</name>`)) {
|
|
115
|
+
return {
|
|
116
|
+
startLine: i + 1,
|
|
117
|
+
startColumn: lines[i].indexOf(name) + 1
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
startLine: 1,
|
|
123
|
+
startColumn: 1
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function mapSeverity(sev) {
|
|
127
|
+
switch(sev === null || sev === void 0 ? void 0 : sev.toLowerCase()){
|
|
128
|
+
case "info":
|
|
129
|
+
case "note":
|
|
130
|
+
return "note";
|
|
131
|
+
case "warning":
|
|
132
|
+
return "warning";
|
|
133
|
+
default:
|
|
134
|
+
return "error";
|
|
135
|
+
}
|
|
136
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flow-scanner/lightning-flow-scanner-core",
|
|
3
3
|
"description": "A lightweight, purpose-built engine for parsing and analyzing Salesforce Flow metadata in Node.js or browser environments. Scan, validate, and optimize Flow automations for security risks, best practices, governor limits, and performance bottlenecks.",
|
|
4
|
-
"version": "6.
|
|
4
|
+
"version": "6.1.1",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
7
7
|
"engines": {
|