@cardenelabs/dragon 0.30.0 → 0.32.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.
Files changed (55) hide show
  1. package/README.md +314 -12
  2. package/dist/index.cjs +6966 -1438
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +2150 -118
  5. package/dist/index.d.ts +2150 -118
  6. package/dist/index.js +6950 -1440
  7. package/dist/index.js.map +1 -1
  8. package/package.json +12 -13
  9. package/src/compile/actor-ids.ts +6 -15
  10. package/src/compile/actor-option-notice.ts +379 -0
  11. package/src/compile/actors.ts +32 -3
  12. package/src/compile/c4.ts +0 -3
  13. package/src/compile/chain.ts +43 -4
  14. package/src/compile/chart-fields.ts +16 -1
  15. package/src/compile/direction.ts +50 -11
  16. package/src/compile/edge-option-notice.ts +112 -0
  17. package/src/compile/flowchart.ts +344 -0
  18. package/src/compile/funnel.ts +14 -2
  19. package/src/compile/gantt.ts +141 -36
  20. package/src/compile/generic.ts +473 -61
  21. package/src/compile/journey.ts +14 -5
  22. package/src/compile/kinds.ts +5 -13
  23. package/src/compile/lanes.ts +95 -13
  24. package/src/compile/metro.ts +271 -0
  25. package/src/compile/mind.ts +55 -5
  26. package/src/compile/notice.ts +51 -4
  27. package/src/compile/order.ts +62 -0
  28. package/src/compile/parts.ts +107 -33
  29. package/src/compile/placement-apply.ts +27 -11
  30. package/src/compile/quadrant.ts +171 -16
  31. package/src/compile/record.ts +75 -0
  32. package/src/compile/row-marks.ts +128 -0
  33. package/src/compile/sequence.ts +105 -26
  34. package/src/compile/slug.ts +9 -1
  35. package/src/compile/stages.ts +247 -0
  36. package/src/compile/subtitle.ts +15 -2
  37. package/src/compile/swimlane-marks.ts +87 -0
  38. package/src/compile/swimlane.ts +13 -14
  39. package/src/compile/timeline.ts +213 -0
  40. package/src/compile/topology.ts +3 -9
  41. package/src/compile/tree.ts +13 -4
  42. package/src/compile/value-chart.ts +179 -25
  43. package/src/compile.ts +1550 -370
  44. package/src/focus.ts +2 -2
  45. package/src/index.ts +34 -2
  46. package/src/json-parser.ts +1407 -48
  47. package/src/keywords.ts +251 -17
  48. package/src/notation-lint.ts +41 -64
  49. package/src/schemas/diagram.json +643 -20
  50. package/src/types.ts +336 -35
  51. package/src/v05/parser.ts +2451 -271
  52. package/src/compile/class.ts +0 -100
  53. package/src/compile/er.ts +0 -44
  54. package/src/compile/solidity.ts +0 -39
  55. package/src/compile/state.ts +0 -71
@@ -1,7 +1,7 @@
1
- import { diagram } from "@cardenelabs/cdl";
1
+ import { diagram, 木の札の幅 } from "@cardenelabs/cdl";
2
2
  import type { CdlDiagram } from "@cardenelabs/cdl";
3
3
  import type { DslDocument } from "../types";
4
- import { 図表の大きさ } from "./chart-fields";
4
+ import { 図表の大きさ, 図表の大きさを読む } from "./chart-fields";
5
5
  import { 矢印から親を決める, 放射に出す文字 } from "./hierarchy";
6
6
  import type { CompileNotice } from "./notice";
7
7
  import { slugify } from "./slug";
@@ -14,8 +14,6 @@ import { 図の小見出し } from "./subtitle";
14
14
  */
15
15
  export function compileTree(doc: DslDocument, onNotice?: (n: CompileNotice) => void): CdlDiagram {
16
16
  const b = diagram(slugify(doc.title), { topic: doc.title, type: "tree" });
17
- const { w: W, h: H } = 図表の大きさ.tree;
18
- b.lane("chart", { width: W + 64 });
19
17
  // **同じ slug になる名前を先に見る**。 違う名前が同じ id に潰れると、 自分を親にしたと
20
18
  // 誤判定したり、 同じ id の要素が 2 つできたりする (review 指摘)
21
19
  const slug別 = new Map<string, string[]>();
@@ -46,6 +44,12 @@ export function compileTree(doc: DslDocument, onNotice?: (n: CompileNotice) => v
46
44
  // 書いた文字が図に出ない
47
45
  return { id, ...放射に出す文字(a), ...(p3 !== undefined ? { parent: p3 } : {}) };
48
46
  });
47
+ // 札の幅は葉の数で変わる (cdl#970)。 **規則は描画側が持つ** ので、ここでは引くだけにする。
48
+ // 写すと、描画側が割付を変えた時に記法の側だけが古い幅を渡す。
49
+ // 高さは段の数で決まり、描画側が既定を返す形なので表から取る
50
+ const 既定W = 木の札の幅(data);
51
+ const { w: W, h: H } = 図表の大きさを読む(doc, { w: 既定W, h: 図表の大きさ.tree.h });
52
+ b.lane("chart", { width: W + 64 });
49
53
  b.node(`${slugify(doc.title) || "tree"}-chart`, {
50
54
  lane: "chart",
51
55
  stack: 0,
@@ -55,6 +59,11 @@ export function compileTree(doc: DslDocument, onNotice?: (n: CompileNotice) => v
55
59
  w: W,
56
60
  h: H,
57
61
  treeData: data,
62
+ ...(doc.treeNodeForm !== undefined ? { treeNodeForm: doc.treeNodeForm } : {}),
63
+ ...(doc.treeSize !== undefined ? { treeSize: doc.treeSize } : {}),
64
+ ...(doc.treeEdgeTone !== undefined ? { treeEdgeTone: doc.treeEdgeTone } : {}),
65
+ ...(doc.treeEdgeHead !== undefined ? { treeEdgeHead: doc.treeEdgeHead } : {}),
66
+ ...(doc.figureKindLabel !== undefined ? { figureKindLabel: doc.figureKindLabel } : {}),
58
67
  });
59
68
  return b.build();
60
69
  }
@@ -1,13 +1,25 @@
1
1
  import { diagram } from "@cardenelabs/cdl";
2
2
  import type { CdlDiagram } from "@cardenelabs/cdl";
3
3
  import type { DslDocument } from "../types";
4
- import { parseChartValue, 数の欄から参照できる名前, 参照する名前 } from "./chart-fields";
4
+ import type { DslShape } from "../keywords";
5
+ import { parseChartValue, 数の欄から参照できる名前, 参照する名前, 図表の大きさを読む } from "./chart-fields";
5
6
 
6
7
  import { 箱の題 } from "./node-title";
7
8
  import type { CompileNotice } from "./notice";
8
9
  import { slugify } from "./slug";
9
10
  import { 図の小見出し } from "./subtitle";
10
- /**
11
+ import { truncateForMessage } from "./subtitle";
12
+
13
+ /** 記法で受ける円の見せ方と、描画側へ渡す値。 */
14
+ export const CHART_PIE_FORM_WORDS: ReadonlyMap<string, "ring" | "arcs" | "table"> = new Map([
15
+ ["ring", "ring"],
16
+ ["輪", "ring"],
17
+ ["arcs", "arcs"],
18
+ ["積層の弧", "arcs"],
19
+ ["table", "table"],
20
+ ["銘板", "table"],
21
+ ]);
22
+ /*
11
23
  * 棒 / 折れ線の組立て。 円グラフと **入力の形が同じ**なので 1 つにまとめる。
12
24
  *
13
25
  * 3 種とも `- 名前: "45"` の 1 行 1 値で書く。 違うのは描画側の種別と、 値の意味だけ。
@@ -23,34 +35,108 @@ import { 図の小見出し } from "./subtitle";
23
35
  *
24
36
  * 矢印は描けない。 書かれていたら警告に出して捨てる (「書いたのに効かない」 を残さない)。
25
37
  */
38
+
39
+ /**
40
+ * 形から描画側の種別を引く (#2657)。
41
+ *
42
+ * **綴りを繋げて作らない**。 8 つは `chart-<形>` で作れるが、積み上げだけ
43
+ * `chart-stacked-bar` で規則から外れる。 繋げて作ると その 1 つが黙って別の種別になる
44
+ * (描画側は知らない種別の大きさを引けず、図の組み立てが落ちる)。
45
+ */
46
+ const 描画側の種別: Readonly<Record<DslShape, CdlDiagram["nodes"][number]["kind"]>> = {
47
+ pie: "chart-pie",
48
+ bar: "chart-bar",
49
+ line: "chart-line",
50
+ gauge: "chart-gauge",
51
+ radial: "chart-radial",
52
+ stat: "chart-stat",
53
+ waffle: "chart-waffle",
54
+ stacked: "chart-stacked-bar",
55
+ slope: "chart-slope",
56
+ };
57
+
58
+ /**
59
+ * 型ごとの札の大きさ。
60
+ *
61
+ * **横も型で決める**。 縦が中身の大きさを決める型 (`stat` / `waffle` / `radial`) は、
62
+ * 横をいくら広げても絵が大きくならない。 描画側の弧は
63
+ * `外半径 = min(使える高さ / 2, 弧に使える幅 / 2)` で決まり、格子は行数で高さを使い切る。
64
+ * 横を一律 640 にしていた間、余った分は左右の余白になるだけで、`stat` は札の 22%、
65
+ * `waffle` は 57%、`radial` は 63% しか使っていなかった (見本帳の実描画を測った値)。
66
+ *
67
+ * **縦を使わない型を 368 にしない**。 `stacked` は帯 2 本と一覧だけで縦に伸びず、
68
+ * 368 だと縦の 39% しか埋まらない。
69
+ *
70
+ * **横の使用率が既に足りている型は触らない**。 `gauge` は 79%、`bar` と `line` は 85%、
71
+ * `slope` は 92% で、狭めても余白が減らず数だけが上がる。
72
+ *
73
+ * **どちらも 16 の倍数にする**。 描画側は大きさを 16 の倍数へ切り上げるため、
74
+ * 外れた値を渡すと下端が格子から外れて全図で位置の警告が出る。
75
+ * 棒と折れ線は 360 を切り上げた 368 になる。
76
+ *
77
+ * 数は見本帳の実描画から測った中身の幅に、その型が描画側で取る左右の余白を足した値。
78
+ * **数だけを直しても合っているかは判らない**ので、実描画から使用率を測る検査
79
+ * (`apps/playground-spa/tests/chart-card-fill.spec.ts`) が下限を見る。
80
+ * 5 型を 640 に戻すと、その検査が 6 件の違反を出して落ちる (実測)。
81
+ *
82
+ * 組立て API (`cdl` の `chart()`) の既定は 640 のままなので、見本の円は `itemWidth` で
83
+ * 揃える。 ずれたら `catalog-source-parity` が落ちる。
84
+ */
85
+ const 札の大きさ: Readonly<Record<Exclude<DslShape, "pie">, { w: number; h: number }>> = {
86
+ // 数値 1 つと名前だけ。 中身は 139 幅 x 137 高
87
+ stat: { w: 384, h: 240 },
88
+ // 格子 (367 幅) と一覧
89
+ waffle: { w: 464, h: 320 },
90
+ // 弧 (401 幅) と一覧
91
+ radial: { w: 512, h: 320 },
92
+ // 半円 (508 幅) と一覧。 横の使用率が 79% で足りているため変えない
93
+ gauge: { w: 640, h: 320 },
94
+ // 5 本の帯を見本の太さ 32 に近い比で置く。304 高では描画側の算式で 31.4px になる
95
+ stacked: { w: 640, h: 304 },
96
+ // 横軸を持つ 3 型。 横の使用率が 85% 以上なので変えない
97
+ bar: { w: 640, h: 368 },
98
+ line: { w: 640, h: 368 },
99
+ slope: { w: 640, h: 368 },
100
+ };
101
+
102
+ /** 描画側の円で使う寸法。`chart-pie.tsx` と同じ意味の値だけをここへ写す。 */
103
+ const 円の寸法 = {
104
+ 余白: 20,
105
+ 弧の一覧の行: 56,
106
+ 表の見出し: 40,
107
+ 表の行: 52,
108
+ } as const;
109
+
110
+ const 格子へ切り上げる = (value: number): number => Math.ceil(value / 16) * 16;
111
+
112
+ /**
113
+ * 輪は、見せ方を書かない既存の円と同じ 480x320 を保つ。
114
+ *
115
+ * 積層の弧と銘板は、描画側が実際に確保する余白と一覧 1 行ぶんを区分数だけ積む。
116
+ * 最後だけ格子に合わせて 16 の倍数へ上げる。
117
+ */
118
+ export function 円の札の大きさ(
119
+ form: "ring" | "arcs" | "table",
120
+ 区分数: number,
121
+ ): { w: number; h: number } {
122
+ if (form === "ring") return { w: 480, h: 320 };
123
+
124
+ const 件数 = Math.max(1, 区分数);
125
+ const 上下の余白 = 円の寸法.余白 * 2;
126
+ const 高さ =
127
+ form === "table"
128
+ ? 上下の余白 + 円の寸法.表の見出し + 円の寸法.表の行 * 件数
129
+ : 上下の余白 + 円の寸法.弧の一覧の行 * 件数;
130
+ return { w: 480, h: 格子へ切り上げる(高さ) };
131
+ }
132
+
26
133
  export function compileValueChart(
27
134
  doc: DslDocument,
28
- 型: "pie" | "bar" | "line" | "gauge" | "radial" | "stat" | "waffle" | "stacked" | "slope",
29
- kind:
30
- | "chart-pie"
31
- | "chart-bar"
32
- | "chart-line"
33
- | "chart-gauge"
34
- | "chart-radial"
35
- | "chart-stat"
36
- | "chart-waffle"
37
- | "chart-stacked-bar"
38
- | "chart-slope",
135
+ 型: DslShape,
39
136
  onNotice?: (notice: CompileNotice) => void,
40
137
  ): CdlDiagram {
138
+ const kind = 描画側の種別[型];
41
139
  const b = diagram(slugify(doc.title), { topic: doc.title, type: "chart" });
42
- const CHART_W = 640;
43
- // **高さは型で違い、 格子に載せる**。 描画側 (`cdl` の `chart()` preset) は `pie` を 320、
44
- // 棒と折れ線を 360 とした上で **16 の倍数へ切り上げる** (360 は 16 で割り切れないので 368)。
45
- // 切り上げないと下端が格子から外れ、 全図で位置の警告が出る (review 指摘)
46
- // 半円と弧は縦を使わないので円と同じ 320。 描画側 (`cdl` の `chart()` preset) が
47
- // `pie` / `gauge` / `radial` を 320、棒と折れ線を 360 とし、16 の倍数へ切り上げる
48
- // 縦に余白が要らない型。 描画側 (`cdl` の `chart()` preset) と揃える。
49
- // 半円 / 弧 / 割合の印 は縦を使わず、値 1 つを大きく示す図も縦に伸びない
50
- const 低い型 =
51
- 型 === "pie" || 型 === "gauge" || 型 === "radial" || 型 === "waffle" || 型 === "stat";
52
- const CHART_H = 低い型 ? 320 : 368;
53
- b.lane("chart", { width: CHART_W + 64 });
54
140
 
55
141
  const data: NonNullable<CdlDiagram["nodes"][number]["chartData"]> = [];
56
142
  const 読めない: string[] = [];
@@ -93,10 +179,12 @@ export function compileValueChart(
93
179
  前が読めない.push(a.name);
94
180
  }
95
181
  data.push({
182
+ ...(型 === "slope" || 型 === "stacked" ? { id: slugify(a.name) } : {}),
96
183
  label: 箱の題(a),
97
184
  value,
98
185
  ...(前 === null ? {} : { previous: 前 }),
99
186
  ...(a.tone !== undefined ? { tone: a.tone } : {}),
187
+ ...(a.emphasis !== undefined ? { emphasis: a.emphasis } : {}),
100
188
  });
101
189
  }
102
190
  // 案内の言葉は型ごとに変える。 共通化した時に `pie` の「割合 / 円 / 45%」 が「値 / 図 / 45」 に
@@ -127,6 +215,16 @@ export function compileValueChart(
127
215
  if (typeof console !== "undefined" && console.warn) console.warn(`[dragon] ${message}`);
128
216
  };
129
217
 
218
+ const pieForm = doc.form === undefined ? undefined : CHART_PIE_FORM_WORDS.get(doc.form);
219
+ if (型 === "pie" && doc.form !== undefined && pieForm === undefined) {
220
+ 伝える(
221
+ "chart-value-unreadable",
222
+ doc.title,
223
+ `type: pie で見せ方 (${truncateForMessage(doc.form)}) が読めません (既定の輪で描きます)。 ring / arcs / table または 輪 / 積層の弧 / 銘板 のどれかを書いてください`,
224
+ doc.formPos?.line ?? 0,
225
+ );
226
+ }
227
+
130
228
  if (読めない.length > 0) {
131
229
  伝える(
132
230
  "chart-value-unreadable",
@@ -168,6 +266,12 @@ export function compileValueChart(
168
266
  );
169
267
  }
170
268
 
269
+ const { w: CHART_W, h: CHART_H } = 図表の大きさを読む(
270
+ doc,
271
+ 型 === "pie" ? 円の札の大きさ(pieForm ?? "ring", data.length) : 札の大きさ[型],
272
+ );
273
+ b.lane("chart", { width: CHART_W + 64 });
274
+
171
275
  b.node(`${slugify(doc.title) || 型}-chart`, {
172
276
  lane: "chart",
173
277
  stack: 0,
@@ -177,6 +281,56 @@ export function compileValueChart(
177
281
  w: CHART_W,
178
282
  h: CHART_H,
179
283
  chartData: data,
284
+ ...(型 === "pie" && pieForm !== undefined ? { chartPieForm: pieForm } : {}),
285
+ ...(doc.chartSeriesSkipMuted !== undefined
286
+ ? { chartSeriesSkipMuted: doc.chartSeriesSkipMuted }
287
+ : {}),
288
+ ...(型 === "line" && doc.chartLineSeries !== undefined
289
+ ? { chartLineSeries: doc.chartLineSeries }
290
+ : {}),
291
+ ...(型 === "pie" && doc.chartPieCenterLabel !== undefined
292
+ ? { chartPieCenterLabel: doc.chartPieCenterLabel }
293
+ : {}),
294
+ ...(型 === "pie" && doc.chartPieTableColumns !== undefined
295
+ ? { chartPieTableColumns: doc.chartPieTableColumns }
296
+ : {}),
297
+ ...(型 === "pie" && doc.chartPieRingWidth !== undefined
298
+ ? { chartPieRingWidth: doc.chartPieRingWidth }
299
+ : {}),
300
+ ...(型 === "bar" && doc.chartBarSize !== undefined ? { chartBarSize: doc.chartBarSize } : {}),
301
+ ...(型 === "bar" && doc.chartBarShape !== undefined ? { chartBarShape: doc.chartBarShape } : {}),
302
+ ...(型 === "line" && doc.chartLineSize !== undefined ? { chartLineSize: doc.chartLineSize } : {}),
303
+ ...(型 === "pie" && doc.chartPieSize !== undefined ? { chartPieSize: doc.chartPieSize } : {}),
304
+ ...(型 === "waffle" && doc.chartWaffleSize !== undefined ? { chartWaffleSize: doc.chartWaffleSize } : {}),
305
+ ...(型 === "slope" && doc.chartSlopeLabelTemplate !== undefined ? { chartSlopeLabelTemplate: doc.chartSlopeLabelTemplate } : {}),
306
+ ...(型 === "slope" && doc.chartSlopeSize !== undefined ? { chartSlopeSize: doc.chartSlopeSize } : {}),
307
+ ...(型 === "stacked" && doc.chartStackedLayout !== undefined ? { chartStackedLayout: doc.chartStackedLayout } : {}),
308
+ ...(型 === "gauge" && doc.chartGaugeSize !== undefined ? { chartGaugeSize: doc.chartGaugeSize } : {}),
309
+ ...((型 === "pie" || 型 === "waffle") && doc.terminalDecoration !== undefined ? { terminalDecoration: doc.terminalDecoration } : {}),
310
+ ...(型 === "slope" && doc.chartSlopePeriods !== undefined
311
+ ? { chartSlopePeriods: doc.chartSlopePeriods }
312
+ : {}),
313
+ ...(型 === "slope" && doc.chartSlopeEmphasisIds !== undefined
314
+ ? { chartSlopeEmphasisIds: doc.chartSlopeEmphasisIds }
315
+ : {}),
316
+ ...(型 === "slope" && doc.chartSlopeUnit !== undefined
317
+ ? { chartSlopeUnit: doc.chartSlopeUnit }
318
+ : {}),
319
+ ...(型 === "stacked" && doc.chartStackedPeriods !== undefined
320
+ ? { chartStackedPeriods: doc.chartStackedPeriods }
321
+ : {}),
322
+ ...(型 === "stacked" && doc.chartStackedRateId !== undefined
323
+ ? { chartStackedRateId: slugify(doc.chartStackedRateId) }
324
+ : {}),
325
+ ...(型 === "stacked" && doc.chartStackedLegendPosition !== undefined
326
+ ? { chartStackedLegendPosition: doc.chartStackedLegendPosition }
327
+ : {}),
328
+ ...(型 === "gauge" && doc.chartGaugeValue !== undefined
329
+ ? { chartGaugeValue: doc.chartGaugeValue }
330
+ : {}),
331
+ ...(型 === "waffle" && doc.chartWaffleLegendPosition !== undefined
332
+ ? { chartWaffleLegendPosition: doc.chartWaffleLegendPosition }
333
+ : {}),
180
334
  });
181
335
 
182
336
  return b.build();