@cardenelabs/cdl 0.9.0 → 0.10.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/CHANGELOG.md CHANGED
@@ -7,6 +7,50 @@ CDL (Chainome Diagram Language) の主要変更履歴。
7
7
 
8
8
  予定 ... feedback を反映した patch / minor。
9
9
 
10
+ ## [0.10.0] - 2026-08-21
11
+
12
+ ### Added
13
+
14
+ - **段の進みで折れ線を左の起点から伸ばせるようにした** (#513)
15
+
16
+ 段 (`CdlPhase`) に `draw` を足した。 `activate` と同じ形で node id を並べると、その node が
17
+ 段の進み (0 → 1) に合わせて描かれる。 最初の対象は折れ線 (`chart-line`) で、線が左端から
18
+ 右へ伸び、点と値の数字は線の先が自分の位置に届いた時に現れる。 軸 / 格子 / 横軸の名前は
19
+ 最初から出る。
20
+
21
+ 伸ばすのは dash (`pathLength` / `strokeDasharray` / `strokeDashoffset`) で、`points` は進みに
22
+ 関わらず全点を持つ。 点を削る形にすると、利用側が数えている点の数が進みの途中で変わる。
23
+
24
+ 引き金に `activate` を使わないのは、1 箱で図全体を描く種別では焦点がその箱に解決されるため。
25
+ 連続する段で光り続ける図が実在し、「光っていたら描く」 にすると値が動くだけの段でも線を
26
+ 引き直すことになる。
27
+
28
+ 組立て API は `PhaseBuilder.draw(...ids)`。 `draw` を書かない図は従来どおり全長で描き、
29
+ DOM に属性も 1 つも増えない。
30
+
31
+ ### Fixed
32
+
33
+ - **候補が node の時に「定義済 lane」 と知らせるのをやめた** (#513)
34
+
35
+ 近い候補が無い時に出る一覧の文言が `lane` 固定で、探す先を間違える案内になっていた。
36
+ `suggest` に候補の種別を渡せるようにし、node を候補にする 3 箇所 (`draw` / edge の `from` /
37
+ edge の `to`) を揃えた。
38
+
39
+ ### Changed
40
+
41
+ - **repo 内の agent worktree を eslint の対象から外した** (#507)
42
+
43
+ 指摘の 6 割が worktree の複製から出ており、実体を直しても消えなかった。
44
+
45
+ - **README と CONTRIBUTING の記述を実態に合わせた** (#505)
46
+
47
+ 存在しない playground と command を前提にした記述が残っていた。
48
+
49
+ - **skip されていた検査 2 件を解除した** (#510 / #511)
50
+
51
+ どちらも routing の不具合ではなく、検査の前提が誤っていた。 実装は 1 行も変えていない。
52
+ 併せて、行き先として書かれていた実在しない Issue 番号を実在するものに付け替えた。
53
+
10
54
  ## [0.9.0] - 2026-08-20
11
55
 
12
56
  `0.8.0` は tag を打った後 npm に公開されないまま 17 commit が載った。 同じ番号で公開すると
@@ -392,7 +436,8 @@ Initial OSS release.
392
436
  使わない = annotated tag を push しても GitHub Release は作られず、 Release を作っていない版で
393
437
  行き止まりになる。
394
438
 
395
- [Unreleased]: https://github.com/cardene777/cdl/compare/v0.9.0...HEAD
439
+ [Unreleased]: https://github.com/cardene777/cdl/compare/v0.10.0...HEAD
440
+ [0.10.0]: https://github.com/cardene777/cdl/compare/v0.9.0...v0.10.0
396
441
  [0.9.0]: https://github.com/cardene777/cdl/compare/v0.8.0...v0.9.0
397
442
  [0.8.0]: https://github.com/cardene777/cdl/compare/v0.7.0...v0.8.0
398
443
  [0.7.0]: https://github.com/cardene777/cdl/compare/v0.6.1...v0.7.0
package/SPEC.md CHANGED
@@ -123,11 +123,20 @@ diagram.phase(id, {
123
123
  body: string, // 説明文 (日本語、 header に表示)
124
124
  }, builder => builder
125
125
  .activate(...ids) // active な node / edge id を列挙
126
+ .draw(...ids) // この phase で左の起点から描き始める node id を列挙
126
127
  .tween(stateId, from, to) // state を線形補間
127
128
  .badge(text) // BalanceDiffCard 等の status badge 文字列
128
129
  );
129
130
  ```
130
131
 
132
+ `draw` は `activate` と別集合で持つ。 1 箱で図全体を描く種別では焦点がその箱に解決される
133
+ ため、 連続する phase で光り続ける図が実在し、 光っているかを引き金にすると値が動くだけの
134
+ phase でも線を引き直すことになる。
135
+
136
+ 対象の node は phase の進み (0→1) に合わせて描かれる。 現在の対象種別は `chart-line` で、
137
+ 折れ線が左端から右へ伸び、 点と値の数字は線の先が届いた時に現れる (軸 / 格子 / 横軸の名前は
138
+ 最初から出る)。 `draw` を書かない図は従来どおり全長で描き、 DOM に dash 属性も付かない。
139
+
131
140
  phase が定義されると自動的に。
132
141
  - 全 phase が timeline 化 (autoplay + loop)
133
142
  - 各 phase の active set 以外は inactive 化 (灰 dashed)
@@ -351,7 +360,7 @@ export const erc20Transfer = diagram("erc20-transfer", { topic: "ERC-20 Transfer
351
360
  | arrow | edge の from/to が存在、 同 from/to ペアが side hint なく被る |
352
361
  | label | label / sublabel 文字数で box が lane 幅を超える |
353
362
  | japanese-only | title / eyebrow / subtitle / label に uppercase 英単語 (FUNCTION/STORAGE/...) |
354
- | phase-isolation | phase の activate id が存在する node/edge を指す |
363
+ | phase-isolation | phase の activate id が存在する node/edge を指す、 draw id が存在する node を指す |
355
364
  | neumorphism | tone が定義された 4 色から外れる |
356
365
 
357
366
  build error / warn を投げ、 著者は cdl 段階で修正できる (screenshot 取る前に)。
package/dist/index.cjs CHANGED
@@ -9363,6 +9363,10 @@ function makePhaseBuilder(acc) {
9363
9363
  acc.activate.push(...ids);
9364
9364
  return api;
9365
9365
  },
9366
+ draw(...ids) {
9367
+ acc.draw.push(...ids);
9368
+ return api;
9369
+ },
9366
9370
  tween(stateId, from, to) {
9367
9371
  acc.tweens.push({ stateId, from, to });
9368
9372
  return api;
@@ -11442,7 +11446,7 @@ function diagram(id, options) {
11442
11446
  }
11443
11447
  },
11444
11448
  phase(phaseId, opts, build) {
11445
- const acc = { activate: [], tweens: [], sets: [] };
11449
+ const acc = { activate: [], draw: [], tweens: [], sets: [] };
11446
11450
  build(makePhaseBuilder(acc));
11447
11451
  phases.push({
11448
11452
  id: phaseId,
@@ -11450,6 +11454,8 @@ function diagram(id, options) {
11450
11454
  title: opts.title,
11451
11455
  body: opts.body,
11452
11456
  activate: acc.activate,
11457
+ // 空なら欄ごと置かない。 置くと `draw` を使わない図の JSON の形が変わる
11458
+ ...acc.draw.length > 0 ? { draw: acc.draw } : {},
11453
11459
  tweens: acc.tweens,
11454
11460
  sets: acc.sets,
11455
11461
  badge: acc.badge
@@ -15921,7 +15927,7 @@ function validate(diag) {
15921
15927
  ...(diag.formulas ?? []).map((f) => f.id),
15922
15928
  ...(diag.scrollTriggers ?? []).map((t) => t.id)
15923
15929
  ]);
15924
- const suggest = (target, candidates) => {
15930
+ const suggest = (target, candidates, candidateKind = "lane") => {
15925
15931
  const list = [...candidates];
15926
15932
  if (list.length === 0) return "";
15927
15933
  let best = "";
@@ -15933,7 +15939,7 @@ function validate(diag) {
15933
15939
  best = c;
15934
15940
  }
15935
15941
  }
15936
- return bestD <= 2 ? ` (\u3082\u3057\u304B\u3057\u3066 "${best}"?)` : ` (\u5B9A\u7FA9\u6E08 lane: ${list.slice(0, 5).join(", ")}${list.length > 5 ? "..." : ""})`;
15942
+ return bestD <= 2 ? ` (\u3082\u3057\u304B\u3057\u3066 "${best}"?)` : ` (\u5B9A\u7FA9\u6E08 ${candidateKind}: ${list.slice(0, 5).join(", ")}${list.length > 5 ? "..." : ""})`;
15937
15943
  };
15938
15944
  for (const n of diag.nodes) {
15939
15945
  if (!laneIds.has(n.lane)) {
@@ -15946,13 +15952,13 @@ function validate(diag) {
15946
15952
  for (const e of diag.edges) {
15947
15953
  if (!nodeIds.has(e.from)) {
15948
15954
  errors.push(
15949
- `[cdl] unknown-ref: edge "${e.id}" \u306E from "${e.from}" \u304C node \u306B\u5B58\u5728\u3057\u307E\u305B\u3093${suggest(e.from, nodeIds)}
15955
+ `[cdl] unknown-ref: edge "${e.id}" \u306E from "${e.from}" \u304C node \u306B\u5B58\u5728\u3057\u307E\u305B\u3093${suggest(e.from, nodeIds, "node")}
15950
15956
  \u2192 \u4FEE\u6B63\u4F8B: .node("${e.from}", { lane: "...", stack: 0, kind: "actor", title: "..." }) \u3092 edge \u5BA3\u8A00\u524D\u306B\u8FFD\u52A0`
15951
15957
  );
15952
15958
  }
15953
15959
  if (!nodeIds.has(e.to)) {
15954
15960
  errors.push(
15955
- `[cdl] unknown-ref: edge "${e.id}" \u306E to "${e.to}" \u304C node \u306B\u5B58\u5728\u3057\u307E\u305B\u3093${suggest(e.to, nodeIds)}
15961
+ `[cdl] unknown-ref: edge "${e.id}" \u306E to "${e.to}" \u304C node \u306B\u5B58\u5728\u3057\u307E\u305B\u3093${suggest(e.to, nodeIds, "node")}
15956
15962
  \u2192 \u4FEE\u6B63\u4F8B: .node("${e.to}", { lane: "...", stack: 0, kind: "...", title: "..." }) \u3092 edge \u5BA3\u8A00\u524D\u306B\u8FFD\u52A0`
15957
15963
  );
15958
15964
  }
@@ -15969,6 +15975,16 @@ function validate(diag) {
15969
15975
  errors.push(`[cdl] unknown-ref: phase "${p.id}" \u306E activate "${id}" \u306F node \u3067\u3082 edge \u3067\u3082\u306A\u3044 (typo \u306E\u53EF\u80FD\u6027)`);
15970
15976
  }
15971
15977
  }
15978
+ for (const id of p.draw ?? []) {
15979
+ if (!nodeIds.has(id)) {
15980
+ errors.push(`[cdl] unknown-ref: phase "${p.id}" \u306E draw "${id}" \u306F node \u3067\u306F\u306A\u3044 (typo \u306E\u53EF\u80FD\u6027)${suggest(id, nodeIds, "node")}`);
15981
+ continue;
15982
+ }
15983
+ const kind = diag.nodes.find((n) => n.id === id)?.kind;
15984
+ if (kind !== "chart-line") {
15985
+ warnings.push(`phase "${p.id}" \u306E draw "${id}" \u306F kind "${kind}" \u3067\u3001 \u5DE6\u304B\u3089\u63CF\u304F\u52D5\u304D\u3092\u6301\u305F\u306A\u3044 (\u5BFE\u8C61\u306F chart-line)`);
15986
+ }
15987
+ }
15972
15988
  for (const t of p.tweens) {
15973
15989
  if (!stateIds.has(t.stateId)) {
15974
15990
  errors.push(`[cdl] unknown-ref: phase "${p.id}" tween \u5BFE\u8C61 state "${t.stateId}" \u672A\u5B9A\u7FA9`);
@@ -21266,7 +21282,9 @@ function resolveMindData(data, values) {
21266
21282
  function ChartLineNode({
21267
21283
  node,
21268
21284
  active,
21269
- stateValues = {}
21285
+ stateValues = {},
21286
+ drawing = false,
21287
+ progress = 1
21270
21288
  }) {
21271
21289
  const x0 = node.cx - node.w / 2;
21272
21290
  const y0 = node.cy - node.h / 2;
@@ -21287,6 +21305,24 @@ function ChartLineNode({
21287
21305
  const xAt = (idx) => PAD_LEFT + (data.length <= 1 ? canvasW / 2 : canvasW * idx / (data.length - 1));
21288
21306
  const yAt = (v) => plotTop + plotH - (v - vMin) / vRange * plotH;
21289
21307
  const points = data.map((d, idx) => `${xAt(idx)},${yAt(d.value)}`).join(" ");
21308
+ const \u70B9\u307E\u3067\u306E\u9577\u3055 = [];
21309
+ let \u7DDA\u306E\u5168\u9577 = 0;
21310
+ let \u524D\u306E\u70B9;
21311
+ for (const [idx, datum] of data.entries()) {
21312
+ const \u4ECA\u306E\u70B9 = { x: xAt(idx), y: yAt(datum.value) };
21313
+ if (\u524D\u306E\u70B9) {
21314
+ \u7DDA\u306E\u5168\u9577 += Math.hypot(\u4ECA\u306E\u70B9.x - \u524D\u306E\u70B9.x, \u4ECA\u306E\u70B9.y - \u524D\u306E\u70B9.y);
21315
+ }
21316
+ \u70B9\u307E\u3067\u306E\u9577\u3055.push(\u7DDA\u306E\u5168\u9577);
21317
+ \u524D\u306E\u70B9 = \u4ECA\u306E\u70B9;
21318
+ }
21319
+ const \u4F38\u3073 = drawing ? Math.min(1, Math.max(0, Number.isFinite(progress) ? progress : 1)) : 1;
21320
+ const \u7DDA\u306E\u5148\u304C\u5C4A\u3044\u305F = (idx) => {
21321
+ if (!drawing) return true;
21322
+ if (data.length <= 1) return true;
21323
+ if (\u7DDA\u306E\u5168\u9577 === 0) return true;
21324
+ return \u4F38\u3073 >= (\u70B9\u307E\u3067\u306E\u9577\u3055[idx] ?? 0) / \u7DDA\u306E\u5168\u9577;
21325
+ };
21290
21326
  const gridCount = 4;
21291
21327
  const gridTicks = Array.from({ length: gridCount + 1 }, (_, i) => {
21292
21328
  const v = vMin + vRange * i / gridCount;
@@ -21364,7 +21400,8 @@ function ChartLineNode({
21364
21400
  stroke: "var(--cdl-tone-accent, #2d6a8f)",
21365
21401
  strokeWidth: 2.5,
21366
21402
  strokeLinejoin: "round",
21367
- strokeLinecap: "round"
21403
+ strokeLinecap: "round",
21404
+ ...drawing ? { pathLength: 1, strokeDasharray: 1, strokeDashoffset: 1 - \u4F38\u3073 } : {}
21368
21405
  }
21369
21406
  ),
21370
21407
  data.map((d, idx) => {
@@ -21375,40 +21412,43 @@ function ChartLineNode({
21375
21412
  const isValley = (prev === void 0 || d.value <= prev) && (next === void 0 || d.value <= next);
21376
21413
  const labelAbove = !isValley;
21377
21414
  const labelY = labelAbove ? cy - 12 : cy + 18;
21415
+ const \u51FA\u3059 = \u7DDA\u306E\u5148\u304C\u5C4A\u3044\u305F(idx);
21378
21416
  return /* @__PURE__ */ jsxRuntime.jsxs("g", { "data-cdl-unresolved": d.unresolved ? "true" : void 0, children: [
21379
- /* @__PURE__ */ jsxRuntime.jsx(
21380
- "circle",
21381
- {
21382
- cx,
21383
- cy,
21384
- r: 5,
21385
- fill: "var(--cdl-node-fill, #ffffff)",
21386
- stroke: "var(--cdl-tone-accent, #2d6a8f)",
21387
- strokeWidth: 2.5
21388
- }
21389
- ),
21390
- /* @__PURE__ */ jsxRuntime.jsx(
21391
- "circle",
21392
- {
21393
- cx,
21394
- cy,
21395
- r: 2.5,
21396
- fill: "var(--cdl-tone-accent, #2d6a8f)"
21397
- }
21398
- ),
21399
- /* @__PURE__ */ jsxRuntime.jsx(
21400
- "text",
21401
- {
21402
- "data-cdl-role": "chart-line-value",
21403
- x: cx,
21404
- y: labelY,
21405
- fontSize: 11,
21406
- fontWeight: 600,
21407
- textAnchor: "middle",
21408
- fill: "var(--cdl-text, #1a1f2a)",
21409
- children: d.value.toLocaleString()
21410
- }
21411
- ),
21417
+ \u51FA\u3059 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
21418
+ /* @__PURE__ */ jsxRuntime.jsx(
21419
+ "circle",
21420
+ {
21421
+ cx,
21422
+ cy,
21423
+ r: 5,
21424
+ fill: "var(--cdl-node-fill, #ffffff)",
21425
+ stroke: "var(--cdl-tone-accent, #2d6a8f)",
21426
+ strokeWidth: 2.5
21427
+ }
21428
+ ),
21429
+ /* @__PURE__ */ jsxRuntime.jsx(
21430
+ "circle",
21431
+ {
21432
+ cx,
21433
+ cy,
21434
+ r: 2.5,
21435
+ fill: "var(--cdl-tone-accent, #2d6a8f)"
21436
+ }
21437
+ ),
21438
+ /* @__PURE__ */ jsxRuntime.jsx(
21439
+ "text",
21440
+ {
21441
+ "data-cdl-role": "chart-line-value",
21442
+ x: cx,
21443
+ y: labelY,
21444
+ fontSize: 11,
21445
+ fontWeight: 600,
21446
+ textAnchor: "middle",
21447
+ fill: "var(--cdl-text, #1a1f2a)",
21448
+ children: d.value.toLocaleString()
21449
+ }
21450
+ )
21451
+ ] }),
21412
21452
  /* @__PURE__ */ jsxRuntime.jsx(
21413
21453
  "text",
21414
21454
  {
@@ -26703,6 +26743,7 @@ function ShapeCustomerServiceNode({ node, active }) {
26703
26743
  function CdlNodeView({
26704
26744
  node,
26705
26745
  active,
26746
+ drawing = false,
26706
26747
  progress,
26707
26748
  stateValues,
26708
26749
  currentPhaseId
@@ -26752,7 +26793,16 @@ function CdlNodeView({
26752
26793
  // 数と語を取る 7 種に対し、mind-map / tree-hierarchy は **名前だけ** を取る (#467)。
26753
26794
  // 親子の繋がりと、描かれない欄 (補足) は解決しない。
26754
26795
  case "chart-line":
26755
- return /* @__PURE__ */ jsxRuntime.jsx(ChartLineNode, { node: resolvedNode, active, stateValues });
26796
+ return /* @__PURE__ */ jsxRuntime.jsx(
26797
+ ChartLineNode,
26798
+ {
26799
+ node: resolvedNode,
26800
+ active,
26801
+ stateValues,
26802
+ drawing,
26803
+ progress
26804
+ }
26805
+ );
26756
26806
  case "chart-pie":
26757
26807
  return /* @__PURE__ */ jsxRuntime.jsx(ChartPieNode, { node: resolvedNode, active, stateValues });
26758
26808
  case "chart-bar":
@@ -26946,6 +26996,7 @@ function CdlStage({
26946
26996
  svgRef
26947
26997
  }) {
26948
26998
  const activeSet = new Set(currentPhase?.activate ?? []);
26999
+ const drawSet = new Set(currentPhase?.draw ?? []);
26949
27000
  const { lifelineStarts, uniformFooterTop } = react.useMemo(() => {
26950
27001
  const starts = lifelineStartYs(laid.nodes);
26951
27002
  return {
@@ -27082,6 +27133,7 @@ function CdlStage({
27082
27133
  {
27083
27134
  node,
27084
27135
  active: activeSet.has(node.id),
27136
+ drawing: drawSet.has(node.id),
27085
27137
  progress,
27086
27138
  stateValues,
27087
27139
  currentPhaseId: currentPhase?.id