Restructure to skill-manager conventions
- Move the TypeScript project under scripts/ (src, tsconfig, package.json, pnpm lockfile/workspace, canonical .gitignore); drop the npm package-lock - Add scripts/Taskfile.yml aggregator plus .scripts modules (loggers, base, cli) with build, run, and validate tasks - Move the six SKILL-*.md docs into references/ with kebab names and extract the connector-routing sections from SKILL.md into references/routing-best-practices.md (SKILL.md 666 -> ~310 lines) - Add license/metadata/compatibility frontmatter, an Available scripts section, and update all CLI paths in README and references skill-manager validate: 13/13 passed, 0 warnings. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* 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<string, unknown> {
|
||||
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<number, Shape[]>();
|
||||
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,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user