Don't hang on using luaToString on recursive data structures

pull/1220/head
Zef Hemel 2025-01-17 18:30:29 +01:00
parent 83550c1623
commit ae20b81126
2 changed files with 21 additions and 6 deletions

View File

@ -50,4 +50,8 @@ Deno.test("Test Lua Rutime", async () => {
assertEquals(await luaToString([{ a: 1 }]), "{{a = 1}}"); assertEquals(await luaToString([{ a: 1 }]), "{{a = 1}}");
// Ensure simple cases are not returning promises // Ensure simple cases are not returning promises
assertEquals(luaToString(10), "10"); assertEquals(luaToString(10), "10");
// Test circular references
const circular: any = {};
circular.self = circular;
assertEquals(await luaToString(circular), "{self = <circular reference>}");
}); });

View File

@ -689,18 +689,29 @@ export function luaTruthy(value: any): boolean {
return true; 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) { if (value === null || value === undefined) {
return "nil"; return "nil";
} }
if (value instanceof Promise) { 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) { if (value.toStringAsync) {
// Add to visited before recursing
visited.add(value);
return value.toStringAsync(); return value.toStringAsync();
} }
// Handle plain JavaScript objects in a Lua-like format // Handle plain JavaScript objects in a Lua-like format
if (typeof value === "object") { if (typeof value === "object") {
// Add to visited before recursing
visited.add(value);
return (async () => { return (async () => {
let result = "{"; let result = "{";
let first = true; let first = true;
@ -713,8 +724,8 @@ export function luaToString(value: any): string | Promise<string> {
} else { } else {
result += ", "; result += ", ";
} }
// Recursively stringify the value // Recursively stringify the value, passing the visited set
const strVal = await luaToString(val); const strVal = await luaToString(val, visited);
result += strVal; result += strVal;
} }
return result + "}"; return result + "}";
@ -732,8 +743,8 @@ export function luaToString(value: any): string | Promise<string> {
} else { } else {
result += `["${key}"] = `; result += `["${key}"] = `;
} }
// Recursively stringify the value // Recursively stringify the value, passing the visited set
const strVal = await luaToString(val); const strVal = await luaToString(val, visited);
result += strVal; result += strVal;
} }
result += "}"; result += "}";