@patterkit/runtime 0.8.0 → 0.9.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/CHANGELOG.md +49 -0
- package/dist/index.cjs +122 -83
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +127 -14
- package/dist/index.d.ts +127 -14
- package/dist/index.js +122 -83
- package/dist/index.js.map +1 -1
- package/dist/patterplay.min.js +2 -2
- package/dist/patterplay.min.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { evaluate, deserialiseAst, makePrng, toUint32 } from "@wildwinter/expr";
|
|
3
3
|
import { matchedSpecificity as scoreSpecificity } from "@wildwinter/expr-specificity";
|
|
4
4
|
import { ScopeRegistry } from "@wildwinter/scoperegistry";
|
|
5
|
+
import { defaultFor, PropertyBag } from "@wildwinter/scoperegistry";
|
|
5
6
|
import { patterDialect, interpolate, splitRef, stripCaptions } from "@patterkit/dialect";
|
|
6
7
|
import { walkNodes, effectiveGameId, castStringKey, DEFAULT_CAPTION_DELIMITERS, DEFAULT_CAPTION_CHARACTER } from "@patterkit/model";
|
|
7
8
|
|
|
@@ -60,6 +61,10 @@ var Engine = class _Engine {
|
|
|
60
61
|
/** The options this engine was built with - reused verbatim by `hotSwap` so the replacement
|
|
61
62
|
* engine keeps the same world resolver, custom RNG, and diagnostic hooks. */
|
|
62
63
|
creationOptions;
|
|
64
|
+
/** The run's ordered stream: every flow's events, each naming its flow. Empty and
|
|
65
|
+
* unwritten unless `options.log` asked for it. */
|
|
66
|
+
engineLog = [];
|
|
67
|
+
engineTraceHandlers = /* @__PURE__ */ new Set();
|
|
63
68
|
constructor(bundle, options = {}) {
|
|
64
69
|
this.creationOptions = options;
|
|
65
70
|
const locale = options.locale ?? bundle.locales.default;
|
|
@@ -95,7 +100,7 @@ var Engine = class _Engine {
|
|
|
95
100
|
const patterSharedDecls = props.filter((p) => p.shared ?? true).map(toDecl);
|
|
96
101
|
const patterLocalDecls = props.filter((p) => !(p.shared ?? true)).map(toDecl);
|
|
97
102
|
const patterSharedNames = new Set(patterSharedDecls.map((d) => d.name.toLowerCase()));
|
|
98
|
-
const shared = new ScopeRegistry().defineOwned("patter", patterSharedDecls);
|
|
103
|
+
const shared = new ScopeRegistry().defineOwned("patter", patterSharedDecls, "@patter.");
|
|
99
104
|
const hostBound = /* @__PURE__ */ new Set();
|
|
100
105
|
if (options.world) {
|
|
101
106
|
const worldSpec = bundle.scopeRegistry?.scopes.find((s) => s.token === "world");
|
|
@@ -114,6 +119,8 @@ var Engine = class _Engine {
|
|
|
114
119
|
sceneSharedNames.set(sceneId, names);
|
|
115
120
|
}
|
|
116
121
|
this.host = {
|
|
122
|
+
logEnabled: options.log ?? false,
|
|
123
|
+
emitEngine: (flow, event, scene) => this.emitEngine(flow, event, scene),
|
|
117
124
|
bundle,
|
|
118
125
|
emitIds,
|
|
119
126
|
strings,
|
|
@@ -488,14 +495,44 @@ var Engine = class _Engine {
|
|
|
488
495
|
}
|
|
489
496
|
/** The shared `@patter` properties, for a live state inspector: each with its ref, type, current
|
|
490
497
|
* value, declared default (for reset), and enum options. Mirrors the Unity / Godot ports. */
|
|
498
|
+
/** The run's decisions, in order, each naming the flow it happened in. Empty unless the
|
|
499
|
+
* run was opened with `log: true`. A flow's own log stays flow-local; this is the only
|
|
500
|
+
* place a story spanning several flows reads as one sequence. */
|
|
501
|
+
log() {
|
|
502
|
+
return this.engineLog;
|
|
503
|
+
}
|
|
504
|
+
/** Drop the retained entries. `seq` does NOT restart: two reads of a log either side of a
|
|
505
|
+
* clear still agree about what came first. */
|
|
506
|
+
clearLog() {
|
|
507
|
+
this.engineLog.length = 0;
|
|
508
|
+
}
|
|
509
|
+
/** Live tap on the run's decisions, for tooling that wants them as they happen rather than
|
|
510
|
+
* retained. Returns its own unsubscribe. */
|
|
511
|
+
onTrace(handler) {
|
|
512
|
+
this.engineTraceHandlers.add(handler);
|
|
513
|
+
return () => this.engineTraceHandlers.delete(handler);
|
|
514
|
+
}
|
|
515
|
+
emitEngine(flow, event, scene) {
|
|
516
|
+
for (const h of this.engineTraceHandlers) h(flow, event);
|
|
517
|
+
if (!this.host.logEnabled) return;
|
|
518
|
+
this.engineLog.push({ ...event, flow, seq: this.engineLog.length, ...scene ? { scene } : {} });
|
|
519
|
+
}
|
|
491
520
|
listProperties() {
|
|
492
521
|
return this.host.patterSharedDecls.map((d) => ({
|
|
493
|
-
|
|
522
|
+
name: d.name,
|
|
523
|
+
// The qualified address, matching what the bag composes for every other scope.
|
|
524
|
+
// `@gold` still resolves on input; it is the shorthand, not the address.
|
|
525
|
+
path: `@patter.${d.name}`,
|
|
494
526
|
type: d.type,
|
|
495
527
|
values: d.values,
|
|
496
528
|
stages: d.stages,
|
|
497
529
|
value: this.getProperty(`@${d.name}`),
|
|
498
|
-
default:
|
|
530
|
+
default: defaultFor(d),
|
|
531
|
+
// Part of the shared row. Always true here today: `toDecl` never sets it, because
|
|
532
|
+
// Patter has no read-only shared property. The Storylet Engine does declare them
|
|
533
|
+
// and its panels disable the editor accordingly, so the field is carried rather
|
|
534
|
+
// than dropped - and the day a read-only @patter property exists, the row says so.
|
|
535
|
+
writable: d.writable ?? true
|
|
499
536
|
}));
|
|
500
537
|
}
|
|
501
538
|
// @scene is scene-namespaced and needs a flow's current scene - silently
|
|
@@ -528,7 +565,7 @@ var Engine = class _Engine {
|
|
|
528
565
|
shared: this.host.shared.save(),
|
|
529
566
|
sharedVisits: Object.fromEntries(this.host.sharedVisits),
|
|
530
567
|
sharedSelectors: serialiseSelectors(this.host.sharedSelectors),
|
|
531
|
-
stageBags: Object.fromEntries([...this.host.stageBags].map(([s, bag]) => [s,
|
|
568
|
+
stageBags: Object.fromEntries([...this.host.stageBags].map(([s, bag]) => [s, bag.save()])),
|
|
532
569
|
flows
|
|
533
570
|
};
|
|
534
571
|
}
|
|
@@ -541,7 +578,13 @@ var Engine = class _Engine {
|
|
|
541
578
|
this.host.sharedSelectors.clear();
|
|
542
579
|
for (const [id, st] of deserialiseSelectors(save.sharedSelectors)) this.host.sharedSelectors.set(id, st);
|
|
543
580
|
this.host.stageBags.clear();
|
|
544
|
-
for (const [s,
|
|
581
|
+
for (const [s, values] of Object.entries(save.stageBags ?? {})) {
|
|
582
|
+
const shared = this.host.sceneSharedNames.get(s) ?? /* @__PURE__ */ new Set();
|
|
583
|
+
const decls = (this.host.bundle.scenes[s]?.sceneProps ?? []).filter((d) => shared.has(d.name.toLowerCase()));
|
|
584
|
+
const bag = new PropertyBag(decls);
|
|
585
|
+
bag.load(values);
|
|
586
|
+
this.host.stageBags.set(s, bag);
|
|
587
|
+
}
|
|
545
588
|
this.flowsById.clear();
|
|
546
589
|
for (const [id, snap] of Object.entries(save.flows)) {
|
|
547
590
|
const flow = new Flow(id, this.host, this.defaultSeed);
|
|
@@ -584,6 +627,7 @@ var Flow = class {
|
|
|
584
627
|
// The SHARED halves live on the host (`host.shared` / `host.stageBags`). Each
|
|
585
628
|
// resolver presents one merged scope, routing each property to its half by the
|
|
586
629
|
// declared `shared` flag.
|
|
630
|
+
/** This flow's per-scene LOCAL scene props; see FlowHost.stageBags. */
|
|
587
631
|
sceneBags = /* @__PURE__ */ new Map();
|
|
588
632
|
patterResolver = {
|
|
589
633
|
get: (n) => this.host.patterSharedNames.has(n) ? this.host.shared.get("patter", n) : this.local.get("patter", n),
|
|
@@ -597,13 +641,13 @@ var Flow = class {
|
|
|
597
641
|
const s = this.currentSceneId;
|
|
598
642
|
if (s === null) return void 0;
|
|
599
643
|
const bag = this.host.sceneSharedNames.get(s)?.has(n) ? this.host.stageBags.get(s) : this.sceneBags.get(s);
|
|
600
|
-
return bag?.
|
|
644
|
+
return bag?.get(n);
|
|
601
645
|
},
|
|
602
646
|
set: (n, v) => {
|
|
603
647
|
const s = this.currentSceneId;
|
|
604
648
|
if (s === null) return;
|
|
605
649
|
const bag = this.host.sceneSharedNames.get(s)?.has(n) ? this.host.stageBags.get(s) : this.sceneBags.get(s);
|
|
606
|
-
if (bag) bag
|
|
650
|
+
if (bag) bag.set(n, v);
|
|
607
651
|
}
|
|
608
652
|
};
|
|
609
653
|
// The eval context is built ONCE: every constituent resolves live state at
|
|
@@ -612,6 +656,9 @@ var Flow = class {
|
|
|
612
656
|
// `local`/`sceneBags`/`currentSceneId`; the host callbacks read current flow
|
|
613
657
|
// fields). Rebuilding it per evaluation was the engine's hottest allocation.
|
|
614
658
|
evalCtx;
|
|
659
|
+
flowLog = [];
|
|
660
|
+
/** Monotonic across the flow's life; survives clearLog so two reads agree on order. */
|
|
661
|
+
flowSeq = 0;
|
|
615
662
|
constructor(id, host, seed) {
|
|
616
663
|
this.id = id;
|
|
617
664
|
this.host = host;
|
|
@@ -837,7 +884,17 @@ var Flow = class {
|
|
|
837
884
|
this.stack.pop();
|
|
838
885
|
continue;
|
|
839
886
|
}
|
|
887
|
+
const from = frame.index;
|
|
840
888
|
while (frame.index < children.length && !this.eligible(children[frame.index])) frame.index++;
|
|
889
|
+
if (this.host.logEnabled && frame.index !== from) {
|
|
890
|
+
this.emit({
|
|
891
|
+
type: "select",
|
|
892
|
+
group: frame.containerId,
|
|
893
|
+
selector: "run",
|
|
894
|
+
children: children.slice(from, frame.index + 1).map((c, i) => ({ id: c.id, eligible: from + i === frame.index })),
|
|
895
|
+
picked: children[frame.index]?.id ?? null
|
|
896
|
+
});
|
|
897
|
+
}
|
|
841
898
|
if (frame.index >= children.length) {
|
|
842
899
|
this.stack.pop();
|
|
843
900
|
continue;
|
|
@@ -846,6 +903,24 @@ var Flow = class {
|
|
|
846
903
|
}
|
|
847
904
|
}
|
|
848
905
|
/** The options of a pending choice (empty when not at a choice point). */
|
|
906
|
+
/** This flow's decisions, in order. Empty unless the run was opened with `log: true`.
|
|
907
|
+
* The engine's log carries the same events tagged with the flow; this one is what a
|
|
908
|
+
* single conversation reads as. */
|
|
909
|
+
log() {
|
|
910
|
+
return this.flowLog;
|
|
911
|
+
}
|
|
912
|
+
/** Drop the retained entries. `seq` keeps counting, so order survives a clear. */
|
|
913
|
+
clearLog() {
|
|
914
|
+
this.flowLog.length = 0;
|
|
915
|
+
}
|
|
916
|
+
/** Record one decision, on this flow's log and the engine's. Cheap to call with logging
|
|
917
|
+
* off: the entry is never built. */
|
|
918
|
+
emit(event) {
|
|
919
|
+
const scene = this.currentSceneId ?? void 0;
|
|
920
|
+
this.host.emitEngine(this.id, event, scene);
|
|
921
|
+
if (!this.host.logEnabled) return;
|
|
922
|
+
this.flowLog.push({ ...event, seq: this.flowSeq++, ...scene ? { scene } : {} });
|
|
923
|
+
}
|
|
849
924
|
getChoices() {
|
|
850
925
|
return this.pendingChoice?.options ?? [];
|
|
851
926
|
}
|
|
@@ -857,6 +932,7 @@ var Flow = class {
|
|
|
857
932
|
if (!option) throw new Error(`unknown choice option: ${id}`);
|
|
858
933
|
if (!option.eligible) throw new Error(`choice option is not eligible: ${id}`);
|
|
859
934
|
const node = choice.byId.get(id);
|
|
935
|
+
this.emit({ type: "chose", group: choice.groupId, option: id });
|
|
860
936
|
this.pendingChoice = null;
|
|
861
937
|
this.pendingPromptBeat = this.host.replayPromptOnChoose ? this.promptBeatOf(node) ?? null : null;
|
|
862
938
|
this.pendingPromptOwnerId = this.pendingPromptBeat ? node.id : null;
|
|
@@ -890,7 +966,7 @@ var Flow = class {
|
|
|
890
966
|
return {
|
|
891
967
|
scopes: this.local.save(),
|
|
892
968
|
// owned scope "patter" = the NOT-shared globals (@scene saved separately)
|
|
893
|
-
sceneBags: Object.fromEntries([...this.sceneBags].map(([s, bag]) => [s,
|
|
969
|
+
sceneBags: Object.fromEntries([...this.sceneBags].map(([s, bag]) => [s, bag.save()])),
|
|
894
970
|
rngState: this.rngState,
|
|
895
971
|
visits: Object.fromEntries(this.visitCounts),
|
|
896
972
|
cursor: {
|
|
@@ -928,7 +1004,13 @@ var Flow = class {
|
|
|
928
1004
|
}
|
|
929
1005
|
return { ...frame };
|
|
930
1006
|
});
|
|
931
|
-
this.sceneBags = new Map(Object.entries(snap.sceneBags ?? {}).map(([s,
|
|
1007
|
+
this.sceneBags = new Map(Object.entries(snap.sceneBags ?? {}).map(([s, values]) => {
|
|
1008
|
+
const shared = this.host.sceneSharedNames.get(s) ?? /* @__PURE__ */ new Set();
|
|
1009
|
+
const decls = (this.host.bundle.scenes[s]?.sceneProps ?? []).filter((d) => !shared.has(d.name.toLowerCase()));
|
|
1010
|
+
const bag = new PropertyBag(decls);
|
|
1011
|
+
bag.load(values);
|
|
1012
|
+
return [s, bag];
|
|
1013
|
+
}));
|
|
932
1014
|
this.local = this.freshLocal();
|
|
933
1015
|
this.local.load(snap.scopes);
|
|
934
1016
|
this.activeSnippet = null;
|
|
@@ -1022,6 +1104,7 @@ var Flow = class {
|
|
|
1022
1104
|
byId.set(child.id, child);
|
|
1023
1105
|
}
|
|
1024
1106
|
if (options.length > 0) {
|
|
1107
|
+
this.emit({ type: "choice", group: group.id, options: options.map((o) => ({ id: o.id, eligible: o.eligible })) });
|
|
1025
1108
|
this.pendingChoice = { groupId: group.id, options, byId };
|
|
1026
1109
|
return;
|
|
1027
1110
|
}
|
|
@@ -1030,6 +1113,7 @@ var Flow = class {
|
|
|
1030
1113
|
this.enterChild(fallback);
|
|
1031
1114
|
return;
|
|
1032
1115
|
}
|
|
1116
|
+
this.emit({ type: "dry", group: group.id });
|
|
1033
1117
|
this.host.onDryChoice?.(group.id);
|
|
1034
1118
|
}
|
|
1035
1119
|
// -- Jumps (jump / call-return) ----------------------------------------
|
|
@@ -1044,6 +1128,7 @@ var Flow = class {
|
|
|
1044
1128
|
* hard-ends the flow regardless of the callstack.
|
|
1045
1129
|
*/
|
|
1046
1130
|
enterTarget(to, mode) {
|
|
1131
|
+
this.emit({ type: "jump", to, mode });
|
|
1047
1132
|
if (to === "END") {
|
|
1048
1133
|
this.flowEnded = true;
|
|
1049
1134
|
this.stack = [];
|
|
@@ -1075,17 +1160,28 @@ var Flow = class {
|
|
|
1075
1160
|
}
|
|
1076
1161
|
// -- Selectors ------------------------------------------------------------
|
|
1077
1162
|
selectChild(group) {
|
|
1163
|
+
const verdicts = group.children.map((c) => ({ id: c.id, eligible: this.eligible(c) }));
|
|
1078
1164
|
const eligible = group.children.filter((c) => this.eligible(c));
|
|
1079
|
-
|
|
1165
|
+
const order = group.options?.order ?? "sequential";
|
|
1166
|
+
const exhaust = group.options?.exhaust ?? "once";
|
|
1167
|
+
const trace = (picked) => {
|
|
1168
|
+
this.emit({
|
|
1169
|
+
type: "select",
|
|
1170
|
+
group: group.id,
|
|
1171
|
+
selector: group.selector ?? "default",
|
|
1172
|
+
...group.selector === "sequence" ? { order, exhaust } : {},
|
|
1173
|
+
children: verdicts,
|
|
1174
|
+
picked: picked?.id ?? null
|
|
1175
|
+
});
|
|
1176
|
+
return picked;
|
|
1177
|
+
};
|
|
1178
|
+
if (eligible.length === 0) return trace(null);
|
|
1080
1179
|
const st = this.selectorState(group);
|
|
1081
1180
|
switch (group.selector) {
|
|
1082
1181
|
case "branch":
|
|
1083
|
-
return eligible[0];
|
|
1084
|
-
case "sequence":
|
|
1085
|
-
|
|
1086
|
-
const exhaust = group.options?.exhaust ?? "once";
|
|
1087
|
-
return order === "shuffle" ? this.pickShuffle(eligible, exhaust, st) : order === "specificity" ? this.pickSpecificity(eligible, exhaust, st) : this.pickSequential(eligible, exhaust, st);
|
|
1088
|
-
}
|
|
1182
|
+
return trace(eligible[0]);
|
|
1183
|
+
case "sequence":
|
|
1184
|
+
return trace(order === "shuffle" ? this.pickShuffle(eligible, exhaust, st) : order === "specificity" ? this.pickSpecificity(eligible, exhaust, st) : this.pickSequential(eligible, exhaust, st));
|
|
1089
1185
|
case "run":
|
|
1090
1186
|
case "choice":
|
|
1091
1187
|
default:
|
|
@@ -1203,7 +1299,10 @@ var Flow = class {
|
|
|
1203
1299
|
// -- Effects + expressions ------------------------------------------------
|
|
1204
1300
|
runEffects(effects) {
|
|
1205
1301
|
for (const e of effects ?? []) {
|
|
1206
|
-
|
|
1302
|
+
const value = this.evalExpr(e.value);
|
|
1303
|
+
const prev = this.host.logEnabled ? this.getProperty(e.target) : void 0;
|
|
1304
|
+
this.setProperty(e.target, value);
|
|
1305
|
+
this.emit({ type: "write", target: e.target, value, ...prev !== void 0 ? { prev } : {} });
|
|
1207
1306
|
}
|
|
1208
1307
|
}
|
|
1209
1308
|
eligible(node) {
|
|
@@ -1347,7 +1446,7 @@ var Flow = class {
|
|
|
1347
1446
|
}
|
|
1348
1447
|
/** The per-flow registry: the NOT-shared `@patter` globals (the shared ones live on the host). */
|
|
1349
1448
|
freshLocal() {
|
|
1350
|
-
return new ScopeRegistry().defineOwned("patter", this.host.patterLocalDecls);
|
|
1449
|
+
return new ScopeRegistry().defineOwned("patter", this.host.patterLocalDecls, "@patter.");
|
|
1351
1450
|
}
|
|
1352
1451
|
/**
|
|
1353
1452
|
* Seed a scene's `@scene` props (spec §7). The not-shared props seed THIS flow's
|
|
@@ -1358,27 +1457,18 @@ var Flow = class {
|
|
|
1358
1457
|
*/
|
|
1359
1458
|
seedScene(scene) {
|
|
1360
1459
|
const shared = this.host.sceneSharedNames.get(scene.id) ?? /* @__PURE__ */ new Set();
|
|
1460
|
+
const props = scene.sceneProps ?? [];
|
|
1361
1461
|
if (!this.sceneBags.has(scene.id)) {
|
|
1362
|
-
|
|
1363
|
-
for (const decl of scene.sceneProps ?? []) {
|
|
1364
|
-
const name = decl.name.toLowerCase();
|
|
1365
|
-
if (!shared.has(name)) bag[name] = sceneDefault(decl);
|
|
1366
|
-
}
|
|
1367
|
-
this.sceneBags.set(scene.id, bag);
|
|
1462
|
+
this.sceneBags.set(scene.id, new PropertyBag(props.filter((d) => !shared.has(d.name.toLowerCase()))));
|
|
1368
1463
|
}
|
|
1369
1464
|
if (!this.host.stageBags.has(scene.id)) {
|
|
1370
|
-
|
|
1371
|
-
for (const decl of scene.sceneProps ?? []) {
|
|
1372
|
-
const name = decl.name.toLowerCase();
|
|
1373
|
-
if (shared.has(name)) bag[name] = sceneDefault(decl);
|
|
1374
|
-
}
|
|
1375
|
-
this.host.stageBags.set(scene.id, bag);
|
|
1465
|
+
this.host.stageBags.set(scene.id, new PropertyBag(props.filter((d) => shared.has(d.name.toLowerCase()))));
|
|
1376
1466
|
}
|
|
1377
1467
|
for (const decl of scene.sceneProps ?? []) {
|
|
1378
1468
|
if (!decl.temporary) continue;
|
|
1379
1469
|
const name = decl.name.toLowerCase();
|
|
1380
1470
|
const bag = shared.has(name) ? this.host.stageBags.get(scene.id) : this.sceneBags.get(scene.id);
|
|
1381
|
-
if (bag) bag
|
|
1471
|
+
if (bag) bag.set(name, defaultFor(decl));
|
|
1382
1472
|
}
|
|
1383
1473
|
}
|
|
1384
1474
|
};
|
|
@@ -1416,47 +1506,13 @@ function deserialiseSelectors(rec) {
|
|
|
1416
1506
|
function toDecl(decl) {
|
|
1417
1507
|
return { name: decl.name, type: decl.type, values: decl.values, stages: decl.stages, default: decl.default };
|
|
1418
1508
|
}
|
|
1419
|
-
function declDefault(d) {
|
|
1420
|
-
if (d.default !== void 0) return d.default;
|
|
1421
|
-
switch (d.type) {
|
|
1422
|
-
case "number":
|
|
1423
|
-
return 0;
|
|
1424
|
-
case "string":
|
|
1425
|
-
return "";
|
|
1426
|
-
case "flags":
|
|
1427
|
-
return [];
|
|
1428
|
-
case "enum":
|
|
1429
|
-
return d.values?.[0] ?? "";
|
|
1430
|
-
case "quality":
|
|
1431
|
-
return d.stages?.[0] ?? "";
|
|
1432
|
-
default:
|
|
1433
|
-
return false;
|
|
1434
|
-
}
|
|
1435
|
-
}
|
|
1436
1509
|
function toForeignDecl(decl) {
|
|
1437
1510
|
return { name: decl.name, type: decl.type, values: decl.values, stages: decl.stages, default: decl.default, writable: decl.writable };
|
|
1438
1511
|
}
|
|
1439
|
-
function hostScopeDefault(decl) {
|
|
1440
|
-
if (decl.default !== void 0) return decl.default;
|
|
1441
|
-
switch (decl.type) {
|
|
1442
|
-
case "boolean":
|
|
1443
|
-
return false;
|
|
1444
|
-
case "number":
|
|
1445
|
-
return 0;
|
|
1446
|
-
case "string":
|
|
1447
|
-
return "";
|
|
1448
|
-
case "flags":
|
|
1449
|
-
return [];
|
|
1450
|
-
case "enum":
|
|
1451
|
-
return decl.values?.[0] ?? "";
|
|
1452
|
-
case "quality":
|
|
1453
|
-
return decl.stages?.[0] ?? "";
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
1512
|
function selfBackedResolver(decls) {
|
|
1457
1513
|
const key = (name) => name.toLowerCase();
|
|
1458
1514
|
const bag = /* @__PURE__ */ new Map();
|
|
1459
|
-
for (const d of decls) bag.set(key(d.name),
|
|
1515
|
+
for (const d of decls) bag.set(key(d.name), defaultFor(d));
|
|
1460
1516
|
return {
|
|
1461
1517
|
get: (name) => bag.get(key(name)),
|
|
1462
1518
|
set: (name, value) => {
|
|
@@ -1464,23 +1520,6 @@ function selfBackedResolver(decls) {
|
|
|
1464
1520
|
}
|
|
1465
1521
|
};
|
|
1466
1522
|
}
|
|
1467
|
-
function sceneDefault(decl) {
|
|
1468
|
-
if (decl.default !== void 0) return decl.default;
|
|
1469
|
-
switch (decl.type) {
|
|
1470
|
-
case "boolean":
|
|
1471
|
-
return false;
|
|
1472
|
-
case "number":
|
|
1473
|
-
return 0;
|
|
1474
|
-
case "string":
|
|
1475
|
-
return "";
|
|
1476
|
-
case "flags":
|
|
1477
|
-
return [];
|
|
1478
|
-
case "enum":
|
|
1479
|
-
return decl.values?.[0] ?? "";
|
|
1480
|
-
case "quality":
|
|
1481
|
-
return decl.stages?.[0] ?? "";
|
|
1482
|
-
}
|
|
1483
|
-
}
|
|
1484
1523
|
function truthy(v) {
|
|
1485
1524
|
if (typeof v === "boolean") return v;
|
|
1486
1525
|
if (typeof v === "number") return v !== 0;
|