@cardenelabs/cdl 0.105.0 → 0.107.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
@@ -5,6 +5,70 @@ CDL (Chainome Diagram Language) の主要変更履歴。
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.107.0] - 2026-09-30
9
+
10
+ ### Fixed
11
+
12
+ - **収まっている題を「はみ出す」 と判定するのをやめた** (#951)
13
+
14
+ 軸 3 (`text-readability`) の見積りが、実際に描く形と 2 点で違っていた。
15
+
16
+ 第一に、字の幅の表が **組み方のための上振れ値** だった。 箱の大きさと線の置き場を決める
17
+ 側は狭く見積もると字が枠から出るため、表は広い側へ寄せてある。 同じ値で「はみ出すか」 を
18
+ 判定すると、収まっている題まで挙がる。
19
+
20
+ 見本帳の題 407 か所を `getComputedTextLength()` で測ると、上振れは字種で分かれた。
21
+
22
+ | 字種 | 件数 | 見積り / 実描画 |
23
+ |---|---|---|
24
+ | 和文だけ | 247 | 1.080 倍 (例外なし) |
25
+ | 欧文だけ | 119 | 1.16 から 1.82 倍 (中央 1.27 倍) |
26
+ | 混在 | 41 | 1.09 から 1.35 倍 |
27
+
28
+ 第二に、**描く側は箱に収まるまで字を小さくする**。 `actor` / `card` / `event` / `function` /
29
+ `storage` は読める下限 11px まで 1 ずつ落とし、絵の中に字を置く 34 種は下限なく縮める。
30
+ 軸 3 は種別ごとの最大値で見積もっていたので、縮めて収めた題まで挙がっていた。
31
+
32
+ 2 点を直した。
33
+
34
+ | 直した所 | 内容 |
35
+ |---|---|
36
+ | `measureTextWidth` | `bound: "drawn"` を足し、字種ごとに上振れを割り戻す。 既定 (`layout`) は変えない |
37
+ | 軸 3 | 縮める種別は「読める下限を割るか」、縮めない種別は「箱の幅を超えるか」 を見る |
38
+
39
+ **組み方の見積りは 1 つも変えていない**。 箱の大きさと線の置き場は従来どおりで、
40
+ 焼き付けた見た目も動かない。
41
+
42
+ 検知力は下げていない。 縮める種別では、下限 11px まで落としても収まらない題を挙げる
43
+ (`storage` の箱 400px に全角 40 字を書くと挙がる)。 絵の中に字を置く 34 種では、
44
+ 下限を割る大きさまで縮む題を挙げる = 直す前は「はみ出す」 という当たらない理由で
45
+ 挙げていたものを、実際に起きること (読めない大きさになる) に付け替えた。
46
+
47
+ 引く側は cardene777/dragon#2701 で 9 枚が受け入れ一覧に載っていた。 本版でその 9 枚が
48
+ 挙がらなくなる。
49
+
50
+ ## [0.106.0] - 2026-09-30
51
+
52
+ ### Fixed
53
+
54
+ - **箱の題の幅を、字ごとの実幅で見積もるようにした** (#949)
55
+
56
+ 軸 3 (`text-readability`) は字数に 1 字の幅を掛けて見積もっていた。
57
+ 英数字は全角の半分ほどしか取らないため、英数字の題を持つ箱で過大に見積もる。
58
+
59
+ | 題 | 種別 | 字数の近似 | 字ごとの実幅 |
60
+ |---|---|---|---|
61
+ | `order_items` | `storage` (34) | 426px | 約 250px |
62
+
63
+ engine は字ごとの実幅を出す `measureTextWidth` を既に持ち、辺の名札の外枠で使っている。
64
+ 軸 3 だけが字数の近似を使っていたので、同じものに揃えた。
65
+
66
+ 0.105.0 (#946) で 1 字の幅を種別ごとの実寸にした結果、大きく描く種別
67
+ (`storage` 34 / `actor` 32 / `card` 24 / `function` 24) で英数字の題が新しく挙がっていた。
68
+ 引く側 (見本帳) で 11 枚を実測している。 本版でその 11 枚が挙がらなくなる。
69
+
70
+ 判定の向きは変えていない。 全角の題が箱に収まらない場合は従来どおり挙がる。
71
+
8
72
  ## [0.105.0] - 2026-09-30
9
73
 
10
74
  ### Fixed
@@ -4263,7 +4327,9 @@ Initial OSS release.
4263
4327
  使わない = annotated tag を push しても GitHub Release は作られず、 Release を作っていない版で
4264
4328
  行き止まりになる。
4265
4329
 
4266
- [Unreleased]: https://github.com/cardene777/cdl/compare/v0.105.0...HEAD
4330
+ [Unreleased]: https://github.com/cardene777/cdl/compare/v0.107.0...HEAD
4331
+ [0.107.0]: https://github.com/cardene777/cdl/compare/v0.106.0...v0.107.0
4332
+ [0.106.0]: https://github.com/cardene777/cdl/compare/v0.105.0...v0.106.0
4267
4333
  [0.105.0]: https://github.com/cardene777/cdl/compare/v0.104.0...v0.105.0
4268
4334
  [0.104.0]: https://github.com/cardene777/cdl/compare/v0.103.0...v0.104.0
4269
4335
  [0.103.0]: https://github.com/cardene777/cdl/compare/v0.102.0...v0.103.0
package/dist/index.cjs CHANGED
@@ -12241,6 +12241,11 @@ function isHalfwidthKana(code) {
12241
12241
  }
12242
12242
  var EMOJI_ADVANCE_EM = 1.05;
12243
12243
  var MONO_EMOJI_ADVANCE_EM = 1.16;
12244
+ var DRAWN_CJK_RATIO = 1.08;
12245
+ var DRAWN_ASCII_RATIO = 1.16;
12246
+ function isAscii(code) {
12247
+ return code < 128;
12248
+ }
12244
12249
  var WIDE_SYMBOL_ADVANCE_EM = 0.95;
12245
12250
  function isEmoji(code) {
12246
12251
  return code >= 126976 && code <= 129791 || // 絵文字の主要面
@@ -12279,29 +12284,31 @@ function measureTextWidth(text, opts = {}) {
12279
12284
  const fontSize = opts.fontSize ?? 22;
12280
12285
  const letterSpacing = opts.letterSpacing ?? 0;
12281
12286
  const fontFamily = opts.fontFamily ?? "sans";
12287
+ const bound = opts.bound ?? "layout";
12282
12288
  let advanceEmSum = 0;
12283
12289
  let charCount = 0;
12284
12290
  const \u6587\u5B57\u5217 = CLUSTER_JOINER_RE.test(text) ? segmentGraphemes(text) : [...text];
12285
12291
  for (const ch of \u6587\u5B57\u5217) {
12286
12292
  charCount++;
12287
12293
  const code = ch.codePointAt(0) ?? 0;
12294
+ const \u5272\u308A\u623B\u3057 = bound === "drawn" && !isEmojiGrapheme(ch, code) ? isAscii(code) ? DRAWN_ASCII_RATIO : isCJK(code) ? DRAWN_CJK_RATIO : 1 : 1;
12288
12295
  if (isEmojiGrapheme(ch, code)) {
12289
12296
  advanceEmSum += fontFamily === "mono" ? MONO_EMOJI_ADVANCE_EM : EMOJI_ADVANCE_EM;
12290
12297
  continue;
12291
12298
  }
12292
12299
  if (fontFamily === "mono") {
12293
- advanceEmSum += isCJK(code) ? 1.08 : JETBRAINS_MONO_ADVANCE_EM;
12300
+ advanceEmSum += (isCJK(code) ? 1.08 : JETBRAINS_MONO_ADVANCE_EM) / \u5272\u308A\u623B\u3057;
12294
12301
  continue;
12295
12302
  }
12296
12303
  if (isCJK(code)) {
12297
- advanceEmSum += 1.08;
12304
+ advanceEmSum += 1.08 / \u5272\u308A\u623B\u3057;
12298
12305
  continue;
12299
12306
  }
12300
12307
  const table = ch.length === 1 ? INTER_BOLD_ADVANCE_EM[ch] : void 0;
12301
- advanceEmSum += table !== void 0 ? table : defaultAdvanceEm(ch, code);
12308
+ advanceEmSum += (table !== void 0 ? table : defaultAdvanceEm(ch, code)) / \u5272\u308A\u623B\u3057;
12302
12309
  }
12303
12310
  const w = advanceEmSum * fontSize + letterSpacing * charCount;
12304
- return Math.max(w, fontSize * 1.2);
12311
+ return bound === "drawn" ? w : Math.max(w, fontSize * 1.2);
12305
12312
  }
12306
12313
  function \u53CE\u3081\u308B\u500D\u7387(text, opts, \u5E45) {
12307
12314
  if (!(\u5E45 > 0) || !(opts.fontSize > 0)) return 1;
@@ -12442,6 +12449,51 @@ function titleFontSize(kind) {
12442
12449
  return TITLE_FONT_SIZE.get(kind ?? "") ?? TITLE_FONT_SIZE_DEFAULT;
12443
12450
  }
12444
12451
  var TITLE_BOX_PADDING = 52;
12452
+ var KINDS_SCALING_TITLE_WHEN_LOW = /* @__PURE__ */ new Set(["actor", "event", "function", "storage"]);
12453
+ var KINDS_SCALING_TITLE_ALWAYS = /* @__PURE__ */ new Set([
12454
+ "card",
12455
+ "shape-file",
12456
+ "shape-folder",
12457
+ "shape-cloud",
12458
+ "shape-cylinder",
12459
+ "shape-hexagon",
12460
+ "shape-diamond",
12461
+ "shape-stack",
12462
+ "shape-person",
12463
+ "shape-server-rack",
12464
+ "shape-network-node",
12465
+ "shape-mobile-device",
12466
+ "shape-satellite",
12467
+ "shape-smart-contract",
12468
+ "shape-rpc-node",
12469
+ "shape-wallet",
12470
+ "shape-nft",
12471
+ "shape-token",
12472
+ "shape-blockchain",
12473
+ "shape-bitcoin-chain",
12474
+ "shape-ethereum-chain",
12475
+ "shape-blockchain-node",
12476
+ "shape-bank",
12477
+ "shape-trust-bank",
12478
+ "shape-payment-provider",
12479
+ "shape-credit-card",
12480
+ "shape-brokerage",
12481
+ "shape-exchange",
12482
+ "shape-atm",
12483
+ "shape-website",
12484
+ "shape-storefront",
12485
+ "shape-warehouse",
12486
+ "shape-online-shop",
12487
+ "shape-cdn-edge",
12488
+ "shape-api-gateway"
12489
+ ]);
12490
+ var COMPACT_TITLE_MAX_H = 100;
12491
+ function titleScalesToFit(kind, h) {
12492
+ const k = kind ?? "";
12493
+ if (KINDS_SCALING_TITLE_ALWAYS.has(k)) return true;
12494
+ return KINDS_SCALING_TITLE_WHEN_LOW.has(k) && h < COMPACT_TITLE_MAX_H;
12495
+ }
12496
+ var MIN_TITLE_FONT_SIZE = 11;
12445
12497
  var KINDS_DRAWN_BY_GENERIC = [
12446
12498
  "person",
12447
12499
  "user-group",
@@ -17225,12 +17277,23 @@ function runAxes(laid, diag, violations, counts, push, profile, skippedAxes, \u5
17225
17277
  if (!isRenderedNode(n)) continue;
17226
17278
  const titleTrimmed = n.title?.trim() ?? "";
17227
17279
  if (!titleTrimmed) continue;
17228
- const titleLen = titleTrimmed.length;
17229
- const expectedW = titleLen * titleFontSize(n.kind) + (drawsTitleOutsideBox(n.kind) ? 0 : TITLE_BOX_PADDING);
17230
- if (expectedW > n.w + 8) {
17280
+ const \u4F59\u767D = drawsTitleOutsideBox(n.kind) ? 0 : TITLE_BOX_PADDING;
17281
+ const \u4F7F\u3048\u308B\u5E452 = n.w - \u4F59\u767D;
17282
+ const \u5B9F\u5E45 = measureTextWidth(titleTrimmed, { fontSize: titleFontSize(n.kind), bound: "drawn" });
17283
+ if (titleScalesToFit(n.kind, n.h)) {
17284
+ const \u7E2E\u3081\u305F\u5927\u304D\u3055 = \u5B9F\u5E45 > 0 ? titleFontSize(n.kind) * Math.min(1, \u4F7F\u3048\u308B\u5E452 / \u5B9F\u5E45) : titleFontSize(n.kind);
17285
+ if (\u7E2E\u3081\u305F\u5927\u304D\u3055 < MIN_TITLE_FONT_SIZE) {
17286
+ push(
17287
+ "text-readability",
17288
+ `node "${n.id}" title "${n.title}" \u304C node \u5E45 ${n.w}px \u306B\u53CE\u307E\u3089\u305A\u3001\u8AAD\u3081\u308B\u4E0B\u9650 ${MIN_TITLE_FONT_SIZE}px \u3092\u5272\u308B (\u7E2E\u3081\u3066 ${\u7E2E\u3081\u305F\u5927\u304D\u3055.toFixed(1)}px)`,
17289
+ "warn"
17290
+ );
17291
+ }
17292
+ } else if (\u5B9F\u5E45 > \u4F7F\u3048\u308B\u5E452 + 8) {
17231
17293
  push(
17232
17294
  "text-readability",
17233
- `node "${n.id}" title "${n.title}" \u304C node \u5E45 ${n.w}px \u3092\u8D85\u904E\u3059\u308B\u53EF\u80FD\u6027 (\u671F\u5F85 ${expectedW}px)`,
17295
+ // 字ごとの実幅は小数になるので、読む人に出す時だけ丸める (判定は丸めない)
17296
+ `node "${n.id}" title "${n.title}" \u304C node \u5E45 ${n.w}px \u3092\u8D85\u904E\u3059\u308B\u53EF\u80FD\u6027 (\u671F\u5F85 ${Math.round(\u5B9F\u5E45 + \u4F59\u767D)}px)`,
17234
17297
  "warn"
17235
17298
  );
17236
17299
  }