schematex 0.9.5 → 0.9.7

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.
@@ -9260,8 +9260,8 @@ function parseHeaderLine(ln, ast) {
9260
9260
  }
9261
9261
  case "layout": {
9262
9262
  const l = value.toLowerCase();
9263
- if (l !== "network" && l !== "timescaled" && l !== "aoa") {
9264
- throw new PertParseError(`layout must be network, timescaled, or aoa (got '${value}')`, ln.line);
9263
+ if (l !== "network" && l !== "timescaled" && l !== "aoa" && l !== "gantt") {
9264
+ throw new PertParseError(`layout must be network, timescaled, aoa, or gantt (got '${value}')`, ln.line);
9265
9265
  }
9266
9266
  ast.layout = l;
9267
9267
  return true;
@@ -9272,6 +9272,26 @@ function parseHeaderLine(ln, ast) {
9272
9272
  case "show-sentinels":
9273
9273
  ast.showSentinels = /^(true|yes|on)$/i.test(value);
9274
9274
  return true;
9275
+ case "start":
9276
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
9277
+ throw new PertParseError(`start must be a date 'YYYY-MM-DD' (got '${value}')`, ln.line);
9278
+ }
9279
+ ast.start = value;
9280
+ return true;
9281
+ case "calendar": {
9282
+ const c = value.toLowerCase();
9283
+ if (c !== "continuous" && c !== "5day" && c !== "7day") {
9284
+ throw new PertParseError(`calendar must be continuous, 7day, or 5day (got '${value}')`, ln.line);
9285
+ }
9286
+ ast.calendar = c === "5day" ? "5day" : "continuous";
9287
+ return true;
9288
+ }
9289
+ case "today":
9290
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
9291
+ throw new PertParseError(`today must be a date 'YYYY-MM-DD' (got '${value}')`, ln.line);
9292
+ }
9293
+ ast.today = value;
9294
+ return true;
9275
9295
  default:
9276
9296
  return false;
9277
9297
  }
@@ -9336,7 +9356,7 @@ function parseDepRef(raw, unit, lineNo) {
9336
9356
  }
9337
9357
  throw new PertParseError(`cannot parse predecessor reference '${ref}'`, lineNo);
9338
9358
  }
9339
- var KEY_RE = /\b(duration|after|tags|class|lane)\s*:/gi;
9359
+ var KEY_RE = /\b(duration|after|tags|class|lane|progress|done)\s*:/gi;
9340
9360
  function parseTaskLine(ln, ast) {
9341
9361
  const head = ln.text.match(/^task\s+(\S+)\s*(.*)$/i);
9342
9362
  if (!head) {
@@ -9411,6 +9431,13 @@ function parseTaskLine(ln, ast) {
9411
9431
  const tags = values.tags ? values.tags.split(",").map((t) => t.trim()).filter(Boolean) : [];
9412
9432
  const className = values.class ? values.class.trim() : void 0;
9413
9433
  const lane = values.lane ? stripQuotes3(values.lane) : void 0;
9434
+ const progressRaw = values.progress ?? values.done;
9435
+ let progress;
9436
+ if (progressRaw !== void 0 && progressRaw !== "") {
9437
+ const pct = progressRaw.trim().replace(/%$/, "");
9438
+ const n = parseNumber(pct, ln.line, "progress");
9439
+ progress = Math.max(0, Math.min(100, n));
9440
+ }
9414
9441
  const task = {
9415
9442
  id,
9416
9443
  label,
@@ -9424,6 +9451,7 @@ function parseTaskLine(ln, ast) {
9424
9451
  if (variance !== void 0) task.variance = variance;
9425
9452
  if (className) task.className = className;
9426
9453
  if (lane) task.lane = lane;
9454
+ if (progress !== void 0) task.progress = progress;
9427
9455
  ast.tasks.push(task);
9428
9456
  }
9429
9457
  function parsePert(src) {
@@ -9434,18 +9462,21 @@ function parsePert(src) {
9434
9462
  layout: "network",
9435
9463
  criticalTolerance: 0,
9436
9464
  showSentinels: false,
9465
+ calendar: "continuous",
9437
9466
  tasks: [],
9438
9467
  warnings: []
9439
9468
  };
9440
9469
  const lines = preprocess8(src);
9441
9470
  if (lines.length === 0) {
9442
- throw new PertParseError("empty document \u2014 expected 'pert' header", 1);
9471
+ throw new PertParseError("empty document \u2014 expected 'pert' or 'gantt' header", 1);
9443
9472
  }
9444
9473
  const first = lines[0];
9445
- if (!/^pert\b/i.test(first.text)) {
9446
- throw new PertParseError(`first non-comment line must start with 'pert' (got: ${first.text})`, first.line);
9474
+ if (!/^(pert|gantt)\b/i.test(first.text)) {
9475
+ throw new PertParseError(`first non-comment line must start with 'pert' or 'gantt' (got: ${first.text})`, first.line);
9447
9476
  }
9448
- const inlineTitle = first.text.replace(/^pert\b/i, "").trim();
9477
+ const isGanttHeader = /^gantt\b/i.test(first.text);
9478
+ if (isGanttHeader) ast.layout = "gantt";
9479
+ const inlineTitle = first.text.replace(/^(pert|gantt)\b/i, "").trim();
9449
9480
  if (inlineTitle) {
9450
9481
  const m = inlineTitle.match(/^"([^"]+)"$/) || inlineTitle.match(/^'([^']+)'$/);
9451
9482
  if (m) ast.title = m[1];
@@ -10525,10 +10556,381 @@ function layoutPert(ast, schedule) {
10525
10556
  return layoutNetwork(ast, sched);
10526
10557
  }
10527
10558
 
10528
- // src/diagrams/pert/renderer.ts
10559
+ // src/diagrams/pert/gantt.ts
10560
+ var PALETTES = {
10561
+ default: {
10562
+ bar: "#cfe0f5",
10563
+ barStroke: "#5b85c0",
10564
+ barDone: "#5b85c0",
10565
+ critBar: "#fbe6e0",
10566
+ critStroke: "#d2604f",
10567
+ critDone: "#d2604f",
10568
+ milestone: "#3c5a80",
10569
+ text: "#234567",
10570
+ subtext: "#728198",
10571
+ axis: "#8497ad",
10572
+ grid: "#e3eaf3",
10573
+ sectionBand: "#eef3fa",
10574
+ sectionText: "#41597a",
10575
+ dep: "#9fb0c6",
10576
+ today: "#d2604f"
10577
+ },
10578
+ monochrome: {
10579
+ bar: "#ffffff",
10580
+ barStroke: "#000000",
10581
+ barDone: "#9a9a9a",
10582
+ critBar: "#ffffff",
10583
+ critStroke: "#000000",
10584
+ critDone: "#000000",
10585
+ milestone: "#000000",
10586
+ text: "#000000",
10587
+ subtext: "#555555",
10588
+ axis: "#000000",
10589
+ grid: "#dddddd",
10590
+ sectionBand: "#f2f2f2",
10591
+ sectionText: "#000000",
10592
+ dep: "#888888",
10593
+ today: "#000000"
10594
+ },
10595
+ dark: {
10596
+ bar: "#37506e",
10597
+ barStroke: "#89b4fa",
10598
+ barDone: "#89b4fa",
10599
+ critBar: "#5a3540",
10600
+ critStroke: "#f38ba8",
10601
+ critDone: "#f38ba8",
10602
+ milestone: "#bac2de",
10603
+ text: "#cdd6f4",
10604
+ subtext: "#9399b2",
10605
+ axis: "#7f849c",
10606
+ grid: "#313244",
10607
+ sectionBand: "#272838",
10608
+ sectionText: "#bac2de",
10609
+ dep: "#6c7086",
10610
+ today: "#f38ba8"
10611
+ }
10612
+ };
10613
+ function ymdToDays(y, m, d) {
10614
+ const yy = m <= 2 ? y - 1 : y;
10615
+ const era = Math.floor((yy >= 0 ? yy : yy - 399) / 400);
10616
+ const yoe = yy - era * 400;
10617
+ const doy = Math.floor((153 * (m > 2 ? m - 3 : m + 9) + 2) / 5) + d - 1;
10618
+ const doe = yoe * 365 + Math.floor(yoe / 4) - Math.floor(yoe / 100) + doy;
10619
+ return era * 146097 + doe - 719468;
10620
+ }
10621
+ function daysToYmd(z) {
10622
+ const zz = z + 719468;
10623
+ const era = Math.floor((zz >= 0 ? zz : zz - 146096) / 146097);
10624
+ const doe = zz - era * 146097;
10625
+ const yoe = Math.floor((doe - Math.floor(doe / 1460) + Math.floor(doe / 36524) - Math.floor(doe / 146096)) / 365);
10626
+ const y = yoe + era * 400;
10627
+ const doy = doe - (365 * yoe + Math.floor(yoe / 4) - Math.floor(yoe / 100));
10628
+ const mp = Math.floor((5 * doy + 2) / 153);
10629
+ const d = doy - Math.floor((153 * mp + 2) / 5) + 1;
10630
+ const m = mp < 10 ? mp + 3 : mp - 9;
10631
+ return { y: m <= 2 ? y + 1 : y, m, d };
10632
+ }
10633
+ function parseISODays(s) {
10634
+ const [y, m, d] = s.split("-").map(Number);
10635
+ return ymdToDays(y, m, d);
10636
+ }
10637
+ function dow(days) {
10638
+ return (days % 7 + 4 + 7e3) % 7;
10639
+ }
10640
+ function isWeekend(days) {
10641
+ const w = dow(days);
10642
+ return w === 0 || w === 6;
10643
+ }
10644
+ function advanceWorking(startDays, n) {
10645
+ let cur = startDays;
10646
+ let left = Math.round(n);
10647
+ const step = left >= 0 ? 1 : -1;
10648
+ left = Math.abs(left);
10649
+ while (left > 0) {
10650
+ cur += step;
10651
+ if (!isWeekend(cur)) left--;
10652
+ }
10653
+ return cur;
10654
+ }
10655
+ var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
10656
+ function fmtDate(days) {
10657
+ const { m, d } = daysToYmd(days);
10658
+ return `${MONTHS[m - 1]} ${d}`;
10659
+ }
10660
+ var G = {
10661
+ PAD: 20,
10662
+ TITLE_H: 30,
10663
+ AXIS_H: 26,
10664
+ ROW_H: 28,
10665
+ BAR_H: 15,
10666
+ SECTION_H: 24,
10667
+ LABEL_MIN: 120,
10668
+ LABEL_MAX: 250,
10669
+ CHAR_W: 6.6,
10670
+ LABEL_PAD: 12,
10671
+ TARGET_CHART_W: 740,
10672
+ MIN_PX_UNIT: 5,
10673
+ MAX_PX_UNIT: 56,
10674
+ FOOTER_H: 28
10675
+ };
10676
+ function renderGantt2(ast, schedule, config) {
10677
+ const base = chunkENUM7GMZ_cjs.resolveBaseTheme(config?.theme ?? "default");
10678
+ const themeName = (config?.theme ?? "default") in PALETTES ? config.theme : "default";
10679
+ const P = PALETTES[themeName];
10680
+ const tasks = ast.tasks;
10681
+ const span = Math.max(schedule.projectDuration, 1);
10682
+ const unitToDay = ast.unit === "weeks" ? 7 : 1;
10683
+ const unitToWork = ast.unit === "weeks" ? 5 : 1;
10684
+ const pxUnit = Math.max(G.MIN_PX_UNIT, Math.min(G.MAX_PX_UNIT, G.TARGET_CHART_W / span));
10685
+ const longest = tasks.reduce((mx, t) => Math.max(mx, (t.label ?? t.id).length), 4);
10686
+ const labelW = Math.max(G.LABEL_MIN, Math.min(G.LABEL_MAX, Math.ceil(longest * G.CHAR_W) + 2 * G.LABEL_PAD));
10687
+ const chartX = G.PAD + labelW + 8;
10688
+ const chartW = Math.ceil(span * pxUnit);
10689
+ const hasTitle = !!ast.title;
10690
+ const topY = G.PAD + (hasTitle ? G.TITLE_H : 0);
10691
+ const axisBottom = topY + G.AXIS_H;
10692
+ const rows = [];
10693
+ let cursorY = axisBottom + 6;
10694
+ let lastLane = "\0";
10695
+ for (const t of tasks) {
10696
+ const lane = t.lane;
10697
+ if (lane !== lastLane && lane !== void 0) {
10698
+ rows.push({ kind: "section", y: cursorY, h: G.SECTION_H, label: lane });
10699
+ cursorY += G.SECTION_H;
10700
+ lastLane = lane;
10701
+ } else if (lane === void 0) {
10702
+ lastLane = void 0;
10703
+ }
10704
+ rows.push({ kind: "task", y: cursorY, h: G.ROW_H, task: t });
10705
+ cursorY += G.ROW_H;
10706
+ }
10707
+ const chartBottom = cursorY;
10708
+ const totalH = chartBottom + G.FOOTER_H + G.PAD;
10709
+ const totalW = chartX + chartW + G.PAD;
10710
+ const startDays = ast.start ? parseISODays(ast.start) : void 0;
10711
+ const xAt = (unitOffset) => chartX + unitOffset * pxUnit;
10712
+ const offsetToDate = (u) => {
10713
+ if (startDays === void 0) return void 0;
10714
+ return ast.calendar === "5day" ? advanceWorking(startDays, u * unitToWork) : startDays + Math.round(u * unitToDay);
10715
+ };
10716
+ const niceStep2 = (s) => {
10717
+ const raw = s / 9;
10718
+ const candidates = [1, 2, 5, 7, 10, 14, 20, 25, 50, 100];
10719
+ for (const c of candidates) if (c >= raw) return c;
10720
+ return Math.ceil(raw / 50) * 50;
10721
+ };
10722
+ const step = niceStep2(span);
10723
+ const styleBlock = chunk3WNW5Y7P_cjs.el("style", {}, `
10724
+ .sx-gantt-bg { fill: ${base.bg}; }
10725
+ .sx-gantt-title { fill: ${P.text}; font-size: 15px; font-weight: 700; }
10726
+ .sx-gantt-grid { stroke: ${P.grid}; stroke-width: 1; }
10727
+ .sx-gantt-axis-tick { stroke: ${P.axis}; stroke-width: 1; }
10728
+ .sx-gantt-axis-text { fill: ${P.subtext}; font-size: 9.5px; }
10729
+ .sx-gantt-axis-base { stroke: ${P.axis}; stroke-width: 1.2; }
10730
+ .sx-gantt-section { fill: ${P.sectionBand}; }
10731
+ .sx-gantt-section-text { fill: ${P.sectionText}; font-size: 11px; font-weight: 700; }
10732
+ .sx-gantt-rowlabel { fill: ${P.text}; font-size: 11.5px; }
10733
+ .sx-gantt-rowlabel.crit { fill: ${P.critStroke}; font-weight: 600; }
10734
+ .sx-gantt-bar { fill: ${P.bar}; stroke: ${P.barStroke}; stroke-width: 1; }
10735
+ .sx-gantt-bar[data-critical="true"] { fill: ${P.critBar}; stroke: ${P.critStroke}; stroke-width: 1.4; }
10736
+ .sx-gantt-done { fill: ${P.barDone}; }
10737
+ .sx-gantt-done[data-critical="true"] { fill: ${P.critDone}; }
10738
+ .sx-gantt-ms { fill: ${P.milestone}; stroke: ${P.milestone}; }
10739
+ .sx-gantt-ms[data-critical="true"] { fill: ${P.critStroke}; stroke: ${P.critStroke}; }
10740
+ .sx-gantt-dep { fill: none; stroke: ${P.dep}; stroke-width: 1; }
10741
+ .sx-gantt-barlabel { fill: ${P.subtext}; font-size: 9.5px; }
10742
+ .sx-gantt-today { stroke: ${P.today}; stroke-width: 1.3; stroke-dasharray: 4 3; }
10743
+ .sx-gantt-today-text { fill: ${P.today}; font-size: 9.5px; font-weight: 700; }
10744
+ .sx-gantt-footer { fill: ${P.subtext}; font-size: 10px; }
10745
+ `.trim());
10746
+ const children = [
10747
+ chunk3WNW5Y7P_cjs.title(`Gantt chart${ast.title ? " \u2014 " + ast.title : ""}`),
10748
+ chunk3WNW5Y7P_cjs.desc(summarise(ast, schedule)),
10749
+ styleBlock,
10750
+ chunk3WNW5Y7P_cjs.rect({ x: 0, y: 0, width: totalW, height: totalH, class: "sx-gantt-bg" })
10751
+ ];
10752
+ if (hasTitle) {
10753
+ children.push(chunk3WNW5Y7P_cjs.text({ x: G.PAD, y: G.PAD + 18, class: "sx-gantt-title" }, ast.title));
10754
+ }
10755
+ const bandEls = [];
10756
+ for (const r7 of rows) {
10757
+ if (r7.kind === "section") {
10758
+ bandEls.push(chunk3WNW5Y7P_cjs.rect({ x: G.PAD, y: r7.y, width: totalW - 2 * G.PAD, height: r7.h, class: "sx-gantt-section" }));
10759
+ bandEls.push(chunk3WNW5Y7P_cjs.text({ x: G.PAD + 8, y: r7.y + r7.h / 2 + 4, class: "sx-gantt-section-text" }, r7.label));
10760
+ }
10761
+ }
10762
+ children.push(chunk3WNW5Y7P_cjs.group({ class: "sx-gantt-sections" }, bandEls));
10763
+ const axisEls = [];
10764
+ for (let u = 0; u <= span + 1e-4; u += step) {
10765
+ const x = xAt(u);
10766
+ axisEls.push(chunk3WNW5Y7P_cjs.line({ class: "sx-gantt-grid", x1: x, y1: axisBottom, x2: x, y2: chartBottom }));
10767
+ axisEls.push(chunk3WNW5Y7P_cjs.line({ class: "sx-gantt-axis-tick", x1: x, y1: axisBottom - 5, x2: x, y2: axisBottom }));
10768
+ const cal = offsetToDate(u);
10769
+ const label = cal !== void 0 ? fmtDate(cal) : fmtVal(u);
10770
+ axisEls.push(chunk3WNW5Y7P_cjs.text({ x, y: axisBottom - 9, class: "sx-gantt-axis-text", "text-anchor": "middle" }, label));
10771
+ }
10772
+ axisEls.push(chunk3WNW5Y7P_cjs.line({ class: "sx-gantt-axis-base", x1: chartX, y1: axisBottom, x2: chartX + chartW, y2: axisBottom }));
10773
+ children.push(chunk3WNW5Y7P_cjs.group({ class: "sx-gantt-axis" }, axisEls));
10774
+ const labelEls = [];
10775
+ for (const r7 of rows) {
10776
+ if (r7.kind !== "task" || !r7.task) continue;
10777
+ const c = schedule.computed.get(r7.task.id);
10778
+ const crit = c?.critical ?? false;
10779
+ labelEls.push(
10780
+ chunk3WNW5Y7P_cjs.text(
10781
+ { x: G.PAD + 4, y: r7.y + r7.h / 2 + 4, class: `sx-gantt-rowlabel${crit ? " crit" : ""}` },
10782
+ clip(r7.task.label ?? r7.task.id, Math.floor(labelW / G.CHAR_W))
10783
+ )
10784
+ );
10785
+ }
10786
+ children.push(chunk3WNW5Y7P_cjs.group({ class: "sx-gantt-rowlabels" }, labelEls));
10787
+ const rowOf = /* @__PURE__ */ new Map();
10788
+ for (const r7 of rows) if (r7.kind === "task" && r7.task) rowOf.set(r7.task.id, r7);
10789
+ const depEls = [];
10790
+ for (const t of tasks) {
10791
+ const tr = rowOf.get(t.id);
10792
+ const tc = schedule.computed.get(t.id);
10793
+ if (!tr || !tc) continue;
10794
+ const succMidY = tr.y + tr.h / 2;
10795
+ const succX = xAt(tc.es);
10796
+ for (const dep of t.deps) {
10797
+ const pr = rowOf.get(dep.pred);
10798
+ const pc2 = schedule.computed.get(dep.pred);
10799
+ if (!pr || !pc2) continue;
10800
+ const predMidY = pr.y + pr.h / 2;
10801
+ const predX = xAt(pc2.ef);
10802
+ const midX = Math.max(predX + 8, succX - 10);
10803
+ depEls.push(chunk3WNW5Y7P_cjs.path({
10804
+ class: "sx-gantt-dep",
10805
+ d: `M ${r1(predX)} ${r1(predMidY)} H ${r1(midX)} V ${r1(succMidY)} H ${r1(succX - 3)}`
10806
+ }));
10807
+ }
10808
+ }
10809
+ children.push(chunk3WNW5Y7P_cjs.group({ class: "sx-gantt-deps" }, depEls));
10810
+ const barEls = [];
10811
+ for (const r7 of rows) {
10812
+ if (r7.kind !== "task" || !r7.task) continue;
10813
+ const t = r7.task;
10814
+ const c = schedule.computed.get(t.id);
10815
+ if (!c) continue;
10816
+ const crit = c.critical;
10817
+ const cy = r7.y + r7.h / 2;
10818
+ if (t.milestone || t.duration === 0) {
10819
+ const x2 = xAt(c.es);
10820
+ const s = 7;
10821
+ barEls.push(chunk3WNW5Y7P_cjs.group(
10822
+ { class: "sx-gantt-task", "data-id": t.id, "data-critical": String(crit), "data-es": String(c.es) },
10823
+ [chunk3WNW5Y7P_cjs.polygon({
10824
+ class: "sx-gantt-ms",
10825
+ "data-critical": String(crit),
10826
+ points: `${r1(x2)},${r1(cy - s)} ${r1(x2 + s)},${r1(cy)} ${r1(x2)},${r1(cy + s)} ${r1(x2 - s)},${r1(cy)}`
10827
+ })]
10828
+ ));
10829
+ continue;
10830
+ }
10831
+ const x = xAt(c.es);
10832
+ const w = Math.max(2, (c.ef - c.es) * pxUnit);
10833
+ const by = cy - G.BAR_H / 2;
10834
+ const parts = [
10835
+ chunk3WNW5Y7P_cjs.rect({ x: r1(x), y: r1(by), width: r1(w), height: G.BAR_H, rx: 3, class: "sx-gantt-bar", "data-critical": String(crit) })
10836
+ ];
10837
+ if (t.progress !== void 0 && t.progress > 0) {
10838
+ parts.push(chunk3WNW5Y7P_cjs.rect({
10839
+ x: r1(x),
10840
+ y: r1(by),
10841
+ width: r1(Math.max(2, w * t.progress / 100)),
10842
+ height: G.BAR_H,
10843
+ rx: 3,
10844
+ class: "sx-gantt-done",
10845
+ "data-critical": String(crit)
10846
+ }));
10847
+ }
10848
+ 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)}`;
10849
+ parts.push(chunk3WNW5Y7P_cjs.text({ x: r1(x + w + 5), y: r1(cy + 3.5), class: "sx-gantt-barlabel" }, cap2));
10850
+ barEls.push(chunk3WNW5Y7P_cjs.group(
10851
+ {
10852
+ class: "sx-gantt-task",
10853
+ "data-id": t.id,
10854
+ "data-critical": String(crit),
10855
+ "data-es": String(c.es),
10856
+ "data-ef": String(c.ef),
10857
+ "data-slack": String(c.slack),
10858
+ ...t.progress !== void 0 ? { "data-progress": String(t.progress) } : {}
10859
+ },
10860
+ parts
10861
+ ));
10862
+ }
10863
+ children.push(chunk3WNW5Y7P_cjs.group({ class: "sx-gantt-bars" }, barEls));
10864
+ if (ast.today && startDays !== void 0) {
10865
+ const todayDays = parseISODays(ast.today);
10866
+ let u;
10867
+ if (ast.calendar === "5day") {
10868
+ u = workingDaysBetween(startDays, todayDays) / unitToWork;
10869
+ } else {
10870
+ u = (todayDays - startDays) / unitToDay;
10871
+ }
10872
+ if (u >= 0 && u <= span) {
10873
+ const x = xAt(u);
10874
+ children.push(chunk3WNW5Y7P_cjs.group({ class: "sx-gantt-today-g" }, [
10875
+ chunk3WNW5Y7P_cjs.line({ class: "sx-gantt-today", x1: x, y1: axisBottom, x2: x, y2: chartBottom }),
10876
+ chunk3WNW5Y7P_cjs.text({ x, y: chartBottom + 12, class: "sx-gantt-today-text", "text-anchor": "middle" }, "today")
10877
+ ]));
10878
+ }
10879
+ }
10880
+ const footer = `${schedule.order.length} tasks \xB7 duration ${fmtVal(schedule.projectDuration)}${unitSuffix2(ast.unit)} \xB7 critical path: ${schedule.criticalPath.join(" \u2192 ") || "\u2014"}`;
10881
+ children.push(chunk3WNW5Y7P_cjs.text({ x: G.PAD, y: totalH - 10, class: "sx-gantt-footer" }, clip(footer, Math.floor((totalW - 2 * G.PAD) / 5.4))));
10882
+ return chunk3WNW5Y7P_cjs.svgRoot(
10883
+ {
10884
+ class: "sx-gantt",
10885
+ role: "img",
10886
+ "aria-label": chunk3WNW5Y7P_cjs.escapeXml(ast.title ?? "Gantt chart"),
10887
+ width: totalW,
10888
+ height: totalH,
10889
+ viewBox: `0 0 ${totalW} ${totalH}`,
10890
+ "data-diagram-type": "pert",
10891
+ "data-layout": "gantt"
10892
+ },
10893
+ children
10894
+ );
10895
+ }
10896
+ function workingDaysBetween(a, b) {
10897
+ if (b < a) return -workingDaysBetween(b, a);
10898
+ let n = 0;
10899
+ for (let d = a; d < b; d++) if (!isWeekend(d)) n++;
10900
+ return n;
10901
+ }
10902
+ function unitSuffix2(unit) {
10903
+ switch (unit) {
10904
+ case "days":
10905
+ return "d";
10906
+ case "weeks":
10907
+ return "w";
10908
+ case "hours":
10909
+ return "h";
10910
+ default:
10911
+ return "";
10912
+ }
10913
+ }
10529
10914
  function fmtVal(n) {
10530
10915
  return String(parseFloat(n.toFixed(2)));
10531
10916
  }
10917
+ function r1(n) {
10918
+ return Math.round(n * 10) / 10;
10919
+ }
10920
+ function clip(s, n) {
10921
+ return s.length <= n ? s : s.slice(0, Math.max(1, n - 1)) + "\u2026";
10922
+ }
10923
+ function summarise(ast, s) {
10924
+ const parts = [`Gantt chart: ${s.order.length} tasks, project duration ${fmtVal(s.projectDuration)}${unitSuffix2(ast.unit)}.`];
10925
+ if (ast.start) parts.push(`Starts ${ast.start} (${ast.calendar === "5day" ? "weekdays only" : "continuous"}).`);
10926
+ if (s.criticalPath.length) parts.push(`Critical path: ${s.criticalPath.join(" \u2192 ")}.`);
10927
+ return parts.join(" ");
10928
+ }
10929
+
10930
+ // src/diagrams/pert/renderer.ts
10931
+ function fmtVal2(n) {
10932
+ return String(parseFloat(n.toFixed(2)));
10933
+ }
10532
10934
  function unitWord(unit) {
10533
10935
  return unit === "abstract" ? "" : unit;
10534
10936
  }
@@ -10632,19 +11034,19 @@ function dataAttrs(b) {
10632
11034
  const attrs = {
10633
11035
  class: `sx-pert-task${c.critical ? " critical" : ""}${b.task.className ? " " + b.task.className : ""}`,
10634
11036
  "data-id": b.id,
10635
- "data-es": fmtVal(c.es),
10636
- "data-ef": fmtVal(c.ef),
10637
- "data-ls": fmtVal(c.ls),
10638
- "data-lf": fmtVal(c.lf),
10639
- "data-slack": fmtVal(c.slack),
10640
- "data-duration": fmtVal(b.task.duration),
11037
+ "data-es": fmtVal2(c.es),
11038
+ "data-ef": fmtVal2(c.ef),
11039
+ "data-ls": fmtVal2(c.ls),
11040
+ "data-lf": fmtVal2(c.lf),
11041
+ "data-slack": fmtVal2(c.slack),
11042
+ "data-duration": fmtVal2(b.task.duration),
10641
11043
  "data-critical": String(c.critical)
10642
11044
  };
10643
11045
  if (b.task.tags.length) attrs["data-tag"] = b.task.tags.join(" ");
10644
11046
  if (b.task.threePoint) {
10645
11047
  const tp = b.task.threePoint;
10646
- attrs["data-pert-triple"] = `${fmtVal(tp.o)}/${fmtVal(tp.m)}/${fmtVal(tp.p)}`;
10647
- if (b.task.variance !== void 0) attrs["data-pert-variance"] = fmtVal(b.task.variance);
11048
+ attrs["data-pert-triple"] = `${fmtVal2(tp.o)}/${fmtVal2(tp.m)}/${fmtVal2(tp.p)}`;
11049
+ if (b.task.variance !== void 0) attrs["data-pert-variance"] = fmtVal2(b.task.variance);
10648
11050
  }
10649
11051
  return attrs;
10650
11052
  }
@@ -10671,16 +11073,16 @@ function renderSixField(b) {
10671
11073
  chunk3WNW5Y7P_cjs.text({ class: "sx-pert-field-label", x: fx, y: y + 9, "text-anchor": "middle" }, label),
10672
11074
  chunk3WNW5Y7P_cjs.text({ class: cls, x: fx, y: y + 19, "text-anchor": "middle" }, value)
10673
11075
  ]);
10674
- parts.push(field(x + col / 2, "ES", fmtVal(c.es)));
10675
- parts.push(field(x + col * 1.5, "DUR", fmtVal(b.task.duration)));
10676
- parts.push(field(x + col * 2.5, "EF", fmtVal(c.ef)));
11076
+ parts.push(field(x + col / 2, "ES", fmtVal2(c.es)));
11077
+ parts.push(field(x + col * 1.5, "DUR", fmtVal2(b.task.duration)));
11078
+ parts.push(field(x + col * 2.5, "EF", fmtVal2(c.ef)));
10677
11079
  const fieldBot = (fx, label, value, cls = "sx-pert-field") => chunk3WNW5Y7P_cjs.group({}, [
10678
11080
  chunk3WNW5Y7P_cjs.text({ class: cls, x: fx, y: yBot + 13, "text-anchor": "middle" }, value),
10679
11081
  chunk3WNW5Y7P_cjs.text({ class: "sx-pert-field-label", x: fx, y: yBot + 21, "text-anchor": "middle" }, label)
10680
11082
  ]);
10681
- parts.push(fieldBot(x + col / 2, "LS", fmtVal(c.ls)));
10682
- parts.push(fieldBot(x + col * 1.5, "SLACK", fmtVal(c.slack), "sx-pert-field slack"));
10683
- parts.push(fieldBot(x + col * 2.5, "LF", fmtVal(c.lf)));
11083
+ parts.push(fieldBot(x + col / 2, "LS", fmtVal2(c.ls)));
11084
+ parts.push(fieldBot(x + col * 1.5, "SLACK", fmtVal2(c.slack), "sx-pert-field slack"));
11085
+ parts.push(fieldBot(x + col * 2.5, "LF", fmtVal2(c.lf)));
10684
11086
  const hasSigma = b.task.variance !== void 0;
10685
11087
  const nameY = hasSigma ? y + topH + 18 : y + topH + 19;
10686
11088
  parts.push(chunk3WNW5Y7P_cjs.text({ class: "sx-pert-name", x: cx, y: nameY, "text-anchor": "middle" }, b.task.label));
@@ -10689,7 +11091,7 @@ function renderSixField(b) {
10689
11091
  parts.push(
10690
11092
  chunk3WNW5Y7P_cjs.text(
10691
11093
  { class: "sx-pert-sigma", x: cx, y: nameY + 27, "text-anchor": "middle" },
10692
- `\u03C3=${fmtVal(Math.sqrt(b.task.variance))}`
11094
+ `\u03C3=${fmtVal2(Math.sqrt(b.task.variance))}`
10693
11095
  )
10694
11096
  );
10695
11097
  }
@@ -10703,7 +11105,7 @@ function renderMilestone(b) {
10703
11105
  const parts = [
10704
11106
  chunk3WNW5Y7P_cjs.polygon({ class: "sx-pert-ms", points: pts }),
10705
11107
  chunk3WNW5Y7P_cjs.text({ class: "sx-pert-name", x: cx, y: cy - 2, "text-anchor": "middle" }, b.task.label),
10706
- chunk3WNW5Y7P_cjs.text({ class: "sx-pert-id", x: cx, y: cy + 12, "text-anchor": "middle" }, `@ ${fmtVal(b.computed.es)}`)
11108
+ chunk3WNW5Y7P_cjs.text({ class: "sx-pert-id", x: cx, y: cy + 12, "text-anchor": "middle" }, `@ ${fmtVal2(b.computed.es)}`)
10707
11109
  ];
10708
11110
  return chunk3WNW5Y7P_cjs.group(dataAttrs(b), parts);
10709
11111
  }
@@ -10716,12 +11118,12 @@ function renderTimescaledBar(b) {
10716
11118
  parts.push(chunk3WNW5Y7P_cjs.text({ class: "sx-pert-id", x: cx, y: y + h / 2 + 4, "text-anchor": "middle" }, b.id));
10717
11119
  const wide = w >= 104;
10718
11120
  if (wide) {
10719
- parts.push(chunk3WNW5Y7P_cjs.text({ class: "sx-pert-field-label", x: x + 7, y: y + 15, "text-anchor": "start" }, `ES ${fmtVal(c.es)}`));
10720
- parts.push(chunk3WNW5Y7P_cjs.text({ class: "sx-pert-field-label", x: x + w - 7, y: y + 15, "text-anchor": "end" }, `EF ${fmtVal(c.ef)}`));
11121
+ parts.push(chunk3WNW5Y7P_cjs.text({ class: "sx-pert-field-label", x: x + 7, y: y + 15, "text-anchor": "start" }, `ES ${fmtVal2(c.es)}`));
11122
+ parts.push(chunk3WNW5Y7P_cjs.text({ class: "sx-pert-field-label", x: x + w - 7, y: y + 15, "text-anchor": "end" }, `EF ${fmtVal2(c.ef)}`));
10721
11123
  parts.push(
10722
11124
  chunk3WNW5Y7P_cjs.text(
10723
11125
  { class: `sx-pert-field-label${c.critical ? " slack" : ""}`, x: cx, y: y + h - 8, "text-anchor": "middle" },
10724
- `slack ${fmtVal(c.slack)}`
11126
+ `slack ${fmtVal2(c.slack)}`
10725
11127
  )
10726
11128
  );
10727
11129
  }
@@ -10806,7 +11208,7 @@ function renderAxis2(axis, gridTop) {
10806
11208
  parts.push(chunk3WNW5Y7P_cjs.line({ x1: tk.pos, y1: axis.baseline, x2: tk.pos, y2: axis.baseline + len }));
10807
11209
  if (tk.major) {
10808
11210
  parts.push(
10809
- chunk3WNW5Y7P_cjs.text({ x: tk.pos, y: axis.baseline + 18, "text-anchor": "middle" }, fmtVal(tk.value))
11211
+ chunk3WNW5Y7P_cjs.text({ x: tk.pos, y: axis.baseline + 18, "text-anchor": "middle" }, fmtVal2(tk.value))
10810
11212
  );
10811
11213
  }
10812
11214
  }
@@ -10832,7 +11234,7 @@ function renderAoa(aoa) {
10832
11234
  );
10833
11235
  if (!a.dummy && a.label) {
10834
11236
  const critCls = a.critical ? " critical" : "";
10835
- const durStr = fmtVal(a.duration ?? 0);
11237
+ const durStr = fmtVal2(a.duration ?? 0);
10836
11238
  const w = Math.max(a.label.length * 6.2, durStr.length * 6) + 8;
10837
11239
  labelEls.push(
10838
11240
  chunk3WNW5Y7P_cjs.rect({ class: "sx-pert-edge-halo", x: a.labelX - w / 2, y: a.labelY - 16, width: w, height: 31, rx: 3, ry: 3 })
@@ -10862,8 +11264,8 @@ function renderAoa(aoa) {
10862
11264
  }
10863
11265
  function summaryText(summary) {
10864
11266
  const u = unitWord(summary.unit);
10865
- const dur = `${fmtVal(summary.projectDuration)}${u ? " " + u : ""}`;
10866
- const sigma = summary.projectStdDev !== void 0 ? ` \xB7 \u03C3 \u2248 ${fmtVal(summary.projectStdDev)}` : "";
11267
+ const dur = `${fmtVal2(summary.projectDuration)}${u ? " " + u : ""}`;
11268
+ const sigma = summary.projectStdDev !== void 0 ? ` \xB7 \u03C3 \u2248 ${fmtVal2(summary.projectStdDev)}` : "";
10867
11269
  const plain = `Project duration ${dur} \xB7 ${summary.taskCount} tasks \xB7 ${summary.depCount} dependencies \xB7 ${summary.criticalCount} critical${sigma}`;
10868
11270
  const critPath = summary.criticalPath.map((id) => id).join(" \u2192 ");
10869
11271
  return { plain, critPath };
@@ -10875,7 +11277,7 @@ function renderPertLayout(layout, config) {
10875
11277
  children.push(chunk3WNW5Y7P_cjs.title(`PERT network${layout.title ? " \u2014 " + layout.title : ""}`));
10876
11278
  children.push(
10877
11279
  chunk3WNW5Y7P_cjs.desc(
10878
- `${layout.summary.taskCount} activities, project duration ${fmtVal(layout.summary.projectDuration)} ${unitWord(layout.unit)}` + (cp.length ? `, critical path ${cp.join(" \u2192 ")}` : "") + "."
11280
+ `${layout.summary.taskCount} activities, project duration ${fmtVal2(layout.summary.projectDuration)} ${unitWord(layout.unit)}` + (cp.length ? `, critical path ${cp.join(" \u2192 ")}` : "") + "."
10879
11281
  )
10880
11282
  );
10881
11283
  children.push(chunk3WNW5Y7P_cjs.el("style", {}, buildCss5(t)));
@@ -10943,6 +11345,7 @@ var PERT_PAD = 24;
10943
11345
  function renderPert(textOrAst, config) {
10944
11346
  const ast = typeof textOrAst === "string" ? parsePert(textOrAst) : textOrAst;
10945
11347
  const schedule = schedulePert(ast);
11348
+ if (ast.layout === "gantt") return renderGantt2(ast, schedule, config);
10946
11349
  const layout = layoutPert(ast, schedule);
10947
11350
  return renderPertLayout(layout, config);
10948
11351
  }
@@ -10955,7 +11358,7 @@ var pert = {
10955
11358
  const t = raw.trim();
10956
11359
  if (!t) continue;
10957
11360
  if (t.startsWith("#") || t.startsWith("//")) continue;
10958
- return /^pert\b/i.test(t);
11361
+ return /^(pert|gantt)\b/i.test(t);
10959
11362
  }
10960
11363
  return false;
10961
11364
  },
@@ -17063,6 +17466,19 @@ function truncate3(s, n) {
17063
17466
  return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
17064
17467
  }
17065
17468
 
17469
+ // src/core/format.ts
17470
+ function formatProbability(n) {
17471
+ if (!Number.isFinite(n)) return String(n);
17472
+ if (n <= 0) return "0";
17473
+ if (n >= 1) return "1";
17474
+ if (n < 1e-3) return n.toExponential(2);
17475
+ for (let p = 3; p <= 9; p++) {
17476
+ const s = parseFloat(n.toPrecision(p));
17477
+ if (s > 0 && s < 1) return String(s);
17478
+ }
17479
+ return String(parseFloat(n.toPrecision(9)));
17480
+ }
17481
+
17066
17482
  // src/diagrams/faulttree/analysis.ts
17067
17483
  var EXPANSION_CAP = 5e4;
17068
17484
  var EXACT_CUTSET_CAP = 20;
@@ -17629,7 +18045,7 @@ function renderFaultTreeLayout(layout, config) {
17629
18045
  const instById = new Map(layout.events.map((e) => [e.instanceId, e]));
17630
18046
  const children = [
17631
18047
  chunk3WNW5Y7P_cjs.title(a11y),
17632
- chunk3WNW5Y7P_cjs.desc(summarise(layout)),
18048
+ chunk3WNW5Y7P_cjs.desc(summarise2(layout)),
17633
18049
  styleBlock,
17634
18050
  chunk3WNW5Y7P_cjs.rect({ x: 0, y: 0, width, height, class: "sx-ft-bg" })
17635
18051
  ];
@@ -17732,7 +18148,7 @@ function leafCaption(e, shapeBottom, label, showProb) {
17732
18148
  const out = [];
17733
18149
  const hasOwnLabel = !!e.event.label && e.event.label !== e.event.id;
17734
18150
  if (hasOwnLabel) {
17735
- out.push(chunk3WNW5Y7P_cjs.text({ x: e.cx, y: shapeBottom + FAULTTREE_CONST.CAP_GAP, class: "sx-ft-cap", "text-anchor": "middle" }, clip(label, 20)));
18151
+ out.push(chunk3WNW5Y7P_cjs.text({ x: e.cx, y: shapeBottom + FAULTTREE_CONST.CAP_GAP, class: "sx-ft-cap", "text-anchor": "middle" }, clip2(label, 20)));
17736
18152
  }
17737
18153
  if (showProb && e.event.prob !== void 0) {
17738
18154
  const y = shapeBottom + (hasOwnLabel ? FAULTTREE_CONST.CAP_GAP + FAULTTREE_CONST.CAP_LINE_H : FAULTTREE_CONST.CAP_GAP);
@@ -17790,7 +18206,7 @@ function topProbLabel(analysis) {
17790
18206
  if (analysis.topProb === void 0) return "P(top) = n/a (missing p)";
17791
18207
  return `P(top) = ${fmtProb(analysis.topProb)} (${analysis.method})`;
17792
18208
  }
17793
- function summarise(layout) {
18209
+ function summarise2(layout) {
17794
18210
  const { ast, analysis } = layout;
17795
18211
  const counts = {};
17796
18212
  for (const e of ast.events) counts[e.kind] = (counts[e.kind] ?? 0) + 1;
@@ -17816,11 +18232,9 @@ function summarise(layout) {
17816
18232
  return parts.join(" ");
17817
18233
  }
17818
18234
  function fmtProb(n) {
17819
- if (n === 0) return "0";
17820
- if (n >= 1e-3) return String(parseFloat(n.toPrecision(3)));
17821
- return n.toExponential(2);
18235
+ return formatProbability(n);
17822
18236
  }
17823
- function clip(s, n) {
18237
+ function clip2(s, n) {
17824
18238
  return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
17825
18239
  }
17826
18240
  function wrap2(s, perLine) {
@@ -17838,7 +18252,7 @@ function wrap2(s, perLine) {
17838
18252
  if (cur) lines.push(cur);
17839
18253
  if (lines.length > 2) {
17840
18254
  lines.length = 2;
17841
- lines[1] = clip(lines[1], perLine);
18255
+ lines[1] = clip2(lines[1], perLine);
17842
18256
  }
17843
18257
  return lines.join("<br/>");
17844
18258
  }
@@ -18327,7 +18741,7 @@ function renderBowtieLayout(layout, config) {
18327
18741
  );
18328
18742
  const children = [
18329
18743
  chunk3WNW5Y7P_cjs.title(a11y),
18330
- chunk3WNW5Y7P_cjs.desc(summarise2(layout)),
18744
+ chunk3WNW5Y7P_cjs.desc(summarise3(layout)),
18331
18745
  styleBlock,
18332
18746
  chunk3WNW5Y7P_cjs.rect({ x: 0, y: 0, width, height, class: "sx-bowtie-bg" })
18333
18747
  ];
@@ -18417,7 +18831,7 @@ function renderLegend2(layout, fontFamily) {
18417
18831
  }
18418
18832
  return chunk3WNW5Y7P_cjs.group({ class: "sx-bowtie-legend", "data-role": "legend" }, parts);
18419
18833
  }
18420
- function summarise2(layout) {
18834
+ function summarise3(layout) {
18421
18835
  const { ast } = layout;
18422
18836
  const barrierCount = layout.boxes.filter((b) => b.role === "barrier").length;
18423
18837
  const escCount = layout.boxes.filter((b) => b.role === "escalation").length;
@@ -18445,11 +18859,11 @@ function wrap3(s, perLine, maxLines) {
18445
18859
  }
18446
18860
  }
18447
18861
  if (cur && lines.length < maxLines) lines.push(cur);
18448
- else if (cur && lines.length === maxLines) lines[maxLines - 1] = clip2(`${lines[maxLines - 1]} ${cur}`, perLine);
18862
+ else if (cur && lines.length === maxLines) lines[maxLines - 1] = clip3(`${lines[maxLines - 1]} ${cur}`, perLine);
18449
18863
  if (lines.length === 0) lines.push(s);
18450
18864
  return lines;
18451
18865
  }
18452
- function clip2(s, n) {
18866
+ function clip3(s, n) {
18453
18867
  return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
18454
18868
  }
18455
18869
  function r4(n) {
@@ -18955,7 +19369,7 @@ function renderEventTreeLayout(layout, config) {
18955
19369
  );
18956
19370
  const children = [
18957
19371
  chunk3WNW5Y7P_cjs.title(a11y),
18958
- chunk3WNW5Y7P_cjs.desc(summarise3(layout)),
19372
+ chunk3WNW5Y7P_cjs.desc(summarise4(layout)),
18959
19373
  styleBlock,
18960
19374
  chunk3WNW5Y7P_cjs.rect({ x: 0, y: 0, width, height, class: "sx-et-bg" })
18961
19375
  ];
@@ -19026,7 +19440,7 @@ function renderEventTreeLayout(layout, config) {
19026
19440
  chunk3WNW5Y7P_cjs.el("circle", { cx: leaf.x, cy: leaf.y, r: 3, class: "sx-et-dot", ...dom }),
19027
19441
  chunk3WNW5Y7P_cjs.text(
19028
19442
  { x: leaf.x + 10, y: leaf.y - 4, class: "sx-et-outcome", ...dom },
19029
- clip3(seq.outcome, 30)
19443
+ clip4(seq.outcome, 30)
19030
19444
  ),
19031
19445
  chunk3WNW5Y7P_cjs.text(
19032
19446
  { x: leaf.x + 10, y: leaf.y + EVENTTREE_CONST.LEAF_LINE_H - 2, class: "sx-et-freq", ...dom },
@@ -19051,7 +19465,7 @@ function renderEventTreeLayout(layout, config) {
19051
19465
  children
19052
19466
  );
19053
19467
  }
19054
- function summarise3(layout) {
19468
+ function summarise4(layout) {
19055
19469
  const { ast, analysis } = layout;
19056
19470
  const parts = [
19057
19471
  `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"}.`
@@ -19084,7 +19498,7 @@ function fmtProb2(n) {
19084
19498
  if (n >= 1e-3) return String(parseFloat(n.toPrecision(3)));
19085
19499
  return n.toExponential(2);
19086
19500
  }
19087
- function clip3(s, n) {
19501
+ function clip4(s, n) {
19088
19502
  return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
19089
19503
  }
19090
19504
 
@@ -20033,7 +20447,7 @@ function renderFmeaLayout(layout, config) {
20033
20447
  const style = chunk3WNW5Y7P_cjs.el("style", {}, buildCss9(p));
20034
20448
  const children = [
20035
20449
  chunk3WNW5Y7P_cjs.title(a11y),
20036
- chunk3WNW5Y7P_cjs.desc(summarise4(layout)),
20450
+ chunk3WNW5Y7P_cjs.desc(summarise5(layout)),
20037
20451
  style,
20038
20452
  chunk3WNW5Y7P_cjs.rect({ x: 0, y: 0, width, height, class: "sx-fmea-bg" })
20039
20453
  ];
@@ -20185,7 +20599,7 @@ function renderHeaderBlock(layout) {
20185
20599
  function capitalise(s) {
20186
20600
  return s.charAt(0).toUpperCase() + s.slice(1);
20187
20601
  }
20188
- function summarise4(layout) {
20602
+ function summarise5(layout) {
20189
20603
  const { ast, analysis } = layout;
20190
20604
  const top = analysis.rows[0];
20191
20605
  const parts = [
@@ -20281,6 +20695,7 @@ function parseRbd(text2) {
20281
20695
  seenIds.add(id);
20282
20696
  let label;
20283
20697
  let R;
20698
+ let dist;
20284
20699
  if (peek()?.t === "string") {
20285
20700
  label = tokens[pos++].v;
20286
20701
  }
@@ -20289,10 +20704,16 @@ function parseRbd(text2) {
20289
20704
  const attr = parseAttr(w);
20290
20705
  if (!attr) break;
20291
20706
  pos++;
20292
- if (attr.key === "p") R = clamp01(1 - attr.value, w, warnings);
20293
- else R = clamp01(attr.value, w, warnings);
20707
+ if (attr.kind === "dist") dist = attr.dist;
20708
+ else R = clamp01(attr.failure ? 1 - attr.value : attr.value, w, warnings);
20294
20709
  }
20295
- return { kind: "block", id, ...label !== void 0 ? { label } : {}, ...R !== void 0 ? { R } : {} };
20710
+ return {
20711
+ kind: "block",
20712
+ id,
20713
+ ...label !== void 0 ? { label } : {},
20714
+ ...R !== void 0 ? { R } : {},
20715
+ ...dist !== void 0 ? { dist } : {}
20716
+ };
20296
20717
  };
20297
20718
  const parseGroup = (kwRaw) => {
20298
20719
  const kw = kwRaw.toLowerCase();
@@ -20366,10 +20787,19 @@ function parseRbd(text2) {
20366
20787
  } else {
20367
20788
  root = { kind: "series", children: top };
20368
20789
  }
20790
+ let mission;
20791
+ if (metadata.mission !== void 0) {
20792
+ const v = parseFloat(metadata.mission);
20793
+ if (!Number.isFinite(v) || v < 0) {
20794
+ throw new RbdParseError(`mission time must be a non-negative number (got '${metadata.mission}')`);
20795
+ }
20796
+ mission = v;
20797
+ }
20369
20798
  return {
20370
20799
  type: "rbd",
20371
20800
  ...title2 ? { title: title2 } : {},
20372
20801
  root,
20802
+ ...mission !== void 0 ? { mission } : {},
20373
20803
  warnings,
20374
20804
  ...Object.keys(metadata).length > 0 ? { metadata } : {}
20375
20805
  };
@@ -20422,11 +20852,10 @@ function tokenize6(src) {
20422
20852
  }
20423
20853
  function stripBodyDirectives(body, metadata) {
20424
20854
  return body.split("\n").filter((line2) => {
20425
- const m = line2.match(/^\s*(title|standard|note)\s*:\s*(.+)$/i);
20855
+ const m = line2.match(/^\s*(title|standard|note|mission)\s*:\s*(.+)$/i);
20426
20856
  if (m) {
20427
20857
  const key = m[1].toLowerCase();
20428
- if (key !== "title") metadata[key] = m[2].trim();
20429
- else metadata.title = m[2].trim();
20858
+ metadata[key] = m[2].trim();
20430
20859
  return false;
20431
20860
  }
20432
20861
  return true;
@@ -20438,15 +20867,33 @@ function extractQuoted(s) {
20438
20867
  return s.length > 0 ? s.trim() : void 0;
20439
20868
  }
20440
20869
  function parseAttr(w) {
20870
+ const wb = w.match(/^weibull\s*[=:]\s*(.+)$/i);
20871
+ if (wb) {
20872
+ const parts = wb[1].split(",").map((s) => parseFloat(s.trim()));
20873
+ if (parts.length === 2 && parts.every((x) => Number.isFinite(x) && x > 0)) {
20874
+ return { kind: "dist", dist: { kind: "weibull", beta: parts[0], eta: parts[1] } };
20875
+ }
20876
+ return null;
20877
+ }
20878
+ const rt = w.match(/^rate\s*[=:]\s*(.+)$/i);
20879
+ if (rt) {
20880
+ const v = parseFloat(rt[1].trim());
20881
+ return Number.isFinite(v) && v >= 0 ? { kind: "dist", dist: { kind: "exp", rate: v } } : null;
20882
+ }
20883
+ const mt = w.match(/^(mtbf|mttf)\s*[=:]\s*(.+)$/i);
20884
+ if (mt) {
20885
+ const v = parseFloat(mt[2].trim());
20886
+ return Number.isFinite(v) && v > 0 ? { kind: "dist", dist: { kind: "exp", rate: 1 / v } } : null;
20887
+ }
20441
20888
  const m = w.match(/^(R|r|p|prob|q)\s*[=:]\s*(.+)$/);
20442
20889
  if (m) {
20443
20890
  const key = m[1].toLowerCase();
20444
20891
  const value = parseNum(m[2]);
20445
20892
  if (value === void 0) return null;
20446
- return { key: key === "p" || key === "q" ? "p" : "R", value };
20893
+ return { kind: "R", value, failure: key === "p" || key === "q" };
20447
20894
  }
20448
20895
  const bare = parseNum(w);
20449
- if (bare !== void 0) return { key: "R", value: bare };
20896
+ if (bare !== void 0) return { kind: "R", value: bare, failure: false };
20450
20897
  return null;
20451
20898
  }
20452
20899
  function parseNum(s) {
@@ -20475,8 +20922,11 @@ var KOFN_ENUM_CAP = 18;
20475
20922
  function analyseRbd(ast) {
20476
20923
  const notes = [];
20477
20924
  const warnings = [...ast.warnings];
20925
+ if (ast.mission !== void 0) {
20926
+ notes.push(`Mission time t = ${ast.mission}; block reliabilities with a rate/MTBF/Weibull are evaluated as R(t).`);
20927
+ }
20478
20928
  const blocks = [];
20479
- collectBlocks(ast.root, blocks);
20929
+ collectBlocks(ast.root, blocks, ast.mission, warnings);
20480
20930
  const missing = blocks.filter((b) => b.R === void 0).map((b) => b.id);
20481
20931
  const baseEnv = new Map(blocks.map((b) => [b.id, b.R]));
20482
20932
  const systemReliability = evalStructure(ast.root, baseEnv, notes);
@@ -20492,10 +20942,15 @@ function analyseRbd(ast) {
20492
20942
  const rDown = evalStructure(ast.root, down, notes);
20493
20943
  const importance = rUp !== void 0 && rDown !== void 0 ? rUp - rDown : void 0;
20494
20944
  const isSpof = rDown === 0;
20945
+ let criticality;
20946
+ if (importance !== void 0 && b.R !== void 0 && systemReliability < 1) {
20947
+ criticality = importance * (1 - b.R) / (1 - systemReliability);
20948
+ }
20495
20949
  return {
20496
20950
  id: b.id,
20497
20951
  ...b.R !== void 0 ? { R: b.R } : {},
20498
20952
  ...importance !== void 0 ? { importance } : {},
20953
+ ...criticality !== void 0 ? { criticality } : {},
20499
20954
  isSpof
20500
20955
  };
20501
20956
  });
@@ -20520,12 +20975,25 @@ function analyseRbd(ast) {
20520
20975
  notes
20521
20976
  };
20522
20977
  }
20523
- function collectBlocks(s, out) {
20978
+ function collectBlocks(s, out, mission, warnings) {
20524
20979
  if (s.kind === "block") {
20525
- out.push({ id: s.id, ...s.R !== void 0 ? { R: s.R } : {} });
20980
+ const R = resolveBlockR(s, mission, warnings);
20981
+ out.push({ id: s.id, ...R !== void 0 ? { R } : {} });
20526
20982
  return;
20527
20983
  }
20528
- for (const c of s.children) collectBlocks(c, out);
20984
+ for (const c of s.children) collectBlocks(c, out, mission, warnings);
20985
+ }
20986
+ function resolveBlockR(b, mission, warnings) {
20987
+ if (b.dist) {
20988
+ if (mission === void 0) {
20989
+ warnings.push(`Block "${b.id}" has a failure distribution but no mission time \u2014 add 'mission: <t>' to evaluate R(t)${b.R !== void 0 ? ", falling back to its constant R" : ""}.`);
20990
+ return b.R;
20991
+ }
20992
+ const t = mission;
20993
+ if (b.dist.kind === "exp") return Math.exp(-b.dist.rate * t);
20994
+ return Math.exp(-Math.pow(t / b.dist.eta, b.dist.beta));
20995
+ }
20996
+ return b.R;
20529
20997
  }
20530
20998
  function evalStructure(s, env, notes) {
20531
20999
  if (s.kind === "block") return env.get(s.id);
@@ -20735,7 +21203,7 @@ function renderRbdLayout(layout, config) {
20735
21203
  );
20736
21204
  const children = [
20737
21205
  chunk3WNW5Y7P_cjs.title(a11y),
20738
- chunk3WNW5Y7P_cjs.desc(summarise5(layout)),
21206
+ chunk3WNW5Y7P_cjs.desc(summarise6(layout)),
20739
21207
  styleBlock,
20740
21208
  chunk3WNW5Y7P_cjs.rect({ x: 0, y: 0, width, height, class: "sx-rbd-bg" })
20741
21209
  ];
@@ -20756,7 +21224,7 @@ function renderRbdLayout(layout, config) {
20756
21224
  class: "sx-rbd-rsys",
20757
21225
  "text-anchor": "middle"
20758
21226
  },
20759
- systemLabel(analysis)
21227
+ systemLabel(analysis, ast.mission)
20760
21228
  )
20761
21229
  );
20762
21230
  for (const w of layout.wires) inner.push(chunk3WNW5Y7P_cjs.path({ d: w.path, class: "sx-rbd-wire" }));
@@ -20826,12 +21294,16 @@ function renderBlock(b) {
20826
21294
  parts
20827
21295
  );
20828
21296
  }
20829
- function systemLabel(analysis) {
21297
+ function systemLabel(analysis, mission) {
20830
21298
  if (analysis.systemReliability === void 0) {
20831
21299
  const miss = analysis.missing.length > 0 ? ` \u2014 missing R on ${analysis.missing.join(", ")}` : "";
20832
21300
  return `System reliability: n/a${miss}`;
20833
21301
  }
20834
- return `System reliability R = ${fmtR(analysis.systemReliability)}`;
21302
+ const arg = mission !== void 0 ? `(t=${fmtVal3(mission)})` : "";
21303
+ return `System reliability R${arg} = ${fmtR(analysis.systemReliability)}`;
21304
+ }
21305
+ function fmtVal3(n) {
21306
+ return String(parseFloat(n.toFixed(2)));
20835
21307
  }
20836
21308
  function fmtR(n) {
20837
21309
  if (n >= 1) return "1";
@@ -20842,7 +21314,7 @@ function fmtR(n) {
20842
21314
  }
20843
21315
  return String(parseFloat(n.toPrecision(9)));
20844
21316
  }
20845
- function summarise5(layout) {
21317
+ function summarise6(layout) {
20846
21318
  const { analysis } = layout;
20847
21319
  const n = layout.blocks.length;
20848
21320
  const parts = [`Reliability block diagram: ${n} block${n === 1 ? "" : "s"}.`];
@@ -21582,7 +22054,7 @@ function renderCausalLoopLayout(layout, config) {
21582
22054
  );
21583
22055
  const children = [
21584
22056
  chunk3WNW5Y7P_cjs.title(a11y),
21585
- chunk3WNW5Y7P_cjs.desc(summarise6(layout)),
22057
+ chunk3WNW5Y7P_cjs.desc(summarise7(layout)),
21586
22058
  styleBlock,
21587
22059
  chunk3WNW5Y7P_cjs.el("rect", { x: 0, y: 0, width, height, class: "sx-cld-bg" })
21588
22060
  ];
@@ -21751,7 +22223,7 @@ function glyphArrow(x, y, tx, ty) {
21751
22223
  const p2 = `${fmt4(bx - px * wide)},${fmt4(by - py * wide)}`;
21752
22224
  return chunk3WNW5Y7P_cjs.polygon({ points: `${fmt4(x)},${fmt4(y)} ${p1} ${p2}`, class: "sx-cld-glyph-head" });
21753
22225
  }
21754
- function summarise6(layout) {
22226
+ function summarise7(layout) {
21755
22227
  const { ast, analysis } = layout;
21756
22228
  const parts = [
21757
22229
  `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"}.`
@@ -23420,7 +23892,7 @@ function renderGitGraphLayout(layout, config) {
23420
23892
  const styleBlock = buildStyle2(pal, ast.showBranches);
23421
23893
  const children = [
23422
23894
  chunk3WNW5Y7P_cjs.title(a11y),
23423
- chunk3WNW5Y7P_cjs.desc(summarise7(layout)),
23895
+ chunk3WNW5Y7P_cjs.desc(summarise8(layout)),
23424
23896
  styleBlock,
23425
23897
  chunk3WNW5Y7P_cjs.rect({ x: 0, y: 0, width, height, class: "sx-gg-bg" })
23426
23898
  ];
@@ -23670,7 +24142,7 @@ ${laneRules}
23670
24142
  function num2(n) {
23671
24143
  return Number.isInteger(n) ? String(n) : n.toFixed(2);
23672
24144
  }
23673
- function summarise7(layout) {
24145
+ function summarise8(layout) {
23674
24146
  const c = layout.replay.commits.length;
23675
24147
  const b = layout.replay.branches.length;
23676
24148
  const merges = layout.replay.commits.filter((n) => n.isMerge).length;
@@ -24511,7 +24983,7 @@ function renderEpcLayout(layout, config) {
24511
24983
  );
24512
24984
  const children = [
24513
24985
  chunk3WNW5Y7P_cjs.title(a11y),
24514
- chunk3WNW5Y7P_cjs.desc(summarise8(layout)),
24986
+ chunk3WNW5Y7P_cjs.desc(summarise9(layout)),
24515
24987
  styleBlock,
24516
24988
  chunk3WNW5Y7P_cjs.defs([
24517
24989
  chunk3WNW5Y7P_cjs.el("marker", {
@@ -24647,7 +25119,7 @@ function renderEdge6(e) {
24647
25119
  if (e.edge.label) {
24648
25120
  parts.push(chunk3WNW5Y7P_cjs.text(
24649
25121
  { x: e.mid.x, y: e.mid.y - 4, class: "sx-epc-edge-label", "text-anchor": "middle" },
24650
- clip4(e.edge.label, 24)
25122
+ clip5(e.edge.label, 24)
24651
25123
  ));
24652
25124
  }
24653
25125
  return chunk3WNW5Y7P_cjs.group(
@@ -24655,7 +25127,7 @@ function renderEdge6(e) {
24655
25127
  parts
24656
25128
  );
24657
25129
  }
24658
- function summarise8(layout) {
25130
+ function summarise9(layout) {
24659
25131
  const { ast, analysis } = layout;
24660
25132
  const counts = { event: 0, function: 0, connector: 0 };
24661
25133
  for (const n of ast.nodes) counts[n.kind]++;
@@ -24675,7 +25147,7 @@ function describeWellFormed(analysis) {
24675
25147
  if (warns) bits.push(`${warns} warning${warns > 1 ? "s" : ""}`);
24676
25148
  return `${bits.join(", ")}.`;
24677
25149
  }
24678
- function clip4(s, n) {
25150
+ function clip5(s, n) {
24679
25151
  return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
24680
25152
  }
24681
25153
  function wrap5(s, perLine) {
@@ -24692,7 +25164,7 @@ function wrap5(s, perLine) {
24692
25164
  if (cur) lines.push(cur);
24693
25165
  if (lines.length > 3) {
24694
25166
  lines.length = 3;
24695
- lines[2] = clip4(lines[2], perLine);
25167
+ lines[2] = clip5(lines[2], perLine);
24696
25168
  }
24697
25169
  return lines.join("<br/>");
24698
25170
  }
@@ -25268,7 +25740,7 @@ function renderIdef0Layout(layout, config) {
25268
25740
  );
25269
25741
  const children = [
25270
25742
  chunk3WNW5Y7P_cjs.title(a11y),
25271
- chunk3WNW5Y7P_cjs.desc(summarise9(layout)),
25743
+ chunk3WNW5Y7P_cjs.desc(summarise10(layout)),
25272
25744
  styleBlock,
25273
25745
  chunk3WNW5Y7P_cjs.rect({ x: 0, y: 0, width, height, class: "sx-idef0-bg" })
25274
25746
  ];
@@ -25422,11 +25894,11 @@ function renderTitleBlock(width, height, node, title2) {
25422
25894
  chunk3WNW5Y7P_cjs.text({ x: x0 + 6, y: y + 13, class: "sx-idef0-tb-key" }, "NODE"),
25423
25895
  chunk3WNW5Y7P_cjs.text({ x: x0 + 6, y: y + 27, class: "sx-idef0-tb-text" }, node),
25424
25896
  chunk3WNW5Y7P_cjs.text({ x: c1 + 6, y: y + 13, class: "sx-idef0-tb-key" }, "TITLE"),
25425
- chunk3WNW5Y7P_cjs.text({ x: c1 + 6, y: y + 27, class: "sx-idef0-tb-text" }, clip5(title2 || "\u2014", 60)),
25897
+ chunk3WNW5Y7P_cjs.text({ x: c1 + 6, y: y + 27, class: "sx-idef0-tb-text" }, clip6(title2 || "\u2014", 60)),
25426
25898
  chunk3WNW5Y7P_cjs.text({ x: c2 + 6, y: y + 13, class: "sx-idef0-tb-key" }, "NUMBER")
25427
25899
  ]);
25428
25900
  }
25429
- function summarise9(layout) {
25901
+ function summarise10(layout) {
25430
25902
  const { ast } = layout;
25431
25903
  const counts = {};
25432
25904
  for (const a of ast.arrows) counts[a.role] = (counts[a.role] ?? 0) + 1;
@@ -25441,7 +25913,7 @@ function summarise9(layout) {
25441
25913
  for (const w of ast.warnings) parts.push(w);
25442
25914
  return parts.join(" ");
25443
25915
  }
25444
- function clip5(s, n) {
25916
+ function clip6(s, n) {
25445
25917
  return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
25446
25918
  }
25447
25919
  function wrap6(s, perLine) {
@@ -25460,7 +25932,7 @@ function wrap6(s, perLine) {
25460
25932
  if (cur) lines.push(cur);
25461
25933
  if (lines.length > 3) {
25462
25934
  lines.length = 3;
25463
- lines[2] = clip5(lines[2], perLine);
25935
+ lines[2] = clip6(lines[2], perLine);
25464
25936
  }
25465
25937
  return lines.join("<br/>");
25466
25938
  }
@@ -26087,7 +26559,7 @@ function renderThreatModelLayout(layout, config) {
26087
26559
  ]);
26088
26560
  const children = [
26089
26561
  chunk3WNW5Y7P_cjs.title(a11y),
26090
- chunk3WNW5Y7P_cjs.desc(summarise10(layout)),
26562
+ chunk3WNW5Y7P_cjs.desc(summarise11(layout)),
26091
26563
  styleBlock,
26092
26564
  markerDefs,
26093
26565
  chunk3WNW5Y7P_cjs.rect({ x: 0, y: 0, width, height, class: "sx-tm-bg" })
@@ -26304,7 +26776,7 @@ function arrowMarker2(id, cls, crossing) {
26304
26776
  function round8(n) {
26305
26777
  return Math.round(n * 100) / 100;
26306
26778
  }
26307
- function summarise10(layout) {
26779
+ function summarise11(layout) {
26308
26780
  const a = layout.analysis;
26309
26781
  const counts = {
26310
26782
  external: layout.nodes.filter((n) => n.kind === "external").length,
@@ -40557,7 +41029,7 @@ function renderPlaybookLayout(lay, config) {
40557
41029
  const surfaceBase = chunk3WNW5Y7P_cjs.rect({ class: surfaceCls, x: EDGE, y: r28(fieldTop), width: r28(fieldW), height: r28(fieldH), rx: fieldRx });
40558
41030
  const boundary = chunk3WNW5Y7P_cjs.rect({ class: boundaryCls, x: EDGE, y: r28(fieldTop), width: r28(fieldW), height: r28(fieldH), rx: fieldRx });
40559
41031
  const clipId = "sx-pb-clip";
40560
- const clip6 = chunk3WNW5Y7P_cjs.el("clipPath", { id: clipId }, [chunk3WNW5Y7P_cjs.rect({ x: EDGE, y: r28(fieldTop), width: r28(fieldW), height: r28(fieldH), rx: fieldRx })]);
41032
+ const clip7 = chunk3WNW5Y7P_cjs.el("clipPath", { id: clipId }, [chunk3WNW5Y7P_cjs.rect({ x: EDGE, y: r28(fieldTop), width: r28(fieldW), height: r28(fieldH), rx: fieldRx })]);
40561
41033
  const field = chunk3WNW5Y7P_cjs.group({ "clip-path": `url(#${clipId})` }, [mod.drawField(lay, ctx, t)]);
40562
41034
  const zones = [];
40563
41035
  for (const z of lay.zones) {
@@ -40585,7 +41057,7 @@ function renderPlaybookLayout(lay, config) {
40585
41057
  chunk3WNW5Y7P_cjs.desc(descText),
40586
41058
  chunk3WNW5Y7P_cjs.el("style", {}, buildCss14(t)),
40587
41059
  chunk3WNW5Y7P_cjs.rect({ fill: t.bg, x: 0, y: 0, width: W2, height: H2 }),
40588
- chunk3WNW5Y7P_cjs.el("defs", {}, [clip6]),
41060
+ chunk3WNW5Y7P_cjs.el("defs", {}, [clip7]),
40589
41061
  chunk3WNW5Y7P_cjs.text({ class: "sx-pb-title", x: r28(W2 / 2), y: chunkENUM7GMZ_cjs.TITLE.y, "text-anchor": "middle" }, lay.title),
40590
41062
  ...annoParts,
40591
41063
  surround,
@@ -40877,5 +41349,5 @@ exports.timeline = timeline;
40877
41349
  exports.umlclass = umlclass;
40878
41350
  exports.usecase = usecase;
40879
41351
  exports.welding = welding;
40880
- //# sourceMappingURL=chunk-Q7CWX6HA.cjs.map
40881
- //# sourceMappingURL=chunk-Q7CWX6HA.cjs.map
41352
+ //# sourceMappingURL=chunk-6X7MVZZT.cjs.map
41353
+ //# sourceMappingURL=chunk-6X7MVZZT.cjs.map