schematex 0.6.9 → 0.7.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/ai/ai-sdk.cjs +8 -8
- package/dist/ai/ai-sdk.js +3 -3
- package/dist/ai/index.cjs +14 -14
- package/dist/ai/index.js +3 -3
- package/dist/browser.cjs +9 -9
- package/dist/browser.js +3 -3
- package/dist/{chunk-25TO5A4F.cjs → chunk-CTMJ3XP2.cjs} +156 -9
- package/dist/chunk-CTMJ3XP2.cjs.map +1 -0
- package/dist/{chunk-HL5PS6MG.js → chunk-EENA7KNU.js} +324 -27
- package/dist/chunk-EENA7KNU.js.map +1 -0
- package/dist/{chunk-5IZL57YJ.cjs → chunk-HFATQXFN.cjs} +1455 -158
- package/dist/chunk-HFATQXFN.cjs.map +1 -0
- package/dist/{chunk-3DPWFWQU.js → chunk-IFNNV54X.js} +1454 -157
- package/dist/chunk-IFNNV54X.js.map +1 -0
- package/dist/{chunk-Q5V4LUQR.js → chunk-IFXHIYZE.js} +154 -7
- package/dist/chunk-IFXHIYZE.js.map +1 -0
- package/dist/{chunk-BL57NQKN.cjs → chunk-JAYJ2G4R.cjs} +324 -27
- package/dist/chunk-JAYJ2G4R.cjs.map +1 -0
- package/dist/diagrams/phylo/index.cjs +6 -6
- package/dist/diagrams/phylo/index.d.cts +21 -0
- package/dist/diagrams/phylo/index.d.ts +21 -0
- package/dist/diagrams/phylo/index.js +1 -1
- package/dist/index.cjs +25 -25
- package/dist/index.js +3 -3
- package/dist/react.cjs +3 -3
- package/dist/react.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-25TO5A4F.cjs.map +0 -1
- package/dist/chunk-3DPWFWQU.js.map +0 -1
- package/dist/chunk-5IZL57YJ.cjs.map +0 -1
- package/dist/chunk-BL57NQKN.cjs.map +0 -1
- package/dist/chunk-HL5PS6MG.js.map +0 -1
- package/dist/chunk-Q5V4LUQR.js.map +0 -1
|
@@ -11,7 +11,7 @@ import { genogram } from './chunk-6NUAGU6O.js';
|
|
|
11
11
|
import { ecomap } from './chunk-K2D6VFLP.js';
|
|
12
12
|
import { pedigree } from './chunk-JN6FHUC6.js';
|
|
13
13
|
import { parseFrontmatter } from './chunk-2KTQ75LN.js';
|
|
14
|
-
import { phylo } from './chunk-
|
|
14
|
+
import { phylo } from './chunk-EENA7KNU.js';
|
|
15
15
|
import { sociogram } from './chunk-OFKRELZK.js';
|
|
16
16
|
import { timing } from './chunk-P26FCZP3.js';
|
|
17
17
|
import { logic } from './chunk-3GAPHXCE.js';
|
|
@@ -19,6 +19,207 @@ import { resolveBaseTheme, resolveTimelineTheme, cssCustomProperties, resolvePet
|
|
|
19
19
|
import { matchQuotedTitle, stripQuotes } from './chunk-5IKOLUWK.js';
|
|
20
20
|
import { el, escapeXml, group, rect, text, line, path, circle, polygon, title, desc, svgRoot, defs, multilineText } from './chunk-SYYBKDL7.js';
|
|
21
21
|
|
|
22
|
+
// src/diagrams/decisiontree/influence-parser.ts
|
|
23
|
+
function preprocess(src) {
|
|
24
|
+
const out = [];
|
|
25
|
+
const lines = src.split(/\r?\n/);
|
|
26
|
+
for (let i = 0; i < lines.length; i++) {
|
|
27
|
+
const raw = lines[i];
|
|
28
|
+
if (raw === void 0) continue;
|
|
29
|
+
const trimmed = raw.trim();
|
|
30
|
+
if (!trimmed || trimmed.startsWith("#") || trimmed.startsWith("//")) continue;
|
|
31
|
+
out.push({ text: trimmed, line: i + 1 });
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
function tokenize(s, lineNum) {
|
|
36
|
+
const tokens = [];
|
|
37
|
+
let i = 0;
|
|
38
|
+
while (i < s.length) {
|
|
39
|
+
const ch = s[i];
|
|
40
|
+
if (/\s/.test(ch)) {
|
|
41
|
+
i++;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (ch === '"') {
|
|
45
|
+
const end = s.indexOf('"', i + 1);
|
|
46
|
+
if (end < 0) throw new DTreeParseError(`Unterminated string: ${s}`, lineNum);
|
|
47
|
+
tokens.push(s.slice(i, end + 1));
|
|
48
|
+
i = end + 1;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
let j = i;
|
|
52
|
+
while (j < s.length && !/\s/.test(s[j]) && s[j] !== '"') j++;
|
|
53
|
+
tokens.push(s.slice(i, j));
|
|
54
|
+
i = j;
|
|
55
|
+
}
|
|
56
|
+
return tokens;
|
|
57
|
+
}
|
|
58
|
+
function unquote(s) {
|
|
59
|
+
if (s.startsWith('"') && s.endsWith('"')) return s.slice(1, -1);
|
|
60
|
+
return s;
|
|
61
|
+
}
|
|
62
|
+
function isQuoted(s) {
|
|
63
|
+
return s.startsWith('"') && s.endsWith('"') && s.length >= 2;
|
|
64
|
+
}
|
|
65
|
+
function toKind(kw) {
|
|
66
|
+
if (kw === "decision" || kw === "dec") return "decision";
|
|
67
|
+
if (kw === "chance" || kw === "uncertainty" || kw === "event") return "chance";
|
|
68
|
+
if (kw === "value" || kw === "utility" || kw === "objective") return "value";
|
|
69
|
+
return void 0;
|
|
70
|
+
}
|
|
71
|
+
var NODE_KEYWORDS = /* @__PURE__ */ new Set([
|
|
72
|
+
"decision",
|
|
73
|
+
"dec",
|
|
74
|
+
"chance",
|
|
75
|
+
"uncertainty",
|
|
76
|
+
"event",
|
|
77
|
+
"value",
|
|
78
|
+
"utility",
|
|
79
|
+
"objective",
|
|
80
|
+
"node"
|
|
81
|
+
]);
|
|
82
|
+
function parseInfluence(src, title2) {
|
|
83
|
+
const lines = preprocess(src);
|
|
84
|
+
const nodes = [];
|
|
85
|
+
const nodeById = /* @__PURE__ */ new Map();
|
|
86
|
+
const arcDecls = [];
|
|
87
|
+
let direction = "left-right";
|
|
88
|
+
for (const { text: text2, line: line2 } of lines) {
|
|
89
|
+
const cfg = text2.match(/^([a-zA-Z][\w-]*)\s*:\s*(.+)$/);
|
|
90
|
+
if (cfg && !text2.includes("->") && !NODE_KEYWORDS.has(cfg[1].toLowerCase())) {
|
|
91
|
+
const key = cfg[1].toLowerCase();
|
|
92
|
+
const val = cfg[2].trim().toLowerCase();
|
|
93
|
+
if (key === "direction") {
|
|
94
|
+
direction = val === "top-down" || val === "td" ? "top-down" : "left-right";
|
|
95
|
+
}
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (text2.includes("->")) {
|
|
99
|
+
const arrowIdx = text2.indexOf("->");
|
|
100
|
+
const fromPart = text2.slice(0, arrowIdx).trim();
|
|
101
|
+
const afterTokens = tokenize(text2.slice(arrowIdx + 2).trim(), line2);
|
|
102
|
+
const to = afterTokens[0];
|
|
103
|
+
if (!fromPart || !to) {
|
|
104
|
+
throw new DTreeParseError(`Malformed arc: "${text2}"`, line2);
|
|
105
|
+
}
|
|
106
|
+
let label2;
|
|
107
|
+
if (afterTokens[1] !== void 0 && isQuoted(afterTokens[1])) {
|
|
108
|
+
label2 = unquote(afterTokens[1]);
|
|
109
|
+
}
|
|
110
|
+
arcDecls.push({ from: fromPart, to: unquote(to), label: label2, line: line2 });
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
const tokens = tokenize(text2, line2);
|
|
114
|
+
const kw = tokens[0];
|
|
115
|
+
if (!kw) continue;
|
|
116
|
+
let kind;
|
|
117
|
+
let idIdx = 1;
|
|
118
|
+
if (kw === "node") {
|
|
119
|
+
kind = void 0;
|
|
120
|
+
} else {
|
|
121
|
+
kind = toKind(kw.toLowerCase());
|
|
122
|
+
if (!kind) {
|
|
123
|
+
throw new DTreeParseError(
|
|
124
|
+
`Unknown influence statement "${kw}" (expected decision/chance/value or an arc "a -> b")`,
|
|
125
|
+
line2
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const id = tokens[idIdx];
|
|
130
|
+
if (!id || isQuoted(id)) {
|
|
131
|
+
throw new DTreeParseError(`Node declaration requires an id: "${text2}"`, line2);
|
|
132
|
+
}
|
|
133
|
+
idIdx++;
|
|
134
|
+
let label = "";
|
|
135
|
+
let utility;
|
|
136
|
+
for (let k = idIdx; k < tokens.length; k++) {
|
|
137
|
+
const tok = tokens[k];
|
|
138
|
+
if (isQuoted(tok)) {
|
|
139
|
+
label = unquote(tok);
|
|
140
|
+
} else if (tok.includes("=")) {
|
|
141
|
+
const eq = tok.indexOf("=");
|
|
142
|
+
const key = tok.slice(0, eq).toLowerCase();
|
|
143
|
+
const value = tok.slice(eq + 1);
|
|
144
|
+
if (key === "utility" || key === "payoff" || key === "value") {
|
|
145
|
+
const num = Number(value);
|
|
146
|
+
if (!Number.isNaN(num)) utility = num;
|
|
147
|
+
} else if (key === "kind") {
|
|
148
|
+
const resolved = toKind(value.toLowerCase());
|
|
149
|
+
if (!resolved) throw new DTreeParseError(`Unknown node kind "${value}"`, line2);
|
|
150
|
+
kind = resolved;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (!kind) {
|
|
155
|
+
throw new DTreeParseError(`node "${id}" is missing a kind (use kind=decision|chance|value)`, line2);
|
|
156
|
+
}
|
|
157
|
+
if (nodeById.has(id)) {
|
|
158
|
+
throw new DTreeParseError(`Duplicate node id "${id}"`, line2);
|
|
159
|
+
}
|
|
160
|
+
const node = { id, kind, label: label || id };
|
|
161
|
+
if (utility !== void 0) node.utility = utility;
|
|
162
|
+
nodes.push(node);
|
|
163
|
+
nodeById.set(id, node);
|
|
164
|
+
}
|
|
165
|
+
if (nodes.length === 0) {
|
|
166
|
+
throw new DTreeParseError("Influence diagram has no nodes");
|
|
167
|
+
}
|
|
168
|
+
const valueNodes = nodes.filter((n) => n.kind === "value");
|
|
169
|
+
if (valueNodes.length === 0) {
|
|
170
|
+
throw new DTreeParseError(
|
|
171
|
+
'Influence diagram requires at least one value node (declare `value <id> "..."`)'
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
const arcs = [];
|
|
175
|
+
for (const a of arcDecls) {
|
|
176
|
+
const fromNode = nodeById.get(a.from);
|
|
177
|
+
const toNode = nodeById.get(a.to);
|
|
178
|
+
if (!fromNode) throw new DTreeParseError(`Arc references undefined node "${a.from}"`, a.line);
|
|
179
|
+
if (!toNode) throw new DTreeParseError(`Arc references undefined node "${a.to}"`, a.line);
|
|
180
|
+
if (a.from === a.to) throw new DTreeParseError(`Self-loop on node "${a.from}" is not allowed`, a.line);
|
|
181
|
+
const kind = toNode.kind === "decision" ? "information" : toNode.kind === "value" ? "functional" : "relevance";
|
|
182
|
+
const arc = { from: a.from, to: a.to, kind };
|
|
183
|
+
if (a.label !== void 0) arc.label = a.label;
|
|
184
|
+
arcs.push(arc);
|
|
185
|
+
}
|
|
186
|
+
detectCycle(nodes, arcs);
|
|
187
|
+
return {
|
|
188
|
+
type: "decisiontree",
|
|
189
|
+
mode: "influence",
|
|
190
|
+
title: title2,
|
|
191
|
+
direction,
|
|
192
|
+
nodes,
|
|
193
|
+
arcs
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
function detectCycle(nodes, arcs) {
|
|
197
|
+
const adj = /* @__PURE__ */ new Map();
|
|
198
|
+
for (const n of nodes) adj.set(n.id, []);
|
|
199
|
+
for (const a of arcs) adj.get(a.from).push(a.to);
|
|
200
|
+
const state2 = /* @__PURE__ */ new Map();
|
|
201
|
+
for (const n of nodes) state2.set(n.id, 0);
|
|
202
|
+
const stackPath = [];
|
|
203
|
+
function visit(id) {
|
|
204
|
+
state2.set(id, 1);
|
|
205
|
+
stackPath.push(id);
|
|
206
|
+
for (const next of adj.get(id) ?? []) {
|
|
207
|
+
const s = state2.get(next) ?? 0;
|
|
208
|
+
if (s === 1) {
|
|
209
|
+
const cycleStart = stackPath.indexOf(next);
|
|
210
|
+
const cycle = [...stackPath.slice(cycleStart), next].join(" -> ");
|
|
211
|
+
throw new DTreeParseError(`Influence diagram must be acyclic \u2014 cycle detected: ${cycle}`);
|
|
212
|
+
}
|
|
213
|
+
if (s === 0) visit(next);
|
|
214
|
+
}
|
|
215
|
+
stackPath.pop();
|
|
216
|
+
state2.set(id, 2);
|
|
217
|
+
}
|
|
218
|
+
for (const n of nodes) {
|
|
219
|
+
if (state2.get(n.id) === 0) visit(n.id);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
22
223
|
// src/diagrams/decisiontree/parser.ts
|
|
23
224
|
var DTreeParseError = class extends Error {
|
|
24
225
|
constructor(message, line2, column, source) {
|
|
@@ -32,7 +233,7 @@ var DTreeParseError = class extends Error {
|
|
|
32
233
|
column;
|
|
33
234
|
source;
|
|
34
235
|
};
|
|
35
|
-
function
|
|
236
|
+
function preprocess2(src) {
|
|
36
237
|
const out = [];
|
|
37
238
|
const lines = src.split(/\r?\n/);
|
|
38
239
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -44,7 +245,7 @@ function preprocess(src) {
|
|
|
44
245
|
}
|
|
45
246
|
return out;
|
|
46
247
|
}
|
|
47
|
-
function
|
|
248
|
+
function tokenize2(s) {
|
|
48
249
|
const tokens = [];
|
|
49
250
|
let i = 0;
|
|
50
251
|
while (i < s.length) {
|
|
@@ -75,7 +276,7 @@ function tokenize(s) {
|
|
|
75
276
|
}
|
|
76
277
|
return tokens;
|
|
77
278
|
}
|
|
78
|
-
function
|
|
279
|
+
function unquote2(s) {
|
|
79
280
|
if (s.startsWith('"') && s.endsWith('"')) return s.slice(1, -1);
|
|
80
281
|
return s;
|
|
81
282
|
}
|
|
@@ -85,7 +286,7 @@ function parseKV(tokens) {
|
|
|
85
286
|
const rest = [];
|
|
86
287
|
for (const tok of tokens) {
|
|
87
288
|
if (tok.startsWith('"') && tok.endsWith('"')) {
|
|
88
|
-
labels.push(
|
|
289
|
+
labels.push(unquote2(tok));
|
|
89
290
|
} else if (tok.includes("=")) {
|
|
90
291
|
const idx = tok.indexOf("=");
|
|
91
292
|
const k = tok.slice(0, idx);
|
|
@@ -114,7 +315,7 @@ function parseDecisionLine(tokens, _ctx, lineNum) {
|
|
|
114
315
|
idx++;
|
|
115
316
|
const next = tokens[idx];
|
|
116
317
|
if (!next || !next.startsWith('"')) throw new DTreeParseError(`"choice" requires a label`, lineNum);
|
|
117
|
-
incomingChoice =
|
|
318
|
+
incomingChoice = unquote2(next);
|
|
118
319
|
idx++;
|
|
119
320
|
if (idx >= tokens.length) {
|
|
120
321
|
return {
|
|
@@ -213,7 +414,7 @@ function parseTaxonomyLine(tokens, _ctx, lineNum) {
|
|
|
213
414
|
idx++;
|
|
214
415
|
const lbl = tokens[idx];
|
|
215
416
|
if (!lbl || !lbl.startsWith('"')) throw new DTreeParseError(`"label" requires a quoted string`, lineNum);
|
|
216
|
-
branchLabel =
|
|
417
|
+
branchLabel = unquote2(lbl.replace(/":?$/, '"'));
|
|
217
418
|
if (lbl.endsWith(':"')) ;
|
|
218
419
|
idx++;
|
|
219
420
|
if (tokens[idx] === ":") idx++;
|
|
@@ -237,7 +438,7 @@ function parseTaxonomyLine(tokens, _ctx, lineNum) {
|
|
|
237
438
|
}
|
|
238
439
|
function parseNodeLine(text2, mode, ctx, lineNum) {
|
|
239
440
|
const normalized = text2.replace(/"\s*:\s*/g, '" : ');
|
|
240
|
-
const tokens =
|
|
441
|
+
const tokens = tokenize2(normalized).filter((t) => t !== ":");
|
|
241
442
|
if (mode === "decision") return parseDecisionLine(tokens, ctx, lineNum);
|
|
242
443
|
if (mode === "ml") return parseMlLine(tokens, ctx, lineNum);
|
|
243
444
|
return parseTaxonomyLine(tokens, ctx, lineNum);
|
|
@@ -305,14 +506,19 @@ function validateDecision(node, lineMap) {
|
|
|
305
506
|
}
|
|
306
507
|
function parseDecisionTree(src) {
|
|
307
508
|
idCounter = 0;
|
|
308
|
-
const lines =
|
|
509
|
+
const lines = preprocess2(src);
|
|
309
510
|
if (lines.length === 0) throw new DTreeParseError("Empty input");
|
|
310
511
|
const header = lines.shift();
|
|
311
512
|
const headerMatch = header.text.match(/^decisiontree(?::(\w+))?(?:\s+"([^"]*)")?\s*$/i);
|
|
312
513
|
if (!headerMatch) throw new DTreeParseError(`Invalid header: ${header.text}`, header.line);
|
|
313
514
|
const modeRaw = (headerMatch[1] ?? "taxonomy").toLowerCase();
|
|
314
|
-
const mode = modeRaw === "decision" || modeRaw === "da" ? "decision" : modeRaw === "ml" ? "ml" : "taxonomy";
|
|
315
515
|
const title2 = headerMatch[2];
|
|
516
|
+
const wantsInfluence = modeRaw === "influence" || modeRaw === "id" || lines.some((l) => /^(mode|layout)\s*:\s*influence\s*$/i.test(l.text));
|
|
517
|
+
if (wantsInfluence) {
|
|
518
|
+
const body = lines.map((l) => l.text).join("\n");
|
|
519
|
+
return parseInfluence(body, title2);
|
|
520
|
+
}
|
|
521
|
+
const mode = modeRaw === "decision" || modeRaw === "da" ? "decision" : modeRaw === "ml" ? "ml" : "taxonomy";
|
|
316
522
|
const nodeKeywords = /* @__PURE__ */ new Set([
|
|
317
523
|
"decision",
|
|
318
524
|
"chance",
|
|
@@ -623,7 +829,7 @@ function layoutDecisionTree(ast) {
|
|
|
623
829
|
enforceSibGap(root, sibH, sibGap);
|
|
624
830
|
const levelOffsets = computeLevelOffsets(root, sibH, levelGap);
|
|
625
831
|
setFinal(root, sibH, levelOffsets);
|
|
626
|
-
const
|
|
832
|
+
const PADDING4 = 40;
|
|
627
833
|
const extraLeft = ast.mode === "decision" && !sibH ? 110 : 0;
|
|
628
834
|
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
629
835
|
for (const n of all) {
|
|
@@ -648,8 +854,8 @@ function layoutDecisionTree(ast) {
|
|
|
648
854
|
maxX = Math.max(maxX, n.xFinal + n.size.w / 2);
|
|
649
855
|
}
|
|
650
856
|
}
|
|
651
|
-
const offsetX =
|
|
652
|
-
const offsetY =
|
|
857
|
+
const offsetX = PADDING4 + extraLeft - minX;
|
|
858
|
+
const offsetY = PADDING4 - minY;
|
|
653
859
|
const layoutNodes = all.map((w) => ({
|
|
654
860
|
node: w.node,
|
|
655
861
|
x: w.xFinal + offsetX,
|
|
@@ -710,8 +916,8 @@ function layoutDecisionTree(ast) {
|
|
|
710
916
|
for (const n of layoutNodes) if (n.node.kind === "end") endX = Math.max(endX, n.x + n.width / 2);
|
|
711
917
|
payoffColumnX = endX + payoffColGap;
|
|
712
918
|
}
|
|
713
|
-
const width = Math.ceil(maxX - minX +
|
|
714
|
-
const height = Math.ceil(maxY - minY +
|
|
919
|
+
const width = Math.ceil(maxX - minX + PADDING4 * 2 + extraRight + extraLeft);
|
|
920
|
+
const height = Math.ceil(maxY - minY + PADDING4 * 2);
|
|
715
921
|
return {
|
|
716
922
|
width,
|
|
717
923
|
height,
|
|
@@ -741,6 +947,296 @@ function formatProb(p) {
|
|
|
741
947
|
return `p=${p}`;
|
|
742
948
|
}
|
|
743
949
|
|
|
950
|
+
// src/diagrams/decisiontree/influence-layout.ts
|
|
951
|
+
function sizeOf2(node) {
|
|
952
|
+
const labelW = Math.min(180, Math.max(72, node.label.length * 8 + 28));
|
|
953
|
+
if (node.kind === "decision") return { w: labelW, h: 48 };
|
|
954
|
+
if (node.kind === "value") return { w: labelW + 12, h: 54 };
|
|
955
|
+
return { w: labelW, h: 52 };
|
|
956
|
+
}
|
|
957
|
+
var LAYER_GAP = 80;
|
|
958
|
+
var CROSS_GAP = 36;
|
|
959
|
+
var PADDING = 36;
|
|
960
|
+
function assignLayers(nodes, arcs) {
|
|
961
|
+
const adj = /* @__PURE__ */ new Map();
|
|
962
|
+
const indeg = /* @__PURE__ */ new Map();
|
|
963
|
+
for (const n of nodes) {
|
|
964
|
+
adj.set(n.id, []);
|
|
965
|
+
indeg.set(n.id, 0);
|
|
966
|
+
}
|
|
967
|
+
for (const a of arcs) {
|
|
968
|
+
adj.get(a.from).push(a.to);
|
|
969
|
+
indeg.set(a.to, (indeg.get(a.to) ?? 0) + 1);
|
|
970
|
+
}
|
|
971
|
+
const queue = [];
|
|
972
|
+
for (const n of nodes) if ((indeg.get(n.id) ?? 0) === 0) queue.push(n.id);
|
|
973
|
+
const layer = /* @__PURE__ */ new Map();
|
|
974
|
+
for (const n of nodes) layer.set(n.id, 0);
|
|
975
|
+
const indegWork = new Map(indeg);
|
|
976
|
+
while (queue.length > 0) {
|
|
977
|
+
const id = queue.shift();
|
|
978
|
+
for (const next of adj.get(id) ?? []) {
|
|
979
|
+
const cand = (layer.get(id) ?? 0) + 1;
|
|
980
|
+
if (cand > (layer.get(next) ?? 0)) layer.set(next, cand);
|
|
981
|
+
indegWork.set(next, (indegWork.get(next) ?? 0) - 1);
|
|
982
|
+
if ((indegWork.get(next) ?? 0) === 0) queue.push(next);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
const maxLayer = Math.max(0, ...nodes.map((n) => layer.get(n.id) ?? 0));
|
|
986
|
+
for (const n of nodes) {
|
|
987
|
+
if (n.kind === "value") layer.set(n.id, maxLayer);
|
|
988
|
+
}
|
|
989
|
+
return layer;
|
|
990
|
+
}
|
|
991
|
+
function layoutInfluence(ast) {
|
|
992
|
+
const flowVertical = ast.direction === "top-down";
|
|
993
|
+
const layerOf = assignLayers(ast.nodes, ast.arcs);
|
|
994
|
+
const sizes = new Map(ast.nodes.map((n) => [n.id, sizeOf2(n)]));
|
|
995
|
+
const layers = /* @__PURE__ */ new Map();
|
|
996
|
+
for (const n of ast.nodes) {
|
|
997
|
+
const l = layerOf.get(n.id) ?? 0;
|
|
998
|
+
if (!layers.has(l)) layers.set(l, []);
|
|
999
|
+
layers.get(l).push(n);
|
|
1000
|
+
}
|
|
1001
|
+
const layerIndices = Array.from(layers.keys()).sort((a, b) => a - b);
|
|
1002
|
+
const flowExtent = (s) => flowVertical ? s.h : s.w;
|
|
1003
|
+
const crossExtent = (s) => flowVertical ? s.w : s.h;
|
|
1004
|
+
const layerFlowSize = /* @__PURE__ */ new Map();
|
|
1005
|
+
for (const l of layerIndices) {
|
|
1006
|
+
let maxF = 0;
|
|
1007
|
+
for (const n of layers.get(l)) maxF = Math.max(maxF, flowExtent(sizes.get(n.id)));
|
|
1008
|
+
layerFlowSize.set(l, maxF);
|
|
1009
|
+
}
|
|
1010
|
+
const layerFlowCentre = /* @__PURE__ */ new Map();
|
|
1011
|
+
let acc = PADDING;
|
|
1012
|
+
for (const l of layerIndices) {
|
|
1013
|
+
const half = layerFlowSize.get(l) / 2;
|
|
1014
|
+
acc += half;
|
|
1015
|
+
layerFlowCentre.set(l, acc);
|
|
1016
|
+
acc += half + LAYER_GAP;
|
|
1017
|
+
}
|
|
1018
|
+
const flowTotal = acc - LAYER_GAP + PADDING;
|
|
1019
|
+
const layerCrossExtent = /* @__PURE__ */ new Map();
|
|
1020
|
+
for (const l of layerIndices) {
|
|
1021
|
+
const ns = layers.get(l);
|
|
1022
|
+
let total = 0;
|
|
1023
|
+
for (let i = 0; i < ns.length; i++) {
|
|
1024
|
+
total += crossExtent(sizes.get(ns[i].id));
|
|
1025
|
+
if (i < ns.length - 1) total += CROSS_GAP;
|
|
1026
|
+
}
|
|
1027
|
+
layerCrossExtent.set(l, total);
|
|
1028
|
+
}
|
|
1029
|
+
const maxCross = Math.max(PADDING, ...Array.from(layerCrossExtent.values()));
|
|
1030
|
+
const crossTotal = maxCross + PADDING * 2;
|
|
1031
|
+
const crossCentre = PADDING + maxCross / 2;
|
|
1032
|
+
const placed = /* @__PURE__ */ new Map();
|
|
1033
|
+
for (const l of layerIndices) {
|
|
1034
|
+
const ns = layers.get(l);
|
|
1035
|
+
const bandLen = layerCrossExtent.get(l);
|
|
1036
|
+
let cursor = crossCentre - bandLen / 2;
|
|
1037
|
+
const flowPos = layerFlowCentre.get(l);
|
|
1038
|
+
for (const n of ns) {
|
|
1039
|
+
const s = sizes.get(n.id);
|
|
1040
|
+
const crossCentrePos = cursor + crossExtent(s) / 2;
|
|
1041
|
+
cursor += crossExtent(s) + CROSS_GAP;
|
|
1042
|
+
const x = flowVertical ? crossCentrePos : flowPos;
|
|
1043
|
+
const y = flowVertical ? flowPos : crossCentrePos;
|
|
1044
|
+
placed.set(n.id, {
|
|
1045
|
+
node: n,
|
|
1046
|
+
x,
|
|
1047
|
+
y,
|
|
1048
|
+
width: s.w,
|
|
1049
|
+
height: s.h,
|
|
1050
|
+
layer: l
|
|
1051
|
+
});
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
const width = Math.ceil(flowVertical ? crossTotal : flowTotal);
|
|
1055
|
+
const height = Math.ceil(flowVertical ? flowTotal : crossTotal);
|
|
1056
|
+
const arcs = [];
|
|
1057
|
+
for (const a of ast.arcs) {
|
|
1058
|
+
const from = placed.get(a.from);
|
|
1059
|
+
const to = placed.get(a.to);
|
|
1060
|
+
if (!from || !to) continue;
|
|
1061
|
+
const start = boundaryPoint(from, to.x, to.y);
|
|
1062
|
+
const end = boundaryPoint(to, from.x, from.y);
|
|
1063
|
+
const angle = Math.atan2(end.y - start.y, end.x - start.x) * 180 / Math.PI;
|
|
1064
|
+
const arc = {
|
|
1065
|
+
from: a.from,
|
|
1066
|
+
to: a.to,
|
|
1067
|
+
kind: a.kind,
|
|
1068
|
+
path: `M ${round(start.x)} ${round(start.y)} L ${round(end.x)} ${round(end.y)}`,
|
|
1069
|
+
tip: { x: end.x, y: end.y, angle },
|
|
1070
|
+
labelAt: { x: (start.x + end.x) / 2, y: (start.y + end.y) / 2 }
|
|
1071
|
+
};
|
|
1072
|
+
if (a.label !== void 0) arc.label = a.label;
|
|
1073
|
+
arcs.push(arc);
|
|
1074
|
+
}
|
|
1075
|
+
return {
|
|
1076
|
+
width,
|
|
1077
|
+
height,
|
|
1078
|
+
nodes: Array.from(placed.values()),
|
|
1079
|
+
arcs,
|
|
1080
|
+
title: ast.title,
|
|
1081
|
+
direction: ast.direction
|
|
1082
|
+
};
|
|
1083
|
+
}
|
|
1084
|
+
function boundaryPoint(n, tx, ty) {
|
|
1085
|
+
const dx = tx - n.x;
|
|
1086
|
+
const dy = ty - n.y;
|
|
1087
|
+
if (dx === 0 && dy === 0) return { x: n.x, y: n.y };
|
|
1088
|
+
const hw = n.width / 2;
|
|
1089
|
+
const hh = n.height / 2;
|
|
1090
|
+
if (n.node.kind === "chance") {
|
|
1091
|
+
const denom = Math.sqrt(dx * dx / (hw * hw) + dy * dy / (hh * hh));
|
|
1092
|
+
return { x: n.x + dx / denom, y: n.y + dy / denom };
|
|
1093
|
+
}
|
|
1094
|
+
const scaleX = dx !== 0 ? hw / Math.abs(dx) : Infinity;
|
|
1095
|
+
const scaleY = dy !== 0 ? hh / Math.abs(dy) : Infinity;
|
|
1096
|
+
const scale = Math.min(scaleX, scaleY);
|
|
1097
|
+
return { x: n.x + dx * scale, y: n.y + dy * scale };
|
|
1098
|
+
}
|
|
1099
|
+
function round(n) {
|
|
1100
|
+
return Math.round(n * 100) / 100;
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
// src/diagrams/decisiontree/influence-renderer.ts
|
|
1104
|
+
function buildCss(t) {
|
|
1105
|
+
return `
|
|
1106
|
+
.lt-dtree { font-family: system-ui, -apple-system, sans-serif; }
|
|
1107
|
+
.lt-dtree-title { font: 500 16px sans-serif; fill: ${t.text}; }
|
|
1108
|
+
.lt-dtree-decision { fill: #dbeafe; stroke: #1d4ed8; stroke-width: 1.6; }
|
|
1109
|
+
.lt-dtree-chance { fill: #fef3c7; stroke: #b45309; stroke-width: 1.6; }
|
|
1110
|
+
.lt-dtree-value { fill: #dcfce7; stroke: #15803d; stroke-width: 1.6; }
|
|
1111
|
+
.lt-dtree-node-label { font: 500 12px sans-serif; fill: ${t.text}; text-anchor: middle; dominant-baseline: middle; }
|
|
1112
|
+
.lt-dtree-value-util { font: 600 10px "SF Mono", monospace; fill: ${t.textMuted}; text-anchor: middle; }
|
|
1113
|
+
.lt-dtree-arc { fill: none; stroke: ${t.stroke}; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
|
|
1114
|
+
.lt-dtree-arc-information { fill: none; stroke: ${t.stroke}; stroke-width: 1.6; stroke-dasharray: 5 4; stroke-linecap: round; }
|
|
1115
|
+
.lt-dtree-arc-head { fill: ${t.stroke}; stroke: none; }
|
|
1116
|
+
.lt-dtree-arc-label { font: 500 10px sans-serif; fill: ${t.textMuted}; text-anchor: middle; dominant-baseline: middle; }
|
|
1117
|
+
.lt-dtree-arc-label-bg { fill: ${t.bg}; stroke: none; }
|
|
1118
|
+
`.trim();
|
|
1119
|
+
}
|
|
1120
|
+
function renderNode(ln) {
|
|
1121
|
+
const n = ln.node;
|
|
1122
|
+
const parts = [];
|
|
1123
|
+
const hw = ln.width / 2;
|
|
1124
|
+
const hh = ln.height / 2;
|
|
1125
|
+
if (n.kind === "decision") {
|
|
1126
|
+
parts.push(rect({
|
|
1127
|
+
x: ln.x - hw,
|
|
1128
|
+
y: ln.y - hh,
|
|
1129
|
+
width: ln.width,
|
|
1130
|
+
height: ln.height,
|
|
1131
|
+
rx: 3,
|
|
1132
|
+
ry: 3,
|
|
1133
|
+
class: "lt-dtree-decision"
|
|
1134
|
+
}));
|
|
1135
|
+
} else if (n.kind === "chance") {
|
|
1136
|
+
parts.push(el("ellipse", {
|
|
1137
|
+
cx: ln.x,
|
|
1138
|
+
cy: ln.y,
|
|
1139
|
+
rx: hw,
|
|
1140
|
+
ry: hh,
|
|
1141
|
+
class: "lt-dtree-chance"
|
|
1142
|
+
}));
|
|
1143
|
+
} else {
|
|
1144
|
+
const ix = Math.min(14, ln.width * 0.2);
|
|
1145
|
+
const iy = Math.min(10, hh * 0.55);
|
|
1146
|
+
const pts = [
|
|
1147
|
+
`${ln.x - hw + ix},${ln.y - hh}`,
|
|
1148
|
+
`${ln.x + hw - ix},${ln.y - hh}`,
|
|
1149
|
+
`${ln.x + hw},${ln.y - hh + iy}`,
|
|
1150
|
+
`${ln.x + hw},${ln.y + hh - iy}`,
|
|
1151
|
+
`${ln.x + hw - ix},${ln.y + hh}`,
|
|
1152
|
+
`${ln.x - hw + ix},${ln.y + hh}`,
|
|
1153
|
+
`${ln.x - hw},${ln.y + hh - iy}`,
|
|
1154
|
+
`${ln.x - hw},${ln.y - hh + iy}`
|
|
1155
|
+
].join(" ");
|
|
1156
|
+
parts.push(polygon({ points: pts, class: "lt-dtree-value" }));
|
|
1157
|
+
}
|
|
1158
|
+
const hasUtil = n.kind === "value" && n.utility !== void 0;
|
|
1159
|
+
const labelY = hasUtil ? ln.y - 6 : ln.y;
|
|
1160
|
+
parts.push(text({ x: ln.x, y: labelY, class: "lt-dtree-node-label" }, n.label));
|
|
1161
|
+
if (hasUtil) {
|
|
1162
|
+
parts.push(text({ x: ln.x, y: ln.y + 11, class: "lt-dtree-value-util" }, `U=${formatNum(n.utility)}`));
|
|
1163
|
+
}
|
|
1164
|
+
return group({
|
|
1165
|
+
"data-node-id": n.id,
|
|
1166
|
+
"data-node-kind": n.kind,
|
|
1167
|
+
"data-layer": String(ln.layer)
|
|
1168
|
+
}, parts);
|
|
1169
|
+
}
|
|
1170
|
+
function arrowHead(arc) {
|
|
1171
|
+
const size = 9;
|
|
1172
|
+
const rad = arc.tip.angle * Math.PI / 180;
|
|
1173
|
+
const tx = arc.tip.x;
|
|
1174
|
+
const ty = arc.tip.y;
|
|
1175
|
+
const spread = 25 * Math.PI / 180;
|
|
1176
|
+
const bx1 = tx - size * Math.cos(rad - spread);
|
|
1177
|
+
const by1 = ty - size * Math.sin(rad - spread);
|
|
1178
|
+
const bx2 = tx - size * Math.cos(rad + spread);
|
|
1179
|
+
const by2 = ty - size * Math.sin(rad + spread);
|
|
1180
|
+
const pts = `${round2(tx)},${round2(ty)} ${round2(bx1)},${round2(by1)} ${round2(bx2)},${round2(by2)}`;
|
|
1181
|
+
return polygon({ points: pts, class: "lt-dtree-arc-head" });
|
|
1182
|
+
}
|
|
1183
|
+
function renderArc(arc) {
|
|
1184
|
+
const parts = [];
|
|
1185
|
+
const cls = arc.kind === "information" ? "lt-dtree-arc-information" : "lt-dtree-arc";
|
|
1186
|
+
parts.push(path({ d: arc.path, class: cls, "data-arc": `${arc.from}->${arc.to}`, "data-arc-kind": arc.kind }));
|
|
1187
|
+
parts.push(arrowHead(arc));
|
|
1188
|
+
if (arc.label && arc.labelAt) {
|
|
1189
|
+
const w = Math.max(arc.label.length * 5.6 + 8, 16);
|
|
1190
|
+
parts.push(rect({
|
|
1191
|
+
x: arc.labelAt.x - w / 2,
|
|
1192
|
+
y: arc.labelAt.y - 7,
|
|
1193
|
+
width: w,
|
|
1194
|
+
height: 14,
|
|
1195
|
+
rx: 3,
|
|
1196
|
+
ry: 3,
|
|
1197
|
+
class: "lt-dtree-arc-label-bg"
|
|
1198
|
+
}));
|
|
1199
|
+
parts.push(text({ x: arc.labelAt.x, y: arc.labelAt.y, class: "lt-dtree-arc-label" }, arc.label));
|
|
1200
|
+
}
|
|
1201
|
+
return group({}, parts);
|
|
1202
|
+
}
|
|
1203
|
+
function formatNum(n) {
|
|
1204
|
+
if (Math.abs(n) >= 1e4) return n.toLocaleString(void 0, { maximumFractionDigits: 0 });
|
|
1205
|
+
if (Number.isInteger(n)) return String(n);
|
|
1206
|
+
return n.toFixed(2);
|
|
1207
|
+
}
|
|
1208
|
+
function round2(n) {
|
|
1209
|
+
return Math.round(n * 100) / 100;
|
|
1210
|
+
}
|
|
1211
|
+
function renderInfluence(ast, config) {
|
|
1212
|
+
const t = resolveBaseTheme(config?.theme ?? "default");
|
|
1213
|
+
const layout = layoutInfluence(ast);
|
|
1214
|
+
const titleOffset = ast.title ? 36 : 10;
|
|
1215
|
+
const width = Math.ceil(layout.width);
|
|
1216
|
+
const height = Math.ceil(layout.height + titleOffset);
|
|
1217
|
+
const children = [];
|
|
1218
|
+
children.push(title(ast.title ?? "Influence Diagram"));
|
|
1219
|
+
children.push(desc(
|
|
1220
|
+
`Influence diagram with ${layout.nodes.length} nodes and ${layout.arcs.length} arcs`
|
|
1221
|
+
));
|
|
1222
|
+
children.push(el("style", {}, buildCss(t)));
|
|
1223
|
+
if (ast.title) {
|
|
1224
|
+
children.push(text({ x: 20, y: 24, class: "lt-dtree-title" }, ast.title));
|
|
1225
|
+
}
|
|
1226
|
+
const inner = [];
|
|
1227
|
+
for (const arc of layout.arcs) inner.push(renderArc(arc));
|
|
1228
|
+
for (const ln of layout.nodes) inner.push(renderNode(ln));
|
|
1229
|
+
children.push(group({ transform: `translate(0, ${titleOffset})`, "data-mode": "influence" }, inner));
|
|
1230
|
+
return svgRoot({
|
|
1231
|
+
class: "lt-dtree",
|
|
1232
|
+
role: "img",
|
|
1233
|
+
"aria-label": escapeXml(ast.title ?? "Influence diagram"),
|
|
1234
|
+
width,
|
|
1235
|
+
height,
|
|
1236
|
+
viewBox: `0 0 ${width} ${height}`
|
|
1237
|
+
}, children);
|
|
1238
|
+
}
|
|
1239
|
+
|
|
744
1240
|
// src/diagrams/decisiontree/renderer.ts
|
|
745
1241
|
var CLASS_PALETTE = [
|
|
746
1242
|
"#0ea5e9",
|
|
@@ -754,7 +1250,7 @@ var CLASS_PALETTE = [
|
|
|
754
1250
|
"#06b6d4",
|
|
755
1251
|
"#f97316"
|
|
756
1252
|
];
|
|
757
|
-
function
|
|
1253
|
+
function buildCss2(t) {
|
|
758
1254
|
return `
|
|
759
1255
|
.lt-dtree { font-family: system-ui, -apple-system, sans-serif; }
|
|
760
1256
|
.lt-dtree-title { font: 500 16px sans-serif; fill: ${t.text}; }
|
|
@@ -819,7 +1315,7 @@ function renderDecisionNode(ln, layout) {
|
|
|
819
1315
|
y: ln.y + ln.height / 2 + 13,
|
|
820
1316
|
class: "lt-dtree-ev",
|
|
821
1317
|
"text-anchor": "middle"
|
|
822
|
-
}, `EV=${
|
|
1318
|
+
}, `EV=${formatNum2(n.ev)}`));
|
|
823
1319
|
}
|
|
824
1320
|
} else if (n.kind === "chance") {
|
|
825
1321
|
parts.push(circle({
|
|
@@ -851,7 +1347,7 @@ function renderDecisionNode(ln, layout) {
|
|
|
851
1347
|
y: ln.y + ln.height / 2 + 13,
|
|
852
1348
|
class: n.optimal ? "lt-dtree-ev-optimal" : "lt-dtree-ev",
|
|
853
1349
|
"text-anchor": "middle"
|
|
854
|
-
}, `EV=${
|
|
1350
|
+
}, `EV=${formatNum2(n.ev)}`));
|
|
855
1351
|
}
|
|
856
1352
|
} else if (n.kind === "end") {
|
|
857
1353
|
const halfW = ln.width / 2;
|
|
@@ -907,7 +1403,7 @@ function renderDecisionNode(ln, layout) {
|
|
|
907
1403
|
"data-ev": n.ev !== void 0 ? String(n.ev) : ""
|
|
908
1404
|
}, parts);
|
|
909
1405
|
}
|
|
910
|
-
function
|
|
1406
|
+
function formatNum2(n) {
|
|
911
1407
|
if (Math.abs(n) >= 1e4) return n.toLocaleString(void 0, { maximumFractionDigits: 0 });
|
|
912
1408
|
if (Number.isInteger(n)) return String(n);
|
|
913
1409
|
return n.toFixed(2);
|
|
@@ -958,7 +1454,7 @@ function renderMlNode(ln, ast) {
|
|
|
958
1454
|
let textY = y + 16;
|
|
959
1455
|
const lineH = 14;
|
|
960
1456
|
if (n.kind === "split" && n.feature) {
|
|
961
|
-
const thresh = typeof n.threshold === "number" ?
|
|
1457
|
+
const thresh = typeof n.threshold === "number" ? formatNum2(n.threshold) : n.threshold ?? "";
|
|
962
1458
|
parts.push(text(
|
|
963
1459
|
{ x: textX, y: textY, class: "lt-dtree-ml-line-1", "text-anchor": "middle" },
|
|
964
1460
|
`${n.feature} ${n.op ?? ""} ${thresh}`
|
|
@@ -972,7 +1468,7 @@ function renderMlNode(ln, ast) {
|
|
|
972
1468
|
const impName = ast.impurityName ?? "gini";
|
|
973
1469
|
parts.push(text(
|
|
974
1470
|
{ x: textX, y: textY, class: "lt-dtree-ml-line-muted", "text-anchor": "middle" },
|
|
975
|
-
`${impName} = ${
|
|
1471
|
+
`${impName} = ${formatNum2(n.impurity)}`
|
|
976
1472
|
));
|
|
977
1473
|
textY += lineH;
|
|
978
1474
|
}
|
|
@@ -984,7 +1480,7 @@ function renderMlNode(ln, ast) {
|
|
|
984
1480
|
textY += lineH;
|
|
985
1481
|
}
|
|
986
1482
|
if (n.value !== void 0) {
|
|
987
|
-
const vStr = Array.isArray(n.value) ? `value = [${n.value.join(", ")}]` : `value = ${
|
|
1483
|
+
const vStr = Array.isArray(n.value) ? `value = [${n.value.join(", ")}]` : `value = ${formatNum2(n.value)}`;
|
|
988
1484
|
parts.push(text({ x: textX, y: textY, class: "lt-dtree-ml-mono", "text-anchor": "middle" }, vStr));
|
|
989
1485
|
textY += lineH;
|
|
990
1486
|
}
|
|
@@ -1002,7 +1498,7 @@ function renderMlNode(ln, ast) {
|
|
|
1002
1498
|
} else if (typeof n.value === "number") {
|
|
1003
1499
|
parts.push(text(
|
|
1004
1500
|
{ x: textX, y: textY, class: "lt-dtree-ml-class", "text-anchor": "middle", fill: "#0f172a" },
|
|
1005
|
-
`predicted = ${
|
|
1501
|
+
`predicted = ${formatNum2(n.value)}`
|
|
1006
1502
|
));
|
|
1007
1503
|
textY += lineH;
|
|
1008
1504
|
}
|
|
@@ -1078,6 +1574,7 @@ function wrapText(text2, maxChars) {
|
|
|
1078
1574
|
return lines.slice(0, 2);
|
|
1079
1575
|
}
|
|
1080
1576
|
function renderDecisionTree(ast, config) {
|
|
1577
|
+
if ("arcs" in ast) return renderInfluence(ast, config);
|
|
1081
1578
|
const t = resolveBaseTheme(config?.theme ?? "default");
|
|
1082
1579
|
const layout = layoutDecisionTree(ast);
|
|
1083
1580
|
const titleOffset = ast.title ? 36 : 10;
|
|
@@ -1086,7 +1583,7 @@ function renderDecisionTree(ast, config) {
|
|
|
1086
1583
|
const children = [];
|
|
1087
1584
|
children.push(title(ast.title ?? "Decision Tree"));
|
|
1088
1585
|
children.push(desc(`Decision tree (${ast.mode} mode) with ${layout.nodes.length} nodes and ${layout.edges.length} edges`));
|
|
1089
|
-
children.push(el("style", {},
|
|
1586
|
+
children.push(el("style", {}, buildCss2(t)));
|
|
1090
1587
|
if (ast.title) {
|
|
1091
1588
|
children.push(text({ x: 20, y: 24, class: "lt-dtree-title" }, ast.title));
|
|
1092
1589
|
}
|
|
@@ -1249,7 +1746,7 @@ var TimelineParseError = class extends Error {
|
|
|
1249
1746
|
column;
|
|
1250
1747
|
source;
|
|
1251
1748
|
};
|
|
1252
|
-
function
|
|
1749
|
+
function preprocess3(src) {
|
|
1253
1750
|
const out = [];
|
|
1254
1751
|
const lines = src.split(/\r?\n/);
|
|
1255
1752
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -1363,7 +1860,7 @@ function splitDateAndBody(s, lineNum) {
|
|
|
1363
1860
|
return { date: datePart, body };
|
|
1364
1861
|
}
|
|
1365
1862
|
function parseTimeline(src) {
|
|
1366
|
-
const lines =
|
|
1863
|
+
const lines = preprocess3(src);
|
|
1367
1864
|
if (!lines.length) throw new TimelineParseError("Empty timeline");
|
|
1368
1865
|
const ast = {
|
|
1369
1866
|
type: "timeline",
|
|
@@ -2702,7 +3199,7 @@ var MERMAID_STEREOTYPE = {
|
|
|
2702
3199
|
join: "join",
|
|
2703
3200
|
end: "final"
|
|
2704
3201
|
};
|
|
2705
|
-
function
|
|
3202
|
+
function preprocess4(src) {
|
|
2706
3203
|
const out = [];
|
|
2707
3204
|
const lines = src.split(/\r?\n/);
|
|
2708
3205
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -2716,7 +3213,7 @@ function preprocess3(src) {
|
|
|
2716
3213
|
}
|
|
2717
3214
|
return out;
|
|
2718
3215
|
}
|
|
2719
|
-
function
|
|
3216
|
+
function unquote3(s) {
|
|
2720
3217
|
if (s.length >= 2 && s.startsWith('"') && s.endsWith('"')) {
|
|
2721
3218
|
return s.slice(1, -1);
|
|
2722
3219
|
}
|
|
@@ -2729,7 +3226,7 @@ function parseProps(s) {
|
|
|
2729
3226
|
for (const part of inner.split(",")) {
|
|
2730
3227
|
const idx = part.indexOf(":");
|
|
2731
3228
|
if (idx < 0) continue;
|
|
2732
|
-
out[part.slice(0, idx).trim()] =
|
|
3229
|
+
out[part.slice(0, idx).trim()] = unquote3(part.slice(idx + 1).trim());
|
|
2733
3230
|
}
|
|
2734
3231
|
return out;
|
|
2735
3232
|
}
|
|
@@ -2870,7 +3367,7 @@ function isIdent(tok) {
|
|
|
2870
3367
|
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(tok);
|
|
2871
3368
|
}
|
|
2872
3369
|
function parseStateDiagram(src) {
|
|
2873
|
-
const lines =
|
|
3370
|
+
const lines = preprocess4(src);
|
|
2874
3371
|
if (lines.length === 0) {
|
|
2875
3372
|
throw new StateParseError("Empty document");
|
|
2876
3373
|
}
|
|
@@ -2892,7 +3389,7 @@ function parseStateDiagram(src) {
|
|
|
2892
3389
|
if (props.direction === "TB" || props.direction === "LR") direction = props.direction;
|
|
2893
3390
|
beforeProps = headerRest.slice(0, propsMatch.index).trim();
|
|
2894
3391
|
}
|
|
2895
|
-
if (beforeProps.startsWith('"')) title2 =
|
|
3392
|
+
if (beforeProps.startsWith('"')) title2 = unquote3(beforeProps);
|
|
2896
3393
|
else if (beforeProps.length > 0) title2 = beforeProps;
|
|
2897
3394
|
const ctx = {
|
|
2898
3395
|
states: [],
|
|
@@ -2979,7 +3476,7 @@ function parseStateDiagram(src) {
|
|
|
2979
3476
|
const stateLabelMatch = text2.match(/^state\s+([A-Za-z_][A-Za-z0-9_]*)\s*:\s*(.+)$/);
|
|
2980
3477
|
if (stateLabelMatch) {
|
|
2981
3478
|
const node = ensureSimpleState(ctx, stateLabelMatch[1], parent);
|
|
2982
|
-
node.label =
|
|
3479
|
+
node.label = unquote3(stateLabelMatch[2].trim());
|
|
2983
3480
|
i++;
|
|
2984
3481
|
continue;
|
|
2985
3482
|
}
|
|
@@ -3114,7 +3611,7 @@ function parseStateDiagram(src) {
|
|
|
3114
3611
|
const labelOnlyMatch = text2.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*:\s*(.+)$/);
|
|
3115
3612
|
if (labelOnlyMatch && isIdent(labelOnlyMatch[1])) {
|
|
3116
3613
|
const node = ensureSimpleState(ctx, labelOnlyMatch[1], parent);
|
|
3117
|
-
node.label =
|
|
3614
|
+
node.label = unquote3(labelOnlyMatch[2].trim());
|
|
3118
3615
|
i++;
|
|
3119
3616
|
continue;
|
|
3120
3617
|
}
|
|
@@ -3842,7 +4339,7 @@ function renderPseudo(node) {
|
|
|
3842
4339
|
return "";
|
|
3843
4340
|
}
|
|
3844
4341
|
}
|
|
3845
|
-
function
|
|
4342
|
+
function renderNode2(node) {
|
|
3846
4343
|
if (node.node.kind === "pseudo") return renderPseudo(node);
|
|
3847
4344
|
return renderSimple(node);
|
|
3848
4345
|
}
|
|
@@ -3924,7 +4421,7 @@ function renderLayout(layout) {
|
|
|
3924
4421
|
titleNode,
|
|
3925
4422
|
// Composite clusters first so simple-state bodies sit on top.
|
|
3926
4423
|
group({ class: "lt-clusters" }, layout.clusters.map(renderComposite)),
|
|
3927
|
-
group({ class: "lt-state-bodies" }, layout.nodes.map(
|
|
4424
|
+
group({ class: "lt-state-bodies" }, layout.nodes.map(renderNode2)),
|
|
3928
4425
|
group({ class: "lt-edges" }, layout.edges.map(renderEdge)),
|
|
3929
4426
|
group({ class: "lt-notes" }, layout.notes.map(renderNote))
|
|
3930
4427
|
]
|
|
@@ -4005,7 +4502,7 @@ var INST_CATEGORIES = /* @__PURE__ */ new Set([
|
|
|
4005
4502
|
"local_discrete",
|
|
4006
4503
|
"local_shared"
|
|
4007
4504
|
]);
|
|
4008
|
-
function
|
|
4505
|
+
function preprocess5(src) {
|
|
4009
4506
|
const out = [];
|
|
4010
4507
|
const lines = src.split(/\r?\n/);
|
|
4011
4508
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -4025,7 +4522,7 @@ function preprocess4(src) {
|
|
|
4025
4522
|
}
|
|
4026
4523
|
return out;
|
|
4027
4524
|
}
|
|
4028
|
-
function
|
|
4525
|
+
function unquote4(s) {
|
|
4029
4526
|
const t = s.trim();
|
|
4030
4527
|
if (t.length >= 2 && t.startsWith('"') && t.endsWith('"')) {
|
|
4031
4528
|
return t.slice(1, -1).replace(/\\"/g, '"');
|
|
@@ -4054,7 +4551,7 @@ function parseAttrList(inside) {
|
|
|
4054
4551
|
const idx = p.indexOf(":");
|
|
4055
4552
|
if (idx < 0) continue;
|
|
4056
4553
|
const key = p.slice(0, idx).trim();
|
|
4057
|
-
const val =
|
|
4554
|
+
const val = unquote4(p.slice(idx + 1).trim());
|
|
4058
4555
|
out[key] = val;
|
|
4059
4556
|
}
|
|
4060
4557
|
return out;
|
|
@@ -4089,7 +4586,7 @@ function parseAnchor(tok) {
|
|
|
4089
4586
|
return { id: tok.slice(0, dot), port: tok.slice(dot + 1) };
|
|
4090
4587
|
}
|
|
4091
4588
|
function parsePid(src) {
|
|
4092
|
-
const lines =
|
|
4589
|
+
const lines = preprocess5(src);
|
|
4093
4590
|
if (lines.length === 0) {
|
|
4094
4591
|
throw new PidParseError("Empty document");
|
|
4095
4592
|
}
|
|
@@ -4103,7 +4600,7 @@ function parsePid(src) {
|
|
|
4103
4600
|
const { rest, attrs: headerAttrs } = extractAttrs(headerRest);
|
|
4104
4601
|
if (headerAttrs.direction === "TB") direction = "TB";
|
|
4105
4602
|
if (headerAttrs.direction === "LR") direction = "LR";
|
|
4106
|
-
if (rest) title2 =
|
|
4603
|
+
if (rest) title2 = unquote4(rest);
|
|
4107
4604
|
const equipment = [];
|
|
4108
4605
|
const linesAst = [];
|
|
4109
4606
|
const instruments = [];
|
|
@@ -5076,7 +5573,7 @@ function renderInstrument(category, letterCode, loopNumber) {
|
|
|
5076
5573
|
}
|
|
5077
5574
|
|
|
5078
5575
|
// src/diagrams/pid/layout.ts
|
|
5079
|
-
var
|
|
5576
|
+
var PADDING2 = 30;
|
|
5080
5577
|
var TITLE_AREA = 26;
|
|
5081
5578
|
var EQUIP_GAP_X = 70;
|
|
5082
5579
|
var INST_RADIUS = 14;
|
|
@@ -5143,8 +5640,8 @@ function layoutPid(ast) {
|
|
|
5143
5640
|
const equipById = /* @__PURE__ */ new Map();
|
|
5144
5641
|
const heights = ast.equipment.map((e) => GEOMETRY[e.equipType]?.height ?? 60);
|
|
5145
5642
|
const maxH = Math.max(...heights, 0);
|
|
5146
|
-
const rowY =
|
|
5147
|
-
let cursorX =
|
|
5643
|
+
const rowY = PADDING2 + TITLE_AREA + maxH / 2 + 30;
|
|
5644
|
+
let cursorX = PADDING2 + 40;
|
|
5148
5645
|
for (const equip of ast.equipment) {
|
|
5149
5646
|
const geo = GEOMETRY[equip.equipType] ?? { width: 60, height: 40, ports: {} };
|
|
5150
5647
|
const cx = cursorX + geo.width / 2;
|
|
@@ -5169,29 +5666,42 @@ function layoutPid(ast) {
|
|
|
5169
5666
|
equipById.set(equip.id, layoutEq);
|
|
5170
5667
|
cursorX += geo.width + EQUIP_GAP_X;
|
|
5171
5668
|
}
|
|
5669
|
+
const lineMidById = /* @__PURE__ */ new Map();
|
|
5670
|
+
for (const ln of ast.lines) {
|
|
5671
|
+
const from = equipById.get(ln.from.id);
|
|
5672
|
+
const to = equipById.get(ln.to.id);
|
|
5673
|
+
if (!from || !to) continue;
|
|
5674
|
+
const fa = getAnchor(from, ln.from.port, "out");
|
|
5675
|
+
const ta = getAnchor(to, ln.to.port, "in");
|
|
5676
|
+
lineMidById.set(ln.id, { x: (fa.x + ta.x) / 2, y: (fa.y + ta.y) / 2 });
|
|
5677
|
+
}
|
|
5678
|
+
const targetX = (tgt, fallback) => {
|
|
5679
|
+
const eq = equipById.get(tgt);
|
|
5680
|
+
if (eq) return eq.cx;
|
|
5681
|
+
const lm = lineMidById.get(tgt);
|
|
5682
|
+
if (lm) return lm.x;
|
|
5683
|
+
return fallback;
|
|
5684
|
+
};
|
|
5172
5685
|
const instruments = [];
|
|
5173
5686
|
const instById = /* @__PURE__ */ new Map();
|
|
5174
|
-
const crBandY =
|
|
5687
|
+
const crBandY = PADDING2 + TITLE_AREA + 40;
|
|
5175
5688
|
let crSlot = 0;
|
|
5176
5689
|
for (const inst of ast.instruments) {
|
|
5177
5690
|
let cx = 0;
|
|
5178
5691
|
let cy = 0;
|
|
5179
5692
|
if (inst.category.startsWith("cr_")) {
|
|
5180
5693
|
const tgt = inst.controls ?? inst.measures ?? "";
|
|
5181
|
-
|
|
5182
|
-
cx = tgtEq ? tgtEq.cx : PADDING + 80 + crSlot * (INST_RADIUS * 2 + 28);
|
|
5694
|
+
cx = targetX(tgt, PADDING2 + 80 + crSlot * (INST_RADIUS * 2 + 28));
|
|
5183
5695
|
cy = crBandY;
|
|
5184
5696
|
crSlot += 1;
|
|
5185
5697
|
} else if (inst.category.startsWith("local_")) {
|
|
5186
5698
|
cy = rowY + maxH / 2 + INST_OFFSET + INST_RADIUS;
|
|
5187
5699
|
const tgt = inst.measures ?? inst.controls ?? "";
|
|
5188
|
-
|
|
5189
|
-
cx = tgtEq ? tgtEq.cx : PADDING + 80;
|
|
5700
|
+
cx = targetX(tgt, PADDING2 + 80);
|
|
5190
5701
|
} else {
|
|
5191
5702
|
cy = rowY + maxH / 2 + INST_OFFSET;
|
|
5192
5703
|
const tgt = inst.measures ?? inst.controls ?? "";
|
|
5193
|
-
|
|
5194
|
-
cx = tgtEq ? tgtEq.cx : PADDING + 80;
|
|
5704
|
+
cx = targetX(tgt, PADDING2 + 80);
|
|
5195
5705
|
}
|
|
5196
5706
|
const lay = {
|
|
5197
5707
|
inst,
|
|
@@ -5202,13 +5712,14 @@ function layoutPid(ast) {
|
|
|
5202
5712
|
instruments.push(lay);
|
|
5203
5713
|
instById.set(inst.tag, lay);
|
|
5204
5714
|
}
|
|
5205
|
-
const
|
|
5715
|
+
const INST_FANOUT = INST_RADIUS * 2 + 12;
|
|
5716
|
+
const sameYRow = (a, b) => Math.abs(a.cy - b.cy) < INST_RADIUS;
|
|
5206
5717
|
const sortedByX = [...instruments].sort((a, b) => a.cx - b.cx);
|
|
5207
5718
|
for (let i = 1; i < sortedByX.length; i++) {
|
|
5208
5719
|
const prev = sortedByX[i - 1];
|
|
5209
5720
|
const cur = sortedByX[i];
|
|
5210
|
-
if (
|
|
5211
|
-
cur.cx = prev.cx +
|
|
5721
|
+
if (sameYRow(prev, cur) && cur.cx < prev.cx + INST_FANOUT) {
|
|
5722
|
+
cur.cx = prev.cx + INST_FANOUT;
|
|
5212
5723
|
}
|
|
5213
5724
|
}
|
|
5214
5725
|
const lines = [];
|
|
@@ -5234,8 +5745,8 @@ function layoutPid(ast) {
|
|
|
5234
5745
|
const maxX = Math.max(...allX);
|
|
5235
5746
|
const maxY = Math.max(...allY);
|
|
5236
5747
|
return {
|
|
5237
|
-
width: Math.max(maxX +
|
|
5238
|
-
height: Math.max(maxY +
|
|
5748
|
+
width: Math.max(maxX + PADDING2, 400),
|
|
5749
|
+
height: Math.max(maxY + PADDING2, 200),
|
|
5239
5750
|
equipment,
|
|
5240
5751
|
instruments,
|
|
5241
5752
|
lines,
|
|
@@ -5298,6 +5809,7 @@ var STYLE2 = `
|
|
|
5298
5809
|
.lt-inst-local-line { stroke: #1d1d1d; stroke-width: 1; stroke-dasharray: 2 2; }
|
|
5299
5810
|
.lt-pid-valve-body { fill: #ffffff; stroke: #1d1d1d; stroke-width: 1.4; }
|
|
5300
5811
|
|
|
5812
|
+
.lt-pid-line-path { fill: none; }
|
|
5301
5813
|
.lt-pid-line-tag-bg { fill: #ffffff; stroke: #1d1d1d; stroke-width: 0.6; }
|
|
5302
5814
|
.lt-pid-line-tag-text { font: 9px ui-monospace, monospace; fill: #1d1d1d; }
|
|
5303
5815
|
|
|
@@ -5308,15 +5820,37 @@ var STYLE2 = `
|
|
|
5308
5820
|
.lt-pid-unknown-type { font: 9px ui-monospace, monospace; fill: #6a6a6a; }
|
|
5309
5821
|
`;
|
|
5310
5822
|
var ARROW_ID = "lt-pid-arrow";
|
|
5823
|
+
var LINE_CLASS = {
|
|
5824
|
+
process: "lt-pid-process",
|
|
5825
|
+
process_minor: "lt-pid-process-min",
|
|
5826
|
+
pneumatic: "lt-pid-pneumatic",
|
|
5827
|
+
electric: "lt-pid-electric",
|
|
5828
|
+
hydraulic: "lt-pid-hydraulic",
|
|
5829
|
+
capillary: "lt-pid-capillary",
|
|
5830
|
+
software: "lt-pid-software",
|
|
5831
|
+
mechanical: "lt-pid-mechanical"
|
|
5832
|
+
};
|
|
5833
|
+
var SIGNAL_LINE_TYPES = /* @__PURE__ */ new Set([
|
|
5834
|
+
"pneumatic",
|
|
5835
|
+
"electric",
|
|
5836
|
+
"hydraulic",
|
|
5837
|
+
"capillary",
|
|
5838
|
+
"software",
|
|
5839
|
+
"mechanical"
|
|
5840
|
+
]);
|
|
5311
5841
|
function lineClass(t) {
|
|
5312
|
-
return `lt-pid-${t.replace(
|
|
5842
|
+
return LINE_CLASS[t] ?? `lt-pid-${String(t).replace(/_/g, "-")}`;
|
|
5843
|
+
}
|
|
5844
|
+
function isSignalLine(l) {
|
|
5845
|
+
return SIGNAL_LINE_TYPES.has(l.line.lineType);
|
|
5313
5846
|
}
|
|
5314
5847
|
function renderLine(l) {
|
|
5315
5848
|
const cls = lineClass(l.line.lineType);
|
|
5316
5849
|
const parts = [
|
|
5317
5850
|
path({
|
|
5318
5851
|
d: l.path,
|
|
5319
|
-
class
|
|
5852
|
+
// Type class + a shared no-fill guard class on every line path.
|
|
5853
|
+
class: `${cls} lt-pid-line-path`,
|
|
5320
5854
|
"data-line-id": l.line.id,
|
|
5321
5855
|
"data-service": l.line.service ?? ""
|
|
5322
5856
|
})
|
|
@@ -5483,9 +6017,16 @@ function renderLayout2(layout) {
|
|
|
5483
6017
|
el("style", {}, STYLE2)
|
|
5484
6018
|
]),
|
|
5485
6019
|
titleNode,
|
|
6020
|
+
// Z-order: process pipes behind equipment; signal lines + instruments above.
|
|
6021
|
+
group(
|
|
6022
|
+
{ class: "lt-pid-lines lt-pid-process-lines" },
|
|
6023
|
+
layout.lines.filter((l) => !isSignalLine(l)).map(renderLine)
|
|
6024
|
+
),
|
|
5486
6025
|
group({ class: "lt-pid-equipment" }, equipNodes),
|
|
5487
|
-
group(
|
|
5488
|
-
|
|
6026
|
+
group(
|
|
6027
|
+
{ class: "lt-pid-lines lt-pid-signal-lines" },
|
|
6028
|
+
[...layout.lines.filter(isSignalLine).map(renderLine), ...autoSignals]
|
|
6029
|
+
),
|
|
5489
6030
|
group({ class: "lt-pid-instruments" }, instNodes)
|
|
5490
6031
|
]
|
|
5491
6032
|
);
|
|
@@ -5636,7 +6177,7 @@ var PrismaParseError = class extends Error {
|
|
|
5636
6177
|
}
|
|
5637
6178
|
line;
|
|
5638
6179
|
};
|
|
5639
|
-
function
|
|
6180
|
+
function preprocess6(src) {
|
|
5640
6181
|
const out = [];
|
|
5641
6182
|
const rows = src.split(/\r?\n/);
|
|
5642
6183
|
for (let i = 0; i < rows.length; i++) {
|
|
@@ -5909,7 +6450,7 @@ var STAGE_KEYS = /* @__PURE__ */ new Set([
|
|
|
5909
6450
|
"included"
|
|
5910
6451
|
]);
|
|
5911
6452
|
function parsePrisma(src) {
|
|
5912
|
-
const lines =
|
|
6453
|
+
const lines = preprocess6(src);
|
|
5913
6454
|
if (lines.length === 0) throw new PrismaParseError("empty input");
|
|
5914
6455
|
const header = lines.shift();
|
|
5915
6456
|
if (header.indent !== 0 || header.text.toLowerCase() !== "prisma") {
|
|
@@ -5937,10 +6478,10 @@ function parsePrisma(src) {
|
|
|
5937
6478
|
validateCounts = parseValidate(value, l.line);
|
|
5938
6479
|
break;
|
|
5939
6480
|
case "title":
|
|
5940
|
-
title2 =
|
|
6481
|
+
title2 = unquote5(value);
|
|
5941
6482
|
break;
|
|
5942
6483
|
case "review-id":
|
|
5943
|
-
reviewId =
|
|
6484
|
+
reviewId = unquote5(value);
|
|
5944
6485
|
break;
|
|
5945
6486
|
case "direction":
|
|
5946
6487
|
if (!/^(TB|TD)$/i.test(value.trim())) {
|
|
@@ -6028,7 +6569,7 @@ function parsePrisma(src) {
|
|
|
6028
6569
|
runArithmeticValidation(ast);
|
|
6029
6570
|
return ast;
|
|
6030
6571
|
}
|
|
6031
|
-
function
|
|
6572
|
+
function unquote5(s) {
|
|
6032
6573
|
const t = s.trim();
|
|
6033
6574
|
if (t.startsWith('"') && t.endsWith('"')) return t.slice(1, -1);
|
|
6034
6575
|
return t;
|
|
@@ -6842,7 +7383,7 @@ function headerHeightFor(lineCount) {
|
|
|
6842
7383
|
}
|
|
6843
7384
|
|
|
6844
7385
|
// src/diagrams/prisma/renderer.ts
|
|
6845
|
-
function
|
|
7386
|
+
function buildCss3(t) {
|
|
6846
7387
|
return `
|
|
6847
7388
|
.prisma { font-family: system-ui, -apple-system, sans-serif; }
|
|
6848
7389
|
.prisma-title { font: 600 17px sans-serif; fill: ${t.text}; }
|
|
@@ -7072,7 +7613,7 @@ function renderPrismaLayout(layout, config) {
|
|
|
7072
7613
|
`PRISMA 2020 flow diagram (${layout.mode}, ${layout.kind}) \u2014 ${layout.boxes.length} boxes, ${layout.edges.length} arrows` + (layout.warnings.length > 0 ? `. Warnings: ${layout.warnings.join("; ")}` : "")
|
|
7073
7614
|
)
|
|
7074
7615
|
);
|
|
7075
|
-
children.push(el("style", {},
|
|
7616
|
+
children.push(el("style", {}, buildCss3(t)));
|
|
7076
7617
|
children.push(arrowMarker(t));
|
|
7077
7618
|
if (layout.title) {
|
|
7078
7619
|
children.push(
|
|
@@ -7164,7 +7705,7 @@ var UsecaseParseError = class extends Error {
|
|
|
7164
7705
|
if (line2 !== void 0) this.line = line2;
|
|
7165
7706
|
}
|
|
7166
7707
|
};
|
|
7167
|
-
function
|
|
7708
|
+
function preprocess7(src) {
|
|
7168
7709
|
const out = [];
|
|
7169
7710
|
const rows = src.split(/\r?\n/);
|
|
7170
7711
|
for (let i = 0; i < rows.length; i++) {
|
|
@@ -7647,7 +8188,7 @@ function parseUsecase(src) {
|
|
|
7647
8188
|
const state2 = {
|
|
7648
8189
|
ast,
|
|
7649
8190
|
idTable: /* @__PURE__ */ new Map(),
|
|
7650
|
-
lines:
|
|
8191
|
+
lines: preprocess7(src),
|
|
7651
8192
|
i: 0
|
|
7652
8193
|
};
|
|
7653
8194
|
parseHeader(state2);
|
|
@@ -8095,10 +8636,10 @@ function layoutUsecase(ast) {
|
|
|
8095
8636
|
const maxY2 = Math.max(...ys);
|
|
8096
8637
|
if (useTree) {
|
|
8097
8638
|
const legPaths2 = [
|
|
8098
|
-
`M ${
|
|
8639
|
+
`M ${round3(busX)} ${round3(minY2)} L ${round3(busX)} ${round3(maxY2)}`
|
|
8099
8640
|
];
|
|
8100
8641
|
for (const c of childAnchors) {
|
|
8101
|
-
legPaths2.push(`M ${
|
|
8642
|
+
legPaths2.push(`M ${round3(c.p.x)} ${round3(c.p.y)} L ${round3(busX)} ${round3(c.p.y)}`);
|
|
8102
8643
|
handledGen.add(c.r);
|
|
8103
8644
|
}
|
|
8104
8645
|
trees.push({
|
|
@@ -8107,14 +8648,14 @@ function layoutUsecase(ast) {
|
|
|
8107
8648
|
stemX: busX,
|
|
8108
8649
|
stemTop: minY2,
|
|
8109
8650
|
stemBottom: maxY2,
|
|
8110
|
-
trunkD: `M ${
|
|
8651
|
+
trunkD: `M ${round3(busX)} ${round3(pAnchor.y)} L ${round3(pAnchor.x)} ${round3(pAnchor.y)}`,
|
|
8111
8652
|
legPaths: legPaths2
|
|
8112
8653
|
});
|
|
8113
8654
|
} else {
|
|
8114
8655
|
for (const c of childAnchors) {
|
|
8115
8656
|
edges.push({
|
|
8116
8657
|
relation: c.r,
|
|
8117
|
-
d: `M ${
|
|
8658
|
+
d: `M ${round3(c.p.x)} ${round3(c.p.y)} L ${round3(busX)} ${round3(c.p.y)} L ${round3(busX)} ${round3(pAnchor.y)} L ${round3(pAnchor.x)} ${round3(pAnchor.y)}`,
|
|
8118
8659
|
arrowKind: "hollow",
|
|
8119
8660
|
dashed: false
|
|
8120
8661
|
});
|
|
@@ -8139,7 +8680,7 @@ function layoutUsecase(ast) {
|
|
|
8139
8680
|
const legPaths = [];
|
|
8140
8681
|
for (const r5 of rels) {
|
|
8141
8682
|
const cPt = perimeter(r5.source, jx, jy);
|
|
8142
|
-
legPaths.push(`M ${
|
|
8683
|
+
legPaths.push(`M ${round3(cPt.x)} ${round3(cPt.y)} L ${round3(jx)} ${round3(jy)}`);
|
|
8143
8684
|
handledGen.add(r5);
|
|
8144
8685
|
}
|
|
8145
8686
|
trees.push({
|
|
@@ -8148,7 +8689,7 @@ function layoutUsecase(ast) {
|
|
|
8148
8689
|
stemX: jx,
|
|
8149
8690
|
stemTop: jy,
|
|
8150
8691
|
stemBottom: jy,
|
|
8151
|
-
trunkD: `M ${
|
|
8692
|
+
trunkD: `M ${round3(jx)} ${round3(jy)} L ${round3(pPt.x)} ${round3(pPt.y)}`,
|
|
8152
8693
|
legPaths
|
|
8153
8694
|
});
|
|
8154
8695
|
}
|
|
@@ -8164,7 +8705,7 @@ function layoutUsecase(ast) {
|
|
|
8164
8705
|
const busX = side === "left" ? Math.min(pAnchor.x, cAnchor.x) - 20 : Math.max(pAnchor.x, cAnchor.x) + 20;
|
|
8165
8706
|
edges.push({
|
|
8166
8707
|
relation: r5,
|
|
8167
|
-
d: `M ${
|
|
8708
|
+
d: `M ${round3(cAnchor.x)} ${round3(cAnchor.y)} L ${round3(busX)} ${round3(cAnchor.y)} L ${round3(busX)} ${round3(pAnchor.y)} L ${round3(pAnchor.x)} ${round3(pAnchor.y)}`,
|
|
8168
8709
|
arrowKind: "hollow",
|
|
8169
8710
|
dashed: false
|
|
8170
8711
|
});
|
|
@@ -8190,7 +8731,7 @@ function layoutUsecase(ast) {
|
|
|
8190
8731
|
else if (r5.kind === "generalization") arrowKind2 = "hollow";
|
|
8191
8732
|
const edge = {
|
|
8192
8733
|
relation: r5,
|
|
8193
|
-
d: `M ${
|
|
8734
|
+
d: `M ${round3(pa.x)} ${round3(pa.y)} L ${round3(pb.x)} ${round3(pb.y)}`,
|
|
8194
8735
|
arrowKind: arrowKind2,
|
|
8195
8736
|
dashed
|
|
8196
8737
|
};
|
|
@@ -8259,14 +8800,14 @@ function placeMultiplicity(near, far, text2) {
|
|
|
8259
8800
|
const oy = dy / len * 14;
|
|
8260
8801
|
const px = -dy / len * 9;
|
|
8261
8802
|
const py = dx / len * 9;
|
|
8262
|
-
return { text: text2, x:
|
|
8803
|
+
return { text: text2, x: round3(near.x + ox + px), y: round3(near.y + oy + py) };
|
|
8263
8804
|
}
|
|
8264
|
-
function
|
|
8805
|
+
function round3(n) {
|
|
8265
8806
|
return Math.round(n * 100) / 100;
|
|
8266
8807
|
}
|
|
8267
8808
|
|
|
8268
8809
|
// src/diagrams/usecase/renderer.ts
|
|
8269
|
-
function
|
|
8810
|
+
function buildCss4(t) {
|
|
8270
8811
|
const ucFill = "#eaf2fc";
|
|
8271
8812
|
const ucStroke = "#5b85c0";
|
|
8272
8813
|
const subjectStroke = "#c2cede";
|
|
@@ -8545,7 +9086,7 @@ function renderUsecaseLayout(layout, config) {
|
|
|
8545
9086
|
`${layout.subject ? "Subject: " + layout.subject.name + ". " : ""}${layout.actors.length} actors, ${layout.usecases.length} use cases, ${nInclude} include, ${nExtend} extend.`
|
|
8546
9087
|
)
|
|
8547
9088
|
);
|
|
8548
|
-
children.push(el("style", {},
|
|
9089
|
+
children.push(el("style", {}, buildCss4(t)));
|
|
8549
9090
|
children.push(markers(t));
|
|
8550
9091
|
if (layout.title) {
|
|
8551
9092
|
children.push(
|
|
@@ -8642,7 +9183,7 @@ var UNIT_SUFFIX = {
|
|
|
8642
9183
|
function normalizeQuotes(s) {
|
|
8643
9184
|
return s.replace(/[“”〝〞"]/g, '"').replace(/[‘’]/g, "'").replace(/[「」『』]/g, '"');
|
|
8644
9185
|
}
|
|
8645
|
-
function
|
|
9186
|
+
function preprocess8(src) {
|
|
8646
9187
|
const out = [];
|
|
8647
9188
|
const rows = normalizeQuotes(src).split(/\r?\n/);
|
|
8648
9189
|
for (let i = 0; i < rows.length; i++) {
|
|
@@ -8892,7 +9433,7 @@ function parsePert(src) {
|
|
|
8892
9433
|
tasks: [],
|
|
8893
9434
|
warnings: []
|
|
8894
9435
|
};
|
|
8895
|
-
const lines =
|
|
9436
|
+
const lines = preprocess8(src);
|
|
8896
9437
|
if (lines.length === 0) {
|
|
8897
9438
|
throw new PertParseError("empty document \u2014 expected 'pert' header", 1);
|
|
8898
9439
|
}
|
|
@@ -9092,13 +9633,13 @@ function schedulePert(ast) {
|
|
|
9092
9633
|
const realOrder = order.filter((n) => n !== START && n !== FINISH);
|
|
9093
9634
|
let negativeSlack = false;
|
|
9094
9635
|
for (const id of realOrder) {
|
|
9095
|
-
const slack =
|
|
9636
|
+
const slack = round4(ls.get(id) - es.get(id));
|
|
9096
9637
|
if (slack < -1e-9) negativeSlack = true;
|
|
9097
9638
|
computed.set(id, {
|
|
9098
|
-
es:
|
|
9099
|
-
ef:
|
|
9100
|
-
ls:
|
|
9101
|
-
lf:
|
|
9639
|
+
es: round4(es.get(id)),
|
|
9640
|
+
ef: round4(ef.get(id)),
|
|
9641
|
+
ls: round4(ls.get(id)),
|
|
9642
|
+
lf: round4(lf.get(id)),
|
|
9102
9643
|
slack,
|
|
9103
9644
|
critical: slack <= tol + 1e-9
|
|
9104
9645
|
});
|
|
@@ -9113,8 +9654,8 @@ function schedulePert(ast) {
|
|
|
9113
9654
|
for (const t of ast.tasks) {
|
|
9114
9655
|
if (t.variance !== void 0 && computed.get(t.id).critical) sum += t.variance;
|
|
9115
9656
|
}
|
|
9116
|
-
projectVariance =
|
|
9117
|
-
projectStdDev =
|
|
9657
|
+
projectVariance = round4(sum);
|
|
9658
|
+
projectStdDev = round4(Math.sqrt(sum));
|
|
9118
9659
|
}
|
|
9119
9660
|
const depCount = ast.tasks.reduce((n, t) => n + t.deps.length, 0);
|
|
9120
9661
|
if (negativeSlack) {
|
|
@@ -9125,7 +9666,7 @@ function schedulePert(ast) {
|
|
|
9125
9666
|
const result = {
|
|
9126
9667
|
computed,
|
|
9127
9668
|
order: realOrder,
|
|
9128
|
-
projectDuration:
|
|
9669
|
+
projectDuration: round4(projectDuration),
|
|
9129
9670
|
criticalPath,
|
|
9130
9671
|
criticalCount,
|
|
9131
9672
|
depCount
|
|
@@ -9167,7 +9708,7 @@ function extractCriticalPath(ast, g, computed) {
|
|
|
9167
9708
|
}
|
|
9168
9709
|
return path2;
|
|
9169
9710
|
}
|
|
9170
|
-
function
|
|
9711
|
+
function round4(n) {
|
|
9171
9712
|
return Math.round(n * 1e4) / 1e4;
|
|
9172
9713
|
}
|
|
9173
9714
|
|
|
@@ -9318,8 +9859,8 @@ function layoutAoa(ast, schedule) {
|
|
|
9318
9859
|
x: cx[e],
|
|
9319
9860
|
y: cy[e],
|
|
9320
9861
|
r: AOA.R,
|
|
9321
|
-
te:
|
|
9322
|
-
tl:
|
|
9862
|
+
te: round5(te[e]),
|
|
9863
|
+
tl: round5(tl[e]),
|
|
9323
9864
|
critical: eventCritical(e)
|
|
9324
9865
|
}));
|
|
9325
9866
|
const outArcs = arcs.map((a) => {
|
|
@@ -9378,7 +9919,7 @@ function arcGeometry(tx, ty, hx, hy, r5) {
|
|
|
9378
9919
|
const sy = ty + uy * r5;
|
|
9379
9920
|
const ex = hx - ux * r5;
|
|
9380
9921
|
const ey = hy - uy * r5;
|
|
9381
|
-
return { d: `M ${
|
|
9922
|
+
return { d: `M ${round5(sx)} ${round5(sy)} L ${round5(ex)} ${round5(ey)}`, mx: (sx + ex) / 2, my: (sy + ey) / 2 };
|
|
9382
9923
|
}
|
|
9383
9924
|
function buildAoaSummary(ast, sched) {
|
|
9384
9925
|
const summary = {
|
|
@@ -9392,7 +9933,7 @@ function buildAoaSummary(ast, sched) {
|
|
|
9392
9933
|
if (sched.projectStdDev !== void 0) summary.projectStdDev = sched.projectStdDev;
|
|
9393
9934
|
return summary;
|
|
9394
9935
|
}
|
|
9395
|
-
function
|
|
9936
|
+
function round5(n) {
|
|
9396
9937
|
return Math.round(n * 1e3) / 1e3;
|
|
9397
9938
|
}
|
|
9398
9939
|
|
|
@@ -10009,7 +10550,7 @@ var PALETTE = {
|
|
|
10009
10550
|
axisBaseline: "#8497ad",
|
|
10010
10551
|
grid: "#e3eaf3"
|
|
10011
10552
|
};
|
|
10012
|
-
function
|
|
10553
|
+
function buildCss5(t) {
|
|
10013
10554
|
const P = PALETTE;
|
|
10014
10555
|
return `
|
|
10015
10556
|
.sx-pert { font-family: system-ui, -apple-system, sans-serif; }
|
|
@@ -10333,7 +10874,7 @@ function renderPertLayout(layout, config) {
|
|
|
10333
10874
|
`${layout.summary.taskCount} activities, project duration ${fmtVal(layout.summary.projectDuration)} ${unitWord(layout.unit)}` + (cp.length ? `, critical path ${cp.join(" \u2192 ")}` : "") + "."
|
|
10334
10875
|
)
|
|
10335
10876
|
);
|
|
10336
|
-
children.push(el("style", {},
|
|
10877
|
+
children.push(el("style", {}, buildCss5(t)));
|
|
10337
10878
|
children.push(markers2());
|
|
10338
10879
|
if (layout.title) {
|
|
10339
10880
|
children.push(
|
|
@@ -11248,7 +11789,7 @@ function layoutSequence(ast) {
|
|
|
11248
11789
|
// src/diagrams/sequence/renderer.ts
|
|
11249
11790
|
var HEAD = "#e8f0fb";
|
|
11250
11791
|
var HEAD_STROKE = "#5b85c0";
|
|
11251
|
-
function
|
|
11792
|
+
function buildCss6(t) {
|
|
11252
11793
|
return `
|
|
11253
11794
|
.sx-seq { font-family: system-ui, -apple-system, sans-serif; }
|
|
11254
11795
|
.sx-seq-axis { stroke: ${t.neutral}; stroke-width: 1; stroke-dasharray: 4 4; }
|
|
@@ -11543,7 +12084,7 @@ function renderSequenceLayout(layout, config) {
|
|
|
11543
12084
|
`${layout.lifelines.length} participants, ${nMsg} messages, ${nFrag} combined fragments.`
|
|
11544
12085
|
)
|
|
11545
12086
|
);
|
|
11546
|
-
children.push(el("style", {},
|
|
12087
|
+
children.push(el("style", {}, buildCss6(t)));
|
|
11547
12088
|
children.push(markers3(t));
|
|
11548
12089
|
const titleBand = layout.title ? 32 : 0;
|
|
11549
12090
|
if (layout.title) {
|
|
@@ -11614,7 +12155,7 @@ var PetriParseError = class extends Error {
|
|
|
11614
12155
|
};
|
|
11615
12156
|
var OPENERS = ['"', "\u201C", "\u300C", "\u300E", "\xAB"];
|
|
11616
12157
|
var CLOSERS = ['"', "\u201D", "\u300D", "\u300F", "\xBB"];
|
|
11617
|
-
function
|
|
12158
|
+
function tokenize4(s) {
|
|
11618
12159
|
const out = [];
|
|
11619
12160
|
let i = 0;
|
|
11620
12161
|
while (i < s.length) {
|
|
@@ -11681,7 +12222,7 @@ function parsePetri(text2) {
|
|
|
11681
12222
|
if (trimmed.startsWith("#") || trimmed.startsWith("//")) continue;
|
|
11682
12223
|
if (!sawHeader && /^petri(net)?\b/i.test(trimmed)) {
|
|
11683
12224
|
sawHeader = true;
|
|
11684
|
-
const toks =
|
|
12225
|
+
const toks = tokenize4(trimmed);
|
|
11685
12226
|
const titleTok = toks.find((t, idx) => idx > 0 && t.quoted);
|
|
11686
12227
|
if (titleTok) ast.title = titleTok.text;
|
|
11687
12228
|
else if (toks[1] && !toks[1].quoted) ast.title = toks.slice(1).map((t) => t.text).join(" ");
|
|
@@ -11743,7 +12284,7 @@ function declareDup(id, lineNo, placeIds, transIds) {
|
|
|
11743
12284
|
}
|
|
11744
12285
|
}
|
|
11745
12286
|
function parsePlace(line2, lineNo, placeIds, transIds) {
|
|
11746
|
-
const toks =
|
|
12287
|
+
const toks = tokenize4(normalizeKeyNums(line2));
|
|
11747
12288
|
const idTok = toks[1];
|
|
11748
12289
|
if (!idTok || idTok.quoted) throw new PetriParseError(`place is missing an id`, lineNo);
|
|
11749
12290
|
const id = idTok.text;
|
|
@@ -11782,7 +12323,7 @@ function parseTransition(line2, lineNo, placeIds, transIds) {
|
|
|
11782
12323
|
guard = String(g).trim();
|
|
11783
12324
|
return " ";
|
|
11784
12325
|
});
|
|
11785
|
-
const toks =
|
|
12326
|
+
const toks = tokenize4(normalizeKeyNums(stripped));
|
|
11786
12327
|
const idTok = toks[1];
|
|
11787
12328
|
if (!idTok || idTok.quoted) throw new PetriParseError(`transition is missing an id`, lineNo);
|
|
11788
12329
|
const id = idTok.text;
|
|
@@ -11840,7 +12381,7 @@ function parseArc(m, lineNo, placeIds, transIds) {
|
|
|
11840
12381
|
throw new PetriParseError(`${type} arcs are place\u2192transition only`, lineNo);
|
|
11841
12382
|
}
|
|
11842
12383
|
const arc = { from, to, type, weight: 1, line: lineNo };
|
|
11843
|
-
const toks =
|
|
12384
|
+
const toks = tokenize4(normalizeKeyNums(rest));
|
|
11844
12385
|
const labelParts = [];
|
|
11845
12386
|
for (const t of toks) {
|
|
11846
12387
|
if (t.quoted) {
|
|
@@ -11977,7 +12518,7 @@ function layoutPetri(ast) {
|
|
|
11977
12518
|
reindex();
|
|
11978
12519
|
}
|
|
11979
12520
|
}
|
|
11980
|
-
const
|
|
12521
|
+
const sizeOf3 = (id) => {
|
|
11981
12522
|
if (kindOf.get(id) === "place") return { halfW: C2.PLACE_R, halfH: C2.PLACE_R, r: C2.PLACE_R };
|
|
11982
12523
|
const tr = ast.transitions.find((t) => t.id === id);
|
|
11983
12524
|
const long = tr.kind === "timed" ? C2.TRANS_BOX_H : C2.TRANS_BAR_H;
|
|
@@ -11987,11 +12528,11 @@ function layoutPetri(ast) {
|
|
|
11987
12528
|
return { halfW, halfH, r: 0 };
|
|
11988
12529
|
};
|
|
11989
12530
|
const flowHalf = (id) => {
|
|
11990
|
-
const s =
|
|
12531
|
+
const s = sizeOf3(id);
|
|
11991
12532
|
return dir === "lr" ? s.halfW : s.halfH;
|
|
11992
12533
|
};
|
|
11993
12534
|
const crossHalf = (id) => {
|
|
11994
|
-
const s =
|
|
12535
|
+
const s = sizeOf3(id);
|
|
11995
12536
|
return dir === "lr" ? s.halfH : s.halfW;
|
|
11996
12537
|
};
|
|
11997
12538
|
const layerHalf = layers.map((arr) => Math.max(0, ...arr.map(flowHalf)));
|
|
@@ -12014,7 +12555,7 @@ function layoutPetri(ast) {
|
|
|
12014
12555
|
const flow = flowCenter[L];
|
|
12015
12556
|
const cx = dir === "lr" ? flow : cross;
|
|
12016
12557
|
const cy = dir === "lr" ? cross : flow;
|
|
12017
|
-
const s =
|
|
12558
|
+
const s = sizeOf3(id);
|
|
12018
12559
|
geom.set(id, { id, kind: kindOf.get(id), cx, cy, halfW: s.halfW, halfH: s.halfH, r: s.r, layer: L });
|
|
12019
12560
|
});
|
|
12020
12561
|
});
|
|
@@ -12208,7 +12749,7 @@ function detectSubclass(ast) {
|
|
|
12208
12749
|
}
|
|
12209
12750
|
|
|
12210
12751
|
// src/diagrams/petri/renderer.ts
|
|
12211
|
-
function
|
|
12752
|
+
function buildCss7(t) {
|
|
12212
12753
|
return `
|
|
12213
12754
|
.sx-petri { font-family: system-ui, -apple-system, sans-serif; }
|
|
12214
12755
|
.sx-petri-place { fill: ${t.placeFill}; stroke: ${t.placeStroke}; stroke-width: 2; }
|
|
@@ -12352,7 +12893,7 @@ function arcPath(ag) {
|
|
|
12352
12893
|
}
|
|
12353
12894
|
return `M ${p[0].x} ${p[0].y} L ${p[p.length - 1].x} ${p[p.length - 1].y}`;
|
|
12354
12895
|
}
|
|
12355
|
-
function
|
|
12896
|
+
function renderArc2(ag) {
|
|
12356
12897
|
const parts = [];
|
|
12357
12898
|
let cls = "sx-petri-arc";
|
|
12358
12899
|
let markerEnd;
|
|
@@ -12399,14 +12940,14 @@ function renderPetriLayout(layout, config) {
|
|
|
12399
12940
|
].filter(Boolean);
|
|
12400
12941
|
children.push(title(`Petri net${layout.title ? " \u2014 " + layout.title : ""}`));
|
|
12401
12942
|
children.push(desc(descParts.join(" ")));
|
|
12402
|
-
children.push(el("style", {},
|
|
12943
|
+
children.push(el("style", {}, buildCss7(t)));
|
|
12403
12944
|
children.push(markers4(t));
|
|
12404
12945
|
const titleBand = layout.title ? 32 : 0;
|
|
12405
12946
|
if (layout.title) {
|
|
12406
12947
|
children.push(text({ x: layout.width / 2, y: 22, class: "sx-petri-title", "text-anchor": "middle" }, layout.title));
|
|
12407
12948
|
}
|
|
12408
12949
|
const body = [];
|
|
12409
|
-
body.push(group({ class: "sx-petri-arcs" }, layout.arcs.map(
|
|
12950
|
+
body.push(group({ class: "sx-petri-arcs" }, layout.arcs.map(renderArc2)));
|
|
12410
12951
|
body.push(group({ class: "sx-petri-places" }, layout.places.map((p) => renderPlace(p, layout.ast.tokenStyle))));
|
|
12411
12952
|
body.push(group({ class: "sx-petri-transitions" }, layout.transitions.map(renderTransition)));
|
|
12412
12953
|
children.push(titleBand ? group({ transform: `translate(0, ${titleBand})` }, body) : group({}, body));
|
|
@@ -12579,7 +13120,7 @@ function splitStatements(line2) {
|
|
|
12579
13120
|
out.push(buf);
|
|
12580
13121
|
return out;
|
|
12581
13122
|
}
|
|
12582
|
-
function
|
|
13123
|
+
function tokenize5(raw) {
|
|
12583
13124
|
const line2 = stripComment2(raw);
|
|
12584
13125
|
const strings = [];
|
|
12585
13126
|
const masked = line2.replace(QUOTE_RE, (...m) => {
|
|
@@ -12734,7 +13275,7 @@ function parseNetwork(text2) {
|
|
|
12734
13275
|
});
|
|
12735
13276
|
for (const stmt of statements) {
|
|
12736
13277
|
const lineNo = stmt.no;
|
|
12737
|
-
const toks =
|
|
13278
|
+
const toks = tokenize5(stmt.text);
|
|
12738
13279
|
if (toks.length === 0) continue;
|
|
12739
13280
|
const t0 = toks[0];
|
|
12740
13281
|
if (!headerSeen) {
|
|
@@ -13720,7 +14261,7 @@ function layoutNetwork2(ast) {
|
|
|
13720
14261
|
|
|
13721
14262
|
// src/diagrams/network/renderer.ts
|
|
13722
14263
|
var r22 = (n) => Math.round(n * 100) / 100;
|
|
13723
|
-
function
|
|
14264
|
+
function buildCss8(t) {
|
|
13724
14265
|
return `
|
|
13725
14266
|
.sx-net { font-family: system-ui, -apple-system, sans-serif; }
|
|
13726
14267
|
.sx-net-body { fill: ${t.deviceFill}; stroke: ${t.deviceStroke}; stroke-width: 2; }
|
|
@@ -13780,7 +14321,7 @@ function annotation(link) {
|
|
|
13780
14321
|
if (link.label) parts.push(link.label);
|
|
13781
14322
|
return parts.join(" \xB7 ");
|
|
13782
14323
|
}
|
|
13783
|
-
function
|
|
14324
|
+
function arrowHead2(x1, y1, x2, y2, color, hs = 6) {
|
|
13784
14325
|
const ang = Math.atan2(y2 - y1, x2 - x1);
|
|
13785
14326
|
const a1 = ang + Math.PI - 0.45;
|
|
13786
14327
|
const a2 = ang + Math.PI + 0.45;
|
|
@@ -13805,7 +14346,7 @@ function renderLink(lg, t) {
|
|
|
13805
14346
|
} else {
|
|
13806
14347
|
parts.push(el("polyline", { class: cls, stroke: color, points: lg.points.map((p) => `${r22(p.x)},${r22(p.y)}`).join(" ") }));
|
|
13807
14348
|
}
|
|
13808
|
-
if (link.directed) parts.push(
|
|
14349
|
+
if (link.directed) parts.push(arrowHead2(p1.x, p1.y, p2.x, p2.y, color));
|
|
13809
14350
|
if (link.linkType === "fiber") {
|
|
13810
14351
|
const ang = Math.atan2(p2.y - p1.y, p2.x - p1.x) + Math.PI / 2;
|
|
13811
14352
|
for (const f of [0.4, 0.55]) {
|
|
@@ -13879,7 +14420,7 @@ function renderNetworkLayout(layout, config) {
|
|
|
13879
14420
|
].filter(Boolean);
|
|
13880
14421
|
children.push(title(`Network diagram${layout.title ? " \u2014 " + layout.title : ""}`));
|
|
13881
14422
|
children.push(desc(descParts.join(" ")));
|
|
13882
|
-
children.push(el("style", {},
|
|
14423
|
+
children.push(el("style", {}, buildCss8(t)));
|
|
13883
14424
|
const titleBand = layout.title ? 30 : 0;
|
|
13884
14425
|
if (layout.title) {
|
|
13885
14426
|
children.push(text({ x: r22(layout.width / 2), y: 21, class: "sx-net-title", "text-anchor": "middle" }, layout.title));
|
|
@@ -15518,10 +16059,10 @@ function buildTree2(kind, parent, children, vertical) {
|
|
|
15518
16059
|
const avgChildX = childXs.reduce((a, b) => a + b, 0) / childXs.length;
|
|
15519
16060
|
const trunkX = Math.max(parent.x + 10, Math.min(parent.x + parent.width - 10, avgChildX));
|
|
15520
16061
|
const trunkBaseY = parentBottom + UMLCLASS_CONST.TRIANGLE_H;
|
|
15521
|
-
const trunkD2 = `M ${
|
|
16062
|
+
const trunkD2 = `M ${round6(trunkX)} ${round6(junctionY)} L ${round6(trunkX)} ${round6(trunkBaseY)}`;
|
|
15522
16063
|
const legPaths2 = children.map((c) => {
|
|
15523
16064
|
const cx = c.box.x + c.box.width / 2;
|
|
15524
|
-
return `M ${
|
|
16065
|
+
return `M ${round6(cx)} ${round6(c.box.y)} L ${round6(cx)} ${round6(junctionY)} L ${round6(trunkX)} ${round6(junctionY)}`;
|
|
15525
16066
|
});
|
|
15526
16067
|
return {
|
|
15527
16068
|
parentId: parent.classifier.id,
|
|
@@ -15541,10 +16082,10 @@ function buildTree2(kind, parent, children, vertical) {
|
|
|
15541
16082
|
const avgChildY = childYs.reduce((a, b) => a + b, 0) / childYs.length;
|
|
15542
16083
|
const trunkY = Math.max(parent.y + 10, Math.min(parent.y + parent.height - 10, avgChildY));
|
|
15543
16084
|
const trunkBaseX = parentRight + UMLCLASS_CONST.TRIANGLE_H;
|
|
15544
|
-
const trunkD = `M ${
|
|
16085
|
+
const trunkD = `M ${round6(junctionX)} ${round6(trunkY)} L ${round6(trunkBaseX)} ${round6(trunkY)}`;
|
|
15545
16086
|
const legPaths = children.map((c) => {
|
|
15546
16087
|
const cy = c.box.y + c.box.height / 2;
|
|
15547
|
-
return `M ${
|
|
16088
|
+
return `M ${round6(c.box.x)} ${round6(cy)} L ${round6(junctionX)} ${round6(cy)} L ${round6(junctionX)} ${round6(trunkY)}`;
|
|
15548
16089
|
});
|
|
15549
16090
|
return {
|
|
15550
16091
|
parentId: parent.classifier.id,
|
|
@@ -15607,7 +16148,7 @@ function adornmentBase(end, outset) {
|
|
|
15607
16148
|
}
|
|
15608
16149
|
}
|
|
15609
16150
|
function polyline(pts) {
|
|
15610
|
-
return pts.map((p, i) => `${i === 0 ? "M" : "L"} ${
|
|
16151
|
+
return pts.map((p, i) => `${i === 0 ? "M" : "L"} ${round6(p.x)} ${round6(p.y)}`).join(" ");
|
|
15611
16152
|
}
|
|
15612
16153
|
function midOf(pts) {
|
|
15613
16154
|
if (pts.length === 0) return { x: 0, y: 0 };
|
|
@@ -15615,7 +16156,7 @@ function midOf(pts) {
|
|
|
15615
16156
|
const a = pts[i], b = pts[i + 1] ?? pts[i];
|
|
15616
16157
|
return { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };
|
|
15617
16158
|
}
|
|
15618
|
-
function
|
|
16159
|
+
function round6(n) {
|
|
15619
16160
|
return Math.round(n * 10) / 10;
|
|
15620
16161
|
}
|
|
15621
16162
|
|
|
@@ -18204,6 +18745,24 @@ function splitWordsWithTrailingSpace(s) {
|
|
|
18204
18745
|
return out.length > 0 ? out : [s];
|
|
18205
18746
|
}
|
|
18206
18747
|
|
|
18748
|
+
// src/diagrams/mindmap/modes.ts
|
|
18749
|
+
var EXTENDED_MODES = [
|
|
18750
|
+
"futureswheel",
|
|
18751
|
+
"driver"
|
|
18752
|
+
];
|
|
18753
|
+
function baseStyleFor(mode) {
|
|
18754
|
+
if (mode === "futureswheel") return "map";
|
|
18755
|
+
if (mode === "driver") return "logic-right";
|
|
18756
|
+
return mode;
|
|
18757
|
+
}
|
|
18758
|
+
var modeRegistry = /* @__PURE__ */ new WeakMap();
|
|
18759
|
+
function setMode(ast, mode) {
|
|
18760
|
+
modeRegistry.set(ast, mode);
|
|
18761
|
+
}
|
|
18762
|
+
function modeOf(ast) {
|
|
18763
|
+
return modeRegistry.get(ast) ?? ast.style;
|
|
18764
|
+
}
|
|
18765
|
+
|
|
18207
18766
|
// src/diagrams/mindmap/parser.ts
|
|
18208
18767
|
var MindmapParseError = class extends Error {
|
|
18209
18768
|
constructor(message, line2, column, source) {
|
|
@@ -18227,6 +18786,10 @@ function parseDirective(line2, out) {
|
|
|
18227
18786
|
const val = body.slice(idx + 1).trim();
|
|
18228
18787
|
if (key === "style" && VALID_STYLES.includes(val)) {
|
|
18229
18788
|
out.style = val;
|
|
18789
|
+
out.mode = val;
|
|
18790
|
+
} else if (key === "style" && EXTENDED_MODES.includes(val)) {
|
|
18791
|
+
out.mode = val;
|
|
18792
|
+
out.style = baseStyleFor(out.mode);
|
|
18230
18793
|
} else if (key === "theme") {
|
|
18231
18794
|
out.themeOverride = val;
|
|
18232
18795
|
} else if (key === "maxlabelwidth") {
|
|
@@ -18245,7 +18808,7 @@ function parseMindmap(text2) {
|
|
|
18245
18808
|
lineOffset = 1;
|
|
18246
18809
|
}
|
|
18247
18810
|
const lines = allLines;
|
|
18248
|
-
const directives = { style: "map", maxLabelWidth: DEFAULT_MAX_LABEL_WIDTH };
|
|
18811
|
+
const directives = { style: "map", mode: "map", maxLabelWidth: DEFAULT_MAX_LABEL_WIDTH };
|
|
18249
18812
|
let root = null;
|
|
18250
18813
|
let rootInferred;
|
|
18251
18814
|
let idCounter2 = 0;
|
|
@@ -18320,6 +18883,7 @@ function parseMindmap(text2) {
|
|
|
18320
18883
|
};
|
|
18321
18884
|
if (rootInferred) ast.rootInferred = rootInferred;
|
|
18322
18885
|
if (directives.themeOverride) ast.themeOverride = directives.themeOverride;
|
|
18886
|
+
setMode(ast, directives.mode);
|
|
18323
18887
|
return ast;
|
|
18324
18888
|
}
|
|
18325
18889
|
|
|
@@ -18352,8 +18916,127 @@ function lintMindmap(text2) {
|
|
|
18352
18916
|
return out;
|
|
18353
18917
|
}
|
|
18354
18918
|
|
|
18919
|
+
// src/diagrams/mindmap/futureswheel.ts
|
|
18920
|
+
var RING_GAP = 150;
|
|
18921
|
+
function spokePath(x1, y1, x2, y2) {
|
|
18922
|
+
return `M ${x1.toFixed(1)} ${y1.toFixed(1)} L ${x2.toFixed(1)} ${y2.toFixed(1)}`;
|
|
18923
|
+
}
|
|
18924
|
+
function edgeWidthForOrder(order) {
|
|
18925
|
+
if (order <= 1) return 2.2;
|
|
18926
|
+
if (order === 2) return 1.6;
|
|
18927
|
+
return 1.2;
|
|
18928
|
+
}
|
|
18929
|
+
function leafCount(node) {
|
|
18930
|
+
if (node.children.length === 0) return 1;
|
|
18931
|
+
let sum = 0;
|
|
18932
|
+
for (const c of node.children) sum += leafCount(c);
|
|
18933
|
+
return sum;
|
|
18934
|
+
}
|
|
18935
|
+
function layoutFuturesWheel(ast) {
|
|
18936
|
+
const root = ast.root;
|
|
18937
|
+
const mw = ast.maxLabelWidth;
|
|
18938
|
+
const nodes = [];
|
|
18939
|
+
const placed = /* @__PURE__ */ new Map();
|
|
18940
|
+
const rootM = measureLabel(root, widthBudget(0, mw));
|
|
18941
|
+
const rootLayout = {
|
|
18942
|
+
node: root,
|
|
18943
|
+
x: 0,
|
|
18944
|
+
y: 0,
|
|
18945
|
+
side: "center",
|
|
18946
|
+
branchIndex: -1,
|
|
18947
|
+
labelWidth: rootM.width,
|
|
18948
|
+
labelHeight: rootM.height,
|
|
18949
|
+
fontSize: fontSizeOf(0),
|
|
18950
|
+
lines: rootM.lines
|
|
18951
|
+
};
|
|
18952
|
+
nodes.push(rootLayout);
|
|
18953
|
+
placed.set(root.id, { layout: rootLayout, angle: 0 });
|
|
18954
|
+
const placeChildren = (node, a0, a1, branchIndex) => {
|
|
18955
|
+
const kids = node.children;
|
|
18956
|
+
if (kids.length === 0) return;
|
|
18957
|
+
const weights = kids.map(leafCount);
|
|
18958
|
+
const totalW = weights.reduce((s, w) => s + w, 0);
|
|
18959
|
+
const span = a1 - a0;
|
|
18960
|
+
let cursor = a0;
|
|
18961
|
+
for (let i = 0; i < kids.length; i++) {
|
|
18962
|
+
const child = kids[i];
|
|
18963
|
+
const slice = weights[i] / totalW * span;
|
|
18964
|
+
const sliceStart = cursor;
|
|
18965
|
+
const sliceEnd = cursor + slice;
|
|
18966
|
+
const mid = (sliceStart + sliceEnd) / 2;
|
|
18967
|
+
cursor = sliceEnd;
|
|
18968
|
+
const order = child.depth;
|
|
18969
|
+
const radius = order * RING_GAP;
|
|
18970
|
+
const m = measureLabel(child, widthBudget(child.depth, mw));
|
|
18971
|
+
const childBranch = node.depth === 0 ? i : branchIndex;
|
|
18972
|
+
const layout = {
|
|
18973
|
+
node: child,
|
|
18974
|
+
x: radius * Math.cos(mid),
|
|
18975
|
+
y: radius * Math.sin(mid),
|
|
18976
|
+
// Right half-plane → label extends right; left half-plane → left.
|
|
18977
|
+
side: Math.cos(mid) >= 0 ? "right" : "left",
|
|
18978
|
+
branchIndex: childBranch,
|
|
18979
|
+
labelWidth: m.width,
|
|
18980
|
+
labelHeight: m.height,
|
|
18981
|
+
fontSize: fontSizeOf(child.depth),
|
|
18982
|
+
lines: m.lines
|
|
18983
|
+
};
|
|
18984
|
+
nodes.push(layout);
|
|
18985
|
+
placed.set(child.id, { layout, angle: mid });
|
|
18986
|
+
placeChildren(child, sliceStart, sliceEnd, childBranch);
|
|
18987
|
+
}
|
|
18988
|
+
};
|
|
18989
|
+
const START2 = -Math.PI / 2;
|
|
18990
|
+
placeChildren(root, START2, START2 + Math.PI * 2, -1);
|
|
18991
|
+
const edges = [];
|
|
18992
|
+
const walkEdges = (parent) => {
|
|
18993
|
+
const p = placed.get(parent.id);
|
|
18994
|
+
if (!p) return;
|
|
18995
|
+
for (const c of parent.children) {
|
|
18996
|
+
const cp = placed.get(c.id);
|
|
18997
|
+
if (!cp) continue;
|
|
18998
|
+
edges.push({
|
|
18999
|
+
from: parent.id,
|
|
19000
|
+
to: c.id,
|
|
19001
|
+
path: spokePath(p.layout.x, p.layout.y, cp.layout.x, cp.layout.y),
|
|
19002
|
+
color: "",
|
|
19003
|
+
width: edgeWidthForOrder(c.depth)
|
|
19004
|
+
});
|
|
19005
|
+
walkEdges(c);
|
|
19006
|
+
}
|
|
19007
|
+
};
|
|
19008
|
+
walkEdges(root);
|
|
19009
|
+
const { width, height } = normalize(nodes);
|
|
19010
|
+
const byId = new Map(nodes.map((n) => [n.node.id, n]));
|
|
19011
|
+
for (const e of edges) {
|
|
19012
|
+
const f = byId.get(e.from);
|
|
19013
|
+
const t = byId.get(e.to);
|
|
19014
|
+
if (f && t) e.path = spokePath(f.x, f.y, t.x, t.y);
|
|
19015
|
+
}
|
|
19016
|
+
return {
|
|
19017
|
+
width,
|
|
19018
|
+
height,
|
|
19019
|
+
// `style` is constrained to the base union; futureswheel renders on `map`.
|
|
19020
|
+
style: "map",
|
|
19021
|
+
nodes,
|
|
19022
|
+
edges,
|
|
19023
|
+
title: ast.title
|
|
19024
|
+
};
|
|
19025
|
+
}
|
|
19026
|
+
function wheelCenter(result) {
|
|
19027
|
+
for (const n of result.nodes) {
|
|
19028
|
+
if (n.node.depth === 0) return { cx: n.x, cy: n.y };
|
|
19029
|
+
}
|
|
19030
|
+
return { cx: result.width / 2, cy: result.height / 2 };
|
|
19031
|
+
}
|
|
19032
|
+
function maxOrder(result) {
|
|
19033
|
+
let max = 0;
|
|
19034
|
+
for (const n of result.nodes) if (n.node.depth > max) max = n.node.depth;
|
|
19035
|
+
return max;
|
|
19036
|
+
}
|
|
19037
|
+
|
|
18355
19038
|
// src/diagrams/mindmap/layout.ts
|
|
18356
|
-
var
|
|
19039
|
+
var PADDING3 = 40;
|
|
18357
19040
|
var SIBLING_GAP = 18;
|
|
18358
19041
|
var MAIN_GAP = 44;
|
|
18359
19042
|
var UNDERLINE_GAP = 4;
|
|
@@ -18500,13 +19183,13 @@ function normalize(nodes) {
|
|
|
18500
19183
|
minY = Math.min(minY, n.y - lh / 2);
|
|
18501
19184
|
maxY = Math.max(maxY, n.y + lh / 2);
|
|
18502
19185
|
}
|
|
18503
|
-
const dx =
|
|
18504
|
-
const dy =
|
|
19186
|
+
const dx = PADDING3 - minX;
|
|
19187
|
+
const dy = PADDING3 - minY;
|
|
18505
19188
|
for (const n of nodes) {
|
|
18506
19189
|
n.x += dx;
|
|
18507
19190
|
n.y += dy;
|
|
18508
19191
|
}
|
|
18509
|
-
return { width: maxX - minX +
|
|
19192
|
+
return { width: maxX - minX + PADDING3 * 2, height: maxY - minY + PADDING3 * 2 };
|
|
18510
19193
|
}
|
|
18511
19194
|
function underlineY(n) {
|
|
18512
19195
|
return n.y + n.labelHeight / 2 - UNDERLINE_GAP / 2;
|
|
@@ -18621,6 +19304,9 @@ function layoutLogicRight(ast) {
|
|
|
18621
19304
|
return { width, height, style: "logic-right", nodes, edges, title: ast.title };
|
|
18622
19305
|
}
|
|
18623
19306
|
function layoutMindmap(ast) {
|
|
19307
|
+
const mode = modeOf(ast);
|
|
19308
|
+
if (mode === "futureswheel") return layoutFuturesWheel(ast);
|
|
19309
|
+
if (mode === "driver") return layoutLogicRight(ast);
|
|
18624
19310
|
const style = ast.style;
|
|
18625
19311
|
if (style === "logic-right") return layoutLogicRight(ast);
|
|
18626
19312
|
return layoutMap(ast);
|
|
@@ -18749,7 +19435,7 @@ function tspan(attrs, content) {
|
|
|
18749
19435
|
}
|
|
18750
19436
|
return `<tspan ${pairs.join(" ")}>${escapeXml(content)}</tspan>`;
|
|
18751
19437
|
}
|
|
18752
|
-
function
|
|
19438
|
+
function renderNode3(n, color, theme, fontFamily, orderClass) {
|
|
18753
19439
|
const isRoot = n.node.depth === 0;
|
|
18754
19440
|
const isMain = n.node.depth === 1;
|
|
18755
19441
|
const fs = n.fontSize;
|
|
@@ -18782,12 +19468,14 @@ function renderNode2(n, color, theme, fontFamily) {
|
|
|
18782
19468
|
"stroke-linecap": "round"
|
|
18783
19469
|
})
|
|
18784
19470
|
);
|
|
18785
|
-
const
|
|
19471
|
+
const baseCls = isRoot ? "schematex-mindmap-central" : isMain ? "schematex-mindmap-main" : "schematex-mindmap-leaf";
|
|
19472
|
+
const cls = orderClass ? `${baseCls} mm-order-${n.node.depth}` : baseCls;
|
|
18786
19473
|
return group(
|
|
18787
19474
|
{
|
|
18788
19475
|
class: cls,
|
|
18789
19476
|
"data-node-id": n.node.id,
|
|
18790
19477
|
"data-depth": n.node.depth,
|
|
19478
|
+
"data-order": orderClass ? n.node.depth : void 0,
|
|
18791
19479
|
"data-branch-idx": n.branchIndex
|
|
18792
19480
|
},
|
|
18793
19481
|
[...decorations, ...children]
|
|
@@ -18795,8 +19483,30 @@ function renderNode2(n, color, theme, fontFamily) {
|
|
|
18795
19483
|
}
|
|
18796
19484
|
function renderMindmapAST(ast, themeName = "default", fontFamily = "system-ui, -apple-system, sans-serif") {
|
|
18797
19485
|
const theme = resolveMindmapTheme(ast.themeOverride ?? themeName);
|
|
19486
|
+
const mode = modeOf(ast);
|
|
19487
|
+
const isWheel = mode === "futureswheel";
|
|
18798
19488
|
const layout = layoutMindmap(ast);
|
|
18799
19489
|
const byId = new Map(layout.nodes.map((n) => [n.node.id, n]));
|
|
19490
|
+
const ringSvgs = [];
|
|
19491
|
+
if (isWheel) {
|
|
19492
|
+
const { cx, cy } = wheelCenter(layout);
|
|
19493
|
+
const rings = maxOrder(layout);
|
|
19494
|
+
for (let order = 1; order <= rings; order++) {
|
|
19495
|
+
ringSvgs.push(
|
|
19496
|
+
circle({
|
|
19497
|
+
cx: cx.toFixed(1),
|
|
19498
|
+
cy: cy.toFixed(1),
|
|
19499
|
+
r: (order * RING_GAP).toFixed(1),
|
|
19500
|
+
fill: "none",
|
|
19501
|
+
stroke: theme.centralFill,
|
|
19502
|
+
"stroke-width": 1,
|
|
19503
|
+
"stroke-dasharray": "3 5",
|
|
19504
|
+
opacity: 0.25,
|
|
19505
|
+
class: `mm-ring mm-ring-${order}`
|
|
19506
|
+
})
|
|
19507
|
+
);
|
|
19508
|
+
}
|
|
19509
|
+
}
|
|
18800
19510
|
const edgeSvgs = [];
|
|
18801
19511
|
for (const e of layout.edges) {
|
|
18802
19512
|
const target = byId.get(e.to);
|
|
@@ -18815,9 +19525,10 @@ function renderMindmapAST(ast, themeName = "default", fontFamily = "system-ui, -
|
|
|
18815
19525
|
const nodeSvgs = [];
|
|
18816
19526
|
for (const n of layout.nodes) {
|
|
18817
19527
|
const color = n.node.depth === 0 ? theme.centralFill : paletteColor(theme, n.branchIndex);
|
|
18818
|
-
nodeSvgs.push(
|
|
19528
|
+
nodeSvgs.push(renderNode3(n, color, theme, fontFamily, isWheel));
|
|
18819
19529
|
}
|
|
18820
19530
|
const title2 = ast.title ?? tokensToPlainText(ast.root.tokens);
|
|
19531
|
+
const descLabel = isWheel ? `futures-wheel mindmap with ${layout.nodes.length} nodes` : `${layout.style} mindmap with ${layout.nodes.length} nodes`;
|
|
18821
19532
|
return svgRoot(
|
|
18822
19533
|
{
|
|
18823
19534
|
viewBox: `0 0 ${layout.width.toFixed(1)} ${layout.height.toFixed(1)}`,
|
|
@@ -18828,8 +19539,9 @@ function renderMindmapAST(ast, themeName = "default", fontFamily = "system-ui, -
|
|
|
18828
19539
|
},
|
|
18829
19540
|
[
|
|
18830
19541
|
title(title2),
|
|
18831
|
-
desc(
|
|
19542
|
+
desc(descLabel),
|
|
18832
19543
|
rect({ x: 0, y: 0, width: layout.width, height: layout.height, fill: theme.bg }),
|
|
19544
|
+
group({ class: "schematex-mindmap-rings", "aria-hidden": "true" }, ringSvgs),
|
|
18833
19545
|
group({ class: "schematex-mindmap-edges", "aria-hidden": "true" }, edgeSvgs),
|
|
18834
19546
|
group({ class: "schematex-mindmap-nodes" }, nodeSvgs)
|
|
18835
19547
|
]
|
|
@@ -19020,6 +19732,30 @@ var DEFAULT_CONFIG = {
|
|
|
19020
19732
|
function emptyAxis() {
|
|
19021
19733
|
return { low: "", high: "" };
|
|
19022
19734
|
}
|
|
19735
|
+
function emptySipoc() {
|
|
19736
|
+
return { suppliers: [], inputs: [], process: [], outputs: [], customers: [] };
|
|
19737
|
+
}
|
|
19738
|
+
function emptyQfd() {
|
|
19739
|
+
return { whats: [], hows: [], relationships: [], roof: [], normalize: false };
|
|
19740
|
+
}
|
|
19741
|
+
function parseItemList(raw) {
|
|
19742
|
+
return parseNumberList2(raw);
|
|
19743
|
+
}
|
|
19744
|
+
function parseStrength(tok) {
|
|
19745
|
+
const t = tok.trim().toLowerCase();
|
|
19746
|
+
if (t === "9" || t === "strong" || t === "\u25CF" || t === "\u25C9" || t === "\u2B24") return 9;
|
|
19747
|
+
if (t === "3" || t === "medium" || t === "\u25CB" || t === "\u25EF" || t === "o") return 3;
|
|
19748
|
+
if (t === "1" || t === "weak" || t === "\u25B3" || t === "\u25BD" || t === "\u25B2") return 1;
|
|
19749
|
+
return void 0;
|
|
19750
|
+
}
|
|
19751
|
+
function parseCorrelation(tok) {
|
|
19752
|
+
const t = tok.trim();
|
|
19753
|
+
if (t === "++" || /^strong\+?$/i.test(t) || t === "\u25CE") return "++";
|
|
19754
|
+
if (t === "+" || /^pos(itive)?$/i.test(t) || t === "\u25CB") return "+";
|
|
19755
|
+
if (t === "--" || t === "\u2212\u2212" || /^strong-$/i.test(t) || t === "\u2715" || t === "\u2716" || t === "\xD7") return "--";
|
|
19756
|
+
if (t === "-" || t === "\u2212" || /^neg(ative)?$/i.test(t) || t === "\u2717") return "-";
|
|
19757
|
+
return void 0;
|
|
19758
|
+
}
|
|
19023
19759
|
function quadrantToCell(q) {
|
|
19024
19760
|
switch (q) {
|
|
19025
19761
|
case 1:
|
|
@@ -19172,6 +19908,91 @@ function parseCellLine(line2, st) {
|
|
|
19172
19908
|
}
|
|
19173
19909
|
return true;
|
|
19174
19910
|
}
|
|
19911
|
+
var SIPOC_KEYS = [
|
|
19912
|
+
"suppliers",
|
|
19913
|
+
"inputs",
|
|
19914
|
+
"process",
|
|
19915
|
+
"outputs",
|
|
19916
|
+
"customers"
|
|
19917
|
+
];
|
|
19918
|
+
function parseSipocLine(line2, ast) {
|
|
19919
|
+
if (!ast.sipoc) return false;
|
|
19920
|
+
const m = line2.match(/^([a-zA-Z]+)\s*:\s*(.*)$/);
|
|
19921
|
+
if (!m) return false;
|
|
19922
|
+
let key = m[1].toLowerCase();
|
|
19923
|
+
if (key === "supplier") key = "suppliers";
|
|
19924
|
+
else if (key === "input") key = "inputs";
|
|
19925
|
+
else if (key === "output") key = "outputs";
|
|
19926
|
+
else if (key === "customer") key = "customers";
|
|
19927
|
+
const col = SIPOC_KEYS.find((k) => k === key);
|
|
19928
|
+
if (!col) return false;
|
|
19929
|
+
const items = parseItemList(m[2]);
|
|
19930
|
+
ast.sipoc[col].push(...items);
|
|
19931
|
+
return true;
|
|
19932
|
+
}
|
|
19933
|
+
function parseQfdLine(line2, ast) {
|
|
19934
|
+
const qfd = ast.qfd;
|
|
19935
|
+
if (!qfd) return false;
|
|
19936
|
+
const normMatch = line2.match(/^normali[sz]e\s*:\s*(.+)$/i);
|
|
19937
|
+
if (normMatch) {
|
|
19938
|
+
const v = normMatch[1].trim().toLowerCase();
|
|
19939
|
+
qfd.normalize = v === "true" || v === "on" || v === "1" || v === "percent" || v === "%";
|
|
19940
|
+
return true;
|
|
19941
|
+
}
|
|
19942
|
+
const whatMatch = line2.match(/^what\s*:\s*(.*)$/i);
|
|
19943
|
+
if (whatMatch) {
|
|
19944
|
+
const q = readQuoted2(whatMatch[1], 0);
|
|
19945
|
+
if (!q) return true;
|
|
19946
|
+
const rest = whatMatch[1].slice(q.next);
|
|
19947
|
+
const wMatch = rest.match(/(?:weight|wt|imp(?:ortance)?)\s*:\s*(-?\d+(?:\.\d+)?)/i);
|
|
19948
|
+
const weight = wMatch ? Number(wMatch[1]) : 1;
|
|
19949
|
+
qfd.whats.push({ label: q.text, weight });
|
|
19950
|
+
return true;
|
|
19951
|
+
}
|
|
19952
|
+
const howMatch = line2.match(/^how\s*:\s*(.*)$/i);
|
|
19953
|
+
if (howMatch) {
|
|
19954
|
+
const q = readQuoted2(howMatch[1], 0);
|
|
19955
|
+
if (!q) return true;
|
|
19956
|
+
const rest = howMatch[1].slice(q.next);
|
|
19957
|
+
const dMatch = rest.match(/(?:dir(?:ection)?|target)\s*:\s*([a-zA-Z↑↓○]+)/i);
|
|
19958
|
+
let direction;
|
|
19959
|
+
if (dMatch) {
|
|
19960
|
+
const d = dMatch[1].toLowerCase();
|
|
19961
|
+
if (d === "up" || d === "max" || d === "maximise" || d === "maximize" || d === "\u2191") direction = "up";
|
|
19962
|
+
else if (d === "down" || d === "min" || d === "minimise" || d === "minimize" || d === "\u2193") direction = "down";
|
|
19963
|
+
else if (d === "target" || d === "nominal" || d === "\u25CB") direction = "target";
|
|
19964
|
+
}
|
|
19965
|
+
qfd.hows.push(direction ? { label: q.text, direction } : { label: q.text });
|
|
19966
|
+
return true;
|
|
19967
|
+
}
|
|
19968
|
+
const relMatch = line2.match(/^rel\s*\(\s*(\d+)\s*,\s*(\d+)\s*\)\s*:?\s*(.+)$/i);
|
|
19969
|
+
if (relMatch) {
|
|
19970
|
+
const what = Number(relMatch[1]);
|
|
19971
|
+
const how = Number(relMatch[2]);
|
|
19972
|
+
const strength = parseStrength(relMatch[3]);
|
|
19973
|
+
if (strength !== void 0) qfd.relationships.push({ what, how, strength });
|
|
19974
|
+
return true;
|
|
19975
|
+
}
|
|
19976
|
+
const cellMatch = line2.match(/^cell\s*\(\s*(\d+)\s*,\s*(\d+)\s*\)\s*(.*)$/i);
|
|
19977
|
+
if (cellMatch) {
|
|
19978
|
+
const how = Number(cellMatch[1]);
|
|
19979
|
+
const what = Number(cellMatch[2]);
|
|
19980
|
+
const valMatch = cellMatch[3].match(/value\s*:\s*(\d+)/i);
|
|
19981
|
+
const strength = valMatch ? parseStrength(valMatch[1]) : void 0;
|
|
19982
|
+
if (strength !== void 0) qfd.relationships.push({ what, how, strength });
|
|
19983
|
+
return true;
|
|
19984
|
+
}
|
|
19985
|
+
const roofMatch = line2.match(/^roof\s*\(\s*(\d+)\s*,\s*(\d+)\s*\)\s*:?\s*(.+)$/i);
|
|
19986
|
+
if (roofMatch) {
|
|
19987
|
+
let a = Number(roofMatch[1]);
|
|
19988
|
+
let b = Number(roofMatch[2]);
|
|
19989
|
+
if (a > b) [a, b] = [b, a];
|
|
19990
|
+
const correlation = parseCorrelation(roofMatch[3]);
|
|
19991
|
+
if (correlation !== void 0 && a !== b) qfd.roof.push({ a, b, correlation });
|
|
19992
|
+
return true;
|
|
19993
|
+
}
|
|
19994
|
+
return false;
|
|
19995
|
+
}
|
|
19175
19996
|
function parseConfigLine(key, value, ast) {
|
|
19176
19997
|
const k = key.trim().toLowerCase();
|
|
19177
19998
|
const v = value.trim();
|
|
@@ -19214,6 +20035,26 @@ function parseHeader2(line2, ast) {
|
|
|
19214
20035
|
if (title2) ast.title = stripQuotes4(title2);
|
|
19215
20036
|
return void 0;
|
|
19216
20037
|
}
|
|
20038
|
+
const sipocMatch = rest.match(/^sipoc\b\s*(.*)$/i);
|
|
20039
|
+
if (sipocMatch) {
|
|
20040
|
+
ast.mode = "sipoc";
|
|
20041
|
+
ast.grid = "NxM";
|
|
20042
|
+
ast.cols = 5;
|
|
20043
|
+
ast.rows = 0;
|
|
20044
|
+
ast.sipoc = emptySipoc();
|
|
20045
|
+
const title2 = sipocMatch[1].trim();
|
|
20046
|
+
if (title2) ast.title = stripQuotes4(title2);
|
|
20047
|
+
return void 0;
|
|
20048
|
+
}
|
|
20049
|
+
const qfdMatch = rest.match(/^qfd\b\s*(.*)$/i);
|
|
20050
|
+
if (qfdMatch) {
|
|
20051
|
+
ast.mode = "qfd";
|
|
20052
|
+
ast.grid = "NxM";
|
|
20053
|
+
ast.qfd = emptyQfd();
|
|
20054
|
+
const title2 = qfdMatch[1].trim();
|
|
20055
|
+
if (title2) ast.title = stripQuotes4(title2);
|
|
20056
|
+
return void 0;
|
|
20057
|
+
}
|
|
19217
20058
|
const tokenMatch = rest.match(/^([a-zA-Z0-9_-]+)\s*(.*)$/);
|
|
19218
20059
|
if (tokenMatch) {
|
|
19219
20060
|
const tok = tokenMatch[1].toLowerCase();
|
|
@@ -19264,6 +20105,8 @@ function parseMatrix(text2) {
|
|
|
19264
20105
|
st.ast.title = stripQuotes4(line2.replace(/^title\s*:\s*/i, ""));
|
|
19265
20106
|
continue;
|
|
19266
20107
|
}
|
|
20108
|
+
if (st.ast.mode === "sipoc" && parseSipocLine(line2, st.ast)) continue;
|
|
20109
|
+
if (st.ast.mode === "qfd" && parseQfdLine(line2, st.ast)) continue;
|
|
19267
20110
|
if (/^x-axis\s*:/i.test(line2)) {
|
|
19268
20111
|
st.ast.xAxis = parseAxis(line2.replace(/^x-axis\s*:\s*/i, ""));
|
|
19269
20112
|
continue;
|
|
@@ -19362,10 +20205,27 @@ function parseMatrix(text2) {
|
|
|
19362
20205
|
st.ast.template = templateName;
|
|
19363
20206
|
}
|
|
19364
20207
|
}
|
|
19365
|
-
if (st.ast.cols === 3 && st.ast.rows === 3 && st.ast.grid !== "NxM") {
|
|
20208
|
+
if (st.ast.cols === 3 && st.ast.rows === 3 && st.ast.grid !== "NxM" && st.ast.mode !== "sipoc" && st.ast.mode !== "qfd") {
|
|
19366
20209
|
st.ast.grid = "3x3";
|
|
19367
20210
|
}
|
|
19368
|
-
if (st.ast.mode === "heatmap" || st.ast.mode === "correlation"
|
|
20211
|
+
if (st.ast.mode === "heatmap" || st.ast.mode === "correlation" || st.ast.mode === "sipoc" || st.ast.mode === "qfd") {
|
|
20212
|
+
st.ast.grid = "NxM";
|
|
20213
|
+
}
|
|
20214
|
+
if (st.ast.mode === "sipoc" && st.ast.sipoc) {
|
|
20215
|
+
const s = st.ast.sipoc;
|
|
20216
|
+
st.ast.cols = 5;
|
|
20217
|
+
st.ast.rows = Math.max(
|
|
20218
|
+
s.suppliers.length,
|
|
20219
|
+
s.inputs.length,
|
|
20220
|
+
s.process.length,
|
|
20221
|
+
s.outputs.length,
|
|
20222
|
+
s.customers.length
|
|
20223
|
+
);
|
|
20224
|
+
}
|
|
20225
|
+
if (st.ast.mode === "qfd" && st.ast.qfd) {
|
|
20226
|
+
st.ast.cols = st.ast.qfd.hows.length;
|
|
20227
|
+
st.ast.rows = st.ast.qfd.whats.length;
|
|
20228
|
+
}
|
|
19369
20229
|
return st.ast;
|
|
19370
20230
|
}
|
|
19371
20231
|
function findCommentStart(line2) {
|
|
@@ -19383,6 +20243,23 @@ function findCommentStart(line2) {
|
|
|
19383
20243
|
return -1;
|
|
19384
20244
|
}
|
|
19385
20245
|
|
|
20246
|
+
// src/diagrams/matrix/types.ts
|
|
20247
|
+
function computeQfdImportance(qfd) {
|
|
20248
|
+
const raw = qfd.hows.map(() => 0);
|
|
20249
|
+
for (const r5 of qfd.relationships) {
|
|
20250
|
+
if (r5.how < 0 || r5.how >= qfd.hows.length) continue;
|
|
20251
|
+
if (r5.what < 0 || r5.what >= qfd.whats.length) continue;
|
|
20252
|
+
const w = qfd.whats[r5.what].weight;
|
|
20253
|
+
raw[r5.how] += w * r5.strength;
|
|
20254
|
+
}
|
|
20255
|
+
const total = raw.reduce((acc, v) => acc + v, 0);
|
|
20256
|
+
return raw.map((importance, how) => ({
|
|
20257
|
+
how,
|
|
20258
|
+
importance,
|
|
20259
|
+
percent: total > 0 ? Math.round(importance / total * 100) : 0
|
|
20260
|
+
}));
|
|
20261
|
+
}
|
|
20262
|
+
|
|
19386
20263
|
// src/diagrams/matrix/layout.ts
|
|
19387
20264
|
var CANVAS_W = 720;
|
|
19388
20265
|
var CANVAS_H = 560;
|
|
@@ -19492,6 +20369,65 @@ function resolveLabelCollisions(points, plot, mode) {
|
|
|
19492
20369
|
}
|
|
19493
20370
|
}
|
|
19494
20371
|
}
|
|
20372
|
+
var SIPOC_COL_W = 168;
|
|
20373
|
+
var SIPOC_X0 = 24;
|
|
20374
|
+
var SIPOC_Y0 = 24;
|
|
20375
|
+
var SIPOC_HEADER_H = 40;
|
|
20376
|
+
var SIPOC_ROW_H = 44;
|
|
20377
|
+
function layoutSipoc(ast) {
|
|
20378
|
+
const rows = Math.max(1, ast.rows);
|
|
20379
|
+
const titleH = ast.title ? 40 : 0;
|
|
20380
|
+
const y0 = SIPOC_Y0 + titleH;
|
|
20381
|
+
const canvasWidth = SIPOC_X0 * 2 + SIPOC_COL_W * 5;
|
|
20382
|
+
const canvasHeight = y0 + SIPOC_HEADER_H + rows * SIPOC_ROW_H + SIPOC_Y0;
|
|
20383
|
+
return {
|
|
20384
|
+
canvasWidth,
|
|
20385
|
+
canvasHeight,
|
|
20386
|
+
x0: SIPOC_X0,
|
|
20387
|
+
y0,
|
|
20388
|
+
colW: SIPOC_COL_W,
|
|
20389
|
+
headerH: SIPOC_HEADER_H,
|
|
20390
|
+
rowH: SIPOC_ROW_H,
|
|
20391
|
+
rows
|
|
20392
|
+
};
|
|
20393
|
+
}
|
|
20394
|
+
var QFD_CELL = 46;
|
|
20395
|
+
var QFD_WHAT_LABEL_W = 190;
|
|
20396
|
+
var QFD_WEIGHT_W = 46;
|
|
20397
|
+
var QFD_HOW_LABEL_H = 130;
|
|
20398
|
+
var QFD_FOOTER_H = 64;
|
|
20399
|
+
var QFD_PAD = 24;
|
|
20400
|
+
function layoutQfd(ast) {
|
|
20401
|
+
const cols = Math.max(1, ast.cols);
|
|
20402
|
+
const rows = Math.max(1, ast.rows);
|
|
20403
|
+
const cellW = QFD_CELL;
|
|
20404
|
+
const cellH = QFD_CELL;
|
|
20405
|
+
const titleH = ast.title ? 40 : 0;
|
|
20406
|
+
const roofH = Math.ceil(cellW / 2 * cols) + 8;
|
|
20407
|
+
const whatLabelW = QFD_WHAT_LABEL_W;
|
|
20408
|
+
const weightW = QFD_WEIGHT_W;
|
|
20409
|
+
const howLabelH = QFD_HOW_LABEL_H;
|
|
20410
|
+
const footerH = QFD_FOOTER_H;
|
|
20411
|
+
const gridX0 = QFD_PAD + whatLabelW + weightW;
|
|
20412
|
+
const gridY0 = QFD_PAD + titleH + roofH + howLabelH;
|
|
20413
|
+
const canvasWidth = gridX0 + cols * cellW + QFD_PAD;
|
|
20414
|
+
const canvasHeight = gridY0 + rows * cellH + footerH + QFD_PAD;
|
|
20415
|
+
return {
|
|
20416
|
+
canvasWidth,
|
|
20417
|
+
canvasHeight,
|
|
20418
|
+
gridX0,
|
|
20419
|
+
gridY0,
|
|
20420
|
+
cellW,
|
|
20421
|
+
cellH,
|
|
20422
|
+
cols,
|
|
20423
|
+
rows,
|
|
20424
|
+
whatLabelW,
|
|
20425
|
+
weightW,
|
|
20426
|
+
howLabelH,
|
|
20427
|
+
roofH,
|
|
20428
|
+
footerH
|
|
20429
|
+
};
|
|
20430
|
+
}
|
|
19495
20431
|
function layoutMatrix(ast) {
|
|
19496
20432
|
const canvasWidth = CANVAS_W;
|
|
19497
20433
|
const canvasHeight = CANVAS_H;
|
|
@@ -19591,6 +20527,35 @@ var CSS = `
|
|
|
19591
20527
|
.sx-matrix-leader { stroke: #94a3b8; stroke-width: 0.6; opacity: 0.7; fill: none; }
|
|
19592
20528
|
.sx-matrix-legend-text { font: 500 11px sans-serif; fill: #374151; }
|
|
19593
20529
|
.sx-matrix-offchart { fill: #ea580c; }
|
|
20530
|
+
.sx-sipoc-header { font: 700 13px sans-serif; fill: #fff; text-anchor: middle; dominant-baseline: central; }
|
|
20531
|
+
.sx-sipoc-headbox { stroke: #fff; stroke-width: 1; }
|
|
20532
|
+
.sx-sipoc-cell { fill: #fff; stroke: #cbd5e1; stroke-width: 1; }
|
|
20533
|
+
.sx-sipoc-cell-alt { fill: #f8fafc; stroke: #cbd5e1; stroke-width: 1; }
|
|
20534
|
+
.sx-sipoc-process { fill: #eff6ff; stroke: #cbd5e1; stroke-width: 1; }
|
|
20535
|
+
.sx-sipoc-item { font: 500 12px sans-serif; fill: #1f2937; text-anchor: middle; dominant-baseline: central; }
|
|
20536
|
+
.sx-sipoc-step { font: 600 12px sans-serif; fill: #1e3a8a; text-anchor: middle; dominant-baseline: central; }
|
|
20537
|
+
.sx-qfd-grid { stroke: #cbd5e1; stroke-width: 1; fill: none; }
|
|
20538
|
+
.sx-qfd-cellbg { fill: #fff; }
|
|
20539
|
+
.sx-qfd-cellbg-alt { fill: #f8fafc; }
|
|
20540
|
+
.sx-qfd-what { font: 500 12px sans-serif; fill: #1f2937; text-anchor: end; dominant-baseline: central; }
|
|
20541
|
+
.sx-qfd-how { font: 500 11.5px sans-serif; fill: #1f2937; }
|
|
20542
|
+
.sx-qfd-weight { font: 600 12px sans-serif; fill: #111; text-anchor: middle; dominant-baseline: central; }
|
|
20543
|
+
.sx-qfd-weight-head { font: 600 10px sans-serif; fill: #475569; text-anchor: middle; dominant-baseline: central; }
|
|
20544
|
+
.sx-qfd-rel-strong { fill: #2563eb; }
|
|
20545
|
+
.sx-qfd-rel-medium { fill: #93c5fd; stroke: #2563eb; stroke-width: 1.4; }
|
|
20546
|
+
.sx-qfd-rel-weak { fill: none; stroke: #2563eb; stroke-width: 1.4; }
|
|
20547
|
+
.sx-qfd-roof-cell { fill: #f8fafc; stroke: #94a3b8; stroke-width: 0.8; }
|
|
20548
|
+
.sx-qfd-roof-cell-filled { fill: #eef2ff; stroke: #64748b; stroke-width: 0.9; }
|
|
20549
|
+
.sx-qfd-corr { font: 700 13px sans-serif; text-anchor: middle; dominant-baseline: central; }
|
|
20550
|
+
.sx-qfd-corr-strong-pos { fill: #15803d; }
|
|
20551
|
+
.sx-qfd-corr-pos { fill: #16a34a; }
|
|
20552
|
+
.sx-qfd-corr-neg { fill: #dc2626; }
|
|
20553
|
+
.sx-qfd-corr-strong-neg { fill: #b91c1c; }
|
|
20554
|
+
.sx-qfd-imp-band { fill: #eff6ff; stroke: #cbd5e1; stroke-width: 1; }
|
|
20555
|
+
.sx-qfd-imp-head { font: 600 11px sans-serif; fill: #1e3a8a; text-anchor: end; dominant-baseline: central; }
|
|
20556
|
+
.sx-qfd-imp-value { font: 700 13px sans-serif; fill: #1e3a8a; text-anchor: middle; dominant-baseline: central; }
|
|
20557
|
+
.sx-qfd-imp-value-top { font: 800 14px sans-serif; fill: #dc2626; text-anchor: middle; dominant-baseline: central; }
|
|
20558
|
+
.sx-qfd-dir { font: 700 13px sans-serif; fill: #475569; text-anchor: middle; dominant-baseline: central; }
|
|
19594
20559
|
`.trim();
|
|
19595
20560
|
function axisArrow() {
|
|
19596
20561
|
return el(
|
|
@@ -20377,7 +21342,339 @@ function renderTitle(ast, lay) {
|
|
|
20377
21342
|
ast.title
|
|
20378
21343
|
);
|
|
20379
21344
|
}
|
|
21345
|
+
var SIPOC_COLUMN_DEFS = [
|
|
21346
|
+
{ key: "suppliers", label: "Suppliers", color: "#2563eb" },
|
|
21347
|
+
{ key: "inputs", label: "Inputs", color: "#0891b2" },
|
|
21348
|
+
{ key: "process", label: "Process", color: "#1e3a8a" },
|
|
21349
|
+
{ key: "outputs", label: "Outputs", color: "#0891b2" },
|
|
21350
|
+
{ key: "customers", label: "Customers", color: "#2563eb" }
|
|
21351
|
+
];
|
|
21352
|
+
function wrapToLines(textStr, maxChars, maxLines) {
|
|
21353
|
+
const lines = wrapLabel(textStr, maxChars);
|
|
21354
|
+
if (lines.length <= maxLines) return lines;
|
|
21355
|
+
const kept = lines.slice(0, maxLines);
|
|
21356
|
+
kept[maxLines - 1] = kept[maxLines - 1].replace(/\s+\S*$/, "") + "\u2026";
|
|
21357
|
+
return kept;
|
|
21358
|
+
}
|
|
21359
|
+
function renderSipocAST(ast) {
|
|
21360
|
+
const sipoc = ast.sipoc ?? { suppliers: [], inputs: [], process: [], outputs: [], customers: [] };
|
|
21361
|
+
const lay = layoutSipoc(ast);
|
|
21362
|
+
const nodes = [];
|
|
21363
|
+
if (ast.title) {
|
|
21364
|
+
nodes.push(
|
|
21365
|
+
text(
|
|
21366
|
+
{ x: lay.canvasWidth / 2, y: 24, class: "sx-matrix-title", "text-anchor": "middle" },
|
|
21367
|
+
ast.title
|
|
21368
|
+
)
|
|
21369
|
+
);
|
|
21370
|
+
}
|
|
21371
|
+
const maxChars = Math.max(10, Math.floor((lay.colW - 16) / 6.4));
|
|
21372
|
+
SIPOC_COLUMN_DEFS.forEach((def, ci) => {
|
|
21373
|
+
const colX = lay.x0 + ci * lay.colW;
|
|
21374
|
+
nodes.push(
|
|
21375
|
+
rect({
|
|
21376
|
+
x: colX,
|
|
21377
|
+
y: lay.y0,
|
|
21378
|
+
width: lay.colW,
|
|
21379
|
+
height: lay.headerH,
|
|
21380
|
+
fill: def.color,
|
|
21381
|
+
class: "sx-sipoc-headbox"
|
|
21382
|
+
})
|
|
21383
|
+
);
|
|
21384
|
+
nodes.push(
|
|
21385
|
+
text(
|
|
21386
|
+
{ x: colX + lay.colW / 2, y: lay.y0 + lay.headerH / 2, class: "sx-sipoc-header" },
|
|
21387
|
+
def.label
|
|
21388
|
+
)
|
|
21389
|
+
);
|
|
21390
|
+
const items = sipoc[def.key];
|
|
21391
|
+
const isProcess = def.key === "process";
|
|
21392
|
+
const cellNodes = [];
|
|
21393
|
+
for (let r5 = 0; r5 < lay.rows; r5++) {
|
|
21394
|
+
const cellY = lay.y0 + lay.headerH + r5 * lay.rowH;
|
|
21395
|
+
const item = items[r5];
|
|
21396
|
+
const cellClass = isProcess ? "sx-sipoc-process" : r5 % 2 === 0 ? "sx-sipoc-cell" : "sx-sipoc-cell-alt";
|
|
21397
|
+
cellNodes.push(
|
|
21398
|
+
rect({ x: colX, y: cellY, width: lay.colW, height: lay.rowH, class: cellClass })
|
|
21399
|
+
);
|
|
21400
|
+
if (item) {
|
|
21401
|
+
const label = isProcess ? `${r5 + 1}. ${item}` : item;
|
|
21402
|
+
const lines = wrapToLines(label, maxChars, 2);
|
|
21403
|
+
const lineH = 14;
|
|
21404
|
+
const startY = cellY + lay.rowH / 2 - (lines.length - 1) * lineH / 2;
|
|
21405
|
+
for (let i = 0; i < lines.length; i++) {
|
|
21406
|
+
cellNodes.push(
|
|
21407
|
+
text(
|
|
21408
|
+
{
|
|
21409
|
+
x: colX + lay.colW / 2,
|
|
21410
|
+
y: startY + i * lineH,
|
|
21411
|
+
class: isProcess ? "sx-sipoc-step" : "sx-sipoc-item"
|
|
21412
|
+
},
|
|
21413
|
+
lines[i]
|
|
21414
|
+
)
|
|
21415
|
+
);
|
|
21416
|
+
}
|
|
21417
|
+
}
|
|
21418
|
+
}
|
|
21419
|
+
nodes.push(
|
|
21420
|
+
group({ class: "sx-sipoc-column", "data-column": def.key }, [
|
|
21421
|
+
title(`${def.label}: ${items.join(", ")}`),
|
|
21422
|
+
...cellNodes
|
|
21423
|
+
])
|
|
21424
|
+
);
|
|
21425
|
+
});
|
|
21426
|
+
return svgRoot(
|
|
21427
|
+
{
|
|
21428
|
+
class: "sx-matrix sx-sipoc",
|
|
21429
|
+
"data-diagram-type": "matrix",
|
|
21430
|
+
"data-mode": "sipoc",
|
|
21431
|
+
width: lay.canvasWidth,
|
|
21432
|
+
height: lay.canvasHeight,
|
|
21433
|
+
viewBox: `0 0 ${lay.canvasWidth} ${lay.canvasHeight}`,
|
|
21434
|
+
role: "graphics-document"
|
|
21435
|
+
},
|
|
21436
|
+
[
|
|
21437
|
+
title(ast.title ? `SIPOC \u2014 ${escapeXml(ast.title)}` : "SIPOC diagram"),
|
|
21438
|
+
desc(
|
|
21439
|
+
`SIPOC scoping table \u2014 ${sipoc.suppliers.length} supplier(s), ${sipoc.inputs.length} input(s), ${sipoc.process.length} process step(s), ${sipoc.outputs.length} output(s), ${sipoc.customers.length} customer(s)`
|
|
21440
|
+
),
|
|
21441
|
+
defs([el("style", {}, CSS)]),
|
|
21442
|
+
...nodes
|
|
21443
|
+
]
|
|
21444
|
+
);
|
|
21445
|
+
}
|
|
21446
|
+
var CORR_GLYPH = {
|
|
21447
|
+
"++": "\u25CF",
|
|
21448
|
+
"+": "\u25CB",
|
|
21449
|
+
"-": "\u2212",
|
|
21450
|
+
"--": "\u2715"
|
|
21451
|
+
};
|
|
21452
|
+
var CORR_CLASS = {
|
|
21453
|
+
"++": "sx-qfd-corr-strong-pos",
|
|
21454
|
+
"+": "sx-qfd-corr-pos",
|
|
21455
|
+
"-": "sx-qfd-corr-neg",
|
|
21456
|
+
"--": "sx-qfd-corr-strong-neg"
|
|
21457
|
+
};
|
|
21458
|
+
var CORR_LABEL = {
|
|
21459
|
+
"++": "strong positive",
|
|
21460
|
+
"+": "positive",
|
|
21461
|
+
"-": "negative",
|
|
21462
|
+
"--": "strong negative"
|
|
21463
|
+
};
|
|
21464
|
+
function renderQfdRelationshipSymbol(strength, cx, cy, r5) {
|
|
21465
|
+
if (strength === 9) {
|
|
21466
|
+
return group({}, [
|
|
21467
|
+
circle({ cx, cy, r: r5, fill: "none", stroke: "#2563eb", "stroke-width": 1.4 }),
|
|
21468
|
+
circle({ cx, cy, r: r5 * 0.5, class: "sx-qfd-rel-strong" })
|
|
21469
|
+
]);
|
|
21470
|
+
}
|
|
21471
|
+
if (strength === 3) {
|
|
21472
|
+
return circle({ cx, cy, r: r5, class: "sx-qfd-rel-medium" });
|
|
21473
|
+
}
|
|
21474
|
+
const t = r5 * 0.95;
|
|
21475
|
+
return polygon({
|
|
21476
|
+
points: `${cx},${cy - t} ${cx + t},${cy + t * 0.85} ${cx - t},${cy + t * 0.85}`,
|
|
21477
|
+
class: "sx-qfd-rel-weak"
|
|
21478
|
+
});
|
|
21479
|
+
}
|
|
21480
|
+
function renderQfdAST(ast) {
|
|
21481
|
+
const qfd = ast.qfd ?? { whats: [], hows: [], relationships: [], roof: [], normalize: false };
|
|
21482
|
+
const lay = layoutQfd(ast);
|
|
21483
|
+
const importance = computeQfdImportance(qfd);
|
|
21484
|
+
const maxImp = importance.reduce((m, c) => Math.max(m, c.importance), 0);
|
|
21485
|
+
const nodes = [];
|
|
21486
|
+
if (ast.title) {
|
|
21487
|
+
nodes.push(
|
|
21488
|
+
text(
|
|
21489
|
+
{ x: lay.canvasWidth / 2, y: 24, class: "sx-matrix-title", "text-anchor": "middle" },
|
|
21490
|
+
ast.title
|
|
21491
|
+
)
|
|
21492
|
+
);
|
|
21493
|
+
}
|
|
21494
|
+
const gridRight = lay.gridX0 + lay.cols * lay.cellW;
|
|
21495
|
+
const gridBottom = lay.gridY0 + lay.rows * lay.cellH;
|
|
21496
|
+
const roofNodes = [];
|
|
21497
|
+
const half = lay.cellW / 2;
|
|
21498
|
+
const roofBaseY = lay.gridY0 - lay.howLabelH;
|
|
21499
|
+
const corrByPair = /* @__PURE__ */ new Map();
|
|
21500
|
+
for (const rc of qfd.roof) {
|
|
21501
|
+
const a = Math.min(rc.a, rc.b);
|
|
21502
|
+
const b = Math.max(rc.a, rc.b);
|
|
21503
|
+
corrByPair.set(`${a},${b}`, rc.correlation);
|
|
21504
|
+
}
|
|
21505
|
+
for (let i = 0; i < lay.cols; i++) {
|
|
21506
|
+
for (let j = i + 1; j < lay.cols; j++) {
|
|
21507
|
+
const depth = j - i;
|
|
21508
|
+
const cx = lay.gridX0 + ((i + j) / 2 + 0.5) * lay.cellW;
|
|
21509
|
+
const cy = roofBaseY - (depth - 0.5) * half;
|
|
21510
|
+
const corr = corrByPair.get(`${i},${j}`);
|
|
21511
|
+
const diamond = polygon({
|
|
21512
|
+
points: `${cx},${cy - half} ${cx + half},${cy} ${cx},${cy + half} ${cx - half},${cy}`,
|
|
21513
|
+
class: corr ? "sx-qfd-roof-cell-filled" : "sx-qfd-roof-cell"
|
|
21514
|
+
});
|
|
21515
|
+
const cellChildren = [
|
|
21516
|
+
title(
|
|
21517
|
+
corr ? `${qfd.hows[i]?.label ?? `HOW ${i}`} \u2194 ${qfd.hows[j]?.label ?? `HOW ${j}`}: ${CORR_LABEL[corr]}` : `${qfd.hows[i]?.label ?? `HOW ${i}`} \u2194 ${qfd.hows[j]?.label ?? `HOW ${j}`}: no correlation`
|
|
21518
|
+
),
|
|
21519
|
+
diamond
|
|
21520
|
+
];
|
|
21521
|
+
if (corr) {
|
|
21522
|
+
cellChildren.push(
|
|
21523
|
+
text(
|
|
21524
|
+
{ x: cx, y: cy, class: `sx-qfd-corr ${CORR_CLASS[corr]}` },
|
|
21525
|
+
CORR_GLYPH[corr]
|
|
21526
|
+
)
|
|
21527
|
+
);
|
|
21528
|
+
}
|
|
21529
|
+
roofNodes.push(
|
|
21530
|
+
group(
|
|
21531
|
+
{
|
|
21532
|
+
class: "sx-qfd-roof-pair",
|
|
21533
|
+
"data-pair": `${i},${j}`,
|
|
21534
|
+
...corr ? { "data-corr": corr } : {}
|
|
21535
|
+
},
|
|
21536
|
+
cellChildren
|
|
21537
|
+
)
|
|
21538
|
+
);
|
|
21539
|
+
}
|
|
21540
|
+
}
|
|
21541
|
+
nodes.push(group({ class: "sx-qfd-roof" }, [title("Roof: engineering correlation matrix"), ...roofNodes]));
|
|
21542
|
+
qfd.hows.forEach((how, ci) => {
|
|
21543
|
+
const cx = lay.gridX0 + (ci + 0.5) * lay.cellW;
|
|
21544
|
+
const baseY = lay.gridY0 - 8;
|
|
21545
|
+
nodes.push(
|
|
21546
|
+
text(
|
|
21547
|
+
{
|
|
21548
|
+
x: cx,
|
|
21549
|
+
y: baseY,
|
|
21550
|
+
class: "sx-qfd-how",
|
|
21551
|
+
"text-anchor": "start",
|
|
21552
|
+
transform: `rotate(-60 ${cx} ${baseY})`
|
|
21553
|
+
},
|
|
21554
|
+
how.label
|
|
21555
|
+
)
|
|
21556
|
+
);
|
|
21557
|
+
if (how.direction) {
|
|
21558
|
+
const glyph = how.direction === "up" ? "\u25B2" : how.direction === "down" ? "\u25BC" : "\u25C7";
|
|
21559
|
+
nodes.push(
|
|
21560
|
+
text({ x: cx, y: lay.gridY0 - 4, class: "sx-qfd-dir" }, glyph)
|
|
21561
|
+
);
|
|
21562
|
+
}
|
|
21563
|
+
});
|
|
21564
|
+
nodes.push(
|
|
21565
|
+
text(
|
|
21566
|
+
{ x: lay.gridX0 - lay.weightW / 2, y: lay.gridY0 - 8, class: "sx-qfd-weight-head" },
|
|
21567
|
+
"Wt"
|
|
21568
|
+
)
|
|
21569
|
+
);
|
|
21570
|
+
const gridNodes = [];
|
|
21571
|
+
for (let r5 = 0; r5 < lay.rows; r5++) {
|
|
21572
|
+
const y = lay.gridY0 + r5 * lay.cellH;
|
|
21573
|
+
gridNodes.push(
|
|
21574
|
+
rect({
|
|
21575
|
+
x: lay.gridX0,
|
|
21576
|
+
y,
|
|
21577
|
+
width: lay.cols * lay.cellW,
|
|
21578
|
+
height: lay.cellH,
|
|
21579
|
+
class: r5 % 2 === 0 ? "sx-qfd-cellbg" : "sx-qfd-cellbg-alt"
|
|
21580
|
+
})
|
|
21581
|
+
);
|
|
21582
|
+
}
|
|
21583
|
+
for (let i = 0; i <= lay.cols; i++) {
|
|
21584
|
+
const x = lay.gridX0 + i * lay.cellW;
|
|
21585
|
+
gridNodes.push(line({ x1: x, y1: lay.gridY0, x2: x, y2: gridBottom, class: "sx-qfd-grid" }));
|
|
21586
|
+
}
|
|
21587
|
+
for (let j = 0; j <= lay.rows; j++) {
|
|
21588
|
+
const y = lay.gridY0 + j * lay.cellH;
|
|
21589
|
+
gridNodes.push(line({ x1: lay.gridX0, y1: y, x2: gridRight, y2: y, class: "sx-qfd-grid" }));
|
|
21590
|
+
}
|
|
21591
|
+
nodes.push(group({ class: "sx-qfd-gridlines" }, gridNodes));
|
|
21592
|
+
const whatMaxChars = Math.max(10, Math.floor((lay.whatLabelW - 12) / 6.4));
|
|
21593
|
+
qfd.whats.forEach((what, ri) => {
|
|
21594
|
+
const cy = lay.gridY0 + (ri + 0.5) * lay.cellH;
|
|
21595
|
+
const lines = wrapToLines(what.label, whatMaxChars, 2);
|
|
21596
|
+
const lineH = 13;
|
|
21597
|
+
const startY = cy - (lines.length - 1) * lineH / 2;
|
|
21598
|
+
const labelNodes = lines.map(
|
|
21599
|
+
(ln, i) => text({ x: lay.gridX0 - lay.weightW - 8, y: startY + i * lineH, class: "sx-qfd-what" }, ln)
|
|
21600
|
+
);
|
|
21601
|
+
labelNodes.push(
|
|
21602
|
+
text({ x: lay.gridX0 - lay.weightW / 2, y: cy, class: "sx-qfd-weight" }, String(what.weight))
|
|
21603
|
+
);
|
|
21604
|
+
nodes.push(
|
|
21605
|
+
group({ class: "sx-qfd-what-row", "data-what": String(ri) }, [
|
|
21606
|
+
title(`${what.label} (weight ${what.weight})`),
|
|
21607
|
+
...labelNodes
|
|
21608
|
+
])
|
|
21609
|
+
);
|
|
21610
|
+
});
|
|
21611
|
+
const relNodes = [];
|
|
21612
|
+
const symR = Math.min(lay.cellW, lay.cellH) * 0.3;
|
|
21613
|
+
for (const rel of qfd.relationships) {
|
|
21614
|
+
if (rel.how < 0 || rel.how >= lay.cols || rel.what < 0 || rel.what >= lay.rows) continue;
|
|
21615
|
+
const cx = lay.gridX0 + (rel.how + 0.5) * lay.cellW;
|
|
21616
|
+
const cy = lay.gridY0 + (rel.what + 0.5) * lay.cellH;
|
|
21617
|
+
relNodes.push(
|
|
21618
|
+
group(
|
|
21619
|
+
{ class: "sx-qfd-rel", "data-strength": String(rel.strength) },
|
|
21620
|
+
[
|
|
21621
|
+
title(`${qfd.whats[rel.what]?.label ?? ""} \xD7 ${qfd.hows[rel.how]?.label ?? ""} = ${rel.strength}`),
|
|
21622
|
+
renderQfdRelationshipSymbol(rel.strength, cx, cy, symR)
|
|
21623
|
+
]
|
|
21624
|
+
)
|
|
21625
|
+
);
|
|
21626
|
+
}
|
|
21627
|
+
nodes.push(group({ class: "sx-qfd-relationships" }, relNodes));
|
|
21628
|
+
const footerNodes = [];
|
|
21629
|
+
const impRowY = gridBottom;
|
|
21630
|
+
const impH = lay.footerH;
|
|
21631
|
+
footerNodes.push(
|
|
21632
|
+
rect({ x: lay.gridX0, y: impRowY, width: lay.cols * lay.cellW, height: impH, class: "sx-qfd-imp-band" })
|
|
21633
|
+
);
|
|
21634
|
+
for (let i = 1; i < lay.cols; i++) {
|
|
21635
|
+
const x = lay.gridX0 + i * lay.cellW;
|
|
21636
|
+
footerNodes.push(line({ x1: x, y1: impRowY, x2: x, y2: impRowY + impH, class: "sx-qfd-grid" }));
|
|
21637
|
+
}
|
|
21638
|
+
const footerLabel = qfd.normalize ? "Importance %" : "Technical importance \u03A3(wt\xD7rel)";
|
|
21639
|
+
footerNodes.push(
|
|
21640
|
+
text({ x: lay.gridX0 - 8, y: impRowY + impH / 2, class: "sx-qfd-imp-head" }, footerLabel)
|
|
21641
|
+
);
|
|
21642
|
+
importance.forEach((col) => {
|
|
21643
|
+
const cx = lay.gridX0 + (col.how + 0.5) * lay.cellW;
|
|
21644
|
+
const cy = impRowY + impH / 2;
|
|
21645
|
+
const isTop = col.importance === maxImp && maxImp > 0;
|
|
21646
|
+
const display = qfd.normalize ? `${col.percent}%` : String(col.importance);
|
|
21647
|
+
footerNodes.push(
|
|
21648
|
+
text(
|
|
21649
|
+
{ x: cx, y: cy, class: isTop ? "sx-qfd-imp-value-top" : "sx-qfd-imp-value" },
|
|
21650
|
+
display
|
|
21651
|
+
)
|
|
21652
|
+
);
|
|
21653
|
+
});
|
|
21654
|
+
nodes.push(group({ class: "sx-qfd-importance" }, [title("Computed technical importance per engineering characteristic"), ...footerNodes]));
|
|
21655
|
+
return svgRoot(
|
|
21656
|
+
{
|
|
21657
|
+
class: "sx-matrix sx-qfd",
|
|
21658
|
+
"data-diagram-type": "matrix",
|
|
21659
|
+
"data-mode": "qfd",
|
|
21660
|
+
width: lay.canvasWidth,
|
|
21661
|
+
height: lay.canvasHeight,
|
|
21662
|
+
viewBox: `0 0 ${lay.canvasWidth} ${lay.canvasHeight}`,
|
|
21663
|
+
role: "graphics-document"
|
|
21664
|
+
},
|
|
21665
|
+
[
|
|
21666
|
+
title(ast.title ? `QFD House of Quality \u2014 ${escapeXml(ast.title)}` : "QFD House of Quality"),
|
|
21667
|
+
desc(
|
|
21668
|
+
`QFD House of Quality \u2014 ${qfd.whats.length} customer requirement(s), ${qfd.hows.length} engineering characteristic(s), ${qfd.relationships.length} relationship(s); technical importance computed per column`
|
|
21669
|
+
),
|
|
21670
|
+
defs([el("style", {}, CSS)]),
|
|
21671
|
+
...nodes
|
|
21672
|
+
]
|
|
21673
|
+
);
|
|
21674
|
+
}
|
|
20380
21675
|
function renderMatrixAST(ast) {
|
|
21676
|
+
if (ast.mode === "sipoc") return renderSipocAST(ast);
|
|
21677
|
+
if (ast.mode === "qfd") return renderQfdAST(ast);
|
|
20381
21678
|
const lay = layoutMatrix(ast);
|
|
20382
21679
|
const needsLegendSpace = lay.categories.length > 0 || ast.mode === "correlation";
|
|
20383
21680
|
const extraWidth = needsLegendSpace && lay.plot.x0 + lay.plot.w + 140 > lay.canvasWidth ? 160 : 0;
|
|
@@ -20457,7 +21754,7 @@ function stripComment6(s) {
|
|
|
20457
21754
|
}
|
|
20458
21755
|
return out;
|
|
20459
21756
|
}
|
|
20460
|
-
function
|
|
21757
|
+
function unquote6(v) {
|
|
20461
21758
|
const t = v.trim();
|
|
20462
21759
|
if (t.length >= 2 && t.startsWith('"') && t.endsWith('"')) return t.slice(1, -1);
|
|
20463
21760
|
return t;
|
|
@@ -20546,7 +21843,7 @@ function parseErd(text2) {
|
|
|
20546
21843
|
continue;
|
|
20547
21844
|
}
|
|
20548
21845
|
if (lower.startsWith("title:")) {
|
|
20549
|
-
title2 =
|
|
21846
|
+
title2 = unquote6(t.slice("title:".length).trim());
|
|
20550
21847
|
i++;
|
|
20551
21848
|
continue;
|
|
20552
21849
|
}
|
|
@@ -20746,7 +22043,7 @@ function parseAttributeLine(raw, lineNumber, tableId) {
|
|
|
20746
22043
|
let comment;
|
|
20747
22044
|
const colonIdx = findUnquotedChar(s, ":");
|
|
20748
22045
|
if (colonIdx >= 0) {
|
|
20749
|
-
comment =
|
|
22046
|
+
comment = unquote6(s.slice(colonIdx + 1).trim());
|
|
20750
22047
|
s = s.slice(0, colonIdx).trim();
|
|
20751
22048
|
}
|
|
20752
22049
|
let fkTarget;
|
|
@@ -20798,7 +22095,7 @@ function parseRefLine(raw, lineNumber, outRefs) {
|
|
|
20798
22095
|
let label;
|
|
20799
22096
|
const colonIdx = findUnquotedChar(s, ":");
|
|
20800
22097
|
if (colonIdx >= 0) {
|
|
20801
|
-
label =
|
|
22098
|
+
label = unquote6(s.slice(colonIdx + 1).trim());
|
|
20802
22099
|
s = s.slice(0, colonIdx).trim();
|
|
20803
22100
|
}
|
|
20804
22101
|
const merm = /^(\S+)\s+([}|o][o|]|\|\||\|o)(\.\.|--|~~)([}|o][{|]|\|\||o\|)\s+(\S+)$/.exec(s);
|
|
@@ -21247,7 +22544,7 @@ function sideAnchor(e, side, col) {
|
|
|
21247
22544
|
}
|
|
21248
22545
|
|
|
21249
22546
|
// src/diagrams/erd/renderer.ts
|
|
21250
|
-
function
|
|
22547
|
+
function buildCss9(t) {
|
|
21251
22548
|
return `
|
|
21252
22549
|
.lt-erd { font-family: system-ui, -apple-system, sans-serif; }
|
|
21253
22550
|
.lt-erd-title { font: bold 16px sans-serif; fill: ${t.text}; }
|
|
@@ -21557,7 +22854,7 @@ function renderEdge5(edge) {
|
|
|
21557
22854
|
function renderErdAst(result, themeName = "default") {
|
|
21558
22855
|
const theme = resolveBaseTheme(themeName);
|
|
21559
22856
|
const { entities, edges, width, height, ast } = result;
|
|
21560
|
-
const cssBlock = el("style", {},
|
|
22857
|
+
const cssBlock = el("style", {}, buildCss9(theme));
|
|
21561
22858
|
const titleNode = title(ast.title ?? "Schematex ERD");
|
|
21562
22859
|
const descNode = desc(
|
|
21563
22860
|
`Entity-Relationship Diagram with ${entities.length} entities and ${edges.length} relationships.`
|
|
@@ -21638,7 +22935,7 @@ function stripComment7(s) {
|
|
|
21638
22935
|
}
|
|
21639
22936
|
return out;
|
|
21640
22937
|
}
|
|
21641
|
-
function
|
|
22938
|
+
function unquote7(v) {
|
|
21642
22939
|
const t = v.trim();
|
|
21643
22940
|
if (t.length >= 2 && t.startsWith('"') && t.endsWith('"')) return t.slice(1, -1);
|
|
21644
22941
|
return t;
|
|
@@ -21880,7 +23177,7 @@ function parseBreadboard(text2) {
|
|
|
21880
23177
|
continue;
|
|
21881
23178
|
}
|
|
21882
23179
|
if (lower.startsWith("title:")) {
|
|
21883
|
-
title2 =
|
|
23180
|
+
title2 = unquote7(line2.text.slice("title:".length).trim());
|
|
21884
23181
|
i++;
|
|
21885
23182
|
continue;
|
|
21886
23183
|
}
|
|
@@ -22627,7 +23924,7 @@ var WIRE_COLOR_MAP = {
|
|
|
22627
23924
|
brown: "#78350f",
|
|
22628
23925
|
grey: "#64748b"
|
|
22629
23926
|
};
|
|
22630
|
-
function
|
|
23927
|
+
function buildCss10(t) {
|
|
22631
23928
|
return `
|
|
22632
23929
|
.lt-bb { font-family: system-ui, -apple-system, sans-serif; }
|
|
22633
23930
|
.lt-bb-title { font: 600 16px sans-serif; fill: ${t.text}; }
|
|
@@ -22775,7 +24072,7 @@ function renderWire(lw) {
|
|
|
22775
24072
|
}
|
|
22776
24073
|
function renderBreadboardLayout(layout, config) {
|
|
22777
24074
|
const theme = resolveBaseTheme(config?.theme ?? "default");
|
|
22778
|
-
const css =
|
|
24075
|
+
const css = buildCss10(theme);
|
|
22779
24076
|
const titleStr = layout.ast.title ?? "Breadboard";
|
|
22780
24077
|
const titleNode = layout.ast.title ? text({ x: BB_CONST.MARGIN, y: 22, class: "lt-bb-title" }, layout.ast.title) : "";
|
|
22781
24078
|
const substrate = renderSubstrate(layout.substrate);
|
|
@@ -22834,7 +24131,7 @@ var BpmnParseError = class extends Error {
|
|
|
22834
24131
|
}
|
|
22835
24132
|
line;
|
|
22836
24133
|
};
|
|
22837
|
-
function
|
|
24134
|
+
function unquote8(s) {
|
|
22838
24135
|
return s.replace(/^"|"$/g, "").replace(/\\"/g, '"');
|
|
22839
24136
|
}
|
|
22840
24137
|
function takeQuoted(rest) {
|
|
@@ -23004,7 +24301,7 @@ function parsePool(lines, startIdx, pools, lanesById, events, activities, gatewa
|
|
|
23004
24301
|
const ln = lines[startIdx];
|
|
23005
24302
|
const m = ln.text.match(/^pool\s+("(?:\\.|[^"\\])*")\s*(.*)$/);
|
|
23006
24303
|
if (!m) throw new BpmnParseError("malformed pool declaration", ln.no);
|
|
23007
|
-
const label =
|
|
24304
|
+
const label = unquote8(m[1]);
|
|
23008
24305
|
const tail = m[2].trim();
|
|
23009
24306
|
let blackbox = false;
|
|
23010
24307
|
let hasBrace = false;
|
|
@@ -23056,7 +24353,7 @@ function parseLane(lines, startIdx, pool, lanesById, events, activities, gateway
|
|
|
23056
24353
|
const ln = lines[startIdx];
|
|
23057
24354
|
const m = ln.text.match(/^lane\s+("(?:\\.|[^"\\])*")\s*\{?\s*$/);
|
|
23058
24355
|
if (!m) throw new BpmnParseError("malformed lane declaration", ln.no);
|
|
23059
|
-
const label =
|
|
24356
|
+
const label = unquote8(m[1]);
|
|
23060
24357
|
const hasBrace = ln.text.endsWith("{");
|
|
23061
24358
|
if (pool.blackbox) {
|
|
23062
24359
|
throw new BpmnParseError(
|
|
@@ -25141,7 +26438,7 @@ function buildGraph2(network2) {
|
|
|
25141
26438
|
}
|
|
25142
26439
|
return { incoming, outgoing, inputVars, outputVars };
|
|
25143
26440
|
}
|
|
25144
|
-
function
|
|
26441
|
+
function assignLayers2(network2, graph) {
|
|
25145
26442
|
const layer = /* @__PURE__ */ new Map();
|
|
25146
26443
|
const visiting = /* @__PURE__ */ new Set();
|
|
25147
26444
|
const visit = (id) => {
|
|
@@ -25165,7 +26462,7 @@ function layoutNetwork3(network2, originX, originY) {
|
|
|
25165
26462
|
const graph = buildGraph2(network2);
|
|
25166
26463
|
const sizes = /* @__PURE__ */ new Map();
|
|
25167
26464
|
for (const b of network2.blocks) sizes.set(b.id, computeBlockSize(b));
|
|
25168
|
-
const layerOf =
|
|
26465
|
+
const layerOf = assignLayers2(network2, graph);
|
|
25169
26466
|
const maxLayer = Math.max(0, ...Array.from(layerOf.values()));
|
|
25170
26467
|
const byLayer = Array.from({ length: maxLayer + 1 }, () => []);
|
|
25171
26468
|
for (const b of network2.blocks) byLayer[layerOf.get(b.id)].push(b.id);
|
|
@@ -26602,7 +27899,7 @@ function normalizeHeader(text2, type) {
|
|
|
26602
27899
|
}
|
|
26603
27900
|
return text2;
|
|
26604
27901
|
}
|
|
26605
|
-
function
|
|
27902
|
+
function preprocess9(text2) {
|
|
26606
27903
|
const { data, body } = parseFrontmatter(stripCodeFences(text2));
|
|
26607
27904
|
if (!data.title) return body;
|
|
26608
27905
|
const safeTitle = data.title.replace(/"/g, '\\"');
|
|
@@ -26617,7 +27914,7 @@ function preprocess8(text2) {
|
|
|
26617
27914
|
return body;
|
|
26618
27915
|
}
|
|
26619
27916
|
function parse(text2, config) {
|
|
26620
|
-
const prepared0 =
|
|
27917
|
+
const prepared0 = preprocess9(text2);
|
|
26621
27918
|
const plugin = detectPlugin(prepared0, config);
|
|
26622
27919
|
const prepared = normalizeHeader(prepared0, plugin.type);
|
|
26623
27920
|
if (plugin.parse) return plugin.parse(prepared);
|
|
@@ -26628,7 +27925,7 @@ function parse(text2, config) {
|
|
|
26628
27925
|
function parseResult(text2, config) {
|
|
26629
27926
|
let plugin;
|
|
26630
27927
|
try {
|
|
26631
|
-
const prepared0 =
|
|
27928
|
+
const prepared0 = preprocess9(text2);
|
|
26632
27929
|
plugin = detectPlugin(prepared0, config);
|
|
26633
27930
|
if (!plugin.parse) {
|
|
26634
27931
|
throw new Error(
|
|
@@ -26664,7 +27961,7 @@ function runLint(plugin, prepared) {
|
|
|
26664
27961
|
}
|
|
26665
27962
|
function render(text2, config) {
|
|
26666
27963
|
if (config?.mode === "preview") return renderResult(text2, config).svg;
|
|
26667
|
-
const prepared0 =
|
|
27964
|
+
const prepared0 = preprocess9(text2);
|
|
26668
27965
|
const plugin = detectPlugin(prepared0, config);
|
|
26669
27966
|
const prepared = normalizeHeader(prepared0, plugin.type);
|
|
26670
27967
|
return renderWithPlugin(prepared, plugin, config);
|
|
@@ -26672,7 +27969,7 @@ function render(text2, config) {
|
|
|
26672
27969
|
function renderResult(text2, config) {
|
|
26673
27970
|
let plugin;
|
|
26674
27971
|
try {
|
|
26675
|
-
const prepared0 =
|
|
27972
|
+
const prepared0 = preprocess9(text2);
|
|
26676
27973
|
plugin = detectPlugin(prepared0, config);
|
|
26677
27974
|
const prepared = normalizeHeader(prepared0, plugin.type);
|
|
26678
27975
|
const svg = renderWithPlugin(prepared, plugin, config);
|
|
@@ -26712,5 +28009,5 @@ function renderWithPlugin(prepared, plugin, config) {
|
|
|
26712
28009
|
}
|
|
26713
28010
|
|
|
26714
28011
|
export { GEOMETRY, bowtie2 as bowtie, decisiontree, drawDeviceIcon, faulttree, iconSize, network, parse, parseResult, pert, petri, pid, prisma, render, renderEquip, renderPreview, renderResult, sequence, state, timeline, umlclass, usecase };
|
|
26715
|
-
//# sourceMappingURL=chunk-
|
|
26716
|
-
//# sourceMappingURL=chunk-
|
|
28012
|
+
//# sourceMappingURL=chunk-IFNNV54X.js.map
|
|
28013
|
+
//# sourceMappingURL=chunk-IFNNV54X.js.map
|