@cardenelabs/cdl 0.27.0 → 0.29.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.
@@ -2453,6 +2453,17 @@ type CdlDiagram = {
2453
2453
  * 既定の図にも当たる。
2454
2454
  */
2455
2455
  palette?: string;
2456
+ /**
2457
+ * この図がどの種類か (#645)。 書かない図は種類を持たない。
2458
+ *
2459
+ * **`cdl` は種類の名前だけを出す**。 名前を `data-cdl-type` として図の根に出すだけで、
2460
+ * 太さや色などの見た目は消費側が決める。 見た目を `cdl` に持たせると、消費側の表現を
2461
+ * 変えるたびに `cdl` の更新が要る。
2462
+ *
2463
+ * 空文字は書かなかった扱いにする = 空を出すと消費側の `[data-cdl-type]` が
2464
+ * 種類を書いていない図にも当たる。
2465
+ */
2466
+ type?: string;
2456
2467
  /**
2457
2468
  * 矢印をいつ出すか (既定 = `"phase"`、 #582)。
2458
2469
  *
@@ -2652,6 +2663,8 @@ type LaidDiagram = {
2652
2663
  topic: string;
2653
2664
  /** どの配色で描くか (#1553)。 `CdlDiagram.palette` をそのまま持ち越す */
2654
2665
  palette?: string;
2666
+ /** どの種類の図か (#645)。 `CdlDiagram.type` をそのまま持ち越す */
2667
+ type?: string;
2655
2668
  viewBox: {
2656
2669
  x: number;
2657
2670
  y: number;
@@ -2453,6 +2453,17 @@ type CdlDiagram = {
2453
2453
  * 既定の図にも当たる。
2454
2454
  */
2455
2455
  palette?: string;
2456
+ /**
2457
+ * この図がどの種類か (#645)。 書かない図は種類を持たない。
2458
+ *
2459
+ * **`cdl` は種類の名前だけを出す**。 名前を `data-cdl-type` として図の根に出すだけで、
2460
+ * 太さや色などの見た目は消費側が決める。 見た目を `cdl` に持たせると、消費側の表現を
2461
+ * 変えるたびに `cdl` の更新が要る。
2462
+ *
2463
+ * 空文字は書かなかった扱いにする = 空を出すと消費側の `[data-cdl-type]` が
2464
+ * 種類を書いていない図にも当たる。
2465
+ */
2466
+ type?: string;
2456
2467
  /**
2457
2468
  * 矢印をいつ出すか (既定 = `"phase"`、 #582)。
2458
2469
  *
@@ -2652,6 +2663,8 @@ type LaidDiagram = {
2652
2663
  topic: string;
2653
2664
  /** どの配色で描くか (#1553)。 `CdlDiagram.palette` をそのまま持ち越す */
2654
2665
  palette?: string;
2666
+ /** どの種類の図か (#645)。 `CdlDiagram.type` をそのまま持ち越す */
2667
+ type?: string;
2655
2668
  viewBox: {
2656
2669
  x: number;
2657
2670
  y: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cardenelabs/cdl",
3
- "version": "0.27.0",
3
+ "version": "0.29.0",
4
4
  "description": "CDL (Chainome Diagram Language). Mermaid-like declarative DSL that compiles to animated SVG diagrams. Built for blockchain / Solidity flows, generic enough for sequence / flow / state / ER / topology diagrams.",
5
5
  "license": "MIT",
6
6
  "author": "cardene777",
package/src/builder.ts CHANGED
@@ -1642,6 +1642,10 @@ export function diagram(
1642
1642
  * この図をどの配色で描くか (#1553)。 詳細は `CdlDiagram.palette` の doc 参照。
1643
1643
  */
1644
1644
  palette?: string;
1645
+ /**
1646
+ * この図がどの種類か (#645)。 詳しくは `CdlDiagram.type` の説明を参照。
1647
+ */
1648
+ type?: string;
1645
1649
  },
1646
1650
  ): DiagramBuilder {
1647
1651
  const lanes: CdlLane[] = [];
@@ -3780,6 +3784,8 @@ export function diagram(
3780
3784
  ...(options.structuredData === "exclude" ? { structuredData: "exclude" as const } : {}),
3781
3785
  // 配色の名前は素通しする。 空文字の遮断は `layout` が持つ (後段が必ず通るため)
3782
3786
  ...(options.palette !== undefined ? { palette: options.palette } : {}),
3787
+ // 種類の名前も同じ経路で渡し、空文字の扱いを `layout` の 1 箇所に揃える
3788
+ ...(options.type !== undefined ? { type: options.type } : {}),
3783
3789
  // inputs / formulas / scrollTriggers / eventBindings は空なら省略 (static diagram の JSON 形状維持)
3784
3790
  ...(inputs.length > 0 ? { inputs: [...inputs] } : {}),
3785
3791
  ...(formulas.length > 0 ? { formulas: [...formulas] } : {}),
package/src/layout.ts CHANGED
@@ -403,6 +403,8 @@ export function layout(diag: CdlDiagram): LaidDiagram {
403
403
  // **遮断はここだけに置く**。 描画は必ず組み立てを通り、組み立て API も `er` も
404
404
  // 素通しにしてある。 上流にも置くと、どの入力でも通らない分岐が残る
405
405
  ...(diag.palette ? { palette: diag.palette } : {}),
406
+ // 種類も配色と同じく空の目印を出さない。 遮断をここに揃えると手書きの図にも効く
407
+ ...(diag.type ? { type: diag.type } : {}),
406
408
  bboxes,
407
409
  collisions,
408
410
  nearCollisions,
package/src/presets.ts CHANGED
@@ -217,7 +217,7 @@ export type SwimlaneResult = DiagramBuilder & {
217
217
 
218
218
  export function swimlane(preset: SwimlanePreset): SwimlaneResult {
219
219
  const w = preset.laneWidth ?? 400;
220
- const b = diagram(preset.id, { topic: preset.topic });
220
+ const b = diagram(preset.id, { topic: preset.topic, type: "swimlane" });
221
221
  const labelToId = new Map<string, string>();
222
222
  const idsInOrder: string[] = [];
223
223
  for (const label of preset.lanes) {
@@ -297,7 +297,7 @@ export type FlowBuilder = {
297
297
  */
298
298
  export function flow(preset: FlowPreset): FlowBuilder {
299
299
  const w = preset.laneWidth ?? 400;
300
- const b = diagram(preset.id, { topic: preset.topic });
300
+ const b = diagram(preset.id, { topic: preset.topic, type: "flow" });
301
301
  b.lane("flow", { width: w, ...(preset.laneLabel ? { label: preset.laneLabel } : {}) });
302
302
  const tone: Tone = preset.defaultTone ?? "accent";
303
303
  const style: EdgeStyle = preset.defaultStyle ?? "dotted-flow";
@@ -451,7 +451,7 @@ export type SequenceBuilder = {
451
451
  */
452
452
  export function sequence(preset: SequencePreset): SequenceBuilder {
453
453
  const tone: Tone = preset.defaultTone ?? "accent";
454
- const b = diagram(preset.id, { topic: preset.topic });
454
+ const b = diagram(preset.id, { topic: preset.topic, type: "sequence" });
455
455
 
456
456
  // 名前だけの文字列と、呼び名を添えた物の両方を受ける (#578)
457
457
  const 面々: SequenceBoardActor[] = preset.actors.map((a) =>
@@ -591,7 +591,7 @@ export function topology(preset: TopologyPreset): TopologyBuilder {
591
591
  const groupW = preset.groupWidth ?? 460;
592
592
  const tone: Tone = preset.defaultTone ?? "accent";
593
593
  const style: EdgeStyle = preset.defaultStyle ?? "solid";
594
- const b = diagram(preset.id, { topic: preset.topic });
594
+ const b = diagram(preset.id, { topic: preset.topic, type: "topology" });
595
595
 
596
596
  const groupOrder: string[] = [];
597
597
  const groupStackCount = new Map<string, number>();
@@ -803,7 +803,7 @@ export function er(preset: ErPreset): ErBuilder {
803
803
  const tone: Tone = preset.defaultTone ?? "info";
804
804
  const 縞を敷く = preset.rowStripe ?? true;
805
805
  // 配色の名前は素通しする。 空文字の遮断は `diagram` が持つ = ここで重ねると到達しない分岐になる
806
- const b = diagram(preset.id, { topic: preset.topic, palette: preset.palette });
806
+ const b = diagram(preset.id, { topic: preset.topic, palette: preset.palette, type: "er" });
807
807
 
808
808
  const entities: string[] = [];
809
809
  const phaseActivate: string[] = [];
@@ -1030,7 +1030,7 @@ export type StateMachineBuilder = {
1030
1030
  export function stateMachine(preset: StateMachinePreset): StateMachineBuilder {
1031
1031
  const stateW = resolveStateW(preset.stateWidth, "stateMachine");
1032
1032
  const tone: Tone = preset.defaultTone ?? "accent";
1033
- const b = diagram(preset.id, { topic: preset.topic });
1033
+ const b = diagram(preset.id, { topic: preset.topic, type: "state" });
1034
1034
 
1035
1035
  const phaseActivate: string[] = [];
1036
1036
  const stateOrder = new Map<string, number>();
@@ -1236,7 +1236,7 @@ export function infrastructure(preset: InfrastructurePreset): InfrastructureBuil
1236
1236
  const laneW = preset.laneWidth ?? 380;
1237
1237
  const tone: Tone = preset.defaultTone ?? "accent";
1238
1238
  const style: EdgeStyle = preset.defaultStyle ?? "solid";
1239
- const b = diagram(preset.id, { topic: preset.topic });
1239
+ const b = diagram(preset.id, { topic: preset.topic, type: "infrastructure" });
1240
1240
 
1241
1241
  // col → laneId、 col の数で lane を auto 作成
1242
1242
  const colLaneIds = new Map<number, string>();
@@ -1347,6 +1347,38 @@ export const CLASS_RELATION_LOOK: Record<
1347
1347
  uses: { head: "open", fill: "solid", tailHead: "none", tailFill: "solid", style: "dashed" },
1348
1348
  };
1349
1349
 
1350
+ /**
1351
+ * 関係の 6 種を 3 群に寄せた色み (#641)。
1352
+ *
1353
+ * 足す前は 6 種とも 1 色で、種類の違いが色に出なかった。 見分けを担うのは 線 / 印の形 /
1354
+ * 印が付く側 の 3 軸だけで、6 種を 1 枚に並べると印の形まで見ないとどれがどれか判らない。
1355
+ *
1356
+ * **群の中は色を分けない**。 群の中の 2 種は既に線か印の塗りで分かれているので、色まで足すと
1357
+ * 同じことを 2 回言うことになる。 色が担うのは群の見分けだけ。
1358
+ *
1359
+ * | 群 | 種類 | 群の中の見分け |
1360
+ * |---|---|---|
1361
+ * | 縦の関係 | `extends` / `implements` | 線 (実線 / 破線) |
1362
+ * | 所有 | `aggregates` / `composes` | 印の塗り (白抜き / 塗る) |
1363
+ * | 向きだけ | `associates` / `uses` | 線 (実線 / 破線) |
1364
+ *
1365
+ * 群の分け方は `CLASS_RELATION_LOOK` と同じ = あちらの 印の形 が群を表しており、
1366
+ * 三角 = 縦の関係 / 菱 = 所有 / 開いた矢 = 向きだけ に 1 対 1 で対応する。
1367
+ *
1368
+ * **色の値は持たない**。 描き手は名前だけを図に載せ、実際の色は消費側が `data-cdl-tone` を
1369
+ * 見て当てる。 値を持たせると、色を変えるたびに描き手を出し直すことになる。
1370
+ *
1371
+ * `Record<ClassRelationType, Tone>` なので、種類を足すと色みも要る。
1372
+ */
1373
+ export const CLASS_RELATION_TONE: Record<ClassRelationType, Tone> = {
1374
+ extends: "accent",
1375
+ implements: "accent",
1376
+ aggregates: "teal",
1377
+ composes: "teal",
1378
+ associates: "success",
1379
+ uses: "success",
1380
+ };
1381
+
1350
1382
  /** 端の形だけを引く経路 (cdl#574 からの名前を残す)。 実体は `CLASS_RELATION_LOOK` */
1351
1383
  export const CLASS_RELATION_HEAD: Record<ClassRelationType, EdgeHead> = Object.fromEntries(
1352
1384
  Object.entries(CLASS_RELATION_LOOK).map(([k, v]) => [k, v.head]),
@@ -1457,10 +1489,16 @@ export type ClassDiagramBuilder = {
1457
1489
  */
1458
1490
  export function classDiagram(preset: ClassDiagramPreset): ClassDiagramBuilder {
1459
1491
  const classW = resolveStorageBoxW(preset.classWidth, "classDiagram", "classWidth");
1460
- const tone: Tone = preset.defaultTone ?? "info";
1492
+ /**
1493
+ * 図ぜんぶに効く色み (#641)。 **書かなければ種類ごとに決まる**。
1494
+ *
1495
+ * 書いた図は「全部同じ色みにする」 と宣言しているので、種類の既定より勝たせる。
1496
+ * 優先順位は 関係に書いた色み > 図に書いた既定 > 種類から決まる既定 の 3 段。
1497
+ */
1498
+ const 図の既定 = preset.defaultTone;
1461
1499
  // 縞と配色は `er()` と同じ扱い (#627)。 箱の作りが同じなので、既定も揃える
1462
1500
  const 縞を敷く = preset.rowStripe ?? true;
1463
- const b = diagram(preset.id, { topic: preset.topic, palette: preset.palette });
1501
+ const b = diagram(preset.id, { topic: preset.topic, palette: preset.palette, type: "class" });
1464
1502
 
1465
1503
  const classes: string[] = [];
1466
1504
  const phaseActivate: string[] = [];
@@ -1536,7 +1574,7 @@ export function classDiagram(preset: ClassDiagramPreset): ClassDiagramBuilder {
1536
1574
  id: edgeId,
1537
1575
  label: r.label ?? r.type,
1538
1576
  ...(r.cardinality ? { sub: r.cardinality } : {}),
1539
- tone: r.tone ?? tone,
1577
+ tone: r.tone ?? 図の既定 ?? CLASS_RELATION_TONE[r.type],
1540
1578
  // 関係の種類から線と端の形を決める (cdl#574 / #578)。 書いた値が勝つ
1541
1579
  style: r.style ?? 見た目.style,
1542
1580
  head: r.head ?? 見た目.head,
@@ -1602,7 +1640,7 @@ export type TreeBuilder = {
1602
1640
  export function tree(preset: TreePreset): TreeBuilder {
1603
1641
  const canvasW = preset.nodeWidth ? preset.nodeWidth * 2 : 720;
1604
1642
  const canvasH = 480;
1605
- const b = diagram(preset.id, { topic: preset.topic });
1643
+ const b = diagram(preset.id, { topic: preset.topic, type: "tree" });
1606
1644
  const treeNodes: TreeNode[] = [];
1607
1645
 
1608
1646
  const api: TreeBuilder = {
@@ -1684,7 +1722,7 @@ export type UserJourneyBuilder = {
1684
1722
  export function userJourney(preset: UserJourneyPreset): UserJourneyBuilder {
1685
1723
  const canvasW = preset.stepWidth ? preset.stepWidth * 2 : 720;
1686
1724
  const canvasH = 480;
1687
- const b = diagram(preset.id, { topic: preset.topic });
1725
+ const b = diagram(preset.id, { topic: preset.topic, type: "journey" });
1688
1726
  const steps: JourneyStep[] = [];
1689
1727
 
1690
1728
  const api: UserJourneyBuilder = {
@@ -1767,7 +1805,7 @@ export type MindMapBuilder = {
1767
1805
  export function mindMap(preset: MindMapPreset): MindMapBuilder {
1768
1806
  const canvasW = preset.branchWidth ? preset.branchWidth * 2 : 720;
1769
1807
  const canvasH = 480;
1770
- const b = diagram(preset.id, { topic: preset.topic });
1808
+ const b = diagram(preset.id, { topic: preset.topic, type: "mindmap" });
1771
1809
  const branches: MindBranch[] = [];
1772
1810
 
1773
1811
  const api: MindMapBuilder = {
@@ -1849,7 +1887,7 @@ export type FunnelBuilder = {
1849
1887
  export function funnel(preset: FunnelPreset): FunnelBuilder {
1850
1888
  const canvasW = toGridSize(preset.stageWidth ?? 560);
1851
1889
  const canvasH = 480;
1852
- const b = diagram(preset.id, { topic: preset.topic });
1890
+ const b = diagram(preset.id, { topic: preset.topic, type: "funnel" });
1853
1891
  const stages: FunnelStage[] = [];
1854
1892
 
1855
1893
  const api: FunnelBuilder = {
@@ -1936,7 +1974,7 @@ export type QuadrantBuilder = {
1936
1974
  export function quadrant(preset: QuadrantPreset): QuadrantBuilder {
1937
1975
  const canvasW = 640;
1938
1976
  const canvasH = 480;
1939
- const b = diagram(preset.id, { topic: preset.topic });
1977
+ const b = diagram(preset.id, { topic: preset.topic, type: "quadrant" });
1940
1978
  const items: QuadrantItem[] = [];
1941
1979
 
1942
1980
  const api: QuadrantBuilder = {
@@ -2050,7 +2088,7 @@ export function chart(preset: ChartPreset): ChartBuilder {
2050
2088
  ? 320
2051
2089
  : 360,
2052
2090
  );
2053
- const b = diagram(preset.id, { topic: preset.topic });
2091
+ const b = diagram(preset.id, { topic: preset.topic, type: "chart" });
2054
2092
  const data: ChartDatum[] = [];
2055
2093
 
2056
2094
  const kindMap = {
@@ -2161,7 +2199,7 @@ export function gantt(preset: GanttPreset): GanttBuilder {
2161
2199
  const canvasW = preset.laneWidth ? preset.laneWidth * 2 : 720;
2162
2200
  const canvasH = 360;
2163
2201
  const tone: Tone = preset.defaultTone ?? "teal";
2164
- const b = diagram(preset.id, { topic: preset.topic });
2202
+ const b = diagram(preset.id, { topic: preset.topic, type: "gantt" });
2165
2203
  const tasks: GanttTask[] = [];
2166
2204
 
2167
2205
  const api: GanttBuilder = {
@@ -2288,7 +2326,7 @@ const SHAPE_EYEBROW: Record<FlowchartNodeShape, string> = {
2288
2326
  export function flowchart(preset: FlowchartPreset): FlowchartBuilder {
2289
2327
  const laneW = preset.laneWidth ?? 380;
2290
2328
  const tone: Tone = preset.defaultTone ?? "accent";
2291
- const b = diagram(preset.id, { topic: preset.topic });
2329
+ const b = diagram(preset.id, { topic: preset.topic, type: "flowchart" });
2292
2330
 
2293
2331
  const laneToId = new Map<string, string>();
2294
2332
  const laneStackCount = new Map<string, number>();
@@ -2405,7 +2443,7 @@ const NET_KIND_MAP: Record<NetworkDeviceKind, NodeKind> = {
2405
2443
  export function network(preset: NetworkPreset): NetworkBuilder {
2406
2444
  const laneW = preset.laneWidth ?? 320;
2407
2445
  const tone: Tone = preset.defaultTone ?? "info";
2408
- const b = diagram(preset.id, { topic: preset.topic });
2446
+ const b = diagram(preset.id, { topic: preset.topic, type: "network" });
2409
2447
 
2410
2448
  const colLaneIds = new Map<number, string>();
2411
2449
  const phaseActivate: string[] = [];
@@ -2522,7 +2560,7 @@ export function stateMachine2(preset: StateMachine2Preset): StateMachine2Builder
2522
2560
  const stateW = resolveStateW(preset.stateWidth, "stateMachine2");
2523
2561
  const laneW = boxLaneW(stateW);
2524
2562
  const tone: Tone = preset.defaultTone ?? "accent";
2525
- const b = diagram(preset.id, { topic: preset.topic });
2563
+ const b = diagram(preset.id, { topic: preset.topic, type: "state" });
2526
2564
 
2527
2565
  const stateOrder = new Map<string, number>();
2528
2566
  const phaseActivate: string[] = [];
@@ -151,6 +151,7 @@ export function CdlStage({
151
151
  // 通るため、空文字は `layout` が既に落としている。 ここにも守りを置くと、
152
152
  // どの入力でも通らない分岐が残る
153
153
  data-cdl-palette={laid.palette}
154
+ data-cdl-type={laid.type}
154
155
  >
155
156
  <defs>
156
157
  {/* CAR-643 = cdl は geometry only。 shadow / border effect の filter は cdl SVG 内に
package/src/types.ts CHANGED
@@ -2528,6 +2528,17 @@ export type CdlDiagram = {
2528
2528
  * 既定の図にも当たる。
2529
2529
  */
2530
2530
  palette?: string;
2531
+ /**
2532
+ * この図がどの種類か (#645)。 書かない図は種類を持たない。
2533
+ *
2534
+ * **`cdl` は種類の名前だけを出す**。 名前を `data-cdl-type` として図の根に出すだけで、
2535
+ * 太さや色などの見た目は消費側が決める。 見た目を `cdl` に持たせると、消費側の表現を
2536
+ * 変えるたびに `cdl` の更新が要る。
2537
+ *
2538
+ * 空文字は書かなかった扱いにする = 空を出すと消費側の `[data-cdl-type]` が
2539
+ * 種類を書いていない図にも当たる。
2540
+ */
2541
+ type?: string;
2531
2542
  /**
2532
2543
  * 矢印をいつ出すか (既定 = `"phase"`、 #582)。
2533
2544
  *
@@ -2734,6 +2745,8 @@ export type LaidDiagram = {
2734
2745
  topic: string;
2735
2746
  /** どの配色で描くか (#1553)。 `CdlDiagram.palette` をそのまま持ち越す */
2736
2747
  palette?: string;
2748
+ /** どの種類の図か (#645)。 `CdlDiagram.type` をそのまま持ち越す */
2749
+ type?: string;
2737
2750
  viewBox: { x: number; y: number; w: number; h: number };
2738
2751
  /**
2739
2752
  * 図全体の倍率 (`CdlViewport.scale` を正規化した値)。