@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
@@ -0,0 +1,146 @@
1
+ /**
2
+ * 同じ原本の JSON から、mp4、GIF、HTML、PNG を書き出す。
3
+ *
4
+ * 見せ方は頁と同じく枠の幅で選ぶ (`chooseView`)。幅は寄って見せる窓の幅にもなる。
5
+ * 寄って見せる図で幅の指定が無い時は、記事の本文ほどの枠 (`DEFAULTS.followWidth`) で寄る。
6
+ * PNG は最後の段の止め絵を、全体を止めた見せ方で撮る。
7
+ * 字は図で描く字だけに削り、撮る頁と HTML の両方に同じ物を埋める。
8
+ */
9
+ import { mkdirSync, rmSync, writeFileSync } from "node:fs";
10
+ import { join } from "node:path";
11
+ import { paletteVars, resolvePalette, type Theme } from "../look/values";
12
+ import { BUTTON_TEXT, stepNo } from "../player";
13
+ import { drawSvg, type Rendered, renderDiagram } from "../render/svg";
14
+ import type { ViewMode } from "../schema";
15
+ import { chooseView } from "../view";
16
+ import type { NotationLang } from "../words";
17
+ import { film, launch, sizeOf, stage, still } from "./capture";
18
+ import { charsOf, fontFaces } from "./fonts";
19
+ import { pageHtml } from "./html";
20
+
21
+ export type ExportFormat = "mp4" | "gif" | "html" | "png";
22
+
23
+ export interface ExportOptions {
24
+ /** 書き出す先の dir。無ければ作り、書き出しに失敗した時は作った dir を残さない (#3013) */
25
+ outDir: string;
26
+ /** file の名前 (拡張子を除く)。既定は `diagram` */
27
+ name?: string;
28
+ /** 書き出す形。既定は 4 つ全て */
29
+ formats?: ExportFormat[];
30
+ /** 枠の幅 (CSS の px)。見せ方を選び、寄って見せる窓の幅になる */
31
+ width?: number;
32
+ palette?: string;
33
+ theme?: Theme;
34
+ /** mp4 の 1 秒のコマの数 */
35
+ fps?: number;
36
+ /** GIF の 1 秒のコマの数 */
37
+ gifFps?: number;
38
+ /** 図の中の字 (全体図の札、HTML の読み上げの名前、描けない時の断りの文) の言葉。書かなければ日本語 (#3001) */
39
+ lang?: NotationLang;
40
+ }
41
+
42
+ export interface ExportResult {
43
+ /** 書き出した file の path */
44
+ files: Partial<Record<ExportFormat, string>>;
45
+ view: ViewMode;
46
+ /** 撮ったコマの数 */
47
+ frames: number;
48
+ /** 動画のコマの大きさ (CSS の px)。撮る画素はこの 2 倍 */
49
+ width: number;
50
+ height: number;
51
+ }
52
+
53
+ /** 書き出せる形。命令が `--format` の値を確かめる時にも使う */
54
+ export const FORMATS: readonly ExportFormat[] = ["mp4", "gif", "html", "png"];
55
+ const DEFAULTS = { fps: 30, gifFps: 10, followWidth: 728 };
56
+
57
+ const unescape = (s: string): string => s.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&amp;/g, "&");
58
+
59
+ /** SVG の中で描かれる字 (`<text>` の中身) */
60
+ const svgTexts = (svg: string): string[] => [...svg.matchAll(/<text\b[^>]*>([\s\S]*?)<\/text>/g)].map((m) => unescape((m[1] ?? "").replace(/<[^>]+>/g, "")));
61
+
62
+ /** 頁と書き出しで描かれうる字。寄って見せる時の全体図の題 (`followSvg` の中) と、釦と段の番号の字も含む */
63
+ function drawnTexts(rendered: Rendered, followSvg: string | undefined): string[] {
64
+ const { diagram } = rendered;
65
+ const svgs = followSvg === undefined ? [rendered.svg] : [rendered.svg, followSvg];
66
+ const count = diagram.steps.length;
67
+ return [...svgs.flatMap(svgTexts), ...diagram.steps.flatMap((step, s) => [step.title, step.body, stepNo(s, count)]), ...Object.values(BUTTON_TEXT)];
68
+ }
69
+
70
+ export async function exportDiagram(input: unknown, options: ExportOptions): Promise<ExportResult> {
71
+ const formats = options.formats ?? FORMATS;
72
+ const lang = options.lang ?? "ja";
73
+ const rendered = renderDiagram(input, {
74
+ ...(options.palette ? { palette: options.palette } : {}),
75
+ ...(options.theme ? { theme: options.theme } : {}),
76
+ lang,
77
+ });
78
+ const { diagram, layout, timeline, theme } = rendered;
79
+ const palette = resolvePalette(rendered.palette);
80
+ const vars = paletteVars(palette, theme);
81
+ const width = options.width ?? (rendered.view === "follow" ? DEFAULTS.followWidth : layout.width);
82
+ const view = chooseView(rendered, width).mode;
83
+ // 寄って見せる図は動画と字の file の両方に使うので 1 度だけ描き、2 つの全体図の札の言葉を揃える
84
+ const followSvg = rendered.view === "fixed" ? undefined : drawSvg(diagram, layout, timeline, palette, theme, { width, lang });
85
+ const videoSvg = view === "follow" && followSvg ? followSvg : rendered.svg;
86
+ const fontCss = await fontFaces(charsOf(drawnTexts(rendered, followSvg)));
87
+
88
+ // 撮る物を全て撮り終えてから書く。撮る所で失敗した時に、書き出し先の dir と途中の file を残さないため (#3013)
89
+ const outputs: [ExportFormat, string | Buffer][] = [];
90
+
91
+ if (formats.includes("html")) outputs.push(["html", pageHtml(diagram, { palette: palette.id, theme, vars, lang }, fontCss)]);
92
+
93
+ let frames = 0;
94
+ const mp4 = formats.includes("mp4");
95
+ const gif = formats.includes("gif");
96
+ if (mp4 || gif || formats.includes("png")) {
97
+ const browser = await launch(lang);
98
+ try {
99
+ if (formats.includes("png")) {
100
+ const fixed = await stage(browser, rendered.svg, fontCss, "");
101
+ outputs.push(["png", await still(fixed, timeline.stills[timeline.stills.length - 1] ?? 0)]);
102
+ }
103
+ if (mp4 || gif) {
104
+ const fps = mp4 ? (options.fps ?? DEFAULTS.fps) : (options.gifFps ?? DEFAULTS.gifFps);
105
+ const gifEvery = gif ? Math.max(1, Math.round(fps / (options.gifFps ?? DEFAULTS.gifFps))) : 0;
106
+ const shot = await film(await stage(browser, videoSvg, fontCss, `${vars};background:var(--bg)`), {
107
+ total: timeline.total,
108
+ fps,
109
+ mp4,
110
+ gifEvery,
111
+ // GIF の色の表は、最初の絵と段ごとの止め絵から作る
112
+ samples: [0, ...timeline.stills],
113
+ });
114
+ frames = shot.frames;
115
+ if (shot.mp4) outputs.push(["mp4", shot.mp4]);
116
+ if (shot.gif) outputs.push(["gif", shot.gif]);
117
+ }
118
+ } finally {
119
+ await browser.close();
120
+ }
121
+ }
122
+ const files = writeOutputs(options.outDir, options.name ?? "diagram", outputs);
123
+ return { files, view, frames, ...sizeOf(videoSvg) };
124
+ }
125
+
126
+ /**
127
+ * 書き出し先の dir を作り、撮った物を並びの順に書く。
128
+ * 書いている途中で失敗した時は、この回に作った dir を中身ごと消してから投げ直す (#3013)。
129
+ * 前から在った dir は消さない。
130
+ */
131
+ function writeOutputs(outDir: string, name: string, outputs: [ExportFormat, string | Buffer][]): Partial<Record<ExportFormat, string>> {
132
+ // 作った dir の内で一番上の path。前から在った時は undefined
133
+ const created = mkdirSync(outDir, { recursive: true });
134
+ const files: Partial<Record<ExportFormat, string>> = {};
135
+ try {
136
+ for (const [format, data] of outputs) {
137
+ const path = join(outDir, `${name}.${format}`);
138
+ writeFileSync(path, data);
139
+ files[format] = path;
140
+ }
141
+ } catch (error) {
142
+ if (created !== undefined) rmSync(created, { recursive: true, force: true });
143
+ throw error;
144
+ }
145
+ return files;
146
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * 原本の JSON の誤りの文 (#2999)。
3
+ *
4
+ * JSON は語を持たず file から言葉を決められないので、呼ぶ側 (頁なら頁の言葉) が言葉を渡す。
5
+ * 文は schema が使う決まり (JSON Schema の keyword) ごとに持ち、ajv の英語の文はそのまま出さない。
6
+ * schema に決まりを足して文が無い時は、`every-schema-keyword-has-messages` の検査が落ちる。
7
+ */
8
+ import type { NotationLang } from "./words";
9
+
10
+ /** `^[^…]+$` の形の決まりが書けないとする字。`space` は空白 (`\s`) */
11
+ export interface Forbidden {
12
+ space: boolean;
13
+ chars: string[];
14
+ }
15
+
16
+ /** 書けない組み合わせ (`not`) の欄と、その欄を書ける時の `kind` の値 */
17
+ export interface Allowed {
18
+ field: string;
19
+ kind: string;
20
+ }
21
+
22
+ export interface FieldMessages {
23
+ additionalProperties: (key: string) => string;
24
+ required: (key: string) => string;
25
+ enum: (values: readonly string[]) => string;
26
+ type: (type: string) => string;
27
+ minLength: (limit: number) => string;
28
+ /** 書けない字を読めない形の決まりでは `undefined` */
29
+ pattern: (forbidden: Forbidden | undefined) => string;
30
+ minItems: (limit: number) => string;
31
+ minimum: (limit: number) => string;
32
+ const: (value: string) => string;
33
+ /** どの欄の組み合わせか判らない場所では `undefined` */
34
+ not: (allowed: Allowed | undefined) => string;
35
+ /** 選べる決まりがどれも欄が足りない時の、足りない欄。それ以外の時は空 */
36
+ anyOf: (fields: readonly string[]) => string;
37
+ oneOf: string;
38
+ discriminator: (tag: string, values: readonly string[]) => string;
39
+ /** 道具より新しい版の図 */
40
+ newer: (version: number, tool: number) => string;
41
+ }
42
+
43
+ const TYPES_JA: Record<string, string> = {
44
+ string: "文字列にする",
45
+ integer: "整数にする",
46
+ number: "数にする",
47
+ object: "オブジェクトにする",
48
+ array: "配列にする",
49
+ boolean: "true か false にする",
50
+ null: "null にする",
51
+ };
52
+
53
+ const TYPES_EN: Record<string, string> = {
54
+ string: "Use a string",
55
+ integer: "Use an integer",
56
+ number: "Use a number",
57
+ object: "Use an object",
58
+ array: "Use an array",
59
+ boolean: "Use true or false",
60
+ null: "Use null",
61
+ };
62
+
63
+ const plural = (count: number, word: string): string => `${count} ${word}${count === 1 ? "" : "s"}`;
64
+
65
+ const ja: FieldMessages = {
66
+ additionalProperties: (key) => `${key} という欄は書けない`,
67
+ required: (key) => `${key} の欄が要る`,
68
+ enum: (values) => `${values.join(" / ")} のどれかにする`,
69
+ type: (type) => TYPES_JA[type] ?? `${type} にする`,
70
+ minLength: (limit) => `${limit} 字以上書く`,
71
+ pattern: (forbidden) =>
72
+ forbidden ? `${forbidden.space ? "空白と " : ""}${forbidden.chars.join(" ")} は使えない` : "使えない字が入っている",
73
+ minItems: (limit) => `${limit} つ以上書く`,
74
+ minimum: (limit) => `${limit} 以上にする`,
75
+ const: (value) => `${value} にする`,
76
+ not: (allowed) => (allowed ? `${allowed.field} の欄は kind が ${allowed.kind} の時だけ書ける` : "この欄の組み合わせは書けない"),
77
+ anyOf: (fields) =>
78
+ fields.length > 0 ? `${fields.join(" か ")} の${fields.length === 2 ? "どちらか" : "どれか"}の欄が要る` : "書ける形のどれにも合わない",
79
+ oneOf: "書ける形のどれか 1 つだけに合わせる",
80
+ discriminator: (tag, values) => `${tag} は ${values.join(" / ")} のどれかにする`,
81
+ newer: (version, tool) => `版 ${version} の図は、この道具 (版 ${tool}) より新しいので読めない。道具を新しくする`,
82
+ };
83
+
84
+ const en: FieldMessages = {
85
+ additionalProperties: (key) => `The ${key} field is not allowed`,
86
+ required: (key) => `The ${key} field is required`,
87
+ enum: (values) => `Use one of ${values.join(" / ")}`,
88
+ type: (type) => TYPES_EN[type] ?? `Use ${type}`,
89
+ minLength: (limit) => `Write at least ${plural(limit, "character")}`,
90
+ pattern: (forbidden) =>
91
+ forbidden
92
+ ? `Cannot contain ${forbidden.space ? "spaces or " : ""}${forbidden.chars.join(" ")}`
93
+ : "Contains characters that are not allowed",
94
+ minItems: (limit) => `Write at least ${plural(limit, "item")}`,
95
+ minimum: (limit) => `Use ${limit} or greater`,
96
+ const: (value) => `Use ${value}`,
97
+ not: (allowed) => (allowed ? `The ${allowed.field} field is allowed only when kind is ${allowed.kind}` : "This combination of fields is not allowed"),
98
+ anyOf: (fields) => (fields.length > 0 ? `Write one of the ${fields.join(" or ")} fields` : "Does not match any of the allowed shapes"),
99
+ oneOf: "Match exactly one of the allowed shapes",
100
+ discriminator: (tag, values) => `${tag} is one of ${values.join(" / ")}`,
101
+ newer: (version, tool) => `Version ${version} diagrams are newer than this tool (version ${tool}) and cannot be read. Update the tool`,
102
+ };
103
+
104
+ export const FIELD_MESSAGES: Record<NotationLang, FieldMessages> = { ja, en };
@@ -0,0 +1,42 @@
1
+ /**
2
+ * 描く部品が出す字 (#3001)。
3
+ *
4
+ * 図の原本は語を持たないので、呼ぶ側が言葉を渡す。渡さなければ日本語で出す。
5
+ * 頁は頁の言葉を、`dragon export` は記法の file の言葉 (`--lang` を渡せばその言葉) を渡す。
6
+ */
7
+ import type { NotationLang } from "./words";
8
+
9
+ export interface FigureText {
10
+ /** 描けない時の断りの文。`detail` は誤りの場所と文を並べた物 */
11
+ cannotDraw: (detail: string) => string;
12
+ /** 寄って動かす見せ方の、隅の全体図の札 */
13
+ overview: string;
14
+ /** 再生の釦の読み上げの名前 */
15
+ prev: string;
16
+ pause: string;
17
+ play: string;
18
+ next: string;
19
+ /** 段の一覧の読み上げの名前 */
20
+ steps: (title: string) => string;
21
+ }
22
+
23
+ export const FIGURE_TEXT: Record<NotationLang, FigureText> = {
24
+ ja: {
25
+ cannotDraw: (detail) => `図を描けない: ${detail}`,
26
+ overview: "全体図",
27
+ prev: "前の段",
28
+ pause: "止める",
29
+ play: "動かす",
30
+ next: "次の段",
31
+ steps: (title) => `${title} の段`,
32
+ },
33
+ en: {
34
+ cannotDraw: (detail) => `Cannot draw the diagram: ${detail}`,
35
+ overview: "Overview",
36
+ prev: "Previous step",
37
+ pause: "Pause",
38
+ play: "Play",
39
+ next: "Next step",
40
+ steps: (title) => `Steps of ${title}`,
41
+ },
42
+ };
package/src/index.ts CHANGED
@@ -1,287 +1,34 @@
1
1
  /**
2
- * Dragon — Text DSL public API
2
+ * dragon の入口。
3
3
  *
4
- * Mermaid 感覚で animated SVG を生成する Text DSL。 cdl engine を呼出して CdlDiagram を返す。
5
- *
6
- * 使い方:
7
- * const diagram = textDslToDiagram(source);
8
- * // diagram は @cardenelabs/cdl の CdlDiagram、 そのまま CdlDiagramView 等に渡せる
9
- */
10
-
11
- export { parseTextDsl } from "./parser";
12
- export { compileToCdl } from "./compile";
13
- export type { CompileNotice } from "./compile";
14
- /**
15
- * 組み立てた図の型 (#1415)。
16
- *
17
- * `textDslToDiagram` が返す型そのもので、実体は `@cardenelabs/cdl` が持つ。 使う側が
18
- * 戻り値に型を付けるには必ず要るので、ここから引けるようにする。
19
- *
20
- * 再 export が無い間、使う側は `@cardenelabs/cdl` を直接の依存に足す必要があった。
21
- * 足さずに書くと **型が暗黙の `any` に落ち、その先の `.map((n) => ...)` まで検査が効かなく
22
- * なる** (実測 = この 1 件が 39 件の暗黙 `any` を生んでいた)。
4
+ * 図の原本は JSON で、人は 1 行が 1 本の線になる記法で書く。記法と JSON は行き来でき、
5
+ * JSON は JSON Schema 1 本で検査する。原本から図を描き、頁に置いて段ごとに動かす。
6
+ * 頁に字を読み込むのは別の入口 `@cardenelabs/dragon/fonts`。
23
7
  */
24
- export type { CdlDiagram } from "@cardenelabs/cdl";
25
- export { parseTextDslV05 } from "./v05";
26
- // 記法一覧が「実際に受け付ける値」 を実装から引くための公開。 手書きすると説明と実装がずれる。
27
- export {
28
- DRAW_TARGETS,
29
- DRAW_WORDS,
30
- PHASE_ITEM_WORDS,
31
- PRESET_TYPES,
32
- TOP_LEVEL_KEYS,
33
- TYPE_ALIASES,
34
- } from "./v05/parser";
35
- // 行頭の印の語 (#2782)。 見本がどの語を使っているかを数える検査が、一覧を実装から引く
36
- export { 行頭の語 } from "./compile/row-marks";
37
- export {
38
- TONE_ALIAS,
39
- NODE_KIND_ALIAS,
40
- DIRECTION_ALIAS,
41
- ORDERS,
42
- ORDER_ALIAS,
43
- SHAPES,
44
- SWIMLANE_SHAPES,
45
- DIAGRAM_SHAPES,
46
- ALL_DIAGRAM_SHAPES,
47
- THEMES,
48
- THEME_ALIAS,
49
- resolveTheme,
50
- LEGEND_MARK_ALIAS,
51
- resolveLegendMark,
52
- 意匠の字の測り方,
53
- 意匠の円の区画の間,
54
- 棒を描く節か,
55
- 意匠の棒の角,
56
- } from "./keywords";
57
- export type { DslTheme, DslShape, DslSwimlaneShape, DslDiagramShape } from "./keywords";
58
- export { lintDiagram, autoFix } from "./notation-lint";
59
- export type { LintIssue, LintReport, LintSeverity } from "./notation-lint";
60
- // canvas pivot 新 spec 図境界計算 helper (§diagram-boundary SSOT)
61
- export { computeDiagramBoundingBox, rectsOverlap, DIAGRAM_BOUNDARY_PADDING } from "./canvas-bounds";
62
- export type { DiagramBoundingBox } from "./canvas-bounds";
63
- // 位置を相対で書くための解決。 組み立て側と画面側の両方が同じ規則を使うために公開する。
64
- export {
65
- parseRelativePos,
66
- resolveRelativePos,
67
- orderByDependency,
68
- RELATIVE_GAP_DEFAULT,
69
- } from "./relative-pos";
70
- export type { RelativePos, RelativeDirection, AnchorBox } from "./relative-pos";
71
- // 光らせる相手の書き方の読み取り。 図種ごとの解決経路が同じ規則を共有する。
72
- export { parseFocusEntry } from "./focus";
73
- export type { FocusEntry } from "./focus";
74
- // 画面で見えている座標を記法に落とすための書込み。 記法を知る側に置く。
75
- export { writeActorPosition } from "./write-position";
76
- // 図の上での位置を測る。 editor が現在位置を出すのと、 相対指定を解くので同じ規則を使う。
77
- export { measureActorBoxes } from "./compile";
78
- // 本文に書いた部品の状態の上書きと色番号を、部品の図へ当てる。 編集画面が重ねて描く部品にも
79
- // 組み立て側と同じ値を使う (#1973)
80
- export { 部品に上書きを当てる } from "./compile";
81
- // 測るためだけの配置が受け取った、描かれない図についての知らせの数 (#2312)。 読み込み時の
82
- // 知らせを 0 行で固定する検査が、母数として読む (0 件なら測る経路を通っていない)
83
- export { 測るために受け取った知らせの数 } from "./compile";
84
- // パーツの見た目の大きさと、 位置を書かなかった時の格子。 画面側と組み立て側で同じ規則を使う。
85
- // 記法が受理する種類の全体。 画面側が「本文が見本を使っているか」 を判定するのに使う (#1022)。
86
- export { NODE_KIND_VALID } from "./v05/parser";
87
-
88
- // パーツの大きさを測る 3 つ。 用途で使い分ける (取り違えると経路ごとに絵が変わる)。
89
- //
90
- // - `partRenderSize` = 図枠。 画面が描く大きさと、 格子が確保する場所に使う
91
- // - `partBoxInFrame` = 図枠の中の箱 (パーツ自身の座標)。 画面が書いた座標と相対指定を解くのに使う
92
- // - `partVisualSize` = 箱の外接矩形 (merge の座標)。 組み立て側が取り込んだ後の大きさに使う
93
- //
94
- // 格子だけ図枠なのは、 隣と重ならない幅を確保するのが目的で描く大きさそのものが要るため。
95
- // 座標と間隔は見えている箱で測る (#937 / #1014)。
96
- // `大きさ:` の倍率は `partTargetScale` が持つ。 画面側も同じ規則で拡大しないと、
97
- // 書いた見本だけ経路で大きさが変わる (#1018)。
98
- // `partDrawsInDiagram` = その見本が図の中に描かれる部品を持つか。 実体が操作パネルの
99
- // 部品だけの見本 (catalog 80 件中 17 件) は重ねても図に出ないため、画面側が知らせる (#1017)。
100
- // `倍率:` (`scale`) は図形の倍率として予約する (#1026)。 画面と組み立てで意味が違うと、
101
- // 同じ本文が経路で別の絵になる。 正規化 (`normalizePartScale`) と `大きさ:` との掛け合わせ
102
- // (`partTargetSize`) を engine 側に置き、画面側も同じ関数を呼ぶ。
8
+ export { extractDiagrams, type Fence } from "./markdown";
9
+ export { type LineError, type ParseOptions, type Parsed, parseNotation } from "./parser";
10
+ export { type PrintOptions, printNotation } from "./printer";
11
+ export { type NotationLang, notationLanguage } from "./words";
103
12
  export {
104
- partRenderSize,
105
- partVisualSize,
106
- partBoxInFrame,
107
- partTargetScale,
108
- partTargetSize,
109
- partScaleFactor,
110
- normalizePartScale,
111
- MAX_PART_SCALE,
112
- partDrawsInDiagram,
113
- partIsMeasurable,
114
- partsBaseBottom,
115
- partsGridCenters,
116
- } from "./compile";
117
- // 色として読めるかの判定と、 図の外を指す値かの判定。 状態の上書きを受け取る側 / 画面が色欄を
118
- // 作る側 / 画面が背景色を直接書く側で同じ物差しを使う (別々に持つと、 片方だけ直した時に片方が通す)。
119
- export { isColorValue, pointsOutside, stripExternalPaint } from "./color";
120
- // 引用符の外し方 (#1028)。 画面側が本文から見本を抜く時に同じ判定を使う。
121
- // 別々に持つと、片方だけが読める本文ができる (実測 = `位置: '300,200"` が
122
- // 画面側では座標 300 として通り、組み立て側では読めない値として知らせが出た)
123
- export { stripQuotes } from "./v05/parser";
124
-
125
- // 画面で色分けするための分解器 (#1310)。 色は持たず、種類名と位置だけを返す
126
- export { 記法を分解する, JSONを分解する, 区間に広げる } from "./tokenize";
127
- export type { トークン, トークンの種類 } from "./tokenize";
128
- // 大きすぎる入力を組み立てる前に止める上限 (#1005)。 画面側も同じ物差しで事前に知らせられるよう公開する。
129
- export {
130
- MAX_INPUT_ELEMENTS,
131
- MAX_INPUT_BYTES,
132
- countDocElements,
133
- countDiagramElements,
134
- countBytes,
135
- describeOversize,
136
- describeOversizeSource,
137
- } from "./input-size";
138
- export type { InputSize } from "./input-size";
139
-
140
- // LLM 向け JSON DSL (Issue #208)
141
- export { jsonToDiagram, validateDragonJson } from "./json-parser";
142
- // JSON / YAML の本文で書いた場所を指す鍵 (#2117)。 表を作る側 (画面の YAML 欄) と引く側
143
- // (`json-parser.ts`) が同じ規則を使うために公開する
144
- export { 書いた場所の鍵 } from "./json-line-map";
145
- export type { 書いた行の表 } from "./json-line-map";
146
- export { diagramJsonSchema } from "./schema";
147
- export type {
148
- DragonJson,
149
- JsonActor,
150
- JsonAxes,
151
- JsonStep,
152
- JsonPhase,
153
- JsonDslError,
154
- } from "./json-parser";
155
- export type {
156
- DslDocument,
157
- DslActor,
158
- DslStep,
159
- DslAnimate,
160
- DslState,
161
- DslPhase,
162
- DslTween,
163
- DslSet,
164
- // `DslDocument.values` を触る利用者が型を import できるようにする (#1169)。
165
- // 兄弟の `DslState` / `DslTween` / `DslSet` は公開されており、これだけ漏れていた
166
- DslValue,
167
- DslError,
168
- PresetType,
169
- DslLane,
170
- DslGroup,
171
- DslViewport,
172
- // CAR-1693 Phase 1: canvas pivot DSL 表面 pos + layout mode の public 型
173
- LayoutPos,
174
- LayoutMode,
175
- } from "./types";
176
-
177
- import { parseTextDsl } from "./parser";
178
- import { parseTextDslV05 } from "./v05";
179
- import { compileToCdl } from "./compile";
180
- import { describeOversizeSource } from "./input-size";
181
- import type { CompileNotice } from "./compile";
182
- import type { CdlDiagram } from "@cardenelabs/cdl";
183
-
184
- /**
185
- * CAR-1657 = compile 時 parts identifier lookup 用 catalog。
186
- * caller (CdlEditor 等) が loadPartsItems() の結果を Record<partId, CdlDiagram> で inject。
187
- * 未渡し時 partId set actor は「未解決」 として skip + console.warn (diagram render は継続)。
188
- */
189
- export interface CompileOpts {
190
- partsCatalog?: Record<string, CdlDiagram>;
191
- /**
192
- * 図は出せるが書いた通りにならなかったことの受け取り口 (`位置: Web の下` が順序図で
193
- * 効かない等)。 判定は組み立て側が持ち、 呼出側は受け取って表示するだけにする。
194
- */
195
- onNotice?: (notice: CompileNotice) => void;
196
- /**
197
- * edge が DSL のどの行から来たかの受け取り口 (#998)。
198
- *
199
- * preset によっては書いた step と生成される edge が一致しない (`type: flow` は actor を鎖状に
200
- * 繋ぐため `a -> c` と書いても `a -> b` になる)。 edge を起点に本文の行を直す機能 (自動修正の
201
- * 書き戻し等) は、 この対応が無いと別の行を書き換える。
202
- *
203
- * **対応が取れない edge については呼ばれない**。 「対応が無い」 と「行 0」 を区別するため。
204
- */
205
- onEdgeSource?: (edgeId: string, line: number) => void;
206
- }
207
-
208
- /**
209
- * Dragon DSL から CdlDiagram に一発変換。 v0.5 (英語 keyword) / v0.4 (日本語 keyword) を auto-detect。
210
- *
211
- * 判定 ... src 内に v0.5 専用 syntax (`animation:` block / `- A -> B` flow / `step: "..."` ) を含むなら v0.5、
212
- * 含まなければ v0.4 (deprecated、 console.warn を出す)。
213
- *
214
- * エラー時は throw、 詳細を取りたい場合は parseTextDslV05 / parseTextDsl を直接呼ぶ。
215
- * opts.partsCatalog を渡すと CAR-1657 parts kind (arc-gauge 等) の actor が merge 展開される。
216
- */
217
- export function textDslToDiagram(src: string, opts?: CompileOpts): CdlDiagram {
218
- // 読み取る前に大きさを見る (#1005)。 要素数の上限は読み取った後にしか分からないため、
219
- // 巨大な本文そのものによる待ちと記憶の消費はここでしか防げない
220
- const oversize = describeOversizeSource(src);
221
- if (oversize) throw new Error(oversize);
222
-
223
- if (isV05Source(src)) {
224
- const r = parseTextDslV05(src);
225
- if (!r.ok) {
226
- const msg = r.errors
227
- .map((e) => ` L${e.line}: ${e.message}${e.hint ? `\n hint: ${e.hint}` : ""}`)
228
- .join("\n");
229
- throw new Error(`Dragon DSL v0.5 parse error:\n${msg}`);
230
- }
231
- return compileToCdl(r.doc, opts);
232
- }
233
- // v0.4 fallback (deprecated)
234
- if (typeof console !== "undefined" && console.warn) {
235
- console.warn(
236
- "[dragon] v0.4 syntax (Japanese keywords) is deprecated. Please migrate to v0.5 (English keywords) by 2026-12-31.",
237
- );
238
- }
239
- const r = parseTextDsl(src);
240
- if (!r.ok) {
241
- const msg = r.errors
242
- .map((e) => ` L${e.line}: ${e.message}${e.hint ? `\n ヒント: ${e.hint}` : ""}`)
243
- .join("\n");
244
- throw new Error(`Dragon DSL parse error:\n${msg}`);
245
- }
246
- return compileToCdl(r.doc, opts);
247
- }
248
-
249
- function isV05Source(src: string): boolean {
250
- // 既定は v0.5 で、v0.4 の目印を 1 つでも見つけた時だけ v0.4 として読む (CAR-1657)。
251
- // v0.4 は 2026-12-31 に廃止予定なので、新しく書かれた本文は v0.5 として扱うのが当たりやすい。
252
- //
253
- // 目印に見出しの名前だけを使うと足りない = v0.4 も英語の別名 (`animate:` / `animation:`) を受けるため。
254
- // v0.4 にしかない書き方 (`step "..." Xs` = コロンの無い段、`^\d+\.\s+` = 番号付きの流れ) も目印に足す。
255
- const V04_KEYWORDS = [
256
- // Japanese v0.4 専用 keyword (v0.5 は英語のみ)。
257
- //
258
- // **字下げした行には当てない** (#1300)。 v0.4 の見出しは行頭に書くが、v0.5 の縦書き形は
259
- // 必ず字下げする。 同じ語が「v0.4 の見出し」 と「v0.5 の箱の欄 / 見本の状態名」 の両方で
260
- // 使われるため、`\s*` を許すと **正しい v0.5 の本文が旧 parser へ回る**。
261
- //
262
- // 実測 = `種類:` を箱の欄として縦に書いた本文と、見本の状態名が下の 7 語のいずれかである
263
- // 本文が、いずれも v0.4 として読まれて別の行を指す誤りを返していた。
264
- /^タイトル\s*[::]/, // title (JA)
265
- /^種類\s*[::]/, // type (JA)
266
- /^登場人物\s*[::]/, // actors (JA)
267
- /^流れ\s*[::]/, // flow (JA)
268
- /^アニメーション\s*[::]/, // animation (JA)
269
- /^動作\s*[::]/, // step (JA)
270
- /^状態\s*[::]/, // state (JA)
271
- // 鉤括弧が続く形は v0.5 に無い (状態名は `ステップ: 5` の形しか取れない) ため、
272
- // 字下げを許しても v0.5 と衝突しない。 v0.4 では `アニメーション:` の下に字下げして書く
273
- /^\s*ステップ\s*[「『]/, // step (JA)
274
- // v0.4 English-specific syntax = colon なし step (v0.5 は step: 必須)
275
- /^\s*step\s+"[^"]+"\s+[\d.]+\s*s\b/,
276
- /^\s*step\s+'[^']+'\s+[\d.]+\s*s\b/,
277
- // v0.4 numbered flow (`1. A → B`、 v0.5 は `- A -> B`)
278
- /^\s*\d+\.\s+\S+\s*(?:→|->)\s*\S+/,
279
- ];
280
- const lines = src.split("\n");
281
- for (const ln of lines) {
282
- for (const kw of V04_KEYWORDS) {
283
- if (kw.test(ln)) return false; // v0.4 detected → false
284
- }
285
- }
286
- return true; // no v0.4 marker → v0.5 default
287
- }
13
+ type Box,
14
+ type Carry,
15
+ type Checked,
16
+ type CheckOptions,
17
+ type Color,
18
+ type Diagram,
19
+ type DiagramEvent,
20
+ type FieldError,
21
+ type LabelSide,
22
+ type Region,
23
+ type Step,
24
+ validateDiagram,
25
+ type ViewMode,
26
+ } from "./schema";
27
+ export { FORMAT_VERSION, type Migrated, migrateFile, type Read, readDiagram } from "./version";
28
+ export type { Layout } from "./layout/scene";
29
+ export { FONTS } from "./look/fonts";
30
+ export { DEFAULT_PALETTE, type Palette, PALETTES, resolvePalette, type Theme } from "./look/values";
31
+ export { mountDiagram, type Player } from "./player";
32
+ export { type Rendered, type RenderOptions, renderDiagram } from "./render/svg";
33
+ export type { Timeline } from "./timeline";
34
+ export { chooseView } from "./view";