@cardenelabs/dragon 0.34.0 → 0.35.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 (127) hide show
  1. package/README.md +39 -720
  2. package/dist/cli.cjs +4529 -0
  3. package/dist/cli.cjs.map +1 -0
  4. package/dist/cli.js +4523 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/export.cjs +3912 -0
  7. package/dist/export.cjs.map +1 -0
  8. package/dist/export.d.cts +36 -0
  9. package/dist/export.d.ts +36 -0
  10. package/dist/export.js +3907 -0
  11. package/dist/export.js.map +1 -0
  12. package/dist/fonts.cjs +7 -0
  13. package/dist/fonts.cjs.map +1 -0
  14. package/dist/fonts.js +4 -0
  15. package/dist/fonts.js.map +1 -0
  16. package/dist/index.cjs +4105 -20356
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +227 -5522
  19. package/dist/index.d.ts +227 -5522
  20. package/dist/index.js +4091 -20283
  21. package/dist/index.js.map +1 -1
  22. package/dist/player.global.js +2 -0
  23. package/dist/schema-BBWfniwH.d.cts +112 -0
  24. package/dist/schema-BBWfniwH.d.ts +112 -0
  25. package/package.json +39 -24
  26. package/src/cli.ts +237 -0
  27. package/src/export/capture.ts +277 -0
  28. package/src/export/fonts.ts +68 -0
  29. package/src/export/html.ts +32 -0
  30. package/src/export/index.ts +146 -0
  31. package/src/field-messages.ts +104 -0
  32. package/src/figure-text.ts +42 -0
  33. package/src/index.ts +30 -283
  34. package/src/layout/architecture.ts +381 -0
  35. package/src/layout/measure.ts +21 -0
  36. package/src/layout/scene.ts +353 -0
  37. package/src/layout/sequence.ts +189 -0
  38. package/src/load-fonts.ts +8 -0
  39. package/src/look/fonts.ts +33 -0
  40. package/src/look/palettes.json +209 -0
  41. package/src/look/values.ts +155 -0
  42. package/src/markdown.ts +35 -0
  43. package/src/messages.ts +122 -0
  44. package/src/parser.ts +342 -310
  45. package/src/player-global.ts +4 -0
  46. package/src/player.ts +271 -0
  47. package/src/printer.ts +76 -0
  48. package/src/render/icons.ts +41 -0
  49. package/src/render/motion.ts +106 -0
  50. package/src/render/parts.ts +279 -0
  51. package/src/render/svg.ts +341 -0
  52. package/src/schema.ts +161 -16
  53. package/src/schemas/diagram.schema.json +150 -0
  54. package/src/schemas/validate-diagram.d.ts +12 -0
  55. package/src/schemas/validate-diagram.js +8 -0
  56. package/src/timeline.ts +166 -0
  57. package/src/tokenize.ts +20 -281
  58. package/src/version.ts +55 -0
  59. package/src/view.ts +16 -0
  60. package/src/words.ts +79 -0
  61. package/examples/quick-start.md +0 -142
  62. package/src/canvas-bounds.ts +0 -52
  63. package/src/color.ts +0 -197
  64. package/src/compile/actor-ids.ts +0 -297
  65. package/src/compile/actor-option-notice.ts +0 -379
  66. package/src/compile/actors.ts +0 -103
  67. package/src/compile/c4.ts +0 -74
  68. package/src/compile/chain.ts +0 -93
  69. package/src/compile/chart-fields.ts +0 -193
  70. package/src/compile/deep-rewrite.ts +0 -30
  71. package/src/compile/derived-source.ts +0 -18
  72. package/src/compile/direction.ts +0 -102
  73. package/src/compile/edge-option-notice.ts +0 -112
  74. package/src/compile/er-relation.ts +0 -200
  75. package/src/compile/flow.ts +0 -54
  76. package/src/compile/flowchart.ts +0 -344
  77. package/src/compile/funnel.ts +0 -87
  78. package/src/compile/gantt.ts +0 -337
  79. package/src/compile/generic.ts +0 -696
  80. package/src/compile/hierarchy.ts +0 -92
  81. package/src/compile/journey.ts +0 -93
  82. package/src/compile/kinds.ts +0 -139
  83. package/src/compile/lanes.ts +0 -138
  84. package/src/compile/metro.ts +0 -271
  85. package/src/compile/mind.ts +0 -393
  86. package/src/compile/node-title.ts +0 -24
  87. package/src/compile/notice.ts +0 -141
  88. package/src/compile/order.ts +0 -57
  89. package/src/compile/parts-lookup.ts +0 -17
  90. package/src/compile/parts.ts +0 -2709
  91. package/src/compile/placement-apply.ts +0 -689
  92. package/src/compile/placement.ts +0 -15
  93. package/src/compile/quadrant.ts +0 -265
  94. package/src/compile/record.ts +0 -75
  95. package/src/compile/row-marks.ts +0 -128
  96. package/src/compile/rows.ts +0 -40
  97. package/src/compile/sequence.ts +0 -305
  98. package/src/compile/slug.ts +0 -37
  99. package/src/compile/stages.ts +0 -247
  100. package/src/compile/subtitle.ts +0 -35
  101. package/src/compile/swimlane-marks.ts +0 -87
  102. package/src/compile/swimlane.ts +0 -82
  103. package/src/compile/timeline.ts +0 -213
  104. package/src/compile/topology.ts +0 -44
  105. package/src/compile/tree.ts +0 -69
  106. package/src/compile/value-chart.ts +0 -337
  107. package/src/compile/values.ts +0 -432
  108. package/src/compile/word-state.ts +0 -82
  109. package/src/compile.ts +0 -3168
  110. package/src/focus.ts +0 -46
  111. package/src/input-size.ts +0 -181
  112. package/src/json-line-map.ts +0 -30
  113. package/src/json-parser.ts +0 -4306
  114. package/src/keywords.ts +0 -417
  115. package/src/near-name.ts +0 -42
  116. package/src/notation-lint.ts +0 -342
  117. package/src/relative-pos.ts +0 -251
  118. package/src/schemas/diagram.json +0 -3088
  119. package/src/types.ts +0 -1009
  120. package/src/v05/index.ts +0 -9
  121. package/src/v05/input-table.generated.ts +0 -138
  122. package/src/v05/parser-types.ts +0 -32
  123. package/src/v05/parser.ts +0 -6668
  124. package/src/v05/readout-table.generated.ts +0 -1088
  125. package/src/v05/removed-syntax.ts +0 -115
  126. package/src/value-syntax.ts +0 -313
  127. package/src/write-position.ts +0 -270
package/src/keywords.ts DELETED
@@ -1,417 +0,0 @@
1
- /**
2
- * Text DSL i18n キーワード一覧
3
- * 日本語 / 英語両対応 (大文字小文字無視)
4
- */
5
-
6
- import {
7
- LEGEND_MARKS,
8
- type BarCornerRadii,
9
- type CdlNode,
10
- type LegendMark,
11
- type NodeKind,
12
- type Tone,
13
- } from "@cardenelabs/cdl";
14
-
15
- /** ブロック ヘッダー */
16
- export const HEADERS = {
17
- title: ["タイトル", "title"],
18
- type: ["種類", "type"],
19
- actors: ["登場人物", "actors"],
20
- flow: ["流れ", "flow", "steps"],
21
- animate: ["アニメーション", "animate", "animation"],
22
- } as const;
23
-
24
- /** preset 名 */
25
- export const PRESET_NAMES = ["sequence", "flow", "swimlane", "record", "topology"] as const;
26
-
27
- /**
28
- * 図の並ぶ向き (`direction:`、 #1494)。
29
- *
30
- * 縦列 (`lane`) は横、段 (`stack`) は縦に置かれるので、向きは「1 つの縦列に積む」 か
31
- * 「1 人ずつ縦列を作る」 かの選択になる。 どちらも組み立て側に既にある経路で、
32
- * 記法から名指しできる言葉が無かった。
33
- */
34
- export const DIRECTIONS = ["縦", "横"] as const;
35
- export type DslDirection = (typeof DIRECTIONS)[number];
36
-
37
- /**
38
- * 向きの別名。 色 (`色` / `color` / `tone`) と同じく日本語と英語の両方で書ける。
39
- *
40
- * 正規の語を鍵にも入れておく = 引く側が別名かどうかを気にせず 1 度で解決できる。
41
- */
42
- export const DIRECTION_ALIAS: Record<string, DslDirection> = {
43
- 縦: "縦",
44
- 横: "横",
45
- vertical: "縦",
46
- horizontal: "横",
47
- };
48
-
49
- /** 書いた向きを正規の語に直す。 読めない語は `null`。 */
50
- export function resolveDirection(s: string): DslDirection | null {
51
- const k = s.trim().toLowerCase();
52
- return Object.hasOwn(DIRECTION_ALIAS, k) ? DIRECTION_ALIAS[k]! : null;
53
- }
54
-
55
- /**
56
- * 箱を並べる順 (`order:`、 #2655)。
57
- *
58
- * 書かなければ **書いた順** のまま。 `種類` と書くと箱の種類で並べ替えてから置く。
59
- *
60
- * これは図の型として持っていた差を語に出したもの。 並べ替えの鍵しか持たない型が在り、
61
- * `compile.ts` は「順序図 または その型」 という条件を 6 か所で書いていた。 **型が 1 つ増えるたびに条件を 2 つ並べる形**になるので、差が並べ替えだけなら
62
- * 型ではなく語で表す。
63
- */
64
- export const ORDERS = ["種類"] as const;
65
- export type DslOrder = (typeof ORDERS)[number];
66
-
67
- /**
68
- * 並び順の別名。 向きと同じく日本語と英語の両方で書ける。
69
- *
70
- * 正規の語を鍵にも入れておく = 引く側が別名かどうかを気にせず 1 度で解決できる。
71
- */
72
- export const ORDER_ALIAS: Record<string, DslOrder> = {
73
- 種類: "種類",
74
- kind: "種類",
75
- };
76
-
77
- /** 書いた並び順を正規の語に直す。 読めない語は `null`。 */
78
- export function resolveOrder(s: string): DslOrder | null {
79
- const k = s.trim().toLowerCase();
80
- return Object.hasOwn(ORDER_ALIAS, k) ? ORDER_ALIAS[k]! : null;
81
- }
82
-
83
- /**
84
- * 数を描く図の形 (`shape:`、 #2657)。
85
- *
86
- * 数の書き方 (`- 名前: "45"` の 1 行 1 値) は 9 つとも同じで、違うのは描かれる形だけ。
87
- * 差が形だけなので型ではなく語で表す (並べ替えの語 #2655 と同じ判断)。
88
- *
89
- * **日本語の別名は持たない**。 いま `type:` に書く語が英語なので、語を移した先で
90
- * 書き手が覚える綴りが増えない形にする。
91
- */
92
- export const SHAPES = [
93
- "pie",
94
- "bar",
95
- "line",
96
- "gauge",
97
- "radial",
98
- "stat",
99
- "waffle",
100
- "stacked",
101
- "slope",
102
- ] as const;
103
- export type DslShape = (typeof SHAPES)[number];
104
-
105
- /** 泳法図の形 (`shape:`、 #2797)。 後続の形も chart と混ぜずここへ足す。 */
106
- export const SWIMLANE_SHAPES = ["stages", "metro", "timeline"] as const;
107
- export type DslSwimlaneShape = (typeof SWIMLANE_SHAPES)[number];
108
-
109
- /** 最上位の `shape:` が取り得る語。 図種ごとの集合は `DIAGRAM_SHAPES` が決める。 */
110
- export type DslDiagramShape = DslShape | DslSwimlaneShape;
111
-
112
- /**
113
- * `shape:` を選べる図種と、その図種で書ける語 (#2797)。
114
- *
115
- * 解析・組み立て・schema の照合はこの表から導く。 集合を別々の場所で対応付けると、形を
116
- * 足した時に一方だけが古くなり、同じ語が入口によって通ったり落ちたりする。
117
- */
118
- export const DIAGRAM_SHAPES = {
119
- chart: SHAPES,
120
- swimlane: SWIMLANE_SHAPES,
121
- } as const satisfies Record<string, readonly DslDiagramShape[]>;
122
-
123
- export type ShapeDiagramType = keyof typeof DIAGRAM_SHAPES;
124
-
125
- /** 全図種の `shape:` の語。 図種を決める前の読み取りと schema の照合に使う。 */
126
- export const ALL_DIAGRAM_SHAPES: readonly DslDiagramShape[] = Object.values(DIAGRAM_SHAPES).flat();
127
-
128
- /** 書いた形を正規の語に直す。 読めない語は `null`。 */
129
- export function resolveShape(s: string): DslShape | null {
130
- const k = s.trim().toLowerCase();
131
- return (SHAPES as readonly string[]).includes(k) ? (k as DslShape) : null;
132
- }
133
-
134
- /** 書いた形を図種をまたぐ正規の語に直す。 読めない語は `null`。 */
135
- export function resolveDiagramShape(s: string): DslDiagramShape | null {
136
- const k = s.trim().toLowerCase();
137
- return (ALL_DIAGRAM_SHAPES as readonly string[]).includes(k)
138
- ? (k as DslDiagramShape)
139
- : null;
140
- }
141
-
142
- /** その図種で書ける形。 形を持たない図種は空の並びを返す。 */
143
- export function shapesForDiagramType(type: string): readonly DslDiagramShape[] {
144
- return Object.hasOwn(DIAGRAM_SHAPES, type)
145
- ? DIAGRAM_SHAPES[type as ShapeDiagramType]
146
- : [];
147
- }
148
-
149
- /**
150
- * 図の意匠 (`theme:`、 #1553 / #2790 / #2791 / #2792 / #2793 / #2794 / #2795 / #2796)。
151
- *
152
- * cdl は色を持たない (形だけを描く)。 名前を `data-cdl-palette` として markup に出すので、
153
- * dragon の `cdl-theme.css` がその名前を見て 9 つの口
154
- * (台 / 行の面 / 縞 / 枠 / 字 / 型名 / 線 / 所有 / 向きだけ) に色を当てる。
155
- *
156
- * **名前を自由文字列にしない**。 書き間違えると既定の色みのまま出るので、書き手には
157
- * 「効かない」 としか見えない。 語を絞れば読めない語をその場で知らせられる。
158
- */
159
- export const THEMES = ["kinari", "celadon", "blueprint", "letterpress", "catalog", "terminal", "sketch", "neon", "relief"] as const;
160
- export type DslTheme = (typeof THEMES)[number];
161
-
162
- /**
163
- * 意匠の別名 (#2790 / #2791 / #2792 / #2793 / #2794 / #2795 / #2796)。 向きと同じく日本語と英語の両方で書ける。
164
- *
165
- * `kinari` = 生成りに茶、 `celadon` = 青磁に墨、 `blueprint` = 図面、 `letterpress` = 活版、
166
- * `catalog` = 図録、 `terminal` = 端末、 `sketch` = 手描き、 `neon` = 電飾、 `relief` = 浮彫。
167
- *
168
- * record は用途を一つに決められないため既定の意匠を持たない。UML クラス図に生成り色が要る時も
169
- * 書き手が `theme:` を明記する。
170
- */
171
- export const THEME_ALIAS: Record<string, DslTheme> = {
172
- kinari: "kinari",
173
- celadon: "celadon",
174
- blueprint: "blueprint",
175
- letterpress: "letterpress",
176
- catalog: "catalog",
177
- terminal: "terminal",
178
- sketch: "sketch",
179
- neon: "neon",
180
- relief: "relief",
181
- 生成り: "kinari",
182
- 生成りに茶: "kinari",
183
- 青磁: "celadon",
184
- 青磁に墨: "celadon",
185
- 図面: "blueprint",
186
- 活版: "letterpress",
187
- 図録: "catalog",
188
- 端末: "terminal",
189
- 手描き: "sketch",
190
- 電飾: "neon",
191
- 浮彫: "relief",
192
- };
193
-
194
- /** 書いた意匠を正規の語に直す。 読めない語は `null`。 */
195
- export function resolveTheme(s: string): DslTheme | null {
196
- const k = s.trim().toLowerCase();
197
- return Object.hasOwn(THEME_ALIAS, k) ? THEME_ALIAS[k]! : null;
198
- }
199
-
200
- /** 描画側の凡例の印と、日本語で書く名前の対応。 印が増えた時は型検査で不足を知らせる。 */
201
- const LEGEND_MARK_NAMES = {
202
- diamond: "菱形",
203
- "filled-circle": "塗った丸",
204
- "double-circle": "二重丸",
205
- "dotted-line": "点線",
206
- "solid-line": "実線",
207
- "curved-line": "曲線",
208
- "rounded-label": "角丸の札",
209
- "numbered-circle": "番号の丸",
210
- station: "駅",
211
- arrow: "矢印",
212
- "line-triangle-hollow": "白抜き三角の線",
213
- "line-diamond-hollow": "白抜き菱形の線",
214
- "line-diamond-solid": "塗った菱形の線",
215
- "rounded-box": "角丸の囲い",
216
- } satisfies Record<LegendMark, string>;
217
-
218
- /** 凡例の印の日本語名を描画側の名前へ直す表。 */
219
- export const LEGEND_MARK_ALIAS: Readonly<Record<string, LegendMark>> = Object.fromEntries(
220
- Object.entries(LEGEND_MARK_NAMES).map(([mark, name]) => [name, mark as LegendMark]),
221
- );
222
-
223
- /** 凡例の印を描画側の名前へ直す。 読めない語は `null`。 */
224
- export function resolveLegendMark(s: string): LegendMark | null {
225
- const k = s.trim().toLowerCase();
226
- if ((LEGEND_MARKS as readonly string[]).includes(k)) return k as LegendMark;
227
- return Object.hasOwn(LEGEND_MARK_ALIAS, k) ? (LEGEND_MARK_ALIAS[k] ?? null) : null;
228
- }
229
-
230
- /**
231
- * 意匠から字の測り方を引く (#2818 / #2918)。
232
- *
233
- * 意匠を替えても骨組みを変えず、端末の等幅字も箱へ収めるため、比例・等幅の広い方で測る。
234
- * 公開済みの関数なので窓口を残し、どの意匠でも組み立てと同じ値を返す。
235
- */
236
- export function 意匠の字の測り方(_theme: DslTheme): "widest" {
237
- return "widest";
238
- }
239
-
240
- /**
241
- * 意匠と節から円の区画間の弧の長さを引く (#2871 / #2926)。
242
- *
243
- * 区画の形を意匠で変えないため値は返さない。公開済みの関数なので互換の窓口だけを残す。
244
- */
245
- export function 意匠の円の区画の間(
246
- _theme: DslTheme,
247
- _node: Pick<CdlNode, "kind">,
248
- ): undefined {
249
- return undefined;
250
- }
251
-
252
- /** `barCornerRadii` が効く棒を描く節か。 */
253
- export function 棒を描く節か(
254
- node: Pick<CdlNode, "kind" | "funnelForm">,
255
- ): boolean {
256
- return node.kind === "chart-bar" ||
257
- node.kind === "gantt-timeline" ||
258
- node.kind === "chart-stacked-bar" ||
259
- (node.kind === "funnel-stages" && node.funnelForm === "proportional-bars");
260
- }
261
-
262
- /**
263
- * 意匠と節から、見本に合わせた棒の 4 隅の丸みを引く (#2863)。
264
- *
265
- * 手描きの見本は楕円の角 (`10px 14px 6px 12px / 14px 8px 12px 6px`) だが、cdl は
266
- * 円の角だけを持つため、各隅の横と縦の平均を丸めて 12 / 11 / 9 / 9 とする。
267
- * 生成りと青磁には見本が無いため値を返さず、記法で組み立てた形を保つ。
268
- */
269
- export function 意匠の棒の角(
270
- theme: DslTheme,
271
- node: Pick<CdlNode, "kind" | "funnelForm">,
272
- ): BarCornerRadii | undefined {
273
- if (!棒を描く節か(node) || theme === "kinari" || theme === "celadon") return undefined;
274
-
275
- const category = node.kind === "chart-bar"
276
- ? "vertical"
277
- : node.kind === "gantt-timeline"
278
- ? "schedule"
279
- : "horizontal";
280
-
281
- const values = {
282
- blueprint: {
283
- vertical: [0, 0, 0, 0], schedule: [0, 0, 0, 0], horizontal: [0, 0, 0, 0],
284
- },
285
- letterpress: {
286
- vertical: [0, 0, 0, 0], schedule: [0, 0, 0, 0], horizontal: [0, 0, 0, 0],
287
- },
288
- catalog: {
289
- vertical: [4, 4, 0, 0], schedule: [4, 4, 0, 0], horizontal: [4, 4, 0, 0],
290
- },
291
- terminal: {
292
- vertical: [3, 3, 0, 0], schedule: [0, 3, 3, 0], horizontal: [0, 3, 3, 0],
293
- },
294
- sketch: {
295
- vertical: [12, 11, 9, 9], schedule: [12, 11, 9, 9], horizontal: [12, 11, 9, 9],
296
- },
297
- neon: {
298
- vertical: [10, 10, 3, 3], schedule: [3, 10, 10, 3], horizontal: [12, 12, 12, 12],
299
- },
300
- relief: {
301
- vertical: [12, 12, 5, 5], schedule: [5, 12, 12, 5], horizontal: [10, 10, 10, 10],
302
- },
303
- } as const;
304
- const [topLeft, topRight, bottomRight, bottomLeft] = values[theme][category];
305
- return { topLeft, topRight, bottomRight, bottomLeft };
306
- }
307
-
308
- /** NodeKind 別名 (日本語 → English) */
309
- export const NODE_KIND_ALIAS: Record<string, NodeKind> = {
310
- // 日本語
311
- 人: "actor",
312
- 関数: "function",
313
- ストレージ: "storage",
314
- イベント: "event",
315
- // 英語 (NodeKind そのまま)
316
- actor: "actor",
317
- function: "function",
318
- storage: "storage",
319
- event: "event",
320
- cdn: "cdn",
321
- service: "service",
322
- database: "database",
323
- cache: "cache",
324
- queue: "queue",
325
- // ... 残り 29 NodeKind は parser 内で types.NodeKind を直接受理
326
- };
327
-
328
- /** Tone 別名 */
329
- export const TONE_ALIAS: Record<string, Tone> = {
330
- // 日本語
331
- 成功: "success",
332
- 失敗: "error",
333
- 警告: "warning",
334
- 情報: "info",
335
- 中立: "accent",
336
- // 英語
337
- success: "success",
338
- error: "error",
339
- warning: "warning",
340
- info: "info",
341
- neutral: "accent",
342
- accent: "accent",
343
- teal: "teal",
344
- };
345
-
346
- /**
347
- * 段の説明を受ける語 (#2621)。 先頭が正の語で、後ろは同じ意味の別名。
348
- *
349
- * **2 形 (記法 / JSON) の入口と、公開している schema はここから導く**。 3 か所に別々に
350
- * 書いていたため、記法は `description` を受けるのに JSON は弾く状態が生まれた
351
- * (実測 = `$.animation[N].description: unknown key`)。
352
- *
353
- * 別名を落とさないのは、見本の記法の中に `description:` が 859 行あり、利用者が書いた
354
- * 記法も同じ語を使えるため。 落とすと外から見える壊し方になる。
355
- */
356
- export const PHASE_BODY_KEYS = ["body", "description"] as const;
357
-
358
- /** 段の説明の正の語 (別名を写す先) */
359
- export const PHASE_BODY_CANONICAL = PHASE_BODY_KEYS[0];
360
-
361
- /** アニメ サブキー */
362
- export const ANIM_SUBKEYS = {
363
- state: ["状態", "state"],
364
- step: ["ステップ", "step"],
365
- highlight: ["強調", "highlight", "active", "activate"],
366
- tween: ["遷移", "tween"],
367
- set: ["切替", "set"],
368
- body: ["説明", "body", "description"],
369
- badge: ["バッジ", "badge"],
370
- } as const;
371
-
372
- /** 矢印記号 全変種を統一形 → に正規化 */
373
- export const ARROW_PATTERNS = ["→", "->", "=>", ">>", "->>", "-->>", "->>"];
374
-
375
- export function normalizeArrow(s: string): string {
376
- let r = s;
377
- for (const p of ARROW_PATTERNS) {
378
- r = r.split(p).join("→");
379
- }
380
- return r;
381
- }
382
-
383
- /** ヘッダー名 (日本語 or 英語) を canonical name に解決 */
384
- export function resolveHeader(s: string): keyof typeof HEADERS | null {
385
- const lower = s.toLowerCase().trim();
386
- for (const [canon, aliases] of Object.entries(HEADERS)) {
387
- if ((aliases as readonly string[]).some((a) => a.toLowerCase() === lower)) {
388
- return canon as keyof typeof HEADERS;
389
- }
390
- }
391
- return null;
392
- }
393
-
394
- export function resolveAnimSubkey(s: string): keyof typeof ANIM_SUBKEYS | null {
395
- const lower = s.toLowerCase().trim();
396
- for (const [canon, aliases] of Object.entries(ANIM_SUBKEYS)) {
397
- if ((aliases as readonly string[]).some((a) => a.toLowerCase() === lower)) {
398
- return canon as keyof typeof ANIM_SUBKEYS;
399
- }
400
- }
401
- return null;
402
- }
403
-
404
- /** duration 文字列 (1.5 秒 / 1500ms / 2 秒) を ms に変換 */
405
- export function parseDuration(s: string): number | null {
406
- const trimmed = s.trim();
407
- // "1.5 秒" / "2 秒"
408
- const sec = trimmed.match(/^([\d.]+)\s*秒$/);
409
- if (sec) return Math.round(parseFloat(sec[1]!) * 1000);
410
- // "1500ms" / "1500 ms"
411
- const ms = trimmed.match(/^([\d.]+)\s*ms$/i);
412
- if (ms) return Math.round(parseFloat(ms[1]!));
413
- // "1.5s" / "2s"
414
- const en = trimmed.match(/^([\d.]+)\s*s$/i);
415
- if (en) return Math.round(parseFloat(en[1]!) * 1000);
416
- return null;
417
- }
package/src/near-name.ts DELETED
@@ -1,42 +0,0 @@
1
- /**
2
- * 書き間違えた名前に綴りの近い候補を探す (#1295 で JSON の項目名に作り、#2113 で部品の名前と共有した)。
3
- *
4
- * 「知らない名前です」 だけだと、書いた人は正しい綴りを探しに行く必要がある。
5
- * 2 文字の違い (足りない / 多い / 別の字) までを候補とする。 隣どうしの入れ替わりは 2 文字の違いに数える。
6
- *
7
- * 遠い名前は勧めない。 無関係な名前を勧めると、書いた人がそちらへ直して二度手間になる。
8
- * 大文字と小文字は区別しない。
9
- */
10
- export function 近い名前(語: string, 候補: Iterable<string>): string | undefined {
11
- const 小文字 = 語.toLowerCase();
12
- let 最短: { 名: string; 距離: number } | undefined;
13
- for (const c of 候補) {
14
- const d = 編集距離(小文字, c.toLowerCase(), 2);
15
- if (d <= 2 && (最短 === undefined || d < 最短.距離)) 最短 = { 名: c, 距離: d };
16
- }
17
- return 最短?.名;
18
- }
19
-
20
- /**
21
- * 2 つの語の編集距離 (上限付き)。
22
- *
23
- * 上限を持つのは、長い語どうしで表を全部埋めないため。 上限を超えた時点で打ち切る。
24
- */
25
- function 編集距離(a: string, b: string, 上限: number): number {
26
- if (Math.abs(a.length - b.length) > 上限) return 上限 + 1;
27
- let 前 = Array.from({ length: b.length + 1 }, (_, i) => i);
28
- for (let i = 1; i <= a.length; i += 1) {
29
- const 今: number[] = [i];
30
- let 行の最小 = i;
31
- for (let j = 1; j <= b.length; j += 1) {
32
- const 費用 = a[i - 1] === b[j - 1] ? 0 : 1;
33
- const v = Math.min(今[j - 1]! + 1, 前[j]! + 1, 前[j - 1]! + 費用);
34
- 今.push(v);
35
- if (v < 行の最小) 行の最小 = v;
36
- }
37
- // その行の最小が上限を超えたら、以降どう進んでも上限以下にはならない
38
- if (行の最小 > 上限) return 上限 + 1;
39
- 前 = 今;
40
- }
41
- return 前[b.length]!;
42
- }