@oml/markdown 0.11.0 → 0.13.0
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/out/md/md-execution.d.ts +16 -0
- package/out/md/md-executor.d.ts +1 -0
- package/out/md/md-executor.js +219 -35
- package/out/md/md-executor.js.map +1 -1
- package/out/renderers/diagram-renderer.js +160 -1
- package/out/renderers/diagram-renderer.js.map +1 -1
- package/out/renderers/graph-renderer.js +452 -18
- package/out/renderers/graph-renderer.js.map +1 -1
- package/out/renderers/matrix-renderer.d.ts +0 -2
- package/out/renderers/matrix-renderer.js +45 -40
- package/out/renderers/matrix-renderer.js.map +1 -1
- package/out/renderers/renderer.d.ts +4 -1
- package/out/renderers/renderer.js +98 -0
- package/out/renderers/renderer.js.map +1 -1
- package/out/renderers/table-renderer.d.ts +4 -2
- package/out/renderers/table-renderer.js +104 -38
- package/out/renderers/table-renderer.js.map +1 -1
- package/out/renderers/types.d.ts +16 -0
- package/out/renderers/wikilink-utils.d.ts +1 -0
- package/out/renderers/wikilink-utils.js +60 -32
- package/out/renderers/wikilink-utils.js.map +1 -1
- package/out/static/browser-runtime.bundle.js +7452 -1297
- package/out/static/browser-runtime.bundle.js.map +4 -4
- package/out/static/browser-runtime.js +15 -2
- package/out/static/browser-runtime.js.map +1 -1
- package/package.json +2 -2
- package/src/md/md-execution.ts +20 -0
- package/src/md/md-executor.ts +268 -40
- package/src/renderers/diagram-renderer.ts +167 -1
- package/src/renderers/graph-renderer.ts +512 -12
- package/src/renderers/matrix-renderer.ts +57 -44
- package/src/renderers/renderer.ts +105 -1
- package/src/renderers/table-renderer.ts +151 -39
- package/src/renderers/types.ts +20 -0
- package/src/renderers/wikilink-utils.ts +66 -31
- package/src/static/browser-runtime.ts +20 -2
- package/src/static/markdown-webview.css +44 -15
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
// Copyright (c) 2026 Modelware. All rights reserved.
|
|
2
2
|
|
|
3
3
|
import { QueryMarkdownBlockRenderer } from './renderer.js';
|
|
4
|
-
import type { MdBlockExecutionResult } from './types.js';
|
|
5
|
-
import { appendTokenizedValueParts, createWikiLinkElement, isIriValue, shortLabelFromIri } from './wikilink-utils.js';
|
|
4
|
+
import type { MdBlockExecutionResult, MdTableCell, MdTableCellValue } from './types.js';
|
|
6
5
|
|
|
7
6
|
type MatrixStyleRuleKind = 'row' | 'column' | 'cell' | 'header';
|
|
8
7
|
type MatrixStyleRuleTarget = 'cell' | 'value';
|
|
@@ -44,13 +43,15 @@ type MatrixSelectorContext =
|
|
|
44
43
|
| { kind: 'header'; context: MatrixHeaderContext };
|
|
45
44
|
|
|
46
45
|
type MatrixCellRecord = {
|
|
47
|
-
|
|
46
|
+
cell: MdTableCell;
|
|
48
47
|
};
|
|
49
48
|
|
|
50
49
|
type MatrixModel = {
|
|
51
50
|
rowKeys: string[];
|
|
52
51
|
columnKeys: string[];
|
|
53
52
|
cells: Map<string, MatrixCellRecord>;
|
|
53
|
+
rowHeaders: Map<string, MdTableCell>;
|
|
54
|
+
columnHeaders: Map<string, MdTableCell>;
|
|
54
55
|
};
|
|
55
56
|
|
|
56
57
|
export class MatrixMarkdownBlockRenderer extends QueryMarkdownBlockRenderer {
|
|
@@ -79,7 +80,7 @@ export class MatrixMarkdownBlockRenderer extends QueryMarkdownBlockRenderer {
|
|
|
79
80
|
|
|
80
81
|
const stylesheet = compileMatrixStylesheet(result.options);
|
|
81
82
|
const rowColumnLabel = extractRowColumnLabel(result.options);
|
|
82
|
-
const model = this.buildMatrixModel(payloadRows, rowIndex, columnIndex, valueIndex);
|
|
83
|
+
const model = this.buildMatrixModel(payloadRows, result.payload?.rowsTyped ?? [], rowIndex, columnIndex, valueIndex);
|
|
83
84
|
container.appendChild(this.renderMatrix(model, stylesheet, rowColumnLabel));
|
|
84
85
|
return container;
|
|
85
86
|
}
|
|
@@ -167,7 +168,8 @@ export class MatrixMarkdownBlockRenderer extends QueryMarkdownBlockRenderer {
|
|
|
167
168
|
for (const [columnIndex, columnName] of visibleColumns.entries()) {
|
|
168
169
|
const th = document.createElement('div');
|
|
169
170
|
th.className = 'table-header-cell';
|
|
170
|
-
const label = this.
|
|
171
|
+
const label = this.renderCellValue(columnName, model.columnHeaders.get(columnName));
|
|
172
|
+
label.style.fontWeight = '400';
|
|
171
173
|
th.appendChild(label);
|
|
172
174
|
this.applyStylesheet(th, undefined, stylesheet, [
|
|
173
175
|
{ kind: 'column', context: { index: columnIndex, name: columnName } }
|
|
@@ -183,7 +185,7 @@ export class MatrixMarkdownBlockRenderer extends QueryMarkdownBlockRenderer {
|
|
|
183
185
|
|
|
184
186
|
const rowHeaderCell = document.createElement('div');
|
|
185
187
|
rowHeaderCell.className = 'table-cell';
|
|
186
|
-
const rowHeaderValue = this.
|
|
188
|
+
const rowHeaderValue = this.renderCellValue(rowName, model.rowHeaders.get(rowName));
|
|
187
189
|
rowHeaderCell.appendChild(rowHeaderValue);
|
|
188
190
|
const rowContext: MatrixRowContext = { index: rowCounter, name: rowName };
|
|
189
191
|
this.applyStylesheet(rowHeaderCell, rowHeaderValue, stylesheet, [
|
|
@@ -195,13 +197,13 @@ export class MatrixMarkdownBlockRenderer extends QueryMarkdownBlockRenderer {
|
|
|
195
197
|
for (const [columnIndex, columnName] of visibleColumns.entries()) {
|
|
196
198
|
const key = buildMatrixKey(rowName, columnName);
|
|
197
199
|
const record = model.cells.get(key);
|
|
198
|
-
const
|
|
199
|
-
const displayValue =
|
|
200
|
+
const recordCell = record?.cell;
|
|
201
|
+
const displayValue = this.formatCellDisplayText(recordCell?.value ?? '', recordCell);
|
|
200
202
|
const columnContext: MatrixColumnContext = { index: columnIndex, name: columnName };
|
|
201
203
|
|
|
202
204
|
const td = document.createElement('div');
|
|
203
205
|
td.className = 'table-cell';
|
|
204
|
-
const valueElement = this.
|
|
206
|
+
const valueElement = this.renderCellValue(recordCell?.value ?? '', recordCell);
|
|
205
207
|
td.appendChild(valueElement);
|
|
206
208
|
|
|
207
209
|
const cellContext: MatrixCellContext = {
|
|
@@ -241,61 +243,49 @@ export class MatrixMarkdownBlockRenderer extends QueryMarkdownBlockRenderer {
|
|
|
241
243
|
return columns.join(' ');
|
|
242
244
|
}
|
|
243
245
|
|
|
244
|
-
private buildMatrixModel(
|
|
246
|
+
private buildMatrixModel(
|
|
247
|
+
rows: string[][],
|
|
248
|
+
rowsTyped: MdTableCell[][],
|
|
249
|
+
rowIndex: number,
|
|
250
|
+
columnIndex: number,
|
|
251
|
+
valueIndex: number
|
|
252
|
+
): MatrixModel {
|
|
245
253
|
const rowKeys: string[] = [];
|
|
246
254
|
const columnKeys: string[] = [];
|
|
247
255
|
const seenRows = new Set<string>();
|
|
248
256
|
const seenColumns = new Set<string>();
|
|
249
257
|
const cells = new Map<string, MatrixCellRecord>();
|
|
258
|
+
const rowHeaders = new Map<string, MdTableCell>();
|
|
259
|
+
const columnHeaders = new Map<string, MdTableCell>();
|
|
250
260
|
|
|
251
|
-
for (
|
|
261
|
+
for (let index = 0; index < rows.length; index += 1) {
|
|
262
|
+
const row = rows[index];
|
|
263
|
+
const typedRow = rowsTyped[index] ?? [];
|
|
252
264
|
const rowKey = row[rowIndex] ?? '';
|
|
253
265
|
const columnKey = row[columnIndex] ?? '';
|
|
254
|
-
const
|
|
266
|
+
const rowCell = typedRow[rowIndex] ?? literalCell(rowKey);
|
|
267
|
+
const columnCell = typedRow[columnIndex] ?? literalCell(columnKey);
|
|
268
|
+
const valueCell = typedRow[valueIndex] ?? literalCell(row[valueIndex] ?? '');
|
|
255
269
|
if (!rowKey || !columnKey) {
|
|
256
270
|
continue;
|
|
257
271
|
}
|
|
258
272
|
if (!seenRows.has(rowKey)) {
|
|
259
273
|
seenRows.add(rowKey);
|
|
260
274
|
rowKeys.push(rowKey);
|
|
275
|
+
rowHeaders.set(rowKey, rowCell);
|
|
261
276
|
}
|
|
262
277
|
if (!seenColumns.has(columnKey)) {
|
|
263
278
|
seenColumns.add(columnKey);
|
|
264
279
|
columnKeys.push(columnKey);
|
|
280
|
+
columnHeaders.set(columnKey, columnCell);
|
|
265
281
|
}
|
|
266
282
|
const key = buildMatrixKey(rowKey, columnKey);
|
|
267
|
-
const record = cells.get(key) ?? { values:
|
|
268
|
-
record.values
|
|
283
|
+
const record = cells.get(key) ?? { cell: { ...valueCell, values: valueCell.values.slice() } };
|
|
284
|
+
mergeCellValues(record.cell, valueCell.values);
|
|
269
285
|
cells.set(key, record);
|
|
270
286
|
}
|
|
271
287
|
|
|
272
|
-
return { rowKeys, columnKeys, cells };
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
private renderValueParts(values: string[]): HTMLElement {
|
|
276
|
-
const value = document.createElement('span');
|
|
277
|
-
value.className = 'table-value';
|
|
278
|
-
const normalized = values.filter((entry) => entry.length > 0);
|
|
279
|
-
if (normalized.length === 0) {
|
|
280
|
-
value.textContent = '';
|
|
281
|
-
return value;
|
|
282
|
-
}
|
|
283
|
-
for (const rawPart of normalized) {
|
|
284
|
-
appendTokenizedValueParts(value, rawPart, 'table-value-part');
|
|
285
|
-
}
|
|
286
|
-
return value;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
private renderHeaderLabel(raw: string): HTMLElement {
|
|
290
|
-
const label = document.createElement('span');
|
|
291
|
-
label.className = 'table-header-label';
|
|
292
|
-
label.style.fontWeight = '400';
|
|
293
|
-
if (!isIriValue(raw)) {
|
|
294
|
-
label.textContent = raw;
|
|
295
|
-
return label;
|
|
296
|
-
}
|
|
297
|
-
label.appendChild(createWikiLinkElement(raw, shortLabelFromIri(raw)));
|
|
298
|
-
return label;
|
|
288
|
+
return { rowKeys, columnKeys, cells, rowHeaders, columnHeaders };
|
|
299
289
|
}
|
|
300
290
|
|
|
301
291
|
private applyStylesheet(
|
|
@@ -365,7 +355,7 @@ export class MatrixMarkdownBlockRenderer extends QueryMarkdownBlockRenderer {
|
|
|
365
355
|
if (!record) {
|
|
366
356
|
continue;
|
|
367
357
|
}
|
|
368
|
-
const cellText = record.
|
|
358
|
+
const cellText = this.formatCellDisplayText(record.cell.value, record.cell).toLowerCase();
|
|
369
359
|
if (cellText.includes(search)) {
|
|
370
360
|
matchedRows.add(rowName);
|
|
371
361
|
matchedColumns.add(columnName);
|
|
@@ -400,10 +390,11 @@ export class MatrixMarkdownBlockRenderer extends QueryMarkdownBlockRenderer {
|
|
|
400
390
|
const lines: string[] = [];
|
|
401
391
|
lines.push([escapeCell(rowColumnLabel), ...visibleColumns.map(escapeCell)].join(','));
|
|
402
392
|
for (const rowName of visibleRows) {
|
|
403
|
-
const
|
|
393
|
+
const rowHeader = model.rowHeaders.get(rowName);
|
|
394
|
+
const row: string[] = [escapeCell(this.formatCellDisplayText(rowHeader?.value ?? rowName, rowHeader))];
|
|
404
395
|
for (const columnName of visibleColumns) {
|
|
405
396
|
const record = model.cells.get(buildMatrixKey(rowName, columnName));
|
|
406
|
-
row.push(escapeCell((record?.
|
|
397
|
+
row.push(escapeCell(this.formatCellDisplayText(record?.cell.value ?? '', record?.cell)));
|
|
407
398
|
}
|
|
408
399
|
lines.push(row.join(','));
|
|
409
400
|
}
|
|
@@ -424,6 +415,28 @@ function buildMatrixKey(rowKey: string, columnKey: string): string {
|
|
|
424
415
|
return `${rowKey}\u0000${columnKey}`;
|
|
425
416
|
}
|
|
426
417
|
|
|
418
|
+
function literalCell(value: string): MdTableCell {
|
|
419
|
+
return { kind: 'literal', value, values: [{ kind: 'literal', value }] };
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function mergeCellValues(target: MdTableCell, additions: ReadonlyArray<MdTableCellValue>): void {
|
|
423
|
+
const existing = new Set(target.values.map((value) => `${value.kind}\u0000${value.value}`));
|
|
424
|
+
for (const value of additions) {
|
|
425
|
+
const key = `${value.kind}\u0000${value.value}`;
|
|
426
|
+
if (existing.has(key)) {
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
existing.add(key);
|
|
430
|
+
target.values.push(value);
|
|
431
|
+
}
|
|
432
|
+
target.value = target.values.map((value) => {
|
|
433
|
+
if (value.kind === 'bnode') {
|
|
434
|
+
return `_:${value.value}`;
|
|
435
|
+
}
|
|
436
|
+
return value.value;
|
|
437
|
+
}).join(', ');
|
|
438
|
+
}
|
|
439
|
+
|
|
427
440
|
function createDownloadButton(): HTMLButtonElement {
|
|
428
441
|
const downloadButton = document.createElement('button');
|
|
429
442
|
downloadButton.className = 'tree-download-btn';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Copyright (c) 2026 Modelware. All rights reserved.
|
|
2
2
|
|
|
3
|
-
import type { MdBlockExecutionResult } from './types.js';
|
|
3
|
+
import type { MdBlockExecutionResult, MdTableCell, MdTableCellValue } from './types.js';
|
|
4
|
+
import { appendInlineValue, createWikiLinkElement, isUrlValue, shortLabelFromIri } from './wikilink-utils.js';
|
|
4
5
|
|
|
5
6
|
export interface MarkdownBlockRenderer {
|
|
6
7
|
canRender(result: MdBlockExecutionResult): boolean;
|
|
@@ -119,6 +120,43 @@ export abstract class BaseMarkdownBlockRenderer implements MarkdownBlockRenderer
|
|
|
119
120
|
}
|
|
120
121
|
|
|
121
122
|
export abstract class QueryMarkdownBlockRenderer extends BaseMarkdownBlockRenderer {
|
|
123
|
+
protected renderCellValue(raw: string, typedValue?: MdTableCell): HTMLElement {
|
|
124
|
+
const value = document.createElement('span');
|
|
125
|
+
value.className = 'table-value';
|
|
126
|
+
const entries = typedValue?.values ?? [];
|
|
127
|
+
if (entries.length > 0) {
|
|
128
|
+
entries.forEach((entry, index) => {
|
|
129
|
+
if (index > 0) {
|
|
130
|
+
value.appendChild(document.createTextNode(' '));
|
|
131
|
+
}
|
|
132
|
+
value.appendChild(this.renderValueToken(entry));
|
|
133
|
+
});
|
|
134
|
+
return value;
|
|
135
|
+
}
|
|
136
|
+
const display = this.formatCellDisplayText(raw, typedValue);
|
|
137
|
+
const fragment = document.createElement('span');
|
|
138
|
+
fragment.className = 'table-value-part';
|
|
139
|
+
fragment.dataset.value = display;
|
|
140
|
+
appendInlineValue(fragment, display);
|
|
141
|
+
value.appendChild(fragment);
|
|
142
|
+
return value;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
protected formatCellDisplayText(raw: string, typedValue?: MdTableCell): string {
|
|
146
|
+
if (typedValue?.values?.length) {
|
|
147
|
+
return typedValue.values.map((entry) => {
|
|
148
|
+
if (entry.kind === 'iri') {
|
|
149
|
+
return shortLabelFromIri(entry.value);
|
|
150
|
+
}
|
|
151
|
+
if (entry.kind === 'bnode') {
|
|
152
|
+
return `_:${entry.value}`;
|
|
153
|
+
}
|
|
154
|
+
return entry.value;
|
|
155
|
+
}).join(' ');
|
|
156
|
+
}
|
|
157
|
+
return raw;
|
|
158
|
+
}
|
|
159
|
+
|
|
122
160
|
protected getBlockSource(result: MdBlockExecutionResult): string | undefined {
|
|
123
161
|
return result.blockSource;
|
|
124
162
|
}
|
|
@@ -130,6 +168,33 @@ export abstract class QueryMarkdownBlockRenderer extends BaseMarkdownBlockRender
|
|
|
130
168
|
protected getBlockRange(result: MdBlockExecutionResult): { start?: number; end?: number } {
|
|
131
169
|
return { start: result.blockLineStart, end: result.blockLineEnd };
|
|
132
170
|
}
|
|
171
|
+
|
|
172
|
+
private renderValueToken(entry: MdTableCellValue): HTMLElement {
|
|
173
|
+
const fragment = document.createElement('span');
|
|
174
|
+
fragment.className = 'table-value-part';
|
|
175
|
+
fragment.dataset.value = entry.value;
|
|
176
|
+
if (entry.kind === 'iri') {
|
|
177
|
+
if (isBuiltInOntologyIri(entry.value)) {
|
|
178
|
+
appendInlineValue(fragment, shortLabelFromIri(entry.value));
|
|
179
|
+
} else {
|
|
180
|
+
fragment.appendChild(createWikiLinkElement(entry.value, shortLabelFromIri(entry.value)));
|
|
181
|
+
}
|
|
182
|
+
return fragment;
|
|
183
|
+
}
|
|
184
|
+
if (entry.kind === 'bnode') {
|
|
185
|
+
appendInlineValue(fragment, `_:${entry.value}`);
|
|
186
|
+
return fragment;
|
|
187
|
+
}
|
|
188
|
+
if (isUrlValue(entry.value)) {
|
|
189
|
+
const link = document.createElement('a');
|
|
190
|
+
link.href = entry.value;
|
|
191
|
+
link.textContent = entry.value;
|
|
192
|
+
fragment.appendChild(link);
|
|
193
|
+
return fragment;
|
|
194
|
+
}
|
|
195
|
+
appendInlineValue(fragment, entry.value);
|
|
196
|
+
return fragment;
|
|
197
|
+
}
|
|
133
198
|
}
|
|
134
199
|
|
|
135
200
|
export abstract class CanvasMarkdownBlockRenderer extends QueryMarkdownBlockRenderer {
|
|
@@ -148,3 +213,42 @@ export abstract class CanvasMarkdownBlockRenderer extends QueryMarkdownBlockRend
|
|
|
148
213
|
return container;
|
|
149
214
|
}
|
|
150
215
|
}
|
|
216
|
+
|
|
217
|
+
const BUILT_IN_ONTOLOGY_IRIS = new Set([
|
|
218
|
+
'http://opencaesar.io/oml',
|
|
219
|
+
'http://www.w3.org/2001/XMLSchema',
|
|
220
|
+
'http://www.w3.org/1999/02/22-rdf-syntax-ns',
|
|
221
|
+
'http://www.w3.org/2000/01/rdf-schema',
|
|
222
|
+
'http://www.w3.org/2002/07/owl',
|
|
223
|
+
'http://www.w3.org/2003/11/swrl',
|
|
224
|
+
'http://www.w3.org/2003/11/swrlb',
|
|
225
|
+
]);
|
|
226
|
+
|
|
227
|
+
function ontologyLookupKeyFromIri(value: string): string | undefined {
|
|
228
|
+
const iri = String(value ?? '').trim().replace(/^<|>$/g, '');
|
|
229
|
+
if (!iri || !/^[A-Za-z][A-Za-z0-9+.-]*:[^\s]+$/.test(iri)) {
|
|
230
|
+
return undefined;
|
|
231
|
+
}
|
|
232
|
+
const hashIndex = iri.indexOf('#');
|
|
233
|
+
if (hashIndex >= 0) {
|
|
234
|
+
return normalizeOntologyLookupKey(iri.slice(0, hashIndex + 1));
|
|
235
|
+
}
|
|
236
|
+
const schemeIndex = iri.indexOf('://');
|
|
237
|
+
const slashIndex = iri.lastIndexOf('/');
|
|
238
|
+
if (slashIndex > schemeIndex + 2) {
|
|
239
|
+
return normalizeOntologyLookupKey(iri.slice(0, slashIndex + 1));
|
|
240
|
+
}
|
|
241
|
+
return normalizeOntologyLookupKey(iri);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function normalizeOntologyLookupKey(value: string): string {
|
|
245
|
+
return value.trim().replace(/^<|>$/g, '').replace(/[\/#]+$/, '');
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function isBuiltInOntologyIri(iri: string): boolean {
|
|
249
|
+
const key = ontologyLookupKeyFromIri(iri);
|
|
250
|
+
if (!key) {
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
return BUILT_IN_ONTOLOGY_IRIS.has(normalizeOntologyLookupKey(key));
|
|
254
|
+
}
|