@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/DialogueController-BMeNLi0v.d.cts +1204 -0
- package/dist/DialogueController-Cs5IUc-u.d.ts +1204 -0
- package/dist/chunk-7QVYU63E.js +7 -0
- package/dist/chunk-7QVYU63E.js.map +1 -0
- package/dist/chunk-CU47RPEB.js +410 -0
- package/dist/chunk-CU47RPEB.js.map +1 -0
- package/dist/chunk-GJQKZCOL.js +983 -0
- package/dist/chunk-GJQKZCOL.js.map +1 -0
- package/dist/index.cjs +3441 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +591 -0
- package/dist/index.d.ts +591 -0
- package/dist/index.js +2048 -0
- package/dist/index.js.map +1 -0
- package/dist/presenters.cjs +3149 -0
- package/dist/presenters.cjs.map +1 -0
- package/dist/presenters.d.cts +1817 -0
- package/dist/presenters.d.ts +1817 -0
- package/dist/presenters.js +2920 -0
- package/dist/presenters.js.map +1 -0
- package/dist/types-DSbBSlh7.d.cts +375 -0
- package/dist/types-DSbBSlh7.d.ts +375 -0
- package/dist/yaml.cjs +726 -0
- package/dist/yaml.cjs.map +1 -0
- package/dist/yaml.d.cts +23 -0
- package/dist/yaml.d.ts +23 -0
- package/dist/yaml.js +37 -0
- package/dist/yaml.js.map +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,983 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__name
|
|
3
|
+
} from "./chunk-7QVYU63E.js";
|
|
4
|
+
|
|
5
|
+
// src/core/vars.ts
|
|
6
|
+
function materialize(storage) {
|
|
7
|
+
const out = {};
|
|
8
|
+
for (const [name, value] of storage.entries()) out[name] = value;
|
|
9
|
+
return out;
|
|
10
|
+
}
|
|
11
|
+
__name(materialize, "materialize");
|
|
12
|
+
var MemoryVariableStorage = class {
|
|
13
|
+
static {
|
|
14
|
+
__name(this, "MemoryVariableStorage");
|
|
15
|
+
}
|
|
16
|
+
map = /* @__PURE__ */ new Map();
|
|
17
|
+
constructor(initial) {
|
|
18
|
+
if (initial) for (const [name, value] of Object.entries(initial)) this.map.set(name, value);
|
|
19
|
+
}
|
|
20
|
+
get(name) {
|
|
21
|
+
return this.map.get(name);
|
|
22
|
+
}
|
|
23
|
+
set(name, value) {
|
|
24
|
+
this.map.set(name, value);
|
|
25
|
+
}
|
|
26
|
+
has(name) {
|
|
27
|
+
return this.map.has(name);
|
|
28
|
+
}
|
|
29
|
+
entries() {
|
|
30
|
+
return this.map.entries();
|
|
31
|
+
}
|
|
32
|
+
/** Drop everything — host-controlled reset (variables persist across plays by default). */
|
|
33
|
+
clear() {
|
|
34
|
+
this.map.clear();
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
function cells(defs) {
|
|
38
|
+
const read = /* @__PURE__ */ __name((name) => {
|
|
39
|
+
const cell = defs[name];
|
|
40
|
+
return typeof cell === "function" ? cell() : cell.get();
|
|
41
|
+
}, "read");
|
|
42
|
+
return {
|
|
43
|
+
get(name) {
|
|
44
|
+
return Object.hasOwn(defs, name) ? read(name) : void 0;
|
|
45
|
+
},
|
|
46
|
+
set(name, value) {
|
|
47
|
+
if (!Object.hasOwn(defs, name)) {
|
|
48
|
+
throw new Error(`dialogue: cells() has no accessor for "${name}"`);
|
|
49
|
+
}
|
|
50
|
+
const cell = defs[name];
|
|
51
|
+
if (typeof cell === "function" || cell.set === void 0) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
`dialogue: "${name}" is read-only (a cells getter without a setter)`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
cell.set(value);
|
|
57
|
+
},
|
|
58
|
+
has(name) {
|
|
59
|
+
return Object.hasOwn(defs, name);
|
|
60
|
+
},
|
|
61
|
+
*entries() {
|
|
62
|
+
for (const name of Object.keys(defs)) yield [name, read(name)];
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
__name(cells, "cells");
|
|
67
|
+
function compose(...storages) {
|
|
68
|
+
if (storages.length === 0) {
|
|
69
|
+
throw new Error("dialogue: compose() needs at least one storage");
|
|
70
|
+
}
|
|
71
|
+
const last = storages[storages.length - 1];
|
|
72
|
+
return {
|
|
73
|
+
get(name) {
|
|
74
|
+
for (const s of storages) if (s.has(name)) return s.get(name);
|
|
75
|
+
return void 0;
|
|
76
|
+
},
|
|
77
|
+
set(name, value) {
|
|
78
|
+
for (const s of storages) {
|
|
79
|
+
if (s.has(name)) {
|
|
80
|
+
s.set(name, value);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
last.set(name, value);
|
|
85
|
+
},
|
|
86
|
+
has(name) {
|
|
87
|
+
return storages.some((s) => s.has(name));
|
|
88
|
+
},
|
|
89
|
+
*entries() {
|
|
90
|
+
const seen = /* @__PURE__ */ new Set();
|
|
91
|
+
for (const s of storages) {
|
|
92
|
+
for (const [name, value] of s.entries()) {
|
|
93
|
+
if (!seen.has(name)) {
|
|
94
|
+
seen.add(name);
|
|
95
|
+
yield [name, value];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
__name(compose, "compose");
|
|
103
|
+
|
|
104
|
+
// src/core/expr.ts
|
|
105
|
+
function createScope(storage, functions) {
|
|
106
|
+
return {
|
|
107
|
+
get: /* @__PURE__ */ __name((name) => storage.get(name) ?? null, "get"),
|
|
108
|
+
call: /* @__PURE__ */ __name((fn, args) => {
|
|
109
|
+
const f = functions[fn];
|
|
110
|
+
if (!f) throw new Error(`dialogue: no function "${fn}" is installed`);
|
|
111
|
+
return f(...args);
|
|
112
|
+
}, "call"),
|
|
113
|
+
vars: /* @__PURE__ */ __name(() => materialize(storage), "vars")
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
__name(createScope, "createScope");
|
|
117
|
+
function holds(condition, scope) {
|
|
118
|
+
return condition === void 0 ? true : evalCondition(condition, scope);
|
|
119
|
+
}
|
|
120
|
+
__name(holds, "holds");
|
|
121
|
+
function evalCondition(condition, scope) {
|
|
122
|
+
if (typeof condition === "function") return condition(scope.vars());
|
|
123
|
+
if (typeof condition === "string") return truthy(scope.get(condition));
|
|
124
|
+
if (isExpr(condition)) return truthy(evaluate(condition, scope));
|
|
125
|
+
const { var: name, op, value } = condition;
|
|
126
|
+
if (op === "truthy") return truthy(scope.get(name));
|
|
127
|
+
if (op === "falsy") return !truthy(scope.get(name));
|
|
128
|
+
return truthy(
|
|
129
|
+
evaluate(
|
|
130
|
+
{
|
|
131
|
+
kind: "binary",
|
|
132
|
+
op,
|
|
133
|
+
left: { kind: "varRef", name },
|
|
134
|
+
right: { kind: "literal", value }
|
|
135
|
+
},
|
|
136
|
+
scope
|
|
137
|
+
)
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
__name(evalCondition, "evalCondition");
|
|
141
|
+
function evaluate(expr, scope) {
|
|
142
|
+
switch (expr.kind) {
|
|
143
|
+
case "literal":
|
|
144
|
+
return expr.value;
|
|
145
|
+
case "varRef":
|
|
146
|
+
return scope.get(expr.name);
|
|
147
|
+
case "group":
|
|
148
|
+
return evaluate(expr.expr, scope);
|
|
149
|
+
case "call":
|
|
150
|
+
return scope.call(
|
|
151
|
+
expr.fn,
|
|
152
|
+
(expr.args ?? []).map((a) => evaluate(a, scope))
|
|
153
|
+
);
|
|
154
|
+
case "unary":
|
|
155
|
+
return applyUnary(expr.op, evaluate(expr.operand, scope));
|
|
156
|
+
case "binary": {
|
|
157
|
+
const { op } = expr;
|
|
158
|
+
if (op === "and" || op === "&&") {
|
|
159
|
+
return truthy(evaluate(expr.left, scope)) && truthy(evaluate(expr.right, scope));
|
|
160
|
+
}
|
|
161
|
+
if (op === "or" || op === "||") {
|
|
162
|
+
return truthy(evaluate(expr.left, scope)) || truthy(evaluate(expr.right, scope));
|
|
163
|
+
}
|
|
164
|
+
return applyBinary(op, evaluate(expr.left, scope), evaluate(expr.right, scope));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
__name(evaluate, "evaluate");
|
|
169
|
+
function isExpr(value) {
|
|
170
|
+
return typeof value === "object" && value !== null && "kind" in value;
|
|
171
|
+
}
|
|
172
|
+
__name(isExpr, "isExpr");
|
|
173
|
+
function truthy(value) {
|
|
174
|
+
return Boolean(value);
|
|
175
|
+
}
|
|
176
|
+
__name(truthy, "truthy");
|
|
177
|
+
function applyUnary(op, v) {
|
|
178
|
+
switch (op) {
|
|
179
|
+
case "not":
|
|
180
|
+
case "!":
|
|
181
|
+
return !truthy(v);
|
|
182
|
+
case "-":
|
|
183
|
+
return -num(v);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
__name(applyUnary, "applyUnary");
|
|
187
|
+
function applyBinary(op, l, r) {
|
|
188
|
+
switch (op) {
|
|
189
|
+
case "==":
|
|
190
|
+
case "eq":
|
|
191
|
+
case "is":
|
|
192
|
+
return l === r;
|
|
193
|
+
case "!=":
|
|
194
|
+
case "neq":
|
|
195
|
+
return l !== r;
|
|
196
|
+
case ">":
|
|
197
|
+
case "gt":
|
|
198
|
+
return num(l) > num(r);
|
|
199
|
+
case "<":
|
|
200
|
+
case "lt":
|
|
201
|
+
return num(l) < num(r);
|
|
202
|
+
case ">=":
|
|
203
|
+
case "gte":
|
|
204
|
+
return num(l) >= num(r);
|
|
205
|
+
case "<=":
|
|
206
|
+
case "lte":
|
|
207
|
+
return num(l) <= num(r);
|
|
208
|
+
// `and`/`or` (and `&&`/`||`) are short-circuited in evaluate() and never
|
|
209
|
+
// reach here; `xor` needs both operands, so it stays.
|
|
210
|
+
case "xor":
|
|
211
|
+
case "^":
|
|
212
|
+
return truthy(l) !== truthy(r);
|
|
213
|
+
case "+":
|
|
214
|
+
return typeof l === "string" || typeof r === "string" ? `${str(l)}${str(r)}` : num(l) + num(r);
|
|
215
|
+
case "-":
|
|
216
|
+
return num(l) - num(r);
|
|
217
|
+
case "*":
|
|
218
|
+
return num(l) * num(r);
|
|
219
|
+
case "/":
|
|
220
|
+
return num(l) / num(r);
|
|
221
|
+
case "%":
|
|
222
|
+
return num(l) % num(r);
|
|
223
|
+
default:
|
|
224
|
+
throw new Error(`dialogue: unknown binary operator "${op}"`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
__name(applyBinary, "applyBinary");
|
|
228
|
+
function num(v) {
|
|
229
|
+
return typeof v === "number" ? v : Number(v);
|
|
230
|
+
}
|
|
231
|
+
__name(num, "num");
|
|
232
|
+
function str(v) {
|
|
233
|
+
return v === null ? "" : String(v);
|
|
234
|
+
}
|
|
235
|
+
__name(str, "str");
|
|
236
|
+
|
|
237
|
+
// src/core/i18n.ts
|
|
238
|
+
var IdentityI18n = class {
|
|
239
|
+
constructor(locale = "en") {
|
|
240
|
+
this.locale = locale;
|
|
241
|
+
}
|
|
242
|
+
locale;
|
|
243
|
+
static {
|
|
244
|
+
__name(this, "IdentityI18n");
|
|
245
|
+
}
|
|
246
|
+
t(_key, fallback, params) {
|
|
247
|
+
return params ? interpolate(fallback, params) : fallback;
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
var TOKEN = /\{(\w+)\}/g;
|
|
251
|
+
function interpolate(text, params) {
|
|
252
|
+
return text.replace(
|
|
253
|
+
TOKEN,
|
|
254
|
+
(whole, name) => Object.hasOwn(params, name) ? String(params[name]) : whole
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
__name(interpolate, "interpolate");
|
|
258
|
+
function tokensIn(text) {
|
|
259
|
+
const names = /* @__PURE__ */ new Set();
|
|
260
|
+
for (const m of text.matchAll(TOKEN)) names.add(m[1]);
|
|
261
|
+
return [...names];
|
|
262
|
+
}
|
|
263
|
+
__name(tokensIn, "tokensIn");
|
|
264
|
+
|
|
265
|
+
// src/core/validate.ts
|
|
266
|
+
var DialogueScriptError = class extends Error {
|
|
267
|
+
static {
|
|
268
|
+
__name(this, "DialogueScriptError");
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
var DialoguePlayError = class extends Error {
|
|
272
|
+
static {
|
|
273
|
+
__name(this, "DialoguePlayError");
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
var NUMERIC_OPS = /* @__PURE__ */ new Set([">", ">=", "<", "<="]);
|
|
277
|
+
var NUMERIC_EXPR_OPS = /* @__PURE__ */ new Set([
|
|
278
|
+
">",
|
|
279
|
+
"<",
|
|
280
|
+
">=",
|
|
281
|
+
"<=",
|
|
282
|
+
"gt",
|
|
283
|
+
"lt",
|
|
284
|
+
"gte",
|
|
285
|
+
"lte",
|
|
286
|
+
"-",
|
|
287
|
+
"*",
|
|
288
|
+
"/",
|
|
289
|
+
"%"
|
|
290
|
+
]);
|
|
291
|
+
var BUILTIN_COMMANDS = /* @__PURE__ */ new Set(["set"]);
|
|
292
|
+
function operandRequirement(op) {
|
|
293
|
+
if (op === "+") return "numberOrString";
|
|
294
|
+
return NUMERIC_EXPR_OPS.has(op) ? "number" : null;
|
|
295
|
+
}
|
|
296
|
+
__name(operandRequirement, "operandRequirement");
|
|
297
|
+
var analysisCache = /* @__PURE__ */ new WeakMap();
|
|
298
|
+
function analyzeScript(script) {
|
|
299
|
+
const cached = analysisCache.get(script);
|
|
300
|
+
if (cached) return cached;
|
|
301
|
+
const analysis = computeAnalysis(script);
|
|
302
|
+
analysisCache.set(script, analysis);
|
|
303
|
+
return analysis;
|
|
304
|
+
}
|
|
305
|
+
__name(analyzeScript, "analyzeScript");
|
|
306
|
+
function computeAnalysis(script) {
|
|
307
|
+
const declaredTypes = /* @__PURE__ */ new Map();
|
|
308
|
+
for (const [name, value] of Object.entries(script.declare ?? {})) {
|
|
309
|
+
declaredTypes.set(name, valueType(value));
|
|
310
|
+
}
|
|
311
|
+
const readVars = /* @__PURE__ */ new Set();
|
|
312
|
+
const setTargets = /* @__PURE__ */ new Set();
|
|
313
|
+
const calledFunctions = /* @__PURE__ */ new Set();
|
|
314
|
+
const commandTypes = /* @__PURE__ */ new Set();
|
|
315
|
+
const collectExpr = /* @__PURE__ */ __name((expr, where) => {
|
|
316
|
+
switch (expr.kind) {
|
|
317
|
+
case "literal":
|
|
318
|
+
return;
|
|
319
|
+
case "varRef":
|
|
320
|
+
readVars.add(expr.name);
|
|
321
|
+
return;
|
|
322
|
+
case "call":
|
|
323
|
+
calledFunctions.add(expr.fn);
|
|
324
|
+
for (const arg of expr.args ?? []) collectExpr(arg, where);
|
|
325
|
+
return;
|
|
326
|
+
case "group":
|
|
327
|
+
collectExpr(expr.expr, where);
|
|
328
|
+
return;
|
|
329
|
+
case "unary":
|
|
330
|
+
collectExpr(expr.operand, where);
|
|
331
|
+
return;
|
|
332
|
+
case "binary":
|
|
333
|
+
collectExpr(expr.left, where);
|
|
334
|
+
collectExpr(expr.right, where);
|
|
335
|
+
checkBinaryOperands(expr, where);
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
}, "collectExpr");
|
|
339
|
+
const checkBinaryOperands = /* @__PURE__ */ __name((expr, where) => {
|
|
340
|
+
const req = operandRequirement(expr.op);
|
|
341
|
+
if (!req) return;
|
|
342
|
+
const expected = req === "numberOrString" ? "a number or string" : "a number";
|
|
343
|
+
for (const operand of [expr.left, expr.right]) {
|
|
344
|
+
if (operand.kind === "literal") {
|
|
345
|
+
const t = valueType(operand.value);
|
|
346
|
+
if (t === "number" || req === "numberOrString" && t === "string") continue;
|
|
347
|
+
throw new DialogueScriptError(
|
|
348
|
+
`${where}: operator "${expr.op}" expects ${expected}, got ${t}`
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
if (operand.kind === "varRef" && req === "number") {
|
|
352
|
+
const t = declaredTypes.get(operand.name);
|
|
353
|
+
if (t !== void 0 && t !== "number" && t !== "null") {
|
|
354
|
+
throw new DialogueScriptError(
|
|
355
|
+
`${where}: operator "${expr.op}" needs a number; "${operand.name}" is ${t}`
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}, "checkBinaryOperands");
|
|
361
|
+
const checkTokens = /* @__PURE__ */ __name((text) => {
|
|
362
|
+
if (!text) return;
|
|
363
|
+
for (const token of tokensIn(text)) readVars.add(token);
|
|
364
|
+
}, "checkTokens");
|
|
365
|
+
const checkCondition = /* @__PURE__ */ __name((condition, where) => {
|
|
366
|
+
if (condition === void 0 || typeof condition === "function") return;
|
|
367
|
+
if (typeof condition === "string") {
|
|
368
|
+
readVars.add(condition);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
if (isExpr(condition)) {
|
|
372
|
+
collectExpr(condition, where);
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
readVars.add(condition.var);
|
|
376
|
+
if (NUMERIC_OPS.has(condition.op)) {
|
|
377
|
+
const t = declaredTypes.get(condition.var);
|
|
378
|
+
if (t !== void 0 && t !== "number" && t !== "null") {
|
|
379
|
+
throw new DialogueScriptError(
|
|
380
|
+
`${where}: operator "${condition.op}" needs a number; "${condition.var}" is ${t}`
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
if (typeof condition.value !== "number") {
|
|
384
|
+
throw new DialogueScriptError(
|
|
385
|
+
`${where}: operator "${condition.op}" compares against a number, got ${typeof condition.value}`
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}, "checkCondition");
|
|
390
|
+
const checkSetLiteralType = /* @__PURE__ */ __name((target, value, where) => {
|
|
391
|
+
const declared = declaredTypes.get(target);
|
|
392
|
+
if (declared !== void 0 && declared !== "null" && value !== null && typeof value !== declared) {
|
|
393
|
+
throw new DialogueScriptError(
|
|
394
|
+
`${where}: set "${target}" expects ${declared}, got ${typeof value}`
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
}, "checkSetLiteralType");
|
|
398
|
+
const checkCommands = /* @__PURE__ */ __name((commands, where) => {
|
|
399
|
+
for (const cmd of commands ?? []) {
|
|
400
|
+
if (cmd.type === "set") {
|
|
401
|
+
const target = cmd["var"];
|
|
402
|
+
if (typeof target !== "string") {
|
|
403
|
+
throw new DialogueScriptError(`${where}: set command has no string "var"`);
|
|
404
|
+
}
|
|
405
|
+
setTargets.add(target);
|
|
406
|
+
const value = cmd["value"];
|
|
407
|
+
if (value === void 0) {
|
|
408
|
+
throw new DialogueScriptError(`${where}: set "${target}" has no value`);
|
|
409
|
+
}
|
|
410
|
+
if (isExpr(value)) {
|
|
411
|
+
collectExpr(value, where);
|
|
412
|
+
if (value.kind === "literal") checkSetLiteralType(target, value.value, where);
|
|
413
|
+
} else {
|
|
414
|
+
checkSetLiteralType(target, value, where);
|
|
415
|
+
}
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
if (!BUILTIN_COMMANDS.has(cmd.type)) commandTypes.add(cmd.type);
|
|
419
|
+
}
|
|
420
|
+
}, "checkCommands");
|
|
421
|
+
for (const speaker of Object.values(script.speakers ?? {})) {
|
|
422
|
+
checkTokens(speaker.name);
|
|
423
|
+
}
|
|
424
|
+
for (const node of Object.values(script.nodes)) {
|
|
425
|
+
const where = `node "${node.id}"`;
|
|
426
|
+
for (const step of node.steps) {
|
|
427
|
+
switch (step.kind) {
|
|
428
|
+
case "say": {
|
|
429
|
+
const s = step;
|
|
430
|
+
checkTokens(s.text);
|
|
431
|
+
checkCommands(s.commands, `${where} say`);
|
|
432
|
+
break;
|
|
433
|
+
}
|
|
434
|
+
case "choice": {
|
|
435
|
+
const c = step;
|
|
436
|
+
checkTokens(c.text);
|
|
437
|
+
for (const opt of c.options) {
|
|
438
|
+
checkTokens(opt.text);
|
|
439
|
+
checkTokens(opt.disabledReason);
|
|
440
|
+
checkCondition(opt.condition, `${where} choice option "${opt.text}"`);
|
|
441
|
+
checkCommands(opt.commands, `${where} choice option "${opt.text}"`);
|
|
442
|
+
}
|
|
443
|
+
break;
|
|
444
|
+
}
|
|
445
|
+
case "command": {
|
|
446
|
+
const cs = step;
|
|
447
|
+
checkCommands(cs.commands, `${where} command`);
|
|
448
|
+
checkCondition(cs.condition, `${where} command`);
|
|
449
|
+
break;
|
|
450
|
+
}
|
|
451
|
+
default:
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
return { declaredTypes, readVars, setTargets, calledFunctions, commandTypes };
|
|
457
|
+
}
|
|
458
|
+
__name(computeAnalysis, "computeAnalysis");
|
|
459
|
+
function validatePlay(analysis, env) {
|
|
460
|
+
for (const [name, type] of analysis.declaredTypes) {
|
|
461
|
+
if (type === "null" || !env.storage.has(name)) continue;
|
|
462
|
+
const current = env.storage.get(name);
|
|
463
|
+
if (current !== void 0 && current !== null && typeof current !== type) {
|
|
464
|
+
throw new DialoguePlayError(
|
|
465
|
+
`declared default for "${name}" is ${type} but storage already holds ${typeof current}`
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
for (const name of analysis.readVars) {
|
|
470
|
+
if (!analysis.declaredTypes.has(name) && !env.storage.has(name) && !analysis.setTargets.has(name)) {
|
|
471
|
+
throw new DialoguePlayError(
|
|
472
|
+
`script reads "${name}" but nothing provides it (no declared default, no storage value, no \`set\`; for an argument read use a function call)`
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
for (const fn of analysis.calledFunctions) {
|
|
477
|
+
if (!Object.hasOwn(env.functions, fn)) {
|
|
478
|
+
throw new DialoguePlayError(
|
|
479
|
+
`script calls function "${fn}" but no such function is installed`
|
|
480
|
+
);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
for (const target of analysis.setTargets) {
|
|
484
|
+
if (Object.hasOwn(env.functions, target)) {
|
|
485
|
+
throw new DialoguePlayError(
|
|
486
|
+
`set target "${target}" is a function (read-only); functions cannot be assigned`
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
if (env.fallbackCommand === void 0) {
|
|
491
|
+
const unhandled = [...analysis.commandTypes].filter((t) => !Object.hasOwn(env.commands, t));
|
|
492
|
+
if (unhandled.length > 0) {
|
|
493
|
+
throw new DialoguePlayError(
|
|
494
|
+
`no handler for command type(s): ${unhandled.join(", ")} (add to commands, or set fallbackCommand)`
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
__name(validatePlay, "validatePlay");
|
|
500
|
+
function valueType(value) {
|
|
501
|
+
if (value === null) return "null";
|
|
502
|
+
if (typeof value === "string") return "string";
|
|
503
|
+
if (typeof value === "number") return "number";
|
|
504
|
+
return "boolean";
|
|
505
|
+
}
|
|
506
|
+
__name(valueType, "valueType");
|
|
507
|
+
|
|
508
|
+
// src/core/expr-parse.ts
|
|
509
|
+
var DialogueExprError = class extends DialogueScriptError {
|
|
510
|
+
static {
|
|
511
|
+
__name(this, "DialogueExprError");
|
|
512
|
+
}
|
|
513
|
+
line;
|
|
514
|
+
col;
|
|
515
|
+
constructor(message, line, col) {
|
|
516
|
+
super(`${message} (at ${line}:${col})`);
|
|
517
|
+
this.name = "DialogueExprError";
|
|
518
|
+
this.line = line;
|
|
519
|
+
this.col = col;
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
function parseExpr(src) {
|
|
523
|
+
const tokens = tokenize(src);
|
|
524
|
+
return new Parser(tokens).parse();
|
|
525
|
+
}
|
|
526
|
+
__name(parseExpr, "parseExpr");
|
|
527
|
+
var KEYWORDS = {
|
|
528
|
+
and: "&&",
|
|
529
|
+
or: "||",
|
|
530
|
+
not: "!",
|
|
531
|
+
xor: "xor",
|
|
532
|
+
is: "==",
|
|
533
|
+
eq: "==",
|
|
534
|
+
neq: "!=",
|
|
535
|
+
gt: ">",
|
|
536
|
+
lt: "<",
|
|
537
|
+
gte: ">=",
|
|
538
|
+
lte: "<=",
|
|
539
|
+
true: "true",
|
|
540
|
+
false: "false",
|
|
541
|
+
null: "null"
|
|
542
|
+
};
|
|
543
|
+
var isDigit = /* @__PURE__ */ __name((c) => c >= "0" && c <= "9", "isDigit");
|
|
544
|
+
var isIdentStart = /* @__PURE__ */ __name((c) => c >= "A" && c <= "Z" || c >= "a" && c <= "z" || c === "_" || c === "$", "isIdentStart");
|
|
545
|
+
var isIdentPart = /* @__PURE__ */ __name((c) => isIdentStart(c) || isDigit(c) || c === ".", "isIdentPart");
|
|
546
|
+
function tokenize(src) {
|
|
547
|
+
const tokens = [];
|
|
548
|
+
let i = 0;
|
|
549
|
+
let line = 1;
|
|
550
|
+
let col = 1;
|
|
551
|
+
const advance = /* @__PURE__ */ __name((n = 1) => {
|
|
552
|
+
for (let k = 0; k < n; k++) {
|
|
553
|
+
if (src[i] === "\n") {
|
|
554
|
+
line++;
|
|
555
|
+
col = 1;
|
|
556
|
+
} else {
|
|
557
|
+
col++;
|
|
558
|
+
}
|
|
559
|
+
i++;
|
|
560
|
+
}
|
|
561
|
+
}, "advance");
|
|
562
|
+
while (i < src.length) {
|
|
563
|
+
const c = src[i];
|
|
564
|
+
if (c === " " || c === " " || c === "\n" || c === "\r") {
|
|
565
|
+
advance();
|
|
566
|
+
continue;
|
|
567
|
+
}
|
|
568
|
+
const startLine = line;
|
|
569
|
+
const startCol = col;
|
|
570
|
+
if (isDigit(c)) {
|
|
571
|
+
let text = "";
|
|
572
|
+
while (i < src.length && isDigit(src[i])) {
|
|
573
|
+
text += src[i];
|
|
574
|
+
advance();
|
|
575
|
+
}
|
|
576
|
+
if (src[i] === "." && isDigit(src[i + 1] ?? "")) {
|
|
577
|
+
text += ".";
|
|
578
|
+
advance();
|
|
579
|
+
while (i < src.length && isDigit(src[i])) {
|
|
580
|
+
text += src[i];
|
|
581
|
+
advance();
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
tokens.push({ kind: "number", value: Number(text), line: startLine, col: startCol });
|
|
585
|
+
continue;
|
|
586
|
+
}
|
|
587
|
+
if (c === "'" || c === '"') {
|
|
588
|
+
const quote = c;
|
|
589
|
+
advance();
|
|
590
|
+
let text = "";
|
|
591
|
+
while (i < src.length && src[i] !== quote) {
|
|
592
|
+
if (src[i] === "\\") {
|
|
593
|
+
advance();
|
|
594
|
+
if (i >= src.length) break;
|
|
595
|
+
text += unescape(src[i]);
|
|
596
|
+
} else {
|
|
597
|
+
text += src[i];
|
|
598
|
+
}
|
|
599
|
+
advance();
|
|
600
|
+
}
|
|
601
|
+
if (src[i] !== quote) {
|
|
602
|
+
throw new DialogueExprError("unterminated string literal", startLine, startCol);
|
|
603
|
+
}
|
|
604
|
+
advance();
|
|
605
|
+
tokens.push({ kind: "string", value: text, line: startLine, col: startCol });
|
|
606
|
+
continue;
|
|
607
|
+
}
|
|
608
|
+
if (isIdentStart(c)) {
|
|
609
|
+
let text = "";
|
|
610
|
+
while (i < src.length && isIdentPart(src[i])) {
|
|
611
|
+
text += src[i];
|
|
612
|
+
advance();
|
|
613
|
+
}
|
|
614
|
+
const keyword = KEYWORDS[text];
|
|
615
|
+
if (keyword === void 0) {
|
|
616
|
+
tokens.push({ kind: "ident", value: text, line: startLine, col: startCol });
|
|
617
|
+
} else if (keyword === "true" || keyword === "false" || keyword === "null") {
|
|
618
|
+
const value = keyword === "true" ? true : keyword === "false" ? false : null;
|
|
619
|
+
tokens.push({ kind: keyword, value, line: startLine, col: startCol });
|
|
620
|
+
} else {
|
|
621
|
+
tokens.push({ kind: keyword, line: startLine, col: startCol });
|
|
622
|
+
}
|
|
623
|
+
continue;
|
|
624
|
+
}
|
|
625
|
+
const two = src.slice(i, i + 2);
|
|
626
|
+
if (two === "&&" || two === "||" || two === "==" || two === "!=" || two === ">=" || two === "<=") {
|
|
627
|
+
tokens.push({ kind: two, line: startLine, col: startCol });
|
|
628
|
+
advance(2);
|
|
629
|
+
continue;
|
|
630
|
+
}
|
|
631
|
+
if (c === ">" || c === "<" || c === "!" || c === "+" || c === "-" || c === "(" || c === ")" || c === ",") {
|
|
632
|
+
tokens.push({ kind: c, line: startLine, col: startCol });
|
|
633
|
+
advance();
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
throw new DialogueExprError(`unexpected character "${c}"`, startLine, startCol);
|
|
637
|
+
}
|
|
638
|
+
tokens.push({ kind: "eof", line, col });
|
|
639
|
+
return tokens;
|
|
640
|
+
}
|
|
641
|
+
__name(tokenize, "tokenize");
|
|
642
|
+
function unescape(c) {
|
|
643
|
+
switch (c) {
|
|
644
|
+
case "n":
|
|
645
|
+
return "\n";
|
|
646
|
+
case "t":
|
|
647
|
+
return " ";
|
|
648
|
+
case "r":
|
|
649
|
+
return "\r";
|
|
650
|
+
default:
|
|
651
|
+
return c;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
__name(unescape, "unescape");
|
|
655
|
+
var INFIX_BP = {
|
|
656
|
+
"||": 1,
|
|
657
|
+
"&&": 2,
|
|
658
|
+
"==": 3,
|
|
659
|
+
"!=": 3,
|
|
660
|
+
">": 3,
|
|
661
|
+
"<": 3,
|
|
662
|
+
">=": 3,
|
|
663
|
+
"<=": 3,
|
|
664
|
+
"+": 4,
|
|
665
|
+
"-": 4
|
|
666
|
+
};
|
|
667
|
+
var Parser = class {
|
|
668
|
+
constructor(tokens) {
|
|
669
|
+
this.tokens = tokens;
|
|
670
|
+
}
|
|
671
|
+
tokens;
|
|
672
|
+
static {
|
|
673
|
+
__name(this, "Parser");
|
|
674
|
+
}
|
|
675
|
+
pos = 0;
|
|
676
|
+
parse() {
|
|
677
|
+
const expr = this.parseBinary(0);
|
|
678
|
+
const t = this.peek();
|
|
679
|
+
if (t.kind !== "eof") {
|
|
680
|
+
throw new DialogueExprError(`unexpected trailing token "${describe(t)}"`, t.line, t.col);
|
|
681
|
+
}
|
|
682
|
+
return expr;
|
|
683
|
+
}
|
|
684
|
+
parseBinary(minBp) {
|
|
685
|
+
let left = this.parseUnary();
|
|
686
|
+
for (; ; ) {
|
|
687
|
+
const t = this.peek();
|
|
688
|
+
const bp = INFIX_BP[t.kind];
|
|
689
|
+
if (bp === void 0 || bp < minBp) break;
|
|
690
|
+
this.next();
|
|
691
|
+
const right = this.parseBinary(bp + 1);
|
|
692
|
+
left = { kind: "binary", op: t.kind, left, right };
|
|
693
|
+
}
|
|
694
|
+
return left;
|
|
695
|
+
}
|
|
696
|
+
parseUnary() {
|
|
697
|
+
const t = this.peek();
|
|
698
|
+
if (t.kind === "!" || t.kind === "-") {
|
|
699
|
+
this.next();
|
|
700
|
+
const operand = this.parseUnary();
|
|
701
|
+
return { kind: "unary", op: t.kind === "!" ? "!" : "-", operand };
|
|
702
|
+
}
|
|
703
|
+
return this.parsePrimary();
|
|
704
|
+
}
|
|
705
|
+
parsePrimary() {
|
|
706
|
+
const t = this.peek();
|
|
707
|
+
switch (t.kind) {
|
|
708
|
+
case "number":
|
|
709
|
+
case "string":
|
|
710
|
+
this.next();
|
|
711
|
+
return { kind: "literal", value: t.value };
|
|
712
|
+
case "true":
|
|
713
|
+
case "false":
|
|
714
|
+
case "null":
|
|
715
|
+
this.next();
|
|
716
|
+
return { kind: "literal", value: t.value };
|
|
717
|
+
case "ident": {
|
|
718
|
+
this.next();
|
|
719
|
+
const name = t.value;
|
|
720
|
+
if (this.peek().kind === "(") {
|
|
721
|
+
this.next();
|
|
722
|
+
const args = this.parseArgs();
|
|
723
|
+
return { kind: "call", fn: name, args };
|
|
724
|
+
}
|
|
725
|
+
return { kind: "varRef", name };
|
|
726
|
+
}
|
|
727
|
+
case "(": {
|
|
728
|
+
this.next();
|
|
729
|
+
const inner = this.parseBinary(0);
|
|
730
|
+
this.expect(")");
|
|
731
|
+
return { kind: "group", expr: inner };
|
|
732
|
+
}
|
|
733
|
+
default:
|
|
734
|
+
throw new DialogueExprError(`unexpected ${describe(t)}`, t.line, t.col);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
/** Parse a comma-separated argument list; the opening `(` is already consumed. */
|
|
738
|
+
parseArgs() {
|
|
739
|
+
const args = [];
|
|
740
|
+
if (this.peek().kind === ")") {
|
|
741
|
+
this.next();
|
|
742
|
+
return args;
|
|
743
|
+
}
|
|
744
|
+
for (; ; ) {
|
|
745
|
+
args.push(this.parseBinary(0));
|
|
746
|
+
const t = this.peek();
|
|
747
|
+
if (t.kind === ",") {
|
|
748
|
+
this.next();
|
|
749
|
+
continue;
|
|
750
|
+
}
|
|
751
|
+
if (t.kind === ")") {
|
|
752
|
+
this.next();
|
|
753
|
+
return args;
|
|
754
|
+
}
|
|
755
|
+
throw new DialogueExprError(`expected "," or ")" in argument list, got ${describe(t)}`, t.line, t.col);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
expect(kind) {
|
|
759
|
+
const t = this.peek();
|
|
760
|
+
if (t.kind !== kind) {
|
|
761
|
+
throw new DialogueExprError(`expected "${kind}", got ${describe(t)}`, t.line, t.col);
|
|
762
|
+
}
|
|
763
|
+
this.next();
|
|
764
|
+
}
|
|
765
|
+
peek() {
|
|
766
|
+
return this.tokens[this.pos];
|
|
767
|
+
}
|
|
768
|
+
next() {
|
|
769
|
+
return this.tokens[this.pos++];
|
|
770
|
+
}
|
|
771
|
+
};
|
|
772
|
+
function describe(t) {
|
|
773
|
+
if (t.kind === "eof") return "end of input";
|
|
774
|
+
if (t.kind === "ident") return `"${String(t.value)}"`;
|
|
775
|
+
if (t.kind === "string") return `string "${String(t.value)}"`;
|
|
776
|
+
if (t.kind === "number") return `number ${String(t.value)}`;
|
|
777
|
+
return `"${t.kind}"`;
|
|
778
|
+
}
|
|
779
|
+
__name(describe, "describe");
|
|
780
|
+
|
|
781
|
+
// src/core/formats/canonical.ts
|
|
782
|
+
function loadScript(raw) {
|
|
783
|
+
if (!raw || typeof raw !== "object") {
|
|
784
|
+
throw new DialogueScriptError("script must be an object");
|
|
785
|
+
}
|
|
786
|
+
if (!raw.id) throw new DialogueScriptError("script.id is required");
|
|
787
|
+
if (!raw.nodes || typeof raw.nodes !== "object") {
|
|
788
|
+
throw new DialogueScriptError(`script "${raw.id}" has no nodes`);
|
|
789
|
+
}
|
|
790
|
+
const nodeIds = Object.keys(raw.nodes);
|
|
791
|
+
if (nodeIds.length === 0) {
|
|
792
|
+
throw new DialogueScriptError(`script "${raw.id}" has no nodes`);
|
|
793
|
+
}
|
|
794
|
+
const start = raw.start ?? nodeIds[0];
|
|
795
|
+
if (!raw.nodes[start]) {
|
|
796
|
+
throw new DialogueScriptError(`start node "${start}" not found in "${raw.id}"`);
|
|
797
|
+
}
|
|
798
|
+
for (const [key, speaker] of Object.entries(raw.speakers ?? {})) {
|
|
799
|
+
if (speaker.id !== key) {
|
|
800
|
+
throw new DialogueScriptError(
|
|
801
|
+
`speaker key "${key}" != speaker.id "${speaker.id}"`
|
|
802
|
+
);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
for (const [id, node] of Object.entries(raw.nodes)) {
|
|
806
|
+
validateNode(raw, id, node);
|
|
807
|
+
}
|
|
808
|
+
const resolved = resolveExpressions(raw);
|
|
809
|
+
const script = Object.freeze({ ...resolved, start });
|
|
810
|
+
analyzeScript(script);
|
|
811
|
+
return script;
|
|
812
|
+
}
|
|
813
|
+
__name(loadScript, "loadScript");
|
|
814
|
+
function validateNode(script, id, node) {
|
|
815
|
+
if (node.id !== id) {
|
|
816
|
+
throw new DialogueScriptError(`node key "${id}" != node.id "${node.id}"`);
|
|
817
|
+
}
|
|
818
|
+
if (!Array.isArray(node.steps) || node.steps.length === 0) {
|
|
819
|
+
throw new DialogueScriptError(`node "${id}" has no steps`);
|
|
820
|
+
}
|
|
821
|
+
for (const step of node.steps) validateStep(script, id, step);
|
|
822
|
+
}
|
|
823
|
+
__name(validateNode, "validateNode");
|
|
824
|
+
function validateStep(script, nodeId, step) {
|
|
825
|
+
const targetExists = /* @__PURE__ */ __name((t) => {
|
|
826
|
+
if (t !== void 0 && !script.nodes[t]) {
|
|
827
|
+
throw new DialogueScriptError(
|
|
828
|
+
`node "${nodeId}": jump target "${t}" does not exist`
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
}, "targetExists");
|
|
832
|
+
const speakerExists = /* @__PURE__ */ __name((s) => {
|
|
833
|
+
if (s !== void 0 && !script.speakers?.[s]) {
|
|
834
|
+
throw new DialogueScriptError(
|
|
835
|
+
`node "${nodeId}": speaker "${s}" is not in script.speakers`
|
|
836
|
+
);
|
|
837
|
+
}
|
|
838
|
+
}, "speakerExists");
|
|
839
|
+
switch (step.kind) {
|
|
840
|
+
case "say":
|
|
841
|
+
if (typeof step.text !== "string") {
|
|
842
|
+
throw new DialogueScriptError(`node "${nodeId}": say.text must be a string`);
|
|
843
|
+
}
|
|
844
|
+
speakerExists(step.speaker);
|
|
845
|
+
break;
|
|
846
|
+
case "choice":
|
|
847
|
+
if (!Array.isArray(step.options) || step.options.length === 0) {
|
|
848
|
+
throw new DialogueScriptError(`node "${nodeId}": choice has no options`);
|
|
849
|
+
}
|
|
850
|
+
speakerExists(step.speaker);
|
|
851
|
+
for (const opt of step.options) targetExists(opt.target);
|
|
852
|
+
break;
|
|
853
|
+
case "command":
|
|
854
|
+
targetExists(step.target);
|
|
855
|
+
break;
|
|
856
|
+
case "goto":
|
|
857
|
+
if (step.target === void 0) {
|
|
858
|
+
throw new DialogueScriptError(`node "${nodeId}": goto has no target`);
|
|
859
|
+
}
|
|
860
|
+
targetExists(step.target);
|
|
861
|
+
break;
|
|
862
|
+
case "end":
|
|
863
|
+
break;
|
|
864
|
+
default:
|
|
865
|
+
throw new DialogueScriptError(
|
|
866
|
+
`node "${nodeId}": unknown step kind "${step.kind}"`
|
|
867
|
+
);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
__name(validateStep, "validateStep");
|
|
871
|
+
function resolveExpressions(script) {
|
|
872
|
+
let nodesChanged = false;
|
|
873
|
+
const nodes = {};
|
|
874
|
+
for (const [id, node] of Object.entries(script.nodes)) {
|
|
875
|
+
let stepsChanged = false;
|
|
876
|
+
const steps = node.steps.map((step) => {
|
|
877
|
+
const next = resolveStep(step);
|
|
878
|
+
if (next !== step) stepsChanged = true;
|
|
879
|
+
return next;
|
|
880
|
+
});
|
|
881
|
+
if (stepsChanged) {
|
|
882
|
+
nodes[id] = { ...node, steps };
|
|
883
|
+
nodesChanged = true;
|
|
884
|
+
} else {
|
|
885
|
+
nodes[id] = node;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
return nodesChanged ? { ...script, nodes } : script;
|
|
889
|
+
}
|
|
890
|
+
__name(resolveExpressions, "resolveExpressions");
|
|
891
|
+
function resolveStep(step) {
|
|
892
|
+
switch (step.kind) {
|
|
893
|
+
case "say":
|
|
894
|
+
return resolveSay(step);
|
|
895
|
+
case "choice":
|
|
896
|
+
return resolveChoice(step);
|
|
897
|
+
case "command":
|
|
898
|
+
return resolveCommandStep(step);
|
|
899
|
+
case "goto":
|
|
900
|
+
case "end":
|
|
901
|
+
return step;
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
__name(resolveStep, "resolveStep");
|
|
905
|
+
function resolveSay(step) {
|
|
906
|
+
const commands = rewriteCommands(step.commands);
|
|
907
|
+
return commands ? { ...step, commands } : step;
|
|
908
|
+
}
|
|
909
|
+
__name(resolveSay, "resolveSay");
|
|
910
|
+
function resolveCommandStep(step) {
|
|
911
|
+
const condition = rewriteCondition(step.condition);
|
|
912
|
+
const commands = rewriteCommands(step.commands);
|
|
913
|
+
if (!condition && !commands) return step;
|
|
914
|
+
return {
|
|
915
|
+
...step,
|
|
916
|
+
...condition ? { condition } : {},
|
|
917
|
+
...commands ? { commands } : {}
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
__name(resolveCommandStep, "resolveCommandStep");
|
|
921
|
+
function resolveChoice(step) {
|
|
922
|
+
let changed = false;
|
|
923
|
+
const options = step.options.map((opt) => {
|
|
924
|
+
const next = rewriteOption(opt);
|
|
925
|
+
if (next) {
|
|
926
|
+
changed = true;
|
|
927
|
+
return next;
|
|
928
|
+
}
|
|
929
|
+
return opt;
|
|
930
|
+
});
|
|
931
|
+
return changed ? { ...step, options } : step;
|
|
932
|
+
}
|
|
933
|
+
__name(resolveChoice, "resolveChoice");
|
|
934
|
+
function rewriteOption(opt) {
|
|
935
|
+
const condition = rewriteCondition(opt.condition);
|
|
936
|
+
const commands = rewriteCommands(opt.commands);
|
|
937
|
+
if (!condition && !commands) return void 0;
|
|
938
|
+
return {
|
|
939
|
+
...opt,
|
|
940
|
+
...condition ? { condition } : {},
|
|
941
|
+
...commands ? { commands } : {}
|
|
942
|
+
};
|
|
943
|
+
}
|
|
944
|
+
__name(rewriteOption, "rewriteOption");
|
|
945
|
+
function rewriteCondition(condition) {
|
|
946
|
+
return typeof condition === "string" ? parseExpr(condition) : void 0;
|
|
947
|
+
}
|
|
948
|
+
__name(rewriteCondition, "rewriteCondition");
|
|
949
|
+
function rewriteCommands(commands) {
|
|
950
|
+
if (!commands) return void 0;
|
|
951
|
+
let changed = false;
|
|
952
|
+
const out = commands.map((cmd) => {
|
|
953
|
+
if (cmd.type === "set" && typeof cmd.value === "string") {
|
|
954
|
+
changed = true;
|
|
955
|
+
return { ...cmd, value: parseExpr(cmd.value) };
|
|
956
|
+
}
|
|
957
|
+
return cmd;
|
|
958
|
+
});
|
|
959
|
+
return changed ? out : void 0;
|
|
960
|
+
}
|
|
961
|
+
__name(rewriteCommands, "rewriteCommands");
|
|
962
|
+
|
|
963
|
+
export {
|
|
964
|
+
materialize,
|
|
965
|
+
MemoryVariableStorage,
|
|
966
|
+
cells,
|
|
967
|
+
compose,
|
|
968
|
+
createScope,
|
|
969
|
+
holds,
|
|
970
|
+
evalCondition,
|
|
971
|
+
evaluate,
|
|
972
|
+
isExpr,
|
|
973
|
+
IdentityI18n,
|
|
974
|
+
interpolate,
|
|
975
|
+
DialogueScriptError,
|
|
976
|
+
DialoguePlayError,
|
|
977
|
+
analyzeScript,
|
|
978
|
+
validatePlay,
|
|
979
|
+
DialogueExprError,
|
|
980
|
+
parseExpr,
|
|
981
|
+
loadScript
|
|
982
|
+
};
|
|
983
|
+
//# sourceMappingURL=chunk-GJQKZCOL.js.map
|