@buun_group/plotwork-mcp 0.1.0-beta.3 → 0.1.0-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/plotwork-mcp.mjs CHANGED
@@ -51,7 +51,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
51
51
  var package_default;
52
52
  var init_package = __esm({
53
53
  "package.json"() {
54
- package_default = { version: "0.1.0-beta.3" };
54
+ package_default = { version: "0.1.0-beta.5" };
55
55
  }
56
56
  });
57
57
 
@@ -273,6 +273,21 @@ var init_overlays = __esm({
273
273
  }
274
274
  });
275
275
 
276
+ // ../../packages/diagrams/src/constants/node-change.ts
277
+ var NODE_CHANGES, NODE_CHANGE_SPECS;
278
+ var init_node_change = __esm({
279
+ "../../packages/diagrams/src/constants/node-change.ts"() {
280
+ "use strict";
281
+ NODE_CHANGES = ["create", "update", "replace", "destroy"];
282
+ NODE_CHANGE_SPECS = {
283
+ create: { tone: "green", sign: "+", meaning: "made by the change" },
284
+ update: { tone: "amber", sign: "~", meaning: "changed in place" },
285
+ replace: { tone: "orange", sign: "\xB1", meaning: "destroyed and made again" },
286
+ destroy: { tone: "red", sign: "\u2212", meaning: "destroyed by the change" }
287
+ };
288
+ }
289
+ });
290
+
276
291
  // ../../packages/diagrams/src/constants/node-stack.ts
277
292
  var STACK_LIMIT;
278
293
  var init_node_stack = __esm({
@@ -628,12 +643,30 @@ var init_view_links = __esm({
628
643
  };
629
644
  CLI_RELEASE = {
630
645
  packageName: "@buun_group/plotwork",
631
- version: "0.1.0-beta.2",
646
+ version: "0.1.0-beta.6",
632
647
  onNpm: true
633
648
  };
634
649
  }
635
650
  });
636
651
 
652
+ // ../../packages/diagrams/src/constants/mcp-release.ts
653
+ function mcpPackagePin(release = MCP_RELEASE) {
654
+ return `${release.packageName}@${release.version}`;
655
+ }
656
+ function mcpCommand(release = MCP_RELEASE) {
657
+ return `npx -y ${mcpPackagePin(release)}`;
658
+ }
659
+ var MCP_RELEASE;
660
+ var init_mcp_release = __esm({
661
+ "../../packages/diagrams/src/constants/mcp-release.ts"() {
662
+ "use strict";
663
+ MCP_RELEASE = {
664
+ packageName: "@buun_group/plotwork-mcp",
665
+ version: "0.1.0-beta.4"
666
+ };
667
+ }
668
+ });
669
+
637
670
  // ../../packages/diagrams/src/constants/layout-limits.ts
638
671
  var LAYOUT_LIMITS;
639
672
  var init_layout_limits = __esm({
@@ -709,7 +742,7 @@ var init_style_rules = __esm({
709
742
  /** The address of the JSON Schema an editor reads from `$schema`; the docs app serves it. Nothing in Plotwork fetches it. */
710
743
  schemaUrl: "https://docs.plotwork.dev/schemas/plotwork.config.json",
711
744
  /** The largest settings file read, in bytes. */
712
- maxBytes: 65536,
745
+ maxBytes: 262144,
713
746
  /** The longest value a header default may have, in characters. */
714
747
  maxValueLength: 200
715
748
  };
@@ -723,7 +756,7 @@ var init_generate = __esm({
723
756
  "use strict";
724
757
  GENERATE = {
725
758
  /** The most sources one settings file lists. */
726
- maxSources: 50,
759
+ maxSources: 250,
727
760
  /** The most patterns one source's `from` lists. */
728
761
  maxPatterns: 20,
729
762
  /** The most files one source reads, after its patterns are expanded. */
@@ -736,6 +769,8 @@ var init_generate = __esm({
736
769
  maxOverrideEntries: 500,
737
770
  /** The address of the JSON Schema of an overrides file, for editors; the docs app serves it, and Plotwork never fetches it. */
738
771
  overridesSchemaUrl: "https://docs.plotwork.dev/schemas/plotwork.overrides.json",
772
+ /** The address of the JSON Schema of the report `generate --format json` and the Action's `report-file` write; the docs app serves it. */
773
+ reportSchemaUrl: "https://docs.plotwork.dev/schemas/plotwork.report.json",
739
774
  /** The first words of the comment a generated diagram starts with, by which it is told apart from a hand-written one. */
740
775
  banner: "# Generated by plotwork generate",
741
776
  /** The trailer of a commit the GitHub Action writes, by which its next run knows the push was its own and stops a loop. */
@@ -3515,6 +3550,7 @@ var init_constants = __esm({
3515
3550
  init_flow_node_types();
3516
3551
  init_group_types();
3517
3552
  init_overlays();
3553
+ init_node_change();
3518
3554
  init_node_stack();
3519
3555
  init_line_options();
3520
3556
  init_line_roles();
@@ -3525,6 +3561,7 @@ var init_constants = __esm({
3525
3561
  init_editing();
3526
3562
  init_diagram_links();
3527
3563
  init_view_links();
3564
+ init_mcp_release();
3528
3565
  init_layout_limits();
3529
3566
  init_lint_limits();
3530
3567
  init_style_rules();
@@ -3807,13 +3844,14 @@ var init_diagnostics = __esm({
3807
3844
  settingIgnored: "S200",
3808
3845
  // Generated diagrams (src/generate). S101-S104 stop one source: a source the run cannot use, an overrides file that does not check,
3809
3846
  // a source whose files are missing, a Markdown fence that is not there. S201-S202 are warnings: an override whose target is gone, and
3810
- // one the diagram could not take.
3847
+ // one the diagram could not take. S203 is an overrides file a source names that is not there.
3811
3848
  sourceInvalid: "S101",
3812
3849
  overridesInvalid: "S102",
3813
3850
  sourceNoFiles: "S103",
3814
3851
  fenceMissing: "S104",
3815
3852
  overrideStale: "S201",
3816
- overrideRefused: "S202"
3853
+ overrideRefused: "S202",
3854
+ overridesMissing: "S203"
3817
3855
  };
3818
3856
  }
3819
3857
  });
@@ -4021,20 +4059,20 @@ function customIconNamedBy(text3) {
4021
4059
  if (index2 === null) return null;
4022
4060
  const phrase2 = normalizePhrase(text3);
4023
4061
  if (phrase2 === "") return null;
4024
- const hits = [...index2.phrases].filter(([, names7]) => names7.has(phrase2)).map(([name2]) => name2);
4062
+ const hits = [...index2.phrases].filter(([, names8]) => names8.has(phrase2)).map(([name2]) => name2);
4025
4063
  return hits.length === 1 ? `${ORG_ICON_SET}:${hits[0]}` : null;
4026
4064
  }
4027
4065
  function scoreCustomIcons(phrase2, words2, scores2) {
4028
4066
  const index2 = activeIndex();
4029
4067
  if (index2 === null || words2.length === 0) return [];
4030
4068
  const found = [];
4031
- for (const [name2, names7] of index2.phrases) {
4069
+ for (const [name2, names8] of index2.phrases) {
4032
4070
  const ref = `${ORG_ICON_SET}:${name2}`;
4033
- if (names7.has(phrase2)) {
4071
+ if (names8.has(phrase2)) {
4034
4072
  found.push({ ref, score: scores2.exact });
4035
4073
  continue;
4036
4074
  }
4037
- const all = [...names7];
4075
+ const all = [...names8];
4038
4076
  if (words2.length > 1 && all.some((candidate2) => ` ${candidate2} `.includes(` ${phrase2} `))) {
4039
4077
  found.push({ ref, score: scores2.phrase });
4040
4078
  continue;
@@ -6732,8 +6770,8 @@ var init_search_scores = __esm({
6732
6770
  // ../../packages/diagrams/src/icons/search.ts
6733
6771
  function buildConceptEntries() {
6734
6772
  const entries2 = /* @__PURE__ */ new Map();
6735
- for (const [phrase2, names7] of Object.entries(ICON_CONCEPTS)) {
6736
- names7.forEach((name2, position) => {
6773
+ for (const [phrase2, names8] of Object.entries(ICON_CONCEPTS)) {
6774
+ names8.forEach((name2, position) => {
6737
6775
  const existing = entries2.get(name2);
6738
6776
  entries2.set(name2, {
6739
6777
  words: [...existing?.words ?? [], ...phrase2.split(/\s+/)],
@@ -101543,6 +101581,14 @@ var init_metrics = __esm({
101543
101581
  stackGap: 6,
101544
101582
  stackTop: 8,
101545
101583
  borderWidth: 1,
101584
+ /** A node with `change=`: its outline in the change's tone, this wide, and a round badge on its top edge with the change's sign. */
101585
+ changeBorderWidth: 2,
101586
+ changeBadgeRadius: 8,
101587
+ /** From the card's right edge to the badge's centre; the badge sits in the top padding, so it never covers text. */
101588
+ changeBadgeInset: 18,
101589
+ /** Half the length of each stroke of the sign in the badge. */
101590
+ changeSignHalf: 4,
101591
+ changeSignWidth: 1.75,
101546
101592
  maxLabelLines: 3,
101547
101593
  /** Pills, used for terminal nodes such as "Done" or "Access denied". */
101548
101594
  pillPaddingX: 22,
@@ -104816,9 +104862,9 @@ function providerSetFor(guess) {
104816
104862
  return CLOUD_SETS.find((set2) => set2 === lowered || CLOUD_PROVIDER_SPECS[set2].misspellings.includes(lowered));
104817
104863
  }
104818
104864
  function nearestIcon(set2, name2) {
104819
- const names7 = listSetNames(set2);
104820
- const handWritten = names7.filter((candidate2) => findIcon(`${set2}:${candidate2}`)?.vendor === void 0);
104821
- const spelled = suggest(name2, handWritten) ?? suggest(name2, names7, VENDOR_SPELLING_DISTANCE);
104865
+ const names8 = listSetNames(set2);
104866
+ const handWritten = names8.filter((candidate2) => findIcon(`${set2}:${candidate2}`)?.vendor === void 0);
104867
+ const spelled = suggest(name2, handWritten) ?? suggest(name2, names8, VENDOR_SPELLING_DISTANCE);
104822
104868
  if (spelled !== null) return { ref: `${set2}:${spelled}`, isSpelling: true };
104823
104869
  const found = searchIcons(name2.replace(/-/g, " "), 3);
104824
104870
  const best = found.find((ref) => ref.startsWith(`${set2}:`)) ?? found[0];
@@ -104841,11 +104887,11 @@ function orgIconHint(name2) {
104841
104887
  if (!hasCustomIcons()) {
104842
104888
  return `org: icons are an organisation's own icons. They draw only on the hosted service, for a caller in an organisation that uploaded them; the local package has none. ${FIND_HINT}`;
104843
104889
  }
104844
- const names7 = listCustomIconNames();
104845
- const spelled = suggest(name2, names7);
104890
+ const names8 = listCustomIconNames();
104891
+ const spelled = suggest(name2, names8);
104846
104892
  if (spelled !== null) return `Did you mean "${ORG_ICON_SET}:${spelled}"?`;
104847
- const shown = names7.slice(0, ORG_NAMES_IN_HINT).map((candidate2) => `${ORG_ICON_SET}:${candidate2}`);
104848
- const more = names7.length > shown.length ? ` and ${names7.length - shown.length} more` : "";
104893
+ const shown = names8.slice(0, ORG_NAMES_IN_HINT).map((candidate2) => `${ORG_ICON_SET}:${candidate2}`);
104894
+ const more = names8.length > shown.length ? ` and ${names8.length - shown.length} more` : "";
104849
104895
  return `Your organisation has no icon named "${name2}". Its icons: ${shown.join(", ")}${more}. ${FIND_HINT}`;
104850
104896
  }
104851
104897
  function iconHint(value) {
@@ -105257,13 +105303,13 @@ function parseRelationship(cursor, state, line3) {
105257
105303
  function resolveRelationships(state) {
105258
105304
  const elementIds = new Set(state.elements.map((element) => element.id));
105259
105305
  const boundaryIds = new Set(state.boundaries.map((boundary) => boundary.id));
105260
- const names7 = [...elementIds];
105306
+ const names8 = [...elementIds];
105261
105307
  const resolved = [];
105262
105308
  let suggested = 0;
105263
105309
  for (const pending of state.pending) {
105264
105310
  const missing = [pending.from, pending.to].filter((end) => !elementIds.has(end.text));
105265
105311
  for (const end of missing) {
105266
- const guess = suggested < SUGGESTIONS ? `${didYouMean(end.text, names7)} ` : "";
105312
+ const guess = suggested < SUGGESTIONS ? `${didYouMean(end.text, names8)} ` : "";
105267
105313
  suggested += 1;
105268
105314
  const message2 = boundaryIds.has(end.text) ? `"${end.text}" is a boundary, and a relationship joins elements` : `Unknown element "${end.text}"`;
105269
105315
  state.report.push(errorAt(DIAGNOSTIC_CODES.unknownNode, message2, spanOf2(end), `${guess}Declare it first with: container ${end.text} "Name"`));
@@ -106745,9 +106791,9 @@ function runsAlongside(moved3, others, axis) {
106745
106791
  if (!isRun && !isBar) continue;
106746
106792
  const own2 = isRun ? [axis.along(a), axis.along(b)] : [axis.cross(a), axis.cross(b)];
106747
106793
  const theirs = isRun ? [axis.along(c), axis.along(d)] : [axis.cross(c), axis.cross(d)];
106748
- const overlaps7 = Math.min(...own2) < Math.max(...theirs) - 2 && Math.max(...own2) > Math.min(...theirs) + 2;
106794
+ const overlaps8 = Math.min(...own2) < Math.max(...theirs) - 2 && Math.max(...own2) > Math.min(...theirs) + 2;
106749
106795
  const gap2 = isRun ? Math.abs(axis.cross(a) - axis.cross(c)) : Math.abs(axis.along(a) - axis.along(c));
106750
- if (overlaps7 && gap2 < PARALLEL_GAP) return true;
106796
+ if (overlaps8 && gap2 < PARALLEL_GAP) return true;
106751
106797
  }
106752
106798
  }
106753
106799
  }
@@ -109453,6 +109499,60 @@ var init_fan_order = __esm({
109453
109499
  }
109454
109500
  });
109455
109501
 
109502
+ // ../../packages/diagrams/src/layout/flow/label-separation.ts
109503
+ function changeBadgeRect(card5) {
109504
+ const r = NODE_METRICS.changeBadgeRadius;
109505
+ return { x: card5.x + card5.width - NODE_METRICS.changeBadgeInset - r, y: card5.y - r, width: 2 * r, height: 2 * r };
109506
+ }
109507
+ function straddles(label, frame) {
109508
+ if (!overlaps3(label, frame, 0)) return false;
109509
+ const inside = label.x >= frame.x && label.y >= frame.y && label.x + label.width <= frame.x + frame.width && label.y + label.height <= frame.y + frame.height;
109510
+ const holds = frame.x >= label.x && frame.y >= label.y && frame.x + frame.width <= label.x + label.width && frame.y + frame.height <= label.y + label.height;
109511
+ return !inside && !holds;
109512
+ }
109513
+ function placesOn(points, rect, from) {
109514
+ const out = [];
109515
+ for (let index2 = 1; index2 < points.length; index2 += 1) {
109516
+ const a = points[index2 - 1];
109517
+ const b = points[index2];
109518
+ const vertical = Math.abs(a.x - b.x) < 1;
109519
+ if (!vertical && Math.abs(a.y - b.y) >= 1) continue;
109520
+ const half = (vertical ? rect.height : rect.width) / 2 + RUN_END_ROOM;
109521
+ const [low, high] = vertical ? [Math.min(a.y, b.y), Math.max(a.y, b.y)] : [Math.min(a.x, b.x), Math.max(a.x, b.x)];
109522
+ for (let at3 = low + half; at3 <= high - half; at3 += STEP) out.push(vertical ? { x: a.x, y: at3 } : { x: at3, y: a.y });
109523
+ }
109524
+ const distance4 = (point) => Math.abs(point.x - from.x) + Math.abs(point.y - from.y);
109525
+ return out.sort((p, q) => distance4(p) - distance4(q) || p.y - q.y || p.x - q.x);
109526
+ }
109527
+ function separateLabels(edges, obstacles) {
109528
+ const settled = [];
109529
+ const clear = (rect, gap2) => !settled.some((other) => overlaps3(rect, other, gap2)) && !obstacles.nodes.some((node3) => overlaps3(rect, node3, gap2)) && !obstacles.tabs.some((tab) => overlaps3(rect, tab, gap2)) && !(obstacles.badges ?? []).some((badge) => overlaps3(rect, badge, gap2)) && !obstacles.frames.some((frame) => straddles(rect, frame));
109530
+ return edges.map((edge) => {
109531
+ if (edge.label === null) return edge;
109532
+ const rect = edge.label.rect;
109533
+ if (clear(rect, 0)) {
109534
+ settled.push(rect);
109535
+ return edge;
109536
+ }
109537
+ const place2 = placesOn(edge.points, rect, centreOf(rect)).map((point) => centredAt(rect, point)).find((candidate2) => clear(candidate2, LABEL_GAP4));
109538
+ settled.push(place2 ?? rect);
109539
+ return place2 === void 0 ? edge : { ...edge, label: { ...edge.label, rect: place2 } };
109540
+ });
109541
+ }
109542
+ var LABEL_GAP4, RUN_END_ROOM, STEP, overlaps3, centreOf, centredAt;
109543
+ var init_label_separation = __esm({
109544
+ "../../packages/diagrams/src/layout/flow/label-separation.ts"() {
109545
+ "use strict";
109546
+ init_theme();
109547
+ LABEL_GAP4 = 4;
109548
+ RUN_END_ROOM = 6;
109549
+ STEP = 4;
109550
+ overlaps3 = (a, b, gap2) => a.x < b.x + b.width + gap2 && b.x < a.x + a.width + gap2 && a.y < b.y + b.height + gap2 && b.y < a.y + a.height + gap2;
109551
+ centreOf = (rect) => ({ x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 });
109552
+ centredAt = (rect, point) => ({ ...rect, x: point.x - rect.width / 2, y: point.y - rect.height / 2 });
109553
+ }
109554
+ });
109555
+
109456
109556
  // ../../packages/diagrams/src/layout/flow/level-edges.ts
109457
109557
  function ancestorsOf(diagram, edge, id) {
109458
109558
  const found = /* @__PURE__ */ new Set();
@@ -109632,14 +109732,14 @@ var init_canvas_room = __esm({
109632
109732
  });
109633
109733
 
109634
109734
  // ../../packages/diagrams/src/layout/flow/overlay-tab.ts
109635
- function overlaps3(a, b) {
109735
+ function overlaps4(a, b) {
109636
109736
  return a.x < b.x + b.width && b.x < a.x + a.width && a.y < b.y + b.height && b.y < a.y + a.height;
109637
109737
  }
109638
109738
  function grown(frame, amount) {
109639
109739
  return { x: frame.x - amount, y: frame.y - amount, width: frame.width + amount * 2, height: frame.height + amount * 2 };
109640
109740
  }
109641
109741
  function freeStretch(frame, size, obstacles, clearance) {
109642
- const blocker = (x2) => obstacles.find((other) => overlaps3({ x: x2, y: frame.y, width: size.width, height: size.height }, grown(other, clearance)));
109742
+ const blocker = (x2) => obstacles.find((other) => overlaps4({ x: x2, y: frame.y, width: size.width, height: size.height }, grown(other, clearance)));
109643
109743
  let x = frame.x;
109644
109744
  for (let found = blocker(x); found !== void 0; found = blocker(x)) {
109645
109745
  x = found.x + found.width + GROUP_METRICS.overlayTabGap;
@@ -109650,7 +109750,7 @@ function freeStretch(frame, size, obstacles, clearance) {
109650
109750
  function grazes(frame, groups) {
109651
109751
  const near3 = (a, b) => Math.abs(a - b) < FRAME_CLEARANCE;
109652
109752
  return groups.some((group2) => {
109653
- if (!overlaps3(frame, group2)) return false;
109753
+ if (!overlaps4(frame, group2)) return false;
109654
109754
  const sides = [frame.x, frame.x + frame.width];
109655
109755
  const groupSides = [group2.x, group2.x + group2.width];
109656
109756
  const tops = [frame.y, frame.y + frame.height];
@@ -109958,6 +110058,10 @@ function placeLevelEdges(diagram, level2, nodes, direction) {
109958
110058
  return placed === null ? [] : [placed];
109959
110059
  });
109960
110060
  }
110061
+ function changeBadges(diagram, nodes) {
110062
+ const changed = new Set(diagram.nodes.filter((node3) => node3.change !== void 0).map((node3) => node3.id));
110063
+ return nodes.filter((node3) => changed.has(node3.id)).map((node3) => changeBadgeRect(node3.rect));
110064
+ }
109961
110065
  async function layoutWith2(diagram, boxes2, direction) {
109962
110066
  const level2 = levelEdgeIds(diagram);
109963
110067
  const laidOut2 = await runElk3(diagram, boxes2, direction, level2);
@@ -109982,9 +110086,10 @@ async function layoutWith2(diagram, boxes2, direction) {
109982
110086
  overlays,
109983
110087
  overlayCovers: spanned.covers,
109984
110088
  // A stretch moved off a tab can land past a sibling edge's stub; that stub then steps past it, so the two do not cross by their node.
109985
- edges: orderStubs(routes.map((edge) => routeAroundTabs2(edge, tabRects, nodeRects)), nodeRects, tabRects)
110089
+ // Last, so no later step moves a label back onto another: two labels never cover each other, a node, a tab, or a frame's border.
110090
+ edges: separateLabels(orderStubs(routes.map((edge) => routeAroundTabs2(edge, tabRects, nodeRects)), nodeRects, tabRects), { nodes: nodeRects, tabs: tabRects, frames: shapes2.groups.map((group2) => group2.rect), badges: changeBadges(diagram, shapes2.nodes) })
109986
110091
  };
109987
- return makeRoomFor(layout, spanned.grown);
110092
+ return makeRoomFor(layout, [...spanned.grown, ...layout.edges.flatMap((edge) => edge.label === null ? [] : [edge.label.rect])]);
109988
110093
  }
109989
110094
  async function layoutFlowOnce(diagram) {
109990
110095
  const boxes2 = evenFlowBoxes(diagram, new Map(diagram.nodes.map((node3) => [node3.id, sizeNode(node3)])));
@@ -110007,6 +110112,7 @@ var init_layout_flow = __esm({
110007
110112
  init_end_room();
110008
110113
  init_elk_graph();
110009
110114
  init_fan_order();
110115
+ init_label_separation();
110010
110116
  init_large_diagram();
110011
110117
  init_level_edges();
110012
110118
  init_level_route();
@@ -110027,7 +110133,8 @@ var init_layout_flow = __esm({
110027
110133
  function nodeLine(node3) {
110028
110134
  const detail = node3.sub === null ? "" : ` (${node3.sub})`;
110029
110135
  const stack = node3.stack.length === 0 ? "" : `, stack: ${markNames(node3.stack)}`;
110030
- return `${node3.label}${detail}, ${node3.type}${stack}`;
110136
+ const change = node3.change === void 0 ? "" : `, change: ${node3.change}`;
110137
+ return `${node3.label}${detail}, ${node3.type}${stack}${change}`;
110031
110138
  }
110032
110139
  function groupLine(group2) {
110033
110140
  const kind = group2.type === null ? "Group" : GROUP_TYPE_SPECS[group2.type].title;
@@ -110326,11 +110433,12 @@ function parseNodeStatement(cursor, state, line3, group2) {
110326
110433
  const labelToken = cursor.peek();
110327
110434
  const label = readLabel(cursor, state, line3, "label");
110328
110435
  const options3 = readOptions(cursor, NODE_OPTIONS, state.report, { lists: ["stack"] });
110329
- rejectTrailing(cursor, state, 'A node is: node id type "Label" sub="..." icon=lucide:name tone=blue stack=simple:angular,simple:typescript');
110436
+ rejectTrailing(cursor, state, 'A node is: node id type "Label" sub="..." icon=lucide:name tone=blue stack=simple:angular,simple:typescript change=update');
110330
110437
  if (id === null || type === void 0 || label === null) return;
110331
110438
  const defaults = FLOW_NODE_TYPE_DEFAULTS[type];
110332
110439
  const sub = findOption(options3, "sub")?.value ?? null;
110333
110440
  const iconOption2 = findOption(options3, "icon");
110441
+ const change = resolveChange(findOption(options3, "change"), state);
110334
110442
  state.nodes.push({
110335
110443
  id: toNodeId(id.text),
110336
110444
  type,
@@ -110340,10 +110448,17 @@ function parseNodeStatement(cursor, state, line3, group2) {
110340
110448
  icon: nodeIcon(iconOption2, type, [label, sub], group2, state),
110341
110449
  hasOwnIcon: iconOption2 !== void 0,
110342
110450
  stack: resolveStack(findOption(options3, "stack"), state, defaults.shape === "card"),
110451
+ ...change === null ? {} : { change },
110343
110452
  group: group2,
110344
110453
  labelAt: spanOf4(labelToken)
110345
110454
  });
110346
110455
  }
110456
+ function resolveChange(option, state) {
110457
+ if (option === void 0) return null;
110458
+ const found = NODE_CHANGES.find((candidate2) => candidate2 === option.value);
110459
+ if (found === void 0) state.report.push(errorAt(DIAGNOSTIC_CODES.badOptionValue, `Unknown change "${option.value}"`, option.valueToken, didYouMean(option.value, NODE_CHANGES)));
110460
+ return found ?? null;
110461
+ }
110347
110462
  function providerAround(group2, state) {
110348
110463
  if (group2 === null) return state.provider;
110349
110464
  return state.groups.find((candidate2) => candidate2.id === group2)?.provider ?? state.provider;
@@ -110452,7 +110567,7 @@ var init_flow_statements = __esm({
110452
110567
  init_statement_helpers();
110453
110568
  init_suggest();
110454
110569
  init_token_cursor();
110455
- NODE_OPTIONS = ["sub", "icon", "tone", "stack"];
110570
+ NODE_OPTIONS = ["sub", "icon", "tone", "stack", "change"];
110456
110571
  MOVED_GROUP_OPTIONS = { boundary: "A trust boundary is now a group type: write type=trust-boundary." };
110457
110572
  EDGE_OPTIONS = ["icon", "role", ...LINE_MOTION_OPTIONS];
110458
110573
  HEADER_OPTIONS2 = ["direction", "desc", "provider", "legend", "icons", ...HEADER_MOTION_OPTIONS];
@@ -110671,7 +110786,7 @@ function runsOf2(edges) {
110671
110786
  }
110672
110787
  return { horizontal, vertical };
110673
110788
  }
110674
- function overlaps4(a, b, margin) {
110789
+ function overlaps5(a, b, margin) {
110675
110790
  return a.x - margin < b.x + b.width && a.x + a.width + margin > b.x && a.y - margin < b.y + b.height && a.y + a.height + margin > b.y;
110676
110791
  }
110677
110792
  function findFlowHops(edges, nodes) {
@@ -110696,7 +110811,7 @@ function findFlowHops(edges, nodes) {
110696
110811
  const key = `${run3.edge}|${run3.y.toFixed(2)}|${x.toFixed(2)}`;
110697
110812
  if (seen.has(key)) continue;
110698
110813
  const arc = { x: x - radius, y: run3.y - radius, width: radius * 2, height: radius };
110699
- if (obstacles.some((obstacle) => overlaps4(arc, obstacle, BREATHING))) continue;
110814
+ if (obstacles.some((obstacle) => overlaps5(arc, obstacle, BREATHING))) continue;
110700
110815
  const isCrowded = vertical.some((side) => side !== other && Math.abs(side.x - x) >= SAME_LINE5 && Math.abs(side.x - x) < radius * 2 + BREATHING && run3.y > side.low && run3.y < side.high);
110701
110816
  if (isCrowded) continue;
110702
110817
  const isTrunk = horizontal.some((side) => side.edge !== run3.edge && Math.abs(side.y - run3.y) < BREATHING && x > side.low && x < side.high);
@@ -110722,13 +110837,36 @@ var init_crossings = __esm({
110722
110837
  // ../../packages/diagrams/src/render/flow/paint-node.ts
110723
110838
  function outlineAttrs(frame, stroke) {
110724
110839
  const defaults = FLOW_NODE_TYPE_DEFAULTS[frame.node.type];
110840
+ const change = frame.node.change;
110725
110841
  return {
110726
- stroke,
110727
- "stroke-width": NODE_METRICS.borderWidth,
110842
+ stroke: change === void 0 ? stroke : frame.theme.tones[NODE_CHANGE_SPECS[change].tone].outline,
110843
+ "stroke-width": change === void 0 ? NODE_METRICS.borderWidth : NODE_METRICS.changeBorderWidth,
110728
110844
  "stroke-dasharray": defaults.isDashed ? "4 3" : null,
110729
110845
  filter: defaults.isDashed ? null : LIFT
110730
110846
  };
110731
110847
  }
110848
+ function signPath(change, x, y) {
110849
+ const h = NODE_METRICS.changeSignHalf;
110850
+ switch (NODE_CHANGE_SPECS[change].sign) {
110851
+ case "+":
110852
+ return `M${x - h} ${y}H${x + h}M${x} ${y - h}V${y + h}`;
110853
+ case "\u2212":
110854
+ return `M${x - h} ${y}H${x + h}`;
110855
+ case "\xB1":
110856
+ return `M${x - h} ${y - 1}H${x + h}M${x} ${y - h - 1}V${y + h - 3}M${x - h} ${y + h}H${x + h}`;
110857
+ case "~":
110858
+ return `M${x - h - 0.5} ${y + 1}q${h / 2 + 0.25} ${-h + 0.5} ${h + 0.5} -1t${h + 0.5} -1`;
110859
+ }
110860
+ }
110861
+ function paintChangeBadge(change, rect, theme) {
110862
+ const badge = changeBadgeRect(rect);
110863
+ const cx = badge.x + badge.width / 2;
110864
+ const fill = theme.tones[NODE_CHANGE_SPECS[change].tone].outline;
110865
+ return el("g", { "data-change": change }, [
110866
+ el("circle", { cx, cy: rect.y, r: NODE_METRICS.changeBadgeRadius, fill, stroke: theme.surface, "stroke-width": NODE_METRICS.borderWidth * 1.5 }),
110867
+ el("path", { d: signPath(change, cx, rect.y), fill: "none", stroke: theme.surface, "stroke-width": NODE_METRICS.changeSignWidth, "stroke-linecap": "round", "stroke-linejoin": "round" })
110868
+ ]);
110869
+ }
110732
110870
  function isTintedCard(node3) {
110733
110871
  const defaults = FLOW_NODE_TYPE_DEFAULTS[node3.type];
110734
110872
  return defaults.isTinted || defaults.icon === null && node3.icon === null && node3.tone !== "neutral";
@@ -110764,6 +110902,7 @@ function paintCard(frame) {
110764
110902
  parts.push(paintTextBlock({ x: x + textLeft, top: subTop, lines: placed.subLines, role: "sub", color: theme.inkSecondary }));
110765
110903
  }
110766
110904
  if (node3.stack.length > 0) parts.push(...paintMarks(node3.stack, x + textLeft, top + textHeight3 + NODE_METRICS.stackTop, theme, theme.tones.neutral.chipFill));
110905
+ if (node3.change !== void 0) parts.push(paintChangeBadge(node3.change, placed.rect, theme));
110767
110906
  return el("g", { "data-node": node3.id, "data-type": node3.type }, parts);
110768
110907
  }
110769
110908
  function paintPill(frame) {
@@ -110781,6 +110920,7 @@ function paintPill(frame) {
110781
110920
  const textX2 = inset2 + NODE_METRICS.pillPaddingX + NODE_METRICS.iconSize + NODE_METRICS.pillIconGap;
110782
110921
  parts.push(paintTextBlock({ x: textX2, top, lines: placed.labelLines, role: "label", color: theme.ink }));
110783
110922
  }
110923
+ if (node3.change !== void 0) parts.push(paintChangeBadge(node3.change, placed.rect, theme));
110784
110924
  return el("g", { "data-node": node3.id, "data-type": node3.type }, parts);
110785
110925
  }
110786
110926
  function paintNode(node3, placed, theme) {
@@ -110797,6 +110937,7 @@ var init_paint_node = __esm({
110797
110937
  init_core();
110798
110938
  init_icons();
110799
110939
  init_theme();
110940
+ init_label_separation();
110800
110941
  init_size_node();
110801
110942
  init_svg2();
110802
110943
  init_paint_marks();
@@ -112456,8 +112597,8 @@ var init_flowchart_statements = __esm({
112456
112597
  function resolve(declaration) {
112457
112598
  const fill = [...declaration.properties].reverse().find((property) => property.name === "fill")?.value ?? null;
112458
112599
  const tone = fill === null ? null : toneForColour(fill);
112459
- const names7 = declaration.properties.map((property) => property.name).filter((name2) => name2 !== "fill");
112460
- const leftOut = [...new Set(names7)];
112600
+ const names8 = declaration.properties.map((property) => property.name).filter((name2) => name2 !== "fill");
112601
+ const leftOut = [...new Set(names8)];
112461
112602
  if (fill !== null && tone === null) leftOut.unshift(`fill ${fill} has no tone`);
112462
112603
  return { tone, fill, leftOut };
112463
112604
  }
@@ -113884,12 +114025,12 @@ function readTick(rest) {
113884
114025
  return { unit: null, note: count3 === 1 ? `a step of one ${name2} is shorter than a day` : `a step of ${count3} ${name2}s has no Plotwork form` };
113885
114026
  }
113886
114027
  function readExcludes(rest, reader, statement, ctx) {
113887
- const names7 = rest.toLowerCase().split(/[\s,]+/).filter((name2) => name2 !== "");
114028
+ const names8 = rest.toLowerCase().split(/[\s,]+/).filter((name2) => name2 !== "");
113888
114029
  const days = [];
113889
114030
  const weekdays = /* @__PURE__ */ new Set();
113890
114031
  const unread = [];
113891
114032
  let weekends = false;
113892
- for (const name2 of names7) {
114033
+ for (const name2 of names8) {
113893
114034
  const day = reader(name2);
113894
114035
  if (name2 === "weekends") weekends = true;
113895
114036
  else if (WEEKDAYS.some((weekday) => weekday === name2)) weekdays.add(name2);
@@ -114606,8 +114747,8 @@ function reportCycles(items2, waiting, report3) {
114606
114747
  const loop = path.slice(path.indexOf(current));
114607
114748
  const closing = loop[loop.length - 1];
114608
114749
  const token = closing.after.find((candidate2) => candidate2.text === current?.idToken.text) ?? closing.idToken;
114609
- const names7 = [...loop, current].map((item) => item.idToken.text).join(" -> ");
114610
- report3.push(errorAt(DIAGNOSTIC_CODES.ganttCycle, `Tasks wait for each other in a circle: ${names7}`, token, "Remove one after= so the chain has a first task that starts on a fixed day."));
114750
+ const names8 = [...loop, current].map((item) => item.idToken.text).join(" -> ");
114751
+ report3.push(errorAt(DIAGNOSTIC_CODES.ganttCycle, `Tasks wait for each other in a circle: ${names8}`, token, "Remove one after= so the chain has a first task that starts on a fixed day."));
114611
114752
  for (const item of path) covered.add(item.idToken.text);
114612
114753
  }
114613
114754
  }
@@ -117365,10 +117506,10 @@ function initialsCandidates(name2) {
117365
117506
  const candidates2 = [upper(lead), capital2, `${capital2}${first.slice(2, 3).join("").toLowerCase()}`, upper(words2.slice(0, 3).map((word2) => word2[0] ?? ""))];
117366
117507
  return candidates2.filter((candidate2, index2) => candidate2 !== "" && candidates2.indexOf(candidate2) === index2);
117367
117508
  }
117368
- function assignInitials(names7) {
117509
+ function assignInitials(names8) {
117369
117510
  const taken = /* @__PURE__ */ new Set();
117370
117511
  const counters = /* @__PURE__ */ new Map();
117371
- return names7.map((name2) => {
117512
+ return names8.map((name2) => {
117372
117513
  const candidates2 = initialsCandidates(name2);
117373
117514
  let chosen = candidates2.find((candidate2) => !taken.has(candidate2));
117374
117515
  const base = candidates2[0] ?? "?";
@@ -117383,10 +117524,10 @@ function assignInitials(names7) {
117383
117524
  return chosen;
117384
117525
  });
117385
117526
  }
117386
- function lookalikePairs(names7) {
117527
+ function lookalikePairs(names8) {
117387
117528
  const pairs = [];
117388
- names7.forEach((name2, index2) => {
117389
- for (const other of names7.slice(index2 + 1)) {
117529
+ names8.forEach((name2, index2) => {
117530
+ for (const other of names8.slice(index2 + 1)) {
117390
117531
  const [a, b] = [actorKey(name2), actorKey(other)];
117391
117532
  const isLong = Math.min(a.length, b.length) >= JOURNEY_LINT.lookalikeMinLength;
117392
117533
  if (isLong && a !== b && suggest(a, [b], 1) !== null) pairs.push([name2, other]);
@@ -117509,8 +117650,8 @@ function linesOf(ctx) {
117509
117650
  }
117510
117651
  function readActors(ctx, text3, span) {
117511
117652
  if (text3 === void 0 || text3.trim() === "") return { names: [], hasEmptyName: false };
117512
- const names7 = text3.split(",").map((piece) => describeLabel(ctx.reporter, piece, span, { allowSub: false }).label);
117513
- return { names: names7.filter((name2) => name2 !== ""), hasEmptyName: names7.some((name2) => name2 === "") };
117653
+ const names8 = text3.split(",").map((piece) => describeLabel(ctx.reporter, piece, span, { allowSub: false }).label);
117654
+ return { names: names8.filter((name2) => name2 !== ""), hasEmptyName: names8.some((name2) => name2 === "") };
117514
117655
  }
117515
117656
  function readTask2(ctx, line3, text3) {
117516
117657
  const span = spanOf9(line3, text3);
@@ -117741,7 +117882,7 @@ function resolveCast(state) {
117741
117882
  const tones = assignTones(entries2.map((entry2) => entry2.tone));
117742
117883
  const initials = assignInitials(entries2.map((entry2) => entry2.name));
117743
117884
  const actors = entries2.map((entry2, index2) => ({ name: entry2.name, tone: tones[index2] ?? "neutral", initials: initials[index2] ?? "?", isDeclared: entry2.isDeclared }));
117744
- const names7 = new Map(entries2.map((entry2) => [actorKey(entry2.name), entry2.name]));
117885
+ const names8 = new Map(entries2.map((entry2) => [actorKey(entry2.name), entry2.name]));
117745
117886
  const known3 = entries2.map((entry2) => entry2.name);
117746
117887
  const resolve5 = (section) => ({
117747
117888
  label: section.label,
@@ -117753,7 +117894,7 @@ function resolveCast(state) {
117753
117894
  score: task.score,
117754
117895
  labelAt: task.labelAt,
117755
117896
  actors: task.names.flatMap((ref) => {
117756
- const name2 = names7.get(actorKey(ref.name));
117897
+ const name2 = names8.get(actorKey(ref.name));
117757
117898
  if (name2 !== void 0) return [name2];
117758
117899
  state.report.push(errorAt(DIAGNOSTIC_CODES.unknownNode, `Unknown actor "${ref.name}"`, ref.at, `${didYouMean(ref.name, known3)} Or declare it with: actor "${ref.name}"`));
117759
117900
  return [];
@@ -117967,10 +118108,10 @@ function parseTaskStatement2(cursor, state, line3) {
117967
118108
  const options3 = readOptions(cursor, TASK_OPTIONS2, state.report, { lists: ["actors"] });
117968
118109
  rejectTrailing(cursor, state, TASK_SYNTAX);
117969
118110
  const score = readScore(findOption(options3, "score"), name2?.at ?? cursor.endPosition(line3), state);
117970
- const names7 = readActors2(findOption(options3, "actors"), state);
118111
+ const names8 = readActors2(findOption(options3, "actors"), state);
117971
118112
  if (name2 === null || score === null) return;
117972
118113
  const sub = findOption(options3, "sub");
117973
- currentTasks(state).push({ label: name2.text, sub: sub === void 0 || cleanName(sub.value) === "" ? null : cleanName(sub.value), score, names: names7, labelAt: name2.at });
118114
+ currentTasks(state).push({ label: name2.text, sub: sub === void 0 || cleanName(sub.value) === "" ? null : cleanName(sub.value), score, names: names8, labelAt: name2.at });
117974
118115
  }
117975
118116
  var TASK_OPTIONS2, TASK_SYNTAX, SCORE_HINT, NUMBER2, textOf2;
117976
118117
  var init_parse_task = __esm({
@@ -119773,13 +119914,13 @@ function layoutTable(diagram) {
119773
119914
  const heads = diagram.columns.map(placeHead);
119774
119915
  heads.forEach((head, place2) => head.block.isShortened && cuts.push(`the column "${diagram.columns[place2]?.label ?? ""}"`));
119775
119916
  const texts = diagram.rows.map((row) => row.cells.map((cell2) => cell2.kind === "text" ? fitBlock2(cell2.text, "sub", M4.textWidth, M4.textHardWidth, M4.textLines) : null));
119776
- const names7 = diagram.rows.map((row) => fitBlock2(row.label, "label", M4.nameWidth, M4.nameHardWidth, M4.nameLines));
119917
+ const names8 = diagram.rows.map((row) => fitBlock2(row.label, "label", M4.nameWidth, M4.nameHardWidth, M4.nameLines));
119777
119918
  const subs = diagram.rows.map((row) => row.sub === null ? null : fitBlock2(row.sub, "sub", M4.nameWidth, M4.nameHardWidth, 1));
119778
119919
  diagram.rows.forEach((row, at3) => {
119779
- if (names7[at3]?.isShortened === true || subs[at3]?.isShortened === true) cuts.push(`the row "${row.label}"`);
119920
+ if (names8[at3]?.isShortened === true || subs[at3]?.isShortened === true) cuts.push(`the row "${row.label}"`);
119780
119921
  row.cells.forEach((cell2, place2) => texts[at3]?.[place2]?.isShortened === true && cuts.push(`the cell of "${row.label}" under "${diagram.columns[place2]?.label ?? ""}"`));
119781
119922
  });
119782
- const firstWidth = Math.max(M4.nameMin, ...diagram.rows.map((row, at3) => nameLead(row) + Math.max(names7[at3]?.width ?? 0, subs[at3]?.width ?? 0) + M4.namePaddingX));
119923
+ const firstWidth = Math.max(M4.nameMin, ...diagram.rows.map((row, at3) => nameLead(row) + Math.max(names8[at3]?.width ?? 0, subs[at3]?.width ?? 0) + M4.namePaddingX));
119783
119924
  const widths = columnWidths(diagram, heads, texts);
119784
119925
  const totalWidth = totals === null ? 0 : M4.totalWidth;
119785
119926
  const frameX = M4.padding;
@@ -119799,7 +119940,7 @@ function layoutTable(diagram) {
119799
119940
  let y = headerTop + headerHeight;
119800
119941
  const rows = diagram.rows.map((row, at3) => {
119801
119942
  const isRecommended = diagram.recommended === at3;
119802
- const textHeight3 = (names7[at3]?.lines.length ?? 0) * TYPE_ROLES.label.lineHeight + (subs[at3] === null ? 0 : NODE_METRICS.subGap + TYPE_ROLES.sub.lineHeight);
119943
+ const textHeight3 = (names8[at3]?.lines.length ?? 0) * TYPE_ROLES.label.lineHeight + (subs[at3] === null ? 0 : NODE_METRICS.subGap + TYPE_ROLES.sub.lineHeight);
119803
119944
  const content = Math.max(textHeight3, row.icon === null ? 0 : M4.chipSize, ...row.cells.map((cell2, place2) => contentHeight(cell2, texts[at3]?.[place2] ?? null)));
119804
119945
  const bodyHeight = Math.max(M4.rowMin, content + M4.cellPadY * 2);
119805
119946
  const band = isRecommended ? M4.cardInset + M4.tabHeight : 0;
@@ -119812,7 +119953,7 @@ function layoutTable(diagram) {
119812
119953
  isBanded: at3 % 2 === 1,
119813
119954
  isRecommended,
119814
119955
  tone: toneOf2(diagram, row, isRecommended),
119815
- name: names7[at3],
119956
+ name: names8[at3],
119816
119957
  sub: subs[at3] ?? null,
119817
119958
  texts: texts[at3] ?? [],
119818
119959
  tabWidth: isRecommended ? tabWidth2 : 0,
@@ -120405,15 +120546,15 @@ function parseLevels(cursor, state, line3) {
120405
120546
  state.report.push(errorAt(DIAGNOSTIC_CODES.badOptionValue, "Expected which axis the levels name", axis ?? cursor.endPosition(line3), axis?.kind === "word" ? `${didYouMean(axis.text, axes)} ${LEVELS_HINT}` : LEVELS_HINT));
120406
120547
  return;
120407
120548
  }
120408
- const names7 = [];
120409
- for (let token = cursor.peek(); token?.kind === "string"; token = cursor.peek()) names7.push(cursor.next());
120549
+ const names8 = [];
120550
+ for (let token = cursor.peek(); token?.kind === "string"; token = cursor.peek()) names8.push(cursor.next());
120410
120551
  const options3 = readOptions(cursor, LEVELS_OPTIONS, state.report);
120411
120552
  rejectTrailing(cursor, state, LEVELS_HINT);
120412
120553
  const title = findOption(options3, "title")?.value.trim() ?? "";
120413
- const levels = names7.map((token) => token.kind === "string" ? token.text.trim() : "");
120554
+ const levels = names8.map((token) => token.kind === "string" ? token.text.trim() : "");
120414
120555
  const earlier = state.levelsLines.get(axis.text);
120415
- if (names7.length !== GRID_LEVELS || levels.includes("")) {
120416
- state.report.push(errorAt(DIAGNOSTIC_CODES.syntax, `The ${axis.text} levels need ${GRID_LEVELS} names with some text, found ${names7.length}`, names7[0] ?? keyword, LEVELS_HINT));
120556
+ if (names8.length !== GRID_LEVELS || levels.includes("")) {
120557
+ state.report.push(errorAt(DIAGNOSTIC_CODES.syntax, `The ${axis.text} levels need ${GRID_LEVELS} names with some text, found ${names8.length}`, names8[0] ?? keyword, LEVELS_HINT));
120417
120558
  return;
120418
120559
  }
120419
120560
  if (earlier !== void 0) {
@@ -121462,8 +121603,8 @@ function sideMiddle(topic, heading) {
121462
121603
  function endsAlong(parent, child, heading) {
121463
121604
  const end = sideMiddle(child, { x: -heading.x, y: -heading.y });
121464
121605
  if (parent.depth > 0 || heading.y !== 0) return { start: sideMiddle(parent, heading), end, leaving: heading, entering: heading };
121465
- const leaving = unitBetween(centreOf(parent.rect), end);
121466
- return { start: along3(centreOf(parent.rect), leaving, edgeDistance(parent.shape, parent.rect.width, parent.rect.height, leaving)), end, leaving, entering: heading };
121606
+ const leaving = unitBetween(centreOf2(parent.rect), end);
121607
+ return { start: along3(centreOf2(parent.rect), leaving, edgeDistance(parent.shape, parent.rect.width, parent.rect.height, leaving)), end, leaving, entering: heading };
121467
121608
  }
121468
121609
  function headingOf(child, arrangement, directions) {
121469
121610
  if (arrangement === "down") return { x: 0, y: 1 };
@@ -121503,14 +121644,14 @@ function routeLinks3(topics2, arrangement, directions) {
121503
121644
  };
121504
121645
  });
121505
121646
  }
121506
- var TUCK, centreOf, along3, dot, unitBetween, farSide, columnKey;
121647
+ var TUCK, centreOf2, along3, dot, unitBetween, farSide, columnKey;
121507
121648
  var init_links = __esm({
121508
121649
  "../../packages/diagrams/src/kinds/mindmap/layout/links.ts"() {
121509
121650
  "use strict";
121510
121651
  init_metrics9();
121511
121652
  init_shapes2();
121512
121653
  TUCK = 1.5;
121513
- centreOf = (rect) => ({ x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 });
121654
+ centreOf2 = (rect) => ({ x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 });
121514
121655
  along3 = (from, direction, distance4) => ({ x: from.x + direction.x * distance4, y: from.y + direction.y * distance4 });
121515
121656
  dot = (a, b) => a.x * b.x + a.y * b.y;
121516
121657
  unitBetween = (from, to) => {
@@ -123251,7 +123392,7 @@ function readSlice(ctx, line3, text3, match) {
123251
123392
  function parsePieMermaid(ctx) {
123252
123393
  const head = readHeaderRest2(ctx);
123253
123394
  const slices = [];
123254
- const names7 = /* @__PURE__ */ new Set();
123395
+ const names8 = /* @__PURE__ */ new Set();
123255
123396
  let showData = head.showData;
123256
123397
  for (const line3 of [...head.line === null ? [] : [head.line], ...ctx.prepared.body]) {
123257
123398
  const text3 = line3.text.trim();
@@ -123267,11 +123408,11 @@ function parsePieMermaid(ctx) {
123267
123408
  } else {
123268
123409
  const slice = readSlice(ctx, line3, text3, data);
123269
123410
  if (slice === null) continue;
123270
- if (names7.has(nameKey(slice.label))) {
123411
+ if (names8.has(nameKey(slice.label))) {
123271
123412
  ctx.reporter.add(DIAGNOSTIC_CODES.mermaidDuplicateDropped, slice.span, `A second slice named "${slice.label}" was dropped; the first is kept.`, "Add the two values in the Mermaid first if both should count, or tell the slices apart in their names.", "pie-duplicate");
123272
123413
  continue;
123273
123414
  }
123274
- names7.add(nameKey(slice.label));
123415
+ names8.add(nameKey(slice.label));
123275
123416
  slices.push(slice);
123276
123417
  }
123277
123418
  if (slices.length > PIE_LIMITS.maxSlices) {
@@ -123999,7 +124140,7 @@ var init_layout_axes = __esm({
123999
124140
  function around(center, half) {
124000
124141
  return { x: center.x - half, y: center.y - half, width: half * 2, height: half * 2 };
124001
124142
  }
124002
- function overlaps5(a, b, margin = 0) {
124143
+ function overlaps6(a, b, margin = 0) {
124003
124144
  return a.x < b.x + b.width + margin && b.x < a.x + a.width + margin && a.y < b.y + b.height + margin && b.y < a.y + a.height + margin;
124004
124145
  }
124005
124146
  function isWithin(inner, outer, inset2 = 0) {
@@ -124040,11 +124181,11 @@ function candidatesFor2(request, gap2) {
124040
124181
  }
124041
124182
  function isFree(rect, request, world, placed, mayLeaveZone) {
124042
124183
  const isInZone = isWithin(rect, request.zone, M9.edgeInset);
124043
- const reachesAcross = mayLeaveZone && isWithin(rect, world.plot, M9.edgeInset) && overlaps5(rect, request.zone);
124184
+ const reachesAcross = mayLeaveZone && isWithin(rect, world.plot, M9.edgeInset) && overlaps6(rect, request.zone);
124044
124185
  if (!isInZone && !reachesAcross) return false;
124045
- if (world.chips.some((chip2, index2) => index2 !== request.index && overlaps5(rect, chip2, M9.keepOff - 1))) return false;
124046
- if (world.tabs.some((tab) => overlaps5(rect, tab, M9.keepOff))) return false;
124047
- return !placed.some((other) => overlaps5(rect, other, M9.keepOff));
124186
+ if (world.chips.some((chip2, index2) => index2 !== request.index && overlaps6(rect, chip2, M9.keepOff - 1))) return false;
124187
+ if (world.tabs.some((tab) => overlaps6(rect, tab, M9.keepOff))) return false;
124188
+ return !placed.some((other) => overlaps6(rect, other, M9.keepOff));
124048
124189
  }
124049
124190
  function placeLabels2(requests, world) {
124050
124191
  const freeCount = (request) => candidatesFor2(request, M9.labelGap).filter((candidate2) => isFree(candidate2.rect, request, world, [], false)).length;
@@ -124056,7 +124197,7 @@ function placeLabels2(requests, world) {
124056
124197
  for (const attempt of ATTEMPTS) {
124057
124198
  const found = candidatesFor2(request, attempt.gap).find((candidate2) => isFree(candidate2.rect, request, world, placed, attempt.mayLeaveZone));
124058
124199
  if (found === void 0) continue;
124059
- const hasHalo = world.lines.some((line3) => overlaps5(found.rect, line3, M9.keepOff));
124200
+ const hasHalo = world.lines.some((line3) => overlaps6(found.rect, line3, M9.keepOff));
124060
124201
  label = { lines: request.lines, rect: found.rect, anchor: found.anchor, hasHalo, isShortened: request.isShortened };
124061
124202
  placed.push(found.rect);
124062
124203
  break;
@@ -124092,7 +124233,7 @@ function sizeZoneTab(zone, zoneWidth) {
124092
124233
  }
124093
124234
  function placeZoneTab(zone, size, chips) {
124094
124235
  const rectAt = (offset2) => ({ x: zone.x + offset2, y: zone.y, width: size.width, height: GROUP_METRICS.tabHeight });
124095
- const underTab = (rect) => chips.flatMap((chip2, index2) => overlaps5(rect, chip2, M10.tabClearance) ? [index2] : []);
124236
+ const underTab = (rect) => chips.flatMap((chip2, index2) => overlaps6(rect, chip2, M10.tabClearance) ? [index2] : []);
124096
124237
  const byLeft = [...chips.keys()].sort((a, b) => (chips[a]?.x ?? 0) - (chips[b]?.x ?? 0));
124097
124238
  let offset = 0;
124098
124239
  for (let attempt = 0; attempt <= chips.length; attempt += 1) {
@@ -124165,7 +124306,7 @@ function collisionsOf(chips) {
124165
124306
  const pairs = [];
124166
124307
  chips.forEach((chip2, first) => {
124167
124308
  for (let second = first + 1; second < chips.length; second += 1) {
124168
- if (overlaps5(chip2, chips[second], 2)) pairs.push([first, second]);
124309
+ if (overlaps6(chip2, chips[second], 2)) pairs.push([first, second]);
124169
124310
  }
124170
124311
  });
124171
124312
  return pairs;
@@ -125889,9 +126030,9 @@ var init_layout11 = __esm({
125889
126030
  });
125890
126031
 
125891
126032
  // ../../packages/diagrams/src/kinds/sankey/lint.ts
125892
- function nameList(names7) {
125893
- const shown = names7.slice(0, LISTED3).map((name2) => `"${oneLine6(name2)}"`).join(", ");
125894
- return names7.length > LISTED3 ? `${shown}, and ${names7.length - LISTED3} more` : shown;
126033
+ function nameList(names8) {
126034
+ const shown = names8.slice(0, LISTED3).map((name2) => `"${oneLine6(name2)}"`).join(", ");
126035
+ return names8.length > LISTED3 ? `${shown}, and ${names8.length - LISTED3} more` : shown;
125895
126036
  }
125896
126037
  function balanceWarnings(diagram) {
125897
126038
  const totals = totalsOf2(diagram);
@@ -126028,11 +126169,11 @@ function addFlow(ctx, flows, flow) {
126028
126169
  }
126029
126170
  function removeLoops(ctx, flows) {
126030
126171
  for (let guard = 0; guard <= flows.length; guard += 1) {
126031
- const names7 = [...new Set(flows.flatMap((flow) => [flow.from, flow.to]))];
126032
- const { cycle } = layerNodes(names7.length, flows.map((flow) => ({ from: names7.indexOf(flow.from), to: names7.indexOf(flow.to) })), "justify");
126172
+ const names8 = [...new Set(flows.flatMap((flow) => [flow.from, flow.to]))];
126173
+ const { cycle } = layerNodes(names8.length, flows.map((flow) => ({ from: names8.indexOf(flow.from), to: names8.indexOf(flow.to) })), "justify");
126033
126174
  if (cycle === null) return true;
126034
- const from = names7[cycle[cycle.length - 1] ?? 0];
126035
- const to = names7[cycle[0] ?? 0];
126175
+ const from = names8[cycle[cycle.length - 1] ?? 0];
126176
+ const to = names8[cycle[0] ?? 0];
126036
126177
  const at3 = flows.findIndex((flow) => flow.from === from && flow.to === to);
126037
126178
  const closing = flows[at3];
126038
126179
  if (closing === void 0) return false;
@@ -126350,9 +126491,9 @@ function wholeSourceErrors(state, header) {
126350
126491
  }
126351
126492
  const { cycle } = layerNodes(state.nodes.length, state.flows, state.align);
126352
126493
  if (cycle !== null) {
126353
- const names7 = [...cycle, cycle[0] ?? 0].map((node3) => `"${state.nodes[node3]?.label ?? ""}"`).join(" -> ");
126494
+ const names8 = [...cycle, cycle[0] ?? 0].map((node3) => `"${state.nodes[node3]?.label ?? ""}"`).join(" -> ");
126354
126495
  const closing = state.flows.find((flow) => flow.from === cycle[cycle.length - 1] && flow.to === cycle[0]);
126355
- found.push(errorAt(DIAGNOSTIC_CODES.syntax, `These flows go round in a loop: ${names7}`, closing?.at ?? state.nodes[cycle[0] ?? 0]?.at ?? { line: 1, column: 1, length: 1 }, 'A sankey only goes forward, so a loop cannot be drawn. Remove the flow that goes back, or split the stage in two, for example "Orders" and "Orders retried".'));
126496
+ found.push(errorAt(DIAGNOSTIC_CODES.syntax, `These flows go round in a loop: ${names8}`, closing?.at ?? state.nodes[cycle[0] ?? 0]?.at ?? { line: 1, column: 1, length: 1 }, 'A sankey only goes forward, so a loop cannot be drawn. Remove the flow that goes back, or split the stage in two, for example "Orders" and "Orders retried".'));
126356
126497
  }
126357
126498
  return found;
126358
126499
  }
@@ -131098,7 +131239,7 @@ function lineage(id, byId) {
131098
131239
  return chain2;
131099
131240
  }
131100
131241
  function resolveTransitions(state, byId) {
131101
- const names7 = state.nodes.filter((node3) => node3.kind === "state" || node3.kind === "composite" || node3.kind === "choice" || node3.kind === "fork" || node3.kind === "join" || node3.kind === "history").map((node3) => node3.id);
131242
+ const names8 = state.nodes.filter((node3) => node3.kind === "state" || node3.kind === "composite" || node3.kind === "choice" || node3.kind === "fork" || node3.kind === "join" || node3.kind === "history").map((node3) => node3.id);
131102
131243
  const resolved = [];
131103
131244
  let suggested = 0;
131104
131245
  for (const pending of state.transitions) {
@@ -131107,7 +131248,7 @@ function resolveTransitions(state, byId) {
131107
131248
  { id: pending.to, token: pending.toToken }
131108
131249
  ].filter((end) => !byId.has(end.id));
131109
131250
  for (const end of missing) {
131110
- const guess = suggested < SUGGESTIONS2 ? `${didYouMean(end.id, names7)} ` : "";
131251
+ const guess = suggested < SUGGESTIONS2 ? `${didYouMean(end.id, names8)} ` : "";
131111
131252
  suggested += 1;
131112
131253
  reportAt(state, DIAGNOSTIC_CODES.unknownNode, `Unknown state "${end.id}"`, spanOfToken(end.token), `${guess}Declare it first with: state ${end.id} "Label"`);
131113
131254
  }
@@ -131127,7 +131268,7 @@ function resolveTransitions(state, byId) {
131127
131268
  return resolved;
131128
131269
  }
131129
131270
  function resolveNotes2(state, byId) {
131130
- const names7 = state.nodes.filter((node3) => node3.kind === "state" || node3.kind === "composite" || node3.kind === "choice").map((node3) => node3.id);
131271
+ const names8 = state.nodes.filter((node3) => node3.kind === "state" || node3.kind === "composite" || node3.kind === "choice").map((node3) => node3.id);
131131
131272
  const notes = [];
131132
131273
  let suggested = 0;
131133
131274
  for (const pending of state.notes) {
@@ -131137,7 +131278,7 @@ function resolveNotes2(state, byId) {
131137
131278
  continue;
131138
131279
  }
131139
131280
  if (target === void 0) {
131140
- const guess = suggested < SUGGESTIONS2 ? `${didYouMean(pending.target, names7)} ` : "";
131281
+ const guess = suggested < SUGGESTIONS2 ? `${didYouMean(pending.target, names8)} ` : "";
131141
131282
  suggested += 1;
131142
131283
  state.report.push(errorAt(DIAGNOSTIC_CODES.unknownNode, `Unknown state "${pending.target}"`, spanOfToken(pending.targetToken), `${guess}A note attaches to a state that is declared.`));
131143
131284
  continue;
@@ -131951,21 +132092,21 @@ function placePills2(routes, runs, extents, items2, forced) {
131951
132092
  });
131952
132093
  const costed = spots.map(({ at: at3, rank, middle: middle2 }) => {
131953
132094
  const pill2 = pillAt2(flow, at3);
131954
- return { at: at3, cost: lines.filter((line3) => line3.flow !== flow && overlaps6(pill2, line3.box)).length * COST.line + placed.filter((other) => overlaps6(pill2, other)).length * COST.pill + items2.filter((item) => overlaps6(pill2, item)).length * COST.item + rank * COST.otherRun + Math.abs(at3.x - middle2) * 1e-3 };
132095
+ return { at: at3, cost: lines.filter((line3) => line3.flow !== flow && overlaps7(pill2, line3.box)).length * COST.line + placed.filter((other) => overlaps7(pill2, other)).length * COST.pill + items2.filter((item) => overlaps7(pill2, item)).length * COST.item + rank * COST.otherRun + Math.abs(at3.x - middle2) * 1e-3 };
131955
132096
  });
131956
132097
  const chosen = costed.reduce((best, spot) => best === null || spot.cost < best.cost ? spot : best, null);
131957
132098
  if (chosen !== null) placed.push(pillAt2(flow, chosen.at));
131958
132099
  return chosen === null ? null : chosen.at;
131959
132100
  });
131960
132101
  }
131961
- var GUTTER, COST, overlaps6;
132102
+ var GUTTER, COST, overlaps7;
131962
132103
  var init_pills = __esm({
131963
132104
  "../../packages/diagrams/src/kinds/swimlane/layout/pills.ts"() {
131964
132105
  "use strict";
131965
132106
  init_theme();
131966
132107
  GUTTER = { base: 52, stub: 20, pitch: 12, corner: 10, headClear: 14, pillGap: 6, roundRoom: 24, endRun: EDGE_METRICS.endRun };
131967
132108
  COST = { line: 3, pill: 60, item: 1e3, otherRun: 0.4 };
131968
- overlaps6 = (a, b) => a.x < b.x + b.width && b.x < a.x + a.width && a.y < b.y + b.height && b.y < a.y + a.height;
132109
+ overlaps7 = (a, b) => a.x < b.x + b.width && b.x < a.x + a.width && a.y < b.y + b.height && b.y < a.y + a.height;
131969
132110
  }
131970
132111
  });
131971
132112
 
@@ -132404,13 +132545,13 @@ function parseFlow2(cursor, p, line3) {
132404
132545
  p.pending.push({ from, to, label, line: style, step: look.step, at: spanOfLine6(line3) });
132405
132546
  }
132406
132547
  function resolveFlows(p) {
132407
- const names7 = p.items.map((item) => item.id);
132548
+ const names8 = p.items.map((item) => item.id);
132408
132549
  const resolved = [];
132409
132550
  let suggested = 0;
132410
132551
  for (const pending of p.pending) {
132411
- const missing = [pending.from, pending.to].filter((end) => !names7.includes(end.text));
132552
+ const missing = [pending.from, pending.to].filter((end) => !names8.includes(end.text));
132412
132553
  for (const end of missing) {
132413
- const guess = suggested < SUGGESTIONS3 ? `${didYouMean(end.text, names7)} ` : "";
132554
+ const guess = suggested < SUGGESTIONS3 ? `${didYouMean(end.text, names8)} ` : "";
132414
132555
  suggested += 1;
132415
132556
  fail(p, `Unknown step "${end.text}"`, spanOf22(end), `${guess}Declare it first inside a lane: step ${end.text} "Label"`, DIAGNOSTIC_CODES.unknownNode);
132416
132557
  }
@@ -136290,9 +136431,9 @@ var init_layout16 = __esm({
136290
136431
  });
136291
136432
 
136292
136433
  // ../../packages/diagrams/src/kinds/treemap/lint.ts
136293
- function nameList2(names7) {
136294
- const shown = names7.slice(0, LISTED4).map((name2) => `"${name2.replace(/\s+/g, " ").trim()}"`).join(", ");
136295
- return names7.length > LISTED4 ? `${shown}, and ${names7.length - LISTED4} more` : shown;
136434
+ function nameList2(names8) {
136435
+ const shown = names8.slice(0, LISTED4).map((name2) => `"${name2.replace(/\s+/g, " ").trim()}"`).join(", ");
136436
+ return names8.length > LISTED4 ? `${shown}, and ${names8.length - LISTED4} more` : shown;
136296
136437
  }
136297
136438
  function densityWarning11(items2) {
136298
136439
  if (items2 <= TREEMAP_LIMITS.warnItems) return null;
@@ -137662,7 +137803,7 @@ function layoutXychartNow(diagram) {
137662
137803
  const { scale } = shaped;
137663
137804
  const isHorizontal3 = diagram.direction === "horizontal";
137664
137805
  const unit3 = diagram.y.unit;
137665
- const names7 = placeNames(diagram, shaped);
137806
+ const names8 = placeNames(diagram, shaped);
137666
137807
  const mode = labelMode(diagram, isHorizontal3);
137667
137808
  const cut = [];
137668
137809
  const seriesPill = (index2, withValue) => {
@@ -137674,7 +137815,7 @@ function layoutXychartNow(diagram) {
137674
137815
  const directPills = mode === "direct" ? shaped.series.map((_, index2) => seriesPill(index2, true)) : [];
137675
137816
  const legendPills = mode === "legend" ? shaped.series.map((_, index2) => seriesPill(index2, false)) : [];
137676
137817
  const gutterWidth = isHorizontal3 ? 0 : Math.max(0, ...directPills.map((pill2) => pill2.width), ...thresholdPills.map((pill2) => pill2.width));
137677
- const rowLabels = isHorizontal3 ? fitRowLabels(names7) : null;
137818
+ const rowLabels = isHorizontal3 ? fitRowLabels(names8) : null;
137678
137819
  const reach2 = valueLabelReach(diagram, shaped);
137679
137820
  const left = XYCHART_METRICS.padding + (rowLabels === null ? tickWidth(scale, unit3) + XYCHART_METRICS.tickGap : rowLabels.width + XYCHART_METRICS.rowLabelGap);
137680
137821
  const right = XYCHART_METRICS.padding + (isHorizontal3 ? reach2 === 0 ? 0 : reach2 + XYCHART_METRICS.valueGap + 4 : gutterWidth === 0 ? 0 : gutterWidth + XYCHART_METRICS.gutterGap);
@@ -137684,7 +137825,7 @@ function layoutXychartNow(diagram) {
137684
137825
  const plotHeight = isHorizontal3 ? Math.max(XYCHART_METRICS.plot.minHeight / 2, shaped.count * pitch) : XYCHART_METRICS.plot.height;
137685
137826
  const frameWidth = Math.ceil(left + plotWidth + right);
137686
137827
  const aim = placeFrame(diagram, shaped, { x: left, y: 0, width: plotWidth, height: plotHeight }, isHorizontal3);
137687
- const fitted = isHorizontal3 || diagram.x?.kind !== "category" ? null : fitPlaces(names7, aim.slot, aim.center, { left: XYCHART_METRICS.padding, right: frameWidth - XYCHART_METRICS.padding });
137828
+ const fitted = isHorizontal3 || diagram.x?.kind !== "category" ? null : fitPlaces(names8, aim.slot, aim.center, { left: XYCHART_METRICS.padding, right: frameWidth - XYCHART_METRICS.padding });
137688
137829
  const vTitleText = isHorizontal3 ? diagram.x?.title ?? null : valueAxisTitle(diagram.y.title, unit3);
137689
137830
  const hTitleText = isHorizontal3 ? valueAxisTitle(diagram.y.title, unit3) : diagram.x?.title ?? null;
137690
137831
  const vTitleContent = oneLine9(vTitleText ?? "") === "" ? null : measurePill2({ key: "none", tone: null, icon: null, name: vTitleText ?? "", value: null, index: -1 });
@@ -137739,7 +137880,7 @@ function layoutXychartNow(diagram) {
137739
137880
  let labelStep = 1;
137740
137881
  if (rowLabels !== null) {
137741
137882
  places = rowLabels.texts.map((text3, index2) => ({ lines: [text3], x: plot.x - XYCHART_METRICS.rowLabelGap, top: frame.center(index2) - SUB_LINE2 / 2, anchor: "end" }));
137742
- rowLabels.isCut.forEach((isCut, index2) => isCut && cut.push(names7[index2] ?? ""));
137883
+ rowLabels.isCut.forEach((isCut, index2) => isCut && cut.push(names8[index2] ?? ""));
137743
137884
  placesBottom = Math.max(...ticks.map((tick) => tick.label.top + SUB_LINE2));
137744
137885
  } else if (diagram.x?.kind === "number") {
137745
137886
  places = placeNumberTicks(shaped, frame, placesTop);
@@ -137747,7 +137888,7 @@ function layoutXychartNow(diagram) {
137747
137888
  } else if (fitted !== null) {
137748
137889
  labelStep = fitted.step;
137749
137890
  places = fitted.lines.flatMap((lines2, index2) => index2 % labelStep === 0 ? [{ lines: lines2, x: fitted.x[index2] ?? frame.center(index2), top: placesTop, anchor: "middle" }] : []);
137750
- fitted.isCut.forEach((isCut, index2) => isCut && index2 % labelStep === 0 && cut.push(names7[index2] ?? ""));
137891
+ fitted.isCut.forEach((isCut, index2) => isCut && index2 % labelStep === 0 && cut.push(names8[index2] ?? ""));
137751
137892
  placesBottom = placesTop + SUB_LINE2 * Math.max(1, ...places.map((place2) => place2.lines.length));
137752
137893
  }
137753
137894
  const hTitleName = oneLine9(hTitleText ?? "");
@@ -138019,11 +138160,11 @@ function summarizeXychart(diagram) {
138019
138160
  const description = diagram.meta.description === null ? "" : ` ${oneLine9(diagram.meta.description)}`;
138020
138161
  return `${xychartTitle(diagram)}: ${countOf(diagram.series.length, "series", "series")} (${kinds2}) over ${countOf(shaped.count, "place")} on the ${axis} axis, on a scale of ${scale}.${description}`;
138021
138162
  }
138022
- function crossings(diagram, names7) {
138163
+ function crossings(diagram, names8) {
138023
138164
  return diagram.thresholds.flatMap((threshold) => {
138024
138165
  if (threshold.breach === "none") return [];
138025
138166
  const found = diagram.series.flatMap((series) => {
138026
- const places = series.values.flatMap((value, place2) => (threshold.breach === "above" ? value > threshold.value : value < threshold.value) ? [names7[place2] ?? ""] : []);
138167
+ const places = series.values.flatMap((value, place2) => (threshold.breach === "above" ? value > threshold.value : value < threshold.value) ? [names8[place2] ?? ""] : []);
138027
138168
  return places.length === 0 ? [] : [`${oneLine9(series.label)} in ${joinWords(places, "and")}`];
138028
138169
  });
138029
138170
  return [`- Crossed ${threshold.breach} ${oneLine9(threshold.label)}: ${found.length === 0 ? "nothing" : found.join("; ")}`];
@@ -138031,19 +138172,19 @@ function crossings(diagram, names7) {
138031
138172
  }
138032
138173
  function outlineXychart(diagram) {
138033
138174
  const shaped = shapeChart(diagram);
138034
- const names7 = placeNames(diagram, shaped);
138175
+ const names8 = placeNames(diagram, shaped);
138035
138176
  const unit3 = diagram.y.unit;
138036
138177
  const axis = diagram.x;
138037
- const at3 = (value, place2) => `${names7[place2] ?? ""} ${formatValue4(value, unit3)}`;
138178
+ const at3 = (value, place2) => `${names8[place2] ?? ""} ${formatValue4(value, unit3)}`;
138038
138179
  const lines = [summarizeXychart(diagram)];
138039
- if (axis?.kind === "category") lines.push(`X axis, ${axis.title === null ? "places" : oneLine9(axis.title)}: ${names7.join(", ")}.`);
138180
+ if (axis?.kind === "category") lines.push(`X axis, ${axis.title === null ? "places" : oneLine9(axis.title)}: ${names8.join(", ")}.`);
138040
138181
  if (axis?.kind === "number") lines.push(`X axis, ${axis.title === null ? "number" : oneLine9(axis.title)}: ${formatNumber4(axis.from)} to ${formatNumber4(axis.to)}, with the ${shaped.count} values spread evenly over it.`);
138041
138182
  lines.push(`Y axis${diagram.y.title === null ? "" : `, ${oneLine9(diagram.y.title)}`}: ${formatValue4(shaped.scale.min, unit3)} to ${formatValue4(shaped.scale.max, unit3)}.`);
138042
138183
  lines.push(`Drawn with the places ${diagram.direction === "horizontal" ? "down the side" : "along the bottom"}.`, shaped.isStacked ? "Series (the bars are stacked):" : "Series:");
138043
138184
  for (const series of diagram.series) lines.push(`- ${oneLine9(series.label)} (${series.kind}): ${series.values.map(at3).join(", ")}`);
138044
138185
  if (shaped.isStacked) lines.push(`- Bar totals: ${shaped.totals.map(at3).join(", ")}`);
138045
- if (diagram.thresholds.length > 0) lines.push("Thresholds:", ...diagram.thresholds.map((threshold) => `- ${oneLine9(threshold.label)}: ${formatValue4(threshold.value, unit3)}`), ...crossings(diagram, names7));
138046
- if (diagram.notes.length > 0) lines.push("Notes:", ...diagram.notes.map((note) => `- ${axis?.kind === "category" ? names7[note.where] ?? "" : formatNumber4(note.where)}: ${oneLine9(note.text)}`));
138186
+ if (diagram.thresholds.length > 0) lines.push("Thresholds:", ...diagram.thresholds.map((threshold) => `- ${oneLine9(threshold.label)}: ${formatValue4(threshold.value, unit3)}`), ...crossings(diagram, names8));
138187
+ if (diagram.notes.length > 0) lines.push("Notes:", ...diagram.notes.map((note) => `- ${axis?.kind === "category" ? names8[note.where] ?? "" : formatNumber4(note.where)}: ${oneLine9(note.text)}`));
138047
138188
  return lines;
138048
138189
  }
138049
138190
  var xychartTitle;
@@ -139658,13 +139799,13 @@ function renamedName(element, rename2) {
139658
139799
  function entriesOf3(source, rename2) {
139659
139800
  const { elements } = scanSource(source);
139660
139801
  const seen = /* @__PURE__ */ new Map();
139661
- const parentOf3 = (element) => element.parent === null ? null : renamedName(elements[element.parent], rename2);
139802
+ const parentOf4 = (element) => element.parent === null ? null : renamedName(elements[element.parent], rename2);
139662
139803
  return elements.map((element) => {
139663
139804
  const own2 = renamedName(element, rename2);
139664
- const base = element.role === "row" && element.keyword === null ? `${parentOf3(element) ?? ""}.${own2}` : own2;
139805
+ const base = element.role === "row" && element.keyword === null ? `${parentOf4(element) ?? ""}.${own2}` : own2;
139665
139806
  const count3 = (seen.get(base) ?? 0) + 1;
139666
139807
  seen.set(base, count3);
139667
- return { key: count3 === 1 ? base : `${base}#${count3}`, element, subject: subjectOf(element), parent: parentOf3(element) };
139808
+ return { key: count3 === 1 ? base : `${base}#${count3}`, element, subject: subjectOf(element), parent: parentOf4(element) };
139668
139809
  });
139669
139810
  }
139670
139811
  function valueChange(before, after) {
@@ -143154,7 +143295,7 @@ var init_schemas = __esm({
143154
143295
  }
143155
143296
  return propValues;
143156
143297
  });
143157
- const isObject4 = isObject;
143298
+ const isObject5 = isObject;
143158
143299
  const catchall = def.catchall;
143159
143300
  let value;
143160
143301
  const memo3 = globalConfig.memoizer;
@@ -143162,7 +143303,7 @@ var init_schemas = __esm({
143162
143303
  inst._zod.parse = (payload, ctx) => {
143163
143304
  value ?? (value = _normalized.value);
143164
143305
  const input2 = payload.value;
143165
- if (!isObject4(input2)) {
143306
+ if (!isObject5(input2)) {
143166
143307
  payload.issues.push({
143167
143308
  expected: "object",
143168
143309
  code: "invalid_type",
@@ -143298,7 +143439,7 @@ var init_schemas = __esm({
143298
143439
  return doc.compile();
143299
143440
  };
143300
143441
  let fastpass;
143301
- const isObject4 = isObject;
143442
+ const isObject5 = isObject;
143302
143443
  const jit = !globalConfig.jitless;
143303
143444
  const allowsEval2 = allowsEval;
143304
143445
  const fastEnabled = jit && allowsEval2.value;
@@ -143307,7 +143448,7 @@ var init_schemas = __esm({
143307
143448
  inst._zod.parse = (payload, ctx) => {
143308
143449
  value ?? (value = _normalized.value);
143309
143450
  const input2 = payload.value;
143310
- if (!isObject4(input2)) {
143451
+ if (!isObject5(input2)) {
143311
143452
  payload.issues.push({
143312
143453
  expected: "object",
143313
143454
  code: "invalid_type",
@@ -155894,12 +156035,12 @@ function rewriteKeyNames(ctx) {
155894
156035
  const rewrites = /* @__PURE__ */ new Map();
155895
156036
  for (const record2 of pendingRecords.get(ctx) ?? []) {
155896
156037
  const seen = ctx.seen.get(record2);
155897
- const names7 = (seen?.def ?? seen?.schema)?.propertyNames;
155898
- if (!names7 || names7 === true || rewrites.has(names7))
156038
+ const names8 = (seen?.def ?? seen?.schema)?.propertyNames;
156039
+ if (!names8 || names8 === true || rewrites.has(names8))
155899
156040
  continue;
155900
- const rewritten = stringifyKeyNames(bySchema, names7, /* @__PURE__ */ new Set());
155901
- if (rewritten !== names7)
155902
- rewrites.set(names7, rewritten);
156041
+ const rewritten = stringifyKeyNames(bySchema, names8, /* @__PURE__ */ new Set());
156042
+ if (rewritten !== names8)
156043
+ rewrites.set(names8, rewritten);
155903
156044
  }
155904
156045
  if (!rewrites.size)
155905
156046
  return;
@@ -161991,13 +162132,13 @@ function detourOf(lines) {
161991
162132
  function measureScene(scene) {
161992
162133
  const boxes2 = solidBoxes(scene.boxes);
161993
162134
  const over = linesOverBoxes(scene.lines, boxes2);
161994
- const overlaps7 = overlappingLabels(scene.labels, boxes2);
162135
+ const overlaps8 = overlappingLabels(scene.labels, boxes2);
161995
162136
  const biggest = [...scene.groups].sort((a, b) => b.boxes - a.boxes || a.id.localeCompare(b.id))[0];
161996
162137
  return {
161997
162138
  measures: {
161998
162139
  crossings: countCrossings(scene.lines),
161999
162140
  lineOverBox: over.count,
162000
- labelOverlaps: overlaps7.count,
162141
+ labelOverlaps: overlaps8.count,
162001
162142
  smallestTextPx: round(smallestText(scene), 1),
162002
162143
  aspectRatio: scene.height > 0 ? round(scene.width / scene.height, 2) : 0,
162003
162144
  emptySpace: round(emptyShare(scene), 2),
@@ -162010,7 +162151,7 @@ function measureScene(scene) {
162010
162151
  slices: scene.slices
162011
162152
  },
162012
162153
  lineOverBox: over.first,
162013
- labelPair: overlaps7.first,
162154
+ labelPair: overlaps8.first,
162014
162155
  biggestGroup: biggest === void 0 || biggest.boxes === 0 ? null : { id: biggest.id, boxes: biggest.boxes }
162015
162156
  };
162016
162157
  }
@@ -168741,9 +168882,9 @@ var init_ajvProvider_CEoC_sr = __esm({
168741
168882
  }
168742
168883
  get names() {
168743
168884
  var _a3;
168744
- return (_a3 = this._names) !== null && _a3 !== void 0 ? _a3 : this._names = this._items.reduce((names7, c) => {
168745
- if (c instanceof Name) names7[c.str] = (names7[c.str] || 0) + 1;
168746
- return names7;
168885
+ return (_a3 = this._names) !== null && _a3 !== void 0 ? _a3 : this._names = this._items.reduce((names8, c) => {
168886
+ if (c instanceof Name) names8[c.str] = (names8[c.str] || 0) + 1;
168887
+ return names8;
168747
168888
  }, {});
168748
168889
  }
168749
168890
  };
@@ -169078,9 +169219,9 @@ var init_ajvProvider_CEoC_sr = __esm({
169078
169219
  const rhs = this.rhs === void 0 ? "" : ` = ${this.rhs}`;
169079
169220
  return `${varKind} ${this.name}${rhs};` + _n;
169080
169221
  }
169081
- optimizeNames(names7, constants) {
169082
- if (!names7[this.name.str]) return;
169083
- if (this.rhs) this.rhs = optimizeExpr(this.rhs, names7, constants);
169222
+ optimizeNames(names8, constants) {
169223
+ if (!names8[this.name.str]) return;
169224
+ if (this.rhs) this.rhs = optimizeExpr(this.rhs, names8, constants);
169084
169225
  return this;
169085
169226
  }
169086
169227
  get names() {
@@ -169097,9 +169238,9 @@ var init_ajvProvider_CEoC_sr = __esm({
169097
169238
  render({ _n }) {
169098
169239
  return `${this.lhs} = ${this.rhs};` + _n;
169099
169240
  }
169100
- optimizeNames(names7, constants) {
169101
- if (this.lhs instanceof code_1.Name && !names7[this.lhs.str] && !this.sideEffects) return;
169102
- this.rhs = optimizeExpr(this.rhs, names7, constants);
169241
+ optimizeNames(names8, constants) {
169242
+ if (this.lhs instanceof code_1.Name && !names8[this.lhs.str] && !this.sideEffects) return;
169243
+ this.rhs = optimizeExpr(this.rhs, names8, constants);
169103
169244
  return this;
169104
169245
  }
169105
169246
  get names() {
@@ -169158,8 +169299,8 @@ var init_ajvProvider_CEoC_sr = __esm({
169158
169299
  optimizeNodes() {
169159
169300
  return `${this.code}` ? this : void 0;
169160
169301
  }
169161
- optimizeNames(names7, constants) {
169162
- this.code = optimizeExpr(this.code, names7, constants);
169302
+ optimizeNames(names8, constants) {
169303
+ this.code = optimizeExpr(this.code, names8, constants);
169163
169304
  return this;
169164
169305
  }
169165
169306
  get names() {
@@ -169185,19 +169326,19 @@ var init_ajvProvider_CEoC_sr = __esm({
169185
169326
  }
169186
169327
  return nodes.length > 0 ? this : void 0;
169187
169328
  }
169188
- optimizeNames(names7, constants) {
169329
+ optimizeNames(names8, constants) {
169189
169330
  const { nodes } = this;
169190
169331
  let i = nodes.length;
169191
169332
  while (i--) {
169192
169333
  const n = nodes[i];
169193
- if (n.optimizeNames(names7, constants)) continue;
169194
- subtractNames(names7, n.names);
169334
+ if (n.optimizeNames(names8, constants)) continue;
169335
+ subtractNames(names8, n.names);
169195
169336
  nodes.splice(i, 1);
169196
169337
  }
169197
169338
  return nodes.length > 0 ? this : void 0;
169198
169339
  }
169199
169340
  get names() {
169200
- return this.nodes.reduce((names7, n) => addNames(names7, n.names), {});
169341
+ return this.nodes.reduce((names8, n) => addNames(names8, n.names), {});
169201
169342
  }
169202
169343
  };
169203
169344
  var BlockNode = class extends ParentNode {
@@ -169237,18 +169378,18 @@ var init_ajvProvider_CEoC_sr = __esm({
169237
169378
  if (cond === false || !this.nodes.length) return void 0;
169238
169379
  return this;
169239
169380
  }
169240
- optimizeNames(names7, constants) {
169381
+ optimizeNames(names8, constants) {
169241
169382
  var _a3;
169242
- this.else = (_a3 = this.else) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names7, constants);
169243
- if (!(super.optimizeNames(names7, constants) || this.else)) return;
169244
- this.condition = optimizeExpr(this.condition, names7, constants);
169383
+ this.else = (_a3 = this.else) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names8, constants);
169384
+ if (!(super.optimizeNames(names8, constants) || this.else)) return;
169385
+ this.condition = optimizeExpr(this.condition, names8, constants);
169245
169386
  return this;
169246
169387
  }
169247
169388
  get names() {
169248
- const names7 = super.names;
169249
- addExprNames(names7, this.condition);
169250
- if (this.else) addNames(names7, this.else.names);
169251
- return names7;
169389
+ const names8 = super.names;
169390
+ addExprNames(names8, this.condition);
169391
+ if (this.else) addNames(names8, this.else.names);
169392
+ return names8;
169252
169393
  }
169253
169394
  };
169254
169395
  If.kind = "if";
@@ -169263,9 +169404,9 @@ var init_ajvProvider_CEoC_sr = __esm({
169263
169404
  render(opts) {
169264
169405
  return `for(${this.iteration})` + super.render(opts);
169265
169406
  }
169266
- optimizeNames(names7, constants) {
169267
- if (!super.optimizeNames(names7, constants)) return;
169268
- this.iteration = optimizeExpr(this.iteration, names7, constants);
169407
+ optimizeNames(names8, constants) {
169408
+ if (!super.optimizeNames(names8, constants)) return;
169409
+ this.iteration = optimizeExpr(this.iteration, names8, constants);
169269
169410
  return this;
169270
169411
  }
169271
169412
  get names() {
@@ -169300,9 +169441,9 @@ var init_ajvProvider_CEoC_sr = __esm({
169300
169441
  render(opts) {
169301
169442
  return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
169302
169443
  }
169303
- optimizeNames(names7, constants) {
169304
- if (!super.optimizeNames(names7, constants)) return;
169305
- this.iterable = optimizeExpr(this.iterable, names7, constants);
169444
+ optimizeNames(names8, constants) {
169445
+ if (!super.optimizeNames(names8, constants)) return;
169446
+ this.iterable = optimizeExpr(this.iterable, names8, constants);
169306
169447
  return this;
169307
169448
  }
169308
169449
  get names() {
@@ -169341,18 +169482,18 @@ var init_ajvProvider_CEoC_sr = __esm({
169341
169482
  (_b = this.finally) === null || _b === void 0 || _b.optimizeNodes();
169342
169483
  return this;
169343
169484
  }
169344
- optimizeNames(names7, constants) {
169485
+ optimizeNames(names8, constants) {
169345
169486
  var _a3, _b;
169346
- super.optimizeNames(names7, constants);
169347
- (_a3 = this.catch) === null || _a3 === void 0 || _a3.optimizeNames(names7, constants);
169348
- (_b = this.finally) === null || _b === void 0 || _b.optimizeNames(names7, constants);
169487
+ super.optimizeNames(names8, constants);
169488
+ (_a3 = this.catch) === null || _a3 === void 0 || _a3.optimizeNames(names8, constants);
169489
+ (_b = this.finally) === null || _b === void 0 || _b.optimizeNames(names8, constants);
169349
169490
  return this;
169350
169491
  }
169351
169492
  get names() {
169352
- const names7 = super.names;
169353
- if (this.catch) addNames(names7, this.catch.names);
169354
- if (this.finally) addNames(names7, this.finally.names);
169355
- return names7;
169493
+ const names8 = super.names;
169494
+ if (this.catch) addNames(names8, this.catch.names);
169495
+ if (this.finally) addNames(names8, this.finally.names);
169496
+ return names8;
169356
169497
  }
169357
169498
  };
169358
169499
  var Catch = class extends BlockNode {
@@ -169587,14 +169728,14 @@ var init_ajvProvider_CEoC_sr = __esm({
169587
169728
  }
169588
169729
  };
169589
169730
  exports.CodeGen = CodeGen;
169590
- function addNames(names7, from) {
169591
- for (const n in from) names7[n] = (names7[n] || 0) + (from[n] || 0);
169592
- return names7;
169731
+ function addNames(names8, from) {
169732
+ for (const n in from) names8[n] = (names8[n] || 0) + (from[n] || 0);
169733
+ return names8;
169593
169734
  }
169594
- function addExprNames(names7, from) {
169595
- return from instanceof code_1._CodeOrName ? addNames(names7, from.names) : names7;
169735
+ function addExprNames(names8, from) {
169736
+ return from instanceof code_1._CodeOrName ? addNames(names8, from.names) : names8;
169596
169737
  }
169597
- function optimizeExpr(expr, names7, constants) {
169738
+ function optimizeExpr(expr, names8, constants) {
169598
169739
  if (expr instanceof code_1.Name) return replaceName(expr);
169599
169740
  if (!canOptimize(expr)) return expr;
169600
169741
  return new code_1._Code(expr._items.reduce((items2, c) => {
@@ -169605,16 +169746,16 @@ var init_ajvProvider_CEoC_sr = __esm({
169605
169746
  }, []));
169606
169747
  function replaceName(n) {
169607
169748
  const c = constants[n.str];
169608
- if (c === void 0 || names7[n.str] !== 1) return n;
169609
- delete names7[n.str];
169749
+ if (c === void 0 || names8[n.str] !== 1) return n;
169750
+ delete names8[n.str];
169610
169751
  return c;
169611
169752
  }
169612
169753
  function canOptimize(e) {
169613
- return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names7[c.str] === 1 && constants[c.str] !== void 0);
169754
+ return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names8[c.str] === 1 && constants[c.str] !== void 0);
169614
169755
  }
169615
169756
  }
169616
- function subtractNames(names7, from) {
169617
- for (const n in from) names7[n] = (names7[n] || 0) - (from[n] || 0);
169757
+ function subtractNames(names8, from) {
169758
+ for (const n in from) names8[n] = (names8[n] || 0) - (from[n] || 0);
169618
169759
  }
169619
169760
  function not(x) {
169620
169761
  return typeof x == "boolean" || typeof x == "number" || x === null ? !x : (0, code_1._)`!${par(x)}`;
@@ -169779,7 +169920,7 @@ var init_ajvProvider_CEoC_sr = __esm({
169779
169920
  require_names = /* @__PURE__ */ __commonJSMin(((exports) => {
169780
169921
  Object.defineProperty(exports, "__esModule", { value: true });
169781
169922
  const codegen_1 = require_codegen();
169782
- const names7 = {
169923
+ const names8 = {
169783
169924
  data: new codegen_1.Name("data"),
169784
169925
  valCxt: new codegen_1.Name("valCxt"),
169785
169926
  instancePath: new codegen_1.Name("instancePath"),
@@ -169797,7 +169938,7 @@ var init_ajvProvider_CEoC_sr = __esm({
169797
169938
  jsonLen: new codegen_1.Name("jsonLen"),
169798
169939
  jsonPart: new codegen_1.Name("jsonPart")
169799
169940
  };
169800
- exports.default = names7;
169941
+ exports.default = names8;
169801
169942
  }));
169802
169943
  require_errors = /* @__PURE__ */ __commonJSMin(((exports) => {
169803
169944
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -177905,7 +178046,7 @@ var IMPORT_FORMATS, IMPORT_VIEWS, IMPORT_CHARTS, IMPORT_GROUP_BY, NO_STATS;
177905
178046
  var init_types2 = __esm({
177906
178047
  "../../packages/diagrams/src/importers/types.ts"() {
177907
178048
  "use strict";
177908
- IMPORT_FORMATS = ["sql", "prisma", "drizzle", "openapi", "terraform", "bicep", "arm", "pulumi", "cloudformation", "compose", "kubernetes", "github-actions", "csv", "json", "tree", "git-log"];
178049
+ IMPORT_FORMATS = ["sql", "prisma", "drizzle", "openapi", "terraform", "terraform-plan", "bicep", "arm", "pulumi", "cloudformation", "compose", "kubernetes", "github-actions", "csv", "json", "tree", "git-log"];
177909
178050
  IMPORT_VIEWS = ["endpoints", "map", "sequence", "git", "timeline"];
177910
178051
  IMPORT_CHARTS = ["auto", "xychart", "pie", "sankey", "treemap", "matrix"];
177911
178052
  IMPORT_GROUP_BY = ["module", "network", "file"];
@@ -178519,7 +178660,7 @@ var init_import_source = __esm({
178519
178660
  init_kinds2();
178520
178661
  init_workflows();
178521
178662
  ImportSourceInputSchema = external_exports.object({
178522
- format: external_exports.enum(IMPORT_FORMATS).describe("What the text is. sql, prisma, drizzle: a schema. openapi: endpoints or a sequence. terraform, bicep, arm, pulumi, cloudformation, compose, kubernetes, github-actions: a flow. csv, json: a chart. tree: a tree. git-log: a git graph or timeline."),
178663
+ format: external_exports.enum(IMPORT_FORMATS).describe("What the text is. sql, prisma, drizzle: a schema. openapi: endpoints or a sequence. terraform, terraform-plan (terraform show -json), bicep, arm, pulumi, cloudformation, compose, kubernetes, github-actions: a flow. csv, json: a chart. tree: a tree. git-log: a git graph or timeline."),
178523
178664
  // Neither text nor files has a length here: a call over the limits is answered with I102 and a hint, as data.
178524
178665
  text: external_exports.string().optional().describe("The file content, as text. Send text or files, not both."),
178525
178666
  files: external_exports.array(
@@ -181025,6 +181166,7 @@ var init_detect = __esm({
181025
181166
  { format: "prisma", test: (text3) => /^\s*model\s+\w+\s*\{/m.test(text3) && /@id\b|@relation\b|^\s*datasource\s+\w+\s*\{/m.test(text3) },
181026
181167
  { format: "drizzle", test: (text3) => /\b(?:pgTable|sqliteTable|mysqlTable)\s*\(/.test(text3) },
181027
181168
  { format: "openapi", test: (text3) => /^\s*["']?openapi["']?\s*:\s*["']?3\./m.test(text3) || /"openapi"\s*:\s*"3\./.test(text3) },
181169
+ { format: "terraform-plan", test: (text3) => /^\s*\{\s*"format_version"\s*:/.test(text3) && /"terraform_version"\s*:/.test(text3) && /"(?:planned_values|resource_changes|root_module)"\s*:/.test(text3) },
181028
181170
  { format: "terraform", test: (text3) => /^\s*resource\s+"[A-Za-z0-9_]+"\s+"[^"]+"\s*\{/m.test(text3) },
181029
181171
  { format: "bicep", test: (text3) => /^\s*(?:resource|module)\s+[A-Za-z_]\w*\s+'[^'\n]+'\s*(?:existing\s*)?=/m.test(text3) || /^\s*targetScope\s*=\s*'/m.test(text3) },
181030
181172
  { format: "arm", test: (text3) => /"\$schema"\s*:\s*"https?:\/\/schema\.management\.azure\.com\/schemas\/[^"]*(?:deploymentTemplate|DeploymentTemplate)/.test(text3) },
@@ -181043,6 +181185,7 @@ var init_detect = __esm({
181043
181185
  { format: "compose", words: /\b(?:docker[- ]compose|compose (?:file|yaml|yml|stack))\b/i },
181044
181186
  { format: "kubernetes", words: /\b(?:kubernetes|k8s)\b/i },
181045
181187
  { format: "github-actions", words: /\b(?:github actions?|workflow (?:file|yaml|yml)|ci workflow)\b/i },
181188
+ { format: "terraform-plan", words: /\b(?:terraform|tofu) (?:plan|state|show -json)\b|\bplan\.json\b/i },
181046
181189
  { format: "terraform", words: /\b(?:terraform|opentofu|hcl|\.tf files?)\b/i },
181047
181190
  { format: "bicep", words: /\b(?:bicep|\.bicep files?)\b/i },
181048
181191
  { format: "arm", words: /\b(?:arm templates?|azure resource manager|azuredeploy\.json)\b/i },
@@ -181057,7 +181200,7 @@ var init_detect = __esm({
181057
181200
  { format: "json", words: /\bjson (?:data|file|records|export)\b/i },
181058
181201
  { format: "tree", words: /\b(?:tree output|folder (?:structure|tree|listing)|directory (?:tree|listing))\b/i }
181059
181202
  ];
181060
- SURE_FROM_DATA = /* @__PURE__ */ new Set(["sql", "prisma", "drizzle", "openapi", "terraform", "bicep", "arm", "pulumi", "cloudformation", "compose", "kubernetes", "github-actions", "git-log"]);
181203
+ SURE_FROM_DATA = /* @__PURE__ */ new Set(["sql", "prisma", "drizzle", "openapi", "terraform", "terraform-plan", "bicep", "arm", "pulumi", "cloudformation", "compose", "kubernetes", "github-actions", "git-log"]);
181061
181204
  }
181062
181205
  });
181063
181206
 
@@ -181498,8 +181641,8 @@ function fewer(parts, most, biggest) {
181498
181641
  return out;
181499
181642
  }
181500
181643
  function titleOf2(units) {
181501
- const names7 = [...new Set(units.map((unit3) => unit3.name))];
181502
- return names7.length <= 2 ? names7.join(" and ") : `${names7.slice(0, 2).join(", ")}, and ${names7.length - 2} more`;
181644
+ const names8 = [...new Set(units.map((unit3) => unit3.name))];
181645
+ return names8.length <= 2 ? names8.join(" and ") : `${names8.slice(0, 2).join(", ")}, and ${names8.length - 2} more`;
181503
181646
  }
181504
181647
  function bundleLabel(edges) {
181505
181648
  const counts = /* @__PURE__ */ new Map();
@@ -181672,7 +181815,7 @@ function writeOneFlow(draft, report3) {
181672
181815
  const nodeLine4 = (node3, depth) => {
181673
181816
  const named2 = node3.type === "decision" || node3.type === "terminal" ? null : iconNamedBy(node3.label, draft.provider ?? null) ?? (node3.sub === void 0 || node3.sub === null ? null : iconNamedBy(node3.sub, draft.provider ?? null));
181674
181817
  const icon = known2(node3.icon ?? null) ?? known2(named2);
181675
- lines.add(`node ${ids.idFor(`node:${node3.key}`)} ${node3.type} ${quote(node3.label)}${options2({ sub: node3.sub ?? null, icon, tone: node3.tone ?? null })}`, depth);
181818
+ lines.add(`node ${ids.idFor(`node:${node3.key}`)} ${node3.type} ${quote(node3.label)}${options2({ sub: node3.sub ?? null, icon, tone: node3.tone ?? null, change: node3.change ?? null })}`, depth);
181676
181819
  };
181677
181820
  const writtenGroups = new Set(groups.map((group2) => group2.key));
181678
181821
  const effective = /* @__PURE__ */ new Map();
@@ -181684,11 +181827,11 @@ function writeOneFlow(draft, report3) {
181684
181827
  }
181685
181828
  effective.set(group2.key, parent);
181686
181829
  }
181687
- const parentOf3 = (group2) => effective.get(group2.key) ?? null;
181688
- const children = (parent) => groups.filter((group2) => parentOf3(group2) === parent);
181830
+ const parentOf4 = (group2) => effective.get(group2.key) ?? null;
181831
+ const children = (parent) => groups.filter((group2) => parentOf4(group2) === parent);
181689
181832
  const writeGroup = (group2, depth) => {
181690
181833
  lines.gap();
181691
- lines.add(`group ${ids.idFor(`group:${group2.key}`)} ${quote(group2.label)}${options2({ type: group2.type ?? namedType(group2.label), icon: known2(group2.icon ?? null), sub: group2.sub ?? null })} {`, depth);
181834
+ lines.add(`group ${ids.idFor(`group:${group2.key}`)} ${quote(group2.label)}${options2({ type: group2.type ?? namedType(group2.label), icon: known2(group2.icon ?? null), sub: group2.sub ?? null, tone: group2.tone ?? null })} {`, depth);
181692
181835
  for (const node3 of kept2) if ((node3.group ?? null) === group2.key) nodeLine4(node3, depth + 1);
181693
181836
  for (const child of children(group2.key)) writeGroup(child, depth + 1);
181694
181837
  lines.add("}", depth);
@@ -181776,8 +181919,8 @@ function chosenTables(tables, patterns, report3) {
181776
181919
  if (patterns === void 0 || patterns.length === 0) return tables;
181777
181920
  const chosen = tables.filter((table2) => patterns.some((pattern3) => matches2(table2, pattern3)));
181778
181921
  if (chosen.length === 0) {
181779
- const names7 = tables.slice(0, 12).map((table2) => table2.key);
181780
- report3.add(DIAGNOSTIC_CODES.importNotFound, START, `No table matches ${patterns.map((pattern3) => `"${pattern3}"`).join(", ")}.`, `Name tables the file has, such as ${names7.join(", ")}${tables.length > names7.length ? ", and more" : ""}, or a prefix such as ${names7[0] ?? "users"}*.`);
181922
+ const names8 = tables.slice(0, 12).map((table2) => table2.key);
181923
+ report3.add(DIAGNOSTIC_CODES.importNotFound, START, `No table matches ${patterns.map((pattern3) => `"${pattern3}"`).join(", ")}.`, `Name tables the file has, such as ${names8.join(", ")}${tables.length > names8.length ? ", and more" : ""}, or a prefix such as ${names8[0] ?? "users"}*.`);
181781
181924
  return null;
181782
181925
  }
181783
181926
  return chosen;
@@ -181825,11 +181968,11 @@ function clusterOrder(tables, relations) {
181825
181968
  return [...tables.filter((table2) => hubs.has(fold(table2.key))), ...areasOf(tables, relations).flatMap((area) => area.members)];
181826
181969
  }
181827
181970
  function partOf(area) {
181828
- const names7 = area.members.map((table2) => fold(table2.key));
181971
+ const names8 = area.members.map((table2) => fold(table2.key));
181829
181972
  const firstWord2 = (name2) => name2.split("_")[0] ?? name2;
181830
- const prefix = firstWord2(names7[0] ?? "");
181831
- const shared = names7.length > 1 && prefix !== "" && names7.every((name2) => firstWord2(name2) === prefix && name2.includes("_"));
181832
- const written3 = [...area.hubs.map((table2) => fold(table2.key)), ...shared ? [`${prefix}_*`] : names7];
181973
+ const prefix = firstWord2(names8[0] ?? "");
181974
+ const shared = names8.length > 1 && prefix !== "" && names8.every((name2) => firstWord2(name2) === prefix && name2.includes("_"));
181975
+ const written3 = [...area.hubs.map((table2) => fold(table2.key)), ...shared ? [`${prefix}_*`] : names8];
181833
181976
  const shown = written3.slice(0, NAMES_PER_PART).map((name2) => `"${name2}"`);
181834
181977
  return `[${shown.join(", ")}${written3.length > shown.length ? ", ..." : ""}]`;
181835
181978
  }
@@ -181988,8 +182131,8 @@ function writeSchema(draft, report3) {
181988
182131
  if (chosen === null) return null;
181989
182132
  const allTables = draft.tables.length;
181990
182133
  const filtered = chosen.length < draft.tables.length;
181991
- const names7 = new Set(chosen.map((table2) => fold3(table2.key)));
181992
- const inside = draft.relations.filter((relation2) => names7.has(fold3(relation2.fromTable)) && names7.has(fold3(relation2.toTable)));
182134
+ const names8 = new Set(chosen.map((table2) => fold3(table2.key)));
182135
+ const inside = draft.relations.filter((relation2) => names8.has(fold3(relation2.fromTable)) && names8.has(fold3(relation2.toTable)));
181993
182136
  const outside = filtered ? draft.relations.length - inside.length : 0;
181994
182137
  const ordered = clusterOrder(chosen, inside);
181995
182138
  if (ordered.length <= WORKFLOW_LIMITS.maxImportTables) adviseSplit(ordered, inside, filtered, report3);
@@ -182027,14 +182170,14 @@ function writeOneSchema(draft, report3, cap2, allTables, outside) {
182027
182170
  const id = tableIds.idFor(fold3(table2.key), table2.key);
182028
182171
  named[table2.key] = id;
182029
182172
  const label = table2.label === id ? "" : ` ${quote(table2.label)}`;
182030
- const names7 = new IdAllocator(false);
182173
+ const names8 = new IdAllocator(false);
182031
182174
  const byName = /* @__PURE__ */ new Map();
182032
182175
  columnIds.set(fold3(table2.key), byName);
182033
182176
  lines.gap();
182034
182177
  lines.add(`table ${id}${label} {`);
182035
182178
  for (const column of table2.columns) {
182036
182179
  if (byName.has(fold3(column.name))) continue;
182037
- const name2 = names7.idFor(fold3(column.name), column.name);
182180
+ const name2 = names8.idFor(fold3(column.name), column.name);
182038
182181
  byName.set(fold3(column.name), name2);
182039
182182
  const flags = [column.pk === true ? "pk" : "", column.fk === true ? "fk" : "", column.unique === true && column.pk !== true ? "unique" : "", column.nullable === true && column.pk !== true ? "nullable" : ""].filter((flag) => flag !== "");
182040
182183
  const note = column.note ?? (name2 === column.name ? null : column.name);
@@ -183205,10 +183348,10 @@ var init_plan9 = __esm({
183205
183348
  /** The variable a placement attribute names for a frame of a type, when it names no resource. */
183206
183349
  variableFrame(resource, attribute2) {
183207
183350
  const type = PLACEMENT_GROUP_TYPES[attribute2];
183208
- const names7 = resource.vars.get(attribute2) ?? [];
183209
- if (type === void 0 || names7.length === 0 || (resource.byAttribute.get(attribute2) ?? []).length > 0) return null;
183351
+ const names8 = resource.vars.get(attribute2) ?? [];
183352
+ if (type === void 0 || names8.length === 0 || (resource.byAttribute.get(attribute2) ?? []).length > 0) return null;
183210
183353
  const words2 = VARIABLE_WORDS[type];
183211
- const name2 = names7.length === 1 ? names7[0] : names7.find((candidate2) => words2?.test(candidate2) === true);
183354
+ const name2 = names8.length === 1 ? names8[0] : names8.find((candidate2) => words2?.test(candidate2) === true);
183212
183355
  if (name2 === void 0) return null;
183213
183356
  const value = this.variableValue(name2);
183214
183357
  const same = value === null ? void 0 : [...this.resources.values()].find((other) => this.shapes.get(other.key) === "frame" && other.key !== resource.key && this.frameType(other.key) !== null && sameKind(this.frameType(other.key), type) && other.values.get("name") === value);
@@ -183652,6 +183795,35 @@ var init_module_frames = __esm({
183652
183795
  }
183653
183796
  });
183654
183797
 
183798
+ // ../../packages/diagrams/src/importers/terraform/network-layer.ts
183799
+ function layerNetworks(plan) {
183800
+ let moved3 = false;
183801
+ for (const [key, parent] of [...plan.parents]) {
183802
+ const resource = plan.resources.get(key.replace(/^(?:frame|anchor):/, ""));
183803
+ if (resource === void 0 || NETWORK_TYPE.test(resource.type)) continue;
183804
+ let target = parent;
183805
+ for (let depth = 0; target !== void 0 && depth < MAX_DEPTH5; depth += 1) {
183806
+ const type = plan.frameType(target);
183807
+ if (type === null || !NETWORK_FRAMES.has(type)) break;
183808
+ target = plan.parents.get(target);
183809
+ }
183810
+ if (target === parent) continue;
183811
+ if (target === void 0) plan.parents.delete(key);
183812
+ else plan.parents.set(key, target);
183813
+ moved3 = true;
183814
+ }
183815
+ return moved3;
183816
+ }
183817
+ var MAX_DEPTH5, NETWORK_FRAMES, NETWORK_TYPE;
183818
+ var init_network_layer = __esm({
183819
+ "../../packages/diagrams/src/importers/terraform/network-layer.ts"() {
183820
+ "use strict";
183821
+ MAX_DEPTH5 = 16;
183822
+ NETWORK_FRAMES = /* @__PURE__ */ new Set(["network", "subnet", "public-subnet", "private-subnet", "management-subnet", "isolated-subnet"]);
183823
+ NETWORK_TYPE = /^(?:azurerm_(?:virtual_network|subnet|network_|route|nat_gateway|public_ip|firewall|application_gateway|lb$|lb_|private_dns)|aws_(?:vpc|subnet|security_group|network_acl|route|internet_gateway|nat_gateway|eip|egress_only)|google_compute_(?:network|subnetwork|firewall|router|route|address))/;
183824
+ }
183825
+ });
183826
+
183655
183827
  // ../../packages/diagrams/src/importers/terraform/module-icons.ts
183656
183828
  function moduleWords(name2, source) {
183657
183829
  const segments = source.replace(/[?#].*$/, "").replace(/\.git$/, "").split(/[/:]/).filter((part) => part !== "" && !NOISE.has(part.toLowerCase()));
@@ -183793,9 +183965,9 @@ function picture(plan, context, groupType) {
183793
183965
  if (near3 !== void 0 && near3 !== null) plan.parents.set(key, near3);
183794
183966
  }
183795
183967
  plan.wrapAccounts();
183796
- const names7 = /* @__PURE__ */ new Map();
183797
- for (const resource of resources.values()) if (plan.isBox(resource.key) || plan.shapes.get(resource.key) === "frame") names7.set(resource.name, (names7.get(resource.name) ?? 0) + 1);
183798
- const shared = new Set([...names7].filter(([, count3]) => count3 > 1).map(([name2]) => name2));
183968
+ const names8 = /* @__PURE__ */ new Map();
183969
+ for (const resource of resources.values()) if (plan.isBox(resource.key) || plan.shapes.get(resource.key) === "frame") names8.set(resource.name, (names8.get(resource.name) ?? 0) + 1);
183970
+ const shared = new Set([...names8].filter(([, count3]) => count3 > 1).map(([name2]) => name2));
183799
183971
  const files = /* @__PURE__ */ new Map();
183800
183972
  const fileFrame = (resource) => {
183801
183973
  const path = fileOf(resource, context.files);
@@ -183806,7 +183978,7 @@ function picture(plan, context, groupType) {
183806
183978
  const groups = [];
183807
183979
  const nodes = [];
183808
183980
  const drawn = /* @__PURE__ */ new Set();
183809
- const parentOf3 = (key, resource) => {
183981
+ const parentOf4 = (key, resource) => {
183810
183982
  if (!byFile) return plan.parents.get(key) ?? null;
183811
183983
  const holder = plan.holder.get(resource.key);
183812
183984
  const holderResource = holder === void 0 ? void 0 : resources.get(holder);
@@ -183832,12 +184004,12 @@ function picture(plan, context, groupType) {
183832
184004
  const box = boxOf2(resource, plan, shared);
183833
184005
  if (shape === "container") {
183834
184006
  const frame = containerFrame(resource.key);
183835
- const parent = byFile ? parentOf3(frame, resource) : plan.parents.get(frame) ?? null;
184007
+ const parent = byFile ? parentOf4(frame, resource) : plan.parents.get(frame) ?? null;
183836
184008
  groups.push({ key: frame, label: box.label, type: null, icon: box.icon ?? null, sub: null, parent, idHint: `${resource.name}_group` });
183837
184009
  const product = role.role === "node" ? productOf2(resource, plan) : box.label;
183838
184010
  nodes.push({ ...box, label: box.label === product ? box.label : product, sub: box.label === product ? box.sub ?? null : withParts(literalDetails(resource), multiplicity(resource), resource.kind === "data" && !plan.compatible ? "existing" : null), group: frame });
183839
184011
  } else {
183840
- nodes.push({ ...box, group: parentOf3(resource.key, resource) });
184012
+ nodes.push({ ...box, group: parentOf4(resource.key, resource) });
183841
184013
  }
183842
184014
  drawn.add(resource.key);
183843
184015
  } else if (shape === "nested") {
@@ -183866,7 +184038,7 @@ function picture(plan, context, groupType) {
183866
184038
  }
183867
184039
  for (const [key, path] of files) groups.push({ key, label: path === "" ? "main.tf" : path, type: null, icon: "lucide:file-code", sub: null, parent: null, idHint: path.replace(/\.tf$/, "") });
183868
184040
  if (byFile) {
183869
- for (const [child, holder] of plan.holder) if (parentOf3(child, resources.get(child)) !== containerFrame(holder)) arrows.push({ from: child, to: holder, label: "in", grant: false, via: child });
184041
+ for (const [child, holder] of plan.holder) if (parentOf4(child, resources.get(child)) !== containerFrame(holder)) arrows.push({ from: child, to: holder, label: "in", grant: false, via: child });
183870
184042
  for (const [subject, host] of plan.attached) for (const via of plan.attachedBy.get(subject) ?? []) arrows.push({ from: subject, to: anchorOf(host), label: "attached", grant: false, via });
183871
184043
  }
183872
184044
  return { groups, nodes, arrows, drawn };
@@ -183915,8 +184087,8 @@ function anchorBox(plan, key, groupType, byFile) {
183915
184087
  }
183916
184088
  function literalDetails(resource) {
183917
184089
  const role = resource.role;
183918
- const names7 = role.role === "node" ? role.detail ?? [] : ["sku_name", "os_type", "sku"];
183919
- const values = names7.map((name2) => literal2(resource, name2)).filter((value) => value !== null && value !== "");
184090
+ const names8 = role.role === "node" ? role.detail ?? [] : ["sku_name", "os_type", "sku"];
184091
+ const values = names8.map((name2) => literal2(resource, name2)).filter((value) => value !== null && value !== "");
183920
184092
  return values.length === 0 ? null : values.join(" ");
183921
184093
  }
183922
184094
  var ACCOUNT_NAMES;
@@ -183943,6 +184115,7 @@ function drawStack(input2) {
183943
184115
  const resources = compatible ? new Map([...input2.resources].map(([key, resource]) => [key, withoutNewNames(resource)])) : input2.resources;
183944
184116
  const plan = new StackPlan(resources, groupType, input2.providers, input2.variableName, input2.variableValue, compatible ? void 0 : input2.regionOf);
183945
184117
  plan.compatible = compatible;
184118
+ const layered = input2.layered === true && input2.modules.length === 0 && layerNetworks(plan);
183946
184119
  if (context.options.groupBy === void 0 || context.options.groupBy === "module") frameModules(plan, input2.modules);
183947
184120
  const frameless = ![...plan.shapes.values()].some((shape) => shape === "frame" || shape === "container") && ![...plan.outer.values()].some((outer) => outer.type !== "account") && plan.modules.size === 0;
183948
184121
  const boxCount = [...plan.shapes.values()].filter((shape) => shape === "node").length;
@@ -183956,7 +184129,11 @@ function drawStack(input2) {
183956
184129
  for (const arrow of written3) drawn.add(arrow.via);
183957
184130
  const bundled = bundleArrows(drafted.nodes, drafted.groups, joinArrows(written3), (frame) => plan.resources.has(frame) || plan.outer.has(frame) ? anchorBox(plan, frame, groupType, context.options.groupBy === "file") : null, !compatible);
183958
184131
  const edges = bundled.edges;
183959
- const { nodes, groups } = withoutIdleBoxes(bundled.nodes, drafted.groups, edges);
184132
+ const idle = withoutIdleBoxes(bundled.nodes, drafted.groups, edges);
184133
+ const changeOf = input2.change;
184134
+ const groups = changeOf === void 0 ? idle.groups : idle.groups.map((group2) => withChange(group2, changeOf(itemKey(group2.key))));
184135
+ const framed = new Set(idle.groups.map((group2) => itemKey(group2.key)));
184136
+ const nodes = changeOf === void 0 ? idle.nodes : idle.nodes.map((node3) => withMark(withChange(node3, changeOf(itemKey(node3.key)), !framed.has(itemKey(node3.key))), changeOf(itemKey(node3.key))));
183960
184137
  let total = 0;
183961
184138
  let counted2 = 0;
183962
184139
  for (const resource of resources.values()) {
@@ -183968,11 +184145,11 @@ function drawStack(input2) {
183968
184145
  const provider = providers.size === 1 ? [...providers][0] : providers.size === 0 ? input2.cloud ?? null : null;
183969
184146
  const owner = provider === null ? null : SHORT_NAMES2[provider] ?? CLOUD_PROVIDER_SPECS[provider].title;
183970
184147
  const where = owner === null ? "on more than one cloud" : `on ${owner}`;
183971
- const nesting2 = context.options.groupBy === "file" ? "framed by the file that declares them" : plan.modules.size > 0 ? "framed by the module that declares them and nested in the groups, networks, and subnets that hold them" : "nested in the groups, networks, and subnets that hold them";
183972
- const title = context.title ?? (owner === null ? "Cloud infrastructure" : `${owner} infrastructure`);
184148
+ const nesting2 = context.options.groupBy === "file" ? "framed by the file that declares them" : plan.modules.size > 0 ? "framed by the module that declares them and nested in the groups, networks, and subnets that hold them" : layered ? "nested in the groups that hold them, beside the network, with an arrow to the subnet each one sits in" : "nested in the groups, networks, and subnets that hold them";
184149
+ const title = context.title ?? `${owner === null ? "Cloud infrastructure" : `${owner} infrastructure`}${input2.summary === void 0 ? "" : `: ${input2.summary}`}`;
183973
184150
  const draft = {
183974
184151
  title,
183975
- desc: `${countOf2(total, "resource")} ${where}, ${nesting2}, imported from ${input2.tool}. An arrow means one resource refers to another, and its label says how: a role, a private link, logs, or a secret.`,
184152
+ desc: `${countOf2(total, "resource")} ${where}, ${nesting2}, imported from ${input2.tool}. An arrow means one resource refers to another, and its label says how: a role, a private link, logs, or a secret.${input2.note === void 0 ? "" : ` ${input2.note}`}`,
183976
184153
  // Modules read as layers, from the root's callers down to what they use.
183977
184154
  direction: plan.modules.size > 0 ? "down" : directionOf4(nodes.map((node3) => node3.key), edges),
183978
184155
  provider,
@@ -183991,6 +184168,12 @@ function drawStack(input2) {
183991
184168
  const whole2 = writeFlow({ ...draft, cap: Number.POSITIVE_INFINITY }, new ImportReporter());
183992
184169
  return renamed({ ...whole2, source: parts[0]?.source ?? whole2.source, parts });
183993
184170
  }
184171
+ function withChange(item, change, worded = true) {
184172
+ return change === null ? item : { ...item, tone: change.tone, sub: worded ? withParts(item.sub ?? null, change.word) : item.sub ?? null };
184173
+ }
184174
+ function withMark(node3, change) {
184175
+ return change?.mark === void 0 ? node3 : { ...node3, change: change.mark };
184176
+ }
183994
184177
  function withoutNewNames(resource) {
183995
184178
  const values = new Map(resource.values);
183996
184179
  values.delete("tags.Name");
@@ -184018,7 +184201,7 @@ function joinRoots(drafts2) {
184018
184201
  ids: parts[0]?.ids ?? {}
184019
184202
  };
184020
184203
  }
184021
- var SHORT_NAMES2;
184204
+ var SHORT_NAMES2, itemKey;
184022
184205
  var init_draw = __esm({
184023
184206
  "../../packages/diagrams/src/importers/terraform/draw.ts"() {
184024
184207
  "use strict";
@@ -184028,10 +184211,12 @@ var init_draw = __esm({
184028
184211
  init_edges2();
184029
184212
  init_labels();
184030
184213
  init_module_frames();
184214
+ init_network_layer();
184031
184215
  init_picture();
184032
184216
  init_plan9();
184033
184217
  init_resources();
184034
184218
  SHORT_NAMES2 = { aws: "AWS", azure: "Azure", gcp: "Google Cloud" };
184219
+ itemKey = (key) => key.replace(/^(?:anchor|frame):/, "");
184035
184220
  }
184036
184221
  });
184037
184222
 
@@ -184256,13 +184441,13 @@ function lastPart(value) {
184256
184441
  if (!value.includes("/")) return value;
184257
184442
  return value.split("/").filter((part) => part !== "").pop() ?? value;
184258
184443
  }
184259
- var MAX_DEPTH5, MAX_VALUE_LENGTH, MAX_ENTRIES, ValueResolver;
184444
+ var MAX_DEPTH6, MAX_VALUE_LENGTH, MAX_ENTRIES, ValueResolver;
184260
184445
  var init_values2 = __esm({
184261
184446
  "../../packages/diagrams/src/importers/terraform/values.ts"() {
184262
184447
  "use strict";
184263
184448
  init_expressions();
184264
184449
  init_parse21();
184265
- MAX_DEPTH5 = 8;
184450
+ MAX_DEPTH6 = 8;
184266
184451
  MAX_VALUE_LENGTH = 600;
184267
184452
  MAX_ENTRIES = 64;
184268
184453
  ValueResolver = class _ValueResolver {
@@ -184320,7 +184505,7 @@ var init_values2 = __esm({
184320
184505
  }
184321
184506
  /** The value of an expression as written, or null when it cannot be known from the text. */
184322
184507
  value(raw, depth = 0) {
184323
- if (depth > MAX_DEPTH5) return null;
184508
+ if (depth > MAX_DEPTH6) return null;
184324
184509
  const text3 = raw.trim();
184325
184510
  const memoKey = `${depth}\0${text3}`;
184326
184511
  if (this.memo.has(memoKey)) return this.memo.get(memoKey) ?? null;
@@ -184341,7 +184526,7 @@ var init_values2 = __esm({
184341
184526
  const part = (expression2) => this.value(expression2, depth + 1) ?? this.readable(expression2, depth + 1) ?? `{${shortName(expression2)}}`;
184342
184527
  if (text3.startsWith('"') && text3.endsWith('"') && text3.length >= 2 && interpolationsClosed(text3)) return this.template(text3.slice(1, -1), depth, part);
184343
184528
  const call = /^(format|join|lower|upper)\(([\s\S]*)\)$/.exec(text3);
184344
- if (call === null || depth > MAX_DEPTH5) return null;
184529
+ if (call === null || depth > MAX_DEPTH6) return null;
184345
184530
  const args = argumentsOf(call[2] ?? "");
184346
184531
  if (args === null || args.length === 0) return null;
184347
184532
  if (call[1] === "format") {
@@ -184367,7 +184552,7 @@ var init_values2 = __esm({
184367
184552
  * `toset`, `tolist`, `keys`, `values`, `merge`, `each.value`, and a `for` over a known map or list. Null when unknown.
184368
184553
  */
184369
184554
  collection(raw, depth = 0) {
184370
- if (depth > MAX_DEPTH5) return null;
184555
+ if (depth > MAX_DEPTH6) return null;
184371
184556
  const text3 = raw.trim();
184372
184557
  if (text3.startsWith("{") && text3.endsWith("}")) {
184373
184558
  const forMap = /^\{\s*for\s+([A-Za-z_]\w*)\s*(?:,\s*([A-Za-z_]\w*)\s*)?in\s+([^:]+):\s*([A-Za-z_]\w*)\s*=>/.exec(text3);
@@ -184461,7 +184646,7 @@ var init_values2 = __esm({
184461
184646
  fieldOf(base, fields, depth) {
184462
184647
  let current = base;
184463
184648
  for (const field of fields) {
184464
- if (current === null || depth > MAX_DEPTH5) return null;
184649
+ if (current === null || depth > MAX_DEPTH6) return null;
184465
184650
  const map2 = current.scope.collection(current.raw, depth + 1);
184466
184651
  if (map2?.kind !== "map") return null;
184467
184652
  current = map2.entries.find(([key]) => key === field)?.[1] ?? null;
@@ -184741,6 +184926,10 @@ function providerName(block, type, scope) {
184741
184926
  const written3 = block.attributes.find((attribute2) => attribute2.name === "provider")?.raw.trim() ?? type.split("_")[0] ?? "";
184742
184927
  return scope.providers.get(written3) ?? written3;
184743
184928
  }
184929
+ function copyName(name2, key) {
184930
+ if (key === null) return name2;
184931
+ return (PLAIN_NAMES.has(name2.toLowerCase()) ? key : `${name2} ${key}`).replace(/[^A-Za-z0-9_-]+/g, "_");
184932
+ }
184744
184933
  function readResources(root) {
184745
184934
  const bySite = new Map(allScopes(root).map((scope) => [scope.prefix, scope]));
184746
184935
  const readers = /* @__PURE__ */ new Map();
@@ -184804,12 +184993,11 @@ function readResources(root) {
184804
184993
  const tags = block.attributes.find((attribute2) => attribute2.name === "tags");
184805
184994
  const tagName3 = tags === void 0 ? null : resolver.fieldValue(tags.raw, "Name");
184806
184995
  if (tagName3 !== null) values.set("tags.Name", tagName3);
184807
- const name2 = copy.key === null ? id.name : PLAIN_NAMES.has(id.name.toLowerCase()) ? copy.key : `${id.name} ${copy.key}`;
184808
184996
  resources.set(key, {
184809
184997
  key,
184810
184998
  kind: id.kind,
184811
184999
  type: id.type,
184812
- name: copy.key === null ? name2 : name2.replace(/[^A-Za-z0-9_-]+/g, "_"),
185000
+ name: copyName(id.name, copy.key),
184813
185001
  block,
184814
185002
  role,
184815
185003
  refs: from((attribute2) => !PLACEMENT_ATTRIBUTES.has(attribute2.name)),
@@ -184851,7 +185039,7 @@ function readResources(root) {
184851
185039
  }
184852
185040
  return { resources, modules, empty };
184853
185041
  }
184854
- var MAX_DEPTH6, TYPE, unique, ScopeReader, isItem2, PLAIN_NAMES, NAMED;
185042
+ var MAX_DEPTH7, TYPE, unique, ScopeReader, isItem2, PLAIN_NAMES, NAMED;
184855
185043
  var init_graph4 = __esm({
184856
185044
  "../../packages/diagrams/src/importers/terraform/graph.ts"() {
184857
185045
  "use strict";
@@ -184861,7 +185049,7 @@ var init_graph4 = __esm({
184861
185049
  init_modules2();
184862
185050
  init_parse21();
184863
185051
  init_resources();
184864
- MAX_DEPTH6 = 6;
185052
+ MAX_DEPTH7 = 6;
184865
185053
  TYPE = /^[a-z][a-z0-9]*_[a-z0-9_]+$/;
184866
185054
  unique = (values) => [...new Set(values)];
184867
185055
  ScopeReader = class {
@@ -184881,7 +185069,7 @@ var init_graph4 = __esm({
184881
185069
  }
184882
185070
  /** Every address a text names, with `var.` names for the variables that name no item: `aws_vpc.main`, `module.network.azurerm_subnet.this["app"]`, `var.region`. */
184883
185071
  read(text3, depth = 0) {
184884
- if (depth > MAX_DEPTH6) return [];
185072
+ if (depth > MAX_DEPTH7) return [];
184885
185073
  const out = [];
184886
185074
  for (const steps of references(text3)) out.push(...this.interpret(steps, depth));
184887
185075
  return out;
@@ -184970,7 +185158,7 @@ var init_graph4 = __esm({
184970
185158
 
184971
185159
  // ../../packages/diagrams/src/importers/terraform/json-syntax.ts
184972
185160
  function expression(value, depth) {
184973
- if (depth > MAX_DEPTH7) return "null";
185161
+ if (depth > MAX_DEPTH8) return "null";
184974
185162
  if (typeof value === "string") return JSON.stringify(value);
184975
185163
  if (typeof value === "number" || typeof value === "boolean") return String(value);
184976
185164
  if (value === null) return "null";
@@ -184979,13 +185167,13 @@ function expression(value, depth) {
184979
185167
  }
184980
185168
  function body5(object2, depth, lines) {
184981
185169
  for (const [key, value] of Object.entries(object2)) {
184982
- const isObject4 = (item) => typeof item === "object" && item !== null && !Array.isArray(item);
184983
- if (key === "locals" || key === "tags" || key === "labels" || key === "app_settings" || key === "default" || depth > MAX_DEPTH7) lines.push(`${keyOf(key)} = ${expression(value, depth)}`);
184984
- else if (isObject4(value)) {
185170
+ const isObject5 = (item) => typeof item === "object" && item !== null && !Array.isArray(item);
185171
+ if (key === "locals" || key === "tags" || key === "labels" || key === "app_settings" || key === "default" || depth > MAX_DEPTH8) lines.push(`${keyOf(key)} = ${expression(value, depth)}`);
185172
+ else if (isObject5(value)) {
184985
185173
  lines.push(`${keyOf(key)} {`);
184986
185174
  body5(value, depth + 1, lines);
184987
185175
  lines.push("}");
184988
- } else if (Array.isArray(value) && value.length > 0 && value.every(isObject4)) {
185176
+ } else if (Array.isArray(value) && value.length > 0 && value.every(isObject5)) {
184989
185177
  for (const item of value) {
184990
185178
  lines.push(`${keyOf(key)} {`);
184991
185179
  body5(item, depth + 1, lines);
@@ -185046,13 +185234,13 @@ function readJsonFiles(text3, context, index2) {
185046
185234
  }
185047
185235
  return { text: blanked, blocks: out };
185048
185236
  }
185049
- var MAX_DEPTH7, LABELS, keyOf;
185237
+ var MAX_DEPTH8, LABELS, keyOf;
185050
185238
  var init_json_syntax = __esm({
185051
185239
  "../../packages/diagrams/src/importers/terraform/json-syntax.ts"() {
185052
185240
  "use strict";
185053
185241
  init_core();
185054
185242
  init_parse21();
185055
- MAX_DEPTH7 = 24;
185243
+ MAX_DEPTH8 = 24;
185056
185244
  LABELS = { resource: 2, data: 2, module: 1, variable: 1, output: 1, provider: 1 };
185057
185245
  keyOf = (key) => /^[A-Za-z_][A-Za-z0-9_-]*$/.test(key) ? key : JSON.stringify(key);
185058
185246
  }
@@ -185102,12 +185290,12 @@ function readVariableFiles(text3, files, context, index2, folder = null) {
185102
185290
  } else {
185103
185291
  chosen = [];
185104
185292
  if (others.length > 1) {
185105
- const names7 = others.map((span) => span.path);
185293
+ const names8 = others.map((span) => span.path);
185106
185294
  context.report.add(
185107
185295
  DIAGNOSTIC_CODES.importSkipped,
185108
185296
  START,
185109
- `${countOf2(others.length, "variables file")} ${others.length === 1 ? "is" : "are"} not applied, because Terraform loads none of them on its own and they set the same variables: ${names7.slice(0, LISTED5).join(", ")}${names7.length > LISTED5 ? ", and more" : ""}.`,
185110
- `Set options.varFiles to the environment to draw, such as ["${names7[0] ?? ""}"]; until then, variables show their defaults or their names.`
185297
+ `${countOf2(others.length, "variables file")} ${others.length === 1 ? "is" : "are"} not applied, because Terraform loads none of them on its own and they set the same variables: ${names8.slice(0, LISTED5).join(", ")}${names8.length > LISTED5 ? ", and more" : ""}.`,
185298
+ `Set options.varFiles to the environment to draw, such as ["${names8[0] ?? ""}"]; until then, variables show their defaults or their names.`
185111
185299
  );
185112
185300
  }
185113
185301
  }
@@ -185191,11 +185379,46 @@ function scopeOfVariable(scopes, name2) {
185191
185379
  const root = scopes[0];
185192
185380
  return root === void 0 ? null : { scope: root, name: name2 };
185193
185381
  }
185382
+ function withoutUndeclared(resources, scopes) {
185383
+ const declared2 = new Map(scopes.map((scope) => [scope, declaredVariables(scope.blocks)]));
185384
+ const undeclared = /* @__PURE__ */ new Map();
185385
+ const isDeclared = (name2) => {
185386
+ const found = scopeOfVariable(scopes, name2);
185387
+ const names8 = found === null ? void 0 : declared2.get(found.scope);
185388
+ return found === null || names8 === void 0 || names8.size === 0 || names8.has(found.name.split(".")[0] ?? "");
185389
+ };
185390
+ const out = /* @__PURE__ */ new Map();
185391
+ for (const [key, resource] of resources) {
185392
+ const vars = /* @__PURE__ */ new Map();
185393
+ let changed = false;
185394
+ for (const [attribute2, names8] of resource.vars) {
185395
+ const kept2 = names8.filter((name2) => isDeclared(name2));
185396
+ for (const name2 of names8) if (!kept2.includes(name2) && !undeclared.has(name2)) undeclared.set(name2, key);
185397
+ if (kept2.length > 0) vars.set(attribute2, kept2);
185398
+ changed ||= kept2.length < names8.length;
185399
+ }
185400
+ out.set(key, changed ? { ...resource, vars } : resource);
185401
+ }
185402
+ return { resources: out, undeclared };
185403
+ }
185194
185404
  function drawRoot(text3, folders, root, blocks2, context, index2) {
185195
185405
  const variableFiles = readVariableFiles(text3, context.files, context, index2, folders.roots.length > 1 || root !== "" ? root : null);
185196
185406
  const scope = buildScope(folders, root, variableFiles.assigned);
185197
185407
  const scopes = allScopes(scope);
185198
- const { resources, modules, empty } = readResources(scope);
185408
+ const read = readResources(scope);
185409
+ const { modules, empty } = read;
185410
+ const { resources, undeclared } = withoutUndeclared(read.resources, scopes);
185411
+ const [firstName, firstKey] = [...undeclared][0] ?? [];
185412
+ if (firstName !== void 0 && firstKey !== void 0) {
185413
+ const names8 = [...undeclared.keys()];
185414
+ const block = resources.get(firstKey)?.block;
185415
+ context.report.add(
185416
+ DIAGNOSTIC_CODES.importUnresolved,
185417
+ index2.span(block?.start ?? 0, block?.type.length ?? 1),
185418
+ `${names8.length === 1 ? "A variable is" : `${names8.length} variables are`} named but never declared, so nothing is framed by ${names8.length === 1 ? "it" : "them"}: ${names8.slice(0, 3).map((name2) => `var.${cleanText(name2)}`).join(", ")}.`,
185419
+ `Declare ${names8.length === 1 ? "it" : "each"} with a variable block, such as variable "${cleanText(firstName.split(".").pop() ?? firstName)}" {}, or send the file that declares ${names8.length === 1 ? "it" : "them"}.`
185420
+ );
185421
+ }
185199
185422
  for (const item of empty.slice(0, 1)) {
185200
185423
  context.report.add(DIAGNOSTIC_CODES.importSkipped, index2.span(item.block.start, item.block.type.length), `${countWord(empty.length)} make${empty.length === 1 ? "s" : ""} no copy with the values given (count or for_each is empty), so ${empty.length === 1 ? "it is" : "they are"} not drawn: ${empty.slice(0, 3).map((entry2) => entry2.key).join(", ")}.`, "Set the variable that turns it on, in a variables file or options.varFiles, to draw it.");
185201
185424
  }
@@ -185347,13 +185570,13 @@ function bodyObject(value) {
185347
185570
  if (value.kind === "if" || value.kind === "for") return bodyObject(value.body);
185348
185571
  return null;
185349
185572
  }
185350
- var MAX_DEPTH8, MAX_ITEMS, Env, Evaluator;
185573
+ var MAX_DEPTH9, MAX_ITEMS, Env, Evaluator;
185351
185574
  var init_evaluate = __esm({
185352
185575
  "../../packages/diagrams/src/importers/bicep/evaluate.ts"() {
185353
185576
  "use strict";
185354
185577
  init_value();
185355
185578
  init_value();
185356
- MAX_DEPTH8 = 24;
185579
+ MAX_DEPTH9 = 24;
185357
185580
  MAX_ITEMS = 256;
185358
185581
  Env = class _Env {
185359
185582
  constructor(unit3, inputs, loop, prefix, children) {
@@ -185376,7 +185599,7 @@ var init_evaluate = __esm({
185376
185599
  Evaluator = class {
185377
185600
  memo = /* @__PURE__ */ new Map();
185378
185601
  evaluate(expr, env, depth = 0) {
185379
- if (depth > MAX_DEPTH8) return new Unknown(shortOf(expr));
185602
+ if (depth > MAX_DEPTH9) return new Unknown(shortOf(expr));
185380
185603
  switch (expr.kind) {
185381
185604
  case "literal":
185382
185605
  return expr.value;
@@ -186255,8 +186478,8 @@ var init_references = __esm({
186255
186478
  }
186256
186479
  const nested2 = rest[0];
186257
186480
  if (nested2?.kind === "member" && nested2.nested) {
186258
- const names7 = slots.flatMap((slot) => (this.slots.get(`${slot.name}::${nested2.name}`) ?? []).map((child) => child.name));
186259
- return names7.length > 0 ? names7 : slots.map((slot) => slot.name);
186481
+ const names8 = slots.flatMap((slot) => (this.slots.get(`${slot.name}::${nested2.name}`) ?? []).map((child) => child.name));
186482
+ return names8.length > 0 ? names8 : slots.map((slot) => slot.name);
186260
186483
  }
186261
186484
  const [properties, subnets, position] = rest;
186262
186485
  if (properties?.kind === "member" && properties.name === "properties" && subnets?.kind === "member" && subnets.name === "subnets" && position?.kind === "index") {
@@ -186300,14 +186523,14 @@ var init_references = __esm({
186300
186523
  const values = expr.args.map((arg) => textOf5(this.evaluator.evaluate(arg, env)));
186301
186524
  const typeAt = values.findIndex((value) => value !== null && value.includes("/"));
186302
186525
  const type = typeAt === -1 ? null : values[typeAt].toLowerCase();
186303
- const names7 = values.slice(typeAt + 1);
186304
- const last = names7[names7.length - 1];
186526
+ const names8 = values.slice(typeAt + 1);
186527
+ const last = names8[names8.length - 1];
186305
186528
  if (type !== null && last !== null && last !== void 0) {
186306
186529
  for (const list of this.slots.values()) {
186307
186530
  for (const slot of list) {
186308
186531
  const own2 = nameOf7(slot, this.evaluator);
186309
- if (slot.armType.toLowerCase() === type && (own2 === last || own2 === names7.join("/"))) return [slot.name];
186310
- if (type === `${slot.armType.toLowerCase()}/subnets` && nameOf7(slot, this.evaluator) === names7[names7.length - 2]) {
186532
+ if (slot.armType.toLowerCase() === type && (own2 === last || own2 === names8.join("/"))) return [slot.name];
186533
+ if (type === `${slot.armType.toLowerCase()}/subnets` && nameOf7(slot, this.evaluator) === names8[names8.length - 2]) {
186311
186534
  const subnet = slot.subnets.find((entry2) => entry2.display === last || entry2.label === last);
186312
186535
  if (subnet !== void 0) return [subnet.name];
186313
186536
  }
@@ -186645,12 +186868,12 @@ function parseExpression(text3) {
186645
186868
  throw error62;
186646
186869
  }
186647
186870
  }
186648
- var MAX_DEPTH9, SKIPPED, PRECEDENCE, ReadError, BicepReader;
186871
+ var MAX_DEPTH10, SKIPPED, PRECEDENCE, ReadError, BicepReader;
186649
186872
  var init_parse22 = __esm({
186650
186873
  "../../packages/diagrams/src/importers/bicep/parse.ts"() {
186651
186874
  "use strict";
186652
186875
  init_tokens2();
186653
- MAX_DEPTH9 = 64;
186876
+ MAX_DEPTH10 = 64;
186654
186877
  SKIPPED = /* @__PURE__ */ new Set(["import", "type", "func", "metadata", "extension", "provider", "assert"]);
186655
186878
  PRECEDENCE = { "??": 1, "||": 2, "&&": 3, "==": 4, "!=": 4, "=~": 4, "!~": 4, "<": 5, ">": 5, "<=": 5, ">=": 5, "+": 6, "-": 6, "*": 7, "/": 7, "%": 7 };
186656
186879
  ReadError = class extends Error {
@@ -186835,7 +187058,7 @@ var init_parse22 = __esm({
186835
187058
  }
186836
187059
  /** An expression: a conditional over binary operators over unary ones over postfix chains. */
186837
187060
  expression(depth) {
186838
- if (depth > MAX_DEPTH9) this.fail("The expression is nested too deep.", `Keep nesting under ${MAX_DEPTH9} levels.`);
187061
+ if (depth > MAX_DEPTH10) this.fail("The expression is nested too deep.", `Keep nesting under ${MAX_DEPTH10} levels.`);
186839
187062
  const test = this.binary(0, depth + 1);
186840
187063
  if (this.isSign("=>")) {
186841
187064
  this.index += 1;
@@ -186935,15 +187158,15 @@ var init_parse22 = __esm({
186935
187158
  this.skipNewlines();
186936
187159
  const inner = this.expression(depth + 1);
186937
187160
  this.skipNewlines();
186938
- const names7 = [inner];
187161
+ const names8 = [inner];
186939
187162
  while (this.isSign(",")) {
186940
187163
  this.index += 1;
186941
187164
  this.skipNewlines();
186942
- names7.push(this.expression(depth + 1));
187165
+ names8.push(this.expression(depth + 1));
186943
187166
  this.skipNewlines();
186944
187167
  }
186945
187168
  this.expectSign(")", "Close the bracket.");
186946
- return names7.length === 1 ? inner : { kind: "array", items: names7, start: token.start };
187169
+ return names8.length === 1 ? inner : { kind: "array", items: names8, start: token.start };
186947
187170
  }
186948
187171
  if (token.kind === "sign" && token.text === "{") return this.object(depth + 1);
186949
187172
  if (token.kind === "sign" && token.text === "[") return this.array(depth + 1);
@@ -186959,7 +187182,7 @@ var init_parse22 = __esm({
186959
187182
  return value;
186960
187183
  }
186961
187184
  object(depth) {
186962
- if (depth > MAX_DEPTH9) this.fail("The objects are nested too deep.", `Keep nesting under ${MAX_DEPTH9} levels.`);
187185
+ if (depth > MAX_DEPTH10) this.fail("The objects are nested too deep.", `Keep nesting under ${MAX_DEPTH10} levels.`);
186963
187186
  const open2 = this.expectSign("{", "An object is written { key: value }.");
186964
187187
  const entries2 = [];
186965
187188
  const nested2 = [];
@@ -186997,7 +187220,7 @@ var init_parse22 = __esm({
186997
187220
  }
186998
187221
  }
186999
187222
  array(depth) {
187000
- if (depth > MAX_DEPTH9) this.fail("The lists are nested too deep.", `Keep nesting under ${MAX_DEPTH9} levels.`);
187223
+ if (depth > MAX_DEPTH10) this.fail("The lists are nested too deep.", `Keep nesting under ${MAX_DEPTH10} levels.`);
187001
187224
  const open2 = this.expectSign("[", "A list is written [ a, b ].");
187002
187225
  this.skipNewlines();
187003
187226
  if (this.isWord("for")) return this.loop(open2, depth);
@@ -187223,7 +187446,7 @@ function bicepQuotes(text3) {
187223
187446
  return out;
187224
187447
  }
187225
187448
  function exprOf(value, start2, depth = 0) {
187226
- if (depth > MAX_DEPTH10) return { kind: "literal", value: null, start: start2 };
187449
+ if (depth > MAX_DEPTH11) return { kind: "literal", value: null, start: start2 };
187227
187450
  if (typeof value === "string") {
187228
187451
  if (value.startsWith("[[")) return { kind: "string", parts: [value.slice(1)], start: start2 };
187229
187452
  if (value.startsWith("[") && value.endsWith("]")) {
@@ -187261,10 +187484,10 @@ function dependsOnOf(value, start2, symbols) {
187261
187484
  if (symbols.has(item)) return { kind: "name", name: item, start: start2 };
187262
187485
  const parts = item.split("/");
187263
187486
  const type = parts.slice(0, 2).join("/");
187264
- const names7 = parts.slice(2);
187265
- const childTypes = names7.length > 1 ? names7.filter((_part, index2) => index2 % 2 === 1) : [];
187487
+ const names8 = parts.slice(2);
187488
+ const childTypes = names8.length > 1 ? names8.filter((_part, index2) => index2 % 2 === 1) : [];
187266
187489
  const typed = [type, ...childTypes].join("/");
187267
- const named = names7.filter((_part, index2) => index2 % 2 === 0);
187490
+ const named = names8.filter((_part, index2) => index2 % 2 === 0);
187268
187491
  return { kind: "call", callee: { kind: "name", name: "resourceId", start: start2 }, name: "resourceId", args: [typed, ...named].map((part) => ({ kind: "string", parts: [part], start: start2 })), start: start2 };
187269
187492
  }),
187270
187493
  start: start2
@@ -187317,13 +187540,13 @@ function templateDeclarations(template, offsetOf) {
187317
187540
  for (const [name2, output2] of Object.entries(outputs)) if (isRecord2(output2)) declarations.push({ kind: "output", name: name2, value: exprOf(output2["value"], offsetOf(name2)), start: offsetOf(name2) });
187318
187541
  return declarations;
187319
187542
  }
187320
- var COPY_INDEX, MAX_DEPTH10, isRecord2;
187543
+ var COPY_INDEX, MAX_DEPTH11, isRecord2;
187321
187544
  var init_convert2 = __esm({
187322
187545
  "../../packages/diagrams/src/importers/arm/convert.ts"() {
187323
187546
  "use strict";
187324
187547
  init_parse22();
187325
187548
  COPY_INDEX = "copyIndex";
187326
- MAX_DEPTH10 = 48;
187549
+ MAX_DEPTH11 = 48;
187327
187550
  isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
187328
187551
  }
187329
187552
  });
@@ -187731,13 +187954,13 @@ function parseYaml(text3) {
187731
187954
  }
187732
187955
  return { documents, error: null };
187733
187956
  }
187734
- var MAX_DEPTH11, MAX_JOINED_LINES, YamlProblem, isItem3, BlockReader;
187957
+ var MAX_DEPTH12, MAX_JOINED_LINES, YamlProblem, isItem3, BlockReader;
187735
187958
  var init_parse23 = __esm({
187736
187959
  "../../packages/diagrams/src/importers/shared/yaml/parse.ts"() {
187737
187960
  "use strict";
187738
187961
  init_lines();
187739
187962
  init_scalars();
187740
- MAX_DEPTH11 = 64;
187963
+ MAX_DEPTH12 = 64;
187741
187964
  MAX_JOINED_LINES = 200;
187742
187965
  YamlProblem = class extends Error {
187743
187966
  constructor(line3, column, message2, hint2) {
@@ -187773,7 +187996,7 @@ var init_parse23 = __esm({
187773
187996
  /** A block that starts at the current line, indented `indent` spaces: a sequence, a mapping, or a scalar. */
187774
187997
  block(indent, depth) {
187775
187998
  const line3 = this.lines[this.index];
187776
- if (depth > MAX_DEPTH11) throw this.problem(line3, "The YAML is nested too deep.", `Keep nesting under ${MAX_DEPTH11} levels.`);
187999
+ if (depth > MAX_DEPTH12) throw this.problem(line3, "The YAML is nested too deep.", `Keep nesting under ${MAX_DEPTH12} levels.`);
187777
188000
  if (isItem3(line3.text)) return this.sequence(indent, depth);
187778
188001
  if (splitKey(line3.text) !== null) return this.mapping(indent, depth);
187779
188002
  this.index += 1;
@@ -188118,14 +188341,14 @@ function templateItems(template, offsetOf) {
188118
188341
  }
188119
188342
  return { items: items2, empty };
188120
188343
  }
188121
- var MAX_DEPTH12, PSEUDO, entryOf, scalarOf, itemsOf, subNames, Template;
188344
+ var MAX_DEPTH13, PSEUDO, entryOf, scalarOf, itemsOf, subNames, Template;
188122
188345
  var init_template = __esm({
188123
188346
  "../../packages/diagrams/src/importers/cloudformation/template.ts"() {
188124
188347
  "use strict";
188125
188348
  init_attributes();
188126
188349
  init_type_names();
188127
188350
  init_value();
188128
- MAX_DEPTH12 = 16;
188351
+ MAX_DEPTH13 = 16;
188129
188352
  PSEUDO = {
188130
188353
  "AWS::Region": "region",
188131
188354
  "AWS::AccountId": "account",
@@ -188155,7 +188378,7 @@ var init_template = __esm({
188155
188378
  }
188156
188379
  /** The value of a node as far as the template's defaults give it. */
188157
188380
  evaluate(node3, depth = 0) {
188158
- if (node3 === void 0 || depth > MAX_DEPTH12) return new Unknown("value");
188381
+ if (node3 === void 0 || depth > MAX_DEPTH13) return new Unknown("value");
188159
188382
  const intrinsic = intrinsicOf(node3);
188160
188383
  if (intrinsic !== null) return this.call(intrinsic, depth);
188161
188384
  if (node3.kind === "scalar") return node3.isNull ? null : node3.value;
@@ -188263,7 +188486,7 @@ var init_template = __esm({
188263
188486
  }
188264
188487
  /** The resources a node names: `Ref`, `GetAtt`, and `${ }` of `Sub`, and only the branch an `If` takes when its condition is known. */
188265
188488
  refs(node3, depth = 0) {
188266
- if (node3 === void 0 || depth > MAX_DEPTH12) return [];
188489
+ if (node3 === void 0 || depth > MAX_DEPTH13) return [];
188267
188490
  const intrinsic = intrinsicOf(node3);
188268
188491
  if (intrinsic !== null) {
188269
188492
  const argument = intrinsic.argument;
@@ -188293,7 +188516,7 @@ var init_template = __esm({
188293
188516
  }
188294
188517
  /** Every reference a node holds, by the keys that lead to it. */
188295
188518
  refsByPath(node3, path, out, depth = 0) {
188296
- if (node3 === void 0 || depth > MAX_DEPTH12) return;
188519
+ if (node3 === void 0 || depth > MAX_DEPTH13) return;
188297
188520
  if (intrinsicOf(node3) === null && node3.kind === "map") {
188298
188521
  for (const entry2 of node3.entries) this.refsByPath(entry2.value, [...path, entry2.key], out, depth + 1);
188299
188522
  return;
@@ -188861,14 +189084,14 @@ function writeMatrix(table2, title, report3) {
188861
189084
  const columnPages = pages(columns.map((_, index2) => index2), columnPlan);
188862
189085
  const rowPlan = paging(table2.rows.length, WORKFLOW_LIMITS.maxImportRows, MAX_ROWS, Math.max(1, Math.floor(WORKFLOW_LIMITS.maxImportParts / columnPages.length)));
188863
189086
  const rowPages = pages(table2.rows.map((_, index2) => index2), rowPlan);
188864
- const names7 = [];
189087
+ const names8 = [];
188865
189088
  const taken = /* @__PURE__ */ new Set();
188866
189089
  for (const [index2, row] of table2.rows.entries()) {
188867
189090
  const base = cleanText(row[0] ?? "", `Row ${index2 + 1}`);
188868
189091
  let name2 = base;
188869
189092
  for (let seen = 2; taken.has(name2.toLowerCase()); seen += 1) name2 = `${base} (${seen})`;
188870
189093
  taken.add(name2.toLowerCase());
188871
- names7.push(name2);
189094
+ names8.push(name2);
188872
189095
  }
188873
189096
  const marks = table2.rows.map(
188874
189097
  (row, index2) => columns.map((_, column) => {
@@ -188894,7 +189117,7 @@ function writeMatrix(table2, title, report3) {
188894
189117
  for (const row of rowPage) {
188895
189118
  const cells = columnPage.map((column) => marks[row]?.[column] ?? "na");
188896
189119
  for (const cell2 of cells) used.add(cell2);
188897
- lines.add(`row ${quote(names7[row] ?? "")} : ${cells.join(", ")}`);
189120
+ lines.add(`row ${quote(names8[row] ?? "")} : ${cells.join(", ")}`);
188898
189121
  }
188899
189122
  lines.gap();
188900
189123
  const legend2 = ["yes", "partial", "no", "na"].filter((mark) => used.has(mark));
@@ -190024,13 +190247,13 @@ function cleanName2(name2) {
190024
190247
  return clean === "" ? "branch" : clean.slice(0, 40);
190025
190248
  }
190026
190249
  function namesOf(runs) {
190027
- const names7 = /* @__PURE__ */ new Map();
190250
+ const names8 = /* @__PURE__ */ new Map();
190028
190251
  const taken = /* @__PURE__ */ new Set();
190029
190252
  const claim2 = (run3, wanted2) => {
190030
190253
  let name2 = cleanName2(wanted2);
190031
190254
  for (let count3 = 2; taken.has(name2.toLowerCase()); count3 += 1) name2 = `${cleanName2(wanted2)}-${count3}`;
190032
190255
  taken.add(name2.toLowerCase());
190033
- names7.set(run3, name2);
190256
+ names8.set(run3, name2);
190034
190257
  };
190035
190258
  const [main2, ...others] = runs;
190036
190259
  if (main2 !== void 0) {
@@ -190043,7 +190266,7 @@ function namesOf(runs) {
190043
190266
  const merged = run3.mergedBy === null ? null : mergedName(run3.mergedBy.message);
190044
190267
  claim2(run3, decorated ?? merged ?? `branch-${run3.lane}`);
190045
190268
  }
190046
- return names7;
190269
+ return names8;
190047
190270
  }
190048
190271
  function commitOptions(commit, id) {
190049
190272
  const tags = commit.tags.slice(0, MAX_TAGS).map((tag) => cleanText(tag, ""));
@@ -190051,13 +190274,13 @@ function commitOptions(commit, id) {
190051
190274
  }
190052
190275
  function writeGit(rows, title, dropped) {
190053
190276
  const { runs, runOf, merges } = readLanes(rows);
190054
- const names7 = namesOf(runs);
190277
+ const names8 = namesOf(runs);
190055
190278
  const forkIds = /* @__PURE__ */ new Map();
190056
190279
  for (const run3 of runs) if (run3.forkFrom !== null) forkIds.set(run3.forkFrom, `c${run3.forkFrom.hash.slice(0, 7)}`);
190057
190280
  const main2 = runs[0];
190058
190281
  const commits = rows.flatMap((row) => row.kind === "commit" ? [row.commit] : []).reverse();
190059
190282
  const linear = runs.length === 1 ? linearBranches(commits) : null;
190060
- const mainName = linear === null ? names7.get(main2) ?? "main" : cleanName2(linear.first);
190283
+ const mainName = linear === null ? names8.get(main2) ?? "main" : cleanName2(linear.first);
190061
190284
  let linearBranchCount = 0;
190062
190285
  const created = /* @__PURE__ */ new Set([main2]);
190063
190286
  const hasCommits = /* @__PURE__ */ new Set();
@@ -190072,13 +190295,13 @@ function writeGit(rows, title, dropped) {
190072
190295
  if (hasCommits.size === 0) run3 = main2;
190073
190296
  if (!created.has(run3)) {
190074
190297
  const fork = run3.forkFrom !== null && emitted.has(run3.forkFrom) ? forkIds.get(run3.forkFrom) : void 0;
190075
- const parent = run3.parent !== null && hasCommits.has(run3.parent) ? names7.get(run3.parent) : void 0;
190298
+ const parent = run3.parent !== null && hasCommits.has(run3.parent) ? names8.get(run3.parent) : void 0;
190076
190299
  const from = fork ?? parent ?? mainName;
190077
- body6.add(`branch ${word(names7.get(run3) ?? "branch")}${from === names7.get(current) ? "" : options2({ from })}`);
190300
+ body6.add(`branch ${word(names8.get(run3) ?? "branch")}${from === names8.get(current) ? "" : options2({ from })}`);
190078
190301
  created.add(run3);
190079
190302
  current = run3;
190080
190303
  } else if (run3 !== current) {
190081
- body6.add(`checkout ${word(names7.get(run3) ?? mainName)}`);
190304
+ body6.add(`checkout ${word(names8.get(run3) ?? mainName)}`);
190082
190305
  current = run3;
190083
190306
  }
190084
190307
  const merged = merges.get(commit);
@@ -190087,7 +190310,7 @@ function writeGit(rows, title, dropped) {
190087
190310
  if (merged !== void 0 && hasCommits.has(merged) && !done.has(merged) && merged !== run3) {
190088
190311
  done.add(merged);
190089
190312
  mergeCount += 1;
190090
- body6.add(`merge ${word(names7.get(merged) ?? "branch")}${mergeMessage(commit.message)}${commitOptions(commit, id)}`);
190313
+ body6.add(`merge ${word(names8.get(merged) ?? "branch")}${mergeMessage(commit.message)}${commitOptions(commit, id)}`);
190091
190314
  } else {
190092
190315
  body6.add(`commit ${quote(message(commit.message))}${commitOptions(commit, id)}`);
190093
190316
  }
@@ -191184,8 +191407,8 @@ function chunkTitle(title, index2, count3) {
191184
191407
  return `${title} (${index2 + 1} of ${count3})`;
191185
191408
  }
191186
191409
  function chunkTags(chunk) {
191187
- const names7 = chunk.map(pieceName);
191188
- return names7.length <= 2 ? names7.join(" and ") : `${names7.slice(0, -1).join(", ")}, and ${names7[names7.length - 1] ?? ""}`;
191410
+ const names8 = chunk.map(pieceName);
191411
+ return names8.length <= 2 ? names8.join(" and ") : `${names8.slice(0, -1).join(", ")}, and ${names8[names8.length - 1] ?? ""}`;
191189
191412
  }
191190
191413
  function wanted(operation, tags, paths) {
191191
191414
  const tagged2 = tags === void 0 || tags.length === 0 || operation.tags.some((tag) => tags.some((want) => want.toLowerCase() === tag.toLowerCase()));
@@ -191494,8 +191717,8 @@ function short2(text3) {
191494
191717
  function needs(operation, schemes) {
191495
191718
  const first = operation.security?.find((requirement) => requirement.size > 0);
191496
191719
  if (first === void 0) return { token: false, names: [], scopes: [] };
191497
- const names7 = [...first.keys()];
191498
- return { token: names7.some((name2) => TOKEN_SCHEMES.has(schemes.get(name2)?.type ?? "")), names: names7, scopes: [...first.values()].flat() };
191720
+ const names8 = [...first.keys()];
191721
+ return { token: names8.some((name2) => TOKEN_SCHEMES.has(schemes.get(name2)?.type ?? "")), names: names8, scopes: [...first.values()].flat() };
191499
191722
  }
191500
191723
  function sequenceSource(operation, need, api, title, responses, page) {
191501
191724
  const lines = new SourceLines();
@@ -191921,14 +192144,14 @@ function piecesOf4(value) {
191921
192144
  }
191922
192145
  return out;
191923
192146
  }
191924
- var MAX_DEPTH13, Program;
192147
+ var MAX_DEPTH14, Program;
191925
192148
  var init_program = __esm({
191926
192149
  "../../packages/diagrams/src/importers/pulumi/program.ts"() {
191927
192150
  "use strict";
191928
192151
  init_value();
191929
192152
  init_yaml();
191930
192153
  init_item();
191931
- MAX_DEPTH13 = 16;
192154
+ MAX_DEPTH14 = 16;
191932
192155
  Program = class {
191933
192156
  constructor(root, config2, stack, project) {
191934
192157
  this.config = config2;
@@ -191956,7 +192179,7 @@ var init_program = __esm({
191956
192179
  }
191957
192180
  /** The value of a node as far as the program and the stack give it. */
191958
192181
  evaluate(node3, depth = 0) {
191959
- if (node3 === void 0 || depth > MAX_DEPTH13) return new Unknown("value");
192182
+ if (node3 === void 0 || depth > MAX_DEPTH14) return new Unknown("value");
191960
192183
  if (node3.kind === "scalar") {
191961
192184
  if (node3.isNull) return null;
191962
192185
  if (!node3.value.includes("${")) return node3.value;
@@ -192041,7 +192264,7 @@ var init_program = __esm({
192041
192264
  }
192042
192265
  /** The resources a node names, through the variables it uses. */
192043
192266
  refs(node3, depth = 0) {
192044
- if (node3 === void 0 || depth > MAX_DEPTH13) return [];
192267
+ if (node3 === void 0 || depth > MAX_DEPTH14) return [];
192045
192268
  if (node3.kind === "scalar") {
192046
192269
  if (!node3.value.includes("${")) return [];
192047
192270
  return piecesOf4(node3.value).flatMap((piece) => {
@@ -192064,7 +192287,7 @@ var init_program = __esm({
192064
192287
  }
192065
192288
  /** Every reference a node holds, by the keys that lead to it. */
192066
192289
  refsByPath(node3, path, out, depth) {
192067
- if (node3 === void 0 || depth > MAX_DEPTH13) return;
192290
+ if (node3 === void 0 || depth > MAX_DEPTH14) return;
192068
192291
  if (node3.kind === "map" && !(node3.entries.length === 1 && node3.entries[0]?.key.startsWith("fn::"))) {
192069
192292
  for (const entry2 of node3.entries) this.refsByPath(entry2.value, [...path, entry2.key], out, depth + 1);
192070
192293
  return;
@@ -192353,7 +192576,9 @@ function drawSource(source, context, index2) {
192353
192576
  return item === void 0 ? { line: 1, column: 1, length: 1 } : index2.span(item.start);
192354
192577
  },
192355
192578
  tool: "Pulumi",
192356
- stableName: stack.stableName
192579
+ stableName: stack.stableName,
192580
+ // A YAML program has no component to layer it by; a state's components, when it has them, frame it instead.
192581
+ layered: true
192357
192582
  });
192358
192583
  }
192359
192584
  var LISTED9, stackOf, pulumiImporter;
@@ -192509,8 +192734,8 @@ function readNameList(tokens, open2) {
192509
192734
  if (!isSign(tokens[open2], "(")) return null;
192510
192735
  const close2 = closeOf2(tokens, open2);
192511
192736
  if (close2 === -1) return null;
192512
- const names7 = splitParts2(tokens, open2 + 1, close2).map((part) => part.find((token) => isName(token))?.text).filter((name2) => name2 !== void 0);
192513
- return { names: names7, next: close2 + 1 };
192737
+ const names8 = splitParts2(tokens, open2 + 1, close2).map((part) => part.find((token) => isName(token))?.text).filter((name2) => name2 !== void 0);
192738
+ return { names: names8, next: close2 + 1 };
192514
192739
  }
192515
192740
  function tableOf(schema, name2) {
192516
192741
  const key = name2.toLowerCase();
@@ -192556,7 +192781,7 @@ function renameColumn(schema, table2, from, to) {
192556
192781
  table2.byName.delete(column.name.toLowerCase());
192557
192782
  column.name = to;
192558
192783
  table2.byName.set(to.toLowerCase(), column);
192559
- const rename2 = (names7) => names7.map((name2) => name2.toLowerCase() === from.toLowerCase() ? to : name2);
192784
+ const rename2 = (names8) => names8.map((name2) => name2.toLowerCase() === from.toLowerCase() ? to : name2);
192560
192785
  for (const foreign of schema.keys) {
192561
192786
  if (foreign.fromTable === table2.key) foreign.fromColumns = rename2(foreign.fromColumns);
192562
192787
  if (foreign.toTable.toLowerCase() === table2.key) foreign.toColumns = rename2(foreign.toColumns);
@@ -192860,6 +193085,623 @@ var init_sql = __esm({
192860
193085
  }
192861
193086
  });
192862
193087
 
193088
+ // ../../packages/diagrams/src/importers/terraform-plan/document.ts
193089
+ function moduleOfAddress(address, type, mode) {
193090
+ const own2 = `${mode === "data" ? "data." : ""}${type}.`;
193091
+ const at3 = address.lastIndexOf(own2);
193092
+ return at3 <= 0 ? "" : address.slice(0, at3 - 1);
193093
+ }
193094
+ function resourceOf3(raw, module) {
193095
+ if (!isObject4(raw) || typeof raw["address"] !== "string" || typeof raw["type"] !== "string" || typeof raw["name"] !== "string") return null;
193096
+ const mode = raw["mode"] === "data" ? "data" : "managed";
193097
+ const index2 = typeof raw["index"] === "string" || typeof raw["index"] === "number" ? raw["index"] : null;
193098
+ return {
193099
+ address: raw["address"],
193100
+ mode,
193101
+ type: raw["type"],
193102
+ name: raw["name"],
193103
+ index: index2,
193104
+ module: module === "" ? moduleOfAddress(raw["address"], raw["type"], mode) : module,
193105
+ values: isObject4(raw["values"]) ? raw["values"] : {},
193106
+ sensitive: isObject4(raw["sensitive_values"]) ? raw["sensitive_values"] : {},
193107
+ dependsOn: strings2(raw["depends_on"])
193108
+ };
193109
+ }
193110
+ function moduleResources(raw, depth = 0) {
193111
+ if (!isObject4(raw) || depth > MAX_MODULE_DEPTH2) return [];
193112
+ const address = typeof raw["address"] === "string" ? raw["address"] : "";
193113
+ const own2 = (Array.isArray(raw["resources"]) ? raw["resources"] : []).map((entry2) => resourceOf3(entry2, address)).filter((entry2) => entry2 !== null);
193114
+ const children = Array.isArray(raw["child_modules"]) ? raw["child_modules"].flatMap((child) => moduleResources(child, depth + 1)) : [];
193115
+ return [...own2, ...children];
193116
+ }
193117
+ function variablesOf(raw, sensitive) {
193118
+ const out = /* @__PURE__ */ new Map();
193119
+ if (!isObject4(raw)) return out;
193120
+ for (const [name2, entry2] of Object.entries(raw)) {
193121
+ if (sensitive.has(name2) || !isObject4(entry2)) continue;
193122
+ const value = entry2["value"];
193123
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") out.set(name2, String(value));
193124
+ }
193125
+ return out;
193126
+ }
193127
+ function sensitiveVariables(configuration) {
193128
+ const out = /* @__PURE__ */ new Set();
193129
+ const root = configuration === null ? null : configuration["root_module"];
193130
+ const variables = isObject4(root) && isObject4(root["variables"]) ? root["variables"] : {};
193131
+ for (const [name2, entry2] of Object.entries(variables)) if (isObject4(entry2) && entry2["sensitive"] === true) out.add(name2);
193132
+ return out;
193133
+ }
193134
+ function changesOf(raw) {
193135
+ const out = /* @__PURE__ */ new Map();
193136
+ if (!Array.isArray(raw)) return out;
193137
+ for (const entry2 of raw) {
193138
+ if (!isObject4(entry2) || typeof entry2["address"] !== "string" || !isObject4(entry2["change"])) continue;
193139
+ const change = entry2["change"];
193140
+ out.set(entry2["address"], { actions: strings2(change["actions"]), previous: typeof entry2["previous_address"] === "string" ? entry2["previous_address"] : null, before: isObject4(change["before"]) ? change["before"] : null });
193141
+ }
193142
+ return out;
193143
+ }
193144
+ function readPlanDocument(json2) {
193145
+ if (!isObject4(json2)) return null;
193146
+ const configuration = isObject4(json2["configuration"]) ? json2["configuration"] : null;
193147
+ const providers = configuration !== null && isObject4(configuration["provider_config"]) ? configuration["provider_config"] : {};
193148
+ const variables = variablesOf(json2["variables"], sensitiveVariables(configuration));
193149
+ if (isObject4(json2["planned_values"]) || Array.isArray(json2["resource_changes"])) {
193150
+ const planned = isObject4(json2["planned_values"]) ? moduleResources(json2["planned_values"]["root_module"]) : [];
193151
+ const prior = isObject4(json2["prior_state"]) && isObject4(json2["prior_state"]["values"]) ? moduleResources(json2["prior_state"]["values"]["root_module"]) : [];
193152
+ const changes = changesOf(json2["resource_changes"]);
193153
+ const kept2 = new Set(planned.map((resource) => resource.address));
193154
+ const data = prior.filter((resource) => resource.mode === "data" && !kept2.has(resource.address));
193155
+ const destroyed = [];
193156
+ const priorOf = new Map(prior.map((resource) => [resource.address, resource]));
193157
+ for (const [address, change] of changes) {
193158
+ if (!destroys(change) || kept2.has(address)) continue;
193159
+ const known3 = priorOf.get(address);
193160
+ if (known3 !== void 0) destroyed.push(known3);
193161
+ }
193162
+ const drift = /* @__PURE__ */ new Set();
193163
+ if (Array.isArray(json2["resource_drift"])) {
193164
+ for (const entry2 of json2["resource_drift"]) if (isObject4(entry2) && typeof entry2["address"] === "string") drift.add(entry2["address"]);
193165
+ }
193166
+ return { kind: "plan", resources: [...planned, ...data], destroyed, changes, drift, configuration, providers, variables };
193167
+ }
193168
+ if (isObject4(json2["values"]) && isObject4(json2["values"]["root_module"])) {
193169
+ return { kind: "state", resources: moduleResources(json2["values"]["root_module"]), destroyed: [], changes: /* @__PURE__ */ new Map(), drift: /* @__PURE__ */ new Set(), configuration, providers, variables };
193170
+ }
193171
+ if (Array.isArray(json2["resources"]) && typeof json2["version"] === "number") return { kind: "state", resources: rawStateResources(json2["resources"]), destroyed: [], changes: /* @__PURE__ */ new Map(), drift: /* @__PURE__ */ new Set(), configuration: null, providers: {}, variables: /* @__PURE__ */ new Map() };
193172
+ return null;
193173
+ }
193174
+ function rawStateResources(raw) {
193175
+ const out = [];
193176
+ for (const block of raw) {
193177
+ if (!isObject4(block) || typeof block["type"] !== "string" || typeof block["name"] !== "string" || !Array.isArray(block["instances"])) continue;
193178
+ const module = typeof block["module"] === "string" ? block["module"] : "";
193179
+ const mode = block["mode"] === "data" ? "data" : "managed";
193180
+ const base = `${module === "" ? "" : `${module}.`}${mode === "data" ? "data." : ""}${block["type"]}.${block["name"]}`;
193181
+ for (const instance of block["instances"]) {
193182
+ if (!isObject4(instance)) continue;
193183
+ const key = instance["index_key"];
193184
+ const index2 = typeof key === "string" || typeof key === "number" ? key : null;
193185
+ const address = `${base}${index2 === null ? "" : typeof index2 === "number" ? `[${index2}]` : `[${JSON.stringify(index2)}]`}`;
193186
+ const sensitive = {};
193187
+ if (Array.isArray(instance["sensitive_attributes"])) {
193188
+ for (const path of instance["sensitive_attributes"]) {
193189
+ const first = Array.isArray(path) ? path[0] : null;
193190
+ if (isObject4(first) && typeof first["value"] === "string") sensitive[first["value"]] = true;
193191
+ }
193192
+ }
193193
+ out.push({ address, mode, type: block["type"], name: block["name"], index: index2, module, values: isObject4(instance["attributes"]) ? instance["attributes"] : {}, sensitive, dependsOn: strings2(instance["dependencies"]) });
193194
+ }
193195
+ }
193196
+ return out;
193197
+ }
193198
+ var MAX_MODULE_DEPTH2, isObject4, strings2, destroys;
193199
+ var init_document3 = __esm({
193200
+ "../../packages/diagrams/src/importers/terraform-plan/document.ts"() {
193201
+ "use strict";
193202
+ MAX_MODULE_DEPTH2 = 16;
193203
+ isObject4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
193204
+ strings2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
193205
+ destroys = (change) => change !== void 0 && change.actions.length === 1 && change.actions[0] === "delete";
193206
+ }
193207
+ });
193208
+
193209
+ // ../../packages/diagrams/src/importers/terraform-plan/references.ts
193210
+ function attributesOf3(expressions, depth = 0) {
193211
+ if (!isObject4(expressions) || depth > MAX_NESTING) return [];
193212
+ const out = [];
193213
+ for (const [name2, value] of Object.entries(expressions)) {
193214
+ if (isObject4(value) && ("references" in value || "constant_value" in value)) {
193215
+ const refs = strings3(value["references"]);
193216
+ out.push({ name: name2, refs: refs.filter((ref) => !SAME_INSTANCE.has(ref)), paired: refs.some((ref) => SAME_INSTANCE.has(ref)) });
193217
+ } else if (Array.isArray(value)) for (const block of value) out.push(...attributesOf3(block, depth + 1));
193218
+ else if (isObject4(value)) out.push(...attributesOf3(value, depth + 1));
193219
+ }
193220
+ return out;
193221
+ }
193222
+ function suffixOf2(step) {
193223
+ if (step?.kind !== "index") return null;
193224
+ if (/^[0-9]+$/.test(step.text)) return `[${step.text}]`;
193225
+ return /^"(?:[^"\\]|\\.)*"$/.test(step.text) ? `[${step.text}]` : null;
193226
+ }
193227
+ function callsOf2(address) {
193228
+ const steps = references(address)[0] ?? [];
193229
+ const out = [];
193230
+ for (let index2 = 0; index2 < steps.length; index2 += 1) {
193231
+ if (steps[index2]?.text !== "module" || steps[index2]?.kind !== "name") continue;
193232
+ const name2 = steps[index2 + 1];
193233
+ if (name2?.kind !== "name") break;
193234
+ const key = steps[index2 + 2];
193235
+ out.push({ name: name2.text, suffix: key?.kind === "index" ? `[${key.text}]` : "" });
193236
+ }
193237
+ return out;
193238
+ }
193239
+ function parentOf3(module) {
193240
+ const at3 = module.lastIndexOf(".module.");
193241
+ return at3 === -1 ? "" : module.slice(0, at3);
193242
+ }
193243
+ var MAX_DEPTH15, MAX_NESTING, TYPE2, SAME_INSTANCE, strings3, Configuration;
193244
+ var init_references2 = __esm({
193245
+ "../../packages/diagrams/src/importers/terraform-plan/references.ts"() {
193246
+ "use strict";
193247
+ init_address();
193248
+ init_document3();
193249
+ MAX_DEPTH15 = 8;
193250
+ MAX_NESTING = 8;
193251
+ TYPE2 = /^[a-z][a-z0-9]*_[a-z0-9_]+$/;
193252
+ SAME_INSTANCE = /* @__PURE__ */ new Set(["each.key", "each.value", "count.index"]);
193253
+ strings3 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
193254
+ Configuration = class {
193255
+ constructor(root, instances) {
193256
+ this.root = root;
193257
+ this.instances = instances;
193258
+ }
193259
+ root;
193260
+ instances;
193261
+ /** The configuration of the module a module instance runs, or null when the plan has none. */
193262
+ moduleAt(address) {
193263
+ let module = this.root;
193264
+ for (const call of callsOf2(address)) {
193265
+ const calls = isObject4(module) && isObject4(module["module_calls"]) ? module["module_calls"] : null;
193266
+ const entry2 = calls === null ? null : calls[call.name];
193267
+ module = isObject4(entry2) ? entry2["module"] : null;
193268
+ }
193269
+ return isObject4(module) ? module : null;
193270
+ }
193271
+ /** The call of a module instance, as its parent's configuration writes it: its source, version, and the values it passes. */
193272
+ callAt(address) {
193273
+ const calls = callsOf2(address);
193274
+ const last = calls[calls.length - 1];
193275
+ if (last === void 0) return null;
193276
+ const parent = this.moduleAt(parentOf3(address));
193277
+ const entry2 = parent !== null && isObject4(parent["module_calls"]) ? parent["module_calls"][last.name] : null;
193278
+ return isObject4(entry2) ? entry2 : null;
193279
+ }
193280
+ /** The configured block of a resource, by the module instance it is in and its address inside the module. */
193281
+ resourceAt(module, local2) {
193282
+ const config2 = this.moduleAt(module);
193283
+ const list = config2 !== null && Array.isArray(config2["resources"]) ? config2["resources"] : [];
193284
+ const found = list.find((entry2) => isObject4(entry2) && entry2["address"] === local2);
193285
+ if (found === void 0) return null;
193286
+ return { attributes: attributesOf3(found["expressions"]), dependsOn: strings3(found["depends_on"]), providerKey: typeof found["provider_config_key"] === "string" ? found["provider_config_key"] : null };
193287
+ }
193288
+ /** What a reference written in a module instance names, followed through module outputs and the variables its call passes. */
193289
+ resolve(ref, module, depth = 0) {
193290
+ if (depth > MAX_DEPTH15) return [];
193291
+ const steps = references(ref)[0] ?? [];
193292
+ const [first, second, third, fourth] = steps;
193293
+ const name2 = (step) => step?.kind === "name" ? step.text : null;
193294
+ const prefix = module === "" ? "" : `${module}.`;
193295
+ const head = name2(first);
193296
+ if (head === null) return [];
193297
+ if (head === "data" && TYPE2.test(name2(second) ?? "") && name2(third) !== null) return [{ kind: "item", address: `${prefix}data.${name2(second)}.${name2(third)}`, index: suffixOf2(fourth) }];
193298
+ if (TYPE2.test(head) && name2(second) !== null && name2(second) !== "*") return [{ kind: "item", address: `${prefix}${head}.${name2(second)}`, index: suffixOf2(third) }];
193299
+ if (head === "module" && name2(second) !== null) return this.output(module, name2(second), steps.slice(2), depth);
193300
+ if (head === "var" && name2(second) !== null) return this.variable(module, name2(second), depth);
193301
+ return [];
193302
+ }
193303
+ /** `module.name.output`: what the output's expression names in each instance of the call, or in the one the key chooses. */
193304
+ output(module, call, rest, depth) {
193305
+ const prefix = module === "" ? "" : `${module}.`;
193306
+ const key = suffixOf2(rest[0]);
193307
+ const after = rest[0]?.kind === "index" ? rest.slice(1) : rest;
193308
+ const output2 = after[0]?.kind === "name" ? after[0].text : null;
193309
+ if (output2 === null) return [];
193310
+ const base = `${prefix}module.${call}`;
193311
+ const chosen = this.instances.filter((address) => key === null ? address === base || address.startsWith(`${base}[`) && !address.slice(base.length).includes(".") : address === `${base}${key}`);
193312
+ const out = [];
193313
+ for (const instance of chosen) {
193314
+ const config2 = this.moduleAt(instance);
193315
+ const outputs = config2 !== null && isObject4(config2["outputs"]) ? config2["outputs"] : {};
193316
+ const entry2 = outputs[output2];
193317
+ const expression2 = isObject4(entry2) && isObject4(entry2["expression"]) ? entry2["expression"] : null;
193318
+ for (const inner of strings3(expression2?.["references"])) out.push(...this.resolve(inner, instance, depth + 1));
193319
+ }
193320
+ return out;
193321
+ }
193322
+ /** `var.name` in a module: what its call passes, read where the call is written; at the root, the variable itself. */
193323
+ variable(module, variable, depth) {
193324
+ if (module === "") return [{ kind: "var", name: variable }];
193325
+ const call = this.callAt(module);
193326
+ const expressions = call !== null && isObject4(call["expressions"]) ? call["expressions"] : {};
193327
+ const passed = expressions[variable];
193328
+ const refs = isObject4(passed) ? strings3(passed["references"]).filter((ref) => !SAME_INSTANCE.has(ref)) : [];
193329
+ return refs.flatMap((ref) => this.resolve(ref, parentOf3(module), depth + 1));
193330
+ }
193331
+ };
193332
+ }
193333
+ });
193334
+
193335
+ // ../../packages/diagrams/src/importers/terraform-plan/resources.ts
193336
+ function rawOf(value) {
193337
+ if (isObject4(value)) {
193338
+ const entries2 = Object.entries(value).filter((entry2) => typeof entry2[1] === "string");
193339
+ return `{ ${entries2.map(([key, entry2]) => `${key} = ${JSON.stringify(entry2)}`).join(", ")} }`;
193340
+ }
193341
+ return JSON.stringify(value);
193342
+ }
193343
+ function valuesOf2(resource) {
193344
+ const out = /* @__PURE__ */ new Map();
193345
+ for (const [name2, value] of Object.entries(resource.values)) {
193346
+ if (resource.sensitive[name2] === true || SKIPPED2.has(name2)) continue;
193347
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") out.set(name2, String(value));
193348
+ }
193349
+ const tags = resource.values["tags"];
193350
+ const hidden = resource.sensitive["tags"];
193351
+ if (isObject4(tags) && typeof tags["Name"] === "string" && !(isObject4(hidden) && hidden["Name"] === true) && hidden !== true) out.set("tags.Name", tags["Name"]);
193352
+ return out;
193353
+ }
193354
+ function blockOf2(resource, values, start2) {
193355
+ const attributes2 = [];
193356
+ for (const [name2, value] of Object.entries(resource.values)) {
193357
+ if (resource.sensitive[name2] === true || SKIPPED2.has(name2) || value === null) continue;
193358
+ if (name2 === "tags" && !values.has("tags.Name")) continue;
193359
+ attributes2.push({ name: name2, raw: rawOf(value), literal: values.get(name2) ?? null });
193360
+ }
193361
+ return { type: resource.mode === "data" ? "data" : "resource", labels: [resource.type, resource.name], start: start2, body: "", attributes: attributes2, blocks: [] };
193362
+ }
193363
+ function stringsOf(values, sensitive) {
193364
+ const out = [];
193365
+ const walk = (value, name2, hidden, depth) => {
193366
+ if (out.length >= MAX_VALUES || depth > MAX_VALUE_DEPTH || hidden === true) return;
193367
+ if (typeof value === "string") out.push({ name: name2, value });
193368
+ else if (Array.isArray(value)) value.forEach((item, index2) => walk(item, name2, Array.isArray(hidden) ? hidden[index2] : void 0, depth + 1));
193369
+ else if (isObject4(value)) for (const [key, entry2] of Object.entries(value)) walk(entry2, key, isObject4(hidden) ? hidden[key] : void 0, depth + 1);
193370
+ };
193371
+ for (const [name2, value] of Object.entries(values)) if (!OWN_IDS.has(name2) && !SKIPPED2.has(name2) && name2 !== "tags") walk(value, name2, sensitive[name2], 0);
193372
+ return out;
193373
+ }
193374
+ function planResources(document2, text3) {
193375
+ const all = [...document2.resources, ...document2.destroyed.filter((resource) => !document2.resources.some((kept2) => kept2.address === resource.address))];
193376
+ const byBase = /* @__PURE__ */ new Map();
193377
+ for (const resource of all) byBase.set(baseOf(resource), [...byBase.get(baseOf(resource)) ?? [], resource]);
193378
+ const keyOf5 = /* @__PURE__ */ new Map();
193379
+ for (const resource of all) {
193380
+ const copies = byBase.get(baseOf(resource)) ?? [];
193381
+ keyOf5.set(resource.address, copies.length === 1 && resource.index === 0 ? baseOf(resource) : resource.address);
193382
+ }
193383
+ const alias = /* @__PURE__ */ new Map();
193384
+ for (const resource of all) {
193385
+ if (resource.mode !== "data") continue;
193386
+ const same = `${resource.module === "" ? "" : `${resource.module}.`}${resource.type}.${resource.name}`;
193387
+ if (byBase.has(same)) alias.set(baseOf(resource), same);
193388
+ }
193389
+ const instances = [...new Set(all.map((resource) => resource.module).filter((module) => module !== "").flatMap((module) => callsOf2(module).map((_call, index2, calls) => calls.slice(0, index2 + 1).map((call) => `module.${call.name}${call.suffix}`).join("."))))];
193390
+ const configuration = new Configuration(document2.configuration === null ? null : isObject4(document2.configuration["root_module"]) ? document2.configuration["root_module"] : null, instances);
193391
+ const expand2 = (target, own2, paired) => {
193392
+ if (target.kind !== "item") return [];
193393
+ const base = alias.get(target.address) ?? target.address;
193394
+ const copies = byBase.get(base) ?? [];
193395
+ const chosen = target.index !== null ? copies.filter((copy) => indexSuffix(copy.index) === target.index) : paired && own2 !== null && copies.some((copy) => copy.index === own2) ? copies.filter((copy) => copy.index === own2) : copies;
193396
+ return chosen.map((copy) => keyOf5.get(copy.address) ?? copy.address);
193397
+ };
193398
+ const byId = /* @__PURE__ */ new Map();
193399
+ const idsOf2 = /* @__PURE__ */ new Map();
193400
+ const byName = /* @__PURE__ */ new Map();
193401
+ for (const resource of all) {
193402
+ const key = keyOf5.get(resource.address) ?? resource.address;
193403
+ for (const attribute2 of ID_ATTRIBUTES) {
193404
+ const value = resource.values[attribute2];
193405
+ if (typeof value !== "string" || value.length < MIN_ID_LENGTH) continue;
193406
+ byId.set(value, byId.has(value) && byId.get(value) !== key ? null : key);
193407
+ idsOf2.set(key, /* @__PURE__ */ new Set([...idsOf2.get(key) ?? [], value]));
193408
+ }
193409
+ const name2 = resource.values["name"];
193410
+ if (typeof name2 === "string" && name2 !== "") byName.set(name2, [...byName.get(name2) ?? [], { type: resource.type, key }]);
193411
+ }
193412
+ const chosenBy = (keys, value) => {
193413
+ if (keys.length < 2 || value === void 0) return [...keys];
193414
+ const held = keys.filter((target) => [...idsOf2.get(target) ?? []].some((id) => value.has(id)));
193415
+ return held.length === 0 ? [...keys] : held;
193416
+ };
193417
+ const resources = /* @__PURE__ */ new Map();
193418
+ const offsets2 = /* @__PURE__ */ new Map();
193419
+ const throughLocals = [];
193420
+ const fromState = /* @__PURE__ */ new Set();
193421
+ for (const resource of all) {
193422
+ const key = keyOf5.get(resource.address) ?? resource.address;
193423
+ if (resource.mode === "data" && alias.has(baseOf(resource))) continue;
193424
+ const start2 = Math.max(0, text3.indexOf(JSON.stringify(resource.address)));
193425
+ offsets2.set(key, start2);
193426
+ const byAttribute = /* @__PURE__ */ new Map();
193427
+ const vars = /* @__PURE__ */ new Map();
193428
+ const add2 = (map2, name2, refs) => {
193429
+ const kept2 = refs.filter((ref) => ref !== key);
193430
+ if (kept2.length > 0) map2.set(name2, [.../* @__PURE__ */ new Set([...map2.get(name2) ?? [], ...kept2])]);
193431
+ };
193432
+ const local2 = `${resource.mode === "data" ? "data." : ""}${resource.type}.${resource.name}`;
193433
+ const configured = document2.destroyed.includes(resource) ? null : configuration.resourceAt(resource.module, local2);
193434
+ if (configured !== null) {
193435
+ if (configured.attributes.some((attribute2) => attribute2.refs.some((ref) => ref.startsWith("local.")))) throughLocals.push(key);
193436
+ const known3 = /* @__PURE__ */ new Map();
193437
+ for (const { name: name2, value } of stringsOf(resource.values, resource.sensitive)) known3.set(name2, /* @__PURE__ */ new Set([...known3.get(name2) ?? [], value]));
193438
+ for (const attribute2 of configured.attributes) {
193439
+ for (const ref of attribute2.refs) {
193440
+ for (const target of configuration.resolve(ref, resource.module)) {
193441
+ if (target.kind === "var") add2(vars, attribute2.name, [target.name]);
193442
+ else add2(byAttribute, attribute2.name, chosenBy(expand2(target, resource.index, attribute2.paired), known3.get(attribute2.name)));
193443
+ }
193444
+ }
193445
+ }
193446
+ const order = configured.dependsOn.flatMap((ref) => configuration.resolve(ref, resource.module)).flatMap((target) => expand2(target, null, false));
193447
+ add2(byAttribute, "depends_on", order);
193448
+ } else {
193449
+ const allowed = (target) => resource.dependsOn.length === 0 || resource.dependsOn.some((written3) => names7(written3, target));
193450
+ for (const { name: name2, value } of stringsOf(resource.values, resource.sensitive)) {
193451
+ const byIdKey = value.length >= MIN_ID_LENGTH ? byId.get(value) : void 0;
193452
+ if (byIdKey !== void 0 && byIdKey !== null && allowed(byIdKey)) {
193453
+ add2(byAttribute, name2, [byIdKey]);
193454
+ continue;
193455
+ }
193456
+ const stem2 = /^(.+)_name$/.exec(name2)?.[1];
193457
+ const named = stem2 === void 0 ? [] : (byName.get(value) ?? []).filter((entry2) => entry2.type.endsWith(`_${stem2}`) && allowed(entry2.key));
193458
+ if (named.length === 1 && named[0] !== void 0) add2(byAttribute, name2, [named[0].key]);
193459
+ }
193460
+ const joined2 = new Set([...byAttribute.values()].flat());
193461
+ const order = [...keyOf5.values()].filter((other) => resource.dependsOn.some((entry2) => !isModuleAddress(entry2) && names7(entry2, other)) && !joined2.has(other));
193462
+ add2(byAttribute, "depends_on", order);
193463
+ if (order.length > 0) fromState.add(key);
193464
+ }
193465
+ const values = valuesOf2(resource);
193466
+ const from = (placement) => [...new Set([...byAttribute].filter(([name2]) => PLACEMENT_ATTRIBUTES.has(name2) === placement).flatMap(([, refs]) => refs))];
193467
+ const providerKey = configured?.providerKey ?? null;
193468
+ resources.set(key, {
193469
+ key,
193470
+ kind: resource.mode === "data" ? "data" : "resource",
193471
+ type: resource.type,
193472
+ name: copyName(resource.name, key === baseOf(resource) ? null : String(resource.index)),
193473
+ block: blockOf2(resource, values, start2),
193474
+ role: roleOf2(resource.type),
193475
+ refs: from(false),
193476
+ placement: from(true),
193477
+ byAttribute,
193478
+ vars,
193479
+ values,
193480
+ readable: /* @__PURE__ */ new Map(),
193481
+ local: local2,
193482
+ scope: resource.module === "" ? "" : `${resource.module}.`,
193483
+ instance: key !== baseOf(resource),
193484
+ provider: providerKey === null ? resource.type.split("_")[0] ?? "" : providerKey.split(":").pop() ?? providerKey
193485
+ });
193486
+ }
193487
+ for (const key of fromState) {
193488
+ const resource = resources.get(key);
193489
+ if (resource !== void 0) resources.set(key, withoutIndirectOrder(resource, resources));
193490
+ }
193491
+ return { resources, modules: moduleFrames(instances, configuration, text3), offsets: offsets2, throughLocals };
193492
+ }
193493
+ function withoutIndirectOrder(resource, resources) {
193494
+ const order = resource.byAttribute.get("depends_on") ?? [];
193495
+ const direct = [...new Set([...resource.byAttribute.values()].flat())];
193496
+ const reachable = /* @__PURE__ */ new Set();
193497
+ let frontier = direct.flatMap((key) => [...resources.get(key)?.byAttribute.values() ?? []].flat());
193498
+ for (let depth = 0; frontier.length > 0 && depth < MAX_ORDER_DEPTH; depth += 1) {
193499
+ const next = frontier.filter((key) => key !== resource.key && !reachable.has(key));
193500
+ for (const key of next) reachable.add(key);
193501
+ frontier = next.flatMap((key) => [...resources.get(key)?.byAttribute.values() ?? []].flat());
193502
+ }
193503
+ const kept2 = order.filter((key) => !reachable.has(key));
193504
+ if (kept2.length === order.length) return resource;
193505
+ const byAttribute = new Map(resource.byAttribute);
193506
+ if (kept2.length === 0) byAttribute.delete("depends_on");
193507
+ else byAttribute.set("depends_on", kept2);
193508
+ const from = (placement) => [...new Set([...byAttribute].filter(([name2]) => PLACEMENT_ATTRIBUTES.has(name2) === placement).flatMap(([, refs]) => refs))];
193509
+ return { ...resource, byAttribute, refs: from(false), placement: from(true) };
193510
+ }
193511
+ function moduleFrames(instances, configuration, text3) {
193512
+ return instances.map((address) => {
193513
+ const calls = callsOf2(address);
193514
+ const last = calls[calls.length - 1];
193515
+ const call = configuration.callAt(address);
193516
+ const source = call !== null && typeof call["source"] === "string" ? call["source"] : "";
193517
+ const name2 = last?.name ?? address;
193518
+ const key = last?.suffix ?? "";
193519
+ const instance = key === "" ? null : key.replace(/^\["?|"?\]$/g, "");
193520
+ const start2 = Math.max(0, text3.indexOf(`"${address.replace(/"/g, '\\"')}"`));
193521
+ return { prefix: `${address}.`, key: address, name: name2, instance, source, block: { type: "module", labels: [name2], start: start2, body: "", attributes: [], blocks: [] } };
193522
+ });
193523
+ }
193524
+ var MAX_VALUE_DEPTH, MAX_VALUES, MIN_ID_LENGTH, OWN_IDS, ID_ATTRIBUTES, SKIPPED2, baseOf, names7, MAX_ORDER_DEPTH, isModuleAddress;
193525
+ var init_resources2 = __esm({
193526
+ "../../packages/diagrams/src/importers/terraform-plan/resources.ts"() {
193527
+ "use strict";
193528
+ init_address();
193529
+ init_generic();
193530
+ init_graph4();
193531
+ init_resources();
193532
+ init_document3();
193533
+ init_references2();
193534
+ MAX_VALUE_DEPTH = 6;
193535
+ MAX_VALUES = 400;
193536
+ MIN_ID_LENGTH = 6;
193537
+ OWN_IDS = /* @__PURE__ */ new Set(["id", "arn", "self_link", "unique_id"]);
193538
+ ID_ATTRIBUTES = ["id", "arn", "self_link"];
193539
+ SKIPPED2 = /* @__PURE__ */ new Set(["tags_all", "timeouts"]);
193540
+ baseOf = (resource) => `${resource.module === "" ? "" : `${resource.module}.`}${resource.mode === "data" ? "data." : ""}${resource.type}.${resource.name}`;
193541
+ names7 = (written3, address) => address === written3 || address.startsWith(`${written3}[`) || address.startsWith(`${written3}.`);
193542
+ MAX_ORDER_DEPTH = 32;
193543
+ isModuleAddress = (address) => !/(?:^|\.)[a-z][a-z0-9]*_[a-z0-9_]+\.[A-Za-z0-9_-]+(?:\[[^\]]*\])?$/.test(address);
193544
+ }
193545
+ });
193546
+
193547
+ // ../../packages/diagrams/src/importers/terraform-plan/index.ts
193548
+ function changeName(change, importing) {
193549
+ if (change === void 0) return null;
193550
+ const actions = change.actions.join(",");
193551
+ if (actions === "create") return "create";
193552
+ if (actions === "update") return importing ? "import" : "update";
193553
+ if (actions === "delete,create" || actions === "create,delete") return "replace";
193554
+ if (actions === "delete") return "destroy";
193555
+ if (actions === "forget") return "forget";
193556
+ if (actions === "no-op") return importing ? "import" : change.previous !== null ? "move" : null;
193557
+ return null;
193558
+ }
193559
+ function importedOf(json2) {
193560
+ const out = /* @__PURE__ */ new Set();
193561
+ const changes = json2["resource_changes"];
193562
+ if (Array.isArray(changes)) {
193563
+ for (const entry2 of changes) if (isObject4(entry2) && isObject4(entry2["change"]) && entry2["change"]["importing"] !== void 0 && typeof entry2["address"] === "string") out.add(entry2["address"]);
193564
+ }
193565
+ return out;
193566
+ }
193567
+ function accountsOf(document2, types) {
193568
+ const out = /* @__PURE__ */ new Map();
193569
+ for (const entry2 of Object.values(document2.providers)) {
193570
+ if (!isObject4(entry2) || typeof entry2["name"] !== "string") continue;
193571
+ const cloud = providerOf2(`${entry2["name"]}_x`);
193572
+ if (cloud === null || out.get(cloud) !== void 0) continue;
193573
+ const expressions = isObject4(entry2["expressions"]) ? entry2["expressions"] : {};
193574
+ const project = isObject4(expressions["project"]) ? expressions["project"]["constant_value"] : void 0;
193575
+ out.set(cloud, cloud === "gcp" && typeof project === "string" ? project : null);
193576
+ }
193577
+ for (const type of types) {
193578
+ const cloud = providerOf2(type);
193579
+ if (cloud !== null && !out.has(cloud)) out.set(cloud, null);
193580
+ }
193581
+ return out;
193582
+ }
193583
+ function regionsOf2(document2) {
193584
+ const out = /* @__PURE__ */ new Map();
193585
+ const byProvider = /* @__PURE__ */ new Map();
193586
+ for (const [key, entry2] of Object.entries(document2.providers)) {
193587
+ if (!isObject4(entry2) || typeof entry2["name"] !== "string" || key.includes(":")) continue;
193588
+ const expressions = isObject4(entry2["expressions"]) ? entry2["expressions"] : {};
193589
+ const region = isObject4(expressions["region"]) ? expressions["region"]["constant_value"] : void 0;
193590
+ if (typeof region !== "string" || region === "") continue;
193591
+ out.set(key, region);
193592
+ byProvider.set(entry2["name"], /* @__PURE__ */ new Set([...byProvider.get(entry2["name"]) ?? [], region]));
193593
+ }
193594
+ for (const [key] of out) if ((byProvider.get(key.split(".")[0] ?? "")?.size ?? 0) < 2) out.delete(key);
193595
+ return out;
193596
+ }
193597
+ function summaryOf(document2, imported) {
193598
+ let add2 = 0;
193599
+ let change = 0;
193600
+ let destroy = 0;
193601
+ let importing = 0;
193602
+ for (const [address, entry2] of document2.changes) {
193603
+ const actions = entry2.actions.join(",");
193604
+ if (actions === "create" || actions === "delete,create" || actions === "create,delete") add2 += 1;
193605
+ if (actions === "update") change += 1;
193606
+ if (actions === "delete" || actions === "delete,create" || actions === "create,delete") destroy += 1;
193607
+ if (imported.has(address)) importing += 1;
193608
+ }
193609
+ if (add2 + change + destroy + importing === 0) return "no changes";
193610
+ return `${importing > 0 ? `${importing} to import, ` : ""}${add2} to add, ${change} to change, ${destroy} to destroy`;
193611
+ }
193612
+ function readTerraformPlan(text3, context) {
193613
+ const index2 = new LineIndex(text3);
193614
+ let json2;
193615
+ try {
193616
+ json2 = JSON.parse(text3);
193617
+ } catch (error62) {
193618
+ context.report.add(DIAGNOSTIC_CODES.importUnreadable, START, `The text is not JSON: ${error62 instanceof Error ? error62.message : "it cannot be read"}.`, "Send the output of terraform show -json plan.out, or of terraform show -json for the state, as it is written.");
193619
+ return null;
193620
+ }
193621
+ const document2 = readPlanDocument(json2);
193622
+ if (document2 === null || !isObject4(json2)) {
193623
+ context.report.add(DIAGNOSTIC_CODES.importNoShape, START, "The JSON is neither a plan (planned_values and resource_changes) nor a state (values.root_module).", "Run terraform plan -out=plan.out, then send the output of terraform show -json plan.out; or send terraform show -json for the state.");
193624
+ return null;
193625
+ }
193626
+ if (json2["errored"] === true) context.report.add(DIAGNOSTIC_CODES.importChanged, START, "The plan stopped on an error, so it may hold only part of the stack.", "Fix the error terraform plan reports, and send the plan again.");
193627
+ const missing = [...document2.changes].filter(([address, change]) => destroys(change) && !document2.destroyed.some((resource) => resource.address === address)).map(([address]) => address);
193628
+ if (missing.length > 0) context.report.add(DIAGNOSTIC_CODES.importSkipped, START, `${countOf2(missing.length, "resource")} the plan destroys ${missing.length === 1 ? "is" : "are"} not in its prior state, so ${missing.length === 1 ? "it is" : "they are"} not drawn: ${missing.slice(0, 3).map((address) => cleanText(address)).join(", ")}.`, "Send the plan as terraform show -json writes it, with prior_state.");
193629
+ const stack = planResources(document2, text3);
193630
+ if (![...stack.resources.values()].some((resource) => resource.kind !== "data")) {
193631
+ context.report.add(DIAGNOSTIC_CODES.importNoShape, START, `The ${document2.kind} holds no managed resource.`, document2.kind === "plan" ? "Send the plan of a stack with resource blocks." : "Send the state of a stack that has been applied.");
193632
+ return null;
193633
+ }
193634
+ const first = stack.throughLocals[0];
193635
+ if (first !== void 0) {
193636
+ context.report.add(DIAGNOSTIC_CODES.importUnresolved, index2.span(stack.offsets.get(first) ?? 0), `${countOf2(stack.throughLocals.length, "resource")} name${stack.throughLocals.length === 1 ? "s" : ""} other resources through local values, which the plan's JSON does not expand, so those arrows are not drawn: ${stack.throughLocals.slice(0, 3).join(", ")}.`, "Import the .tf files with format terraform for those arrows, or reference the resources directly.");
193637
+ }
193638
+ const imported = importedOf(json2);
193639
+ const tones = /* @__PURE__ */ new Set();
193640
+ const changeOf = (key) => {
193641
+ const address = document2.changes.has(key) ? key : `${key}[0]`;
193642
+ const name2 = changeName(document2.changes.get(address), imported.has(address));
193643
+ const drifted2 = document2.drift.has(address);
193644
+ if (name2 === null) return drifted2 ? { tone: "neutral", word: "drifted" } : null;
193645
+ const look = CHANGES[name2];
193646
+ if (look === void 0) return null;
193647
+ tones.add(name2);
193648
+ return { tone: look.tone, word: drifted2 ? `${look.word}, drifted` : look.word, ...look.mark === void 0 ? {} : { mark: look.mark } };
193649
+ };
193650
+ for (const key of stack.resources.keys()) changeOf(key);
193651
+ const said = Object.keys(CHANGES).filter((name2) => tones.has(name2)).map((name2, at3) => (CHANGES[name2]?.said ?? "").replace(/^(?:a box|one) /, at3 === 0 ? "a box " : "one "));
193652
+ const drifted = [...document2.drift].length;
193653
+ const note = document2.kind === "state" ? "It is drawn from the state, as the stack was last applied." : `It is drawn as the plan leaves the stack${said.length === 0 ? ", which the plan does not change" : `: ${joinWords2(said)}`}.${drifted > 0 ? ` ${countOf2(drifted, "resource")} changed outside Terraform since the last apply, marked drifted.` : ""}`;
193654
+ const variable = (name2) => {
193655
+ const value = document2.variables.get(name2);
193656
+ return value === void 0 || value === "" ? null : lastPart(value);
193657
+ };
193658
+ const regions = regionsOf2(document2);
193659
+ const keyed = [...stack.resources.values()];
193660
+ return drawStack({
193661
+ resources: stack.resources,
193662
+ modules: stack.modules,
193663
+ compatible: stack.modules.length === 0 && !keyed.some((resource) => resource.instance === true),
193664
+ regionOf: (resource) => regions.get(resource.provider ?? "") ?? null,
193665
+ providers: accountsOf(document2, keyed.map((resource) => resource.type)),
193666
+ variableName: (name2) => variable(name2) ?? variableLabel(name2),
193667
+ variableValue: variable,
193668
+ context,
193669
+ span: (key) => index2.span(stack.offsets.get(key) ?? 0),
193670
+ tool: "Terraform",
193671
+ change: changeOf,
193672
+ ...document2.kind === "plan" ? { summary: summaryOf(document2, imported) } : {},
193673
+ note
193674
+ });
193675
+ }
193676
+ function joinWords2(words2) {
193677
+ if (words2.length < 3) return words2.join(" or ");
193678
+ return `${words2.slice(0, -1).join(", ")}, or ${words2[words2.length - 1] ?? ""}`;
193679
+ }
193680
+ var CHANGES, terraformPlanImporter;
193681
+ var init_terraform_plan = __esm({
193682
+ "../../packages/diagrams/src/importers/terraform-plan/index.ts"() {
193683
+ "use strict";
193684
+ init_core();
193685
+ init_shared2();
193686
+ init_terraform();
193687
+ init_labels();
193688
+ init_resources();
193689
+ init_values2();
193690
+ init_document3();
193691
+ init_resources2();
193692
+ CHANGES = {
193693
+ create: { tone: "green", word: "create", said: "one marked + is created", mark: "create" },
193694
+ update: { tone: "amber", word: "update", said: "one marked ~ is changed in place", mark: "update" },
193695
+ replace: { tone: "orange", word: "replace", said: "one marked \xB1 is replaced", mark: "replace" },
193696
+ destroy: { tone: "red", word: "destroy", said: "one marked \u2212 is destroyed", mark: "destroy" },
193697
+ import: { tone: "aqua", word: "import", said: "one in aqua is imported" },
193698
+ move: { tone: "aqua", word: "move", said: "one in aqua is moved" },
193699
+ forget: { tone: "violet", word: "forget", said: "one in violet is removed from the state and kept in the cloud" }
193700
+ };
193701
+ terraformPlanImporter = { format: "terraform-plan", kinds: ["flow"], joins: null, extensions: [".json"], read: readTerraformPlan };
193702
+ }
193703
+ });
193704
+
192863
193705
  // ../../packages/diagrams/src/importers/tree/read.ts
192864
193706
  function childOf(parent, name2, line3) {
192865
193707
  const existing = parent.find((entry3) => entry3.name === name2);
@@ -193175,6 +194017,7 @@ var init_registry4 = __esm({
193175
194017
  init_pulumi();
193176
194018
  init_sql();
193177
194019
  init_terraform();
194020
+ init_terraform_plan();
193178
194021
  init_tree5();
193179
194022
  IMPORTERS = {
193180
194023
  sql: sqlImporter,
@@ -193182,6 +194025,7 @@ var init_registry4 = __esm({
193182
194025
  drizzle: drizzleImporter,
193183
194026
  openapi: openapiImporter,
193184
194027
  terraform: terraformImporter,
194028
+ "terraform-plan": terraformPlanImporter,
193185
194029
  bicep: bicepImporter,
193186
194030
  arm: armImporter,
193187
194031
  pulumi: pulumiImporter,
@@ -193298,7 +194142,7 @@ function importSource(format, input2, title = null, options3 = {}, limits = HOST
193298
194142
  const report3 = new ImportReporter();
193299
194143
  const files = typeof input2 === "string" ? [{ path: "", text: input2 }] : input2;
193300
194144
  const characters = files.reduce((total, file2) => total + file2.text.length, 0);
193301
- const local2 = limits.maxLength < WORKFLOW_LIMITS.maxImportLocalLength ? ` The local server (npx -y @buun_group/plotwork-mcp) runs on your own machine and reads far more.` : "";
194145
+ const local2 = limits.maxLength < WORKFLOW_LIMITS.maxImportLocalLength ? ` The local server (${mcpCommand()}) runs on your own machine and reads far more.` : "";
193302
194146
  if (characters > limits.maxText || files.length > limits.maxFiles) {
193303
194147
  report3.add(
193304
194148
  DIAGNOSTIC_CODES.importTooLarge,
@@ -193577,13 +194421,13 @@ var init_definitions = __esm({
193577
194421
 
193578
194422
  // ../../packages/diagrams/src/edit/find.ts
193579
194423
  function namesIn2(scan) {
193580
- const names7 = /* @__PURE__ */ new Set();
194424
+ const names8 = /* @__PURE__ */ new Set();
193581
194425
  for (const element of scan.elements) {
193582
194426
  if (!NAMED_ROLES.has(element.role)) continue;
193583
- if (element.id !== null) names7.add(element.id);
193584
- if (element.label !== null) names7.add(element.label);
194427
+ if (element.id !== null) names8.add(element.id);
194428
+ if (element.label !== null) names8.add(element.label);
193585
194429
  }
193586
- return [...names7];
194430
+ return [...names8];
193587
194431
  }
193588
194432
  function unknownHint(scan, target) {
193589
194433
  const close2 = suggest(target, namesIn2(scan));
@@ -193696,7 +194540,7 @@ function spliced(line3, splices) {
193696
194540
  return [...splices].sort((a, b) => b.start - a.start).reduce((text3, splice) => `${text3.slice(0, splice.start)}${splice.text}${text3.slice(splice.end)}`, line3);
193697
194541
  }
193698
194542
  var TYPE_WORDS2;
193699
- var init_references2 = __esm({
194543
+ var init_references3 = __esm({
193700
194544
  "../../packages/diagrams/src/edit/references.ts"() {
193701
194545
  "use strict";
193702
194546
  init_constants();
@@ -193770,23 +194614,23 @@ function remove(scan, op) {
193770
194614
  const element = scan.elements[found.index];
193771
194615
  if (element.role === "header") return refused2("The header cannot be removed.", "Change it with set, or replace_text.");
193772
194616
  const gone = [found.index, ...descendantsOf(scan, found.index)];
193773
- const names7 = new Set(gone.map((index2) => referenceName(scan.elements[index2])).filter((name2) => name2 !== null));
194617
+ const names8 = new Set(gone.map((index2) => referenceName(scan.elements[index2])).filter((name2) => name2 !== null));
193774
194618
  const block = element.parent === null ? null : scan.elements[element.parent];
193775
- if (element.role === "row" && element.id !== null && block !== null) names7.add(`${block.id ?? block.label ?? ""}.${element.id}`);
194619
+ if (element.role === "row" && element.id !== null && block !== null) names8.add(`${block.id ?? block.label ?? ""}.${element.id}`);
193776
194620
  const drop = /* @__PURE__ */ new Set();
193777
194621
  for (let line3 = element.start; line3 <= element.end; line3 += 1) drop.add(line3);
193778
194622
  const left = [];
193779
194623
  let edges = 0;
193780
194624
  let others = 0;
193781
- const isGone = (end) => end !== null && [...names7].some((name2) => end === name2 || end.startsWith(`${name2}.`));
194625
+ const isGone = (end) => end !== null && [...names8].some((name2) => end === name2 || end.startsWith(`${name2}.`));
193782
194626
  scan.elements.forEach((candidate2) => {
193783
194627
  if (drop.has(candidate2.start) || candidate2.role === "header") return;
193784
194628
  const tokens = scan.tokens.get(candidate2.start) ?? [];
193785
- if (candidate2.role === "edge" ? isGone(candidate2.from) || isGone(candidate2.to) : candidate2.role === "other" && [...names7].some((name2) => idReferences(tokens, name2, false).length > 0 || tokens.some((token) => token.kind === "string" && token.text === name2))) {
194629
+ if (candidate2.role === "edge" ? isGone(candidate2.from) || isGone(candidate2.to) : candidate2.role === "other" && [...names8].some((name2) => idReferences(tokens, name2, false).length > 0 || tokens.some((token) => token.kind === "string" && token.text === name2))) {
193786
194630
  if (candidate2.role === "edge") edges += 1;
193787
194631
  else others += 1;
193788
194632
  for (let line3 = candidate2.start; line3 <= candidate2.end; line3 += 1) drop.add(line3);
193789
- } else if (candidate2.options.some((option) => REFERENCE_OPTIONS.has(option.key) && option.value.split(",").some((value) => names7.has(value.trim())))) {
194633
+ } else if (candidate2.options.some((option) => REFERENCE_OPTIONS.has(option.key) && option.value.split(",").some((value) => names8.has(value.trim())))) {
193790
194634
  left.push(candidate2.start);
193791
194635
  }
193792
194636
  });
@@ -193835,7 +194679,7 @@ var init_structure = __esm({
193835
194679
  "use strict";
193836
194680
  init_find();
193837
194681
  init_outcome();
193838
- init_references2();
194682
+ init_references3();
193839
194683
  init_scan2();
193840
194684
  init_source_text();
193841
194685
  NODE_STATEMENTS = {
@@ -194033,7 +194877,7 @@ var init_rename_set = __esm({
194033
194877
  "use strict";
194034
194878
  init_find();
194035
194879
  init_outcome();
194036
- init_references2();
194880
+ init_references3();
194037
194881
  init_source_text();
194038
194882
  }
194039
194883
  });
@@ -194659,7 +195503,7 @@ var init_import_source3 = __esm({
194659
195503
  importSourceWorkflow = defineWorkflow({
194660
195504
  name: "import_source",
194661
195505
  title: "Import source",
194662
- description: "Workflow. Turns a file into a finished diagram in one call: SQL DDL, Prisma, or Drizzle into a schema; an OpenAPI document into an endpoint access matrix, a map of its endpoints by tag, or one operation as a sequence; Terraform, Bicep, ARM, Pulumi, CloudFormation, Compose, Kubernetes, or a GitHub Actions workflow into a flow with icons and frames; CSV or JSON data into the chart its shape suits; tree output or paths into a tree; a git log into a git graph or timeline. Prefer it to writing the diagram by hand whenever the person has such a file: send its text, never a path, or for a Terraform or Bicep stack, SQL migrations, or Kubernetes manifests send every file of the folder in files. Returns the source, diagnostics pointing into the file for anything left out, coverage of the file, parts (every diagram of a split file), the validation, an outline, viewUrl, and saveCommand. It runs no code and reads no file or URL. Replaces reading the file, writing the source by hand, validate_diagram and outline_diagram.",
195506
+ description: "Workflow. Turns a file into a finished diagram in one call: SQL DDL, Prisma, or Drizzle into a schema; an OpenAPI document into an endpoint access matrix, a map of its endpoints by tag, or one operation as a sequence; Terraform, Bicep, ARM, Pulumi, CloudFormation, Compose, Kubernetes, or a GitHub Actions workflow into a flow with icons and frames; CSV or JSON data into the chart its shape suits; tree output or paths into a tree; a git log into a git graph or timeline. Prefer it to writing the diagram by hand whenever the person has such a file: send its text, never a path, or for a stack, migrations, or manifests send every file of the folder in files. Returns the source, diagnostics pointing into the file for anything left out, coverage of the file, parts (every diagram of a split file), the validation, an outline, viewUrl, and saveCommand. It runs no code and reads no file or URL. Replaces writing the source by hand, validate_diagram and outline_diagram.",
194663
195507
  input: ImportSourceInputSchema,
194664
195508
  output: ImportSourceResponseSchema,
194665
195509
  steps: [{ call: "importSource" }, { call: "validate", optional: true }, { call: "outline", optional: true }],
@@ -195358,8 +196202,8 @@ function readMaterial(text3, cap2) {
195358
196202
  }
195359
196203
  closeTable2();
195360
196204
  if (table2 === null && items2.length === 0) table2 = delimitedTable(plain3.filter((line3) => line3.trim() !== ""));
195361
- const names7 = namesInSentence(plain3.join(" "));
195362
- return { items: items2, numbered: items2.length > 0 && numbered * 2 >= items2.length, labelled: labelled2, table: table2, figures, seriesName: series.name, movements, dated, names: names7, relations, actorSteps };
196205
+ const names8 = namesInSentence(plain3.join(" "));
196206
+ return { items: items2, numbered: items2.length > 0 && numbered * 2 >= items2.length, labelled: labelled2, table: table2, figures, seriesName: series.name, movements, dated, names: names8, relations, actorSteps };
195363
196207
  }
195364
196208
  function readShapes(body6, into, cap2) {
195365
196209
  if (body6.length > SHAPE_LINE_CHARACTERS) return;
@@ -195491,8 +196335,8 @@ ${body6.join("\n")}
195491
196335
  `;
195492
196336
  }
195493
196337
  function entitiesOf(material) {
195494
- const names7 = distinctLabels(material.names);
195495
- if (names7.length >= 2) return names7;
196338
+ const names8 = distinctLabels(material.names);
196339
+ if (names8.length >= 2) return names8;
195496
196340
  const items2 = topItems(material);
195497
196341
  if (items2.length >= 2) return items2;
195498
196342
  const labels2 = distinctLabels(material.labelled.map((line3) => line3.label));
@@ -195586,7 +196430,7 @@ var init_charts = __esm({
195586
196430
  return sourceOf(`pie ${quoted4(title)}`, slices.map((slice) => `slice ${quoted4(slice.label)} ${slice.value}`));
195587
196431
  },
195588
196432
  quadrant: (material, title) => {
195589
- const names7 = orDefault(entitiesOf(material), ["Saved filters", "Mobile app", "Footer links", "Rewrite in Rust"], 2, MOST);
196433
+ const names8 = orDefault(entitiesOf(material), ["Saved filters", "Mobile app", "Footer links", "Rewrite in Rust"], 2, MOST);
195590
196434
  const places = [[0.2, 0.8], [0.75, 0.8], [0.25, 0.25], [0.75, 0.25], [0.4, 0.62], [0.6, 0.4], [0.12, 0.5], [0.88, 0.58]];
195591
196435
  return sourceOf(`quadrant ${quoted4(title)} highlight=top-left`, [
195592
196436
  'x "Effort" low="Low effort" high="High effort"',
@@ -195597,7 +196441,7 @@ var init_charts = __esm({
195597
196441
  'zone bottom-left "Fill-ins"',
195598
196442
  'zone bottom-right "Time sinks"',
195599
196443
  "",
195600
- ...names7.map((name2, index2) => `point ${quoted4(name2)} x=${places[index2]?.[0] ?? 0.5} y=${places[index2]?.[1] ?? 0.5}`)
196444
+ ...names8.map((name2, index2) => `point ${quoted4(name2)} x=${places[index2]?.[0] ?? 0.5} y=${places[index2]?.[1] ?? 0.5}`)
195601
196445
  ]);
195602
196446
  },
195603
196447
  sankey: (material, title) => {
@@ -195638,9 +196482,9 @@ function gridOf(material, columnDefaults, rowDefaults) {
195638
196482
  if (table2 !== null && table2.header.length >= 2 && table2.rows.length >= 1) {
195639
196483
  const columns = distinctLabels(table2.header.slice(1)).slice(0, MOST);
195640
196484
  const rows2 = table2.rows.slice(0, MOST);
195641
- const names7 = rows2.map((row, index2) => cleanLabel2(row[0] ?? "") || `Row ${index2 + 1}`);
195642
- if (columns.length === Math.min(table2.header.length - 1, MOST) && new Set(names7.map((name2) => name2.toLowerCase())).size === names7.length) {
195643
- return { rows: names7, columns, cells: rows2.map((row) => columns.map((_, index2) => row[index2 + 1] ?? "")) };
196485
+ const names8 = rows2.map((row, index2) => cleanLabel2(row[0] ?? "") || `Row ${index2 + 1}`);
196486
+ if (columns.length === Math.min(table2.header.length - 1, MOST) && new Set(names8.map((name2) => name2.toLowerCase())).size === names8.length) {
196487
+ return { rows: names8, columns, cells: rows2.map((row) => columns.map((_, index2) => row[index2 + 1] ?? "")) };
195644
196488
  }
195645
196489
  }
195646
196490
  const lists = listsOf(material);
@@ -195740,11 +196584,11 @@ var init_matrix3 = __esm({
195740
196584
  return matrixSource2(title, "raci", grid, cellsOf2(grid, raciCell));
195741
196585
  },
195742
196586
  "matrix-risk": (material, title) => {
195743
- const names7 = orDefault(entitiesOf(material), ["Data loss", "Vendor outage", "Key person leaves", "Cost overrun"], 2, MOST);
196587
+ const names8 = orDefault(entitiesOf(material), ["Data loss", "Vendor outage", "Key person leaves", "Cost overrun"], 2, MOST);
195744
196588
  const places = [[4, 5], [2, 4], [3, 3], [5, 2], [1, 5], [3, 4], [2, 2], [4, 3]];
195745
196589
  return sourceOf(
195746
196590
  `matrix ${quoted4(title)} style=risk`,
195747
- names7.map((name2, index2) => `item ${quoted4(name2)} likelihood=${places[index2]?.[0] ?? 3} impact=${places[index2]?.[1] ?? 3}`)
196591
+ names8.map((name2, index2) => `item ${quoted4(name2)} likelihood=${places[index2]?.[0] ?? 3} impact=${places[index2]?.[1] ?? 3}`)
195748
196592
  );
195749
196593
  }
195750
196594
  };
@@ -195944,9 +196788,9 @@ function layersOf(material) {
195944
196788
  }
195945
196789
  return layers.filter((layer2) => layer2.name !== "").slice(0, 6);
195946
196790
  }
195947
- const names7 = orDefault(entitiesOf(material), ["Web app", "API", "Database"], 2, MOST);
196791
+ const names8 = orDefault(entitiesOf(material), ["Web app", "API", "Database"], 2, MOST);
195948
196792
  const tiers = ["Experience", "Services", "Data"];
195949
- return tiers.map((name2, index2) => ({ name: name2, blocks: names7.filter((_, place2) => place2 % tiers.length === index2) }));
196793
+ return tiers.map((name2, index2) => ({ name: name2, blocks: names8.filter((_, place2) => place2 % tiers.length === index2) }));
195950
196794
  }
195951
196795
  function partType(name2) {
195952
196796
  if (/\b(postgres(ql)?|mysql|database|db|dynamo(db)?|sql|mongo(db)?|redis|cache|s3|bucket|storage|store)\b/i.test(name2)) return /\b(redis|cache)\b/i.test(name2) ? "cache" : /\b(s3|bucket|storage)\b/i.test(name2) ? "storage" : "database";
@@ -196432,8 +197276,8 @@ function nextFor2(suggestions, cloud) {
196432
197276
  }
196433
197277
  function suggestDiagrams(request, data, check2) {
196434
197278
  const read = readMaterial(data ?? "", WORKFLOW_LIMITS.maxStarterItems);
196435
- const names7 = read.names.length >= 2 ? read.names : namesInSentence(request);
196436
- const material = { ...read, names: names7 };
197279
+ const names8 = read.names.length >= 2 ? read.names : namesInSentence(request);
197280
+ const material = { ...read, names: names8 };
196437
197281
  const ranked = rankIntents(
196438
197282
  [
196439
197283
  { text: request, weight: 2 },
@@ -196942,7 +197786,21 @@ function rebaseFileLinks(value, base) {
196942
197786
  const moved3 = files.map((file2) => isRecord5(file2) && typeof file2["viewUrl"] === "string" && file2["viewUrl"].startsWith(`${engine2}#`) ? { ...file2, viewUrl: `${base}${file2["viewUrl"].slice(engine2.length)}` } : file2);
196943
197787
  return { ...value, files: moved3 };
196944
197788
  }
196945
- var SOURCE_OF, VIEW_LINK_TOOLS;
197789
+ function stripViewLinks(value) {
197790
+ if (!isRecord5(value)) return value;
197791
+ const kept2 = { ...value };
197792
+ for (const field of VIEW_LINK_FIELDS) delete kept2[field];
197793
+ const files = kept2["files"];
197794
+ if (Array.isArray(files)) {
197795
+ kept2["files"] = files.map((file2) => {
197796
+ if (!isRecord5(file2) || !("viewUrl" in file2)) return file2;
197797
+ const { viewUrl: _viewUrl, ...rest } = file2;
197798
+ return rest;
197799
+ });
197800
+ }
197801
+ return kept2;
197802
+ }
197803
+ var SOURCE_OF, VIEW_LINK_TOOLS, VIEW_LINK_FIELDS;
196946
197804
  var init_view_link = __esm({
196947
197805
  "../../packages/diagrams/src/tools/view-link.ts"() {
196948
197806
  "use strict";
@@ -196958,6 +197816,7 @@ var init_view_link = __esm({
196958
197816
  import_source: (_args, answer) => answer["validation"]?.["valid"] === true ? answer["source"] : null
196959
197817
  };
196960
197818
  VIEW_LINK_TOOLS = Object.keys(SOURCE_OF);
197819
+ VIEW_LINK_FIELDS = ["viewUrl", "pngUrl", "svgUrl", "saveCommand"];
196961
197820
  }
196962
197821
  });
196963
197822
 
@@ -197330,6 +198189,12 @@ function savingInstructions(release = CLI_RELEASE) {
197330
198189
  `To save a valid diagram into the person's repository, run the saveCommand a drawing tool returns in a shell, changing --out to the path you want (add --theme dark for the dark picture): the Plotwork command line reads the diagram from the link on that machine, fetches nothing, and writes the SVG with its source embedded, so you never copy the SVG yourself. With no shell, draw with svg "always" and embedSource true and write the returned svg. ${people}`
197331
198190
  ];
197332
198191
  }
198192
+ function libraryInstructions(library) {
198193
+ return `This connection publishes to the private library of ${JSON.stringify(library.name)}, which only its members can open. So, unlike a public link, a finished diagram is saved there without asking: once the person is happy with a diagram, call publish_diagram with its source and leave organization out, then give the person the viewUrl it returns. Pass personal true only when the person asks for a public link.`;
198194
+ }
198195
+ function librarySaveStep(library) {
198196
+ return `When the diagram is finished, save it to the private library of ${JSON.stringify(library.name)} with publish_diagram (no need to ask: only members can open it).`;
198197
+ }
197333
198198
  var SERVER_INFO, SAVING_INSTRUCTIONS, SERVER_INSTRUCTIONS, HOSTED_INSTRUCTIONS;
197334
198199
  var init_server_info = __esm({
197335
198200
  "src/server-info.ts"() {
@@ -197361,7 +198226,7 @@ var init_server_info = __esm({
197361
198226
  "Use validate_diagram, outline_diagram, render_diagram, and search_icons only for one fine-grained step.",
197362
198227
  "Choose node types and tones for meaning; colors are chosen by the theme and cannot be set."
197363
198228
  ].join(" ");
197364
- HOSTED_INSTRUCTIONS = "When the person asks to share a finished diagram or wants a link to it, call publish_diagram with the valid source: it returns a public link and a Markdown image to paste, and publishing the same diagram again returns the same link. Publish only when asked, because anyone with the link can see the picture. After you edit a published diagram, call publish_diagram again: an edited diagram is a new picture with a new link, so replace the old link wherever it is used. Set embedSource true on publish_diagram when someone may want to edit the diagram later, and tell the person that the source is then part of the public picture. A drawing too big to return in an answer is also the case for publish_diagram: it gives a link in place of the picture. To keep a diagram inside a team instead, pass organization with the slug or id of an organisation, but only when the person names an organisation or asks for a team diagram: it is stored in that organisation's private library and the answer has a viewUrl for members in place of a public link, so there is no Markdown image. Never guess an organisation, and if it is not found, ask the person which one they mean. An owner may restrict a folder, and a reader may not publish: when the answer says the folder is restricted or the role does not allow it, ask the person which folder they may use instead of trying others or publishing elsewhere. Call list_diagrams when the person asks what they have published or to get a diagram id; it changes nothing. Call delete_diagram only after the person has said which diagram to delete, by name, and tell them what you deleted; never delete on a guess, in bulk, or to make room for a publish unless they asked, and a locked diagram cannot be deleted until the owner unlocks it.";
198229
+ HOSTED_INSTRUCTIONS = "When the person asks to share a finished diagram or wants a link to it, call publish_diagram with the valid source: it returns a public link and a Markdown image to paste, and publishing the same diagram again returns the same link. Publish only when asked, because anyone with the link can see the picture. After you edit a published diagram, call publish_diagram again: an edited diagram is a new picture with a new link, so replace the old link wherever it is used. Set embedSource true on publish_diagram when someone may want to edit the diagram later, and tell the person that the source is then part of the public picture. A drawing too big to return in an answer is also the case for publish_diagram: it gives a link in place of the picture. To keep a diagram inside a team instead, pass organization with the slug or id of an organisation, but only when the person names an organisation or asks for a team diagram: it is stored in that organisation's private library and the answer has a viewUrl for members in place of a public link, so there is no Markdown image. Never guess an organisation, and if it is not found, ask the person which one they mean. An organisation can also send its members' diagrams to its library when organization is left out: the answer then names it and says why, and the person must be told the diagram is in that library, not at a public link. Pass personal true only when the person asks for a public link anyway; an organisation that requires its library refuses it, and then tell the person. An owner may restrict a folder, and a reader may not publish: when the answer says the folder is restricted or the role does not allow it, ask the person which folder they may use instead of trying others or publishing elsewhere. Call list_diagrams when the person asks what they have published or to get a diagram id; it changes nothing. Call delete_diagram only after the person has said which diagram to delete, by name, and tell them what you deleted; never delete on a guess, in bulk, or to make room for a publish unless they asked, and a locked diagram cannot be deleted until the owner unlocks it.";
197365
198230
  }
197366
198231
  });
197367
198232
 
@@ -197632,8 +198497,9 @@ async function callTool(tool, args, log, caller, activity, run3, budget2, answer
197632
198497
  const inputBytes = inputSize(args);
197633
198498
  try {
197634
198499
  const ran = await run3(tool, args);
197635
- const linked = ran.ok ? await attachViewUrl(tool.name, args, ran.value, answers2.viewBase) : null;
197636
- const fitted = linked === null ? null : fitAnswer(linked, args, budget2);
198500
+ const linked = !ran.ok ? null : answers2.viewLinks === false ? stripViewLinks(ran.value) : await attachViewUrl(tool.name, args, ran.value, answers2.viewBase);
198501
+ const saving = linked === null || answers2.library === void 0 || answers2.library === null ? linked : withSaveStep(tool.name, linked, answers2.library);
198502
+ const fitted = saving === null ? null : fitAnswer(saving, args, budget2);
197637
198503
  const shown = fitted === null || answers2.open === void 0 ? fitted : await answers2.open(tool.name, fitted);
197638
198504
  const outcome = ran.ok ? { ok: true, value: shown } : ran;
197639
198505
  logToolCall({ tool: tool.name, outcome: outcome.ok ? "ok" : outcome.error.kind, durationMs: performance.now() - started, inputBytes, caller }, log);
@@ -197647,6 +198513,13 @@ async function callTool(tool, args, log, caller, activity, run3, budget2, answer
197647
198513
  return internalErrorResult();
197648
198514
  }
197649
198515
  }
198516
+ function withSaveStep(tool, value, library) {
198517
+ if (!SAVABLE_TOOLS.has(tool) || typeof value !== "object" || value === null) return value;
198518
+ const answer = value;
198519
+ if (answer["valid"] === false) return value;
198520
+ const next = typeof answer["next"] === "string" && answer["next"] !== "" ? `${answer["next"]} ` : "";
198521
+ return { ...answer, next: `${next}${librarySaveStep(library)}` };
198522
+ }
197650
198523
  async function callHostedTool(tool, args, log, caller) {
197651
198524
  const started = performance.now();
197652
198525
  const inputBytes = inputSize(args);
@@ -197681,7 +198554,8 @@ function createDiagramsServer(options3 = {}, log = logToConsole, caller, hostedT
197681
198554
  if (taken.has(tool.name)) throw new TypeError(`A tool named ${tool.name} is already registered`);
197682
198555
  taken.add(tool.name);
197683
198556
  }
197684
- const instructions = hostedTools.length === 0 ? SERVER_INSTRUCTIONS : `${SERVER_INSTRUCTIONS} ${HOSTED_INSTRUCTIONS}`;
198557
+ const hosted = hostedTools.length === 0 ? SERVER_INSTRUCTIONS : `${SERVER_INSTRUCTIONS} ${HOSTED_INSTRUCTIONS}`;
198558
+ const instructions = hostedTools.length > 0 && answers2.library !== void 0 && answers2.library !== null ? `${hosted} ${libraryInstructions(answers2.library)}` : hosted;
197685
198559
  const server = new McpServer(SERVER_INFO, { instructions, ...options3 });
197686
198560
  for (const tool of hostedTools) {
197687
198561
  server.registerTool(
@@ -197716,7 +198590,7 @@ function createDiagramsServer(options3 = {}, log = logToConsole, caller, hostedT
197716
198590
  registerDiagramPrompts(server, options3.jsonSchemaValidator);
197717
198591
  return server;
197718
198592
  }
197719
- var DEFAULT_VALIDATOR2, wrappers2;
198593
+ var SAVABLE_TOOLS, DEFAULT_VALIDATOR2, wrappers2;
197720
198594
  var init_create_server = __esm({
197721
198595
  "src/create-server.ts"() {
197722
198596
  "use strict";
@@ -197730,6 +198604,7 @@ var init_create_server = __esm({
197730
198604
  init_server_info();
197731
198605
  init_tool_result();
197732
198606
  init_viewer_app();
198607
+ SAVABLE_TOOLS = new Set(VIEW_LINK_TOOLS.filter((name2) => name2 !== "sync_markdown"));
197733
198608
  DEFAULT_VALIDATOR2 = {};
197734
198609
  wrappers2 = /* @__PURE__ */ new WeakMap();
197735
198610
  }