@cardenelabs/dragon 0.8.0 → 0.9.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cardenelabs/dragon",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Dragon — Mermaid 感覚で animated SVG を生成する Text DSL。 cdl engine を内部利用。",
5
5
  "license": "MIT",
6
6
  "author": "cardene777",
@@ -56,7 +56,7 @@
56
56
  "prepublishOnly": "pnpm run typecheck && pnpm run test && pnpm run build"
57
57
  },
58
58
  "dependencies": {
59
- "@cardenelabs/cdl": "^0.9.0"
59
+ "@cardenelabs/cdl": "^0.11.0"
60
60
  },
61
61
  "peerDependencies": {
62
62
  "react": "^19.0.0",
package/src/compile.ts CHANGED
@@ -17,6 +17,7 @@ import {
17
17
  applyDerivedValues, parseFormula,
18
18
  } from "@cardenelabs/cdl";
19
19
  import { parseFocusEntry } from "./focus";
20
+ import { DRAW_TARGETS } from "./v05/parser";
20
21
  import { isColorValue, stripExternalPaint } from "./color";
21
22
  import {
22
23
  MAX_INPUT_ELEMENTS,
@@ -91,7 +92,11 @@ export type CompileNotice = {
91
92
  // 最上位に `eyebrow:` を書いたが、 箱ごとに分かれる図種で相手が決まらなかった (#1247)
92
93
  | "eyebrow-not-honored"
93
94
  // 静止した `type: flow` で、書いた矢印の端が使われなかった (#1269)
94
- | "flow-endpoint-not-honored";
95
+ | "flow-endpoint-not-honored"
96
+ // 起点から描く動きを持たない図種で段に `draw:` を書いた (#1312)
97
+ | "draw-not-honored"
98
+ // `draw:` の語がその図種と食い違う (`type: bar` に `draw: pie`、 #1314)
99
+ | "draw-target-mismatch";
95
100
  /** 対象の名前。 光らせる相手なら書かれた指定そのまま */
96
101
  actor: string;
97
102
  /** 書かれていた行 */
@@ -212,6 +217,7 @@ export function compileToCdl(doc: DslDocument, opts?: CompileToCdlOpts): CdlDiag
212
217
  reportFlowEndpointNotHonored(doc, 分けた.元の名前, opts?.onNotice);
213
218
  reportLaneNotHonored(書いたまま, opts?.onNotice);
214
219
  reportDocEyebrowNotHonored(書いたまま, opts?.onNotice);
220
+ reportDrawNotHonored(書いたまま, opts?.onNotice);
215
221
  reportChartFieldsNotHonored(書いたまま, opts?.onNotice);
216
222
  reportAxesNotHonored(書いたまま, opts?.onNotice);
217
223
  // `位置: Web の右` を実際の配置から絶対座標に直す。 以降は座標を直接書いた時と同じ経路
@@ -553,6 +559,52 @@ function reportDocEyebrowNotHonored(doc: DslDocument, onNotice?: (n: CompileNoti
553
559
  });
554
560
  }
555
561
 
562
+ /**
563
+ * 左から描く動きを持たない図種で段に `draw:` を書いた時に伝える (#1312)。
564
+ *
565
+ * 描く動きを持つのは今のところ折れ線だけ。 他の図種では書いても何も起きないため、
566
+ * 黙って捨てると「書いたのに伸びない」 が手掛かりなしで起きる。
567
+ *
568
+ * 段ごとに知らせる = 5 段のうち 1 段だけに書いた形で、どの段が効いていないかを読めるようにする。
569
+ */
570
+ function reportDrawNotHonored(doc: DslDocument, onNotice?: (n: CompileNotice) => void): void {
571
+ if (!onNotice) return;
572
+ for (const phase of doc.animate?.phases ?? []) {
573
+ if (phase.draw === undefined) continue;
574
+ // 段の `pos` は `- step:` の行を指す。 書いた行に辿り着けるよう `drawPos` を優先する
575
+ const line = phase.drawPos?.line ?? phase.pos?.line ?? 0;
576
+ if (!DRAWABLE_DOC_TYPES.has(doc.type)) {
577
+ onNotice({
578
+ kind: "draw-not-honored",
579
+ actor: phase.name,
580
+ line,
581
+ message: `段 "${phase.name}" に書いた draw は効きません (type: ${doc.type} は起点から描く動きを持ちません)`,
582
+ hint: `draw が効くのは type: ${[...DRAWABLE_DOC_TYPES].join(" / ")} です`,
583
+ });
584
+ continue;
585
+ }
586
+ // 語が別の図種を指している形 (#1314)。 図は描けるので誤りにはしない
587
+ const 語の図種 = DRAW_TARGETS.get(phase.draw);
588
+ if (語の図種 !== undefined && 語の図種 !== doc.type) {
589
+ onNotice({
590
+ kind: "draw-target-mismatch",
591
+ actor: phase.name,
592
+ line,
593
+ message: `段 "${phase.name}" の draw: ${phase.draw} は type: ${doc.type} では効きません (${phase.draw} は type: ${語の図種} の図に書きます)`,
594
+ hint: `この図では draw: ${doc.type} と書いてください`,
595
+ });
596
+ }
597
+ }
598
+ }
599
+
600
+ /**
601
+ * 段の `draw:` が効く図種 (#1312 / #1314)。
602
+ *
603
+ * **語と図種の対応表から導く** (`DRAW_TARGETS`)。 一覧を写すと、語を足した時に片方だけ
604
+ * 古いまま残る。 描画側 (`cdl` の `CdlPhase.draw`) が対応する 3 種と一致する。
605
+ */
606
+ const DRAWABLE_DOC_TYPES: ReadonlySet<PresetType> = new Set<PresetType>(DRAW_TARGETS.values());
607
+
556
608
  /**
557
609
  * 縦列を選べる図種で、一部の箱だけが縦列を書いた時に伝える (#1263)。
558
610
  *
@@ -5563,12 +5615,24 @@ function injectPhasesFallback(diagram: CdlDiagram, doc: DslDocument): void {
5563
5615
  // phase 注入。 CdlPhase.tweens[].stateId / sets[].stateId で state 参照 (state ではない)。
5564
5616
  for (const p of doc.animate.phases) {
5565
5617
  const activateIds: string[] = [...resolveIds(p.highlight ?? [])];
5618
+ // `draw: line` を描画側の欄へ写す (#1312)。 相手は 1 箱で図全体を描く種別の箱で、
5619
+ // 折れ線は必ずこの形になるため名前を書かせずに引ける。
5620
+ //
5621
+ // **`activate` と兼ねない**。 描画側は焦点と別集合で持つ (`cdl#512`) = 焦点が当たり
5622
+ // 続ける図で毎段引き直しになるため。 書いた段だけが欄を持つ
5623
+ const drawIds =
5624
+ p.draw !== undefined &&
5625
+ DRAW_TARGETS.get(p.draw) === doc.type &&
5626
+ singleBoxNode !== undefined
5627
+ ? [singleBoxNode.id]
5628
+ : [];
5566
5629
  diagram.phases.push({
5567
5630
  id: slugify(p.name) || p.name,
5568
5631
  duration: p.durationMs,
5569
5632
  title: p.name,
5570
5633
  body: p.body ?? "",
5571
5634
  activate: activateIds,
5635
+ ...(drawIds.length > 0 ? { draw: drawIds } : {}),
5572
5636
  tweens: (p.tweens ?? []).map((t) => ({ stateId: t.state, from: t.from, to: t.to })),
5573
5637
  sets: (p.sets ?? []).map((s) => ({ stateId: s.state, value: s.value })),
5574
5638
  ...(p.badge ? { badge: p.badge } : {}),
package/src/index.ts CHANGED
@@ -13,16 +13,12 @@ export { compileToCdl } from "./compile";
13
13
  export type { CompileNotice } from "./compile";
14
14
  export { parseTextDslV05 } from "./v05";
15
15
  // 記法一覧が「実際に受け付ける値」 を実装から引くための公開。 手書きすると説明と実装がずれる。
16
- export { PRESET_TYPES, TOP_LEVEL_KEYS } from "./v05/parser";
16
+ export { DRAW_TARGETS, DRAW_WORDS, PRESET_TYPES, TOP_LEVEL_KEYS } from "./v05/parser";
17
17
  export { TONE_ALIAS, NODE_KIND_ALIAS } from "./keywords";
18
18
  export { lintDiagram, autoFix } from "./notation-lint";
19
19
  export type { LintIssue, LintReport, LintSeverity } from "./notation-lint";
20
20
  // canvas pivot 新 spec 図境界計算 helper (§diagram-boundary SSOT)
21
- export {
22
- computeDiagramBoundingBox,
23
- rectsOverlap,
24
- DIAGRAM_BOUNDARY_PADDING,
25
- } from "./canvas-bounds";
21
+ export { computeDiagramBoundingBox, rectsOverlap, DIAGRAM_BOUNDARY_PADDING } from "./canvas-bounds";
26
22
  export type { DiagramBoundingBox } from "./canvas-bounds";
27
23
  // 位置を相対で書くための解決。 組み立て側と画面側の両方が同じ規則を使うために公開する。
28
24
  export {
@@ -78,6 +74,10 @@ export { isColorValue, pointsOutside, stripExternalPaint } from "./color";
78
74
  // 別々に持つと、片方だけが読める本文ができる (実測 = `位置: '300,200"` が
79
75
  // 画面側では座標 300 として通り、組み立て側では読めない値として知らせが出た)
80
76
  export { stripQuotes } from "./v05/parser";
77
+
78
+ // 画面で色分けするための分解器 (#1310)。 色は持たず、種類名と位置だけを返す
79
+ export { 記法を分解する, JSONを分解する, 区間に広げる } from "./tokenize";
80
+ export type { トークン, トークンの種類 } from "./tokenize";
81
81
  // 大きすぎる入力を組み立てる前に止める上限 (#1005)。 画面側も同じ物差しで事前に知らせられるよう公開する。
82
82
  export {
83
83
  MAX_INPUT_ELEMENTS,
@@ -96,6 +96,8 @@ export { diagramJsonSchema } from "./schema";
96
96
  export type {
97
97
  DragonJson,
98
98
  JsonActor,
99
+ JsonActorNodeOverride,
100
+ JsonAxes,
99
101
  JsonStep,
100
102
  JsonPhase,
101
103
  JsonDslError,
@@ -204,15 +206,24 @@ function isV05Source(src: string): boolean {
204
206
  // 判定不足。 v0.4-specific syntax (`step "..." Xs` = colon なし step / `^\d+\.\s+` = 番号 flow) を
205
207
  // negative marker に追加。
206
208
  const V04_KEYWORDS = [
207
- // Japanese v0.4 専用 keyword (v0.5 は英語のみ)
208
- /^\s*タイトル\s*[::]/, // title (JA)
209
- /^\s*種類\s*[::]/, // type (JA)
210
- /^\s*登場人物\s*[::]/, // actors (JA)
211
- /^\s*流れ\s*[::]/, // flow (JA)
212
- /^\s*アニメーション\s*[::]/, // animation (JA)
213
- /^\s*動作\s*[::]/, // step (JA)
214
- /^\s*状態\s*[::]/, // state (JA)
215
- /^\s*ステップ\s*[「『]/, // step (JA)
209
+ // Japanese v0.4 専用 keyword (v0.5 は英語のみ)
210
+ //
211
+ // **字下げした行には当てない** (#1300)。 v0.4 の見出しは行頭に書くが、v0.5 の縦書き形は
212
+ // 必ず字下げする。 同じ語が「v0.4 の見出し」 と「v0.5 の箱の欄 / 見本の状態名」 の両方で
213
+ // 使われるため、`\s*` を許すと **正しい v0.5 の本文が旧 parser へ回る**。
214
+ //
215
+ // 実測 = `種類:` を箱の欄として縦に書いた本文と、見本の状態名が下の 7 語のいずれかである
216
+ // 本文が、いずれも v0.4 として読まれて別の行を指す誤りを返していた。
217
+ /^タイトル\s*[::]/, // title (JA)
218
+ /^種類\s*[::]/, // type (JA)
219
+ /^登場人物\s*[::]/, // actors (JA)
220
+ /^流れ\s*[::]/, // flow (JA)
221
+ /^アニメーション\s*[::]/, // animation (JA)
222
+ /^動作\s*[::]/, // step (JA)
223
+ /^状態\s*[::]/, // state (JA)
224
+ // 鉤括弧が続く形は v0.5 に無い (状態名は `ステップ: 5` の形しか取れない) ため、
225
+ // 字下げを許しても v0.5 と衝突しない。 v0.4 では `アニメーション:` の下に字下げして書く
226
+ /^\s*ステップ\s*[「『]/, // step (JA)
216
227
  // v0.4 English-specific syntax = colon なし step (v0.5 は step: 必須)
217
228
  /^\s*step\s+"[^"]+"\s+[\d.]+\s*s\b/,
218
229
  /^\s*step\s+'[^']+'\s+[\d.]+\s*s\b/,