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