@flow-scanner/lightning-flow-scanner-core 6.5.0 → 6.6.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
@@ -30,9 +30,9 @@
30
30
  <p>📌<strong>Tip:</strong> To link directly to a specific rule, use the full GitHub anchor link format. Example:</p>
31
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
32
 
33
- > Want to code a new rule? → See [How to Write a Rule](docs/write-a-new-rule.md)
33
+ > Want to code a new rule? → See [How to Write a Rule](docs/write-a-rule.md)
34
34
 
35
- ### Action Calls In Loop(Beta)
35
+ ### Action Calls In Loop
36
36
 
37
37
  _[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.
38
38
 
@@ -88,6 +88,10 @@ _[MissingFaultPath](https://github.com/Flow-Scanner/lightning-flow-scanner-core/
88
88
 
89
89
  _[FlowDescription](https://github.com/Flow-Scanner/lightning-flow-scanner-core/tree/main/src/main/rules/FlowDescription.ts)_ - Descriptions play a vital role in documentation. We highly recommend including details about where flows are used and their intended purpose.
90
90
 
91
+ ### MissingMetadataDescription
92
+
93
+ _[MissingMetadataDescription](https://github.com/Flow-Scanner/lightning-flow-scanner-core/tree/main/src/main/rules/MissingMetadataDescription.ts)_ – Flags Flow elements (Get Records, Assignments, Decisions, Actions, etc.) and metadata components (Variables, Formulas, Constants, Text Templates) that lack a description. Adding concise descriptions greatly improves readability, maintainability, and helps AI tools understand your automation intent.
94
+
91
95
  ### Missing Null Handler
92
96
 
93
97
  _[MissingNullHandler](https://github.com/Flow-Scanner/lightning-flow-scanner-core/tree/main/src/main/rules/MissingNullHandler.ts)_ - When a **Get Records** operation finds no data, it returns `null`. Validate data by using a Decision element to check for a non‑null result.
package/index.d.ts CHANGED
@@ -5,7 +5,7 @@ import { Compiler } from "./main/libs/Compiler";
5
5
  import { exportDetails } from "./main/libs/exportAsDetails";
6
6
  import { exportSarif } from "./main/libs/exportAsSarif";
7
7
  import { fix } from "./main/libs/FixFlows";
8
- import { getBetaRules, getRules } from "./main/libs/GetRuleDefinitions";
8
+ import { getRules } from "./main/libs/GetRuleDefinitions";
9
9
  import { parse } from "./main/libs/ParseFlows";
10
10
  import { scan } from "./main/libs/ScanFlows";
11
11
  import { Flow } from "./main/models/Flow";
@@ -19,5 +19,5 @@ import { ParsedFlow } from "./main/models/ParsedFlow";
19
19
  import { RuleResult } from "./main/models/RuleResult";
20
20
  import { ScanResult } from "./main/models/ScanResult";
21
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, };
22
+ export { Compiler, exportDetails, exportSarif, fix, Flow, FlowAttribute, FlowElement, FlowNode, FlowResource, FlowType, FlowVariable, getRules, parse, ParsedFlow, Violation, RuleResult, scan, ScanResult, };
23
23
  export type { FlatViolation, IRuleDefinition, IRulesConfig };
package/index.js CHANGED
@@ -54,9 +54,6 @@ _export(exports, {
54
54
  get fix () {
55
55
  return _FixFlows.fix;
56
56
  },
57
- get getBetaRules () {
58
- return _GetRuleDefinitions.getBetaRules;
59
- },
60
57
  get getRules () {
61
58
  return _GetRuleDefinitions.getRules;
62
59
  },
@@ -1,4 +1,4 @@
1
1
  import { IRuleDefinition } from "../interfaces/IRuleDefinition";
2
2
  export declare class DynamicRule<T extends IRuleDefinition> {
3
- constructor(className: string);
3
+ constructor(className: string, betaMode?: boolean);
4
4
  }
@@ -10,8 +10,8 @@ Object.defineProperty(exports, "DynamicRule", {
10
10
  });
11
11
  const _DefaultRuleStore = require("../store/DefaultRuleStore");
12
12
  let DynamicRule = class DynamicRule {
13
- constructor(className){
14
- if (!_DefaultRuleStore.DefaultRuleStore.hasOwnProperty(className) && _DefaultRuleStore.BetaRuleStore.hasOwnProperty(className)) {
13
+ constructor(className, betaMode = false){
14
+ if (betaMode && _DefaultRuleStore.BetaRuleStore.hasOwnProperty(className)) {
15
15
  return new _DefaultRuleStore.BetaRuleStore[className]();
16
16
  }
17
17
  return new _DefaultRuleStore.DefaultRuleStore[className]();
@@ -1,5 +1,4 @@
1
1
  import { IRuleDefinition } from "../interfaces/IRuleDefinition";
2
2
  import { IRulesConfig } from "../interfaces/IRulesConfig";
3
- export declare function getBetaRules(): IRuleDefinition[];
4
3
  export declare function GetRuleDefinitions(ruleConfig?: Map<string, unknown>, options?: IRulesConfig): IRuleDefinition[];
5
4
  export declare function getRules(ruleNames?: string[], options?: IRulesConfig): IRuleDefinition[];
@@ -12,18 +12,12 @@ _export(exports, {
12
12
  get GetRuleDefinitions () {
13
13
  return GetRuleDefinitions;
14
14
  },
15
- get getBetaRules () {
16
- return getBetaRules;
17
- },
18
15
  get getRules () {
19
16
  return getRules;
20
17
  }
21
18
  });
22
19
  const _DefaultRuleStore = require("../store/DefaultRuleStore");
23
20
  const _DynamicRule = require("./DynamicRule");
24
- function getBetaRules() {
25
- return getBetaDefinition();
26
- }
27
21
  function GetRuleDefinitions(ruleConfig, options) {
28
22
  const selectedRules = [];
29
23
  const includeBeta = (options === null || options === void 0 ? void 0 : options.betaMode) === true || (options === null || options === void 0 ? void 0 : options.betamode) === true;
@@ -36,10 +30,9 @@ function GetRuleDefinitions(ruleConfig, options) {
36
30
  if (configuredSeverity && (configuredSeverity === "error" || configuredSeverity === "warning" || configuredSeverity === "note")) {
37
31
  severity = configuredSeverity;
38
32
  }
39
- const matchedRule = new _DynamicRule.DynamicRule(ruleName);
40
- if (configuredSeverity) {
41
- matchedRule.severity = severity;
42
- }
33
+ // Pass betaMode to DynamicRule
34
+ const matchedRule = new _DynamicRule.DynamicRule(ruleName, includeBeta);
35
+ if (configuredSeverity) matchedRule.severity = severity;
43
36
  selectedRules.push(matchedRule);
44
37
  } catch (error) {
45
38
  console.log(error.message);
@@ -48,14 +41,15 @@ function GetRuleDefinitions(ruleConfig, options) {
48
41
  } else {
49
42
  // Load all defaults
50
43
  for(const rule in _DefaultRuleStore.DefaultRuleStore){
51
- const matchedRule = new _DynamicRule.DynamicRule(rule);
44
+ const matchedRule = new _DynamicRule.DynamicRule(rule, includeBeta);
52
45
  selectedRules.push(matchedRule);
53
46
  }
54
47
  }
55
- if (includeBeta && _DefaultRuleStore.BetaRuleStore && typeof _DefaultRuleStore.BetaRuleStore === 'object' && !Array.isArray(_DefaultRuleStore.BetaRuleStore)) {
48
+ // Optionally add beta-only rules that are not in defaults
49
+ if (includeBeta) {
56
50
  for(const betaRuleName in _DefaultRuleStore.BetaRuleStore){
57
51
  if (!selectedRules.some((r)=>r.name === betaRuleName)) {
58
- const betaRule = new _DynamicRule.DynamicRule(betaRuleName);
52
+ const betaRule = new _DynamicRule.DynamicRule(betaRuleName, true);
59
53
  selectedRules.push(betaRule);
60
54
  }
61
55
  }
@@ -71,10 +65,6 @@ function getRules(ruleNames, options) {
71
65
  }
72
66
  ]));
73
67
  return GetRuleDefinitions(ruleSeverityMap, options);
74
- } else {
75
- return GetRuleDefinitions(undefined, options);
76
68
  }
77
- }
78
- function getBetaDefinition() {
79
- return Object.values(_DefaultRuleStore.BetaRuleStore).map((rule)=>new rule());
69
+ return GetRuleDefinitions(undefined, options);
80
70
  }
@@ -40,9 +40,9 @@ function ScanFlows(flows, ruleOptions) {
40
40
  for (const [ruleName, config] of Object.entries(ruleOptions.rules)){
41
41
  ruleMap.set(ruleName, config);
42
42
  }
43
- selectedRules = (0, _GetRuleDefinitions.GetRuleDefinitions)(ruleMap);
43
+ selectedRules = (0, _GetRuleDefinitions.GetRuleDefinitions)(ruleMap, ruleOptions);
44
44
  } else {
45
- selectedRules = (0, _GetRuleDefinitions.GetRuleDefinitions)();
45
+ selectedRules = (0, _GetRuleDefinitions.GetRuleDefinitions)(undefined, ruleOptions);
46
46
  }
47
47
  const flowXmlCache = new Map();
48
48
  for (const flowInput of flows){
@@ -0,0 +1,7 @@
1
+ import { IRuleDefinition } from "../interfaces/IRuleDefinition";
2
+ import * as core from "../internals/internals";
3
+ import { RuleCommon } from "../models/RuleCommon";
4
+ export declare class MissingMetadataDescription extends RuleCommon implements IRuleDefinition {
5
+ constructor();
6
+ protected check(flow: core.Flow, _options: object | undefined, _suppression: Set<string>): core.Violation[];
7
+ }
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "MissingMetadataDescription", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return MissingMetadataDescription;
9
+ }
10
+ });
11
+ const _internals = /*#__PURE__*/ _interop_require_wildcard(require("../internals/internals"));
12
+ const _RuleCommon = require("../models/RuleCommon");
13
+ function _getRequireWildcardCache(nodeInterop) {
14
+ if (typeof WeakMap !== "function") return null;
15
+ var cacheBabelInterop = new WeakMap();
16
+ var cacheNodeInterop = new WeakMap();
17
+ return (_getRequireWildcardCache = function(nodeInterop) {
18
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
19
+ })(nodeInterop);
20
+ }
21
+ function _interop_require_wildcard(obj, nodeInterop) {
22
+ if (!nodeInterop && obj && obj.__esModule) {
23
+ return obj;
24
+ }
25
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
26
+ return {
27
+ default: obj
28
+ };
29
+ }
30
+ var cache = _getRequireWildcardCache(nodeInterop);
31
+ if (cache && cache.has(obj)) {
32
+ return cache.get(obj);
33
+ }
34
+ var newObj = {
35
+ __proto__: null
36
+ };
37
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
38
+ for(var key in obj){
39
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
40
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
41
+ if (desc && (desc.get || desc.set)) {
42
+ Object.defineProperty(newObj, key, desc);
43
+ } else {
44
+ newObj[key] = obj[key];
45
+ }
46
+ }
47
+ }
48
+ newObj.default = obj;
49
+ if (cache) {
50
+ cache.set(obj, newObj);
51
+ }
52
+ return newObj;
53
+ }
54
+ let MissingMetadataDescription = class MissingMetadataDescription extends _RuleCommon.RuleCommon {
55
+ check(flow, _options, _suppression) {
56
+ const violations = [];
57
+ flow.elements.filter((elem)=>{
58
+ if (elem.metaType !== "metadata" && !elem.element["description"] && elem.subtype !== "start") {
59
+ return elem;
60
+ }
61
+ }).forEach((elem)=>{
62
+ return violations.push(new _internals.Violation(elem));
63
+ });
64
+ return violations;
65
+ }
66
+ constructor(){
67
+ super({
68
+ autoFixable: false,
69
+ description: "Every element must have a meaningful description",
70
+ docRefs: [],
71
+ isConfigurable: false,
72
+ label: "Missing Metadata Description",
73
+ name: "MissingMetadataDescription",
74
+ supportedTypes: _internals.FlowType.allTypes()
75
+ });
76
+ }
77
+ };
@@ -39,6 +39,7 @@ const _TriggerOrder = require("../rules/TriggerOrder");
39
39
  const _UnconnectedElement = require("../rules/UnconnectedElement");
40
40
  const _UnsafeRunningContext = require("../rules/UnsafeRunningContext");
41
41
  const _UnusedVariable = require("../rules/UnusedVariable");
42
+ const _MissingMetadataDescription = require("../rules/MissingMetadataDescription");
42
43
  const DefaultRuleStore = {
43
44
  ActionCallsInLoop: _ActionCallsInLoop.ActionCallsInLoop,
44
45
  APIVersion: _APIVersion.APIVersion,
@@ -64,4 +65,6 @@ const DefaultRuleStore = {
64
65
  UnsafeRunningContext: _UnsafeRunningContext.UnsafeRunningContext,
65
66
  UnusedVariable: _UnusedVariable.UnusedVariable
66
67
  };
67
- const BetaRuleStore = {};
68
+ const BetaRuleStore = {
69
+ MissingMetadataDescription: _MissingMetadataDescription.MissingMetadataDescription
70
+ };
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.5.0",
4
+ "version": "6.6.0",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
7
7
  "engines": {