@rohal12/spindle 0.59.3 → 0.59.4
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/pkg/format.js +1 -1
- package/dist/pkg/headless.js +171 -69
- package/package.json +1 -1
- package/src/components/macros/Include.tsx +7 -2
- package/src/execute-mutation.ts +161 -108
- package/src/saves/save-manager.ts +6 -6
- package/src/saves/storage.ts +24 -1
- package/src/story-api.ts +15 -1
- package/src/structural.ts +54 -28
- package/src/utils/object-path.ts +3 -5
package/dist/pkg/headless.js
CHANGED
|
@@ -12897,6 +12897,23 @@ function makeTables(table) {
|
|
|
12897
12897
|
meta: table("meta", {})
|
|
12898
12898
|
};
|
|
12899
12899
|
}
|
|
12900
|
+
/**
|
|
12901
|
+
* The meta keys a story owns, in one place: save-manager builds them,
|
|
12902
|
+
* deleteMetaByIfid() matches them. A story's key is its prefix followed by
|
|
12903
|
+
* its IFID, except a named slot's pointer, `slot.<name>.<IFID>`.
|
|
12904
|
+
*/
|
|
12905
|
+
var META_PREFIXES = {
|
|
12906
|
+
autosave: "autosave.",
|
|
12907
|
+
slot: "slot.",
|
|
12908
|
+
slotIndex: "slotIndex.",
|
|
12909
|
+
playthroughCount: "playthroughCount.",
|
|
12910
|
+
currentPlaythrough: "currentPlaythroughId."
|
|
12911
|
+
};
|
|
12912
|
+
/** Whether the meta `key` belongs to the story `ifid` (and no other). */
|
|
12913
|
+
function isMetaKeyOf(key, ifid) {
|
|
12914
|
+
const { slot, ...others } = META_PREFIXES;
|
|
12915
|
+
return Object.values(others).some((prefix) => key === prefix + ifid) || key.startsWith(slot) && key.endsWith(`.${ifid}`);
|
|
12916
|
+
}
|
|
12900
12917
|
function createBackend(type, { saves, playthroughs, meta }, destroy) {
|
|
12901
12918
|
/** Delete the records `field` finds, resolving to their keys. */
|
|
12902
12919
|
async function deleteFound(table, keyOf, field, value) {
|
|
@@ -12929,7 +12946,7 @@ function createBackend(type, { saves, playthroughs, meta }, destroy) {
|
|
|
12929
12946
|
setMeta: (key, value) => meta.put(key, value),
|
|
12930
12947
|
deleteMeta: (key) => meta.delete(key),
|
|
12931
12948
|
deleteMetaByPrefix: (prefix) => deleteMetaWhere((key) => key.startsWith(prefix)),
|
|
12932
|
-
deleteMetaByIfid: (ifid) => deleteMetaWhere((key) => key
|
|
12949
|
+
deleteMetaByIfid: (ifid) => deleteMetaWhere((key) => isMetaKeyOf(key, ifid)),
|
|
12933
12950
|
getAllMetaKeys: () => meta.keys(),
|
|
12934
12951
|
destroy
|
|
12935
12952
|
};
|
|
@@ -13250,7 +13267,7 @@ var builtinName = atomicName;
|
|
|
13250
13267
|
* stays an instance of its class (with the same own keys deepClone copies).
|
|
13251
13268
|
*/
|
|
13252
13269
|
function shallowCopy(value) {
|
|
13253
|
-
const copy = Array.isArray(value) ?
|
|
13270
|
+
const copy = Array.isArray(value) ? new Array(value.length) : Object.create(Object.getPrototypeOf(value));
|
|
13254
13271
|
for (const key of Object.keys(value)) Object.defineProperty(copy, key, {
|
|
13255
13272
|
value: value[key],
|
|
13256
13273
|
enumerable: true,
|
|
@@ -13693,23 +13710,42 @@ function underChange(path, keys) {
|
|
|
13693
13710
|
return false;
|
|
13694
13711
|
}
|
|
13695
13712
|
/**
|
|
13696
|
-
*
|
|
13697
|
-
* depth-first order. Plain objects
|
|
13698
|
-
*
|
|
13713
|
+
* Every path each object (or array, or other value) of `root` is at, the
|
|
13714
|
+
* first appearance first, in depth-first order. Plain objects and arrays are
|
|
13715
|
+
* entered, where first met only (an object held in an array is one object,
|
|
13716
|
+
* however it was reached); other values are leaves. A path at or below one
|
|
13717
|
+
* of `skip` is left out.
|
|
13699
13718
|
*/
|
|
13700
|
-
function
|
|
13701
|
-
const
|
|
13719
|
+
function objectPaths(root, skip = /* @__PURE__ */ new Set()) {
|
|
13720
|
+
const all = /* @__PURE__ */ new Map();
|
|
13702
13721
|
(function walk(node, path) {
|
|
13703
13722
|
for (const key of Object.keys(node)) {
|
|
13704
13723
|
const value = node[key];
|
|
13705
|
-
if (!isObjectValue(value)
|
|
13724
|
+
if (!isObjectValue(value)) continue;
|
|
13706
13725
|
const at = [...path, key];
|
|
13707
13726
|
if (skip.has(pathKey(at))) continue;
|
|
13708
|
-
|
|
13709
|
-
if (
|
|
13727
|
+
const known = all.get(value);
|
|
13728
|
+
if (known) {
|
|
13729
|
+
known.push(at);
|
|
13730
|
+
continue;
|
|
13731
|
+
}
|
|
13732
|
+
all.set(value, [at]);
|
|
13733
|
+
if (isMergeable(value) || Array.isArray(value)) walk(value, at);
|
|
13710
13734
|
}
|
|
13711
13735
|
})(root, []);
|
|
13712
|
-
return
|
|
13736
|
+
return all;
|
|
13737
|
+
}
|
|
13738
|
+
/** Where each object of `root` first appears (see objectPaths). */
|
|
13739
|
+
function firstPaths(root, skip) {
|
|
13740
|
+
return new Map([...objectPaths(root, skip)].map(([object, paths]) => [object, paths[0]]));
|
|
13741
|
+
}
|
|
13742
|
+
/**
|
|
13743
|
+
* The objects `root` holds at more than one path (an object two variables
|
|
13744
|
+
* refer to, or one that refers to itself), with every path they are at,
|
|
13745
|
+
* parents before children.
|
|
13746
|
+
*/
|
|
13747
|
+
function sharedPaths(root) {
|
|
13748
|
+
return [...objectPaths(root).values()].filter((paths) => paths.length > 1);
|
|
13713
13749
|
}
|
|
13714
13750
|
/**
|
|
13715
13751
|
* The paths whose object is another one in the references of `after` than in
|
|
@@ -13739,7 +13775,7 @@ function aliasChanges(before, after) {
|
|
|
13739
13775
|
value: y,
|
|
13740
13776
|
alias: true
|
|
13741
13777
|
});
|
|
13742
|
-
if (isMergeable(x) && mergesWith(x, y,
|
|
13778
|
+
if ((isMergeable(x) || Array.isArray(x)) && mergesWith(x, y, true) && pathKey(isAt) === k && pathKey(wasAt) === k) walk(x, y, at);
|
|
13743
13779
|
}
|
|
13744
13780
|
})(before, after, []);
|
|
13745
13781
|
return changes;
|
|
@@ -13780,8 +13816,9 @@ function isApplied(target, change) {
|
|
|
13780
13816
|
return !change.deleted && deepEqual(parent[key], change.value);
|
|
13781
13817
|
}
|
|
13782
13818
|
function applyChange(target, change) {
|
|
13783
|
-
|
|
13784
|
-
|
|
13819
|
+
const root = target;
|
|
13820
|
+
if (change.deleted) deleteByPath(root, change.path);
|
|
13821
|
+
else setByPath(root, change.path, change.value);
|
|
13785
13822
|
}
|
|
13786
13823
|
/**
|
|
13787
13824
|
* Write how `after` differs from `before` (see keyChanges; arrays merge by
|
|
@@ -13931,7 +13968,7 @@ async function startNewPlaythroughNow(ifid, id = randomUUID()) {
|
|
|
13931
13968
|
}
|
|
13932
13969
|
var PLAYTHROUGH_LABEL = /^Playthrough (\d+)$/;
|
|
13933
13970
|
function playthroughCountKey(ifid) {
|
|
13934
|
-
return
|
|
13971
|
+
return `${META_PREFIXES.playthroughCount}${ifid}`;
|
|
13935
13972
|
}
|
|
13936
13973
|
/**
|
|
13937
13974
|
* The number of the next playthrough the story starts: one past the highest
|
|
@@ -13950,7 +13987,7 @@ async function nextPlaythroughNumber(ifid) {
|
|
|
13950
13987
|
return highest + 1;
|
|
13951
13988
|
}
|
|
13952
13989
|
function currentPlaythroughKey(ifid) {
|
|
13953
|
-
return
|
|
13990
|
+
return `${META_PREFIXES.currentPlaythrough}${ifid}`;
|
|
13954
13991
|
}
|
|
13955
13992
|
/**
|
|
13956
13993
|
* Make `id` the story's current playthrough: the playthrough of a save the
|
|
@@ -14157,9 +14194,9 @@ var getSavesGrouped = queued(async function getSavesGroupedNow(ifid) {
|
|
|
14157
14194
|
});
|
|
14158
14195
|
return result;
|
|
14159
14196
|
});
|
|
14160
|
-
var AUTOSAVE_KEY_PREFIX =
|
|
14161
|
-
var SLOT_KEY_PREFIX =
|
|
14162
|
-
var SLOT_INDEX_KEY_PREFIX =
|
|
14197
|
+
var AUTOSAVE_KEY_PREFIX = META_PREFIXES.autosave;
|
|
14198
|
+
var SLOT_KEY_PREFIX = META_PREFIXES.slot;
|
|
14199
|
+
var SLOT_INDEX_KEY_PREFIX = META_PREFIXES.slotIndex;
|
|
14163
14200
|
/**
|
|
14164
14201
|
* Whether `slot` names a slot. The default (autosave) slot is addressed by
|
|
14165
14202
|
* omitting `slot` or by `''`, the identifier its SaveInfo reports.
|
|
@@ -14597,17 +14634,17 @@ function frozenCopy(value) {
|
|
|
14597
14634
|
* path (the code replaced or deleted an intermediate object), its root is
|
|
14598
14635
|
* replaced with the store's root as written.
|
|
14599
14636
|
*/
|
|
14600
|
-
function mirror(draft,
|
|
14601
|
-
const root = change.path
|
|
14602
|
-
for (const scope of scopes) for (const copy of [scope.work
|
|
14637
|
+
function mirror(draft, change, scopes = activeScopes, cloner = clonerOf) {
|
|
14638
|
+
const [ns, root] = change.path;
|
|
14639
|
+
for (const scope of scopes) for (const copy of [scope.work, scope.base]) try {
|
|
14603
14640
|
applyChange(copy, change.deleted ? change : {
|
|
14604
14641
|
...change,
|
|
14605
14642
|
value: cloner(copy)(change.value)
|
|
14606
14643
|
});
|
|
14607
14644
|
} catch {
|
|
14608
14645
|
const stored = draft[ns][root];
|
|
14609
|
-
if (hasOwn(draft[ns], root)) copy[root] = cloneValue(isDraft(stored) ? current(stored) : stored);
|
|
14610
|
-
else delete copy[root];
|
|
14646
|
+
if (hasOwn(draft[ns], root)) copy[ns][root] = cloneValue(isDraft(stored) ? current(stored) : stored);
|
|
14647
|
+
else delete copy[ns][root];
|
|
14611
14648
|
}
|
|
14612
14649
|
}
|
|
14613
14650
|
/** A cloner of a copy of its own (no references shared with others). */
|
|
@@ -14707,16 +14744,19 @@ function routeStoreUpdate(recipe) {
|
|
|
14707
14744
|
transient: inner.work.transient
|
|
14708
14745
|
};
|
|
14709
14746
|
const [next, patches] = scratch.produceWithPatches(view, recipe);
|
|
14710
|
-
const changes = NAMESPACES.
|
|
14747
|
+
const changes = NAMESPACES.flatMap((ns) => {
|
|
14711
14748
|
const own = patches.filter((p) => p.path[0] === ns);
|
|
14712
|
-
return
|
|
14749
|
+
return own.length ? writtenPaths(view[ns], next[ns], own).map((change) => ({
|
|
14750
|
+
...change,
|
|
14751
|
+
path: [ns, ...change.path]
|
|
14752
|
+
})) : [];
|
|
14713
14753
|
});
|
|
14714
14754
|
const cloners = clonersFor();
|
|
14715
14755
|
const owned = (change, target) => change.deleted ? change : {
|
|
14716
14756
|
...change,
|
|
14717
14757
|
value: cloners(target)(change.value)
|
|
14718
14758
|
};
|
|
14719
|
-
for (const
|
|
14759
|
+
for (const change of changes) applyChange(inner.work, owned(change, inner.work));
|
|
14720
14760
|
return (draft) => {
|
|
14721
14761
|
const target = draft;
|
|
14722
14762
|
for (const key of Object.keys(next)) {
|
|
@@ -14724,23 +14764,48 @@ function routeStoreUpdate(recipe) {
|
|
|
14724
14764
|
if (!NAMESPACE_KEYS$1.has(key) && value !== view[key]) target[key] = value;
|
|
14725
14765
|
}
|
|
14726
14766
|
const namespaces = draft;
|
|
14727
|
-
for (const
|
|
14728
|
-
const root = change.path
|
|
14767
|
+
for (const change of changes) {
|
|
14768
|
+
const [ns, root] = change.path;
|
|
14729
14769
|
try {
|
|
14730
|
-
applyChange(namespaces
|
|
14770
|
+
applyChange(namespaces, owned(change, namespaces));
|
|
14731
14771
|
} catch {
|
|
14732
14772
|
if (hasOwn(inner.work[ns], root)) namespaces[ns][root] = cloneValue(inner.work[ns][root]);
|
|
14733
14773
|
else delete namespaces[ns][root];
|
|
14734
14774
|
}
|
|
14735
|
-
mirror(namespaces,
|
|
14775
|
+
mirror(namespaces, change, activeScopes, cloners);
|
|
14736
14776
|
}
|
|
14737
14777
|
};
|
|
14738
14778
|
}
|
|
14739
|
-
|
|
14740
|
-
|
|
14741
|
-
|
|
14742
|
-
|
|
14743
|
-
|
|
14779
|
+
/**
|
|
14780
|
+
* Make the objects `work` holds at several paths one object in `draft`
|
|
14781
|
+
* again where `changes` wrote below one of them: a write through one path
|
|
14782
|
+
* of a draft gives that path a new object, and the other paths would go on
|
|
14783
|
+
* referring to the old one (`$a.n = 2` with `$b` the same object as `$a`).
|
|
14784
|
+
*/
|
|
14785
|
+
function relink(draft, work, changes) {
|
|
14786
|
+
const written = changes.map((c) => pathKey(c.path).slice(0, -1));
|
|
14787
|
+
for (const [first, ...others] of sharedPaths(work)) {
|
|
14788
|
+
const prefixes = [first, ...others].map((p) => pathKey(p).slice(0, -1));
|
|
14789
|
+
if (!written.some((w) => prefixes.some((p) => w.startsWith(p)))) continue;
|
|
14790
|
+
try {
|
|
14791
|
+
const object = getByPath(draft, first);
|
|
14792
|
+
if (object === null || typeof object !== "object") continue;
|
|
14793
|
+
for (const path of others) setByPath(draft, path, object);
|
|
14794
|
+
} catch {}
|
|
14795
|
+
}
|
|
14796
|
+
}
|
|
14797
|
+
/**
|
|
14798
|
+
* Copies of the namespaces that keep their references to each other: an
|
|
14799
|
+
* object held in two of them (`%copy = $a`) is one object in the copies too.
|
|
14800
|
+
*/
|
|
14801
|
+
function cloneNamespaces(from) {
|
|
14802
|
+
const seen = /* @__PURE__ */ new Map();
|
|
14803
|
+
return {
|
|
14804
|
+
variables: deepClone(from.variables, { seen }),
|
|
14805
|
+
temporary: deepClone(from.temporary, { seen }),
|
|
14806
|
+
transient: deepClone(from.transient, { seen })
|
|
14807
|
+
};
|
|
14808
|
+
}
|
|
14744
14809
|
/**
|
|
14745
14810
|
* Commit the property paths each mutation's code changed (work vs base) on
|
|
14746
14811
|
* top of the current store state, so writes made elsewhere during execution
|
|
@@ -14760,9 +14825,9 @@ function commitScopes(commits) {
|
|
|
14760
14825
|
const all = commits.map(({ scope, keepRunning }) => ({
|
|
14761
14826
|
scope,
|
|
14762
14827
|
keepRunning,
|
|
14763
|
-
changes:
|
|
14828
|
+
changes: changesOf(scope.base, scope.work)
|
|
14764
14829
|
}));
|
|
14765
|
-
const changed = all.filter(({ changes }) => changes.
|
|
14830
|
+
const changed = all.filter(({ changes }) => changes.length > 0);
|
|
14766
14831
|
if (changed.length === 0) return;
|
|
14767
14832
|
for (const { scope, keepRunning } of changed) if (keepRunning) scope.base = cloneNamespaces(scope.work);
|
|
14768
14833
|
committing = true;
|
|
@@ -14773,46 +14838,50 @@ function commitScopes(commits) {
|
|
|
14773
14838
|
}
|
|
14774
14839
|
function commitRecipe(draft) {
|
|
14775
14840
|
all.forEach(({ scope, changes }, i) => {
|
|
14776
|
-
const paths =
|
|
14777
|
-
const own =
|
|
14841
|
+
const paths = locateObjects(scope.work, changes);
|
|
14842
|
+
const own = clonerFor(draft, paths);
|
|
14778
14843
|
const enclosing = all.slice(0, i).map((c) => c.scope);
|
|
14779
|
-
const enclosingCloners =
|
|
14780
|
-
|
|
14781
|
-
|
|
14782
|
-
|
|
14783
|
-
|
|
14784
|
-
|
|
14785
|
-
|
|
14786
|
-
|
|
14787
|
-
|
|
14788
|
-
|
|
14789
|
-
}
|
|
14790
|
-
const value = change.alias ? own.get(ns)(change.value) : void 0;
|
|
14791
|
-
if (change.alias ? Object.is(getByPath(draft[ns], change.path), value) : isApplied(draft[ns], change)) continue;
|
|
14792
|
-
applyChange(draft[ns], {
|
|
14793
|
-
...change,
|
|
14794
|
-
value: change.alias ? value : own.get(ns)(change.value)
|
|
14795
|
-
});
|
|
14796
|
-
} catch {
|
|
14797
|
-
draft[ns][root] = own.get(ns)(scope.work[ns][root]);
|
|
14798
|
-
replaced.add(root);
|
|
14844
|
+
const enclosingCloners = clonersFor(() => paths);
|
|
14845
|
+
const replaced = /* @__PURE__ */ new Set();
|
|
14846
|
+
for (const change of changes) {
|
|
14847
|
+
const [ns, root] = change.path;
|
|
14848
|
+
const rootKey = pathKey([ns, root]);
|
|
14849
|
+
if (replaced.has(rootKey)) continue;
|
|
14850
|
+
try {
|
|
14851
|
+
if (change.deleted) {
|
|
14852
|
+
if (!isApplied(draft, change)) applyChange(draft, change);
|
|
14853
|
+
continue;
|
|
14799
14854
|
}
|
|
14855
|
+
const value = change.alias ? own(change.value) : void 0;
|
|
14856
|
+
if (change.alias ? Object.is(getByPath(draft, change.path), value) : isApplied(draft, change)) continue;
|
|
14857
|
+
applyChange(draft, {
|
|
14858
|
+
...change,
|
|
14859
|
+
value: change.alias ? value : own(change.value)
|
|
14860
|
+
});
|
|
14861
|
+
} catch {
|
|
14862
|
+
draft[ns][root] = own(scope.work[ns][root]);
|
|
14863
|
+
replaced.add(rootKey);
|
|
14800
14864
|
}
|
|
14801
|
-
for (const change of list) mirror(draft, ns, change, enclosing, enclosingCloners.get(ns));
|
|
14802
14865
|
}
|
|
14866
|
+
relink(draft, scope.work, changes);
|
|
14867
|
+
for (const change of changes) mirror(draft, change, enclosing, enclosingCloners);
|
|
14803
14868
|
});
|
|
14804
14869
|
}
|
|
14805
14870
|
}
|
|
14806
14871
|
/**
|
|
14807
|
-
* The changes of the code to
|
|
14808
|
-
* (see diffPaths), and those that hold
|
|
14809
|
-
* than they did (see aliasChanges), those
|
|
14872
|
+
* The changes of the code to the namespaces, as paths below them (`['variables',
|
|
14873
|
+
* 'a']`): the property paths that differ (see diffPaths), and those that hold
|
|
14874
|
+
* equal content but another object than they did (see aliasChanges), those
|
|
14875
|
+
* first. Compared as one object, so an object the namespaces share is one
|
|
14876
|
+
* object, whichever of them it is reached through.
|
|
14810
14877
|
*/
|
|
14811
14878
|
function changesOf(base, work) {
|
|
14812
|
-
const
|
|
14879
|
+
const before = base;
|
|
14880
|
+
const after = work;
|
|
14881
|
+
const written = diffPaths(before, after);
|
|
14813
14882
|
const keys = new Set(written.map((c) => pathKey(c.path)));
|
|
14814
14883
|
const aliases = [];
|
|
14815
|
-
for (const change of aliasChanges(
|
|
14884
|
+
for (const change of aliasChanges(before, after)) {
|
|
14816
14885
|
if (underChange(change.path, keys)) continue;
|
|
14817
14886
|
keys.add(pathKey(change.path));
|
|
14818
14887
|
aliases.push(change);
|
|
@@ -14853,14 +14922,38 @@ function runWithCommittedMutations(action) {
|
|
|
14853
14922
|
for (const scope of suspended) resync(scope);
|
|
14854
14923
|
}
|
|
14855
14924
|
}
|
|
14856
|
-
|
|
14925
|
+
/**
|
|
14926
|
+
* Run `run` on working copies of the story state and commit what it changed
|
|
14927
|
+
* to the store, as mutation code does (see commitScopes): the references
|
|
14928
|
+
* between values are kept, which a store update made on a draft does not do.
|
|
14929
|
+
* Nothing is committed when `run` throws.
|
|
14930
|
+
*/
|
|
14931
|
+
function mutateState(run) {
|
|
14932
|
+
commitScopes(running());
|
|
14933
|
+
const scope = startScope();
|
|
14934
|
+
try {
|
|
14935
|
+
run(scope.work);
|
|
14936
|
+
} finally {
|
|
14937
|
+
activeScopes.pop();
|
|
14938
|
+
}
|
|
14939
|
+
commitScopes([...running(), {
|
|
14940
|
+
scope,
|
|
14941
|
+
keepRunning: false
|
|
14942
|
+
}]);
|
|
14943
|
+
}
|
|
14944
|
+
/** Start a mutation, from the pending state of the one it runs inside. */
|
|
14945
|
+
function startScope() {
|
|
14857
14946
|
const start = getActiveMutationScope() ?? useStoryStore.getState();
|
|
14858
14947
|
const scope = {
|
|
14859
14948
|
work: cloneNamespaces(start),
|
|
14860
14949
|
base: cloneNamespaces(start)
|
|
14861
14950
|
};
|
|
14862
|
-
const localsClone = asNamespace(deepClone(mergedLocals, { keepUnregistered: true }));
|
|
14863
14951
|
activeScopes.push(scope);
|
|
14952
|
+
return scope;
|
|
14953
|
+
}
|
|
14954
|
+
function executeMutation(code, mergedLocals, scopeUpdate) {
|
|
14955
|
+
const localsClone = asNamespace(deepClone(mergedLocals, { keepUnregistered: true }));
|
|
14956
|
+
const scope = startScope();
|
|
14864
14957
|
try {
|
|
14865
14958
|
execute(code, scope.work.variables, scope.work.temporary, localsClone, scope.work.transient);
|
|
14866
14959
|
} finally {
|
|
@@ -17338,6 +17431,12 @@ function createStoryAPI() {
|
|
|
17338
17431
|
const { isTransient, key } = parseName(name);
|
|
17339
17432
|
warnIfUndeclared(isTransient, key);
|
|
17340
17433
|
}
|
|
17434
|
+
if (entries.some(([k]) => k.includes("."))) {
|
|
17435
|
+
mutateState((work) => {
|
|
17436
|
+
for (const [k, v] of entries) setOne(work, k, v);
|
|
17437
|
+
});
|
|
17438
|
+
return;
|
|
17439
|
+
}
|
|
17341
17440
|
useStoryStore.getState().updateVariables((draft) => {
|
|
17342
17441
|
for (const [k, v] of entries) setOne(draft, k, v);
|
|
17343
17442
|
});
|
|
@@ -19729,13 +19828,16 @@ defineMacro({
|
|
|
19729
19828
|
}
|
|
19730
19829
|
const passage = storyData?.passages.get(passageName);
|
|
19731
19830
|
const ast = ctx.hooks.useMemo(() => passage ? parseMarkup(passage.content) : null, [passage]);
|
|
19831
|
+
const included = !failure && !!passage;
|
|
19832
|
+
ctx.hooks.useEffect(() => {
|
|
19833
|
+
if (included) useStoryStore.getState().trackRender(passageName);
|
|
19834
|
+
}, [included, passageName]);
|
|
19732
19835
|
if (!storyData) return null;
|
|
19733
19836
|
if (failure) return /* @__PURE__ */ jsx(MacroError, {
|
|
19734
19837
|
macro: "include",
|
|
19735
19838
|
error: failure.error
|
|
19736
19839
|
});
|
|
19737
19840
|
if (!passage || !ast) return null;
|
|
19738
|
-
useStoryStore.getState().trackRender(passageName);
|
|
19739
19841
|
const nobr = passage.tags.includes("nobr");
|
|
19740
19842
|
const content = inline ? ctx.renderInlineNodes(ast) : ctx.renderNodes(ast, nobr ? { nobr: true } : void 0);
|
|
19741
19843
|
if (nobr) return ctx.wrap(ctx.h(NobrContext.Provider, { value: true }, content));
|
package/package.json
CHANGED
|
@@ -38,6 +38,13 @@ defineMacro({
|
|
|
38
38
|
[passage],
|
|
39
39
|
);
|
|
40
40
|
|
|
41
|
+
// Count the inclusion when its content mounts or the passage changes,
|
|
42
|
+
// not on every render (an unrelated variable update re-renders it)
|
|
43
|
+
const included = !failure && !!passage;
|
|
44
|
+
ctx.hooks.useEffect(() => {
|
|
45
|
+
if (included) useStoryStore.getState().trackRender(passageName);
|
|
46
|
+
}, [included, passageName]);
|
|
47
|
+
|
|
41
48
|
if (!storyData) return null;
|
|
42
49
|
if (failure) {
|
|
43
50
|
return (
|
|
@@ -49,8 +56,6 @@ defineMacro({
|
|
|
49
56
|
}
|
|
50
57
|
if (!passage || !ast) return null;
|
|
51
58
|
|
|
52
|
-
useStoryStore.getState().trackRender(passageName);
|
|
53
|
-
|
|
54
59
|
const nobr = passage.tags.includes('nobr');
|
|
55
60
|
const content = inline
|
|
56
61
|
? ctx.renderInlineNodes(ast)
|