@markdy/core 0.7.25 → 0.7.27
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 +26 -1
- package/dist/index.js +187 -8
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -116,6 +116,12 @@ type SceneAST = {
|
|
|
116
116
|
seqs: Record<string, SequenceDef>;
|
|
117
117
|
/** User-defined variables — kept in AST for tooling/inspection. */
|
|
118
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
|
+
*/
|
|
124
|
+
groups: Record<string, string[]>;
|
|
119
125
|
/** Named chapter blocks in author order. Empty when no chapters were used. */
|
|
120
126
|
chapters: Chapter[];
|
|
121
127
|
/** Soft parse issues. Always present; empty in the happy path. */
|
|
@@ -180,6 +186,25 @@ type PresetFn = (args: string[]) => string;
|
|
|
180
186
|
declare const PRESETS: Record<string, PresetFn>;
|
|
181
187
|
declare const PRESET_NAMES: readonly string[];
|
|
182
188
|
|
|
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"];
|
|
183
208
|
type ActorPack = {
|
|
184
209
|
name: string;
|
|
185
210
|
actors: readonly string[];
|
|
@@ -187,4 +212,4 @@ type ActorPack = {
|
|
|
187
212
|
};
|
|
188
213
|
declare function registerActorPack(pack: ActorPack): void;
|
|
189
214
|
|
|
190
|
-
export { type ActorDef, type ActorPack, type ActorType, type AssetDef, type BuiltinActorType, type Chapter, type ImportDecl, PRESETS, PRESET_NAMES, ParseError, type ParseOptions, type ParseWarning, type PresetFn, type SceneAST, type SceneMeta, type SequenceDef, type TemplateDef, type TimelineEvent, parse, registerActorPack };
|
|
215
|
+
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, type TemplateDef, type TimelineEvent, UNIVERSAL_ACTION_NAMES, parse, registerActorPack };
|
package/dist/index.js
CHANGED
|
@@ -232,20 +232,29 @@ var BUILTIN_ACTOR_TYPES = [
|
|
|
232
232
|
"figure",
|
|
233
233
|
"caption"
|
|
234
234
|
];
|
|
235
|
-
var
|
|
235
|
+
var UNIVERSAL_ACTION_NAMES = [
|
|
236
236
|
"enter",
|
|
237
237
|
"exit",
|
|
238
238
|
"move",
|
|
239
|
+
"spring",
|
|
240
|
+
"follow_path",
|
|
239
241
|
"fade_in",
|
|
240
242
|
"fade_out",
|
|
241
243
|
"scale",
|
|
242
244
|
"rotate",
|
|
243
245
|
"shake",
|
|
246
|
+
"pulse",
|
|
247
|
+
"glow",
|
|
248
|
+
"ripple",
|
|
249
|
+
"blur",
|
|
250
|
+
"line_reveal",
|
|
251
|
+
"mask",
|
|
252
|
+
"parallax",
|
|
244
253
|
"say",
|
|
245
254
|
"throw",
|
|
246
255
|
"play"
|
|
247
|
-
]
|
|
248
|
-
var
|
|
256
|
+
];
|
|
257
|
+
var FIGURE_ONLY_ACTION_NAMES = [
|
|
249
258
|
"punch",
|
|
250
259
|
"kick",
|
|
251
260
|
"wave",
|
|
@@ -255,8 +264,11 @@ var FIGURE_ONLY_ACTIONS = /* @__PURE__ */ new Set([
|
|
|
255
264
|
"face",
|
|
256
265
|
"rotate_part",
|
|
257
266
|
"pose"
|
|
258
|
-
]
|
|
259
|
-
var
|
|
267
|
+
];
|
|
268
|
+
var CAMERA_ACTION_NAMES = ["pan", "zoom", "shake"];
|
|
269
|
+
var UNIVERSAL_ACTIONS = new Set(UNIVERSAL_ACTION_NAMES);
|
|
270
|
+
var FIGURE_ONLY_ACTIONS = new Set(FIGURE_ONLY_ACTION_NAMES);
|
|
271
|
+
var CAMERA_ACTIONS = new Set(CAMERA_ACTION_NAMES);
|
|
260
272
|
var actorTypes = new Set(BUILTIN_ACTOR_TYPES);
|
|
261
273
|
var actorActions = /* @__PURE__ */ new Map();
|
|
262
274
|
function registerActorPack(pack) {
|
|
@@ -514,6 +526,22 @@ var SEQ_EVENT_RE = /^@\+([\d.]+):\s+\$\.(!?\w+)\((.*)\)$/;
|
|
|
514
526
|
var CHAPTER_HEADER_RE = /^scene\s+"([^"]+)"\s*\{$/;
|
|
515
527
|
var IMPORT_RE = /^import\s+"([^"]+)"\s+as\s+(\w+)\s*$/;
|
|
516
528
|
var PRESET_RE = /^preset\s+(\w+)(?:\s*\((.*)\))?\s*$/;
|
|
529
|
+
var ARCHITECTURE_NODE_RE = /^(service|database|db|queue|cache|api|user|client|cloud|region|container|microservice|cluster)\s+(\w+)(?:\s+("[^"]+"|'[^']+'))?(?:\s+at\s+\(\s*(-?[\d.]+)\s*,\s*(-?[\d.]+)\s*\))?(.*)$/;
|
|
530
|
+
var ARCHITECTURE_ALIAS_TO_TYPE = {
|
|
531
|
+
api: "service",
|
|
532
|
+
database: "database",
|
|
533
|
+
db: "db",
|
|
534
|
+
user: "client",
|
|
535
|
+
client: "client",
|
|
536
|
+
service: "service",
|
|
537
|
+
queue: "queue",
|
|
538
|
+
cache: "cache",
|
|
539
|
+
cloud: "cloud",
|
|
540
|
+
region: "region",
|
|
541
|
+
container: "container",
|
|
542
|
+
microservice: "microservice",
|
|
543
|
+
cluster: "cluster"
|
|
544
|
+
};
|
|
517
545
|
function interpolate(s, vars) {
|
|
518
546
|
return s.replace(
|
|
519
547
|
/\\?\$\{([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\}/g,
|
|
@@ -555,6 +583,7 @@ function parse(source, opts = {}) {
|
|
|
555
583
|
defs: {},
|
|
556
584
|
seqs: {},
|
|
557
585
|
vars: {},
|
|
586
|
+
groups: {},
|
|
558
587
|
chapters: [],
|
|
559
588
|
warnings: [],
|
|
560
589
|
imports: []
|
|
@@ -775,7 +804,7 @@ function parse(source, opts = {}) {
|
|
|
775
804
|
}
|
|
776
805
|
continue;
|
|
777
806
|
}
|
|
778
|
-
if (raw.startsWith("actor ")) {
|
|
807
|
+
if (raw.startsWith("actor ") || isArchitectureNodeLine(raw)) {
|
|
779
808
|
const actorInfo = parseActorLine(raw, lineNum, ast);
|
|
780
809
|
if (!actorCountWarned && actorCountWarningThreshold > 0) {
|
|
781
810
|
const actorCount = Object.keys(ast.actors).length;
|
|
@@ -800,6 +829,10 @@ function parse(source, opts = {}) {
|
|
|
800
829
|
}
|
|
801
830
|
continue;
|
|
802
831
|
}
|
|
832
|
+
if (raw.startsWith("group ")) {
|
|
833
|
+
parseGroupLine(raw, lineNum, ast);
|
|
834
|
+
continue;
|
|
835
|
+
}
|
|
803
836
|
if (raw.startsWith("@")) {
|
|
804
837
|
parseEventLine(raw, lineNum, ast, inChapter, topScope);
|
|
805
838
|
continue;
|
|
@@ -837,6 +870,8 @@ function parseActorCallArgs(argsRaw) {
|
|
|
837
870
|
});
|
|
838
871
|
}
|
|
839
872
|
function parseActorLine(raw, lineNum, ast) {
|
|
873
|
+
const architectureNode = parseArchitectureNodeLine(raw, lineNum, ast);
|
|
874
|
+
if (architectureNode) return architectureNode;
|
|
840
875
|
const amAnchor = ACTOR_ANCHOR_POS_RE.exec(raw);
|
|
841
876
|
const amNum = amAnchor ? null : ACTOR_NUM_POS_RE.exec(raw);
|
|
842
877
|
if (!amAnchor && !amNum) throw new ParseError(`Invalid actor declaration: ${raw}`, lineNum);
|
|
@@ -927,6 +962,110 @@ function parseActorLine(raw, lineNum, ast) {
|
|
|
927
962
|
};
|
|
928
963
|
return { name, args: resolvedArgs };
|
|
929
964
|
}
|
|
965
|
+
function isArchitectureNodeLine(raw) {
|
|
966
|
+
return ARCHITECTURE_NODE_RE.test(raw);
|
|
967
|
+
}
|
|
968
|
+
function parseArchitectureNodeLine(raw, lineNum, ast) {
|
|
969
|
+
const m = ARCHITECTURE_NODE_RE.exec(raw);
|
|
970
|
+
if (!m) return null;
|
|
971
|
+
const [, alias, name, labelRaw, xRaw, yRaw, trailer] = m;
|
|
972
|
+
if (name === "camera") {
|
|
973
|
+
throw new ParseError(
|
|
974
|
+
`"camera" is a reserved actor name; choose a different architecture node name`,
|
|
975
|
+
lineNum
|
|
976
|
+
);
|
|
977
|
+
}
|
|
978
|
+
const typeName = ARCHITECTURE_ALIAS_TO_TYPE[alias] ?? alias;
|
|
979
|
+
if (!isKnownActorType(typeName)) {
|
|
980
|
+
throw new ParseError(
|
|
981
|
+
`Architecture node "${alias}" requires an actor pack that registers type "${typeName}"`,
|
|
982
|
+
lineNum
|
|
983
|
+
);
|
|
984
|
+
}
|
|
985
|
+
const actorIndex = Object.keys(ast.actors).length;
|
|
986
|
+
const x = xRaw === void 0 ? autoNodeX(actorIndex, ast.meta.width) : Number(xRaw);
|
|
987
|
+
const y = yRaw === void 0 ? autoNodeY(actorIndex, ast.meta.height, ast.meta.width) : Number(yRaw);
|
|
988
|
+
if (x < 0 || x > ast.meta.width || y < 0 || y > ast.meta.height) {
|
|
989
|
+
throw new ParseError(
|
|
990
|
+
`Actor "${name}" position (${x}, ${y}) is outside scene bounds (0\u2013${ast.meta.width}, 0\u2013${ast.meta.height})`,
|
|
991
|
+
lineNum
|
|
992
|
+
);
|
|
993
|
+
}
|
|
994
|
+
const quoted = labelRaw ? parseQuotedLiteral(labelRaw.trim()) : null;
|
|
995
|
+
const label = quoted ?? labelRaw?.trim() ?? name;
|
|
996
|
+
const modifiers = parseActorTrailer(trailer, lineNum, ast.warnings);
|
|
997
|
+
ast.actors[name] = {
|
|
998
|
+
type: typeName,
|
|
999
|
+
args: [label],
|
|
1000
|
+
x,
|
|
1001
|
+
y,
|
|
1002
|
+
...modifiers
|
|
1003
|
+
};
|
|
1004
|
+
return { name, args: [label] };
|
|
1005
|
+
}
|
|
1006
|
+
function autoNodeX(index, width) {
|
|
1007
|
+
const columns = Math.max(1, Math.floor(width / 220));
|
|
1008
|
+
const gutter = width / (columns + 1);
|
|
1009
|
+
return Math.round(gutter * (index % columns + 1));
|
|
1010
|
+
}
|
|
1011
|
+
function autoNodeY(index, height, width = DEFAULTS.width) {
|
|
1012
|
+
const columns = Math.max(1, Math.floor(width / 220));
|
|
1013
|
+
const row = Math.floor(index / columns);
|
|
1014
|
+
return Math.min(height - 60, 90 + row * 120);
|
|
1015
|
+
}
|
|
1016
|
+
var GROUP_RE = /^group\s+([A-Za-z_][\w.]*)\s*=\s*(.+)$/;
|
|
1017
|
+
function parseGroupLine(raw, lineNum, ast) {
|
|
1018
|
+
const m = GROUP_RE.exec(raw);
|
|
1019
|
+
if (!m) {
|
|
1020
|
+
throw new ParseError(`Invalid group declaration: ${raw}`, lineNum);
|
|
1021
|
+
}
|
|
1022
|
+
const [, name, membersRaw] = m;
|
|
1023
|
+
if (ast.actors[name]) {
|
|
1024
|
+
throw new ParseError(`Group "${name}" collides with an actor of the same name`, lineNum);
|
|
1025
|
+
}
|
|
1026
|
+
if (ast.groups[name]) {
|
|
1027
|
+
throw new ParseError(`Group "${name}" is already defined`, lineNum);
|
|
1028
|
+
}
|
|
1029
|
+
const members = splitByComma(membersRaw).map((part) => part.trim()).filter((part) => part.length > 0);
|
|
1030
|
+
if (members.length === 0) {
|
|
1031
|
+
throw new ParseError(`Group "${name}" has no members`, lineNum);
|
|
1032
|
+
}
|
|
1033
|
+
for (const member of members) {
|
|
1034
|
+
if (!ast.actors[member]) {
|
|
1035
|
+
throw new ParseError(`Unknown actor "${member}" in group "${name}"`, lineNum);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1039
|
+
for (const member of members) {
|
|
1040
|
+
if (seen.has(member)) {
|
|
1041
|
+
throw new ParseError(`Actor "${member}" listed twice in group "${name}"`, lineNum);
|
|
1042
|
+
}
|
|
1043
|
+
seen.add(member);
|
|
1044
|
+
}
|
|
1045
|
+
ast.groups[name] = members;
|
|
1046
|
+
}
|
|
1047
|
+
function takeStagger(paramsRaw, lineNum) {
|
|
1048
|
+
if (!paramsRaw.includes("stagger")) return { step: 0, rest: paramsRaw };
|
|
1049
|
+
const kept = [];
|
|
1050
|
+
let step = 0;
|
|
1051
|
+
for (const part of splitByComma(paramsRaw)) {
|
|
1052
|
+
const eq = part.indexOf("=");
|
|
1053
|
+
if (eq !== -1 && part.slice(0, eq).trim() === "stagger") {
|
|
1054
|
+
const rawValue = part.slice(eq + 1).trim();
|
|
1055
|
+
const value = Number(rawValue);
|
|
1056
|
+
if (Number.isNaN(value)) {
|
|
1057
|
+
throw new ParseError(`Invalid stagger value: ${rawValue}`, lineNum);
|
|
1058
|
+
}
|
|
1059
|
+
if (value < 0) {
|
|
1060
|
+
throw new ParseError(`stagger must not be negative (got ${rawValue})`, lineNum);
|
|
1061
|
+
}
|
|
1062
|
+
step = value;
|
|
1063
|
+
continue;
|
|
1064
|
+
}
|
|
1065
|
+
kept.push(part);
|
|
1066
|
+
}
|
|
1067
|
+
return { step, rest: kept.join(",") };
|
|
1068
|
+
}
|
|
930
1069
|
function parseEventLine(raw, lineNum, ast, inChapter, topScope) {
|
|
931
1070
|
const scope = inChapter?.scope ?? topScope;
|
|
932
1071
|
const recordEventTime = (t) => {
|
|
@@ -977,18 +1116,54 @@ function parseEventLine(raw, lineNum, ast, inChapter, topScope) {
|
|
|
977
1116
|
line: lineNum
|
|
978
1117
|
});
|
|
979
1118
|
}
|
|
980
|
-
const
|
|
1119
|
+
const params = parseActionParams(action, paramsRaw);
|
|
981
1120
|
recordEventTime(time);
|
|
982
1121
|
pushEvent(ast, scope, {
|
|
983
1122
|
time,
|
|
984
1123
|
actor: "camera",
|
|
985
1124
|
action,
|
|
986
|
-
params
|
|
1125
|
+
params,
|
|
987
1126
|
line: lineNum,
|
|
988
1127
|
...inChapter ? { chapter: inChapter.name } : {}
|
|
989
1128
|
});
|
|
990
1129
|
return;
|
|
991
1130
|
}
|
|
1131
|
+
const groupMembers = ast.groups[actor];
|
|
1132
|
+
if (!groupMembers && !ast.actors[actor]) {
|
|
1133
|
+
throw new ParseError(`Unknown actor: "${actor}"`, lineNum);
|
|
1134
|
+
}
|
|
1135
|
+
if (groupMembers) {
|
|
1136
|
+
const { step, rest } = takeStagger(paramsRaw, lineNum);
|
|
1137
|
+
groupMembers.forEach((member, index) => {
|
|
1138
|
+
emitActorEvent(
|
|
1139
|
+
member,
|
|
1140
|
+
round3(time + index * step),
|
|
1141
|
+
action,
|
|
1142
|
+
rest,
|
|
1143
|
+
mustUnderstand,
|
|
1144
|
+
lineNum,
|
|
1145
|
+
ast,
|
|
1146
|
+
scope,
|
|
1147
|
+
inChapter,
|
|
1148
|
+
recordEventTime
|
|
1149
|
+
);
|
|
1150
|
+
});
|
|
1151
|
+
return;
|
|
1152
|
+
}
|
|
1153
|
+
emitActorEvent(
|
|
1154
|
+
actor,
|
|
1155
|
+
time,
|
|
1156
|
+
action,
|
|
1157
|
+
paramsRaw,
|
|
1158
|
+
mustUnderstand,
|
|
1159
|
+
lineNum,
|
|
1160
|
+
ast,
|
|
1161
|
+
scope,
|
|
1162
|
+
inChapter,
|
|
1163
|
+
recordEventTime
|
|
1164
|
+
);
|
|
1165
|
+
}
|
|
1166
|
+
function emitActorEvent(actor, time, action, paramsRaw, mustUnderstand, lineNum, ast, scope, inChapter, recordEventTime) {
|
|
992
1167
|
const actorDef = ast.actors[actor];
|
|
993
1168
|
if (!actorDef) {
|
|
994
1169
|
throw new ParseError(`Unknown actor: "${actor}"`, lineNum);
|
|
@@ -1105,9 +1280,13 @@ function round3(n) {
|
|
|
1105
1280
|
return Math.round(n * 1e3) / 1e3;
|
|
1106
1281
|
}
|
|
1107
1282
|
export {
|
|
1283
|
+
BUILTIN_ACTOR_TYPES,
|
|
1284
|
+
CAMERA_ACTION_NAMES,
|
|
1285
|
+
FIGURE_ONLY_ACTION_NAMES,
|
|
1108
1286
|
PRESETS,
|
|
1109
1287
|
PRESET_NAMES,
|
|
1110
1288
|
ParseError,
|
|
1289
|
+
UNIVERSAL_ACTION_NAMES,
|
|
1111
1290
|
parse,
|
|
1112
1291
|
registerActorPack
|
|
1113
1292
|
};
|