schematex 0.9.5 → 0.9.6

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.
@@ -9258,8 +9258,8 @@ function parseHeaderLine(ln, ast) {
9258
9258
  }
9259
9259
  case "layout": {
9260
9260
  const l = value.toLowerCase();
9261
- if (l !== "network" && l !== "timescaled" && l !== "aoa") {
9262
- throw new PertParseError(`layout must be network, timescaled, or aoa (got '${value}')`, ln.line);
9261
+ if (l !== "network" && l !== "timescaled" && l !== "aoa" && l !== "gantt") {
9262
+ throw new PertParseError(`layout must be network, timescaled, aoa, or gantt (got '${value}')`, ln.line);
9263
9263
  }
9264
9264
  ast.layout = l;
9265
9265
  return true;
@@ -9270,6 +9270,26 @@ function parseHeaderLine(ln, ast) {
9270
9270
  case "show-sentinels":
9271
9271
  ast.showSentinels = /^(true|yes|on)$/i.test(value);
9272
9272
  return true;
9273
+ case "start":
9274
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
9275
+ throw new PertParseError(`start must be a date 'YYYY-MM-DD' (got '${value}')`, ln.line);
9276
+ }
9277
+ ast.start = value;
9278
+ return true;
9279
+ case "calendar": {
9280
+ const c = value.toLowerCase();
9281
+ if (c !== "continuous" && c !== "5day" && c !== "7day") {
9282
+ throw new PertParseError(`calendar must be continuous, 7day, or 5day (got '${value}')`, ln.line);
9283
+ }
9284
+ ast.calendar = c === "5day" ? "5day" : "continuous";
9285
+ return true;
9286
+ }
9287
+ case "today":
9288
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
9289
+ throw new PertParseError(`today must be a date 'YYYY-MM-DD' (got '${value}')`, ln.line);
9290
+ }
9291
+ ast.today = value;
9292
+ return true;
9273
9293
  default:
9274
9294
  return false;
9275
9295
  }
@@ -9334,7 +9354,7 @@ function parseDepRef(raw, unit, lineNo) {
9334
9354
  }
9335
9355
  throw new PertParseError(`cannot parse predecessor reference '${ref}'`, lineNo);
9336
9356
  }
9337
- var KEY_RE = /\b(duration|after|tags|class|lane)\s*:/gi;
9357
+ var KEY_RE = /\b(duration|after|tags|class|lane|progress|done)\s*:/gi;
9338
9358
  function parseTaskLine(ln, ast) {
9339
9359
  const head = ln.text.match(/^task\s+(\S+)\s*(.*)$/i);
9340
9360
  if (!head) {
@@ -9409,6 +9429,13 @@ function parseTaskLine(ln, ast) {
9409
9429
  const tags = values.tags ? values.tags.split(",").map((t) => t.trim()).filter(Boolean) : [];
9410
9430
  const className = values.class ? values.class.trim() : void 0;
9411
9431
  const lane = values.lane ? stripQuotes3(values.lane) : void 0;
9432
+ const progressRaw = values.progress ?? values.done;
9433
+ let progress;
9434
+ if (progressRaw !== void 0 && progressRaw !== "") {
9435
+ const pct = progressRaw.trim().replace(/%$/, "");
9436
+ const n = parseNumber(pct, ln.line, "progress");
9437
+ progress = Math.max(0, Math.min(100, n));
9438
+ }
9412
9439
  const task = {
9413
9440
  id,
9414
9441
  label,
@@ -9422,6 +9449,7 @@ function parseTaskLine(ln, ast) {
9422
9449
  if (variance !== void 0) task.variance = variance;
9423
9450
  if (className) task.className = className;
9424
9451
  if (lane) task.lane = lane;
9452
+ if (progress !== void 0) task.progress = progress;
9425
9453
  ast.tasks.push(task);
9426
9454
  }
9427
9455
  function parsePert(src) {
@@ -9432,18 +9460,21 @@ function parsePert(src) {
9432
9460
  layout: "network",
9433
9461
  criticalTolerance: 0,
9434
9462
  showSentinels: false,
9463
+ calendar: "continuous",
9435
9464
  tasks: [],
9436
9465
  warnings: []
9437
9466
  };
9438
9467
  const lines = preprocess8(src);
9439
9468
  if (lines.length === 0) {
9440
- throw new PertParseError("empty document \u2014 expected 'pert' header", 1);
9469
+ throw new PertParseError("empty document \u2014 expected 'pert' or 'gantt' header", 1);
9441
9470
  }
9442
9471
  const first = lines[0];
9443
- if (!/^pert\b/i.test(first.text)) {
9444
- throw new PertParseError(`first non-comment line must start with 'pert' (got: ${first.text})`, first.line);
9472
+ if (!/^(pert|gantt)\b/i.test(first.text)) {
9473
+ throw new PertParseError(`first non-comment line must start with 'pert' or 'gantt' (got: ${first.text})`, first.line);
9445
9474
  }
9446
- const inlineTitle = first.text.replace(/^pert\b/i, "").trim();
9475
+ const isGanttHeader = /^gantt\b/i.test(first.text);
9476
+ if (isGanttHeader) ast.layout = "gantt";
9477
+ const inlineTitle = first.text.replace(/^(pert|gantt)\b/i, "").trim();
9447
9478
  if (inlineTitle) {
9448
9479
  const m = inlineTitle.match(/^"([^"]+)"$/) || inlineTitle.match(/^'([^']+)'$/);
9449
9480
  if (m) ast.title = m[1];
@@ -10523,10 +10554,381 @@ function layoutPert(ast, schedule) {
10523
10554
  return layoutNetwork(ast, sched);
10524
10555
  }
10525
10556
 
10526
- // src/diagrams/pert/renderer.ts
10557
+ // src/diagrams/pert/gantt.ts
10558
+ var PALETTES = {
10559
+ default: {
10560
+ bar: "#cfe0f5",
10561
+ barStroke: "#5b85c0",
10562
+ barDone: "#5b85c0",
10563
+ critBar: "#fbe6e0",
10564
+ critStroke: "#d2604f",
10565
+ critDone: "#d2604f",
10566
+ milestone: "#3c5a80",
10567
+ text: "#234567",
10568
+ subtext: "#728198",
10569
+ axis: "#8497ad",
10570
+ grid: "#e3eaf3",
10571
+ sectionBand: "#eef3fa",
10572
+ sectionText: "#41597a",
10573
+ dep: "#9fb0c6",
10574
+ today: "#d2604f"
10575
+ },
10576
+ monochrome: {
10577
+ bar: "#ffffff",
10578
+ barStroke: "#000000",
10579
+ barDone: "#9a9a9a",
10580
+ critBar: "#ffffff",
10581
+ critStroke: "#000000",
10582
+ critDone: "#000000",
10583
+ milestone: "#000000",
10584
+ text: "#000000",
10585
+ subtext: "#555555",
10586
+ axis: "#000000",
10587
+ grid: "#dddddd",
10588
+ sectionBand: "#f2f2f2",
10589
+ sectionText: "#000000",
10590
+ dep: "#888888",
10591
+ today: "#000000"
10592
+ },
10593
+ dark: {
10594
+ bar: "#37506e",
10595
+ barStroke: "#89b4fa",
10596
+ barDone: "#89b4fa",
10597
+ critBar: "#5a3540",
10598
+ critStroke: "#f38ba8",
10599
+ critDone: "#f38ba8",
10600
+ milestone: "#bac2de",
10601
+ text: "#cdd6f4",
10602
+ subtext: "#9399b2",
10603
+ axis: "#7f849c",
10604
+ grid: "#313244",
10605
+ sectionBand: "#272838",
10606
+ sectionText: "#bac2de",
10607
+ dep: "#6c7086",
10608
+ today: "#f38ba8"
10609
+ }
10610
+ };
10611
+ function ymdToDays(y, m, d) {
10612
+ const yy = m <= 2 ? y - 1 : y;
10613
+ const era = Math.floor((yy >= 0 ? yy : yy - 399) / 400);
10614
+ const yoe = yy - era * 400;
10615
+ const doy = Math.floor((153 * (m > 2 ? m - 3 : m + 9) + 2) / 5) + d - 1;
10616
+ const doe = yoe * 365 + Math.floor(yoe / 4) - Math.floor(yoe / 100) + doy;
10617
+ return era * 146097 + doe - 719468;
10618
+ }
10619
+ function daysToYmd(z) {
10620
+ const zz = z + 719468;
10621
+ const era = Math.floor((zz >= 0 ? zz : zz - 146096) / 146097);
10622
+ const doe = zz - era * 146097;
10623
+ const yoe = Math.floor((doe - Math.floor(doe / 1460) + Math.floor(doe / 36524) - Math.floor(doe / 146096)) / 365);
10624
+ const y = yoe + era * 400;
10625
+ const doy = doe - (365 * yoe + Math.floor(yoe / 4) - Math.floor(yoe / 100));
10626
+ const mp = Math.floor((5 * doy + 2) / 153);
10627
+ const d = doy - Math.floor((153 * mp + 2) / 5) + 1;
10628
+ const m = mp < 10 ? mp + 3 : mp - 9;
10629
+ return { y: m <= 2 ? y + 1 : y, m, d };
10630
+ }
10631
+ function parseISODays(s) {
10632
+ const [y, m, d] = s.split("-").map(Number);
10633
+ return ymdToDays(y, m, d);
10634
+ }
10635
+ function dow(days) {
10636
+ return (days % 7 + 4 + 7e3) % 7;
10637
+ }
10638
+ function isWeekend(days) {
10639
+ const w = dow(days);
10640
+ return w === 0 || w === 6;
10641
+ }
10642
+ function advanceWorking(startDays, n) {
10643
+ let cur = startDays;
10644
+ let left = Math.round(n);
10645
+ const step = left >= 0 ? 1 : -1;
10646
+ left = Math.abs(left);
10647
+ while (left > 0) {
10648
+ cur += step;
10649
+ if (!isWeekend(cur)) left--;
10650
+ }
10651
+ return cur;
10652
+ }
10653
+ var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
10654
+ function fmtDate(days) {
10655
+ const { m, d } = daysToYmd(days);
10656
+ return `${MONTHS[m - 1]} ${d}`;
10657
+ }
10658
+ var G = {
10659
+ PAD: 20,
10660
+ TITLE_H: 30,
10661
+ AXIS_H: 26,
10662
+ ROW_H: 28,
10663
+ BAR_H: 15,
10664
+ SECTION_H: 24,
10665
+ LABEL_MIN: 120,
10666
+ LABEL_MAX: 250,
10667
+ CHAR_W: 6.6,
10668
+ LABEL_PAD: 12,
10669
+ TARGET_CHART_W: 740,
10670
+ MIN_PX_UNIT: 5,
10671
+ MAX_PX_UNIT: 56,
10672
+ FOOTER_H: 28
10673
+ };
10674
+ function renderGantt2(ast, schedule, config) {
10675
+ const base = resolveBaseTheme(config?.theme ?? "default");
10676
+ const themeName = (config?.theme ?? "default") in PALETTES ? config.theme : "default";
10677
+ const P = PALETTES[themeName];
10678
+ const tasks = ast.tasks;
10679
+ const span = Math.max(schedule.projectDuration, 1);
10680
+ const unitToDay = ast.unit === "weeks" ? 7 : 1;
10681
+ const unitToWork = ast.unit === "weeks" ? 5 : 1;
10682
+ const pxUnit = Math.max(G.MIN_PX_UNIT, Math.min(G.MAX_PX_UNIT, G.TARGET_CHART_W / span));
10683
+ const longest = tasks.reduce((mx, t) => Math.max(mx, (t.label ?? t.id).length), 4);
10684
+ const labelW = Math.max(G.LABEL_MIN, Math.min(G.LABEL_MAX, Math.ceil(longest * G.CHAR_W) + 2 * G.LABEL_PAD));
10685
+ const chartX = G.PAD + labelW + 8;
10686
+ const chartW = Math.ceil(span * pxUnit);
10687
+ const hasTitle = !!ast.title;
10688
+ const topY = G.PAD + (hasTitle ? G.TITLE_H : 0);
10689
+ const axisBottom = topY + G.AXIS_H;
10690
+ const rows = [];
10691
+ let cursorY = axisBottom + 6;
10692
+ let lastLane = "\0";
10693
+ for (const t of tasks) {
10694
+ const lane = t.lane;
10695
+ if (lane !== lastLane && lane !== void 0) {
10696
+ rows.push({ kind: "section", y: cursorY, h: G.SECTION_H, label: lane });
10697
+ cursorY += G.SECTION_H;
10698
+ lastLane = lane;
10699
+ } else if (lane === void 0) {
10700
+ lastLane = void 0;
10701
+ }
10702
+ rows.push({ kind: "task", y: cursorY, h: G.ROW_H, task: t });
10703
+ cursorY += G.ROW_H;
10704
+ }
10705
+ const chartBottom = cursorY;
10706
+ const totalH = chartBottom + G.FOOTER_H + G.PAD;
10707
+ const totalW = chartX + chartW + G.PAD;
10708
+ const startDays = ast.start ? parseISODays(ast.start) : void 0;
10709
+ const xAt = (unitOffset) => chartX + unitOffset * pxUnit;
10710
+ const offsetToDate = (u) => {
10711
+ if (startDays === void 0) return void 0;
10712
+ return ast.calendar === "5day" ? advanceWorking(startDays, u * unitToWork) : startDays + Math.round(u * unitToDay);
10713
+ };
10714
+ const niceStep2 = (s) => {
10715
+ const raw = s / 9;
10716
+ const candidates = [1, 2, 5, 7, 10, 14, 20, 25, 50, 100];
10717
+ for (const c of candidates) if (c >= raw) return c;
10718
+ return Math.ceil(raw / 50) * 50;
10719
+ };
10720
+ const step = niceStep2(span);
10721
+ const styleBlock = el("style", {}, `
10722
+ .sx-gantt-bg { fill: ${base.bg}; }
10723
+ .sx-gantt-title { fill: ${P.text}; font-size: 15px; font-weight: 700; }
10724
+ .sx-gantt-grid { stroke: ${P.grid}; stroke-width: 1; }
10725
+ .sx-gantt-axis-tick { stroke: ${P.axis}; stroke-width: 1; }
10726
+ .sx-gantt-axis-text { fill: ${P.subtext}; font-size: 9.5px; }
10727
+ .sx-gantt-axis-base { stroke: ${P.axis}; stroke-width: 1.2; }
10728
+ .sx-gantt-section { fill: ${P.sectionBand}; }
10729
+ .sx-gantt-section-text { fill: ${P.sectionText}; font-size: 11px; font-weight: 700; }
10730
+ .sx-gantt-rowlabel { fill: ${P.text}; font-size: 11.5px; }
10731
+ .sx-gantt-rowlabel.crit { fill: ${P.critStroke}; font-weight: 600; }
10732
+ .sx-gantt-bar { fill: ${P.bar}; stroke: ${P.barStroke}; stroke-width: 1; }
10733
+ .sx-gantt-bar[data-critical="true"] { fill: ${P.critBar}; stroke: ${P.critStroke}; stroke-width: 1.4; }
10734
+ .sx-gantt-done { fill: ${P.barDone}; }
10735
+ .sx-gantt-done[data-critical="true"] { fill: ${P.critDone}; }
10736
+ .sx-gantt-ms { fill: ${P.milestone}; stroke: ${P.milestone}; }
10737
+ .sx-gantt-ms[data-critical="true"] { fill: ${P.critStroke}; stroke: ${P.critStroke}; }
10738
+ .sx-gantt-dep { fill: none; stroke: ${P.dep}; stroke-width: 1; }
10739
+ .sx-gantt-barlabel { fill: ${P.subtext}; font-size: 9.5px; }
10740
+ .sx-gantt-today { stroke: ${P.today}; stroke-width: 1.3; stroke-dasharray: 4 3; }
10741
+ .sx-gantt-today-text { fill: ${P.today}; font-size: 9.5px; font-weight: 700; }
10742
+ .sx-gantt-footer { fill: ${P.subtext}; font-size: 10px; }
10743
+ `.trim());
10744
+ const children = [
10745
+ title(`Gantt chart${ast.title ? " \u2014 " + ast.title : ""}`),
10746
+ desc(summarise(ast, schedule)),
10747
+ styleBlock,
10748
+ rect({ x: 0, y: 0, width: totalW, height: totalH, class: "sx-gantt-bg" })
10749
+ ];
10750
+ if (hasTitle) {
10751
+ children.push(text({ x: G.PAD, y: G.PAD + 18, class: "sx-gantt-title" }, ast.title));
10752
+ }
10753
+ const bandEls = [];
10754
+ for (const r7 of rows) {
10755
+ if (r7.kind === "section") {
10756
+ bandEls.push(rect({ x: G.PAD, y: r7.y, width: totalW - 2 * G.PAD, height: r7.h, class: "sx-gantt-section" }));
10757
+ bandEls.push(text({ x: G.PAD + 8, y: r7.y + r7.h / 2 + 4, class: "sx-gantt-section-text" }, r7.label));
10758
+ }
10759
+ }
10760
+ children.push(group({ class: "sx-gantt-sections" }, bandEls));
10761
+ const axisEls = [];
10762
+ for (let u = 0; u <= span + 1e-4; u += step) {
10763
+ const x = xAt(u);
10764
+ axisEls.push(line({ class: "sx-gantt-grid", x1: x, y1: axisBottom, x2: x, y2: chartBottom }));
10765
+ axisEls.push(line({ class: "sx-gantt-axis-tick", x1: x, y1: axisBottom - 5, x2: x, y2: axisBottom }));
10766
+ const cal = offsetToDate(u);
10767
+ const label = cal !== void 0 ? fmtDate(cal) : fmtVal(u);
10768
+ axisEls.push(text({ x, y: axisBottom - 9, class: "sx-gantt-axis-text", "text-anchor": "middle" }, label));
10769
+ }
10770
+ axisEls.push(line({ class: "sx-gantt-axis-base", x1: chartX, y1: axisBottom, x2: chartX + chartW, y2: axisBottom }));
10771
+ children.push(group({ class: "sx-gantt-axis" }, axisEls));
10772
+ const labelEls = [];
10773
+ for (const r7 of rows) {
10774
+ if (r7.kind !== "task" || !r7.task) continue;
10775
+ const c = schedule.computed.get(r7.task.id);
10776
+ const crit = c?.critical ?? false;
10777
+ labelEls.push(
10778
+ text(
10779
+ { x: G.PAD + 4, y: r7.y + r7.h / 2 + 4, class: `sx-gantt-rowlabel${crit ? " crit" : ""}` },
10780
+ clip(r7.task.label ?? r7.task.id, Math.floor(labelW / G.CHAR_W))
10781
+ )
10782
+ );
10783
+ }
10784
+ children.push(group({ class: "sx-gantt-rowlabels" }, labelEls));
10785
+ const rowOf = /* @__PURE__ */ new Map();
10786
+ for (const r7 of rows) if (r7.kind === "task" && r7.task) rowOf.set(r7.task.id, r7);
10787
+ const depEls = [];
10788
+ for (const t of tasks) {
10789
+ const tr = rowOf.get(t.id);
10790
+ const tc = schedule.computed.get(t.id);
10791
+ if (!tr || !tc) continue;
10792
+ const succMidY = tr.y + tr.h / 2;
10793
+ const succX = xAt(tc.es);
10794
+ for (const dep of t.deps) {
10795
+ const pr = rowOf.get(dep.pred);
10796
+ const pc2 = schedule.computed.get(dep.pred);
10797
+ if (!pr || !pc2) continue;
10798
+ const predMidY = pr.y + pr.h / 2;
10799
+ const predX = xAt(pc2.ef);
10800
+ const midX = Math.max(predX + 8, succX - 10);
10801
+ depEls.push(path({
10802
+ class: "sx-gantt-dep",
10803
+ d: `M ${r1(predX)} ${r1(predMidY)} H ${r1(midX)} V ${r1(succMidY)} H ${r1(succX - 3)}`
10804
+ }));
10805
+ }
10806
+ }
10807
+ children.push(group({ class: "sx-gantt-deps" }, depEls));
10808
+ const barEls = [];
10809
+ for (const r7 of rows) {
10810
+ if (r7.kind !== "task" || !r7.task) continue;
10811
+ const t = r7.task;
10812
+ const c = schedule.computed.get(t.id);
10813
+ if (!c) continue;
10814
+ const crit = c.critical;
10815
+ const cy = r7.y + r7.h / 2;
10816
+ if (t.milestone || t.duration === 0) {
10817
+ const x2 = xAt(c.es);
10818
+ const s = 7;
10819
+ barEls.push(group(
10820
+ { class: "sx-gantt-task", "data-id": t.id, "data-critical": String(crit), "data-es": String(c.es) },
10821
+ [polygon({
10822
+ class: "sx-gantt-ms",
10823
+ "data-critical": String(crit),
10824
+ points: `${r1(x2)},${r1(cy - s)} ${r1(x2 + s)},${r1(cy)} ${r1(x2)},${r1(cy + s)} ${r1(x2 - s)},${r1(cy)}`
10825
+ })]
10826
+ ));
10827
+ continue;
10828
+ }
10829
+ const x = xAt(c.es);
10830
+ const w = Math.max(2, (c.ef - c.es) * pxUnit);
10831
+ const by = cy - G.BAR_H / 2;
10832
+ const parts = [
10833
+ rect({ x: r1(x), y: r1(by), width: r1(w), height: G.BAR_H, rx: 3, class: "sx-gantt-bar", "data-critical": String(crit) })
10834
+ ];
10835
+ if (t.progress !== void 0 && t.progress > 0) {
10836
+ parts.push(rect({
10837
+ x: r1(x),
10838
+ y: r1(by),
10839
+ width: r1(Math.max(2, w * t.progress / 100)),
10840
+ height: G.BAR_H,
10841
+ rx: 3,
10842
+ class: "sx-gantt-done",
10843
+ "data-critical": String(crit)
10844
+ }));
10845
+ }
10846
+ const cap2 = c.slack > 0 ? `${fmtVal(c.ef - c.es)}${unitSuffix2(ast.unit)} \xB7 slack ${fmtVal(c.slack)}` : `${fmtVal(c.ef - c.es)}${unitSuffix2(ast.unit)}`;
10847
+ parts.push(text({ x: r1(x + w + 5), y: r1(cy + 3.5), class: "sx-gantt-barlabel" }, cap2));
10848
+ barEls.push(group(
10849
+ {
10850
+ class: "sx-gantt-task",
10851
+ "data-id": t.id,
10852
+ "data-critical": String(crit),
10853
+ "data-es": String(c.es),
10854
+ "data-ef": String(c.ef),
10855
+ "data-slack": String(c.slack),
10856
+ ...t.progress !== void 0 ? { "data-progress": String(t.progress) } : {}
10857
+ },
10858
+ parts
10859
+ ));
10860
+ }
10861
+ children.push(group({ class: "sx-gantt-bars" }, barEls));
10862
+ if (ast.today && startDays !== void 0) {
10863
+ const todayDays = parseISODays(ast.today);
10864
+ let u;
10865
+ if (ast.calendar === "5day") {
10866
+ u = workingDaysBetween(startDays, todayDays) / unitToWork;
10867
+ } else {
10868
+ u = (todayDays - startDays) / unitToDay;
10869
+ }
10870
+ if (u >= 0 && u <= span) {
10871
+ const x = xAt(u);
10872
+ children.push(group({ class: "sx-gantt-today-g" }, [
10873
+ line({ class: "sx-gantt-today", x1: x, y1: axisBottom, x2: x, y2: chartBottom }),
10874
+ text({ x, y: chartBottom + 12, class: "sx-gantt-today-text", "text-anchor": "middle" }, "today")
10875
+ ]));
10876
+ }
10877
+ }
10878
+ const footer = `${schedule.order.length} tasks \xB7 duration ${fmtVal(schedule.projectDuration)}${unitSuffix2(ast.unit)} \xB7 critical path: ${schedule.criticalPath.join(" \u2192 ") || "\u2014"}`;
10879
+ children.push(text({ x: G.PAD, y: totalH - 10, class: "sx-gantt-footer" }, clip(footer, Math.floor((totalW - 2 * G.PAD) / 5.4))));
10880
+ return svgRoot(
10881
+ {
10882
+ class: "sx-gantt",
10883
+ role: "img",
10884
+ "aria-label": escapeXml(ast.title ?? "Gantt chart"),
10885
+ width: totalW,
10886
+ height: totalH,
10887
+ viewBox: `0 0 ${totalW} ${totalH}`,
10888
+ "data-diagram-type": "pert",
10889
+ "data-layout": "gantt"
10890
+ },
10891
+ children
10892
+ );
10893
+ }
10894
+ function workingDaysBetween(a, b) {
10895
+ if (b < a) return -workingDaysBetween(b, a);
10896
+ let n = 0;
10897
+ for (let d = a; d < b; d++) if (!isWeekend(d)) n++;
10898
+ return n;
10899
+ }
10900
+ function unitSuffix2(unit) {
10901
+ switch (unit) {
10902
+ case "days":
10903
+ return "d";
10904
+ case "weeks":
10905
+ return "w";
10906
+ case "hours":
10907
+ return "h";
10908
+ default:
10909
+ return "";
10910
+ }
10911
+ }
10527
10912
  function fmtVal(n) {
10528
10913
  return String(parseFloat(n.toFixed(2)));
10529
10914
  }
10915
+ function r1(n) {
10916
+ return Math.round(n * 10) / 10;
10917
+ }
10918
+ function clip(s, n) {
10919
+ return s.length <= n ? s : s.slice(0, Math.max(1, n - 1)) + "\u2026";
10920
+ }
10921
+ function summarise(ast, s) {
10922
+ const parts = [`Gantt chart: ${s.order.length} tasks, project duration ${fmtVal(s.projectDuration)}${unitSuffix2(ast.unit)}.`];
10923
+ if (ast.start) parts.push(`Starts ${ast.start} (${ast.calendar === "5day" ? "weekdays only" : "continuous"}).`);
10924
+ if (s.criticalPath.length) parts.push(`Critical path: ${s.criticalPath.join(" \u2192 ")}.`);
10925
+ return parts.join(" ");
10926
+ }
10927
+
10928
+ // src/diagrams/pert/renderer.ts
10929
+ function fmtVal2(n) {
10930
+ return String(parseFloat(n.toFixed(2)));
10931
+ }
10530
10932
  function unitWord(unit) {
10531
10933
  return unit === "abstract" ? "" : unit;
10532
10934
  }
@@ -10630,19 +11032,19 @@ function dataAttrs(b) {
10630
11032
  const attrs = {
10631
11033
  class: `sx-pert-task${c.critical ? " critical" : ""}${b.task.className ? " " + b.task.className : ""}`,
10632
11034
  "data-id": b.id,
10633
- "data-es": fmtVal(c.es),
10634
- "data-ef": fmtVal(c.ef),
10635
- "data-ls": fmtVal(c.ls),
10636
- "data-lf": fmtVal(c.lf),
10637
- "data-slack": fmtVal(c.slack),
10638
- "data-duration": fmtVal(b.task.duration),
11035
+ "data-es": fmtVal2(c.es),
11036
+ "data-ef": fmtVal2(c.ef),
11037
+ "data-ls": fmtVal2(c.ls),
11038
+ "data-lf": fmtVal2(c.lf),
11039
+ "data-slack": fmtVal2(c.slack),
11040
+ "data-duration": fmtVal2(b.task.duration),
10639
11041
  "data-critical": String(c.critical)
10640
11042
  };
10641
11043
  if (b.task.tags.length) attrs["data-tag"] = b.task.tags.join(" ");
10642
11044
  if (b.task.threePoint) {
10643
11045
  const tp = b.task.threePoint;
10644
- attrs["data-pert-triple"] = `${fmtVal(tp.o)}/${fmtVal(tp.m)}/${fmtVal(tp.p)}`;
10645
- if (b.task.variance !== void 0) attrs["data-pert-variance"] = fmtVal(b.task.variance);
11046
+ attrs["data-pert-triple"] = `${fmtVal2(tp.o)}/${fmtVal2(tp.m)}/${fmtVal2(tp.p)}`;
11047
+ if (b.task.variance !== void 0) attrs["data-pert-variance"] = fmtVal2(b.task.variance);
10646
11048
  }
10647
11049
  return attrs;
10648
11050
  }
@@ -10669,16 +11071,16 @@ function renderSixField(b) {
10669
11071
  text({ class: "sx-pert-field-label", x: fx, y: y + 9, "text-anchor": "middle" }, label),
10670
11072
  text({ class: cls, x: fx, y: y + 19, "text-anchor": "middle" }, value)
10671
11073
  ]);
10672
- parts.push(field(x + col / 2, "ES", fmtVal(c.es)));
10673
- parts.push(field(x + col * 1.5, "DUR", fmtVal(b.task.duration)));
10674
- parts.push(field(x + col * 2.5, "EF", fmtVal(c.ef)));
11074
+ parts.push(field(x + col / 2, "ES", fmtVal2(c.es)));
11075
+ parts.push(field(x + col * 1.5, "DUR", fmtVal2(b.task.duration)));
11076
+ parts.push(field(x + col * 2.5, "EF", fmtVal2(c.ef)));
10675
11077
  const fieldBot = (fx, label, value, cls = "sx-pert-field") => group({}, [
10676
11078
  text({ class: cls, x: fx, y: yBot + 13, "text-anchor": "middle" }, value),
10677
11079
  text({ class: "sx-pert-field-label", x: fx, y: yBot + 21, "text-anchor": "middle" }, label)
10678
11080
  ]);
10679
- parts.push(fieldBot(x + col / 2, "LS", fmtVal(c.ls)));
10680
- parts.push(fieldBot(x + col * 1.5, "SLACK", fmtVal(c.slack), "sx-pert-field slack"));
10681
- parts.push(fieldBot(x + col * 2.5, "LF", fmtVal(c.lf)));
11081
+ parts.push(fieldBot(x + col / 2, "LS", fmtVal2(c.ls)));
11082
+ parts.push(fieldBot(x + col * 1.5, "SLACK", fmtVal2(c.slack), "sx-pert-field slack"));
11083
+ parts.push(fieldBot(x + col * 2.5, "LF", fmtVal2(c.lf)));
10682
11084
  const hasSigma = b.task.variance !== void 0;
10683
11085
  const nameY = hasSigma ? y + topH + 18 : y + topH + 19;
10684
11086
  parts.push(text({ class: "sx-pert-name", x: cx, y: nameY, "text-anchor": "middle" }, b.task.label));
@@ -10687,7 +11089,7 @@ function renderSixField(b) {
10687
11089
  parts.push(
10688
11090
  text(
10689
11091
  { class: "sx-pert-sigma", x: cx, y: nameY + 27, "text-anchor": "middle" },
10690
- `\u03C3=${fmtVal(Math.sqrt(b.task.variance))}`
11092
+ `\u03C3=${fmtVal2(Math.sqrt(b.task.variance))}`
10691
11093
  )
10692
11094
  );
10693
11095
  }
@@ -10701,7 +11103,7 @@ function renderMilestone(b) {
10701
11103
  const parts = [
10702
11104
  polygon({ class: "sx-pert-ms", points: pts }),
10703
11105
  text({ class: "sx-pert-name", x: cx, y: cy - 2, "text-anchor": "middle" }, b.task.label),
10704
- text({ class: "sx-pert-id", x: cx, y: cy + 12, "text-anchor": "middle" }, `@ ${fmtVal(b.computed.es)}`)
11106
+ text({ class: "sx-pert-id", x: cx, y: cy + 12, "text-anchor": "middle" }, `@ ${fmtVal2(b.computed.es)}`)
10705
11107
  ];
10706
11108
  return group(dataAttrs(b), parts);
10707
11109
  }
@@ -10714,12 +11116,12 @@ function renderTimescaledBar(b) {
10714
11116
  parts.push(text({ class: "sx-pert-id", x: cx, y: y + h / 2 + 4, "text-anchor": "middle" }, b.id));
10715
11117
  const wide = w >= 104;
10716
11118
  if (wide) {
10717
- parts.push(text({ class: "sx-pert-field-label", x: x + 7, y: y + 15, "text-anchor": "start" }, `ES ${fmtVal(c.es)}`));
10718
- parts.push(text({ class: "sx-pert-field-label", x: x + w - 7, y: y + 15, "text-anchor": "end" }, `EF ${fmtVal(c.ef)}`));
11119
+ parts.push(text({ class: "sx-pert-field-label", x: x + 7, y: y + 15, "text-anchor": "start" }, `ES ${fmtVal2(c.es)}`));
11120
+ parts.push(text({ class: "sx-pert-field-label", x: x + w - 7, y: y + 15, "text-anchor": "end" }, `EF ${fmtVal2(c.ef)}`));
10719
11121
  parts.push(
10720
11122
  text(
10721
11123
  { class: `sx-pert-field-label${c.critical ? " slack" : ""}`, x: cx, y: y + h - 8, "text-anchor": "middle" },
10722
- `slack ${fmtVal(c.slack)}`
11124
+ `slack ${fmtVal2(c.slack)}`
10723
11125
  )
10724
11126
  );
10725
11127
  }
@@ -10804,7 +11206,7 @@ function renderAxis2(axis, gridTop) {
10804
11206
  parts.push(line({ x1: tk.pos, y1: axis.baseline, x2: tk.pos, y2: axis.baseline + len }));
10805
11207
  if (tk.major) {
10806
11208
  parts.push(
10807
- text({ x: tk.pos, y: axis.baseline + 18, "text-anchor": "middle" }, fmtVal(tk.value))
11209
+ text({ x: tk.pos, y: axis.baseline + 18, "text-anchor": "middle" }, fmtVal2(tk.value))
10808
11210
  );
10809
11211
  }
10810
11212
  }
@@ -10830,7 +11232,7 @@ function renderAoa(aoa) {
10830
11232
  );
10831
11233
  if (!a.dummy && a.label) {
10832
11234
  const critCls = a.critical ? " critical" : "";
10833
- const durStr = fmtVal(a.duration ?? 0);
11235
+ const durStr = fmtVal2(a.duration ?? 0);
10834
11236
  const w = Math.max(a.label.length * 6.2, durStr.length * 6) + 8;
10835
11237
  labelEls.push(
10836
11238
  rect({ class: "sx-pert-edge-halo", x: a.labelX - w / 2, y: a.labelY - 16, width: w, height: 31, rx: 3, ry: 3 })
@@ -10860,8 +11262,8 @@ function renderAoa(aoa) {
10860
11262
  }
10861
11263
  function summaryText(summary) {
10862
11264
  const u = unitWord(summary.unit);
10863
- const dur = `${fmtVal(summary.projectDuration)}${u ? " " + u : ""}`;
10864
- const sigma = summary.projectStdDev !== void 0 ? ` \xB7 \u03C3 \u2248 ${fmtVal(summary.projectStdDev)}` : "";
11265
+ const dur = `${fmtVal2(summary.projectDuration)}${u ? " " + u : ""}`;
11266
+ const sigma = summary.projectStdDev !== void 0 ? ` \xB7 \u03C3 \u2248 ${fmtVal2(summary.projectStdDev)}` : "";
10865
11267
  const plain = `Project duration ${dur} \xB7 ${summary.taskCount} tasks \xB7 ${summary.depCount} dependencies \xB7 ${summary.criticalCount} critical${sigma}`;
10866
11268
  const critPath = summary.criticalPath.map((id) => id).join(" \u2192 ");
10867
11269
  return { plain, critPath };
@@ -10873,7 +11275,7 @@ function renderPertLayout(layout, config) {
10873
11275
  children.push(title(`PERT network${layout.title ? " \u2014 " + layout.title : ""}`));
10874
11276
  children.push(
10875
11277
  desc(
10876
- `${layout.summary.taskCount} activities, project duration ${fmtVal(layout.summary.projectDuration)} ${unitWord(layout.unit)}` + (cp.length ? `, critical path ${cp.join(" \u2192 ")}` : "") + "."
11278
+ `${layout.summary.taskCount} activities, project duration ${fmtVal2(layout.summary.projectDuration)} ${unitWord(layout.unit)}` + (cp.length ? `, critical path ${cp.join(" \u2192 ")}` : "") + "."
10877
11279
  )
10878
11280
  );
10879
11281
  children.push(el("style", {}, buildCss5(t)));
@@ -10941,6 +11343,7 @@ var PERT_PAD = 24;
10941
11343
  function renderPert(textOrAst, config) {
10942
11344
  const ast = typeof textOrAst === "string" ? parsePert(textOrAst) : textOrAst;
10943
11345
  const schedule = schedulePert(ast);
11346
+ if (ast.layout === "gantt") return renderGantt2(ast, schedule, config);
10944
11347
  const layout = layoutPert(ast, schedule);
10945
11348
  return renderPertLayout(layout, config);
10946
11349
  }
@@ -10953,7 +11356,7 @@ var pert = {
10953
11356
  const t = raw.trim();
10954
11357
  if (!t) continue;
10955
11358
  if (t.startsWith("#") || t.startsWith("//")) continue;
10956
- return /^pert\b/i.test(t);
11359
+ return /^(pert|gantt)\b/i.test(t);
10957
11360
  }
10958
11361
  return false;
10959
11362
  },
@@ -17627,7 +18030,7 @@ function renderFaultTreeLayout(layout, config) {
17627
18030
  const instById = new Map(layout.events.map((e) => [e.instanceId, e]));
17628
18031
  const children = [
17629
18032
  title(a11y),
17630
- desc(summarise(layout)),
18033
+ desc(summarise2(layout)),
17631
18034
  styleBlock,
17632
18035
  rect({ x: 0, y: 0, width, height, class: "sx-ft-bg" })
17633
18036
  ];
@@ -17730,7 +18133,7 @@ function leafCaption(e, shapeBottom, label, showProb) {
17730
18133
  const out = [];
17731
18134
  const hasOwnLabel = !!e.event.label && e.event.label !== e.event.id;
17732
18135
  if (hasOwnLabel) {
17733
- out.push(text({ x: e.cx, y: shapeBottom + FAULTTREE_CONST.CAP_GAP, class: "sx-ft-cap", "text-anchor": "middle" }, clip(label, 20)));
18136
+ out.push(text({ x: e.cx, y: shapeBottom + FAULTTREE_CONST.CAP_GAP, class: "sx-ft-cap", "text-anchor": "middle" }, clip2(label, 20)));
17734
18137
  }
17735
18138
  if (showProb && e.event.prob !== void 0) {
17736
18139
  const y = shapeBottom + (hasOwnLabel ? FAULTTREE_CONST.CAP_GAP + FAULTTREE_CONST.CAP_LINE_H : FAULTTREE_CONST.CAP_GAP);
@@ -17788,7 +18191,7 @@ function topProbLabel(analysis) {
17788
18191
  if (analysis.topProb === void 0) return "P(top) = n/a (missing p)";
17789
18192
  return `P(top) = ${fmtProb(analysis.topProb)} (${analysis.method})`;
17790
18193
  }
17791
- function summarise(layout) {
18194
+ function summarise2(layout) {
17792
18195
  const { ast, analysis } = layout;
17793
18196
  const counts = {};
17794
18197
  for (const e of ast.events) counts[e.kind] = (counts[e.kind] ?? 0) + 1;
@@ -17818,7 +18221,7 @@ function fmtProb(n) {
17818
18221
  if (n >= 1e-3) return String(parseFloat(n.toPrecision(3)));
17819
18222
  return n.toExponential(2);
17820
18223
  }
17821
- function clip(s, n) {
18224
+ function clip2(s, n) {
17822
18225
  return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
17823
18226
  }
17824
18227
  function wrap2(s, perLine) {
@@ -17836,7 +18239,7 @@ function wrap2(s, perLine) {
17836
18239
  if (cur) lines.push(cur);
17837
18240
  if (lines.length > 2) {
17838
18241
  lines.length = 2;
17839
- lines[1] = clip(lines[1], perLine);
18242
+ lines[1] = clip2(lines[1], perLine);
17840
18243
  }
17841
18244
  return lines.join("<br/>");
17842
18245
  }
@@ -18325,7 +18728,7 @@ function renderBowtieLayout(layout, config) {
18325
18728
  );
18326
18729
  const children = [
18327
18730
  title(a11y),
18328
- desc(summarise2(layout)),
18731
+ desc(summarise3(layout)),
18329
18732
  styleBlock,
18330
18733
  rect({ x: 0, y: 0, width, height, class: "sx-bowtie-bg" })
18331
18734
  ];
@@ -18415,7 +18818,7 @@ function renderLegend2(layout, fontFamily) {
18415
18818
  }
18416
18819
  return group({ class: "sx-bowtie-legend", "data-role": "legend" }, parts);
18417
18820
  }
18418
- function summarise2(layout) {
18821
+ function summarise3(layout) {
18419
18822
  const { ast } = layout;
18420
18823
  const barrierCount = layout.boxes.filter((b) => b.role === "barrier").length;
18421
18824
  const escCount = layout.boxes.filter((b) => b.role === "escalation").length;
@@ -18443,11 +18846,11 @@ function wrap3(s, perLine, maxLines) {
18443
18846
  }
18444
18847
  }
18445
18848
  if (cur && lines.length < maxLines) lines.push(cur);
18446
- else if (cur && lines.length === maxLines) lines[maxLines - 1] = clip2(`${lines[maxLines - 1]} ${cur}`, perLine);
18849
+ else if (cur && lines.length === maxLines) lines[maxLines - 1] = clip3(`${lines[maxLines - 1]} ${cur}`, perLine);
18447
18850
  if (lines.length === 0) lines.push(s);
18448
18851
  return lines;
18449
18852
  }
18450
- function clip2(s, n) {
18853
+ function clip3(s, n) {
18451
18854
  return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
18452
18855
  }
18453
18856
  function r4(n) {
@@ -18953,7 +19356,7 @@ function renderEventTreeLayout(layout, config) {
18953
19356
  );
18954
19357
  const children = [
18955
19358
  title(a11y),
18956
- desc(summarise3(layout)),
19359
+ desc(summarise4(layout)),
18957
19360
  styleBlock,
18958
19361
  rect({ x: 0, y: 0, width, height, class: "sx-et-bg" })
18959
19362
  ];
@@ -19024,7 +19427,7 @@ function renderEventTreeLayout(layout, config) {
19024
19427
  el("circle", { cx: leaf.x, cy: leaf.y, r: 3, class: "sx-et-dot", ...dom }),
19025
19428
  text(
19026
19429
  { x: leaf.x + 10, y: leaf.y - 4, class: "sx-et-outcome", ...dom },
19027
- clip3(seq.outcome, 30)
19430
+ clip4(seq.outcome, 30)
19028
19431
  ),
19029
19432
  text(
19030
19433
  { x: leaf.x + 10, y: leaf.y + EVENTTREE_CONST.LEAF_LINE_H - 2, class: "sx-et-freq", ...dom },
@@ -19049,7 +19452,7 @@ function renderEventTreeLayout(layout, config) {
19049
19452
  children
19050
19453
  );
19051
19454
  }
19052
- function summarise3(layout) {
19455
+ function summarise4(layout) {
19053
19456
  const { ast, analysis } = layout;
19054
19457
  const parts = [
19055
19458
  `Event tree for "${ast.initiating.label ?? ast.initiating.id}" (f\u2080 = ${fmtFreq(ast.initiating.freq)}): ${ast.functions.length} function${ast.functions.length === 1 ? "" : "s"}, ${analysis.sequences.length} sequence${analysis.sequences.length === 1 ? "" : "s"}.`
@@ -19082,7 +19485,7 @@ function fmtProb2(n) {
19082
19485
  if (n >= 1e-3) return String(parseFloat(n.toPrecision(3)));
19083
19486
  return n.toExponential(2);
19084
19487
  }
19085
- function clip3(s, n) {
19488
+ function clip4(s, n) {
19086
19489
  return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
19087
19490
  }
19088
19491
 
@@ -20031,7 +20434,7 @@ function renderFmeaLayout(layout, config) {
20031
20434
  const style = el("style", {}, buildCss9(p));
20032
20435
  const children = [
20033
20436
  title(a11y),
20034
- desc(summarise4(layout)),
20437
+ desc(summarise5(layout)),
20035
20438
  style,
20036
20439
  rect({ x: 0, y: 0, width, height, class: "sx-fmea-bg" })
20037
20440
  ];
@@ -20183,7 +20586,7 @@ function renderHeaderBlock(layout) {
20183
20586
  function capitalise(s) {
20184
20587
  return s.charAt(0).toUpperCase() + s.slice(1);
20185
20588
  }
20186
- function summarise4(layout) {
20589
+ function summarise5(layout) {
20187
20590
  const { ast, analysis } = layout;
20188
20591
  const top = analysis.rows[0];
20189
20592
  const parts = [
@@ -20733,7 +21136,7 @@ function renderRbdLayout(layout, config) {
20733
21136
  );
20734
21137
  const children = [
20735
21138
  title(a11y),
20736
- desc(summarise5(layout)),
21139
+ desc(summarise6(layout)),
20737
21140
  styleBlock,
20738
21141
  rect({ x: 0, y: 0, width, height, class: "sx-rbd-bg" })
20739
21142
  ];
@@ -20840,7 +21243,7 @@ function fmtR(n) {
20840
21243
  }
20841
21244
  return String(parseFloat(n.toPrecision(9)));
20842
21245
  }
20843
- function summarise5(layout) {
21246
+ function summarise6(layout) {
20844
21247
  const { analysis } = layout;
20845
21248
  const n = layout.blocks.length;
20846
21249
  const parts = [`Reliability block diagram: ${n} block${n === 1 ? "" : "s"}.`];
@@ -21580,7 +21983,7 @@ function renderCausalLoopLayout(layout, config) {
21580
21983
  );
21581
21984
  const children = [
21582
21985
  title(a11y),
21583
- desc(summarise6(layout)),
21986
+ desc(summarise7(layout)),
21584
21987
  styleBlock,
21585
21988
  el("rect", { x: 0, y: 0, width, height, class: "sx-cld-bg" })
21586
21989
  ];
@@ -21749,7 +22152,7 @@ function glyphArrow(x, y, tx, ty) {
21749
22152
  const p2 = `${fmt4(bx - px * wide)},${fmt4(by - py * wide)}`;
21750
22153
  return polygon({ points: `${fmt4(x)},${fmt4(y)} ${p1} ${p2}`, class: "sx-cld-glyph-head" });
21751
22154
  }
21752
- function summarise6(layout) {
22155
+ function summarise7(layout) {
21753
22156
  const { ast, analysis } = layout;
21754
22157
  const parts = [
21755
22158
  `Causal loop diagram${ast.title ? ` "${ast.title}"` : ""}: ${ast.variables.length} variable${ast.variables.length === 1 ? "" : "s"}, ${ast.links.length} causal link${ast.links.length === 1 ? "" : "s"}.`
@@ -23418,7 +23821,7 @@ function renderGitGraphLayout(layout, config) {
23418
23821
  const styleBlock = buildStyle2(pal, ast.showBranches);
23419
23822
  const children = [
23420
23823
  title(a11y),
23421
- desc(summarise7(layout)),
23824
+ desc(summarise8(layout)),
23422
23825
  styleBlock,
23423
23826
  rect({ x: 0, y: 0, width, height, class: "sx-gg-bg" })
23424
23827
  ];
@@ -23668,7 +24071,7 @@ ${laneRules}
23668
24071
  function num2(n) {
23669
24072
  return Number.isInteger(n) ? String(n) : n.toFixed(2);
23670
24073
  }
23671
- function summarise7(layout) {
24074
+ function summarise8(layout) {
23672
24075
  const c = layout.replay.commits.length;
23673
24076
  const b = layout.replay.branches.length;
23674
24077
  const merges = layout.replay.commits.filter((n) => n.isMerge).length;
@@ -24509,7 +24912,7 @@ function renderEpcLayout(layout, config) {
24509
24912
  );
24510
24913
  const children = [
24511
24914
  title(a11y),
24512
- desc(summarise8(layout)),
24915
+ desc(summarise9(layout)),
24513
24916
  styleBlock,
24514
24917
  defs([
24515
24918
  el("marker", {
@@ -24645,7 +25048,7 @@ function renderEdge6(e) {
24645
25048
  if (e.edge.label) {
24646
25049
  parts.push(text(
24647
25050
  { x: e.mid.x, y: e.mid.y - 4, class: "sx-epc-edge-label", "text-anchor": "middle" },
24648
- clip4(e.edge.label, 24)
25051
+ clip5(e.edge.label, 24)
24649
25052
  ));
24650
25053
  }
24651
25054
  return group(
@@ -24653,7 +25056,7 @@ function renderEdge6(e) {
24653
25056
  parts
24654
25057
  );
24655
25058
  }
24656
- function summarise8(layout) {
25059
+ function summarise9(layout) {
24657
25060
  const { ast, analysis } = layout;
24658
25061
  const counts = { event: 0, function: 0, connector: 0 };
24659
25062
  for (const n of ast.nodes) counts[n.kind]++;
@@ -24673,7 +25076,7 @@ function describeWellFormed(analysis) {
24673
25076
  if (warns) bits.push(`${warns} warning${warns > 1 ? "s" : ""}`);
24674
25077
  return `${bits.join(", ")}.`;
24675
25078
  }
24676
- function clip4(s, n) {
25079
+ function clip5(s, n) {
24677
25080
  return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
24678
25081
  }
24679
25082
  function wrap5(s, perLine) {
@@ -24690,7 +25093,7 @@ function wrap5(s, perLine) {
24690
25093
  if (cur) lines.push(cur);
24691
25094
  if (lines.length > 3) {
24692
25095
  lines.length = 3;
24693
- lines[2] = clip4(lines[2], perLine);
25096
+ lines[2] = clip5(lines[2], perLine);
24694
25097
  }
24695
25098
  return lines.join("<br/>");
24696
25099
  }
@@ -25266,7 +25669,7 @@ function renderIdef0Layout(layout, config) {
25266
25669
  );
25267
25670
  const children = [
25268
25671
  title(a11y),
25269
- desc(summarise9(layout)),
25672
+ desc(summarise10(layout)),
25270
25673
  styleBlock,
25271
25674
  rect({ x: 0, y: 0, width, height, class: "sx-idef0-bg" })
25272
25675
  ];
@@ -25420,11 +25823,11 @@ function renderTitleBlock(width, height, node, title2) {
25420
25823
  text({ x: x0 + 6, y: y + 13, class: "sx-idef0-tb-key" }, "NODE"),
25421
25824
  text({ x: x0 + 6, y: y + 27, class: "sx-idef0-tb-text" }, node),
25422
25825
  text({ x: c1 + 6, y: y + 13, class: "sx-idef0-tb-key" }, "TITLE"),
25423
- text({ x: c1 + 6, y: y + 27, class: "sx-idef0-tb-text" }, clip5(title2 || "\u2014", 60)),
25826
+ text({ x: c1 + 6, y: y + 27, class: "sx-idef0-tb-text" }, clip6(title2 || "\u2014", 60)),
25424
25827
  text({ x: c2 + 6, y: y + 13, class: "sx-idef0-tb-key" }, "NUMBER")
25425
25828
  ]);
25426
25829
  }
25427
- function summarise9(layout) {
25830
+ function summarise10(layout) {
25428
25831
  const { ast } = layout;
25429
25832
  const counts = {};
25430
25833
  for (const a of ast.arrows) counts[a.role] = (counts[a.role] ?? 0) + 1;
@@ -25439,7 +25842,7 @@ function summarise9(layout) {
25439
25842
  for (const w of ast.warnings) parts.push(w);
25440
25843
  return parts.join(" ");
25441
25844
  }
25442
- function clip5(s, n) {
25845
+ function clip6(s, n) {
25443
25846
  return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
25444
25847
  }
25445
25848
  function wrap6(s, perLine) {
@@ -25458,7 +25861,7 @@ function wrap6(s, perLine) {
25458
25861
  if (cur) lines.push(cur);
25459
25862
  if (lines.length > 3) {
25460
25863
  lines.length = 3;
25461
- lines[2] = clip5(lines[2], perLine);
25864
+ lines[2] = clip6(lines[2], perLine);
25462
25865
  }
25463
25866
  return lines.join("<br/>");
25464
25867
  }
@@ -26085,7 +26488,7 @@ function renderThreatModelLayout(layout, config) {
26085
26488
  ]);
26086
26489
  const children = [
26087
26490
  title(a11y),
26088
- desc(summarise10(layout)),
26491
+ desc(summarise11(layout)),
26089
26492
  styleBlock,
26090
26493
  markerDefs,
26091
26494
  rect({ x: 0, y: 0, width, height, class: "sx-tm-bg" })
@@ -26302,7 +26705,7 @@ function arrowMarker2(id, cls, crossing) {
26302
26705
  function round8(n) {
26303
26706
  return Math.round(n * 100) / 100;
26304
26707
  }
26305
- function summarise10(layout) {
26708
+ function summarise11(layout) {
26306
26709
  const a = layout.analysis;
26307
26710
  const counts = {
26308
26711
  external: layout.nodes.filter((n) => n.kind === "external").length,
@@ -40555,7 +40958,7 @@ function renderPlaybookLayout(lay, config) {
40555
40958
  const surfaceBase = rect({ class: surfaceCls, x: EDGE, y: r28(fieldTop), width: r28(fieldW), height: r28(fieldH), rx: fieldRx });
40556
40959
  const boundary = rect({ class: boundaryCls, x: EDGE, y: r28(fieldTop), width: r28(fieldW), height: r28(fieldH), rx: fieldRx });
40557
40960
  const clipId = "sx-pb-clip";
40558
- const clip6 = el("clipPath", { id: clipId }, [rect({ x: EDGE, y: r28(fieldTop), width: r28(fieldW), height: r28(fieldH), rx: fieldRx })]);
40961
+ const clip7 = el("clipPath", { id: clipId }, [rect({ x: EDGE, y: r28(fieldTop), width: r28(fieldW), height: r28(fieldH), rx: fieldRx })]);
40559
40962
  const field = group({ "clip-path": `url(#${clipId})` }, [mod.drawField(lay, ctx, t)]);
40560
40963
  const zones = [];
40561
40964
  for (const z of lay.zones) {
@@ -40583,7 +40986,7 @@ function renderPlaybookLayout(lay, config) {
40583
40986
  desc(descText),
40584
40987
  el("style", {}, buildCss14(t)),
40585
40988
  rect({ fill: t.bg, x: 0, y: 0, width: W2, height: H2 }),
40586
- el("defs", {}, [clip6]),
40989
+ el("defs", {}, [clip7]),
40587
40990
  text({ class: "sx-pb-title", x: r28(W2 / 2), y: TITLE.y, "text-anchor": "middle" }, lay.title),
40588
40991
  ...annoParts,
40589
40992
  surround,
@@ -40843,5 +41246,5 @@ function renderWithPlugin(prepared, plugin, config) {
40843
41246
  }
40844
41247
 
40845
41248
  export { FLOORPLAN_SYMBOLS, GEOMETRY, bowtie2 as bowtie, causalloop, decisiontree, drawDeviceIcon, epc, eventtree, faulttree, fmea, gitgraph, iconSize, idef0, markov, network, parse, parseResult, pert, petri, pid, prisma, rbd, render, renderEquip, renderPreview, renderResult, sequence, state, threatmodel, timeline, umlclass, usecase, welding };
40846
- //# sourceMappingURL=chunk-LMNWUZMD.js.map
40847
- //# sourceMappingURL=chunk-LMNWUZMD.js.map
41249
+ //# sourceMappingURL=chunk-4W75FGWO.js.map
41250
+ //# sourceMappingURL=chunk-4W75FGWO.js.map