Skip to content

Commit

Permalink
Don't hang on using luaToString on recursive data structures
Browse files Browse the repository at this point in the history
  • Loading branch information
zefhemel committed Jan 17, 2025
1 parent 83550c1 commit ae20b81
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 6 deletions.
4 changes: 4 additions & 0 deletions common/space_lua/runtime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,8 @@ Deno.test("Test Lua Rutime", async () => {
assertEquals(await luaToString([{ a: 1 }]), "{{a = 1}}");
// Ensure simple cases are not returning promises
assertEquals(luaToString(10), "10");
// Test circular references
const circular: any = {};
circular.self = circular;
assertEquals(await luaToString(circular), "{self = <circular reference>}");
});
23 changes: 17 additions & 6 deletions common/space_lua/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -689,18 +689,29 @@ export function luaTruthy(value: any): boolean {
return true;
}

export function luaToString(value: any): string | Promise<string> {
export function luaToString(
value: any,
visited: Set<any> = new Set(),
): string | Promise<string> {
if (value === null || value === undefined) {
return "nil";
}
if (value instanceof Promise) {
return value.then(luaToString);
return value.then((v) => luaToString(v, visited));
}
// Check for circular references
if (typeof value === "object" && visited.has(value)) {
return "<circular reference>";
}
if (value.toStringAsync) {
// Add to visited before recursing
visited.add(value);
return value.toStringAsync();
}
// Handle plain JavaScript objects in a Lua-like format
if (typeof value === "object") {
// Add to visited before recursing
visited.add(value);
return (async () => {
let result = "{";
let first = true;
Expand All @@ -713,8 +724,8 @@ export function luaToString(value: any): string | Promise<string> {
} else {
result += ", ";
}
// Recursively stringify the value
const strVal = await luaToString(val);
// Recursively stringify the value, passing the visited set
const strVal = await luaToString(val, visited);
result += strVal;
}
return result + "}";
Expand All @@ -732,8 +743,8 @@ export function luaToString(value: any): string | Promise<string> {
} else {
result += `["${key}"] = `;
}
// Recursively stringify the value
const strVal = await luaToString(val);
// Recursively stringify the value, passing the visited set
const strVal = await luaToString(val, visited);
result += strVal;
}
result += "}";
Expand Down

0 comments on commit ae20b81

Please sign in to comment.