@@ -42,13 +42,124 @@ export const ConfigView = () => {
4242 } , [ klasses , options , memory . klasses , memory . options ] ) ;
4343
4444 const onSave = useCallback ( ( ) => {
45+ // Check if stringsAsObjects option has changed
46+ const stringsAsObjectsChanged = options . stringsAsObjects !== memory . options . stringsAsObjects ;
47+
4548 // Update existing objects to match new class definitions
4649 const updatedObjects = { ...memory . objects } ;
50+ const updatedMethodCalls = { ...memory . methodCalls } ;
51+
52+ // Helper to generate unique object IDs
53+ const generateId = ( ) => `@${ Math . random ( ) . toString ( 36 ) . slice ( 2 , 18 ) } ` ;
54+
55+ // Handle conversion when stringsAsObjects option changes
56+ if ( stringsAsObjectsChanged ) {
57+ if ( options . stringsAsObjects ) {
58+ // Converting TO String objects mode
59+ // Create String objects for all String primitive values
60+
61+ // Convert String attributes in heap objects
62+ Object . entries ( updatedObjects ) . forEach ( ( [ _ , obj ] ) => {
63+ Object . entries ( obj . attributes ) . forEach ( ( [ attrName , attr ] ) => {
64+ if ( attr . dataType === "String" && attr . value && typeof attr . value === "string" && ! attr . value . startsWith ( "@" ) ) {
65+ // Create a new String object
66+ const stringObjId = generateId ( ) ;
67+ updatedObjects [ stringObjId ] = {
68+ klass : "String" ,
69+ attributes : {
70+ value : {
71+ dataType : "String" ,
72+ value : attr . value ,
73+ } ,
74+ } ,
75+ position : {
76+ x : obj . position . x + 250 ,
77+ y : obj . position . y ,
78+ } ,
79+ } ;
80+ // Update the attribute to reference the String object
81+ obj . attributes [ attrName ] = {
82+ dataType : "String" ,
83+ value : stringObjId ,
84+ } ;
85+ }
86+ } ) ;
87+ } ) ;
88+
89+ // Convert String variables in method calls
90+ Object . entries ( updatedMethodCalls ) . forEach ( ( [ _ , call ] ) => {
91+ Object . entries ( call . localVariables ) . forEach ( ( [ varName , variable ] ) => {
92+ if ( variable . dataType === "String" && variable . value && typeof variable . value === "string" && ! variable . value . startsWith ( "@" ) ) {
93+ // Create a new String object
94+ const stringObjId = generateId ( ) ;
95+ updatedObjects [ stringObjId ] = {
96+ klass : "String" ,
97+ attributes : {
98+ value : {
99+ dataType : "String" ,
100+ value : variable . value ,
101+ } ,
102+ } ,
103+ position : {
104+ x : call . position . x + 250 ,
105+ y : call . position . y ,
106+ } ,
107+ } ;
108+ // Update the variable to reference the String object
109+ call . localVariables [ varName ] = {
110+ dataType : "String" ,
111+ value : stringObjId ,
112+ } ;
113+ }
114+ } ) ;
115+ } ) ;
116+ } else {
117+ // Converting FROM String objects mode TO primitives
118+ // Find all String objects and extract their values
119+ const stringObjects : Record < string , string > = { } ;
120+ Object . entries ( updatedObjects ) . forEach ( ( [ objId , obj ] ) => {
121+ if ( obj . klass === "String" && obj . attributes . value ) {
122+ stringObjects [ objId ] = String ( obj . attributes . value . value || "" ) ;
123+ }
124+ } ) ;
125+
126+ // Convert String references in heap objects back to primitives
127+ Object . entries ( updatedObjects ) . forEach ( ( [ _ , obj ] ) => {
128+ Object . entries ( obj . attributes ) . forEach ( ( [ attrName , attr ] ) => {
129+ if ( attr . dataType === "String" && attr . value && typeof attr . value === "string" && attr . value . startsWith ( "@" ) ) {
130+ const stringValue = stringObjects [ attr . value ] || "" ;
131+ obj . attributes [ attrName ] = {
132+ dataType : "String" ,
133+ value : stringValue ,
134+ } ;
135+ }
136+ } ) ;
137+ } ) ;
138+
139+ // Convert String references in method calls back to primitives
140+ Object . entries ( updatedMethodCalls ) . forEach ( ( [ _ , call ] ) => {
141+ Object . entries ( call . localVariables ) . forEach ( ( [ varName , variable ] ) => {
142+ if ( variable . dataType === "String" && variable . value && typeof variable . value === "string" && variable . value . startsWith ( "@" ) ) {
143+ const stringValue = stringObjects [ variable . value ] || "" ;
144+ call . localVariables [ varName ] = {
145+ dataType : "String" ,
146+ value : stringValue ,
147+ } ;
148+ }
149+ } ) ;
150+ } ) ;
151+
152+ // Remove all String objects
153+ Object . keys ( stringObjects ) . forEach ( objId => {
154+ delete updatedObjects [ objId ] ;
155+ } ) ;
156+ }
157+ }
47158
48159 Object . entries ( updatedObjects ) . forEach ( ( [ objId , obj ] ) => {
49160 const klassDefinition = klasses [ obj . klass ] ;
50161
51- // Skip if class doesn't exist (e.g., Array) or object class is not in klasses
162+ // Skip if class doesn't exist (e.g., Array, String ) or object class is not in klasses
52163 if ( ! klassDefinition ) return ;
53164
54165 const updatedAttributes = { ...obj . attributes } ;
@@ -83,6 +194,7 @@ export const ConfigView = () => {
83194 klasses,
84195 options,
85196 objects : updatedObjects ,
197+ methodCalls : updatedMethodCalls ,
86198 } ) ;
87199 setHasUnsavedChanges ( false ) ;
88200 setShowSaveSuccess ( true ) ;
@@ -422,6 +534,28 @@ export const ConfigView = () => {
422534 />
423535 Create New On Edge Drop
424536 </ label >
537+ < label style = { {
538+ display : "flex" ,
539+ alignItems : "center" ,
540+ gap : "8px" ,
541+ fontSize : "14px" ,
542+ color : "#374151" ,
543+ cursor : "pointer"
544+ } } >
545+ < input
546+ type = "checkbox"
547+ checked = { options . stringsAsObjects || false }
548+ onChange = { ( e ) =>
549+ handleOptionChange ( "stringsAsObjects" , e . target . checked )
550+ }
551+ style = { {
552+ width : "16px" ,
553+ height : "16px" ,
554+ cursor : "pointer"
555+ } }
556+ />
557+ Strings as Objects
558+ </ label >
425559 </ div >
426560 </ div >
427561
0 commit comments