@transitrix/diagrams 1.8.13 → 1.8.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/activities/validate.js +9 -1
- package/dist/blocks/index.d.ts +5 -4
- package/dist/blocks/index.js +3 -2
- package/dist/blocks/layout.d.ts +8 -1
- package/dist/blocks/layout.js +57 -0
- package/dist/blocks/templates/index.d.ts +9 -0
- package/dist/blocks/templates/index.js +11 -0
- package/dist/blocks/templates/raci.d.ts +9 -0
- package/dist/blocks/templates/raci.js +24 -0
- package/dist/blocks/types.d.ts +58 -0
- package/dist/blocks/validate.d.ts +31 -1
- package/dist/blocks/validate.js +127 -0
- package/dist/capability-map/validate.js +41 -0
- package/dist/fgca/parse-canonical.js +8 -0
- package/dist/repo-validate/check-element-hygiene.d.ts +8 -0
- package/dist/repo-validate/check-element-hygiene.js +211 -0
- package/dist/repo-validate/check-strategy-chain.d.ts +8 -0
- package/dist/repo-validate/check-strategy-chain.js +491 -0
- package/dist/repo-validate/types.d.ts +14 -1
- package/dist/repo-validate/types.js +22 -3
- package/dist/repo-validate/validate-repo.d.ts +3 -2
- package/dist/repo-validate/validate-repo.js +16 -4
- package/dist/webview/render-blocks.d.ts +23 -1
- package/dist/webview/render-blocks.js +100 -2
- package/package.json +1 -1
- package/src/activities/validate.ts +9 -1
- package/src/blocks/index.ts +16 -2
- package/src/blocks/layout.ts +70 -0
- package/src/blocks/templates/index.ts +13 -0
- package/src/blocks/templates/raci.ts +28 -0
- package/src/blocks/types.ts +67 -0
- package/src/blocks/validate.ts +157 -1
- package/src/capability-map/validate.ts +40 -0
- package/src/fgca/parse-canonical.ts +8 -0
- package/src/repo-validate/check-element-hygiene.ts +236 -0
- package/src/repo-validate/check-strategy-chain.ts +528 -0
- package/src/repo-validate/types.ts +36 -4
- package/src/repo-validate/validate-repo.ts +16 -4
- package/src/webview/render-blocks.ts +159 -2
|
@@ -12,14 +12,25 @@
|
|
|
12
12
|
* the shared theme CSS embedded in a `<style>` element and a simple optional
|
|
13
13
|
* title `<text>`.
|
|
14
14
|
*/
|
|
15
|
-
import { layoutNestedBlocks } from '../blocks/layout.js';
|
|
16
|
-
import type {
|
|
15
|
+
import { layoutNestedBlocks, layoutGrid } from '../blocks/layout.js';
|
|
16
|
+
import type {
|
|
17
|
+
BlocksFile,
|
|
18
|
+
BlocksLayout,
|
|
19
|
+
BlocksLayoutOptions,
|
|
20
|
+
GridFile,
|
|
21
|
+
GridLayout,
|
|
22
|
+
GridLayoutOptions,
|
|
23
|
+
LaidOutBlock,
|
|
24
|
+
} from '../blocks/types.js';
|
|
17
25
|
import { parseNodeSizePreset, resolveBlocksLeafSize, type NodeSizePreset } from '../node-size-presets.js';
|
|
18
26
|
import { generateSvgEmbedCss, type ThemeId } from '../theme/index.js';
|
|
19
27
|
import {
|
|
28
|
+
CHAR_W_PRIMARY,
|
|
20
29
|
emitCenteredTextSvg,
|
|
21
30
|
layoutHeaderBlockText,
|
|
22
31
|
layoutLeafBlockText,
|
|
32
|
+
maxCharsForInnerWidth,
|
|
33
|
+
wrapWords,
|
|
23
34
|
} from './entity-text-layout.js';
|
|
24
35
|
import { escXml } from './render-util.js';
|
|
25
36
|
import { ENTITY_NODE_RX } from './notation-style.js';
|
|
@@ -141,3 +152,149 @@ export function renderBlocksSvg(doc: BlocksFile, options: RenderBlocksOptions =
|
|
|
141
152
|
|
|
142
153
|
return renderBlocksLayoutSvg(layout, { title: titleSvg, embedCssTheme: 'transitrix' });
|
|
143
154
|
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Matrix subset (08-blocks.md §4a) — first cut: a single-layer rectangular
|
|
158
|
+
* `grid:` document (the RACI-style matrix case) rendered as a plain
|
|
159
|
+
* HTML/CSS-table-like SVG grid. Layers, arbitrary
|
|
160
|
+
* (non-rectangular) cell sets, and nested sub-grids belong to the general
|
|
161
|
+
* layered-grid superset, which is still in design upstream (methodology) and
|
|
162
|
+
* out of scope here — see 08-blocks.md §4a / §8.
|
|
163
|
+
*/
|
|
164
|
+
const GRID_CELL_PAD_X = 8;
|
|
165
|
+
const GRID_LINE_HEIGHT = 15;
|
|
166
|
+
const GRID_EMBED_CSS = `
|
|
167
|
+
.blocks-grid-border { fill: none; stroke: var(--ts-border, #cbd5e1); }`;
|
|
168
|
+
|
|
169
|
+
function centeredGridCellTextSvg(
|
|
170
|
+
lines: string[],
|
|
171
|
+
cls: string,
|
|
172
|
+
cx: number,
|
|
173
|
+
cellTop: number,
|
|
174
|
+
cellHeight: number,
|
|
175
|
+
): string {
|
|
176
|
+
const ls = lines.length > 0 ? lines : [''];
|
|
177
|
+
const firstY = cellTop + cellHeight / 2 - ((ls.length - 1) / 2) * GRID_LINE_HEIGHT;
|
|
178
|
+
const tspans = ls
|
|
179
|
+
.map((ln, i) => `<tspan x="${cx}" y="${firstY + i * GRID_LINE_HEIGHT}">${escXml(ln)}</tspan>`)
|
|
180
|
+
.join('');
|
|
181
|
+
return `<text class="${cls}" text-anchor="middle" dominant-baseline="central">${tspans}</text>`;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Emit the grid body (headers, cells, grid lines) at the given origin offset.
|
|
186
|
+
* Shared by the host-neutral wrapper below; VS Code's blocks preview wraps
|
|
187
|
+
* this the same way it wraps {@link renderBlocksLayoutSvg} for the tree form.
|
|
188
|
+
*/
|
|
189
|
+
export function renderGridBody(layout: GridLayout, ox: number, oy: number): string {
|
|
190
|
+
const tw = layout.bounds.width;
|
|
191
|
+
const th = layout.bounds.height;
|
|
192
|
+
const parts: string[] = [];
|
|
193
|
+
|
|
194
|
+
parts.push(`<rect class="diagram-node level-0" x="${ox}" y="${oy}" width="${tw}" height="${th}" stroke="none"/>`);
|
|
195
|
+
|
|
196
|
+
// Corner cell (above the row headers, left of the column headers).
|
|
197
|
+
parts.push(
|
|
198
|
+
`<rect class="diagram-node level-1" x="${ox}" y="${oy}" width="${layout.rowHeaderWidth}" height="${layout.headerHeight}" stroke="none"/>`,
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
for (const col of layout.columns) {
|
|
202
|
+
const x = col.x + ox;
|
|
203
|
+
parts.push(
|
|
204
|
+
`<rect class="diagram-node level-1" x="${x}" y="${oy}" width="${col.width}" height="${layout.headerHeight}" stroke="none"/>`,
|
|
205
|
+
);
|
|
206
|
+
const maxChars = maxCharsForInnerWidth(col.width - GRID_CELL_PAD_X * 2, CHAR_W_PRIMARY);
|
|
207
|
+
const lines = wrapWords(col.name, maxChars, 2);
|
|
208
|
+
parts.push(centeredGridCellTextSvg(lines, 'text-header', x + col.width / 2, oy, layout.headerHeight));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
for (const row of layout.rows) {
|
|
212
|
+
const y = row.y + oy;
|
|
213
|
+
parts.push(
|
|
214
|
+
`<rect class="diagram-node level-2" x="${ox}" y="${y}" width="${layout.rowHeaderWidth}" height="${row.height}" stroke="none"/>`,
|
|
215
|
+
);
|
|
216
|
+
const maxChars = maxCharsForInnerWidth(layout.rowHeaderWidth - GRID_CELL_PAD_X * 2, CHAR_W_PRIMARY);
|
|
217
|
+
const lines = wrapWords(row.name, maxChars, 2);
|
|
218
|
+
parts.push(centeredGridCellTextSvg(lines, 'text-primary', ox + layout.rowHeaderWidth / 2, y, row.height));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
for (const cell of layout.cells) {
|
|
222
|
+
if (cell.value === undefined) continue;
|
|
223
|
+
const cx = cell.x + ox + cell.width / 2;
|
|
224
|
+
const cy = cell.y + oy + cell.height / 2;
|
|
225
|
+
parts.push(
|
|
226
|
+
`<text class="text-secondary" x="${cx}" y="${cy}" text-anchor="middle" dominant-baseline="central">${escXml(cell.value)}</text>`,
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const gridX1 = ox;
|
|
231
|
+
const gridX2 = ox + tw;
|
|
232
|
+
const gridY1 = oy;
|
|
233
|
+
const gridY2 = oy + th;
|
|
234
|
+
|
|
235
|
+
const headerBottomY = oy + layout.headerHeight;
|
|
236
|
+
parts.push(`<line class="diagram-edge" x1="${gridX1}" y1="${headerBottomY}" x2="${gridX2}" y2="${headerBottomY}"/>`);
|
|
237
|
+
for (const row of layout.rows) {
|
|
238
|
+
const rowBottomY = oy + row.y + row.height;
|
|
239
|
+
parts.push(`<line class="diagram-edge" x1="${gridX1}" y1="${rowBottomY}" x2="${gridX2}" y2="${rowBottomY}"/>`);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const rowHeaderLineX = ox + layout.rowHeaderWidth;
|
|
243
|
+
parts.push(`<line class="diagram-edge" x1="${rowHeaderLineX}" y1="${gridY1}" x2="${rowHeaderLineX}" y2="${gridY2}"/>`);
|
|
244
|
+
for (const col of layout.columns) {
|
|
245
|
+
const colLineX = ox + col.x + col.width;
|
|
246
|
+
parts.push(`<line class="diagram-edge" x1="${colLineX}" y1="${gridY1}" x2="${colLineX}" y2="${gridY2}"/>`);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
parts.push(`<rect class="blocks-grid-border" x="${ox}" y="${oy}" width="${tw}" height="${th}"/>`);
|
|
250
|
+
|
|
251
|
+
return parts.join('\n');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export interface RenderGridLayoutOptions {
|
|
255
|
+
/** Extra vertical space reserved at the top of the canvas (e.g. for a title block). */
|
|
256
|
+
topInset?: number;
|
|
257
|
+
/** Raw SVG injected immediately after the opening tag — a header line or a full title block. */
|
|
258
|
+
title?: string;
|
|
259
|
+
/** When set, the theme CSS is embedded as `<style>` so the SVG is self-contained. */
|
|
260
|
+
embedCssTheme?: ThemeId;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/** The single grid (matrix subset) SVG emitter shared by every host. */
|
|
264
|
+
export function renderGridLayoutSvg(layout: GridLayout, options: RenderGridLayoutOptions = {}): string {
|
|
265
|
+
const { topInset = 0, title = '', embedCssTheme } = options;
|
|
266
|
+
|
|
267
|
+
const w = layout.bounds.width + PAD * 2;
|
|
268
|
+
const h = layout.bounds.height + PAD * 2 + topInset;
|
|
269
|
+
const ox = PAD;
|
|
270
|
+
const oy = PAD + topInset;
|
|
271
|
+
|
|
272
|
+
const body = renderGridBody(layout, ox, oy);
|
|
273
|
+
const styleLine = embedCssTheme ? `\n<style>${generateSvgEmbedCss(embedCssTheme)}${GRID_EMBED_CSS}</style>` : '';
|
|
274
|
+
|
|
275
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}" viewBox="0 0 ${w} ${h}">${styleLine}
|
|
276
|
+
${title}
|
|
277
|
+
${body}
|
|
278
|
+
</svg>`;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export interface RenderGridOptions {
|
|
282
|
+
title?: string;
|
|
283
|
+
layoutOptions?: GridLayoutOptions;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/** Host-neutral grid (matrix subset) renderer (IntelliJ/UI). */
|
|
287
|
+
export function renderGridSvg(doc: GridFile, options: RenderGridOptions = {}): string {
|
|
288
|
+
const { title = '', layoutOptions } = options;
|
|
289
|
+
const layout = layoutGrid(doc, layoutOptions);
|
|
290
|
+
|
|
291
|
+
if (layout.columns.length === 0 || layout.rows.length === 0) {
|
|
292
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" viewBox="0 0 0 0"></svg>`;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const titleSvg = title
|
|
296
|
+
? `<text class="text-header" x="${PAD}" y="${PAD - 6}">${escXml(`Nested Blocks — ${title}`)}</text>`
|
|
297
|
+
: '';
|
|
298
|
+
|
|
299
|
+
return renderGridLayoutSvg(layout, { title: titleSvg, embedCssTheme: 'transitrix' });
|
|
300
|
+
}
|