@cardenelabs/cdl 0.5.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 (108) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +343 -0
  3. package/SPEC.md +374 -0
  4. package/dist/index.cjs +28085 -0
  5. package/dist/index.cjs.map +1 -0
  6. package/dist/index.d.cts +3415 -0
  7. package/dist/index.d.ts +3415 -0
  8. package/dist/index.js +27962 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/react.cjs +23043 -0
  11. package/dist/react.cjs.map +1 -0
  12. package/dist/react.d.cts +2 -0
  13. package/dist/react.d.ts +2 -0
  14. package/dist/react.js +23041 -0
  15. package/dist/react.js.map +1 -0
  16. package/dist/render-C78lIXeC.d.cts +2449 -0
  17. package/dist/render-C78lIXeC.d.ts +2449 -0
  18. package/examples/quick-start.md +88 -0
  19. package/package.json +79 -0
  20. package/src/anim/core/easing.ts +77 -0
  21. package/src/anim/core/timeline.ts +335 -0
  22. package/src/anim/core/types.ts +42 -0
  23. package/src/anim/index.ts +20 -0
  24. package/src/anim/react/index.ts +3 -0
  25. package/src/anim/react/useReducedMotion.ts +27 -0
  26. package/src/anim/react/useTimeline.ts +48 -0
  27. package/src/assert-never.ts +16 -0
  28. package/src/author-intent-verify.ts +587 -0
  29. package/src/builder.ts +3740 -0
  30. package/src/compile.ts +12 -0
  31. package/src/dom-verify-core.ts +121 -0
  32. package/src/dom-verify-types.ts +21 -0
  33. package/src/dom-verify.ts +948 -0
  34. package/src/event-handler/index.ts +184 -0
  35. package/src/formula/ast.ts +46 -0
  36. package/src/formula/evaluator.ts +163 -0
  37. package/src/formula/formula-computeds.ts +83 -0
  38. package/src/formula/index.ts +5 -0
  39. package/src/formula/parser.ts +399 -0
  40. package/src/index.ts +284 -0
  41. package/src/input-signals.ts +74 -0
  42. package/src/kinds/actor.tsx +79 -0
  43. package/src/kinds/card.tsx +61 -0
  44. package/src/kinds/chart-bar.tsx +121 -0
  45. package/src/kinds/chart-line.tsx +163 -0
  46. package/src/kinds/chart-pie.tsx +107 -0
  47. package/src/kinds/compact-title.ts +164 -0
  48. package/src/kinds/dyn-shape.tsx +394 -0
  49. package/src/kinds/event.tsx +70 -0
  50. package/src/kinds/function.tsx +53 -0
  51. package/src/kinds/funnel.tsx +122 -0
  52. package/src/kinds/gantt.tsx +193 -0
  53. package/src/kinds/generic.tsx +368 -0
  54. package/src/kinds/mind-map.tsx +367 -0
  55. package/src/kinds/mind-radial.tsx +209 -0
  56. package/src/kinds/node-tone.ts +18 -0
  57. package/src/kinds/quadrant.tsx +164 -0
  58. package/src/kinds/row-align.ts +179 -0
  59. package/src/kinds/shape-basement.tsx +683 -0
  60. package/src/kinds/shape-blockchain.tsx +750 -0
  61. package/src/kinds/shape-commerce.tsx +553 -0
  62. package/src/kinds/shape-finance.tsx +706 -0
  63. package/src/kinds/shape-hardware.tsx +862 -0
  64. package/src/kinds/shape-people.tsx +439 -0
  65. package/src/kinds/shape-region.tsx +383 -0
  66. package/src/kinds/shape-software.tsx +859 -0
  67. package/src/kinds/storage.tsx +180 -0
  68. package/src/kinds/text-width.ts +73 -0
  69. package/src/kinds/tree.tsx +275 -0
  70. package/src/kinds/user-journey.tsx +240 -0
  71. package/src/label-text.ts +71 -0
  72. package/src/layout/clearance-constants.ts +47 -0
  73. package/src/layout/collisions.ts +2078 -0
  74. package/src/layout/edges.ts +2498 -0
  75. package/src/layout/footer-shape.ts +97 -0
  76. package/src/layout/geometry.ts +135 -0
  77. package/src/layout/label-shift.ts +28 -0
  78. package/src/layout/lanes.ts +328 -0
  79. package/src/layout/nodes.ts +190 -0
  80. package/src/layout/predict-bbox.ts +76 -0
  81. package/src/layout/px-projection.ts +176 -0
  82. package/src/layout/spec.ts +872 -0
  83. package/src/layout/text-width.ts +133 -0
  84. package/src/layout/tokens.ts +181 -0
  85. package/src/layout/viewbox.ts +47 -0
  86. package/src/layout-with-validation.ts +175 -0
  87. package/src/layout.ts +381 -0
  88. package/src/presets.ts +2108 -0
  89. package/src/reactive/batch.ts +48 -0
  90. package/src/reactive/computed.ts +85 -0
  91. package/src/reactive/effect.ts +145 -0
  92. package/src/reactive/index.ts +6 -0
  93. package/src/reactive/internal.ts +109 -0
  94. package/src/reactive/signal.ts +113 -0
  95. package/src/render/edges.tsx +318 -0
  96. package/src/render/header.tsx +146 -0
  97. package/src/render/interactive-panel.tsx +9620 -0
  98. package/src/render/nodes.tsx +319 -0
  99. package/src/render/stage.tsx +377 -0
  100. package/src/render/tone.ts +64 -0
  101. package/src/render/utils.ts +238 -0
  102. package/src/render.tsx +221 -0
  103. package/src/scroll-trigger/index.ts +109 -0
  104. package/src/scroll-trigger/progress.ts +49 -0
  105. package/src/thumbnail.tsx +114 -0
  106. package/src/types.ts +2371 -0
  107. package/src/validate.ts +268 -0
  108. package/src/visual-validate.ts +4381 -0
@@ -0,0 +1,399 @@
1
+ import { ALLOWED_MATH_FNS, type BinaryOp, type FormulaAst, type MathFnName } from "./ast";
2
+
3
+ /**
4
+ * formula expression parser (CAR #244)。
5
+ *
6
+ * safe subset のみ受け付ける:
7
+ * - 数値リテラル (整数 / 小数、 負数 は unary `-` 経由)
8
+ * - identifier (signal 名参照、 property access `.` は Math. 以外禁止)
9
+ * - Math.* 関数 (min / max / abs / floor / ceil / round のみ、 他は syntax error)
10
+ * - 算術 (+ - * / %) / 比較 (< <= > >= == !=) / 三項 (?:)
11
+ * - 括弧 ( )
12
+ *
13
+ * 禁止 pattern (parse 時に throw):
14
+ * - 代入 (= は == のみ、 単独 = は throw)
15
+ * - property access `x.y` (Math.* 以外)
16
+ * - Function / eval / import / for / while (identifier として来た場合は signal として扱われるので直接 error にならないが、
17
+ * runtime に signal lookup 失敗する = evaluator 側で throw)
18
+ * - `!` (単独。 `!=` は accept)
19
+ */
20
+
21
+ type Token =
22
+ | { kind: "num"; value: number; pos: number }
23
+ | { kind: "id"; name: string; pos: number }
24
+ | { kind: "math"; fn: MathFnName; pos: number }
25
+ | { kind: "op"; op: BinaryOp; pos: number }
26
+ | { kind: "lparen"; pos: number }
27
+ | { kind: "rparen"; pos: number }
28
+ | { kind: "comma"; pos: number }
29
+ | { kind: "question"; pos: number }
30
+ | { kind: "colon"; pos: number }
31
+ | { kind: "unaryMinus"; pos: number };
32
+
33
+ function tokenize(src: string): Token[] {
34
+ const tokens: Token[] = [];
35
+ let i = 0;
36
+ while (i < src.length) {
37
+ const c = src[i]!;
38
+ if (c === " " || c === "\t" || c === "\n" || c === "\r") {
39
+ i++;
40
+ continue;
41
+ }
42
+ // number: digits + optional decimal
43
+ if (c >= "0" && c <= "9") {
44
+ const start = i;
45
+ let hasDot = false;
46
+ while (i < src.length) {
47
+ const cc = src[i]!;
48
+ if (cc >= "0" && cc <= "9") {
49
+ i++;
50
+ } else if (cc === "." && !hasDot) {
51
+ hasDot = true;
52
+ i++;
53
+ } else {
54
+ break;
55
+ }
56
+ }
57
+ const numStr = src.slice(start, i);
58
+ const num = Number(numStr);
59
+ if (Number.isNaN(num)) {
60
+ throw new Error(`invalid number literal "${numStr}" at position ${start}`);
61
+ }
62
+ tokens.push({ kind: "num", value: num, pos: start });
63
+ continue;
64
+ }
65
+ // decimal starting with `.` (e.g. .5)
66
+ if (c === "." && i + 1 < src.length && src[i + 1]! >= "0" && src[i + 1]! <= "9") {
67
+ const start = i;
68
+ i++;
69
+ while (i < src.length && src[i]! >= "0" && src[i]! <= "9") i++;
70
+ const num = Number(src.slice(start, i));
71
+ tokens.push({ kind: "num", value: num, pos: start });
72
+ continue;
73
+ }
74
+ // identifier / Math.<fn>
75
+ if ((c >= "a" && c <= "z") || (c >= "A" && c <= "Z") || c === "_" || c === "$") {
76
+ const start = i;
77
+ while (i < src.length) {
78
+ const cc = src[i]!;
79
+ if (
80
+ (cc >= "a" && cc <= "z") ||
81
+ (cc >= "A" && cc <= "Z") ||
82
+ (cc >= "0" && cc <= "9") ||
83
+ cc === "_" ||
84
+ cc === "$"
85
+ ) {
86
+ i++;
87
+ } else {
88
+ break;
89
+ }
90
+ }
91
+ const name = src.slice(start, i);
92
+ // Math.<fn>
93
+ if (name === "Math") {
94
+ if (src[i] !== ".") {
95
+ throw new Error(
96
+ `bare "Math" identifier at position ${start} is not allowed (use Math.min / Math.max / Math.abs / Math.floor / Math.ceil / Math.round)`,
97
+ );
98
+ }
99
+ i++; // skip .
100
+ const fnStart = i;
101
+ while (i < src.length) {
102
+ const cc = src[i]!;
103
+ if ((cc >= "a" && cc <= "z") || (cc >= "A" && cc <= "Z")) {
104
+ i++;
105
+ } else {
106
+ break;
107
+ }
108
+ }
109
+ const fnName = src.slice(fnStart, i);
110
+ if (!ALLOWED_MATH_FNS.has(fnName)) {
111
+ throw new Error(
112
+ `unsupported Math.${fnName} at position ${start} (allowed: Math.min / Math.max / Math.abs / Math.floor / Math.ceil / Math.round)`,
113
+ );
114
+ }
115
+ tokens.push({ kind: "math", fn: `Math.${fnName}` as MathFnName, pos: start });
116
+ continue;
117
+ }
118
+ // property access on other identifiers is禁止
119
+ if (src[i] === ".") {
120
+ throw new Error(
121
+ `property access "${name}.${src[i + 1] ?? ""}..." at position ${start} is not allowed (only Math.* namespace is accessible)`,
122
+ );
123
+ }
124
+ tokens.push({ kind: "id", name, pos: start });
125
+ continue;
126
+ }
127
+ // operators
128
+ if (c === "+") {
129
+ tokens.push({ kind: "op", op: "+", pos: i });
130
+ i++;
131
+ continue;
132
+ }
133
+ if (c === "-") {
134
+ // unary vs binary は parser 側で判定、 tokenizer は「-」 として emit
135
+ tokens.push({ kind: "op", op: "-", pos: i });
136
+ i++;
137
+ continue;
138
+ }
139
+ if (c === "*") {
140
+ tokens.push({ kind: "op", op: "*", pos: i });
141
+ i++;
142
+ continue;
143
+ }
144
+ if (c === "/") {
145
+ tokens.push({ kind: "op", op: "/", pos: i });
146
+ i++;
147
+ continue;
148
+ }
149
+ if (c === "%") {
150
+ tokens.push({ kind: "op", op: "%", pos: i });
151
+ i++;
152
+ continue;
153
+ }
154
+ if (c === "<") {
155
+ if (src[i + 1] === "=") {
156
+ tokens.push({ kind: "op", op: "<=", pos: i });
157
+ i += 2;
158
+ } else {
159
+ tokens.push({ kind: "op", op: "<", pos: i });
160
+ i++;
161
+ }
162
+ continue;
163
+ }
164
+ if (c === ">") {
165
+ if (src[i + 1] === "=") {
166
+ tokens.push({ kind: "op", op: ">=", pos: i });
167
+ i += 2;
168
+ } else {
169
+ tokens.push({ kind: "op", op: ">", pos: i });
170
+ i++;
171
+ }
172
+ continue;
173
+ }
174
+ if (c === "=") {
175
+ if (src[i + 1] === "=") {
176
+ tokens.push({ kind: "op", op: "==", pos: i });
177
+ i += 2;
178
+ continue;
179
+ }
180
+ throw new Error(
181
+ `assignment "=" at position ${i} is not allowed (use "==" for equality comparison)`,
182
+ );
183
+ }
184
+ if (c === "!") {
185
+ if (src[i + 1] === "=") {
186
+ tokens.push({ kind: "op", op: "!=", pos: i });
187
+ i += 2;
188
+ continue;
189
+ }
190
+ throw new Error(`unary "!" (logical not) at position ${i} is not allowed`);
191
+ }
192
+ if (c === "(") {
193
+ tokens.push({ kind: "lparen", pos: i });
194
+ i++;
195
+ continue;
196
+ }
197
+ if (c === ")") {
198
+ tokens.push({ kind: "rparen", pos: i });
199
+ i++;
200
+ continue;
201
+ }
202
+ if (c === ",") {
203
+ tokens.push({ kind: "comma", pos: i });
204
+ i++;
205
+ continue;
206
+ }
207
+ if (c === "?") {
208
+ tokens.push({ kind: "question", pos: i });
209
+ i++;
210
+ continue;
211
+ }
212
+ if (c === ":") {
213
+ tokens.push({ kind: "colon", pos: i });
214
+ i++;
215
+ continue;
216
+ }
217
+ throw new Error(`unexpected character "${c}" at position ${i}`);
218
+ }
219
+ return tokens;
220
+ }
221
+
222
+ /**
223
+ * 再帰下降 parser。 precedence (low → high):
224
+ * ternary (?:) → comparison (< <= > >= == !=) → additive (+ -) → multiplicative (* / %) → unary (-) → primary
225
+ */
226
+ class Parser {
227
+ private pos = 0;
228
+ constructor(private readonly tokens: Token[]) {}
229
+
230
+ private peek(): Token | undefined {
231
+ return this.tokens[this.pos];
232
+ }
233
+
234
+ private consume(): Token {
235
+ const t = this.tokens[this.pos];
236
+ if (!t) throw new Error("unexpected end of expression");
237
+ this.pos++;
238
+ return t;
239
+ }
240
+
241
+ private isOp(...ops: BinaryOp[]): boolean {
242
+ const t = this.peek();
243
+ return !!t && t.kind === "op" && ops.includes(t.op);
244
+ }
245
+
246
+ parse(): FormulaAst {
247
+ const ast = this.parseTernary();
248
+ if (this.pos < this.tokens.length) {
249
+ const t = this.tokens[this.pos]!;
250
+ throw new Error(`unexpected token after expression at position ${t.pos}`);
251
+ }
252
+ return ast;
253
+ }
254
+
255
+ private parseTernary(): FormulaAst {
256
+ const condition = this.parseComparison();
257
+ if (this.peek()?.kind === "question") {
258
+ this.consume();
259
+ const whenTrue = this.parseTernary();
260
+ const colon = this.peek();
261
+ if (!colon || colon.kind !== "colon") {
262
+ throw new Error("expected ':' in ternary expression");
263
+ }
264
+ this.consume();
265
+ const whenFalse = this.parseTernary();
266
+ return { type: "ternary", condition, whenTrue, whenFalse };
267
+ }
268
+ return condition;
269
+ }
270
+
271
+ private parseComparison(): FormulaAst {
272
+ let left = this.parseAdditive();
273
+ while (this.isOp("<", "<=", ">", ">=", "==", "!=")) {
274
+ const opTok = this.consume() as Extract<Token, { kind: "op" }>;
275
+ const right = this.parseAdditive();
276
+ left = { type: "binaryOp", op: opTok.op, left, right };
277
+ }
278
+ return left;
279
+ }
280
+
281
+ private parseAdditive(): FormulaAst {
282
+ let left = this.parseMultiplicative();
283
+ while (this.isOp("+", "-")) {
284
+ const opTok = this.consume() as Extract<Token, { kind: "op" }>;
285
+ const right = this.parseMultiplicative();
286
+ left = { type: "binaryOp", op: opTok.op, left, right };
287
+ }
288
+ return left;
289
+ }
290
+
291
+ private parseMultiplicative(): FormulaAst {
292
+ let left = this.parseUnary();
293
+ while (this.isOp("*", "/", "%")) {
294
+ const opTok = this.consume() as Extract<Token, { kind: "op" }>;
295
+ const right = this.parseUnary();
296
+ left = { type: "binaryOp", op: opTok.op, left, right };
297
+ }
298
+ return left;
299
+ }
300
+
301
+ private parseUnary(): FormulaAst {
302
+ if (this.isOp("-")) {
303
+ this.consume();
304
+ const operand = this.parseUnary();
305
+ return { type: "unaryOp", op: "-", operand };
306
+ }
307
+ return this.parsePrimary();
308
+ }
309
+
310
+ private parsePrimary(): FormulaAst {
311
+ const t = this.peek();
312
+ if (!t) throw new Error("unexpected end of expression");
313
+ if (t.kind === "num") {
314
+ this.consume();
315
+ return { type: "number", value: t.value };
316
+ }
317
+ if (t.kind === "id") {
318
+ this.consume();
319
+ return { type: "identifier", name: t.name };
320
+ }
321
+ if (t.kind === "math") {
322
+ this.consume();
323
+ const lparen = this.peek();
324
+ if (!lparen || lparen.kind !== "lparen") {
325
+ throw new Error(`expected '(' after ${t.fn} at position ${t.pos}`);
326
+ }
327
+ this.consume();
328
+ const args: FormulaAst[] = [];
329
+ if (this.peek()?.kind !== "rparen") {
330
+ args.push(this.parseTernary());
331
+ while (this.peek()?.kind === "comma") {
332
+ this.consume();
333
+ args.push(this.parseTernary());
334
+ }
335
+ }
336
+ const rparen = this.peek();
337
+ if (!rparen || rparen.kind !== "rparen") {
338
+ throw new Error(`expected ')' to close ${t.fn} at position ${t.pos}`);
339
+ }
340
+ this.consume();
341
+ return { type: "call", fn: t.fn, args };
342
+ }
343
+ if (t.kind === "lparen") {
344
+ this.consume();
345
+ const inner = this.parseTernary();
346
+ const rparen = this.peek();
347
+ if (!rparen || rparen.kind !== "rparen") {
348
+ throw new Error(`unmatched '(' at position ${t.pos}`);
349
+ }
350
+ this.consume();
351
+ return inner;
352
+ }
353
+ throw new Error(`unexpected token '${t.kind}' at position ${t.pos}`);
354
+ }
355
+ }
356
+
357
+ /**
358
+ * expression 文字列を parse して AST に変換する。 syntax error は Error を throw する。
359
+ * 空文字列は Error。
360
+ */
361
+ export function parseFormula(expression: string): FormulaAst {
362
+ const tokens = tokenize(expression);
363
+ if (tokens.length === 0) {
364
+ throw new Error("empty formula expression");
365
+ }
366
+ return new Parser(tokens).parse();
367
+ }
368
+
369
+ /**
370
+ * AST 内で参照される identifier (signal 名) を全て収集する。 evaluator が signal 経由で
371
+ * runtime value を lookup する時の識別子リスト作成に使う。
372
+ */
373
+ export function extractIdentifiers(ast: FormulaAst, out: Set<string> = new Set()): Set<string> {
374
+ switch (ast.type) {
375
+ case "number":
376
+ break;
377
+ case "identifier":
378
+ out.add(ast.name);
379
+ break;
380
+ case "binaryOp":
381
+ extractIdentifiers(ast.left, out);
382
+ extractIdentifiers(ast.right, out);
383
+ break;
384
+ case "unaryOp":
385
+ extractIdentifiers(ast.operand, out);
386
+ break;
387
+ case "ternary":
388
+ extractIdentifiers(ast.condition, out);
389
+ extractIdentifiers(ast.whenTrue, out);
390
+ extractIdentifiers(ast.whenFalse, out);
391
+ break;
392
+ case "call":
393
+ for (const arg of ast.args) {
394
+ extractIdentifiers(arg, out);
395
+ }
396
+ break;
397
+ }
398
+ return out;
399
+ }
package/src/index.ts ADDED
@@ -0,0 +1,284 @@
1
+ // reactive primitives (signal / computed / effect / batch / untrack) — base 機能 (CAR #242)、
2
+ // interactive / animation 系 primitive (input widget / formula / event handler) の依存基盤。
3
+ // Preact signals 相当の pull-based reactive graph、 zero runtime deps。
4
+ export { signal, computed, effect, batch, untrack } from "./reactive";
5
+ export type { Signal, Computed } from "./reactive";
6
+
7
+ // input widget primitive (CAR #243) — builder chain `.input.slider() / .number() / .dropdown() / .toggle()` で
8
+ // 追加、 consumer app 側 HTML widget と signal 経由で bind する。 cdl 自身は widget を描画せず metadata のみ。
9
+ export { createInputSignals, inputDefaultValue } from "./input-signals";
10
+ export type { InputChain } from "./builder";
11
+ export type { CdlInput } from "./types";
12
+
13
+ // formula primitive (CAR #244) — builder chain `.formula(id, "gasBase * 2")` で safe subset の
14
+ // algebraic expression を追加、 createFormulaComputeds(diagram, signals) で computed を得て
15
+ // signal と reactive bind する (Step 2 の computed 経路に統合)。
16
+ export {
17
+ parseFormula,
18
+ extractIdentifiers,
19
+ evaluate as evaluateFormula,
20
+ createFormulaComputeds,
21
+ } from "./formula";
22
+ export type { FormulaAst, FormulaContext, BinaryOp, MathFnName } from "./formula";
23
+ export type { CdlFormula } from "./types";
24
+
25
+ // scroll-driven trigger (CAR #245) — builder chain `.animation.scroll(id, opts)` で scroll trigger を
26
+ // 追加、 createScrollProgressSignals(diagram) で { progress signal, attach(element), detach } を得て
27
+ // DOM element に IntersectionObserver 経由で bind、 signal.value で 0..1 progress を read。
28
+ export {
29
+ createScrollProgressSignals,
30
+ createScrollProgressHandle,
31
+ computeScrollProgress,
32
+ } from "./scroll-trigger";
33
+ export type { ScrollProgressHandle } from "./scroll-trigger";
34
+ export type { AnimationChain } from "./builder";
35
+ export type { CdlScrollTrigger } from "./types";
36
+
37
+ // event handler primitive (CAR #246) — builder chain `.on.click(target, handlerId)` / `.on.hover(...)` で
38
+ // DOM event を bind、 attachEventHandlers(root, diagram, handlers) で consumer 関数 map と紐付ける。
39
+ // handler 内で signal 更新 → SVG reactive update の flow に統合。
40
+ export { attachEventHandlers, resolveTarget, resolveTargetAll } from "./event-handler";
41
+ export type { InteractiveHandlerMap, InteractiveSignalsAccessor } from "./render/interactive-panel";
42
+ export {
43
+ hasInteractivePrimitives,
44
+ computeInputSignalKey,
45
+ computeFormulaKey,
46
+ computeScrollTriggerKey,
47
+ computeEventBindingKey,
48
+ createInteractiveSignalsAccessor,
49
+ } from "./render/interactive-panel";
50
+ export { assertNever } from "./assert-never";
51
+ export type { CdlEventHandler, EventAttachHandle } from "./event-handler";
52
+ export type { EventChain } from "./builder";
53
+ export type { CdlEventBinding, CdlEventTarget, CdlEventKind } from "./types";
54
+
55
+ export { diagram } from "./builder";
56
+ export type { DiagramBuilder, PhaseBuilder } from "./builder";
57
+ export { compile } from "./compile";
58
+ export { layout } from "./layout";
59
+ export { validate } from "./validate";
60
+ export { countEdgeCrossings, visualValidate, visualValidateLaid, visualValidateAll } from "./visual-validate";
61
+ export type {
62
+ Violation,
63
+ VisualAxis,
64
+ VisualValidationReport,
65
+ SweepReport,
66
+ ValidateOptions,
67
+ ValidationProfile,
68
+ } from "./visual-validate";
69
+ // edge label の文字仕様。 下流が主題で色を上書きする時、 「その文字に何 :1 が要るか」 は
70
+ // 大きさと太さで決まる。 下流が 22 / 19 / 700 を書き写すと、 engine 側を変えた時に下流の
71
+ // 検査だけが古い前提で測り続ける。
72
+ export {
73
+ EDGE_LABEL_TEXT,
74
+ WCAG_AA_LARGE,
75
+ WCAG_AA_NORMAL,
76
+ isLargeText,
77
+ requiredContrastRatio,
78
+ } from "./label-text";
79
+ export type { EdgeLabelLine, EdgeLabelTextSpec } from "./label-text";
80
+ export { layoutWithValidation } from "./layout-with-validation";
81
+ export type { LayoutWithValidationOptions, LayoutWithValidationResult } from "./layout-with-validation";
82
+ export {
83
+ pointRectEdgeDistance,
84
+ rectRectOverlapArea,
85
+ rectRectClearance,
86
+ segmentsIntersect,
87
+ } from "./layout/geometry";
88
+ export type { Segment as GeometrySegment, Rect as GeometryRect } from "./layout/geometry";
89
+ export { verifyDiagramDom, verifyAllDiagramsDom, cdlAdapter } from "./dom-verify";
90
+ // 描画されない計測用の目印を取る selector。 consumer (dragon 等) も同じ要素を掴む必要があるので
91
+ // 公開する。 文字列を写すと、 こちらが目印を変えた時に consumer が黙って何も掴まなくなる。
92
+ export { STAGE_SVG_SELECTOR, NODE_FRAME_SELECTOR } from "./dom-verify";
93
+ export type { Discrepancy, DiscrepancyKind, VerifyOptions, DomVerifyReport, PageLike } from "./dom-verify";
94
+ // 目 v4 library 化前段 ... GenericDiagramSpec / DiagramAdapter 型 + 将来の独立 publish 用 core
95
+ export type {
96
+ GenericDiagramSpec,
97
+ GenericDiscrepancy,
98
+ GenericDiscrepancyKind,
99
+ GenericVerifyOptions,
100
+ DiagramAdapter,
101
+ } from "./dom-verify-core";
102
+ // 目 v5 author intent verifier (作者意図 ↔ 実画面 一致確認)
103
+ export { verifyAuthorIntent, verifyAuthorIntentAll } from "./author-intent-verify";
104
+ export type {
105
+ IntentDiscrepancy,
106
+ IntentDiscrepancyKind,
107
+ AuthorIntentOptions,
108
+ AuthorIntentReport,
109
+ } from "./author-intent-verify";
110
+ export { CdlDiagramView } from "./render";
111
+ export { CdlDiagramThumbnail } from "./thumbnail";
112
+ // px-projection = world 座標 → DOM px 変換 SSOT (pixel-perfect assertion 用)
113
+ export {
114
+ computeViewportScale,
115
+ worldToPx,
116
+ pxToWorld,
117
+ projectNode,
118
+ projectEdgeLabel,
119
+ projectPathSegment,
120
+ bboxClearance,
121
+ pointToSegmentDistance,
122
+ } from "./layout/px-projection";
123
+ // clearance / distance SSOT 定数 (world unit)
124
+ export {
125
+ CLEARANCE_NODE_LABEL,
126
+ CLEARANCE_LANE_LABEL,
127
+ CLEARANCE_LABEL_LABEL,
128
+ CLEARANCE_PATH_LABEL,
129
+ DIST_LABEL_PATH_MIN,
130
+ DIST_LABEL_PATH_MAX,
131
+ TARGET_LABEL_PATH_DIST,
132
+ ARROW_ANGLE_MAX_DEG,
133
+ FAN_GAP,
134
+ DETOUR_GAP,
135
+ } from "./layout/clearance-constants";
136
+ // spec SSOT = positive-check axis の目標値 SSOT (CAR-421 追加、 clearance-constants.ts と分離)
137
+ export {
138
+ LABEL_TO_PATH_CLEARANCE,
139
+ // CAR-468 追加 = routePath() init labelY SSOT (LABEL_TO_PATH_CLEARANCE + pill h/2 = 34 world、 CAR-630 で 26 → 34 復帰)
140
+ LABEL_INIT_CLEARANCE,
141
+ // CAR-518 追加 = dotted-flow edge label init clearance (marker glow radius 分拡張、 62 world、 CAR-630 で 54 → 62 復帰)
142
+ LABEL_INIT_CLEARANCE_DOTTED_FLOW,
143
+ MARKER_GLOW_RADIUS,
144
+ labelInitClearance,
145
+ EDGE_STUB_OUT,
146
+ DETOUR_SLOT_GAP,
147
+ MIN_ROW_ALIGNMENT_TOLERANCE,
148
+ MIN_COLUMN_ALIGNMENT_TOLERANCE,
149
+ SPEC_CLEARANCE_POLICY,
150
+ requiredSpecClearance,
151
+ CHAIN_SHIFT_MAX_ITER,
152
+ CHAIN_MIN_CLEARANCE,
153
+ CHAIN_SHIFT_MAX_ACCUMULATED,
154
+ // CAR-422 追加 = 5 axis の目標値 SSOT
155
+ ARROW_ENDPOINT_CENTER_TOL,
156
+ ROW_GAP_VARIANCE_TOL,
157
+ COLUMN_GAP_VARIANCE_TOL,
158
+ LANE_BORDER_CLEARANCE_TOL,
159
+ // CAR-424 追加 = near-collision policy SSOT (旧 collisions.ts CLEARANCE_POLICY を集約)
160
+ NEAR_COLLISION_POLICY,
161
+ NEAR_COLLISION_DEFAULT_MIN,
162
+ requiredNearClearance,
163
+ // #387 追加 = 下流が「この種別に rows を持たせてよいか」 「行が収まる寸法はいくつか」 を
164
+ // engine と同じ式で決められるようにする。 baseline / 行送り / descender は内部実装値なので
165
+ // 出さない (出すと下流が式を組み直せてしまい、 SSOT から逸脱する余地ができる)。
166
+ rendersRows,
167
+ requiredRowsHeight,
168
+ } from "./layout/spec";
169
+ // #387 追加 = rows の内容から必要 width を出す。 下流が preset の固定 w を rows に合わせて
170
+ // 広げる際に、 engine と同じ式を使えるようにする。
171
+ export { requiredRowsWidth } from "./kinds/row-align";
172
+ // chain 伝搬 shift resolver (CAR-421 追加、 opt-in export)
173
+ // CAR-426 で edge-label 用の resolveEdgeLabelOverlapsWithChain を追加、 label 層の
174
+ // chain 伝搬解消を担当 (node 層は resolveOverlapsWithChain と役割分担)。
175
+ // CAR-482 で resolveEdgeLabelOverlapsWithChainAndPropagate を追加、 node / lane-label 連鎖 shift 拡張版。
176
+ export {
177
+ resolveOverlapsWithChain,
178
+ resolveEdgeLabelOverlapsWithChain,
179
+ resolveEdgeLabelOverlapsWithChainAndPropagate,
180
+ } from "./layout/collisions";
181
+ // predict-bbox = engine 予測 bbox の world 単位計算 SSOT (副次係数 COEFF 撤廃用)
182
+ export {
183
+ predictLabelBBoxWorld,
184
+ predictNodeBBoxWorld,
185
+ FONT_RENDER_TOLERANCE_WORLD,
186
+ LABEL_SIZE_TOLERANCE_WORLD,
187
+ bboxDiffWorld,
188
+ } from "./layout/predict-bbox";
189
+ export { swimlane, flow, sequence, topology, er, stateMachine, infrastructure, classDiagram, tree, userJourney, mindMap, mindMapRadial, funnel, quadrant, chart, gantt, flowchart, network, stateMachine2 } from "./presets";
190
+ // Text DSL は @cardenelabs/dragon に切出済 (cdl は engine only)
191
+ export type {
192
+ SwimlanePreset,
193
+ FlowPreset,
194
+ FlowBuilder,
195
+ FlowStepInput,
196
+ SequencePreset,
197
+ SequenceBuilder,
198
+ SequenceStep,
199
+ TopologyPreset,
200
+ TopologyBuilder,
201
+ TopologyGroupBuilder,
202
+ TopologyContainer,
203
+ TopologyConnection,
204
+ ErPreset,
205
+ ErBuilder,
206
+ ErEntity,
207
+ ErRelation,
208
+ ErRelationCardinality,
209
+ StateMachinePreset,
210
+ StateMachineBuilder,
211
+ FsmState,
212
+ FsmTransition,
213
+ InfrastructurePreset,
214
+ InfrastructureBuilder,
215
+ InfraNode,
216
+ InfraConnection,
217
+ ClassDiagramPreset,
218
+ ClassDiagramBuilder,
219
+ UmlClass,
220
+ UmlRelation,
221
+ ClassRelationType,
222
+ TreePreset,
223
+ TreeBuilder,
224
+ TreeNode,
225
+ UserJourneyPreset,
226
+ UserJourneyBuilder,
227
+ JourneyStep,
228
+ JourneyEmotion,
229
+ MindMapPreset,
230
+ MindMapBuilder,
231
+ MindBranch,
232
+ MindMapRadialPreset,
233
+ MindMapRadialBuilder,
234
+ MindMapRadialBranch,
235
+ FunnelPreset,
236
+ FunnelBuilder,
237
+ FunnelStage,
238
+ QuadrantPreset,
239
+ QuadrantBuilder,
240
+ QuadrantItem,
241
+ QuadrantQuadrantLabel,
242
+ ChartPreset,
243
+ ChartBuilder,
244
+ ChartDatum,
245
+ ChartType,
246
+ GanttPreset,
247
+ GanttBuilder,
248
+ GanttTask,
249
+ FlowchartPreset,
250
+ FlowchartBuilder,
251
+ FlowchartNode,
252
+ FlowchartEdge,
253
+ FlowchartNodeShape,
254
+ NetworkPreset,
255
+ NetworkBuilder,
256
+ NetworkDevice,
257
+ NetworkLink,
258
+ NetworkDeviceKind,
259
+ StateMachine2Preset,
260
+ StateMachine2Builder,
261
+ FsmStateNested,
262
+ FsmTransitionExt,
263
+ } from "./presets";
264
+ export type {
265
+ CdlDiagram,
266
+ CdlEdge,
267
+ CdlLane,
268
+ CdlNode,
269
+ CdlPhase,
270
+ CdlState,
271
+ EdgeStyle,
272
+ LaidDiagram,
273
+ LaidEdge,
274
+ LaidLane,
275
+ LaidNode,
276
+ NodeKind,
277
+ Side,
278
+ Tone,
279
+ } from "./types";
280
+ // 値としての tone 一覧。 downstream (dragon の parser 等) が受理できる色名の集合を
281
+ // 手書きせずに済ませるため公開する。
282
+ // 値としての tone / kind 一覧。 downstream (dragon の記法一覧 / parser 等) が
283
+ // 受理できる値の集合を手書きせずに済ませるため公開する。
284
+ export { TONES, NODE_KINDS } from "./types";