@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.
- package/README.md +314 -12
- package/dist/index.cjs +6966 -1438
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2150 -118
- package/dist/index.d.ts +2150 -118
- package/dist/index.js +6950 -1440
- package/dist/index.js.map +1 -1
- package/package.json +12 -13
- package/src/compile/actor-ids.ts +6 -15
- package/src/compile/actor-option-notice.ts +379 -0
- package/src/compile/actors.ts +32 -3
- package/src/compile/c4.ts +0 -3
- package/src/compile/chain.ts +43 -4
- package/src/compile/chart-fields.ts +16 -1
- package/src/compile/direction.ts +50 -11
- package/src/compile/edge-option-notice.ts +112 -0
- package/src/compile/flowchart.ts +344 -0
- package/src/compile/funnel.ts +14 -2
- package/src/compile/gantt.ts +141 -36
- package/src/compile/generic.ts +473 -61
- package/src/compile/journey.ts +14 -5
- package/src/compile/kinds.ts +5 -13
- package/src/compile/lanes.ts +95 -13
- package/src/compile/metro.ts +271 -0
- package/src/compile/mind.ts +55 -5
- package/src/compile/notice.ts +51 -4
- package/src/compile/order.ts +62 -0
- package/src/compile/parts.ts +107 -33
- package/src/compile/placement-apply.ts +27 -11
- package/src/compile/quadrant.ts +171 -16
- package/src/compile/record.ts +75 -0
- package/src/compile/row-marks.ts +128 -0
- package/src/compile/sequence.ts +105 -26
- package/src/compile/slug.ts +9 -1
- package/src/compile/stages.ts +247 -0
- package/src/compile/subtitle.ts +15 -2
- package/src/compile/swimlane-marks.ts +87 -0
- package/src/compile/swimlane.ts +13 -14
- package/src/compile/timeline.ts +213 -0
- package/src/compile/topology.ts +3 -9
- package/src/compile/tree.ts +13 -4
- package/src/compile/value-chart.ts +179 -25
- package/src/compile.ts +1550 -370
- package/src/focus.ts +2 -2
- package/src/index.ts +34 -2
- package/src/json-parser.ts +1407 -48
- package/src/keywords.ts +251 -17
- package/src/notation-lint.ts +41 -64
- package/src/schemas/diagram.json +643 -20
- package/src/types.ts +336 -35
- package/src/v05/parser.ts +2451 -271
- package/src/compile/class.ts +0 -100
- package/src/compile/er.ts +0 -44
- package/src/compile/solidity.ts +0 -39
- package/src/compile/state.ts +0 -71
package/src/compile/notice.ts
CHANGED
|
@@ -18,6 +18,20 @@ export type CompileNotice = {
|
|
|
18
18
|
| "part-not-drawn"
|
|
19
19
|
// 向きが効かない形で `向き:` を書いた (#1494)
|
|
20
20
|
| "direction-not-honored"
|
|
21
|
+
// 既定と同じ向きを書き、その向きを外しても同じ組み立てを通る (#2421)。 書いた行が図を
|
|
22
|
+
// 1 ピクセルも動かさない形で、書き手には効いたのか効かなかったのかが画面から読めない。
|
|
23
|
+
// **経路が切り替わる形とは別物** = 向きを書くとフローは鎖をやめ、担当の図は共通の組み立てへ
|
|
24
|
+
// 回る。 その切替が起きる図では既定と同じ値でも絵が変わるので、この知らせは出さない
|
|
25
|
+
| "direction-same-as-default"
|
|
26
|
+
// 並び順が効かない図種に `order:` を書いた (#2655)
|
|
27
|
+
| "order-not-honored"
|
|
28
|
+
| "shape-not-honored"
|
|
29
|
+
// 段階ごとの箱で `stage` を省き、担当または箱名から段階を補った (#2797)
|
|
30
|
+
| "stage-from-lane"
|
|
31
|
+
// 路線図で `lane` を省き、箱名を線路名に使った (#2799)
|
|
32
|
+
| "track-from-name"
|
|
33
|
+
// `theme:` とその別名 `palette:` を両方書き、`theme:` を使った (#2790)
|
|
34
|
+
| "theme-palette-both"
|
|
21
35
|
// `倍率:` を書いた見本が、同じ名前の状態も持っていた (#1026)
|
|
22
36
|
| "scale-reserved"
|
|
23
37
|
// 部品に書いた色が効かない (#1973)。 色番号を入れる状態を 1 つも持たない部品に色番号を
|
|
@@ -38,21 +52,37 @@ export type CompileNotice = {
|
|
|
38
52
|
// 箱ごとの値や時期を読んで 1 つの図に描く図種で、読めない項目があった (#1154)。 使う図種は
|
|
39
53
|
// 各図種の組み立て (`compile/*.ts`) が決める
|
|
40
54
|
| "chart-value-unreadable"
|
|
41
|
-
// 同じ図種で、書いた矢印を描かなかった (#1154)。 関係を描かない図種と、端を描けない矢印 (
|
|
55
|
+
// 同じ図種で、書いた矢印を描かなかった (#1154)。 関係を描かない図種と、端を描けない矢印 (ガントチャートで
|
|
42
56
|
// 時期の無い項目を指す等、#2111)
|
|
43
57
|
| "chart-edge-dropped"
|
|
44
58
|
// 同じ名前を `states` と `values` の両方に書いた (#1162)
|
|
45
59
|
| "value-shadows-state"
|
|
60
|
+
// 同じ名前を `states` と `inputs` の両方に書き、 値がずれた (#2413)。 両方に書くこと自体は
|
|
61
|
+
// 意図された書き方 (見本 105 箇所) だが、 描く側はつまみの既定値で状態を塗るため、
|
|
62
|
+
// ずれると状態の初期値は図のどの瞬間にも出ない
|
|
63
|
+
| "state-shadowed-by-input"
|
|
46
64
|
// 式を解けず、その値を止めた (輪 / 無い名前 / 読めない式 / 数として読めない値、 #1162)
|
|
47
65
|
| "value-unresolved"
|
|
48
66
|
// 同じ名前を `values` に 2 度書いた。 先に書いた式を使う (#1162)
|
|
49
67
|
| "value-duplicate"
|
|
50
68
|
// 矢印が `actors` に無い名前を指した (#1209)
|
|
51
69
|
| "flow-actor-missing"
|
|
70
|
+
// 帯 (`bands:`) を、 帯を描かない図種に書いた (#2404)。 帯は板の縦線に重ねる四角なので、
|
|
71
|
+
// 板を作らない図種には載せる先が無い (実測 = 24 図種のうち 22 図種が黙って捨てていた)
|
|
72
|
+
| "band-not-honored"
|
|
73
|
+
// 順序図の帯 (`bands:`) が `actors` に無い名前を指した (#2404)。 描く側は見つからない名前を
|
|
74
|
+
// 先頭の面に倒すため、 綴り違いの帯は正しく書いた帯と同じ図になり、 書き間違いが見えない
|
|
75
|
+
| "band-actor-missing"
|
|
76
|
+
// 順序図の帯に書いた区間が、 板に載る言づての並びに収まらない (#2404)。 範囲外と、
|
|
77
|
+
// 始まりが終わりより後ろ の 2 形。 **`row` は言づての行** = 描く側が `rowY(i)` で
|
|
78
|
+
// i 通目の言づての高さを返す。 段 (`animation` の `step`) ではないので `step` と呼ばない
|
|
79
|
+
| "band-row-out-of-range"
|
|
52
80
|
// きっかけ形の値を段に畳めなかった (段が無い / 相手が境目を通らない / 段からはみ出す、 #1161)
|
|
53
81
|
| "value-trigger-unresolved"
|
|
54
82
|
// 箱に `lane:` を書いたが、 縦列は図種が決めるため効かなかった (#1246)
|
|
55
83
|
| "lane-not-honored"
|
|
84
|
+
// 路線図以外の lane に、路線図の名札だけが読む補足を書いた
|
|
85
|
+
| "lane-option-not-honored"
|
|
56
86
|
// `lanes:` に書いた縦列に箱が 1 つも入らなかった (#1241)
|
|
57
87
|
| "lane-declared-empty"
|
|
58
88
|
// 最上位に `eyebrow:` を書いたが、 箱ごとに分かれる図種で相手が決まらなかった (#1247)
|
|
@@ -65,14 +95,31 @@ export type CompileNotice = {
|
|
|
65
95
|
| "draw-target-mismatch"
|
|
66
96
|
// 式が、どこにも書かれていない名前を読んだ (#1391)
|
|
67
97
|
| "formula-unresolved"
|
|
68
|
-
//
|
|
98
|
+
// 値を見せる部品が、どこにも書かれていない名前を読んだ (#2405)。 読む元は `states` /
|
|
99
|
+
// `inputs` / `formulas` の 3 つ。 見る欄は `source` の 1 つではなく、 綴りの規則
|
|
100
|
+
// (`source` / `〜Source` / `sourceA`) に当たる全ての欄
|
|
101
|
+
| "readout-source-missing"
|
|
102
|
+
// 出来事が指す相手が図に無い (#1393)。 書いた名前が本文のどこにも無い時に出す = 書き直せば直る
|
|
69
103
|
| "event-target-missing"
|
|
104
|
+
// 出来事が指す名前は本文に在るが、この図種はそれを箱 / 矢印にしない (#2336)。
|
|
105
|
+
// 値を並べる図種は図全体で 1 つの箱になり、 順序図と solidity は 1 枚の板になる。
|
|
106
|
+
// `event-target-missing` と分けるのは、こちらが **書き直しても直らない** 側だから
|
|
107
|
+
| "event-target-not-honored"
|
|
108
|
+
// 段の注目先に書いた名前は本文に在るが、この図種はそれを箱 / 矢印にしない (#2398)。
|
|
109
|
+
// `focus-target-missing` と分けるのは、こちらが **書き直しても直らない** 側だから。
|
|
110
|
+
// 出来事の側の `event-target-not-honored` と同じ性質で、同じ 7 図種でだけ相手を選べる
|
|
111
|
+
| "focus-target-not-honored"
|
|
70
112
|
// 順序図で面に種類を書いたが、板は名前と呼び名しか描かない (#1466)
|
|
71
113
|
| "actor-kind-not-honored"
|
|
114
|
+
// 箱に、その図種が描かない指定を書いた (#2360)。 木の図は位置も大きさも親子関係から決めるため
|
|
115
|
+
// 箱ごとの飾りを載せる先が無い。 板の 2 図種は `actor-kind-not-honored` が受け持つ
|
|
116
|
+
| "actor-option-not-honored"
|
|
72
117
|
// 順序図の言づてに、板が描かない飾りを書いた (#1466)。 数える飾りは `reportMessageOptionNotHonored` の一覧が持つ
|
|
73
118
|
| "message-option-not-honored"
|
|
74
119
|
// 位置のずらし (`pos` / `offsetX` / `offsetY`) を載せる相手が無いか、書いた量だけ動かせなかった (#1971)
|
|
75
120
|
| "position-offset-ignored"
|
|
121
|
+
// 箱の座標を横と縦のどちらか一方だけ書いた (#2362)。 座標は両方書いた時だけ効く
|
|
122
|
+
| "position-axis-missing"
|
|
76
123
|
// 組 (`groups:`) が束ねる縦列が図に無い (#1972)
|
|
77
124
|
| "group-lane-missing"
|
|
78
125
|
// 組が束ねる縦列の間に、束ねない縦列を挟んでいる (#1972)
|
|
@@ -80,10 +127,10 @@ export type CompileNotice = {
|
|
|
80
127
|
// 矢印に書いた多重度 (`cardinality`) から端の形を描けない (#2107)。 `er` で端の形が決まる 6 語以外を
|
|
81
128
|
// 書き、端を両方は書いていない時と、`er` 以外の図種に書いた時
|
|
82
129
|
| "cardinality-not-honored"
|
|
83
|
-
// 矢印に、その図種が描かない飾り (文字 / 色 / 線種 / 多重度) を書いた (#2111)。
|
|
130
|
+
// 矢印に、その図種が描かない飾り (文字 / 色 / 線種 / 多重度) を書いた (#2111)。 ガントチャートの矢印は
|
|
84
131
|
// 前後の関係だけを使う
|
|
85
132
|
| "edge-option-not-honored"
|
|
86
|
-
//
|
|
133
|
+
// ガントチャートの項目の終わりが始まりより前か、状態で決まる終わりが始まりより前の値を取る (#2111)
|
|
87
134
|
| "gantt-end-before-start";
|
|
88
135
|
/** 対象の名前。 光らせる相手なら書かれた指定そのまま */
|
|
89
136
|
actor: string;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { DslDocument, PresetType } from "../types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 箱を並べる順 (`order:`、 #2655)。
|
|
5
|
+
*
|
|
6
|
+
* ## 型ではなく語で持つ
|
|
7
|
+
*
|
|
8
|
+
* 並べ替えの鍵しか持たない図種 (`solidity`) が在り、独自の組み立てを 1 行も持たずに
|
|
9
|
+
* 箱を種類で並べ替えてから順序図の組み立てをそのまま呼んでいた。
|
|
10
|
+
*
|
|
11
|
+
* 型として持つと、振る舞いを書くたびに「順序図 または その型」 という条件を並べることになる。
|
|
12
|
+
* 実際 `compile.ts` に 6 か所あり、**次に条件を足す人が片方を書き忘れれば黙って外れる**
|
|
13
|
+
* 形になっていた。 差が並べ替えだけなら語で表す。
|
|
14
|
+
*
|
|
15
|
+
* ## 種類の順は 4 段
|
|
16
|
+
*
|
|
17
|
+
* 人 → 契約 → しまう場所 → 出来事 の順に置く。 元の実装が持っていた並びをそのまま移した。
|
|
18
|
+
* **同じ段の中では書いた順のまま** = 比べる値が等しい時の並びは変わらない。
|
|
19
|
+
*
|
|
20
|
+
* 表に無い種類は最後に置く。 知らない種類を先頭へ寄せると、書き手が種類を書き間違えた図で
|
|
21
|
+
* 並びが大きく崩れて原因が読めない。
|
|
22
|
+
*/
|
|
23
|
+
const 種類の段: Record<string, number> = {
|
|
24
|
+
eoa: 0,
|
|
25
|
+
actor: 0,
|
|
26
|
+
multisig: 0,
|
|
27
|
+
signer: 0,
|
|
28
|
+
wallet: 0,
|
|
29
|
+
contract: 1,
|
|
30
|
+
proxy: 1,
|
|
31
|
+
library: 1,
|
|
32
|
+
interface: 1,
|
|
33
|
+
storage: 2,
|
|
34
|
+
event: 3,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/** 表に無い種類を置く段。 どの段よりも後ろになる数にする */
|
|
38
|
+
const 表に無い種類の段 = 5;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 並び順を書ける図種 (#2655)。
|
|
42
|
+
*
|
|
43
|
+
* 順序図だけ。 他の図種は並び方そのものが読み方を担う (縦列が役割を表す / 段が階層を表す)
|
|
44
|
+
* ので、外から並べ替えると図の意味が変わる。 書いても効かせず、書いたことを知らせる。
|
|
45
|
+
*/
|
|
46
|
+
export const 並び順を選べる図種: ReadonlySet<PresetType> = new Set<PresetType>(["sequence"]);
|
|
47
|
+
|
|
48
|
+
/** 書いた並び順が効くか (#2655) */
|
|
49
|
+
export function 並び順が効くか(doc: DslDocument): boolean {
|
|
50
|
+
return doc.order !== undefined && 並び順を選べる図種.has(doc.type);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 並び順を当てた文書を返す (#2655)。
|
|
55
|
+
*
|
|
56
|
+
* 効かない図種と、書かなかった図はそのまま返す = **書かない図の並びは 1 つも動かない**。
|
|
57
|
+
*/
|
|
58
|
+
export function 並べ替えた文書(doc: DslDocument): DslDocument {
|
|
59
|
+
if (!並び順が効くか(doc)) return doc;
|
|
60
|
+
const 段 = (kind: string): number => 種類の段[kind] ?? 表に無い種類の段;
|
|
61
|
+
return { ...doc, actors: [...doc.actors].sort((a, b) => 段(a.kind) - 段(b.kind)) };
|
|
62
|
+
}
|
package/src/compile/parts.ts
CHANGED
|
@@ -319,9 +319,10 @@ export function partRenderSize(part: CdlDiagram): { w: number; h: number } {
|
|
|
319
319
|
* `readouts` を図の中では扱わないため、図として重ねても何も出ない。 位置決めのための
|
|
320
320
|
* 1x1 の箱が 1 つあるだけになる。
|
|
321
321
|
*
|
|
322
|
-
* catalog
|
|
323
|
-
* `readouts` を持つ 17 件は箱と図枠の面積比が全件 0.
|
|
324
|
-
*
|
|
322
|
+
* catalog を測ると、この 2 群は `readouts` の有無で完全に分かれる。
|
|
323
|
+
* `readouts` を持つ 17 件は箱と図枠の面積比が全件 0.00007 (箱は 1x1 で図枠は 120x120)、
|
|
324
|
+
* 持たない群は最小でも 0.37662。 境目に入る件は無い
|
|
325
|
+
* (#2681 で図枠が中身に寄るようになり、どちらの群も値が上がったが隔たりは残った)。
|
|
325
326
|
*
|
|
326
327
|
* 判定は面積の閾値ではなく **`readouts` を持ち、かつ箱が図枠に対して極小** の 2 条件で行う。
|
|
327
328
|
* 閾値だけで見ると、小さい箱を意図して置いた見本を巻き込む。 `readouts` だけで見ると、
|
|
@@ -436,6 +437,64 @@ function partFrameGeometry(part: CdlDiagram): PartFrameGeometry {
|
|
|
436
437
|
return out;
|
|
437
438
|
}
|
|
438
439
|
|
|
440
|
+
/** 測るためだけの配置が受け取った知らせの数 (#2312)。 */
|
|
441
|
+
let 測るために受け取った知らせ = 0;
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* **測るためだけに配置する** (#2312)。
|
|
445
|
+
*
|
|
446
|
+
* 組み立て処理は、縦列の位置や部品の図枠を知るために図を配置する。 その配置は読むだけで、
|
|
447
|
+
* 画面にも書き出しにも出ない。 部品や位置はこの後に動かすので、測った時の並びは残らない。
|
|
448
|
+
*
|
|
449
|
+
* ところが記法の engine は配置のたびに重なりを `console.warn` に出す。 測るためだけの配置でも
|
|
450
|
+
* 出るので、**描かれない図についての知らせ** が端末に流れていた。 カタログの群 14 file を
|
|
451
|
+
* 読み込むだけで 481 行 (箱どうしの重なり 48 件は、出来上がった図では 1 件も重ならない)。
|
|
452
|
+
*
|
|
453
|
+
* engine の `layout()` は引数を 1 つしか取らず、知らせを止める口が無い。 呼ぶ側で受け取る。
|
|
454
|
+
*
|
|
455
|
+
* **黙って捨てない**。 受け取った数を覚えておき、`測るために受け取った知らせの数()` で読める。
|
|
456
|
+
* 数えないと「知らせが無い」 と「この経路を通っていない」 が区別できず、読み込み時の知らせを
|
|
457
|
+
* 0 行で固定する検査が空振りしても気付けない。
|
|
458
|
+
*
|
|
459
|
+
* 記法の engine 以外の知らせ (`[dragon]` で始まる組み立て側の知らせなど) はそのまま通す。
|
|
460
|
+
* 止めるのは engine が配置のたびに出す分に限る。
|
|
461
|
+
*
|
|
462
|
+
* 出来上がった図についての知らせは止めない。 画面を描く側の配置は別の経路で、
|
|
463
|
+
* そちらの知らせは `layout-warn-ledger` が宣言と突き合わせている (#2308)。
|
|
464
|
+
*
|
|
465
|
+
* **配置できない図の扱いは呼ぶ側のまま**。 例外はそのまま返す = ここで握ると、今まで
|
|
466
|
+
* 例外を投げていた呼び出し (`partsBaseBottomWithoutParts`) が黙って `undefined` を返す形に
|
|
467
|
+
* 変わる。 知らせを受け取ること以外は何も変えない。
|
|
468
|
+
*/
|
|
469
|
+
export function 測るために配置する(d: CdlDiagram): LaidDiagram {
|
|
470
|
+
const 元 =
|
|
471
|
+
typeof console !== "undefined" && typeof console.warn === "function" ? console.warn : undefined;
|
|
472
|
+
if (元) {
|
|
473
|
+
console.warn = (...a: unknown[]) => {
|
|
474
|
+
if (a.map(String).join(" ").includes("[cdl layout]")) {
|
|
475
|
+
測るために受け取った知らせ++;
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
元(...(a as []));
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
try {
|
|
482
|
+
return layout(d);
|
|
483
|
+
} finally {
|
|
484
|
+
if (元) console.warn = 元;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* 測るためだけの配置が受け取った知らせの数 (#2312)。
|
|
490
|
+
*
|
|
491
|
+
* 読み込み時の知らせを 0 行で固定する検査が、母数として読む。 0 件なら「知らせが無い」 では
|
|
492
|
+
* なく「測るための配置を 1 度も通っていない」 = 検査が空振りしている。
|
|
493
|
+
*/
|
|
494
|
+
export function 測るために受け取った知らせの数(): number {
|
|
495
|
+
return 測るために受け取った知らせ;
|
|
496
|
+
}
|
|
497
|
+
|
|
439
498
|
/**
|
|
440
499
|
* 部品の頁 (部品の図だけ) を配置した結果。 配置できない図では `undefined` (#1992)。
|
|
441
500
|
*
|
|
@@ -453,7 +512,7 @@ function 部品の頁を配置する(part: CdlDiagram): LaidDiagram | undefined
|
|
|
453
512
|
let out: LaidDiagram | null = null;
|
|
454
513
|
if (countDiagramElements(part) <= MAX_INPUT_ELEMENTS) {
|
|
455
514
|
try {
|
|
456
|
-
out =
|
|
515
|
+
out = 測るために配置する(part);
|
|
457
516
|
} catch {
|
|
458
517
|
out = null;
|
|
459
518
|
}
|
|
@@ -508,10 +567,19 @@ function 部品の置き方を読む(part: CdlDiagram): 部品の置き方 {
|
|
|
508
567
|
* 縦列の外接矩形。 幅が正でない時 (縦列が 1 本も無い図) は 400 に落とす。
|
|
509
568
|
* 1 未満の正の幅はそのまま使う。 1 に切り上げると、その分だけ `大きさ:` の倍率が小さくなる
|
|
510
569
|
*/
|
|
511
|
-
function 縦列の外接(縦列: ReadonlyMap<string, { x: number; w: number }>): {
|
|
570
|
+
function 縦列の外接(縦列: ReadonlyMap<string, { x: number; w: number }>): {
|
|
571
|
+
左端: number;
|
|
572
|
+
幅: number;
|
|
573
|
+
} {
|
|
512
574
|
const 値 = [...縦列.values()];
|
|
513
|
-
const 左端 = minOf(
|
|
514
|
-
|
|
575
|
+
const 左端 = minOf(
|
|
576
|
+
値.map((g) => g.x),
|
|
577
|
+
0,
|
|
578
|
+
);
|
|
579
|
+
const 右端 = maxOf(
|
|
580
|
+
値.map((g) => g.x + g.w),
|
|
581
|
+
400,
|
|
582
|
+
);
|
|
515
583
|
return { 左端, 幅: positiveOr(右端 - 左端, 400) };
|
|
516
584
|
}
|
|
517
585
|
|
|
@@ -816,8 +884,9 @@ function baseDiagramBottom(
|
|
|
816
884
|
// 早い戻り。 変異試験でこの行を外しても落ちる検査は 0 件で、それが期待どおり
|
|
817
885
|
if (baseNodes.length === 0) return undefined;
|
|
818
886
|
const baseIds = new Set(baseNodes.map((n) => n.id));
|
|
887
|
+
// 部品を外した並びの下端を測るだけで、この配置は残らない (#2312)
|
|
819
888
|
return partsBaseBottom(
|
|
820
|
-
|
|
889
|
+
測るために配置する({
|
|
821
890
|
...target,
|
|
822
891
|
lanes: target.lanes.filter((l) => !partsLaneIds.has(l.id)),
|
|
823
892
|
nodes: [...baseNodes],
|
|
@@ -902,12 +971,9 @@ function partGridCenters(
|
|
|
902
971
|
//
|
|
903
972
|
// **座標で書いた箱は数える**。 こちらは格子より先に位置が決まっており、1 度目と 2 度目で
|
|
904
973
|
// 動かない。 外すと、座標で下に置いた箱にパーツが重なる。
|
|
905
|
-
const 相対で置く箱 = new Set(
|
|
906
|
-
doc.actors.filter((a) => a.posRel !== undefined).map((a) => a.name),
|
|
907
|
-
);
|
|
974
|
+
const 相対で置く箱 = new Set(doc.actors.filter((a) => a.posRel !== undefined).map((a) => a.name));
|
|
908
975
|
const baseNodes = target.nodes.filter(
|
|
909
|
-
(n) =>
|
|
910
|
-
!partsActorNames.has(n.title) && !partsLaneIds.has(n.lane) && !相対で置く箱.has(n.title),
|
|
976
|
+
(n) => !partsActorNames.has(n.title) && !partsLaneIds.has(n.lane) && !相対で置く箱.has(n.title),
|
|
911
977
|
);
|
|
912
978
|
// 取り込まれない見本は格子の枠を使わない (#1015)。 枠を使うと、落とした見本の分だけ
|
|
913
979
|
// 後続がずれる (実測 = 隣の見本の左端が 60 から 725 に動いた)
|
|
@@ -1050,7 +1116,10 @@ function 部品の要素へ繋ぐ(
|
|
|
1050
1116
|
} else {
|
|
1051
1117
|
理由 =
|
|
1052
1118
|
要素.length === 0
|
|
1053
|
-
? {
|
|
1119
|
+
? {
|
|
1120
|
+
message: "の中に繋げる要素が無い",
|
|
1121
|
+
hint: "この部品は要素を持たないため、矢印の端にできません",
|
|
1122
|
+
}
|
|
1054
1123
|
: {
|
|
1055
1124
|
message: "の中のどの要素に繋ぐかが決まらない",
|
|
1056
1125
|
hint: `要素が 2 つ以上ある部品は、矢印に ${欄}: <要素の id> を書いて繋ぐ要素を選ぶ (要素 = ${要素の一覧})`,
|
|
@@ -1077,7 +1146,7 @@ function 部品の要素へ繋ぐ(
|
|
|
1077
1146
|
* 名指しは部品の端でだけ読む。 部品でない箱の端に書くと値はどこにも届かず、黙って捨てると
|
|
1078
1147
|
* 「書いたのに繋ぎ先が変わらない」 が手掛かりなしで起きる。
|
|
1079
1148
|
*
|
|
1080
|
-
* 順序図 (`sequence`
|
|
1149
|
+
* 順序図 (`sequence`) は板の言づてが縦の線に届き、部品の要素へは繋がないため、
|
|
1081
1150
|
* 部品の端に書いても効かない。 部品の一覧に無い部品は組み立てが部品を引いてから知らせる。
|
|
1082
1151
|
*/
|
|
1083
1152
|
export function reportPartNodeNotHonored(
|
|
@@ -1085,7 +1154,7 @@ export function reportPartNodeNotHonored(
|
|
|
1085
1154
|
onNotice?: (notice: CompileNotice) => void,
|
|
1086
1155
|
): void {
|
|
1087
1156
|
if (!onNotice) return;
|
|
1088
|
-
const 順序図 = doc.type === "sequence"
|
|
1157
|
+
const 順序図 = doc.type === "sequence";
|
|
1089
1158
|
const 部品 = new Set(doc.actors.filter((a) => a.partId !== undefined).map((a) => a.name));
|
|
1090
1159
|
const 居る = new Set(doc.actors.map((a) => a.name));
|
|
1091
1160
|
for (const s of doc.flow) {
|
|
@@ -1173,7 +1242,7 @@ function 仮の箱のidか(doc: DslDocument, name: string): (id: string) => bool
|
|
|
1173
1242
|
* 限る = 全員が 1 本の縦列を共有する図種 (`flow` / `topology` / `c4`) は格子のまま残る。
|
|
1174
1243
|
* 仮の箱が作られない形 (流れに現れない `swimlane` の登場人物) は、名札が部品の名前の空の縦列で引く。
|
|
1175
1244
|
*
|
|
1176
|
-
* **順序図 (`sequence`
|
|
1245
|
+
* **順序図 (`sequence`) は対象にしない**。 1 枚の板で描き、縦列を持たない (#1466)。
|
|
1177
1246
|
*
|
|
1178
1247
|
* **他の箱の位置の基準になっている部品は縦列に置かない**。 相対の位置 (`位置: 印 の右 200`) は
|
|
1179
1248
|
* 組み立ての前に格子の位置を基準に解くため、基準の部品だけを縦列へ動かすと書いた位置関係が
|
|
@@ -1185,7 +1254,7 @@ function 縦列に置く部品(
|
|
|
1185
1254
|
): { 縦列: Map<string, string>; 基準のため外した: Map<string, string> } {
|
|
1186
1255
|
const 縦列 = new Map<string, string>();
|
|
1187
1256
|
const 基準のため外した = new Map<string, string>();
|
|
1188
|
-
if (doc.type === "sequence"
|
|
1257
|
+
if (doc.type === "sequence") return { 縦列, 基準のため外した };
|
|
1189
1258
|
const 基準の名前 = new Set(
|
|
1190
1259
|
doc.actors.map((a) => a.posRel?.anchor).filter((n): n is string => n !== undefined),
|
|
1191
1260
|
);
|
|
@@ -1220,7 +1289,8 @@ function 部品の縦列(
|
|
|
1220
1289
|
if (仮の箱の縦列.size > 1) return undefined;
|
|
1221
1290
|
const [入っていた] = [...仮の箱の縦列];
|
|
1222
1291
|
const 候補 =
|
|
1223
|
-
入っていた ??
|
|
1292
|
+
入っていた ??
|
|
1293
|
+
target.lanes.find((l) => l.label === a.name && !target.nodes.some((n) => n.lane === l.id))?.id;
|
|
1224
1294
|
if (候補 === undefined) return undefined;
|
|
1225
1295
|
// 他の登場人物の箱が同じ縦列に居れば、自分だけの縦列ではない
|
|
1226
1296
|
return target.nodes.some((n) => n.lane === 候補 && !仮の箱か(n.id)) ? undefined : 候補;
|
|
@@ -1244,7 +1314,7 @@ function cleanupPlaceholderActor(
|
|
|
1244
1314
|
): void {
|
|
1245
1315
|
const aliasSlug = slugify(a.name);
|
|
1246
1316
|
const ownedLaneIds = new Set<string>();
|
|
1247
|
-
if (doc.type === "sequence"
|
|
1317
|
+
if (doc.type === "sequence") {
|
|
1248
1318
|
for (const l of target.lanes) {
|
|
1249
1319
|
// 明示 lane mapping (a.lane) 先は part の張替え先で actor 専用 lane ではないため除外
|
|
1250
1320
|
if (a.lane !== undefined && l.id === a.lane) continue;
|
|
@@ -1283,7 +1353,7 @@ function cleanupPlaceholderActor(
|
|
|
1283
1353
|
// 生成する。 node/edge だけ消して lane を残すと、 merge 後の part 側 lane (label = alias) と 2 本が
|
|
1284
1354
|
// 同じ label を lane-label として描画し二重表示になる (actor ラベル二重表示 bug の root cause)。
|
|
1285
1355
|
//
|
|
1286
|
-
//
|
|
1356
|
+
// 削除は順序図 (sequence = compileSequence 経由) に限定する。 これらは
|
|
1287
1357
|
// 1 actor = 1 lane (lane.label === a.name、 lane.id は actor 名の slug) の生成規則が成立し、
|
|
1288
1358
|
// parts actor 用 lane を安全に削除できる。 他 preset (flow / topology / class / pie 等) は複数
|
|
1289
1359
|
// actor が共有 lane (id = "main" 等) を参照するため、 一致 lane を消すと通常 actor の node が
|
|
@@ -1454,7 +1524,7 @@ export function mergePartsFromActors(
|
|
|
1454
1524
|
const 値 = s[欄];
|
|
1455
1525
|
if (値 === undefined || s[側] !== actor.name) continue;
|
|
1456
1526
|
// 順序図は部品の有無に依らず名指しが効かない。 そちらの知らせと 2 度出さない
|
|
1457
|
-
if (doc.type === "sequence"
|
|
1527
|
+
if (doc.type === "sequence") continue;
|
|
1458
1528
|
onNotice?.({
|
|
1459
1529
|
kind: "part-node-ignored",
|
|
1460
1530
|
actor: actor.name,
|
|
@@ -1471,7 +1541,7 @@ export function mergePartsFromActors(
|
|
|
1471
1541
|
// slug で始まる名前をまとめて対象にする。
|
|
1472
1542
|
//
|
|
1473
1543
|
// sweep に使う slug は 2 系統ある (#873)。 dragon の slugify は `_` / 全角を保持するが、 非 animate
|
|
1474
|
-
// sequence
|
|
1544
|
+
// sequence の node は cdl preset 側の slugify (`_` → `-` 置換、 NFKC なし) で生成される
|
|
1475
1545
|
// ため、 dragon slug だけで sweep すると `arc_one` → 実 id `arc-one-header` を取りこぼし、 header /
|
|
1476
1546
|
// footer (title = actor 名) が残って actor 名が多重表示される。
|
|
1477
1547
|
//
|
|
@@ -1620,7 +1690,7 @@ export function mergePartsFromActors(
|
|
|
1620
1690
|
* 1 つも部品を光らせていなかった)。
|
|
1621
1691
|
*
|
|
1622
1692
|
* **仮の箱を消す所で置き換えず、書いた `focus` を読み直す**。 仮の箱の id の形は図種で違い
|
|
1623
|
-
* (順序図は縦列の上端 / 下端 /
|
|
1693
|
+
* (順序図は縦列の上端 / 下端 / 手順箱、フローは箱 1 つ)、置き換えると図種ごとに規則が要る。
|
|
1624
1694
|
* 書いた名前から引けば、図種に依らず同じ規則で足せる。
|
|
1625
1695
|
*
|
|
1626
1696
|
* | 書いた相手 | 足すもの |
|
|
@@ -1658,7 +1728,10 @@ function 部品の名前で光らせる(
|
|
|
1658
1728
|
線: part.edges.map((e) => e.id).filter((id) => 線.has(`${名前}__${id}`)),
|
|
1659
1729
|
};
|
|
1660
1730
|
部品の中.set(名前, 中);
|
|
1661
|
-
部品の相手.set(
|
|
1731
|
+
部品の相手.set(
|
|
1732
|
+
名前,
|
|
1733
|
+
[...中.要素, ...中.線].map((id) => `${名前}__${id}`),
|
|
1734
|
+
);
|
|
1662
1735
|
}
|
|
1663
1736
|
const 長い名前から = [...取り込んだ.keys()].sort((a, b) => b.length - a.length);
|
|
1664
1737
|
const 見せる数 = 8;
|
|
@@ -1670,7 +1743,8 @@ function 部品の名前で光らせる(
|
|
|
1670
1743
|
// 部品だけが光らない状態を作らないよう揃える。 2 つ以上の名前が同じ slug になる時は引かない
|
|
1671
1744
|
const 書いた名前 = new Set(doc.actors.map((a) => a.name));
|
|
1672
1745
|
const slugの数 = new Map<string, number>();
|
|
1673
|
-
for (const 名前 of 書いた名前)
|
|
1746
|
+
for (const 名前 of 書いた名前)
|
|
1747
|
+
slugの数.set(slugify(名前), (slugの数.get(slugify(名前)) ?? 0) + 1);
|
|
1674
1748
|
const slugから = new Map<string, string[]>();
|
|
1675
1749
|
for (const [名前, 相手] of 部品の相手) {
|
|
1676
1750
|
if (slugの数.get(slugify(名前)) === 1) slugから.set(slugify(名前), 相手);
|
|
@@ -1731,8 +1805,8 @@ const 部品の縦列の名札の高さ = 60;
|
|
|
1731
1805
|
*
|
|
1732
1806
|
* 部品の要素は座標で置くが、縦列は描画側が左から詰めて並べ直す。 格子の 2 段目の部品の縦列は
|
|
1733
1807
|
* 1 段目の縦列と重なるため右へ送られ、名札が別の部品の上に出て、送った分だけ図が横に伸びた
|
|
1734
|
-
* (実測 = 部品 4
|
|
1735
|
-
*
|
|
1808
|
+
* (実測 = 部品 4 つのフローで `稼働2` の名札が `稼働3` の上、図の右に 875 の空き)。 部品が 1 つでも
|
|
1809
|
+
* 名札は図の上端に出て、フローの途中に置くと先頭の箱の見出しに見えた。
|
|
1736
1810
|
*
|
|
1737
1811
|
* 描画側は `posX` と `posY` を両方持つ縦列を置いた位置に置き、詰める送りも幅の自動拡張もしない。
|
|
1738
1812
|
* 幅は `posW` が無ければ縦列の `width` を使うので、横は位置だけを書く。
|
|
@@ -1778,7 +1852,8 @@ function 部品の縦列を部品に固定する(
|
|
|
1778
1852
|
if (対象.length === 0) return;
|
|
1779
1853
|
let laid: LaidDiagram;
|
|
1780
1854
|
try {
|
|
1781
|
-
|
|
1855
|
+
// 部品の要素の上下端を測るだけで、この配置は残らない (#2312)
|
|
1856
|
+
laid = 測るために配置する(target);
|
|
1782
1857
|
} catch {
|
|
1783
1858
|
return;
|
|
1784
1859
|
}
|
|
@@ -1951,9 +2026,10 @@ const 部品の縦列の余白 = 25;
|
|
|
1951
2026
|
*/
|
|
1952
2027
|
function 縦列に置いた部品を揃える(target: CdlDiagram, 置いた: readonly 縦列に置いた部品[]): void {
|
|
1953
2028
|
if (置いた.length === 0) return;
|
|
2029
|
+
// 揃える前の並びを測るだけで、この配置は残らない。 知らせは呼ぶ側で受け取る (#2312)
|
|
1954
2030
|
const 配置する = (): LaidDiagram | undefined => {
|
|
1955
2031
|
try {
|
|
1956
|
-
return
|
|
2032
|
+
return 測るために配置する(target);
|
|
1957
2033
|
} catch {
|
|
1958
2034
|
return undefined;
|
|
1959
2035
|
}
|
|
@@ -2361,9 +2437,7 @@ function mergePartIntoDiagram(
|
|
|
2361
2437
|
const mappedLane = laneIdMap.get(nodeOrig.lane) ?? nodeOrig.lane;
|
|
2362
2438
|
// 形の中の文字は、入れ子の底まで辿って差し替える。
|
|
2363
2439
|
// 1 段だけ見る形だと `fill: { gradient: "{v}" }` のような書き方が置き換わらずに残る。
|
|
2364
|
-
let newShape = nodeOrig.shape
|
|
2365
|
-
? deepRewriteStrings(nodeOrig.shape, rewriteTemplate)
|
|
2366
|
-
: undefined;
|
|
2440
|
+
let newShape = nodeOrig.shape ? deepRewriteStrings(nodeOrig.shape, rewriteTemplate) : undefined;
|
|
2367
2441
|
// parts 全体 resize (I2 forensic): shape 内 radius / outerRadius / innerRadius / thickness に
|
|
2368
2442
|
// scale 反映 = user が SE handle drag で拡大すると shape の見た目も比例拡大される。 scaleX を採用
|
|
2369
2443
|
// (等比 scale 相当、 縦方向 scaleY と乖離する場合は近似)、 shape 内数値 field のうち幾何寸法系
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { layout } from "@cardenelabs/cdl";
|
|
2
1
|
import type { CdlDiagram, LaidDiagram } from "@cardenelabs/cdl";
|
|
3
2
|
import {
|
|
4
3
|
orderByDependency,
|
|
@@ -8,7 +7,8 @@ import {
|
|
|
8
7
|
} from "../relative-pos";
|
|
9
8
|
import type { DslDocument } from "../types";
|
|
10
9
|
import type { CompileNotice } from "./notice";
|
|
11
|
-
import {
|
|
10
|
+
import { 箱の題 } from "./node-title";
|
|
11
|
+
import { partBoxes, partSizes, 測るために配置する } from "./parts";
|
|
12
12
|
import { PLACEMENT_TOLERANCE } from "./placement";
|
|
13
13
|
import { slugify } from "./slug";
|
|
14
14
|
import { truncateForMessage } from "./subtitle";
|
|
@@ -125,11 +125,11 @@ export function resolveRelativeDoc(
|
|
|
125
125
|
* 見逃す。 書いた言葉 (`Web の右 200`) が最後の図でも成り立つかを見る。
|
|
126
126
|
*
|
|
127
127
|
* **落とす側 (`relative-position-ignored` を出す枝) に届く入力は組めていない** (#2041 の実測)。
|
|
128
|
-
* 試した形は 56 通り = 22 図種 × 右と下、値を持つ `pie` / `bar`、板になる `
|
|
128
|
+
* 試した形は 56 通り = 22 図種 × 右と下、値を持つ `pie` / `bar`、板になる `sequence` と `tree`、
|
|
129
129
|
* 同じ場所に 2 つ置く / 間隔 0 で隣に置く / 縦列をまたいで下に置く / 囲いの外へ 3000 出す。
|
|
130
130
|
* どれも知らせが 0 件だった。
|
|
131
131
|
*
|
|
132
|
-
* 座標が効かない図種は、そもそも面ごとの箱を持たない (`sequence`
|
|
132
|
+
* 座標が効かない図種は、そもそも面ごとの箱を持たない (`sequence` の板)。
|
|
133
133
|
* その場合は上の `boxes.get(actor.name)` が空になって手前で抜けるため、この枝には来ない。
|
|
134
134
|
* 箱を持つ図種では座標がそのまま効く。 描画側が置いた位置を動かす規則を持った時に備えて残す。
|
|
135
135
|
*
|
|
@@ -241,7 +241,7 @@ export function measureActorBoxes(
|
|
|
241
241
|
*/
|
|
242
242
|
laidHint?: LaidDiagram,
|
|
243
243
|
): Map<string, AnchorBox> {
|
|
244
|
-
const laid = laidHint ??
|
|
244
|
+
const laid = laidHint ?? 測るために配置する(diagram);
|
|
245
245
|
const bounds = new Map<string, { x0: number; y0: number; x1: number; y1: number }>();
|
|
246
246
|
for (const n of laid.nodes) {
|
|
247
247
|
const title = n.title;
|
|
@@ -351,9 +351,9 @@ export function applyLayoutOffsets(
|
|
|
351
351
|
const ずらす縦列 = Object.entries(doc.lanes ?? {}).filter(([, l]) => l.layoutPos !== undefined);
|
|
352
352
|
if (ずらす箱.length === 0 && ずらす縦列.length === 0) return;
|
|
353
353
|
// 順序図の板は面ごとの箱を持たない。 効かないことは `reportActorKindNotHonored` が伝える
|
|
354
|
-
if (doc.type === "sequence"
|
|
354
|
+
if (doc.type === "sequence") return;
|
|
355
355
|
|
|
356
|
-
const 前 =
|
|
356
|
+
const 前 = 測るために配置する(diagram);
|
|
357
357
|
const 箱の配置 = new Map(前.nodes.map((n) => [n.id, n] as const));
|
|
358
358
|
const 縦列の配置 = new Map(前.lanes.map((l) => [l.id, l] as const));
|
|
359
359
|
const 相手たち: ずらしの相手[] = [];
|
|
@@ -457,7 +457,7 @@ export function applyLayoutOffsets(
|
|
|
457
457
|
node.posX = 狙い.x;
|
|
458
458
|
node.posY = 狙い.y;
|
|
459
459
|
}
|
|
460
|
-
基準 =
|
|
460
|
+
基準 = 測るために配置する(diagram);
|
|
461
461
|
for (const node of diagram.nodes) {
|
|
462
462
|
if (!箱だけの狙い.has(node.id)) continue;
|
|
463
463
|
const 元 = 元の箱.get(node.id)!;
|
|
@@ -508,7 +508,7 @@ export function applyLayoutOffsets(
|
|
|
508
508
|
};
|
|
509
509
|
/** 狙いと実際の差。 縦列を固定する時は、ずらさない縦列と箱も元の位置に居るかを見る */
|
|
510
510
|
const 測る = (): Map<string, { x: number; y: number }> => {
|
|
511
|
-
const 後 =
|
|
511
|
+
const 後 = 測るために配置する(diagram);
|
|
512
512
|
const 差 = new Map<string, { x: number; y: number }>();
|
|
513
513
|
for (const n of 後.nodes) {
|
|
514
514
|
const 狙い = 箱の狙い.get(n.id);
|
|
@@ -610,12 +610,26 @@ export function applyLayoutOffsets(
|
|
|
610
610
|
/**
|
|
611
611
|
* 全図種共通の後処理で、 登場人物に書かれた色を対応する箱に載せる。
|
|
612
612
|
*
|
|
613
|
-
* 箱を作る経路は図種ごとに違い、 cdl の preset を経由する図種 (
|
|
613
|
+
* 箱を作る経路は図種ごとに違い、 cdl の preset を経由する図種 (フロー / ER / 状態遷移 / 構成図)
|
|
614
614
|
* では preset の入力型が色の項目を持たない。 箱が出来上がった後に id で対応付けることで、
|
|
615
615
|
* どの図種でも同じ書き方が効く。 座標を伝播する `applyCanvasPivotPositions` と同じ経路。
|
|
616
616
|
*
|
|
617
617
|
* 対応付けは箱に表示される名前との一致で行う。 id は使わない。
|
|
618
618
|
*
|
|
619
|
+
* **表示される名前は `箱の題` が決める** (#2333)。 `actor.name` と直接比べていた間、
|
|
620
|
+
* **題 (`title`) を書いた箱の色が黙って消えていた** = 題を書くと箱に出るのは題なので、
|
|
621
|
+
* 名前と比べた照合が外れる。 実測で箱になる 7 図種のうち 5 図種 (フロー / 構成図 /
|
|
622
|
+
* 状態遷移 / クラス図 / ER 図) が落ちており、知らせも出ないため「書いたのに色が付かない」
|
|
623
|
+
* だけが残った。
|
|
624
|
+
*
|
|
625
|
+
* **呼ぶ位置も合わせて決まる**。 題が箱に入る時点は図種で 2 つに割れ、帯図と c4 は登場人物の
|
|
626
|
+
* 名前で箱を作って `applyV05Extensions` が後から題へ書き換える。 そのため本関数は書き換えの
|
|
627
|
+
* 後に呼ぶ (呼出側の説明が SSOT)。 前に呼んだまま照合だけを題へ寄せると、今度はその 2 図種で
|
|
628
|
+
* 色が落ちる (実測)。
|
|
629
|
+
*
|
|
630
|
+
* 題を持たない箱 (始まりと終わりの印、順序図の間隔用) は `箱の題` が空を返す。
|
|
631
|
+
* 空のまま照合すると同じく空の別の箱を巻き込むので、空は対象から外す。
|
|
632
|
+
*
|
|
619
633
|
* id での対応付けは 2 通りに壊れる。 id は名前を slug に変換して作るが、 その変換規則が
|
|
620
634
|
* dragon と cdl で違い、 記号を含む名前では一致しない (実測 = `A_B` が dragon 側で `a_b`、
|
|
621
635
|
* cdl 側で `a-b`)。 逆に、 生成した id (`{slug}-header`) をそのまま名前に持つ登場人物が
|
|
@@ -631,8 +645,10 @@ export function applyLayoutOffsets(
|
|
|
631
645
|
export function applyNodeTones(diagram: CdlDiagram, doc: DslDocument): void {
|
|
632
646
|
for (const actor of doc.actors) {
|
|
633
647
|
if (actor.tone === undefined) continue;
|
|
648
|
+
const 題 = 箱の題(actor);
|
|
649
|
+
if (題 === "") continue;
|
|
634
650
|
for (const node of diagram.nodes) {
|
|
635
|
-
if (node.title ===
|
|
651
|
+
if (node.title === 題) node.tone = actor.tone;
|
|
636
652
|
}
|
|
637
653
|
}
|
|
638
654
|
}
|