@cardenelabs/dragon 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { NODE_KINDS, TONES, parseFormula, extractIdentifiers, inputDefaultValue, layout, applyDerivedValues, diagram, rendersRows, requiredRowsHeight, requiredRowsWidth, sequence, flow, swimlane, er, stateMachine, topology } from '@cardenelabs/cdl';
1
+ import { NODE_KINDS, TONES, EDGE_STYLES, EDGE_REVEALS, parseFormula, EDGE_HEADS, EDGE_HEAD_FILLS, extractIdentifiers, inputDefaultValue, layout, applyDerivedValues, diagram, classDiagram, sequence, sequenceStepId, flow, swimlane, er, stateMachine, topology, CLASS_RELATION_LOOK, SEQUENCE_MESSAGE_LOOK, FSM_ACTION_MARK } from '@cardenelabs/cdl';
2
2
 
3
3
  // src/keywords.ts
4
4
  var HEADERS = {
@@ -1883,6 +1883,10 @@ var \u3064\u307E\u307F\u306E\u8868 = {
1883
1883
 
1884
1884
  // src/v05/parser.ts
1885
1885
  var EDGE_SIDE_VALUES = ["top", "right", "bottom", "left"];
1886
+ var EDGE_HEAD_VALUES = EDGE_HEADS;
1887
+ var EDGE_HEAD_FILL_VALUES = EDGE_HEAD_FILLS;
1888
+ var CLASS_RELATION_VALUES = Object.keys(CLASS_RELATION_LOOK);
1889
+ var SEQ_MESSAGE_VALUES = Object.keys(SEQUENCE_MESSAGE_LOOK);
1886
1890
  var TOP_LEVEL_KEYS = [
1887
1891
  "title",
1888
1892
  "type",
@@ -1907,7 +1911,11 @@ var TOP_LEVEL_KEYS = [
1907
1911
  // 押下などの出来事で動く仕掛け (#1393)
1908
1912
  "events",
1909
1913
  // 巻き上げに応じて進む値 (#1393)
1910
- "scrolls"
1914
+ "scrolls",
1915
+ // 動いている間の帯 (#1466)。 順序図だけが読む
1916
+ "bands",
1917
+ // 矢印をいつ出すか (#1470)
1918
+ "reveal"
1911
1919
  ];
1912
1920
  var LANE_ID_ENTRY = /^([\p{L}\p{N}_-]+)\s*:\s*\{([^}]*)\}\s*$/u;
1913
1921
  function \u540D\u524D\u3068\u4E2D\u62EC\u5F27\u306B\u5272\u308B(\u884C) {
@@ -2047,7 +2055,7 @@ var NODE_KIND_VALID = /* @__PURE__ */ new Set([
2047
2055
  ...Object.keys(INFRA_KIND_ALIAS)
2048
2056
  ]);
2049
2057
  var TONE_VALID = new Set(TONES);
2050
- var STYLE_VALID = /* @__PURE__ */ new Set(["solid", "dotted-flow"]);
2058
+ var STYLE_VALID = new Set(EDGE_STYLES);
2051
2059
  function \u66F8\u3051\u308B\u8272\u540D() {
2052
2060
  return [.../* @__PURE__ */ new Set([...TONES, ...Object.keys(TONE_ALIAS)])];
2053
2061
  }
@@ -2067,6 +2075,7 @@ function parseTextDslV05(src) {
2067
2075
  let type = null;
2068
2076
  let eyebrow = null;
2069
2077
  let eyebrowLine = 0;
2078
+ let reveal = null;
2070
2079
  let axes = void 0;
2071
2080
  let axesLine = 0;
2072
2081
  let actors = [];
@@ -2075,6 +2084,7 @@ function parseTextDslV05(src) {
2075
2084
  const values = [];
2076
2085
  let viewport = void 0;
2077
2086
  let lanesMap = void 0;
2087
+ let bands = void 0;
2078
2088
  let readoutsList = void 0;
2079
2089
  let inputsList = void 0;
2080
2090
  let formulasList = void 0;
@@ -2107,6 +2117,22 @@ function parseTextDslV05(src) {
2107
2117
  i += 1;
2108
2118
  continue;
2109
2119
  }
2120
+ if (head.key === "reveal") {
2121
+ const v = (head.value ?? "").trim();
2122
+ if (v.length > 0) {
2123
+ if (EDGE_REVEALS.includes(v)) {
2124
+ reveal = v;
2125
+ } else {
2126
+ errors.push({
2127
+ line: line.no,
2128
+ message: `reveal \u304C\u8AAD\u3081\u307E\u305B\u3093 (\u66F8\u3044\u305F\u5024: ${v})`,
2129
+ hint: `\u4F7F\u3048\u308B\u8A9E = ${EDGE_REVEALS.join(" / ")}`
2130
+ });
2131
+ }
2132
+ }
2133
+ i += 1;
2134
+ continue;
2135
+ }
2110
2136
  if (head.key === "eyebrow") {
2111
2137
  const v = (head.value ?? "").trim();
2112
2138
  eyebrow = v.length > 0 ? v : null;
@@ -2287,6 +2313,24 @@ function parseTextDslV05(src) {
2287
2313
  i = next;
2288
2314
  continue;
2289
2315
  }
2316
+ if (head.key === "bands") {
2317
+ const { items, next } = collectIndentedList(lines, i + 1, line.indent);
2318
+ bands = [];
2319
+ for (const it of items) {
2320
+ const m = it.trimmed.match(/^(?:-\s*)?(.+?)\s*:\s*(\d+)\s*\.\.\s*(\d+)\s*$/);
2321
+ if (!m) {
2322
+ errors.push({
2323
+ line: it.no,
2324
+ message: `\u5E2F\u306E\u66F8\u304D\u65B9\u304C\u8AAD\u3081\u307E\u305B\u3093: "${it.trimmed}"`,
2325
+ hint: "use `- DB: 1..2` (\u9762\u306E\u540D\u524D\u3068\u3001\u6BB5\u306E\u756A\u53F7\u306E\u533A\u9593)"
2326
+ });
2327
+ continue;
2328
+ }
2329
+ bands.push({ actor: m[1], from: Number(m[2]), to: Number(m[3]) });
2330
+ }
2331
+ i = next;
2332
+ continue;
2333
+ }
2290
2334
  if (head.key === "lanes") {
2291
2335
  const { items, next } = collectIndentedList(lines, i + 1, line.indent);
2292
2336
  lanesMap = {};
@@ -2501,6 +2545,7 @@ function parseTextDslV05(src) {
2501
2545
  title,
2502
2546
  type,
2503
2547
  ...eyebrow !== null ? { eyebrow, eyebrowPos: { line: eyebrowLine } } : {},
2548
+ ...reveal !== null ? { reveal } : {},
2504
2549
  ...axes !== void 0 ? { axes, axesPos: { line: axesLine } } : {},
2505
2550
  actors,
2506
2551
  flow: flow2,
@@ -2508,6 +2553,7 @@ function parseTextDslV05(src) {
2508
2553
  ...values.length > 0 ? { values } : {},
2509
2554
  viewport,
2510
2555
  lanes: lanesMap,
2556
+ ...bands && bands.length > 0 ? { bands } : {},
2511
2557
  readouts: readoutsList,
2512
2558
  inputs: inputsList,
2513
2559
  formulas: formulasList,
@@ -3470,6 +3516,19 @@ function applyContinuationLines(actor, rest, errors) {
3470
3516
  case "\u884C":
3471
3517
  out.rows = raw.replace(/^\[|\]$/g, "").split(/,(?![^[]*\])/).map((x) => stripQuotes(x.trim())).filter(Boolean);
3472
3518
  break;
3519
+ /*
3520
+ * 行頭の印 (#1466)。 `rows` と同じ並びで、空文字はその行に印を付けない。
3521
+ *
3522
+ * **語の意味は図の種類が決める**。 ER は `pk` / `fk` / `opt`、状態遷移は
3523
+ * `entry` / `exit` / `do` / `internal`。 印の 2 軸 (形 × 塗り) は共通だが、その軸が
3524
+ * 何を指すかは種類ごとに違う = 1 つの語彙に畳むと、どの図でも意味が合わない語が残る。
3525
+ *
3526
+ * 空の要素を捨てない (`filter(Boolean)` を掛けない) = 並びが `rows` とずれる。
3527
+ */
3528
+ case "marks":
3529
+ case "\u5370":
3530
+ out.marks = raw.replace(/^\[|\]$/g, "").split(/,(?![^[]*\])/).map((x) => stripQuotes(x.trim()));
3531
+ break;
3473
3532
  case "\u4F4D\u7F6E":
3474
3533
  case "pos": {
3475
3534
  const value = stripQuotes(raw);
@@ -3589,6 +3648,9 @@ var ACTOR_ITEM_KEYS = /* @__PURE__ */ new Set([
3589
3648
  "\u524D\u306E\u5024",
3590
3649
  "rows",
3591
3650
  "\u884C",
3651
+ // 行頭の印 (#1466)。 `rows` と同じ並びで、形 × 塗り の 2 軸を語で書く
3652
+ "marks",
3653
+ "\u5370",
3592
3654
  // 箱の中に描く図形 (#1374)
3593
3655
  "shape",
3594
3656
  "\u56F3\u5F62",
@@ -3714,6 +3776,7 @@ var ACTOR_RESERVED_FIELDS = /* @__PURE__ */ new Set([
3714
3776
  "value",
3715
3777
  "previous",
3716
3778
  "rows",
3779
+ "marks",
3717
3780
  "lane",
3718
3781
  "stack",
3719
3782
  "initial",
@@ -3816,7 +3879,8 @@ var INLINE_ACTOR_ALIASES = {
3816
3879
  \u88DC\u8DB3: "subtitle",
3817
3880
  \u5024: "value",
3818
3881
  \u524D\u306E\u5024: "previous",
3819
- \u884C: "rows"
3882
+ \u884C: "rows",
3883
+ \u5370: "marks"
3820
3884
  };
3821
3885
  function \u4E2D\u62EC\u5F27\u306E\u5225\u540D\u3092\u5BC4\u305B\u308B(opts) {
3822
3886
  let \u89E6\u3063\u305F = false;
@@ -3836,6 +3900,7 @@ var INLINE_ACTOR_KEYS = /* @__PURE__ */ new Set([
3836
3900
  "value",
3837
3901
  "previous",
3838
3902
  "rows",
3903
+ "marks",
3839
3904
  "lane",
3840
3905
  "stack",
3841
3906
  "initial",
@@ -3882,6 +3947,27 @@ var FLOW_INLINE_READERS = {
3882
3947
  cardinality: (v) => v,
3883
3948
  // 矢印がどの辺から出るか (#1385)。 描画側は 4 方向を取り、書かなければ自動で選ぶ
3884
3949
  side: (v) => v !== void 0 && EDGE_SIDE_VALUES.includes(v) ? v : void 0,
3950
+ // 矢印の先の形 (#1462)。 書かなければ描画側の既定 (塗った三角) になる
3951
+ head: (v) => v !== void 0 && EDGE_HEAD_VALUES.includes(v) ? v : void 0,
3952
+ // 出どころ側の端の形 (#1466)。 ER は端ごとに違う個数を示すので両端に要る
3953
+ tailHead: (v) => v !== void 0 && EDGE_HEAD_VALUES.includes(v) ? v : void 0,
3954
+ // 端の印の塗り (#1466)。 白抜きの菱が「持つ」、塗った菱が「抱える」
3955
+ headFill: (v) => v !== void 0 && EDGE_HEAD_FILL_VALUES.includes(v) ? v : void 0,
3956
+ tailHeadFill: (v) => v !== void 0 && EDGE_HEAD_FILL_VALUES.includes(v) ? v : void 0,
3957
+ /*
3958
+ * クラス図の関係の種類 (#1466)。 書くと **線と端の形と塗りと付く側** がまとめて決まる
3959
+ * (`CLASS_RELATION_LOOK`)。
3960
+ *
3961
+ * 4 つを個別に書かせない = 組合せは 6 通りしか無く、1 つでも書き違えると読み手に別の意味で
3962
+ * 伝わる (菱を逆に置くと持ち主が入れ替わる)。 種類で書けばその 6 通りから外れない。
3963
+ */
3964
+ relation: (v) => v !== void 0 && CLASS_RELATION_VALUES.includes(v) ? v : void 0,
3965
+ /*
3966
+ * 順序図の言づての種類 (#1466)。 書くと線と矢の形がまとめて決まる。
3967
+ *
3968
+ * 呼ぶ (実線 + 塗った矢) / 返す (破線 + 開いた矢) / 投げる (実線 + 開いた矢) の 3 つ。
3969
+ */
3970
+ kind: (v) => v !== void 0 && SEQ_MESSAGE_VALUES.includes(v) ? v : void 0,
3885
3971
  /*
3886
3972
  * 矢印を値に追随させる 3 欄 (#1396)。 箱の `wBind` (#1392) と同じく文字列だけを取る。
3887
3973
  *
@@ -3948,6 +4034,8 @@ function parseActor2(line, errors) {
3948
4034
  value: opts.value,
3949
4035
  previous: opts.previous,
3950
4036
  rows: opts.rows ? opts.rows.replace(/^\[|\]$/g, "").split(/,(?![^[]*\])/).map((x) => stripQuotes(x.trim())).filter(Boolean) : void 0,
4037
+ // 行頭の印 (#1466)。 `rows` と同じ並びなので **空の要素を捨てない**
4038
+ marks: opts.marks ? opts.marks.replace(/^\[|\]$/g, "").split(/,(?![^[]*\])/).map((x) => stripQuotes(x.trim())) : void 0,
3951
4039
  lane: opts.lane,
3952
4040
  // 箱の中に描く図形 (#1374)。 パーツでは状態の上書きとして意味を持つため横取りしない
3953
4041
  shape: isPart || opts.shape === void 0 ? void 0 : \u56F3\u5F62\u3068\u3057\u3066\u8AAD\u3080(opts.shape, line.no, errors),
@@ -4043,6 +4131,22 @@ function parseFlowStep(line, no, errors) {
4043
4131
  hint: `\u4F7F\u3048\u308B\u5024 = ${EDGE_SIDE_VALUES.join(", ")}`
4044
4132
  });
4045
4133
  }
4134
+ for (const [\u6B04, \u4F7F\u3048\u308B] of [
4135
+ ["head", EDGE_HEAD_VALUES],
4136
+ ["tailHead", EDGE_HEAD_VALUES],
4137
+ ["headFill", EDGE_HEAD_FILL_VALUES],
4138
+ ["tailHeadFill", EDGE_HEAD_FILL_VALUES],
4139
+ ["relation", CLASS_RELATION_VALUES],
4140
+ ["kind", SEQ_MESSAGE_VALUES]
4141
+ ]) {
4142
+ if (opts[\u6B04] !== void 0 && \u4E2D\u62EC\u5F27[\u6B04] === void 0) {
4143
+ errors.push({
4144
+ line: line.no,
4145
+ message: `\u77E2\u5370\u306E ${\u6B04} \u304C\u8AAD\u3081\u307E\u305B\u3093: "${opts[\u6B04]}"`,
4146
+ hint: `\u4F7F\u3048\u308B\u5024 = ${\u4F7F\u3048\u308B.join(", ")}`
4147
+ });
4148
+ }
4149
+ }
4046
4150
  \u6570\u3068\u771F\u507D = \u8868\u3067\u8AAD\u3080(FLOW_INLINE_VALUE_KINDS, opts, "\u77E2\u5370\u306E ", line.no, errors);
4047
4151
  rest = \u584A.\u524D.trim();
4048
4152
  }
@@ -4050,6 +4154,12 @@ function parseFlowStep(line, no, errors) {
4050
4154
  const guard = \u4E2D\u62EC\u5F27.guard;
4051
4155
  const cardinality = \u4E2D\u62EC\u5F27.cardinality;
4052
4156
  const side = \u4E2D\u62EC\u5F27.side;
4157
+ const head = \u4E2D\u62EC\u5F27.head;
4158
+ const tailHead = \u4E2D\u62EC\u5F27.tailHead;
4159
+ const headFill = \u4E2D\u62EC\u5F27.headFill;
4160
+ const tailHeadFill = \u4E2D\u62EC\u5F27.tailHeadFill;
4161
+ const relation = \u4E2D\u62EC\u5F27.relation;
4162
+ const msgKind = \u4E2D\u62EC\u5F27.kind;
4053
4163
  const widthBind = \u8FFD\u968F\u3059\u308B\u5927\u304D\u3055\u3068\u3057\u3066\u8AAD\u3080(
4054
4164
  \u4E2D\u62EC\u5F27.widthBind,
4055
4165
  "\u77E2\u5370\u306E widthBind ",
@@ -4119,6 +4229,12 @@ function parseFlowStep(line, no, errors) {
4119
4229
  guard,
4120
4230
  cardinality,
4121
4231
  side,
4232
+ head,
4233
+ tailHead,
4234
+ headFill,
4235
+ tailHeadFill,
4236
+ relation,
4237
+ msgKind,
4122
4238
  widthBind,
4123
4239
  strokeBind,
4124
4240
  dashOffsetBind,
@@ -4808,7 +4924,6 @@ function compileToCdl(doc, opts) {
4808
4924
  doc = canonicalizeFlowActors(doc);
4809
4925
  const \u66F8\u3044\u305F\u307E\u307E = doc;
4810
4926
  doc = dropUnresolvedFlow(doc);
4811
- doc = dropSelfLoopFlow(doc);
4812
4927
  const \u5206\u3051\u305F = disambiguateActorIds(doc, opts?.onNotice);
4813
4928
  doc = \u5206\u3051\u305F.doc;
4814
4929
  let diagram2;
@@ -4892,15 +5007,16 @@ function compileToCdl(doc, opts) {
4892
5007
  applyNodeTones(diagram2, doc);
4893
5008
  reportMissingFocusTargets(\u66F8\u3044\u305F\u307E\u307E, opts?.onNotice);
4894
5009
  reportMissingFlowActors(\u66F8\u3044\u305F\u307E\u307E, opts?.onNotice);
4895
- reportSelfLoopFlow(\u66F8\u3044\u305F\u307E\u307E, opts?.onNotice);
4896
5010
  reportFlowEndpointNotHonored(doc, \u5206\u3051\u305F.\u5143\u306E\u540D\u524D, opts?.onNotice);
4897
5011
  reportLaneNotHonored(\u66F8\u3044\u305F\u307E\u307E, opts?.onNotice);
5012
+ reportActorKindNotHonored(\u66F8\u3044\u305F\u307E\u307E, opts?.onNotice);
5013
+ reportMessageOptionNotHonored(\u66F8\u3044\u305F\u307E\u307E, opts?.onNotice);
4898
5014
  reportDocEyebrowNotHonored(\u66F8\u3044\u305F\u307E\u307E, opts?.onNotice);
4899
5015
  reportDrawNotHonored(\u66F8\u3044\u305F\u307E\u307E, opts?.onNotice);
4900
5016
  reportChartFieldsNotHonored(\u66F8\u3044\u305F\u307E\u307E, opts?.onNotice);
4901
5017
  reportAxesNotHonored(\u66F8\u3044\u305F\u307E\u307E, opts?.onNotice);
4902
5018
  const placed = resolveRelativeDoc(diagram2, doc, opts?.onNotice, opts?.partsCatalog);
4903
- applyCanvasPivotPositions(diagram2, placed);
5019
+ applyCanvasPivotPositions(diagram2, placed, opts?.onNotice);
4904
5020
  const \u8FFD\u52A0\u3057\u305F\u7E26\u5217 = [];
4905
5021
  const extended = applyV05Extensions(diagram2, placed, \u8FFD\u52A0\u3057\u305F\u7E26\u5217);
4906
5022
  const inheritedDerivedSourceLines = opts?.onNotice ? /* @__PURE__ */ new Map() : void 0;
@@ -4923,6 +5039,7 @@ function compileToCdl(doc, opts) {
4923
5039
  }
4924
5040
  injectStaticPhase(merged);
4925
5041
  materializeStates(merged, doc);
5042
+ if (doc.reveal !== void 0) merged.edgeReveal = doc.reveal;
4926
5043
  \u8A9E\u306E\u72B6\u614B\u3092\u56F3\u306E\u8A9E\u3078\u76F4\u3059(merged);
4927
5044
  const \u7573\u3093\u3060\u304D\u3063\u304B\u3051 = foldValueTriggers(merged, doc, opts?.onNotice);
4928
5045
  attachDerivedValues(merged, doc, opts?.onNotice, inheritedDerivedSourceLines, \u7573\u3093\u3060\u304D\u3063\u304B\u3051);
@@ -5139,27 +5256,6 @@ function dropUnresolvedFlow(doc) {
5139
5256
  const flow2 = doc.flow.filter((s) => \u8868.has(s.from) && \u8868.has(s.to));
5140
5257
  return flow2.length === doc.flow.length ? doc : { ...doc, flow: flow2 };
5141
5258
  }
5142
- function dropSelfLoopFlow(doc) {
5143
- if (\u56F3\u7A2E\u306E\u4F5C\u308A[doc.type] === "\u56F3\u5168\u4F53\u3092 1 \u7BB1") return doc;
5144
- const flow2 = doc.flow.filter((s) => s.from !== s.to);
5145
- return flow2.length === doc.flow.length ? doc : { ...doc, flow: flow2 };
5146
- }
5147
- function reportSelfLoopFlow(doc, onNotice) {
5148
- if (!onNotice) return;
5149
- if (\u56F3\u7A2E\u306E\u4F5C\u308A[doc.type] === "\u56F3\u5168\u4F53\u3092 1 \u7BB1") return;
5150
- const \u77E5\u3089\u305B\u305F = /* @__PURE__ */ new Set();
5151
- for (const s of doc.flow) {
5152
- if (s.from !== s.to || \u77E5\u3089\u305B\u305F.has(s.from)) continue;
5153
- \u77E5\u3089\u305B\u305F.add(s.from);
5154
- onNotice({
5155
- kind: "flow-self-loop",
5156
- actor: s.from,
5157
- line: s.pos.line,
5158
- 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)`,
5159
- 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"
5160
- });
5161
- }
5162
- }
5163
5259
  function \u56F3\u306E\u5C0F\u898B\u51FA\u3057(doc) {
5164
5260
  return doc.eyebrow === void 0 ? {} : { eyebrow: doc.eyebrow };
5165
5261
  }
@@ -5238,6 +5334,59 @@ function reportFlowEndpointNotHonored(doc, \u5143\u306E\u540D\u524D, onNotice) {
5238
5334
  });
5239
5335
  }
5240
5336
  }
5337
+ function reportMessageOptionNotHonored(doc, onNotice) {
5338
+ if (!onNotice) return;
5339
+ if (doc.type !== "sequence" && doc.type !== "solidity") return;
5340
+ for (const s of doc.flow) {
5341
+ const \u52B9\u304B\u306A\u3044 = [
5342
+ s.tone !== void 0 ? "\u8272\u5473" : "",
5343
+ s.sub !== void 0 ? "\u6DFB\u3048\u5B57" : "",
5344
+ s.side !== void 0 ? "\u5BC4\u305B" : ""
5345
+ ].filter((x) => x !== "");
5346
+ if (\u52B9\u304B\u306A\u3044.length === 0) continue;
5347
+ onNotice({
5348
+ kind: "message-option-not-honored",
5349
+ actor: s.from,
5350
+ line: s.pos?.line ?? 0,
5351
+ message: `"${truncateForMessage(s.label)}" \u306B\u66F8\u3044\u305F ${\u52B9\u304B\u306A\u3044.join(" / ")} \u306F\u52B9\u304D\u307E\u305B\u3093 (type: ${doc.type} \u306E\u677F\u306F\u8A9E\u3068\u5411\u304D\u3068\u7A2E\u985E\u3060\u3051\u3092\u63CF\u304D\u307E\u3059)`,
5352
+ hint: "\u677F\u306B\u306F\u77E2\u5370\u304C\u7121\u3044\u305F\u3081\u98FE\u308A\u3092\u8F09\u305B\u308B\u5148\u304C\u3042\u308A\u307E\u305B\u3093\u3002 \u8A00\u3065\u3066\u306E\u7A2E\u985E (kind: call / return / fire) \u3067\u63CF\u304D\u5206\u3051\u3066\u304F\u3060\u3055\u3044"
5353
+ });
5354
+ }
5355
+ }
5356
+ function reportActorKindNotHonored(doc, onNotice) {
5357
+ if (!onNotice) return;
5358
+ if (doc.type !== "sequence" && doc.type !== "solidity") return;
5359
+ for (const a of doc.actors) {
5360
+ if (a.partId !== void 0) continue;
5361
+ const \u52B9\u304B\u306A\u3044 = [
5362
+ /*
5363
+ * 種類は `sequence` でだけ落ちる。
5364
+ *
5365
+ * `solidity` は種類で **面の並びを決める** (`compileSolidity`) ので、絵にならなくても
5366
+ * 書いた意味は figure に出ている。 落ちたと伝えると、正しく効いている指定に毎回鳴る。
5367
+ *
5368
+ * 記法を通すと既定の `actor` が必ず入るため、値ではなく書いたかどうかの印で見る。
5369
+ * 記法を通さず直接組み立てた場合はこの印が無いので、種類を置いたこと自体を「書いた」 とみなす
5370
+ */
5371
+ doc.type === "sequence" && a.kindWritten !== false && a.kind !== void 0 ? "\u7A2E\u985E" : "",
5372
+ a.posW !== void 0 || a.posH !== void 0 ? "\u5927\u304D\u3055" : "",
5373
+ a.posX !== void 0 || a.posY !== void 0 || a.posRel !== void 0 ? "\u4F4D\u7F6E" : "",
5374
+ a.rows !== void 0 ? "\u884C" : "",
5375
+ a.tone !== void 0 ? "\u8272" : "",
5376
+ a.eyebrow !== void 0 ? "\u5C0F\u898B\u51FA\u3057" : "",
5377
+ a.value !== void 0 ? "\u5024" : "",
5378
+ a.shape !== void 0 ? "\u56F3\u5F62" : ""
5379
+ ].filter((x) => x !== "");
5380
+ if (\u52B9\u304B\u306A\u3044.length === 0) continue;
5381
+ onNotice({
5382
+ kind: "actor-kind-not-honored",
5383
+ actor: a.name,
5384
+ line: a.pos?.line ?? 0,
5385
+ message: `"${truncateForMessage(a.name)}" \u306B\u66F8\u3044\u305F ${\u52B9\u304B\u306A\u3044.join(" / ")} \u306F\u52B9\u304D\u307E\u305B\u3093 (type: ${doc.type} \u306E\u677F\u306F\u540D\u524D\u3068\u547C\u3073\u540D\u3060\u3051\u3092\u63CF\u304D\u307E\u3059)`,
5386
+ hint: "\u677F\u306B\u306F\u9762\u3054\u3068\u306E\u7BB1\u304C\u7121\u3044\u305F\u3081\u98FE\u308A\u3092\u8F09\u305B\u308B\u5148\u304C\u3042\u308A\u307E\u305B\u3093\u3002 \u547C\u3073\u540D (subtitle) \u306B\u66F8\u304F\u304B\u3001\u7BB1\u3092\u6301\u3064\u56F3\u7A2E\u3092\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044"
5387
+ });
5388
+ }
5389
+ }
5241
5390
  function reportLaneNotHonored(doc, onNotice) {
5242
5391
  if (!onNotice) return;
5243
5392
  if (doc.type === "mind") return;
@@ -5637,7 +5786,7 @@ function applyNodeTones(diagram2, doc) {
5637
5786
  }
5638
5787
  }
5639
5788
  }
5640
- function applyCanvasPivotPositions(diagram2, doc) {
5789
+ function applyCanvasPivotPositions(diagram2, doc, onNotice) {
5641
5790
  for (const actor of doc.actors) {
5642
5791
  if (actor.partId !== void 0) continue;
5643
5792
  const aliasSlug = slugify(actor.name);
@@ -5662,14 +5811,25 @@ function applyCanvasPivotPositions(diagram2, doc) {
5662
5811
  if (actor.nodes) {
5663
5812
  for (const [subKey, override] of Object.entries(actor.nodes)) {
5664
5813
  if (override.posX === void 0 || override.posY === void 0) continue;
5814
+ let \u5F53\u305F\u3063\u305F = 0;
5665
5815
  for (const node of diagram2.nodes) {
5666
5816
  if (node.id === `${aliasSlug}-${subKey}` || node.id === `${subKey}-${aliasSlug}`) {
5667
5817
  node.posX = override.posX;
5668
5818
  node.posY = override.posY;
5669
5819
  if (override.posW !== void 0) node.posW = override.posW;
5670
5820
  if (override.posH !== void 0) node.posH = override.posH;
5821
+ \u5F53\u305F\u3063\u305F += 1;
5671
5822
  }
5672
5823
  }
5824
+ if (\u5F53\u305F\u3063\u305F === 0) {
5825
+ onNotice?.({
5826
+ kind: "sub-node-not-found",
5827
+ actor: actor.name,
5828
+ line: actor.pos?.line ?? 0,
5829
+ message: `"${truncateForMessage(actor.name)}" \u306E nodes \u306B\u66F8\u3044\u305F "${truncateForMessage(subKey)}" \u306B\u5F53\u305F\u308B\u7BB1\u304C\u56F3\u306B\u3042\u308A\u307E\u305B\u3093`,
5830
+ hint: "1 \u4EBA\u306B\u8907\u6570\u306E\u7BB1\u3092\u4F5C\u308B\u56F3\u7A2E\u3067\u3060\u3051\u52B9\u304D\u307E\u3059\u3002 \u7BB1\u305D\u306E\u3082\u306E\u306E\u4F4D\u7F6E\u306F actor \u5074\u306E \u4F4D\u7F6E: \u306B\u66F8\u3044\u3066\u304F\u3060\u3055\u3044"
5831
+ });
5832
+ }
5673
5833
  }
5674
5834
  }
5675
5835
  }
@@ -5892,10 +6052,13 @@ function partVisualSize(part, targetW, targetH) {
5892
6052
  var PARTS_PER_ROW = 3;
5893
6053
  var PARTS_GAP = 120;
5894
6054
  var STACK_PITCH = 280;
5895
- function partsGridCenters(baseNodeCount, items) {
6055
+ function partsBaseRows(nodes) {
6056
+ return nodes.reduce((acc, n) => acc + Math.max(1, Math.ceil(positiveOr(n.h, 0) / STACK_PITCH)), 0);
6057
+ }
6058
+ function partsGridCenters(baseRows, items) {
5896
6059
  const out = /* @__PURE__ */ new Map();
5897
6060
  if (items.length === 0) return out;
5898
- const safeCount = Number.isSafeInteger(baseNodeCount) && baseNodeCount >= 0 ? baseNodeCount : 0;
6061
+ const safeCount = Number.isSafeInteger(baseRows) && baseRows >= 0 ? baseRows : 0;
5899
6062
  const top = safeCount * STACK_PITCH + PARTS_GAP * 2;
5900
6063
  const seen = /* @__PURE__ */ new Set();
5901
6064
  const unique = items.filter((i) => {
@@ -5978,7 +6141,7 @@ function partGridCenters(target, doc, partsCatalog, accepted, acceptedFrom) {
5978
6141
  extents.set(a.name, partFrameExtent(part, t.w, t.h));
5979
6142
  }
5980
6143
  const centers = partsGridCenters(
5981
- baseNodes.length,
6144
+ partsBaseRows(baseNodes),
5982
6145
  placedActors.map((a) => ({ id: a.name, ...extents.get(a.name) }))
5983
6146
  );
5984
6147
  const out = /* @__PURE__ */ new Map();
@@ -6028,7 +6191,11 @@ function cleanupPlaceholderActor(target, doc, a) {
6028
6191
  for (const n of target.nodes) {
6029
6192
  if (ownedLaneIds.has(n.lane)) ownedNodeIds.add(n.id);
6030
6193
  }
6194
+ const \u7D20\u306E\u7BB1\u306Eid = new Set(
6195
+ doc.actors.filter((x) => x.partId === void 0).map((x) => slugify(x.name))
6196
+ );
6031
6197
  const matchesAliasSlug = (id) => {
6198
+ if (\u7D20\u306E\u7BB1\u306Eid.has(id)) return false;
6032
6199
  if (id === aliasSlug) return true;
6033
6200
  if (id.startsWith(`${aliasSlug}-`)) return true;
6034
6201
  if (/^s\d+-/.test(id) && id.endsWith(`-${aliasSlug}`)) return true;
@@ -6042,14 +6209,14 @@ function cleanupPlaceholderActor(target, doc, a) {
6042
6209
  if (drop) removedEdgeIds.add(e.id);
6043
6210
  return !drop;
6044
6211
  });
6045
- if (doc.type === "sequence" || doc.type === "solidity") {
6046
- target.lanes = target.lanes.filter((l) => {
6047
- if (a.lane !== void 0 && l.id === a.lane) return true;
6048
- if (l.label === a.name) return false;
6049
- if (l.id === aliasSlug) return false;
6050
- return true;
6051
- });
6052
- }
6212
+ const \u6B8B\u308B\u7BB1\u3092\u6301\u3064 = new Set(target.nodes.map((n) => n.lane));
6213
+ target.lanes = target.lanes.filter((l) => {
6214
+ if (a.lane !== void 0 && l.id === a.lane) return true;
6215
+ if (\u6B8B\u308B\u7BB1\u3092\u6301\u3064.has(l.id)) return true;
6216
+ if (l.label === a.name) return false;
6217
+ if (l.id === aliasSlug) return false;
6218
+ return true;
6219
+ });
6053
6220
  for (const phase of target.phases) {
6054
6221
  phase.activate = phase.activate.filter((id) => !relatedToActor(id) && !removedEdgeIds.has(id));
6055
6222
  }
@@ -6411,15 +6578,11 @@ function applyEdgeInlineOptions(diagram2, doc, sourceLines) {
6411
6578
  return;
6412
6579
  }
6413
6580
  const used = /* @__PURE__ */ new Set();
6414
- const isSeqLike = doc.type === "sequence" || doc.type === "solidity";
6415
- doc.flow.forEach((s, stepIdx) => {
6581
+ doc.flow.forEach((s) => {
6416
6582
  const fromId = slugify(s.from);
6417
6583
  const toId = slugify(s.to);
6418
6584
  const target = diagram2.edges.find((e) => {
6419
6585
  if (used.has(e.id)) return false;
6420
- if (isSeqLike) {
6421
- return (e.from === `s${stepIdx}-${fromId}` || e.from === fromId) && (e.to === `s${stepIdx}-${toId}` || e.from === e.to);
6422
- }
6423
6586
  return e.from === fromId && e.to === toId;
6424
6587
  });
6425
6588
  if (!target) return;
@@ -6470,6 +6633,10 @@ function \u77E2\u5370\u3078\u66F8\u304D\u5199\u3059(target, s, doc) {
6470
6633
  }
6471
6634
  }
6472
6635
  if (s.side !== void 0) target.side = s.side;
6636
+ if (s.head !== void 0) target.head = s.head;
6637
+ if (s.tailHead !== void 0) target.tailHead = s.tailHead;
6638
+ if (s.headFill !== void 0) target.headFill = s.headFill;
6639
+ if (s.tailHeadFill !== void 0) target.tailHeadFill = s.tailHeadFill;
6473
6640
  if (s.labelOffsetX !== void 0) target.labelOffsetX = s.labelOffsetX;
6474
6641
  if (s.labelOffsetY !== void 0) target.labelOffsetY = s.labelOffsetY;
6475
6642
  if (s.overlay !== void 0) target.overlay = s.overlay;
@@ -6487,16 +6654,6 @@ function \u9396\u306E\u3069\u306E\u884C\u304B\u3089\u6765\u305F\u304B(doc, edgeI
6487
6654
  if (to === void 0) return void 0;
6488
6655
  return doc.flow.find((s) => s.to === to.name);
6489
6656
  }
6490
- var DRAWABLE_KINDS = new Set(NODE_KINDS);
6491
- var KIND_ALIAS = {
6492
- eoa: "shape-wallet",
6493
- wallet: "shape-wallet",
6494
- multisig: "signer",
6495
- contract: "shape-smart-contract",
6496
- proxy: "shape-smart-contract",
6497
- library: "shape-code-block",
6498
- interface: "shape-code-block"
6499
- };
6500
6657
  function \u5F0F\u306B\u66F8\u304F\u6570(n) {
6501
6658
  if (!Number.isFinite(n)) return "0";
6502
6659
  const text = String(n);
@@ -6824,99 +6981,6 @@ var SINGLE_BOX_KINDS = /* @__PURE__ */ new Set([
6824
6981
  "tree-hierarchy",
6825
6982
  "journey-map"
6826
6983
  ]);
6827
- function drawableKind(kind) {
6828
- if (kind === void 0) return void 0;
6829
- const mapped = KIND_ALIAS[kind] ?? kind;
6830
- return DRAWABLE_KINDS.has(mapped) ? mapped : void 0;
6831
- }
6832
- function alignSeqHeaderHeights(diagram2, doc) {
6833
- if (doc.type !== "sequence" && doc.type !== "solidity") return;
6834
- const isEnd = (n) => n.id === `${n.lane}-header` || n.id === `${n.lane}-footer`;
6835
- const ends = diagram2.nodes.filter(isEnd);
6836
- if (ends.length === 0) return;
6837
- const auto = ends.filter((n) => n.posH === void 0);
6838
- if (auto.length === 0) return;
6839
- const tallest = Math.max(...auto.map((n) => n.h ?? 0));
6840
- if (tallest <= 0) return;
6841
- for (const n of auto) n.h = tallest;
6842
- }
6843
- var LABEL_MIN_H = {
6844
- // `shape-` のうち、 高さを上げれば下のはみ出しが消える 4 種 (#1067)。 値は「収まる最小の高さ」
6845
- // で、 1 手前 (値 - 1) では 0.9-1 はみ出すことを実測した
6846
- "shape-person": 228,
6847
- // 名札 72 で下へ 155.9
6848
- "shape-server-rack": 166,
6849
- // 94
6850
- "shape-website": 98,
6851
- // 26
6852
- "shape-warehouse": 79
6853
- // 7
6854
- };
6855
- var LABEL_NEVER_FITS = /* @__PURE__ */ new Set([
6856
- // 左右にはみ出す 24 種。 横幅は高さで変わらないため直らない
6857
- "shape-api-gateway",
6858
- "shape-atm",
6859
- "shape-auditor",
6860
- "shape-bank",
6861
- "shape-bitcoin-chain",
6862
- "shape-blockchain",
6863
- "shape-blockchain-block",
6864
- "shape-blockchain-node",
6865
- "shape-brokerage",
6866
- "shape-code-block",
6867
- "shape-customer-service",
6868
- "shape-ethereum-chain",
6869
- "shape-hexagon",
6870
- "shape-kanban-card",
6871
- "shape-lawyer",
6872
- "shape-network-node",
6873
- "shape-nft",
6874
- "shape-notary",
6875
- "shape-regulator",
6876
- "shape-satellite",
6877
- "shape-smart-contract",
6878
- "shape-terminal",
6879
- "shape-trader",
6880
- "shape-trust-bank",
6881
- // 下のはみ出しが高さに依らない 6 種
6882
- "shape-cylinder",
6883
- "shape-diamond",
6884
- "shape-file",
6885
- "shape-folder",
6886
- "shape-mobile-device",
6887
- "shape-stack",
6888
- // 上へ出る絵が名札の大きさでは読めない。 `#1067` では「上は何ともぶつからない」 として残したが、
6889
- // 実際には絵が小さく潰れて名前と重なり、 横に並べた時も 1 本だけ頭が浮く (user 実機確認)
6890
- "shape-wallet"
6891
- ]);
6892
- function hasAuthoredText(n) {
6893
- if (n.subtitle !== void 0 || n.eyebrow !== void 0 || n.value !== void 0) return true;
6894
- return rendersRows(n.kind) && (n.rows?.length ?? 0) > 0;
6895
- }
6896
- function dropUnfittableEndKinds(diagram2, doc) {
6897
- if (doc.type !== "sequence" && doc.type !== "solidity") return;
6898
- const ends = /* @__PURE__ */ new Map();
6899
- for (const n of diagram2.nodes) {
6900
- if (n.id !== `${n.lane}-header` && n.id !== `${n.lane}-footer`) continue;
6901
- const pair = ends.get(n.lane);
6902
- if (pair === void 0) ends.set(n.lane, [n]);
6903
- else pair.push(n);
6904
- }
6905
- for (const pair of ends.values()) {
6906
- if (pair.some(hasAuthoredText)) continue;
6907
- const \u53CE\u307E\u3089\u306A\u3044 = pair.some((n) => {
6908
- if (LABEL_NEVER_FITS.has(n.kind)) return true;
6909
- const need = LABEL_MIN_H[n.kind];
6910
- if (need === void 0) return false;
6911
- const h = (n.posX !== void 0 && n.posY !== void 0 ? n.posH : void 0) ?? n.h;
6912
- return h !== void 0 && h < need;
6913
- });
6914
- if (!\u53CE\u307E\u3089\u306A\u3044) continue;
6915
- for (const n of pair) {
6916
- if (LABEL_NEVER_FITS.has(n.kind) || LABEL_MIN_H[n.kind] !== void 0) n.kind = "card";
6917
- }
6918
- }
6919
- }
6920
6984
  function applyGroupContainers(diagram2, doc) {
6921
6985
  if (!doc.groups || Object.keys(doc.groups).length === 0) return;
6922
6986
  for (const [id, g] of Object.entries(doc.groups)) {
@@ -7084,34 +7148,46 @@ function compileGantt(doc) {
7084
7148
  return b.build();
7085
7149
  }
7086
7150
  function compileClass(doc) {
7087
- const b = diagram(slugify(doc.title), { topic: doc.title });
7088
- const CLASS_W = 400;
7089
- const CLASS_LANE_W = 450;
7090
- if (doc.actors.length === 0) return b.build();
7091
- doc.actors.forEach((a, idx) => {
7092
- const nodeId = slugify(a.name);
7093
- const laneId = `lane-${nodeId}`;
7094
- b.lane(laneId, { width: CLASS_LANE_W });
7095
- b.node(nodeId, {
7096
- lane: laneId,
7097
- stack: 0,
7098
- kind: "storage",
7151
+ const b = classDiagram({ id: slugify(doc.title), topic: doc.title });
7152
+ if (doc.actors.length === 0) return diagram(slugify(doc.title), { topic: doc.title }).build();
7153
+ const \u5217\u756A\u53F7 = /* @__PURE__ */ new Map();
7154
+ for (const a of doc.actors) {
7155
+ if (a.lane === void 0) continue;
7156
+ if (!\u5217\u756A\u53F7.has(a.lane)) \u5217\u756A\u53F7.set(a.lane, \u5217\u756A\u53F7.size);
7157
+ }
7158
+ for (const a of doc.actors) {
7159
+ const rows = (a.rows ?? []).filter((r) => !/^[─-]+$/.test(r.trim()));
7160
+ const \u632F\u308B\u821E\u3044 = (r) => r.includes("(");
7161
+ const attributes = rows.filter((r) => !\u632F\u308B\u821E\u3044(r));
7162
+ const methods = rows.filter(\u632F\u308B\u821E\u3044);
7163
+ b.class({
7164
+ id: slugify(a.name),
7099
7165
  title: \u7BB1\u306E\u984C(a),
7100
- w: CLASS_W
7166
+ ...attributes.length > 0 ? { attributes: [...attributes] } : {},
7167
+ ...methods.length > 0 ? { methods: [...methods] } : {},
7168
+ ...a.eyebrow ? { stereotype: a.eyebrow } : {},
7169
+ ...a.lane !== void 0 ? { col: \u5217\u756A\u53F7.get(a.lane) ?? 0 } : {},
7170
+ ...a.stack !== void 0 ? { row: a.stack } : {}
7101
7171
  });
7102
- });
7103
- for (const s of doc.flow) {
7104
- const fromId = slugify(s.from);
7105
- const toId = slugify(s.to);
7106
- b.edge(fromId, toId, {
7107
- label: s.label,
7108
- ...s.sub ? { sub: s.sub } : {},
7109
- ...s.side ? { side: s.side } : {},
7110
- ...s.tone ? { tone: s.tone } : {},
7111
- ...s.style ? { style: s.style } : {}
7172
+ }
7173
+ for (const s2 of doc.flow) {
7174
+ b.relation({
7175
+ from: slugify(s2.from),
7176
+ to: slugify(s2.to),
7177
+ // 種類を書かない矢印は「使う」 扱い = 端が開いた矢になり、線と印の組が最も素直
7178
+ type: s2.relation ?? "uses",
7179
+ ...s2.label ? { label: s2.label } : {},
7180
+ ...s2.sub ? { cardinality: s2.sub } : {},
7181
+ ...s2.tone ? { tone: s2.tone } : {},
7182
+ ...s2.style ? { style: s2.style } : {},
7183
+ ...s2.head ? { head: s2.head } : {},
7184
+ ...s2.headFill ? { headFill: s2.headFill } : {},
7185
+ ...s2.tailHead ? { tailHead: s2.tailHead } : {}
7112
7186
  });
7113
7187
  }
7114
- return b.build();
7188
+ const built = b.build();
7189
+ const \u66F8\u3044\u305F\u6BB5\u304C\u3042\u308B = (doc.animate?.phases.length ?? 0) > 0;
7190
+ return \u66F8\u3044\u305F\u6BB5\u304C\u3042\u308B ? { ...built, phases: [] } : built;
7115
7191
  }
7116
7192
  function parseShareValue(raw) {
7117
7193
  if (raw === void 0) return null;
@@ -7693,9 +7769,50 @@ function compileC4(doc) {
7693
7769
  }
7694
7770
  return b.build();
7695
7771
  }
7772
+ var \u984C\u3092\u6301\u305F\u306A\u3044\u7A2E\u985E = /* @__PURE__ */ new Set(["mark-start", "mark-end"]);
7696
7773
  function \u7BB1\u306E\u984C(a) {
7774
+ if (a.title === void 0 && a.kind !== void 0 && \u984C\u3092\u6301\u305F\u306A\u3044\u7A2E\u985E.has(a.kind)) return "";
7697
7775
  return a.title ?? a.name;
7698
7776
  }
7777
+ function \u884C\u3092\u7D44\u307F\u7ACB\u3066\u5668\u304C\u6301\u3064(type) {
7778
+ return type === "class";
7779
+ }
7780
+ function \u884C\u3068\u5370\u3092\u7D44\u3080(type, rows, marks) {
7781
+ const \u5370 = \u884C\u982D\u306E\u5370\u306B\u3059\u308B(type, marks);
7782
+ if (\u5370 === null) return null;
7783
+ if (type !== "er") {
7784
+ return { rows: [...rows], rowMarks: rows.map((_, i) => \u5370[i] ?? null) };
7785
+ }
7786
+ const \u9375 = [];
7787
+ const \u5024 = [];
7788
+ rows.forEach((_, i) => (\u5370[i]?.underline === true ? \u9375 : \u5024).push(i));
7789
+ const \u4E26\u3073 = \u9375.length > 0 && \u5024.length > 0 ? [...\u9375, -1, ...\u5024] : [...\u9375, ...\u5024];
7790
+ return {
7791
+ rows: \u4E26\u3073.map((i) => i < 0 ? "" : rows[i] ?? ""),
7792
+ rowMarks: \u4E26\u3073.map((i) => i < 0 ? null : \u5370[i] ?? null)
7793
+ };
7794
+ }
7795
+ function \u884C\u982D\u306E\u5370\u306B\u3059\u308B(type, marks) {
7796
+ if (type === "er") {
7797
+ return marks.map((m) => {
7798
+ const \u8A9E = m.trim().split(/\s+/).filter(Boolean);
7799
+ return {
7800
+ shape: \u8A9E.includes("fk") ? "chevron" : "square",
7801
+ filled: !\u8A9E.includes("opt"),
7802
+ ...\u8A9E.includes("pk") ? { underline: true } : {}
7803
+ };
7804
+ });
7805
+ }
7806
+ if (type === "state") {
7807
+ return marks.map((m) => {
7808
+ const \u8A9E = m.trim();
7809
+ if (\u8A9E === "") return null;
7810
+ const \u8868 = FSM_ACTION_MARK;
7811
+ return \u8868[\u8A9E] ?? null;
7812
+ });
7813
+ }
7814
+ return null;
7815
+ }
7699
7816
  var \u653E\u5C04\u3067\u63CF\u3051\u306A\u3044\u6B04\u306E\u540D\u524D = {
7700
7817
  kind: "\u7A2E\u985E",
7701
7818
  eyebrow: "\u4E0A\u306E\u5C0F\u898B\u51FA\u3057",
@@ -7704,6 +7821,7 @@ var \u653E\u5C04\u3067\u63CF\u3051\u306A\u3044\u6B04\u306E\u540D\u524D = {
7704
7821
  owner: "\u62C5\u5F53 (\u5DE5\u7A0B\u306E\u4E26\u3073\u306E\u6B04)",
7705
7822
  end: "\u7D42\u308F\u308B\u6642\u671F (\u5DE5\u7A0B\u306E\u4E26\u3073\u306E\u6B04)",
7706
7823
  rows: "\u884C",
7824
+ marks: "\u5370",
7707
7825
  lane: "\u67A0\u306E\u6307\u5B9A",
7708
7826
  stack: "\u7A4D\u3080\u9806",
7709
7827
  initial: "\u59CB\u307E\u308A / \u7D42\u308F\u308A \u306E\u5370",
@@ -7903,75 +8021,35 @@ function reportEmptyDeclaredLanes(diagram2, \u8FFD\u52A0\u3057\u305F\u7E26\u5217
7903
8021
  }
7904
8022
  }
7905
8023
  function applyV05Extensions(diagram2, doc, \u8FFD\u52A0\u3057\u305F\u7E26\u5217out) {
7906
- const isSeqLike = doc.type === "sequence" || doc.type === "solidity";
7907
8024
  for (const a of doc.actors) {
7908
8025
  const dragonSlug = slugify(a.name);
7909
- let primaryNodes;
7910
- if (isSeqLike) {
7911
- const ownedLaneIds = new Set(
7912
- diagram2.lanes.filter((l) => l.label === a.name).map((l) => l.id)
7913
- );
7914
- primaryNodes = ownedLaneIds.size > 0 ? diagram2.nodes.filter((n) => ownedLaneIds.has(n.lane) && n.id === `${n.lane}-header`) : diagram2.nodes.filter((n) => n.id === `${dragonSlug}-header`);
7915
- } else {
7916
- primaryNodes = diagram2.nodes.filter((n) => n.id === dragonSlug);
7917
- }
8026
+ const primaryNodes = diagram2.nodes.filter((n) => n.id === dragonSlug);
7918
8027
  for (const node of primaryNodes) {
7919
- if (a.title !== void 0) {
7920
- node.title = a.title;
7921
- if (isSeqLike) {
7922
- const footer = diagram2.nodes.find((n) => n.id === `${node.lane}-footer`);
7923
- if (footer) footer.title = a.title;
7924
- if (a.posW === void 0) {
7925
- const titleW = Math.max(140, a.title.length * 22 + 52);
7926
- node.w = titleW;
7927
- if (footer) footer.w = titleW;
7928
- }
7929
- }
7930
- }
8028
+ if (a.title !== void 0) node.title = a.title;
7931
8029
  const \u8AAC\u660E = doc.type === "c4" ? \u6BB5\u3092\u8AAD\u307F\u53D6\u308B(a.subtitle).\u8AAC\u660E : a.subtitle;
7932
8030
  if (\u8AAC\u660E !== void 0) node.subtitle = \u8AAC\u660E;
7933
8031
  if (a.eyebrow !== void 0) node.eyebrow = a.eyebrow;
7934
8032
  if (a.value !== void 0) node.value = a.value;
7935
- if (a.rows !== void 0) node.rows = a.rows;
7936
- if (!isSeqLike) {
7937
- if (a.posW !== void 0) node.w = a.posW;
7938
- if (a.posH !== void 0) node.h = a.posH;
7939
- }
7940
- const drawn = isSeqLike && a.kindWritten !== false ? drawableKind(a.kind) : void 0;
7941
- if (drawn !== void 0) {
7942
- node.kind = drawn;
7943
- const footer = diagram2.nodes.find((n) => n.id === `${node.lane}-footer`);
7944
- if (footer) footer.kind = drawn;
7945
- }
7946
- if (isSeqLike && a.rows !== void 0 && a.rows.length > 0 && rendersRows(a.kind)) {
7947
- node.h = Math.max(node.h ?? 0, requiredRowsHeight(a.kind, a.rows.length) ?? 0);
7948
- node.w = Math.max(node.w ?? 0, requiredRowsWidth(a.rows, a.kind));
7949
- }
7950
- if (isSeqLike) {
7951
- if (a.posW !== void 0) node.w = a.posW;
7952
- if (a.posH !== void 0) node.h = a.posH;
7953
- const footer = diagram2.nodes.find((n) => n.id === `${node.lane}-footer`);
7954
- if (footer && a.posW !== void 0) footer.w = a.posW;
8033
+ if (a.rows !== void 0 && !\u884C\u3092\u7D44\u307F\u7ACB\u3066\u5668\u304C\u6301\u3064(doc.type)) node.rows = a.rows;
8034
+ if (a.marks !== void 0 && a.rows !== void 0) {
8035
+ const \u7D44 = \u884C\u3068\u5370\u3092\u7D44\u3080(doc.type, a.rows, a.marks);
8036
+ if (\u7D44 !== null) {
8037
+ node.rows = \u7D44.rows;
8038
+ node.rowMarks = \u7D44.rowMarks;
8039
+ }
8040
+ }
8041
+ if (doc.type === "state" && node.kind === "storage" && node.rowMarks === void 0) {
8042
+ node.rows = a.rows ?? [];
8043
+ node.rowMarks = [];
7955
8044
  }
8045
+ if (a.posW !== void 0) node.w = a.posW;
8046
+ if (a.posH !== void 0) node.h = a.posH;
7956
8047
  if (a.shape !== void 0) {
7957
8048
  const dynamicKind = `dyn-${a.shape.kind}`;
7958
8049
  node.kind = dynamicKind;
7959
8050
  node.shape = { ...a.shape };
7960
- if (isSeqLike) {
7961
- const footer = diagram2.nodes.find((n) => n.id === `${node.lane}-footer`);
7962
- if (footer) {
7963
- footer.kind = dynamicKind;
7964
- footer.shape = { ...a.shape };
7965
- }
7966
- }
7967
- }
7968
- if (a.visibleIf !== void 0) {
7969
- node.visibleIf = a.visibleIf;
7970
- if (isSeqLike) {
7971
- const footer = diagram2.nodes.find((n) => n.id === `${node.lane}-footer`);
7972
- if (footer) footer.visibleIf = a.visibleIf;
7973
- }
7974
8051
  }
8052
+ if (a.visibleIf !== void 0) node.visibleIf = a.visibleIf;
7975
8053
  if (a.wBind !== void 0) node.wBind = a.wBind;
7976
8054
  if (a.hBind !== void 0) node.hBind = a.hBind;
7977
8055
  if (a.opacity !== void 0) node.opacity = a.opacity;
@@ -7979,8 +8057,6 @@ function applyV05Extensions(diagram2, doc, \u8FFD\u52A0\u3057\u305F\u7E26\u5217o
7979
8057
  if (a.renderOffsetY !== void 0) node.renderOffsetY = a.renderOffsetY;
7980
8058
  }
7981
8059
  }
7982
- alignSeqHeaderHeights(diagram2, doc);
7983
- dropUnfittableEndKinds(diagram2, doc);
7984
8060
  if (doc.animate && doc.animate.phases.length > 0 && diagram2.phases.length === 0) {
7985
8061
  injectPhasesFallback(diagram2, doc);
7986
8062
  }
@@ -8086,13 +8162,17 @@ function injectPhasesFallback(diagram2, doc) {
8086
8162
  }
8087
8163
  }
8088
8164
  function compileSequence(doc) {
8089
- if (doc.animate && doc.animate.phases.length > 0) {
8090
- return compileSequenceWithAnimate(doc);
8091
- }
8092
8165
  const seqBuilder = sequence({
8093
8166
  id: slugify(doc.title),
8094
8167
  topic: doc.title,
8095
- actors: doc.actors.map((a) => a.name)
8168
+ /*
8169
+ * 見出しに出すのは **書いた題** (#1466)。 名前は矢印の端として指すためのもので、
8170
+ * `title:` を書いたらそちらを出す (`箱の題`)。 板でも他の図種と同じ規約にする。
8171
+ */
8172
+ actors: doc.actors.map(
8173
+ (a) => a.subtitle ? { name: \u7BB1\u306E\u984C(a), subtitle: a.subtitle } : \u7BB1\u306E\u984C(a)
8174
+ ),
8175
+ ...doc.bands && doc.bands.length > 0 ? { bands: doc.bands } : {}
8096
8176
  });
8097
8177
  for (const s of doc.flow) {
8098
8178
  seqBuilder.step({
@@ -8102,140 +8182,43 @@ function compileSequence(doc) {
8102
8182
  ...s.sub ? { sub: s.sub } : {},
8103
8183
  ...s.side ? { side: s.side } : {},
8104
8184
  ...s.tone ? { tone: s.tone } : {},
8105
- ...s.style ? { style: s.style } : {}
8185
+ ...s.style ? { style: s.style } : {},
8186
+ ...s.msgKind ? { kind: s.msgKind } : {}
8106
8187
  });
8107
8188
  }
8108
- return seqBuilder.build();
8109
- }
8110
- function compileSequenceWithAnimate(doc) {
8111
- const b = diagram(slugify(doc.title), { topic: doc.title });
8112
- const laneW = 340;
8113
- const actorIds = /* @__PURE__ */ new Map();
8114
- doc.actors.forEach((a, i) => {
8115
- const id = slugify(a.name);
8116
- actorIds.set(a.name, id);
8117
- actorIds.set(id, id);
8118
- const laneOpts = { width: laneW, label: a.name, lifeline: true };
8119
- if (a.posX !== void 0 && a.posY !== void 0) {
8120
- laneOpts.posX = a.posX;
8121
- laneOpts.posY = a.posY;
8122
- if (a.posW !== void 0) laneOpts.posW = a.posW;
8123
- if (a.posH !== void 0) laneOpts.posH = a.posH;
8124
- }
8125
- b.lane(id, laneOpts);
8126
- const headerId = `${id}-header`;
8127
- const actorW = Math.max(140, \u7BB1\u306E\u984C(a).length * 22 + 52);
8128
- b.node(headerId, { lane: id, stack: 0, kind: "card", title: \u7BB1\u306E\u984C(a), w: actorW, h: 72 });
8129
- const spacerId = `${id}-spacer`;
8130
- b.node(spacerId, { lane: id, stack: 1, kind: "card", title: "", w: 2, h: 40 });
8131
- });
8132
- doc.flow.forEach((s, idx) => {
8133
- const fromLaneId = actorIds.get(s.from);
8134
- const toLaneId = actorIds.get(s.to);
8135
- if (fromLaneId === void 0 || toLaneId === void 0) return;
8136
- const stack = idx + 2;
8137
- const fromBoxId = `s${idx}-${fromLaneId}`;
8138
- const toBoxId = `s${idx}-${toLaneId}`;
8139
- b.node(fromBoxId, { lane: fromLaneId, stack, kind: "card", title: "", w: 2, h: 2 });
8140
- if (fromLaneId !== toLaneId) {
8141
- b.node(toBoxId, { lane: toLaneId, stack, kind: "card", title: "", w: 2, h: 2 });
8142
- }
8143
- const edgeId = `e${idx}-${fromLaneId}-${toLaneId}`;
8144
- b.edge(fromBoxId, fromLaneId === toLaneId ? fromBoxId : toBoxId, {
8145
- id: edgeId,
8146
- label: s.label,
8147
- ...s.sub ? { sub: s.sub } : {},
8148
- ...s.side ? { side: s.side } : {},
8149
- ...s.tone ? { tone: s.tone } : {},
8150
- ...s.style ? { style: s.style } : {}
8151
- });
8152
- });
8153
- const footerStack = doc.flow.length + 2;
8154
- doc.actors.forEach((a) => {
8155
- const laneId = actorIds.get(a.name) ?? slugify(a.name);
8156
- const footerId = `${laneId}-footer`;
8157
- const actorW = Math.max(140, \u7BB1\u306E\u984C(a).length * 22 + 52);
8158
- b.node(footerId, {
8159
- lane: laneId,
8160
- stack: footerStack,
8161
- kind: "card",
8162
- title: \u7BB1\u306E\u984C(a),
8163
- w: actorW,
8164
- h: 72,
8165
- role: "lifeline-footer"
8166
- });
8167
- });
8168
- for (const st of doc.animate?.states ?? []) {
8169
- b.state(st.name, { initial: st.initial });
8170
- }
8171
- for (const p of doc.animate?.phases ?? []) {
8172
- b.phase(
8173
- slugify(p.name),
8174
- {
8189
+ const built = seqBuilder.build();
8190
+ const \u6BB5 = doc.animate?.phases ?? [];
8191
+ if (\u6BB5.length === 0) return built;
8192
+ const \u756A\u53F7 = /* @__PURE__ */ new Map();
8193
+ doc.flow.forEach((f, i) => \u756A\u53F7.set(`${slugify(f.from)} -> ${slugify(f.to)}`, i));
8194
+ const \u72B6\u614B\u540D = sequenceStepId();
8195
+ return {
8196
+ ...built,
8197
+ states: [...built.states, { id: \u72B6\u614B\u540D, initial: "0" }],
8198
+ phases: \u6BB5.map((p, i) => {
8199
+ const \u756A = Math.max(
8200
+ 0,
8201
+ ...(p.highlight ?? []).map(
8202
+ (f) => \u756A\u53F7.get(f.split("->").map((x) => slugify(x.trim())).join(" -> ")) ?? -1
8203
+ )
8204
+ );
8205
+ return {
8206
+ id: `p${i}`,
8175
8207
  duration: p.durationMs,
8176
8208
  title: p.name,
8177
- body: p.body ?? ""
8178
- },
8179
- (pb) => {
8180
- const activateIds = resolveHighlight(p, doc, actorIds);
8181
- if (activateIds.length > 0) {
8182
- pb.activate(...activateIds);
8183
- }
8184
- for (const t of p.tweens ?? []) {
8185
- pb.tween(t.state, t.from, t.to);
8186
- }
8187
- for (const s of p.sets ?? []) {
8188
- pb.set(s.state, s.value);
8189
- }
8190
- if (p.badge) {
8191
- pb.badge(p.badge);
8192
- }
8193
- return pb;
8194
- }
8195
- );
8196
- }
8197
- return b.build();
8198
- }
8199
- function resolveHighlight(phase, doc, actorIds, _stepEdgeIds) {
8200
- const out = [];
8201
- const knownNames = new Set(actorIds.keys());
8202
- for (const raw of phase.highlight ?? []) {
8203
- const entry = parseFocusEntry(raw, knownNames);
8204
- if (entry.kind === "edge") {
8205
- const fromLaneId = actorIds.get(entry.from) ?? slugify(entry.from);
8206
- const toLaneId = actorIds.get(entry.to) ?? slugify(entry.to);
8207
- doc.flow.forEach((s, idx) => {
8208
- const sFromId = actorIds.get(s.from) ?? slugify(s.from);
8209
- const sToId = actorIds.get(s.to) ?? slugify(s.to);
8210
- if (sFromId === fromLaneId && sToId === toLaneId) {
8211
- out.push(`e${idx}-${fromLaneId}-${toLaneId}`);
8212
- }
8213
- });
8214
- const stackIdx = doc.flow.findIndex((s) => {
8215
- const sFromId = actorIds.get(s.from) ?? slugify(s.from);
8216
- const sToId = actorIds.get(s.to) ?? slugify(s.to);
8217
- return sFromId === fromLaneId && sToId === toLaneId;
8218
- });
8219
- if (stackIdx >= 0) {
8220
- out.push(`s${stackIdx}-${fromLaneId}`);
8221
- if (fromLaneId !== toLaneId) out.push(`s${stackIdx}-${toLaneId}`);
8222
- }
8223
- continue;
8224
- }
8225
- const laneId = actorIds.get(entry.name) ?? slugLookup(actorIds, entry.name);
8226
- if (laneId) {
8227
- out.push(`${laneId}-header`);
8228
- out.push(`${laneId}-footer`);
8229
- doc.flow.forEach((s, idx) => {
8230
- const sFromId = actorIds.get(s.from) ?? slugify(s.from);
8231
- const sToId = actorIds.get(s.to) ?? slugify(s.to);
8232
- if (sFromId === laneId || sToId === laneId) {
8233
- out.push(`s${idx}-${laneId}`);
8234
- }
8235
- });
8236
- }
8237
- }
8238
- return out;
8209
+ body: p.body ?? "",
8210
+ activate: [slugify(doc.title)],
8211
+ ...p.badge ? { badge: p.badge } : {},
8212
+ /*
8213
+ * **書いた状態の動きも一緒に運ぶ** (#1466)。 板の段は「今どの言づてか」 を状態に
8214
+ * 書くが、記法は同じ段に `遷移:` / `切替:` も書ける。 板の分だけを載せると、
8215
+ * 書いた動きが黙って落ちる (実測で `tweens` が 0 件になっていた)。
8216
+ */
8217
+ sets: [...(p.sets ?? []).map((x) => ({ stateId: x.state, value: x.value })), { stateId: \u72B6\u614B\u540D, value: \u756A }],
8218
+ tweens: (p.tweens ?? []).map((t) => ({ stateId: t.state, from: t.from, to: t.to }))
8219
+ };
8220
+ })
8221
+ };
8239
8222
  }
8240
8223
  function slugLookup(byName, wanted) {
8241
8224
  let hit;
@@ -8433,7 +8416,13 @@ function \u5F8C\u308D\u3078\u623B\u308B\u77E2\u5370\u304B(kind, fromId, toId, \u
8433
8416
  if (\u5143 === void 0 || \u5148 === void 0) return false;
8434
8417
  return \u5148 < \u5143;
8435
8418
  }
8436
- var \u7E26\u5217\u3092\u9078\u3079\u308B\u56F3\u7A2E = /* @__PURE__ */ new Set(["flow", "topology", "swimlane"]);
8419
+ var \u7E26\u5217\u3092\u9078\u3079\u308B\u56F3\u7A2E = /* @__PURE__ */ new Set([
8420
+ "flow",
8421
+ "topology",
8422
+ "swimlane",
8423
+ "class",
8424
+ "state"
8425
+ ]);
8437
8426
  function \u66F8\u3044\u305F\u7E26\u5217\u306B\u7F6E\u304F(kind, doc) {
8438
8427
  if (!\u7E26\u5217\u3092\u9078\u3079\u308B\u56F3\u7A2E.has(kind)) return false;
8439
8428
  const \u5BFE\u8C61 = doc.actors.filter((a) => a.partId === void 0);
@@ -9061,7 +9050,7 @@ function writeVerticalForm(seg, headIdx, lineCount, headIndent, x, y) {
9061
9050
  else seg.splice(insertAt * 2, 0, newLine, sep);
9062
9051
  return seg.join("");
9063
9052
  }
9064
- var \u7DDA\u7A2E = ["solid", "dotted-flow"];
9053
+ var \u7DDA\u7A2E = EDGE_STYLES;
9065
9054
  var \u8272\u540D\u306E\u8868 = new Map([
9066
9055
  ...TONES.map((t) => [t.toLowerCase(), t]),
9067
9056
  ...Object.entries(TONE_ALIAS).map(([k, v]) => [k.toLowerCase(), v])
@@ -9228,7 +9217,11 @@ var ACCEPTED_KEYS = {
9228
9217
  "formulas",
9229
9218
  // 押下などの出来事で動く仕掛けと、巻き上げに応じて進む値 (#1393)
9230
9219
  "events",
9231
- "scrolls"
9220
+ "scrolls",
9221
+ // 順序図で面が動いている間の帯 (#1466)
9222
+ "bands",
9223
+ // 矢印をいつ出すか (#1470)
9224
+ "reveal"
9232
9225
  ],
9233
9226
  actor: [
9234
9227
  "name",
@@ -9268,7 +9261,9 @@ var ACCEPTED_KEYS = {
9268
9261
  "hBind",
9269
9262
  "opacity",
9270
9263
  "renderOffsetX",
9271
- "renderOffsetY"
9264
+ "renderOffsetY",
9265
+ // 行頭の印 (#1466)。 行ごとに 1 つ、図の種類ごとの語で書く
9266
+ "marks"
9272
9267
  ],
9273
9268
  step: [
9274
9269
  "from",
@@ -9277,6 +9272,14 @@ var ACCEPTED_KEYS = {
9277
9272
  "sub",
9278
9273
  // 矢印がどの辺から出るか (#1385)
9279
9274
  "side",
9275
+ // 矢印の先の形 (#1462)
9276
+ "head",
9277
+ // 端の印の残り 3 欄と、関係の語 / 言づての種類 (#1466)
9278
+ "tailHead",
9279
+ "headFill",
9280
+ "tailHeadFill",
9281
+ "relation",
9282
+ "kind",
9280
9283
  "tone",
9281
9284
  "style",
9282
9285
  "guard",
@@ -9322,7 +9325,11 @@ var \u6B04\u306E\u578B\u8868 = {
9322
9325
  formulas: "object",
9323
9326
  // 押下と巻き上げ (#1393)。 中身は下の検査が 1 件ずつ見る
9324
9327
  events: "\u4E26\u3073",
9325
- scrolls: "object"
9328
+ scrolls: "object",
9329
+ // 順序図で面が動いている間の帯 (#1466)
9330
+ bands: "\u4E26\u3073",
9331
+ // 矢印をいつ出すか (#1470)
9332
+ reveal: "\u975E\u7A7A\u306E\u6587\u5B57\u5217"
9326
9333
  },
9327
9334
  actor: {
9328
9335
  name: "\u5FC5\u9808\u306E\u975E\u7A7A\u6587\u5B57\u5217",
@@ -9361,7 +9368,9 @@ var \u6B04\u306E\u578B\u8868 = {
9361
9368
  hBind: "\u975E\u7A7A\u306E\u6587\u5B57\u5217",
9362
9369
  opacity: "\u6570\u304B\u6587\u5B57\u5217",
9363
9370
  renderOffsetX: "\u6570\u304B\u6587\u5B57\u5217",
9364
- renderOffsetY: "\u6570\u304B\u6587\u5B57\u5217"
9371
+ renderOffsetY: "\u6570\u304B\u6587\u5B57\u5217",
9372
+ // 行頭の印 (#1466)
9373
+ marks: "\u6587\u5B57\u5217\u306E\u4E26\u3073"
9365
9374
  },
9366
9375
  step: {
9367
9376
  from: "\u5FC5\u9808\u306E\u6587\u5B57\u5217",
@@ -9370,6 +9379,13 @@ var \u6B04\u306E\u578B\u8868 = {
9370
9379
  sub: "\u6587\u5B57\u5217",
9371
9380
  // 矢印がどの辺から出るか (#1385)
9372
9381
  side: "\u8FBA",
9382
+ head: "\u7AEF\u306E\u5F62",
9383
+ // 端の印の残り 3 欄と、関係の語 / 言づての種類 (#1466)
9384
+ tailHead: "\u7AEF\u306E\u5F62",
9385
+ headFill: "\u975E\u7A7A\u306E\u6587\u5B57\u5217",
9386
+ tailHeadFill: "\u975E\u7A7A\u306E\u6587\u5B57\u5217",
9387
+ relation: "\u975E\u7A7A\u306E\u6587\u5B57\u5217",
9388
+ kind: "\u975E\u7A7A\u306E\u6587\u5B57\u5217",
9373
9389
  tone: "\u8272",
9374
9390
  style: "\u7DDA\u7A2E",
9375
9391
  guard: "\u6587\u5B57\u5217",
@@ -9551,6 +9567,16 @@ function \u5024\u3092\u691C\u67FB(v, \u578B, path, \u540D\u524D, errors) {
9551
9567
  });
9552
9568
  }
9553
9569
  return;
9570
+ case "\u7AEF\u306E\u5F62":
9571
+ if (v === void 0) return;
9572
+ if (typeof v !== "string" || !EDGE_HEAD_VALUES.includes(v)) {
9573
+ errors.push({
9574
+ path,
9575
+ message: `${\u540D\u524D} must be one of: ${EDGE_HEAD_VALUES.join(", ")}`,
9576
+ hint: typeof v === "string" ? `got "${v}"` : `got ${typeof v}`
9577
+ });
9578
+ }
9579
+ return;
9554
9580
  case "\u63CF\u304F\u3082\u306E":
9555
9581
  if (v === void 0) return;
9556
9582
  if (typeof v !== "string" || !DRAW_WORDS.has(v)) {
@@ -9735,6 +9761,33 @@ function \u8868\u3067\u4E2D\u8EAB\u3092\u691C\u67FB\u3059\u308B(o, \u8868, path,
9735
9761
  }
9736
9762
  }
9737
9763
  }
9764
+ function validateBands(v, errors) {
9765
+ if (v === void 0) return;
9766
+ if (!Array.isArray(v)) {
9767
+ errors.push({
9768
+ path: "$.bands",
9769
+ message: "bands must be an array of band objects",
9770
+ hint: `got ${v === null ? "null" : typeof v}`
9771
+ });
9772
+ return;
9773
+ }
9774
+ v.forEach((b, i) => {
9775
+ const path = `$.bands[${i}]`;
9776
+ if (typeof b !== "object" || b === null || Array.isArray(b)) {
9777
+ errors.push({ path, message: "band must be an object", hint: "{ actor, from, to } \u306E\u5F62\u3067\u66F8\u304F" });
9778
+ return;
9779
+ }
9780
+ const o = b;
9781
+ if (typeof o.actor !== "string" || o.actor === "") {
9782
+ errors.push({ path: `${path}.actor`, message: "band.actor must be a non-empty string" });
9783
+ }
9784
+ for (const k of ["from", "to"]) {
9785
+ if (typeof o[k] !== "number" || !Number.isInteger(o[k]) || o[k] < 0) {
9786
+ errors.push({ path: `${path}.${k}`, message: `band.${k} must be a non-negative integer` });
9787
+ }
9788
+ }
9789
+ });
9790
+ }
9738
9791
  function validateReadouts(v, errors) {
9739
9792
  if (v === void 0) return;
9740
9793
  if (!Array.isArray(v)) {
@@ -10199,6 +10252,7 @@ function validateJson(json) {
10199
10252
  const j = \u5199\u3057.value;
10200
10253
  checkUnknownKeys(j, "root", "$", errors);
10201
10254
  validateReadouts(j.readouts, errors);
10255
+ validateBands(j.bands, errors);
10202
10256
  validateInputs(j.inputs, errors);
10203
10257
  validateFormulas(j.formulas, j.inputs, errors);
10204
10258
  validateEvents(j.events, errors);
@@ -10432,6 +10486,8 @@ function jsonToDoc(json) {
10432
10486
  value: a.value,
10433
10487
  previous: a.previous,
10434
10488
  rows: a.rows,
10489
+ // 行頭の印 (#1466)。 行と対で読む
10490
+ marks: a.marks,
10435
10491
  lane: a.lane,
10436
10492
  stack: a.stack,
10437
10493
  initial: a.initial,
@@ -10487,6 +10543,14 @@ function jsonToDoc(json) {
10487
10543
  label: s.label,
10488
10544
  sub: s.sub,
10489
10545
  side: s.side,
10546
+ // 矢印の先の形 (#1462)。 読めない語は組み立てが落とす
10547
+ head: s.head,
10548
+ // 端の印の残り 3 欄と、関係の語 / 言づての種類 (#1466)
10549
+ tailHead: s.tailHead,
10550
+ headFill: s.headFill,
10551
+ tailHeadFill: s.tailHeadFill,
10552
+ relation: s.relation,
10553
+ msgKind: s.kind,
10490
10554
  // 箱と同じ読み替えを通す (#1304)。 通さないと `tone: "成功"` が色名として解決されないまま
10491
10555
  // 図に届き、同じ値が箱では色になり矢印では色にならない
10492
10556
  tone: resolveTone(s.tone),
@@ -10582,6 +10646,10 @@ function jsonToDoc(json) {
10582
10646
  formulas,
10583
10647
  events,
10584
10648
  scrolls,
10649
+ // 順序図で面が動いている間の帯 (#1466)
10650
+ bands: json.bands,
10651
+ // 矢印をいつ出すか (#1470)
10652
+ reveal: json.reveal,
10585
10653
  pos: p0
10586
10654
  };
10587
10655
  }
@@ -10725,6 +10793,13 @@ var diagram_default = {
10725
10793
  },
10726
10794
  description: "storage \u5185\u306E column \u5217 (kind: storage \u7528)"
10727
10795
  },
10796
+ marks: {
10797
+ type: "array",
10798
+ items: {
10799
+ type: "string"
10800
+ },
10801
+ description: "\u884C\u982D\u306E\u5370\u3002 rows \u3068\u540C\u3058\u6570\u3060\u3051\u4E26\u3079\u308B\u3002 \u8A9E\u306E\u610F\u5473\u306F\u56F3\u306E\u7A2E\u985E\u304C\u6C7A\u3081\u308B = er \u306F pk / fk / opt\u3001class \u306F + / - \u3068 () \u306E\u6709\u7121\u3001state \u306F entry / do / exit / internal"
10802
+ },
10728
10803
  lane: {
10729
10804
  type: "string",
10730
10805
  description: "swimlane / topology \u3067\u5C5E\u3059\u308B lane id"
@@ -11059,7 +11134,7 @@ var diagram_default = {
11059
11134
  },
11060
11135
  style: {
11061
11136
  type: "string",
11062
- enum: ["solid", "dotted-flow"],
11137
+ enum: ["solid", "dotted-flow", "dashed"],
11063
11138
  description: "\u77E2\u5370\u306E\u7DDA\u7A2E"
11064
11139
  },
11065
11140
  guard: {
@@ -11075,6 +11150,36 @@ var diagram_default = {
11075
11150
  enum: ["top", "right", "bottom", "left"],
11076
11151
  description: "\u77E2\u5370\u304C\u3069\u306E\u8FBA\u304B\u3089\u51FA\u308B\u304B\u3002 \u66F8\u304B\u306A\u3051\u308C\u3070\u63CF\u753B\u5074\u304C\u81EA\u52D5\u3067\u9078\u3076\u3002"
11077
11152
  },
11153
+ head: {
11154
+ type: "string",
11155
+ enum: ["none", "triangle", "diamond", "open", "crow", "one", "zero-one", "many", "zero-many"],
11156
+ description: "\u7740\u304D\u5148\u5074\u306E\u7AEF\u306E\u5F62\u3002 \u7AEF\u306E\u5F62\u3067\u95A2\u4FC2\u306E\u7A2E\u985E\u3092\u793A\u3059 = triangle (\u7D99\u3050) / diamond (\u6301\u3064) / open (\u4F7F\u3046) / crow (\u591A) / one / zero-one / many / zero-many (\u500B\u6570)\u3002 \u66F8\u304B\u306A\u3051\u308C\u3070\u5857\u3063\u305F\u4E09\u89D2\u306B\u306A\u308B\u3002"
11157
+ },
11158
+ tailHead: {
11159
+ type: "string",
11160
+ enum: ["none", "triangle", "diamond", "open", "crow", "one", "zero-one", "many", "zero-many"],
11161
+ description: "\u51FA\u3069\u3053\u308D\u5074\u306E\u7AEF\u306E\u5F62\u3002 \u4E21\u7AEF\u306B\u5225\u3005\u306E\u5370\u3092\u7ACB\u3066\u308B\u6642\u306B\u66F8\u304F\u3002"
11162
+ },
11163
+ headFill: {
11164
+ type: "string",
11165
+ enum: ["solid", "hollow"],
11166
+ description: "\u7740\u304D\u5148\u5074\u306E\u7AEF\u306E\u5857\u308A\u3002 \u4E2D\u7A7A\u306F\u300C\u5F31\u3044\u95A2\u4FC2\u300D \u3092\u8868\u3059\u3002"
11167
+ },
11168
+ tailHeadFill: {
11169
+ type: "string",
11170
+ enum: ["solid", "hollow"],
11171
+ description: "\u51FA\u3069\u3053\u308D\u5074\u306E\u7AEF\u306E\u5857\u308A\u3002"
11172
+ },
11173
+ relation: {
11174
+ type: "string",
11175
+ enum: ["extends", "implements", "aggregates", "composes", "associates", "uses"],
11176
+ description: "\u30AF\u30E9\u30B9\u56F3\u306E\u95A2\u4FC2\u306E\u8A9E\u3002 \u66F8\u304F\u3068\u7AEF\u306E\u5F62 / \u5857\u308A / \u7DDA\u7A2E\u304C\u307E\u3068\u3081\u3066\u6C7A\u307E\u308B\u3002"
11177
+ },
11178
+ kind: {
11179
+ type: "string",
11180
+ enum: ["call", "return", "fire"],
11181
+ description: "\u9806\u5E8F\u56F3\u306E\u8A00\u3065\u3066\u306E\u7A2E\u985E\u3002 call (\u8FD4\u4E8B\u3092\u5F85\u3064) / return (\u8FD4\u3057) / fire (\u8FD4\u4E8B\u3092\u5F85\u305F\u306A\u3044)\u3002"
11182
+ },
11078
11183
  labelOffsetX: {
11079
11184
  type: "number",
11080
11185
  description: "\u30E9\u30D9\u30EB\u4F4D\u7F6E x \u8ABF\u6574"
@@ -12361,6 +12466,25 @@ var diagram_default = {
12361
12466
  pattern: "^[A-Za-z_][A-Za-z0-9_]*$"
12362
12467
  }
12363
12468
  },
12469
+ reveal: {
12470
+ type: "string",
12471
+ enum: ["phase", "all"],
12472
+ description: "\u77E2\u5370\u3092\u3044\u3064\u51FA\u3059\u304B\u3002 phase (\u65E2\u5B9A) = \u6BB5\u304C\u540D\u6307\u3057\u3059\u308B\u77E2\u5370\u306F\u305D\u306E\u6BB5\u304C\u6765\u308B\u307E\u3067\u63CF\u304B\u306A\u3044\u3002 all = \u6BB5\u306B\u95A2\u308F\u3089\u305A\u6700\u521D\u304B\u3089\u5168\u90E8\u63CF\u304F\u3002"
12473
+ },
12474
+ bands: {
12475
+ type: "array",
12476
+ description: "\u9806\u5E8F\u56F3\u3067\u9762\u304C\u52D5\u3044\u3066\u3044\u308B\u9593\u306E\u5E2F\u3002 \u66F8\u304B\u306A\u3051\u308C\u3070\u9762\u3054\u3068\u306B\u300C\u6700\u521D\u306B\u95A2\u308F\u3063\u305F\u6BB5\u304B\u3089\u6700\u5F8C\u307E\u3067\u300D \u306E 1 \u672C\u306B\u306A\u308B\u3002",
12477
+ items: {
12478
+ type: "object",
12479
+ required: ["actor", "from", "to"],
12480
+ additionalProperties: false,
12481
+ properties: {
12482
+ actor: { type: "string", description: "\u5E2F\u3092\u51FA\u3059\u9762\u306E\u540D\u524D" },
12483
+ from: { type: "integer", minimum: 0, description: "\u59CB\u307E\u308A\u306E\u8A00\u3065\u3066\u306E\u756A\u53F7 (0 \u8D77\u70B9)" },
12484
+ to: { type: "integer", minimum: 0, description: "\u7D42\u308F\u308A\u306E\u8A00\u3065\u3066\u306E\u756A\u53F7 (0 \u8D77\u70B9)" }
12485
+ }
12486
+ }
12487
+ },
12364
12488
  events: {
12365
12489
  type: "array",
12366
12490
  description: "\u62BC\u4E0B\u306A\u3069\u306E\u51FA\u6765\u4E8B\u3067\u52D5\u304F\u4ED5\u639B\u3051\u3002 \u76F8\u624B\u306F\u540D\u524D\u3067\u6307\u3059 (box / lane / arrow / diagram \u306E\u3069\u308C\u304B 1 \u3064)\u3002",
@@ -12536,6 +12660,6 @@ function isV05Source(src) {
12536
12660
  return true;
12537
12661
  }
12538
12662
 
12539
- export { DIAGRAM_BOUNDARY_PADDING, DRAW_TARGETS, DRAW_WORDS, JSONを分解する, MAX_INPUT_BYTES, MAX_INPUT_ELEMENTS, MAX_PART_SCALE, NODE_KIND_ALIAS, NODE_KIND_VALID, PHASE_ITEM_WORDS, PRESET_TYPES, RELATIVE_GAP_DEFAULT, TONE_ALIAS, TOP_LEVEL_KEYS, autoFix, compileToCdl, computeDiagramBoundingBox, countBytes, countDiagramElements, countDocElements, describeOversize, describeOversizeSource, diagramJsonSchema, isColorValue, jsonToDiagram, lintDiagram, measureActorBoxes, normalizePartScale, orderByDependency, parseFocusEntry, parseRelativePos, parseTextDsl, parseTextDslV05, partBoxInFrame, partDrawsInDiagram, partIsMeasurable, partRenderSize, partScaleFactor, partTargetScale, partTargetSize, partVisualSize, partsGridCenters, pointsOutside, rectsOverlap, resolveRelativePos, stripExternalPaint, stripQuotes, textDslToDiagram, validateDragonJson, writeActorPosition, 区間に広げる, 記法を分解する };
12663
+ export { DIAGRAM_BOUNDARY_PADDING, DRAW_TARGETS, DRAW_WORDS, JSONを分解する, MAX_INPUT_BYTES, MAX_INPUT_ELEMENTS, MAX_PART_SCALE, NODE_KIND_ALIAS, NODE_KIND_VALID, PHASE_ITEM_WORDS, PRESET_TYPES, RELATIVE_GAP_DEFAULT, TONE_ALIAS, TOP_LEVEL_KEYS, autoFix, compileToCdl, computeDiagramBoundingBox, countBytes, countDiagramElements, countDocElements, describeOversize, describeOversizeSource, diagramJsonSchema, isColorValue, jsonToDiagram, lintDiagram, measureActorBoxes, normalizePartScale, orderByDependency, parseFocusEntry, parseRelativePos, parseTextDsl, parseTextDslV05, partBoxInFrame, partDrawsInDiagram, partIsMeasurable, partRenderSize, partScaleFactor, partTargetScale, partTargetSize, partVisualSize, partsBaseRows, partsGridCenters, pointsOutside, rectsOverlap, resolveRelativePos, stripExternalPaint, stripQuotes, textDslToDiagram, validateDragonJson, writeActorPosition, 区間に広げる, 記法を分解する };
12540
12664
  //# sourceMappingURL=index.js.map
12541
12665
  //# sourceMappingURL=index.js.map