fix(web): dedupe tree keys and guard against circular JSON
Key tree nodes by their index path instead of GUID, since TTS saves can contain duplicate GUIDs. Skip the Parent back-reference in the default viewer and stringify with a circular-reference guard.
This commit is contained in:
@@ -27,20 +27,41 @@ export function resolveViewer(object: TTSObject): ObjectViewer['component'] {
|
||||
export function DefaultViewer({ object }: { object: TTSObject }) {
|
||||
return (
|
||||
<dl className="grid grid-cols-1 gap-2 text-sm sm:grid-cols-2">
|
||||
{Object.entries(object).map(([key, value]) => (
|
||||
<div key={key} className="rounded-lg border border-zinc-800 bg-zinc-900 p-3">
|
||||
<dt className="font-mono text-xs uppercase text-zinc-500">{key}</dt>
|
||||
<dd className="mt-1 break-words text-zinc-200">
|
||||
{typeof value === 'string' || typeof value === 'number' ? (
|
||||
value
|
||||
) : (
|
||||
<pre className="whitespace-pre-wrap font-mono text-xs">
|
||||
{JSON.stringify(value, null, 2)}
|
||||
</pre>
|
||||
)}
|
||||
</dd>
|
||||
</div>
|
||||
))}
|
||||
{Object.entries(object).map(([key, value]) => {
|
||||
// `Parent` is a back-reference added during traversal; it creates a
|
||||
// cycle with `ContainedObjects`, so skip it in the default view.
|
||||
if (key === 'Parent') return null;
|
||||
return (
|
||||
<div key={key} className="rounded-lg border border-zinc-800 bg-zinc-900 p-3">
|
||||
<dt className="font-mono text-xs uppercase text-zinc-500">{key}</dt>
|
||||
<dd className="mt-1 break-words text-zinc-200">
|
||||
{typeof value === 'string' || typeof value === 'number' ? (
|
||||
value
|
||||
) : (
|
||||
<pre className="whitespace-pre-wrap font-mono text-xs">
|
||||
{safeStringify(value)}
|
||||
</pre>
|
||||
)}
|
||||
</dd>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</dl>
|
||||
);
|
||||
}
|
||||
|
||||
/** JSON-stringify a value, replacing any circular references with a marker. */
|
||||
function safeStringify(value: unknown): string {
|
||||
const seen = new Set<object>();
|
||||
return JSON.stringify(
|
||||
value,
|
||||
(_key, v) => {
|
||||
if (typeof v === 'object' && v !== null) {
|
||||
if (seen.has(v)) return '[Circular]';
|
||||
seen.add(v);
|
||||
}
|
||||
return v;
|
||||
},
|
||||
2,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user