@markdy/core 0.8.8 → 0.8.9
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/dist/index.d.ts +3 -1
- package/dist/index.js +116 -21
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -222,6 +222,8 @@ declare function resolveTheme(name: string): ThemeTokens;
|
|
|
222
222
|
|
|
223
223
|
declare const NODE_KINDS: Set<string>;
|
|
224
224
|
declare const EDGE_OPERATORS: Record<string, "request" | "response" | "event" | "dependency">;
|
|
225
|
+
/** Natural-language cue synonyms that AIs reach for, mapped to real cues. */
|
|
226
|
+
declare const CUE_ALIASES: Record<string, string>;
|
|
225
227
|
declare const BEAT_CUE_KEYWORDS: Set<string>;
|
|
226
228
|
declare const SCENE_KEYS: Set<string>;
|
|
227
229
|
declare function nodeRole(kind: string): string;
|
|
@@ -234,4 +236,4 @@ declare const TECHNICAL_NODE_TYPES: readonly ["service", "api", "microservice",
|
|
|
234
236
|
declare const VISUAL_PRIMITIVE_TYPES: readonly ["panel", "surface", "terminal", "metric", "stat", "grid", "matrix", "lane", "track", "marker", "dot", "token_strip", "chips", "glyph_card", "glyph"];
|
|
235
237
|
declare const TECHNICAL_NODE_KINDS: Record<(typeof TECHNICAL_NODE_TYPES)[number], string>;
|
|
236
238
|
|
|
237
|
-
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 };
|
|
239
|
+
export { BEAT_CUE_KEYWORDS, type BeatDecl, type BeatRange, CUE_ALIASES, 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 };
|
package/dist/index.js
CHANGED
|
@@ -350,7 +350,20 @@ var EDGE_OPERATORS = {
|
|
|
350
350
|
"--": "dependency"
|
|
351
351
|
};
|
|
352
352
|
var RESERVED_SELECTORS = /* @__PURE__ */ new Set(["$title", "$nodes", "$edges"]);
|
|
353
|
-
var
|
|
353
|
+
var CUE_ALIASES = {
|
|
354
|
+
pulse: "focus",
|
|
355
|
+
highlight: "glow",
|
|
356
|
+
emphasize: "glow"
|
|
357
|
+
};
|
|
358
|
+
var BEAT_CUE_KEYWORDS = /* @__PURE__ */ new Set([
|
|
359
|
+
"show",
|
|
360
|
+
"hide",
|
|
361
|
+
"glow",
|
|
362
|
+
"focus",
|
|
363
|
+
"frame",
|
|
364
|
+
"use",
|
|
365
|
+
...Object.keys(CUE_ALIASES)
|
|
366
|
+
]);
|
|
354
367
|
var SCENE_KEYS = /* @__PURE__ */ new Set(["width", "height", "fps", "theme", "duration", "direction", "layout"]);
|
|
355
368
|
function nodeRole(kind) {
|
|
356
369
|
return TECHNICAL_NODE_KINDS[kind] ?? "compute";
|
|
@@ -777,7 +790,9 @@ function stripComment(line) {
|
|
|
777
790
|
}
|
|
778
791
|
if (inString) continue;
|
|
779
792
|
if (ch === "/" && line[i + 1] === "/") return line.slice(0, i);
|
|
780
|
-
if (ch === "#" && (i === 0 || /\s/.test(line[i - 1]))
|
|
793
|
+
if (ch === "#" && (i === 0 || /\s/.test(line[i - 1])) && (i + 1 >= line.length || /\s/.test(line[i + 1]))) {
|
|
794
|
+
return line.slice(0, i);
|
|
795
|
+
}
|
|
781
796
|
}
|
|
782
797
|
return line;
|
|
783
798
|
}
|
|
@@ -905,9 +920,41 @@ function stripCueProps(raw, keys) {
|
|
|
905
920
|
}
|
|
906
921
|
return raw.trim();
|
|
907
922
|
}
|
|
923
|
+
function tokenizeFlowChain(line) {
|
|
924
|
+
const parts = [];
|
|
925
|
+
let current = "";
|
|
926
|
+
let inString = false;
|
|
927
|
+
let escaped = false;
|
|
928
|
+
for (let i = 0; i < line.length; i++) {
|
|
929
|
+
const ch = line[i];
|
|
930
|
+
if (inString) {
|
|
931
|
+
current += ch;
|
|
932
|
+
if (escaped) escaped = false;
|
|
933
|
+
else if (ch === "\\") escaped = true;
|
|
934
|
+
else if (ch === '"') inString = false;
|
|
935
|
+
continue;
|
|
936
|
+
}
|
|
937
|
+
if (ch === '"') {
|
|
938
|
+
inString = true;
|
|
939
|
+
current += ch;
|
|
940
|
+
continue;
|
|
941
|
+
}
|
|
942
|
+
const op = line.slice(i, i + 2);
|
|
943
|
+
if (op === "->" || op === "<-" || op === "~>" || op === "--") {
|
|
944
|
+
if (current.trim()) parts.push(current.trim());
|
|
945
|
+
parts.push(op);
|
|
946
|
+
current = "";
|
|
947
|
+
i += 1;
|
|
948
|
+
continue;
|
|
949
|
+
}
|
|
950
|
+
current += ch;
|
|
951
|
+
}
|
|
952
|
+
if (current.trim()) parts.push(current.trim());
|
|
953
|
+
return parts;
|
|
954
|
+
}
|
|
908
955
|
function parseFlowChain(line, lineNo) {
|
|
909
956
|
const segments = [];
|
|
910
|
-
const parts = line
|
|
957
|
+
const parts = tokenizeFlowChain(line);
|
|
911
958
|
if (parts.length < 3) {
|
|
912
959
|
throw new ParseError(`expected flow chain like A -> B "label"`, lineNo);
|
|
913
960
|
}
|
|
@@ -966,7 +1013,8 @@ function parseCueLine(line, lineNo) {
|
|
|
966
1013
|
};
|
|
967
1014
|
}
|
|
968
1015
|
const [head, ...rest] = trimmed.split(/\s+/);
|
|
969
|
-
const
|
|
1016
|
+
const rawKeyword = head.toLowerCase();
|
|
1017
|
+
const keyword = CUE_ALIASES[rawKeyword] ?? rawKeyword;
|
|
970
1018
|
if (keyword === "show" || keyword === "hide") {
|
|
971
1019
|
const targetRaw = stripCueProps(rest.join(" "), ["dur", "stagger"]);
|
|
972
1020
|
return {
|
|
@@ -1029,7 +1077,7 @@ function parseCueLine(line, lineNo) {
|
|
|
1029
1077
|
}
|
|
1030
1078
|
return { kind: "use", pattern: m[1], args, line: lineNo };
|
|
1031
1079
|
}
|
|
1032
|
-
throw new ParseError(`unknown cue '${head}'`, lineNo);
|
|
1080
|
+
throw new ParseError(`unknown cue '${head}'; use show, hide, glow, focus, frame, or use`, lineNo);
|
|
1033
1081
|
}
|
|
1034
1082
|
function expandPatternCues(cues, patterns, line) {
|
|
1035
1083
|
const out = [];
|
|
@@ -1128,20 +1176,49 @@ function normalizeCueBlocks(blocks) {
|
|
|
1128
1176
|
return normalized;
|
|
1129
1177
|
}
|
|
1130
1178
|
function unsupportedSyntaxMessage(line) {
|
|
1131
|
-
if (/^var\s+/.test(line)) {
|
|
1132
|
-
return "unsupported variable declaration; use scene properties and style declarations instead";
|
|
1133
|
-
}
|
|
1134
1179
|
if (/^actor\s+/.test(line) || /\bfigure\s*\(/.test(line) || /\bbox\s*\(/.test(line) || /\bat\s*\(/.test(line)) {
|
|
1135
1180
|
return "unsupported manual drawing syntax; declare architecture nodes like service API, cache Redis, and database DB";
|
|
1136
1181
|
}
|
|
1137
1182
|
if (/^@\+?\d/.test(line)) {
|
|
1138
1183
|
return "unsupported timeline command; put flow and cue lines inside beat blocks";
|
|
1139
1184
|
}
|
|
1140
|
-
if (/^camera
|
|
1185
|
+
if (/^camera\b/.test(line)) {
|
|
1141
1186
|
return "unsupported camera command; use frame NodeOrGroup zoom=... inside a beat";
|
|
1142
1187
|
}
|
|
1143
1188
|
return null;
|
|
1144
1189
|
}
|
|
1190
|
+
var RESERVED_VAR_NAMES = /* @__PURE__ */ new Set(["nodes", "title", "edges"]);
|
|
1191
|
+
function extractVars(blocks, diagnostics) {
|
|
1192
|
+
const vars = /* @__PURE__ */ new Map();
|
|
1193
|
+
const rest = [];
|
|
1194
|
+
for (const block of blocks) {
|
|
1195
|
+
if (!/^var\b/.test(block.text)) {
|
|
1196
|
+
rest.push(block);
|
|
1197
|
+
continue;
|
|
1198
|
+
}
|
|
1199
|
+
const m = block.text.match(/^var\s+([A-Za-z_]\w*)\s*=\s*(.+)$/);
|
|
1200
|
+
if (!m) throw new ParseError("expected var name = value", block.line);
|
|
1201
|
+
const name = m[1];
|
|
1202
|
+
if (RESERVED_VAR_NAMES.has(name)) {
|
|
1203
|
+
diagnostics.push({ severity: "warning", message: `var '${name}' shadows a reserved selector and was ignored`, line: block.line });
|
|
1204
|
+
continue;
|
|
1205
|
+
}
|
|
1206
|
+
const raw = m[2].trim();
|
|
1207
|
+
const str = parseStringToken(raw);
|
|
1208
|
+
vars.set(name, str && str.rest === "" ? str.value : raw);
|
|
1209
|
+
}
|
|
1210
|
+
return { vars, rest };
|
|
1211
|
+
}
|
|
1212
|
+
function applyVars(blocks, vars) {
|
|
1213
|
+
if (vars.size === 0) return blocks;
|
|
1214
|
+
return blocks.map((block) => {
|
|
1215
|
+
let text = block.text;
|
|
1216
|
+
for (const [name, value] of vars) {
|
|
1217
|
+
text = text.replace(new RegExp(`\\$${name}(?![\\w])`, "g"), value);
|
|
1218
|
+
}
|
|
1219
|
+
return { ...block, text };
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1145
1222
|
function pushWarning(diagnostics, seen, line, message) {
|
|
1146
1223
|
const key = `${line}:${message}`;
|
|
1147
1224
|
if (seen.has(key)) return;
|
|
@@ -1221,7 +1298,9 @@ function parse(source, opts = {}) {
|
|
|
1221
1298
|
const beats = [];
|
|
1222
1299
|
let title = "";
|
|
1223
1300
|
let edgeCounter = 0;
|
|
1224
|
-
const
|
|
1301
|
+
const rawBlocks = readBlocks(lines.map(stripComment));
|
|
1302
|
+
const { vars, rest } = extractVars(rawBlocks, diagnostics);
|
|
1303
|
+
const blocks = applyVars(rest, vars);
|
|
1225
1304
|
let i = 0;
|
|
1226
1305
|
while (i < blocks.length) {
|
|
1227
1306
|
const block = blocks[i];
|
|
@@ -1230,12 +1309,12 @@ function parse(source, opts = {}) {
|
|
|
1230
1309
|
const unsupportedMessage = unsupportedSyntaxMessage(line);
|
|
1231
1310
|
if (unsupportedMessage) throw new ParseError(unsupportedMessage, lineNo);
|
|
1232
1311
|
if (line.startsWith("scene")) {
|
|
1233
|
-
const
|
|
1312
|
+
const rest2 = line.slice(5).trim();
|
|
1234
1313
|
if (line.endsWith("{")) {
|
|
1235
1314
|
throw new ParseError(`nested scene blocks are not supported; use one scene with multiple beat blocks`, lineNo);
|
|
1236
1315
|
}
|
|
1237
|
-
let remainder =
|
|
1238
|
-
const str = parseStringToken(
|
|
1316
|
+
let remainder = rest2;
|
|
1317
|
+
const str = parseStringToken(rest2);
|
|
1239
1318
|
if (str) {
|
|
1240
1319
|
title = str.value;
|
|
1241
1320
|
remainder = str.rest;
|
|
@@ -1282,16 +1361,31 @@ function parse(source, opts = {}) {
|
|
|
1282
1361
|
continue;
|
|
1283
1362
|
}
|
|
1284
1363
|
if (line.startsWith("group ")) {
|
|
1285
|
-
const
|
|
1286
|
-
if (
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1364
|
+
const inline = line.match(/^group\s+(\w+)(?:\s+"([^"]*)")?\s*:\s*(.+)$/);
|
|
1365
|
+
if (inline) {
|
|
1366
|
+
groups[inline[1]] = {
|
|
1367
|
+
id: inline[1],
|
|
1368
|
+
label: inline[2],
|
|
1369
|
+
members: splitTargets(inline[3]),
|
|
1370
|
+
props: {},
|
|
1371
|
+
line: lineNo
|
|
1372
|
+
};
|
|
1373
|
+
i++;
|
|
1374
|
+
continue;
|
|
1375
|
+
}
|
|
1376
|
+
const header = line.match(/^group\s+(\w+)(?:\s+"([^"]*)")?\s*:\s*$/);
|
|
1377
|
+
if (!header) throw new ParseError(`expected group name: A B C`, lineNo);
|
|
1378
|
+
const { body, nextIdx } = readIndentedBody(blocks, i + 1, block.indent);
|
|
1379
|
+
const members = body.flatMap((b) => splitTargets(b.text));
|
|
1380
|
+
if (members.length === 0) throw new ParseError(`group '${header[1]}' has no members`, lineNo);
|
|
1381
|
+
groups[header[1]] = {
|
|
1382
|
+
id: header[1],
|
|
1383
|
+
label: header[2],
|
|
1384
|
+
members,
|
|
1291
1385
|
props: {},
|
|
1292
1386
|
line: lineNo
|
|
1293
1387
|
};
|
|
1294
|
-
i
|
|
1388
|
+
i = nextIdx;
|
|
1295
1389
|
continue;
|
|
1296
1390
|
}
|
|
1297
1391
|
if (line.startsWith("edge ")) {
|
|
@@ -1313,7 +1407,7 @@ function parse(source, opts = {}) {
|
|
|
1313
1407
|
continue;
|
|
1314
1408
|
}
|
|
1315
1409
|
if (line.startsWith("beat ")) {
|
|
1316
|
-
const m = line.match(/^beat\s+(\w+)(?:\s+"([^"]*)")?\s*(?::|\{)\s*$/);
|
|
1410
|
+
const m = line.match(/^beat\s+([\w.-]+)(?:\s+"([^"]*)")?\s*(?::|\{)\s*$/);
|
|
1317
1411
|
if (!m) throw new ParseError(`expected beat name:`, lineNo);
|
|
1318
1412
|
const { body, nextIdx } = readBody(blocks, i + 1, block.indent, line.endsWith("{"));
|
|
1319
1413
|
let cues = normalizeCueBlocks(body).map((b) => parseCueLine(b.text, b.line));
|
|
@@ -1384,6 +1478,7 @@ function parseAndCompile(source) {
|
|
|
1384
1478
|
}
|
|
1385
1479
|
export {
|
|
1386
1480
|
BEAT_CUE_KEYWORDS,
|
|
1481
|
+
CUE_ALIASES,
|
|
1387
1482
|
EDGE_OPERATORS,
|
|
1388
1483
|
NODE_ALIASES,
|
|
1389
1484
|
NODE_KINDS,
|
package/package.json
CHANGED