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