@diagrammo/dgmo 0.45.0 → 0.47.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/dist/advanced.cjs +31 -25
- package/dist/advanced.d.cts +3 -855
- package/dist/advanced.d.ts +3 -855
- package/dist/advanced.js +541 -70101
- package/dist/analyzer-UYKBXAKR.js +15 -0
- package/dist/auto.cjs +500 -341
- package/dist/auto.css +342 -159
- package/dist/auto.d.cts +10 -8
- package/dist/auto.d.ts +10 -8
- package/dist/auto.js +373 -265
- package/dist/auto.mjs +500 -341
- package/dist/block.cjs +31 -25
- package/dist/block.js +83 -69411
- package/dist/calculator-LDYQCDDY.js +11 -0
- package/dist/charts-d3-QOZHKTCT.js +25 -0
- package/dist/chunk-2DXMZRWJ.js +800 -0
- package/dist/chunk-2LACINWN.js +786 -0
- package/dist/chunk-33LCUH4H.js +893 -0
- package/dist/chunk-3CIOJ5YJ.js +35 -0
- package/dist/chunk-3HDBAXF5.js +86 -0
- package/dist/chunk-3JLKYGBQ.js +290 -0
- package/dist/chunk-3MQQNXPD.js +415 -0
- package/dist/chunk-3R5POCTZ.js +967 -0
- package/dist/chunk-3SMGIJDD.js +112 -0
- package/dist/chunk-44CM72SQ.js +409 -0
- package/dist/chunk-4GRI7MEB.js +1604 -0
- package/dist/chunk-4OHACBGX.js +606 -0
- package/dist/chunk-5DH3KYFH.js +21 -0
- package/dist/chunk-5MLYVTYM.js +76 -0
- package/dist/chunk-5QXL4NYS.js +553 -0
- package/dist/chunk-5WRI5ZAA.js +31 -0
- package/dist/chunk-6EK55ART.js +117 -0
- package/dist/chunk-6FZYCKXB.js +2065 -0
- package/dist/chunk-6HO5ZTXK.js +277 -0
- package/dist/chunk-6KFWC4CO.js +7 -0
- package/dist/chunk-6MTWIQVO.js +121 -0
- package/dist/chunk-6NYWYNBI.js +329 -0
- package/dist/chunk-6SM5NJQH.js +620 -0
- package/dist/chunk-725LDASD.js +422 -0
- package/dist/chunk-76OWZ3BA.js +130 -0
- package/dist/chunk-7JEGTRLD.js +338 -0
- package/dist/chunk-A44USUV7.js +923 -0
- package/dist/chunk-A4GOY3PE.js +25 -0
- package/dist/chunk-A4VFQH5G.js +251 -0
- package/dist/chunk-AELOBFW5.js +375 -0
- package/dist/chunk-AN2MOO5T.js +522 -0
- package/dist/chunk-BMR4CIEO.js +41 -0
- package/dist/chunk-BS7SV7C3.js +51 -0
- package/dist/chunk-BUPDIHML.js +613 -0
- package/dist/chunk-BUVJFRPY.js +887 -0
- package/dist/chunk-C3Z4DX3V.js +112 -0
- package/dist/chunk-CI2G3OEB.js +1818 -0
- package/dist/chunk-CKNVO24D.js +54 -0
- package/dist/chunk-CUVHQHZ7.js +391 -0
- package/dist/chunk-CXK4DZH3.js +114 -0
- package/dist/chunk-DKEPS5LH.js +315 -0
- package/dist/chunk-DU7W62N5.js +487 -0
- package/dist/chunk-DZAQBW35.js +751 -0
- package/dist/chunk-EB6FPQUP.js +316 -0
- package/dist/chunk-EMS2SK26.js +376 -0
- package/dist/chunk-ERLBPDGU.js +510 -0
- package/dist/chunk-EVCVDTXE.js +732 -0
- package/dist/chunk-FCIIHT24.js +384 -0
- package/dist/chunk-FFUN5D66.js +97 -0
- package/dist/chunk-FITOLXSX.js +714 -0
- package/dist/chunk-FMDSF3OV.js +68 -0
- package/dist/chunk-FNB3PNGF.js +410 -0
- package/dist/chunk-G2H74XJZ.js +2104 -0
- package/dist/chunk-GMR5MFHJ.js +339 -0
- package/dist/chunk-H6PI3KJT.js +305 -0
- package/dist/chunk-I46X5VUA.js +59 -0
- package/dist/chunk-I5IGB56C.js +255 -0
- package/dist/chunk-IH6ZMVQ5.js +3950 -0
- package/dist/chunk-IJZFN3HM.js +463 -0
- package/dist/chunk-IPWPWM6R.js +3079 -0
- package/dist/chunk-IYULMRBE.js +23 -0
- package/dist/chunk-IZMRON6C.js +167 -0
- package/dist/chunk-J5FIXQRT.js +813 -0
- package/dist/chunk-JED6ZDEE.js +73 -0
- package/dist/chunk-JEUJOX5X.js +136 -0
- package/dist/chunk-JM4LEPY3.js +436 -0
- package/dist/chunk-L3UHP6TD.js +101 -0
- package/dist/chunk-L66GEFB6.js +524 -0
- package/dist/chunk-LIOHW36Z.js +469 -0
- package/dist/chunk-LP7EC4MI.js +16 -0
- package/dist/chunk-MITI6NOL.js +548 -0
- package/dist/chunk-MO5YHHMQ.js +168 -0
- package/dist/chunk-MZSBFAPJ.js +885 -0
- package/dist/chunk-NNAAJVBU.js +9 -0
- package/dist/chunk-NOTA6TEI.js +47 -0
- package/dist/chunk-NURGB5Z4.js +335 -0
- package/dist/chunk-NX4EQS3U.js +1062 -0
- package/dist/chunk-NXMESY4J.js +1 -0
- package/dist/chunk-OJR3MQYV.js +1458 -0
- package/dist/chunk-OURHMODR.js +454 -0
- package/dist/chunk-P235SVAH.js +1057 -0
- package/dist/chunk-P4RH4OSP.js +1038 -0
- package/dist/chunk-P6T66CCZ.js +226 -0
- package/dist/chunk-PBAHEPLQ.js +223 -0
- package/dist/chunk-PBHE5UG6.js +1530 -0
- package/dist/chunk-PDKUANDZ.js +35 -0
- package/dist/chunk-PWIHZ6NJ.js +296 -0
- package/dist/chunk-QEBUY5NY.js +1685 -0
- package/dist/chunk-QLCCJEJI.js +253 -0
- package/dist/chunk-QOOUC2J5.js +52 -0
- package/dist/chunk-QYTPPDAO.js +402 -0
- package/dist/chunk-R3XI2VC7.js +801 -0
- package/dist/chunk-RCERWOJR.js +154 -0
- package/dist/chunk-RJE5JTVK.js +362 -0
- package/dist/chunk-RTLBSQ3G.js +1155 -0
- package/dist/chunk-RUNNI6VE.js +448 -0
- package/dist/chunk-RVMRZAPB.js +354 -0
- package/dist/chunk-RYEGFMUO.js +955 -0
- package/dist/chunk-RZCF2VVM.js +528 -0
- package/dist/chunk-SML67VPV.js +1025 -0
- package/dist/chunk-SQ7IY53Q.js +44 -0
- package/dist/chunk-SQAG3UXH.js +161 -0
- package/dist/chunk-SRTU6HMQ.js +1851 -0
- package/dist/chunk-T2OE3YQB.js +550 -0
- package/dist/chunk-T3UBLACL.js +299 -0
- package/dist/chunk-TLVIHFRO.js +296 -0
- package/dist/chunk-TYS6CSS5.js +52 -0
- package/dist/chunk-U6EQI3U6.js +130 -0
- package/dist/chunk-UJ4FJLBF.js +86 -0
- package/dist/chunk-ULOEATBZ.js +347 -0
- package/dist/chunk-UNCCZ3NU.js +127 -0
- package/dist/chunk-USZW2HHU.js +197 -0
- package/dist/chunk-UWN33VNX.js +1610 -0
- package/dist/chunk-UZ7EZW3B.js +40 -0
- package/dist/chunk-VOKGH627.js +37 -0
- package/dist/chunk-WBRZJOEC.js +204 -0
- package/dist/chunk-WCSOJFU3.js +380 -0
- package/dist/chunk-WCT3NYCV.js +160 -0
- package/dist/chunk-WVAJFAIA.js +529 -0
- package/dist/chunk-X5LCYCL5.js +394 -0
- package/dist/chunk-XAKEUMEJ.js +1256 -0
- package/dist/chunk-Y2ZE3MSG.js +590 -0
- package/dist/chunk-Y3J7VR52.js +646 -0
- package/dist/chunk-Y5QGVTVC.js +33 -0
- package/dist/chunk-YAA6IID3.js +548 -0
- package/dist/chunk-YGJTDXVR.js +692 -0
- package/dist/chunk-YRYKTYMQ.js +186 -0
- package/dist/chunk-YYVTBZZC.js +61 -0
- package/dist/chunk-Z5CGSFJB.js +647 -0
- package/dist/chunk-Z72XRXD4.js +787 -0
- package/dist/chunk-ZGR7ULFJ.js +978 -0
- package/dist/chunk-ZJEL4H2R.js +851 -0
- package/dist/chunk-ZO27FGJS.js +554 -0
- package/dist/cli.cjs +112 -112
- package/dist/collapse-CLPJD2RL.js +11 -0
- package/dist/collapse-SLINJQW6.js +9 -0
- package/dist/collapse-ZWUFFCK2.js +9 -0
- package/dist/compute-G55RG53N.js +8 -0
- package/dist/dgmo-router-DZCIDUO5.js +73 -0
- package/dist/dimensions-J3FHIMJ6.js +22 -0
- package/dist/element.cjs +492 -325
- package/dist/element.js +367 -259
- package/dist/element.mjs +492 -325
- package/dist/flowchart-parser-ZNSKIBVR.js +21 -0
- package/dist/flowchart-renderer-ZAEOL4DX.js +35 -0
- package/dist/index.cjs +34 -28
- package/dist/index.d.cts +3 -469
- package/dist/index.d.ts +3 -469
- package/dist/index.js +137 -69679
- package/dist/layout-46N4JJYK.js +17 -0
- package/dist/layout-5RA6QWR6.js +26 -0
- package/dist/layout-5T6RH5M6.js +14 -0
- package/dist/layout-7QXCNOVS.js +13 -0
- package/dist/layout-EE6GE46Y.js +17 -0
- package/dist/layout-G23F7LDH.js +9 -0
- package/dist/layout-HRBZPFCN.js +23 -0
- package/dist/layout-HWDSRX5E.js +20 -0
- package/dist/layout-HYZPWAK5.js +18 -0
- package/dist/layout-N76NR4ZO.js +19 -0
- package/dist/layout-OB3RI63S.js +14 -0
- package/dist/layout-S2QBYSK2.js +15 -0
- package/dist/layout-UM5F4DJB.js +15 -0
- package/dist/layout-search-OYV77HHS.js +1655 -0
- package/dist/load-data-EHDDZ5ZS.js +8 -0
- package/dist/palettes-PRJ2RI6D.js +56 -0
- package/dist/parser-2MFP2H2E.js +11 -0
- package/dist/parser-3STE62GB.js +21 -0
- package/dist/parser-4FL2CMDG.js +18 -0
- package/dist/parser-4OGOBJJ4.js +13 -0
- package/dist/parser-6BTRLKRZ.js +15 -0
- package/dist/parser-AQETEVRW.js +21 -0
- package/dist/parser-CFZD5IBL.js +12 -0
- package/dist/parser-FUSKFGZN.js +16 -0
- package/dist/parser-I6KXEYFK.js +13 -0
- package/dist/parser-IXSZZQHY.js +18 -0
- package/dist/parser-JAL2HD4I.js +13 -0
- package/dist/parser-KNSQSKQO.js +20 -0
- package/dist/parser-N5O4IHUN.js +13 -0
- package/dist/parser-NGU3ETO6.js +16 -0
- package/dist/parser-NRAI6O25.js +19 -0
- package/dist/parser-O5J4VBII.js +11 -0
- package/dist/parser-OV7NOBW6.js +21 -0
- package/dist/parser-PQ3POX45.js +23 -0
- package/dist/parser-TFZFBVWN.js +11 -0
- package/dist/parser-TRTHDFPP.js +18 -0
- package/dist/parser-VQP2UJ6W.js +11 -0
- package/dist/parser-XDVELHRK.js +13 -0
- package/dist/parser-XKRP7QKP.js +11 -0
- package/dist/parser-Y6WTBU76.js +14 -0
- package/dist/parser-ZSDPZYQP.js +12 -0
- package/dist/renderer-2XQQQ6QR.js +28 -0
- package/dist/renderer-5NDVNDAZ.js +26 -0
- package/dist/renderer-6EEZHMH4.js +26 -0
- package/dist/renderer-6W5462RB.js +43 -0
- package/dist/renderer-7MVLWWQD.js +22 -0
- package/dist/renderer-AWWAF6XD.js +33 -0
- package/dist/renderer-BYCNMBF7.js +34 -0
- package/dist/renderer-CLJHQPBJ.js +29 -0
- package/dist/renderer-GHPZMFU2.js +15 -0
- package/dist/renderer-JGBKUCZD.js +16 -0
- package/dist/renderer-KQB7UGDS.js +19 -0
- package/dist/renderer-PGX2TKVS.js +24 -0
- package/dist/renderer-QIWVHWZO.js +15 -0
- package/dist/renderer-RPOA5YPZ.js +35 -0
- package/dist/renderer-SMIBCRVB.js +24 -0
- package/dist/renderer-T7YKC5VP.js +28 -0
- package/dist/renderer-TOCOVLHS.js +37 -0
- package/dist/renderer-UWA5XS74.js +39 -0
- package/dist/renderer-VACVQYML.js +25 -0
- package/dist/renderer-W4M6QLIJ.js +37 -0
- package/dist/renderer-WZRREQ2P.js +23 -0
- package/dist/renderer-YY2OSF6E.js +27 -0
- package/dist/renderer-Z7I3W2PP.js +24 -0
- package/dist/renderer-ZGNTUWC4.js +22 -0
- package/dist/renderer-ZTR3DER3.js +19 -0
- package/dist/renderer-radial-C32GPJQ7.js +21 -0
- package/dist/resolver-NOAA7ID7.js +13 -0
- package/dist/state-collapse-HCGD6IVJ.js +8 -0
- package/dist/state-parser-Z2V23ATR.js +18 -0
- package/dist/state-renderer-RFYHSP4K.js +34 -0
- package/dist/themes-1-CuKpeH.d.cts +908 -0
- package/dist/themes-1-CuKpeH.d.ts +908 -0
- package/package.json +1 -1
- package/src/auto/index.ts +55 -57
- package/src/auto/shared.ts +142 -142
- package/src/auto/styles.ts +44 -199
- package/src/c4/renderer.ts +2 -2
- package/src/element/index.ts +29 -21
- package/src/infra/renderer.ts +1 -1
- package/src/render.ts +34 -14
- package/src/sitemap/renderer.ts +1 -1
- package/src/timeline/renderer.ts +1 -1
- package/src/utils/hover-styles.ts +6 -1
- package/src/utils/legend-d3.ts +1 -4
- package/src/utils/legend-svg.ts +1 -1
|
@@ -0,0 +1,893 @@
|
|
|
1
|
+
import {
|
|
2
|
+
INFRA_BEHAVIOR_KEY_SET,
|
|
3
|
+
INFRA_EDGE_ONLY_KEY_SET,
|
|
4
|
+
INFRA_TOP_LEVEL_OPTION_SET
|
|
5
|
+
} from "./chunk-DKEPS5LH.js";
|
|
6
|
+
import {
|
|
7
|
+
tryStripDescriptionKeyword
|
|
8
|
+
} from "./chunk-IYULMRBE.js";
|
|
9
|
+
import {
|
|
10
|
+
matchTagBlockHeading,
|
|
11
|
+
stripDefaultModifier,
|
|
12
|
+
tagAttrKey,
|
|
13
|
+
validateTagGroupNames
|
|
14
|
+
} from "./chunk-QLCCJEJI.js";
|
|
15
|
+
import {
|
|
16
|
+
GRAPH_DX
|
|
17
|
+
} from "./chunk-I46X5VUA.js";
|
|
18
|
+
import {
|
|
19
|
+
parseInArrowLabel
|
|
20
|
+
} from "./chunk-FFUN5D66.js";
|
|
21
|
+
import {
|
|
22
|
+
displayName,
|
|
23
|
+
normalizeName
|
|
24
|
+
} from "./chunk-NOTA6TEI.js";
|
|
25
|
+
import {
|
|
26
|
+
INFRA_REGISTRY,
|
|
27
|
+
OPTION_NOCOLON_RE,
|
|
28
|
+
measureIndent,
|
|
29
|
+
parseFirstLine,
|
|
30
|
+
tryParseSharedOption,
|
|
31
|
+
warnUnknownMetaKeys,
|
|
32
|
+
withTagAliases
|
|
33
|
+
} from "./chunk-Y3J7VR52.js";
|
|
34
|
+
import {
|
|
35
|
+
isRecognizedColorName
|
|
36
|
+
} from "./chunk-TLVIHFRO.js";
|
|
37
|
+
import {
|
|
38
|
+
NAME_DIAGNOSTIC_CODES,
|
|
39
|
+
emit,
|
|
40
|
+
formatDgmoError,
|
|
41
|
+
makeDgmoError,
|
|
42
|
+
nameMergedMessage,
|
|
43
|
+
suggest
|
|
44
|
+
} from "./chunk-CXK4DZH3.js";
|
|
45
|
+
|
|
46
|
+
// src/infra/types.ts
|
|
47
|
+
var INFRA_BEHAVIOR_KEYS = INFRA_BEHAVIOR_KEY_SET;
|
|
48
|
+
var EDGE_ONLY_KEYS = INFRA_EDGE_ONLY_KEY_SET;
|
|
49
|
+
|
|
50
|
+
// src/infra/parser.ts
|
|
51
|
+
var CONNECTION_RE = /^-(?:([^-].*?))?->\s*(.+?)\s*$/;
|
|
52
|
+
var SIMPLE_CONNECTION_RE = /^->\s*(.+?)\s*$/;
|
|
53
|
+
var ASYNC_CONNECTION_RE = /^~(?:([^~].*?))?~>\s*(.+?)\s*$/;
|
|
54
|
+
var ASYNC_SIMPLE_CONNECTION_RE = /^~>\s*(.+?)\s*$/;
|
|
55
|
+
var DEPRECATED_FANOUT_RE = /\bx(\d+)\s*$/;
|
|
56
|
+
var GROUP_RE = /^\[([^\]]+)\]\s*(?:as\s+([A-Za-z][A-Za-z0-9_]{0,11})\s*)?((?:\|.*)|(?:[a-zA-Z_]\w*\s*:.*))?$/;
|
|
57
|
+
var TAG_VALUE_RE = /^(\w[\w\s]+?)\s*$/;
|
|
58
|
+
var COMPONENT_RE = /^(?:"(?<qname>[^"]+)"|(?<uname>[a-zA-Z_][\w -]*?))(?:\s+as\s+(?<alias>[A-Za-z][A-Za-z0-9_]{0,11}))?\s*(?<meta>(?:\|.*)|(?:[a-zA-Z_]\w*\s*:.*))?$/;
|
|
59
|
+
var PIPE_META_RE = /[|,]\s*(\w+)\s*:\s*([^|,]+)/g;
|
|
60
|
+
var SAMELINE_META_RE = /(?:^|[\s,])(\w+)\s*:\s*([^,]+?)(?=\s*,|\s*$)/g;
|
|
61
|
+
var PROPERTY_RE = /^([\w-]+):\s*(.+)$/;
|
|
62
|
+
var PERCENT_RE = /^([\d.]+)%$/;
|
|
63
|
+
var RANGE_RE = /^(\d+)-(\d+)$/;
|
|
64
|
+
var EDGE_NODE_NAMES = /* @__PURE__ */ new Set(["edge", "internet"]);
|
|
65
|
+
var INFRA_TOP_LEVEL_OPTIONS = INFRA_TOP_LEVEL_OPTION_SET;
|
|
66
|
+
var TOP_LEVEL_OPTIONS = INFRA_TOP_LEVEL_OPTIONS;
|
|
67
|
+
function nodeId(name) {
|
|
68
|
+
return normalizeName(name);
|
|
69
|
+
}
|
|
70
|
+
function groupId(name) {
|
|
71
|
+
return `[${normalizeName(name)}]`;
|
|
72
|
+
}
|
|
73
|
+
function parsePropertyValue(raw) {
|
|
74
|
+
const pct = raw.match(PERCENT_RE);
|
|
75
|
+
if (pct) return parseFloat(pct[1]);
|
|
76
|
+
const num = parseFloat(raw);
|
|
77
|
+
if (!isNaN(num) && String(num) === raw.trim()) return num;
|
|
78
|
+
return raw.trim();
|
|
79
|
+
}
|
|
80
|
+
function extractPipeMetadata(rest) {
|
|
81
|
+
const tags = {};
|
|
82
|
+
let clean = rest;
|
|
83
|
+
let match;
|
|
84
|
+
const hadPipe = rest.includes("|");
|
|
85
|
+
if (hadPipe) {
|
|
86
|
+
PIPE_META_RE.lastIndex = 0;
|
|
87
|
+
while ((match = PIPE_META_RE.exec(rest)) !== null) {
|
|
88
|
+
tags[match[1].trim()] = match[2].trim();
|
|
89
|
+
clean = clean.replace(match[0], "");
|
|
90
|
+
}
|
|
91
|
+
return { tags, clean: clean.trim(), hadPipe: true };
|
|
92
|
+
}
|
|
93
|
+
SAMELINE_META_RE.lastIndex = 0;
|
|
94
|
+
let firstMatchIdx = -1;
|
|
95
|
+
while ((match = SAMELINE_META_RE.exec(rest)) !== null) {
|
|
96
|
+
tags[match[1].trim()] = match[2].trim();
|
|
97
|
+
if (firstMatchIdx === -1) firstMatchIdx = match.index;
|
|
98
|
+
}
|
|
99
|
+
if (firstMatchIdx >= 0) {
|
|
100
|
+
clean = rest.substring(0, firstMatchIdx).trim();
|
|
101
|
+
}
|
|
102
|
+
return { tags, clean: clean.trim(), hadPipe: false };
|
|
103
|
+
}
|
|
104
|
+
var UNPARSED_SPLIT_RE = /\bsplit\s+(\d+)%/;
|
|
105
|
+
function warnUnparsedPipeMeta(targetName, lineNumber, warnFn) {
|
|
106
|
+
if (!targetName.includes("|")) return;
|
|
107
|
+
const splitMatch = targetName.match(UNPARSED_SPLIT_RE);
|
|
108
|
+
if (splitMatch) {
|
|
109
|
+
warnFn(
|
|
110
|
+
lineNumber,
|
|
111
|
+
`'split ${splitMatch[1]}%' needs a colon \u2014 use 'split: ${splitMatch[1]}%'`
|
|
112
|
+
);
|
|
113
|
+
} else {
|
|
114
|
+
warnFn(
|
|
115
|
+
lineNumber,
|
|
116
|
+
`Unparsed pipe metadata in target \u2014 pipe values use 'key: value' syntax`
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function parseInfra(content) {
|
|
121
|
+
const lines = content.split("\n");
|
|
122
|
+
const options = {};
|
|
123
|
+
const result = {
|
|
124
|
+
type: "infra",
|
|
125
|
+
title: null,
|
|
126
|
+
titleLineNumber: null,
|
|
127
|
+
direction: "LR",
|
|
128
|
+
nodes: [],
|
|
129
|
+
edges: [],
|
|
130
|
+
groups: [],
|
|
131
|
+
tagGroups: [],
|
|
132
|
+
options,
|
|
133
|
+
diagnostics: [],
|
|
134
|
+
error: null
|
|
135
|
+
};
|
|
136
|
+
const nodeMap = /* @__PURE__ */ new Map();
|
|
137
|
+
const nodeMutableTags = /* @__PURE__ */ new Map();
|
|
138
|
+
function pushDescription(node, text) {
|
|
139
|
+
const existing = node.description ?? [];
|
|
140
|
+
existing.push(text);
|
|
141
|
+
node.description = existing;
|
|
142
|
+
}
|
|
143
|
+
const tagAliasSet = /* @__PURE__ */ new Set();
|
|
144
|
+
const EDGE_PIPE_REGISTRY = {
|
|
145
|
+
keys: /* @__PURE__ */ new Set(["split", "fanout"]),
|
|
146
|
+
tagAliases: /* @__PURE__ */ new Set()
|
|
147
|
+
};
|
|
148
|
+
const nameAliasMap = /* @__PURE__ */ new Map();
|
|
149
|
+
function peelAlias(label) {
|
|
150
|
+
const trimmed = label.trim();
|
|
151
|
+
const m = trimmed.match(/^(.*?)\s+as\s+([A-Za-z][A-Za-z0-9_]{0,11})\s*$/);
|
|
152
|
+
if (!m) return { label: trimmed };
|
|
153
|
+
return { label: m[1].trim(), ...m[2] !== void 0 && { alias: m[2] } };
|
|
154
|
+
}
|
|
155
|
+
const IS_A_SUFFIX = /^(.*?)\s+is\s+an?\s+[A-Za-z][\w-]*\s*$/i;
|
|
156
|
+
function peelInfraDecorations(rawName, lineNumber) {
|
|
157
|
+
const peeled = peelAlias(rawName);
|
|
158
|
+
const m = peeled.label.match(IS_A_SUFFIX);
|
|
159
|
+
if (!m) return peeled;
|
|
160
|
+
warn(
|
|
161
|
+
lineNumber,
|
|
162
|
+
`Infra nodes don't use 'is a <type>' \u2014 types are inferred from properties (cache-hit, buffer, drain-rate, \u2026). Drop the 'is a' suffix.`
|
|
163
|
+
);
|
|
164
|
+
return {
|
|
165
|
+
label: m[1].trim(),
|
|
166
|
+
...peeled.alias !== void 0 && { alias: peeled.alias }
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function resolveTargetId(rawName) {
|
|
170
|
+
const aliasResolved = nameAliasMap.get(rawName.trim());
|
|
171
|
+
if (aliasResolved !== void 0) return aliasResolved;
|
|
172
|
+
return nodeId(rawName);
|
|
173
|
+
}
|
|
174
|
+
const targetDisplays = /* @__PURE__ */ new Map();
|
|
175
|
+
const rememberTargetDisplay = (key, display) => {
|
|
176
|
+
if (!targetDisplays.has(key)) targetDisplays.set(key, display.trim());
|
|
177
|
+
};
|
|
178
|
+
const setError = (line, message) => {
|
|
179
|
+
const diag = makeDgmoError(line, message);
|
|
180
|
+
result.diagnostics.push(diag);
|
|
181
|
+
if (!result.error) result.error = formatDgmoError(diag);
|
|
182
|
+
};
|
|
183
|
+
const warn = (line, message) => {
|
|
184
|
+
result.diagnostics.push(makeDgmoError(line, message, "warning"));
|
|
185
|
+
};
|
|
186
|
+
let currentNode = null;
|
|
187
|
+
let currentGroup = null;
|
|
188
|
+
let currentTagGroup = null;
|
|
189
|
+
let baseIndent = 0;
|
|
190
|
+
let firstLineConsumed = false;
|
|
191
|
+
function finishCurrentNode() {
|
|
192
|
+
if (!currentNode) return;
|
|
193
|
+
const key = currentNode.id;
|
|
194
|
+
const existing = nodeMap.get(key);
|
|
195
|
+
if (existing) {
|
|
196
|
+
const incomingDisplay = displayName(currentNode.label);
|
|
197
|
+
const existingDisplay = displayName(existing.label);
|
|
198
|
+
const isAliasRef = nameAliasMap.get(currentNode.label) === key;
|
|
199
|
+
if (incomingDisplay !== existingDisplay && !isAliasRef) {
|
|
200
|
+
result.diagnostics.push(
|
|
201
|
+
makeDgmoError(
|
|
202
|
+
currentNode.lineNumber,
|
|
203
|
+
nameMergedMessage({
|
|
204
|
+
incomingDisplay,
|
|
205
|
+
incomingLine: currentNode.lineNumber,
|
|
206
|
+
existingDisplay,
|
|
207
|
+
existingLine: existing.lineNumber
|
|
208
|
+
}),
|
|
209
|
+
"warning",
|
|
210
|
+
NAME_DIAGNOSTIC_CODES.NAME_MERGED
|
|
211
|
+
)
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
currentNode = null;
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const keys = new Set(currentNode.properties.map((p) => p.key));
|
|
218
|
+
if (keys.has("concurrency") && (keys.has("instances") || keys.has("max-rps"))) {
|
|
219
|
+
const conflicting = [
|
|
220
|
+
keys.has("instances") ? "instances" : "",
|
|
221
|
+
keys.has("max-rps") ? "max-rps" : ""
|
|
222
|
+
].filter(Boolean).join(", ");
|
|
223
|
+
warn(
|
|
224
|
+
currentNode.lineNumber,
|
|
225
|
+
`'concurrency' (serverless) is mutually exclusive with ${conflicting}. Serverless nodes scale via concurrency, not instances.`
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
if (keys.has("buffer") && keys.has("max-rps")) {
|
|
229
|
+
warn(
|
|
230
|
+
currentNode.lineNumber,
|
|
231
|
+
`'buffer' (queue) and 'max-rps' (service) represent different capacity models. A queue buffers messages; a service processes them.`
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
nodeMap.set(key, currentNode);
|
|
235
|
+
result.nodes.push(currentNode);
|
|
236
|
+
currentNode = null;
|
|
237
|
+
}
|
|
238
|
+
function finishCurrentTagGroup() {
|
|
239
|
+
if (currentTagGroup) {
|
|
240
|
+
result.tagGroups.push(currentTagGroup);
|
|
241
|
+
}
|
|
242
|
+
currentTagGroup = null;
|
|
243
|
+
}
|
|
244
|
+
for (let i = 0; i < lines.length; i++) {
|
|
245
|
+
const raw = lines[i];
|
|
246
|
+
const lineNumber = i + 1;
|
|
247
|
+
const trimmed = raw.trim();
|
|
248
|
+
const indent = measureIndent(raw);
|
|
249
|
+
if (!trimmed || trimmed.startsWith("//")) continue;
|
|
250
|
+
if (/^#{2,}\s+/.test(trimmed)) continue;
|
|
251
|
+
if (indent === 0) {
|
|
252
|
+
if (indent === 0 && currentNode && !trimmed.startsWith("-")) {
|
|
253
|
+
finishCurrentNode();
|
|
254
|
+
}
|
|
255
|
+
if (!firstLineConsumed) {
|
|
256
|
+
firstLineConsumed = true;
|
|
257
|
+
const firstLineResult = parseFirstLine(trimmed);
|
|
258
|
+
if (firstLineResult) {
|
|
259
|
+
if (firstLineResult.chartType !== "infra") {
|
|
260
|
+
setError(
|
|
261
|
+
lineNumber,
|
|
262
|
+
`Expected chart type 'infra', got '${firstLineResult.chartType}'`
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
if (firstLineResult.title) {
|
|
266
|
+
result.title = firstLineResult.title;
|
|
267
|
+
result.titleLineNumber = lineNumber;
|
|
268
|
+
}
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
if (/^direction-tb$/i.test(trimmed)) {
|
|
273
|
+
result.direction = "TB";
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
if (trimmed === "animate" || trimmed === "no-animate") {
|
|
277
|
+
warn(
|
|
278
|
+
lineNumber,
|
|
279
|
+
'"animate" / "no-animate" have been removed \u2014 animation is controlled by the rendering context.'
|
|
280
|
+
);
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
if (tryParseSharedOption(trimmed, options)) {
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
const optMatch = trimmed.match(OPTION_NOCOLON_RE);
|
|
287
|
+
if (optMatch && TOP_LEVEL_OPTIONS.has(optMatch[1].toLowerCase())) {
|
|
288
|
+
options[optMatch[1].toLowerCase()] = optMatch[2].trim();
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
const tagMatch = matchTagBlockHeading(trimmed);
|
|
292
|
+
if (tagMatch) {
|
|
293
|
+
finishCurrentNode();
|
|
294
|
+
finishCurrentTagGroup();
|
|
295
|
+
if (tagMatch.alias) tagAliasSet.add(normalizeName(tagMatch.alias));
|
|
296
|
+
currentTagGroup = {
|
|
297
|
+
name: tagMatch.name,
|
|
298
|
+
alias: tagMatch.alias ?? null,
|
|
299
|
+
values: [],
|
|
300
|
+
lineNumber
|
|
301
|
+
};
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
const groupMatch = trimmed.match(GROUP_RE);
|
|
305
|
+
if (groupMatch) {
|
|
306
|
+
finishCurrentNode();
|
|
307
|
+
finishCurrentTagGroup();
|
|
308
|
+
const gLabel = groupMatch[1].trim();
|
|
309
|
+
const groupAlias = groupMatch[2];
|
|
310
|
+
const gId = groupId(gLabel);
|
|
311
|
+
if (groupAlias) nameAliasMap.set(groupAlias, gId);
|
|
312
|
+
const groupMeta = groupMatch[3] ? extractPipeMetadata(groupMatch[3]).tags : void 0;
|
|
313
|
+
if (groupMeta) {
|
|
314
|
+
warnUnknownMetaKeys(
|
|
315
|
+
groupMeta,
|
|
316
|
+
withTagAliases(INFRA_REGISTRY, tagAliasSet),
|
|
317
|
+
(msg) => warn(lineNumber, msg)
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
const hasMeta = groupMeta && Object.keys(groupMeta).length > 0;
|
|
321
|
+
const newGroup = {
|
|
322
|
+
id: gId,
|
|
323
|
+
label: gLabel,
|
|
324
|
+
...hasMeta && { metadata: groupMeta },
|
|
325
|
+
lineNumber
|
|
326
|
+
};
|
|
327
|
+
currentGroup = newGroup;
|
|
328
|
+
result.groups.push(newGroup);
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
const compMatch = trimmed.match(COMPONENT_RE);
|
|
332
|
+
if (compMatch) {
|
|
333
|
+
finishCurrentNode();
|
|
334
|
+
finishCurrentTagGroup();
|
|
335
|
+
const { qname, uname, alias: asAlias, meta } = compMatch.groups;
|
|
336
|
+
const rawName = (qname ?? uname ?? "").trim();
|
|
337
|
+
const peeled = peelInfraDecorations(rawName, lineNumber);
|
|
338
|
+
const name = peeled.label;
|
|
339
|
+
const alias = asAlias ?? peeled.alias;
|
|
340
|
+
const rest = meta ?? "";
|
|
341
|
+
const { tags } = extractPipeMetadata(rest);
|
|
342
|
+
warnUnknownMetaKeys(
|
|
343
|
+
tags,
|
|
344
|
+
withTagAliases(INFRA_REGISTRY, tagAliasSet),
|
|
345
|
+
(msg) => warn(lineNumber, msg)
|
|
346
|
+
);
|
|
347
|
+
const id = nameAliasMap.get(name) ?? nodeId(name);
|
|
348
|
+
if (alias) nameAliasMap.set(alias, id);
|
|
349
|
+
const isEdge = EDGE_NODE_NAMES.has(id.toLowerCase());
|
|
350
|
+
currentNode = {
|
|
351
|
+
id,
|
|
352
|
+
label: name,
|
|
353
|
+
properties: [],
|
|
354
|
+
groupId: null,
|
|
355
|
+
tags,
|
|
356
|
+
isEdge,
|
|
357
|
+
lineNumber
|
|
358
|
+
};
|
|
359
|
+
nodeMutableTags.set(id, tags);
|
|
360
|
+
currentGroup = null;
|
|
361
|
+
baseIndent = 0;
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (currentTagGroup && indent > 0) {
|
|
366
|
+
const { text: cleanEntry, isDefault } = stripDefaultModifier(trimmed);
|
|
367
|
+
const lastSpaceIdx = cleanEntry.lastIndexOf(" ");
|
|
368
|
+
let valueName = cleanEntry;
|
|
369
|
+
let rawColor;
|
|
370
|
+
if (lastSpaceIdx > 0) {
|
|
371
|
+
const trailing = cleanEntry.substring(lastSpaceIdx + 1);
|
|
372
|
+
if (isRecognizedColorName(trailing)) {
|
|
373
|
+
rawColor = trailing;
|
|
374
|
+
valueName = cleanEntry.substring(0, lastSpaceIdx).trimEnd();
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
const tvMatch = valueName.match(TAG_VALUE_RE);
|
|
378
|
+
if (tvMatch || /^\w+$/.test(valueName)) {
|
|
379
|
+
currentTagGroup.values.push({
|
|
380
|
+
name: valueName,
|
|
381
|
+
...rawColor !== void 0 && { color: rawColor }
|
|
382
|
+
});
|
|
383
|
+
if (isDefault) {
|
|
384
|
+
currentTagGroup.defaultValue = valueName;
|
|
385
|
+
} else if (currentTagGroup.values.length === 1) {
|
|
386
|
+
currentTagGroup.defaultValue = valueName;
|
|
387
|
+
}
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
warn(
|
|
391
|
+
lineNumber,
|
|
392
|
+
`Invalid tag value '${trimmed}' in tag group '${currentTagGroup.name}' \u2014 a value is a bare word with an optional trailing color (e.g. 'Production red'); no ':' or '|'.`
|
|
393
|
+
);
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
if (currentGroup && !currentNode && indent > 0) {
|
|
397
|
+
const propMatch = trimmed.match(PROPERTY_RE);
|
|
398
|
+
if (propMatch) {
|
|
399
|
+
const key = propMatch[1].toLowerCase();
|
|
400
|
+
const val = propMatch[2].trim();
|
|
401
|
+
if (key === "instances") {
|
|
402
|
+
const rangeM = val.match(RANGE_RE);
|
|
403
|
+
if (rangeM) {
|
|
404
|
+
currentGroup.instances = val;
|
|
405
|
+
} else {
|
|
406
|
+
const num = parseInt(val, 10);
|
|
407
|
+
if (!isNaN(num)) currentGroup.instances = num;
|
|
408
|
+
}
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
if (key === "collapsed") {
|
|
412
|
+
currentGroup.collapsed = val.toLowerCase() === "true";
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
const compMatch = trimmed.match(COMPONENT_RE);
|
|
417
|
+
if (compMatch) {
|
|
418
|
+
finishCurrentTagGroup();
|
|
419
|
+
const { qname, uname, alias: asAlias, meta } = compMatch.groups;
|
|
420
|
+
const rawName = (qname ?? uname ?? "").trim();
|
|
421
|
+
const peeled = peelInfraDecorations(rawName, lineNumber);
|
|
422
|
+
const name = peeled.label;
|
|
423
|
+
const alias = asAlias ?? peeled.alias;
|
|
424
|
+
const rest = meta ?? "";
|
|
425
|
+
const { tags: nodeTags } = extractPipeMetadata(rest);
|
|
426
|
+
warnUnknownMetaKeys(
|
|
427
|
+
nodeTags,
|
|
428
|
+
withTagAliases(INFRA_REGISTRY, tagAliasSet),
|
|
429
|
+
(msg) => warn(lineNumber, msg)
|
|
430
|
+
);
|
|
431
|
+
const id = nameAliasMap.get(name) ?? nodeId(name);
|
|
432
|
+
if (alias) nameAliasMap.set(alias, id);
|
|
433
|
+
const tags = currentGroup.metadata ? { ...currentGroup.metadata, ...nodeTags } : nodeTags;
|
|
434
|
+
currentNode = {
|
|
435
|
+
id,
|
|
436
|
+
label: name,
|
|
437
|
+
properties: [],
|
|
438
|
+
groupId: currentGroup.id,
|
|
439
|
+
tags,
|
|
440
|
+
isEdge: false,
|
|
441
|
+
lineNumber
|
|
442
|
+
};
|
|
443
|
+
nodeMutableTags.set(id, tags);
|
|
444
|
+
baseIndent = indent;
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
if (currentNode && indent > baseIndent) {
|
|
449
|
+
const deprecatedFanout = trimmed.match(DEPRECATED_FANOUT_RE);
|
|
450
|
+
if (deprecatedFanout && (trimmed.startsWith("->") || trimmed.startsWith("-") || trimmed.startsWith("~"))) {
|
|
451
|
+
const n = deprecatedFanout[1];
|
|
452
|
+
setError(
|
|
453
|
+
lineNumber,
|
|
454
|
+
`'x${n}' fanout syntax is no longer supported \u2014 use 'fanout: ${n}' instead`
|
|
455
|
+
);
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
const asyncSimpleConn = trimmed.match(ASYNC_SIMPLE_CONNECTION_RE);
|
|
459
|
+
if (asyncSimpleConn) {
|
|
460
|
+
const targetRaw = asyncSimpleConn[1].trim();
|
|
461
|
+
const pipeMeta = extractPipeMetadata(targetRaw);
|
|
462
|
+
const targetName = pipeMeta.clean || targetRaw;
|
|
463
|
+
warnUnparsedPipeMeta(targetName, lineNumber, warn);
|
|
464
|
+
warnUnknownMetaKeys(
|
|
465
|
+
pipeMeta.tags,
|
|
466
|
+
EDGE_PIPE_REGISTRY,
|
|
467
|
+
(msg) => warn(lineNumber, msg)
|
|
468
|
+
);
|
|
469
|
+
const split = pipeMeta.tags["split"] ? parseFloat(pipeMeta.tags["split"]) : null;
|
|
470
|
+
const fanoutRaw = pipeMeta.tags["fanout"] ? parseInt(pipeMeta.tags["fanout"], 10) : null;
|
|
471
|
+
if (fanoutRaw !== null && fanoutRaw < 1) {
|
|
472
|
+
warn(
|
|
473
|
+
lineNumber,
|
|
474
|
+
`Fan-out multiplier must be at least 1 (got fanout: ${fanoutRaw}). Ignoring.`
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
const fanout = fanoutRaw !== null && fanoutRaw >= 1 ? fanoutRaw : null;
|
|
478
|
+
const targetIdAsync = resolveTargetId(targetName);
|
|
479
|
+
rememberTargetDisplay(targetIdAsync, targetName);
|
|
480
|
+
result.edges.push({
|
|
481
|
+
sourceId: currentNode.id,
|
|
482
|
+
targetId: targetIdAsync,
|
|
483
|
+
label: "",
|
|
484
|
+
async: true,
|
|
485
|
+
split,
|
|
486
|
+
fanout,
|
|
487
|
+
lineNumber
|
|
488
|
+
});
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
const asyncConnMatch = trimmed.match(ASYNC_CONNECTION_RE);
|
|
492
|
+
if (asyncConnMatch) {
|
|
493
|
+
const rawLabel = asyncConnMatch[1] ?? "";
|
|
494
|
+
const labelResult = parseInArrowLabel(rawLabel, lineNumber);
|
|
495
|
+
result.diagnostics.push(...labelResult.diagnostics);
|
|
496
|
+
const label = labelResult.label ?? "";
|
|
497
|
+
const targetRaw = asyncConnMatch[2].trim();
|
|
498
|
+
const pipeMeta = extractPipeMetadata(targetRaw);
|
|
499
|
+
const targetName = pipeMeta.clean || targetRaw;
|
|
500
|
+
warnUnparsedPipeMeta(targetName, lineNumber, warn);
|
|
501
|
+
warnUnknownMetaKeys(
|
|
502
|
+
pipeMeta.tags,
|
|
503
|
+
EDGE_PIPE_REGISTRY,
|
|
504
|
+
(msg) => warn(lineNumber, msg)
|
|
505
|
+
);
|
|
506
|
+
const split = pipeMeta.tags["split"] ? parseFloat(pipeMeta.tags["split"]) : null;
|
|
507
|
+
const fanoutRaw = pipeMeta.tags["fanout"] ? parseInt(pipeMeta.tags["fanout"], 10) : null;
|
|
508
|
+
if (fanoutRaw !== null && fanoutRaw < 1) {
|
|
509
|
+
warn(
|
|
510
|
+
lineNumber,
|
|
511
|
+
`Fan-out multiplier must be at least 1 (got fanout: ${fanoutRaw}). Ignoring.`
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
const fanout = fanoutRaw !== null && fanoutRaw >= 1 ? fanoutRaw : null;
|
|
515
|
+
let targetId;
|
|
516
|
+
const targetGroupMatch = targetName.match(/^\[([^\]]+)\]/);
|
|
517
|
+
if (targetGroupMatch) {
|
|
518
|
+
targetId = groupId(targetGroupMatch[1]);
|
|
519
|
+
rememberTargetDisplay(targetId, `[${targetGroupMatch[1]}]`);
|
|
520
|
+
} else {
|
|
521
|
+
targetId = resolveTargetId(targetName);
|
|
522
|
+
rememberTargetDisplay(targetId, targetName);
|
|
523
|
+
}
|
|
524
|
+
result.edges.push({
|
|
525
|
+
sourceId: currentNode.id,
|
|
526
|
+
targetId,
|
|
527
|
+
label,
|
|
528
|
+
async: true,
|
|
529
|
+
split,
|
|
530
|
+
fanout,
|
|
531
|
+
lineNumber
|
|
532
|
+
});
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
const simpleConn = trimmed.match(SIMPLE_CONNECTION_RE);
|
|
536
|
+
if (simpleConn) {
|
|
537
|
+
const targetRaw = simpleConn[1].trim();
|
|
538
|
+
const pipeMeta = extractPipeMetadata(targetRaw);
|
|
539
|
+
const targetName = pipeMeta.clean || targetRaw;
|
|
540
|
+
warnUnparsedPipeMeta(targetName, lineNumber, warn);
|
|
541
|
+
warnUnknownMetaKeys(
|
|
542
|
+
pipeMeta.tags,
|
|
543
|
+
EDGE_PIPE_REGISTRY,
|
|
544
|
+
(msg) => warn(lineNumber, msg)
|
|
545
|
+
);
|
|
546
|
+
const split = pipeMeta.tags["split"] ? parseFloat(pipeMeta.tags["split"]) : null;
|
|
547
|
+
const fanoutRaw = pipeMeta.tags["fanout"] ? parseInt(pipeMeta.tags["fanout"], 10) : null;
|
|
548
|
+
if (fanoutRaw !== null && fanoutRaw < 1) {
|
|
549
|
+
warn(
|
|
550
|
+
lineNumber,
|
|
551
|
+
`Fan-out multiplier must be at least 1 (got fanout: ${fanoutRaw}). Ignoring.`
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
const fanout = fanoutRaw !== null && fanoutRaw >= 1 ? fanoutRaw : null;
|
|
555
|
+
const targetIdSimple = resolveTargetId(targetName);
|
|
556
|
+
rememberTargetDisplay(targetIdSimple, targetName);
|
|
557
|
+
result.edges.push({
|
|
558
|
+
sourceId: currentNode.id,
|
|
559
|
+
targetId: targetIdSimple,
|
|
560
|
+
label: "",
|
|
561
|
+
async: false,
|
|
562
|
+
split,
|
|
563
|
+
fanout,
|
|
564
|
+
lineNumber
|
|
565
|
+
});
|
|
566
|
+
continue;
|
|
567
|
+
}
|
|
568
|
+
const connMatch = trimmed.match(CONNECTION_RE);
|
|
569
|
+
if (connMatch) {
|
|
570
|
+
const rawLabel = connMatch[1] ?? "";
|
|
571
|
+
const labelResult = parseInArrowLabel(rawLabel, lineNumber);
|
|
572
|
+
result.diagnostics.push(...labelResult.diagnostics);
|
|
573
|
+
const label = labelResult.label ?? "";
|
|
574
|
+
const targetRaw = connMatch[2].trim();
|
|
575
|
+
const pipeMeta = extractPipeMetadata(targetRaw);
|
|
576
|
+
const targetName = pipeMeta.clean || targetRaw;
|
|
577
|
+
warnUnparsedPipeMeta(targetName, lineNumber, warn);
|
|
578
|
+
warnUnknownMetaKeys(
|
|
579
|
+
pipeMeta.tags,
|
|
580
|
+
EDGE_PIPE_REGISTRY,
|
|
581
|
+
(msg) => warn(lineNumber, msg)
|
|
582
|
+
);
|
|
583
|
+
const split = pipeMeta.tags["split"] ? parseFloat(pipeMeta.tags["split"]) : null;
|
|
584
|
+
const fanoutRaw = pipeMeta.tags["fanout"] ? parseInt(pipeMeta.tags["fanout"], 10) : null;
|
|
585
|
+
if (fanoutRaw !== null && fanoutRaw < 1) {
|
|
586
|
+
warn(
|
|
587
|
+
lineNumber,
|
|
588
|
+
`Fan-out multiplier must be at least 1 (got fanout: ${fanoutRaw}). Ignoring.`
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
const fanout = fanoutRaw !== null && fanoutRaw >= 1 ? fanoutRaw : null;
|
|
592
|
+
let targetId;
|
|
593
|
+
const targetGroupMatch = targetName.match(/^\[([^\]]+)\]/);
|
|
594
|
+
if (targetGroupMatch) {
|
|
595
|
+
targetId = groupId(targetGroupMatch[1]);
|
|
596
|
+
rememberTargetDisplay(targetId, `[${targetGroupMatch[1]}]`);
|
|
597
|
+
} else {
|
|
598
|
+
targetId = resolveTargetId(targetName);
|
|
599
|
+
rememberTargetDisplay(targetId, targetName);
|
|
600
|
+
}
|
|
601
|
+
result.edges.push({
|
|
602
|
+
sourceId: currentNode.id,
|
|
603
|
+
targetId,
|
|
604
|
+
label,
|
|
605
|
+
async: false,
|
|
606
|
+
split,
|
|
607
|
+
fanout,
|
|
608
|
+
lineNumber
|
|
609
|
+
});
|
|
610
|
+
continue;
|
|
611
|
+
}
|
|
612
|
+
if (/^description\s*:?\s*$/i.test(trimmed)) continue;
|
|
613
|
+
const propMatch = trimmed.match(PROPERTY_RE);
|
|
614
|
+
if (propMatch) {
|
|
615
|
+
const key = propMatch[1].toLowerCase();
|
|
616
|
+
const rawVal = propMatch[2].trim();
|
|
617
|
+
if (key === "description" && currentNode) {
|
|
618
|
+
if (!currentNode.isEdge) {
|
|
619
|
+
pushDescription(currentNode, rawVal);
|
|
620
|
+
}
|
|
621
|
+
continue;
|
|
622
|
+
}
|
|
623
|
+
if (currentNode && tagAliasSet.has(normalizeName(key))) {
|
|
624
|
+
const mut = nodeMutableTags.get(currentNode.id);
|
|
625
|
+
if (mut) mut[tagAttrKey(key)] = rawVal;
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
if (!INFRA_BEHAVIOR_KEYS.has(key) && !EDGE_ONLY_KEYS.has(key)) {
|
|
629
|
+
const allKeys = [...INFRA_BEHAVIOR_KEYS, ...EDGE_ONLY_KEYS];
|
|
630
|
+
const hint = suggest(key, allKeys);
|
|
631
|
+
const valueLooksNumeric = /^[\d.]+%?$/.test(rawVal);
|
|
632
|
+
if (hint || valueLooksNumeric) {
|
|
633
|
+
let msg = `Unknown infra property '${key}'.`;
|
|
634
|
+
if (hint) msg += ` ${hint}`;
|
|
635
|
+
else
|
|
636
|
+
msg += ` Properties are colon-keyed 'key: value' from the known schema (e.g. latency-ms, max-rps, cache-hit, instances, concurrency).`;
|
|
637
|
+
warn(lineNumber, msg);
|
|
638
|
+
} else if (!currentNode.isEdge) {
|
|
639
|
+
pushDescription(currentNode, trimmed);
|
|
640
|
+
continue;
|
|
641
|
+
}
|
|
642
|
+
continue;
|
|
643
|
+
}
|
|
644
|
+
if (EDGE_ONLY_KEYS.has(key) && !currentNode.isEdge) {
|
|
645
|
+
warn(
|
|
646
|
+
lineNumber,
|
|
647
|
+
`Property '${key}' belongs on the entry point \u2014 declare it indented under an 'internet' or 'edge' node, not on '${currentNode.label}'.`
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
const value = parsePropertyValue(rawVal);
|
|
651
|
+
currentNode.properties.push({ key, value, lineNumber });
|
|
652
|
+
continue;
|
|
653
|
+
}
|
|
654
|
+
const descResult = tryStripDescriptionKeyword(trimmed);
|
|
655
|
+
if (descResult.isKeyword && !descResult.needsColon) {
|
|
656
|
+
if (currentNode.isEdge) {
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
659
|
+
pushDescription(currentNode, descResult.text);
|
|
660
|
+
continue;
|
|
661
|
+
}
|
|
662
|
+
warn(
|
|
663
|
+
lineNumber,
|
|
664
|
+
`Unexpected line inside component '${currentNode.label}'. Expected a property (key: value), connection (-> Target), or a description (description: text).`
|
|
665
|
+
);
|
|
666
|
+
continue;
|
|
667
|
+
}
|
|
668
|
+
if (currentGroup && indent > 0) {
|
|
669
|
+
finishCurrentNode();
|
|
670
|
+
const compMatch = trimmed.match(COMPONENT_RE);
|
|
671
|
+
if (compMatch) {
|
|
672
|
+
const { qname, uname, alias: asAlias, meta } = compMatch.groups;
|
|
673
|
+
const rawName = (qname ?? uname ?? "").trim();
|
|
674
|
+
const peeled = peelInfraDecorations(rawName, lineNumber);
|
|
675
|
+
const name = peeled.label;
|
|
676
|
+
const alias = asAlias ?? peeled.alias;
|
|
677
|
+
const rest = meta ?? "";
|
|
678
|
+
const { tags: nodeTags } = extractPipeMetadata(rest);
|
|
679
|
+
warnUnknownMetaKeys(
|
|
680
|
+
nodeTags,
|
|
681
|
+
withTagAliases(INFRA_REGISTRY, tagAliasSet),
|
|
682
|
+
(msg) => warn(lineNumber, msg)
|
|
683
|
+
);
|
|
684
|
+
const id = nameAliasMap.get(name) ?? nodeId(name);
|
|
685
|
+
if (alias) nameAliasMap.set(alias, id);
|
|
686
|
+
const tags = currentGroup.metadata ? { ...currentGroup.metadata, ...nodeTags } : nodeTags;
|
|
687
|
+
currentNode = {
|
|
688
|
+
id,
|
|
689
|
+
label: name,
|
|
690
|
+
properties: [],
|
|
691
|
+
groupId: currentGroup.id,
|
|
692
|
+
tags,
|
|
693
|
+
isEdge: false,
|
|
694
|
+
lineNumber
|
|
695
|
+
};
|
|
696
|
+
nodeMutableTags.set(id, tags);
|
|
697
|
+
baseIndent = indent;
|
|
698
|
+
continue;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
if (indent === 0) {
|
|
702
|
+
const compMatch = trimmed.match(COMPONENT_RE);
|
|
703
|
+
if (compMatch) {
|
|
704
|
+
finishCurrentNode();
|
|
705
|
+
finishCurrentTagGroup();
|
|
706
|
+
currentGroup = null;
|
|
707
|
+
const { qname, uname, alias: asAlias, meta } = compMatch.groups;
|
|
708
|
+
const rawName = (qname ?? uname ?? "").trim();
|
|
709
|
+
const peeled = peelInfraDecorations(rawName, lineNumber);
|
|
710
|
+
const name = peeled.label;
|
|
711
|
+
const alias = asAlias ?? peeled.alias;
|
|
712
|
+
const rest = meta ?? "";
|
|
713
|
+
const { tags } = extractPipeMetadata(rest);
|
|
714
|
+
warnUnknownMetaKeys(
|
|
715
|
+
tags,
|
|
716
|
+
withTagAliases(INFRA_REGISTRY, tagAliasSet),
|
|
717
|
+
(msg) => warn(lineNumber, msg)
|
|
718
|
+
);
|
|
719
|
+
const id = nameAliasMap.get(name) ?? nodeId(name);
|
|
720
|
+
if (alias) nameAliasMap.set(alias, id);
|
|
721
|
+
currentNode = {
|
|
722
|
+
id,
|
|
723
|
+
label: name,
|
|
724
|
+
properties: [],
|
|
725
|
+
groupId: null,
|
|
726
|
+
tags,
|
|
727
|
+
isEdge: EDGE_NODE_NAMES.has(id.toLowerCase()),
|
|
728
|
+
lineNumber
|
|
729
|
+
};
|
|
730
|
+
nodeMutableTags.set(id, tags);
|
|
731
|
+
baseIndent = 0;
|
|
732
|
+
continue;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
warn(
|
|
736
|
+
lineNumber,
|
|
737
|
+
currentGroup ? `Unexpected line: '${trimmed}'. Inside a group, indent a component name under the '[Group]'.` : `Unexpected line: '${trimmed}'. Expected a node ('Api Gateway'), a group ('[Backend]'), a tag group ('tag Tier as t'), or an option ('default-rps 100'); node properties go indented under a node as 'key: value'.`
|
|
738
|
+
);
|
|
739
|
+
}
|
|
740
|
+
finishCurrentNode();
|
|
741
|
+
finishCurrentTagGroup();
|
|
742
|
+
for (const edge of result.edges) {
|
|
743
|
+
if (!nodeMap.has(edge.targetId)) {
|
|
744
|
+
const isGroup = result.groups.some((g) => g.id === edge.targetId);
|
|
745
|
+
if (!isGroup) {
|
|
746
|
+
const stubDisplay = targetDisplays.get(edge.targetId) ?? edge.targetId;
|
|
747
|
+
const stubTags = {};
|
|
748
|
+
const stub = {
|
|
749
|
+
id: edge.targetId,
|
|
750
|
+
label: stubDisplay,
|
|
751
|
+
properties: [],
|
|
752
|
+
groupId: null,
|
|
753
|
+
tags: stubTags,
|
|
754
|
+
isEdge: false,
|
|
755
|
+
lineNumber: edge.lineNumber
|
|
756
|
+
};
|
|
757
|
+
nodeMap.set(stub.id, stub);
|
|
758
|
+
result.nodes.push(stub);
|
|
759
|
+
nodeMutableTags.set(stub.id, stubTags);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
for (const tg of result.tagGroups) {
|
|
764
|
+
if (!tg.defaultValue) continue;
|
|
765
|
+
const key = tagAttrKey(tg.alias ?? tg.name);
|
|
766
|
+
for (const node of result.nodes) {
|
|
767
|
+
if (node.isEdge) continue;
|
|
768
|
+
if (!(key in node.tags)) {
|
|
769
|
+
const tags = nodeMutableTags.get(node.id);
|
|
770
|
+
if (tags) tags[key] = tg.defaultValue;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
validateTagGroupNames(result.tagGroups, warn, setError);
|
|
775
|
+
checkReachability(result);
|
|
776
|
+
return result;
|
|
777
|
+
}
|
|
778
|
+
function checkReachability(result) {
|
|
779
|
+
if (result.nodes.length === 0) return;
|
|
780
|
+
const entries = result.nodes.filter((n) => n.isEdge);
|
|
781
|
+
if (entries.length === 0) {
|
|
782
|
+
const line = result.titleLineNumber ?? result.nodes[0]?.lineNumber ?? 1;
|
|
783
|
+
result.diagnostics.push(emit(GRAPH_DX.INFRA_NO_ENTRY, line));
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
const groupChildMap = /* @__PURE__ */ new Map();
|
|
787
|
+
for (const node of result.nodes) {
|
|
788
|
+
if (node.groupId) {
|
|
789
|
+
const list = groupChildMap.get(node.groupId) ?? [];
|
|
790
|
+
list.push(node.id);
|
|
791
|
+
groupChildMap.set(node.groupId, list);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
const outbound = /* @__PURE__ */ new Map();
|
|
795
|
+
for (const edge of result.edges) {
|
|
796
|
+
const targets = groupChildMap.get(edge.targetId) ?? [edge.targetId];
|
|
797
|
+
const list = outbound.get(edge.sourceId) ?? [];
|
|
798
|
+
list.push(...targets);
|
|
799
|
+
outbound.set(edge.sourceId, list);
|
|
800
|
+
}
|
|
801
|
+
const reachable = /* @__PURE__ */ new Set();
|
|
802
|
+
const queue = [];
|
|
803
|
+
for (const entry of entries) {
|
|
804
|
+
reachable.add(entry.id);
|
|
805
|
+
queue.push(entry.id);
|
|
806
|
+
}
|
|
807
|
+
while (queue.length > 0) {
|
|
808
|
+
const current = queue.shift();
|
|
809
|
+
for (const next of outbound.get(current) ?? []) {
|
|
810
|
+
if (!reachable.has(next)) {
|
|
811
|
+
reachable.add(next);
|
|
812
|
+
queue.push(next);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
for (const node of result.nodes) {
|
|
817
|
+
if (node.isEdge || reachable.has(node.id)) continue;
|
|
818
|
+
result.diagnostics.push(
|
|
819
|
+
emit(GRAPH_DX.INFRA_UNREACHABLE, node.lineNumber, { label: node.label })
|
|
820
|
+
);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
function stripNodeDecorations(name) {
|
|
824
|
+
let s = name.trim();
|
|
825
|
+
const aliasMatch = s.match(/^(.*?)\s+as\s+[A-Za-z][A-Za-z0-9_]{0,11}\s*$/);
|
|
826
|
+
if (aliasMatch) s = aliasMatch[1].trim();
|
|
827
|
+
const isAMatch = s.match(/^(.*?)\s+is\s+an?\s+[A-Za-z][\w-]*\s*$/i);
|
|
828
|
+
if (isAMatch) s = isAMatch[1].trim();
|
|
829
|
+
return s;
|
|
830
|
+
}
|
|
831
|
+
function extractSymbols(docText) {
|
|
832
|
+
const entities = [];
|
|
833
|
+
let inMetadata = true;
|
|
834
|
+
let inTagGroup = false;
|
|
835
|
+
for (const rawLine of docText.split("\n")) {
|
|
836
|
+
const line = rawLine.trim();
|
|
837
|
+
if (line.length === 0) continue;
|
|
838
|
+
const indented = /^\s/.test(rawLine);
|
|
839
|
+
if (inMetadata) {
|
|
840
|
+
if (!indented) {
|
|
841
|
+
const firstLine = parseFirstLine(line);
|
|
842
|
+
if (firstLine) continue;
|
|
843
|
+
if (/^(?:direction-tb|animate|no-animate|slo-|default-)/i.test(line))
|
|
844
|
+
continue;
|
|
845
|
+
if (/^[a-z-]+\s*:/i.test(line)) continue;
|
|
846
|
+
inMetadata = false;
|
|
847
|
+
} else {
|
|
848
|
+
continue;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
if (!indented) {
|
|
852
|
+
if (/^tag\s/i.test(line)) {
|
|
853
|
+
inTagGroup = true;
|
|
854
|
+
continue;
|
|
855
|
+
}
|
|
856
|
+
if (/^tag\s*:/i.test(line)) {
|
|
857
|
+
inTagGroup = true;
|
|
858
|
+
continue;
|
|
859
|
+
}
|
|
860
|
+
inTagGroup = false;
|
|
861
|
+
if (/^\[/.test(line)) continue;
|
|
862
|
+
const m = COMPONENT_RE.exec(line);
|
|
863
|
+
if (m) {
|
|
864
|
+
const name = stripNodeDecorations((m[1] ?? m[2] ?? "").trim());
|
|
865
|
+
if (name && !entities.includes(name)) entities.push(name);
|
|
866
|
+
}
|
|
867
|
+
} else {
|
|
868
|
+
if (inTagGroup) continue;
|
|
869
|
+
if (/^->/.test(line)) continue;
|
|
870
|
+
if (/^~>/.test(line)) continue;
|
|
871
|
+
if (/^-[^>]+-?>/.test(line)) continue;
|
|
872
|
+
if (/^~[^~]+~>/.test(line)) continue;
|
|
873
|
+
if (/^\w[\w-]*\s*:/.test(line)) continue;
|
|
874
|
+
const firstToken = line.split(/\s/)[0].toLowerCase();
|
|
875
|
+
if ((INFRA_BEHAVIOR_KEYS.has(firstToken) || EDGE_ONLY_KEYS.has(firstToken) || firstToken === "description" || firstToken === "instances" || firstToken === "collapsed") && /\s/.test(line))
|
|
876
|
+
continue;
|
|
877
|
+
const m = COMPONENT_RE.exec(line);
|
|
878
|
+
if (m) {
|
|
879
|
+
const name = stripNodeDecorations((m[1] ?? m[2] ?? "").trim());
|
|
880
|
+
if (name && !entities.includes(name)) entities.push(name);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
return { kind: "infra", entities };
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
export {
|
|
888
|
+
INFRA_BEHAVIOR_KEYS,
|
|
889
|
+
INFRA_TOP_LEVEL_OPTIONS,
|
|
890
|
+
parseInfra,
|
|
891
|
+
extractSymbols
|
|
892
|
+
};
|
|
893
|
+
//# sourceMappingURL=chunk-33LCUH4H.js.map
|