@yagejs-addons/dialogue 0.1.0 → 0.2.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/dist/yaml.cjs ADDED
@@ -0,0 +1,726 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/yaml.ts
22
+ var yaml_exports = {};
23
+ __export(yaml_exports, {
24
+ loadYaml: () => loadYaml
25
+ });
26
+ module.exports = __toCommonJS(yaml_exports);
27
+
28
+ // src/core/formats/yaml.ts
29
+ var import_yaml = require("yaml");
30
+
31
+ // src/core/expr.ts
32
+ function isExpr(value) {
33
+ return typeof value === "object" && value !== null && "kind" in value;
34
+ }
35
+ __name(isExpr, "isExpr");
36
+
37
+ // src/core/i18n.ts
38
+ var TOKEN = /\{(\w+)\}/g;
39
+ function tokensIn(text) {
40
+ const names = /* @__PURE__ */ new Set();
41
+ for (const m of text.matchAll(TOKEN)) names.add(m[1]);
42
+ return [...names];
43
+ }
44
+ __name(tokensIn, "tokensIn");
45
+
46
+ // src/core/validate.ts
47
+ var DialogueScriptError = class extends Error {
48
+ static {
49
+ __name(this, "DialogueScriptError");
50
+ }
51
+ };
52
+ var NUMERIC_OPS = /* @__PURE__ */ new Set([">", ">=", "<", "<="]);
53
+ var NUMERIC_EXPR_OPS = /* @__PURE__ */ new Set([
54
+ ">",
55
+ "<",
56
+ ">=",
57
+ "<=",
58
+ "gt",
59
+ "lt",
60
+ "gte",
61
+ "lte",
62
+ "-",
63
+ "*",
64
+ "/",
65
+ "%"
66
+ ]);
67
+ var BUILTIN_COMMANDS = /* @__PURE__ */ new Set(["set"]);
68
+ function operandRequirement(op) {
69
+ if (op === "+") return "numberOrString";
70
+ return NUMERIC_EXPR_OPS.has(op) ? "number" : null;
71
+ }
72
+ __name(operandRequirement, "operandRequirement");
73
+ var analysisCache = /* @__PURE__ */ new WeakMap();
74
+ function analyzeScript(script) {
75
+ const cached = analysisCache.get(script);
76
+ if (cached) return cached;
77
+ const analysis = computeAnalysis(script);
78
+ analysisCache.set(script, analysis);
79
+ return analysis;
80
+ }
81
+ __name(analyzeScript, "analyzeScript");
82
+ function computeAnalysis(script) {
83
+ const declaredTypes = /* @__PURE__ */ new Map();
84
+ for (const [name, value] of Object.entries(script.declare ?? {})) {
85
+ declaredTypes.set(name, valueType(value));
86
+ }
87
+ const readVars = /* @__PURE__ */ new Set();
88
+ const setTargets = /* @__PURE__ */ new Set();
89
+ const calledFunctions = /* @__PURE__ */ new Set();
90
+ const commandTypes = /* @__PURE__ */ new Set();
91
+ const collectExpr = /* @__PURE__ */ __name((expr, where) => {
92
+ switch (expr.kind) {
93
+ case "literal":
94
+ return;
95
+ case "varRef":
96
+ readVars.add(expr.name);
97
+ return;
98
+ case "call":
99
+ calledFunctions.add(expr.fn);
100
+ for (const arg of expr.args ?? []) collectExpr(arg, where);
101
+ return;
102
+ case "group":
103
+ collectExpr(expr.expr, where);
104
+ return;
105
+ case "unary":
106
+ collectExpr(expr.operand, where);
107
+ return;
108
+ case "binary":
109
+ collectExpr(expr.left, where);
110
+ collectExpr(expr.right, where);
111
+ checkBinaryOperands(expr, where);
112
+ return;
113
+ }
114
+ }, "collectExpr");
115
+ const checkBinaryOperands = /* @__PURE__ */ __name((expr, where) => {
116
+ const req = operandRequirement(expr.op);
117
+ if (!req) return;
118
+ const expected = req === "numberOrString" ? "a number or string" : "a number";
119
+ for (const operand of [expr.left, expr.right]) {
120
+ if (operand.kind === "literal") {
121
+ const t = valueType(operand.value);
122
+ if (t === "number" || req === "numberOrString" && t === "string") continue;
123
+ throw new DialogueScriptError(
124
+ `${where}: operator "${expr.op}" expects ${expected}, got ${t}`
125
+ );
126
+ }
127
+ if (operand.kind === "varRef" && req === "number") {
128
+ const t = declaredTypes.get(operand.name);
129
+ if (t !== void 0 && t !== "number" && t !== "null") {
130
+ throw new DialogueScriptError(
131
+ `${where}: operator "${expr.op}" needs a number; "${operand.name}" is ${t}`
132
+ );
133
+ }
134
+ }
135
+ }
136
+ }, "checkBinaryOperands");
137
+ const checkTokens = /* @__PURE__ */ __name((text) => {
138
+ if (!text) return;
139
+ for (const token of tokensIn(text)) readVars.add(token);
140
+ }, "checkTokens");
141
+ const checkCondition = /* @__PURE__ */ __name((condition, where) => {
142
+ if (condition === void 0 || typeof condition === "function") return;
143
+ if (typeof condition === "string") {
144
+ readVars.add(condition);
145
+ return;
146
+ }
147
+ if (isExpr(condition)) {
148
+ collectExpr(condition, where);
149
+ return;
150
+ }
151
+ readVars.add(condition.var);
152
+ if (NUMERIC_OPS.has(condition.op)) {
153
+ const t = declaredTypes.get(condition.var);
154
+ if (t !== void 0 && t !== "number" && t !== "null") {
155
+ throw new DialogueScriptError(
156
+ `${where}: operator "${condition.op}" needs a number; "${condition.var}" is ${t}`
157
+ );
158
+ }
159
+ if (typeof condition.value !== "number") {
160
+ throw new DialogueScriptError(
161
+ `${where}: operator "${condition.op}" compares against a number, got ${typeof condition.value}`
162
+ );
163
+ }
164
+ }
165
+ }, "checkCondition");
166
+ const checkSetLiteralType = /* @__PURE__ */ __name((target, value, where) => {
167
+ const declared = declaredTypes.get(target);
168
+ if (declared !== void 0 && declared !== "null" && value !== null && typeof value !== declared) {
169
+ throw new DialogueScriptError(
170
+ `${where}: set "${target}" expects ${declared}, got ${typeof value}`
171
+ );
172
+ }
173
+ }, "checkSetLiteralType");
174
+ const checkCommands = /* @__PURE__ */ __name((commands, where) => {
175
+ for (const cmd of commands ?? []) {
176
+ if (cmd.type === "set") {
177
+ const target = cmd["var"];
178
+ if (typeof target !== "string") {
179
+ throw new DialogueScriptError(`${where}: set command has no string "var"`);
180
+ }
181
+ setTargets.add(target);
182
+ const value = cmd["value"];
183
+ if (value === void 0) {
184
+ throw new DialogueScriptError(`${where}: set "${target}" has no value`);
185
+ }
186
+ if (isExpr(value)) {
187
+ collectExpr(value, where);
188
+ if (value.kind === "literal") checkSetLiteralType(target, value.value, where);
189
+ } else {
190
+ checkSetLiteralType(target, value, where);
191
+ }
192
+ continue;
193
+ }
194
+ if (!BUILTIN_COMMANDS.has(cmd.type)) commandTypes.add(cmd.type);
195
+ }
196
+ }, "checkCommands");
197
+ for (const speaker of Object.values(script.speakers ?? {})) {
198
+ checkTokens(speaker.name);
199
+ }
200
+ for (const node of Object.values(script.nodes)) {
201
+ const where = `node "${node.id}"`;
202
+ for (const step of node.steps) {
203
+ switch (step.kind) {
204
+ case "say": {
205
+ const s = step;
206
+ checkTokens(s.text);
207
+ checkCommands(s.commands, `${where} say`);
208
+ break;
209
+ }
210
+ case "choice": {
211
+ const c = step;
212
+ checkTokens(c.text);
213
+ for (const opt of c.options) {
214
+ checkTokens(opt.text);
215
+ checkTokens(opt.disabledReason);
216
+ checkCondition(opt.condition, `${where} choice option "${opt.text}"`);
217
+ checkCommands(opt.commands, `${where} choice option "${opt.text}"`);
218
+ }
219
+ break;
220
+ }
221
+ case "command": {
222
+ const cs = step;
223
+ checkCommands(cs.commands, `${where} command`);
224
+ checkCondition(cs.condition, `${where} command`);
225
+ break;
226
+ }
227
+ default:
228
+ break;
229
+ }
230
+ }
231
+ }
232
+ return { declaredTypes, readVars, setTargets, calledFunctions, commandTypes };
233
+ }
234
+ __name(computeAnalysis, "computeAnalysis");
235
+ function valueType(value) {
236
+ if (value === null) return "null";
237
+ if (typeof value === "string") return "string";
238
+ if (typeof value === "number") return "number";
239
+ return "boolean";
240
+ }
241
+ __name(valueType, "valueType");
242
+
243
+ // src/core/expr-parse.ts
244
+ var DialogueExprError = class extends DialogueScriptError {
245
+ static {
246
+ __name(this, "DialogueExprError");
247
+ }
248
+ line;
249
+ col;
250
+ constructor(message, line, col) {
251
+ super(`${message} (at ${line}:${col})`);
252
+ this.name = "DialogueExprError";
253
+ this.line = line;
254
+ this.col = col;
255
+ }
256
+ };
257
+ function parseExpr(src) {
258
+ const tokens = tokenize(src);
259
+ return new Parser(tokens).parse();
260
+ }
261
+ __name(parseExpr, "parseExpr");
262
+ var KEYWORDS = {
263
+ and: "&&",
264
+ or: "||",
265
+ not: "!",
266
+ xor: "xor",
267
+ is: "==",
268
+ eq: "==",
269
+ neq: "!=",
270
+ gt: ">",
271
+ lt: "<",
272
+ gte: ">=",
273
+ lte: "<=",
274
+ true: "true",
275
+ false: "false",
276
+ null: "null"
277
+ };
278
+ var isDigit = /* @__PURE__ */ __name((c) => c >= "0" && c <= "9", "isDigit");
279
+ var isIdentStart = /* @__PURE__ */ __name((c) => c >= "A" && c <= "Z" || c >= "a" && c <= "z" || c === "_" || c === "$", "isIdentStart");
280
+ var isIdentPart = /* @__PURE__ */ __name((c) => isIdentStart(c) || isDigit(c) || c === ".", "isIdentPart");
281
+ function tokenize(src) {
282
+ const tokens = [];
283
+ let i = 0;
284
+ let line = 1;
285
+ let col = 1;
286
+ const advance = /* @__PURE__ */ __name((n = 1) => {
287
+ for (let k = 0; k < n; k++) {
288
+ if (src[i] === "\n") {
289
+ line++;
290
+ col = 1;
291
+ } else {
292
+ col++;
293
+ }
294
+ i++;
295
+ }
296
+ }, "advance");
297
+ while (i < src.length) {
298
+ const c = src[i];
299
+ if (c === " " || c === " " || c === "\n" || c === "\r") {
300
+ advance();
301
+ continue;
302
+ }
303
+ const startLine = line;
304
+ const startCol = col;
305
+ if (isDigit(c)) {
306
+ let text = "";
307
+ while (i < src.length && isDigit(src[i])) {
308
+ text += src[i];
309
+ advance();
310
+ }
311
+ if (src[i] === "." && isDigit(src[i + 1] ?? "")) {
312
+ text += ".";
313
+ advance();
314
+ while (i < src.length && isDigit(src[i])) {
315
+ text += src[i];
316
+ advance();
317
+ }
318
+ }
319
+ tokens.push({ kind: "number", value: Number(text), line: startLine, col: startCol });
320
+ continue;
321
+ }
322
+ if (c === "'" || c === '"') {
323
+ const quote = c;
324
+ advance();
325
+ let text = "";
326
+ while (i < src.length && src[i] !== quote) {
327
+ if (src[i] === "\\") {
328
+ advance();
329
+ if (i >= src.length) break;
330
+ text += unescape(src[i]);
331
+ } else {
332
+ text += src[i];
333
+ }
334
+ advance();
335
+ }
336
+ if (src[i] !== quote) {
337
+ throw new DialogueExprError("unterminated string literal", startLine, startCol);
338
+ }
339
+ advance();
340
+ tokens.push({ kind: "string", value: text, line: startLine, col: startCol });
341
+ continue;
342
+ }
343
+ if (isIdentStart(c)) {
344
+ let text = "";
345
+ while (i < src.length && isIdentPart(src[i])) {
346
+ text += src[i];
347
+ advance();
348
+ }
349
+ const keyword = KEYWORDS[text];
350
+ if (keyword === void 0) {
351
+ tokens.push({ kind: "ident", value: text, line: startLine, col: startCol });
352
+ } else if (keyword === "true" || keyword === "false" || keyword === "null") {
353
+ const value = keyword === "true" ? true : keyword === "false" ? false : null;
354
+ tokens.push({ kind: keyword, value, line: startLine, col: startCol });
355
+ } else {
356
+ tokens.push({ kind: keyword, line: startLine, col: startCol });
357
+ }
358
+ continue;
359
+ }
360
+ const two = src.slice(i, i + 2);
361
+ if (two === "&&" || two === "||" || two === "==" || two === "!=" || two === ">=" || two === "<=") {
362
+ tokens.push({ kind: two, line: startLine, col: startCol });
363
+ advance(2);
364
+ continue;
365
+ }
366
+ if (c === ">" || c === "<" || c === "!" || c === "+" || c === "-" || c === "(" || c === ")" || c === ",") {
367
+ tokens.push({ kind: c, line: startLine, col: startCol });
368
+ advance();
369
+ continue;
370
+ }
371
+ throw new DialogueExprError(`unexpected character "${c}"`, startLine, startCol);
372
+ }
373
+ tokens.push({ kind: "eof", line, col });
374
+ return tokens;
375
+ }
376
+ __name(tokenize, "tokenize");
377
+ function unescape(c) {
378
+ switch (c) {
379
+ case "n":
380
+ return "\n";
381
+ case "t":
382
+ return " ";
383
+ case "r":
384
+ return "\r";
385
+ default:
386
+ return c;
387
+ }
388
+ }
389
+ __name(unescape, "unescape");
390
+ var INFIX_BP = {
391
+ "||": 1,
392
+ "&&": 2,
393
+ "==": 3,
394
+ "!=": 3,
395
+ ">": 3,
396
+ "<": 3,
397
+ ">=": 3,
398
+ "<=": 3,
399
+ "+": 4,
400
+ "-": 4
401
+ };
402
+ var Parser = class {
403
+ constructor(tokens) {
404
+ this.tokens = tokens;
405
+ }
406
+ tokens;
407
+ static {
408
+ __name(this, "Parser");
409
+ }
410
+ pos = 0;
411
+ parse() {
412
+ const expr = this.parseBinary(0);
413
+ const t = this.peek();
414
+ if (t.kind !== "eof") {
415
+ throw new DialogueExprError(`unexpected trailing token "${describe(t)}"`, t.line, t.col);
416
+ }
417
+ return expr;
418
+ }
419
+ parseBinary(minBp) {
420
+ let left = this.parseUnary();
421
+ for (; ; ) {
422
+ const t = this.peek();
423
+ const bp = INFIX_BP[t.kind];
424
+ if (bp === void 0 || bp < minBp) break;
425
+ this.next();
426
+ const right = this.parseBinary(bp + 1);
427
+ left = { kind: "binary", op: t.kind, left, right };
428
+ }
429
+ return left;
430
+ }
431
+ parseUnary() {
432
+ const t = this.peek();
433
+ if (t.kind === "!" || t.kind === "-") {
434
+ this.next();
435
+ const operand = this.parseUnary();
436
+ return { kind: "unary", op: t.kind === "!" ? "!" : "-", operand };
437
+ }
438
+ return this.parsePrimary();
439
+ }
440
+ parsePrimary() {
441
+ const t = this.peek();
442
+ switch (t.kind) {
443
+ case "number":
444
+ case "string":
445
+ this.next();
446
+ return { kind: "literal", value: t.value };
447
+ case "true":
448
+ case "false":
449
+ case "null":
450
+ this.next();
451
+ return { kind: "literal", value: t.value };
452
+ case "ident": {
453
+ this.next();
454
+ const name = t.value;
455
+ if (this.peek().kind === "(") {
456
+ this.next();
457
+ const args = this.parseArgs();
458
+ return { kind: "call", fn: name, args };
459
+ }
460
+ return { kind: "varRef", name };
461
+ }
462
+ case "(": {
463
+ this.next();
464
+ const inner = this.parseBinary(0);
465
+ this.expect(")");
466
+ return { kind: "group", expr: inner };
467
+ }
468
+ default:
469
+ throw new DialogueExprError(`unexpected ${describe(t)}`, t.line, t.col);
470
+ }
471
+ }
472
+ /** Parse a comma-separated argument list; the opening `(` is already consumed. */
473
+ parseArgs() {
474
+ const args = [];
475
+ if (this.peek().kind === ")") {
476
+ this.next();
477
+ return args;
478
+ }
479
+ for (; ; ) {
480
+ args.push(this.parseBinary(0));
481
+ const t = this.peek();
482
+ if (t.kind === ",") {
483
+ this.next();
484
+ continue;
485
+ }
486
+ if (t.kind === ")") {
487
+ this.next();
488
+ return args;
489
+ }
490
+ throw new DialogueExprError(`expected "," or ")" in argument list, got ${describe(t)}`, t.line, t.col);
491
+ }
492
+ }
493
+ expect(kind) {
494
+ const t = this.peek();
495
+ if (t.kind !== kind) {
496
+ throw new DialogueExprError(`expected "${kind}", got ${describe(t)}`, t.line, t.col);
497
+ }
498
+ this.next();
499
+ }
500
+ peek() {
501
+ return this.tokens[this.pos];
502
+ }
503
+ next() {
504
+ return this.tokens[this.pos++];
505
+ }
506
+ };
507
+ function describe(t) {
508
+ if (t.kind === "eof") return "end of input";
509
+ if (t.kind === "ident") return `"${String(t.value)}"`;
510
+ if (t.kind === "string") return `string "${String(t.value)}"`;
511
+ if (t.kind === "number") return `number ${String(t.value)}`;
512
+ return `"${t.kind}"`;
513
+ }
514
+ __name(describe, "describe");
515
+
516
+ // src/core/formats/canonical.ts
517
+ function loadScript(raw) {
518
+ if (!raw || typeof raw !== "object") {
519
+ throw new DialogueScriptError("script must be an object");
520
+ }
521
+ if (!raw.id) throw new DialogueScriptError("script.id is required");
522
+ if (!raw.nodes || typeof raw.nodes !== "object") {
523
+ throw new DialogueScriptError(`script "${raw.id}" has no nodes`);
524
+ }
525
+ const nodeIds = Object.keys(raw.nodes);
526
+ if (nodeIds.length === 0) {
527
+ throw new DialogueScriptError(`script "${raw.id}" has no nodes`);
528
+ }
529
+ const start = raw.start ?? nodeIds[0];
530
+ if (!raw.nodes[start]) {
531
+ throw new DialogueScriptError(`start node "${start}" not found in "${raw.id}"`);
532
+ }
533
+ for (const [key, speaker] of Object.entries(raw.speakers ?? {})) {
534
+ if (speaker.id !== key) {
535
+ throw new DialogueScriptError(
536
+ `speaker key "${key}" != speaker.id "${speaker.id}"`
537
+ );
538
+ }
539
+ }
540
+ for (const [id, node] of Object.entries(raw.nodes)) {
541
+ validateNode(raw, id, node);
542
+ }
543
+ const resolved = resolveExpressions(raw);
544
+ const script = Object.freeze({ ...resolved, start });
545
+ analyzeScript(script);
546
+ return script;
547
+ }
548
+ __name(loadScript, "loadScript");
549
+ function validateNode(script, id, node) {
550
+ if (node.id !== id) {
551
+ throw new DialogueScriptError(`node key "${id}" != node.id "${node.id}"`);
552
+ }
553
+ if (!Array.isArray(node.steps) || node.steps.length === 0) {
554
+ throw new DialogueScriptError(`node "${id}" has no steps`);
555
+ }
556
+ for (const step of node.steps) validateStep(script, id, step);
557
+ }
558
+ __name(validateNode, "validateNode");
559
+ function validateStep(script, nodeId, step) {
560
+ const targetExists = /* @__PURE__ */ __name((t) => {
561
+ if (t !== void 0 && !script.nodes[t]) {
562
+ throw new DialogueScriptError(
563
+ `node "${nodeId}": jump target "${t}" does not exist`
564
+ );
565
+ }
566
+ }, "targetExists");
567
+ const speakerExists = /* @__PURE__ */ __name((s) => {
568
+ if (s !== void 0 && !script.speakers?.[s]) {
569
+ throw new DialogueScriptError(
570
+ `node "${nodeId}": speaker "${s}" is not in script.speakers`
571
+ );
572
+ }
573
+ }, "speakerExists");
574
+ switch (step.kind) {
575
+ case "say":
576
+ if (typeof step.text !== "string") {
577
+ throw new DialogueScriptError(`node "${nodeId}": say.text must be a string`);
578
+ }
579
+ speakerExists(step.speaker);
580
+ break;
581
+ case "choice":
582
+ if (!Array.isArray(step.options) || step.options.length === 0) {
583
+ throw new DialogueScriptError(`node "${nodeId}": choice has no options`);
584
+ }
585
+ speakerExists(step.speaker);
586
+ for (const opt of step.options) targetExists(opt.target);
587
+ break;
588
+ case "command":
589
+ targetExists(step.target);
590
+ break;
591
+ case "goto":
592
+ if (step.target === void 0) {
593
+ throw new DialogueScriptError(`node "${nodeId}": goto has no target`);
594
+ }
595
+ targetExists(step.target);
596
+ break;
597
+ case "end":
598
+ break;
599
+ default:
600
+ throw new DialogueScriptError(
601
+ `node "${nodeId}": unknown step kind "${step.kind}"`
602
+ );
603
+ }
604
+ }
605
+ __name(validateStep, "validateStep");
606
+ function resolveExpressions(script) {
607
+ let nodesChanged = false;
608
+ const nodes = {};
609
+ for (const [id, node] of Object.entries(script.nodes)) {
610
+ let stepsChanged = false;
611
+ const steps = node.steps.map((step) => {
612
+ const next = resolveStep(step);
613
+ if (next !== step) stepsChanged = true;
614
+ return next;
615
+ });
616
+ if (stepsChanged) {
617
+ nodes[id] = { ...node, steps };
618
+ nodesChanged = true;
619
+ } else {
620
+ nodes[id] = node;
621
+ }
622
+ }
623
+ return nodesChanged ? { ...script, nodes } : script;
624
+ }
625
+ __name(resolveExpressions, "resolveExpressions");
626
+ function resolveStep(step) {
627
+ switch (step.kind) {
628
+ case "say":
629
+ return resolveSay(step);
630
+ case "choice":
631
+ return resolveChoice(step);
632
+ case "command":
633
+ return resolveCommandStep(step);
634
+ case "goto":
635
+ case "end":
636
+ return step;
637
+ }
638
+ }
639
+ __name(resolveStep, "resolveStep");
640
+ function resolveSay(step) {
641
+ const commands = rewriteCommands(step.commands);
642
+ return commands ? { ...step, commands } : step;
643
+ }
644
+ __name(resolveSay, "resolveSay");
645
+ function resolveCommandStep(step) {
646
+ const condition = rewriteCondition(step.condition);
647
+ const commands = rewriteCommands(step.commands);
648
+ if (!condition && !commands) return step;
649
+ return {
650
+ ...step,
651
+ ...condition ? { condition } : {},
652
+ ...commands ? { commands } : {}
653
+ };
654
+ }
655
+ __name(resolveCommandStep, "resolveCommandStep");
656
+ function resolveChoice(step) {
657
+ let changed = false;
658
+ const options = step.options.map((opt) => {
659
+ const next = rewriteOption(opt);
660
+ if (next) {
661
+ changed = true;
662
+ return next;
663
+ }
664
+ return opt;
665
+ });
666
+ return changed ? { ...step, options } : step;
667
+ }
668
+ __name(resolveChoice, "resolveChoice");
669
+ function rewriteOption(opt) {
670
+ const condition = rewriteCondition(opt.condition);
671
+ const commands = rewriteCommands(opt.commands);
672
+ if (!condition && !commands) return void 0;
673
+ return {
674
+ ...opt,
675
+ ...condition ? { condition } : {},
676
+ ...commands ? { commands } : {}
677
+ };
678
+ }
679
+ __name(rewriteOption, "rewriteOption");
680
+ function rewriteCondition(condition) {
681
+ return typeof condition === "string" ? parseExpr(condition) : void 0;
682
+ }
683
+ __name(rewriteCondition, "rewriteCondition");
684
+ function rewriteCommands(commands) {
685
+ if (!commands) return void 0;
686
+ let changed = false;
687
+ const out = commands.map((cmd) => {
688
+ if (cmd.type === "set" && typeof cmd.value === "string") {
689
+ changed = true;
690
+ return { ...cmd, value: parseExpr(cmd.value) };
691
+ }
692
+ return cmd;
693
+ });
694
+ return changed ? out : void 0;
695
+ }
696
+ __name(rewriteCommands, "rewriteCommands");
697
+
698
+ // src/core/formats/yaml.ts
699
+ function loadYaml(text) {
700
+ let raw;
701
+ try {
702
+ raw = (0, import_yaml.parse)(text);
703
+ } catch (e) {
704
+ throw new DialogueScriptError(
705
+ `YAML parse error: ${e instanceof Error ? e.message : String(e)}`
706
+ );
707
+ }
708
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
709
+ throw new DialogueScriptError(
710
+ `YAML root must be a mapping (the script object), got ${describeRoot(raw, text)}`
711
+ );
712
+ }
713
+ return loadScript(raw);
714
+ }
715
+ __name(loadYaml, "loadYaml");
716
+ function describeRoot(v, text) {
717
+ if (v === null) return text.trim() === "" ? "an empty document" : "null";
718
+ if (Array.isArray(v)) return "an array";
719
+ return `a ${typeof v}`;
720
+ }
721
+ __name(describeRoot, "describeRoot");
722
+ // Annotate the CommonJS export names for ESM import in node:
723
+ 0 && (module.exports = {
724
+ loadYaml
725
+ });
726
+ //# sourceMappingURL=yaml.cjs.map