@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.
Files changed (71) hide show
  1. package/README.md +51 -14
  2. package/index.d.ts +4 -3
  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 +6 -5
  7. package/main/internals/internals.js +11 -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 +2 -15
  12. package/main/libs/exportAsDetails.js +69 -26
  13. package/main/libs/exportAsSarif.js +19 -18
  14. package/main/models/FlatViolation.d.ts +7 -0
  15. package/main/models/Flow.d.ts +18 -10
  16. package/main/models/Flow.js +82 -61
  17. package/main/models/LoopRuleCommon.d.ts +2 -2
  18. package/main/models/LoopRuleCommon.js +8 -10
  19. package/main/models/RuleCommon.d.ts +14 -2
  20. package/main/models/RuleCommon.js +16 -3
  21. package/main/models/RuleResult.d.ts +3 -3
  22. package/main/models/ScanResult.d.ts +1 -1
  23. package/main/models/Violation.d.ts +12 -0
  24. package/main/models/Violation.js +101 -0
  25. package/main/rules/APIVersion.d.ts +3 -3
  26. package/main/rules/APIVersion.js +20 -24
  27. package/main/rules/ActionCallsInLoop.js +1 -1
  28. package/main/rules/AutoLayout.d.ts +1 -3
  29. package/main/rules/AutoLayout.js +10 -20
  30. package/main/rules/CopyAPIName.d.ts +1 -1
  31. package/main/rules/CopyAPIName.js +4 -13
  32. package/main/rules/CyclomaticComplexity.d.ts +4 -4
  33. package/main/rules/CyclomaticComplexity.js +19 -27
  34. package/main/rules/DuplicateDMLOperation.d.ts +2 -2
  35. package/main/rules/DuplicateDMLOperation.js +53 -56
  36. package/main/rules/FlowDescription.d.ts +1 -1
  37. package/main/rules/FlowDescription.js +8 -12
  38. package/main/rules/FlowName.d.ts +2 -2
  39. package/main/rules/FlowName.js +12 -18
  40. package/main/rules/GetRecordAllFields.d.ts +1 -1
  41. package/main/rules/GetRecordAllFields.js +11 -21
  42. package/main/rules/HardcodedId.d.ts +1 -1
  43. package/main/rules/HardcodedId.js +4 -15
  44. package/main/rules/HardcodedUrl.d.ts +2 -2
  45. package/main/rules/HardcodedUrl.js +4 -17
  46. package/main/rules/InactiveFlow.d.ts +1 -1
  47. package/main/rules/InactiveFlow.js +7 -10
  48. package/main/rules/MissingFaultPath.d.ts +1 -1
  49. package/main/rules/MissingFaultPath.js +22 -24
  50. package/main/rules/MissingNullHandler.d.ts +1 -1
  51. package/main/rules/MissingNullHandler.js +67 -70
  52. package/main/rules/ProcessBuilder.d.ts +1 -3
  53. package/main/rules/ProcessBuilder.js +4 -8
  54. package/main/rules/RecursiveAfterUpdate.d.ts +1 -1
  55. package/main/rules/RecursiveAfterUpdate.js +29 -31
  56. package/main/rules/SameRecordFieldUpdates.d.ts +1 -1
  57. package/main/rules/SameRecordFieldUpdates.js +15 -21
  58. package/main/rules/TriggerOrder.d.ts +1 -1
  59. package/main/rules/TriggerOrder.js +8 -13
  60. package/main/rules/UnconnectedElement.d.ts +1 -1
  61. package/main/rules/UnconnectedElement.js +12 -15
  62. package/main/rules/UnsafeRunningContext.d.ts +1 -1
  63. package/main/rules/UnsafeRunningContext.js +12 -13
  64. package/main/rules/UnusedVariable.d.ts +1 -1
  65. package/main/rules/UnusedVariable.js +23 -27
  66. package/main/store/DefaultRuleStore.js +2 -3
  67. package/package.json +6 -7
  68. package/main/interfaces/AutoFixable.d.ts +0 -10
  69. package/main/models/ResultDetails.d.ts +0 -10
  70. package/main/models/ResultDetails.js +0 -57
  71. /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></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>
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
- It is recommended to set up configuration and define:
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
- "<ResultName>", // Suppress specific result
205
- "*", // Suppress ALL results of this rule
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
- "betamode": true
260
+ "betaMode": true
240
261
  }
262
+
241
263
  ```
242
264
 
243
265
  ---
244
266
 
245
267
  ## Usage
246
268
 
247
- `lightning-flow-scanner-core` can be used as a dependency in Node.js and browser environments, or as a standalone UMD module.
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. Test as local dependency(Optional):
352
- a. run:
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. Go to the dependent project (e.g. VSX or CLI) and use:
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. Create a standalone UMD Module(Optional):
395
+ 6. Deploy Demo Flows (Optional):
367
396
 
368
- ```bash
369
- npm run vite:dist // creates UMD at`dist/lightning-flow-scanner-core.umd.js`.
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
- export { Compiler, exportDetails, exportSarif, fix, Flow, FlowAttribute, FlowElement, FlowNode, FlowResource, FlowType, FlowVariable, getBetaRules, getRules, parse, ParsedFlow, ResultDetails, RuleResult, scan, ScanResult, };
22
- export type { IRuleDefinition, IRulesConfig };
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 { ResultDetails } from "../models/ResultDetails";
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 { 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, };
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 _ResultDetails = require("../models/ResultDetails");
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 _RuleCommon = require("../models/RuleCommon");
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
- // 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,3 @@
1
+ import { FlatViolation } from "../models/FlatViolation";
1
2
  import { ScanResult } from "../models/ScanResult";
2
- export interface FlatViolation {
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
- /* 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) {
@@ -0,0 +1,7 @@
1
+ import { Violation } from "./Violation";
2
+ export interface FlatViolation extends Omit<Violation, 'details'> {
3
+ flowFile: string;
4
+ flowName: string;
5
+ ruleName: string;
6
+ severity: string;
7
+ }
@@ -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;