@flow-scanner/lightning-flow-scanner-core 6.0.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.
- package/CONTRIBUTING.md +30 -0
- package/LICENSE.md +21 -0
- package/README.md +314 -0
- package/SECURITY.md +26 -0
- package/assets/media/bannerslim.png +0 -0
- package/index.d.ts +21 -0
- package/index.js +83 -0
- package/main/interfaces/AdvancedRuleConfig.d.ts +11 -0
- package/main/interfaces/AdvancedRuleConfig.js +4 -0
- package/main/interfaces/AdvancedRuleDefintion.d.ts +5 -0
- package/main/interfaces/AdvancedRuleDefintion.js +4 -0
- package/main/interfaces/AdvancedSuppression.d.ts +21 -0
- package/main/interfaces/AdvancedSuppression.js +4 -0
- package/main/interfaces/AutoFixable.d.ts +10 -0
- package/main/interfaces/AutoFixable.js +4 -0
- package/main/interfaces/IExceptions.d.ts +5 -0
- package/main/interfaces/IExceptions.js +4 -0
- package/main/interfaces/IRuleConfig.d.ts +3 -0
- package/main/interfaces/IRuleConfig.js +4 -0
- package/main/interfaces/IRuleDefinition.d.ts +17 -0
- package/main/interfaces/IRuleDefinition.js +4 -0
- package/main/interfaces/IRuleOptions.d.ts +4 -0
- package/main/interfaces/IRuleOptions.js +4 -0
- package/main/interfaces/IRulesConfig.d.ts +8 -0
- package/main/interfaces/IRulesConfig.js +4 -0
- package/main/internals/internals.d.ts +17 -0
- package/main/internals/internals.js +64 -0
- package/main/libs/BuildFlow.d.ts +1 -0
- package/main/libs/BuildFlow.js +20 -0
- package/main/libs/Compiler.d.ts +8 -0
- package/main/libs/Compiler.js +70 -0
- package/main/libs/ConvertFlowNodes.d.ts +1 -0
- package/main/libs/ConvertFlowNodes.js +14 -0
- package/main/libs/DynamicRule.d.ts +5 -0
- package/main/libs/DynamicRule.js +19 -0
- package/main/libs/FixFlows.d.ts +3 -0
- package/main/libs/FixFlows.js +110 -0
- package/main/libs/GetRuleDefinitions.d.ts +5 -0
- package/main/libs/GetRuleDefinitions.js +81 -0
- package/main/libs/ParseFlows.d.ts +2 -0
- package/main/libs/ParseFlows.js +111 -0
- package/main/libs/Scan2.d.ts +3 -0
- package/main/libs/Scan2.js +124 -0
- package/main/libs/ScanFlows.d.ts +4 -0
- package/main/libs/ScanFlows.js +103 -0
- package/main/models/AdvancedRule.d.ts +44 -0
- package/main/models/AdvancedRule.js +84 -0
- package/main/models/Flow.d.ts +33 -0
- package/main/models/Flow.js +277 -0
- package/main/models/FlowAttribute.d.ts +7 -0
- package/main/models/FlowAttribute.js +34 -0
- package/main/models/FlowElement.d.ts +10 -0
- package/main/models/FlowElement.js +37 -0
- package/main/models/FlowElementConnector.d.ts +15 -0
- package/main/models/FlowElementConnector.js +50 -0
- package/main/models/FlowMetadata.d.ts +4 -0
- package/main/models/FlowMetadata.js +16 -0
- package/main/models/FlowNode.d.ts +10 -0
- package/main/models/FlowNode.js +169 -0
- package/main/models/FlowResource.d.ts +5 -0
- package/main/models/FlowResource.js +30 -0
- package/main/models/FlowType.d.ts +23 -0
- package/main/models/FlowType.js +80 -0
- package/main/models/FlowVariable.d.ts +6 -0
- package/main/models/FlowVariable.js +31 -0
- package/main/models/LoopRuleCommon.d.ts +9 -0
- package/main/models/LoopRuleCommon.js +48 -0
- package/main/models/ParsedFlow.d.ts +7 -0
- package/main/models/ParsedFlow.js +35 -0
- package/main/models/ResultDetails.d.ts +10 -0
- package/main/models/ResultDetails.js +57 -0
- package/main/models/RuleCommon.d.ts +19 -0
- package/main/models/RuleCommon.js +48 -0
- package/main/models/RuleInfo.d.ts +55 -0
- package/main/models/RuleInfo.js +61 -0
- package/main/models/RuleResult.d.ts +11 -0
- package/main/models/RuleResult.js +44 -0
- package/main/models/ScanResult.d.ts +7 -0
- package/main/models/ScanResult.js +31 -0
- package/main/rules/APIVersion.d.ts +8 -0
- package/main/rules/APIVersion.js +86 -0
- package/main/rules/ActionCallsInLoop.d.ts +6 -0
- package/main/rules/ActionCallsInLoop.js +38 -0
- package/main/rules/AutoLayout.d.ts +8 -0
- package/main/rules/AutoLayout.js +78 -0
- package/main/rules/CopyAPIName.d.ts +6 -0
- package/main/rules/CopyAPIName.js +82 -0
- package/main/rules/CyclomaticComplexity.d.ts +10 -0
- package/main/rules/CyclomaticComplexity.js +111 -0
- package/main/rules/DMLStatementInLoop.d.ts +6 -0
- package/main/rules/DMLStatementInLoop.js +37 -0
- package/main/rules/DuplicateDMLOperation.d.ts +8 -0
- package/main/rules/DuplicateDMLOperation.js +153 -0
- package/main/rules/FlowDescription.d.ts +6 -0
- package/main/rules/FlowDescription.js +76 -0
- package/main/rules/FlowName.d.ts +7 -0
- package/main/rules/FlowName.js +80 -0
- package/main/rules/GetRecordAllFields.d.ts +6 -0
- package/main/rules/GetRecordAllFields.js +101 -0
- package/main/rules/HardcodedId.d.ts +6 -0
- package/main/rules/HardcodedId.js +87 -0
- package/main/rules/HardcodedUrl.d.ts +6 -0
- package/main/rules/HardcodedUrl.js +50 -0
- package/main/rules/InactiveFlow.d.ts +6 -0
- package/main/rules/InactiveFlow.js +73 -0
- package/main/rules/MissingFaultPath.d.ts +12 -0
- package/main/rules/MissingFaultPath.js +161 -0
- package/main/rules/MissingNullHandler.d.ts +6 -0
- package/main/rules/MissingNullHandler.js +152 -0
- package/main/rules/ProcessBuilder.d.ts +8 -0
- package/main/rules/ProcessBuilder.js +77 -0
- package/main/rules/RecursiveAfterUpdate.d.ts +7 -0
- package/main/rules/RecursiveAfterUpdate.js +124 -0
- package/main/rules/SOQLQueryInLoop.d.ts +6 -0
- package/main/rules/SOQLQueryInLoop.js +35 -0
- package/main/rules/SameRecordFieldUpdates.d.ts +7 -0
- package/main/rules/SameRecordFieldUpdates.js +111 -0
- package/main/rules/TriggerOrder.d.ts +7 -0
- package/main/rules/TriggerOrder.js +101 -0
- package/main/rules/UnconnectedElement.d.ts +7 -0
- package/main/rules/UnconnectedElement.js +93 -0
- package/main/rules/UnsafeRunningContext.d.ts +6 -0
- package/main/rules/UnsafeRunningContext.js +86 -0
- package/main/rules/UnusedVariable.d.ts +6 -0
- package/main/rules/UnusedVariable.js +100 -0
- package/main/store/DefaultRuleStore.d.ts +2 -0
- package/main/store/DefaultRuleStore.js +68 -0
- package/package.json +88 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "HardcodedId", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return HardcodedId;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _AdvancedRule = require("../models/AdvancedRule");
|
|
12
|
+
const _internals = /*#__PURE__*/ _interop_require_wildcard(require("../internals/internals"));
|
|
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 HardcodedId = class HardcodedId extends _AdvancedRule.AdvancedRule {
|
|
55
|
+
execute(flow) {
|
|
56
|
+
const nodesWithHardcodedIds = [];
|
|
57
|
+
const salesforceIdRegex = /\b[a-zA-Z0-9]{5}0[a-zA-Z0-9]{9}([a-zA-Z0-9]{3})?\b/g;
|
|
58
|
+
for (const node of flow.elements){
|
|
59
|
+
const nodeString = JSON.stringify(node);
|
|
60
|
+
if (salesforceIdRegex.test(nodeString)) {
|
|
61
|
+
nodesWithHardcodedIds.push(node);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const results = nodesWithHardcodedIds.map((node)=>new _internals.ResultDetails(node));
|
|
65
|
+
return new _internals.RuleResult(this, results);
|
|
66
|
+
}
|
|
67
|
+
constructor(){
|
|
68
|
+
super({
|
|
69
|
+
name: "HardcodedId",
|
|
70
|
+
label: "Hardcoded Id",
|
|
71
|
+
description: "Avoid hard-coding IDs as they are org-specific. Instead, pass them into variables at the start of the flow. You can achieve this by utilizing merge fields in URL parameters or employing a Get Records element.",
|
|
72
|
+
supportedTypes: _internals.FlowType.allTypes(),
|
|
73
|
+
docRefs: [
|
|
74
|
+
{
|
|
75
|
+
label: "Flow Best Practices",
|
|
76
|
+
path: "https://help.salesforce.com/s/articleView?id=sf.flow_prep_bestpractices.htm&type=5"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
label: "Don't hard code Record Type IDs in Flow. By Stephen Church.",
|
|
80
|
+
path: "https://www.linkedin.com/feed/update/urn:li:activity:6947530300012826624/?updateEntityUrn=urn%3Ali%3Afs_feedUpdate%3A%28V2%2Curn%3Ali%3Aactivity%3A6947530300012826624%29"
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
isConfigurable: false,
|
|
84
|
+
autoFixable: false
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Flow, IRuleDefinition, RuleResult } from "../internals/internals";
|
|
2
|
+
import { AdvancedRule } from "../models/AdvancedRule";
|
|
3
|
+
export declare class HardcodedUrl extends AdvancedRule implements IRuleDefinition {
|
|
4
|
+
constructor();
|
|
5
|
+
execute(flow: Flow): RuleResult;
|
|
6
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "HardcodedUrl", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return HardcodedUrl;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _internals = require("../internals/internals");
|
|
12
|
+
const _AdvancedRule = require("../models/AdvancedRule");
|
|
13
|
+
let HardcodedUrl = class HardcodedUrl extends _AdvancedRule.AdvancedRule {
|
|
14
|
+
execute(flow) {
|
|
15
|
+
const results = [];
|
|
16
|
+
if (!flow.elements || flow.elements.length === 0) {
|
|
17
|
+
return new _internals.RuleResult(this, results);
|
|
18
|
+
}
|
|
19
|
+
const urlRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}force\.com/g;
|
|
20
|
+
for (const element of flow.elements){
|
|
21
|
+
const nodeString = JSON.stringify(element);
|
|
22
|
+
if (urlRegex.test(nodeString)) {
|
|
23
|
+
results.push(new _internals.ResultDetails(element));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return new _internals.RuleResult(this, results);
|
|
27
|
+
}
|
|
28
|
+
constructor(){
|
|
29
|
+
super({
|
|
30
|
+
autoFixable: false,
|
|
31
|
+
description: "Avoid hard-coding URLs as they are org-specific. Instead, use a $API formula (preferred) or you can use an environment-specific such as custom labels, custom metadata, or custom settings.",
|
|
32
|
+
docRefs: [
|
|
33
|
+
{
|
|
34
|
+
label: "The Ultimate Guide to Salesforce Flow Best Practices",
|
|
35
|
+
path: "https://admin.salesforce.com/blog/2021/the-ultimate-guide-to-flow-best-practices-and-standards"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
label: "Why You Should Avoid Hard Coding and Three Alternative Solutions",
|
|
39
|
+
path: "https://admin.salesforce.com/blog/2021/why-you-should-avoid-hard-coding-and-three-alternative-solutions"
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
isConfigurable: false,
|
|
43
|
+
label: "Hardcoded Url",
|
|
44
|
+
name: "HardcodedUrl",
|
|
45
|
+
supportedTypes: _internals.FlowType.allTypes()
|
|
46
|
+
}, {
|
|
47
|
+
severity: "warning"
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "InactiveFlow", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return InactiveFlow;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _AdvancedRule = require("../models/AdvancedRule");
|
|
12
|
+
const _internals = /*#__PURE__*/ _interop_require_wildcard(require("../internals/internals"));
|
|
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 InactiveFlow = class InactiveFlow extends _AdvancedRule.AdvancedRule {
|
|
55
|
+
execute(flow) {
|
|
56
|
+
const results = [];
|
|
57
|
+
if (flow.status !== "Active") {
|
|
58
|
+
results.push(new _internals.ResultDetails(new _internals.FlowAttribute(flow.status, "status", "!= Active")));
|
|
59
|
+
}
|
|
60
|
+
return new _internals.RuleResult(this, results);
|
|
61
|
+
}
|
|
62
|
+
constructor(){
|
|
63
|
+
super({
|
|
64
|
+
name: "InactiveFlow",
|
|
65
|
+
label: "Inactive Flow",
|
|
66
|
+
description: "Like cleaning out your closet: deleting unused flows is essential. Inactive flows can still cause trouble, like accidentally deleting records during testing, or being activated as subflows within parent flows.",
|
|
67
|
+
supportedTypes: _internals.FlowType.allTypes(),
|
|
68
|
+
docRefs: [],
|
|
69
|
+
isConfigurable: false,
|
|
70
|
+
autoFixable: false
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AdvancedConfig } from "../interfaces/AdvancedRuleConfig";
|
|
2
|
+
import { AdvancedSuppression } from "../interfaces/AdvancedSuppression";
|
|
3
|
+
import * as core from "../internals/internals";
|
|
4
|
+
import { AdvancedRule } from "../models/AdvancedRule";
|
|
5
|
+
export declare class MissingFaultPath extends AdvancedRule implements AdvancedSuppression, core.IRuleDefinition {
|
|
6
|
+
protected applicableElements: string[];
|
|
7
|
+
constructor();
|
|
8
|
+
private isValidSubtype;
|
|
9
|
+
execute(flow: core.Flow): core.RuleResult;
|
|
10
|
+
suppress(scanResult: core.RuleResult, ruleConfiguration?: AdvancedConfig): core.RuleResult;
|
|
11
|
+
private isPartOfFaultHandlingFlow;
|
|
12
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "MissingFaultPath", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return MissingFaultPath;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _internals = /*#__PURE__*/ _interop_require_wildcard(require("../internals/internals"));
|
|
12
|
+
const _AdvancedRule = require("../models/AdvancedRule");
|
|
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
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
27
|
+
if (typeof WeakMap !== "function") return null;
|
|
28
|
+
var cacheBabelInterop = new WeakMap();
|
|
29
|
+
var cacheNodeInterop = new WeakMap();
|
|
30
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
31
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
32
|
+
})(nodeInterop);
|
|
33
|
+
}
|
|
34
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
35
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
36
|
+
return obj;
|
|
37
|
+
}
|
|
38
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
39
|
+
return {
|
|
40
|
+
default: obj
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
44
|
+
if (cache && cache.has(obj)) {
|
|
45
|
+
return cache.get(obj);
|
|
46
|
+
}
|
|
47
|
+
var newObj = {
|
|
48
|
+
__proto__: null
|
|
49
|
+
};
|
|
50
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
51
|
+
for(var key in obj){
|
|
52
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
53
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
54
|
+
if (desc && (desc.get || desc.set)) {
|
|
55
|
+
Object.defineProperty(newObj, key, desc);
|
|
56
|
+
} else {
|
|
57
|
+
newObj[key] = obj[key];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
newObj.default = obj;
|
|
62
|
+
if (cache) {
|
|
63
|
+
cache.set(obj, newObj);
|
|
64
|
+
}
|
|
65
|
+
return newObj;
|
|
66
|
+
}
|
|
67
|
+
let MissingFaultPath = class MissingFaultPath extends _AdvancedRule.AdvancedRule {
|
|
68
|
+
isValidSubtype(proxyNode) {
|
|
69
|
+
if (!this.applicableElements.includes(proxyNode.subtype)) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
if (proxyNode.subtype === "waits") {
|
|
73
|
+
var _proxyNode_element;
|
|
74
|
+
const elementSubtype = (_proxyNode_element = proxyNode.element) === null || _proxyNode_element === void 0 ? void 0 : _proxyNode_element["elementSubtype"];
|
|
75
|
+
const excludedSubtypes = [
|
|
76
|
+
"WaitDuration",
|
|
77
|
+
"WaitDate"
|
|
78
|
+
];
|
|
79
|
+
return !excludedSubtypes.includes(elementSubtype);
|
|
80
|
+
}
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
execute(flow) {
|
|
84
|
+
var _flow_elements;
|
|
85
|
+
const compiler = new _internals.Compiler();
|
|
86
|
+
const results = [];
|
|
87
|
+
const elementsWhereFaultPathIsApplicable = ((_flow_elements = flow.elements) === null || _flow_elements === void 0 ? void 0 : _flow_elements.filter((node)=>{
|
|
88
|
+
const proxyNode = node;
|
|
89
|
+
return this.isValidSubtype(proxyNode);
|
|
90
|
+
})).map((e)=>e.name);
|
|
91
|
+
const isRecordBeforeSave = flow.start.triggerType === "RecordBeforeSave";
|
|
92
|
+
const visitCallback = (element)=>{
|
|
93
|
+
var _element_connectors;
|
|
94
|
+
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)) {
|
|
95
|
+
if (isRecordBeforeSave && element.subtype === "recordUpdates") {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
// Check if the element is part of another fault path
|
|
99
|
+
if (!this.isPartOfFaultHandlingFlow(element, flow)) {
|
|
100
|
+
results.push(new _internals.ResultDetails(element));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
// Use the core.Compiler for traversal
|
|
105
|
+
compiler.traverseFlow(flow, flow.startReference, visitCallback);
|
|
106
|
+
return new _internals.RuleResult(this, results);
|
|
107
|
+
}
|
|
108
|
+
suppress(scanResult, ruleConfiguration) {
|
|
109
|
+
const suppressedResults = [];
|
|
110
|
+
const suppressionElementKey = this.suppressionElement;
|
|
111
|
+
for (const resultDetails of scanResult.details){
|
|
112
|
+
var _ruleConfiguration_suppressions;
|
|
113
|
+
if ("violation" in resultDetails && "element" in resultDetails.violation && typeof resultDetails.violation.element === "object" && !Array.isArray(resultDetails.violation.element) && suppressionElementKey in resultDetails.violation.element && (ruleConfiguration === null || ruleConfiguration === void 0 ? void 0 : (_ruleConfiguration_suppressions = ruleConfiguration.suppressions) === null || _ruleConfiguration_suppressions === void 0 ? void 0 : _ruleConfiguration_suppressions.includes(resultDetails.violation.element[suppressionElementKey]))) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
suppressedResults.push(resultDetails);
|
|
117
|
+
}
|
|
118
|
+
return new _internals.RuleResult(this, suppressedResults);
|
|
119
|
+
}
|
|
120
|
+
isPartOfFaultHandlingFlow(element, flow) {
|
|
121
|
+
var _flow_elements;
|
|
122
|
+
const flowelements = (_flow_elements = flow.elements) === null || _flow_elements === void 0 ? void 0 : _flow_elements.filter((el)=>el instanceof _internals.FlowNode);
|
|
123
|
+
for (const otherElement of flowelements){
|
|
124
|
+
if (otherElement !== element) {
|
|
125
|
+
var _otherElement_connectors;
|
|
126
|
+
// Check if the otherElement has a faultConnector pointing to element
|
|
127
|
+
if ((_otherElement_connectors = otherElement.connectors) === null || _otherElement_connectors === void 0 ? void 0 : _otherElement_connectors.find((connector)=>connector.type === "faultConnector" && connector.reference === element.name)) {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
constructor(){
|
|
135
|
+
super({
|
|
136
|
+
autoFixable: false,
|
|
137
|
+
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.",
|
|
138
|
+
docRefs: [
|
|
139
|
+
{
|
|
140
|
+
label: "Flow Best Practices",
|
|
141
|
+
path: "https://help.salesforce.com/s/articleView?id=sf.flow_prep_bestpractices.htm&type=5"
|
|
142
|
+
}
|
|
143
|
+
],
|
|
144
|
+
isConfigurable: false,
|
|
145
|
+
label: "Missing Fault Path",
|
|
146
|
+
name: "MissingFaultPath",
|
|
147
|
+
supportedTypes: [
|
|
148
|
+
..._internals.FlowType.backEndTypes,
|
|
149
|
+
..._internals.FlowType.visualTypes
|
|
150
|
+
],
|
|
151
|
+
suppressionElement: "actionName"
|
|
152
|
+
}), _define_property(this, "applicableElements", [
|
|
153
|
+
"recordLookups",
|
|
154
|
+
"recordDeletes",
|
|
155
|
+
"recordUpdates",
|
|
156
|
+
"recordCreates",
|
|
157
|
+
"waits",
|
|
158
|
+
"actionCalls"
|
|
159
|
+
]);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "MissingNullHandler", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return MissingNullHandler;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _internals = /*#__PURE__*/ _interop_require_wildcard(require("../internals/internals"));
|
|
12
|
+
const _AdvancedRule = require("../models/AdvancedRule");
|
|
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 MissingNullHandler = class MissingNullHandler extends _AdvancedRule.AdvancedRule {
|
|
55
|
+
execute(flow) {
|
|
56
|
+
const getOperations = [
|
|
57
|
+
"recordLookups"
|
|
58
|
+
];
|
|
59
|
+
const getOperationElements = flow.elements.filter((node)=>node.metaType === "node" && getOperations.includes(node.subtype));
|
|
60
|
+
const decisionElements = flow.elements.filter((node)=>node.metaType === "node" && node.subtype === "decisions");
|
|
61
|
+
const getOperationsWithoutNullHandler = [];
|
|
62
|
+
for (const getElement of getOperationElements){
|
|
63
|
+
const elementName = getElement.name;
|
|
64
|
+
let nullCheckFound = false;
|
|
65
|
+
let resultReferences = [];
|
|
66
|
+
if (getElement.element["storeOutputAutomatically"]) {
|
|
67
|
+
resultReferences = [
|
|
68
|
+
elementName
|
|
69
|
+
];
|
|
70
|
+
} else if (getElement.element["outputReference"]) {
|
|
71
|
+
resultReferences = getElement.element["outputReference"];
|
|
72
|
+
} else if (getElement.element["outputAssignments"]) {
|
|
73
|
+
const outputAssignments = getElement.element["outputAssignments"];
|
|
74
|
+
for (const assignment of outputAssignments){
|
|
75
|
+
resultReferences.push(assignment.assignToReference);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// ✅ Skip check if result is never used inside the flow
|
|
79
|
+
const resultIsUsed = flow.elements.some((el)=>{
|
|
80
|
+
if (el.name === getElement.name) return false;
|
|
81
|
+
const json = JSON.stringify(el.element);
|
|
82
|
+
return resultReferences.some((ref)=>json.includes(`"${ref}"`) || json.includes(`"${ref}.`));
|
|
83
|
+
});
|
|
84
|
+
if (!resultIsUsed) continue;
|
|
85
|
+
for (const el of decisionElements){
|
|
86
|
+
let rules = el.element["rules"];
|
|
87
|
+
const isRuleAnArray = Array.isArray(rules);
|
|
88
|
+
if (!isRuleAnArray) {
|
|
89
|
+
rules = [
|
|
90
|
+
rules
|
|
91
|
+
];
|
|
92
|
+
}
|
|
93
|
+
for (const rule of rules){
|
|
94
|
+
let conditions = rule.conditions;
|
|
95
|
+
const isConditionsAnArray = Array.isArray(conditions);
|
|
96
|
+
if (!isConditionsAnArray) {
|
|
97
|
+
conditions = [
|
|
98
|
+
conditions
|
|
99
|
+
];
|
|
100
|
+
}
|
|
101
|
+
for (const condition of conditions){
|
|
102
|
+
let referenceFound = false;
|
|
103
|
+
let isNullOperator = false;
|
|
104
|
+
let checksIfFalse = false;
|
|
105
|
+
if (condition.leftValueReference && condition.leftValueReference.length > 0) {
|
|
106
|
+
const valueReference = condition.leftValueReference;
|
|
107
|
+
for (const ref of resultReferences){
|
|
108
|
+
referenceFound = valueReference.startsWith(ref);
|
|
109
|
+
if (referenceFound) {
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (condition.operator && (!Array.isArray(condition.operator) || condition.operator.length > 0)) {
|
|
115
|
+
const operator = condition.operator;
|
|
116
|
+
isNullOperator = operator === "IsNull";
|
|
117
|
+
}
|
|
118
|
+
if (condition.rightValue && (!Array.isArray(condition.rightValue) || condition.rightValue.length > 0) && condition.rightValue.booleanValue && (!Array.isArray(condition.rightValue.booleanValue) || condition.rightValue.booleanValue.length > 0)) {
|
|
119
|
+
const rightValue = condition.rightValue.booleanValue;
|
|
120
|
+
checksIfFalse = rightValue.toLowerCase() === "false";
|
|
121
|
+
}
|
|
122
|
+
if (referenceFound && isNullOperator && checksIfFalse) {
|
|
123
|
+
nullCheckFound = true;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (!nullCheckFound) {
|
|
129
|
+
getOperationsWithoutNullHandler.push(getElement);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const results = [];
|
|
133
|
+
for (const det of getOperationsWithoutNullHandler){
|
|
134
|
+
results.push(new _internals.ResultDetails(det));
|
|
135
|
+
}
|
|
136
|
+
return new _internals.RuleResult(this, results);
|
|
137
|
+
}
|
|
138
|
+
constructor(){
|
|
139
|
+
super({
|
|
140
|
+
autoFixable: false,
|
|
141
|
+
description: "When a Get Records operation doesn't find any data, it returns null. To ensure data validation, utilize a decision element on the operation result variable to check for a non-null result.",
|
|
142
|
+
docRefs: [],
|
|
143
|
+
isConfigurable: false,
|
|
144
|
+
label: "Missing Null Handler",
|
|
145
|
+
name: "MissingNullHandler",
|
|
146
|
+
supportedTypes: [
|
|
147
|
+
..._internals.FlowType.backEndTypes,
|
|
148
|
+
..._internals.FlowType.visualTypes
|
|
149
|
+
]
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as core from "../internals/internals";
|
|
2
|
+
import { AdvancedRule } from "../models/AdvancedRule";
|
|
3
|
+
export declare class ProcessBuilder extends AdvancedRule implements core.IRuleDefinition {
|
|
4
|
+
constructor();
|
|
5
|
+
execute(flow: core.Flow, options?: {
|
|
6
|
+
expression: string;
|
|
7
|
+
}): core.RuleResult;
|
|
8
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "ProcessBuilder", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return ProcessBuilder;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _internals = /*#__PURE__*/ _interop_require_wildcard(require("../internals/internals"));
|
|
12
|
+
const _AdvancedRule = require("../models/AdvancedRule");
|
|
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 ProcessBuilder = class ProcessBuilder extends _AdvancedRule.AdvancedRule {
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
56
|
+
execute(flow, options) {
|
|
57
|
+
return new _internals.RuleResult(this, [
|
|
58
|
+
new _internals.ResultDetails(new _internals.FlowAttribute("Workflow", "processType", "== Workflow"))
|
|
59
|
+
]);
|
|
60
|
+
}
|
|
61
|
+
constructor(){
|
|
62
|
+
super({
|
|
63
|
+
name: "ProcessBuilder",
|
|
64
|
+
label: "No Process Builder",
|
|
65
|
+
description: "Salesforce is transitioning away from Workflow Rules and Process Builder in favor of Flow. Ensure you're prepared for this transition by migrating your organization's automation to Flow. Refer to official documentation for more information on the transition process and tools available.",
|
|
66
|
+
supportedTypes: _internals.FlowType.processBuilder,
|
|
67
|
+
docRefs: [
|
|
68
|
+
{
|
|
69
|
+
label: "Process Builder Retirement",
|
|
70
|
+
path: "https://help.salesforce.com/s/articleView?id=000389396&type=1"
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
isConfigurable: true,
|
|
74
|
+
autoFixable: false
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as core from "../internals/internals";
|
|
2
|
+
import { AdvancedRule } from "../models/AdvancedRule";
|
|
3
|
+
export declare class RecursiveAfterUpdate extends AdvancedRule implements core.IRuleDefinition {
|
|
4
|
+
protected qualifiedRecordTriggerTypes: Set<string>;
|
|
5
|
+
constructor();
|
|
6
|
+
execute(flow: core.Flow): core.RuleResult;
|
|
7
|
+
}
|