@markdy/core 0.7.9 → 0.7.11
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 +23 -3
- package/dist/index.js +99 -40
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ type AssetDef = {
|
|
|
7
7
|
value: string;
|
|
8
8
|
};
|
|
9
9
|
type ActorDef = {
|
|
10
|
-
type:
|
|
10
|
+
type: ActorType;
|
|
11
11
|
/** Constructor arguments: asset name for sprite, display text for text/caption actors. */
|
|
12
12
|
args: string[];
|
|
13
13
|
x: number;
|
|
@@ -26,6 +26,8 @@ type ActorDef = {
|
|
|
26
26
|
*/
|
|
27
27
|
anchor?: "top" | "bottom" | "center";
|
|
28
28
|
};
|
|
29
|
+
type BuiltinActorType = "sprite" | "text" | "box" | "figure" | "caption";
|
|
30
|
+
type ActorType = BuiltinActorType | (string & {});
|
|
29
31
|
type TimelineEvent = {
|
|
30
32
|
time: number;
|
|
31
33
|
actor: string;
|
|
@@ -89,7 +91,7 @@ type Chapter = {
|
|
|
89
91
|
* renderer otherwise no-ops the offending statement.
|
|
90
92
|
*/
|
|
91
93
|
type ParseWarning = {
|
|
92
|
-
kind: "unknown-action" | "unknown-modifier" | "unknown-scene-key" | "unknown-camera-action" | "unknown-preset" | "import-unresolved" | "preset-mixed";
|
|
94
|
+
kind: "unknown-action" | "unknown-modifier" | "unknown-scene-key" | "unknown-camera-action" | "unknown-preset" | "import-unresolved" | "preset-mixed" | "actor-count-threshold" | "label-overflow";
|
|
93
95
|
message: string;
|
|
94
96
|
line: number;
|
|
95
97
|
};
|
|
@@ -137,6 +139,17 @@ interface ParseOptions {
|
|
|
137
139
|
* `<ns>.<name>` prefix. Missing namespaces produce a soft warning.
|
|
138
140
|
*/
|
|
139
141
|
imports?: Record<string, SceneAST>;
|
|
142
|
+
/**
|
|
143
|
+
* Emit a non-fatal warning when actor count exceeds this threshold.
|
|
144
|
+
* Set to <= 0 to disable.
|
|
145
|
+
*/
|
|
146
|
+
actorCountWarningThreshold?: number;
|
|
147
|
+
/**
|
|
148
|
+
* Emit a non-fatal warning when actor labels exceed this length.
|
|
149
|
+
* Applies to the first constructor arg when it is a string.
|
|
150
|
+
* Set to <= 0 to disable.
|
|
151
|
+
*/
|
|
152
|
+
labelLengthWarningThreshold?: number;
|
|
140
153
|
/**
|
|
141
154
|
* Internal flag — distinguishes a top-level call from a recursive
|
|
142
155
|
* call used to expand a `preset`. Preset expansion bypasses the
|
|
@@ -167,4 +180,11 @@ type PresetFn = (args: string[]) => string;
|
|
|
167
180
|
declare const PRESETS: Record<string, PresetFn>;
|
|
168
181
|
declare const PRESET_NAMES: readonly string[];
|
|
169
182
|
|
|
170
|
-
|
|
183
|
+
type ActorPack = {
|
|
184
|
+
name: string;
|
|
185
|
+
actors: readonly string[];
|
|
186
|
+
actions?: Record<string, readonly string[]>;
|
|
187
|
+
};
|
|
188
|
+
declare function registerActorPack(pack: ActorPack): void;
|
|
189
|
+
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -224,6 +224,69 @@ actor title = caption("tier list") at top
|
|
|
224
224
|
};
|
|
225
225
|
var PRESET_NAMES = Object.keys(PRESETS);
|
|
226
226
|
|
|
227
|
+
// src/registry.ts
|
|
228
|
+
var BUILTIN_ACTOR_TYPES = [
|
|
229
|
+
"sprite",
|
|
230
|
+
"text",
|
|
231
|
+
"box",
|
|
232
|
+
"figure",
|
|
233
|
+
"caption"
|
|
234
|
+
];
|
|
235
|
+
var UNIVERSAL_ACTIONS = /* @__PURE__ */ new Set([
|
|
236
|
+
"enter",
|
|
237
|
+
"exit",
|
|
238
|
+
"move",
|
|
239
|
+
"fade_in",
|
|
240
|
+
"fade_out",
|
|
241
|
+
"scale",
|
|
242
|
+
"rotate",
|
|
243
|
+
"shake",
|
|
244
|
+
"say",
|
|
245
|
+
"throw",
|
|
246
|
+
"play"
|
|
247
|
+
]);
|
|
248
|
+
var FIGURE_ONLY_ACTIONS = /* @__PURE__ */ new Set([
|
|
249
|
+
"punch",
|
|
250
|
+
"kick",
|
|
251
|
+
"wave",
|
|
252
|
+
"nod",
|
|
253
|
+
"jump",
|
|
254
|
+
"bounce",
|
|
255
|
+
"face",
|
|
256
|
+
"rotate_part",
|
|
257
|
+
"pose"
|
|
258
|
+
]);
|
|
259
|
+
var CAMERA_ACTIONS = /* @__PURE__ */ new Set(["pan", "zoom", "shake"]);
|
|
260
|
+
var actorTypes = new Set(BUILTIN_ACTOR_TYPES);
|
|
261
|
+
var actorActions = /* @__PURE__ */ new Map();
|
|
262
|
+
function registerActorPack(pack) {
|
|
263
|
+
for (const actor of pack.actors) {
|
|
264
|
+
actorTypes.add(actor);
|
|
265
|
+
if (!actorActions.has(actor)) actorActions.set(actor, /* @__PURE__ */ new Set());
|
|
266
|
+
}
|
|
267
|
+
if (!pack.actions) return;
|
|
268
|
+
for (const [actorType, actions] of Object.entries(pack.actions)) {
|
|
269
|
+
actorTypes.add(actorType);
|
|
270
|
+
const known = actorActions.get(actorType) ?? /* @__PURE__ */ new Set();
|
|
271
|
+
for (const action of actions) known.add(action);
|
|
272
|
+
actorActions.set(actorType, known);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
function isKnownActorType(type) {
|
|
276
|
+
return actorTypes.has(type);
|
|
277
|
+
}
|
|
278
|
+
function isFigureOnlyAction(action) {
|
|
279
|
+
return FIGURE_ONLY_ACTIONS.has(action);
|
|
280
|
+
}
|
|
281
|
+
function isCameraAction(action) {
|
|
282
|
+
return CAMERA_ACTIONS.has(action);
|
|
283
|
+
}
|
|
284
|
+
function isKnownAction(actorType, action) {
|
|
285
|
+
if (UNIVERSAL_ACTIONS.has(action)) return true;
|
|
286
|
+
if (actorType === "figure" && FIGURE_ONLY_ACTIONS.has(action)) return true;
|
|
287
|
+
return actorActions.get(actorType)?.has(action) ?? false;
|
|
288
|
+
}
|
|
289
|
+
|
|
227
290
|
// src/parser.ts
|
|
228
291
|
var ParseError = class extends Error {
|
|
229
292
|
constructor(message, line) {
|
|
@@ -369,36 +432,6 @@ function parseActionParams(action, raw) {
|
|
|
369
432
|
}
|
|
370
433
|
return params;
|
|
371
434
|
}
|
|
372
|
-
var UNIVERSAL_ACTIONS = /* @__PURE__ */ new Set([
|
|
373
|
-
"enter",
|
|
374
|
-
"exit",
|
|
375
|
-
"move",
|
|
376
|
-
"fade_in",
|
|
377
|
-
"fade_out",
|
|
378
|
-
"scale",
|
|
379
|
-
"rotate",
|
|
380
|
-
"shake",
|
|
381
|
-
"say",
|
|
382
|
-
"throw",
|
|
383
|
-
"play"
|
|
384
|
-
]);
|
|
385
|
-
var FIGURE_ONLY_ACTIONS = /* @__PURE__ */ new Set([
|
|
386
|
-
"punch",
|
|
387
|
-
"kick",
|
|
388
|
-
"wave",
|
|
389
|
-
"nod",
|
|
390
|
-
"jump",
|
|
391
|
-
"bounce",
|
|
392
|
-
"face",
|
|
393
|
-
"rotate_part",
|
|
394
|
-
"pose"
|
|
395
|
-
]);
|
|
396
|
-
var CAMERA_ACTIONS = /* @__PURE__ */ new Set(["pan", "zoom", "shake"]);
|
|
397
|
-
function isKnownAction(actorType, action) {
|
|
398
|
-
if (actorType === "camera") return CAMERA_ACTIONS.has(action);
|
|
399
|
-
if (UNIVERSAL_ACTIONS.has(action)) return true;
|
|
400
|
-
return FIGURE_ONLY_ACTIONS.has(action);
|
|
401
|
-
}
|
|
402
435
|
var MODIFIER_KEYS = /* @__PURE__ */ new Set(["scale", "rotate", "opacity", "size", "z"]);
|
|
403
436
|
function parseSpaceModifiers(raw, lineNum, warnings) {
|
|
404
437
|
const result = {};
|
|
@@ -469,14 +502,13 @@ function parseActorTrailer(trailerRaw, lineNum, warnings) {
|
|
|
469
502
|
return { ...fromSpace, ...fromWith };
|
|
470
503
|
}
|
|
471
504
|
var ASSET_RE = /^asset\s+(\w+)\s*=\s*(image|icon)\("([^"]+)"\)$/;
|
|
472
|
-
var BUILTIN_ACTOR_TYPES = /* @__PURE__ */ new Set(["sprite", "text", "box", "figure", "caption"]);
|
|
473
505
|
var ACTOR_NUM_POS_RE = /^actor\s+(\w+)\s*=\s*([\w.]+)\(([^)]*)\)\s+at\s+\(\s*(-?[\d.]+)\s*,\s*(-?[\d.]+)\s*\)(.*)$/;
|
|
474
506
|
var ACTOR_ANCHOR_POS_RE = /^actor\s+(\w+)\s*=\s*([\w.]+)\(([^)]*)\)\s+at\s+(top|bottom|center)\b(.*)$/;
|
|
475
507
|
var EVENT_RE = /^@([\d.]+):\s+(\w+)\.(!?\w+)\((.*)\)$/;
|
|
476
508
|
var REL_EVENT_RE = /^@\+([\d.]+):\s+(\w+)\.(!?\w+)\((.*)\)$/;
|
|
477
509
|
var VAR_RE = /^var\s+(\w+)\s*=\s*(.+)$/;
|
|
478
510
|
var DEF_HEADER_RE = /^def\s+(\w+)\(([^)]*)\)\s*\{$/;
|
|
479
|
-
var DEF_BODY_RE = /^\s*(
|
|
511
|
+
var DEF_BODY_RE = /^\s*([\w]+)\(([^)]*)\)\s*$/;
|
|
480
512
|
var SEQ_HEADER_RE = /^seq\s+(\w+)(?:\(([^)]*)\))?\s*\{$/;
|
|
481
513
|
var SEQ_EVENT_RE = /^@\+([\d.]+):\s+\$\.(!?\w+)\((.*)\)$/;
|
|
482
514
|
var CHAPTER_HEADER_RE = /^scene\s+"([^"]+)"\s*\{$/;
|
|
@@ -527,6 +559,9 @@ function parse(source, opts = {}) {
|
|
|
527
559
|
warnings: [],
|
|
528
560
|
imports: []
|
|
529
561
|
};
|
|
562
|
+
const actorCountWarningThreshold = opts.actorCountWarningThreshold ?? 10;
|
|
563
|
+
const labelLengthWarningThreshold = opts.labelLengthWarningThreshold ?? 36;
|
|
564
|
+
let actorCountWarned = false;
|
|
530
565
|
let sceneFound = false;
|
|
531
566
|
const lines = source.split(/\r?\n/);
|
|
532
567
|
let inDef = null;
|
|
@@ -584,6 +619,9 @@ function parse(source, opts = {}) {
|
|
|
584
619
|
throw new ParseError(`Invalid def body (expected "type(args)"): ${raw}`, lineNum);
|
|
585
620
|
}
|
|
586
621
|
const [, actorType, bodyArgsRaw] = bm;
|
|
622
|
+
if (!isKnownActorType(actorType)) {
|
|
623
|
+
throw new ParseError(`Unknown actor type in def body: "${actorType}"`, lineNum);
|
|
624
|
+
}
|
|
587
625
|
const bodyArgs = bodyArgsRaw.trim() ? splitByComma(bodyArgsRaw).map((a) => a.trim()) : [];
|
|
588
626
|
ast.defs[inDef.name] = {
|
|
589
627
|
params: inDef.params,
|
|
@@ -738,7 +776,28 @@ function parse(source, opts = {}) {
|
|
|
738
776
|
continue;
|
|
739
777
|
}
|
|
740
778
|
if (raw.startsWith("actor ")) {
|
|
741
|
-
parseActorLine(raw, lineNum, ast);
|
|
779
|
+
const actorInfo = parseActorLine(raw, lineNum, ast);
|
|
780
|
+
if (!actorCountWarned && actorCountWarningThreshold > 0) {
|
|
781
|
+
const actorCount = Object.keys(ast.actors).length;
|
|
782
|
+
if (actorCount > actorCountWarningThreshold) {
|
|
783
|
+
actorCountWarned = true;
|
|
784
|
+
ast.warnings.push({
|
|
785
|
+
kind: "actor-count-threshold",
|
|
786
|
+
message: `scene has ${actorCount} actors (threshold ${actorCountWarningThreshold}); consider splitting into multiple scenes`,
|
|
787
|
+
line: lineNum
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
if (labelLengthWarningThreshold > 0 && typeof actorInfo.args[0] === "string") {
|
|
792
|
+
const label = actorInfo.args[0];
|
|
793
|
+
if (label.length > labelLengthWarningThreshold) {
|
|
794
|
+
ast.warnings.push({
|
|
795
|
+
kind: "label-overflow",
|
|
796
|
+
message: `actor "${actorInfo.name}" label length ${label.length} exceeds ${labelLengthWarningThreshold}; consider shortening to reduce overlap`,
|
|
797
|
+
line: lineNum
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
}
|
|
742
801
|
continue;
|
|
743
802
|
}
|
|
744
803
|
if (raw.startsWith("@")) {
|
|
@@ -780,9 +839,7 @@ function parseActorCallArgs(argsRaw) {
|
|
|
780
839
|
function parseActorLine(raw, lineNum, ast) {
|
|
781
840
|
const amAnchor = ACTOR_ANCHOR_POS_RE.exec(raw);
|
|
782
841
|
const amNum = amAnchor ? null : ACTOR_NUM_POS_RE.exec(raw);
|
|
783
|
-
if (!amAnchor && !amNum) {
|
|
784
|
-
throw new ParseError(`Invalid actor declaration: ${raw}`, lineNum);
|
|
785
|
-
}
|
|
842
|
+
if (!amAnchor && !amNum) throw new ParseError(`Invalid actor declaration: ${raw}`, lineNum);
|
|
786
843
|
let name;
|
|
787
844
|
let typeName;
|
|
788
845
|
let argsRaw;
|
|
@@ -827,7 +884,7 @@ function parseActorLine(raw, lineNum, ast) {
|
|
|
827
884
|
const rawArgs = parseActorCallArgs(argsRaw);
|
|
828
885
|
let resolvedType;
|
|
829
886
|
let resolvedArgs;
|
|
830
|
-
if (
|
|
887
|
+
if (isKnownActorType(typeName)) {
|
|
831
888
|
resolvedType = typeName;
|
|
832
889
|
resolvedArgs = rawArgs;
|
|
833
890
|
} else if (ast.defs[typeName]) {
|
|
@@ -868,6 +925,7 @@ function parseActorLine(raw, lineNum, ast) {
|
|
|
868
925
|
...modifiers,
|
|
869
926
|
...anchor ? { anchor } : {}
|
|
870
927
|
};
|
|
928
|
+
return { name, args: resolvedArgs };
|
|
871
929
|
}
|
|
872
930
|
function parseEventLine(raw, lineNum, ast, inChapter, topScope) {
|
|
873
931
|
const scope = inChapter?.scope ?? topScope;
|
|
@@ -909,7 +967,7 @@ function parseEventLine(raw, lineNum, ast, inChapter, topScope) {
|
|
|
909
967
|
const mustUnderstand = actionToken.startsWith("!");
|
|
910
968
|
const action = mustUnderstand ? actionToken.slice(1) : actionToken;
|
|
911
969
|
if (actor === "camera") {
|
|
912
|
-
if (!
|
|
970
|
+
if (!isCameraAction(action)) {
|
|
913
971
|
if (mustUnderstand) {
|
|
914
972
|
throw new ParseError(`Unknown camera action "${action}"`, lineNum);
|
|
915
973
|
}
|
|
@@ -998,7 +1056,7 @@ function pushEvent(ast, scope, ev) {
|
|
|
998
1056
|
if (endTime > scope.prevEnd) scope.prevEnd = endTime;
|
|
999
1057
|
}
|
|
1000
1058
|
function validateActionForActor(action, actorDef, mustUnderstand, lineNum, warnings) {
|
|
1001
|
-
if (
|
|
1059
|
+
if (isFigureOnlyAction(action)) {
|
|
1002
1060
|
if (actorDef.type !== "figure") {
|
|
1003
1061
|
throw new ParseError(
|
|
1004
1062
|
`action "${action}" is figure-only; actor type is "${actorDef.type}"`,
|
|
@@ -1050,5 +1108,6 @@ export {
|
|
|
1050
1108
|
PRESETS,
|
|
1051
1109
|
PRESET_NAMES,
|
|
1052
1110
|
ParseError,
|
|
1053
|
-
parse
|
|
1111
|
+
parse,
|
|
1112
|
+
registerActorPack
|
|
1054
1113
|
};
|