Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 64 additions & 1 deletion src/main/flow_parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export interface Transition {
*/
export interface ParsedFlow {
label?: string;
processType?: flowTypes.FlowProcessType;
start?: flowTypes.FlowStart;
apexPluginCalls?: flowTypes.FlowApexPluginCall[];
assignments?: flowTypes.FlowAssignment[];
Expand Down Expand Up @@ -131,8 +132,10 @@ export class FlowParser {

private populateFlowNodes(flow: flowTypes.Flow) {
this.beingParsed.label = flow.label;
this.beingParsed.processType = flow.processType;
this.beingParsed.start = flow.start;
this.validateFlowStart();
setFlowStart(this.beingParsed.start);

this.beingParsed.apexPluginCalls = ensureArray(flow.apexPluginCalls);
this.beingParsed.assignments = ensureArray(flow.assignments);
Expand Down Expand Up @@ -257,7 +260,9 @@ export class FlowParser {
*/
private getTransitionsForNode(node: flowTypes.FlowNode): Transition[] {
const transitions: Transition[] = [];
if (
if (isFlowStart(node)) {
transitions.push(...this.getTransitionsFromFlowStart(node));
} else if (
isRecordCreate(node) ||
isRecordDelete(node) ||
isRecordLookup(node) ||
Expand Down Expand Up @@ -431,6 +436,31 @@ export class FlowParser {
}
return result;
}

private getTransitionsFromFlowStart(node: flowTypes.FlowStart): Transition[] {
const result: Transition[] = [];

// Add main flow transition
if (node.connector) {
result.push(
this.createTransition(node, node.connector, false, undefined),
);
}

// Add scheduled path transitions
if (node.scheduledPaths && node.scheduledPaths.length > 0) {
for (const scheduledPath of node.scheduledPaths) {
if (scheduledPath.connector) {
const label = scheduledPath.pathType;
result.push(
this.createTransition(node, scheduledPath.connector, false, label),
);
}
}
}

return result;
}
}

/**
Expand Down Expand Up @@ -570,6 +600,33 @@ function setCustomErrorMessages(
}
}

/**
* Set Flow Start
*
* Flow Start filters and scheduled paths are nested properties which also
* need to be converted to arrays.
*/
function setFlowStart(start: flowTypes.FlowStart | undefined) {
if (!start) {
return;
}
if (start.filters) {
start.filters = ensureArray(
start.filters,
) as flowTypes.FlowRecordFilter[];
}
if (start.scheduledPaths) {
start.scheduledPaths = ensureArray(
start.scheduledPaths,
) as flowTypes.FlowScheduledPath[];
}
if (start.capabilityTypes) {
start.capabilityTypes = ensureArray(
start.capabilityTypes,
) as flowTypes.FlowCapability[];
}
}

/**
* The following functions are used to determine if a node is a specific type
* of node.
Expand Down Expand Up @@ -666,3 +723,9 @@ function isCustomError(
): node is flowTypes.FlowCustomError {
return (node as flowTypes.FlowCustomError).customErrorMessages !== undefined;
}

function isFlowStart(
node: flowTypes.FlowNode,
): node is flowTypes.FlowStart {
return (node as flowTypes.FlowStart).connector !== undefined;
}
6 changes: 3 additions & 3 deletions src/main/flow_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ export interface FlowScheduledPath extends FlowElement {
connector: FlowConnector;
label: string;
maxBatchSize?: number; // Default is 200
offsetNumber: number; // Can be positive or negative
offsetNumber: string; // XML parser returns string values for numbers
offsetUnit: FlowScheduledPathOffsetUnit;
pathType?: FlowScheduledPathType; // Default is null
recordField?: string; // Required if timeSource is RecordField
Expand Down Expand Up @@ -824,13 +824,13 @@ export interface FlowActionCallOutputParameter {

export interface FlowElementReferenceOrValue {
apexValue?: string;
booleanValue?: boolean;
booleanValue?: string; // XML parser returns string values for booleans
dateTimeValue?: string; // Assuming dateTime is represented as a string
dateValue?: string; // Assuming date is represented as a string
elementReference?: string;
formulaDataType?: FormulaDataType;
formulaExpression?: string;
numberValue?: number; // using number to represent double
numberValue?: string; // XML parser returns string values for numbers
setupReference?: string;
setupReferenceType?: string;
sobjectValue?: string;
Expand Down
111 changes: 108 additions & 3 deletions src/main/uml_generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export abstract class UmlGenerator {
generateUml(): string {
const result = [
this.getHeader(this.parsedFlow.label!),
this.getFlowStart(),
this.processFlowElements<flowTypes.FlowApexPluginCall>(
this.parsedFlow.apexPluginCalls,
(node) => this.getFlowApexPluginCall(node),
Expand Down Expand Up @@ -175,6 +176,110 @@ export abstract class UmlGenerator {
abstract getTransition(transition: Transition): string;
abstract getFooter(): string;

private getFlowStart(): string {
if (!this.parsedFlow.start) {
return "";
}

const start = this.parsedFlow.start;
const entryCriteria: string[] = [];

// Add process type information from the flow
if (this.parsedFlow.processType) {
entryCriteria.push(`Process Type: ${this.parsedFlow.processType}`);
}

// Add trigger type information
if (start.triggerType) {
entryCriteria.push(`Trigger Type: ${start.triggerType}`);
}

// Add object information for record-triggered flows
if (start.object) {
entryCriteria.push(`Object: ${start.object}`);
}

// Add record trigger type information
if (start.recordTriggerType) {
entryCriteria.push(`Record Trigger: ${start.recordTriggerType}`);
}

// Add entry type information
if (start.entryType) {
entryCriteria.push(`Entry Type: ${start.entryType}`);
}

// Add filter information
if (start.filterLogic && start.filters && start.filters.length > 0) {
entryCriteria.push(`Filter Logic: ${start.filterLogic}`);
start.filters.forEach((filter, index) => {
entryCriteria.push(
`${index + 1}. ${filter.field} ${filter.operator} ${
toString(filter.value)
}`,
);
});
}

// Add filter formula if present
if (start.filterFormula) {
entryCriteria.push(`Filter Formula: ${start.filterFormula}`);
}

// Add schedule information for scheduled flows
if (start.schedule) {
entryCriteria.push(
`Schedule: ${start.schedule.frequency} starting ${start.schedule.startDate} at ${start.schedule.startTime}`,
);
}

// Add capability information
if (start.capabilityTypes && start.capabilityTypes.length > 0) {
start.capabilityTypes.forEach((capability, index) => {
entryCriteria.push(
`Capability ${index + 1}: ${capability.capabilityName}`,
);
});
}

// Add form information for form-triggered flows
if (start.form) {
entryCriteria.push(`Form: ${start.form}`);
}

// Add segment information
if (start.segment) {
entryCriteria.push(`Segment: ${start.segment}`);
}

// Add flow run as user information
if (start.flowRunAsUser) {
entryCriteria.push(`Run As: ${start.flowRunAsUser}`);
}

// If no specific criteria found, add a default message
if (entryCriteria.length === 0) {
entryCriteria.push("No specific entry criteria defined");
}

return this.toUmlString({
id: "FLOW_START",
label: "Flow Start",
type: "Flow Start",
color: SkinColor.NONE,
icon: Icon.NONE,
diffStatus: start.diffStatus,
innerNodes: [
{
id: "FlowStart__EntryCriteria",
type: "Flow Details",
label: "",
content: entryCriteria,
},
],
});
}

private getFlowApexPluginCall(node: flowTypes.FlowApexPluginCall): string {
return this.toUmlString({
id: node.name,
Expand Down Expand Up @@ -631,10 +736,10 @@ function toString(element: flowTypes.FlowElementReferenceOrValue | undefined) {
return new Date(element.dateValue).toLocaleDateString();
}
if (element.numberValue) {
return element.numberValue.toString();
return element.numberValue;
}
if (element.booleanValue) {
return element.booleanValue ? "true" : "false";
if (element.booleanValue !== undefined) {
return element.booleanValue;
}
return "";
}
Loading