import type { HierarchicalMapNode, MapNode } from "@/types/map/mapScene"; export interface ParsedMapNodes { mapNodes: MapNode[]; mapTree: HierarchicalMapNode | HierarchicalMapNode[]; } function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null; } function isVector3Tuple(value: unknown): value is [number, number, number] { return ( Array.isArray(value) && value.length === 3 && value.every((item) => typeof item === "number" && Number.isFinite(item)) ); } function isMapNode(value: unknown): value is MapNode { if (!isRecord(value)) { return false; } return ( (value.id === undefined || typeof value.id === "string") && typeof value.name === "string" && typeof value.type === "string" && isVector3Tuple(value.position) && isVector3Tuple(value.rotation) && isVector3Tuple(value.scale) ); } function isHierarchicalMapNode(value: unknown): value is HierarchicalMapNode { if (!isMapNode(value)) { return false; } if ("role" in value && value.role !== undefined && value.role !== "group") { return false; } if (!("children" in value)) { return true; } return ( value.children === undefined || (Array.isArray(value.children) && value.children.every(isHierarchicalMapNode)) ); } function flattenMapNode(node: HierarchicalMapNode, path: number[]): MapNode[] { const mapNode: MapNode = { ...(node.id ? { id: node.id } : {}), name: node.name, type: node.type, position: node.position, rotation: node.rotation, scale: node.scale, sourcePath: path, }; const childNodes = node.children?.flatMap((child, index) => flattenMapNode(child, [...path, index]), ) ?? []; if (node.role === "group" || node.type === "Mesh") { return childNodes; } return [mapNode, ...childNodes]; } export function parseMapNodes(value: unknown): MapNode[] { return parseMapData(value).mapNodes; } export function parseMapData(value: unknown): ParsedMapNodes { if (Array.isArray(value) && value.every(isHierarchicalMapNode)) { return { mapNodes: value.flatMap((node, index) => flattenMapNode(node, [index])), mapTree: value, }; } if (isHierarchicalMapNode(value)) { return { mapNodes: flattenMapNode(value, []), mapTree: value, }; } throw new Error("Invalid map node data"); }