@cardenelabs/dragon 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { NODE_KINDS, TONES, layout, diagram, rendersRows, requiredRowsHeight, requiredRowsWidth, sequence, flow, swimlane, er, stateMachine, topology } from '@cardenelabs/cdl';
1
+ import { NODE_KINDS, TONES, layout, applyDerivedValues, diagram, rendersRows, requiredRowsHeight, requiredRowsWidth, sequence, flow, swimlane, er, stateMachine, topology, parseFormula } from '@cardenelabs/cdl';
2
2
 
3
3
  // src/keywords.ts
4
4
  var HEADERS = {
@@ -608,7 +608,7 @@ function countDocElements(doc) {
608
608
  (acc, p) => acc + (p.highlight?.length ?? 0) + (p.tweens?.length ?? 0) + (p.sets?.length ?? 0),
609
609
  0
610
610
  );
611
- return doc.actors.length + doc.flow.length + phases.length + phaseChildren + (doc.animate?.states.length ?? 0) + (doc.groups ? Object.keys(doc.groups).length : 0) + (doc.lanes ? Object.keys(doc.lanes).length : 0);
611
+ return doc.actors.length + doc.flow.length + phases.length + phaseChildren + (doc.animate?.states.length ?? 0) + (doc.values?.length ?? 0) + (doc.groups ? Object.keys(doc.groups).length : 0) + (doc.lanes ? Object.keys(doc.lanes).length : 0);
612
612
  }
613
613
  function countDiagramElements(diagram2) {
614
614
  const phases = Array.isArray(diagram2.phases) ? diagram2.phases : [];
@@ -617,7 +617,8 @@ function countDiagramElements(diagram2) {
617
617
  return acc + (Array.isArray(ph?.activate) ? ph.activate.length : 0) + (Array.isArray(ph?.highlight) ? ph.highlight.length : 0) + (Array.isArray(ph?.tweens) ? ph.tweens.length : 0) + (Array.isArray(ph?.sets) ? ph.sets.length : 0);
618
618
  }, 0);
619
619
  return (diagram2.nodes?.length ?? 0) + (diagram2.edges?.length ?? 0) + (diagram2.lanes?.length ?? 0) + (diagram2.states?.length ?? 0) + phases.length + phaseChildren + // 図が持てる並びは全部数える。 1 つでも外すと、そこに寄せた図が素通りする
620
- (diagram2.readouts?.length ?? 0) + (diagram2.inputs?.length ?? 0) + (diagram2.formulas?.length ?? 0) + (diagram2.scrollTriggers?.length ?? 0) + (diagram2.eventBindings?.length ?? 0);
620
+ (diagram2.readouts?.length ?? 0) + (diagram2.inputs?.length ?? 0) + (diagram2.formulas?.length ?? 0) + (diagram2.scrollTriggers?.length ?? 0) + (diagram2.eventBindings?.length ?? 0) + // 他の値から決まる値 (#1162)。 記法側 (`countDocElements`) が数えるので、こちらも揃える
621
+ (diagram2.derived?.length ?? 0);
621
622
  }
622
623
  function countBytes(src) {
623
624
  return new TextEncoder().encode(src).length;
@@ -723,6 +724,12 @@ function orderByDependency(items) {
723
724
  function compileToCdl(doc, opts) {
724
725
  const oversize = describeOversize({ elements: countDocElements(doc), bytes: 0 });
725
726
  if (oversize) throw new Error(oversize);
727
+ doc = canonicalizeFlowActors(doc);
728
+ const \u66F8\u3044\u305F\u307E\u307E = doc;
729
+ doc = dropUnresolvedFlow(doc);
730
+ doc = dropSelfLoopFlow(doc);
731
+ const \u5206\u3051\u305F = disambiguateActorIds(doc, opts?.onNotice);
732
+ doc = \u5206\u3051\u305F.doc;
726
733
  let diagram2;
727
734
  switch (doc.type) {
728
735
  case "sequence":
@@ -753,27 +760,64 @@ function compileToCdl(doc, opts) {
753
760
  diagram2 = compileClass(doc);
754
761
  break;
755
762
  case "pie":
756
- diagram2 = compilePie(doc);
763
+ diagram2 = compileValueChart(doc, "pie", "chart-pie", opts?.onNotice);
764
+ break;
765
+ case "bar":
766
+ diagram2 = compileValueChart(doc, "bar", "chart-bar", opts?.onNotice);
767
+ break;
768
+ case "line":
769
+ diagram2 = compileValueChart(doc, "line", "chart-line", opts?.onNotice);
770
+ break;
771
+ case "funnel":
772
+ diagram2 = compileFunnel(doc, opts?.onNotice);
773
+ break;
774
+ case "tree":
775
+ diagram2 = compileTree(doc, opts?.onNotice);
776
+ break;
777
+ case "journey":
778
+ diagram2 = compileJourney(doc, opts?.onNotice);
779
+ break;
780
+ case "quadrant":
781
+ diagram2 = compileQuadrant(doc, opts?.onNotice);
757
782
  break;
758
783
  case "c4":
759
784
  diagram2 = compileC4(doc);
760
785
  break;
761
786
  case "mind":
762
- diagram2 = compileMind(doc);
787
+ diagram2 = compileMind(doc, opts?.onNotice);
763
788
  break;
764
789
  default:
765
790
  throw new Error(`unknown type: ${String(doc.type)}`);
766
791
  }
792
+ const \u4F5C\u308A\u66FF\u3048\u305F\u5BFE\u8C61 = collectRenamedTargets(diagram2, \u5206\u3051\u305F.\u5143\u306E\u540D\u524D);
767
793
  const edgeSourceLines = opts?.onEdgeSource ? /* @__PURE__ */ new Map() : void 0;
768
794
  applyEdgeInlineOptions(diagram2, doc, edgeSourceLines);
769
- if (edgeSourceLines) fillFlowEdgeSources(diagram2, doc, edgeSourceLines);
770
795
  applyGroupContainers(diagram2, doc);
771
796
  applyNodeTones(diagram2, doc);
772
- reportMissingFocusTargets(doc, opts?.onNotice);
797
+ reportMissingFocusTargets(\u66F8\u3044\u305F\u307E\u307E, opts?.onNotice);
798
+ reportMissingFlowActors(\u66F8\u3044\u305F\u307E\u307E, opts?.onNotice);
799
+ reportSelfLoopFlow(\u66F8\u3044\u305F\u307E\u307E, opts?.onNotice);
800
+ reportFlowEndpointNotHonored(doc, \u5206\u3051\u305F.\u5143\u306E\u540D\u524D, opts?.onNotice);
801
+ reportLaneNotHonored(\u66F8\u3044\u305F\u307E\u307E, opts?.onNotice);
802
+ reportDocEyebrowNotHonored(\u66F8\u3044\u305F\u307E\u307E, opts?.onNotice);
803
+ reportChartFieldsNotHonored(\u66F8\u3044\u305F\u307E\u307E, opts?.onNotice);
804
+ reportAxesNotHonored(\u66F8\u3044\u305F\u307E\u307E, opts?.onNotice);
773
805
  const placed = resolveRelativeDoc(diagram2, doc, opts?.onNotice, opts?.partsCatalog);
774
806
  applyCanvasPivotPositions(diagram2, placed);
775
- const extended = applyV05Extensions(diagram2, placed);
776
- const merged = mergePartsFromActors(extended, placed, opts?.partsCatalog, opts?.onNotice);
807
+ const \u8FFD\u52A0\u3057\u305F\u7E26\u5217 = [];
808
+ const extended = applyV05Extensions(diagram2, placed, \u8FFD\u52A0\u3057\u305F\u7E26\u5217);
809
+ const inheritedDerivedSourceLines = opts?.onNotice ? /* @__PURE__ */ new Map() : void 0;
810
+ for (const value of extended.derived ?? []) {
811
+ recordDerivedSourceLine(inheritedDerivedSourceLines, value.id, 0);
812
+ }
813
+ const merged = mergePartsFromActors(
814
+ extended,
815
+ placed,
816
+ opts?.partsCatalog,
817
+ opts?.onNotice,
818
+ inheritedDerivedSourceLines
819
+ );
820
+ reportEmptyDeclaredLanes(merged, \u8FFD\u52A0\u3057\u305F\u7E26\u5217, opts?.onNotice);
777
821
  if (edgeSourceLines && opts?.onEdgeSource) {
778
822
  const alive = new Set(merged.edges.map((e) => e.id));
779
823
  for (const [id, line] of edgeSourceLines) {
@@ -781,6 +825,10 @@ function compileToCdl(doc, opts) {
781
825
  }
782
826
  }
783
827
  injectStaticPhase(merged);
828
+ materializeStates(merged, doc);
829
+ \u8A9E\u306E\u72B6\u614B\u3092\u56F3\u306E\u8A9E\u3078\u76F4\u3059(merged);
830
+ const \u7573\u3093\u3060\u304D\u3063\u304B\u3051 = foldValueTriggers(merged, doc, opts?.onNotice);
831
+ attachDerivedValues(merged, doc, opts?.onNotice, inheritedDerivedSourceLines, \u7573\u3093\u3060\u304D\u3063\u304B\u3051);
784
832
  for (const dropped of stripExternalPaint(merged)) {
785
833
  opts?.onNotice?.({
786
834
  kind: "external-paint-dropped",
@@ -790,8 +838,17 @@ function compileToCdl(doc, opts) {
790
838
  hint: "\u8272\u306F `#ff0000` \u306E\u3088\u3046\u306A\u8272\u756A\u53F7\u304B\u3001 `red` \u306E\u3088\u3046\u306A\u8272\u540D\u3067\u66F8\u304F"
791
839
  });
792
840
  }
841
+ restoreActorNames(merged, \u5206\u3051\u305F.\u5143\u306E\u540D\u524D, \u4F5C\u308A\u66FF\u3048\u305F\u5BFE\u8C61);
793
842
  return merged;
794
843
  }
844
+ function materializeStates(diagram2, doc) {
845
+ const \u8F09\u3063\u3066\u3044\u308B = new Set(diagram2.states.map((s) => s.id));
846
+ for (const st of doc.animate?.states ?? []) {
847
+ if (\u8F09\u3063\u3066\u3044\u308B.has(st.name)) continue;
848
+ diagram2.states.push({ id: st.name, initial: st.initial });
849
+ \u8F09\u3063\u3066\u3044\u308B.add(st.name);
850
+ }
851
+ }
795
852
  function injectStaticPhase(diagram2) {
796
853
  if (diagram2.phases.length > 0) return;
797
854
  const activate = [...diagram2.nodes.map((n) => n.id), ...diagram2.edges.map((e) => e.id)];
@@ -809,6 +866,314 @@ function truncateForMessage(v) {
809
866
  const s = v.trim();
810
867
  return s.length <= 40 ? s : `${s.slice(0, 37)}...`;
811
868
  }
869
+ function actorRefTable(doc) {
870
+ const \u8868 = /* @__PURE__ */ new Map();
871
+ const slug\u6570 = /* @__PURE__ */ new Map();
872
+ for (const a of doc.actors) {
873
+ const sl = slugify(a.name);
874
+ slug\u6570.set(sl, (slug\u6570.get(sl) ?? 0) + 1);
875
+ }
876
+ for (const a of doc.actors) {
877
+ \u8868.set(a.name, a.name);
878
+ const sl = slugify(a.name);
879
+ if ((slug\u6570.get(sl) ?? 0) === 1) \u8868.set(sl, a.name);
880
+ }
881
+ return \u8868;
882
+ }
883
+ function canonicalizeFlowActors(doc) {
884
+ const \u8868 = actorRefTable(doc);
885
+ let \u5909\u3048\u305F = false;
886
+ const flow2 = doc.flow.map((s) => {
887
+ const from = \u8868.get(s.from) ?? s.from;
888
+ const to = \u8868.get(s.to) ?? s.to;
889
+ if (from === s.from && to === s.to) return s;
890
+ \u5909\u3048\u305F = true;
891
+ return { ...s, from, to };
892
+ });
893
+ return \u5909\u3048\u305F ? { ...doc, flow: flow2 } : doc;
894
+ }
895
+ var \u56F3\u7A2E\u306E\u4F5C\u308A = {
896
+ // 矢印の端と登場人物の名前が、 そのまま箱や枠の id になる
897
+ sequence: "\u767B\u5834\u4EBA\u7269\u3054\u3068\u306B\u7BB1",
898
+ flow: "\u767B\u5834\u4EBA\u7269\u3054\u3068\u306B\u7BB1",
899
+ swimlane: "\u767B\u5834\u4EBA\u7269\u3054\u3068\u306B\u7BB1",
900
+ er: "\u767B\u5834\u4EBA\u7269\u3054\u3068\u306B\u7BB1",
901
+ state: "\u767B\u5834\u4EBA\u7269\u3054\u3068\u306B\u7BB1",
902
+ topology: "\u767B\u5834\u4EBA\u7269\u3054\u3068\u306B\u7BB1",
903
+ solidity: "\u767B\u5834\u4EBA\u7269\u3054\u3068\u306B\u7BB1",
904
+ class: "\u767B\u5834\u4EBA\u7269\u3054\u3068\u306B\u7BB1",
905
+ c4: "\u767B\u5834\u4EBA\u7269\u3054\u3068\u306B\u7BB1",
906
+ // 中身は payload が持ち、 図そのものは 1 箱。 矢印は描かず本数を数えて知らせる
907
+ gantt: "\u56F3\u5168\u4F53\u3092 1 \u7BB1",
908
+ pie: "\u56F3\u5168\u4F53\u3092 1 \u7BB1",
909
+ bar: "\u56F3\u5168\u4F53\u3092 1 \u7BB1",
910
+ line: "\u56F3\u5168\u4F53\u3092 1 \u7BB1",
911
+ funnel: "\u56F3\u5168\u4F53\u3092 1 \u7BB1",
912
+ tree: "\u56F3\u5168\u4F53\u3092 1 \u7BB1",
913
+ journey: "\u56F3\u5168\u4F53\u3092 1 \u7BB1",
914
+ quadrant: "\u56F3\u5168\u4F53\u3092 1 \u7BB1",
915
+ mind: "\u56F3\u5168\u4F53\u3092 1 \u7BB1"
916
+ };
917
+ function dropUnresolvedFlow(doc) {
918
+ if (\u56F3\u7A2E\u306E\u4F5C\u308A[doc.type] === "\u56F3\u5168\u4F53\u3092 1 \u7BB1") return doc;
919
+ const \u8868 = actorRefTable(doc);
920
+ const flow2 = doc.flow.filter((s) => \u8868.has(s.from) && \u8868.has(s.to));
921
+ return flow2.length === doc.flow.length ? doc : { ...doc, flow: flow2 };
922
+ }
923
+ function dropSelfLoopFlow(doc) {
924
+ if (\u56F3\u7A2E\u306E\u4F5C\u308A[doc.type] === "\u56F3\u5168\u4F53\u3092 1 \u7BB1") return doc;
925
+ const flow2 = doc.flow.filter((s) => s.from !== s.to);
926
+ return flow2.length === doc.flow.length ? doc : { ...doc, flow: flow2 };
927
+ }
928
+ function reportSelfLoopFlow(doc, onNotice) {
929
+ if (!onNotice) return;
930
+ if (\u56F3\u7A2E\u306E\u4F5C\u308A[doc.type] === "\u56F3\u5168\u4F53\u3092 1 \u7BB1") return;
931
+ const \u77E5\u3089\u305B\u305F = /* @__PURE__ */ new Set();
932
+ for (const s of doc.flow) {
933
+ if (s.from !== s.to || \u77E5\u3089\u305B\u305F.has(s.from)) continue;
934
+ \u77E5\u3089\u305B\u305F.add(s.from);
935
+ onNotice({
936
+ kind: "flow-self-loop",
937
+ actor: s.from,
938
+ line: s.pos.line,
939
+ message: `"${truncateForMessage(s.from)}" \u304B\u3089\u81EA\u5206\u3078\u623B\u308B\u77E2\u5370\u306F\u63CF\u3051\u307E\u305B\u3093 (\u7D44\u307F\u7ACB\u3066\u304B\u3089\u5916\u3057\u307E\u3057\u305F)`,
940
+ hint: "\u9014\u4E2D\u306E\u7BB1\u3092 1 \u3064\u8DB3\u3057\u3066 2 \u672C\u306B\u5206\u3051\u308B\u304B\u3001 \u6BB5 (animation) \u3067\u72B6\u614B\u304C\u5909\u308F\u308B\u69D8\u5B50\u3068\u3057\u3066\u898B\u305B\u308B"
941
+ });
942
+ }
943
+ }
944
+ function \u56F3\u306E\u5C0F\u898B\u51FA\u3057(doc) {
945
+ return doc.eyebrow === void 0 ? {} : { eyebrow: doc.eyebrow };
946
+ }
947
+ function reportDocEyebrowNotHonored(doc, onNotice) {
948
+ if (!onNotice) return;
949
+ if (doc.eyebrow === void 0) return;
950
+ if (\u56F3\u7A2E\u306E\u4F5C\u308A[doc.type] === "\u56F3\u5168\u4F53\u3092 1 \u7BB1") return;
951
+ onNotice({
952
+ kind: "eyebrow-not-honored",
953
+ actor: doc.title,
954
+ // 図の `pos` は常に 1 行目を指す。 書いた行に辿り着けるよう `eyebrowPos` を優先する
955
+ line: doc.eyebrowPos?.line ?? doc.pos?.line ?? 0,
956
+ message: `\u6700\u4E0A\u4F4D\u306B\u66F8\u3044\u305F eyebrow \u306F\u52B9\u304D\u307E\u305B\u3093 (type: ${doc.type} \u306F\u7BB1\u3054\u3068\u306B\u5206\u304B\u308C\u308B\u305F\u3081\u76F8\u624B\u304C\u6C7A\u307E\u308A\u307E\u305B\u3093)`,
957
+ hint: '\u7BB1\u3054\u3068\u306B\u66F8\u3044\u3066\u304F\u3060\u3055\u3044 (`- A: { eyebrow: "..." }`)'
958
+ });
959
+ }
960
+ function reportLaneMixed(doc, onNotice) {
961
+ const \u5BFE\u8C61 = doc.actors.filter((a) => a.partId === void 0);
962
+ const \u66F8\u3044\u305F = \u5BFE\u8C61.filter((a) => a.lane !== void 0);
963
+ if (\u66F8\u3044\u305F.length === 0 || \u66F8\u3044\u305F.length === \u5BFE\u8C61.length) return;
964
+ const \u66F8\u3044\u3066\u3044\u306A\u3044 = \u5BFE\u8C61.filter((a) => a.lane === void 0);
965
+ onNotice({
966
+ kind: "lane-not-honored",
967
+ actor: \u66F8\u3044\u3066\u3044\u306A\u3044[0]?.name ?? "",
968
+ line: \u66F8\u3044\u3066\u3044\u306A\u3044[0]?.pos?.line ?? 0,
969
+ message: `type: ${doc.type} \u3067\u306F\u7E26\u5217\u3092\u66F8\u304F\u306A\u3089\u5168\u3066\u306E\u7BB1\u306B\u66F8\u304D\u307E\u3059 (\u66F8\u3044\u3066\u3044\u306A\u3044\u7BB1: ${\u66F8\u3044\u3066\u3044\u306A\u3044.map((a) => truncateForMessage(a.name)).join(" / ")})`,
970
+ hint: "\u66F8\u304B\u306A\u304B\u3063\u305F\u7BB1\u3092\u3069\u306E\u7E26\u5217\u306B\u7F6E\u304F\u304B\u3092\u6C7A\u3081\u3089\u308C\u306A\u3044\u305F\u3081\u3001\u5168\u90E8\u66F8\u304F\u304B 1 \u3064\u3082\u66F8\u304B\u306A\u3044\u304B\u306B\u3057\u3066\u304F\u3060\u3055\u3044"
971
+ });
972
+ }
973
+ function reportFlowEndpointNotHonored(doc, \u5143\u306E\u540D\u524D, onNotice) {
974
+ if (!onNotice) return;
975
+ if (!\u9396\u3067\u3064\u306A\u3050\u5F62\u304B(doc)) return;
976
+ const \u66F8\u3044\u305F\u540D\u524D = (name) => \u5143\u306E\u540D\u524D.get(name) ?? name;
977
+ const \u9396\u306E\u7D44 = /* @__PURE__ */ new Set();
978
+ doc.actors.forEach((a, i) => {
979
+ const \u6B21 = doc.actors[i + 1];
980
+ if (\u6B21 === void 0) return;
981
+ \u9396\u306E\u7D44.add(`${a.name}\0${\u6B21.name}`);
982
+ });
983
+ for (const s of doc.flow) {
984
+ if (\u9396\u306E\u7D44.has(`${s.from}\0${s.to}`)) continue;
985
+ onNotice({
986
+ kind: "flow-endpoint-not-honored",
987
+ actor: \u66F8\u3044\u305F\u540D\u524D(s.from),
988
+ line: s.pos.line,
989
+ message: `"${truncateForMessage(\u66F8\u3044\u305F\u540D\u524D(s.from))} -> ${truncateForMessage(\u66F8\u3044\u305F\u540D\u524D(s.to))}" \u306E\u7AEF\u306F\u4F7F\u308F\u308C\u307E\u305B\u3093 (type: flow \u306F\u767B\u5834\u4EBA\u7269\u3092\u66F8\u3044\u305F\u9806\u306B\u7E4B\u304E\u307E\u3059)`,
990
+ hint: "\u66F8\u3044\u305F\u7AEF\u3069\u304A\u308A\u306B\u7E4B\u3050\u306B\u306F\u3001\u7BB1\u306B lane: \u3092\u66F8\u3044\u3066\u304F\u3060\u3055\u3044 (\u7E26\u5217\u3092\u66F8\u3044\u305F\u5F62\u306F\u66F8\u3044\u305F\u7AEF\u304C\u305D\u306E\u307E\u307E\u77E2\u5370\u306B\u306A\u308A\u307E\u3059)"
991
+ });
992
+ }
993
+ }
994
+ function reportLaneNotHonored(doc, onNotice) {
995
+ if (!onNotice) return;
996
+ if (doc.type === "mind") return;
997
+ const \u52B9\u304F\u56F3\u7A2E = \u7E26\u5217\u3092\u9078\u3079\u308B\u56F3\u7A2E.has(doc.type);
998
+ if (\u52B9\u304F\u56F3\u7A2E && \u66F8\u3044\u305F\u7E26\u5217\u306B\u7F6E\u304F(doc.type, doc)) return;
999
+ if (\u52B9\u304F\u56F3\u7A2E) {
1000
+ reportLaneMixed(doc, onNotice);
1001
+ return;
1002
+ }
1003
+ for (const a of doc.actors) {
1004
+ if (a.partId !== void 0) continue;
1005
+ if (a.lane === void 0) continue;
1006
+ onNotice({
1007
+ kind: "lane-not-honored",
1008
+ actor: a.name,
1009
+ line: a.pos?.line ?? 0,
1010
+ message: `"${truncateForMessage(a.name)}" \u306B\u66F8\u3044\u305F lane \u306F\u52B9\u304D\u307E\u305B\u3093 (\u7E26\u5217\u306F type: ${doc.type} \u304C\u6C7A\u3081\u307E\u3059)`,
1011
+ hint: "\u7E26\u5217\u306F\u56F3\u7A2E\u304C\u6C7A\u3081\u308B\u305F\u3081\u7BB1\u304B\u3089\u306F\u9078\u3079\u307E\u305B\u3093\u3002 lane \u3092\u6D88\u3057\u3066\u304F\u3060\u3055\u3044 (\u898B\u672C\u3067\u306F\u5F35\u66FF\u3048\u5148\u3068\u3057\u3066\u4F7F\u3048\u307E\u3059)"
1012
+ });
1013
+ }
1014
+ }
1015
+ function \u540D\u524D\u306E\u5C3E(name) {
1016
+ let h = 2166136261;
1017
+ for (const c of name) {
1018
+ h ^= c.codePointAt(0) ?? 0;
1019
+ h = Math.imul(h, 16777619) >>> 0;
1020
+ }
1021
+ return h.toString(16).padStart(8, "0").slice(0, 6);
1022
+ }
1023
+ function cdl\u5074\u306Eslug(s) {
1024
+ return s.toLowerCase().replace(/[^a-z0-9぀-ゟ゠-ヿ一-龯]+/g, "-").replace(/^-|-$/g, "");
1025
+ }
1026
+ var \u7A7A\u306E\u5F62\u306E\u9003\u3052\u5148 = {
1027
+ sequence: ["actor-"],
1028
+ solidity: ["actor-"],
1029
+ swimlane: ["lane-"],
1030
+ flow: [],
1031
+ er: [],
1032
+ state: [],
1033
+ topology: [],
1034
+ class: [],
1035
+ c4: [],
1036
+ // 図全体を 1 箱で描く群 (作り替えないのでここは使わない)
1037
+ gantt: [],
1038
+ pie: [],
1039
+ bar: [],
1040
+ line: [],
1041
+ funnel: [],
1042
+ tree: [],
1043
+ journey: [],
1044
+ quadrant: [],
1045
+ mind: []
1046
+ };
1047
+ function id\u306B\u306A\u308B\u5F62(name, \u4F4D\u7F6E, \u9003\u3052\u5148\u306E\u982D = []) {
1048
+ const cdl = cdl\u5074\u306Eslug(name);
1049
+ const out = [slugify(name), cdl];
1050
+ if (cdl === "" && \u4F4D\u7F6E !== void 0) {
1051
+ for (const \u982D of \u9003\u3052\u5148\u306E\u982D) out.push(`${\u982D}${\u4F4D\u7F6E}`);
1052
+ }
1053
+ return out;
1054
+ }
1055
+ function disambiguateActorIds(doc, onNotice) {
1056
+ const \u5143\u306E\u540D\u524D = /* @__PURE__ */ new Map();
1057
+ if (\u56F3\u7A2E\u306E\u4F5C\u308A[doc.type] !== "\u767B\u5834\u4EBA\u7269\u3054\u3068\u306B\u7BB1") return { doc, \u5143\u306E\u540D\u524D };
1058
+ const \u898B\u305F = /* @__PURE__ */ new Set();
1059
+ const \u6B8B\u3059 = [];
1060
+ for (const a of doc.actors) {
1061
+ if (\u898B\u305F.has(a.name)) {
1062
+ onNotice?.({
1063
+ kind: "chart-value-unreadable",
1064
+ actor: a.name,
1065
+ line: a.pos?.line ?? 0,
1066
+ message: `"${truncateForMessage(a.name)}" \u3092 2 \u5EA6\u66F8\u3044\u3066\u3044\u307E\u3059 (\u5148\u306B\u66F8\u3044\u305F\u65B9\u3060\u3051\u63CF\u304D\u307E\u3059)`,
1067
+ hint: "\u9055\u3046\u540D\u524D\u306B\u3059\u308B\u304B\u3001 1 \u3064\u306B\u307E\u3068\u3081\u308B"
1068
+ });
1069
+ continue;
1070
+ }
1071
+ \u898B\u305F.add(a.name);
1072
+ \u6B8B\u3059.push(a);
1073
+ }
1074
+ const \u5F62\u3054\u3068\u306E\u540D\u524D = /* @__PURE__ */ new Map();
1075
+ const \u4F4D\u7F6E = /* @__PURE__ */ new Map();
1076
+ \u6B8B\u3059.forEach((a, i) => \u4F4D\u7F6E.set(a.name, i));
1077
+ const \u52D5\u304D\u3092\u66F8\u3044\u305F = (doc.animate?.phases.length ?? 0) > 0;
1078
+ const \u9003\u3052\u5148\u306E\u982D = \u52D5\u304D\u3092\u66F8\u3044\u305F ? [] : \u7A7A\u306E\u5F62\u306E\u9003\u3052\u5148[doc.type];
1079
+ for (const a of \u6B8B\u3059) {
1080
+ for (const \u5F62 of id\u306B\u306A\u308B\u5F62(a.name, \u4F4D\u7F6E.get(a.name), \u9003\u3052\u5148\u306E\u982D)) {
1081
+ const \u7FA4 = \u5F62\u3054\u3068\u306E\u540D\u524D.get(\u5F62) ?? /* @__PURE__ */ new Set();
1082
+ \u7FA4.add(a.name);
1083
+ \u5F62\u3054\u3068\u306E\u540D\u524D.set(\u5F62, \u7FA4);
1084
+ }
1085
+ }
1086
+ const \u91CD\u306A\u308B = (name) => id\u306B\u306A\u308B\u5F62(name, \u4F4D\u7F6E.get(name), \u9003\u3052\u5148\u306E\u982D).some(
1087
+ (\u5F62) => (\u5F62\u3054\u3068\u306E\u540D\u524D.get(\u5F62)?.size ?? 0) > 1
1088
+ );
1089
+ const \u4F5C\u308A\u66FF\u3048\u308B = \u6B8B\u3059.filter((a) => a.partId === void 0 && \u91CD\u306A\u308B(a.name));
1090
+ const \u4F7F\u3046\u5F62 = /* @__PURE__ */ new Set();
1091
+ for (const a of \u6B8B\u3059) {
1092
+ if (\u4F5C\u308A\u66FF\u3048\u308B.some((b) => b.name === a.name)) continue;
1093
+ for (const \u5F62 of id\u306B\u306A\u308B\u5F62(a.name)) \u4F7F\u3046\u5F62.add(\u5F62);
1094
+ }
1095
+ const \u65B0\u3057\u3044\u540D\u524D = /* @__PURE__ */ new Map();
1096
+ for (const a of [...\u4F5C\u308A\u66FF\u3048\u308B].sort((x, y) => x.name < y.name ? -1 : x.name > y.name ? 1 : 0)) {
1097
+ const \u5C3E = \u540D\u524D\u306E\u5C3E(a.name);
1098
+ const \u4F59\u5730 = ID_MAX - (\u5C3E.length + 1);
1099
+ const \u57FA\u5E95 = a.name.slice(0, \u4F59\u5730);
1100
+ let \u5019\u88DC = `${\u57FA\u5E95} ${\u5C3E}`;
1101
+ let n = 0;
1102
+ while (id\u306B\u306A\u308B\u5F62(\u5019\u88DC).some((\u5F62) => \u4F7F\u3046\u5F62.has(\u5F62))) {
1103
+ n += 1;
1104
+ \u5019\u88DC = `${\u57FA\u5E95.slice(0, \u4F59\u5730 - String(n).length)} ${\u5C3E}${n}`;
1105
+ }
1106
+ for (const \u5F62 of id\u306B\u306A\u308B\u5F62(\u5019\u88DC)) \u4F7F\u3046\u5F62.add(\u5F62);
1107
+ \u65B0\u3057\u3044\u540D\u524D.set(a.name, \u5019\u88DC);
1108
+ \u5143\u306E\u540D\u524D.set(\u5019\u88DC, a.name);
1109
+ }
1110
+ if (\u65B0\u3057\u3044\u540D\u524D.size === 0 && \u6B8B\u3059.length === doc.actors.length) return { doc, \u5143\u306E\u540D\u524D };
1111
+ const \u76F4\u3059 = (\u540D) => \u65B0\u3057\u3044\u540D\u524D.get(\u540D) ?? \u540D;
1112
+ const \u6B21 = {
1113
+ ...doc,
1114
+ actors: \u6B8B\u3059.map((a) => \u65B0\u3057\u3044\u540D\u524D.has(a.name) ? { ...a, name: \u76F4\u3059(a.name) } : a),
1115
+ flow: doc.flow.map((s) => {
1116
+ const from = \u76F4\u3059(s.from);
1117
+ const to = \u76F4\u3059(s.to);
1118
+ return from === s.from && to === s.to ? s : { ...s, from, to };
1119
+ })
1120
+ };
1121
+ if (\u6B21.animate) {
1122
+ \u6B21.animate = {
1123
+ ...\u6B21.animate,
1124
+ phases: \u6B21.animate.phases.map(
1125
+ (ph) => ph.highlight ? { ...ph, highlight: ph.highlight.map((h) => \u76F4\u3059(h)) } : ph
1126
+ )
1127
+ };
1128
+ }
1129
+ \u6B21.actors = \u6B21.actors.map(
1130
+ (a) => a.posRel ? { ...a, posRel: { ...a.posRel, anchor: \u76F4\u3059(a.posRel.anchor) } } : a
1131
+ );
1132
+ return { doc: \u6B21, \u5143\u306E\u540D\u524D };
1133
+ }
1134
+ function collectRenamedTargets(diagram2, \u5143\u306E\u540D\u524D) {
1135
+ const \u7BB1 = /* @__PURE__ */ new Set();
1136
+ const \u67A0 = /* @__PURE__ */ new Set();
1137
+ if (\u5143\u306E\u540D\u524D.size === 0) return { \u7BB1, \u67A0 };
1138
+ for (const n of diagram2.nodes) if (\u5143\u306E\u540D\u524D.has(n.title)) \u7BB1.add(n.id);
1139
+ for (const l of diagram2.lanes) if (l.label !== void 0 && \u5143\u306E\u540D\u524D.has(l.label)) \u67A0.add(l.id);
1140
+ return { \u7BB1, \u67A0 };
1141
+ }
1142
+ function restoreActorNames(diagram2, \u5143\u306E\u540D\u524D, \u5BFE\u8C61) {
1143
+ if (\u5143\u306E\u540D\u524D.size === 0) return;
1144
+ for (const n of diagram2.nodes) {
1145
+ if (!\u5BFE\u8C61.\u7BB1.has(n.id)) continue;
1146
+ const \u5143 = \u5143\u306E\u540D\u524D.get(n.title);
1147
+ if (\u5143 !== void 0) n.title = \u5143;
1148
+ }
1149
+ for (const l of diagram2.lanes) {
1150
+ if (!\u5BFE\u8C61.\u67A0.has(l.id) || l.label === void 0) continue;
1151
+ const \u5143 = \u5143\u306E\u540D\u524D.get(l.label);
1152
+ if (\u5143 !== void 0) l.label = \u5143;
1153
+ }
1154
+ }
1155
+ function reportMissingFlowActors(doc, onNotice) {
1156
+ if (!onNotice) return;
1157
+ const \u8868 = actorRefTable(doc);
1158
+ const \u898B\u305B\u308B\u6570 = 8;
1159
+ const \u540D\u524D\u4E00\u89A7 = doc.actors.slice(0, \u898B\u305B\u308B\u6570).map((a) => truncateForMessage(a.name)).join(" / ");
1160
+ const \u6B8B\u308A = doc.actors.length - \u898B\u305B\u308B\u6570;
1161
+ const hint = doc.actors.length > 0 ? `actors \u306B\u66F8\u3044\u305F\u540D\u524D\u3067\u6307\u3059 (${\u540D\u524D\u4E00\u89A7}${\u6B8B\u308A > 0 ? ` \u307B\u304B ${\u6B8B\u308A} \u4EF6` : ""})` : "actors \u306B\u767B\u5834\u4EBA\u7269\u3092\u66F8\u304F";
1162
+ const \u77E5\u3089\u305B\u305F = /* @__PURE__ */ new Set();
1163
+ for (const s of doc.flow) {
1164
+ for (const ref of [s.from, s.to]) {
1165
+ if (\u8868.has(ref) || \u77E5\u3089\u305B\u305F.has(ref)) continue;
1166
+ \u77E5\u3089\u305B\u305F.add(ref);
1167
+ onNotice({
1168
+ kind: "flow-actor-missing",
1169
+ actor: ref,
1170
+ line: s.pos.line,
1171
+ message: `\u77E2\u5370\u304C "${truncateForMessage(ref)}" \u3092\u6307\u3057\u3066\u3044\u307E\u3059\u304C\u3001 actors \u306B\u66F8\u304B\u308C\u3066\u3044\u307E\u305B\u3093`,
1172
+ hint
1173
+ });
1174
+ }
1175
+ }
1176
+ }
812
1177
  function reportMissingFocusTargets(doc, onNotice) {
813
1178
  if (!onNotice || !doc.animate) return;
814
1179
  const names = new Set(doc.actors.map((a) => a.name));
@@ -825,10 +1190,12 @@ function reportMissingFocusTargets(doc, onNotice) {
825
1190
  tos.add(st.to);
826
1191
  steps.set(st.from, tos);
827
1192
  }
1193
+ const \u540D\u524D\u3078 = actorRefTable(doc);
1194
+ const \u63C3\u3048\u308B = (ref) => \u540D\u524D\u3078.get(ref) ?? ref;
828
1195
  for (const phase of doc.animate.phases) {
829
1196
  for (const raw of phase.highlight ?? []) {
830
1197
  const entry = parseFocusEntry(raw, names);
831
- const found = entry.kind === "edge" ? steps.get(entry.from)?.has(entry.to) ?? false : accepted.has(entry.name);
1198
+ const found = entry.kind === "edge" ? steps.get(\u63C3\u3048\u308B(entry.from))?.has(\u63C3\u3048\u308B(entry.to)) ?? false : accepted.has(entry.name);
832
1199
  if (found) continue;
833
1200
  onNotice({
834
1201
  kind: "focus-target-missing",
@@ -1416,9 +1783,10 @@ function cleanupPlaceholderActor(target, doc, a) {
1416
1783
  phase.activate = phase.activate.filter((id) => !relatedToActor(id) && !removedEdgeIds.has(id));
1417
1784
  }
1418
1785
  }
1419
- function mergePartsFromActors(target, doc, partsCatalog, onNotice) {
1786
+ function mergePartsFromActors(target, doc, partsCatalog, onNotice, derivedSourceLines) {
1420
1787
  const partsActors = doc.actors.filter((a) => a.partId !== void 0);
1421
1788
  if (partsActors.length === 0) return target;
1789
+ const \u5024\u306E\u524D\u7F6E\u304D = \u5024\u306E\u524D\u7F6E\u304D\u3092\u4F5C\u308B(partsActors.map((a) => a.name));
1422
1790
  if (!partsCatalog) {
1423
1791
  if (typeof console !== "undefined" && console.warn) {
1424
1792
  const names = partsActors.map((a) => `${a.name} (kind: ${a.partId ?? "?"})`).join(", ");
@@ -1474,7 +1842,21 @@ function mergePartsFromActors(target, doc, partsCatalog, onNotice) {
1474
1842
  }
1475
1843
  }
1476
1844
  const t = partTargetSize(part, actor.posW, actor.posH, actor.scale);
1477
- mergePartIntoDiagram(target, part, actor.name, merged, actor.lane, placeX, placeY, t.w, t.h, onNotice, actor.pos?.line ?? 0);
1845
+ mergePartIntoDiagram(
1846
+ target,
1847
+ part,
1848
+ actor.name,
1849
+ merged,
1850
+ actor.lane,
1851
+ placeX,
1852
+ placeY,
1853
+ t.w,
1854
+ t.h,
1855
+ onNotice,
1856
+ actor.pos?.line ?? 0,
1857
+ derivedSourceLines,
1858
+ \u5024\u306E\u524D\u7F6E\u304D.get(actor.name)
1859
+ );
1478
1860
  }
1479
1861
  return target;
1480
1862
  }
@@ -1493,15 +1875,47 @@ function applyColorHex(part, colorHex, stateOverride) {
1493
1875
  }
1494
1876
  return out;
1495
1877
  }
1496
- function mergePartIntoDiagram(target, part, alias, stateOverride, laneMapping, offsetX, offsetY, targetW, targetH, onNotice, noticeLine = 0) {
1878
+ function \u5024\u306E\u524D\u7F6E\u304D\u3092\u4F5C\u308B(\u540D\u524D\u305F\u3061) {
1879
+ const \u51FA\u529B = /* @__PURE__ */ new Map();
1880
+ const \u4F7F\u7528\u4E2D = /* @__PURE__ */ new Set();
1881
+ const \u6B21\u306E\u756A\u53F7 = /* @__PURE__ */ new Map();
1882
+ for (const \u540D\u524D of \u540D\u524D\u305F\u3061) {
1883
+ if (\u51FA\u529B.has(\u540D\u524D)) continue;
1884
+ let \u7D20 = \u540D\u524D.normalize("NFKC").replace(/[^A-Za-z0-9_]+/g, "_").replace(/^_+|_+$/g, "");
1885
+ if (\u7D20 === "" || /^[0-9]/.test(\u7D20)) \u7D20 = `p${\u7D20}`;
1886
+ let \u5019\u88DC = \u7D20;
1887
+ let \u756A\u53F7 = \u6B21\u306E\u756A\u53F7.get(\u7D20) ?? 2;
1888
+ while (\u4F7F\u7528\u4E2D.has(\u5019\u88DC)) {
1889
+ \u5019\u88DC = `${\u7D20}_${\u756A\u53F7}`;
1890
+ \u756A\u53F7 += 1;
1891
+ }
1892
+ \u6B21\u306E\u756A\u53F7.set(\u7D20, \u756A\u53F7);
1893
+ \u4F7F\u7528\u4E2D.add(\u5019\u88DC);
1894
+ \u51FA\u529B.set(\u540D\u524D, \u5019\u88DC);
1895
+ }
1896
+ return \u51FA\u529B;
1897
+ }
1898
+ function mergePartIntoDiagram(target, part, alias, stateOverride, laneMapping, offsetX, offsetY, targetW, targetH, onNotice, noticeLine = 0, derivedSourceLines, valueAlias) {
1497
1899
  const prefix = (id) => `${alias}__${id}`;
1498
- const stateIdSet = new Set(part.states.map((s) => s.id));
1900
+ const \u5024\u524D\u7F6E\u304D = valueAlias ?? alias;
1901
+ const valuePrefix = (id) => `${\u5024\u524D\u7F6E\u304D}__${id}`;
1902
+ const ownIdSet = /* @__PURE__ */ new Set([
1903
+ ...part.states.map((s) => s.id),
1904
+ ...(part.derived ?? []).map((d) => d.id)
1905
+ ]);
1499
1906
  const rewriteTemplate = (s) => {
1500
1907
  if (!s) return s;
1501
- return s.replace(/\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g, (m, name) => {
1502
- return stateIdSet.has(name) ? `{${prefix(name)}}` : m;
1908
+ return s.replace(/\{(\w+)\}/g, (m, name) => {
1909
+ return ownIdSet.has(name) ? `{${valuePrefix(name)}}` : m;
1503
1910
  });
1504
1911
  };
1912
+ const rewriteDerivedExpression = (expression) => {
1913
+ try {
1914
+ return writeFormula(renameFormulaIdentifiers(parseFormula(expression), valuePrefix));
1915
+ } catch {
1916
+ return expression;
1917
+ }
1918
+ };
1505
1919
  const targetLaneId = laneMapping;
1506
1920
  const laneIdMap = /* @__PURE__ */ new Map();
1507
1921
  const PARTS_LANE_GAP = 300;
@@ -1619,7 +2033,16 @@ function mergePartIntoDiagram(target, part, alias, stateOverride, laneMapping, o
1619
2033
  hint: "\u8272\u306F `#ff0000` \u306E\u3088\u3046\u306A\u8272\u756A\u53F7\u304B\u3001 `red` \u306E\u3088\u3046\u306A\u8272\u540D\u3067\u66F8\u304F"
1620
2034
  });
1621
2035
  }
1622
- target.states.push({ id: prefix(stateOrig.id), initial });
2036
+ target.states.push({ id: valuePrefix(stateOrig.id), initial });
2037
+ }
2038
+ for (const derivedOrig of part.derived ?? []) {
2039
+ if (!target.derived) target.derived = [];
2040
+ const id = valuePrefix(derivedOrig.id);
2041
+ target.derived.push({
2042
+ id,
2043
+ expression: rewriteDerivedExpression(derivedOrig.expression)
2044
+ });
2045
+ recordDerivedSourceLine(derivedSourceLines, id, noticeLine);
1623
2046
  }
1624
2047
  for (const edgeOrig of part.edges) {
1625
2048
  target.edges.push({
@@ -1649,8 +2072,8 @@ function mergePartIntoDiagram(target, part, alias, stateOverride, laneMapping, o
1649
2072
  ...phaseOrig,
1650
2073
  id: prefix(phaseOrig.id),
1651
2074
  activate: phaseOrig.activate.map(prefix),
1652
- tweens: phaseOrig.tweens.map((t) => ({ ...t, stateId: prefix(t.stateId) })),
1653
- sets: phaseOrig.sets.map((s) => ({ ...s, stateId: prefix(s.stateId) }))
2075
+ tweens: phaseOrig.tweens.map((t) => ({ ...t, stateId: valuePrefix(t.stateId) })),
2076
+ sets: phaseOrig.sets.map((s) => ({ ...s, stateId: valuePrefix(s.stateId) }))
1654
2077
  });
1655
2078
  }
1656
2079
  } else {
@@ -1662,8 +2085,8 @@ function mergePartIntoDiagram(target, part, alias, stateOverride, laneMapping, o
1662
2085
  const partPhase = part.phases[i];
1663
2086
  targetPhase.duration = Math.max(targetPhase.duration, partPhase.duration);
1664
2087
  targetPhase.activate = [...targetPhase.activate, ...partPhase.activate.map(prefix)];
1665
- targetPhase.tweens = [...targetPhase.tweens, ...partPhase.tweens.map((t) => ({ ...t, stateId: prefix(t.stateId) }))];
1666
- targetPhase.sets = [...targetPhase.sets, ...partPhase.sets.map((s) => ({ ...s, stateId: prefix(s.stateId) }))];
2088
+ targetPhase.tweens = [...targetPhase.tweens, ...partPhase.tweens.map((t) => ({ ...t, stateId: valuePrefix(t.stateId) }))];
2089
+ targetPhase.sets = [...targetPhase.sets, ...partPhase.sets.map((s) => ({ ...s, stateId: valuePrefix(s.stateId) }))];
1667
2090
  }
1668
2091
  for (let i = commonLen; i < partsLen; i++) {
1669
2092
  const phaseOrig = part.phases[i];
@@ -1671,8 +2094,8 @@ function mergePartIntoDiagram(target, part, alias, stateOverride, laneMapping, o
1671
2094
  ...phaseOrig,
1672
2095
  id: prefix(phaseOrig.id),
1673
2096
  activate: phaseOrig.activate.map(prefix),
1674
- tweens: phaseOrig.tweens.map((t) => ({ ...t, stateId: prefix(t.stateId) })),
1675
- sets: phaseOrig.sets.map((s) => ({ ...s, stateId: prefix(s.stateId) }))
2097
+ tweens: phaseOrig.tweens.map((t) => ({ ...t, stateId: valuePrefix(t.stateId) })),
2098
+ sets: phaseOrig.sets.map((s) => ({ ...s, stateId: valuePrefix(s.stateId) }))
1676
2099
  });
1677
2100
  }
1678
2101
  }
@@ -1692,6 +2115,15 @@ function deepRewriteStrings(value, rewrite, seen = /* @__PURE__ */ new WeakSet()
1692
2115
  return out;
1693
2116
  }
1694
2117
  function applyEdgeInlineOptions(diagram2, doc, sourceLines) {
2118
+ if (\u9396\u3067\u3064\u306A\u3050\u5F62\u304B(doc)) {
2119
+ diagram2.edges.forEach((e, idx) => {
2120
+ const s = \u9396\u306E\u3069\u306E\u884C\u304B\u3089\u6765\u305F\u304B(doc, idx);
2121
+ if (s === void 0) return;
2122
+ sourceLines?.set(e.id, s.pos.line);
2123
+ \u77E2\u5370\u3078\u66F8\u304D\u5199\u3059(e, s, doc);
2124
+ });
2125
+ return;
2126
+ }
1695
2127
  const used = /* @__PURE__ */ new Set();
1696
2128
  const isSeqLike = doc.type === "sequence" || doc.type === "solidity";
1697
2129
  doc.flow.forEach((s, stepIdx) => {
@@ -1707,20 +2139,35 @@ function applyEdgeInlineOptions(diagram2, doc, sourceLines) {
1707
2139
  if (!target) return;
1708
2140
  used.add(target.id);
1709
2141
  sourceLines?.set(target.id, s.pos.line);
1710
- if (s.guard !== void 0) {
1711
- target.guard = s.guard;
1712
- if (doc.type === "state" && target.sub === void 0) target.sub = s.guard;
1713
- }
1714
- if (s.cardinality !== void 0) {
1715
- target.cardinality = s.cardinality;
1716
- if (doc.type === "er" && !target.label.includes(s.cardinality)) {
1717
- target.label = target.label ? `${target.label} (${s.cardinality})` : `(${s.cardinality})`;
1718
- }
1719
- }
1720
- if (s.labelOffsetX !== void 0) target.labelOffsetX = s.labelOffsetX;
1721
- if (s.labelOffsetY !== void 0) target.labelOffsetY = s.labelOffsetY;
2142
+ \u77E2\u5370\u3078\u66F8\u304D\u5199\u3059(target, s, doc);
1722
2143
  });
1723
2144
  }
2145
+ function \u77E2\u5370\u3078\u66F8\u304D\u5199\u3059(target, s, doc) {
2146
+ if (s.sub !== void 0) target.sub = s.sub;
2147
+ if (s.guard !== void 0) {
2148
+ target.guard = s.guard;
2149
+ if (doc.type === "state" && target.sub === void 0) target.sub = s.guard;
2150
+ }
2151
+ if (s.cardinality !== void 0) {
2152
+ target.cardinality = s.cardinality;
2153
+ if (doc.type === "er" && !target.label.includes(s.cardinality)) {
2154
+ target.label = target.label ? `${target.label} (${s.cardinality})` : `(${s.cardinality})`;
2155
+ }
2156
+ }
2157
+ if (s.labelOffsetX !== void 0) target.labelOffsetX = s.labelOffsetX;
2158
+ if (s.labelOffsetY !== void 0) target.labelOffsetY = s.labelOffsetY;
2159
+ if (s.overlay !== void 0) target.overlay = s.overlay;
2160
+ }
2161
+ function \u9396\u3067\u3064\u306A\u3050\u5F62\u304B(doc) {
2162
+ if (doc.type !== "flow") return false;
2163
+ if (doc.animate && doc.animate.phases.length > 0) return false;
2164
+ return !\u66F8\u3044\u305F\u7E26\u5217\u306B\u7F6E\u304F("flow", doc);
2165
+ }
2166
+ function \u9396\u306E\u3069\u306E\u884C\u304B\u3089\u6765\u305F\u304B(doc, edgeIndex) {
2167
+ const to = doc.actors[edgeIndex + 1];
2168
+ if (to === void 0) return void 0;
2169
+ return doc.flow.find((s) => s.to === to.name);
2170
+ }
1724
2171
  var DRAWABLE_KINDS = new Set(NODE_KINDS);
1725
2172
  var KIND_ALIAS = {
1726
2173
  eoa: "shape-wallet",
@@ -1731,13 +2178,312 @@ var KIND_ALIAS = {
1731
2178
  library: "shape-code-block",
1732
2179
  interface: "shape-code-block"
1733
2180
  };
2181
+ function \u5F0F\u306B\u66F8\u304F\u6570(n) {
2182
+ if (!Number.isFinite(n)) return "0";
2183
+ const text = String(n);
2184
+ if (!/[eE]/.test(text)) return text;
2185
+ const [coefficient = "0", exponentText = "0"] = text.toLowerCase().split("e");
2186
+ const negative = coefficient.startsWith("-");
2187
+ const unsigned = negative ? coefficient.slice(1) : coefficient;
2188
+ const [whole = "0", fraction = ""] = unsigned.split(".");
2189
+ const digits = `${whole}${fraction}`;
2190
+ const decimalAt = whole.length + Number(exponentText);
2191
+ let expanded;
2192
+ if (decimalAt <= 0) expanded = `0.${"0".repeat(-decimalAt)}${digits}`;
2193
+ else if (decimalAt >= digits.length) expanded = `${digits}${"0".repeat(decimalAt - digits.length)}`;
2194
+ else expanded = `${digits.slice(0, decimalAt)}.${digits.slice(decimalAt)}`;
2195
+ return negative ? `-${expanded}` : expanded;
2196
+ }
2197
+ function \u5883\u76EE\u3092\u901A\u308B\u6642\u523B(\u533A\u9593, op, \u5883\u76EE) {
2198
+ const \u6E80\u305F\u3059 = (x) => {
2199
+ switch (op) {
2200
+ case ">=":
2201
+ return x >= \u5883\u76EE;
2202
+ case ">":
2203
+ return x > \u5883\u76EE;
2204
+ case "<=":
2205
+ return x <= \u5883\u76EE;
2206
+ case "<":
2207
+ return x < \u5883\u76EE;
2208
+ case "==":
2209
+ return x === \u5883\u76EE;
2210
+ case "!=":
2211
+ return x !== \u5883\u76EE;
2212
+ default:
2213
+ return false;
2214
+ }
2215
+ };
2216
+ if (\u6E80\u305F\u3059(\u533A\u9593.from)) return \u533A\u9593.start;
2217
+ if (op === "==") {
2218
+ const min = Math.min(\u533A\u9593.from, \u533A\u9593.to);
2219
+ const max = Math.max(\u533A\u9593.from, \u533A\u9593.to);
2220
+ if (\u5883\u76EE < min || \u5883\u76EE > max) return null;
2221
+ } else if (!\u6E80\u305F\u3059(\u533A\u9593.to)) {
2222
+ return null;
2223
+ }
2224
+ if (\u533A\u9593.to === \u533A\u9593.from) return null;
2225
+ const t = \u533A\u9593.start + \u533A\u9593.dur * (\u5883\u76EE - \u533A\u9593.from) / (\u533A\u9593.to - \u533A\u9593.from);
2226
+ if (!Number.isFinite(t)) return null;
2227
+ return Math.min(Math.max(t, \u533A\u9593.start), \u533A\u9593.end);
2228
+ }
2229
+ function foldValueTriggers(diagram2, doc, onNotice) {
2230
+ const \u51FA\u529B = /* @__PURE__ */ new Map();
2231
+ const \u304D\u3063\u304B\u3051\u4ED8\u304D = (doc.values ?? []).filter((v) => v.trigger !== void 0);
2232
+ if (\u304D\u3063\u304B\u3051\u4ED8\u304D.length === 0) return \u51FA\u529B;
2233
+ const \u5BA3\u8A00 = /* @__PURE__ */ new Map();
2234
+ for (const v of \u304D\u3063\u304B\u3051\u4ED8\u304D) if (!\u5BA3\u8A00.has(v.name)) \u5BA3\u8A00.set(v.name, v);
2235
+ const \u521D\u671F\u5024 = /* @__PURE__ */ new Map();
2236
+ for (const s of diagram2.states) {
2237
+ const n = Number(s.initial);
2238
+ if (Number.isFinite(n)) \u521D\u671F\u5024.set(s.id, n);
2239
+ }
2240
+ const \u6BB5\u306E\u756A\u53F7 = /* @__PURE__ */ new Map();
2241
+ diagram2.phases.forEach((p, i) => {
2242
+ if (!\u6BB5\u306E\u756A\u53F7.has(p.title)) \u6BB5\u306E\u756A\u53F7.set(p.title, i);
2243
+ if (!\u6BB5\u306E\u756A\u53F7.has(p.id)) \u6BB5\u306E\u756A\u53F7.set(p.id, i);
2244
+ });
2245
+ const \u89E3\u3051\u305F = /* @__PURE__ */ new Map();
2246
+ const \u89E3\u3051\u306A\u3044 = /* @__PURE__ */ new Set();
2247
+ const \u89E3\u6C7A\u4E2D = /* @__PURE__ */ new Set();
2248
+ const \u77E5\u3089\u305B\u308B = (v, message, hint) => {
2249
+ onNotice?.({ kind: "value-trigger-unresolved", actor: v.name, line: v.pos?.line ?? 0, message, hint });
2250
+ };
2251
+ const \u89E3\u304F = (name) => {
2252
+ const \u65E2\u51FA = \u89E3\u3051\u305F.get(name);
2253
+ if (\u65E2\u51FA) return \u65E2\u51FA;
2254
+ if (\u89E3\u3051\u306A\u3044.has(name)) return null;
2255
+ const v = \u5BA3\u8A00.get(name);
2256
+ if (!v || !v.trigger) return null;
2257
+ if (\u89E3\u6C7A\u4E2D.has(name)) {
2258
+ \u89E3\u3051\u306A\u3044.add(name);
2259
+ \u77E5\u3089\u305B\u308B(v, `"${name}" \u306E\u304D\u3063\u304B\u3051\u304C\u4E00\u5468\u3057\u3066\u3044\u307E\u3059`, "\u3069\u308C\u304B 1 \u3064\u3092 `trigger: step ...` \u306B\u5909\u3048\u308B");
2260
+ return null;
2261
+ }
2262
+ \u89E3\u6C7A\u4E2D.add(name);
2263
+ const \u533A\u9593 = \u7D44\u307F\u7ACB\u3066\u308B(v);
2264
+ \u89E3\u6C7A\u4E2D.delete(name);
2265
+ if (!\u533A\u9593) {
2266
+ \u89E3\u3051\u306A\u3044.add(name);
2267
+ return null;
2268
+ }
2269
+ \u89E3\u3051\u305F.set(name, \u533A\u9593);
2270
+ return \u533A\u9593;
2271
+ };
2272
+ const \u7D44\u307F\u7ACB\u3066\u308B = (v) => {
2273
+ const trigger = v.trigger;
2274
+ const from = \u521D\u671F\u5024.get(v.name) ?? 0;
2275
+ const to = v.to ?? 0;
2276
+ const dur = v.durationMs ?? 0;
2277
+ let \u6BB5 = 0;
2278
+ let start = 0;
2279
+ if (trigger.kind === "step") {
2280
+ const idx = \u6BB5\u306E\u756A\u53F7.get(trigger.step);
2281
+ if (idx === void 0) {
2282
+ \u77E5\u3089\u305B\u308B(v, `"${trigger.step}" \u3068\u3044\u3046\u6BB5\u304C\u3042\u308A\u307E\u305B\u3093`, "`animation:` \u306B\u305D\u306E\u540D\u524D\u306E\u6BB5\u3092\u66F8\u304F\u304B\u3001 \u6BB5\u306E\u540D\u524D\u306B\u5408\u308F\u305B\u308B");
2283
+ return null;
2284
+ }
2285
+ \u6BB5 = idx;
2286
+ start = 0;
2287
+ } else {
2288
+ const \u76F8\u624B = \u89E3\u304F(trigger.source);
2289
+ if (!\u76F8\u624B) {
2290
+ \u77E5\u3089\u305B\u308B(
2291
+ v,
2292
+ `"${trigger.source}" \u304C\u52D5\u304F\u5024\u3067\u306A\u3044\u305F\u3081\u3001 \u304D\u3063\u304B\u3051\u306E\u6642\u523B\u3092\u6C7A\u3081\u3089\u308C\u307E\u305B\u3093`,
2293
+ "\u898B\u5F35\u308B\u76F8\u624B\u3082 `trigger:` \u3092\u6301\u3064\u5024\u306B\u3059\u308B"
2294
+ );
2295
+ return null;
2296
+ }
2297
+ const at = \u5883\u76EE\u3092\u901A\u308B\u6642\u523B(\u76F8\u624B, trigger.op, trigger.threshold);
2298
+ if (at === null) {
2299
+ \u77E5\u3089\u305B\u308B(
2300
+ v,
2301
+ `"${trigger.source}" \u306F ${trigger.op} ${trigger.threshold} \u3092\u6E80\u305F\u3057\u307E\u305B\u3093`,
2302
+ "\u76F8\u624B\u304C\u901A\u308B\u5024\u3092\u5883\u76EE\u306B\u3059\u308B\u304B\u3001 \u76F8\u624B\u306E `to` \u3092\u898B\u76F4\u3059"
2303
+ );
2304
+ return null;
2305
+ }
2306
+ \u6BB5 = \u76F8\u624B.\u6BB5;
2307
+ start = at;
2308
+ }
2309
+ const \u6BB5\u306E\u9577\u3055 = diagram2.phases[\u6BB5]?.duration ?? 0;
2310
+ if (start + dur > \u6BB5\u306E\u9577\u3055) {
2311
+ \u77E5\u3089\u305B\u308B(
2312
+ v,
2313
+ `\u6BB5 "${diagram2.phases[\u6BB5]?.title ?? ""}" (${\u6BB5\u306E\u9577\u3055}ms) \u306B\u53CE\u307E\u308A\u307E\u305B\u3093 (${Math.round(start + dur)}ms \u5FC5\u8981)`,
2314
+ "\u6BB5\u3092\u9577\u304F\u3059\u308B\u304B `dur` \u3092\u77ED\u304F\u3059\u308B"
2315
+ );
2316
+ return null;
2317
+ }
2318
+ return { \u6BB5, start, end: start + dur, dur, from, to };
2319
+ };
2320
+ for (const v of \u5BA3\u8A00.values()) \u89E3\u304F(v.name);
2321
+ if (\u89E3\u3051\u305F.size === 0) return \u51FA\u529B;
2322
+ const \u4F7F\u7528\u4E2D = new Set(diagram2.states.map((s) => s.id));
2323
+ for (const v of doc.values ?? []) \u4F7F\u7528\u4E2D.add(v.name);
2324
+ const \u6BB5\u3054\u3068\u306E\u6642\u8A08 = /* @__PURE__ */ new Map();
2325
+ const \u6642\u8A08\u3092\u7528\u610F\u3059\u308B = (\u6BB5) => {
2326
+ const \u65E2\u51FA = \u6BB5\u3054\u3068\u306E\u6642\u8A08.get(\u6BB5);
2327
+ if (\u65E2\u51FA) return \u65E2\u51FA;
2328
+ let \u540D\u524D = `__step_clock_${\u6BB5}`;
2329
+ let \u9023\u756A = 2;
2330
+ while (\u4F7F\u7528\u4E2D.has(\u540D\u524D)) \u540D\u524D = `__step_clock_${\u6BB5}_${\u9023\u756A++}`;
2331
+ \u4F7F\u7528\u4E2D.add(\u540D\u524D);
2332
+ \u6BB5\u3054\u3068\u306E\u6642\u8A08.set(\u6BB5, \u540D\u524D);
2333
+ diagram2.states.push({ id: \u540D\u524D, initial: 0 });
2334
+ const \u6BB5\u306E\u4E2D\u8EAB = diagram2.phases[\u6BB5];
2335
+ if (\u6BB5\u306E\u4E2D\u8EAB) \u6BB5\u306E\u4E2D\u8EAB.tweens = [...\u6BB5\u306E\u4E2D\u8EAB.tweens, { stateId: \u540D\u524D, from: 0, to: \u6BB5\u306E\u4E2D\u8EAB.duration }];
2336
+ return \u540D\u524D;
2337
+ };
2338
+ for (const [name, \u533A\u9593] of \u89E3\u3051\u305F) {
2339
+ const \u6642\u8A08 = \u6642\u8A08\u3092\u7528\u610F\u3059\u308B(\u533A\u9593.\u6BB5);
2340
+ const \u9032\u307F = `min(max(({${\u6642\u8A08}} - ${\u5F0F\u306B\u66F8\u304F\u6570(\u533A\u9593.start)}) / ${\u5F0F\u306B\u66F8\u304F\u6570(\u533A\u9593.dur)}, 0), 1)`;
2341
+ \u51FA\u529B.set(name, `((${\u9032\u307F} * ${\u5F0F\u306B\u66F8\u304F\u6570(\u533A\u9593.to - \u533A\u9593.from)}) + ${\u5F0F\u306B\u66F8\u304F\u6570(\u533A\u9593.from)})`);
2342
+ }
2343
+ return \u51FA\u529B;
2344
+ }
2345
+ function attachDerivedValues(diagram2, doc, onNotice, inheritedSourceLines, foldedTriggers) {
2346
+ const values = doc.values ?? [];
2347
+ if (values.length === 0) {
2348
+ if ((diagram2.derived?.length ?? 0) > 0) {
2349
+ reportUnresolvedValues(diagram2, doc, onNotice, inheritedSourceLines);
2350
+ }
2351
+ return;
2352
+ }
2353
+ const \u72B6\u614B\u306E\u540D\u524D = new Set(diagram2.states.map((s) => s.id));
2354
+ for (const v of values) {
2355
+ if (!\u72B6\u614B\u306E\u540D\u524D.has(v.name)) continue;
2356
+ if (v.trigger !== void 0) continue;
2357
+ onNotice?.({
2358
+ kind: "value-shadows-state",
2359
+ actor: v.name,
2360
+ line: v.pos?.line ?? 0,
2361
+ message: `"${v.name}" \u3092 states \u3068 values \u306E\u4E21\u65B9\u306B\u66F8\u3044\u3066\u3044\u307E\u3059\u3002 values \u3092\u4F7F\u3044\u307E\u3059`,
2362
+ hint: "states \u304B\u3089\u5916\u3059\u304B\u3001 values \u306E\u540D\u524D\u3092\u5909\u3048\u308B"
2363
+ });
2364
+ }
2365
+ const \u8F09\u305B\u308B = [];
2366
+ for (const v of values) {
2367
+ const expression = v.expression ?? foldedTriggers?.get(v.name);
2368
+ if (expression === void 0) continue;
2369
+ \u8F09\u305B\u308B.push({ id: v.name, expression });
2370
+ }
2371
+ diagram2.derived = [...\u8F09\u305B\u308B, ...diagram2.derived ?? []];
2372
+ reportUnresolvedValues(diagram2, doc, onNotice, inheritedSourceLines);
2373
+ }
2374
+ function renameFormulaIdentifiers(ast, rename) {
2375
+ switch (ast.type) {
2376
+ case "number":
2377
+ return ast;
2378
+ case "identifier":
2379
+ return { type: "identifier", name: rename(ast.name) };
2380
+ case "unaryOp":
2381
+ return { ...ast, operand: renameFormulaIdentifiers(ast.operand, rename) };
2382
+ case "binaryOp":
2383
+ return {
2384
+ ...ast,
2385
+ left: renameFormulaIdentifiers(ast.left, rename),
2386
+ right: renameFormulaIdentifiers(ast.right, rename)
2387
+ };
2388
+ case "ternary":
2389
+ return {
2390
+ type: "ternary",
2391
+ condition: renameFormulaIdentifiers(ast.condition, rename),
2392
+ whenTrue: renameFormulaIdentifiers(ast.whenTrue, rename),
2393
+ whenFalse: renameFormulaIdentifiers(ast.whenFalse, rename)
2394
+ };
2395
+ case "call":
2396
+ return { ...ast, args: ast.args.map((a) => renameFormulaIdentifiers(a, rename)) };
2397
+ }
2398
+ }
2399
+ function writeNumber(value) {
2400
+ if (!Number.isFinite(value)) throw new Error(`cannot write non-finite number: ${String(value)}`);
2401
+ const s = String(value);
2402
+ if (!/[eE]/.test(s)) return s;
2403
+ const m = /^(-?)(\d+)(?:\.(\d+))?[eE]([+-]?\d+)$/.exec(s);
2404
+ if (!m) throw new Error(`cannot write number: ${s}`);
2405
+ const sign = m[1] ?? "";
2406
+ const int = m[2] ?? "";
2407
+ const frac = m[3] ?? "";
2408
+ const digits = int + frac;
2409
+ const point = int.length + Number(m[4] ?? "0");
2410
+ if (point <= 0) return `${sign}0.${"0".repeat(-point)}${digits}`;
2411
+ if (point >= digits.length) return `${sign}${digits}${"0".repeat(point - digits.length)}`;
2412
+ return `${sign}${digits.slice(0, point)}.${digits.slice(point)}`;
2413
+ }
2414
+ function writeFormula(ast) {
2415
+ switch (ast.type) {
2416
+ case "number":
2417
+ return writeNumber(ast.value);
2418
+ case "identifier":
2419
+ return /^[A-Za-z_$][\w$]*$/.test(ast.name) ? ast.name : `{${ast.name}}`;
2420
+ case "unaryOp":
2421
+ return `(${ast.op}${writeFormula(ast.operand)})`;
2422
+ case "binaryOp":
2423
+ return `(${writeFormula(ast.left)} ${ast.op} ${writeFormula(ast.right)})`;
2424
+ case "ternary":
2425
+ return `(${writeFormula(ast.condition)} ? ${writeFormula(ast.whenTrue)} : ${writeFormula(ast.whenFalse)})`;
2426
+ case "call":
2427
+ return `${ast.fn}(${ast.args.map(writeFormula).join(", ")})`;
2428
+ }
2429
+ }
2430
+ function recordDerivedSourceLine(sourceLines, id, line) {
2431
+ if (!sourceLines) return;
2432
+ const lines = sourceLines.get(id) ?? [];
2433
+ lines.push(line);
2434
+ sourceLines.set(id, lines);
2435
+ }
2436
+ function reportUnresolvedValues(diagram2, doc, onNotice, inheritedSourceLines) {
2437
+ if (!onNotice) return;
2438
+ const \u521D\u671F\u5024 = /* @__PURE__ */ Object.create(null);
2439
+ for (const s of diagram2.states) \u521D\u671F\u5024[s.id] = String(s.initial);
2440
+ const \u6700\u521D\u306E\u884C = /* @__PURE__ */ new Map();
2441
+ const \u91CD\u8907\u3057\u305F\u884C = /* @__PURE__ */ new Map();
2442
+ for (const v of doc.values ?? []) {
2443
+ if (!\u6700\u521D\u306E\u884C.has(v.name)) {
2444
+ \u6700\u521D\u306E\u884C.set(v.name, v.pos?.line ?? 0);
2445
+ continue;
2446
+ }
2447
+ const \u540C\u3058\u540D\u524D\u306E\u884C = \u91CD\u8907\u3057\u305F\u884C.get(v.name) ?? [];
2448
+ \u540C\u3058\u540D\u524D\u306E\u884C.push(v.pos?.line ?? 0);
2449
+ \u91CD\u8907\u3057\u305F\u884C.set(v.name, \u540C\u3058\u540D\u524D\u306E\u884C);
2450
+ }
2451
+ for (const [id, lines] of inheritedSourceLines ?? []) {
2452
+ for (const line of lines) {
2453
+ if (!\u6700\u521D\u306E\u884C.has(id)) {
2454
+ \u6700\u521D\u306E\u884C.set(id, line);
2455
+ continue;
2456
+ }
2457
+ const \u540C\u3058\u540D\u524D\u306E\u884C = \u91CD\u8907\u3057\u305F\u884C.get(id) ?? [];
2458
+ \u540C\u3058\u540D\u524D\u306E\u884C.push(line);
2459
+ \u91CD\u8907\u3057\u305F\u884C.set(id, \u540C\u3058\u540D\u524D\u306E\u884C);
2460
+ }
2461
+ }
2462
+ for (const n of applyDerivedValues(\u521D\u671F\u5024, diagram2.derived).notices) {
2463
+ onNotice({
2464
+ kind: n.kind === "duplicate-id" ? "value-duplicate" : "value-unresolved",
2465
+ actor: n.id,
2466
+ // 重複は後から書いた宣言そのものを、式の問題は engine が使う最初の宣言を指す
2467
+ line: n.kind === "duplicate-id" ? \u91CD\u8907\u3057\u305F\u884C.get(n.id)?.shift() ?? \u6700\u521D\u306E\u884C.get(n.id) ?? 0 : \u6700\u521D\u306E\u884C.get(n.id) ?? 0,
2468
+ message: n.message,
2469
+ hint: VALUE_NOTICE_HINT[n.kind]
2470
+ });
2471
+ }
2472
+ }
2473
+ var VALUE_NOTICE_HINT = {
2474
+ cycle: "\u53C2\u7167\u304C\u4E00\u5468\u3057\u3066\u3044\u307E\u3059\u3002 \u3069\u308C\u304B 1 \u3064\u3092 states \u306E\u521D\u671F\u5024\u306B\u5909\u3048\u308B",
2475
+ "unknown-reference": "\u305D\u306E\u540D\u524D\u306E states / values \u3092\u8DB3\u3059\u304B\u3001\u7DB4\u308A\u3092\u76F4\u3059",
2476
+ "parse-error": "\u5F0F\u306B\u66F8\u3051\u308B\u306E\u306F\u56DB\u5247 (+ - * /) \u3068\u62EC\u5F27\u3001\u6BD4\u8F03\u3001min / max \u3060\u3051",
2477
+ "eval-error": "\u521D\u671F\u5024\u3067\u8A08\u7B97\u3067\u304D\u306A\u3044\u5F62\u3067\u3059\u3002 \u5272\u308B\u6570\u3084\u3001\u6570\u3068\u3057\u3066\u8AAD\u3081\u306A\u3044\u521D\u671F\u5024\u3092\u898B\u76F4\u3059",
2478
+ "duplicate-id": "\u540C\u3058\u540D\u524D\u304C 2 \u5EA6\u3042\u308A\u307E\u3059\u3002 \u7247\u65B9\u3092\u6D88\u3059\u304B\u540D\u524D\u3092\u5909\u3048\u308B",
2479
+ "invalid-id": "\u540D\u524D\u306B\u4F7F\u3048\u308B\u306E\u306F\u82F1\u6570\u5B57\u3068 _ \u3060\u3051"
2480
+ };
1734
2481
  var SINGLE_BOX_KINDS = /* @__PURE__ */ new Set([
1735
2482
  "chart-pie",
1736
2483
  "chart-line",
1737
2484
  "chart-bar",
1738
2485
  "gantt-timeline",
1739
2486
  "mind-map",
1740
- "mind-radial",
1741
2487
  "funnel-stages",
1742
2488
  "quadrant-matrix",
1743
2489
  "tree-hierarchy",
@@ -1836,17 +2582,6 @@ function dropUnfittableEndKinds(diagram2, doc) {
1836
2582
  }
1837
2583
  }
1838
2584
  }
1839
- function fillFlowEdgeSources(diagram2, doc, sourceLines) {
1840
- if (doc.type !== "flow") return;
1841
- if (doc.animate && doc.animate.phases.length > 0) return;
1842
- diagram2.edges.forEach((e, idx) => {
1843
- const to = doc.actors[idx + 1];
1844
- if (to === void 0) return;
1845
- const step = doc.flow.find((s) => s.to === to.name);
1846
- if (step === void 0) return;
1847
- sourceLines.set(e.id, step.pos.line);
1848
- });
1849
- }
1850
2585
  function applyGroupContainers(diagram2, doc) {
1851
2586
  if (!doc.groups || Object.keys(doc.groups).length === 0) return;
1852
2587
  for (const [id, g] of Object.entries(doc.groups)) {
@@ -1883,10 +2618,57 @@ function compileSolidity(doc) {
1883
2618
  const sortedDoc = { ...doc, actors: sorted };
1884
2619
  return compileSequence(sortedDoc);
1885
2620
  }
2621
+ function \u72B6\u614B\u304C\u53D6\u308B\u5024(\u53C2\u7167, doc) {
2622
+ const \u540D = \u53C2\u7167.slice(1, -1);
2623
+ const out = [];
2624
+ const \u6570\u306B\u3059\u308B = (v) => {
2625
+ if (typeof v === "number") {
2626
+ if (Number.isFinite(v)) out.push(v);
2627
+ return;
2628
+ }
2629
+ const \u6587\u5B57 = String(v).trim();
2630
+ if (\u6587\u5B57 === "") return;
2631
+ const n = Number(\u6587\u5B57);
2632
+ if (Number.isFinite(n)) out.push(n);
2633
+ };
2634
+ for (const st of doc.animate?.states ?? []) if (st.name === \u540D) \u6570\u306B\u3059\u308B(st.initial);
2635
+ for (const p of doc.animate?.phases ?? []) {
2636
+ for (const t of p.tweens ?? []) {
2637
+ if (t.state !== \u540D) continue;
2638
+ \u6570\u306B\u3059\u308B(t.from);
2639
+ \u6570\u306B\u3059\u308B(t.to);
2640
+ }
2641
+ for (const v of p.sets ?? []) if (v.state === \u540D) \u6570\u306B\u3059\u308B(v.value);
2642
+ }
2643
+ return out;
2644
+ }
2645
+ function \u7D42\u308F\u308B\u4F4D\u7F6E(end, \u59CB\u307E\u308A, \u76EE\u76DB\u308A, \u540D\u524D, \u4F1D\u3048\u308B, doc) {
2646
+ if (end === void 0) return { idx: \u59CB\u307E\u308A };
2647
+ if (/^\{\w+\}$/.test(end)) {
2648
+ const \u4F4E\u3044 = \u72B6\u614B\u304C\u53D6\u308B\u5024(end, doc).filter((v) => v < \u59CB\u307E\u308A);
2649
+ if (\u4F4E\u3044.length > 0) {
2650
+ \u4F1D\u3048\u308B(
2651
+ \u540D\u524D,
2652
+ `type: gantt \u3067 ${truncateForMessage(\u540D\u524D)} \u306E\u7D42\u308F\u308A (${truncateForMessage(end)}) \u304C\u59CB\u307E\u308A\u3088\u308A\u524D\u306B\u306A\u308B\u5024\u3092\u53D6\u308A\u307E\u3059 (${[...new Set(\u4F4E\u3044)].join(", ")})\u3002 \u59CB\u307E\u308A\u306F ${\u59CB\u307E\u308A} \u756A\u76EE\u3067\u3059`
2653
+ );
2654
+ }
2655
+ return { idx: end };
2656
+ }
2657
+ const i = \u76EE\u76DB\u308A.indexOf(end);
2658
+ if (i < 0) return { idx: \u59CB\u307E\u308A };
2659
+ if (i < \u59CB\u307E\u308A) {
2660
+ \u4F1D\u3048\u308B(
2661
+ \u540D\u524D,
2662
+ `type: gantt \u3067 ${truncateForMessage(\u540D\u524D)} \u306E\u7D42\u308F\u308A (${truncateForMessage(end)}) \u304C\u59CB\u307E\u308A\u3088\u308A\u524D\u3067\u3059 (\u59CB\u307E\u308A\u3068\u540C\u3058\u306B\u5012\u3057\u307E\u3057\u305F)`
2663
+ );
2664
+ return { idx: \u59CB\u307E\u308A };
2665
+ }
2666
+ return { idx: i, label: end };
2667
+ }
1886
2668
  function compileGantt(doc) {
1887
2669
  const b = diagram(slugify(doc.title), { topic: doc.title });
1888
2670
  const CHART_W = 720;
1889
- b.lane("gantt", { width: CHART_W, label: doc.title });
2671
+ b.lane("gantt", { width: CHART_W });
1890
2672
  const \u76EE\u76DB\u308A = [];
1891
2673
  const \u76EE\u76DB\u308A\u306A\u3057 = [];
1892
2674
  const \u30BF\u30B9\u30AF = [];
@@ -1897,7 +2679,13 @@ function compileGantt(doc) {
1897
2679
  continue;
1898
2680
  }
1899
2681
  if (!\u76EE\u76DB\u308A.includes(label)) \u76EE\u76DB\u308A.push(label);
1900
- \u30BF\u30B9\u30AF.push({ name: a.name, label, ...a.tone !== void 0 ? { tone: a.tone } : {} });
2682
+ \u30BF\u30B9\u30AF.push({
2683
+ name: a.name,
2684
+ label,
2685
+ ...a.tone !== void 0 ? { tone: a.tone } : {},
2686
+ ...a.owner !== void 0 ? { owner: a.owner } : {},
2687
+ ...a.end !== void 0 ? { end: a.end } : {}
2688
+ });
1901
2689
  }
1902
2690
  if (\u76EE\u76DB\u308A\u306A\u3057.length > 0 && typeof console !== "undefined" && console.warn) {
1903
2691
  console.warn(
@@ -1928,24 +2716,30 @@ function compileGantt(doc) {
1928
2716
  `[dragon] type: gantt \u306E\u77E2\u5370\u306F\u524D\u5F8C\u306E\u95A2\u4FC2\u3060\u3051\u3092\u4F7F\u3044\u307E\u3059 (\u6587\u5B57 / \u8272 / \u7DDA\u7A2E\u306F\u63CF\u3051\u307E\u305B\u3093): ${\u88C5\u98FE\u3064\u304D.join(", ")}`
1929
2717
  );
1930
2718
  }
2719
+ const \u9006\u5411\u304D\u3092\u4F1D\u3048\u308B = (_\u540D, message) => {
2720
+ if (typeof console !== "undefined" && console.warn) console.warn(`[dragon] ${message}`);
2721
+ };
1931
2722
  const CHART_H = Math.max(360, 48 * \u30BF\u30B9\u30AF.length + 96);
1932
2723
  b.node(`${slugify(doc.title)}-chart`, {
1933
2724
  lane: "gantt",
1934
2725
  stack: 0,
1935
2726
  kind: "gantt-timeline",
1936
2727
  title: doc.title,
2728
+ ...\u56F3\u306E\u5C0F\u898B\u51FA\u3057(doc),
1937
2729
  w: CHART_W,
1938
2730
  h: CHART_H,
1939
2731
  ganttData: \u30BF\u30B9\u30AF.map((t) => {
1940
2732
  const idx = \u76EE\u76DB\u308A.indexOf(t.label);
1941
2733
  const from = \u4F9D\u5B58\u5143.get(t.name);
2734
+ const \u7D42\u308F\u308A = \u7D42\u308F\u308B\u4F4D\u7F6E(t.end, idx, \u76EE\u76DB\u308A, t.name, \u9006\u5411\u304D\u3092\u4F1D\u3048\u308B, doc);
1942
2735
  return {
1943
2736
  id: slugify(t.name),
1944
2737
  title: t.name,
1945
2738
  startIdx: idx,
1946
- endIdx: idx,
2739
+ endIdx: \u7D42\u308F\u308A.idx,
1947
2740
  startLabel: t.label,
1948
- endLabel: t.label,
2741
+ endLabel: \u7D42\u308F\u308A.label ?? t.label,
2742
+ ...t.owner !== void 0 ? { owner: t.owner } : {},
1949
2743
  ...from !== void 0 ? { dependsOn: slugify(from) } : {},
1950
2744
  ...t.tone !== void 0 ? { tone: t.tone } : {}
1951
2745
  };
@@ -1956,13 +2750,15 @@ function compileGantt(doc) {
1956
2750
  function compileClass(doc) {
1957
2751
  const b = diagram(slugify(doc.title), { topic: doc.title });
1958
2752
  const CLASS_W = 400;
2753
+ const CLASS_LANE_W = 450;
1959
2754
  if (doc.actors.length === 0) return b.build();
1960
- b.lane("class-stack", { width: CLASS_W, label: doc.title });
1961
2755
  doc.actors.forEach((a, idx) => {
1962
2756
  const nodeId = slugify(a.name);
2757
+ const laneId = `lane-${nodeId}`;
2758
+ b.lane(laneId, { width: CLASS_LANE_W });
1963
2759
  b.node(nodeId, {
1964
- lane: "class-stack",
1965
- stack: idx,
2760
+ lane: laneId,
2761
+ stack: 0,
1966
2762
  kind: "storage",
1967
2763
  title: a.name,
1968
2764
  w: CLASS_W
@@ -1982,47 +2778,474 @@ function compileClass(doc) {
1982
2778
  }
1983
2779
  function parseShareValue(raw) {
1984
2780
  if (raw === void 0) return null;
1985
- const m = raw.trim().match(/^(\d+(?:\.\d+)?)\s*%?$/);
2781
+ const m = raw.trim().match(/^(-?\d+(?:\.\d+)?)\s*%?$/);
1986
2782
  if (m === null) return null;
1987
2783
  const v = Number(m[1]);
1988
2784
  return Number.isFinite(v) ? v : null;
1989
2785
  }
1990
- function compilePie(doc) {
2786
+ function parseBoundValue(raw) {
2787
+ if (raw === void 0) return null;
2788
+ const t = raw.trim();
2789
+ return /^\{\w+(?:\.(?:length|sum|max|min|avg)|\[\d+\])?\}$/.test(t) ? t : null;
2790
+ }
2791
+ function parseChartValue(raw) {
2792
+ const n = parseShareValue(raw);
2793
+ if (n !== null) return n;
2794
+ return parseBoundValue(raw);
2795
+ }
2796
+ function \u53C2\u7167\u3059\u308B\u540D\u524D(value) {
2797
+ if (typeof value !== "string") return null;
2798
+ const m = value.match(/^\{(\w+)/);
2799
+ return m ? m[1] : null;
2800
+ }
2801
+ function compileValueChart(doc, \u578B, kind, onNotice) {
1991
2802
  const b = diagram(slugify(doc.title), { topic: doc.title });
1992
2803
  const CHART_W = 640;
1993
- const CHART_H = 320;
1994
- b.lane("chart", { width: CHART_W + 64, label: doc.title });
2804
+ const CHART_H = \u578B === "pie" ? 320 : 368;
2805
+ b.lane("chart", { width: CHART_W + 64 });
1995
2806
  const data = [];
1996
2807
  const \u8AAD\u3081\u306A\u3044 = [];
2808
+ const \u672A\u5BA3\u8A00 = [];
2809
+ let \u672A\u5BA3\u8A00\u884C = 0;
2810
+ const \u53C2\u7167\u3067\u304D\u308B = \u6570\u306E\u6B04\u304B\u3089\u53C2\u7167\u3067\u304D\u308B\u540D\u524D(doc);
2811
+ let \u8AAD\u3081\u306A\u3044\u884C = 0;
1997
2812
  for (const a of doc.actors) {
1998
- const value = parseShareValue(a.value ?? a.subtitle);
1999
- if (value === null) {
2813
+ const value = parseChartValue(a.value ?? a.subtitle);
2814
+ if (value === null || typeof value === "number" && value < 0 && \u578B !== "line") {
2815
+ if (\u8AAD\u3081\u306A\u3044.length === 0) \u8AAD\u3081\u306A\u3044\u884C = a.pos?.line ?? 0;
2000
2816
  \u8AAD\u3081\u306A\u3044.push(a.name);
2001
2817
  continue;
2002
2818
  }
2819
+ const \u540D\u524D = \u53C2\u7167\u3059\u308B\u540D\u524D(value);
2820
+ if (\u540D\u524D !== null && !\u53C2\u7167\u3067\u304D\u308B.has(\u540D\u524D)) {
2821
+ if (\u672A\u5BA3\u8A00.length === 0) \u672A\u5BA3\u8A00\u884C = a.pos?.line ?? 0;
2822
+ \u672A\u5BA3\u8A00.push(a.name);
2823
+ continue;
2824
+ }
2003
2825
  data.push({ label: a.name, value, ...a.tone !== void 0 ? { tone: a.tone } : {} });
2004
2826
  }
2005
- if (\u8AAD\u3081\u306A\u3044.length > 0 && typeof console !== "undefined" && console.warn) {
2006
- console.warn(
2007
- `[dragon] type: pie \u3067\u5272\u5408\u3092\u8AAD\u3081\u306A\u3044\u9805\u76EE\u304C\u3042\u308A\u307E\u3059 (\u5186\u306B\u8F09\u305B\u307E\u305B\u3093): ${\u8AAD\u3081\u306A\u3044.join(", ")}\u3002 \`- \u540D\u524D: "45%"\` \u306E\u5F62\u3067\u66F8\u3044\u3066\u304F\u3060\u3055\u3044`
2827
+ const \u8A9E = \u578B === "pie" ? { \u91CF: "\u5272\u5408", \u56F3: "\u5186", \u4F8B: '"45%"' } : \u578B === "bar" ? { \u91CF: "\u5024", \u56F3: "\u68D2", \u4F8B: '"420"' } : { \u91CF: "\u5024", \u56F3: "\u6298\u308C\u7DDA", \u4F8B: '"180"' };
2828
+ const \u4F1D\u3048\u308B = (\u7A2E\u985E, \u540D\u524D, message, line = 0) => {
2829
+ onNotice?.({ kind: \u7A2E\u985E, actor: \u540D\u524D, line, message });
2830
+ if (typeof console !== "undefined" && console.warn) console.warn(`[dragon] ${message}`);
2831
+ };
2832
+ if (\u8AAD\u3081\u306A\u3044.length > 0) {
2833
+ \u4F1D\u3048\u308B(
2834
+ "chart-value-unreadable",
2835
+ \u8AAD\u3081\u306A\u3044[0],
2836
+ `type: ${\u578B} \u3067${\u8A9E.\u91CF}\u3092\u8AAD\u3081\u306A\u3044\u9805\u76EE\u304C\u3042\u308A\u307E\u3059 (${\u8A9E.\u56F3}\u306B\u8F09\u305B\u307E\u305B\u3093): ${\u8AAD\u3081\u306A\u3044.join(", ")}\u3002 \`- \u540D\u524D: ${\u8A9E.\u4F8B}\` \u306E\u5F62\u3067\u66F8\u3044\u3066\u304F\u3060\u3055\u3044`,
2837
+ \u8AAD\u3081\u306A\u3044\u884C
2008
2838
  );
2009
2839
  }
2010
- if (doc.flow.length > 0 && typeof console !== "undefined" && console.warn) {
2011
- console.warn(
2012
- `[dragon] type: pie \u3067\u306F\u77E2\u5370\u3092\u63CF\u3051\u307E\u305B\u3093 (${doc.flow.length} \u672C\u3092\u7121\u8996\u3057\u307E\u3057\u305F)\u3002 \u95A2\u4FC2\u3092\u63CF\u304F\u306A\u3089 type: flow \u3092\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044`
2840
+ if (\u672A\u5BA3\u8A00.length > 0) {
2841
+ \u4F1D\u3048\u308B(
2842
+ "chart-value-unreadable",
2843
+ \u672A\u5BA3\u8A00[0],
2844
+ `type: ${\u578B} \u3067\u6570\u306B\u306A\u3089\u306A\u3044\u5024\u3092\u53C2\u7167\u3057\u305F\u9805\u76EE\u304C\u3042\u308A\u307E\u3059 (${\u8A9E.\u56F3}\u306B\u8F09\u305B\u307E\u305B\u3093): ${\u672A\u5BA3\u8A00.join(", ")}\u3002 \`states:\` \u306B\u305D\u306E\u540D\u524D\u3092\u6570\u3067\u66F8\u3044\u3066\u304F\u3060\u3055\u3044`,
2845
+ \u672A\u5BA3\u8A00\u884C
2846
+ );
2847
+ }
2848
+ if (doc.flow.length > 0) {
2849
+ \u4F1D\u3048\u308B(
2850
+ "chart-edge-dropped",
2851
+ doc.flow[0]?.from ?? "",
2852
+ `type: ${\u578B} \u3067\u306F\u77E2\u5370\u3092\u63CF\u3051\u307E\u305B\u3093 (${doc.flow.length} \u672C\u3092\u7121\u8996\u3057\u307E\u3057\u305F)\u3002 \u95A2\u4FC2\u3092\u63CF\u304F\u306A\u3089 type: flow \u3092\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044`,
2853
+ doc.flow[0]?.pos?.line ?? 0
2013
2854
  );
2014
2855
  }
2015
2856
  b.node(`${slugify(doc.title)}-chart`, {
2016
2857
  lane: "chart",
2017
2858
  stack: 0,
2018
- kind: "chart-pie",
2859
+ kind,
2019
2860
  title: doc.title,
2861
+ ...\u56F3\u306E\u5C0F\u898B\u51FA\u3057(doc),
2020
2862
  w: CHART_W,
2021
2863
  h: CHART_H,
2022
2864
  chartData: data
2023
2865
  });
2024
2866
  return b.build();
2025
2867
  }
2868
+ var \u56F3\u8868\u306E\u5927\u304D\u3055 = {
2869
+ funnel: { w: 560, h: 480 },
2870
+ tree: { w: 720, h: 480 },
2871
+ mind: { w: 720, h: 480 },
2872
+ journey: { w: 720, h: 480 },
2873
+ quadrant: { w: 640, h: 480 }
2874
+ };
2875
+ var \u6C17\u6301\u3061 = /* @__PURE__ */ new Map([
2876
+ ["\u6700\u9AD8", "delighted"],
2877
+ ["\u6E80\u8DB3", "happy"],
2878
+ ["\u666E\u901A", "neutral"],
2879
+ ["\u4E0D\u6E80", "frustrated"],
2880
+ ["\u6012\u308A", "angry"]
2881
+ ]);
2882
+ var \u533A\u753B = /* @__PURE__ */ new Map([
2883
+ ["\u5DE6\u4E0A", "topLeft"],
2884
+ ["\u53F3\u4E0A", "topRight"],
2885
+ ["\u5DE6\u4E0B", "bottomLeft"],
2886
+ ["\u53F3\u4E0B", "bottomRight"]
2887
+ ]);
2888
+ function \u56F3\u8868\u306E\u6B04\u304B\u3089\u53C2\u7167\u3067\u304D\u308B\u540D\u524D(doc, \u6B04) {
2889
+ const \u5B9F\u52B9 = /* @__PURE__ */ new Map();
2890
+ for (const s of doc.animate?.states ?? []) \u5B9F\u52B9.set(s.name, s.initial);
2891
+ const \u58CA\u308C\u308B = /* @__PURE__ */ new Set();
2892
+ for (const p of doc.animate?.phases ?? []) {
2893
+ for (const st of p.sets ?? []) if (!\u6B04.\u8AAD\u3081\u308B\u304B(st.value)) \u58CA\u308C\u308B.add(st.state);
2894
+ if (\u6B04.\u88DC\u9593\u3067\u58CA\u308C\u308B\u304B) for (const tw of p.tweens ?? []) \u58CA\u308C\u308B.add(tw.state);
2895
+ }
2896
+ const out = /* @__PURE__ */ new Set();
2897
+ for (const [\u540D\u524D, \u5024] of \u5B9F\u52B9) {
2898
+ if (!\u6B04.\u8AAD\u3081\u308B\u304B(\u5024)) continue;
2899
+ if (\u58CA\u308C\u308B.has(\u540D\u524D)) continue;
2900
+ out.add(\u540D\u524D);
2901
+ }
2902
+ if (\u6B04.\u81EA\u52D5\u306E\u5024\u3092\u8A31\u3059\u304B) for (const v of doc.values ?? []) out.add(v.name);
2903
+ return out;
2904
+ }
2905
+ function \u6570\u3068\u3057\u3066\u8AAD\u3081\u308B\u304B(v) {
2906
+ if (typeof v === "number") return Number.isFinite(v);
2907
+ const t = v.trim();
2908
+ if (t === "") return false;
2909
+ return Number.isFinite(Number(t));
2910
+ }
2911
+ function \u6570\u306E\u6B04\u304B\u3089\u53C2\u7167\u3067\u304D\u308B\u540D\u524D(doc) {
2912
+ return \u56F3\u8868\u306E\u6B04\u304B\u3089\u53C2\u7167\u3067\u304D\u308B\u540D\u524D(doc, {
2913
+ \u8AAD\u3081\u308B\u304B: \u6570\u3068\u3057\u3066\u8AAD\u3081\u308B\u304B,
2914
+ // 補間の行き先は数なので、数の欄では壊れない
2915
+ \u88DC\u9593\u3067\u58CA\u308C\u308B\u304B: false,
2916
+ \u81EA\u52D5\u306E\u5024\u3092\u8A31\u3059\u304B: true
2917
+ });
2918
+ }
2919
+ function \u8A9E\u306E\u6B04\u304B\u3089\u53C2\u7167\u3067\u304D\u308B\u540D\u524D(doc, \u8A9E\u8868) {
2920
+ return \u56F3\u8868\u306E\u6B04\u304B\u3089\u53C2\u7167\u3067\u304D\u308B\u540D\u524D(doc, {
2921
+ \u8AAD\u3081\u308B\u304B: (v) => \u8A9E\u8868.has(String(v).trim()),
2922
+ // 補間の行き先は数。 語の欄が読む状態を補間すると、その段で語が数に変わる
2923
+ \u88DC\u9593\u3067\u58CA\u308C\u308B\u304B: true,
2924
+ // 式の評価結果は数になるため、語の欄からは読めない
2925
+ \u81EA\u52D5\u306E\u5024\u3092\u8A31\u3059\u304B: false
2926
+ });
2927
+ }
2928
+ function \u8A9E\u306E\u72B6\u614B\u3092\u56F3\u306E\u8A9E\u3078\u76F4\u3059(diagram2) {
2929
+ const \u5BFE\u8C61 = /* @__PURE__ */ new Map();
2930
+ const \u6570\u306E\u6B04\u304B\u3089 = /* @__PURE__ */ new Set();
2931
+ const \u62FE\u3046 = (v, \u8A9E\u8868) => {
2932
+ const m = typeof v === "string" ? v.match(/^\{(\w+)/) : null;
2933
+ if (m) \u5BFE\u8C61.set(m[1], \u8A9E\u8868);
2934
+ };
2935
+ for (const n of diagram2.nodes) {
2936
+ for (const st of n.journeyData ?? []) \u62FE\u3046(st.emotion, \u6C17\u6301\u3061);
2937
+ for (const it of n.quadrantData?.items ?? []) \u62FE\u3046(it.quadrant, \u533A\u753B);
2938
+ for (const d of n.chartData ?? []) {
2939
+ const m = typeof d.value === "string" ? d.value.match(/^\{(\w+)/) : null;
2940
+ if (m) \u6570\u306E\u6B04\u304B\u3089.add(m[1]);
2941
+ }
2942
+ for (const f of n.funnelData ?? []) {
2943
+ const m = typeof f.count === "string" ? f.count.match(/^\{(\w+)/) : null;
2944
+ if (m) \u6570\u306E\u6B04\u304B\u3089.add(m[1]);
2945
+ }
2946
+ }
2947
+ if (\u5BFE\u8C61.size === 0) return;
2948
+ const \u76F4\u3059 = (\u540D\u524D, \u5024) => {
2949
+ const \u8A9E\u8868 = \u5BFE\u8C61.get(\u540D\u524D);
2950
+ if (!\u8A9E\u8868 || \u6570\u306E\u6B04\u304B\u3089.has(\u540D\u524D)) return \u5024;
2951
+ return \u8A9E\u8868.get(String(\u5024).trim()) ?? \u5024;
2952
+ };
2953
+ for (const s of diagram2.states) s.initial = \u76F4\u3059(s.id, s.initial);
2954
+ for (const p of diagram2.phases) {
2955
+ for (const st of p.sets) st.value = \u76F4\u3059(st.stateId, st.value);
2956
+ }
2957
+ }
2958
+ function compileFunnel(doc, onNotice) {
2959
+ const b = diagram(slugify(doc.title), { topic: doc.title });
2960
+ const { w: W, h: H } = \u56F3\u8868\u306E\u5927\u304D\u3055.funnel;
2961
+ b.lane("chart", { width: W + 64 });
2962
+ const data = [];
2963
+ const \u8AAD\u3081\u306A\u3044 = [];
2964
+ const \u672A\u5BA3\u8A00 = [];
2965
+ const \u53C2\u7167\u3067\u304D\u308B = \u6570\u306E\u6B04\u304B\u3089\u53C2\u7167\u3067\u304D\u308B\u540D\u524D(doc);
2966
+ for (const a of doc.actors) {
2967
+ const v = parseChartValue(a.value ?? a.subtitle);
2968
+ if (v === null || typeof v === "number" && v < 0) {
2969
+ \u8AAD\u3081\u306A\u3044.push(a.name);
2970
+ continue;
2971
+ }
2972
+ const \u540D\u524D = \u53C2\u7167\u3059\u308B\u540D\u524D(v);
2973
+ if (\u540D\u524D !== null && !\u53C2\u7167\u3067\u304D\u308B.has(\u540D\u524D)) {
2974
+ \u672A\u5BA3\u8A00.push(a.name);
2975
+ continue;
2976
+ }
2977
+ data.push({ id: slugify(a.name), title: a.name, count: v });
2978
+ }
2979
+ if (\u672A\u5BA3\u8A00.length > 0) {
2980
+ const m3 = `type: funnel \u3067\u6570\u306B\u306A\u3089\u306A\u3044\u5024\u3092\u53C2\u7167\u3057\u305F\u9805\u76EE\u304C\u3042\u308A\u307E\u3059 (\u6BB5\u306B\u8F09\u305B\u307E\u305B\u3093): ${\u672A\u5BA3\u8A00.join(", ")}\u3002 \`states:\` \u306B\u305D\u306E\u540D\u524D\u3092\u6570\u3067\u66F8\u3044\u3066\u304F\u3060\u3055\u3044`;
2981
+ onNotice?.({ kind: "chart-value-unreadable", actor: \u672A\u5BA3\u8A00[0], line: 0, message: m3 });
2982
+ if (typeof console !== "undefined" && console.warn) console.warn(`[dragon] ${m3}`);
2983
+ }
2984
+ if (\u8AAD\u3081\u306A\u3044.length > 0) {
2985
+ const m = `type: funnel \u3067\u6570\u3092\u8AAD\u3081\u306A\u3044\u9805\u76EE\u304C\u3042\u308A\u307E\u3059 (\u6BB5\u306B\u8F09\u305B\u307E\u305B\u3093): ${\u8AAD\u3081\u306A\u3044.join(", ")}\u3002 \`- \u8A2A\u554F: "12000"\` \u306E\u5F62\u3067\u66F8\u3044\u3066\u304F\u3060\u3055\u3044`;
2986
+ onNotice?.({ kind: "chart-value-unreadable", actor: \u8AAD\u3081\u306A\u3044[0], line: 0, message: m });
2987
+ if (typeof console !== "undefined" && console.warn) console.warn(`[dragon] ${m}`);
2988
+ }
2989
+ if (doc.flow.length > 0) {
2990
+ const m2 = `type: funnel \u3067\u306F\u77E2\u5370\u3092\u63CF\u3051\u307E\u305B\u3093 (${doc.flow.length} \u672C\u3092\u7121\u8996\u3057\u307E\u3057\u305F)\u3002 \u95A2\u4FC2\u3092\u63CF\u304F\u306A\u3089 type: flow \u3092\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044`;
2991
+ onNotice?.({ kind: "chart-edge-dropped", actor: doc.flow[0]?.from ?? "", line: doc.flow[0]?.pos?.line ?? 0, message: m2 });
2992
+ if (typeof console !== "undefined" && console.warn) console.warn(`[dragon] ${m2}`);
2993
+ }
2994
+ b.node(`${slugify(doc.title)}-chart`, {
2995
+ lane: "chart",
2996
+ stack: 0,
2997
+ kind: "funnel-stages",
2998
+ title: doc.title,
2999
+ ...\u56F3\u306E\u5C0F\u898B\u51FA\u3057(doc),
3000
+ w: W,
3001
+ h: H,
3002
+ funnelData: data
3003
+ });
3004
+ return b.build();
3005
+ }
3006
+ function \u77E2\u5370\u304B\u3089\u89AA\u3092\u6C7A\u3081\u308B(doc, \u56F3\u7A2E, \u540D\u524D, \u4F1D\u3048\u308B) {
3007
+ const \u89AA = /* @__PURE__ */ new Map();
3008
+ for (const f of doc.flow) {
3009
+ const \u5B50 = slugify(f.to);
3010
+ const \u89AA\u540D = slugify(f.from);
3011
+ if (!\u540D\u524D.has(\u89AA\u540D)) {
3012
+ \u4F1D\u3048\u308B(f.from, `type: ${\u56F3\u7A2E} \u3067\u66F8\u3044\u3066\u3044\u306A\u3044\u540D\u524D\u3092\u89AA\u306B\u3057\u3066\u3044\u307E\u3059: ${f.from} -> ${f.to}`, f.pos?.line ?? 0);
3013
+ continue;
3014
+ }
3015
+ if (!\u540D\u524D.has(\u5B50)) {
3016
+ \u4F1D\u3048\u308B(f.to, `type: ${\u56F3\u7A2E} \u3067\u66F8\u3044\u3066\u3044\u306A\u3044\u540D\u524D\u3092\u5B50\u306B\u3057\u3066\u3044\u307E\u3059: ${f.from} -> ${f.to}`, f.pos?.line ?? 0);
3017
+ continue;
3018
+ }
3019
+ if (\u5B50 === \u89AA\u540D) {
3020
+ \u4F1D\u3048\u308B(f.to, `type: ${\u56F3\u7A2E} \u3067\u81EA\u5206\u3092\u89AA\u306B\u3057\u3066\u3044\u307E\u3059: ${f.to}`, f.pos?.line ?? 0);
3021
+ continue;
3022
+ }
3023
+ const \u65E2\u5B58 = \u89AA.get(\u5B50);
3024
+ if (\u65E2\u5B58 !== void 0 && \u65E2\u5B58 !== \u89AA\u540D) {
3025
+ \u4F1D\u3048\u308B(f.to, `type: ${\u56F3\u7A2E} \u3067 ${f.to} \u306B\u89AA\u304C 2 \u3064\u3042\u308A\u307E\u3059 (\u5F8C\u306E ${f.from} \u306F\u4F7F\u3044\u307E\u305B\u3093)`, f.pos?.line ?? 0);
3026
+ continue;
3027
+ }
3028
+ \u89AA.set(\u5B50, \u89AA\u540D);
3029
+ }
3030
+ for (const \u5B50 of [...\u89AA.keys()]) {
3031
+ const \u898B\u305F = /* @__PURE__ */ new Set([\u5B50]);
3032
+ let p2 = \u89AA.get(\u5B50);
3033
+ while (p2 !== void 0) {
3034
+ if (\u898B\u305F.has(p2)) {
3035
+ \u4F1D\u3048\u308B(\u5B50, `type: ${\u56F3\u7A2E} \u3067\u89AA\u3092\u8FBF\u308B\u3068\u8F2A\u306B\u306A\u308A\u307E\u3059 (${\u5B50} \u306E\u89AA\u3092\u5916\u3057\u307E\u3057\u305F)`);
3036
+ \u89AA.delete(\u5B50);
3037
+ break;
3038
+ }
3039
+ \u898B\u305F.add(p2);
3040
+ p2 = \u89AA.get(p2);
3041
+ }
3042
+ }
3043
+ return \u89AA;
3044
+ }
3045
+ function compileTree(doc, onNotice) {
3046
+ const b = diagram(slugify(doc.title), { topic: doc.title });
3047
+ const { w: W, h: H } = \u56F3\u8868\u306E\u5927\u304D\u3055.tree;
3048
+ b.lane("chart", { width: W + 64 });
3049
+ const slug\u5225 = /* @__PURE__ */ new Map();
3050
+ for (const a of doc.actors) {
3051
+ const k = slugify(a.name);
3052
+ slug\u5225.set(k, [...slug\u5225.get(k) ?? [], a.name]);
3053
+ }
3054
+ const \u540D\u524D = new Set(slug\u5225.keys());
3055
+ const \u4F1D\u3048\u308B = (\u540D, message, line = 0) => {
3056
+ onNotice?.({ kind: "chart-value-unreadable", actor: \u540D, line, message });
3057
+ if (typeof console !== "undefined" && console.warn) console.warn(`[dragon] ${message}`);
3058
+ };
3059
+ for (const [k, \u7FA4] of slug\u5225) {
3060
+ if (\u7FA4.length > 1) {
3061
+ \u4F1D\u3048\u308B(\u7FA4[0], `type: tree \u3067 ${\u7FA4.join(" / ")} \u304C\u540C\u3058 id (${k}) \u306B\u306A\u308A\u307E\u3059\u3002 \u540D\u524D\u3092\u5909\u3048\u3066\u304F\u3060\u3055\u3044`);
3062
+ }
3063
+ }
3064
+ const \u89AA = \u77E2\u5370\u304B\u3089\u89AA\u3092\u6C7A\u3081\u308B(doc, "tree", \u540D\u524D, \u4F1D\u3048\u308B);
3065
+ const data = doc.actors.map((a) => {
3066
+ const id = slugify(a.name);
3067
+ const p3 = \u89AA.get(id);
3068
+ return { id, title: a.name, ...p3 !== void 0 ? { parent: p3 } : {} };
3069
+ });
3070
+ b.node(`${slugify(doc.title)}-chart`, {
3071
+ lane: "chart",
3072
+ stack: 0,
3073
+ kind: "tree-hierarchy",
3074
+ title: doc.title,
3075
+ ...\u56F3\u306E\u5C0F\u898B\u51FA\u3057(doc),
3076
+ w: W,
3077
+ h: H,
3078
+ treeData: data
3079
+ });
3080
+ return b.build();
3081
+ }
3082
+ function \u9053\u7B4B\u306E\u6B04(a) {
3083
+ return {
3084
+ ...a.touchpoint !== void 0 ? { touchpoint: a.touchpoint } : {},
3085
+ ...a.opportunity !== void 0 ? { opportunity: a.opportunity } : {}
3086
+ };
3087
+ }
3088
+ function reportChartFieldsNotHonored(doc, onNotice) {
3089
+ if (!onNotice) return;
3090
+ if (doc.type === "mind") return;
3091
+ for (const a of doc.actors) {
3092
+ if (a.partId !== void 0) continue;
3093
+ const \u9053\u7B4B = doc.type === "journey" ? [] : [
3094
+ ...a.touchpoint !== void 0 ? ["touchpoint"] : [],
3095
+ ...a.opportunity !== void 0 ? ["opportunity"] : []
3096
+ ];
3097
+ const \u5DE5\u7A0B = doc.type === "gantt" ? [] : [
3098
+ ...a.owner !== void 0 ? ["owner"] : [],
3099
+ ...a.end !== void 0 ? ["end"] : []
3100
+ ];
3101
+ if (\u9053\u7B4B.length > 0) {
3102
+ onNotice({
3103
+ kind: "chart-value-unreadable",
3104
+ actor: a.name,
3105
+ line: a.pos?.line ?? 0,
3106
+ message: `"${truncateForMessage(a.name)}" \u306B\u66F8\u3044\u305F ${\u9053\u7B4B.join(" / ")} \u306F\u52B9\u304D\u307E\u305B\u3093 (type: ${doc.type} \u306B\u306F\u4F53\u9A13\u306E\u9053\u7B4B\u306E\u6B04\u304C\u3042\u308A\u307E\u305B\u3093)`,
3107
+ hint: "\u4F53\u9A13\u306E\u9053\u7B4B\u3092\u63CF\u304F\u306A\u3089 type: journey \u3092\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044"
3108
+ });
3109
+ }
3110
+ if (\u5DE5\u7A0B.length > 0) {
3111
+ onNotice({
3112
+ kind: "chart-value-unreadable",
3113
+ actor: a.name,
3114
+ line: a.pos?.line ?? 0,
3115
+ message: `"${truncateForMessage(a.name)}" \u306B\u66F8\u3044\u305F ${\u5DE5\u7A0B.join(" / ")} \u306F\u52B9\u304D\u307E\u305B\u3093 (type: ${doc.type} \u306B\u306F\u5DE5\u7A0B\u306E\u4E26\u3073\u306E\u6B04\u304C\u3042\u308A\u307E\u305B\u3093)`,
3116
+ hint: "\u5DE5\u7A0B\u306E\u4E26\u3073\u3092\u63CF\u304F\u306A\u3089 type: gantt \u3092\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044"
3117
+ });
3118
+ }
3119
+ }
3120
+ }
3121
+ function compileJourney(doc, onNotice) {
3122
+ const b = diagram(slugify(doc.title), { topic: doc.title });
3123
+ const { w: W, h: H } = \u56F3\u8868\u306E\u5927\u304D\u3055.journey;
3124
+ b.lane("chart", { width: W + 64 });
3125
+ const data = [];
3126
+ const \u8AAD\u3081\u306A\u3044 = [];
3127
+ const \u53C2\u7167\u3067\u304D\u308B = \u8A9E\u306E\u6B04\u304B\u3089\u53C2\u7167\u3067\u304D\u308B\u540D\u524D(doc, \u6C17\u6301\u3061);
3128
+ for (const a of doc.actors) {
3129
+ const \u8A9E = (a.value ?? a.subtitle ?? "").trim();
3130
+ const \u53C2\u7167 = \u8A9E.match(/^\{(\w+)\}$/);
3131
+ if (\u53C2\u7167) {
3132
+ if (!\u53C2\u7167\u3067\u304D\u308B.has(\u53C2\u7167[1])) {
3133
+ \u8AAD\u3081\u306A\u3044.push(a.name);
3134
+ continue;
3135
+ }
3136
+ data.push({ id: slugify(a.name), title: a.name, emotion: \u8A9E, ...\u9053\u7B4B\u306E\u6B04(a) });
3137
+ continue;
3138
+ }
3139
+ const e = \u6C17\u6301\u3061.get(\u8A9E);
3140
+ if (e === void 0) {
3141
+ \u8AAD\u3081\u306A\u3044.push(a.name);
3142
+ continue;
3143
+ }
3144
+ data.push({ id: slugify(a.name), title: a.name, emotion: e, ...\u9053\u7B4B\u306E\u6B04(a) });
3145
+ }
3146
+ if (\u8AAD\u3081\u306A\u3044.length > 0) {
3147
+ const m = `type: journey \u3067\u6C17\u6301\u3061\u3092\u8AAD\u3081\u306A\u3044\u9805\u76EE\u304C\u3042\u308A\u307E\u3059 (\u9053\u7B4B\u306B\u8F09\u305B\u307E\u305B\u3093): ${\u8AAD\u3081\u306A\u3044.join(", ")}\u3002 \`- \u767B\u9332: "\u4E0D\u6E80"\` \u306E\u5F62\u3067\u3001 ${[...\u6C17\u6301\u3061.keys()].join(" / ")} \u306E\u3069\u308C\u304B\u3092\u66F8\u3044\u3066\u304F\u3060\u3055\u3044`;
3148
+ onNotice?.({ kind: "chart-value-unreadable", actor: \u8AAD\u3081\u306A\u3044[0], line: 0, message: m });
3149
+ if (typeof console !== "undefined" && console.warn) console.warn(`[dragon] ${m}`);
3150
+ }
3151
+ if (doc.flow.length > 0) {
3152
+ const m2 = `type: journey \u3067\u306F\u77E2\u5370\u3092\u63CF\u3051\u307E\u305B\u3093 (${doc.flow.length} \u672C\u3092\u7121\u8996\u3057\u307E\u3057\u305F)\u3002 \u95A2\u4FC2\u3092\u63CF\u304F\u306A\u3089 type: flow \u3092\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044`;
3153
+ onNotice?.({ kind: "chart-edge-dropped", actor: doc.flow[0]?.from ?? "", line: doc.flow[0]?.pos?.line ?? 0, message: m2 });
3154
+ if (typeof console !== "undefined" && console.warn) console.warn(`[dragon] ${m2}`);
3155
+ }
3156
+ b.node(`${slugify(doc.title)}-chart`, {
3157
+ lane: "chart",
3158
+ stack: 0,
3159
+ kind: "journey-map",
3160
+ title: doc.title,
3161
+ ...\u56F3\u306E\u5C0F\u898B\u51FA\u3057(doc),
3162
+ w: W,
3163
+ h: H,
3164
+ journeyData: data
3165
+ });
3166
+ return b.build();
3167
+ }
3168
+ var \u8EF8\u306E\u65E2\u5B9A = {
3169
+ xAxis: { left: "\u5C0F\u3055\u3044", right: "\u5927\u304D\u3044" },
3170
+ yAxis: { bottom: "\u5C0F\u3055\u3044", top: "\u5927\u304D\u3044" },
3171
+ quadrantLabels: { topLeft: "\u5DE6\u4E0A", topRight: "\u53F3\u4E0A", bottomLeft: "\u5DE6\u4E0B", bottomRight: "\u53F3\u4E0B" }
3172
+ };
3173
+ function \u8EF8\u3068\u533A\u753B\u306E\u540D\u524D(doc) {
3174
+ if (doc.axes === void 0) return \u8EF8\u306E\u65E2\u5B9A;
3175
+ const left = doc.axes.x?.left ?? \u8EF8\u306E\u65E2\u5B9A.xAxis.left;
3176
+ const right = doc.axes.x?.right ?? \u8EF8\u306E\u65E2\u5B9A.xAxis.right;
3177
+ const bottom = doc.axes.y?.bottom ?? \u8EF8\u306E\u65E2\u5B9A.yAxis.bottom;
3178
+ const top = doc.axes.y?.top ?? \u8EF8\u306E\u65E2\u5B9A.yAxis.top;
3179
+ return {
3180
+ xAxis: { left, right },
3181
+ yAxis: { bottom, top },
3182
+ quadrantLabels: {
3183
+ topLeft: `${top} \xD7 ${left}`,
3184
+ topRight: `${top} \xD7 ${right}`,
3185
+ bottomLeft: `${bottom} \xD7 ${left}`,
3186
+ bottomRight: `${bottom} \xD7 ${right}`
3187
+ }
3188
+ };
3189
+ }
3190
+ function reportAxesNotHonored(doc, onNotice) {
3191
+ if (!onNotice) return;
3192
+ if (doc.axes === void 0) return;
3193
+ if (doc.type === "quadrant") return;
3194
+ onNotice({
3195
+ kind: "chart-value-unreadable",
3196
+ actor: doc.title,
3197
+ line: doc.axesPos?.line ?? doc.pos?.line ?? 0,
3198
+ message: `\u6700\u4E0A\u4F4D\u306B\u66F8\u3044\u305F axes \u306F\u52B9\u304D\u307E\u305B\u3093 (type: ${doc.type} \u306B\u306F\u8EF8\u304C\u3042\u308A\u307E\u305B\u3093)`,
3199
+ hint: "2 \u3064\u306E\u8EF8\u3067\u4ED5\u5206\u3051\u308B\u56F3\u3092\u63CF\u304F\u306A\u3089 type: quadrant \u3092\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044"
3200
+ });
3201
+ }
3202
+ function compileQuadrant(doc, onNotice) {
3203
+ const b = diagram(slugify(doc.title), { topic: doc.title });
3204
+ const { w: W, h: H } = \u56F3\u8868\u306E\u5927\u304D\u3055.quadrant;
3205
+ b.lane("chart", { width: W + 64 });
3206
+ const items = [];
3207
+ const \u8AAD\u3081\u306A\u3044 = [];
3208
+ const \u53C2\u7167\u3067\u304D\u308B = \u8A9E\u306E\u6B04\u304B\u3089\u53C2\u7167\u3067\u304D\u308B\u540D\u524D(doc, \u533A\u753B);
3209
+ for (const a of doc.actors) {
3210
+ const \u8A9E = (a.value ?? a.subtitle ?? "").trim();
3211
+ const \u53C2\u7167 = \u8A9E.match(/^\{(\w+)\}$/);
3212
+ if (\u53C2\u7167) {
3213
+ if (!\u53C2\u7167\u3067\u304D\u308B.has(\u53C2\u7167[1])) {
3214
+ \u8AAD\u3081\u306A\u3044.push(a.name);
3215
+ continue;
3216
+ }
3217
+ items.push({ id: slugify(a.name), title: a.name, quadrant: \u8A9E });
3218
+ continue;
3219
+ }
3220
+ const q = \u533A\u753B.get(\u8A9E);
3221
+ if (q === void 0) {
3222
+ \u8AAD\u3081\u306A\u3044.push(a.name);
3223
+ continue;
3224
+ }
3225
+ items.push({ id: slugify(a.name), title: a.name, quadrant: q });
3226
+ }
3227
+ if (\u8AAD\u3081\u306A\u3044.length > 0) {
3228
+ const m = `type: quadrant \u3067\u533A\u753B\u3092\u8AAD\u3081\u306A\u3044\u9805\u76EE\u304C\u3042\u308A\u307E\u3059 (\u56F3\u306B\u8F09\u305B\u307E\u305B\u3093): ${\u8AAD\u3081\u306A\u3044.join(", ")}\u3002 \`- \u91CD\u8907\u524A\u9664: "\u5DE6\u4E0A"\` \u306E\u5F62\u3067\u3001 ${[...\u533A\u753B.keys()].join(" / ")} \u306E\u3069\u308C\u304B\u3092\u66F8\u3044\u3066\u304F\u3060\u3055\u3044`;
3229
+ onNotice?.({ kind: "chart-value-unreadable", actor: \u8AAD\u3081\u306A\u3044[0], line: 0, message: m });
3230
+ if (typeof console !== "undefined" && console.warn) console.warn(`[dragon] ${m}`);
3231
+ }
3232
+ if (doc.flow.length > 0) {
3233
+ const m2 = `type: quadrant \u3067\u306F\u77E2\u5370\u3092\u63CF\u3051\u307E\u305B\u3093 (${doc.flow.length} \u672C\u3092\u7121\u8996\u3057\u307E\u3057\u305F)\u3002 \u95A2\u4FC2\u3092\u63CF\u304F\u306A\u3089 type: flow \u3092\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044`;
3234
+ onNotice?.({ kind: "chart-edge-dropped", actor: doc.flow[0]?.from ?? "", line: doc.flow[0]?.pos?.line ?? 0, message: m2 });
3235
+ if (typeof console !== "undefined" && console.warn) console.warn(`[dragon] ${m2}`);
3236
+ }
3237
+ b.node(`${slugify(doc.title)}-chart`, {
3238
+ lane: "chart",
3239
+ stack: 0,
3240
+ kind: "quadrant-matrix",
3241
+ title: doc.title,
3242
+ ...\u56F3\u306E\u5C0F\u898B\u51FA\u3057(doc),
3243
+ w: W,
3244
+ h: H,
3245
+ quadrantData: { ...\u8EF8\u3068\u533A\u753B\u306E\u540D\u524D(doc), items }
3246
+ });
3247
+ return b.build();
3248
+ }
2026
3249
  function \u6BB5\u3092\u8AAD\u307F\u53D6\u308B(subtitle) {
2027
3250
  const \u5143 = (subtitle ?? "").trim();
2028
3251
  const m = \u5143.match(/^L([123])(?![0-9A-Za-z])/i);
@@ -2074,74 +3297,196 @@ function compileC4(doc) {
2074
3297
  }
2075
3298
  return b.build();
2076
3299
  }
2077
- function compileMind(doc) {
3300
+ var \u653E\u5C04\u3067\u63CF\u3051\u306A\u3044\u6B04\u306E\u540D\u524D = {
3301
+ kind: "\u7A2E\u985E",
3302
+ eyebrow: "\u4E0A\u306E\u5C0F\u898B\u51FA\u3057",
3303
+ touchpoint: "\u5834\u6240 (\u4F53\u9A13\u306E\u9053\u7B4B\u306E\u6B04)",
3304
+ opportunity: "\u6539\u5584\u306E\u4F59\u5730 (\u4F53\u9A13\u306E\u9053\u7B4B\u306E\u6B04)",
3305
+ owner: "\u62C5\u5F53 (\u5DE5\u7A0B\u306E\u4E26\u3073\u306E\u6B04)",
3306
+ end: "\u7D42\u308F\u308B\u6642\u671F (\u5DE5\u7A0B\u306E\u4E26\u3073\u306E\u6B04)",
3307
+ rows: "\u884C",
3308
+ lane: "\u67A0\u306E\u6307\u5B9A",
3309
+ stack: "\u7A4D\u3080\u9806",
3310
+ initial: "\u59CB\u307E\u308A / \u7D42\u308F\u308A \u306E\u5370",
3311
+ final: "\u59CB\u307E\u308A / \u7D42\u308F\u308A \u306E\u5370",
3312
+ colorHex: "\u8272\u756A\u53F7",
3313
+ stateOverride: "\u72B6\u614B\u306E\u4E0A\u66F8\u304D",
3314
+ // 位置は「登場人物ごとの箱をどこに置くか」 の指定で、 箱が 1 つの図では置く先が無い
3315
+ posX: "\u4F4D\u7F6E (\u5EA7\u6A19)",
3316
+ posY: "\u4F4D\u7F6E (\u5EA7\u6A19)",
3317
+ posW: "\u5927\u304D\u3055",
3318
+ posH: "\u5927\u304D\u3055",
3319
+ scale: "\u500D\u7387",
3320
+ scaleKeys: "\u500D\u7387",
3321
+ posRel: "\u4F4D\u7F6E (\u76F8\u5BFE)",
3322
+ nodes: "\u4E2D\u306E\u7BB1\u3054\u3068\u306E\u6307\u5B9A",
3323
+ layoutPos: "\u914D\u7F6E\u306E\u305A\u3089\u3057"
3324
+ };
3325
+ function \u653E\u5C04\u3067\u63CF\u3051\u306A\u3044\u6B04\u3092\u66F8\u3044\u305F\u304B(a, \u6B04) {
3326
+ if (\u6B04 === "kind") return a.kindWritten === true;
3327
+ const v = a[\u6B04];
3328
+ if (typeof v === "boolean") return v;
3329
+ return v !== void 0;
3330
+ }
3331
+ function \u653E\u5C04\u306B\u51FA\u3059\u6587\u5B57(a) {
3332
+ const \u7D9A\u304D = [a.subtitle, a.value].map((x) => x?.trim()).filter((x) => !!x);
3333
+ return \u7D9A\u304D.length > 0 ? `${a.name} ${\u7D9A\u304D.join(" ")}` : a.name;
3334
+ }
3335
+ function compileMind(doc, onNotice) {
2078
3336
  const b = diagram(slugify(doc.title), { topic: doc.title });
2079
- const LEAF_W = 280;
2080
- const ROOT_W = 320;
2081
- const GAP = 80;
2082
- const \u679D\u306E\u6570 = Math.max(0, doc.actors.length - 1);
2083
- const \u5DE6\u306B\u7F6E\u304F\u6570 = Math.ceil(\u679D\u306E\u6570 / 2);
2084
- const \u53F3\u306B\u7F6E\u304F\u6570 = \u679D\u306E\u6570 - \u5DE6\u306B\u7F6E\u304F\u6570;
2085
- const \u5DE6\u3092\u4F7F\u3046 = \u5DE6\u306B\u7F6E\u304F\u6570 > 0;
2086
- const \u53F3\u3092\u4F7F\u3046 = \u53F3\u306B\u7F6E\u304F\u6570 > 0;
2087
- if (doc.actors.length === 0) return b.build();
2088
- let x = 0;
2089
- if (\u5DE6\u3092\u4F7F\u3046) {
2090
- b.lane("mind-left", { x, width: LEAF_W, label: "" });
2091
- x += LEAF_W + GAP;
2092
- }
2093
- b.lane("mind-center", { x, width: ROOT_W, label: doc.title });
2094
- x += ROOT_W + GAP;
2095
- if (\u53F3\u3092\u4F7F\u3046) {
2096
- b.lane("mind-right", { x, width: LEAF_W, label: "" });
3337
+ const { w: W, h: H } = \u56F3\u8868\u306E\u5927\u304D\u3055.mind;
3338
+ const \u4F1D\u3048\u308B = (kind, \u540D, message, line = 0) => {
3339
+ onNotice?.({ kind, actor: \u540D, line, message });
3340
+ if (typeof console !== "undefined" && console.warn) console.warn(`[dragon] ${message}`);
3341
+ };
3342
+ const \u898B\u672C\u3067\u306A\u3044 = [];
3343
+ for (const a of doc.actors) {
3344
+ if (a.partId !== void 0) {
3345
+ \u4F1D\u3048\u308B(
3346
+ "part-not-drawn",
3347
+ a.name,
3348
+ `type: mind \u3067\u306F\u898B\u672C (${a.partId}) \u3092\u4E2D\u5FC3\u306B\u3082\u679D\u306B\u3082\u3067\u304D\u307E\u305B\u3093\u3002 \u898B\u672C\u306F\u305D\u306E\u307E\u307E\u63CF\u304D\u3001 \u653E\u5C04\u306B\u306F\u8F09\u305B\u307E\u305B\u3093`,
3349
+ a.pos?.line ?? 0
3350
+ );
3351
+ continue;
3352
+ }
3353
+ \u898B\u672C\u3067\u306A\u3044.push(a);
3354
+ }
3355
+ const \u679D\u306E\u540D\u524D = new Set(\u898B\u672C\u3067\u306A\u3044.map((a) => slugify(a.name)));
3356
+ const \u89AA = \u77E2\u5370\u304B\u3089\u89AA\u3092\u6C7A\u3081\u308B(
3357
+ doc,
3358
+ "mind",
3359
+ \u679D\u306E\u540D\u524D,
3360
+ (\u540D, message, line) => (
3361
+ // 親にできなかった矢印は描かれない。 知らせの種別も「矢印を落とした」 にする
3362
+ \u4F1D\u3048\u308B("chart-edge-dropped", \u540D, message, line ?? 0)
3363
+ )
3364
+ );
3365
+ if (\u898B\u672C\u3067\u306A\u3044.length === 0) return b.build();
3366
+ b.lane("chart", { width: W + 64 });
3367
+ const slug\u5225 = /* @__PURE__ */ new Map();
3368
+ for (const a of \u898B\u672C\u3067\u306A\u3044) {
3369
+ const k = slugify(a.name);
3370
+ slug\u5225.set(k, [...slug\u5225.get(k) ?? [], a.name]);
3371
+ }
3372
+ for (const [k, \u7FA4] of slug\u5225) {
3373
+ if (\u7FA4.length > 1) {
3374
+ \u4F1D\u3048\u308B(
3375
+ "chart-value-unreadable",
3376
+ \u7FA4[0],
3377
+ `type: mind \u3067 ${\u7FA4.join(" / ")} \u304C\u540C\u3058 id (${k}) \u306B\u306A\u308A\u307E\u3059\u3002 \u540D\u524D\u3092\u5909\u3048\u3066\u304F\u3060\u3055\u3044`
3378
+ );
3379
+ }
2097
3380
  }
2098
- const root = doc.actors[0];
3381
+ const root = \u898B\u672C\u3067\u306A\u3044[0];
2099
3382
  const rootId = slugify(root.name);
2100
- const leafCount = doc.actors.length - 1;
2101
- const rootStack = Math.floor(leafCount / 2);
2102
- b.node(rootId, {
2103
- lane: "mind-center",
2104
- stack: rootStack,
2105
- kind: "card",
2106
- title: root.name,
2107
- w: ROOT_W
2108
- });
2109
- const stackLeft = { v: 0 };
2110
- const stackRight = { v: 0 };
2111
- doc.actors.slice(1).forEach((a, i) => {
2112
- const isLeft = i % 2 === 0;
2113
- const lid = isLeft ? "mind-left" : "mind-right";
2114
- const counter = isLeft ? stackLeft : stackRight;
2115
- const nodeId = slugify(a.name);
2116
- b.node(nodeId, {
2117
- lane: lid,
2118
- stack: counter.v,
2119
- kind: "card",
2120
- title: a.name,
2121
- w: LEAF_W
3383
+ for (const f of doc.flow) {
3384
+ if (slugify(f.to) !== rootId) continue;
3385
+ \u4F1D\u3048\u308B(
3386
+ "chart-edge-dropped",
3387
+ f.to,
3388
+ `type: mind \u3067\u4E2D\u5FC3 (${truncateForMessage(f.to)}) \u3092\u5B50\u306B\u306F\u3067\u304D\u307E\u305B\u3093 (${truncateForMessage(f.from)} -> ${truncateForMessage(f.to)} \u3092\u4F7F\u3044\u307E\u305B\u3093)\u3002 \u4E2D\u5FC3\u306F\u653E\u5C04\u306E\u771F\u3093\u4E2D\u306B\u7F6E\u304F 1 \u3064\u3060\u3051\u3067\u3059`,
3389
+ f.pos?.line ?? 0
3390
+ );
3391
+ }
3392
+ const \u63CF\u3051\u306A\u3044\u6B04 = (a) => {
3393
+ const out = [];
3394
+ for (const \u6B04 of Object.keys(\u653E\u5C04\u3067\u63CF\u3051\u306A\u3044\u6B04\u306E\u540D\u524D)) {
3395
+ if (!\u653E\u5C04\u3067\u63CF\u3051\u306A\u3044\u6B04\u3092\u66F8\u3044\u305F\u304B(a, \u6B04)) continue;
3396
+ const \u540D\u524D = \u653E\u5C04\u3067\u63CF\u3051\u306A\u3044\u6B04\u306E\u540D\u524D[\u6B04];
3397
+ if (!out.includes(\u540D\u524D)) out.push(\u540D\u524D);
3398
+ }
3399
+ return out;
3400
+ };
3401
+ const \u6D88\u3048\u305F\u6B04 = /* @__PURE__ */ new Map();
3402
+ const \u8A18\u9332\u3059\u308B = (a) => {
3403
+ const \u6B04 = \u63CF\u3051\u306A\u3044\u6B04(a);
3404
+ if (\u6B04.length > 0) \u6D88\u3048\u305F\u6B04.set(a.name, \u6B04);
3405
+ };
3406
+ const branches = [];
3407
+ const \u4F7F\u3063\u305F = /* @__PURE__ */ new Set([rootId]);
3408
+ \u8A18\u9332\u3059\u308B(root);
3409
+ if (root.tone) \u6D88\u3048\u305F\u6B04.set(root.name, [...\u6D88\u3048\u305F\u6B04.get(root.name) ?? [], "\u8272 (\u4E2D\u5FC3\u306F\u6301\u3066\u306A\u3044)"]);
3410
+ \u898B\u672C\u3067\u306A\u3044.slice(1).forEach((a, i) => {
3411
+ const id = slugify(a.name);
3412
+ if (\u4F7F\u3063\u305F.has(id)) {
3413
+ \u4F1D\u3048\u308B(
3414
+ "chart-value-unreadable",
3415
+ a.name,
3416
+ `type: mind \u3067 ${a.name} \u304C\u65E2\u306B\u3042\u308B id (${id}) \u3068\u91CD\u306A\u308A\u307E\u3059 (\u679D\u306B\u8F09\u305B\u307E\u305B\u3093)`,
3417
+ a.pos?.line ?? 0
3418
+ );
3419
+ return;
3420
+ }
3421
+ \u4F7F\u3063\u305F.add(id);
3422
+ \u8A18\u9332\u3059\u308B(a);
3423
+ branches.push({
3424
+ id,
3425
+ title: \u653E\u5C04\u306B\u51FA\u3059\u6587\u5B57(a),
3426
+ parent: \u89AA.get(id) ?? rootId,
3427
+ ...a.tone ? { tone: a.tone } : {}
2122
3428
  });
2123
- counter.v += 1;
2124
3429
  });
2125
- if (doc.flow.length === 0 && doc.actors.length > 1) {
2126
- doc.actors.slice(1).forEach((a) => {
2127
- const leafId = slugify(a.name);
2128
- b.edge(rootId, leafId, { label: "" });
2129
- });
2130
- } else {
2131
- for (const s of doc.flow) {
2132
- const fromId = slugify(s.from);
2133
- const toId = slugify(s.to);
2134
- b.edge(fromId, toId, {
2135
- label: s.label,
2136
- ...s.sub ? { sub: s.sub } : {},
2137
- ...s.tone ? { tone: s.tone } : {},
2138
- ...s.style ? { style: s.style } : {}
2139
- });
2140
- }
3430
+ if (\u6D88\u3048\u305F\u6B04.size > 0) {
3431
+ const \u4E00\u89A7 = [...\u6D88\u3048\u305F\u6B04].map(([\u540D, \u6B04]) => `${\u540D} \u306E${\u6B04.join(" / ")}`).join("\u3001 ");
3432
+ \u4F1D\u3048\u308B(
3433
+ "chart-value-unreadable",
3434
+ [...\u6D88\u3048\u305F\u6B04.keys()][0],
3435
+ `type: mind \u306F\u540D\u524D\u3068\u526F\u984C / \u5024\u3001 \u679D\u306E\u8272\u3057\u304B\u63CF\u3051\u307E\u305B\u3093 (\u63CF\u304B\u306A\u3044\u6B04: ${\u4E00\u89A7})\u3002 \u3053\u308C\u3089\u3092\u63CF\u304F\u306A\u3089 type: tree \u304B type: flow \u3092\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044`
3436
+ );
2141
3437
  }
3438
+ b.node(`${slugify(doc.title)}-chart`, {
3439
+ lane: "chart",
3440
+ stack: 0,
3441
+ kind: "mind-map",
3442
+ title: doc.title,
3443
+ ...\u56F3\u306E\u5C0F\u898B\u51FA\u3057(doc),
3444
+ w: W,
3445
+ h: H,
3446
+ mindData: { rootId, rootTitle: \u653E\u5C04\u306B\u51FA\u3059\u6587\u5B57(root), branches }
3447
+ });
2142
3448
  return b.build();
2143
3449
  }
2144
- function applyV05Extensions(diagram2, doc) {
3450
+ function mergeDuplicateDeclaredLanes(diagram2, \u8FFD\u52A0\u3057\u305F\u7E26\u5217) {
3451
+ for (const \u5BA3\u8A00 of \u8FFD\u52A0\u3057\u305F\u7E26\u5217) {
3452
+ const { id } = \u5BA3\u8A00;
3453
+ const \u540C\u4E00id\u306E\u7E26\u5217 = diagram2.lanes.filter((l) => l.id === id);
3454
+ if (\u540C\u4E00id\u306E\u7E26\u5217.length < 2) continue;
3455
+ const \u6B8B\u3059 = \u540C\u4E00id\u306E\u7E26\u5217.at(-1);
3456
+ if (\u6B8B\u3059 === void 0) continue;
3457
+ const \u5143\u306E\u4E2D\u5FC3X = (\u6B8B\u3059.x ?? 0) + \u6B8B\u3059.width / 2;
3458
+ if (\u5BA3\u8A00.x !== void 0) \u6B8B\u3059.x = \u5BA3\u8A00.x;
3459
+ if (\u5BA3\u8A00.width !== void 0) \u6B8B\u3059.width = \u5BA3\u8A00.width;
3460
+ if (\u5BA3\u8A00.label !== void 0) \u6B8B\u3059.label = \u5BA3\u8A00.label;
3461
+ if (\u5BA3\u8A00.contain !== void 0) \u6B8B\u3059.contain = \u5BA3\u8A00.contain;
3462
+ if (\u5BA3\u8A00.lifeline !== void 0) \u6B8B\u3059.lifeline = \u5BA3\u8A00.lifeline;
3463
+ const \u79FB\u52D5X = (\u6B8B\u3059.x ?? 0) + \u6B8B\u3059.width / 2 - \u5143\u306E\u4E2D\u5FC3X;
3464
+ for (const node of diagram2.nodes) {
3465
+ if (node.lane === id && node.posX !== void 0) node.posX += \u79FB\u52D5X;
3466
+ }
3467
+ for (let i = diagram2.lanes.length - 1; i >= 0; i -= 1) {
3468
+ if (diagram2.lanes[i]?.id === id && diagram2.lanes[i] !== \u6B8B\u3059) diagram2.lanes.splice(i, 1);
3469
+ }
3470
+ }
3471
+ }
3472
+ function reportEmptyDeclaredLanes(diagram2, \u8FFD\u52A0\u3057\u305F\u7E26\u5217, onNotice) {
3473
+ if (\u8FFD\u52A0\u3057\u305F\u7E26\u5217.length === 0) return;
3474
+ mergeDuplicateDeclaredLanes(diagram2, \u8FFD\u52A0\u3057\u305F\u7E26\u5217);
3475
+ if (!onNotice) return;
3476
+ const \u4F7F\u308F\u308C\u3066\u3044\u308B = new Set(diagram2.nodes.map((n) => n.lane));
3477
+ const \u3042\u308B\u7E26\u5217 = diagram2.lanes.map((l) => l.id).filter((x) => \u4F7F\u308F\u308C\u3066\u3044\u308B.has(x));
3478
+ for (const { id, pos } of \u8FFD\u52A0\u3057\u305F\u7E26\u5217) {
3479
+ if (\u4F7F\u308F\u308C\u3066\u3044\u308B.has(id)) continue;
3480
+ onNotice({
3481
+ kind: "lane-declared-empty",
3482
+ actor: id,
3483
+ line: pos?.line ?? 0,
3484
+ message: `lanes \u306B\u66F8\u3044\u305F ${truncateForMessage(id)} \u306F\u3069\u306E\u7BB1\u3082\u5165\u3089\u306A\u3044\u7E26\u5217\u3067\u3059 (\u65B0\u3057\u304F\u4F5C\u308A\u307E\u3057\u305F)`,
3485
+ hint: \u3042\u308B\u7E26\u5217.length > 0 ? `\u3053\u306E\u56F3\u304C\u6301\u3064\u7E26\u5217 = ${\u3042\u308B\u7E26\u5217.join(" / ")}` : "\u3053\u306E\u56F3\u306F\u7BB1\u306E\u5165\u3063\u305F\u7E26\u5217\u3092\u6301\u3061\u307E\u305B\u3093"
3486
+ });
3487
+ }
3488
+ }
3489
+ function applyV05Extensions(diagram2, doc, \u8FFD\u52A0\u3057\u305F\u7E26\u5217out) {
2145
3490
  const isSeqLike = doc.type === "sequence" || doc.type === "solidity";
2146
3491
  for (const a of doc.actors) {
2147
3492
  const dragonSlug = slugify(a.name);
@@ -2160,6 +3505,10 @@ function applyV05Extensions(diagram2, doc) {
2160
3505
  if (a.eyebrow !== void 0) node.eyebrow = a.eyebrow;
2161
3506
  if (a.value !== void 0) node.value = a.value;
2162
3507
  if (a.rows !== void 0) node.rows = a.rows;
3508
+ if (!isSeqLike) {
3509
+ if (a.posW !== void 0) node.w = a.posW;
3510
+ if (a.posH !== void 0) node.h = a.posH;
3511
+ }
2163
3512
  const drawn = isSeqLike && a.kindWritten !== false ? drawableKind(a.kind) : void 0;
2164
3513
  if (drawn !== void 0) {
2165
3514
  node.kind = drawn;
@@ -2183,6 +3532,7 @@ function applyV05Extensions(diagram2, doc) {
2183
3532
  if (doc.animate && doc.animate.phases.length > 0 && diagram2.phases.length === 0) {
2184
3533
  injectPhasesFallback(diagram2, doc);
2185
3534
  }
3535
+ const \u8FFD\u52A0\u3057\u305F\u7E26\u5217 = \u8FFD\u52A0\u3057\u305F\u7E26\u5217out ?? [];
2186
3536
  if (doc.lanes) {
2187
3537
  for (const [id, laneOpt] of Object.entries(doc.lanes)) {
2188
3538
  const lane = diagram2.lanes.find((l) => l.id === id);
@@ -2201,6 +3551,7 @@ function applyV05Extensions(diagram2, doc) {
2201
3551
  contain: laneOpt.contain,
2202
3552
  lifeline: laneOpt.lifeline
2203
3553
  });
3554
+ \u8FFD\u52A0\u3057\u305F\u7E26\u5217.push(laneOpt);
2204
3555
  }
2205
3556
  }
2206
3557
  }
@@ -2321,8 +3672,9 @@ function compileSequenceWithAnimate(doc) {
2321
3672
  b.node(spacerId, { lane: id, stack: 1, kind: "card", title: "", w: 2, h: 40 });
2322
3673
  });
2323
3674
  doc.flow.forEach((s, idx) => {
2324
- const fromLaneId = actorIds.get(s.from) ?? s.from;
2325
- const toLaneId = actorIds.get(s.to) ?? s.to;
3675
+ const fromLaneId = actorIds.get(s.from);
3676
+ const toLaneId = actorIds.get(s.to);
3677
+ if (fromLaneId === void 0 || toLaneId === void 0) return;
2326
3678
  const stack = idx + 2;
2327
3679
  const fromBoxId = `s${idx}-${fromLaneId}`;
2328
3680
  const toBoxId = `s${idx}-${toLaneId}`;
@@ -2336,11 +3688,7 @@ function compileSequenceWithAnimate(doc) {
2336
3688
  label: s.label,
2337
3689
  ...s.sub ? { sub: s.sub } : {},
2338
3690
  ...s.tone ? { tone: s.tone } : {},
2339
- ...s.style ? { style: s.style } : {},
2340
- ...s.guard ? { guard: s.guard } : {},
2341
- ...s.cardinality ? { cardinality: s.cardinality } : {},
2342
- ...s.labelOffsetX !== void 0 ? { labelOffsetX: s.labelOffsetX } : {},
2343
- ...s.labelOffsetY !== void 0 ? { labelOffsetY: s.labelOffsetY } : {}
3691
+ ...s.style ? { style: s.style } : {}
2344
3692
  });
2345
3693
  });
2346
3694
  const footerStack = doc.flow.length + 2;
@@ -2348,12 +3696,20 @@ function compileSequenceWithAnimate(doc) {
2348
3696
  const laneId = actorIds.get(a.name) ?? slugify(a.name);
2349
3697
  const footerId = `${laneId}-footer`;
2350
3698
  const actorW = Math.max(140, a.name.length * 22 + 52);
2351
- b.node(footerId, { lane: laneId, stack: footerStack, kind: "card", title: a.name, w: actorW, h: 72 });
3699
+ b.node(footerId, {
3700
+ lane: laneId,
3701
+ stack: footerStack,
3702
+ kind: "card",
3703
+ title: a.name,
3704
+ w: actorW,
3705
+ h: 72,
3706
+ role: "lifeline-footer"
3707
+ });
2352
3708
  });
2353
- for (const st of doc.animate.states) {
3709
+ for (const st of doc.animate?.states ?? []) {
2354
3710
  b.state(st.name, { initial: st.initial });
2355
3711
  }
2356
- for (const p of doc.animate.phases) {
3712
+ for (const p of doc.animate?.phases ?? []) {
2357
3713
  b.phase(
2358
3714
  slugify(p.name),
2359
3715
  {
@@ -2432,7 +3788,7 @@ function slugLookup(byName, wanted) {
2432
3788
  return hit;
2433
3789
  }
2434
3790
  function compileFlow(doc) {
2435
- if (doc.animate && doc.animate.phases.length > 0) {
3791
+ if (doc.animate && doc.animate.phases.length > 0 || \u66F8\u3044\u305F\u7E26\u5217\u306B\u7F6E\u304F("flow", doc)) {
2436
3792
  return compileGenericWithAnimate(doc, { kind: "flow", laneId: "main", laneWidth: 400 });
2437
3793
  }
2438
3794
  if (doc.actors.length === 0) {
@@ -2458,7 +3814,7 @@ function compileFlow(doc) {
2458
3814
  return flowBuilder.build();
2459
3815
  }
2460
3816
  function compileSwimlane(doc) {
2461
- if (doc.animate && doc.animate.phases.length > 0) {
3817
+ if (doc.animate && doc.animate.phases.length > 0 || \u66F8\u3044\u305F\u7E26\u5217\u306B\u7F6E\u304F("swimlane", doc)) {
2462
3818
  return compileGenericWithAnimate(doc, { kind: "swimlane", laneWidth: 400 });
2463
3819
  }
2464
3820
  const swim = swimlane({
@@ -2492,11 +3848,17 @@ function compileSwimlane(doc) {
2492
3848
  label: s.label,
2493
3849
  ...s.sub ? { sub: s.sub } : {},
2494
3850
  ...s.tone ? { tone: s.tone } : {},
2495
- ...s.style ? { style: s.style } : {},
2496
- ...s.guard ? { guard: s.guard } : {},
2497
- ...s.cardinality ? { cardinality: s.cardinality } : {},
2498
- ...s.labelOffsetX !== void 0 ? { labelOffsetX: s.labelOffsetX } : {},
2499
- ...s.labelOffsetY !== void 0 ? { labelOffsetY: s.labelOffsetY } : {}
3851
+ ...s.style ? { style: s.style } : {}
3852
+ });
3853
+ }
3854
+ if (placedNodes.size === 0) {
3855
+ doc.actors.forEach((a, i) => {
3856
+ swim.node(slugify(a.name), {
3857
+ lane: swim.laneId(a.name),
3858
+ stack: 0,
3859
+ kind: a.kind ?? "actor",
3860
+ title: a.name
3861
+ });
2500
3862
  });
2501
3863
  }
2502
3864
  return swim.build();
@@ -2528,6 +3890,14 @@ function compileEr(doc) {
2528
3890
  }
2529
3891
  return erBuilder.build();
2530
3892
  }
3893
+ function \u59CB\u307E\u308A\u3068\u7D42\u308F\u308A\u306E\u6C7A\u3081\u65B9(doc) {
3894
+ const \u66F8\u3044\u305F\u59CB\u307E\u308A = doc.actors.some((a) => a.initial === true);
3895
+ const \u66F8\u3044\u305F\u7D42\u308F\u308A = doc.actors.some((a) => a.final === true);
3896
+ return {
3897
+ \u59CB\u307E\u308A: (a, idx) => \u66F8\u3044\u305F\u59CB\u307E\u308A ? a.initial === true : idx === 0,
3898
+ \u7D42\u308F\u308A: (a, idx) => \u66F8\u3044\u305F\u7D42\u308F\u308A ? a.final === true : idx === doc.actors.length - 1 && doc.actors.length > 1
3899
+ };
3900
+ }
2531
3901
  function compileState(doc) {
2532
3902
  if (doc.animate && doc.animate.phases.length > 0) {
2533
3903
  return compileGenericWithAnimate(doc, { kind: "state", laneWidth: 360 });
@@ -2536,10 +3906,11 @@ function compileState(doc) {
2536
3906
  id: slugify(doc.title),
2537
3907
  topic: doc.title
2538
3908
  });
3909
+ const \u6C7A\u3081\u65B9 = \u59CB\u307E\u308A\u3068\u7D42\u308F\u308A\u306E\u6C7A\u3081\u65B9(doc);
2539
3910
  for (let i = 0; i < doc.actors.length; i++) {
2540
3911
  const a = doc.actors[i];
2541
- const initial = i === 0;
2542
- const final = i === doc.actors.length - 1 && doc.actors.length > 1;
3912
+ const initial = \u6C7A\u3081\u65B9.\u59CB\u307E\u308A(a, i);
3913
+ const final = \u6C7A\u3081\u65B9.\u7D42\u308F\u308A(a, i);
2543
3914
  fsm.state({
2544
3915
  id: slugify(a.name),
2545
3916
  title: a.name,
@@ -2559,7 +3930,7 @@ function compileState(doc) {
2559
3930
  return fsm.build();
2560
3931
  }
2561
3932
  function compileTopology(doc) {
2562
- if (doc.animate && doc.animate.phases.length > 0) {
3933
+ if (doc.animate && doc.animate.phases.length > 0 || \u66F8\u3044\u305F\u7E26\u5217\u306B\u7F6E\u304F("topology", doc)) {
2563
3934
  return compileGenericWithAnimate(doc, { kind: "topology", laneWidth: 460 });
2564
3935
  }
2565
3936
  if (doc.actors.length === 0) {
@@ -2588,11 +3959,42 @@ function compileTopology(doc) {
2588
3959
  }
2589
3960
  return topo.build();
2590
3961
  }
3962
+ function \u5F8C\u308D\u3078\u623B\u308B\u77E2\u5370\u304B(kind, fromId, toId, \u7BB1\u306E\u4E26\u3073) {
3963
+ if (kind !== "state") return false;
3964
+ const \u5143 = \u7BB1\u306E\u4E26\u3073.get(fromId);
3965
+ const \u5148 = \u7BB1\u306E\u4E26\u3073.get(toId);
3966
+ if (\u5143 === void 0 || \u5148 === void 0) return false;
3967
+ return \u5148 < \u5143;
3968
+ }
3969
+ var \u7E26\u5217\u3092\u9078\u3079\u308B\u56F3\u7A2E = /* @__PURE__ */ new Set(["flow", "topology", "swimlane"]);
3970
+ function \u66F8\u3044\u305F\u7E26\u5217\u306B\u7F6E\u304F(kind, doc) {
3971
+ if (!\u7E26\u5217\u3092\u9078\u3079\u308B\u56F3\u7A2E.has(kind)) return false;
3972
+ const \u5BFE\u8C61 = doc.actors.filter((a) => a.partId === void 0);
3973
+ return \u5BFE\u8C61.length > 0 && \u5BFE\u8C61.every((a) => a.lane !== void 0);
3974
+ }
2591
3975
  function compileGenericWithAnimate(doc, opts) {
2592
3976
  const b = diagram(slugify(doc.title), { topic: doc.title });
2593
3977
  const { kind, laneWidth } = opts;
2594
3978
  const actorToNodeId = /* @__PURE__ */ new Map();
2595
- if (kind === "flow" || kind === "topology") {
3979
+ if (\u66F8\u3044\u305F\u7E26\u5217\u306B\u7F6E\u304F(kind, doc)) {
3980
+ const \u4E26\u3073 = [];
3981
+ for (const a of doc.actors) {
3982
+ const lid = a.lane;
3983
+ if (lid !== void 0 && !\u4E26\u3073.includes(lid)) \u4E26\u3073.push(lid);
3984
+ }
3985
+ for (const lid of \u4E26\u3073) {
3986
+ b.lane(lid, { width: laneWidth, ...kind === "topology" ? { contain: true } : {} });
3987
+ }
3988
+ const \u7A4D\u3093\u3060\u6570 = /* @__PURE__ */ new Map();
3989
+ doc.actors.forEach((a, idx) => {
3990
+ const id = slugify(a.name);
3991
+ actorToNodeId.set(a.name, id);
3992
+ const lid = a.lane;
3993
+ const stack = \u7A4D\u3093\u3060\u6570.get(lid) ?? 0;
3994
+ \u7A4D\u3093\u3060\u6570.set(lid, stack + 1);
3995
+ b.node(id, { lane: lid, stack, kind: a.kind, title: a.name });
3996
+ });
3997
+ } else if (kind === "flow" || kind === "topology") {
2596
3998
  const lid = opts.laneId ?? "main";
2597
3999
  b.lane(lid, { width: laneWidth, label: doc.title, ...kind === "topology" ? { contain: true } : {} });
2598
4000
  doc.actors.forEach((a, idx) => {
@@ -2601,13 +4003,15 @@ function compileGenericWithAnimate(doc, opts) {
2601
4003
  b.node(id, { lane: lid, stack: idx, kind: a.kind, title: a.name });
2602
4004
  });
2603
4005
  } else {
4006
+ const \u898B\u51FA\u3057\u3092\u4ED8\u3051\u308B = kind === "swimlane";
4007
+ const \u6C7A\u3081\u65B92 = \u59CB\u307E\u308A\u3068\u7D42\u308F\u308A\u306E\u6C7A\u3081\u65B9(doc);
2604
4008
  doc.actors.forEach((a, idx) => {
2605
4009
  const lid = `lane-${slugify(a.name)}`;
2606
- b.lane(lid, { width: laneWidth, label: a.name });
4010
+ b.lane(lid, { width: laneWidth, ...\u898B\u51FA\u3057\u3092\u4ED8\u3051\u308B ? { label: a.name } : {} });
2607
4011
  const id = slugify(a.name);
2608
4012
  actorToNodeId.set(a.name, id);
2609
- const isInitial = kind === "state" && idx === 0;
2610
- const isFinal = kind === "state" && idx === doc.actors.length - 1 && doc.actors.length > 1;
4013
+ const isInitial = kind === "state" && \u6C7A\u3081\u65B92.\u59CB\u307E\u308A(a, idx);
4014
+ const isFinal = kind === "state" && \u6C7A\u3081\u65B92.\u7D42\u308F\u308A(a, idx);
2611
4015
  b.node(id, {
2612
4016
  lane: lid,
2613
4017
  stack: 0,
@@ -2618,29 +4022,28 @@ function compileGenericWithAnimate(doc, opts) {
2618
4022
  });
2619
4023
  });
2620
4024
  }
4025
+ const \u7BB1\u306E\u4E26\u3073 = new Map([...actorToNodeId.values()].map((id, i) => [id, i]));
2621
4026
  const edgeIds = [];
2622
4027
  doc.flow.forEach((s, idx) => {
2623
- const fromId = actorToNodeId.get(s.from) ?? slugify(s.from);
2624
- const toId = actorToNodeId.get(s.to) ?? slugify(s.to);
4028
+ const fromId = actorToNodeId.get(s.from);
4029
+ const toId = actorToNodeId.get(s.to);
4030
+ if (fromId === void 0 || toId === void 0) return;
2625
4031
  const edgeId = `e${idx}-${fromId}-${toId}`;
2626
4032
  const labelWithCard = kind === "er" && s.cardinality && !s.label.includes(s.cardinality) ? s.label ? `${s.label} (${s.cardinality})` : `(${s.cardinality})` : s.label;
2627
4033
  b.edge(fromId, toId, {
2628
4034
  id: edgeId,
2629
4035
  label: labelWithCard,
4036
+ ...\u5F8C\u308D\u3078\u623B\u308B\u77E2\u5370\u304B(kind, fromId, toId, \u7BB1\u306E\u4E26\u3073) ? { routing: "back-detour" } : {},
2630
4037
  ...s.sub ? { sub: s.sub } : {},
2631
4038
  ...s.tone ? { tone: s.tone } : {},
2632
- ...s.style ? { style: s.style } : {},
2633
- ...s.guard ? { guard: s.guard } : {},
2634
- ...s.cardinality ? { cardinality: s.cardinality } : {},
2635
- ...s.labelOffsetX !== void 0 ? { labelOffsetX: s.labelOffsetX } : {},
2636
- ...s.labelOffsetY !== void 0 ? { labelOffsetY: s.labelOffsetY } : {}
4039
+ ...s.style ? { style: s.style } : {}
2637
4040
  });
2638
4041
  edgeIds.push(edgeId);
2639
4042
  });
2640
- for (const st of doc.animate.states) {
4043
+ for (const st of doc.animate?.states ?? []) {
2641
4044
  b.state(st.name, { initial: st.initial });
2642
4045
  }
2643
- for (const p of doc.animate.phases) {
4046
+ for (const p of doc.animate?.phases ?? []) {
2644
4047
  b.phase(
2645
4048
  slugify(p.name),
2646
4049
  {
@@ -2683,51 +4086,284 @@ function resolveHighlightGeneric(phase, doc, actorToNodeId, edgeIds) {
2683
4086
  }
2684
4087
  continue;
2685
4088
  }
2686
- const nodeId = actorToNodeId.get(entry.name) ?? slugLookup(actorToNodeId, entry.name);
2687
- if (nodeId) {
2688
- out.push(nodeId);
4089
+ const nodeId = actorToNodeId.get(entry.name) ?? slugLookup(actorToNodeId, entry.name);
4090
+ if (nodeId) {
4091
+ out.push(nodeId);
4092
+ }
4093
+ }
4094
+ return out;
4095
+ }
4096
+ var ID_MAX = 64;
4097
+ function slugify(s) {
4098
+ return s.toLowerCase().normalize("NFKC").replace(/[^a-z0-9ぁ-んァ-ヶ一-龯\-_]+/g, "-").replace(/^-+|-+$/g, "").slice(0, ID_MAX) || "n";
4099
+ }
4100
+ var CARDINALITY_PATTERNS = [
4101
+ [/1:1/, "1:1"],
4102
+ [/1:N/i, "1:N"],
4103
+ [/N:1/i, "N:1"],
4104
+ [/N:M/i, "N:M"],
4105
+ [/0\.\.1/, "0..1"],
4106
+ [/1\.\.\*/, "1..*"]
4107
+ ];
4108
+ function boundedCardinalityRegExp(pattern, extraFlags = "") {
4109
+ const base = pattern.flags.includes("i") ? "i" : "";
4110
+ return new RegExp(`(?<![A-Za-z0-9_])(?:${pattern.source})(?![A-Za-z0-9_])`, base + extraFlags);
4111
+ }
4112
+ function parseCardinalityFromLabel(label) {
4113
+ for (const [pattern, card] of CARDINALITY_PATTERNS) {
4114
+ if (boundedCardinalityRegExp(pattern).test(label)) return card;
4115
+ }
4116
+ return null;
4117
+ }
4118
+ var HORIZONTAL_WS = " \\t\\u3000";
4119
+ var HWS = `[${HORIZONTAL_WS}]`;
4120
+ function stripCardinality(label) {
4121
+ let r = label;
4122
+ let removed = false;
4123
+ for (const [pattern] of CARDINALITY_PATTERNS) {
4124
+ const src = pattern.source;
4125
+ const flags = pattern.flags.includes("i") ? "gi" : "g";
4126
+ const before = r;
4127
+ r = r.replace(new RegExp(`\\(${HWS}*${src}${HWS}*\\)`, flags), "");
4128
+ r = r.replace(boundedCardinalityRegExp(pattern, "g"), "");
4129
+ if (r !== before) removed = true;
4130
+ }
4131
+ if (!removed) return label;
4132
+ r = r.replace(new RegExp(`${HWS}{2,}`, "g"), " ").replace(new RegExp(`${HWS}*([\\r\\n])${HWS}*`, "g"), "$1").replace(new RegExp(`^${HWS}+|${HWS}+$`, "g"), "");
4133
+ const hasVisible = /[^\p{White_Space}\p{Cf}\p{Cc}\p{Default_Ignorable_Code_Point}]/u.test(r);
4134
+ return hasVisible ? r : label;
4135
+ }
4136
+
4137
+ // src/value-syntax.ts
4138
+ var VALUE_NAME_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
4139
+ var VALUE_FNS = /* @__PURE__ */ new Set(["min", "max"]);
4140
+ function isValueName(name) {
4141
+ return VALUE_NAME_RE.test(name);
4142
+ }
4143
+ function valueNameIssue(name) {
4144
+ return {
4145
+ message: `invalid value name: "${name}"`,
4146
+ hint: "\u82F1\u5B57\u304B _ \u3067\u59CB\u3081\u3001 \u82F1\u6570\u5B57\u3068 _ \u3060\u3051\u3092\u4F7F\u3046 (states \u3068\u540C\u3058\u898F\u5247)"
4147
+ };
4148
+ }
4149
+ var TRIGGER_OPS = [">=", "<=", "==", "!=", ">", "<"];
4150
+ function parseDurationMs(text) {
4151
+ const m = text.trim().match(/^(\d+(?:\.\d+)?)\s*(ms|s)?$/);
4152
+ if (!m) return null;
4153
+ const n = parseFloat(m[1] ?? "0");
4154
+ if (!Number.isFinite(n) || n <= 0) return null;
4155
+ const unit = m[2] ?? "s";
4156
+ const durationMs = unit === "ms" ? Math.round(n) : Math.round(n * 1e3);
4157
+ return durationMs > 0 ? durationMs : null;
4158
+ }
4159
+ function splitOutsideQuotes(body) {
4160
+ const out = [];
4161
+ let cur = "";
4162
+ let quote = null;
4163
+ for (const ch of body) {
4164
+ if (quote) {
4165
+ if (ch === quote) quote = null;
4166
+ cur += ch;
4167
+ continue;
4168
+ }
4169
+ if (ch === '"' || ch === "'") {
4170
+ quote = ch;
4171
+ cur += ch;
4172
+ continue;
4173
+ }
4174
+ if (ch === ",") {
4175
+ out.push(cur);
4176
+ cur = "";
4177
+ continue;
4178
+ }
4179
+ cur += ch;
4180
+ }
4181
+ out.push(cur);
4182
+ return out.map((s) => s.trim()).filter((s) => s !== "");
4183
+ }
4184
+ function unquote(s) {
4185
+ const t = s.trim();
4186
+ if (t.length >= 2 && (t[0] === '"' || t[0] === "'") && t[t.length - 1] === t[0]) {
4187
+ return t.slice(1, -1);
4188
+ }
4189
+ return t;
4190
+ }
4191
+ function parseTriggerExpression(raw, name) {
4192
+ const text = raw.trim();
4193
+ const stepMatch = text.match(/^step\s+(.+)$/);
4194
+ if (stepMatch) {
4195
+ const step = unquote(stepMatch[1] ?? "");
4196
+ if (step === "") {
4197
+ return { message: `trigger \u306E\u6BB5\u540D\u304C\u7A7A\u3067\u3059 ("${name}")`, hint: '`trigger: step "\u53D6\u8FBC\u307F"` \u306E\u5F62\u3067\u6BB5\u306E\u540D\u524D\u3092\u66F8\u304F' };
4198
+ }
4199
+ return { kind: "step", step };
4200
+ }
4201
+ for (const op of TRIGGER_OPS) {
4202
+ const at = text.indexOf(op);
4203
+ if (at < 0) continue;
4204
+ const source = text.slice(0, at).trim();
4205
+ const rhs = text.slice(at + op.length).trim();
4206
+ if (!isValueName(source)) {
4207
+ return {
4208
+ message: `trigger \u304C\u898B\u5F35\u308B\u5024\u306E\u540D\u524D\u304C\u4F7F\u3048\u307E\u305B\u3093: "${source}" ("${name}")`,
4209
+ hint: "\u82F1\u5B57\u304B _ \u3067\u59CB\u3081\u3001 \u82F1\u6570\u5B57\u3068 _ \u3060\u3051\u3092\u4F7F\u3046"
4210
+ };
4211
+ }
4212
+ const threshold = Number(rhs);
4213
+ if (rhs === "" || !Number.isFinite(threshold)) {
4214
+ return {
4215
+ message: `trigger \u306E\u5883\u76EE\u304C\u6570\u3067\u306F\u3042\u308A\u307E\u305B\u3093: "${rhs}" ("${name}")`,
4216
+ hint: "`trigger: vDone >= 100` \u306E\u3088\u3046\u306B\u6570\u3067\u66F8\u304F"
4217
+ };
4218
+ }
4219
+ return { kind: "reaches", source, op, threshold };
4220
+ }
4221
+ return {
4222
+ message: `trigger \u306E\u5F62\u304C\u8AAD\u3081\u307E\u305B\u3093: "${text}" ("${name}")`,
4223
+ hint: '`step "\u53D6\u8FBC\u307F"` \u304B `vDone >= 100` \u306E\u5F62\u3067\u66F8\u304F'
4224
+ };
4225
+ }
4226
+ function isTriggerBody(raw) {
4227
+ const t = raw.trim();
4228
+ if (!t.startsWith("{") || !t.endsWith("}") || t.length < 2) return false;
4229
+ const inner = t.slice(1, -1);
4230
+ let quote = null;
4231
+ for (const ch of inner) {
4232
+ if (quote) {
4233
+ if (ch === quote) quote = null;
4234
+ continue;
4235
+ }
4236
+ if (ch === '"' || ch === "'") {
4237
+ quote = ch;
4238
+ continue;
2689
4239
  }
4240
+ if (ch === ":") return true;
2690
4241
  }
2691
- return out;
2692
- }
2693
- function slugify(s) {
2694
- return s.toLowerCase().normalize("NFKC").replace(/[^a-z0-9ぁ-んァ-ヶ一-龯\-_]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64) || "n";
2695
- }
2696
- var CARDINALITY_PATTERNS = [
2697
- [/1:1/, "1:1"],
2698
- [/1:N/i, "1:N"],
2699
- [/N:1/i, "N:1"],
2700
- [/N:M/i, "N:M"],
2701
- [/0\.\.1/, "0..1"],
2702
- [/1\.\.\*/, "1..*"]
2703
- ];
2704
- function boundedCardinalityRegExp(pattern, extraFlags = "") {
2705
- const base = pattern.flags.includes("i") ? "i" : "";
2706
- return new RegExp(`(?<![A-Za-z0-9_])(?:${pattern.source})(?![A-Za-z0-9_])`, base + extraFlags);
4242
+ return false;
2707
4243
  }
2708
- function parseCardinalityFromLabel(label) {
2709
- for (const [pattern, card] of CARDINALITY_PATTERNS) {
2710
- if (boundedCardinalityRegExp(pattern).test(label)) return card;
4244
+ function parseValueTriggerBody(body, name) {
4245
+ const issues = [];
4246
+ const seen = /* @__PURE__ */ new Map();
4247
+ for (const part of splitOutsideQuotes(body)) {
4248
+ const at = part.indexOf(":");
4249
+ if (at < 0) {
4250
+ issues.push({ message: `"${part}" \u306F key: value \u306E\u5F62\u3067\u306F\u3042\u308A\u307E\u305B\u3093 ("${name}")`, hint: "`trigger: ... , to: 100, dur: 2s` \u306E\u5F62\u3067\u66F8\u304F" });
4251
+ continue;
4252
+ }
4253
+ const key = part.slice(0, at).trim().toLowerCase();
4254
+ const value = part.slice(at + 1).trim();
4255
+ if (seen.has(key)) {
4256
+ issues.push({ message: `"${key}" \u3092 2 \u5EA6\u66F8\u3044\u3066\u3044\u307E\u3059 ("${name}")`, hint: "\u540C\u3058\u9805\u76EE\u306F 1 \u5EA6\u3060\u3051\u66F8\u304F" });
4257
+ continue;
4258
+ }
4259
+ seen.set(key, value);
2711
4260
  }
2712
- return null;
4261
+ const known = /* @__PURE__ */ new Set(["trigger", "to", "dur"]);
4262
+ for (const key of seen.keys()) {
4263
+ if (known.has(key)) continue;
4264
+ issues.push({
4265
+ message: `"${key}" \u306F values \u306B\u66F8\u3051\u307E\u305B\u3093 ("${name}")`,
4266
+ hint: `\u66F8\u3051\u308B\u306E\u306F ${[...known].join(" / ")} \u3060\u3051`
4267
+ });
4268
+ }
4269
+ const triggerRaw = seen.get("trigger");
4270
+ let trigger = null;
4271
+ if (triggerRaw === void 0) {
4272
+ issues.push({ message: `trigger \u304C\u3042\u308A\u307E\u305B\u3093 ("${name}")`, hint: '`trigger: step "\u53D6\u8FBC\u307F"` \u304B `trigger: vDone >= 100` \u3092\u66F8\u304F' });
4273
+ } else {
4274
+ const parsed = parseTriggerExpression(triggerRaw, name);
4275
+ if ("message" in parsed) issues.push(parsed);
4276
+ else trigger = parsed;
4277
+ }
4278
+ const toRaw = seen.get("to");
4279
+ let to = 0;
4280
+ if (toRaw === void 0) {
4281
+ issues.push({ message: `to \u304C\u3042\u308A\u307E\u305B\u3093 ("${name}")`, hint: "`to: 100` \u306E\u3088\u3046\u306B\u52D5\u3044\u305F\u5148\u306E\u5024\u3092\u66F8\u304F" });
4282
+ } else {
4283
+ to = Number(unquote(toRaw));
4284
+ if (!Number.isFinite(to)) {
4285
+ issues.push({ message: `to \u304C\u6570\u3067\u306F\u3042\u308A\u307E\u305B\u3093: "${toRaw}" ("${name}")`, hint: "`to: 100` \u306E\u3088\u3046\u306B\u6570\u3067\u66F8\u304F" });
4286
+ }
4287
+ }
4288
+ const durRaw = seen.get("dur");
4289
+ let durationMs = 0;
4290
+ if (durRaw === void 0) {
4291
+ issues.push({ message: `dur \u304C\u3042\u308A\u307E\u305B\u3093 ("${name}")`, hint: "`dur: 2s` \u306E\u3088\u3046\u306B\u52D5\u304F\u9577\u3055\u3092\u66F8\u304F" });
4292
+ } else {
4293
+ const parsedDur = parseDurationMs(unquote(durRaw));
4294
+ if (parsedDur === null) {
4295
+ issues.push({ message: `dur \u304C\u8AAD\u3081\u307E\u305B\u3093: "${durRaw}" ("${name}")`, hint: "`2s` / `1.5s` / `500ms` \u306E\u5F62\u3067\u3001 0 \u3088\u308A\u5927\u304D\u3044\u9577\u3055\u3092\u66F8\u304F" });
4296
+ } else {
4297
+ durationMs = parsedDur;
4298
+ }
4299
+ }
4300
+ if (issues.length > 0 || trigger === null) return { spec: null, issues };
4301
+ return { spec: { trigger, to, durationMs }, issues: [] };
2713
4302
  }
2714
- var HORIZONTAL_WS = " \\t\\u3000";
2715
- var HWS = `[${HORIZONTAL_WS}]`;
2716
- function stripCardinality(label) {
2717
- let r = label;
2718
- let removed = false;
2719
- for (const [pattern] of CARDINALITY_PATTERNS) {
2720
- const src = pattern.source;
2721
- const flags = pattern.flags.includes("i") ? "gi" : "g";
2722
- const before = r;
2723
- r = r.replace(new RegExp(`\\(${HWS}*${src}${HWS}*\\)`, flags), "");
2724
- r = r.replace(boundedCardinalityRegExp(pattern, "g"), "");
2725
- if (r !== before) removed = true;
4303
+ function checkValueExpression(expression, name) {
4304
+ const issues = [];
4305
+ const refRe = /\{([^}]*)\}/g;
4306
+ let m;
4307
+ while ((m = refRe.exec(expression)) !== null) {
4308
+ const ref = (m[1] ?? "").trim();
4309
+ if (!VALUE_NAME_RE.test(ref)) {
4310
+ issues.push({
4311
+ message: `invalid reference "{${ref}}" in "${name}"`,
4312
+ hint: "\u82F1\u5B57\u304B _ \u3067\u59CB\u3081\u3001 \u82F1\u6570\u5B57\u3068 _ \u3060\u3051\u3092\u4F7F\u3046"
4313
+ });
4314
+ }
2726
4315
  }
2727
- if (!removed) return label;
2728
- r = r.replace(new RegExp(`${HWS}{2,}`, "g"), " ").replace(new RegExp(`${HWS}*([\\r\\n])${HWS}*`, "g"), "$1").replace(new RegExp(`^${HWS}+|${HWS}+$`, "g"), "");
2729
- const hasVisible = /[^\p{White_Space}\p{Cf}\p{Cc}\p{Default_Ignorable_Code_Point}]/u.test(r);
2730
- return hasVisible ? r : label;
4316
+ if (expression.includes("{") && !expression.includes("}")) {
4317
+ issues.push({ message: `unclosed "{" in "${name}"`, hint: "`{\u540D\u524D}` \u306E\u5F62\u3067\u9589\u3058\u308B" });
4318
+ }
4319
+ const outside = expression.replace(/\{[^}]*\}/g, " ");
4320
+ if (outside.includes("%")) {
4321
+ issues.push({ message: `"%" \u306F\u5F0F\u306B\u66F8\u3051\u306A\u3044 ("${name}")`, hint: "\u56DB\u5247 (+ - * /) \u3060\u3051\u3092\u4F7F\u3046" });
4322
+ }
4323
+ if (outside.includes("?")) {
4324
+ issues.push({
4325
+ message: `\u6761\u4EF6\u5206\u5C90 (?:) \u306F\u5F0F\u306B\u66F8\u3051\u306A\u3044 ("${name}")`,
4326
+ hint: "\u6BD4\u8F03\u306E\u7D50\u679C\u306F\u771F = 1 / \u507D = 0 \u306E\u6570\u306B\u306A\u308B\u306E\u3067\u3001 \u639B\u3051\u7B97\u3067\u5207\u308A\u66FF\u3048\u308B"
4327
+ });
4328
+ }
4329
+ for (const fn of outside.matchAll(/[a-zA-Z_][a-zA-Z0-9_.]*/g)) {
4330
+ const word = fn[0];
4331
+ if (VALUE_FNS.has(word)) continue;
4332
+ issues.push({
4333
+ message: `"${word}" \u306F\u5F0F\u306B\u66F8\u3051\u306A\u3044 ("${name}")`,
4334
+ hint: word.startsWith("Math.") ? "min / max \u306F Math. \u3092\u4ED8\u3051\u305A\u306B\u66F8\u304F" : `\u4F7F\u3048\u308B\u306E\u306F ${[...VALUE_FNS].join(" / ")} \u3060\u3051\u3002 \u5024\u306F {\u540D\u524D} \u3067\u8AAD\u3080`
4335
+ });
4336
+ }
4337
+ const stray = outside.replace(/[a-zA-Z_][a-zA-Z0-9_.]*/g, " ").match(/[^0-9.,+\-*/()<>=!\s]/g);
4338
+ if (stray) {
4339
+ issues.push({
4340
+ message: `"${[...new Set(stray)].join("")}" \u306F\u5F0F\u306B\u66F8\u3051\u306A\u3044 ("${name}")`,
4341
+ hint: "\u56DB\u5247 (+ - * /) / \u62EC\u5F27 / \u6BD4\u8F03 (> >= < <= == !=) / min / max \u3060\u3051\u3092\u4F7F\u3046"
4342
+ });
4343
+ }
4344
+ return issues;
4345
+ }
4346
+
4347
+ // src/v05/parser.ts
4348
+ var TOP_LEVEL_KEYS = [
4349
+ "title",
4350
+ "type",
4351
+ "actors",
4352
+ "flow",
4353
+ "states",
4354
+ "values",
4355
+ "animation",
4356
+ "viewport",
4357
+ "lanes",
4358
+ "groups",
4359
+ // 図全体を 1 箱にする図種で、 その箱の上に出す小見出し (#1247)
4360
+ "eyebrow",
4361
+ // 2 軸で仕分ける図の軸の名前 (#1251)
4362
+ "axes"
4363
+ ];
4364
+ var LANE_ID_ENTRY = /^([\p{L}\p{N}_-]+)\s*:\s*\{([^}]*)\}\s*$/u;
4365
+ function isTopLevelKey(key) {
4366
+ return TOP_LEVEL_KEYS.includes(key);
2731
4367
  }
2732
4368
  var PRESET_TYPES = /* @__PURE__ */ new Set([
2733
4369
  "sequence",
@@ -2740,6 +4376,12 @@ var PRESET_TYPES = /* @__PURE__ */ new Set([
2740
4376
  "gantt",
2741
4377
  "class",
2742
4378
  "pie",
4379
+ "bar",
4380
+ "line",
4381
+ "funnel",
4382
+ "tree",
4383
+ "journey",
4384
+ "quadrant",
2743
4385
  "c4",
2744
4386
  "mind"
2745
4387
  ]);
@@ -2790,9 +4432,14 @@ function parseTextDslV05(src) {
2790
4432
  const lines = tokenize(src);
2791
4433
  let title = null;
2792
4434
  let type = null;
4435
+ let eyebrow = null;
4436
+ let eyebrowLine = 0;
4437
+ let axes = void 0;
4438
+ let axesLine = 0;
2793
4439
  let actors = [];
2794
4440
  const flow2 = [];
2795
4441
  let animate = void 0;
4442
+ const values = [];
2796
4443
  let viewport = void 0;
2797
4444
  let lanesMap = void 0;
2798
4445
  let groupsMap = void 0;
@@ -2804,11 +4451,11 @@ function parseTextDslV05(src) {
2804
4451
  continue;
2805
4452
  }
2806
4453
  const head = matchTopHeader(line.trimmed);
2807
- if (!head) {
4454
+ if (!head || !isTopLevelKey(head.key)) {
2808
4455
  errors.push({
2809
4456
  line: line.no,
2810
4457
  message: `unknown top-level key: "${line.trimmed}"`,
2811
- hint: "expected one of: title, type, actors, flow, states, animation, viewport, lanes, groups"
4458
+ hint: `expected one of: ${TOP_LEVEL_KEYS.join(", ")}`
2812
4459
  });
2813
4460
  i += 1;
2814
4461
  continue;
@@ -2821,6 +4468,13 @@ function parseTextDslV05(src) {
2821
4468
  i += 1;
2822
4469
  continue;
2823
4470
  }
4471
+ if (head.key === "eyebrow") {
4472
+ const v = (head.value ?? "").trim();
4473
+ eyebrow = v.length > 0 ? v : null;
4474
+ eyebrowLine = line.no;
4475
+ i += 1;
4476
+ continue;
4477
+ }
2824
4478
  if (head.key === "type") {
2825
4479
  const v = (head.value ?? "").trim().toLowerCase();
2826
4480
  if (!PRESET_TYPES.has(v)) {
@@ -2895,6 +4549,25 @@ function parseTextDslV05(src) {
2895
4549
  i = next;
2896
4550
  continue;
2897
4551
  }
4552
+ if (head.key === "values") {
4553
+ const inline = head.value?.trim();
4554
+ if (inline) {
4555
+ errors.push({
4556
+ line: line.no,
4557
+ message: "values \u306F 1 \u884C\u306B\u307E\u3068\u3081\u3066\u66F8\u3051\u306A\u3044",
4558
+ hint: '\u5F0F\u306B `,` \u304C\u5165\u308B\u305F\u3081\u3002 \u6B21\u306E\u884C\u304B\u3089\u5B57\u4E0B\u3052\u3057\u3066 `waiting: "{inflow} - {done}"` \u306E\u5F62\u3067\u4E26\u3079\u308B'
4559
+ });
4560
+ i += 1;
4561
+ continue;
4562
+ }
4563
+ const { items, next } = collectIndentedRaw(lines, i + 1, line.indent);
4564
+ for (const it of items) {
4565
+ const v = parseValueEntry(it.trimmed.replace(/^-\s*/, ""), it.no, errors);
4566
+ if (v) values.push(v);
4567
+ }
4568
+ i = next;
4569
+ continue;
4570
+ }
2898
4571
  if (head.key === "animation") {
2899
4572
  const { items: stepBlocks, next } = collectAnimationSteps(lines, i + 1, line.indent);
2900
4573
  animate = ensureAnimate(animate, line.no);
@@ -2943,11 +4616,42 @@ function parseTextDslV05(src) {
2943
4616
  i = next;
2944
4617
  continue;
2945
4618
  }
4619
+ if (head.key === "axes") {
4620
+ if (head.value !== null && head.value.trim() !== "") {
4621
+ errors.push({
4622
+ line: line.no,
4623
+ message: "axes \u306F 1 \u884C\u306B\u307E\u3068\u3081\u3066\u66F8\u3051\u306A\u3044",
4624
+ hint: '\u6B21\u306E\u884C\u304B\u3089\u5B57\u4E0B\u3052\u3057\u3066 `x: { left: "...", right: "..." }` \u306E\u5F62\u3067\u4E26\u3079\u308B'
4625
+ });
4626
+ i += 1;
4627
+ continue;
4628
+ }
4629
+ const { items, next } = collectIndentedRaw(lines, i + 1, line.indent);
4630
+ axesLine = line.no;
4631
+ const \u7D44\u307F\u7ACB\u3066 = {};
4632
+ for (const it of items) {
4633
+ const m = it.trimmed.match(/^(x|y)\s*:\s*\{([^}]*)\}\s*$/);
4634
+ if (!m) {
4635
+ errors.push({
4636
+ line: it.no,
4637
+ message: `invalid axes entry: "${it.trimmed}"`,
4638
+ hint: 'use `x: { left: "...", right: "..." }` or `y: { bottom: "...", top: "..." }`'
4639
+ });
4640
+ continue;
4641
+ }
4642
+ const opts = parseInlineMapping(m[2] ?? "");
4643
+ if (m[1] === "x") \u7D44\u307F\u7ACB\u3066.x = { left: opts.left, right: opts.right };
4644
+ else \u7D44\u307F\u7ACB\u3066.y = { bottom: opts.bottom, top: opts.top };
4645
+ }
4646
+ axes = \u7D44\u307F\u7ACB\u3066.x !== void 0 || \u7D44\u307F\u7ACB\u3066.y !== void 0 ? \u7D44\u307F\u7ACB\u3066 : void 0;
4647
+ i = next;
4648
+ continue;
4649
+ }
2946
4650
  if (head.key === "lanes") {
2947
4651
  const { items, next } = collectIndentedList(lines, i + 1, line.indent);
2948
4652
  lanesMap = {};
2949
4653
  for (const it of items) {
2950
- const m = it.trimmed.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*\{([^}]*)\}\s*$/);
4654
+ const m = it.trimmed.match(LANE_ID_ENTRY);
2951
4655
  if (m) {
2952
4656
  const id = m[1];
2953
4657
  const opts = parseInlineMapping(m[2]);
@@ -2975,7 +4679,7 @@ function parseTextDslV05(src) {
2975
4679
  const { items, next } = collectIndentedList(lines, i + 1, line.indent);
2976
4680
  groupsMap = {};
2977
4681
  for (const it of items) {
2978
- const m = it.trimmed.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*\{([^}]*)\}\s*$/);
4682
+ const m = it.trimmed.match(LANE_ID_ENTRY);
2979
4683
  if (m) {
2980
4684
  const id = m[1];
2981
4685
  const opts = parseInlineMapping(m[2]);
@@ -3007,9 +4711,12 @@ function parseTextDslV05(src) {
3007
4711
  doc: {
3008
4712
  title,
3009
4713
  type,
4714
+ ...eyebrow !== null ? { eyebrow, eyebrowPos: { line: eyebrowLine } } : {},
4715
+ ...axes !== void 0 ? { axes, axesPos: { line: axesLine } } : {},
3010
4716
  actors,
3011
4717
  flow: flow2,
3012
4718
  animate,
4719
+ ...values.length > 0 ? { values } : {},
3013
4720
  viewport,
3014
4721
  lanes: lanesMap,
3015
4722
  groups: groupsMap,
@@ -3274,6 +4981,7 @@ function applyContinuationLines(actor, rest, errors) {
3274
4981
  const state = { ...actor.stateOverride ?? {} };
3275
4982
  let touchedState = false;
3276
4983
  const scaleWritten = /* @__PURE__ */ new Map();
4984
+ const \u56F3\u7A2E\u3054\u3068\u306E\u6B04 = /* @__PURE__ */ new Map();
3277
4985
  const unknownKeys = [];
3278
4986
  for (const ln of rest) {
3279
4987
  const idx = ln.trimmed.indexOf(":");
@@ -3362,6 +5070,12 @@ function applyContinuationLines(actor, rest, errors) {
3362
5070
  });
3363
5071
  break;
3364
5072
  }
5073
+ case "touchpoint":
5074
+ case "opportunity":
5075
+ case "owner":
5076
+ case "end":
5077
+ \u56F3\u7A2E\u3054\u3068\u306E\u6B04.set(key, stripQuotes(raw));
5078
+ break;
3365
5079
  case "lane":
3366
5080
  out.lane = stripQuotes(raw);
3367
5081
  break;
@@ -3380,6 +5094,17 @@ function applyContinuationLines(actor, rest, errors) {
3380
5094
  out.scale = s.scale;
3381
5095
  out.scaleKeys = [.../* @__PURE__ */ new Set([...actor.scaleKeys ?? [], ...s.keys])];
3382
5096
  }
5097
+ for (const [key, v] of \u56F3\u7A2E\u3054\u3068\u306E\u6B04) {
5098
+ if (out.partId !== void 0) {
5099
+ state[key] = coerceStateValue(v);
5100
+ touchedState = true;
5101
+ continue;
5102
+ }
5103
+ if (key === "touchpoint") out.touchpoint = v;
5104
+ else if (key === "opportunity") out.opportunity = v;
5105
+ else if (key === "owner") out.owner = v;
5106
+ else out.end = v;
5107
+ }
3383
5108
  if (out.partId !== void 0) {
3384
5109
  if (touchedState) out.stateOverride = state;
3385
5110
  return out;
@@ -3412,7 +5137,13 @@ var ACTOR_ITEM_KEYS = /* @__PURE__ */ new Set([
3412
5137
  "\u500D\u7387",
3413
5138
  "scale",
3414
5139
  "lane",
3415
- "stack"
5140
+ "stack",
5141
+ // 体験の道筋の欄 (#1251)
5142
+ "touchpoint",
5143
+ "opportunity",
5144
+ // 工程の並びの欄 (#1251)
5145
+ "owner",
5146
+ "end"
3416
5147
  ]);
3417
5148
  function validateRelativePositions(actors, errors) {
3418
5149
  const named = new Set(actors.map((a) => a.name));
@@ -3511,6 +5242,9 @@ var ACTOR_RESERVED_FIELDS = /* @__PURE__ */ new Set([
3511
5242
  "initial",
3512
5243
  "final",
3513
5244
  "state",
5245
+ // 体験の道筋の欄 (`touchpoint` / `opportunity`) はここに載せない (#1251 Round 1 の指摘)。
5246
+ // 載せるとパーツで同じ名前の状態を書いた時に横取りされる = 既に動いている見本が静かに変わる。
5247
+ // パーツでない箱でだけ道筋の欄として読む (`parseActor` / `applyContinuationLines` が分岐する)
3514
5248
  // canvas pivot 新 spec = 絶対座標 4 field (dragon canvas pivot spec §layout-role-conversion)
3515
5249
  "posX",
3516
5250
  "posY",
@@ -3617,6 +5351,12 @@ var INLINE_ACTOR_KEYS = /* @__PURE__ */ new Set([
3617
5351
  "final",
3618
5352
  "tone",
3619
5353
  "nodes",
5354
+ // 体験の道筋の欄 (#1251)。 他の図種では組み立て側が知らせる
5355
+ "touchpoint",
5356
+ "opportunity",
5357
+ // 工程の並びの欄 (#1251)
5358
+ "owner",
5359
+ "end",
3620
5360
  "posX",
3621
5361
  "posY",
3622
5362
  "posW",
@@ -3626,6 +5366,15 @@ var INLINE_ACTOR_KEYS = /* @__PURE__ */ new Set([
3626
5366
  "scale",
3627
5367
  "\u500D\u7387"
3628
5368
  ]);
5369
+ var FLOW_INLINE_READERS = {
5370
+ sub: (v) => v,
5371
+ guard: (v) => v,
5372
+ cardinality: (v) => v,
5373
+ labelOffsetX: (v) => numberOrUndef(v),
5374
+ labelOffsetY: (v) => numberOrUndef(v),
5375
+ overlay: (v) => boolOrUndef(v)
5376
+ };
5377
+ var FLOW_INLINE_KEYS = Object.keys(FLOW_INLINE_READERS);
3629
5378
  function reportUnknownInlineKeys(isPart, inner, line, errors) {
3630
5379
  if (isPart) return;
3631
5380
  for (const field of splitInlineFields(inner)) {
@@ -3663,6 +5412,12 @@ function parseActor2(line, errors) {
3663
5412
  kindWritten: kindRaw !== "" && !isPart,
3664
5413
  subtitle: opts.subtitle,
3665
5414
  eyebrow: opts.eyebrow,
5415
+ // パーツでは状態の上書きとして意味を持つため、道筋の欄として横取りしない (#1251)
5416
+ touchpoint: isPart ? void 0 : opts.touchpoint,
5417
+ opportunity: isPart ? void 0 : opts.opportunity,
5418
+ // 見本では状態の上書きとして意味を持つため横取りしない (#1251)
5419
+ owner: isPart ? void 0 : opts.owner,
5420
+ end: isPart ? void 0 : opts.end,
3666
5421
  value: opts.value,
3667
5422
  rows: opts.rows ? opts.rows.replace(/^\[|\]$/g, "").split(/,(?![^[]*\])/).map((x) => stripQuotes(x.trim())).filter(Boolean) : void 0,
3668
5423
  lane: opts.lane,
@@ -3728,21 +5483,19 @@ function parseFlowStep(line, no) {
3728
5483
  let label = "";
3729
5484
  let tone;
3730
5485
  let style;
3731
- let sub;
3732
- let guard;
3733
- let cardinality;
3734
- let labelOffsetX;
3735
- let labelOffsetY;
5486
+ const \u4E2D\u62EC\u5F27 = {};
3736
5487
  const mapMatch = rest.match(/\s*\{([^}]*)\}\s*$/);
3737
5488
  if (mapMatch) {
3738
5489
  const opts = parseInlineMapping(mapMatch[1]);
3739
- sub = opts.sub;
3740
- guard = opts.guard;
3741
- cardinality = opts.cardinality;
3742
- labelOffsetX = numberOrUndef(opts.labelOffsetX);
3743
- labelOffsetY = numberOrUndef(opts.labelOffsetY);
5490
+ for (const k of FLOW_INLINE_KEYS) \u4E2D\u62EC\u5F27[k] = FLOW_INLINE_READERS[k](opts[k]);
3744
5491
  rest = rest.slice(0, mapMatch.index ?? 0).trim();
3745
5492
  }
5493
+ const sub = \u4E2D\u62EC\u5F27.sub;
5494
+ const guard = \u4E2D\u62EC\u5F27.guard;
5495
+ const cardinality = \u4E2D\u62EC\u5F27.cardinality;
5496
+ const labelOffsetX = \u4E2D\u62EC\u5F27.labelOffsetX;
5497
+ const labelOffsetY = \u4E2D\u62EC\u5F27.labelOffsetY;
5498
+ const overlay = \u4E2D\u62EC\u5F27.overlay;
3746
5499
  const optMatch = rest.match(/\s*\(([^)]*)\)\s*$/);
3747
5500
  if (optMatch) {
3748
5501
  const opts = (optMatch[1] ?? "").split(",").map((s) => s.trim());
@@ -3791,19 +5544,72 @@ function parseFlowStep(line, no) {
3791
5544
  cardinality,
3792
5545
  labelOffsetX,
3793
5546
  labelOffsetY,
5547
+ overlay,
3794
5548
  pos: { line: line.no }
3795
5549
  };
3796
5550
  }
3797
5551
  function parseStateEntry(text, lineNo) {
3798
- const m = text.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*(.+)$/);
5552
+ const m = text.match(/^([^:]+?)\s*:\s*(.+)$/);
3799
5553
  if (!m) return null;
3800
- const name = m[1] ?? "";
5554
+ const name = (m[1] ?? "").trim();
5555
+ if (!isValueName(name)) return null;
3801
5556
  const raw = (m[2] ?? "").trim();
3802
5557
  const stripped = stripQuotes(raw);
3803
5558
  const asNum = Number(stripped);
3804
5559
  const initial = Number.isFinite(asNum) && stripped !== "" && !isNaN(asNum) ? asNum : stripped;
3805
5560
  return { name, initial, pos: { line: lineNo } };
3806
5561
  }
5562
+ function collectIndentedRaw(lines, start, parentIndent) {
5563
+ const items = [];
5564
+ let i = start;
5565
+ while (i < lines.length) {
5566
+ const ln = lines[i];
5567
+ if (!ln || !ln.trimmed || ln.trimmed.startsWith("#")) {
5568
+ i += 1;
5569
+ continue;
5570
+ }
5571
+ if (ln.indent <= parentIndent) break;
5572
+ items.push(ln);
5573
+ i += 1;
5574
+ }
5575
+ return { items, next: i };
5576
+ }
5577
+ function parseValueEntry(text, lineNo, errors) {
5578
+ const m = text.match(/^([^:]+?)\s*:\s*(.+)$/);
5579
+ if (!m) {
5580
+ errors.push({
5581
+ line: lineNo,
5582
+ message: `invalid value entry: "${text}"`,
5583
+ hint: '`waiting: "{inflow} - {done}"` \u306E\u5F62\u3067\u66F8\u304F'
5584
+ });
5585
+ return null;
5586
+ }
5587
+ const name = (m[1] ?? "").trim();
5588
+ if (!isValueName(name)) {
5589
+ errors.push({ line: lineNo, ...valueNameIssue(name) });
5590
+ return null;
5591
+ }
5592
+ const rest = (m[2] ?? "").trim();
5593
+ if (isTriggerBody(rest)) {
5594
+ const { spec, issues: issues2 } = parseValueTriggerBody(rest.slice(1, -1), name);
5595
+ if (spec === null) {
5596
+ for (const issue of issues2) errors.push({ line: lineNo, ...issue });
5597
+ return null;
5598
+ }
5599
+ return { name, trigger: spec.trigger, to: spec.to, durationMs: spec.durationMs, pos: { line: lineNo } };
5600
+ }
5601
+ const expression = stripQuotes(rest);
5602
+ if (expression === "") {
5603
+ errors.push({ line: lineNo, message: `empty expression for "${name}"`, hint: '`"{a} + {b}"` \u306E\u3088\u3046\u306B\u5F0F\u3092\u66F8\u304F' });
5604
+ return null;
5605
+ }
5606
+ const issues = checkValueExpression(expression, name);
5607
+ if (issues.length > 0) {
5608
+ for (const issue of issues) errors.push({ line: lineNo, ...issue });
5609
+ return null;
5610
+ }
5611
+ return { name, expression, pos: { line: lineNo } };
5612
+ }
3807
5613
  function splitTopLevelCommas(s) {
3808
5614
  return s.split(",").map((x) => x.trim()).filter(Boolean);
3809
5615
  }
@@ -3927,12 +5733,23 @@ function parseStepHead(s) {
3927
5733
  function parseFocusList(s) {
3928
5734
  let body = s.trim();
3929
5735
  if (body.startsWith("[") && body.endsWith("]")) body = body.slice(1, -1);
3930
- const parts = [];
5736
+ const groups = [];
5737
+ let group = [];
3931
5738
  let buf = "";
3932
5739
  let quote = null;
5740
+ const pushFragment = (quoted) => {
5741
+ if (buf.trim()) group.push({ text: buf, quoted });
5742
+ buf = "";
5743
+ };
5744
+ const pushGroup = () => {
5745
+ pushFragment(false);
5746
+ if (group.length > 0) groups.push(group);
5747
+ group = [];
5748
+ };
3933
5749
  for (const ch of body) {
3934
5750
  if (quote) {
3935
5751
  if (ch === quote) {
5752
+ pushFragment(true);
3936
5753
  quote = null;
3937
5754
  continue;
3938
5755
  }
@@ -3940,41 +5757,49 @@ function parseFocusList(s) {
3940
5757
  continue;
3941
5758
  }
3942
5759
  if (ch === '"' || ch === "'") {
3943
- quote = ch;
3944
- continue;
5760
+ if (!buf || /\s$/.test(buf)) {
5761
+ pushFragment(false);
5762
+ quote = ch;
5763
+ continue;
5764
+ }
3945
5765
  }
3946
5766
  if (ch === ",") {
3947
- const t = buf.trim();
3948
- if (t) parts.push(t);
3949
- buf = "";
5767
+ pushGroup();
3950
5768
  continue;
3951
5769
  }
3952
5770
  buf += ch;
3953
5771
  }
3954
- const tail = buf.trim();
3955
- if (tail) parts.push(tail);
5772
+ pushFragment(quote !== null);
5773
+ if (group.length > 0) groups.push(group);
3956
5774
  const out = [];
3957
- for (const p of parts) {
3958
- if (/[-→][>]?/.test(p) && /\s/.test(p)) {
3959
- out.push(p);
5775
+ for (const fragments of groups) {
5776
+ const whole = fragments.map(({ text }) => text).join("").trim();
5777
+ if (fragments.every(({ quoted }) => !quoted) && /[-→][>]?/.test(whole) && /\s/.test(whole)) {
5778
+ out.push(whole);
3960
5779
  continue;
3961
5780
  }
3962
- if (/\s/.test(p)) {
3963
- for (const x of p.split(/\s+/)) {
3964
- if (x) out.push(x);
5781
+ for (const { text, quoted } of fragments) {
5782
+ const p = text.trim();
5783
+ if (!p) continue;
5784
+ if (quoted) {
5785
+ out.push(p);
5786
+ } else {
5787
+ for (const x of p.split(/\s+/)) {
5788
+ if (x) out.push(x);
5789
+ }
3965
5790
  }
3966
- continue;
3967
5791
  }
3968
- out.push(p);
3969
5792
  }
3970
5793
  return out;
3971
5794
  }
3972
5795
  function parseTweenLine(s, lineNo) {
3973
5796
  const cleaned = s.replace(/^-\s*/, "").trim();
3974
- const m = cleaned.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*[:\s]\s*(-?\d+(?:\.\d+)?)\s*->\s*(-?\d+(?:\.\d+)?)$/);
5797
+ const m = cleaned.match(/^([^:\s]+)\s*[:\s]\s*(-?\d+(?:\.\d+)?)\s*->\s*(-?\d+(?:\.\d+)?)$/);
3975
5798
  if (!m) return null;
5799
+ const state = m[1] ?? "";
5800
+ if (!isValueName(state)) return null;
3976
5801
  return {
3977
- state: m[1] ?? "",
5802
+ state,
3978
5803
  from: parseFloat(m[2] ?? "0"),
3979
5804
  to: parseFloat(m[3] ?? "0"),
3980
5805
  pos: { line: lineNo }
@@ -3982,13 +5807,15 @@ function parseTweenLine(s, lineNo) {
3982
5807
  }
3983
5808
  function parseSetLine(s, lineNo) {
3984
5809
  const cleaned = s.replace(/^-\s*/, "").trim();
3985
- const m = cleaned.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*[:\s]\s*(.+)$/);
5810
+ const m = cleaned.match(/^([^:\s]+)\s*[:\s]\s*(.+)$/);
3986
5811
  if (!m) return null;
5812
+ const state = m[1] ?? "";
5813
+ if (!isValueName(state)) return null;
3987
5814
  const raw = (m[2] ?? "").trim();
3988
5815
  const stripped = stripQuotes(raw);
3989
5816
  const asNum = Number(stripped);
3990
5817
  const value = Number.isFinite(asNum) && stripped !== "" && !isNaN(asNum) ? asNum : stripped;
3991
- return { state: m[1] ?? "", value, pos: { line: lineNo } };
5818
+ return { state, value, pos: { line: lineNo } };
3992
5819
  }
3993
5820
 
3994
5821
  // src/notation-lint.ts
@@ -4038,7 +5865,6 @@ var KIND_TO_JA = {
4038
5865
  tree: "\u968E\u5C64\u30C4\u30EA\u30FC",
4039
5866
  userJourney: "\u30E6\u30FC\u30B6\u30FC\u30B8\u30E3\u30FC\u30CB\u30FC",
4040
5867
  mindMap: "\u30DE\u30A4\u30F3\u30C9\u30DE\u30C3\u30D7",
4041
- mindMapRadial: "\u653E\u5C04\u72B6\u30DE\u30A4\u30F3\u30C9\u30DE\u30C3\u30D7",
4042
5868
  funnel: "\u30D5\u30A1\u30CD\u30EB (\u6BB5\u968E\u5225\u96E2\u8131)",
4043
5869
  quadrant: "\u56DB\u8C61\u9650\u30DE\u30C8\u30EA\u30AF\u30B9",
4044
5870
  gantt: "\u30AC\u30F3\u30C8\u30C1\u30E3\u30FC\u30C8",
@@ -4047,7 +5873,7 @@ var KIND_TO_JA = {
4047
5873
  };
4048
5874
  function applyTopicAutoFix(topic) {
4049
5875
  const kindMatch = topic.match(
4050
- /^\s*(chart|flow|swimlane|sequence|topology|er|stateMachine2?|infrastructure|classDiagram|tree|userJourney|mindMap(?:Radial)?|funnel|quadrant|gantt|flowchart|network|line chart|pie chart|bar chart)\b/i
5876
+ /^\s*(chart|flow|swimlane|sequence|topology|er|stateMachine2?|infrastructure|classDiagram|tree|userJourney|mindMap|funnel|quadrant|gantt|flowchart|network|line chart|pie chart|bar chart)\b/i
4051
5877
  );
4052
5878
  if (kindMatch) {
4053
5879
  const kind = kindMatch[1].toLowerCase();
@@ -4133,7 +5959,7 @@ function ruleGanttUnknownDependsOn(d) {
4133
5959
  function ruleMindMapParentReference(d) {
4134
5960
  const out = [];
4135
5961
  for (const n of d.nodes) {
4136
- if ((n.kind === "mind-map" || n.kind === "mind-radial") && n.mindData) {
5962
+ if (n.kind === "mind-map" && n.mindData) {
4137
5963
  const known = /* @__PURE__ */ new Set([n.mindData.rootId]);
4138
5964
  for (const b of n.mindData.branches) known.add(b.id);
4139
5965
  for (const b of n.mindData.branches) {
@@ -4209,7 +6035,10 @@ function ruleFunnelMonotonicCount(d) {
4209
6035
  if (n.kind === "funnel-stages" && n.funnelData) {
4210
6036
  const stages = n.funnelData;
4211
6037
  for (let i = 1; i < stages.length; i++) {
4212
- if (stages[i].count > stages[i - 1].count) {
6038
+ const \u4ECA = stages[i].count;
6039
+ const \u524D = stages[i - 1].count;
6040
+ if (typeof \u4ECA !== "number" || typeof \u524D !== "number") continue;
6041
+ if (\u4ECA > \u524D) {
4213
6042
  out.push({
4214
6043
  rule: "funnel-increasing-count",
4215
6044
  severity: "warn",
@@ -4297,7 +6126,7 @@ function matchActorHead(line) {
4297
6126
  indentText: indentText2,
4298
6127
  indent: indentText2.length,
4299
6128
  rawName: rawName2,
4300
- name: unquote(rawName2),
6129
+ name: unquote2(rawName2),
4301
6130
  hasColon: true,
4302
6131
  rest: rest.trimEnd()
4303
6132
  };
@@ -4310,21 +6139,21 @@ function matchActorHead(line) {
4310
6139
  indentText,
4311
6140
  indent: indentText.length,
4312
6141
  rawName,
4313
- name: unquote(rawName),
6142
+ name: unquote2(rawName),
4314
6143
  hasColon: false,
4315
6144
  rest: ""
4316
6145
  };
4317
6146
  }
4318
- function unquote(raw) {
6147
+ function unquote2(raw) {
4319
6148
  if (!raw.startsWith('"') || !raw.endsWith('"') || raw.length < 2) return raw;
4320
6149
  return raw.slice(1, -1).replace(/\\(.)/g, "$1");
4321
6150
  }
4322
6151
  function upsertAtToken(rest, x, y) {
4323
- const kept = splitOutsideQuotes(rest).filter((t) => !/^@-?\d+(\.\d+)?\s*[,、]\s*-?\d+(\.\d+)?$/.test(t));
6152
+ const kept = splitOutsideQuotes2(rest).filter((t) => !/^@-?\d+(\.\d+)?\s*[,、]\s*-?\d+(\.\d+)?$/.test(t));
4324
6153
  kept.push(`@${x},${y}`);
4325
6154
  return kept.join(" ");
4326
6155
  }
4327
- function splitOutsideQuotes(s) {
6156
+ function splitOutsideQuotes2(s) {
4328
6157
  const out = [];
4329
6158
  let buf = "";
4330
6159
  let quote = null;
@@ -4451,20 +6280,7 @@ var VALID_KIND_SET = /* @__PURE__ */ new Set([
4451
6280
  "library",
4452
6281
  "interface"
4453
6282
  ]);
4454
- var VALID_PRESETS = [
4455
- "sequence",
4456
- "flow",
4457
- "swimlane",
4458
- "er",
4459
- "state",
4460
- "topology",
4461
- "solidity",
4462
- "gantt",
4463
- "class",
4464
- "pie",
4465
- "c4",
4466
- "mind"
4467
- ];
6283
+ var VALID_PRESETS = [...PRESET_TYPES];
4468
6284
  function validateLayoutPos(v, path, errors) {
4469
6285
  if (v === void 0) return;
4470
6286
  if (!v || typeof v !== "object" || Array.isArray(v)) {
@@ -4479,15 +6295,122 @@ function validateLayoutPos(v, path, errors) {
4479
6295
  errors.push({ path: `${path}.y`, message: "pos.y must be a finite number" });
4480
6296
  }
4481
6297
  }
6298
+ var \u5199\u3057\u306E\u6700\u5927\u306E\u6DF1\u3055 = 64;
6299
+ var \u5199\u3057\u306E\u6700\u5927\u306E\u9805\u76EE\u6570 = 5e6;
6300
+ var \u5199\u305B\u306A\u3044 = class extends Error {
6301
+ constructor(path, \u7406\u7531) {
6302
+ super(`${path}: ${\u7406\u7531}`);
6303
+ this.path = path;
6304
+ this.\u7406\u7531 = \u7406\u7531;
6305
+ }
6306
+ path;
6307
+ \u7406\u7531;
6308
+ };
6309
+ function \u7D20\u306E\u30C7\u30FC\u30BF\u306B\u5199\u3059(root) {
6310
+ const \u5199\u3057\u6E08 = /* @__PURE__ */ new WeakMap();
6311
+ let \u9805\u76EE\u6570 = 0;
6312
+ let \u8AAD\u3093\u3067\u3044\u308B\u5834\u6240 = "$";
6313
+ const \u5668\u3092\u4F5C\u308B = (v, \u6DF1\u3055, path) => {
6314
+ \u9805\u76EE\u6570 += 1;
6315
+ if (\u9805\u76EE\u6570 > \u5199\u3057\u306E\u6700\u5927\u306E\u9805\u76EE\u6570) {
6316
+ throw new \u5199\u305B\u306A\u3044(path, `\u9805\u76EE\u304C\u591A\u3059\u304E\u308B (\u4E0A\u9650 ${\u5199\u3057\u306E\u6700\u5927\u306E\u9805\u76EE\u6570})`);
6317
+ }
6318
+ if (v === null || typeof v !== "object") return { \u5024: v, \u67A0: null };
6319
+ const \u65E2\u306B\u3042\u308B = \u5199\u3057\u6E08.get(v);
6320
+ if (\u65E2\u306B\u3042\u308B !== void 0) return { \u5024: \u65E2\u306B\u3042\u308B, \u67A0: null };
6321
+ if (\u6DF1\u3055 >= \u5199\u3057\u306E\u6700\u5927\u306E\u6DF1\u3055) {
6322
+ throw new \u5199\u305B\u306A\u3044(path, `\u5165\u308C\u5B50\u304C\u6DF1\u3059\u304E\u308B (\u4E0A\u9650 ${\u5199\u3057\u306E\u6700\u5927\u306E\u6DF1\u3055})`);
6323
+ }
6324
+ \u8AAD\u3093\u3067\u3044\u308B\u5834\u6240 = path;
6325
+ const \u4E26\u3073\u304B = Array.isArray(v);
6326
+ const \u5668 = \u4E26\u3073\u304B ? [] : {};
6327
+ \u5199\u3057\u6E08.set(v, \u5668);
6328
+ if (\u4E26\u3073\u304B) {
6329
+ const \u751F\u306E\u9577\u3055 = +v.length;
6330
+ const \u9577\u3055 = Number.isNaN(\u751F\u306E\u9577\u3055) ? 0 : Math.min(Math.max(Math.trunc(\u751F\u306E\u9577\u3055), 0), Number.MAX_SAFE_INTEGER);
6331
+ \u9805\u76EE\u6570 += \u9577\u3055;
6332
+ if (\u9805\u76EE\u6570 > \u5199\u3057\u306E\u6700\u5927\u306E\u9805\u76EE\u6570) {
6333
+ throw new \u5199\u305B\u306A\u3044(path, `\u9805\u76EE\u304C\u591A\u3059\u304E\u308B (\u4E0A\u9650 ${\u5199\u3057\u306E\u6700\u5927\u306E\u9805\u76EE\u6570})`);
6334
+ }
6335
+ return { \u5024: \u5668, \u67A0: { \u5143: v, \u5668, \u540D\u524D\u306E\u4E26\u3073: null, \u9577\u3055, \u6B21: 0, \u6DF1\u3055, path } };
6336
+ }
6337
+ const \u540D\u524D\u306E\u4E26\u3073 = Object.keys(v);
6338
+ \u9805\u76EE\u6570 += \u540D\u524D\u306E\u4E26\u3073.length;
6339
+ if (\u9805\u76EE\u6570 > \u5199\u3057\u306E\u6700\u5927\u306E\u9805\u76EE\u6570) {
6340
+ throw new \u5199\u305B\u306A\u3044(path, `\u9805\u76EE\u304C\u591A\u3059\u304E\u308B (\u4E0A\u9650 ${\u5199\u3057\u306E\u6700\u5927\u306E\u9805\u76EE\u6570})`);
6341
+ }
6342
+ return { \u5024: \u5668, \u67A0: { \u5143: v, \u5668, \u540D\u524D\u306E\u4E26\u3073, \u9577\u3055: \u540D\u524D\u306E\u4E26\u3073.length, \u6B21: 0, \u6DF1\u3055, path } };
6343
+ };
6344
+ try {
6345
+ const \u5148\u982D = \u5668\u3092\u4F5C\u308B(root, 0, "$");
6346
+ const \u7A4D\u307F = \u5148\u982D.\u67A0 ? [\u5148\u982D.\u67A0] : [];
6347
+ while (\u7A4D\u307F.length > 0) {
6348
+ const \u4ECA = \u7A4D\u307F[\u7A4D\u307F.length - 1];
6349
+ if (\u4ECA.\u6B21 >= \u4ECA.\u9577\u3055) {
6350
+ \u7A4D\u307F.pop();
6351
+ continue;
6352
+ }
6353
+ const key = \u4ECA.\u540D\u524D\u306E\u4E26\u3073 === null ? String(\u4ECA.\u6B21) : \u4ECA.\u540D\u524D\u306E\u4E26\u3073[\u4ECA.\u6B21];
6354
+ \u4ECA.\u6B21 += 1;
6355
+ const \u5B50\u306Epath = \u4ECA.\u540D\u524D\u306E\u4E26\u3073 === null ? `${\u4ECA.path}[${key}]` : `${\u4ECA.path}.${key}`;
6356
+ \u8AAD\u3093\u3067\u3044\u308B\u5834\u6240 = \u5B50\u306Epath;
6357
+ const \u751F\u306E\u5024 = \u4ECA.\u5143[key];
6358
+ const \u5B50 = \u5668\u3092\u4F5C\u308B(\u751F\u306E\u5024, \u4ECA.\u6DF1\u3055 + 1, \u5B50\u306Epath);
6359
+ if (Array.isArray(\u4ECA.\u5668)) \u4ECA.\u5668.push(\u5B50.\u5024);
6360
+ else {
6361
+ Object.defineProperty(\u4ECA.\u5668, key, {
6362
+ value: \u5B50.\u5024,
6363
+ enumerable: true,
6364
+ writable: true,
6365
+ configurable: true
6366
+ });
6367
+ }
6368
+ if (\u5B50.\u67A0) \u7A4D\u307F.push(\u5B50.\u67A0);
6369
+ }
6370
+ return { ok: true, value: \u5148\u982D.\u5024 };
6371
+ } catch (e) {
6372
+ if (e instanceof \u5199\u305B\u306A\u3044) {
6373
+ return { ok: false, error: { path: e.path, message: e.\u7406\u7531 } };
6374
+ }
6375
+ return {
6376
+ ok: false,
6377
+ error: {
6378
+ path: \u8AAD\u3093\u3067\u3044\u308B\u5834\u6240,
6379
+ message: "\u5165\u529B\u3092\u8AAD\u307F\u53D6\u308C\u306A\u3044",
6380
+ hint: e instanceof Error ? e.message : String(e)
6381
+ }
6382
+ };
6383
+ }
6384
+ }
4482
6385
  function validateJson(json) {
4483
6386
  const errors = [];
4484
- if (!json || typeof json !== "object" || Array.isArray(json)) {
6387
+ let root\u304Cobject\u304B;
6388
+ try {
6389
+ root\u304Cobject\u304B = !!json && typeof json === "object" && !Array.isArray(json);
6390
+ } catch (e) {
6391
+ return {
6392
+ ok: false,
6393
+ errors: [
6394
+ {
6395
+ path: "$",
6396
+ message: "\u5165\u529B\u3092\u8AAD\u307F\u53D6\u308C\u306A\u3044",
6397
+ hint: e instanceof Error ? e.message : String(e)
6398
+ }
6399
+ ]
6400
+ };
6401
+ }
6402
+ if (!root\u304Cobject\u304B) {
4485
6403
  return { ok: false, errors: [{ path: "$", message: "root must be a JSON object" }] };
4486
6404
  }
4487
- const j = json;
6405
+ const \u5199\u3057 = \u7D20\u306E\u30C7\u30FC\u30BF\u306B\u5199\u3059(json);
6406
+ if (!\u5199\u3057.ok) return { ok: false, errors: [\u5199\u3057.error] };
6407
+ const j = \u5199\u3057.value;
4488
6408
  if (typeof j.title !== "string" || j.title.length === 0) {
4489
6409
  errors.push({ path: "$.title", message: "title must be a non-empty string" });
4490
6410
  }
6411
+ if (j.eyebrow !== void 0 && typeof j.eyebrow !== "string") {
6412
+ errors.push({ path: "$.eyebrow", message: "eyebrow must be a string if present" });
6413
+ }
4491
6414
  if (j.layout !== void 0 && j.layout !== "auto" && j.layout !== "manual") {
4492
6415
  errors.push({ path: "$.layout", message: 'layout must be "auto" or "manual" if present' });
4493
6416
  }
@@ -4567,12 +6490,109 @@ function validateJson(json) {
4567
6490
  if (typeof po.step !== "string" || po.step.length === 0) {
4568
6491
  errors.push({ path: `$.animation[${i}].step`, message: "phase.step must be a non-empty string" });
4569
6492
  }
6493
+ validatePhaseMotion(po, i, errors);
4570
6494
  });
4571
6495
  }
4572
6496
  }
6497
+ validateStates(j.states, errors);
6498
+ validateValues(j.values, errors);
4573
6499
  if (errors.length > 0) return { ok: false, errors };
4574
6500
  return { ok: true, data: j };
4575
6501
  }
6502
+ function validatePhaseMotion(po, i, errors) {
6503
+ if (po.tween !== void 0) {
6504
+ if (!po.tween || typeof po.tween !== "object" || Array.isArray(po.tween)) {
6505
+ errors.push({
6506
+ path: `$.animation[${i}].tween`,
6507
+ message: "tween must be a plain object of state -> [from, to]"
6508
+ });
6509
+ } else {
6510
+ for (const [name, range] of Object.entries(po.tween)) {
6511
+ const path = `$.animation[${i}].tween.${name}`;
6512
+ if (!isValueName(name)) errors.push({ path, ...valueNameIssue(name) });
6513
+ if (!Array.isArray(range) || range.length !== 2) {
6514
+ errors.push({ path, message: "tween value must be [from, to]" });
6515
+ continue;
6516
+ }
6517
+ for (const v of range) {
6518
+ if (typeof v !== "number" || !Number.isFinite(v)) {
6519
+ errors.push({ path, message: "tween value must be finite numbers", hint: `got ${typeof v}` });
6520
+ break;
6521
+ }
6522
+ }
6523
+ }
6524
+ }
6525
+ }
6526
+ if (po.set !== void 0) {
6527
+ if (!po.set || typeof po.set !== "object" || Array.isArray(po.set)) {
6528
+ errors.push({
6529
+ path: `$.animation[${i}].set`,
6530
+ message: "set must be a plain object of state -> value"
6531
+ });
6532
+ } else {
6533
+ for (const [name, value] of Object.entries(po.set)) {
6534
+ const path = `$.animation[${i}].set.${name}`;
6535
+ if (!isValueName(name)) errors.push({ path, ...valueNameIssue(name) });
6536
+ const t = typeof value;
6537
+ if (t !== "number" && t !== "string") {
6538
+ errors.push({ path, message: "set value must be a number or string", hint: `got ${t}` });
6539
+ } else if (t === "number" && !Number.isFinite(value)) {
6540
+ errors.push({ path, message: "set value must be a finite number" });
6541
+ }
6542
+ }
6543
+ }
6544
+ }
6545
+ }
6546
+ function validateStates(v, errors) {
6547
+ if (v === void 0) return;
6548
+ if (!v || typeof v !== "object" || Array.isArray(v)) {
6549
+ errors.push({ path: "$.states", message: "states must be a plain object of name -> initial value" });
6550
+ return;
6551
+ }
6552
+ for (const [name, initial] of Object.entries(v)) {
6553
+ if (!isValueName(name)) {
6554
+ errors.push({ path: `$.states.${name}`, ...valueNameIssue(name) });
6555
+ }
6556
+ const t = typeof initial;
6557
+ if (t !== "number" && t !== "string") {
6558
+ errors.push({
6559
+ path: `$.states.${name}`,
6560
+ message: "state initial must be a number or string",
6561
+ hint: `got ${t}`
6562
+ });
6563
+ } else if (t === "number" && !Number.isFinite(initial)) {
6564
+ errors.push({ path: `$.states.${name}`, message: "state initial must be a finite number" });
6565
+ }
6566
+ }
6567
+ }
6568
+ function validateValues(v, errors) {
6569
+ if (v === void 0) return;
6570
+ if (!v || typeof v !== "object" || Array.isArray(v)) {
6571
+ errors.push({ path: "$.values", message: "values must be a plain object of name -> expression" });
6572
+ return;
6573
+ }
6574
+ for (const [name, expression] of Object.entries(v)) {
6575
+ if (!isValueName(name)) {
6576
+ errors.push({ path: `$.values.${name}`, ...valueNameIssue(name) });
6577
+ }
6578
+ if (typeof expression !== "string" || expression.trim() === "") {
6579
+ errors.push({
6580
+ path: `$.values.${name}`,
6581
+ message: "value expression must be a non-empty string",
6582
+ hint: '`"{inflow} - {done}"` \u306E\u5F62\u3067\u66F8\u304F'
6583
+ });
6584
+ continue;
6585
+ }
6586
+ for (const issue of checkValueExpression(expression, name)) {
6587
+ errors.push({ path: `$.values.${name}`, ...issue });
6588
+ }
6589
+ }
6590
+ }
6591
+ function \u6574\u3048\u305F\u5C0F\u898B\u51FA\u3057(v) {
6592
+ if (v === void 0) return void 0;
6593
+ const t = v.trim();
6594
+ return t.length > 0 ? t : void 0;
6595
+ }
4576
6596
  function jsonToDoc(json) {
4577
6597
  const p0 = { line: 0 };
4578
6598
  const actors = json.actors.map((a) => {
@@ -4614,28 +6634,44 @@ function jsonToDoc(json) {
4614
6634
  cardinality: s.cardinality,
4615
6635
  labelOffsetX: s.labelOffsetX,
4616
6636
  labelOffsetY: s.labelOffsetY,
6637
+ overlay: s.overlay,
4617
6638
  // CAR-1693 Phase 1: DSL 表面 pos → 内部 AST layoutPos
4618
6639
  layoutPos: s.pos,
4619
6640
  pos: p0
4620
6641
  }));
4621
- let animate;
4622
- if (json.animation && json.animation.length > 0) {
4623
- const phases = json.animation.map((p) => ({
4624
- name: p.step,
4625
- durationMs: Math.round((p.duration ?? 1.4) * 1e3),
4626
- highlight: p.focus,
4627
- body: p.body,
4628
- badge: p.badge,
4629
- pos: p0
4630
- }));
4631
- animate = { states: [], phases, pos: p0 };
4632
- }
6642
+ const states = Object.entries(json.states ?? {}).map(([name, initial]) => ({
6643
+ name,
6644
+ initial,
6645
+ pos: p0
6646
+ }));
6647
+ const phases = (json.animation ?? []).map((p) => ({
6648
+ name: p.step,
6649
+ durationMs: Math.round((p.duration ?? 1.4) * 1e3),
6650
+ highlight: p.focus,
6651
+ body: p.body,
6652
+ badge: p.badge,
6653
+ // 段の中で動かす分 (#1186)。 記法側の `tweens` / `sets` と同じ形に写す。
6654
+ // 空の配列を置かないのは、記法側が「無ければ field ごと持たない」 形だから
6655
+ ...p.tween && Object.keys(p.tween).length > 0 ? {
6656
+ tweens: Object.entries(p.tween).map(([state, [from, to]]) => ({ state, from, to, pos: p0 }))
6657
+ } : {},
6658
+ ...p.set && Object.keys(p.set).length > 0 ? { sets: Object.entries(p.set).map(([state, value]) => ({ state, value, pos: p0 })) } : {},
6659
+ pos: p0
6660
+ }));
6661
+ const animate = states.length > 0 || phases.length > 0 ? { states, phases, pos: p0 } : void 0;
4633
6662
  return {
4634
6663
  title: json.title,
4635
6664
  type: json.type,
6665
+ // 前後の空白を落としてから見る。 記法側 (`v05/parser.ts`) が `trim()` してから
6666
+ // 空かどうかを判定するため、 揃えないと **空白だけの値で入口ごとに図が変わる**
6667
+ // (記法は書かなかった扱い、 JSON は中身のない帯を描く。 Round 2 の指摘で実測)
6668
+ ...\u6574\u3048\u305F\u5C0F\u898B\u51FA\u3057(json.eyebrow) !== void 0 ? { eyebrow: \u6574\u3048\u305F\u5C0F\u898B\u51FA\u3057(json.eyebrow), eyebrowPos: p0 } : {},
4636
6669
  actors,
4637
6670
  flow: flow2,
4638
6671
  animate,
6672
+ // 他の値から決まる値 (#1181)。 書いた順に並べる = 解く順は参照から決まるので順序に
6673
+ // 意味は無いが、知らせの並びが書いた順になる
6674
+ values: json.values ? Object.entries(json.values).map(([name, expression]) => ({ name, expression, pos: p0 })) : void 0,
4639
6675
  viewport: json.viewport ? { ...json.viewport, pos: p0 } : void 0,
4640
6676
  lanes: json.lanes ? Object.fromEntries(
4641
6677
  Object.entries(json.lanes).map(([id, l]) => {
@@ -4682,8 +6718,12 @@ var diagram_default = {
4682
6718
  },
4683
6719
  type: {
4684
6720
  type: "string",
4685
- enum: ["sequence", "flow", "swimlane", "er", "state", "topology", "solidity", "gantt", "class", "pie", "c4", "mind"],
4686
- description: "preset type = \u56F3\u306E\u7A2E\u985E\u3002 sequence (\u6642\u7CFB\u5217 API \u547C\u3073\u51FA\u3057) / flow (\u51E6\u7406 flow) / swimlane (\u8CAC\u52D9\u5206\u62C5 flow) / er (DB schema) / state (\u72B6\u614B\u9077\u79FB) / topology (network) / solidity (contract) / gantt (schedule) / class (UML class) / pie (\u5186\u30B0\u30E9\u30D5) / c4 (architecture) / mind (mind map)"
6721
+ enum: ["sequence", "flow", "swimlane", "er", "state", "topology", "solidity", "gantt", "class", "pie", "bar", "line", "funnel", "tree", "journey", "quadrant", "c4", "mind"],
6722
+ description: '\u56F3\u306E\u7A2E\u985E\u3002 \u578B\u3054\u3068\u306B actors \u306E\u66F8\u304D\u65B9\u304C\u9055\u3046\u3002 [\u95A2\u4FC2\u3092\u63CF\u304F] sequence (\u6642\u7CFB\u5217\u306E\u547C\u3073\u51FA\u3057) / flow (\u51E6\u7406\u306E\u6D41\u308C) / swimlane (\u8CAC\u52D9\u3054\u3068\u306E\u6D41\u308C) / er (DB \u306E schema) / state (\u72B6\u614B\u306E\u9077\u79FB) / topology (network) / solidity (contract) / class (UML \u306E class) / c4 (architecture) / mind (\u767A\u60F3\u306E\u679D\u5206\u304B\u308C) \u306F actors \u306B\u540D\u524D\u3092\u4E26\u3079 flow \u306B\u77E2\u5370\u3092\u66F8\u304F\u3002 [\u5024\u3092\u63CF\u304F] pie (\u5272\u5408) / bar (\u68D2\u306E\u9AD8\u3055) / line (\u7DDA\u306E\u9AD8\u3055\u3001 \u66F8\u3044\u305F\u9806\u306B\u4E26\u3076) \u306F actors \u306B `- \u540D\u524D: "45"` \u306E\u5F62\u3067\u6570\u3092\u66F8\u304F\u3002 funnel (\u6BB5\u3054\u3068\u306B\u6E1B\u308B\u6570) \u3082\u540C\u3058\u5F62\u3002 [\u8A9E\u3092\u63CF\u304F] journey (\u4F53\u9A13\u306E\u8D77\u4F0F) \u306F `- \u767B\u9332: "\u4E0D\u6E80"` \u306E\u5F62\u3067 \u6700\u9AD8 / \u6E80\u8DB3 / \u666E\u901A / \u4E0D\u6E80 / \u6012\u308A \u306E\u3069\u308C\u304B\u3092\u66F8\u304F\u3002 quadrant (2 \u8EF8\u306E\u4ED5\u5206\u3051) \u306F `- \u91CD\u8907\u524A\u9664: "\u5DE6\u4E0A"` \u306E\u5F62\u3067 \u5DE6\u4E0A / \u53F3\u4E0A / \u5DE6\u4E0B / \u53F3\u4E0B \u306E\u3069\u308C\u304B\u3092\u66F8\u304F\u3002 [\u6642\u671F\u3092\u63CF\u304F] gantt (\u5DE5\u7A0B\u306E\u4E26\u3073) \u306F `- \u8A2D\u8A08: "1\u6708"` \u306E\u5F62\u3067\u59CB\u307E\u308A\u306E\u6642\u671F\u3092\u66F8\u304D\u3001 flow \u306E\u77E2\u5370\u3067\u524D\u5F8C\u95A2\u4FC2\u3092\u66F8\u304F\u3002 [\u89AA\u5B50\u3092\u63CF\u304F] tree (\u89AA\u5B50\u306E\u5165\u308C\u5B50) \u306F actors \u306B\u540D\u524D\u3092\u4E26\u3079 flow \u306E\u77E2\u5370\u3067\u89AA\u5B50\u3092\u66F8\u304F (\u77E2\u5370\u306E\u5148\u304C\u5B50)'
6723
+ },
6724
+ eyebrow: {
6725
+ type: "string",
6726
+ description: "\u56F3\u8868\u306E\u7BB1\u306E\u4E0A\u306B\u51FA\u3059\u5C0F\u898B\u51FA\u3057 (\u7701\u7565\u53EF)\u3002 \u52B9\u304F\u306E\u306F\u56F3\u5168\u4F53\u3092 1 \u7BB1\u306B\u3059\u308B\u578B (pie / bar / line / funnel / tree / journey / quadrant / mind / gantt) \u3060\u3051\u3002 \u7BB1\u3054\u3068\u306B\u5206\u304B\u308C\u308B\u578B\u3067\u306F\u76F8\u624B\u304C\u6C7A\u307E\u3089\u306A\u3044\u305F\u3081\u3001 actors[].eyebrow \u306B\u66F8\u304F"
4687
6727
  },
4688
6728
  actors: {
4689
6729
  type: "array",
@@ -4735,13 +6775,39 @@ var diagram_default = {
4735
6775
  guard: { type: "string", description: "state \u9077\u79FB\u306E\u6761\u4EF6 (kind: state \u7528)" },
4736
6776
  cardinality: { type: "string", description: "ER \u306E\u591A\u91CD\u5EA6 (1..N \u7B49\u3001 kind: er \u7528)" },
4737
6777
  labelOffsetX: { type: "number", description: "\u30E9\u30D9\u30EB\u4F4D\u7F6E x \u8ABF\u6574" },
4738
- labelOffsetY: { type: "number", description: "\u30E9\u30D9\u30EB\u4F4D\u7F6E y \u8ABF\u6574" }
6778
+ labelOffsetY: { type: "number", description: "\u30E9\u30D9\u30EB\u4F4D\u7F6E y \u8ABF\u6574" },
6779
+ overlay: { type: "boolean", description: "true \u3067\u8AAC\u660E\u6587\u3092\u77E2\u5370\u306E\u7DDA\u306E\u4E0A\u306B\u91CD\u306D\u308B (\u5206\u5C90\u56F3\u306E\u6761\u4EF6\u30E9\u30D9\u30EB\u7528)" }
4739
6780
  }
4740
6781
  }
4741
6782
  },
6783
+ states: {
6784
+ type: "object",
6785
+ description: "\u72B6\u614B\u306E\u521D\u671F\u5024\u3002 \u540D\u524D -> \u521D\u671F\u5024 \u306E object\u3002 optional\u3002 \u7BB1\u306E\u6587\u5B57\u306B `{\u540D\u524D}` \u3092\u7F6E\u304F\u3068\u3001 \u3053\u3053\u306B\u66F8\u3044\u305F\u5024\u304C\u63CF\u753B\u6642\u306B\u7F6E\u304D\u63DB\u308F\u308B\u3002 \u6BB5\u3067\u52D5\u304B\u3059\u306B\u306F animation[].tween / animation[].set \u3092\u4F7F\u3046\u3002",
6786
+ additionalProperties: false,
6787
+ patternProperties: {
6788
+ "^[a-zA-Z_][a-zA-Z0-9_]*$": {
6789
+ type: ["number", "string"],
6790
+ description: "\u521D\u671F\u5024\u3002 \u6570\u304B\u6587\u5B57\u5217\u3002 \u540D\u524D\u306F\u82F1\u5B57\u304B _ \u3067\u59CB\u3081\u3001 \u82F1\u6570\u5B57\u3068 _ \u3060\u3051\u3092\u4F7F\u3046"
6791
+ }
6792
+ },
6793
+ examples: [{ inflow: 0, done: 0 }]
6794
+ },
6795
+ values: {
6796
+ type: "object",
6797
+ description: "\u4ED6\u306E\u5024\u304B\u3089\u81EA\u52D5\u3067\u6C7A\u307E\u308B\u5024\u3002 \u540D\u524D -> \u5F0F \u306E object\u3002 optional\u3002 \u5F0F\u306B\u306F\u56DB\u5247 (+ - * /) \u3068\u62EC\u5F27\u3001 \u6BD4\u8F03 (> >= < <= == !=)\u3001 min / max \u304C\u66F8\u3051\u308B\u3002 \u4ED6\u306E\u5024\u306F {\u540D\u524D} \u3067\u8AAD\u3080\u3002 \u89E3\u304F\u306E\u306F\u63CF\u753B\u5074\u3067\u3001 \u53C2\u7167\u3057\u305F\u5024\u304C\u52D5\u3051\u3070\u8FFD\u968F\u3059\u308B\u3002",
6798
+ additionalProperties: false,
6799
+ patternProperties: {
6800
+ "^[a-zA-Z_][a-zA-Z0-9_]*$": {
6801
+ type: "string",
6802
+ minLength: 1,
6803
+ description: "\u5F0F\u3002 \u4F8B `{inflow} - {done}`"
6804
+ }
6805
+ },
6806
+ examples: [{ waiting: "{inflow} - {done}", busy: "{waiting} > 80" }]
6807
+ },
4742
6808
  animation: {
4743
6809
  type: "array",
4744
- description: "\u30A2\u30CB\u30E1\u30FC\u30B7\u30E7\u30F3 phase \u914D\u5217\u3002 \u5404 phase \u3067 focus \u5BFE\u8C61\u3092 highlight \u3059\u308B\u3002 optional\u3002",
6810
+ description: "\u30A2\u30CB\u30E1\u30FC\u30B7\u30E7\u30F3 phase \u914D\u5217\u3002 \u5404 phase \u3067 focus \u5BFE\u8C61\u3092 highlight \u3057\u3001 tween / set \u3067 states \u306E\u5024\u3092\u52D5\u304B\u3059\u3002 optional\u3002",
4745
6811
  items: {
4746
6812
  type: "object",
4747
6813
  required: ["step"],
@@ -4751,7 +6817,28 @@ var diagram_default = {
4751
6817
  duration: { type: "number", minimum: 0.1, description: "phase \u6642\u9593 (\u79D2\u3001 default 1.4)" },
4752
6818
  focus: { type: "array", items: { type: "string" }, description: "\u3053\u306E phase \u3067 active \u5316\u3059\u308B actor \u540D or edge 'A -> B' \u306E\u914D\u5217" },
4753
6819
  body: { type: "string", description: "phase \u8AAC\u660E\u6587" },
4754
- badge: { type: "string", description: "phase \u4E2D\u306B\u8868\u793A\u3059\u308B badge label" }
6820
+ badge: { type: "string", description: "phase \u4E2D\u306B\u8868\u793A\u3059\u308B badge label" },
6821
+ tween: {
6822
+ type: "object",
6823
+ description: "\u3053\u306E phase \u3067\u88DC\u9593\u3059\u308B\u72B6\u614B\u3002 \u72B6\u614B\u540D -> [\u958B\u59CB\u5024, \u7D42\u4E86\u5024]\u3002 \u540D\u524D\u306F\u82F1\u5B57\u304B _ \u3067\u59CB\u3081\u3001 \u82F1\u6570\u5B57\u3068 _ \u3060\u3051\u3092\u4F7F\u3046",
6824
+ additionalProperties: false,
6825
+ patternProperties: {
6826
+ "^[a-zA-Z_][a-zA-Z0-9_]*$": {
6827
+ type: "array",
6828
+ items: { type: "number" },
6829
+ minItems: 2,
6830
+ maxItems: 2
6831
+ }
6832
+ }
6833
+ },
6834
+ set: {
6835
+ type: "object",
6836
+ description: "\u3053\u306E phase \u306E\u5207\u66FF\u3067\u5DEE\u3057\u66FF\u3048\u308B\u72B6\u614B\u3002 \u72B6\u614B\u540D -> \u5024\u3002 \u540D\u524D\u306F\u82F1\u5B57\u304B _ \u3067\u59CB\u3081\u3001 \u82F1\u6570\u5B57\u3068 _ \u3060\u3051\u3092\u4F7F\u3046",
6837
+ additionalProperties: false,
6838
+ patternProperties: {
6839
+ "^[a-zA-Z_][a-zA-Z0-9_]*$": { type: ["number", "string"] }
6840
+ }
6841
+ }
4755
6842
  }
4756
6843
  }
4757
6844
  },
@@ -4865,6 +6952,6 @@ function isV05Source(src) {
4865
6952
  return true;
4866
6953
  }
4867
6954
 
4868
- export { DIAGRAM_BOUNDARY_PADDING, MAX_INPUT_BYTES, MAX_INPUT_ELEMENTS, MAX_PART_SCALE, NODE_KIND_ALIAS, NODE_KIND_VALID, PRESET_TYPES, RELATIVE_GAP_DEFAULT, TONE_ALIAS, autoFix, compileToCdl, computeDiagramBoundingBox, countBytes, countDiagramElements, countDocElements, describeOversize, describeOversizeSource, diagramJsonSchema, isColorValue, jsonToDiagram, lintDiagram, measureActorBoxes, normalizePartScale, orderByDependency, parseFocusEntry, parseRelativePos, parseTextDsl, parseTextDslV05, partBoxInFrame, partDrawsInDiagram, partIsMeasurable, partRenderSize, partScaleFactor, partTargetScale, partTargetSize, partVisualSize, partsGridCenters, pointsOutside, rectsOverlap, resolveRelativePos, stripExternalPaint, stripQuotes, textDslToDiagram, validateDragonJson, writeActorPosition };
6955
+ export { DIAGRAM_BOUNDARY_PADDING, MAX_INPUT_BYTES, MAX_INPUT_ELEMENTS, MAX_PART_SCALE, NODE_KIND_ALIAS, NODE_KIND_VALID, PRESET_TYPES, RELATIVE_GAP_DEFAULT, TONE_ALIAS, TOP_LEVEL_KEYS, autoFix, compileToCdl, computeDiagramBoundingBox, countBytes, countDiagramElements, countDocElements, describeOversize, describeOversizeSource, diagramJsonSchema, isColorValue, jsonToDiagram, lintDiagram, measureActorBoxes, normalizePartScale, orderByDependency, parseFocusEntry, parseRelativePos, parseTextDsl, parseTextDslV05, partBoxInFrame, partDrawsInDiagram, partIsMeasurable, partRenderSize, partScaleFactor, partTargetScale, partTargetSize, partVisualSize, partsGridCenters, pointsOutside, rectsOverlap, resolveRelativePos, stripExternalPaint, stripQuotes, textDslToDiagram, validateDragonJson, writeActorPosition };
4869
6956
  //# sourceMappingURL=index.js.map
4870
6957
  //# sourceMappingURL=index.js.map