@flow-scanner/lightning-flow-scanner-core 6.4.2 → 6.4.3

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.
Files changed (48) hide show
  1. package/README.md +49 -14
  2. package/index.d.ts +2 -2
  3. package/index.js +4 -4
  4. package/main/interfaces/IRulesConfig.d.ts +6 -0
  5. package/main/interfaces/IRulesConfig.js +11 -0
  6. package/main/internals/internals.d.ts +5 -5
  7. package/main/internals/internals.js +7 -7
  8. package/main/libs/GetRuleDefinitions.d.ts +1 -1
  9. package/main/libs/GetRuleDefinitions.js +5 -6
  10. package/main/libs/ScanFlows.js +29 -3
  11. package/main/libs/exportAsDetails.d.ts +3 -10
  12. package/main/libs/exportAsDetails.js +69 -26
  13. package/main/libs/exportAsSarif.js +19 -18
  14. package/main/models/Flow.d.ts +18 -10
  15. package/main/models/Flow.js +82 -61
  16. package/main/models/LoopRuleCommon.js +1 -1
  17. package/main/models/RuleCommon.js +0 -1
  18. package/main/models/RuleResult.d.ts +3 -3
  19. package/main/models/ScanResult.d.ts +1 -1
  20. package/main/models/Violation.d.ts +12 -0
  21. package/main/models/Violation.js +101 -0
  22. package/main/rules/APIVersion.js +2 -2
  23. package/main/rules/ActionCallsInLoop.js +1 -1
  24. package/main/rules/AutoLayout.js +1 -1
  25. package/main/rules/CopyAPIName.js +1 -1
  26. package/main/rules/CyclomaticComplexity.js +1 -1
  27. package/main/rules/DuplicateDMLOperation.js +1 -1
  28. package/main/rules/FlowDescription.js +1 -1
  29. package/main/rules/FlowName.js +1 -1
  30. package/main/rules/GetRecordAllFields.js +1 -1
  31. package/main/rules/HardcodedId.js +1 -1
  32. package/main/rules/HardcodedUrl.js +1 -1
  33. package/main/rules/InactiveFlow.js +1 -1
  34. package/main/rules/MissingFaultPath.js +1 -1
  35. package/main/rules/MissingNullHandler.js +1 -1
  36. package/main/rules/ProcessBuilder.js +1 -1
  37. package/main/rules/RecursiveAfterUpdate.js +2 -2
  38. package/main/rules/SameRecordFieldUpdates.js +1 -1
  39. package/main/rules/TriggerOrder.js +1 -1
  40. package/main/rules/UnconnectedElement.js +1 -1
  41. package/main/rules/UnsafeRunningContext.js +1 -1
  42. package/main/rules/UnusedVariable.js +1 -1
  43. package/main/store/DefaultRuleStore.js +2 -3
  44. package/package.json +6 -7
  45. package/main/interfaces/AutoFixable.d.ts +0 -10
  46. package/main/interfaces/AutoFixable.js +0 -4
  47. package/main/models/ResultDetails.d.ts +0 -10
  48. package/main/models/ResultDetails.js +0 -57
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,7 @@
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></i></p>
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>
31
32
 
32
33
  ### Action Calls In Loop(Beta)
33
34
 
@@ -125,7 +126,7 @@ _[UnusedVariable](https://github.com/Flow-Scanner/lightning-flow-scanner-core/tr
125
126
 
126
127
  ## Configuration
127
128
 
128
- It is recommended to set up configuration and define:
129
+ Lightning Flow Scanner is plug-and-play by default, but we recommend configuring and defining:
129
130
 
130
131
  - The rules to be executed.
131
132
  - The severity of violating any specific rule.
@@ -201,8 +202,10 @@ Specifying exceptions allows you to exclude specific scenarios from rule enforce
201
202
  "exceptions": {
202
203
  "<FlowName>": {
203
204
  "<RuleName>": [
204
- "<ResultName>", // Suppress specific result
205
- "*", // Suppress ALL results of this rule
205
+ // Suppress a specific result:
206
+ "<ResultName>",
207
+ // Suppress ALL results of rule:
208
+ "*",
206
209
  ...
207
210
  ]
208
211
  },
@@ -224,6 +227,22 @@ _Example_
224
227
  }
225
228
  ```
226
229
 
230
+ ### Report Detail Level
231
+
232
+ 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.
233
+
234
+ ```json
235
+ {
236
+ "rules": {
237
+ ...
238
+ },
239
+ "exceptions": {
240
+ ...
241
+ },
242
+ "detailLevel": "simple"
243
+ }
244
+ ```
245
+
227
246
  ### Include Beta Rules
228
247
 
229
248
  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 +255,16 @@ New rules are introduced in Beta mode before being added to the default ruleset.
236
255
  "exceptions": {
237
256
  ...
238
257
  },
239
- "betamode": true
258
+ "betaMode": true
240
259
  }
260
+
241
261
  ```
242
262
 
243
263
  ---
244
264
 
245
265
  ## Usage
246
266
 
247
- `lightning-flow-scanner-core` can be used as a dependency in Node.js and browser environments, or as a standalone UMD module.
267
+ Use `lightning-flow-scanner-core` as a Node.js/browser dependency or standalone UMD module.
248
268
 
249
269
  ### Examples
250
270
 
@@ -282,7 +302,7 @@ _Retrieves rule definitions used in the scanner._
282
302
 
283
303
  #### [`parse(selectedUris: any): Promise<ParsedFlow[]>`](https://github.com/Flow-Scanner/lightning-flow-scanner-core/tree/main/src/main/libs/ParseFlows.ts)
284
304
 
285
- _Loads Flow XML files into in-memory models._
305
+ _Loads Flow XML files into in-memory models.(Node.js only)_
286
306
 
287
307
  #### [`scan(parsedFlows: ParsedFlow[], ruleOptions?: IRulesConfig): ScanResult[]`](https://github.com/Flow-Scanner/lightning-flow-scanner-core/tree/main/src/main/libs/ScanFlows.ts)
288
308
 
@@ -348,14 +368,21 @@ npm install @flow-scanner/lightning-flow-scanner-core
348
368
  npm run test
349
369
  ```
350
370
 
351
- 5. Test as local dependency(Optional):
352
- a. run:
371
+ 5. Testing the module locally(Optional):
372
+
373
+ To link the module, run:
353
374
 
354
375
  ```bash
355
376
  npm run link
356
377
  ```
357
378
 
358
- b. Go to the dependent project (e.g. VSX or CLI) and use:
379
+ a. Ad-Hoc Testing with node:
380
+
381
+ ```bash
382
+ npm run link
383
+ ```
384
+
385
+ b. Test in a dependent project (e.g. VSX or CLI):
359
386
 
360
387
  ```bash
361
388
  npm link @flow-scanner/lightning-flow-scanner-core
@@ -363,10 +390,18 @@ npm install @flow-scanner/lightning-flow-scanner-core
363
390
 
364
391
  Your local module will now replace any installed version and update on rebuild.
365
392
 
366
- 6. Create a standalone UMD Module(Optional):
393
+ 6. Deploy Demo Flows (Optional):
367
394
 
368
- ```bash
369
- npm run vite:dist // creates UMD at`dist/lightning-flow-scanner-core.umd.js`.
370
- ```
395
+ ```bash
396
+ cd assets/example-flows && sf project deploy start &&
397
+ ```
398
+
399
+ Navigate to the [Demo Readme](assets\example-flows\README.md) for full details
400
+
401
+ 7. Create a standalone UMD Module(Optional):
402
+
403
+ ```bash
404
+ npm run vite:dist // creates UMD at`dist/lightning-flow-scanner-core.umd.js`.
405
+ ```
371
406
 
372
407
  <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
@@ -15,8 +15,8 @@ import { FlowResource } from "./main/models/FlowResource";
15
15
  import { FlowType } from "./main/models/FlowType";
16
16
  import { FlowVariable } from "./main/models/FlowVariable";
17
17
  import { ParsedFlow } from "./main/models/ParsedFlow";
18
- import { ResultDetails } from "./main/models/ResultDetails";
19
18
  import { RuleResult } from "./main/models/RuleResult";
20
19
  import { ScanResult } from "./main/models/ScanResult";
21
- export { Compiler, exportDetails, exportSarif, fix, Flow, FlowAttribute, FlowElement, FlowNode, FlowResource, FlowType, FlowVariable, getBetaRules, getRules, parse, ParsedFlow, ResultDetails, RuleResult, scan, ScanResult, };
20
+ import { Violation } from "./main/models/Violation";
21
+ export { Compiler, exportDetails, exportSarif, fix, Flow, FlowAttribute, FlowElement, FlowNode, FlowResource, FlowType, FlowVariable, getBetaRules, getRules, parse, ParsedFlow, Violation, RuleResult, scan, ScanResult, };
22
22
  export type { 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
+ }({});
@@ -4,14 +4,14 @@ import { Compiler } from "../libs/Compiler";
4
4
  import { Flow } from "../models/Flow";
5
5
  import { FlowAttribute } from "../models/FlowAttribute";
6
6
  import { FlowElement } from "../models/FlowElement";
7
- import { FlowType } from "../models/FlowType";
8
7
  import { FlowNode } from "../models/FlowNode";
9
8
  import { FlowResource } from "../models/FlowResource";
9
+ import { FlowType } from "../models/FlowType";
10
10
  import { FlowVariable } from "../models/FlowVariable";
11
- import { ResultDetails } from "../models/ResultDetails";
11
+ import { ParsedFlow } from "../models/ParsedFlow";
12
+ import { RuleCommon } from "../models/RuleCommon";
12
13
  import { RuleResult } from "../models/RuleResult";
13
14
  import { ScanResult } from "../models/ScanResult";
14
- import { RuleCommon } from "../models/RuleCommon";
15
- import { ParsedFlow } from "../models/ParsedFlow";
16
- export { FlowAttribute, FlowElement, FlowNode, FlowType, FlowVariable, FlowResource, Flow, Compiler, ScanResult, RuleResult, ResultDetails, RuleCommon, ParsedFlow, };
15
+ import { Violation } from "../models/Violation";
16
+ export { FlowAttribute, FlowElement, FlowNode, FlowType, FlowVariable, FlowResource, Flow, Compiler, ScanResult, RuleResult, Violation, RuleCommon, ParsedFlow, };
17
17
  export type { IRuleDefinition, IRulesConfig };
@@ -36,9 +36,6 @@ _export(exports, {
36
36
  get ParsedFlow () {
37
37
  return _ParsedFlow.ParsedFlow;
38
38
  },
39
- get ResultDetails () {
40
- return _ResultDetails.ResultDetails;
41
- },
42
39
  get RuleCommon () {
43
40
  return _RuleCommon.RuleCommon;
44
41
  },
@@ -47,18 +44,21 @@ _export(exports, {
47
44
  },
48
45
  get ScanResult () {
49
46
  return _ScanResult.ScanResult;
47
+ },
48
+ get Violation () {
49
+ return _Violation.Violation;
50
50
  }
51
51
  });
52
52
  const _Compiler = require("../libs/Compiler");
53
53
  const _Flow = require("../models/Flow");
54
54
  const _FlowAttribute = require("../models/FlowAttribute");
55
55
  const _FlowElement = require("../models/FlowElement");
56
- const _FlowType = require("../models/FlowType");
57
56
  const _FlowNode = require("../models/FlowNode");
58
57
  const _FlowResource = require("../models/FlowResource");
58
+ const _FlowType = require("../models/FlowType");
59
59
  const _FlowVariable = require("../models/FlowVariable");
60
- const _ResultDetails = require("../models/ResultDetails");
60
+ const _ParsedFlow = require("../models/ParsedFlow");
61
+ const _RuleCommon = require("../models/RuleCommon");
61
62
  const _RuleResult = require("../models/RuleResult");
62
63
  const _ScanResult = require("../models/ScanResult");
63
- const _RuleCommon = require("../models/RuleCommon");
64
- const _ParsedFlow = require("../models/ParsedFlow");
64
+ 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
- // Append all beta rules if opted in (skip if already included via config/default)
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
  }
@@ -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; // generalSuppressions removed — suppression now inline
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
- for (const flow of flows){
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,9 @@
1
1
  import { ScanResult } from "../models/ScanResult";
2
- export interface FlatViolation {
3
- connectsTo?: string;
4
- dataType?: string;
5
- expression?: string;
2
+ import { Violation } from "../models/Violation";
3
+ export interface FlatViolation extends Omit<Violation, 'details'> {
6
4
  flowFile: string;
7
5
  flowName: string;
8
- locationX?: string;
9
- locationY?: string;
10
- metaType: string;
11
- name: string;
12
6
  ruleName: string;
13
7
  severity: string;
14
- type: string;
15
8
  }
16
- export declare function exportDetails(results: ScanResult[]): FlatViolation[];
9
+ export declare function exportDetails(results: ScanResult[], includeDetails?: boolean): FlatViolation[];
@@ -1,4 +1,4 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */ "use strict";
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 exportDetails(results) {
12
- const violations = [];
13
- for (const result of results){
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
- for (const rule of result.ruleResults){
68
+ return result.ruleResults.filter((rule)=>{
18
69
  var _rule_details;
19
- if (!rule.occurs || !((_rule_details = rule.details) === null || _rule_details === void 0 ? void 0 : _rule_details.length)) continue;
20
- const ruleName = rule.ruleDefinition.label || rule.ruleName;
21
- var _rule_severity;
22
- const severity = (_rule_severity = rule.severity) !== null && _rule_severity !== void 0 ? _rule_severity : "error";
23
- for (const detail of rule.details){
24
- const d = detail.details || {};
25
- violations.push({
26
- connectsTo: Array.isArray(d.connectsTo) ? d.connectsTo.join("; ") : d.connectsTo,
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
- locationX: d.locationX,
32
- locationY: d.locationY,
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, result.flow.toXMLString() || "")
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
- return flow.fsPath ? flow.fsPath.replace(/\\/g, "/") : `flows/${flow.name}.flow-meta.xml`;
104
- }
105
- function mapRegion(detail, rawXml = "") {
106
- if (!rawXml) return {
107
- startLine: 1,
108
- startColumn: 1
109
- };
110
- const lines = rawXml.split("\n");
111
- const name = detail.name;
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
- startLine: 1,
122
- startColumn: 1
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) {
@@ -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: any;
17
+ fsPath?: string;
18
+ uri?: string;
8
19
  interviewLabel?: string;
9
20
  label: string;
10
21
  name?: string;
11
22
  processMetadataValues?: any;
12
- processType?: any;
23
+ processType?: string;
13
24
  root?: any;
14
25
  start?: any;
15
- startElementReference?: any;
16
- startReference: any;
17
- status?: any;
26
+ startElementReference?: string;
27
+ startReference?: string;
28
+ status?: string;
18
29
  triggerOrder?: number;
19
- type?: any;
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;