@diagrammo/dgmo 0.2.26 → 0.2.28
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/.claude/skills/dgmo-chart/SKILL.md +107 -0
- package/.claude/skills/dgmo-flowchart/SKILL.md +61 -0
- package/.claude/skills/dgmo-generate/SKILL.md +58 -0
- package/.claude/skills/dgmo-sequence/SKILL.md +83 -0
- package/.cursorrules +117 -0
- package/.github/copilot-instructions.md +117 -0
- package/.windsurfrules +117 -0
- package/README.md +10 -3
- package/dist/cli.cjs +116 -108
- package/dist/index.cjs +563 -356
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +39 -24
- package/dist/index.d.ts +39 -24
- package/dist/index.js +560 -355
- package/dist/index.js.map +1 -1
- package/docs/ai-integration.md +125 -0
- package/docs/language-reference.md +784 -0
- package/package.json +10 -3
- package/src/c4/parser.ts +90 -74
- package/src/c4/renderer.ts +13 -12
- package/src/c4/types.ts +6 -4
- package/src/chart.ts +3 -2
- package/src/class/parser.ts +2 -10
- package/src/class/types.ts +1 -1
- package/src/cli.ts +135 -19
- package/src/d3.ts +1 -1
- package/src/dgmo-mermaid.ts +1 -1
- package/src/dgmo-router.ts +1 -1
- package/src/echarts.ts +33 -13
- package/src/er/parser.ts +34 -43
- package/src/er/types.ts +1 -1
- package/src/graph/flowchart-parser.ts +2 -25
- package/src/graph/types.ts +1 -1
- package/src/index.ts +5 -0
- package/src/initiative-status/parser.ts +57 -11
- package/src/initiative-status/types.ts +1 -1
- package/src/kanban/parser.ts +32 -53
- package/src/kanban/renderer.ts +9 -8
- package/src/kanban/types.ts +6 -14
- package/src/org/parser.ts +47 -87
- package/src/org/resolver.ts +11 -12
- package/src/sequence/parser.ts +97 -15
- package/src/sequence/renderer.ts +62 -69
- package/src/utils/arrows.ts +75 -0
- package/src/utils/inline-markdown.ts +75 -0
- package/src/utils/parsing.ts +67 -0
- package/src/utils/tag-groups.ts +76 -0
package/dist/index.js
CHANGED
|
@@ -1527,6 +1527,96 @@ var init_participant_inference = __esm({
|
|
|
1527
1527
|
}
|
|
1528
1528
|
});
|
|
1529
1529
|
|
|
1530
|
+
// src/utils/arrows.ts
|
|
1531
|
+
function parseArrow(line7) {
|
|
1532
|
+
const patterns = [
|
|
1533
|
+
{ re: BIDI_SYNC_LABELED_RE, async: false, bidirectional: true },
|
|
1534
|
+
{ re: BIDI_ASYNC_LABELED_RE, async: true, bidirectional: true },
|
|
1535
|
+
{ re: SYNC_LABELED_RE, async: false, bidirectional: false },
|
|
1536
|
+
{ re: ASYNC_LABELED_RE, async: true, bidirectional: false }
|
|
1537
|
+
];
|
|
1538
|
+
for (const { re, async: isAsync, bidirectional } of patterns) {
|
|
1539
|
+
const m = line7.match(re);
|
|
1540
|
+
if (!m) continue;
|
|
1541
|
+
const label = m[2].trim();
|
|
1542
|
+
if (!label) return null;
|
|
1543
|
+
for (const arrow of ARROW_CHARS) {
|
|
1544
|
+
if (label.includes(arrow)) {
|
|
1545
|
+
return {
|
|
1546
|
+
error: "Arrow characters (->, ~>) are not allowed inside labels"
|
|
1547
|
+
};
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
return {
|
|
1551
|
+
from: m[1],
|
|
1552
|
+
to: m[3],
|
|
1553
|
+
label,
|
|
1554
|
+
async: isAsync,
|
|
1555
|
+
bidirectional
|
|
1556
|
+
};
|
|
1557
|
+
}
|
|
1558
|
+
return null;
|
|
1559
|
+
}
|
|
1560
|
+
var BIDI_SYNC_LABELED_RE, BIDI_ASYNC_LABELED_RE, SYNC_LABELED_RE, ASYNC_LABELED_RE, ARROW_CHARS;
|
|
1561
|
+
var init_arrows = __esm({
|
|
1562
|
+
"src/utils/arrows.ts"() {
|
|
1563
|
+
"use strict";
|
|
1564
|
+
BIDI_SYNC_LABELED_RE = /^(\S+)\s+<-(.+)->\s+(\S+)$/;
|
|
1565
|
+
BIDI_ASYNC_LABELED_RE = /^(\S+)\s+<~(.+)~>\s+(\S+)$/;
|
|
1566
|
+
SYNC_LABELED_RE = /^(\S+)\s+-(.+)->\s+(\S+)$/;
|
|
1567
|
+
ASYNC_LABELED_RE = /^(\S+)\s+~(.+)~>\s+(\S+)$/;
|
|
1568
|
+
ARROW_CHARS = ["->", "~>", "<->", "<~>"];
|
|
1569
|
+
}
|
|
1570
|
+
});
|
|
1571
|
+
|
|
1572
|
+
// src/utils/parsing.ts
|
|
1573
|
+
function measureIndent(line7) {
|
|
1574
|
+
let indent = 0;
|
|
1575
|
+
for (const ch of line7) {
|
|
1576
|
+
if (ch === " ") indent++;
|
|
1577
|
+
else if (ch === " ") indent += 4;
|
|
1578
|
+
else break;
|
|
1579
|
+
}
|
|
1580
|
+
return indent;
|
|
1581
|
+
}
|
|
1582
|
+
function extractColor(label, palette) {
|
|
1583
|
+
const m = label.match(COLOR_SUFFIX_RE);
|
|
1584
|
+
if (!m) return { label };
|
|
1585
|
+
const colorName = m[1].trim();
|
|
1586
|
+
return {
|
|
1587
|
+
label: label.substring(0, m.index).trim(),
|
|
1588
|
+
color: resolveColor(colorName, palette)
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1591
|
+
function parsePipeMetadata(segments, aliasMap = /* @__PURE__ */ new Map()) {
|
|
1592
|
+
const metadata = {};
|
|
1593
|
+
for (let j = 1; j < segments.length; j++) {
|
|
1594
|
+
for (const part of segments[j].split(",")) {
|
|
1595
|
+
const trimmedPart = part.trim();
|
|
1596
|
+
if (!trimmedPart) continue;
|
|
1597
|
+
const colonIdx = trimmedPart.indexOf(":");
|
|
1598
|
+
if (colonIdx > 0) {
|
|
1599
|
+
const rawKey = trimmedPart.substring(0, colonIdx).trim().toLowerCase();
|
|
1600
|
+
const key = aliasMap.get(rawKey) ?? rawKey;
|
|
1601
|
+
const value = trimmedPart.substring(colonIdx + 1).trim();
|
|
1602
|
+
metadata[key] = value;
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
return metadata;
|
|
1607
|
+
}
|
|
1608
|
+
var COLOR_SUFFIX_RE, CHART_TYPE_RE, TITLE_RE, OPTION_RE;
|
|
1609
|
+
var init_parsing = __esm({
|
|
1610
|
+
"src/utils/parsing.ts"() {
|
|
1611
|
+
"use strict";
|
|
1612
|
+
init_colors();
|
|
1613
|
+
COLOR_SUFFIX_RE = /\(([^)]+)\)\s*$/;
|
|
1614
|
+
CHART_TYPE_RE = /^chart\s*:\s*(.+)/i;
|
|
1615
|
+
TITLE_RE = /^title\s*:\s*(.+)/i;
|
|
1616
|
+
OPTION_RE = /^([a-z][a-z0-9-]*)\s*:\s*(.+)$/i;
|
|
1617
|
+
}
|
|
1618
|
+
});
|
|
1619
|
+
|
|
1530
1620
|
// src/sequence/parser.ts
|
|
1531
1621
|
var parser_exports = {};
|
|
1532
1622
|
__export(parser_exports, {
|
|
@@ -1568,15 +1658,6 @@ function parseReturnLabel(rawLabel) {
|
|
|
1568
1658
|
}
|
|
1569
1659
|
return { label: rawLabel };
|
|
1570
1660
|
}
|
|
1571
|
-
function measureIndent(line7) {
|
|
1572
|
-
let indent = 0;
|
|
1573
|
-
for (const ch of line7) {
|
|
1574
|
-
if (ch === " ") indent++;
|
|
1575
|
-
else if (ch === " ") indent += 4;
|
|
1576
|
-
else break;
|
|
1577
|
-
}
|
|
1578
|
-
return indent;
|
|
1579
|
-
}
|
|
1580
1661
|
function parseSequenceDgmo(content) {
|
|
1581
1662
|
const result = {
|
|
1582
1663
|
title: null,
|
|
@@ -1798,6 +1879,86 @@ function parseSequenceDgmo(content) {
|
|
|
1798
1879
|
pushError(lineNumber, "Use ~> for async messages: A ~> B: message");
|
|
1799
1880
|
continue;
|
|
1800
1881
|
}
|
|
1882
|
+
const labeledArrow = parseArrow(trimmed);
|
|
1883
|
+
if (labeledArrow && "error" in labeledArrow) {
|
|
1884
|
+
pushError(lineNumber, labeledArrow.error);
|
|
1885
|
+
continue;
|
|
1886
|
+
}
|
|
1887
|
+
if (labeledArrow) {
|
|
1888
|
+
contentStarted = true;
|
|
1889
|
+
const { from, to, label, async: isAsync2, bidirectional } = labeledArrow;
|
|
1890
|
+
lastMsgFrom = from;
|
|
1891
|
+
const msg = {
|
|
1892
|
+
from,
|
|
1893
|
+
to,
|
|
1894
|
+
label,
|
|
1895
|
+
returnLabel: void 0,
|
|
1896
|
+
lineNumber,
|
|
1897
|
+
...isAsync2 ? { async: true } : {},
|
|
1898
|
+
...bidirectional ? { bidirectional: true } : {}
|
|
1899
|
+
};
|
|
1900
|
+
result.messages.push(msg);
|
|
1901
|
+
currentContainer().push(msg);
|
|
1902
|
+
if (!result.participants.some((p) => p.id === from)) {
|
|
1903
|
+
result.participants.push({
|
|
1904
|
+
id: from,
|
|
1905
|
+
label: from,
|
|
1906
|
+
type: inferParticipantType(from),
|
|
1907
|
+
lineNumber
|
|
1908
|
+
});
|
|
1909
|
+
}
|
|
1910
|
+
if (!result.participants.some((p) => p.id === to)) {
|
|
1911
|
+
result.participants.push({
|
|
1912
|
+
id: to,
|
|
1913
|
+
label: to,
|
|
1914
|
+
type: inferParticipantType(to),
|
|
1915
|
+
lineNumber
|
|
1916
|
+
});
|
|
1917
|
+
}
|
|
1918
|
+
continue;
|
|
1919
|
+
}
|
|
1920
|
+
const bidiSyncMatch = trimmed.match(
|
|
1921
|
+
/^(\S+)\s*<->\s*([^\s:]+)\s*(?::\s*(.+))?$/
|
|
1922
|
+
);
|
|
1923
|
+
const bidiAsyncMatch = trimmed.match(
|
|
1924
|
+
/^(\S+)\s*<~>\s*([^\s:]+)\s*(?::\s*(.+))?$/
|
|
1925
|
+
);
|
|
1926
|
+
const bidiMatch = bidiSyncMatch || bidiAsyncMatch;
|
|
1927
|
+
if (bidiMatch) {
|
|
1928
|
+
contentStarted = true;
|
|
1929
|
+
const from = bidiMatch[1];
|
|
1930
|
+
const to = bidiMatch[2];
|
|
1931
|
+
lastMsgFrom = from;
|
|
1932
|
+
const rawLabel = bidiMatch[3]?.trim() || "";
|
|
1933
|
+
const isBidiAsync = !!bidiAsyncMatch;
|
|
1934
|
+
const msg = {
|
|
1935
|
+
from,
|
|
1936
|
+
to,
|
|
1937
|
+
label: rawLabel,
|
|
1938
|
+
lineNumber,
|
|
1939
|
+
bidirectional: true,
|
|
1940
|
+
...isBidiAsync ? { async: true } : {}
|
|
1941
|
+
};
|
|
1942
|
+
result.messages.push(msg);
|
|
1943
|
+
currentContainer().push(msg);
|
|
1944
|
+
if (!result.participants.some((p) => p.id === from)) {
|
|
1945
|
+
result.participants.push({
|
|
1946
|
+
id: from,
|
|
1947
|
+
label: from,
|
|
1948
|
+
type: inferParticipantType(from),
|
|
1949
|
+
lineNumber
|
|
1950
|
+
});
|
|
1951
|
+
}
|
|
1952
|
+
if (!result.participants.some((p) => p.id === to)) {
|
|
1953
|
+
result.participants.push({
|
|
1954
|
+
id: to,
|
|
1955
|
+
label: to,
|
|
1956
|
+
type: inferParticipantType(to),
|
|
1957
|
+
lineNumber
|
|
1958
|
+
});
|
|
1959
|
+
}
|
|
1960
|
+
continue;
|
|
1961
|
+
}
|
|
1801
1962
|
let isAsync = false;
|
|
1802
1963
|
const asyncArrowMatch = trimmed.match(
|
|
1803
1964
|
/^(\S+)\s*~>\s*([^\s:]+)\s*(?::\s*(.+))?$/
|
|
@@ -2035,6 +2196,8 @@ var init_parser = __esm({
|
|
|
2035
2196
|
"use strict";
|
|
2036
2197
|
init_participant_inference();
|
|
2037
2198
|
init_diagnostics();
|
|
2199
|
+
init_arrows();
|
|
2200
|
+
init_parsing();
|
|
2038
2201
|
VALID_PARTICIPANT_TYPES = /* @__PURE__ */ new Set([
|
|
2039
2202
|
"service",
|
|
2040
2203
|
"database",
|
|
@@ -2050,7 +2213,7 @@ var init_parser = __esm({
|
|
|
2050
2213
|
POSITION_ONLY_PATTERN = /^(\S+)\s+position\s+(-?\d+)$/i;
|
|
2051
2214
|
GROUP_HEADING_PATTERN = /^##\s+(.+?)(?:\(([^)]+)\))?\s*$/;
|
|
2052
2215
|
SECTION_PATTERN = /^==\s+(.+?)(?:\s*==)?\s*$/;
|
|
2053
|
-
ARROW_PATTERN = /\S+\s*(
|
|
2216
|
+
ARROW_PATTERN = /\S+\s*(?:<->|<~>|->|~>|-\S+->|~\S+~>|<-\S+->|<~\S+~>)\s*\S+/;
|
|
2054
2217
|
ARROW_RETURN_PATTERN = /^(.+?)\s*<-\s*(.+)$/;
|
|
2055
2218
|
UML_RETURN_PATTERN = /^(\w+\([^)]*\))\s*:\s*(.+)$/;
|
|
2056
2219
|
NOTE_SINGLE = /^note(?:\s+(right|left)\s+of\s+(\S+))?\s*:\s*(.+)$/i;
|
|
@@ -2064,27 +2227,9 @@ __export(flowchart_parser_exports, {
|
|
|
2064
2227
|
looksLikeFlowchart: () => looksLikeFlowchart,
|
|
2065
2228
|
parseFlowchart: () => parseFlowchart
|
|
2066
2229
|
});
|
|
2067
|
-
function measureIndent2(line7) {
|
|
2068
|
-
let indent = 0;
|
|
2069
|
-
for (const ch of line7) {
|
|
2070
|
-
if (ch === " ") indent++;
|
|
2071
|
-
else if (ch === " ") indent += 4;
|
|
2072
|
-
else break;
|
|
2073
|
-
}
|
|
2074
|
-
return indent;
|
|
2075
|
-
}
|
|
2076
2230
|
function nodeId(shape, label) {
|
|
2077
2231
|
return `${shape}:${label.toLowerCase().trim()}`;
|
|
2078
2232
|
}
|
|
2079
|
-
function extractColor(label, palette) {
|
|
2080
|
-
const m = label.match(COLOR_SUFFIX_RE);
|
|
2081
|
-
if (!m) return { label };
|
|
2082
|
-
const colorName = m[1].trim();
|
|
2083
|
-
return {
|
|
2084
|
-
label: label.substring(0, m.index).trim(),
|
|
2085
|
-
color: resolveColor(colorName, palette)
|
|
2086
|
-
};
|
|
2087
|
-
}
|
|
2088
2233
|
function parseNodeRef(text, palette) {
|
|
2089
2234
|
const t = text.trim();
|
|
2090
2235
|
if (!t) return null;
|
|
@@ -2199,7 +2344,8 @@ function parseFlowchart(content, palette) {
|
|
|
2199
2344
|
nodes: [],
|
|
2200
2345
|
edges: [],
|
|
2201
2346
|
options: {},
|
|
2202
|
-
diagnostics: []
|
|
2347
|
+
diagnostics: [],
|
|
2348
|
+
error: null
|
|
2203
2349
|
};
|
|
2204
2350
|
const fail = (line7, message) => {
|
|
2205
2351
|
const diag = makeDgmoError(line7, message);
|
|
@@ -2301,7 +2447,7 @@ function parseFlowchart(content, palette) {
|
|
|
2301
2447
|
const raw = lines[i];
|
|
2302
2448
|
const trimmed = raw.trim();
|
|
2303
2449
|
const lineNumber = i + 1;
|
|
2304
|
-
const indent =
|
|
2450
|
+
const indent = measureIndent(raw);
|
|
2305
2451
|
if (!trimmed) continue;
|
|
2306
2452
|
if (trimmed.startsWith("//")) continue;
|
|
2307
2453
|
const groupMatch = trimmed.match(GROUP_HEADING_RE);
|
|
@@ -2378,13 +2524,13 @@ function looksLikeFlowchart(content) {
|
|
|
2378
2524
|
/->[ \t]*[\[(<\/]/.test(content);
|
|
2379
2525
|
return shapeNearArrow;
|
|
2380
2526
|
}
|
|
2381
|
-
var
|
|
2527
|
+
var GROUP_HEADING_RE;
|
|
2382
2528
|
var init_flowchart_parser = __esm({
|
|
2383
2529
|
"src/graph/flowchart-parser.ts"() {
|
|
2384
2530
|
"use strict";
|
|
2385
2531
|
init_colors();
|
|
2386
2532
|
init_diagnostics();
|
|
2387
|
-
|
|
2533
|
+
init_parsing();
|
|
2388
2534
|
GROUP_HEADING_RE = /^##\s+(.+?)(?:\(([^)]+)\))?\s*$/;
|
|
2389
2535
|
}
|
|
2390
2536
|
});
|
|
@@ -2395,15 +2541,6 @@ __export(parser_exports2, {
|
|
|
2395
2541
|
looksLikeClassDiagram: () => looksLikeClassDiagram,
|
|
2396
2542
|
parseClassDiagram: () => parseClassDiagram
|
|
2397
2543
|
});
|
|
2398
|
-
function measureIndent3(line7) {
|
|
2399
|
-
let indent = 0;
|
|
2400
|
-
for (const ch of line7) {
|
|
2401
|
-
if (ch === " ") indent++;
|
|
2402
|
-
else if (ch === " ") indent += 4;
|
|
2403
|
-
else break;
|
|
2404
|
-
}
|
|
2405
|
-
return indent;
|
|
2406
|
-
}
|
|
2407
2544
|
function classId(name) {
|
|
2408
2545
|
return name.toLowerCase().trim();
|
|
2409
2546
|
}
|
|
@@ -2478,7 +2615,8 @@ function parseClassDiagram(content, palette) {
|
|
|
2478
2615
|
classes: [],
|
|
2479
2616
|
relationships: [],
|
|
2480
2617
|
options: {},
|
|
2481
|
-
diagnostics: []
|
|
2618
|
+
diagnostics: [],
|
|
2619
|
+
error: null
|
|
2482
2620
|
};
|
|
2483
2621
|
const fail = (line7, message) => {
|
|
2484
2622
|
const diag = makeDgmoError(line7, message);
|
|
@@ -2507,7 +2645,7 @@ function parseClassDiagram(content, palette) {
|
|
|
2507
2645
|
const raw = lines[i];
|
|
2508
2646
|
const trimmed = raw.trim();
|
|
2509
2647
|
const lineNumber = i + 1;
|
|
2510
|
-
const indent =
|
|
2648
|
+
const indent = measureIndent(raw);
|
|
2511
2649
|
if (!trimmed) {
|
|
2512
2650
|
if (indent === 0) currentClass = null;
|
|
2513
2651
|
continue;
|
|
@@ -2627,7 +2765,7 @@ function looksLikeClassDiagram(content) {
|
|
|
2627
2765
|
const trimmed = line7.trim();
|
|
2628
2766
|
if (!trimmed || trimmed.startsWith("//")) continue;
|
|
2629
2767
|
if (/^(chart|title)\s*:/i.test(trimmed)) continue;
|
|
2630
|
-
const indent =
|
|
2768
|
+
const indent = measureIndent(line7);
|
|
2631
2769
|
if (indent === 0) {
|
|
2632
2770
|
if (/^[A-Z][A-Za-z0-9_]*\s+\[(abstract|interface|enum)\]/i.test(trimmed)) {
|
|
2633
2771
|
hasModifier = true;
|
|
@@ -2658,6 +2796,7 @@ var init_parser2 = __esm({
|
|
|
2658
2796
|
"use strict";
|
|
2659
2797
|
init_colors();
|
|
2660
2798
|
init_diagnostics();
|
|
2799
|
+
init_parsing();
|
|
2661
2800
|
CLASS_DECL_RE = /^([A-Z][A-Za-z0-9_]*)(?:\s+\[(abstract|interface|enum)\])?(?:\s+\(([^)]+)\))?\s*$/;
|
|
2662
2801
|
REL_KEYWORD_RE = /^([A-Z][A-Za-z0-9_]*)\s+(extends|implements|contains|has|uses)\s+([A-Z][A-Za-z0-9_]*)(?:\s*:\s*(.+))?$/;
|
|
2663
2802
|
REL_ARROW_RE = /^([A-Z][A-Za-z0-9_]*)\s+(--\|>|\.\.\|>|\*--|o--|\.\.\>|->)\s+([A-Z][A-Za-z0-9_]*)(?:\s*:\s*(.+))?$/;
|
|
@@ -2689,22 +2828,14 @@ __export(parser_exports3, {
|
|
|
2689
2828
|
looksLikeERDiagram: () => looksLikeERDiagram,
|
|
2690
2829
|
parseERDiagram: () => parseERDiagram
|
|
2691
2830
|
});
|
|
2692
|
-
function measureIndent4(line7) {
|
|
2693
|
-
let indent = 0;
|
|
2694
|
-
for (const ch of line7) {
|
|
2695
|
-
if (ch === " ") indent++;
|
|
2696
|
-
else if (ch === " ") indent += 4;
|
|
2697
|
-
else break;
|
|
2698
|
-
}
|
|
2699
|
-
return indent;
|
|
2700
|
-
}
|
|
2701
2831
|
function tableId(name) {
|
|
2702
2832
|
return name.toLowerCase().trim();
|
|
2703
2833
|
}
|
|
2704
2834
|
function parseCardSide(token) {
|
|
2705
|
-
|
|
2835
|
+
if (token === "1" || token === "*" || token === "?") return token;
|
|
2836
|
+
return null;
|
|
2706
2837
|
}
|
|
2707
|
-
function parseRelationship(trimmed) {
|
|
2838
|
+
function parseRelationship(trimmed, lineNumber, pushError) {
|
|
2708
2839
|
const sym = trimmed.match(REL_SYMBOLIC_RE);
|
|
2709
2840
|
if (sym) {
|
|
2710
2841
|
const fromCard = parseCardSide(sym[2]);
|
|
@@ -2721,17 +2852,13 @@ function parseRelationship(trimmed) {
|
|
|
2721
2852
|
}
|
|
2722
2853
|
const kw = trimmed.match(REL_KEYWORD_RE2);
|
|
2723
2854
|
if (kw) {
|
|
2724
|
-
const
|
|
2725
|
-
const
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
to: toCard,
|
|
2732
|
-
label: kw[5]?.trim()
|
|
2733
|
-
};
|
|
2734
|
-
}
|
|
2855
|
+
const fromSym = KEYWORD_TO_SYMBOL[kw[2].toLowerCase()] ?? kw[2];
|
|
2856
|
+
const toSym = KEYWORD_TO_SYMBOL[kw[3].toLowerCase()] ?? kw[3];
|
|
2857
|
+
pushError(
|
|
2858
|
+
lineNumber,
|
|
2859
|
+
`Use symbolic cardinality (1--*, ?--1, *--*) instead of "${kw[2]}-to-${kw[3]}". Example: ${kw[1]} ${fromSym}--${toSym} ${kw[4]}`
|
|
2860
|
+
);
|
|
2861
|
+
return null;
|
|
2735
2862
|
}
|
|
2736
2863
|
return null;
|
|
2737
2864
|
}
|
|
@@ -2751,7 +2878,8 @@ function parseERDiagram(content, palette) {
|
|
|
2751
2878
|
options: {},
|
|
2752
2879
|
tables: [],
|
|
2753
2880
|
relationships: [],
|
|
2754
|
-
diagnostics: []
|
|
2881
|
+
diagnostics: [],
|
|
2882
|
+
error: null
|
|
2755
2883
|
};
|
|
2756
2884
|
const fail = (line7, message) => {
|
|
2757
2885
|
const diag = makeDgmoError(line7, message);
|
|
@@ -2759,6 +2887,11 @@ function parseERDiagram(content, palette) {
|
|
|
2759
2887
|
result.error = formatDgmoError(diag);
|
|
2760
2888
|
return result;
|
|
2761
2889
|
};
|
|
2890
|
+
const pushError = (line7, message) => {
|
|
2891
|
+
const diag = makeDgmoError(line7, message);
|
|
2892
|
+
result.diagnostics.push(diag);
|
|
2893
|
+
if (!result.error) result.error = formatDgmoError(diag);
|
|
2894
|
+
};
|
|
2762
2895
|
const tableMap = /* @__PURE__ */ new Map();
|
|
2763
2896
|
let currentTable = null;
|
|
2764
2897
|
let contentStarted = false;
|
|
@@ -2780,7 +2913,7 @@ function parseERDiagram(content, palette) {
|
|
|
2780
2913
|
const raw = lines[i];
|
|
2781
2914
|
const trimmed = raw.trim();
|
|
2782
2915
|
const lineNumber = i + 1;
|
|
2783
|
-
const indent =
|
|
2916
|
+
const indent = measureIndent(raw);
|
|
2784
2917
|
if (!trimmed) {
|
|
2785
2918
|
if (indent === 0) currentTable = null;
|
|
2786
2919
|
continue;
|
|
@@ -2829,7 +2962,7 @@ function parseERDiagram(content, palette) {
|
|
|
2829
2962
|
}
|
|
2830
2963
|
currentTable = null;
|
|
2831
2964
|
contentStarted = true;
|
|
2832
|
-
const rel = parseRelationship(trimmed);
|
|
2965
|
+
const rel = parseRelationship(trimmed, lineNumber, pushError);
|
|
2833
2966
|
if (rel) {
|
|
2834
2967
|
getOrCreateTable(rel.source, lineNumber);
|
|
2835
2968
|
getOrCreateTable(rel.target, lineNumber);
|
|
@@ -2882,7 +3015,7 @@ function looksLikeERDiagram(content) {
|
|
|
2882
3015
|
const trimmed = line7.trim();
|
|
2883
3016
|
if (!trimmed || trimmed.startsWith("//")) continue;
|
|
2884
3017
|
if (/^(chart|title|notation)\s*:/i.test(trimmed)) continue;
|
|
2885
|
-
const indent =
|
|
3018
|
+
const indent = measureIndent(line7);
|
|
2886
3019
|
if (indent > 0) {
|
|
2887
3020
|
if (/\[(pk|fk)\]/i.test(trimmed)) {
|
|
2888
3021
|
hasConstraint = true;
|
|
@@ -2891,7 +3024,7 @@ function looksLikeERDiagram(content) {
|
|
|
2891
3024
|
if (TABLE_DECL_RE.test(trimmed)) {
|
|
2892
3025
|
hasTableDecl = true;
|
|
2893
3026
|
}
|
|
2894
|
-
if (REL_SYMBOLIC_RE.test(trimmed)
|
|
3027
|
+
if (REL_SYMBOLIC_RE.test(trimmed)) {
|
|
2895
3028
|
hasRelationship = true;
|
|
2896
3029
|
}
|
|
2897
3030
|
}
|
|
@@ -2900,12 +3033,13 @@ function looksLikeERDiagram(content) {
|
|
|
2900
3033
|
if (hasRelationship && hasTableDecl && hasConstraint) return true;
|
|
2901
3034
|
return false;
|
|
2902
3035
|
}
|
|
2903
|
-
var TABLE_DECL_RE, COLUMN_RE, CONSTRAINT_MAP,
|
|
3036
|
+
var TABLE_DECL_RE, COLUMN_RE, CONSTRAINT_MAP, REL_SYMBOLIC_RE, REL_KEYWORD_RE2, KEYWORD_TO_SYMBOL;
|
|
2904
3037
|
var init_parser3 = __esm({
|
|
2905
3038
|
"src/er/parser.ts"() {
|
|
2906
3039
|
"use strict";
|
|
2907
3040
|
init_colors();
|
|
2908
3041
|
init_diagnostics();
|
|
3042
|
+
init_parsing();
|
|
2909
3043
|
TABLE_DECL_RE = /^([a-zA-Z_]\w*)(?:\s+\(([^)]+)\))?\s*$/;
|
|
2910
3044
|
COLUMN_RE = /^(\w+)(?:\s*:\s*(\w[\w()]*(?:\s*\[\])?))?(?:\s+\[([^\]]+)\])?\s*$/;
|
|
2911
3045
|
CONSTRAINT_MAP = {
|
|
@@ -2914,16 +3048,13 @@ var init_parser3 = __esm({
|
|
|
2914
3048
|
unique: "unique",
|
|
2915
3049
|
nullable: "nullable"
|
|
2916
3050
|
};
|
|
2917
|
-
|
|
3051
|
+
REL_SYMBOLIC_RE = /^([a-zA-Z_]\w*)\s+([1*?])\s*-{1,2}\s*([1*?])\s+([a-zA-Z_]\w*)(?:\s*:\s*(.+))?$/;
|
|
3052
|
+
REL_KEYWORD_RE2 = /^([a-zA-Z_]\w*)\s+(one|many|zero)[- ]to[- ](one|many|zero)\s+([a-zA-Z_]\w*)(?:\s*:\s*(.+))?$/i;
|
|
3053
|
+
KEYWORD_TO_SYMBOL = {
|
|
2918
3054
|
one: "1",
|
|
2919
3055
|
many: "*",
|
|
2920
|
-
"1": "1",
|
|
2921
|
-
"*": "*",
|
|
2922
|
-
"?": "?",
|
|
2923
3056
|
zero: "?"
|
|
2924
3057
|
};
|
|
2925
|
-
REL_SYMBOLIC_RE = /^([a-zA-Z_]\w*)\s+([1*?])\s*-{1,2}\s*([1*?])\s+([a-zA-Z_]\w*)(?:\s*:\s*(.+))?$/;
|
|
2926
|
-
REL_KEYWORD_RE2 = /^([a-zA-Z_]\w*)\s+(one|many|zero|1|\*|\?)[- ]to[- ](one|many|zero|1|\*|\?)\s+([a-zA-Z_]\w*)(?:\s*:\s*(.+))?$/i;
|
|
2927
3058
|
}
|
|
2928
3059
|
});
|
|
2929
3060
|
|
|
@@ -2933,7 +3064,8 @@ function parseChart(content, palette) {
|
|
|
2933
3064
|
const result = {
|
|
2934
3065
|
type: "bar",
|
|
2935
3066
|
data: [],
|
|
2936
|
-
diagnostics: []
|
|
3067
|
+
diagnostics: [],
|
|
3068
|
+
error: null
|
|
2937
3069
|
};
|
|
2938
3070
|
const fail = (line7, message) => {
|
|
2939
3071
|
const diag = makeDgmoError(line7, message);
|
|
@@ -2946,7 +3078,7 @@ function parseChart(content, palette) {
|
|
|
2946
3078
|
const lineNumber = i + 1;
|
|
2947
3079
|
if (!trimmed) continue;
|
|
2948
3080
|
if (/^#{2,}\s+/.test(trimmed)) continue;
|
|
2949
|
-
if (trimmed.startsWith("
|
|
3081
|
+
if (trimmed.startsWith("//")) continue;
|
|
2950
3082
|
const colonIndex = trimmed.indexOf(":");
|
|
2951
3083
|
if (colonIndex === -1) continue;
|
|
2952
3084
|
const key = trimmed.substring(0, colonIndex).trim().toLowerCase();
|
|
@@ -3105,7 +3237,8 @@ function parseEChart(content, palette) {
|
|
|
3105
3237
|
const result = {
|
|
3106
3238
|
type: "scatter",
|
|
3107
3239
|
data: [],
|
|
3108
|
-
diagnostics: []
|
|
3240
|
+
diagnostics: [],
|
|
3241
|
+
error: null
|
|
3109
3242
|
};
|
|
3110
3243
|
let currentCategory = "Default";
|
|
3111
3244
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -3125,7 +3258,7 @@ function parseEChart(content, palette) {
|
|
|
3125
3258
|
currentCategory = catName;
|
|
3126
3259
|
continue;
|
|
3127
3260
|
}
|
|
3128
|
-
if (trimmed.startsWith("
|
|
3261
|
+
if (trimmed.startsWith("//")) continue;
|
|
3129
3262
|
const categoryMatch = trimmed.match(/^\[(.+)\]$/);
|
|
3130
3263
|
if (categoryMatch) {
|
|
3131
3264
|
currentCategory = categoryMatch[1].trim();
|
|
@@ -3754,7 +3887,7 @@ function buildScatterOption(parsed, palette, textColor, axisLineColor, gridOpaci
|
|
|
3754
3887
|
}
|
|
3755
3888
|
},
|
|
3756
3889
|
grid: {
|
|
3757
|
-
left: parsed.ylabel ? "
|
|
3890
|
+
left: parsed.ylabel ? "12%" : "3%",
|
|
3758
3891
|
right: "4%",
|
|
3759
3892
|
bottom: hasCategories ? "15%" : parsed.xlabel ? "10%" : "3%",
|
|
3760
3893
|
top: parsed.title ? "15%" : "5%",
|
|
@@ -4026,17 +4159,26 @@ function resolveAxisLabels(parsed) {
|
|
|
4026
4159
|
yLabel: parsed.ylabel ?? (isHorizontal ? void 0 : parsed.label)
|
|
4027
4160
|
};
|
|
4028
4161
|
}
|
|
4029
|
-
function makeGridAxis(type, textColor, axisLineColor, splitLineColor, gridOpacity, label, data) {
|
|
4162
|
+
function makeGridAxis(type, textColor, axisLineColor, splitLineColor, gridOpacity, label, data, nameGapOverride) {
|
|
4163
|
+
const defaultGap = type === "value" ? 75 : 40;
|
|
4030
4164
|
return {
|
|
4031
4165
|
type,
|
|
4032
4166
|
...data && { data },
|
|
4033
4167
|
axisLine: { lineStyle: { color: axisLineColor } },
|
|
4034
|
-
axisLabel: {
|
|
4168
|
+
axisLabel: {
|
|
4169
|
+
color: textColor,
|
|
4170
|
+
fontSize: type === "category" && data ? data.length > 10 ? 11 : data.length > 5 ? 12 : 16 : 16,
|
|
4171
|
+
fontFamily: FONT_FAMILY,
|
|
4172
|
+
...type === "category" && {
|
|
4173
|
+
interval: 0,
|
|
4174
|
+
formatter: (value) => value.replace(/([a-z])([A-Z])/g, "$1\n$2").replace(/ /g, "\n")
|
|
4175
|
+
}
|
|
4176
|
+
},
|
|
4035
4177
|
splitLine: { lineStyle: { color: splitLineColor, opacity: gridOpacity } },
|
|
4036
4178
|
...label && {
|
|
4037
4179
|
name: label,
|
|
4038
4180
|
nameLocation: "middle",
|
|
4039
|
-
nameGap:
|
|
4181
|
+
nameGap: nameGapOverride ?? defaultGap,
|
|
4040
4182
|
nameTextStyle: { color: textColor, fontSize: 18, fontFamily: FONT_FAMILY }
|
|
4041
4183
|
}
|
|
4042
4184
|
};
|
|
@@ -4091,7 +4233,8 @@ function buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOp
|
|
|
4091
4233
|
value: d.value,
|
|
4092
4234
|
itemStyle: { color: d.color ?? colors[i % colors.length] }
|
|
4093
4235
|
}));
|
|
4094
|
-
const
|
|
4236
|
+
const hCatGap = isHorizontal && yLabel ? Math.max(40, Math.max(...labels.map((l) => l.length)) * 8 + 16) : void 0;
|
|
4237
|
+
const categoryAxis = makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? yLabel : xLabel, labels, hCatGap);
|
|
4095
4238
|
const valueAxis = makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? xLabel : yLabel);
|
|
4096
4239
|
return {
|
|
4097
4240
|
backgroundColor: "transparent",
|
|
@@ -4103,7 +4246,7 @@ function buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOp
|
|
|
4103
4246
|
axisPointer: { type: "shadow" }
|
|
4104
4247
|
},
|
|
4105
4248
|
grid: {
|
|
4106
|
-
left: yLabel ? "
|
|
4249
|
+
left: yLabel ? "12%" : "3%",
|
|
4107
4250
|
right: "4%",
|
|
4108
4251
|
bottom: xLabel ? "10%" : "3%",
|
|
4109
4252
|
top: parsed.title ? "15%" : "5%",
|
|
@@ -4138,7 +4281,7 @@ function buildLineOption(parsed, palette, textColor, axisLineColor, splitLineCol
|
|
|
4138
4281
|
axisPointer: { type: "line" }
|
|
4139
4282
|
},
|
|
4140
4283
|
grid: {
|
|
4141
|
-
left: yLabel ? "
|
|
4284
|
+
left: yLabel ? "12%" : "3%",
|
|
4142
4285
|
right: "4%",
|
|
4143
4286
|
bottom: xLabel ? "10%" : "3%",
|
|
4144
4287
|
top: parsed.title ? "15%" : "5%",
|
|
@@ -4200,7 +4343,7 @@ function buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor,
|
|
|
4200
4343
|
textStyle: { color: textColor }
|
|
4201
4344
|
},
|
|
4202
4345
|
grid: {
|
|
4203
|
-
left: yLabel ? "
|
|
4346
|
+
left: yLabel ? "12%" : "3%",
|
|
4204
4347
|
right: "4%",
|
|
4205
4348
|
bottom: "15%",
|
|
4206
4349
|
top: parsed.title ? "15%" : "5%",
|
|
@@ -4226,7 +4369,7 @@ function buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineCol
|
|
|
4226
4369
|
axisPointer: { type: "line" }
|
|
4227
4370
|
},
|
|
4228
4371
|
grid: {
|
|
4229
|
-
left: yLabel ? "
|
|
4372
|
+
left: yLabel ? "12%" : "3%",
|
|
4230
4373
|
right: "4%",
|
|
4231
4374
|
bottom: xLabel ? "10%" : "3%",
|
|
4232
4375
|
top: parsed.title ? "15%" : "5%",
|
|
@@ -4423,7 +4566,8 @@ function buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor,
|
|
|
4423
4566
|
}
|
|
4424
4567
|
};
|
|
4425
4568
|
});
|
|
4426
|
-
const
|
|
4569
|
+
const hCatGap = isHorizontal && yLabel ? Math.max(40, Math.max(...labels.map((l) => l.length)) * 8 + 16) : void 0;
|
|
4570
|
+
const categoryAxis = makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? yLabel : xLabel, labels, hCatGap);
|
|
4427
4571
|
const valueAxis = makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? xLabel : yLabel);
|
|
4428
4572
|
return {
|
|
4429
4573
|
backgroundColor: "transparent",
|
|
@@ -4440,7 +4584,7 @@ function buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor,
|
|
|
4440
4584
|
textStyle: { color: textColor }
|
|
4441
4585
|
},
|
|
4442
4586
|
grid: {
|
|
4443
|
-
left: yLabel ? "
|
|
4587
|
+
left: yLabel ? "12%" : "3%",
|
|
4444
4588
|
right: "4%",
|
|
4445
4589
|
bottom: "15%",
|
|
4446
4590
|
top: parsed.title ? "15%" : "5%",
|
|
@@ -4518,35 +4662,51 @@ var init_echarts = __esm({
|
|
|
4518
4662
|
}
|
|
4519
4663
|
});
|
|
4520
4664
|
|
|
4665
|
+
// src/utils/tag-groups.ts
|
|
4666
|
+
function isTagBlockHeading(trimmed) {
|
|
4667
|
+
return TAG_BLOCK_RE.test(trimmed) || GROUP_HEADING_RE2.test(trimmed);
|
|
4668
|
+
}
|
|
4669
|
+
function matchTagBlockHeading(trimmed) {
|
|
4670
|
+
const tagMatch = trimmed.match(TAG_BLOCK_RE);
|
|
4671
|
+
if (tagMatch) {
|
|
4672
|
+
return {
|
|
4673
|
+
name: tagMatch[1].trim(),
|
|
4674
|
+
alias: tagMatch[2] || void 0,
|
|
4675
|
+
colorHint: tagMatch[3] || void 0,
|
|
4676
|
+
deprecated: false
|
|
4677
|
+
};
|
|
4678
|
+
}
|
|
4679
|
+
const groupMatch = trimmed.match(GROUP_HEADING_RE2);
|
|
4680
|
+
if (groupMatch) {
|
|
4681
|
+
return {
|
|
4682
|
+
name: groupMatch[1].trim(),
|
|
4683
|
+
alias: groupMatch[2] || void 0,
|
|
4684
|
+
colorHint: groupMatch[3] || void 0,
|
|
4685
|
+
deprecated: true
|
|
4686
|
+
};
|
|
4687
|
+
}
|
|
4688
|
+
return null;
|
|
4689
|
+
}
|
|
4690
|
+
var TAG_BLOCK_RE, GROUP_HEADING_RE2;
|
|
4691
|
+
var init_tag_groups = __esm({
|
|
4692
|
+
"src/utils/tag-groups.ts"() {
|
|
4693
|
+
"use strict";
|
|
4694
|
+
TAG_BLOCK_RE = /^tag:\s+(.+?)(?:\s+alias\s+(\w+))?(?:\s*\(([^)]+)\))?\s*$/i;
|
|
4695
|
+
GROUP_HEADING_RE2 = /^##\s+(.+?)(?:\s+alias\s+(\w+))?(?:\s*\(([^)]+)\))?\s*$/;
|
|
4696
|
+
}
|
|
4697
|
+
});
|
|
4698
|
+
|
|
4521
4699
|
// src/org/parser.ts
|
|
4522
4700
|
var parser_exports4 = {};
|
|
4523
4701
|
__export(parser_exports4, {
|
|
4524
4702
|
looksLikeOrg: () => looksLikeOrg,
|
|
4525
4703
|
parseOrg: () => parseOrg
|
|
4526
4704
|
});
|
|
4527
|
-
function measureIndent5(line7) {
|
|
4528
|
-
let indent = 0;
|
|
4529
|
-
for (const ch of line7) {
|
|
4530
|
-
if (ch === " ") indent++;
|
|
4531
|
-
else if (ch === " ") indent += 4;
|
|
4532
|
-
else break;
|
|
4533
|
-
}
|
|
4534
|
-
return indent;
|
|
4535
|
-
}
|
|
4536
|
-
function extractColor2(label, palette) {
|
|
4537
|
-
const m = label.match(COLOR_SUFFIX_RE2);
|
|
4538
|
-
if (!m) return { label };
|
|
4539
|
-
const colorName = m[1].trim();
|
|
4540
|
-
return {
|
|
4541
|
-
label: label.substring(0, m.index).trim(),
|
|
4542
|
-
color: resolveColor(colorName, palette)
|
|
4543
|
-
};
|
|
4544
|
-
}
|
|
4545
4705
|
function looksLikeOrg(content) {
|
|
4546
4706
|
for (const line7 of content.split("\n")) {
|
|
4547
4707
|
const trimmed = line7.trim();
|
|
4548
4708
|
if (!trimmed || trimmed.startsWith("//")) continue;
|
|
4549
|
-
if (
|
|
4709
|
+
if (isTagBlockHeading(trimmed)) return true;
|
|
4550
4710
|
}
|
|
4551
4711
|
return false;
|
|
4552
4712
|
}
|
|
@@ -4571,6 +4731,9 @@ function parseOrg(content, palette) {
|
|
|
4571
4731
|
result.diagnostics.push(diag);
|
|
4572
4732
|
if (!result.error) result.error = formatDgmoError(diag);
|
|
4573
4733
|
};
|
|
4734
|
+
const pushWarning = (line7, message) => {
|
|
4735
|
+
result.diagnostics.push(makeDgmoError(line7, message, "warning"));
|
|
4736
|
+
};
|
|
4574
4737
|
if (!content || !content.trim()) {
|
|
4575
4738
|
return fail(0, "No content provided");
|
|
4576
4739
|
}
|
|
@@ -4614,42 +4777,43 @@ function parseOrg(content, palette) {
|
|
|
4614
4777
|
continue;
|
|
4615
4778
|
}
|
|
4616
4779
|
}
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
if (optMatch && !trimmed.startsWith("##")) {
|
|
4620
|
-
const key = optMatch[1].trim().toLowerCase();
|
|
4621
|
-
if (key !== "chart" && key !== "title") {
|
|
4622
|
-
result.options[key] = optMatch[2].trim();
|
|
4623
|
-
continue;
|
|
4624
|
-
}
|
|
4625
|
-
}
|
|
4626
|
-
}
|
|
4627
|
-
const groupMatch = trimmed.match(GROUP_HEADING_RE2);
|
|
4628
|
-
if (groupMatch) {
|
|
4780
|
+
const tagBlockMatch = matchTagBlockHeading(trimmed);
|
|
4781
|
+
if (tagBlockMatch) {
|
|
4629
4782
|
if (contentStarted) {
|
|
4630
|
-
pushError(lineNumber, "Tag groups
|
|
4783
|
+
pushError(lineNumber, "Tag groups must appear before org content");
|
|
4631
4784
|
continue;
|
|
4632
4785
|
}
|
|
4633
|
-
|
|
4634
|
-
|
|
4786
|
+
if (tagBlockMatch.deprecated) {
|
|
4787
|
+
pushWarning(lineNumber, `'## ${tagBlockMatch.name}' is deprecated for tag groups \u2014 use 'tag: ${tagBlockMatch.name}' instead`);
|
|
4788
|
+
}
|
|
4635
4789
|
currentTagGroup = {
|
|
4636
|
-
name:
|
|
4637
|
-
alias,
|
|
4790
|
+
name: tagBlockMatch.name,
|
|
4791
|
+
alias: tagBlockMatch.alias,
|
|
4638
4792
|
entries: [],
|
|
4639
4793
|
lineNumber
|
|
4640
4794
|
};
|
|
4641
|
-
if (alias) {
|
|
4642
|
-
aliasMap.set(alias.toLowerCase(),
|
|
4795
|
+
if (tagBlockMatch.alias) {
|
|
4796
|
+
aliasMap.set(tagBlockMatch.alias.toLowerCase(), tagBlockMatch.name.toLowerCase());
|
|
4643
4797
|
}
|
|
4644
4798
|
result.tagGroups.push(currentTagGroup);
|
|
4645
4799
|
continue;
|
|
4646
4800
|
}
|
|
4801
|
+
if (!contentStarted && !currentTagGroup && measureIndent(line7) === 0) {
|
|
4802
|
+
const optMatch = trimmed.match(OPTION_RE);
|
|
4803
|
+
if (optMatch) {
|
|
4804
|
+
const key = optMatch[1].trim().toLowerCase();
|
|
4805
|
+
if (key !== "chart" && key !== "title") {
|
|
4806
|
+
result.options[key] = optMatch[2].trim();
|
|
4807
|
+
continue;
|
|
4808
|
+
}
|
|
4809
|
+
}
|
|
4810
|
+
}
|
|
4647
4811
|
if (currentTagGroup && !contentStarted) {
|
|
4648
|
-
const indent2 =
|
|
4812
|
+
const indent2 = measureIndent(line7);
|
|
4649
4813
|
if (indent2 > 0) {
|
|
4650
4814
|
const isDefault = /\bdefault\s*$/.test(trimmed);
|
|
4651
4815
|
const entryText = isDefault ? trimmed.replace(/\s+default\s*$/, "").trim() : trimmed;
|
|
4652
|
-
const { label, color } =
|
|
4816
|
+
const { label, color } = extractColor(entryText, palette);
|
|
4653
4817
|
if (!color) {
|
|
4654
4818
|
pushError(lineNumber, `Expected 'Value(color)' in tag group '${currentTagGroup.name}'`);
|
|
4655
4819
|
continue;
|
|
@@ -4668,12 +4832,12 @@ function parseOrg(content, palette) {
|
|
|
4668
4832
|
}
|
|
4669
4833
|
contentStarted = true;
|
|
4670
4834
|
currentTagGroup = null;
|
|
4671
|
-
const indent =
|
|
4835
|
+
const indent = measureIndent(line7);
|
|
4672
4836
|
const containerMatch = trimmed.match(CONTAINER_RE);
|
|
4673
4837
|
const metadataMatch = trimmed.includes("|") ? null : trimmed.match(METADATA_RE);
|
|
4674
4838
|
if (containerMatch) {
|
|
4675
4839
|
const rawLabel = containerMatch[1].trim();
|
|
4676
|
-
const { label, color } =
|
|
4840
|
+
const { label, color } = extractColor(rawLabel, palette);
|
|
4677
4841
|
containerCounter++;
|
|
4678
4842
|
const node = {
|
|
4679
4843
|
id: `container-${containerCounter}`,
|
|
@@ -4718,24 +4882,8 @@ function parseOrg(content, palette) {
|
|
|
4718
4882
|
function parseNodeLabel(trimmed, _indent, lineNumber, palette, counter, aliasMap = /* @__PURE__ */ new Map()) {
|
|
4719
4883
|
const segments = trimmed.split("|").map((s) => s.trim());
|
|
4720
4884
|
let rawLabel = segments[0];
|
|
4721
|
-
const { label, color } =
|
|
4722
|
-
const metadata =
|
|
4723
|
-
const metaParts = [];
|
|
4724
|
-
for (let j = 1; j < segments.length; j++) {
|
|
4725
|
-
for (const part of segments[j].split(",")) {
|
|
4726
|
-
const trimmedPart = part.trim();
|
|
4727
|
-
if (trimmedPart) metaParts.push(trimmedPart);
|
|
4728
|
-
}
|
|
4729
|
-
}
|
|
4730
|
-
for (const part of metaParts) {
|
|
4731
|
-
const colonIdx = part.indexOf(":");
|
|
4732
|
-
if (colonIdx > 0) {
|
|
4733
|
-
const rawKey = part.substring(0, colonIdx).trim().toLowerCase();
|
|
4734
|
-
const key = aliasMap.get(rawKey) ?? rawKey;
|
|
4735
|
-
const value = part.substring(colonIdx + 1).trim();
|
|
4736
|
-
metadata[key] = value;
|
|
4737
|
-
}
|
|
4738
|
-
}
|
|
4885
|
+
const { label, color } = extractColor(rawLabel, palette);
|
|
4886
|
+
const metadata = parsePipeMetadata(segments, aliasMap);
|
|
4739
4887
|
return {
|
|
4740
4888
|
id: `node-${counter}`,
|
|
4741
4889
|
label,
|
|
@@ -4773,19 +4921,15 @@ function findMetadataParent(indent, indentStack) {
|
|
|
4773
4921
|
}
|
|
4774
4922
|
return null;
|
|
4775
4923
|
}
|
|
4776
|
-
var
|
|
4924
|
+
var CONTAINER_RE, METADATA_RE;
|
|
4777
4925
|
var init_parser4 = __esm({
|
|
4778
4926
|
"src/org/parser.ts"() {
|
|
4779
4927
|
"use strict";
|
|
4780
|
-
init_colors();
|
|
4781
4928
|
init_diagnostics();
|
|
4782
|
-
|
|
4783
|
-
|
|
4929
|
+
init_tag_groups();
|
|
4930
|
+
init_parsing();
|
|
4784
4931
|
CONTAINER_RE = /^\[([^\]]+)\]$/;
|
|
4785
4932
|
METADATA_RE = /^([^:]+):\s*(.+)$/;
|
|
4786
|
-
CHART_TYPE_RE = /^chart\s*:\s*(.+)/i;
|
|
4787
|
-
TITLE_RE = /^title\s*:\s*(.+)/i;
|
|
4788
|
-
OPTION_RE = /^([a-z][a-z0-9-]*)\s*:\s*(.+)$/i;
|
|
4789
4933
|
}
|
|
4790
4934
|
});
|
|
4791
4935
|
|
|
@@ -4794,31 +4938,14 @@ var parser_exports5 = {};
|
|
|
4794
4938
|
__export(parser_exports5, {
|
|
4795
4939
|
parseKanban: () => parseKanban
|
|
4796
4940
|
});
|
|
4797
|
-
function measureIndent6(line7) {
|
|
4798
|
-
let indent = 0;
|
|
4799
|
-
for (const ch of line7) {
|
|
4800
|
-
if (ch === " ") indent++;
|
|
4801
|
-
else if (ch === " ") indent += 4;
|
|
4802
|
-
else break;
|
|
4803
|
-
}
|
|
4804
|
-
return indent;
|
|
4805
|
-
}
|
|
4806
|
-
function extractColor3(label, palette) {
|
|
4807
|
-
const m = label.match(COLOR_SUFFIX_RE3);
|
|
4808
|
-
if (!m) return { label };
|
|
4809
|
-
const colorName = m[1].trim();
|
|
4810
|
-
return {
|
|
4811
|
-
label: label.substring(0, m.index).trim(),
|
|
4812
|
-
color: resolveColor(colorName, palette)
|
|
4813
|
-
};
|
|
4814
|
-
}
|
|
4815
4941
|
function parseKanban(content, palette) {
|
|
4816
4942
|
const result = {
|
|
4817
4943
|
type: "kanban",
|
|
4818
4944
|
columns: [],
|
|
4819
4945
|
tagGroups: [],
|
|
4820
4946
|
options: {},
|
|
4821
|
-
diagnostics: []
|
|
4947
|
+
diagnostics: [],
|
|
4948
|
+
error: null
|
|
4822
4949
|
};
|
|
4823
4950
|
const fail = (line7, message) => {
|
|
4824
4951
|
const diag = makeDgmoError(line7, message);
|
|
@@ -4851,7 +4978,7 @@ function parseKanban(content, palette) {
|
|
|
4851
4978
|
}
|
|
4852
4979
|
if (trimmed.startsWith("//")) continue;
|
|
4853
4980
|
if (!contentStarted && !currentTagGroup) {
|
|
4854
|
-
const chartMatch = trimmed.match(
|
|
4981
|
+
const chartMatch = trimmed.match(CHART_TYPE_RE);
|
|
4855
4982
|
if (chartMatch) {
|
|
4856
4983
|
const chartType = chartMatch[1].trim().toLowerCase();
|
|
4857
4984
|
if (chartType !== "kanban") {
|
|
@@ -4875,16 +5002,35 @@ function parseKanban(content, palette) {
|
|
|
4875
5002
|
}
|
|
4876
5003
|
}
|
|
4877
5004
|
if (!contentStarted && !currentTagGroup) {
|
|
4878
|
-
const titleMatch = trimmed.match(
|
|
5005
|
+
const titleMatch = trimmed.match(TITLE_RE);
|
|
4879
5006
|
if (titleMatch) {
|
|
4880
5007
|
result.title = titleMatch[1].trim();
|
|
4881
5008
|
result.titleLineNumber = lineNumber;
|
|
4882
5009
|
continue;
|
|
4883
5010
|
}
|
|
4884
5011
|
}
|
|
4885
|
-
if (!contentStarted
|
|
4886
|
-
const
|
|
4887
|
-
if (
|
|
5012
|
+
if (!contentStarted) {
|
|
5013
|
+
const tagBlockMatch = matchTagBlockHeading(trimmed);
|
|
5014
|
+
if (tagBlockMatch) {
|
|
5015
|
+
if (tagBlockMatch.deprecated) {
|
|
5016
|
+
warn(lineNumber, `'## ${tagBlockMatch.name}' is deprecated for tag groups \u2014 use 'tag: ${tagBlockMatch.name}' instead`);
|
|
5017
|
+
}
|
|
5018
|
+
currentTagGroup = {
|
|
5019
|
+
name: tagBlockMatch.name,
|
|
5020
|
+
alias: tagBlockMatch.alias,
|
|
5021
|
+
entries: [],
|
|
5022
|
+
lineNumber
|
|
5023
|
+
};
|
|
5024
|
+
if (tagBlockMatch.alias) {
|
|
5025
|
+
aliasMap.set(tagBlockMatch.alias.toLowerCase(), tagBlockMatch.name.toLowerCase());
|
|
5026
|
+
}
|
|
5027
|
+
result.tagGroups.push(currentTagGroup);
|
|
5028
|
+
continue;
|
|
5029
|
+
}
|
|
5030
|
+
}
|
|
5031
|
+
if (!contentStarted && !currentTagGroup && measureIndent(line7) === 0) {
|
|
5032
|
+
const optMatch = trimmed.match(OPTION_RE);
|
|
5033
|
+
if (optMatch && !COLUMN_RE2.test(trimmed)) {
|
|
4888
5034
|
const key = optMatch[1].trim().toLowerCase();
|
|
4889
5035
|
if (key !== "chart" && key !== "title") {
|
|
4890
5036
|
result.options[key] = optMatch[2].trim();
|
|
@@ -4892,28 +5038,12 @@ function parseKanban(content, palette) {
|
|
|
4892
5038
|
}
|
|
4893
5039
|
}
|
|
4894
5040
|
}
|
|
4895
|
-
const groupMatch = trimmed.match(GROUP_HEADING_RE3);
|
|
4896
|
-
if (groupMatch && !contentStarted) {
|
|
4897
|
-
const groupName = groupMatch[1].trim();
|
|
4898
|
-
const alias = groupMatch[2] || void 0;
|
|
4899
|
-
currentTagGroup = {
|
|
4900
|
-
name: groupName,
|
|
4901
|
-
alias,
|
|
4902
|
-
entries: [],
|
|
4903
|
-
lineNumber
|
|
4904
|
-
};
|
|
4905
|
-
if (alias) {
|
|
4906
|
-
aliasMap.set(alias.toLowerCase(), groupName.toLowerCase());
|
|
4907
|
-
}
|
|
4908
|
-
result.tagGroups.push(currentTagGroup);
|
|
4909
|
-
continue;
|
|
4910
|
-
}
|
|
4911
5041
|
if (currentTagGroup && !contentStarted) {
|
|
4912
|
-
const indent2 =
|
|
5042
|
+
const indent2 = measureIndent(line7);
|
|
4913
5043
|
if (indent2 > 0) {
|
|
4914
5044
|
const isDefault = /\bdefault\s*$/.test(trimmed);
|
|
4915
5045
|
const entryText = isDefault ? trimmed.replace(/\s+default\s*$/, "").trim() : trimmed;
|
|
4916
|
-
const { label, color } =
|
|
5046
|
+
const { label, color } = extractColor(entryText, palette);
|
|
4917
5047
|
if (!color) {
|
|
4918
5048
|
warn(
|
|
4919
5049
|
lineNumber,
|
|
@@ -4947,7 +5077,7 @@ function parseKanban(content, palette) {
|
|
|
4947
5077
|
columnCounter++;
|
|
4948
5078
|
const rawColName = columnMatch[1].trim();
|
|
4949
5079
|
const wipStr = columnMatch[2];
|
|
4950
|
-
const { label: colName, color: colColor } =
|
|
5080
|
+
const { label: colName, color: colColor } = extractColor(
|
|
4951
5081
|
rawColName,
|
|
4952
5082
|
palette
|
|
4953
5083
|
);
|
|
@@ -4969,7 +5099,7 @@ function parseKanban(content, palette) {
|
|
|
4969
5099
|
warn(lineNumber, "Card line found before any column");
|
|
4970
5100
|
continue;
|
|
4971
5101
|
}
|
|
4972
|
-
const indent =
|
|
5102
|
+
const indent = measureIndent(line7);
|
|
4973
5103
|
if (indent > 0 && currentCard) {
|
|
4974
5104
|
currentCard.details.push(trimmed);
|
|
4975
5105
|
currentCard.endLineNumber = lineNumber;
|
|
@@ -5034,7 +5164,7 @@ function parseCardLine(trimmed, lineNumber, counter, aliasMap, palette) {
|
|
|
5034
5164
|
} else {
|
|
5035
5165
|
rawTitle = trimmed;
|
|
5036
5166
|
}
|
|
5037
|
-
const { label: title, color } =
|
|
5167
|
+
const { label: title, color } = extractColor(rawTitle, palette);
|
|
5038
5168
|
const tags = {};
|
|
5039
5169
|
if (tagsStr) {
|
|
5040
5170
|
for (const part of tagsStr.split(",")) {
|
|
@@ -5057,18 +5187,14 @@ function parseCardLine(trimmed, lineNumber, counter, aliasMap, palette) {
|
|
|
5057
5187
|
color
|
|
5058
5188
|
};
|
|
5059
5189
|
}
|
|
5060
|
-
var
|
|
5190
|
+
var COLUMN_RE2;
|
|
5061
5191
|
var init_parser5 = __esm({
|
|
5062
5192
|
"src/kanban/parser.ts"() {
|
|
5063
5193
|
"use strict";
|
|
5064
|
-
init_colors();
|
|
5065
5194
|
init_diagnostics();
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
OPTION_RE2 = /^([a-z][a-z0-9-]*)\s*:\s*(.+)$/i;
|
|
5069
|
-
GROUP_HEADING_RE3 = /^##\s+(.+?)(?:\s+alias\s+(\w+))?(?:\s*\(([^)]+)\))?\s*$/;
|
|
5195
|
+
init_tag_groups();
|
|
5196
|
+
init_parsing();
|
|
5070
5197
|
COLUMN_RE2 = /^==\s+(.+?)\s*(?:\[wip:\s*(\d+)\])?\s*==$/;
|
|
5071
|
-
COLOR_SUFFIX_RE3 = /\(([^)]+)\)\s*$/;
|
|
5072
5198
|
}
|
|
5073
5199
|
});
|
|
5074
5200
|
|
|
@@ -5077,24 +5203,6 @@ var parser_exports6 = {};
|
|
|
5077
5203
|
__export(parser_exports6, {
|
|
5078
5204
|
parseC4: () => parseC4
|
|
5079
5205
|
});
|
|
5080
|
-
function measureIndent7(line7) {
|
|
5081
|
-
let indent = 0;
|
|
5082
|
-
for (const ch of line7) {
|
|
5083
|
-
if (ch === " ") indent++;
|
|
5084
|
-
else if (ch === " ") indent += 4;
|
|
5085
|
-
else break;
|
|
5086
|
-
}
|
|
5087
|
-
return indent;
|
|
5088
|
-
}
|
|
5089
|
-
function extractColor4(label, palette) {
|
|
5090
|
-
const m = label.match(COLOR_SUFFIX_RE4);
|
|
5091
|
-
if (!m) return { label };
|
|
5092
|
-
const colorName = m[1].trim();
|
|
5093
|
-
return {
|
|
5094
|
-
label: label.substring(0, m.index).trim(),
|
|
5095
|
-
color: resolveColor(colorName, palette)
|
|
5096
|
-
};
|
|
5097
|
-
}
|
|
5098
5206
|
function participantTypeToC4Shape(pType) {
|
|
5099
5207
|
switch (pType) {
|
|
5100
5208
|
case "database":
|
|
@@ -5151,23 +5259,6 @@ function parseRelationshipBody(body) {
|
|
|
5151
5259
|
}
|
|
5152
5260
|
return { target, label: rest };
|
|
5153
5261
|
}
|
|
5154
|
-
function parsePipeMetadata(segments, aliasMap) {
|
|
5155
|
-
const metadata = {};
|
|
5156
|
-
for (let j = 1; j < segments.length; j++) {
|
|
5157
|
-
for (const part of segments[j].split(",")) {
|
|
5158
|
-
const trimmedPart = part.trim();
|
|
5159
|
-
if (!trimmedPart) continue;
|
|
5160
|
-
const colonIdx = trimmedPart.indexOf(":");
|
|
5161
|
-
if (colonIdx > 0) {
|
|
5162
|
-
const rawKey = trimmedPart.substring(0, colonIdx).trim().toLowerCase();
|
|
5163
|
-
const key = aliasMap.get(rawKey) ?? rawKey;
|
|
5164
|
-
const value = trimmedPart.substring(colonIdx + 1).trim();
|
|
5165
|
-
metadata[key] = value;
|
|
5166
|
-
}
|
|
5167
|
-
}
|
|
5168
|
-
}
|
|
5169
|
-
return metadata;
|
|
5170
|
-
}
|
|
5171
5262
|
function parseC4(content, palette) {
|
|
5172
5263
|
const result = {
|
|
5173
5264
|
title: null,
|
|
@@ -5213,7 +5304,7 @@ function parseC4(content, palette) {
|
|
|
5213
5304
|
}
|
|
5214
5305
|
if (trimmed.startsWith("//")) continue;
|
|
5215
5306
|
if (!contentStarted) {
|
|
5216
|
-
const chartMatch = trimmed.match(
|
|
5307
|
+
const chartMatch = trimmed.match(CHART_TYPE_RE);
|
|
5217
5308
|
if (chartMatch) {
|
|
5218
5309
|
const chartType = chartMatch[1].trim().toLowerCase();
|
|
5219
5310
|
if (chartType !== "c4") {
|
|
@@ -5227,49 +5318,50 @@ function parseC4(content, palette) {
|
|
|
5227
5318
|
}
|
|
5228
5319
|
}
|
|
5229
5320
|
if (!contentStarted) {
|
|
5230
|
-
const titleMatch = trimmed.match(
|
|
5321
|
+
const titleMatch = trimmed.match(TITLE_RE);
|
|
5231
5322
|
if (titleMatch) {
|
|
5232
5323
|
result.title = titleMatch[1].trim();
|
|
5233
5324
|
result.titleLineNumber = lineNumber;
|
|
5234
5325
|
continue;
|
|
5235
5326
|
}
|
|
5236
5327
|
}
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
if (optMatch && !trimmed.startsWith("##")) {
|
|
5240
|
-
const key = optMatch[1].trim().toLowerCase();
|
|
5241
|
-
if (key !== "chart" && key !== "title") {
|
|
5242
|
-
result.options[key] = optMatch[2].trim();
|
|
5243
|
-
continue;
|
|
5244
|
-
}
|
|
5245
|
-
}
|
|
5246
|
-
}
|
|
5247
|
-
const groupMatch = trimmed.match(GROUP_HEADING_RE4);
|
|
5248
|
-
if (groupMatch) {
|
|
5328
|
+
const tagBlockMatch = matchTagBlockHeading(trimmed);
|
|
5329
|
+
if (tagBlockMatch) {
|
|
5249
5330
|
if (contentStarted) {
|
|
5250
|
-
pushError(lineNumber, "Tag groups
|
|
5331
|
+
pushError(lineNumber, "Tag groups must appear before content");
|
|
5251
5332
|
continue;
|
|
5252
5333
|
}
|
|
5253
|
-
|
|
5254
|
-
|
|
5334
|
+
if (tagBlockMatch.deprecated) {
|
|
5335
|
+
pushError(lineNumber, `'## ${tagBlockMatch.name}' is deprecated for tag groups \u2014 use 'tag: ${tagBlockMatch.name}' instead`, "warning");
|
|
5336
|
+
}
|
|
5255
5337
|
currentTagGroup = {
|
|
5256
|
-
name:
|
|
5257
|
-
alias,
|
|
5338
|
+
name: tagBlockMatch.name,
|
|
5339
|
+
alias: tagBlockMatch.alias,
|
|
5258
5340
|
entries: [],
|
|
5259
5341
|
lineNumber
|
|
5260
5342
|
};
|
|
5261
|
-
if (alias) {
|
|
5262
|
-
aliasMap.set(alias.toLowerCase(),
|
|
5343
|
+
if (tagBlockMatch.alias) {
|
|
5344
|
+
aliasMap.set(tagBlockMatch.alias.toLowerCase(), tagBlockMatch.name.toLowerCase());
|
|
5263
5345
|
}
|
|
5264
5346
|
result.tagGroups.push(currentTagGroup);
|
|
5265
5347
|
continue;
|
|
5266
5348
|
}
|
|
5349
|
+
if (!contentStarted && !currentTagGroup && measureIndent(line7) === 0) {
|
|
5350
|
+
const optMatch = trimmed.match(OPTION_RE);
|
|
5351
|
+
if (optMatch) {
|
|
5352
|
+
const key = optMatch[1].trim().toLowerCase();
|
|
5353
|
+
if (key !== "chart" && key !== "title") {
|
|
5354
|
+
result.options[key] = optMatch[2].trim();
|
|
5355
|
+
continue;
|
|
5356
|
+
}
|
|
5357
|
+
}
|
|
5358
|
+
}
|
|
5267
5359
|
if (currentTagGroup && !contentStarted) {
|
|
5268
|
-
const indent2 =
|
|
5360
|
+
const indent2 = measureIndent(line7);
|
|
5269
5361
|
if (indent2 > 0) {
|
|
5270
5362
|
const isDefault = /\bdefault\s*$/.test(trimmed);
|
|
5271
5363
|
const entryText = isDefault ? trimmed.replace(/\s+default\s*$/, "").trim() : trimmed;
|
|
5272
|
-
const { label, color } =
|
|
5364
|
+
const { label, color } = extractColor(entryText, palette);
|
|
5273
5365
|
if (!color) {
|
|
5274
5366
|
pushError(
|
|
5275
5367
|
lineNumber,
|
|
@@ -5294,7 +5386,7 @@ function parseC4(content, palette) {
|
|
|
5294
5386
|
if (!sawChartType) {
|
|
5295
5387
|
return fail(lineNumber, 'Missing "chart: c4" header');
|
|
5296
5388
|
}
|
|
5297
|
-
const indent =
|
|
5389
|
+
const indent = measureIndent(line7);
|
|
5298
5390
|
if (inDeployment) {
|
|
5299
5391
|
while (deployStack.length > 0) {
|
|
5300
5392
|
const top = deployStack[deployStack.length - 1];
|
|
@@ -5389,6 +5481,45 @@ function parseC4(content, palette) {
|
|
|
5389
5481
|
}
|
|
5390
5482
|
continue;
|
|
5391
5483
|
}
|
|
5484
|
+
{
|
|
5485
|
+
const labeledPatterns = [
|
|
5486
|
+
{ re: C4_LABELED_BIDI_SYNC_RE, arrowType: "bidirectional" },
|
|
5487
|
+
{ re: C4_LABELED_BIDI_ASYNC_RE, arrowType: "bidirectional-async" },
|
|
5488
|
+
{ re: C4_LABELED_SYNC_RE, arrowType: "sync" },
|
|
5489
|
+
{ re: C4_LABELED_ASYNC_RE, arrowType: "async" }
|
|
5490
|
+
];
|
|
5491
|
+
let labeledHandled = false;
|
|
5492
|
+
for (const { re, arrowType } of labeledPatterns) {
|
|
5493
|
+
const m = trimmed.match(re);
|
|
5494
|
+
if (!m) continue;
|
|
5495
|
+
const rawLabel = m[1].trim();
|
|
5496
|
+
const targetBody = m[2].trim();
|
|
5497
|
+
if (!rawLabel) break;
|
|
5498
|
+
let label = rawLabel;
|
|
5499
|
+
let technology;
|
|
5500
|
+
const techMatch = rawLabel.match(/\[([^\]]+)\]\s*$/);
|
|
5501
|
+
if (techMatch) {
|
|
5502
|
+
label = rawLabel.substring(0, techMatch.index).trim() || void 0;
|
|
5503
|
+
technology = techMatch[1].trim();
|
|
5504
|
+
}
|
|
5505
|
+
const rel = {
|
|
5506
|
+
target: targetBody,
|
|
5507
|
+
label,
|
|
5508
|
+
technology,
|
|
5509
|
+
arrowType,
|
|
5510
|
+
lineNumber
|
|
5511
|
+
};
|
|
5512
|
+
const parentEntry = findParentElement(indent, stack);
|
|
5513
|
+
if (parentEntry) {
|
|
5514
|
+
parentEntry.element.relationships.push(rel);
|
|
5515
|
+
} else {
|
|
5516
|
+
result.relationships.push(rel);
|
|
5517
|
+
}
|
|
5518
|
+
labeledHandled = true;
|
|
5519
|
+
break;
|
|
5520
|
+
}
|
|
5521
|
+
if (labeledHandled) continue;
|
|
5522
|
+
}
|
|
5392
5523
|
const relMatch = trimmed.match(RELATIONSHIP_RE);
|
|
5393
5524
|
if (relMatch) {
|
|
5394
5525
|
const arrowType = parseArrowType(relMatch[1]);
|
|
@@ -5578,22 +5709,22 @@ function validateDeploymentRefs(result, knownNames, pushWarning) {
|
|
|
5578
5709
|
}
|
|
5579
5710
|
walkDeploy(result.deployment);
|
|
5580
5711
|
}
|
|
5581
|
-
var
|
|
5712
|
+
var CONTAINER_RE2, ELEMENT_RE, IS_A_RE, RELATIONSHIP_RE, C4_LABELED_SYNC_RE, C4_LABELED_ASYNC_RE, C4_LABELED_BIDI_SYNC_RE, C4_LABELED_BIDI_ASYNC_RE, SECTION_HEADER_RE, CONTAINER_REF_RE, METADATA_RE2, VALID_ELEMENT_TYPES, VALID_SHAPES, ALL_CHART_TYPES;
|
|
5582
5713
|
var init_parser6 = __esm({
|
|
5583
5714
|
"src/c4/parser.ts"() {
|
|
5584
5715
|
"use strict";
|
|
5585
|
-
init_colors();
|
|
5586
5716
|
init_diagnostics();
|
|
5717
|
+
init_tag_groups();
|
|
5587
5718
|
init_participant_inference();
|
|
5588
|
-
|
|
5589
|
-
TITLE_RE3 = /^title\s*:\s*(.+)/i;
|
|
5590
|
-
OPTION_RE3 = /^([a-z][a-z0-9-]*)\s*:\s*(.+)$/i;
|
|
5591
|
-
GROUP_HEADING_RE4 = /^##\s+(.+?)(?:\s+alias\s+(\w+))?(?:\s*\(([^)]+)\))?\s*$/;
|
|
5592
|
-
COLOR_SUFFIX_RE4 = /\(([^)]+)\)\s*$/;
|
|
5719
|
+
init_parsing();
|
|
5593
5720
|
CONTAINER_RE2 = /^\[([^\]]+)\]$/;
|
|
5594
5721
|
ELEMENT_RE = /^(person|system|container|component)\s+(.+)$/i;
|
|
5595
5722
|
IS_A_RE = /\s+is\s+a(?:n)?\s+(\w+)\s*$/i;
|
|
5596
5723
|
RELATIONSHIP_RE = /^(<?-?>|<?~?>)\s+(.+)$/;
|
|
5724
|
+
C4_LABELED_SYNC_RE = /^-(.+)->\s+(.+)$/;
|
|
5725
|
+
C4_LABELED_ASYNC_RE = /^~(.+)~>\s+(.+)$/;
|
|
5726
|
+
C4_LABELED_BIDI_SYNC_RE = /^<-(.+)->\s+(.+)$/;
|
|
5727
|
+
C4_LABELED_BIDI_ASYNC_RE = /^<~(.+)~>\s+(.+)$/;
|
|
5597
5728
|
SECTION_HEADER_RE = /^(containers|components|deployment)\s*:\s*$/i;
|
|
5598
5729
|
CONTAINER_REF_RE = /^container\s+(.+)$/i;
|
|
5599
5730
|
METADATA_RE2 = /^([^:]+):\s*(.+)$/;
|
|
@@ -5651,20 +5782,23 @@ function looksLikeInitiativeStatus(content) {
|
|
|
5651
5782
|
const lines = content.split("\n");
|
|
5652
5783
|
let hasArrow = false;
|
|
5653
5784
|
let hasStatus = false;
|
|
5785
|
+
let hasIndentedArrow = false;
|
|
5654
5786
|
for (const line7 of lines) {
|
|
5655
5787
|
const trimmed = line7.trim();
|
|
5656
|
-
if (!trimmed || trimmed.startsWith("
|
|
5788
|
+
if (!trimmed || trimmed.startsWith("//")) continue;
|
|
5657
5789
|
if (trimmed.match(/^chart\s*:/i)) continue;
|
|
5658
5790
|
if (trimmed.match(/^title\s*:/i)) continue;
|
|
5659
5791
|
if (trimmed.includes("->")) hasArrow = true;
|
|
5660
5792
|
if (/\|\s*(done|wip|todo|na)\s*$/i.test(trimmed)) hasStatus = true;
|
|
5793
|
+
const isIndented = line7.length > 0 && line7 !== trimmed && /^\s/.test(line7);
|
|
5794
|
+
if (isIndented && (trimmed.startsWith("->") || /^-[^>].*->/.test(trimmed))) hasIndentedArrow = true;
|
|
5661
5795
|
if (hasArrow && hasStatus) return true;
|
|
5662
5796
|
}
|
|
5663
|
-
return
|
|
5797
|
+
return hasIndentedArrow;
|
|
5664
5798
|
}
|
|
5665
5799
|
function parseStatus(raw, line7, diagnostics) {
|
|
5666
5800
|
const trimmed = raw.trim().toLowerCase();
|
|
5667
|
-
if (!trimmed) return
|
|
5801
|
+
if (!trimmed) return "na";
|
|
5668
5802
|
if (VALID_STATUSES.includes(trimmed)) return trimmed;
|
|
5669
5803
|
const hint = suggest(trimmed, VALID_STATUSES);
|
|
5670
5804
|
const msg = `Unknown status "${raw.trim()}"${hint ? `. ${hint}` : ""}`;
|
|
@@ -5681,16 +5815,17 @@ function parseInitiativeStatus(content) {
|
|
|
5681
5815
|
groups: [],
|
|
5682
5816
|
options: {},
|
|
5683
5817
|
diagnostics: [],
|
|
5684
|
-
error:
|
|
5818
|
+
error: null
|
|
5685
5819
|
};
|
|
5686
5820
|
const lines = content.split("\n");
|
|
5687
5821
|
const nodeLabels = /* @__PURE__ */ new Set();
|
|
5688
5822
|
let currentGroup = null;
|
|
5823
|
+
let lastNodeLabel = null;
|
|
5689
5824
|
for (let i = 0; i < lines.length; i++) {
|
|
5690
5825
|
const lineNum = i + 1;
|
|
5691
5826
|
const raw = lines[i];
|
|
5692
5827
|
const trimmed = raw.trim();
|
|
5693
|
-
if (!trimmed || trimmed.startsWith("
|
|
5828
|
+
if (!trimmed || trimmed.startsWith("//")) continue;
|
|
5694
5829
|
const chartMatch = trimmed.match(/^chart\s*:\s*(.+)/i);
|
|
5695
5830
|
if (chartMatch) {
|
|
5696
5831
|
const chartType = chartMatch[1].trim().toLowerCase();
|
|
@@ -5722,12 +5857,23 @@ function parseInitiativeStatus(content) {
|
|
|
5722
5857
|
currentGroup = null;
|
|
5723
5858
|
}
|
|
5724
5859
|
if (trimmed.includes("->")) {
|
|
5725
|
-
|
|
5860
|
+
let edgeText = trimmed;
|
|
5861
|
+
if (trimmed.startsWith("->") || /^-[^>].*->/.test(trimmed)) {
|
|
5862
|
+
if (!lastNodeLabel) {
|
|
5863
|
+
result.diagnostics.push(
|
|
5864
|
+
makeDgmoError(lineNum, "Indented edge has no preceding node to use as source", "warning")
|
|
5865
|
+
);
|
|
5866
|
+
continue;
|
|
5867
|
+
}
|
|
5868
|
+
edgeText = `${lastNodeLabel} ${trimmed}`;
|
|
5869
|
+
}
|
|
5870
|
+
const edge = parseEdgeLine(edgeText, lineNum, result.diagnostics);
|
|
5726
5871
|
if (edge) result.edges.push(edge);
|
|
5727
5872
|
continue;
|
|
5728
5873
|
}
|
|
5729
5874
|
const node = parseNodeLine(trimmed, lineNum, result.diagnostics);
|
|
5730
5875
|
if (node) {
|
|
5876
|
+
lastNodeLabel = node.label;
|
|
5731
5877
|
if (nodeLabels.has(node.label)) {
|
|
5732
5878
|
result.diagnostics.push(
|
|
5733
5879
|
makeDgmoError(lineNum, `Duplicate node "${node.label}"`, "warning")
|
|
@@ -5750,7 +5896,7 @@ function parseInitiativeStatus(content) {
|
|
|
5750
5896
|
makeDgmoError(edge.lineNumber, `Edge source "${edge.source}" is not a declared node`, "warning")
|
|
5751
5897
|
);
|
|
5752
5898
|
if (!result.nodes.some((n) => n.label === edge.source)) {
|
|
5753
|
-
result.nodes.push({ label: edge.source, status:
|
|
5899
|
+
result.nodes.push({ label: edge.source, status: "na", shape: inferParticipantType(edge.source), lineNumber: edge.lineNumber });
|
|
5754
5900
|
nodeLabels.add(edge.source);
|
|
5755
5901
|
}
|
|
5756
5902
|
}
|
|
@@ -5759,7 +5905,7 @@ function parseInitiativeStatus(content) {
|
|
|
5759
5905
|
makeDgmoError(edge.lineNumber, `Edge target "${edge.target}" is not a declared node`, "warning")
|
|
5760
5906
|
);
|
|
5761
5907
|
if (!result.nodes.some((n) => n.label === edge.target)) {
|
|
5762
|
-
result.nodes.push({ label: edge.target, status:
|
|
5908
|
+
result.nodes.push({ label: edge.target, status: "na", shape: inferParticipantType(edge.target), lineNumber: edge.lineNumber });
|
|
5763
5909
|
nodeLabels.add(edge.target);
|
|
5764
5910
|
}
|
|
5765
5911
|
}
|
|
@@ -5775,9 +5921,30 @@ function parseNodeLine(trimmed, lineNum, diagnostics) {
|
|
|
5775
5921
|
const status = parseStatus(statusRaw, lineNum, diagnostics);
|
|
5776
5922
|
return { label, status, shape: inferParticipantType(label), lineNumber: lineNum };
|
|
5777
5923
|
}
|
|
5778
|
-
return { label: trimmed, status:
|
|
5924
|
+
return { label: trimmed, status: "na", shape: inferParticipantType(trimmed), lineNumber: lineNum };
|
|
5779
5925
|
}
|
|
5780
5926
|
function parseEdgeLine(trimmed, lineNum, diagnostics) {
|
|
5927
|
+
const labeledMatch = trimmed.match(/^(\S+)\s+-(.+)->\s+(.+)$/);
|
|
5928
|
+
if (labeledMatch) {
|
|
5929
|
+
const source2 = labeledMatch[1];
|
|
5930
|
+
const label2 = labeledMatch[2].trim();
|
|
5931
|
+
let targetRest = labeledMatch[3].trim();
|
|
5932
|
+
if (label2) {
|
|
5933
|
+
let status2 = "na";
|
|
5934
|
+
const lastPipe2 = targetRest.lastIndexOf("|");
|
|
5935
|
+
if (lastPipe2 >= 0) {
|
|
5936
|
+
const statusRaw = targetRest.slice(lastPipe2 + 1).trim();
|
|
5937
|
+
status2 = parseStatus(statusRaw, lineNum, diagnostics);
|
|
5938
|
+
targetRest = targetRest.slice(0, lastPipe2).trim();
|
|
5939
|
+
}
|
|
5940
|
+
const target2 = targetRest.trim();
|
|
5941
|
+
if (!target2) {
|
|
5942
|
+
diagnostics.push(makeDgmoError(lineNum, "Edge is missing target"));
|
|
5943
|
+
return null;
|
|
5944
|
+
}
|
|
5945
|
+
return { source: source2, target: target2, label: label2, status: status2, lineNumber: lineNum };
|
|
5946
|
+
}
|
|
5947
|
+
}
|
|
5781
5948
|
const arrowIdx = trimmed.indexOf("->");
|
|
5782
5949
|
if (arrowIdx < 0) return null;
|
|
5783
5950
|
const source = trimmed.slice(0, arrowIdx).trim();
|
|
@@ -5786,7 +5953,7 @@ function parseEdgeLine(trimmed, lineNum, diagnostics) {
|
|
|
5786
5953
|
diagnostics.push(makeDgmoError(lineNum, "Edge is missing source or target"));
|
|
5787
5954
|
return null;
|
|
5788
5955
|
}
|
|
5789
|
-
let status =
|
|
5956
|
+
let status = "na";
|
|
5790
5957
|
const lastPipe = rest.lastIndexOf("|");
|
|
5791
5958
|
if (lastPipe >= 0) {
|
|
5792
5959
|
const statusRaw = rest.slice(lastPipe + 1).trim();
|
|
@@ -5832,7 +5999,7 @@ function parseDgmoChartType(content) {
|
|
|
5832
5999
|
const lines = content.split("\n");
|
|
5833
6000
|
for (const line7 of lines) {
|
|
5834
6001
|
const trimmed = line7.trim();
|
|
5835
|
-
if (!trimmed || trimmed.startsWith("
|
|
6002
|
+
if (!trimmed || trimmed.startsWith("//"))
|
|
5836
6003
|
continue;
|
|
5837
6004
|
const match = trimmed.match(/^chart\s*:\s*(.+)/i);
|
|
5838
6005
|
if (match) return match[1].trim().toLowerCase();
|
|
@@ -7094,6 +7261,58 @@ var init_renderer = __esm({
|
|
|
7094
7261
|
}
|
|
7095
7262
|
});
|
|
7096
7263
|
|
|
7264
|
+
// src/utils/inline-markdown.ts
|
|
7265
|
+
function parseInlineMarkdown(text) {
|
|
7266
|
+
const spans = [];
|
|
7267
|
+
const regex = /\*\*(.+?)\*\*|__(.+?)__|\*(.+?)\*|_(.+?)_|`(.+?)`|\[(.+?)\]\((.+?)\)|(https?:\/\/[^\s)>\]]+|www\.[^\s)>\]]+)|([^*_`[]+?(?=https?:\/\/|www\.|$)|[^*_`[]+)/g;
|
|
7268
|
+
let match;
|
|
7269
|
+
while ((match = regex.exec(text)) !== null) {
|
|
7270
|
+
if (match[1]) spans.push({ text: match[1], bold: true });
|
|
7271
|
+
else if (match[2]) spans.push({ text: match[2], bold: true });
|
|
7272
|
+
else if (match[3]) spans.push({ text: match[3], italic: true });
|
|
7273
|
+
else if (match[4]) spans.push({ text: match[4], italic: true });
|
|
7274
|
+
else if (match[5]) spans.push({ text: match[5], code: true });
|
|
7275
|
+
else if (match[6]) spans.push({ text: match[6], href: match[7] });
|
|
7276
|
+
else if (match[8]) {
|
|
7277
|
+
const url = match[8];
|
|
7278
|
+
const href = url.startsWith("www.") ? `https://${url}` : url;
|
|
7279
|
+
spans.push({ text: url, href });
|
|
7280
|
+
} else if (match[9]) spans.push({ text: match[9] });
|
|
7281
|
+
}
|
|
7282
|
+
return spans;
|
|
7283
|
+
}
|
|
7284
|
+
function truncateBareUrl(url) {
|
|
7285
|
+
const stripped = url.replace(/^https?:\/\//, "").replace(/^www\./, "");
|
|
7286
|
+
if (stripped.length <= BARE_URL_MAX_DISPLAY) return stripped;
|
|
7287
|
+
return stripped.slice(0, BARE_URL_MAX_DISPLAY - 1) + "\u2026";
|
|
7288
|
+
}
|
|
7289
|
+
function renderInlineText(textEl, text, palette, fontSize) {
|
|
7290
|
+
const spans = parseInlineMarkdown(text);
|
|
7291
|
+
for (const span of spans) {
|
|
7292
|
+
if (span.href) {
|
|
7293
|
+
const isBareUrl = span.text === span.href || `https://${span.text}` === span.href;
|
|
7294
|
+
const display = isBareUrl ? truncateBareUrl(span.text) : span.text;
|
|
7295
|
+
const a = textEl.append("a").attr("href", span.href);
|
|
7296
|
+
a.append("tspan").text(display).attr("fill", palette.primary).style("text-decoration", "underline");
|
|
7297
|
+
} else {
|
|
7298
|
+
const tspan = textEl.append("tspan").text(span.text);
|
|
7299
|
+
if (span.bold) tspan.attr("font-weight", "bold");
|
|
7300
|
+
if (span.italic) tspan.attr("font-style", "italic");
|
|
7301
|
+
if (span.code) {
|
|
7302
|
+
tspan.attr("font-family", "monospace");
|
|
7303
|
+
if (fontSize) tspan.attr("font-size", fontSize - 1);
|
|
7304
|
+
}
|
|
7305
|
+
}
|
|
7306
|
+
}
|
|
7307
|
+
}
|
|
7308
|
+
var BARE_URL_MAX_DISPLAY;
|
|
7309
|
+
var init_inline_markdown = __esm({
|
|
7310
|
+
"src/utils/inline-markdown.ts"() {
|
|
7311
|
+
"use strict";
|
|
7312
|
+
BARE_URL_MAX_DISPLAY = 35;
|
|
7313
|
+
}
|
|
7314
|
+
});
|
|
7315
|
+
|
|
7097
7316
|
// src/kanban/mutations.ts
|
|
7098
7317
|
function computeCardMove(content, parsed, cardId, targetColumnId, targetIndex) {
|
|
7099
7318
|
let sourceCard = null;
|
|
@@ -7416,7 +7635,8 @@ function renderKanban(container, parsed, palette, isDark, _onNavigateToLine, exp
|
|
|
7416
7635
|
const cx = colLayout.x + cardLayout.x;
|
|
7417
7636
|
const cy = colLayout.y + cardLayout.y;
|
|
7418
7637
|
cg.append("rect").attr("x", cx).attr("y", cy).attr("width", cardLayout.width).attr("height", cardLayout.height).attr("rx", CARD_RADIUS2).attr("fill", cardFill).attr("stroke", cardStroke).attr("stroke-width", CARD_STROKE_WIDTH);
|
|
7419
|
-
cg.append("text").attr("x", cx + CARD_PADDING_X).attr("y", cy + CARD_PADDING_Y + CARD_TITLE_FONT_SIZE).attr("font-size", CARD_TITLE_FONT_SIZE).attr("font-weight", "500").attr("fill", palette.text)
|
|
7638
|
+
const titleEl = cg.append("text").attr("x", cx + CARD_PADDING_X).attr("y", cy + CARD_PADDING_Y + CARD_TITLE_FONT_SIZE).attr("font-size", CARD_TITLE_FONT_SIZE).attr("font-weight", "500").attr("fill", palette.text);
|
|
7639
|
+
renderInlineText(titleEl, card.title, palette, CARD_TITLE_FONT_SIZE);
|
|
7420
7640
|
if (hasMeta) {
|
|
7421
7641
|
const separatorY = cy + CARD_HEADER_HEIGHT;
|
|
7422
7642
|
cg.append("line").attr("x1", cx).attr("y1", separatorY).attr("x2", cx + cardLayout.width).attr("y2", separatorY).attr("stroke", cardStroke).attr("stroke-opacity", 0.3).attr("stroke-width", 1);
|
|
@@ -7428,7 +7648,8 @@ function renderKanban(container, parsed, palette, isDark, _onNavigateToLine, exp
|
|
|
7428
7648
|
metaY += CARD_META_LINE_HEIGHT;
|
|
7429
7649
|
}
|
|
7430
7650
|
for (const detail of card.details) {
|
|
7431
|
-
cg.append("text").attr("x", cx + CARD_PADDING_X).attr("y", metaY).attr("font-size", CARD_META_FONT_SIZE).attr("fill", palette.textMuted)
|
|
7651
|
+
const detailEl = cg.append("text").attr("x", cx + CARD_PADDING_X).attr("y", metaY).attr("font-size", CARD_META_FONT_SIZE).attr("fill", palette.textMuted);
|
|
7652
|
+
renderInlineText(detailEl, detail, palette, CARD_META_FONT_SIZE);
|
|
7432
7653
|
metaY += CARD_META_LINE_HEIGHT;
|
|
7433
7654
|
}
|
|
7434
7655
|
}
|
|
@@ -7453,6 +7674,7 @@ var init_renderer2 = __esm({
|
|
|
7453
7674
|
"src/kanban/renderer.ts"() {
|
|
7454
7675
|
"use strict";
|
|
7455
7676
|
init_fonts();
|
|
7677
|
+
init_inline_markdown();
|
|
7456
7678
|
init_parser5();
|
|
7457
7679
|
init_mutations();
|
|
7458
7680
|
DIAGRAM_PADDING2 = 20;
|
|
@@ -10600,7 +10822,8 @@ function renderC4Context(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10600
10822
|
const contentWidth = w - CARD_H_PAD3 * 2;
|
|
10601
10823
|
const lines = wrapText2(node.description, contentWidth, DESC_CHAR_WIDTH2);
|
|
10602
10824
|
for (const line7 of lines) {
|
|
10603
|
-
nodeG.append("text").attr("x", 0).attr("y", yPos + DESC_FONT_SIZE / 2).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", palette.textMuted).attr("font-size", DESC_FONT_SIZE)
|
|
10825
|
+
const textEl = nodeG.append("text").attr("x", 0).attr("y", yPos + DESC_FONT_SIZE / 2).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", palette.textMuted).attr("font-size", DESC_FONT_SIZE);
|
|
10826
|
+
renderInlineText(textEl, line7, palette, DESC_FONT_SIZE);
|
|
10604
10827
|
yPos += DESC_LINE_HEIGHT2;
|
|
10605
10828
|
}
|
|
10606
10829
|
}
|
|
@@ -11086,7 +11309,8 @@ function renderC4Containers(container, parsed, layout, palette, isDark, onClickI
|
|
|
11086
11309
|
const contentWidth = w - CARD_H_PAD3 * 2;
|
|
11087
11310
|
const lines = wrapText2(node.description, contentWidth, DESC_CHAR_WIDTH2);
|
|
11088
11311
|
for (const line7 of lines) {
|
|
11089
|
-
nodeG.append("text").attr("x", 0).attr("y", yPos + DESC_FONT_SIZE / 2).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", palette.textMuted).attr("font-size", DESC_FONT_SIZE)
|
|
11312
|
+
const textEl = nodeG.append("text").attr("x", 0).attr("y", yPos + DESC_FONT_SIZE / 2).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", palette.textMuted).attr("font-size", DESC_FONT_SIZE);
|
|
11313
|
+
renderInlineText(textEl, line7, palette, DESC_FONT_SIZE);
|
|
11090
11314
|
yPos += DESC_LINE_HEIGHT2;
|
|
11091
11315
|
}
|
|
11092
11316
|
}
|
|
@@ -11109,7 +11333,8 @@ function renderC4Containers(container, parsed, layout, palette, isDark, onClickI
|
|
|
11109
11333
|
const contentWidth = w - CARD_H_PAD3 * 2;
|
|
11110
11334
|
const lines = wrapText2(node.description, contentWidth, DESC_CHAR_WIDTH2);
|
|
11111
11335
|
for (const line7 of lines) {
|
|
11112
|
-
nodeG.append("text").attr("x", 0).attr("y", yPos + DESC_FONT_SIZE / 2).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", palette.textMuted).attr("font-size", DESC_FONT_SIZE)
|
|
11336
|
+
const textEl = nodeG.append("text").attr("x", 0).attr("y", yPos + DESC_FONT_SIZE / 2).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", palette.textMuted).attr("font-size", DESC_FONT_SIZE);
|
|
11337
|
+
renderInlineText(textEl, line7, palette, DESC_FONT_SIZE);
|
|
11113
11338
|
yPos += DESC_LINE_HEIGHT2;
|
|
11114
11339
|
}
|
|
11115
11340
|
}
|
|
@@ -11228,6 +11453,7 @@ var init_renderer6 = __esm({
|
|
|
11228
11453
|
"src/c4/renderer.ts"() {
|
|
11229
11454
|
"use strict";
|
|
11230
11455
|
init_fonts();
|
|
11456
|
+
init_inline_markdown();
|
|
11231
11457
|
init_parser6();
|
|
11232
11458
|
init_layout5();
|
|
11233
11459
|
DIAGRAM_PADDING6 = 20;
|
|
@@ -11726,49 +11952,6 @@ __export(renderer_exports7, {
|
|
|
11726
11952
|
truncateBareUrl: () => truncateBareUrl
|
|
11727
11953
|
});
|
|
11728
11954
|
import * as d3Selection8 from "d3-selection";
|
|
11729
|
-
function parseInlineMarkdown(text) {
|
|
11730
|
-
const spans = [];
|
|
11731
|
-
const regex = /\*\*(.+?)\*\*|__(.+?)__|\*(.+?)\*|_(.+?)_|`(.+?)`|\[(.+?)\]\((.+?)\)|(https?:\/\/[^\s)>\]]+|www\.[^\s)>\]]+)|([^*_`[]+?(?=https?:\/\/|www\.|$)|[^*_`[]+)/g;
|
|
11732
|
-
let match;
|
|
11733
|
-
while ((match = regex.exec(text)) !== null) {
|
|
11734
|
-
if (match[1]) spans.push({ text: match[1], bold: true });
|
|
11735
|
-
else if (match[2]) spans.push({ text: match[2], bold: true });
|
|
11736
|
-
else if (match[3]) spans.push({ text: match[3], italic: true });
|
|
11737
|
-
else if (match[4]) spans.push({ text: match[4], italic: true });
|
|
11738
|
-
else if (match[5]) spans.push({ text: match[5], code: true });
|
|
11739
|
-
else if (match[6]) spans.push({ text: match[6], href: match[7] });
|
|
11740
|
-
else if (match[8]) {
|
|
11741
|
-
const url = match[8];
|
|
11742
|
-
const href = url.startsWith("www.") ? `https://${url}` : url;
|
|
11743
|
-
spans.push({ text: url, href });
|
|
11744
|
-
} else if (match[9]) spans.push({ text: match[9] });
|
|
11745
|
-
}
|
|
11746
|
-
return spans;
|
|
11747
|
-
}
|
|
11748
|
-
function truncateBareUrl(url) {
|
|
11749
|
-
const stripped = url.replace(/^https?:\/\//, "").replace(/^www\./, "");
|
|
11750
|
-
if (stripped.length <= BARE_URL_MAX_DISPLAY) return stripped;
|
|
11751
|
-
return stripped.slice(0, BARE_URL_MAX_DISPLAY - 1) + "\u2026";
|
|
11752
|
-
}
|
|
11753
|
-
function renderInlineText(textEl, text, palette, fontSize) {
|
|
11754
|
-
const spans = parseInlineMarkdown(text);
|
|
11755
|
-
for (const span of spans) {
|
|
11756
|
-
if (span.href) {
|
|
11757
|
-
const isBareUrl = span.text === span.href || `https://${span.text}` === span.href;
|
|
11758
|
-
const display = isBareUrl ? truncateBareUrl(span.text) : span.text;
|
|
11759
|
-
const a = textEl.append("a").attr("href", span.href);
|
|
11760
|
-
a.append("tspan").text(display).attr("fill", palette.primary).style("text-decoration", "underline");
|
|
11761
|
-
} else {
|
|
11762
|
-
const tspan = textEl.append("tspan").text(span.text);
|
|
11763
|
-
if (span.bold) tspan.attr("font-weight", "bold");
|
|
11764
|
-
if (span.italic) tspan.attr("font-style", "italic");
|
|
11765
|
-
if (span.code) {
|
|
11766
|
-
tspan.attr("font-family", "monospace");
|
|
11767
|
-
if (fontSize) tspan.attr("font-size", fontSize - 1);
|
|
11768
|
-
}
|
|
11769
|
-
}
|
|
11770
|
-
}
|
|
11771
|
-
}
|
|
11772
11955
|
function wrapTextLines(text, maxChars) {
|
|
11773
11956
|
const rawLines = text.split("\n");
|
|
11774
11957
|
const wrapped = [];
|
|
@@ -11949,8 +12132,12 @@ function buildRenderSequence(messages) {
|
|
|
11949
12132
|
to: msg.to,
|
|
11950
12133
|
label: msg.label,
|
|
11951
12134
|
messageIndex: mi,
|
|
11952
|
-
...msg.async ? { async: true } : {}
|
|
12135
|
+
...msg.async ? { async: true } : {},
|
|
12136
|
+
...msg.bidirectional ? { bidirectional: true } : {}
|
|
11953
12137
|
});
|
|
12138
|
+
if (msg.bidirectional) {
|
|
12139
|
+
continue;
|
|
12140
|
+
}
|
|
11954
12141
|
if (msg.async) {
|
|
11955
12142
|
continue;
|
|
11956
12143
|
}
|
|
@@ -12442,6 +12629,14 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
12442
12629
|
"points",
|
|
12443
12630
|
`0,0 ${ARROWHEAD_SIZE},${ARROWHEAD_SIZE / 2} 0,${ARROWHEAD_SIZE}`
|
|
12444
12631
|
).attr("fill", "none").attr("stroke", palette.text).attr("stroke-width", 1.2);
|
|
12632
|
+
defs.append("marker").attr("id", "seq-arrowhead-reverse").attr("viewBox", `0 0 ${ARROWHEAD_SIZE} ${ARROWHEAD_SIZE}`).attr("refX", 0).attr("refY", ARROWHEAD_SIZE / 2).attr("markerWidth", ARROWHEAD_SIZE).attr("markerHeight", ARROWHEAD_SIZE).attr("orient", "auto").append("polygon").attr(
|
|
12633
|
+
"points",
|
|
12634
|
+
`${ARROWHEAD_SIZE},0 0,${ARROWHEAD_SIZE / 2} ${ARROWHEAD_SIZE},${ARROWHEAD_SIZE}`
|
|
12635
|
+
).attr("fill", palette.text);
|
|
12636
|
+
defs.append("marker").attr("id", "seq-arrowhead-async-reverse").attr("viewBox", `0 0 ${ARROWHEAD_SIZE} ${ARROWHEAD_SIZE}`).attr("refX", 0).attr("refY", ARROWHEAD_SIZE / 2).attr("markerWidth", ARROWHEAD_SIZE).attr("markerHeight", ARROWHEAD_SIZE).attr("orient", "auto").append("polyline").attr(
|
|
12637
|
+
"points",
|
|
12638
|
+
`${ARROWHEAD_SIZE},0 0,${ARROWHEAD_SIZE / 2} ${ARROWHEAD_SIZE},${ARROWHEAD_SIZE}`
|
|
12639
|
+
).attr("fill", "none").attr("stroke", palette.text).attr("stroke-width", 1.2);
|
|
12445
12640
|
if (title) {
|
|
12446
12641
|
const titleEl = svg.append("text").attr("class", "chart-title").attr("x", svgWidth / 2).attr("y", 30).attr("text-anchor", "middle").attr("fill", palette.text).attr("font-size", 20).attr("font-weight", "bold").text(title);
|
|
12447
12642
|
if (parsed.titleLineNumber) {
|
|
@@ -12722,10 +12917,17 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
12722
12917
|
const x1 = arrowEdgeX(step.from, i, goingRight ? "right" : "left");
|
|
12723
12918
|
const x2 = arrowEdgeX(step.to, i, goingRight ? "left" : "right");
|
|
12724
12919
|
const markerRef = step.async ? "url(#seq-arrowhead-async)" : "url(#seq-arrowhead)";
|
|
12725
|
-
|
|
12920
|
+
const markerStartRef = step.bidirectional ? step.async ? "url(#seq-arrowhead-async-reverse)" : "url(#seq-arrowhead-reverse)" : null;
|
|
12921
|
+
const line7 = svg.append("line").attr("x1", x1).attr("y1", y).attr("x2", x2).attr("y2", y).attr("stroke", palette.text).attr("stroke-width", 1.2).attr("marker-end", markerRef).attr("class", "message-arrow").attr(
|
|
12726
12922
|
"data-line-number",
|
|
12727
12923
|
String(messages[step.messageIndex].lineNumber)
|
|
12728
12924
|
).attr("data-msg-index", String(step.messageIndex)).attr("data-step-index", String(i));
|
|
12925
|
+
if (markerStartRef) {
|
|
12926
|
+
line7.attr("marker-start", markerStartRef);
|
|
12927
|
+
}
|
|
12928
|
+
if (step.bidirectional && step.async) {
|
|
12929
|
+
line7.attr("stroke-dasharray", "6 4");
|
|
12930
|
+
}
|
|
12729
12931
|
if (step.label) {
|
|
12730
12932
|
const midX = (x1 + x2) / 2;
|
|
12731
12933
|
const labelEl = svg.append("text").attr("x", midX).attr("y", y - 8).attr("text-anchor", "middle").attr("fill", palette.text).attr("font-size", 12).attr("class", "message-label").attr(
|
|
@@ -12913,11 +13115,12 @@ function renderParticipant(svg, participant, cx, cy, palette, isDark) {
|
|
|
12913
13115
|
isActor ? PARTICIPANT_BOX_HEIGHT + 14 : PARTICIPANT_BOX_HEIGHT / 2 + 5
|
|
12914
13116
|
).attr("text-anchor", "middle").attr("fill", palette.text).attr("font-size", 13).attr("font-weight", 500).text(participant.label);
|
|
12915
13117
|
}
|
|
12916
|
-
var PARTICIPANT_GAP, PARTICIPANT_BOX_WIDTH, PARTICIPANT_BOX_HEIGHT, TOP_MARGIN, TITLE_HEIGHT4, PARTICIPANT_Y_OFFSET, SERVICE_BORDER_RADIUS, MESSAGE_START_OFFSET, LIFELINE_TAIL, ARROWHEAD_SIZE, NOTE_MAX_W, NOTE_FOLD, NOTE_PAD_H, NOTE_PAD_V, NOTE_FONT_SIZE, NOTE_LINE_H, NOTE_GAP, NOTE_CHAR_W, NOTE_CHARS_PER_LINE, COLLAPSED_NOTE_H, COLLAPSED_NOTE_W,
|
|
13118
|
+
var PARTICIPANT_GAP, PARTICIPANT_BOX_WIDTH, PARTICIPANT_BOX_HEIGHT, TOP_MARGIN, TITLE_HEIGHT4, PARTICIPANT_Y_OFFSET, SERVICE_BORDER_RADIUS, MESSAGE_START_OFFSET, LIFELINE_TAIL, ARROWHEAD_SIZE, NOTE_MAX_W, NOTE_FOLD, NOTE_PAD_H, NOTE_PAD_V, NOTE_FONT_SIZE, NOTE_LINE_H, NOTE_GAP, NOTE_CHAR_W, NOTE_CHARS_PER_LINE, COLLAPSED_NOTE_H, COLLAPSED_NOTE_W, fill, stroke, SW, W, H;
|
|
12917
13119
|
var init_renderer7 = __esm({
|
|
12918
13120
|
"src/sequence/renderer.ts"() {
|
|
12919
13121
|
"use strict";
|
|
12920
13122
|
init_colors();
|
|
13123
|
+
init_inline_markdown();
|
|
12921
13124
|
init_fonts();
|
|
12922
13125
|
init_parser();
|
|
12923
13126
|
PARTICIPANT_GAP = 160;
|
|
@@ -12941,7 +13144,6 @@ var init_renderer7 = __esm({
|
|
|
12941
13144
|
NOTE_CHARS_PER_LINE = Math.floor((NOTE_MAX_W - NOTE_PAD_H * 2 - NOTE_FOLD) / NOTE_CHAR_W);
|
|
12942
13145
|
COLLAPSED_NOTE_H = 20;
|
|
12943
13146
|
COLLAPSED_NOTE_W = 40;
|
|
12944
|
-
BARE_URL_MAX_DISPLAY = 35;
|
|
12945
13147
|
fill = (palette, isDark) => mix8(palette.primary, isDark ? palette.surface : palette.bg, isDark ? 15 : 30);
|
|
12946
13148
|
stroke = (palette) => palette.textMuted;
|
|
12947
13149
|
SW = 1.5;
|
|
@@ -13076,7 +13278,7 @@ function parseD3(content, palette) {
|
|
|
13076
13278
|
}
|
|
13077
13279
|
continue;
|
|
13078
13280
|
}
|
|
13079
|
-
if (line7.startsWith("
|
|
13281
|
+
if (line7.startsWith("//")) {
|
|
13080
13282
|
continue;
|
|
13081
13283
|
}
|
|
13082
13284
|
if (result.type === "arc") {
|
|
@@ -16250,7 +16452,7 @@ function parseQuadrant(content) {
|
|
|
16250
16452
|
for (let i = 0; i < lines.length; i++) {
|
|
16251
16453
|
const line7 = lines[i].trim();
|
|
16252
16454
|
const lineNumber = i + 1;
|
|
16253
|
-
if (!line7 || line7.startsWith("
|
|
16455
|
+
if (!line7 || line7.startsWith("//")) continue;
|
|
16254
16456
|
if (/^chart\s*:/i.test(line7)) continue;
|
|
16255
16457
|
const titleMatch = line7.match(/^title\s*:\s*(.+)/i);
|
|
16256
16458
|
if (titleMatch) {
|
|
@@ -16380,6 +16582,7 @@ init_renderer3();
|
|
|
16380
16582
|
init_parser3();
|
|
16381
16583
|
init_layout3();
|
|
16382
16584
|
init_renderer4();
|
|
16585
|
+
init_inline_markdown();
|
|
16383
16586
|
init_parser4();
|
|
16384
16587
|
init_layout();
|
|
16385
16588
|
init_renderer();
|
|
@@ -16396,12 +16599,12 @@ init_collapse();
|
|
|
16396
16599
|
|
|
16397
16600
|
// src/org/resolver.ts
|
|
16398
16601
|
init_diagnostics();
|
|
16602
|
+
init_tag_groups();
|
|
16399
16603
|
var MAX_DEPTH = 10;
|
|
16400
16604
|
var IMPORT_RE = /^(\s+)import:\s+(.+\.dgmo)\s*$/i;
|
|
16401
16605
|
var TAGS_RE = /^tags:\s+(.+\.dgmo)\s*$/i;
|
|
16402
16606
|
var HEADER_RE = /^(chart|title)\s*:/i;
|
|
16403
|
-
var
|
|
16404
|
-
var GROUP_HEADING_RE5 = /^##\s+/;
|
|
16607
|
+
var OPTION_RE2 = /^[a-z][a-z0-9-]*\s*:/i;
|
|
16405
16608
|
function dirname(filePath) {
|
|
16406
16609
|
const last = filePath.lastIndexOf("/");
|
|
16407
16610
|
return last > 0 ? filePath.substring(0, last) : "/";
|
|
@@ -16422,9 +16625,9 @@ function extractTagGroups(lines) {
|
|
|
16422
16625
|
let current = null;
|
|
16423
16626
|
for (const line7 of lines) {
|
|
16424
16627
|
const trimmed = line7.trim();
|
|
16425
|
-
|
|
16426
|
-
|
|
16427
|
-
const name =
|
|
16628
|
+
const headingMatch = matchTagBlockHeading(trimmed);
|
|
16629
|
+
if (headingMatch) {
|
|
16630
|
+
const name = headingMatch.name.toLowerCase();
|
|
16428
16631
|
current = { name, lines: [line7] };
|
|
16429
16632
|
blocks.push(current);
|
|
16430
16633
|
} else if (current) {
|
|
@@ -16466,7 +16669,7 @@ function parseFileHeader(lines) {
|
|
|
16466
16669
|
tagsDirective = tagsMatch[1].trim();
|
|
16467
16670
|
continue;
|
|
16468
16671
|
}
|
|
16469
|
-
if (
|
|
16672
|
+
if (OPTION_RE2.test(trimmed) && !isTagBlockHeading(trimmed) && !lines[i].match(/^\s/)) {
|
|
16470
16673
|
const key = trimmed.split(":")[0].trim().toLowerCase();
|
|
16471
16674
|
if (key !== "chart" && key !== "title" && !trimmed.includes("|")) {
|
|
16472
16675
|
continue;
|
|
@@ -16496,7 +16699,7 @@ async function resolveFile(content, filePath, readFileFn, diagnostics, ancestorC
|
|
|
16496
16699
|
headerLines.push(lines[i]);
|
|
16497
16700
|
continue;
|
|
16498
16701
|
}
|
|
16499
|
-
if (
|
|
16702
|
+
if (isTagBlockHeading(trimmed)) continue;
|
|
16500
16703
|
if (lines[i] !== trimmed) continue;
|
|
16501
16704
|
const tagsMatch = trimmed.match(TAGS_RE);
|
|
16502
16705
|
if (tagsMatch) {
|
|
@@ -16528,7 +16731,7 @@ async function resolveFile(content, filePath, readFileFn, diagnostics, ancestorC
|
|
|
16528
16731
|
const importMatch = line7.match(IMPORT_RE);
|
|
16529
16732
|
if (!importMatch) {
|
|
16530
16733
|
const trimmed = line7.trim();
|
|
16531
|
-
if (
|
|
16734
|
+
if (isTagBlockHeading(trimmed) || inlineTagGroups.length > 0 && isTagGroupEntry(line7, bodyLines, i)) {
|
|
16532
16735
|
continue;
|
|
16533
16736
|
}
|
|
16534
16737
|
resolvedBodyLines.push(line7);
|
|
@@ -16623,7 +16826,7 @@ function findBodyStart(lines) {
|
|
|
16623
16826
|
if (inTagGroup) inTagGroup = false;
|
|
16624
16827
|
continue;
|
|
16625
16828
|
}
|
|
16626
|
-
if (
|
|
16829
|
+
if (isTagBlockHeading(trimmed)) {
|
|
16627
16830
|
inTagGroup = true;
|
|
16628
16831
|
continue;
|
|
16629
16832
|
}
|
|
@@ -16635,7 +16838,7 @@ function findBodyStart(lines) {
|
|
|
16635
16838
|
}
|
|
16636
16839
|
if (HEADER_RE.test(trimmed)) continue;
|
|
16637
16840
|
if (TAGS_RE.test(trimmed)) continue;
|
|
16638
|
-
if (
|
|
16841
|
+
if (OPTION_RE2.test(trimmed) && !isTagBlockHeading(trimmed) && !lines[i].match(/^\s/) && !trimmed.includes("|")) {
|
|
16639
16842
|
const key = trimmed.split(":")[0].trim().toLowerCase();
|
|
16640
16843
|
if (key !== "chart" && key !== "title") {
|
|
16641
16844
|
continue;
|
|
@@ -16650,7 +16853,7 @@ function isTagGroupEntry(line7, allLines, index) {
|
|
|
16650
16853
|
for (let i = index - 1; i >= 0; i--) {
|
|
16651
16854
|
const prev = allLines[i].trim();
|
|
16652
16855
|
if (prev === "" || prev.startsWith("//")) continue;
|
|
16653
|
-
if (
|
|
16856
|
+
if (isTagBlockHeading(prev)) return true;
|
|
16654
16857
|
if (allLines[i].match(/^\s+/)) continue;
|
|
16655
16858
|
return false;
|
|
16656
16859
|
}
|
|
@@ -16807,6 +17010,7 @@ export {
|
|
|
16807
17010
|
parseERDiagram,
|
|
16808
17011
|
parseFlowchart,
|
|
16809
17012
|
parseInitiativeStatus,
|
|
17013
|
+
parseInlineMarkdown,
|
|
16810
17014
|
parseKanban,
|
|
16811
17015
|
parseOrg,
|
|
16812
17016
|
parseQuadrant,
|
|
@@ -16850,6 +17054,7 @@ export {
|
|
|
16850
17054
|
shade,
|
|
16851
17055
|
solarizedPalette,
|
|
16852
17056
|
tint,
|
|
16853
|
-
tokyoNightPalette
|
|
17057
|
+
tokyoNightPalette,
|
|
17058
|
+
truncateBareUrl
|
|
16854
17059
|
};
|
|
16855
17060
|
//# sourceMappingURL=index.js.map
|