/** * Action: page-hierarchy-full * * Extends page-hierarchy with full geometry for every shape at each nesting level. * * Reuses the shared hierarchy-builder service (same logic as page-hierarchy). * * "Levels" = containment depth levels in the shape hierarchy (diagramming term): * level 1 (depth 0) = root-level shapes (parentId === "1") * level 2 (depth 1) = shapes whose parent is at level 1 * level N (depth N-1) = shapes nested N-1 levels deep * * Output structure: * summary: * levelsTotal — number of distinct nesting levels * shapesTotal — total shape count * shapesPerLevel — { levelNumber: count } * levels: * - number — 1-based nesting level (1 = root, 2 = children, …) * shapeCount * shapes: * - id, label, x, y, width, height, parentId * * IMPORTANT: Parser returns absolute canvas coordinates for all shapes. */ import { parseAllPages } from "../../services/drawio-parser/parser.js"; import { buildHierarchy } from "../../services/hierarchy-builder/hierarchy-builder.js"; import type { Shape } from "../../services/drawio-parser/parser.js"; interface ShapeEntry { id: string; label: string; x: number; y: number; width: number; height: number; parentId: string; } interface NestingLevel { number: number; shapeCount: number; shapes: ShapeEntry[]; } export function run( filePath: string, pageIndex: number = 0 ): Record { const pages = parseAllPages(filePath); const page = pages[pageIndex]; if (!page) { return { error: true, message: `Page index ${pageIndex} not found` }; } // Reuse shared hierarchy builder const { depthMap, maxDepth, totalLevels } = buildHierarchy(page); const allShapes = Array.from(page.shapes.values()); // Group shapes by depth const levelMap = new Map(); for (const s of allShapes) { const d = depthMap.get(s.id); if (d === undefined) continue; if (!levelMap.has(d)) levelMap.set(d, []); levelMap.get(d)!.push(s); } const levels: NestingLevel[] = []; for (let d = 0; d <= maxDepth; d++) { const shapes = (levelMap.get(d) ?? []).sort((a, b) => a.y - b.y || a.x - b.x); levels.push({ number: d + 1, shapeCount: shapes.length, shapes: shapes.map((s) => ({ id: s.id, label: s.label.replace(/\n/g, " / "), x: s.x, y: s.y, width: s.width, height: s.height, parentId: s.parentId, })), }); } return { action: "page-hierarchy-full", file: filePath, pageIndex, summary: { levelsTotal: totalLevels, shapesTotal: allShapes.length, shapesPerLevel: Object.fromEntries(levels.map((l) => [l.number, l.shapeCount])), }, levels, }; }