@markdy/core 0.7.29 → 0.8.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 (4) hide show
  1. package/README.md +21 -16
  2. package/dist/index.d.ts +190 -188
  3. package/dist/index.js +698 -1213
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -33,20 +33,23 @@ pnpm add @markdy/core
33
33
 
34
34
  ```typescript
35
35
  import { parse, ParseError } from "@markdy/core";
36
- import type { SceneAST } from "@markdy/core";
36
+ import type { DiagramAST } from "@markdy/core";
37
37
 
38
38
  const source = `
39
- scene width=600 height=300 bg=white
40
- actor label = text("Hello") at (50, 130) size 40 opacity 0
41
- @0.3: label.fade_in(dur=0.6)
39
+ scene "Request" theme=midnight
40
+ browser Web
41
+ service API
42
+ beat main:
43
+ show $nodes
44
+ Web -> API "GET /users"
42
45
  `;
43
46
 
44
47
  try {
45
- const ast: SceneAST = parse(source);
48
+ const ast: DiagramAST = parse(source);
46
49
 
47
- console.log(ast.meta); // { width: 600, height: 300, fps: 30, bg: "white", duration: 0.9 }
48
- console.log(ast.actors); // { label: { type: "text", args: ["Hello"], x: 50, y: 130, ... } }
49
- console.log(ast.events); // [{ time: 0.3, actor: "label", action: "fade_in", ... }]
50
+ console.log(ast.meta); // { width: 1280, height: 720, fps: 60, theme: "midnight", direction: "LR", title: "Request" }
51
+ console.log(ast.nodes); // { Web: { kind: "browser", ... }, API: { kind: "service", ... } }
52
+ console.log(ast.beats); // [{ name: "main", cues: [...] }]
50
53
  } catch (e) {
51
54
  if (e instanceof ParseError) {
52
55
  console.error(`Line ${e.line}: ${e.message}`);
@@ -58,15 +61,17 @@ try {
58
61
 
59
62
  | Export | Type | Description |
60
63
  |---|---|---|
61
- | `parse` | `(source: string) => SceneAST` | Parse MarkdyScript source into an AST |
64
+ | `parse` | `(source, opts?) => DiagramAST` | Parse MarkdyScript source into a diagram AST |
65
+ | `compile` | `(ast) => RenderPlan` | Lay out nodes, route edges, and schedule cues |
66
+ | `parseAndCompile` | `(source) => { ast, plan }` | Parse and compile in one call |
62
67
  | `ParseError` | class | Error with `.line` number for diagnostics |
63
- | `SceneAST` | type | Complete scene representation |
64
- | `SceneMeta` | type | Scene configuration (width, height, bg, etc.) |
65
- | `AssetDef` | type | Asset declaration (image or icon) |
66
- | `ActorDef` | type | Actor declaration (type, position, modifiers) |
67
- | `TimelineEvent` | type | Timeline event (time, actor, action, params) |
68
- | `TemplateDef` | type | User-defined actor template |
69
- | `SequenceDef` | type | User-defined animation sequence |
68
+ | `DiagramAST` | type | Parsed scene: meta, nodes, edges, groups, patterns, beats |
69
+ | `RenderPlan` | type | Positioned nodes, routed edges, timed cues, beat ranges |
70
+ | `SceneMeta` | type | Scene configuration (width, height, fps, theme, direction) |
71
+ | `NodeDecl` | type | Node declaration (kind, id, label, style) |
72
+ | `EdgeDecl` | type | Edge declaration (kind, from, to, label) |
73
+ | `BeatDecl` | type | Named beat with cues |
74
+ | `THEMES` / `resolveTheme` | tokens | Semantic theme palettes (`midnight`, `paper`) |
70
75
 
71
76
  ## Documentation
72
77
 
package/dist/index.d.ts CHANGED
@@ -1,219 +1,221 @@
1
1
  /**
2
- * AST types for MarkdyScript — the complete output of the parser.
2
+ * Diagram-native AST and RenderPlan types for MarkdyScript 0.8+.
3
3
  * Zero runtime dependencies.
4
4
  */
5
- type AssetDef = {
6
- type: "image" | "icon";
7
- value: string;
8
- };
9
- type ActorDef = {
10
- type: ActorType;
11
- /** Constructor arguments: asset name for sprite, display text for text/caption actors. */
12
- args: string[];
13
- x: number;
14
- y: number;
15
- scale?: number;
16
- rotate?: number;
17
- opacity?: number;
18
- /** Font size in pixels; applies to text actors (via the `size` modifier). */
19
- size?: number;
20
- /** Z-index for layering control (via the `z` modifier). */
21
- z?: number;
22
- /**
23
- * Semantic anchor for captions (`top`, `bottom`, `center`). Absent for
24
- * non-caption actors. The parser also fills `x` and `y` from the anchor
25
- * so renderers that don't understand the field still place the caption.
26
- */
27
- anchor?: "top" | "bottom" | "center";
28
- };
29
- type BuiltinActorType = "sprite" | "text" | "box" | "figure" | "caption";
30
- type ActorType = BuiltinActorType | (string & {});
31
- type TimelineEvent = {
32
- time: number;
33
- actor: string;
34
- action: string;
35
- params: Record<string, unknown>;
36
- line: number;
37
- /**
38
- * The `scene "title" { ... }` block this event belongs to, if any.
39
- * Undefined for events in the top-level scope.
40
- */
41
- chapter?: string;
42
- };
5
+ type LayoutDirection = "LR" | "RL" | "TB" | "BT";
6
+ type EdgeKind = "request" | "response" | "event" | "dependency";
43
7
  type SceneMeta = {
8
+ title?: string;
44
9
  width: number;
45
10
  height: number;
46
11
  fps: number;
47
- bg: string;
48
- /** Auto-computed from the last event + its dur param when not explicitly set. */
12
+ theme: string;
13
+ direction: LayoutDirection;
49
14
  duration?: number;
50
15
  };
51
- /**
52
- * A user-defined actor template (`def`).
53
- * Expands to an actor type + args at parse time — the renderer never sees it.
54
- */
55
- type TemplateDef = {
56
- /** Parameter names declared on the def line. */
57
- params: string[];
58
- /** The actor type this def expands to (e.g. "figure", "sprite"). */
59
- actorType: ActorDef["type"];
60
- /** Raw constructor arg tokens (may contain `${param}` references). */
61
- bodyArgs: string[];
16
+ type NodeDecl = {
17
+ kind: string;
18
+ id: string;
19
+ label: string;
20
+ style?: string;
21
+ props: Record<string, unknown>;
22
+ line: number;
62
23
  };
63
- /**
64
- * A user-defined reusable animation sequence (`seq`).
65
- * Expanded inline wherever `actor.play(seqName)` appears.
66
- */
67
- type SequenceDef = {
68
- /** Parameter names (excluding the implicit `$` target actor). */
69
- params: string[];
70
- /** Raw event lines with `@+offset` and `$` actor placeholder. */
71
- events: Array<{
72
- offset: number;
73
- action: string;
74
- paramsRaw: string;
75
- }>;
24
+ type EdgeDecl = {
25
+ id: string;
26
+ kind: EdgeKind;
27
+ from: string;
28
+ to: string;
29
+ label?: string;
30
+ props: Record<string, unknown>;
31
+ line: number;
76
32
  };
77
- /**
78
- * A `scene "title" { ... }` block — a named grouping of timeline events.
79
- * Start/end times are inclusive wall-clock seconds so renderers and
80
- * tooling can highlight the active chapter without re-walking events.
81
- */
82
- type Chapter = {
33
+ type GroupDecl = {
34
+ id: string;
35
+ label?: string;
36
+ members: string[];
37
+ props: Record<string, unknown>;
38
+ line: number;
39
+ };
40
+ type StyleDecl = {
83
41
  name: string;
84
- startTime: number;
85
- endTime: number;
86
- startLine: number;
42
+ props: Record<string, unknown>;
43
+ line: number;
87
44
  };
88
- /**
89
- * A non-fatal parse issue. Renderers should surface these via
90
- * `onWarning` so the author can fix the underlying cause; the
91
- * renderer otherwise no-ops the offending statement.
92
- */
93
- type ParseWarning = {
94
- kind: "unknown-action" | "unknown-modifier" | "unknown-scene-key" | "unknown-camera-action" | "unknown-preset" | "import-unresolved" | "preset-mixed" | "actor-count-threshold" | "label-overflow";
95
- message: string;
45
+ type FlowSegment = {
46
+ from: string;
47
+ op: EdgeKind;
48
+ to: string;
49
+ label?: string;
50
+ };
51
+ type Cue = {
52
+ kind: "flow";
53
+ segments: FlowSegment[];
54
+ dur?: number;
55
+ line: number;
56
+ } | {
57
+ kind: "show";
58
+ targets: string[];
59
+ stagger?: number;
60
+ dur?: number;
61
+ line: number;
62
+ } | {
63
+ kind: "hide";
64
+ targets: string[];
65
+ dur?: number;
66
+ line: number;
67
+ } | {
68
+ kind: "glow";
69
+ targets: string[];
70
+ color?: string;
71
+ strength?: number;
72
+ dur?: number;
73
+ line: number;
74
+ } | {
75
+ kind: "focus";
76
+ targets: string[];
77
+ zoom?: number;
78
+ dur?: number;
79
+ line: number;
80
+ } | {
81
+ kind: "use";
82
+ pattern: string;
83
+ args: Record<string, string>;
84
+ line: number;
85
+ } | {
86
+ kind: "parallel";
87
+ cues: Cue[];
96
88
  line: number;
97
89
  };
98
- /**
99
- * An `import "path.markdy" as ns` declaration. Parsing records the
100
- * intent; the host (CLI, bundler) resolves the path and may supply
101
- * pre-parsed ASTs via the `parse(..., { imports })` option.
102
- */
103
- type ImportDecl = {
104
- path: string;
105
- namespace: string;
90
+ type BeatDecl = {
91
+ name: string;
92
+ label?: string;
93
+ cues: Cue[];
94
+ dur?: number;
106
95
  line: number;
107
96
  };
108
- type SceneAST = {
97
+ type PatternDecl = {
98
+ name: string;
99
+ params: string[];
100
+ body: Cue[];
101
+ line: number;
102
+ };
103
+ type Diagnostic = {
104
+ severity: "error" | "warning";
105
+ message: string;
106
+ line: number;
107
+ column?: number;
108
+ };
109
+ type DiagramAST = {
109
110
  meta: SceneMeta;
110
- assets: Record<string, AssetDef>;
111
- actors: Record<string, ActorDef>;
112
- events: TimelineEvent[];
113
- /** User-defined actor templates — kept in AST for tooling/inspection. */
114
- defs: Record<string, TemplateDef>;
115
- /** User-defined sequences — kept in AST for tooling/inspection. */
116
- seqs: Record<string, SequenceDef>;
117
- /** User-defined variables — kept in AST for tooling/inspection. */
118
- vars: Record<string, string>;
119
- /**
120
- * Named actor groups, in declaration order, mapping group name to member
121
- * actor names. Groups fan out into per-actor events at parse time, so the
122
- * renderer never sees them — this is kept for tooling and inspection.
123
- */
111
+ styles: Record<string, StyleDecl>;
112
+ nodes: Record<string, NodeDecl>;
113
+ edges: EdgeDecl[];
114
+ groups: Record<string, GroupDecl>;
115
+ patterns: Record<string, PatternDecl>;
116
+ beats: BeatDecl[];
117
+ diagnostics: Diagnostic[];
118
+ };
119
+ type ThemeTokens = {
120
+ name: string;
121
+ canvas: string;
122
+ surface: string;
123
+ surfaceRaised: string;
124
+ border: string;
125
+ text: string;
126
+ textMuted: string;
127
+ gridMinor: string;
128
+ gridMajor: string;
129
+ vignette: string;
130
+ accent: string;
131
+ roles: Record<string, string>;
132
+ edges: Record<EdgeKind, string>;
133
+ };
134
+ type PositionedNode = {
135
+ id: string;
136
+ kind: string;
137
+ role: string;
138
+ label: string;
139
+ x: number;
140
+ y: number;
141
+ width: number;
142
+ height: number;
143
+ style?: Record<string, unknown>;
144
+ opacity: number;
145
+ };
146
+ type RoutedEdge = {
147
+ id: string;
148
+ kind: EdgeKind;
149
+ from: string;
150
+ to: string;
151
+ label?: string;
152
+ };
153
+ type TimedCue = {
154
+ start: number;
155
+ duration: number;
156
+ kind: "show" | "hide" | "flow" | "glow" | "focus";
157
+ targets: string[];
158
+ edgeId?: string;
159
+ segments?: FlowSegment[];
160
+ params: Record<string, unknown>;
161
+ beat: string;
162
+ };
163
+ type BeatRange = {
164
+ name: string;
165
+ label?: string;
166
+ start: number;
167
+ end: number;
168
+ };
169
+ type RenderPlan = {
170
+ meta: SceneMeta;
171
+ theme: ThemeTokens;
172
+ title: string;
173
+ nodes: PositionedNode[];
174
+ edges: RoutedEdge[];
175
+ cues: TimedCue[];
176
+ beats: BeatRange[];
124
177
  groups: Record<string, string[]>;
125
- /** Named chapter blocks in author order. Empty when no chapters were used. */
126
- chapters: Chapter[];
127
- /** Soft parse issues. Always present; empty in the happy path. */
128
- warnings: ParseWarning[];
129
- /** `import` declarations in author order. Always present; empty when none were used. */
130
- imports: ImportDecl[];
178
+ duration: number;
131
179
  };
132
180
 
133
- declare class ParseError extends Error {
134
- readonly line: number;
135
- constructor(message: string, line: number);
136
- }
137
- interface ParseOptions {
138
- /**
139
- * Pre-parsed ASTs for `import "path" as ns` declarations. The host
140
- * (CLI, bundler) is responsible for reading files from disk and
141
- * parsing them; the parser itself is pure.
142
- *
143
- * When an import's namespace is present here, its `vars`, `defs`,
144
- * and `seqs` are merged into the importing AST under the
145
- * `<ns>.<name>` prefix. Missing namespaces produce a soft warning.
146
- */
147
- imports?: Record<string, SceneAST>;
148
- /**
149
- * Emit a non-fatal warning when actor count exceeds this threshold.
150
- * Set to <= 0 to disable.
151
- */
152
- actorCountWarningThreshold?: number;
153
- /**
154
- * Emit a non-fatal warning when actor labels exceed this length.
155
- * Applies to the first constructor arg when it is a string.
156
- * Set to <= 0 to disable.
157
- */
158
- labelLengthWarningThreshold?: number;
159
- /**
160
- * Internal flag — distinguishes a top-level call from a recursive
161
- * call used to expand a `preset`. Preset expansion bypasses the
162
- * "mixed preset and other statements" warning because the expanded
163
- * source is the only content.
164
- */
165
- _fromPreset?: boolean;
166
- }
167
- declare function parse(source: string, opts?: ParseOptions): SceneAST;
181
+ declare function compilePlan(ast: DiagramAST, theme: ThemeTokens): RenderPlan;
168
182
 
169
183
  /**
170
- * MarkdyScript built-in presets.
171
- *
172
- * A preset is a string template that expands at parse time into canonical
173
- * MarkdyScript. The renderer never sees preset statements — by the time
174
- * parsing reaches the actor/event stage, the preset has been replaced
175
- * with its expansion.
176
- *
177
- * Design rules:
178
- * 1. Each preset is self-contained — it declares its own `scene`,
179
- * actors, and timeline.
180
- * 2. Presets are short. The value is in `preset <name>` being a
181
- * one-liner that expands to a scaffold the user can then tweak.
182
- * 3. Presets share a common visual grammar so a feed of them feels
183
- * like a family, not a collage.
184
+ * Diagram-native MarkdyScript parser and compiler.
184
185
  */
185
- type PresetFn = (args: string[]) => string;
186
- declare const PRESETS: Record<string, PresetFn>;
187
- declare const PRESET_NAMES: readonly string[];
188
186
 
189
- /**
190
- * The canonical vocabulary of the language.
191
- *
192
- * These arrays are the single source of truth for every tool that needs to
193
- * know what Markdy understands — the parser, the language server, the
194
- * playground's syntax highlighter, and the renderer's handler-coverage test.
195
- * Anything that hard-codes its own copy will silently drift out of date, so
196
- * import from here instead.
197
- */
198
- declare const BUILTIN_ACTOR_TYPES: readonly BuiltinActorType[];
199
- /** Actions valid on every actor type. */
200
- declare const UNIVERSAL_ACTION_NAMES: readonly ["enter", "exit", "move", "spring", "follow_path", "fade_in", "fade_out", "scale", "rotate", "shake", "pulse", "glow", "ripple", "blur", "line_reveal", "mask", "parallax", "say", "throw", "play"];
201
- /**
202
- * Actions that require a `figure` actor. Applying one to any other actor
203
- * type is a hard `ParseError`, not a soft warning — it's always a mistake.
204
- */
205
- declare const FIGURE_ONLY_ACTION_NAMES: readonly ["punch", "kick", "wave", "nod", "jump", "bounce", "face", "rotate_part", "pose"];
206
- /** Actions valid on the reserved `camera` actor. */
207
- declare const CAMERA_ACTION_NAMES: readonly ["pan", "zoom", "shake"];
208
- type ActorPack = {
209
- name: string;
210
- actors: readonly string[];
211
- actions?: Record<string, readonly string[]>;
187
+ declare class ParseError extends Error {
188
+ readonly line: number;
189
+ readonly column?: number;
190
+ constructor(message: string, line: number, column?: number);
191
+ }
192
+ type ParseResult = {
193
+ ast: DiagramAST;
194
+ plan: RenderPlan;
195
+ };
196
+ type ParseOptions = {
197
+ /** When true, only parse without compiling layout/schedule. */
198
+ parseOnly?: boolean;
212
199
  };
213
- declare function registerActorPack(pack: ActorPack): void;
200
+ declare function parse(source: string, opts?: ParseOptions): DiagramAST;
201
+ declare function compile(ast: DiagramAST): RenderPlan;
202
+ declare function parseAndCompile(source: string): ParseResult;
203
+
204
+ declare const THEMES: Record<string, ThemeTokens>;
205
+ declare function resolveTheme(name: string): ThemeTokens;
206
+
207
+ declare const NODE_KINDS: Set<string>;
208
+ declare const EDGE_OPERATORS: Record<string, "request" | "response" | "event" | "dependency">;
209
+ declare const BEAT_CUE_KEYWORDS: Set<string>;
210
+ declare const SCENE_KEYS: Set<string>;
211
+ declare function nodeRole(kind: string): string;
212
+ declare function humanizeId(id: string): string;
213
+ /** Node kind aliases for concise authoring. */
214
+ declare const NODE_ALIASES: Record<string, string>;
215
+ declare function canonicalNodeKind(kind: string): string;
214
216
 
215
217
  declare const TECHNICAL_NODE_TYPES: readonly ["service", "api", "microservice", "backend", "server", "worker", "job", "scheduler", "cron", "batch", "function", "lambda", "edge", "controller", "handler", "repository", "module", "package", "library", "sdk", "cli", "runtime", "process", "client", "user", "browser", "web", "mobile", "desktop", "frontend", "app", "page", "view", "component", "store", "db", "database", "sql", "nosql", "table", "index", "warehouse", "lake", "object_store", "bucket", "blob", "volume", "disk", "search", "cache", "queue", "topic", "stream", "event", "event_bus", "bus", "broker", "pubsub", "kafka", "producer", "consumer", "dead_letter", "dlq", "webhook", "cloud", "region", "vpc", "subnet", "network", "internet", "dns", "cdn", "proxy", "gateway", "api_gateway", "load_balancer", "reverse_proxy", "router", "switch", "nat", "firewall", "waf", "vpn", "bastion", "container", "cluster", "pod", "node", "deployment", "replicaset", "statefulset", "daemonset", "namespace", "ingress", "service_mesh", "sidecar", "image", "registry", "docker", "compose", "helm", "chart", "configmap", "pvc", "auth", "identity", "oauth", "oidc", "jwt", "session", "policy", "role", "permission", "vault", "secret", "key", "certificate", "repo", "branch", "commit", "pipeline", "workflow", "runner", "build", "test", "artifact", "deploy", "release", "environment", "preview", "monitor", "metrics", "logs", "trace", "alert", "dashboard", "probe", "slo", "start", "end", "state", "decision", "condition", "step", "loop", "sequence", "participant", "replica", "shard", "leader", "follower", "quorum", "consensus", "lock", "class", "interface", "method", "object", "enum", "type"];
216
218
  declare const VISUAL_PRIMITIVE_TYPES: readonly ["panel", "surface", "terminal", "metric", "stat", "grid", "matrix", "lane", "track", "marker", "dot", "token_strip", "chips", "glyph_card", "glyph"];
217
219
  declare const TECHNICAL_NODE_KINDS: Record<(typeof TECHNICAL_NODE_TYPES)[number], string>;
218
220
 
219
- export { type ActorDef, type ActorPack, type ActorType, type AssetDef, BUILTIN_ACTOR_TYPES, type BuiltinActorType, CAMERA_ACTION_NAMES, type Chapter, FIGURE_ONLY_ACTION_NAMES, type ImportDecl, PRESETS, PRESET_NAMES, ParseError, type ParseOptions, type ParseWarning, type PresetFn, type SceneAST, type SceneMeta, type SequenceDef, TECHNICAL_NODE_KINDS, TECHNICAL_NODE_TYPES, type TemplateDef, type TimelineEvent, UNIVERSAL_ACTION_NAMES, VISUAL_PRIMITIVE_TYPES, parse, registerActorPack };
221
+ export { BEAT_CUE_KEYWORDS, type BeatDecl, type BeatRange, type Cue, type Diagnostic, type DiagramAST, EDGE_OPERATORS, type EdgeDecl, type EdgeKind, type FlowSegment, type GroupDecl, type LayoutDirection, NODE_ALIASES, NODE_KINDS, type NodeDecl, ParseError, type ParseOptions, type ParseResult, type PatternDecl, type PositionedNode, type RenderPlan, type RoutedEdge, SCENE_KEYS, type SceneMeta, type StyleDecl, TECHNICAL_NODE_KINDS, TECHNICAL_NODE_TYPES, THEMES, type ThemeTokens, type TimedCue, VISUAL_PRIMITIVE_TYPES, canonicalNodeKind, compile, compilePlan, humanizeId, nodeRole, parse, parseAndCompile, resolveTheme };