@patterkit/runtime 0.8.0 → 0.10.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 +70 -0
- package/dist/index.cjs +148 -83
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +145 -14
- package/dist/index.d.ts +145 -14
- package/dist/index.js +148 -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,
|
|
@@ -456,6 +463,22 @@ var Engine = class _Engine {
|
|
|
456
463
|
flows() {
|
|
457
464
|
return [...this.flowsById.values()];
|
|
458
465
|
}
|
|
466
|
+
/**
|
|
467
|
+
* The SHARED kernel bags with the path each answers to in a log: the `@patter` globals,
|
|
468
|
+
* and one per scene for the shared `@scene` props. Parity with the Storylet Engine's
|
|
469
|
+
* listBags of the same name - it is what a state logger mounts.
|
|
470
|
+
*
|
|
471
|
+
* A stage bag's log path is `@scene:<sceneId>.`, not the bag's own `@scene.`: a property
|
|
472
|
+
* is ADDRESSED relative to a flow's current scene, but a log spans scenes and has to say
|
|
473
|
+
* which one. That is why a mount may override the bag's prefix.
|
|
474
|
+
*
|
|
475
|
+
* loadGame() replaces every bag, so re-enumerate after a load.
|
|
476
|
+
*/
|
|
477
|
+
listBags() {
|
|
478
|
+
const mounts = [{ bag: this.host.shared.ownedBag("patter") }];
|
|
479
|
+
for (const [sceneId, bag] of this.host.stageBags) mounts.push({ bag, pathPrefix: `@scene:${sceneId}.` });
|
|
480
|
+
return mounts;
|
|
481
|
+
}
|
|
459
482
|
/** Close (remove) a flow. The flow object is FINISHED, not merely unregistered, so a host still
|
|
460
483
|
* holding it cannot keep advancing it into the shared world (see {@link Flow.close}). */
|
|
461
484
|
closeFlow(id) {
|
|
@@ -488,14 +511,44 @@ var Engine = class _Engine {
|
|
|
488
511
|
}
|
|
489
512
|
/** The shared `@patter` properties, for a live state inspector: each with its ref, type, current
|
|
490
513
|
* value, declared default (for reset), and enum options. Mirrors the Unity / Godot ports. */
|
|
514
|
+
/** The run's decisions, in order, each naming the flow it happened in. Empty unless the
|
|
515
|
+
* run was opened with `log: true`. A flow's own log stays flow-local; this is the only
|
|
516
|
+
* place a story spanning several flows reads as one sequence. */
|
|
517
|
+
log() {
|
|
518
|
+
return this.engineLog;
|
|
519
|
+
}
|
|
520
|
+
/** Drop the retained entries. `seq` does NOT restart: two reads of a log either side of a
|
|
521
|
+
* clear still agree about what came first. */
|
|
522
|
+
clearLog() {
|
|
523
|
+
this.engineLog.length = 0;
|
|
524
|
+
}
|
|
525
|
+
/** Live tap on the run's decisions, for tooling that wants them as they happen rather than
|
|
526
|
+
* retained. Returns its own unsubscribe. */
|
|
527
|
+
onTrace(handler) {
|
|
528
|
+
this.engineTraceHandlers.add(handler);
|
|
529
|
+
return () => this.engineTraceHandlers.delete(handler);
|
|
530
|
+
}
|
|
531
|
+
emitEngine(flow, event, scene) {
|
|
532
|
+
for (const h of this.engineTraceHandlers) h(flow, event);
|
|
533
|
+
if (!this.host.logEnabled) return;
|
|
534
|
+
this.engineLog.push({ ...event, flow, seq: this.engineLog.length, ...scene ? { scene } : {} });
|
|
535
|
+
}
|
|
491
536
|
listProperties() {
|
|
492
537
|
return this.host.patterSharedDecls.map((d) => ({
|
|
493
|
-
|
|
538
|
+
name: d.name,
|
|
539
|
+
// The qualified address, matching what the bag composes for every other scope.
|
|
540
|
+
// `@gold` still resolves on input; it is the shorthand, not the address.
|
|
541
|
+
path: `@patter.${d.name}`,
|
|
494
542
|
type: d.type,
|
|
495
543
|
values: d.values,
|
|
496
544
|
stages: d.stages,
|
|
497
545
|
value: this.getProperty(`@${d.name}`),
|
|
498
|
-
default:
|
|
546
|
+
default: defaultFor(d),
|
|
547
|
+
// Part of the shared row. Always true here today: `toDecl` never sets it, because
|
|
548
|
+
// Patter has no read-only shared property. The Storylet Engine does declare them
|
|
549
|
+
// and its panels disable the editor accordingly, so the field is carried rather
|
|
550
|
+
// than dropped - and the day a read-only @patter property exists, the row says so.
|
|
551
|
+
writable: d.writable ?? true
|
|
499
552
|
}));
|
|
500
553
|
}
|
|
501
554
|
// @scene is scene-namespaced and needs a flow's current scene - silently
|
|
@@ -528,7 +581,7 @@ var Engine = class _Engine {
|
|
|
528
581
|
shared: this.host.shared.save(),
|
|
529
582
|
sharedVisits: Object.fromEntries(this.host.sharedVisits),
|
|
530
583
|
sharedSelectors: serialiseSelectors(this.host.sharedSelectors),
|
|
531
|
-
stageBags: Object.fromEntries([...this.host.stageBags].map(([s, bag]) => [s,
|
|
584
|
+
stageBags: Object.fromEntries([...this.host.stageBags].map(([s, bag]) => [s, bag.save()])),
|
|
532
585
|
flows
|
|
533
586
|
};
|
|
534
587
|
}
|
|
@@ -541,7 +594,13 @@ var Engine = class _Engine {
|
|
|
541
594
|
this.host.sharedSelectors.clear();
|
|
542
595
|
for (const [id, st] of deserialiseSelectors(save.sharedSelectors)) this.host.sharedSelectors.set(id, st);
|
|
543
596
|
this.host.stageBags.clear();
|
|
544
|
-
for (const [s,
|
|
597
|
+
for (const [s, values] of Object.entries(save.stageBags ?? {})) {
|
|
598
|
+
const shared = this.host.sceneSharedNames.get(s) ?? /* @__PURE__ */ new Set();
|
|
599
|
+
const decls = (this.host.bundle.scenes[s]?.sceneProps ?? []).filter((d) => shared.has(d.name.toLowerCase()));
|
|
600
|
+
const bag = new PropertyBag(decls);
|
|
601
|
+
bag.load(values);
|
|
602
|
+
this.host.stageBags.set(s, bag);
|
|
603
|
+
}
|
|
545
604
|
this.flowsById.clear();
|
|
546
605
|
for (const [id, snap] of Object.entries(save.flows)) {
|
|
547
606
|
const flow = new Flow(id, this.host, this.defaultSeed);
|
|
@@ -584,6 +643,7 @@ var Flow = class {
|
|
|
584
643
|
// The SHARED halves live on the host (`host.shared` / `host.stageBags`). Each
|
|
585
644
|
// resolver presents one merged scope, routing each property to its half by the
|
|
586
645
|
// declared `shared` flag.
|
|
646
|
+
/** This flow's per-scene LOCAL scene props; see FlowHost.stageBags. */
|
|
587
647
|
sceneBags = /* @__PURE__ */ new Map();
|
|
588
648
|
patterResolver = {
|
|
589
649
|
get: (n) => this.host.patterSharedNames.has(n) ? this.host.shared.get("patter", n) : this.local.get("patter", n),
|
|
@@ -597,13 +657,13 @@ var Flow = class {
|
|
|
597
657
|
const s = this.currentSceneId;
|
|
598
658
|
if (s === null) return void 0;
|
|
599
659
|
const bag = this.host.sceneSharedNames.get(s)?.has(n) ? this.host.stageBags.get(s) : this.sceneBags.get(s);
|
|
600
|
-
return bag?.
|
|
660
|
+
return bag?.get(n);
|
|
601
661
|
},
|
|
602
662
|
set: (n, v) => {
|
|
603
663
|
const s = this.currentSceneId;
|
|
604
664
|
if (s === null) return;
|
|
605
665
|
const bag = this.host.sceneSharedNames.get(s)?.has(n) ? this.host.stageBags.get(s) : this.sceneBags.get(s);
|
|
606
|
-
if (bag) bag
|
|
666
|
+
if (bag) bag.set(n, v);
|
|
607
667
|
}
|
|
608
668
|
};
|
|
609
669
|
// The eval context is built ONCE: every constituent resolves live state at
|
|
@@ -612,6 +672,9 @@ var Flow = class {
|
|
|
612
672
|
// `local`/`sceneBags`/`currentSceneId`; the host callbacks read current flow
|
|
613
673
|
// fields). Rebuilding it per evaluation was the engine's hottest allocation.
|
|
614
674
|
evalCtx;
|
|
675
|
+
flowLog = [];
|
|
676
|
+
/** Monotonic across the flow's life; survives clearLog so two reads agree on order. */
|
|
677
|
+
flowSeq = 0;
|
|
615
678
|
constructor(id, host, seed) {
|
|
616
679
|
this.id = id;
|
|
617
680
|
this.host = host;
|
|
@@ -837,7 +900,17 @@ var Flow = class {
|
|
|
837
900
|
this.stack.pop();
|
|
838
901
|
continue;
|
|
839
902
|
}
|
|
903
|
+
const from = frame.index;
|
|
840
904
|
while (frame.index < children.length && !this.eligible(children[frame.index])) frame.index++;
|
|
905
|
+
if (this.host.logEnabled && frame.index !== from) {
|
|
906
|
+
this.emit({
|
|
907
|
+
type: "select",
|
|
908
|
+
group: frame.containerId,
|
|
909
|
+
selector: "run",
|
|
910
|
+
children: children.slice(from, frame.index + 1).map((c, i) => ({ id: c.id, eligible: from + i === frame.index })),
|
|
911
|
+
picked: children[frame.index]?.id ?? null
|
|
912
|
+
});
|
|
913
|
+
}
|
|
841
914
|
if (frame.index >= children.length) {
|
|
842
915
|
this.stack.pop();
|
|
843
916
|
continue;
|
|
@@ -845,6 +918,34 @@ var Flow = class {
|
|
|
845
918
|
this.enterChild(children[frame.index++]);
|
|
846
919
|
}
|
|
847
920
|
}
|
|
921
|
+
/**
|
|
922
|
+
* THIS flow's own kernel bags: its not-shared `@patter` half and its per-scene `@scene`
|
|
923
|
+
* props, each prefixed with the flow id so one path space holds every flow. The shared
|
|
924
|
+
* halves are the Engine's listBags.
|
|
925
|
+
*/
|
|
926
|
+
listBags() {
|
|
927
|
+
const mounts = [{ bag: this.local.ownedBag("patter"), pathPrefix: `${this.id}/@patter.` }];
|
|
928
|
+
for (const [sceneId, bag] of this.sceneBags) mounts.push({ bag, pathPrefix: `${this.id}/@scene:${sceneId}.` });
|
|
929
|
+
return mounts;
|
|
930
|
+
}
|
|
931
|
+
/** This flow's decisions, in order. Empty unless the run was opened with `log: true`.
|
|
932
|
+
* The engine's log carries the same events tagged with the flow; this one is what a
|
|
933
|
+
* single conversation reads as. */
|
|
934
|
+
log() {
|
|
935
|
+
return this.flowLog;
|
|
936
|
+
}
|
|
937
|
+
/** Drop the retained entries. `seq` keeps counting, so order survives a clear. */
|
|
938
|
+
clearLog() {
|
|
939
|
+
this.flowLog.length = 0;
|
|
940
|
+
}
|
|
941
|
+
/** Record one decision, on this flow's log and the engine's. Cheap to call with logging
|
|
942
|
+
* off: the entry is never built. */
|
|
943
|
+
emit(event) {
|
|
944
|
+
const scene = this.currentSceneId ?? void 0;
|
|
945
|
+
this.host.emitEngine(this.id, event, scene);
|
|
946
|
+
if (!this.host.logEnabled) return;
|
|
947
|
+
this.flowLog.push({ ...event, seq: this.flowSeq++, ...scene ? { scene } : {} });
|
|
948
|
+
}
|
|
848
949
|
/** The options of a pending choice (empty when not at a choice point). */
|
|
849
950
|
getChoices() {
|
|
850
951
|
return this.pendingChoice?.options ?? [];
|
|
@@ -857,6 +958,7 @@ var Flow = class {
|
|
|
857
958
|
if (!option) throw new Error(`unknown choice option: ${id}`);
|
|
858
959
|
if (!option.eligible) throw new Error(`choice option is not eligible: ${id}`);
|
|
859
960
|
const node = choice.byId.get(id);
|
|
961
|
+
this.emit({ type: "chose", group: choice.groupId, option: id });
|
|
860
962
|
this.pendingChoice = null;
|
|
861
963
|
this.pendingPromptBeat = this.host.replayPromptOnChoose ? this.promptBeatOf(node) ?? null : null;
|
|
862
964
|
this.pendingPromptOwnerId = this.pendingPromptBeat ? node.id : null;
|
|
@@ -890,7 +992,7 @@ var Flow = class {
|
|
|
890
992
|
return {
|
|
891
993
|
scopes: this.local.save(),
|
|
892
994
|
// owned scope "patter" = the NOT-shared globals (@scene saved separately)
|
|
893
|
-
sceneBags: Object.fromEntries([...this.sceneBags].map(([s, bag]) => [s,
|
|
995
|
+
sceneBags: Object.fromEntries([...this.sceneBags].map(([s, bag]) => [s, bag.save()])),
|
|
894
996
|
rngState: this.rngState,
|
|
895
997
|
visits: Object.fromEntries(this.visitCounts),
|
|
896
998
|
cursor: {
|
|
@@ -928,7 +1030,13 @@ var Flow = class {
|
|
|
928
1030
|
}
|
|
929
1031
|
return { ...frame };
|
|
930
1032
|
});
|
|
931
|
-
this.sceneBags = new Map(Object.entries(snap.sceneBags ?? {}).map(([s,
|
|
1033
|
+
this.sceneBags = new Map(Object.entries(snap.sceneBags ?? {}).map(([s, values]) => {
|
|
1034
|
+
const shared = this.host.sceneSharedNames.get(s) ?? /* @__PURE__ */ new Set();
|
|
1035
|
+
const decls = (this.host.bundle.scenes[s]?.sceneProps ?? []).filter((d) => !shared.has(d.name.toLowerCase()));
|
|
1036
|
+
const bag = new PropertyBag(decls);
|
|
1037
|
+
bag.load(values);
|
|
1038
|
+
return [s, bag];
|
|
1039
|
+
}));
|
|
932
1040
|
this.local = this.freshLocal();
|
|
933
1041
|
this.local.load(snap.scopes);
|
|
934
1042
|
this.activeSnippet = null;
|
|
@@ -1022,6 +1130,7 @@ var Flow = class {
|
|
|
1022
1130
|
byId.set(child.id, child);
|
|
1023
1131
|
}
|
|
1024
1132
|
if (options.length > 0) {
|
|
1133
|
+
this.emit({ type: "choice", group: group.id, options: options.map((o) => ({ id: o.id, eligible: o.eligible })) });
|
|
1025
1134
|
this.pendingChoice = { groupId: group.id, options, byId };
|
|
1026
1135
|
return;
|
|
1027
1136
|
}
|
|
@@ -1030,6 +1139,7 @@ var Flow = class {
|
|
|
1030
1139
|
this.enterChild(fallback);
|
|
1031
1140
|
return;
|
|
1032
1141
|
}
|
|
1142
|
+
this.emit({ type: "dry", group: group.id });
|
|
1033
1143
|
this.host.onDryChoice?.(group.id);
|
|
1034
1144
|
}
|
|
1035
1145
|
// -- Jumps (jump / call-return) ----------------------------------------
|
|
@@ -1044,6 +1154,7 @@ var Flow = class {
|
|
|
1044
1154
|
* hard-ends the flow regardless of the callstack.
|
|
1045
1155
|
*/
|
|
1046
1156
|
enterTarget(to, mode) {
|
|
1157
|
+
this.emit({ type: "jump", to, mode });
|
|
1047
1158
|
if (to === "END") {
|
|
1048
1159
|
this.flowEnded = true;
|
|
1049
1160
|
this.stack = [];
|
|
@@ -1075,17 +1186,28 @@ var Flow = class {
|
|
|
1075
1186
|
}
|
|
1076
1187
|
// -- Selectors ------------------------------------------------------------
|
|
1077
1188
|
selectChild(group) {
|
|
1189
|
+
const verdicts = group.children.map((c) => ({ id: c.id, eligible: this.eligible(c) }));
|
|
1078
1190
|
const eligible = group.children.filter((c) => this.eligible(c));
|
|
1079
|
-
|
|
1191
|
+
const order = group.options?.order ?? "sequential";
|
|
1192
|
+
const exhaust = group.options?.exhaust ?? "once";
|
|
1193
|
+
const trace = (picked) => {
|
|
1194
|
+
this.emit({
|
|
1195
|
+
type: "select",
|
|
1196
|
+
group: group.id,
|
|
1197
|
+
selector: group.selector ?? "default",
|
|
1198
|
+
...group.selector === "sequence" ? { order, exhaust } : {},
|
|
1199
|
+
children: verdicts,
|
|
1200
|
+
picked: picked?.id ?? null
|
|
1201
|
+
});
|
|
1202
|
+
return picked;
|
|
1203
|
+
};
|
|
1204
|
+
if (eligible.length === 0) return trace(null);
|
|
1080
1205
|
const st = this.selectorState(group);
|
|
1081
1206
|
switch (group.selector) {
|
|
1082
1207
|
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
|
-
}
|
|
1208
|
+
return trace(eligible[0]);
|
|
1209
|
+
case "sequence":
|
|
1210
|
+
return trace(order === "shuffle" ? this.pickShuffle(eligible, exhaust, st) : order === "specificity" ? this.pickSpecificity(eligible, exhaust, st) : this.pickSequential(eligible, exhaust, st));
|
|
1089
1211
|
case "run":
|
|
1090
1212
|
case "choice":
|
|
1091
1213
|
default:
|
|
@@ -1203,7 +1325,10 @@ var Flow = class {
|
|
|
1203
1325
|
// -- Effects + expressions ------------------------------------------------
|
|
1204
1326
|
runEffects(effects) {
|
|
1205
1327
|
for (const e of effects ?? []) {
|
|
1206
|
-
|
|
1328
|
+
const value = this.evalExpr(e.value);
|
|
1329
|
+
const prev = this.host.logEnabled ? this.getProperty(e.target) : void 0;
|
|
1330
|
+
this.setProperty(e.target, value);
|
|
1331
|
+
this.emit({ type: "write", target: e.target, value, ...prev !== void 0 ? { prev } : {} });
|
|
1207
1332
|
}
|
|
1208
1333
|
}
|
|
1209
1334
|
eligible(node) {
|
|
@@ -1347,7 +1472,7 @@ var Flow = class {
|
|
|
1347
1472
|
}
|
|
1348
1473
|
/** The per-flow registry: the NOT-shared `@patter` globals (the shared ones live on the host). */
|
|
1349
1474
|
freshLocal() {
|
|
1350
|
-
return new ScopeRegistry().defineOwned("patter", this.host.patterLocalDecls);
|
|
1475
|
+
return new ScopeRegistry().defineOwned("patter", this.host.patterLocalDecls, "@patter.");
|
|
1351
1476
|
}
|
|
1352
1477
|
/**
|
|
1353
1478
|
* Seed a scene's `@scene` props (spec §7). The not-shared props seed THIS flow's
|
|
@@ -1358,27 +1483,18 @@ var Flow = class {
|
|
|
1358
1483
|
*/
|
|
1359
1484
|
seedScene(scene) {
|
|
1360
1485
|
const shared = this.host.sceneSharedNames.get(scene.id) ?? /* @__PURE__ */ new Set();
|
|
1486
|
+
const props = scene.sceneProps ?? [];
|
|
1361
1487
|
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);
|
|
1488
|
+
this.sceneBags.set(scene.id, new PropertyBag(props.filter((d) => !shared.has(d.name.toLowerCase()))));
|
|
1368
1489
|
}
|
|
1369
1490
|
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);
|
|
1491
|
+
this.host.stageBags.set(scene.id, new PropertyBag(props.filter((d) => shared.has(d.name.toLowerCase()))));
|
|
1376
1492
|
}
|
|
1377
1493
|
for (const decl of scene.sceneProps ?? []) {
|
|
1378
1494
|
if (!decl.temporary) continue;
|
|
1379
1495
|
const name = decl.name.toLowerCase();
|
|
1380
1496
|
const bag = shared.has(name) ? this.host.stageBags.get(scene.id) : this.sceneBags.get(scene.id);
|
|
1381
|
-
if (bag) bag
|
|
1497
|
+
if (bag) bag.set(name, defaultFor(decl));
|
|
1382
1498
|
}
|
|
1383
1499
|
}
|
|
1384
1500
|
};
|
|
@@ -1416,47 +1532,13 @@ function deserialiseSelectors(rec) {
|
|
|
1416
1532
|
function toDecl(decl) {
|
|
1417
1533
|
return { name: decl.name, type: decl.type, values: decl.values, stages: decl.stages, default: decl.default };
|
|
1418
1534
|
}
|
|
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
1535
|
function toForeignDecl(decl) {
|
|
1437
1536
|
return { name: decl.name, type: decl.type, values: decl.values, stages: decl.stages, default: decl.default, writable: decl.writable };
|
|
1438
1537
|
}
|
|
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
1538
|
function selfBackedResolver(decls) {
|
|
1457
1539
|
const key = (name) => name.toLowerCase();
|
|
1458
1540
|
const bag = /* @__PURE__ */ new Map();
|
|
1459
|
-
for (const d of decls) bag.set(key(d.name),
|
|
1541
|
+
for (const d of decls) bag.set(key(d.name), defaultFor(d));
|
|
1460
1542
|
return {
|
|
1461
1543
|
get: (name) => bag.get(key(name)),
|
|
1462
1544
|
set: (name, value) => {
|
|
@@ -1464,23 +1546,6 @@ function selfBackedResolver(decls) {
|
|
|
1464
1546
|
}
|
|
1465
1547
|
};
|
|
1466
1548
|
}
|
|
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
1549
|
function truthy(v) {
|
|
1485
1550
|
if (typeof v === "boolean") return v;
|
|
1486
1551
|
if (typeof v === "number") return v !== 0;
|