@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/keywords.ts
CHANGED
|
@@ -3,7 +3,14 @@
|
|
|
3
3
|
* 日本語 / 英語両対応 (大文字小文字無視)
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import
|
|
6
|
+
import {
|
|
7
|
+
LEGEND_MARKS,
|
|
8
|
+
type BarCornerRadii,
|
|
9
|
+
type CdlNode,
|
|
10
|
+
type LegendMark,
|
|
11
|
+
type NodeKind,
|
|
12
|
+
type Tone,
|
|
13
|
+
} from "@cardenelabs/cdl";
|
|
7
14
|
|
|
8
15
|
/** ブロック ヘッダー */
|
|
9
16
|
export const HEADERS = {
|
|
@@ -15,7 +22,7 @@ export const HEADERS = {
|
|
|
15
22
|
} as const;
|
|
16
23
|
|
|
17
24
|
/** preset 名 */
|
|
18
|
-
export const PRESET_NAMES = ["sequence", "flow", "swimlane", "
|
|
25
|
+
export const PRESET_NAMES = ["sequence", "flow", "swimlane", "record", "topology"] as const;
|
|
19
26
|
|
|
20
27
|
/**
|
|
21
28
|
* 図の並ぶ向き (`direction:`、 #1494)。
|
|
@@ -46,41 +53,253 @@ export function resolveDirection(s: string): DslDirection | null {
|
|
|
46
53
|
}
|
|
47
54
|
|
|
48
55
|
/**
|
|
49
|
-
*
|
|
56
|
+
* 箱を並べる順 (`order:`、 #2655)。
|
|
57
|
+
*
|
|
58
|
+
* 書かなければ **書いた順** のまま。 `種類` と書くと箱の種類で並べ替えてから置く。
|
|
59
|
+
*
|
|
60
|
+
* これは図の型として持っていた差を語に出したもの。 並べ替えの鍵しか持たない型
|
|
61
|
+
* (`solidity`) が在り、`compile.ts` は「順序図 または その型」 という条件を 6 か所で
|
|
62
|
+
* 書いていた。 **型が 1 つ増えるたびに条件を 2 つ並べる形**になるので、差が並べ替えだけなら
|
|
63
|
+
* 型ではなく語で表す。
|
|
64
|
+
*/
|
|
65
|
+
export const ORDERS = ["種類"] as const;
|
|
66
|
+
export type DslOrder = (typeof ORDERS)[number];
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 並び順の別名。 向きと同じく日本語と英語の両方で書ける。
|
|
70
|
+
*
|
|
71
|
+
* 正規の語を鍵にも入れておく = 引く側が別名かどうかを気にせず 1 度で解決できる。
|
|
72
|
+
*/
|
|
73
|
+
export const ORDER_ALIAS: Record<string, DslOrder> = {
|
|
74
|
+
種類: "種類",
|
|
75
|
+
kind: "種類",
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/** 書いた並び順を正規の語に直す。 読めない語は `null`。 */
|
|
79
|
+
export function resolveOrder(s: string): DslOrder | null {
|
|
80
|
+
const k = s.trim().toLowerCase();
|
|
81
|
+
return Object.hasOwn(ORDER_ALIAS, k) ? ORDER_ALIAS[k]! : null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 数を描く図の形 (`shape:`、 #2657)。
|
|
86
|
+
*
|
|
87
|
+
* 数の書き方 (`- 名前: "45"` の 1 行 1 値) は 9 つとも同じで、違うのは描かれる形だけ。
|
|
88
|
+
* 差が形だけなので型ではなく語で表す (並べ替えの語 #2655 と同じ判断)。
|
|
89
|
+
*
|
|
90
|
+
* **日本語の別名は持たない**。 いま `type:` に書く語が英語なので、語を移した先で
|
|
91
|
+
* 書き手が覚える綴りが増えない形にする。
|
|
92
|
+
*/
|
|
93
|
+
export const SHAPES = [
|
|
94
|
+
"pie",
|
|
95
|
+
"bar",
|
|
96
|
+
"line",
|
|
97
|
+
"gauge",
|
|
98
|
+
"radial",
|
|
99
|
+
"stat",
|
|
100
|
+
"waffle",
|
|
101
|
+
"stacked",
|
|
102
|
+
"slope",
|
|
103
|
+
] as const;
|
|
104
|
+
export type DslShape = (typeof SHAPES)[number];
|
|
105
|
+
|
|
106
|
+
/** 泳法図の形 (`shape:`、 #2797)。 後続の形も chart と混ぜずここへ足す。 */
|
|
107
|
+
export const SWIMLANE_SHAPES = ["stages", "metro", "timeline"] as const;
|
|
108
|
+
export type DslSwimlaneShape = (typeof SWIMLANE_SHAPES)[number];
|
|
109
|
+
|
|
110
|
+
/** 最上位の `shape:` が取り得る語。 図種ごとの集合は `DIAGRAM_SHAPES` が決める。 */
|
|
111
|
+
export type DslDiagramShape = DslShape | DslSwimlaneShape;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* `shape:` を選べる図種と、その図種で書ける語 (#2797)。
|
|
115
|
+
*
|
|
116
|
+
* 解析・組み立て・schema の照合はこの表から導く。 集合を別々の場所で対応付けると、形を
|
|
117
|
+
* 足した時に一方だけが古くなり、同じ語が入口によって通ったり落ちたりする。
|
|
118
|
+
*/
|
|
119
|
+
export const DIAGRAM_SHAPES = {
|
|
120
|
+
chart: SHAPES,
|
|
121
|
+
swimlane: SWIMLANE_SHAPES,
|
|
122
|
+
} as const satisfies Record<string, readonly DslDiagramShape[]>;
|
|
123
|
+
|
|
124
|
+
export type ShapeDiagramType = keyof typeof DIAGRAM_SHAPES;
|
|
125
|
+
|
|
126
|
+
/** 全図種の `shape:` の語。 図種を決める前の読み取りと schema の照合に使う。 */
|
|
127
|
+
export const ALL_DIAGRAM_SHAPES: readonly DslDiagramShape[] = Object.values(DIAGRAM_SHAPES).flat();
|
|
128
|
+
|
|
129
|
+
/** 書いた形を正規の語に直す。 読めない語は `null`。 */
|
|
130
|
+
export function resolveShape(s: string): DslShape | null {
|
|
131
|
+
const k = s.trim().toLowerCase();
|
|
132
|
+
return (SHAPES as readonly string[]).includes(k) ? (k as DslShape) : null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** 書いた形を図種をまたぐ正規の語に直す。 読めない語は `null`。 */
|
|
136
|
+
export function resolveDiagramShape(s: string): DslDiagramShape | null {
|
|
137
|
+
const k = s.trim().toLowerCase();
|
|
138
|
+
return (ALL_DIAGRAM_SHAPES as readonly string[]).includes(k)
|
|
139
|
+
? (k as DslDiagramShape)
|
|
140
|
+
: null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** その図種で書ける形。 形を持たない図種は空の並びを返す。 */
|
|
144
|
+
export function shapesForDiagramType(type: string): readonly DslDiagramShape[] {
|
|
145
|
+
return Object.hasOwn(DIAGRAM_SHAPES, type)
|
|
146
|
+
? DIAGRAM_SHAPES[type as ShapeDiagramType]
|
|
147
|
+
: [];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* 図の意匠 (`theme:`、 #1553 / #2790 / #2791 / #2792 / #2793 / #2794 / #2795 / #2796)。
|
|
50
152
|
*
|
|
51
153
|
* cdl は色を持たない (形だけを描く)。 名前を `data-cdl-palette` として markup に出すので、
|
|
52
|
-
* dragon の `cdl-theme.css` がその名前を見て
|
|
53
|
-
* に色を当てる。
|
|
154
|
+
* dragon の `cdl-theme.css` がその名前を見て 9 つの口
|
|
155
|
+
* (台 / 行の面 / 縞 / 枠 / 字 / 型名 / 線 / 所有 / 向きだけ) に色を当てる。
|
|
54
156
|
*
|
|
55
157
|
* **名前を自由文字列にしない**。 書き間違えると既定の色みのまま出るので、書き手には
|
|
56
158
|
* 「効かない」 としか見えない。 語を絞れば読めない語をその場で知らせられる。
|
|
57
159
|
*/
|
|
58
|
-
export const
|
|
59
|
-
export type
|
|
160
|
+
export const THEMES = ["kinari", "celadon", "blueprint", "letterpress", "catalog", "terminal", "sketch", "neon", "relief"] as const;
|
|
161
|
+
export type DslTheme = (typeof THEMES)[number];
|
|
60
162
|
|
|
61
163
|
/**
|
|
62
|
-
*
|
|
164
|
+
* 意匠の別名 (#2790 / #2791 / #2792 / #2793 / #2794 / #2795 / #2796)。 向きと同じく日本語と英語の両方で書ける。
|
|
63
165
|
*
|
|
64
|
-
* `kinari` = 生成りに茶、 `celadon` =
|
|
166
|
+
* `kinari` = 生成りに茶、 `celadon` = 青磁に墨、 `blueprint` = 図面、 `letterpress` = 活版、
|
|
167
|
+
* `catalog` = 図録、 `terminal` = 端末、 `sketch` = 手描き、 `neon` = 電飾、 `relief` = 浮彫。
|
|
65
168
|
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* (行の縞) が要る。 縞の色は配色からしか来ないので、既定が無いと縞が箱の面と同じ色に
|
|
69
|
-
* 落ちて 1 本も出ない。 書き手が `palette:` を書いた時はそちらが勝つ。
|
|
169
|
+
* record は用途を一つに決められないため既定の意匠を持たない。UML クラス図に生成り色が要る時も
|
|
170
|
+
* 書き手が `theme:` を明記する。
|
|
70
171
|
*/
|
|
71
|
-
export const
|
|
172
|
+
export const THEME_ALIAS: Record<string, DslTheme> = {
|
|
72
173
|
kinari: "kinari",
|
|
73
174
|
celadon: "celadon",
|
|
175
|
+
blueprint: "blueprint",
|
|
176
|
+
letterpress: "letterpress",
|
|
177
|
+
catalog: "catalog",
|
|
178
|
+
terminal: "terminal",
|
|
179
|
+
sketch: "sketch",
|
|
180
|
+
neon: "neon",
|
|
181
|
+
relief: "relief",
|
|
74
182
|
生成り: "kinari",
|
|
75
183
|
生成りに茶: "kinari",
|
|
76
184
|
青磁: "celadon",
|
|
77
185
|
青磁に墨: "celadon",
|
|
186
|
+
図面: "blueprint",
|
|
187
|
+
活版: "letterpress",
|
|
188
|
+
図録: "catalog",
|
|
189
|
+
端末: "terminal",
|
|
190
|
+
手描き: "sketch",
|
|
191
|
+
電飾: "neon",
|
|
192
|
+
浮彫: "relief",
|
|
78
193
|
};
|
|
79
194
|
|
|
80
|
-
/**
|
|
81
|
-
export function
|
|
195
|
+
/** 書いた意匠を正規の語に直す。 読めない語は `null`。 */
|
|
196
|
+
export function resolveTheme(s: string): DslTheme | null {
|
|
197
|
+
const k = s.trim().toLowerCase();
|
|
198
|
+
return Object.hasOwn(THEME_ALIAS, k) ? THEME_ALIAS[k]! : null;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** 描画側の凡例の印と、日本語で書く名前の対応。 印が増えた時は型検査で不足を知らせる。 */
|
|
202
|
+
const LEGEND_MARK_NAMES = {
|
|
203
|
+
diamond: "菱形",
|
|
204
|
+
"filled-circle": "塗った丸",
|
|
205
|
+
"double-circle": "二重丸",
|
|
206
|
+
"dotted-line": "点線",
|
|
207
|
+
"solid-line": "実線",
|
|
208
|
+
"curved-line": "曲線",
|
|
209
|
+
"rounded-label": "角丸の札",
|
|
210
|
+
"numbered-circle": "番号の丸",
|
|
211
|
+
station: "駅",
|
|
212
|
+
arrow: "矢印",
|
|
213
|
+
"line-triangle-hollow": "白抜き三角の線",
|
|
214
|
+
"line-diamond-hollow": "白抜き菱形の線",
|
|
215
|
+
"line-diamond-solid": "塗った菱形の線",
|
|
216
|
+
"rounded-box": "角丸の囲い",
|
|
217
|
+
} satisfies Record<LegendMark, string>;
|
|
218
|
+
|
|
219
|
+
/** 凡例の印の日本語名を描画側の名前へ直す表。 */
|
|
220
|
+
export const LEGEND_MARK_ALIAS: Readonly<Record<string, LegendMark>> = Object.fromEntries(
|
|
221
|
+
Object.entries(LEGEND_MARK_NAMES).map(([mark, name]) => [name, mark as LegendMark]),
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
/** 凡例の印を描画側の名前へ直す。 読めない語は `null`。 */
|
|
225
|
+
export function resolveLegendMark(s: string): LegendMark | null {
|
|
82
226
|
const k = s.trim().toLowerCase();
|
|
83
|
-
|
|
227
|
+
if ((LEGEND_MARKS as readonly string[]).includes(k)) return k as LegendMark;
|
|
228
|
+
return Object.hasOwn(LEGEND_MARK_ALIAS, k) ? (LEGEND_MARK_ALIAS[k] ?? null) : null;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* 意匠から字の測り方を引く (#2818 / #2918)。
|
|
233
|
+
*
|
|
234
|
+
* 意匠を替えても骨組みを変えず、端末の等幅字も箱へ収めるため、比例・等幅の広い方で測る。
|
|
235
|
+
* 公開済みの関数なので窓口を残し、どの意匠でも組み立てと同じ値を返す。
|
|
236
|
+
*/
|
|
237
|
+
export function 意匠の字の測り方(_theme: DslTheme): "widest" {
|
|
238
|
+
return "widest";
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** 意匠と節から、見本に合わせた円の区画間の弧の長さを引く (#2871)。 */
|
|
242
|
+
export function 意匠の円の区画の間(
|
|
243
|
+
theme: DslTheme,
|
|
244
|
+
node: Pick<CdlNode, "kind">,
|
|
245
|
+
): number | undefined {
|
|
246
|
+
return theme === "neon" && node.kind === "chart-pie" ? 3 : undefined;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/** `barCornerRadii` が効く棒を描く節か。 */
|
|
250
|
+
export function 棒を描く節か(
|
|
251
|
+
node: Pick<CdlNode, "kind" | "funnelForm">,
|
|
252
|
+
): boolean {
|
|
253
|
+
return node.kind === "chart-bar" ||
|
|
254
|
+
node.kind === "gantt-timeline" ||
|
|
255
|
+
node.kind === "chart-stacked-bar" ||
|
|
256
|
+
(node.kind === "funnel-stages" && node.funnelForm === "proportional-bars");
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* 意匠と節から、見本に合わせた棒の 4 隅の丸みを引く (#2863)。
|
|
261
|
+
*
|
|
262
|
+
* 手描きの見本は楕円の角 (`10px 14px 6px 12px / 14px 8px 12px 6px`) だが、cdl は
|
|
263
|
+
* 円の角だけを持つため、各隅の横と縦の平均を丸めて 12 / 11 / 9 / 9 とする。
|
|
264
|
+
* 生成りと青磁には見本が無いため値を返さず、記法で組み立てた形を保つ。
|
|
265
|
+
*/
|
|
266
|
+
export function 意匠の棒の角(
|
|
267
|
+
theme: DslTheme,
|
|
268
|
+
node: Pick<CdlNode, "kind" | "funnelForm">,
|
|
269
|
+
): BarCornerRadii | undefined {
|
|
270
|
+
if (!棒を描く節か(node) || theme === "kinari" || theme === "celadon") return undefined;
|
|
271
|
+
|
|
272
|
+
const category = node.kind === "chart-bar"
|
|
273
|
+
? "vertical"
|
|
274
|
+
: node.kind === "gantt-timeline"
|
|
275
|
+
? "schedule"
|
|
276
|
+
: "horizontal";
|
|
277
|
+
|
|
278
|
+
const values = {
|
|
279
|
+
blueprint: {
|
|
280
|
+
vertical: [0, 0, 0, 0], schedule: [0, 0, 0, 0], horizontal: [0, 0, 0, 0],
|
|
281
|
+
},
|
|
282
|
+
letterpress: {
|
|
283
|
+
vertical: [0, 0, 0, 0], schedule: [0, 0, 0, 0], horizontal: [0, 0, 0, 0],
|
|
284
|
+
},
|
|
285
|
+
catalog: {
|
|
286
|
+
vertical: [4, 4, 0, 0], schedule: [4, 4, 0, 0], horizontal: [4, 4, 0, 0],
|
|
287
|
+
},
|
|
288
|
+
terminal: {
|
|
289
|
+
vertical: [3, 3, 0, 0], schedule: [0, 3, 3, 0], horizontal: [0, 3, 3, 0],
|
|
290
|
+
},
|
|
291
|
+
sketch: {
|
|
292
|
+
vertical: [12, 11, 9, 9], schedule: [12, 11, 9, 9], horizontal: [12, 11, 9, 9],
|
|
293
|
+
},
|
|
294
|
+
neon: {
|
|
295
|
+
vertical: [10, 10, 3, 3], schedule: [3, 10, 10, 3], horizontal: [12, 12, 12, 12],
|
|
296
|
+
},
|
|
297
|
+
relief: {
|
|
298
|
+
vertical: [12, 12, 5, 5], schedule: [5, 12, 12, 5], horizontal: [10, 10, 10, 10],
|
|
299
|
+
},
|
|
300
|
+
} as const;
|
|
301
|
+
const [topLeft, topRight, bottomRight, bottomLeft] = values[theme][category];
|
|
302
|
+
return { topLeft, topRight, bottomRight, bottomLeft };
|
|
84
303
|
}
|
|
85
304
|
|
|
86
305
|
/** NodeKind 別名 (日本語 → English) */
|
|
@@ -121,6 +340,21 @@ export const TONE_ALIAS: Record<string, Tone> = {
|
|
|
121
340
|
teal: "teal",
|
|
122
341
|
};
|
|
123
342
|
|
|
343
|
+
/**
|
|
344
|
+
* 段の説明を受ける語 (#2621)。 先頭が正の語で、後ろは同じ意味の別名。
|
|
345
|
+
*
|
|
346
|
+
* **2 形 (記法 / JSON) の入口と、公開している schema はここから導く**。 3 か所に別々に
|
|
347
|
+
* 書いていたため、記法は `description` を受けるのに JSON は弾く状態が生まれた
|
|
348
|
+
* (実測 = `$.animation[N].description: unknown key`)。
|
|
349
|
+
*
|
|
350
|
+
* 別名を落とさないのは、見本の記法の中に `description:` が 859 行あり、利用者が書いた
|
|
351
|
+
* 記法も同じ語を使えるため。 落とすと外から見える壊し方になる。
|
|
352
|
+
*/
|
|
353
|
+
export const PHASE_BODY_KEYS = ["body", "description"] as const;
|
|
354
|
+
|
|
355
|
+
/** 段の説明の正の語 (別名を写す先) */
|
|
356
|
+
export const PHASE_BODY_CANONICAL = PHASE_BODY_KEYS[0];
|
|
357
|
+
|
|
124
358
|
/** アニメ サブキー */
|
|
125
359
|
export const ANIM_SUBKEYS = {
|
|
126
360
|
state: ["状態", "state"],
|
package/src/notation-lint.ts
CHANGED
|
@@ -98,64 +98,35 @@ export function autoFix(d: CdlDiagram): CdlDiagram {
|
|
|
98
98
|
return patched;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
/** 先頭に置かれる型の名前。 型の名前は実装の語なので、説明の頭に残っていたら落とす */
|
|
102
|
+
const 先頭の型の名前 =
|
|
103
|
+
/^\s*(line chart|pie chart|bar chart|chart|flow|swimlane|sequence|topology|er|stateMachine2?|infrastructure|classDiagram|tree|userJourney|mindMap|funnel|quadrant|gantt|flowchart|network)\b/i;
|
|
104
|
+
|
|
101
105
|
/**
|
|
102
|
-
*
|
|
106
|
+
* 図の説明から実装の語を落とす。
|
|
103
107
|
*
|
|
104
|
-
*
|
|
105
|
-
* `ITEM_NAME_JA` の `preset*`) と同じ字にする。 利用者は自動修正で書き換わった説明の名前で
|
|
106
|
-
* カタログを探すため、 呼び名が割れると同じ型の見本に辿り着けない。 照らす検査は画面側の
|
|
107
|
-
* `lint-topic-names.test.ts` が持つ (この package は画面側の file を読まない)。
|
|
108
|
+
* **落とすだけで、文は書かない** (#2687)。
|
|
108
109
|
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
110
|
+
* 以前は先頭が型の名前なら `${shows}を示す${name}` に丸ごと書き換えていた。
|
|
111
|
+
* 出てくるのは必ず図種の定義文 (「全体に対する内訳の割合を示す円グラフ」) で、
|
|
112
|
+
* その図が何を示しているかは 1 文字も入らない。
|
|
113
|
+
* cdl 0.96.0 で説明が図の題として画面に出るようになり、見本帳の 8 枚がその形で出ていた。
|
|
112
114
|
*
|
|
113
|
-
*
|
|
115
|
+
* 道具は図の中身を知らないので、名前を作れない。 落とした結果が説明として成り立たないなら
|
|
116
|
+
* **元の字をそのまま返す** = 呼出側が「自動修正で消えない」 と判定し、書き手に名前を求める。
|
|
117
|
+
* 置き換えの語 (かつての「図の説明」) を返すと、道具が書いた仮の題が画面に出る。
|
|
114
118
|
*/
|
|
115
|
-
const KIND_TO_JA: Record<string, { shows: string; name: string }> = {
|
|
116
|
-
chart: { shows: "項目ごとの数値", name: "グラフ" },
|
|
117
|
-
"line chart": { shows: "値の移り変わり", name: "折れ線グラフ" },
|
|
118
|
-
"pie chart": { shows: "全体に対する内訳の割合", name: "円グラフ" },
|
|
119
|
-
"bar chart": { shows: "項目ごとの値の大きさ", name: "棒グラフ" },
|
|
120
|
-
flow: { shows: "処理の順番", name: "フロー" },
|
|
121
|
-
swimlane: { shows: "役割ごとの縦列に分けた処理の流れ", name: "スイムレーン" },
|
|
122
|
-
sequence: { shows: "要素どうしのやり取りの順番", name: "シーケンス図" },
|
|
123
|
-
topology: { shows: "システムの構成要素と接続", name: "トポロジー図" },
|
|
124
|
-
er: { shows: "表どうしの関係", name: "ER図" },
|
|
125
|
-
stateMachine: { shows: "状態と遷移の条件", name: "状態遷移図" },
|
|
126
|
-
stateMachine2: { shows: "親の状態の中に置いた子の状態と遷移の条件", name: "入れ子の状態遷移図" },
|
|
127
|
-
infrastructure: { shows: "クラウドとネットワークの構成", name: "階層構成図" },
|
|
128
|
-
classDiagram: { shows: "クラスどうしの関係", name: "クラス図" },
|
|
129
|
-
tree: { shows: "組織や分類の親子の関係", name: "階層図" },
|
|
130
|
-
userJourney: { shows: "利用者の気持ちの移り変わり", name: "体験の道筋" },
|
|
131
|
-
mindMap: { shows: "中心の主題から広がる発想", name: "枝分かれ図" },
|
|
132
|
-
funnel: { shows: "段階ごとに残る数と離れる数", name: "絞り込み図" },
|
|
133
|
-
quadrant: { shows: "2 つの軸で分けた項目の位置", name: "四象限図" },
|
|
134
|
-
gantt: { shows: "作業の期間と前後の関係", name: "工程表" },
|
|
135
|
-
flowchart: { shows: "分岐や判定を含む処理の順番", name: "流れ図" },
|
|
136
|
-
network: { shows: "機器と区画のつながり", name: "ネットワーク図" },
|
|
137
|
-
};
|
|
138
|
-
|
|
139
119
|
function applyTopicAutoFix(topic: string): string {
|
|
140
|
-
// 1. 先頭の kind name を検出、 マッチしたら「{shows}を示す{name}」 に置換
|
|
141
|
-
const kindMatch = topic.match(
|
|
142
|
-
/^\s*(chart|flow|swimlane|sequence|topology|er|stateMachine2?|infrastructure|classDiagram|tree|userJourney|mindMap|funnel|quadrant|gantt|flowchart|network|line chart|pie chart|bar chart)\b/i,
|
|
143
|
-
);
|
|
144
|
-
if (kindMatch) {
|
|
145
|
-
const kind = kindMatch[1]!.toLowerCase();
|
|
146
|
-
const canonical = Object.keys(KIND_TO_JA).find((k) => k.toLowerCase() === kind);
|
|
147
|
-
if (canonical) {
|
|
148
|
-
const { shows, name } = KIND_TO_JA[canonical]!;
|
|
149
|
-
return `${shows}を示す${name}`;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// 2. kind 名で始まらない場合は括弧内実装詳細のみ除去
|
|
154
120
|
let out = topic;
|
|
155
121
|
out = out.replace(/\s*\([^)]*(preset|render|SVG|polygon|polyline|arc|rect|path)[^)]*\)/gi, "");
|
|
122
|
+
out = out.replace(先頭の型の名前, "");
|
|
156
123
|
out = out.replace(/\b(preset|render)\b/gi, "");
|
|
157
|
-
|
|
158
|
-
|
|
124
|
+
// 落とした跡に残る区切りを畳む
|
|
125
|
+
out = out.replace(/^[\s\-—::・]+/, "").replace(/\s+/g, " ").trim();
|
|
126
|
+
// 括弧の中しか残らなかった形 (`(詳細)`) は説明として成り立たない。
|
|
127
|
+
// 字数だけで見ると 4 字あるので通ってしまう
|
|
128
|
+
const 括弧の外 = out.replace(/[((][^))]*[))]/g, "").trim();
|
|
129
|
+
if (out.length < 3 || 括弧の外.length < 3) return topic;
|
|
159
130
|
return out;
|
|
160
131
|
}
|
|
161
132
|
|
|
@@ -173,9 +144,12 @@ function ruleTopicRedundancy(d: CdlDiagram): LintIssue[] {
|
|
|
173
144
|
const 当たる = REDUNDANT_TOPIC_PATTERNS.filter(({ pattern }) => pattern.test(d.topic));
|
|
174
145
|
if (当たる.length === 0) return [];
|
|
175
146
|
const 直した後 = applyTopicAutoFix(d.topic);
|
|
176
|
-
const 直せる =
|
|
177
|
-
|
|
178
|
-
|
|
147
|
+
const 直せる =
|
|
148
|
+
直した後 !== d.topic &&
|
|
149
|
+
!REDUNDANT_TOPIC_PATTERNS.some(({ pattern }) => pattern.test(直した後));
|
|
150
|
+
// 例は見本帳の実物から採る (#2687)。 型の表から作ると図種の定義文になり、
|
|
151
|
+
// 案内どおりに書いた説明がそのまま図の題として画面に出る
|
|
152
|
+
const 手で直す = "その図が何を示しているかを名前で書く (「経路別の流入」 のように)";
|
|
179
153
|
return 当たる.map(({ hint }) => ({
|
|
180
154
|
rule: "topic-redundant-implementation-detail",
|
|
181
155
|
severity: "warn",
|
|
@@ -223,15 +197,18 @@ function ruleGanttUnknownDependsOn(d: CdlDiagram): LintIssue[] {
|
|
|
223
197
|
const tasks = n.ganttData ?? [];
|
|
224
198
|
const ids = new Set(tasks.map((t) => t.id));
|
|
225
199
|
for (const t of tasks) {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
200
|
+
const dependencies = Array.isArray(t.dependsOn) ? t.dependsOn : t.dependsOn ? [t.dependsOn] : [];
|
|
201
|
+
for (const dependency of dependencies) {
|
|
202
|
+
if (!ids.has(dependency)) {
|
|
203
|
+
out.push({
|
|
204
|
+
rule: "gantt-unknown-depends-on",
|
|
205
|
+
severity: "warn",
|
|
206
|
+
target: t.id,
|
|
207
|
+
message: `作業 \`${t.id}\` の \`dependsOn\` が、 無い作業 \`${dependency}\` を指している`,
|
|
208
|
+
suggestion: `\`dependsOn\` を既にある作業の \`id\` に直すか、 \`dependsOn\` を外す`,
|
|
209
|
+
autoFixable: false,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
235
212
|
}
|
|
236
213
|
}
|
|
237
214
|
}
|
|
@@ -306,7 +283,7 @@ function ruleQuadrantMissingItems(d: CdlDiagram): LintIssue[] {
|
|
|
306
283
|
rule: "quadrant-empty",
|
|
307
284
|
severity: "warn",
|
|
308
285
|
target: n.id,
|
|
309
|
-
message:
|
|
286
|
+
message: `マトリクス図 \`${n.id}\` に項目 (\`item\`) が 1 件も無く、 軸だけが描かれる`,
|
|
310
287
|
suggestion: `\`.item({ id, title, quadrant })\` で項目を 1 件以上足す (\`quadrant\` は \`topLeft\` などの 4 区画から選ぶ)`,
|
|
311
288
|
autoFixable: false,
|
|
312
289
|
});
|
|
@@ -317,7 +294,7 @@ function ruleQuadrantMissingItems(d: CdlDiagram): LintIssue[] {
|
|
|
317
294
|
rule: "quadrant-single-quadrant",
|
|
318
295
|
severity: "info",
|
|
319
296
|
target: n.id,
|
|
320
|
-
message:
|
|
297
|
+
message: `マトリクス図 \`${n.id}\` の項目がすべて 1 つの区画に集まり、 4 つに分けた意味が薄い`,
|
|
321
298
|
suggestion: `項目を 2 つ以上の区画に分ける。 強みと弱みを並べる分析 (\`SWOT\`) や優先度を決める図は、 4 つの区画に散らして使う`,
|
|
322
299
|
autoFixable: false,
|
|
323
300
|
});
|
|
@@ -350,7 +327,7 @@ function ruleFunnelMonotonicCount(d: CdlDiagram): LintIssue[] {
|
|
|
350
327
|
rule: "funnel-increasing-count",
|
|
351
328
|
severity: "warn",
|
|
352
329
|
target: stages[i]!.id,
|
|
353
|
-
message: `段階 \`${stages[i]!.id}\` の数 (${今}) が前の段階 (${前}) より多い。
|
|
330
|
+
message: `段階 \`${stages[i]!.id}\` の数 (${今}) が前の段階 (${前}) より多い。 ファネル図は段階が進むほど数が減る`,
|
|
354
331
|
suggestion: `段階の順番を確かめる。 数が増える流れを示すなら、 折れ線グラフ (\`chart-line\`) などの別の図にする`,
|
|
355
332
|
autoFixable: false,
|
|
356
333
|
});
|