11import { XMLBuilder } from "fast-xml-parser" ;
22import * as p from "path" ;
3-
43import { FlowElement } from "./FlowElement" ;
54import { FlowMetadata } from "./FlowMetadata" ;
65import { FlowNode } from "./FlowNode" ;
76import { FlowResource } from "./FlowResource" ;
87import { FlowVariable } from "./FlowVariable" ;
98
109export class Flow {
11- /**
10+ /**
1211 * Metadata Tags of Salesforce Flow Elements
1312 */
1413 public static readonly FLOW_METADATA_TAGS = [
1514 "description" , "apiVersion" , "processMetadataValues" , "processType" ,
1615 "interviewLabel" , "label" , "status" , "runInMode" , "startElementReference" ,
17- "isTemplate" , "fullName" , "timeZoneSidKey" ,
16+ "isTemplate" , "fullName" , "timeZoneSidKey" ,
1817 "isAdditionalPermissionRequiredToRun" , "migratedFromWorkflowRuleName" ,
1918 "triggerOrder" , "environments" , "segment" ,
20- ] ;
19+ ] as const ;
2120
2221 /**
2322 * Categorized flow contents that should be used in the rule implementation
2423 */
25- public elements ?: FlowElement [ ] ;
26- public fsPath ;
27- public interviewLabel ?: string ;
28- public label : string ;
29- public name ?: string ;
30- public processMetadataValues ?;
31- public processType ?;
32- public root ?;
33- public start ?;
34- public startElementReference ?;
35- public startReference ;
36- public status ?;
37- public triggerOrder ?: number ;
38- public type ?;
39-
40- /**
41- * XML to JSON conversion in raw format
42- */
43- public xmldata ;
44- private flowMetadata = Flow . FLOW_METADATA_TAGS ;
45- private flowNodes = [
24+ public static readonly FLOW_NODES = [
4625 "actionCalls" ,
4726 "apexPluginCalls" ,
4827 "assignments" ,
@@ -62,12 +41,36 @@ export class Flow {
6241 "waits" ,
6342 "transforms" ,
6443 "customErrors" ,
65- ] ;
66- private flowResources = [ "textTemplates" , "stages" ] ;
67- private flowVariables = [ "choices" , "constants" , "dynamicChoiceSets" , "formulas" , "variables" ] ;
44+ ] as const ;
45+
46+ public static readonly FLOW_RESOURCES = [ "textTemplates" , "stages" ] as const ;
47+ public static readonly FLOW_VARIABLES = [ "choices" , "constants" , "dynamicChoiceSets" , "formulas" , "variables" ] as const ;
6848
69- constructor ( path ?: string , data ?: unknown ) ;
70- constructor ( path : string , data ?: unknown ) {
49+ /**
50+ * Categorized flow contents that should be used in the rule implementation
51+ */
52+ public elements ?: FlowElement [ ] ;
53+
54+ public fsPath ?: string ;
55+ public interviewLabel ?: string ;
56+ public label : string ;
57+ public name ?: string ;
58+ public processMetadataValues ?: any ;
59+ public processType ?: string ;
60+ public root ?: any ;
61+ public start ?: any ;
62+ public startElementReference ?: string ;
63+ public startReference ?: string ;
64+ public status ?: string ;
65+ public triggerOrder ?: number ;
66+ public type ?: string ;
67+
68+ /**
69+ * XML to JSON conversion in raw format
70+ */
71+ public xmldata : any ;
72+
73+ constructor ( path ?: string , data ?: unknown ) {
7174 if ( path ) {
7275 this . fsPath = p . resolve ( path ) ;
7376 let flowName = p . basename ( p . basename ( this . fsPath ) , p . extname ( this . fsPath ) ) ;
@@ -89,14 +92,14 @@ export class Flow {
8992 if ( obj instanceof Flow ) {
9093 return obj ;
9194 }
92-
95+
9396 const flow = Object . create ( Flow . prototype ) ;
9497 Object . assign ( flow , obj ) ;
95-
98+
9699 if ( ! flow . toXMLString ) {
97100 flow . toXMLString = ( ) => '' ;
98101 }
99-
102+
100103 return flow ;
101104 }
102105
@@ -118,31 +121,31 @@ export class Flow {
118121 continue ;
119122 }
120123 const data = this . xmldata [ nodeType ] ;
121- if ( this . flowMetadata . includes ( nodeType ) ) {
124+ if ( Flow . FLOW_METADATA_TAGS . includes ( nodeType as any ) ) {
122125 if ( Array . isArray ( data ) ) {
123126 for ( const node of data ) {
124127 allNodes . push ( new FlowMetadata ( nodeType , node ) ) ;
125128 }
126129 } else {
127130 allNodes . push ( new FlowMetadata ( nodeType , data ) ) ;
128131 }
129- } else if ( this . flowVariables . includes ( nodeType ) ) {
132+ } else if ( Flow . FLOW_VARIABLES . includes ( nodeType as any ) ) {
130133 if ( Array . isArray ( data ) ) {
131134 for ( const node of data ) {
132135 allNodes . push ( new FlowVariable ( node . name , nodeType , node ) ) ;
133136 }
134137 } else {
135138 allNodes . push ( new FlowVariable ( data . name , nodeType , data ) ) ;
136139 }
137- } else if ( this . flowNodes . includes ( nodeType ) ) {
140+ } else if ( Flow . FLOW_NODES . includes ( nodeType as any ) ) {
138141 if ( Array . isArray ( data ) ) {
139142 for ( const node of data ) {
140143 allNodes . push ( new FlowNode ( node . name , nodeType , node ) ) ;
141144 }
142145 } else {
143146 allNodes . push ( new FlowNode ( data . name , nodeType , data ) ) ;
144147 }
145- } else if ( this . flowResources . includes ( nodeType ) ) {
148+ } else if ( Flow . FLOW_RESOURCES . includes ( nodeType as any ) ) {
146149 if ( Array . isArray ( data ) ) {
147150 for ( const node of data ) {
148151 allNodes . push ( new FlowResource ( node . name , nodeType , node ) ) ;
@@ -189,14 +192,13 @@ export class Flow {
189192 // eslint-disable-next-line sonarjs/no-clear-text-protocols
190193 const flowXmlNamespace = "http://soap.sforce.com/2006/04/metadata" ;
191194 const builderOptions = {
192- attributeNamePrefix : "@_" , // Matches parsing (key prefix)
193- format : true , // Pretty-print (indented; expands empties to </tag>)
194- ignoreAttributes : false , // Preserve attrs like xmlns
195+ attributeNamePrefix : "@_" , // Matches parsing (key prefix)
196+ format : true , // Pretty-print (indented; expands empties to </tag>)
197+ ignoreAttributes : false , // Preserve attrs like xmlns
195198 suppressBooleanAttributes : false , // NEW: Force ="true" for boolean-like strings (fixes missing value)
196- suppressEmptyNode : false // Keep empty tags (but doesn't force self-closing in pretty)
199+ suppressEmptyNode : false // Keep empty tags (but doesn't force self-closing in pretty)
197200 } ;
198201 const builder = new XMLBuilder ( builderOptions ) ;
199-
200202 // Fallback: Inject xmlns as attribute if missing
201203 const xmldataWithNs = { ...this . xmldata } ;
202204 if ( ! xmldataWithNs [ "@_xmlns" ] ) {
@@ -206,7 +208,6 @@ export class Flow {
206208 if ( ! xmldataWithNs [ "@_xmlns:xsi" ] ) {
207209 xmldataWithNs [ "@_xmlns:xsi" ] = "http://www.w3.org/2001/XMLSchema-instance" ;
208210 }
209-
210211 // Build: Wrap in { Flow: ... }
211212 const rootObj = { Flow : xmldataWithNs } ;
212213 return builder . build ( rootObj ) ;
0 commit comments