@flow-scanner/lightning-flow-scanner-core 6.11.5 → 6.13.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 CHANGED
@@ -52,7 +52,7 @@
52
52
 
53
53
  > Want to code a new rule? → See [How to Write a Rule](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/docs/write-a-rule.md)
54
54
 
55
- ### Action Calls In Loop
55
+ ### Action Call In A Loop
56
56
  _[ActionCallsInLoop](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/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.
57
57
  **Rule ID:** `action-call-in-loop`
58
58
  **Severity:** 🔴 *Error*
@@ -193,9 +193,8 @@ _[UnusedVariable](https://github.com/Flow-Scanner/lightning-flow-scanner/blob/ma
193
193
 
194
194
  It is recommend to configure and define:
195
195
 
196
- - The rules to be executed.
197
196
  - The severity of violating any specific rule.
198
- - Rule properties such as REGEX expressions.
197
+ - Expressions used for rules, such as REGEX patterns and comparison operators.
199
198
  - Any known exceptions that should be ignored during scanning.
200
199
 
201
200
  ```json
@@ -216,7 +215,7 @@ By default, all default rules are executed. You can customize individual rules a
216
215
  ```json
217
216
  {
218
217
  "rules": {
219
- "<RuleName>": {
218
+ "<RuleId>": {
220
219
  "severity": "<Severity>", // Override severity level
221
220
  "expression": "<Expression>", // Override rule expression
222
221
  "enabled": "false" // Disable this rule
@@ -232,10 +231,10 @@ When the severity is not provided it will be `warning` by default. Other availab
232
231
  ```json
233
232
  {
234
233
  "rules": {
235
- "FlowDescription": {
234
+ "missing-flow-description": {
236
235
  "severity": "error"
237
236
  },
238
- "UnusedVariable": {
237
+ "unused-variable": {
239
238
  "severity": "note"
240
239
  }
241
240
  }
@@ -249,10 +248,10 @@ Some rules have an expression to configure, such as the expression, that will ov
249
248
  ```json
250
249
  {
251
250
  "rules": {
252
- "APIVersion": {
251
+ "invalid-api-version": {
253
252
  "expression": "===58" // comparison operator
254
253
  },
255
- "FlowName": {
254
+ "invalid-naming-convention": {
256
255
  "expression": "[A-Za-z0-9]" // regular expression
257
256
  }
258
257
  }
@@ -267,7 +266,7 @@ Defining exceptions allows you to exclude specific scenarios from rule enforceme
267
266
  {
268
267
  "exceptions": {
269
268
  "<FlowName>": {
270
- "<RuleName>": [
269
+ "<RuleId>": [
271
270
  "<ResultName>", // Suppress a result
272
271
  "*", // Wildcard to suppress all results
273
272
  ...
@@ -284,8 +283,8 @@ _Example_
284
283
  {
285
284
  "exceptions": {
286
285
  "MyFlow": {
287
- "HardcodedId": ["Old_Lookup_1"]
288
- "MissingNullHandler": ["*"],
286
+ "hardcoded-id": ["Old_Lookup_1"],
287
+ "missing-null-handler": ["*"]
289
288
  }
290
289
  }
291
290
  }
@@ -321,7 +320,7 @@ By default, Lightning Flow Scanner runs **all** default rules and merges any cus
321
320
  | **[Salesforce CLI Plugin](https://www.npmjs.com/package/lightning-flow-scanner)** | Local development, scratch orgs, CI/CD | `sf plugins install lightning-flow-scanner` |
322
321
  | **[VS Code Extension](https://open-vsx.org/extension/ForceConfigControl/lightning-flow-scanner-vsx)** | Real-time scanning inside VS Code | `code --install-extension ForceConfigControl.lightning-flow-scanner-vsx` |
323
322
  | **[Salesforce App (Managed Package)](https://github.com/Flow-Scanner/lightning-flow-scanner-app)** | Run scans directly inside a Salesforce org | `sf package install --package 04tgK0000008CLlQAM` |
324
- | **[GitHub Action](https://github.com/marketplace/actions/lightning-flow-scan)** | Native PR checks | `uses: Flow-Scanner/lightning-flow-scanner@action-v2.6.0` |
323
+ | **[GitHub Action](https://github.com/marketplace/actions/lightning-flow-scan)** | Native PR checks | `uses: Flow-Scanner/lightning-flow-scanner@main` |
325
324
  | **[Core Library](https://www.npmjs.com/package/@flow-scanner/lightning-flow-scanner-core)** (Node.js + Browser) | Custom tools, scripts, extensions, web apps | `npm install -g @flow-scanner/lightning-flow-scanner-core` |
326
325
 
327
326
  **Privacy:** Zero user data collected. All processing is client-side. → See our [Security Policy](https://github.com/Flow-Scanner/lightning-flow-scanner?tab=security-ov-file).
@@ -369,7 +368,7 @@ Add a GitHub workflow file `.github/workflows/scan-flows.yml` to detect issues d
369
368
  ```yaml
370
369
  - name: Lightning Flow Scan
371
370
  id: flowscanner
372
- uses: Flow-Scanner/lightning-flow-scanner@action-v2.6.0
371
+ uses: Flow-Scanner/lightning-flow-scanner@main
373
372
 
374
373
  - name: Upload SARIF to Code Scanning
375
374
  uses: github/codeql-action/upload-sarif@v3
@@ -8,13 +8,16 @@ Object.defineProperty(exports, "BuildFlow", {
8
8
  return BuildFlow;
9
9
  }
10
10
  });
11
- const _ConvertFlowNodes = require("./ConvertFlowNodes");
12
11
  function BuildFlow(nodesToMerge) {
13
12
  let res = {};
14
13
  for (const nodeToMerge of nodesToMerge){
15
14
  const subtype = nodeToMerge.subtype;
16
15
  const nodesOfType = nodesToMerge.filter((node)=>subtype === node.subtype);
17
- res = (0, _ConvertFlowNodes.convertFlowNodes)(res, nodesOfType, subtype);
16
+ res = convertFlowNodes(res, nodesOfType, subtype);
18
17
  }
19
18
  return res;
20
19
  }
20
+ function convertFlowNodes(obj, nodes, key) {
21
+ obj[key] = nodes.map((node)=>node.element);
22
+ return obj;
23
+ }
@@ -16,7 +16,7 @@ _export(exports, {
16
16
  return getRules;
17
17
  }
18
18
  });
19
- const _RuleRegistry = require("../store/RuleRegistry");
19
+ const _RuleRegistry = require("../config/RuleRegistry");
20
20
  function GetRuleDefinitions(ruleConfig, options) {
21
21
  const includeBeta = (options === null || options === void 0 ? void 0 : options.betaMode) === true || (options === null || options === void 0 ? void 0 : options.betamode) === true;
22
22
  const rulesMode = (options === null || options === void 0 ? void 0 : options.ruleMode) || "merged";
@@ -5,7 +5,7 @@ export declare class Flow {
5
5
  /**
6
6
  * Metadata Tags of Salesforce Flow Attributes
7
7
  */
8
- static readonly ATTRIBUTE_TAGS: readonly ["description", "apiVersion", "processMetadataValues", "processType", "interviewLabel", "label", "status", "runInMode", "startElementReference", "isTemplate", "fullName", "timeZoneSidKey", "isAdditionalPermissionRequiredToRun", "migratedFromWorkflowRuleName", "triggerOrder", "environments", "segment"];
8
+ static readonly ATTRIBUTE_TAGS: readonly ["apiVersion", "areMetricsLoggedToDataCloud", "description", "environments", "fullName", "interviewLabel", "isAdditionalPermissionRequiredToRun", "isTemplate", "label", "migratedFromWorkflowRuleName", "processMetadataValues", "processType", "runInMode", "segment", "startElementReference", "status", "timeZoneSidKey", "triggerOrder"];
9
9
  /**
10
10
  * Metadata Tags of Salesforce Flow Nodes
11
11
  */
@@ -331,23 +331,24 @@ let Flow = class Flow {
331
331
  /**
332
332
  * Metadata Tags of Salesforce Flow Attributes
333
333
  */ _define_property(Flow, "ATTRIBUTE_TAGS", [
334
- "description",
335
334
  "apiVersion",
336
- "processMetadataValues",
337
- "processType",
335
+ "areMetricsLoggedToDataCloud",
336
+ "description",
337
+ "environments",
338
+ "fullName",
338
339
  "interviewLabel",
340
+ "isAdditionalPermissionRequiredToRun",
341
+ "isTemplate",
339
342
  "label",
340
- "status",
343
+ "migratedFromWorkflowRuleName",
344
+ "processMetadataValues",
345
+ "processType",
341
346
  "runInMode",
347
+ "segment",
342
348
  "startElementReference",
343
- "isTemplate",
344
- "fullName",
349
+ "status",
345
350
  "timeZoneSidKey",
346
- "isAdditionalPermissionRequiredToRun",
347
- "migratedFromWorkflowRuleName",
348
- "triggerOrder",
349
- "environments",
350
- "segment"
351
+ "triggerOrder"
351
352
  ]);
352
353
  /**
353
354
  * Metadata Tags of Salesforce Flow Nodes
@@ -57,14 +57,14 @@ let APIVersion = class APIVersion extends _RuleCommon.RuleCommon {
57
57
  if (flow.xmldata.apiVersion) {
58
58
  flowAPIVersionNumber = +flow.xmldata.apiVersion;
59
59
  }
60
- // No API version
61
- if (!flowAPIVersionNumber) {
62
- return [
63
- new _internals.Violation(new _internals.FlowAttribute("API Version <49", "apiVersion", "<49"))
64
- ];
65
- }
66
60
  // Custom logic
67
61
  if (options === null || options === void 0 ? void 0 : options.expression) {
62
+ // No API version with custom expression
63
+ if (!flowAPIVersionNumber) {
64
+ return [
65
+ new _internals.Violation(new _internals.FlowAttribute("apiVersion<50", "apiVersion", "<50"))
66
+ ];
67
+ }
68
68
  // Match something like: >= 58
69
69
  const match = options.expression.match(/^\s*(>=|<=|>|<|===|!==)\s*(\d+)\s*$/);
70
70
  if (!match) {
@@ -101,6 +101,13 @@ let APIVersion = class APIVersion extends _RuleCommon.RuleCommon {
101
101
  new _internals.Violation(new _internals.FlowAttribute(`${flowAPIVersionNumber}`, "apiVersion", options.expression))
102
102
  ];
103
103
  }
104
+ } else {
105
+ // Default: no API version OR version below 50
106
+ if (!flowAPIVersionNumber || flowAPIVersionNumber < 50) {
107
+ return [
108
+ new _internals.Violation(new _internals.FlowAttribute(flowAPIVersionNumber ? `${flowAPIVersionNumber}` : "apiVersion<50", "apiVersion", "<50"))
109
+ ];
110
+ }
104
111
  }
105
112
  return [];
106
113
  }
@@ -59,7 +59,9 @@ let GetRecordAllFields = class GetRecordAllFields extends _RuleCommon.RuleCommon
59
59
  const violations = lookupNodes.filter((node)=>{
60
60
  const el = node.element;
61
61
  const storeAllFields = typeof el === "object" && "storeOutputAutomatically" in el && el.storeOutputAutomatically;
62
- const hasQueriedFields = typeof el === "object" && Array.isArray(el.queriedFields) && el.queriedFields.length > 0;
62
+ // Handle both single field (string) and multiple fields (array)
63
+ const queriedFields = el.queriedFields;
64
+ const hasQueriedFields = queriedFields && (Array.isArray(queriedFields) && queriedFields.length > 0 || typeof queriedFields === "string");
63
65
  return storeAllFields && !hasQueriedFields;
64
66
  }).map((node)=>new _internals.Violation(node));
65
67
  return violations;
@@ -64,9 +64,12 @@ let MissingNullHandler = class MissingNullHandler extends _RuleCommon.RuleCommon
64
64
  if (suppressions.has(getElement.name)) continue;
65
65
  const elementName = getElement.name;
66
66
  const assignNulls = String(getElement.element["assignNullValuesIfNoRecordsFound"]).toLowerCase() === "true";
67
- if (!assignNulls) continue;
68
67
  const hasFaultConnector = !!getElement.element["faultConnector"] || ((_getElement_connectors = getElement.connectors) === null || _getElement_connectors === void 0 ? void 0 : _getElement_connectors.some((c)=>c.type === "faultConnector"));
69
- if (hasFaultConnector) continue;
68
+ // Only skip if NOT assigning nulls AND has fault connector
69
+ // (because fault will catch the "no records" error)
70
+ if (!assignNulls && hasFaultConnector) {
71
+ continue;
72
+ }
70
73
  const resultReferences = [];
71
74
  if (getElement.element["storeOutputAutomatically"]) {
72
75
  resultReferences.push(elementName);
@@ -84,6 +87,10 @@ let MissingNullHandler = class MissingNullHandler extends _RuleCommon.RuleCommon
84
87
  return resultReferences.some((ref)=>json.includes(`"${ref}"`) || json.includes(`"${ref}.`));
85
88
  });
86
89
  if (!resultIsUsed) continue;
90
+ // If assignNullValuesIfNoRecordsFound is TRUE, we need a null check decision
91
+ if (!assignNulls) {
92
+ continue;
93
+ }
87
94
  let nullCheckFound = false;
88
95
  for (const decision of decisionElements){
89
96
  let rules = decision.element["rules"];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@flow-scanner/lightning-flow-scanner-core",
3
3
  "description": "A lightweight engine for Flow metadata in Node.js, and browser environments. Assess and enhance Salesforce Flow automations for best practices, security, governor limits, and performance issues.",
4
- "version": "6.11.5",
4
+ "version": "6.13.0",
5
5
  "main": "index.js",
6
6
  "exports": {
7
7
  ".": {
@@ -1 +0,0 @@
1
- export declare function convertFlowNodes(obj: any, nodes: any, key: any): any;
@@ -1,14 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "convertFlowNodes", {
6
- enumerable: true,
7
- get: function() {
8
- return convertFlowNodes;
9
- }
10
- });
11
- function convertFlowNodes(obj, nodes, key) {
12
- obj[key] = nodes.map((node)=>node.element);
13
- return obj;
14
- }
File without changes
File without changes