Files
pi-config/skills/archify/renderers/architecture/grid.mjs
Sam Rolfe 8e68df0830 Add archify skill (v2.14), pi-mermaid ext (v0.3.0), project-diagramming-mermaid + project-diagramming-archify skills
- skills/archify: vendored tt-a1i/archify 2.14.0 (MIT), pure Node 18+, zero deps
- extensions/pi-mermaid: renders mermaid blocks as ASCII in TUI; deps beautiful-mermaid + mermaid
- skills/project-diagramming-*: orchestration skills, per-project docs/ convention
2026-09-06 10:50:29 +10:00

63 lines
2.0 KiB
JavaScript

/** Grid placement for architecture IR (#8). Not auto-layout — fixed cell math only. */
export const DEFAULT_GRID = {
mode: 'grid',
origin: [40, 80],
cols: 4,
gapX: 30,
gapY: 40,
cellW: 130,
cellH: 64,
};
export function gridLayout(arch) {
const raw = arch.layout;
if (!raw || raw.mode !== 'grid') return null;
return { ...DEFAULT_GRID, ...raw };
}
export function resolveComponentPos(component, grid) {
if (Array.isArray(component.pos) && component.pos.length === 2) {
return component.pos;
}
if (!grid) return [NaN, NaN];
if (!Number.isInteger(component.row) || !Number.isInteger(component.col)) {
return [NaN, NaN];
}
const [ox, oy] = grid.origin;
const stepX = grid.cellW + grid.gapX;
const stepY = grid.cellH + grid.gapY;
return [ox + component.col * stepX, oy + component.row * stepY];
}
export function validateGridPlacement(arch, grid, problems) {
if (!grid) return;
if (arch.layout !== undefined && arch.layout.mode !== 'grid') {
problems.push('layout.mode must be "grid" when layout is set (free placement omits layout entirely).');
return;
}
const seen = new Map();
for (const c of arch.components ?? []) {
const hasPos = Array.isArray(c.pos) && c.pos.length === 2;
const hasCell = Number.isInteger(c.row) && Number.isInteger(c.col);
if (hasPos) continue; // pos wins; row/col are optional hints only
if (!hasPos && !hasCell) {
problems.push(`Component "${c.id}" needs pos [x,y] or grid row/col when layout.mode is "grid".`);
continue;
}
if (c.row < 0 || c.col < 0) {
problems.push(`Component "${c.id}" row/col must be non-negative integers.`);
continue;
}
if (c.col >= grid.cols) {
problems.push(`Component "${c.id}" col ${c.col} exceeds layout.cols ${grid.cols} (valid: 0..${grid.cols - 1}).`);
}
const key = `${c.row},${c.col}`;
if (seen.has(key)) {
problems.push(`Components "${seen.get(key)}" and "${c.id}" share grid cell row ${c.row} col ${c.col}.`);
} else {
seen.set(key, c.id);
}
}
}