@flow-scanner/lightning-flow-scanner-core 6.10.5 → 6.11.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 (38) hide show
  1. package/README.md +19 -16
  2. package/index.d.ts +5 -2
  3. package/index.js +19 -0
  4. package/main/config/NodeIcons.d.ts +24 -0
  5. package/main/config/NodeIcons.js +122 -0
  6. package/main/config/VariableIcons.d.ts +25 -0
  7. package/main/config/VariableIcons.js +53 -0
  8. package/main/libs/Compiler.d.ts +1 -2
  9. package/main/libs/Compiler.js +10 -16
  10. package/main/libs/ExportDiagram.d.ts +41 -0
  11. package/main/libs/ExportDiagram.js +40 -0
  12. package/main/libs/ExportSarif.js +1 -1
  13. package/main/models/Flow.d.ts +42 -11
  14. package/main/models/Flow.js +164 -76
  15. package/main/models/FlowGraph.d.ts +85 -0
  16. package/main/models/FlowGraph.js +532 -0
  17. package/main/models/FlowNode.d.ts +58 -2
  18. package/main/models/FlowNode.js +161 -3
  19. package/main/models/FlowVariable.d.ts +59 -1
  20. package/main/models/FlowVariable.js +118 -1
  21. package/main/models/LoopRuleCommon.js +11 -12
  22. package/main/models/ParsedFlow.d.ts +1 -1
  23. package/main/models/RuleCommon.d.ts +30 -7
  24. package/main/models/RuleCommon.js +49 -11
  25. package/main/rules/APIVersion.js +31 -1
  26. package/main/rules/DuplicateDMLOperation.d.ts +1 -2
  27. package/main/rules/DuplicateDMLOperation.js +35 -73
  28. package/main/rules/MissingFaultPath.d.ts +4 -0
  29. package/main/rules/MissingFaultPath.js +19 -15
  30. package/main/rules/MissingFilterRecordTrigger.js +4 -4
  31. package/main/rules/RecordIdAsString.js +3 -2
  32. package/main/rules/RecursiveAfterUpdate.js +7 -4
  33. package/main/rules/SameRecordFieldUpdates.js +5 -3
  34. package/main/rules/TriggerOrder.d.ts +0 -1
  35. package/main/rules/TriggerOrder.js +8 -19
  36. package/main/rules/UnconnectedElement.d.ts +0 -1
  37. package/main/rules/UnconnectedElement.js +2 -13
  38. package/package.json +2 -2
@@ -53,88 +53,50 @@ function _interop_require_wildcard(obj, nodeInterop) {
53
53
  }
54
54
  let DuplicateDMLOperation = class DuplicateDMLOperation extends _RuleCommon.RuleCommon {
55
55
  check(flow, _options, suppressions) {
56
- const flowElements = flow.elements.filter((node)=>node instanceof _internals.FlowNode);
57
- const processedElementIndexes = [];
58
- const unconnectedElementIndexes = [];
59
- const DuplicateDMLOperations = [];
60
- const startingNode = this.findStart(flow);
61
- if (startingNode === -1) {
62
- return [];
63
- }
64
- let dmlFlag = false;
65
- let indexesToProcess = [
66
- startingNode
56
+ const graph = flow.graph;
57
+ const start = flow.startReference;
58
+ if (!start) return [];
59
+ const violations = [];
60
+ const visited = new Set();
61
+ const stack = [
62
+ {
63
+ name: start,
64
+ seenDML: false
65
+ }
67
66
  ];
68
- do {
69
- indexesToProcess = indexesToProcess.filter((index)=>!processedElementIndexes.includes(index));
70
- if (indexesToProcess.length > 0) {
71
- for (const [index, element] of flowElements.entries()){
72
- if (indexesToProcess.includes(index)) {
73
- const references = [];
74
- if (element.connectors && element.connectors.length > 0) {
75
- for (const connector of element.connectors){
76
- if (connector.reference) {
77
- references.push(connector.reference);
78
- }
79
- }
80
- }
81
- dmlFlag = this.flagDML(element, dmlFlag);
82
- if (references.length > 0) {
83
- const elementsByReferences = flowElements.filter((el)=>references.includes(el.name));
84
- for (const nextElement of elementsByReferences){
85
- const nextIndex = flowElements.findIndex((el)=>nextElement.name === el.name);
86
- if (nextElement.subtype === "screens") {
87
- if (dmlFlag && nextElement.element["allowBack"] === "true" && nextElement.element["showFooter"] === "true") {
88
- if (!suppressions.has(nextElement.name)) {
89
- DuplicateDMLOperations.push(nextElement);
90
- }
91
- }
92
- }
93
- if (!processedElementIndexes.includes(nextIndex)) {
94
- indexesToProcess.push(nextIndex);
95
- }
96
- }
97
- }
98
- processedElementIndexes.push(index);
99
- }
100
- }
101
- } else {
102
- for (const index of flowElements.keys()){
103
- if (!processedElementIndexes.includes(index)) {
104
- unconnectedElementIndexes.push(index);
105
- }
106
- }
67
+ while(stack.length > 0){
68
+ const { name, seenDML } = stack.pop();
69
+ const stateKey = `${name}:${seenDML}`;
70
+ if (visited.has(stateKey)) continue;
71
+ visited.add(stateKey);
72
+ const node = graph.getNode(name);
73
+ if (!node) continue;
74
+ let nextSeenDML = seenDML || this.isDML(node);
75
+ if (nextSeenDML && node.subtype === "screens" && node.element["allowBack"] === "true" && node.element["showFooter"] === "true" && !suppressions.has(node.name)) {
76
+ violations.push(new _internals.Violation(node));
77
+ // Note: do NOT return early; multiple violations possible
78
+ }
79
+ // Reset DML flag after screen with back disabled
80
+ if (nextSeenDML && node.subtype === "screens" && node.element["allowBack"] !== "true") {
81
+ nextSeenDML = false;
82
+ }
83
+ for (const next of graph.getNextElements(name)){
84
+ stack.push({
85
+ name: next,
86
+ seenDML: nextSeenDML
87
+ });
107
88
  }
108
- }while (processedElementIndexes.length + unconnectedElementIndexes.length < flowElements.length)
109
- return DuplicateDMLOperations.map((det)=>new _internals.Violation(det));
110
- }
111
- findStart(flow) {
112
- const flowElements = flow.elements.filter((node)=>node instanceof _internals.FlowNode);
113
- if (flow.startElementReference) {
114
- return flowElements.findIndex((n)=>n.name === flow.startElementReference);
115
- } else {
116
- return flowElements.findIndex((n)=>n.subtype === "start");
117
89
  }
90
+ return violations;
118
91
  }
119
- flagDML(element, dmlFlag) {
120
- const dmlStatementTypes = [
121
- "recordDeletes",
122
- "recordUpdates",
123
- "recordCreates"
124
- ];
125
- if (dmlStatementTypes.includes(element.subtype)) {
126
- return true;
127
- } else if (dmlFlag === true && element.subtype === "screens" && element.element["allowBack"] === "true") {
128
- return false;
129
- } else {
130
- return dmlFlag;
131
- }
92
+ isDML(node) {
93
+ return node.subtype === "recordCreates" || node.subtype === "recordUpdates" || node.subtype === "recordDeletes";
132
94
  }
133
95
  constructor(){
134
96
  super({
135
97
  name: "DuplicateDMLOperation",
136
98
  label: "Duplicate DML Operation",
137
- description: "When the flow executes database changes or actions between two screens, it's important to prevent users from navigating back between screens. Failure to do so may result in duplicate database operations being performed within the flow.",
99
+ description: "When the flow executes database changes between screens, users must not be allowed to navigate back, or duplicate DML operations may occur.",
138
100
  supportedTypes: _internals.FlowType.visualTypes,
139
101
  docRefs: []
140
102
  });
@@ -6,5 +6,9 @@ export declare class MissingFaultPath extends RuleCommon implements IRuleDefinit
6
6
  constructor();
7
7
  private isValidSubtype;
8
8
  protected check(flow: core.Flow, _options: object | undefined, suppressions: Set<string>): core.Violation[];
9
+ /**
10
+ * Determine if this is a RecordBeforeSave flow.
11
+ */
12
+ private isRecordBeforeSaveFlow;
9
13
  private isPartOfFaultHandlingFlow;
10
14
  }
@@ -82,14 +82,14 @@ let MissingFaultPath = class MissingFaultPath extends _RuleCommon.RuleCommon {
82
82
  return true;
83
83
  }
84
84
  check(flow, _options, suppressions) {
85
- var _flow_elements;
86
- const compiler = new _internals.Compiler();
85
+ var _flow_graph;
87
86
  const results = [];
88
- const elementsWhereFaultPathIsApplicable = ((_flow_elements = flow.elements) === null || _flow_elements === void 0 ? void 0 : _flow_elements.filter((node)=>{
87
+ const elementsWhereFaultPathIsApplicable = flow.elements.filter((node)=>{
89
88
  const proxyNode = node;
90
89
  return this.isValidSubtype(proxyNode);
91
- })).map((e)=>e.name);
92
- const isRecordBeforeSave = flow.start.triggerType === "RecordBeforeSave";
90
+ }).map((e)=>e.name);
91
+ // Check if this is a RecordBeforeSave flow
92
+ const isRecordBeforeSave = this.isRecordBeforeSaveFlow(flow);
93
93
  const visitCallback = (element)=>{
94
94
  var _element_connectors;
95
95
  if (!(element === null || element === void 0 ? void 0 : (_element_connectors = element.connectors) === null || _element_connectors === void 0 ? void 0 : _element_connectors.find((connector)=>connector.type === "faultConnector")) && elementsWhereFaultPathIsApplicable.includes(element.name)) {
@@ -104,22 +104,26 @@ let MissingFaultPath = class MissingFaultPath extends _RuleCommon.RuleCommon {
104
104
  }
105
105
  }
106
106
  };
107
- compiler.traverseFlow(flow, flow.startReference, visitCallback);
107
+ (_flow_graph = flow.graph) === null || _flow_graph === void 0 ? void 0 : _flow_graph.forEachReachable(visitCallback);
108
108
  return results;
109
109
  }
110
- isPartOfFaultHandlingFlow(element, flow) {
111
- var _flow_elements;
112
- const flowelements = (_flow_elements = flow.elements) === null || _flow_elements === void 0 ? void 0 : _flow_elements.filter((el)=>el instanceof _internals.FlowNode);
113
- for (const otherElement of flowelements){
114
- if (otherElement !== element) {
115
- var _otherElement_connectors;
116
- if ((_otherElement_connectors = otherElement.connectors) === null || _otherElement_connectors === void 0 ? void 0 : _otherElement_connectors.find((connector)=>connector.type === "faultConnector" && connector.reference === element.name)) {
117
- return true;
118
- }
110
+ /**
111
+ * Determine if this is a RecordBeforeSave flow.
112
+ */ isRecordBeforeSaveFlow(flow) {
113
+ var _flow_startNode;
114
+ if ((_flow_startNode = flow.startNode) === null || _flow_startNode === void 0 ? void 0 : _flow_startNode.element) {
115
+ var _flow_startNode_element;
116
+ const triggerType = (_flow_startNode_element = flow.startNode.element) === null || _flow_startNode_element === void 0 ? void 0 : _flow_startNode_element["triggerType"];
117
+ if (triggerType === "RecordBeforeSave") {
118
+ return true;
119
119
  }
120
120
  }
121
121
  return false;
122
122
  }
123
+ isPartOfFaultHandlingFlow(element, flow) {
124
+ var _flow_graph;
125
+ return ((_flow_graph = flow.graph) === null || _flow_graph === void 0 ? void 0 : _flow_graph.isPartOfFaultHandling(element.name)) || false;
126
+ }
123
127
  constructor(){
124
128
  super({
125
129
  description: "At times, a flow may fail to execute a configured operation as intended. By default, the flow displays an error message to the user and notifies the admin who created the flow via email. However, you can customize this behavior by incorporating a Fault Path. This rule checks DML operations, actions (Send Email, Quick Actions), and Invocable Apex Actions for proper error handling.",
@@ -53,10 +53,10 @@ function _interop_require_wildcard(obj, nodeInterop) {
53
53
  }
54
54
  let MissingFilterRecordTrigger = class MissingFilterRecordTrigger extends _RuleCommon.RuleCommon {
55
55
  check(flow, _options, _suppressions) {
56
- var _flow_xmldata_start, _flow_xmldata, _flow_xmldata_start1, _flow_xmldata1, _flow_xmldata_start2, _flow_xmldata2;
56
+ var _flow_xmldata_start, _flow_xmldata;
57
57
  const violations = [];
58
58
  // Check if this is a record-triggered flow
59
- const triggerType = (_flow_xmldata = flow.xmldata) === null || _flow_xmldata === void 0 ? void 0 : (_flow_xmldata_start = _flow_xmldata.start) === null || _flow_xmldata_start === void 0 ? void 0 : _flow_xmldata_start.triggerType;
59
+ const triggerType = this.getStartProperty(flow, 'triggerType');
60
60
  // Only check flows with record trigger types
61
61
  if (!triggerType || ![
62
62
  "RecordAfterSave",
@@ -65,9 +65,9 @@ let MissingFilterRecordTrigger = class MissingFilterRecordTrigger extends _RuleC
65
65
  return violations;
66
66
  }
67
67
  // Check if the flow has filters or entry conditions at the flow level
68
- const filters = (_flow_xmldata1 = flow.xmldata) === null || _flow_xmldata1 === void 0 ? void 0 : (_flow_xmldata_start1 = _flow_xmldata1.start) === null || _flow_xmldata_start1 === void 0 ? void 0 : _flow_xmldata_start1.filters;
68
+ const filters = this.getStartProperty(flow, 'filters');
69
69
  const hasFilters = !!filters;
70
- const scheduledPaths = (_flow_xmldata2 = flow.xmldata) === null || _flow_xmldata2 === void 0 ? void 0 : (_flow_xmldata_start2 = _flow_xmldata2.start) === null || _flow_xmldata_start2 === void 0 ? void 0 : _flow_xmldata_start2.scheduledPaths;
70
+ const scheduledPaths = (_flow_xmldata = flow.xmldata) === null || _flow_xmldata === void 0 ? void 0 : (_flow_xmldata_start = _flow_xmldata.start) === null || _flow_xmldata_start === void 0 ? void 0 : _flow_xmldata_start.scheduledPaths;
71
71
  const hasScheduledPaths = !!scheduledPaths;
72
72
  // If no filters or scheduled paths (which have their own conditions), flag as violation
73
73
  if (!hasFilters && !hasScheduledPaths) {
@@ -53,10 +53,11 @@ function _interop_require_wildcard(obj, nodeInterop) {
53
53
  }
54
54
  let RecordIdAsString = class RecordIdAsString extends _RuleCommon.RuleCommon {
55
55
  check(flow, _options, _suppressions) {
56
- var _flow_start, _flow_start1, _flow_elements;
56
+ var _flow_elements;
57
57
  const violations = [];
58
58
  // Skip record-triggered flows - they don't support this pattern
59
- const isRecordTriggered = ((_flow_start = flow.start) === null || _flow_start === void 0 ? void 0 : _flow_start.triggerType) === "RecordAfterSave" || ((_flow_start1 = flow.start) === null || _flow_start1 === void 0 ? void 0 : _flow_start1.triggerType) === "RecordBeforeSave";
59
+ const triggerType = this.getStartProperty(flow, 'triggerType');
60
+ const isRecordTriggered = triggerType === "RecordAfterSave" || triggerType === "RecordBeforeDelete" || triggerType === "RecordBeforeSave";
60
61
  if (isRecordTriggered) {
61
62
  return violations;
62
63
  }
@@ -66,10 +66,12 @@ function _interop_require_wildcard(obj, nodeInterop) {
66
66
  }
67
67
  let RecursiveAfterUpdate = class RecursiveAfterUpdate extends _RuleCommon.RuleCommon {
68
68
  check(flow, _options, suppressions) {
69
- var _flow_start, _flow_start1, _flow_elements, _flow_elements_filter, _flow_elements1;
69
+ var _flow_elements, _flow_elements_filter, _flow_elements1;
70
70
  const results = [];
71
- const isAfterSave = ((_flow_start = flow.start) === null || _flow_start === void 0 ? void 0 : _flow_start.triggerType) === "RecordAfterSave";
72
- const isQualifiedTriggerTypes = this.qualifiedRecordTriggerTypes.has((_flow_start1 = flow.start) === null || _flow_start1 === void 0 ? void 0 : _flow_start1.recordTriggerType);
71
+ const triggerType = this.getStartProperty(flow, 'triggerType');
72
+ const recordTriggerType = this.getStartProperty(flow, 'recordTriggerType');
73
+ const isAfterSave = triggerType === "RecordAfterSave";
74
+ const isQualifiedTriggerTypes = this.qualifiedRecordTriggerTypes.has(recordTriggerType);
73
75
  if (!isAfterSave || !isQualifiedTriggerTypes) {
74
76
  return results;
75
77
  }
@@ -86,7 +88,8 @@ let RecursiveAfterUpdate = class RecursiveAfterUpdate extends _RuleCommon.RuleCo
86
88
  }
87
89
  }
88
90
  // === Lookup → same object type updates ===
89
- const lookupElementsWithTheSameObjectType = (_flow_elements1 = flow.elements) === null || _flow_elements1 === void 0 ? void 0 : (_flow_elements_filter = _flow_elements1.filter((node)=>node.subtype === "recordLookups" && typeof node.element === "object" && "object" in node.element && flow.start.object === node.element["object"])) === null || _flow_elements_filter === void 0 ? void 0 : _flow_elements_filter.map((node)=>node.name);
91
+ const flowObject = this.getStartProperty(flow, 'object');
92
+ const lookupElementsWithTheSameObjectType = (_flow_elements1 = flow.elements) === null || _flow_elements1 === void 0 ? void 0 : (_flow_elements_filter = _flow_elements1.filter((node)=>node.subtype === "recordLookups" && typeof node.element === "object" && "object" in node.element && flowObject === node.element["object"])) === null || _flow_elements_filter === void 0 ? void 0 : _flow_elements_filter.map((node)=>node.name);
90
93
  if (lookupElementsWithTheSameObjectType == null || typeof lookupElementsWithTheSameObjectType[Symbol.iterator] !== "function") {
91
94
  return results;
92
95
  }
@@ -66,10 +66,12 @@ function _interop_require_wildcard(obj, nodeInterop) {
66
66
  }
67
67
  let SameRecordFieldUpdates = class SameRecordFieldUpdates extends _RuleCommon.RuleCommon {
68
68
  check(flow, _options, _suppressions) {
69
- var _flow_start, _flow_start1, _flow_elements;
69
+ var _flow_elements;
70
70
  const results = [];
71
- const isBeforeSaveType = ((_flow_start = flow.start) === null || _flow_start === void 0 ? void 0 : _flow_start.triggerType) === "RecordBeforeSave";
72
- const isQualifiedTriggerTypes = this.qualifiedRecordTriggerTypes.has((_flow_start1 = flow.start) === null || _flow_start1 === void 0 ? void 0 : _flow_start1.recordTriggerType);
71
+ const triggerType = this.getStartProperty(flow, 'triggerType');
72
+ const recordTriggerType = this.getStartProperty(flow, 'recordTriggerType');
73
+ const isBeforeSaveType = triggerType === "RecordBeforeSave";
74
+ const isQualifiedTriggerTypes = this.qualifiedRecordTriggerTypes.has(recordTriggerType);
73
75
  if (!isBeforeSaveType || !isQualifiedTriggerTypes) {
74
76
  return results;
75
77
  }
@@ -2,7 +2,6 @@ import * as core from "../internals/internals";
2
2
  import { RuleCommon } from "../models/RuleCommon";
3
3
  import { IRuleDefinition } from "../interfaces/IRuleDefinition";
4
4
  export declare class TriggerOrder extends RuleCommon implements IRuleDefinition {
5
- protected qualifiedRecordTriggerTypes: Set<string>;
6
5
  constructor();
7
6
  protected check(flow: core.Flow, _options: object | undefined, _suppressions: Set<string>): core.Violation[];
8
7
  }
@@ -10,19 +10,6 @@ Object.defineProperty(exports, "TriggerOrder", {
10
10
  });
11
11
  const _internals = /*#__PURE__*/ _interop_require_wildcard(require("../internals/internals"));
12
12
  const _RuleCommon = require("../models/RuleCommon");
13
- function _define_property(obj, key, value) {
14
- if (key in obj) {
15
- Object.defineProperty(obj, key, {
16
- value: value,
17
- enumerable: true,
18
- configurable: true,
19
- writable: true
20
- });
21
- } else {
22
- obj[key] = value;
23
- }
24
- return obj;
25
- }
26
13
  function _getRequireWildcardCache(nodeInterop) {
27
14
  if (typeof WeakMap !== "function") return null;
28
15
  var cacheBabelInterop = new WeakMap();
@@ -66,7 +53,12 @@ function _interop_require_wildcard(obj, nodeInterop) {
66
53
  }
67
54
  let TriggerOrder = class TriggerOrder extends _RuleCommon.RuleCommon {
68
55
  check(flow, _options, _suppressions) {
69
- if (!("object" in flow.start)) return [];
56
+ const startObject = this.getStartProperty(flow, "object");
57
+ // If there's no `object` on the start node, this is NOT a record-triggered flow
58
+ if (!startObject) {
59
+ return [];
60
+ }
61
+ // This *is* a record-triggered flow → should have triggerOrder
70
62
  if (!flow.triggerOrder) {
71
63
  return [
72
64
  new _internals.Violation(new _internals.FlowAttribute("TriggerOrder", "TriggerOrder", "10, 20, 30 ..."))
@@ -78,7 +70,7 @@ let TriggerOrder = class TriggerOrder extends _RuleCommon.RuleCommon {
78
70
  super({
79
71
  name: "TriggerOrder",
80
72
  label: "Trigger Order",
81
- description: "With flow trigger ordering, introduced in Spring '22, admins can now assign a priority value to their flows and guarantee their execution order. This priority value is not an absolute value, so the values need not be sequentially numbered as 1, 2, 3, and so on.",
73
+ description: "With flow trigger ordering, introduced in Spring '22, admins can now assign a priority " + "value to their flows and guarantee their execution order. This priority value is not an " + "absolute value, so the values need not be sequentially numbered as 1, 2, 3, and so on.",
82
74
  supportedTypes: [
83
75
  _internals.FlowType.autolaunchedType
84
76
  ],
@@ -90,9 +82,6 @@ let TriggerOrder = class TriggerOrder extends _RuleCommon.RuleCommon {
90
82
  ]
91
83
  }, {
92
84
  severity: "note"
93
- }), _define_property(this, "qualifiedRecordTriggerTypes", new Set([
94
- "Create",
95
- "Update"
96
- ]));
85
+ });
97
86
  }
98
87
  };
@@ -4,5 +4,4 @@ import { IRuleDefinition } from "../interfaces/IRuleDefinition";
4
4
  export declare class UnconnectedElement extends RuleCommon implements IRuleDefinition {
5
5
  constructor();
6
6
  protected check(flow: core.Flow, _options: object | undefined, suppressions: Set<string>): core.Violation[];
7
- private findStart;
8
7
  }
@@ -53,23 +53,12 @@ function _interop_require_wildcard(obj, nodeInterop) {
53
53
  }
54
54
  let UnconnectedElement = class UnconnectedElement extends _RuleCommon.RuleCommon {
55
55
  check(flow, _options, suppressions) {
56
- const connectedElements = new Set();
57
- const logConnected = (element)=>{
58
- connectedElements.add(element.name);
59
- };
56
+ var _flow_graph;
57
+ const connectedElements = ((_flow_graph = flow.graph) === null || _flow_graph === void 0 ? void 0 : _flow_graph.getReachableElements()) || new Set();
60
58
  const flowElements = flow.elements.filter((node)=>node instanceof _internals.FlowNode);
61
- const startIndex = this.findStart(flowElements);
62
- if (startIndex !== -1) {
63
- new _internals.Compiler().traverseFlow(flow, flowElements[startIndex].name, logConnected);
64
- }
65
59
  const unconnectedElements = flowElements.filter((element)=>!connectedElements.has(element.name) && !suppressions.has(element.name));
66
60
  return unconnectedElements.map((det)=>new _internals.Violation(det));
67
61
  }
68
- findStart(nodes) {
69
- return nodes.findIndex((n)=>{
70
- return n.subtype === "start";
71
- });
72
- }
73
62
  constructor(){
74
63
  super({
75
64
  description: "To maintain the efficiency and manageability of your Flow, it's best to avoid including unconnected elements that are not in use.",
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.10.5",
4
+ "version": "6.11.0",
5
5
  "main": "index.js",
6
6
  "exports": {
7
7
  ".": {
@@ -22,7 +22,7 @@
22
22
  "dependencies": {
23
23
  "fast-xml-parser": "^5.3.0"
24
24
  },
25
- "homepage": "https://dev.lightningflowscanner.org",
25
+ "homepage": "https://flow-scanner.github.io/lightning-flow-scanner/",
26
26
  "author": {
27
27
  "name": "Ruben Halman",
28
28
  "url": "https://github.com/RubenHalman"