Skip to content

Commit eae575b

Browse files
Copilotmikebarkmin
andcommitted
Implement useStringAsObject mode with automatic conversion between string primitives and String objects
Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com>
1 parent 977b166 commit eae575b

3 files changed

Lines changed: 136 additions & 5 deletions

File tree

src/ConfigView.tsx

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,128 @@ export const ConfigView = () => {
4242
}, [klasses, options, memory.klasses, memory.options]);
4343

4444
const onSave = useCallback(() => {
45+
// Track if useStringAsObject option changed
46+
const stringAsObjectChanged = options.useStringAsObject !== memory.options.useStringAsObject;
47+
4548
// Update existing objects to match new class definitions
4649
const updatedObjects = { ...memory.objects };
50+
const updatedMethodCalls = { ...memory.methodCalls };
51+
const updatedVariables = { ...memory.variables };
52+
53+
// Helper function to generate unique ID
54+
const generateId = () => `@${Math.random().toString(36).slice(2, 18)}`;
55+
56+
// Convert String values to String objects or vice versa
57+
if (stringAsObjectChanged) {
58+
if (options.useStringAsObject) {
59+
// Converting TO String objects mode
60+
console.log("Converting string primitives to String objects");
61+
62+
// Convert string attributes in objects
63+
Object.entries(updatedObjects).forEach(([_, obj]) => {
64+
Object.entries(obj.attributes).forEach(([attrName, attr]) => {
65+
if (attr.dataType === "String" && attr.value && typeof attr.value === "string" && !attr.value.startsWith("@")) {
66+
// Create a new String object
67+
const stringObjId = generateId();
68+
updatedObjects[stringObjId] = {
69+
klass: "String",
70+
attributes: {
71+
value: {
72+
dataType: "String",
73+
value: attr.value,
74+
},
75+
},
76+
position: {
77+
x: obj.position.x + 200,
78+
y: obj.position.y,
79+
},
80+
};
81+
// Update the attribute to reference the String object
82+
obj.attributes[attrName] = {
83+
dataType: "String",
84+
value: stringObjId,
85+
};
86+
}
87+
});
88+
});
89+
90+
// Convert string local variables in method calls
91+
Object.entries(updatedMethodCalls).forEach(([_, call]) => {
92+
Object.entries(call.localVariables).forEach(([varName, variable]) => {
93+
if (variable.dataType === "String" && variable.value && typeof variable.value === "string" && !variable.value.startsWith("@")) {
94+
// Create a new String object
95+
const stringObjId = generateId();
96+
updatedObjects[stringObjId] = {
97+
klass: "String",
98+
attributes: {
99+
value: {
100+
dataType: "String",
101+
value: variable.value,
102+
},
103+
},
104+
position: {
105+
x: call.position.x + 200,
106+
y: call.position.y,
107+
},
108+
};
109+
// Update the variable to reference the String object
110+
call.localVariables[varName] = {
111+
dataType: "String",
112+
value: stringObjId,
113+
};
114+
}
115+
});
116+
});
117+
118+
} else {
119+
// Converting FROM String objects mode TO primitives
120+
console.log("Converting String objects to string primitives");
121+
122+
// Find all String objects and extract their values
123+
const stringObjects: Record<string, string> = {};
124+
Object.entries(updatedObjects).forEach(([objId, obj]) => {
125+
if (obj.klass === "String" && obj.attributes.value) {
126+
stringObjects[objId] = String(obj.attributes.value.value || "");
127+
}
128+
});
129+
130+
// Convert string references in object attributes back to primitives
131+
Object.entries(updatedObjects).forEach(([_, obj]) => {
132+
Object.entries(obj.attributes).forEach(([attrName, attr]) => {
133+
if (attr.dataType === "String" && attr.value && typeof attr.value === "string" && attr.value.startsWith("@")) {
134+
const stringValue = stringObjects[attr.value] || "";
135+
obj.attributes[attrName] = {
136+
dataType: "String",
137+
value: stringValue,
138+
};
139+
}
140+
});
141+
});
142+
143+
// Convert string references in method call local variables back to primitives
144+
Object.entries(updatedMethodCalls).forEach(([_, call]) => {
145+
Object.entries(call.localVariables).forEach(([varName, variable]) => {
146+
if (variable.dataType === "String" && variable.value && typeof variable.value === "string" && variable.value.startsWith("@")) {
147+
const stringValue = stringObjects[variable.value] || "";
148+
call.localVariables[varName] = {
149+
dataType: "String",
150+
value: stringValue,
151+
};
152+
}
153+
});
154+
});
155+
156+
// Remove all String objects
157+
Object.keys(stringObjects).forEach(objId => {
158+
delete updatedObjects[objId];
159+
});
160+
}
161+
}
47162

48163
Object.entries(updatedObjects).forEach(([objId, obj]) => {
49164
const klassDefinition = klasses[obj.klass];
50165

51-
// Skip if class doesn't exist (e.g., Array) or object class is not in klasses
166+
// Skip if class doesn't exist (e.g., Array, String) or object class is not in klasses
52167
if (!klassDefinition) return;
53168

54169
const updatedAttributes = { ...obj.attributes };
@@ -83,6 +198,8 @@ export const ConfigView = () => {
83198
klasses,
84199
options,
85200
objects: updatedObjects,
201+
methodCalls: updatedMethodCalls,
202+
variables: updatedVariables,
86203
});
87204
setHasUnsavedChanges(false);
88205
setShowSaveSuccess(true);

src/ObjectNode.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ function AttributeHandle({
2020
isFinal,
2121
isConnectable,
2222
nodeId,
23+
useStringAsObject,
2324
}: {
2425
name: string;
2526
value: Attribute;
2627
nodeId: string;
2728
isFinal: boolean;
2829
isConnected: boolean;
2930
isConnectable: boolean;
31+
useStringAsObject?: boolean;
3032
}) {
3133
const { setNodes } = useReactFlow<CustomNodeType, CustomEdgeType>();
3234

@@ -57,7 +59,11 @@ function AttributeHandle({
5759
);
5860
};
5961

60-
return !primitveDataTypes.includes(value.dataType) ? (
62+
// When useStringAsObject is enabled, treat String as an object reference
63+
const isObjectReference = !primitveDataTypes.includes(value.dataType) ||
64+
(value.dataType === "String" && useStringAsObject);
65+
66+
return isObjectReference ? (
6167
<div className="object-node__attribute">
6268
<div className="object-node__attribute-name">{name} =</div>
6369
<Handle
@@ -115,7 +121,7 @@ const selector = (state: RFState) => ({
115121
});
116122

117123
function ObjectNode({ id, data }: NodeProps<ObjectNodeType>) {
118-
const { disableGarbageCollector } = useStore(selector, shallow);
124+
const { disableGarbageCollector, useStringAsObject } = useStore(selector, shallow);
119125
const nodes = useNodes();
120126
const edges = useEdges();
121127
const gc = !disableGarbageCollector &&
@@ -156,6 +162,7 @@ function ObjectNode({ id, data }: NodeProps<ObjectNodeType>) {
156162
nodeId={id}
157163
name={name}
158164
value={value}
165+
useStringAsObject={useStringAsObject}
159166
/>
160167
))}
161168
</div>

src/getEdgesAndNodes.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ export const getEdgesAndNodes = (
1111
} => {
1212
const nodes: CustomNodeType[] = [];
1313
const edges: CustomEdgeType[] = [];
14+
const useStringAsObject = memory.options.useStringAsObject || false;
15+
16+
// Helper function to check if a dataType should be treated as an object reference
17+
const isObjectReference = (dataType: string) => {
18+
return !primitveDataTypes.includes(dataType) ||
19+
(dataType === "String" && useStringAsObject);
20+
};
1421

1522
Object.entries(memory.variables).forEach(([id, data]) => {
1623
nodes.push({
@@ -40,7 +47,7 @@ export const getEdgesAndNodes = (
4047
const methodCallData = data as MethodCall;
4148

4249
Object.entries(methodCallData.localVariables).forEach(([name, value]) => {
43-
if (!primitveDataTypes.includes(value.dataType) && value.value != null) {
50+
if (isObjectReference(value.dataType) && value.value != null) {
4451
edges.push({
4552
id: `method-call-${id}+${name}`,
4653
type: "reference",
@@ -61,7 +68,7 @@ export const getEdgesAndNodes = (
6168
});
6269

6370
Object.entries(data.attributes).forEach(([name, value]) => {
64-
if (!primitveDataTypes.includes(value.dataType) && value.value != null) {
71+
if (isObjectReference(value.dataType) && value.value != null) {
6572
edges.push({
6673
id: `${id}+${name}`,
6774
source: id,

0 commit comments

Comments
 (0)