@patterkit/runtime 0.4.0 → 0.4.2
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 +35 -0
- package/dist/index.cjs +109 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +139 -2
- package/dist/index.d.ts +139 -2
- package/dist/index.js +108 -3
- 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 +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ScalarValue } from '@wildwinter/expr';
|
|
2
2
|
import { ScopeResolver, ScopeRegistry, ScopeDeclaration } from '@wildwinter/scoperegistry';
|
|
3
|
-
import { GameData, Bundle, CompiledGroup, CompiledSnippet, CompiledBlock, PropertyType,
|
|
3
|
+
import { GameData, Bundle, CompiledGroup, CompiledSnippet, CompiledBlock, PropertyType, ScalarValue as ScalarValue$1, GameDataNodeKind, GameDataField } from '@patterkit/model';
|
|
4
4
|
export { Bundle } from '@patterkit/model';
|
|
5
5
|
|
|
6
6
|
type SelectableNode = CompiledGroup | CompiledSnippet;
|
|
@@ -705,6 +705,143 @@ declare class Flow {
|
|
|
705
705
|
private seedScene;
|
|
706
706
|
}
|
|
707
707
|
|
|
708
|
+
/** Which bundle this is: identity, staleness fingerprints, and how it ships. */
|
|
709
|
+
interface BundleIdentity {
|
|
710
|
+
/** The bundle schema tag ("patter/bundle@0"). */
|
|
711
|
+
schema: string;
|
|
712
|
+
/** The project name. A save must agree with this. */
|
|
713
|
+
project: string;
|
|
714
|
+
/** The authored bundle version, if the project stamps one. */
|
|
715
|
+
version?: string;
|
|
716
|
+
/** Fingerprint over the WHOLE bundle: what binds saves and gates staleness. */
|
|
717
|
+
hash?: string;
|
|
718
|
+
/** The same fingerprint with the string tables left out. Equal structureHash
|
|
719
|
+
* plus a different hash means a TEXT-ONLY edit, which is what makes a live
|
|
720
|
+
* hot-swap safe. Showing both lets an integrator tell those apart at sight. */
|
|
721
|
+
structureHash?: string;
|
|
722
|
+
/** Project-wide VO mode. */
|
|
723
|
+
voiced: boolean;
|
|
724
|
+
defaultLocale: string;
|
|
725
|
+
locales: string[];
|
|
726
|
+
/** How strings ship: "embedded" (the runtime resolves text) or "ids" (the
|
|
727
|
+
* runtime emits beat IDs and the game localises them itself). */
|
|
728
|
+
localisation: "embedded" | "ids";
|
|
729
|
+
/** True when the source locale was embedded purely for debug playback. Such a
|
|
730
|
+
* build is NOT shippable, which is worth saying loudly in an inspector. */
|
|
731
|
+
sourceDebug: boolean;
|
|
732
|
+
}
|
|
733
|
+
/** One scene, and the addresses game code may aim at inside it. */
|
|
734
|
+
interface AddressSummary {
|
|
735
|
+
/** The host-facing scene address: what `runFlow` / `goto` take. Derived from
|
|
736
|
+
* the name when the author set no explicit gameId, exactly as the runtime
|
|
737
|
+
* resolves it, so this list is the truth rather than an approximation. */
|
|
738
|
+
gameId: string;
|
|
739
|
+
/** The authored scene name, for recognising the row. */
|
|
740
|
+
name: string;
|
|
741
|
+
/** Block addresses within this scene. A block address is SCENE-SCOPED: the
|
|
742
|
+
* pair is the address, which is why these are nested rather than flattened. */
|
|
743
|
+
blocks: {
|
|
744
|
+
gameId: string;
|
|
745
|
+
name: string;
|
|
746
|
+
}[];
|
|
747
|
+
}
|
|
748
|
+
/** One author-defined gameData field: part of the host-facing data surface. */
|
|
749
|
+
interface GameDataFieldSummary {
|
|
750
|
+
name: string;
|
|
751
|
+
type: string;
|
|
752
|
+
/** Whether the schema carries a fallback. Sparse storage means a node that
|
|
753
|
+
* sets nothing reads this, so a field with no default can arrive absent. */
|
|
754
|
+
hasDefault: boolean;
|
|
755
|
+
/** Allowed values for an enum field: the set host code switches on. */
|
|
756
|
+
values?: string[];
|
|
757
|
+
purpose?: string;
|
|
758
|
+
}
|
|
759
|
+
/** The gameData fields declared for one kind of node. */
|
|
760
|
+
interface GameDataSummary {
|
|
761
|
+
kind: GameDataNodeKind;
|
|
762
|
+
fields: GameDataFieldSummary[];
|
|
763
|
+
}
|
|
764
|
+
/** One declared property. `hasDefault` rather than the value itself: an
|
|
765
|
+
* inspector wants to know whether the host MUST supply something. */
|
|
766
|
+
interface PropertySummary {
|
|
767
|
+
name: string;
|
|
768
|
+
type: PropertyType;
|
|
769
|
+
hasDefault: boolean;
|
|
770
|
+
default?: ScalarValue$1;
|
|
771
|
+
/** Shared across all flows, or kept per-flow. Defaults differ by scope
|
|
772
|
+
* (`@patter` shared, `@scene` per-flow), so it is resolved here. */
|
|
773
|
+
shared: boolean;
|
|
774
|
+
}
|
|
775
|
+
/** A host scope (`@world` and friends): what the GAME must supply.
|
|
776
|
+
*
|
|
777
|
+
* The highest-value section of the whole description. Today an integrator
|
|
778
|
+
* discovers a missing world property when a condition silently reads a
|
|
779
|
+
* self-backed default and a branch never fires. */
|
|
780
|
+
interface HostScopeSummary {
|
|
781
|
+
/** The token after `@`, e.g. "world". */
|
|
782
|
+
token: string;
|
|
783
|
+
/** Scope-level read/write default for its declarations. */
|
|
784
|
+
writable: boolean;
|
|
785
|
+
/** An OPAQUE scope declares no names: any name is accepted, unchecked. The
|
|
786
|
+
* host contract is then "anything", which is worth showing as such rather
|
|
787
|
+
* than as an empty property list. */
|
|
788
|
+
opaque: boolean;
|
|
789
|
+
properties: PropertySummary[];
|
|
790
|
+
}
|
|
791
|
+
/** Story-owned declarations, for orientation rather than for calling. */
|
|
792
|
+
interface OwnedProperties {
|
|
793
|
+
/** Project-level (`@patter`). */
|
|
794
|
+
patter: PropertySummary[];
|
|
795
|
+
/** Per scene (`@scene`), keyed by the scene's host address. */
|
|
796
|
+
scene: {
|
|
797
|
+
gameId: string;
|
|
798
|
+
properties: PropertySummary[];
|
|
799
|
+
}[];
|
|
800
|
+
}
|
|
801
|
+
/** "Is this the right build?" at a glance. */
|
|
802
|
+
interface BundleCounts {
|
|
803
|
+
scenes: number;
|
|
804
|
+
blocks: number;
|
|
805
|
+
groups: number;
|
|
806
|
+
snippets: number;
|
|
807
|
+
/** Snippet beats. This is the SAME population `Engine.getBeatSequence` walks, deliberately, so a
|
|
808
|
+
* tool that lists beats and an inspector that counts them never disagree. Choice prompts are not
|
|
809
|
+
* in it - see `prompts`. */
|
|
810
|
+
beats: number;
|
|
811
|
+
/** Choice-option prompts: beats that live on a group rather than in a snippet.
|
|
812
|
+
*
|
|
813
|
+
* Counted separately rather than folded into `beats` because folding them in would make this
|
|
814
|
+
* number disagree with `getBeatSequence`, and leaving them out entirely would understate a
|
|
815
|
+
* choice-heavy story - a branching script could report a handful of beats and look like the wrong
|
|
816
|
+
* build. Neither silence nor a redefinition; a second row. */
|
|
817
|
+
prompts: number;
|
|
818
|
+
/** Beats that fire a game event rather than producing player-facing words. */
|
|
819
|
+
gameEvents: number;
|
|
820
|
+
/** Cast members the bundle carries (player-facing only; the compiler strips
|
|
821
|
+
* the authoring fields). */
|
|
822
|
+
cast: number;
|
|
823
|
+
}
|
|
824
|
+
interface BundleDescription {
|
|
825
|
+
identity: BundleIdentity;
|
|
826
|
+
/** Everything game code may aim at, in bundle order. */
|
|
827
|
+
addresses: AddressSummary[];
|
|
828
|
+
/** What the host must supply. */
|
|
829
|
+
hostScopes: HostScopeSummary[];
|
|
830
|
+
/** What the story owns. */
|
|
831
|
+
properties: OwnedProperties;
|
|
832
|
+
/** The author-defined data surface, grouped by node kind. */
|
|
833
|
+
gameData: GameDataSummary[];
|
|
834
|
+
counts: BundleCounts;
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* Describe a compiled bundle: what it is, and what a game may call on it.
|
|
838
|
+
*
|
|
839
|
+
* Pure and allocation-light. Safe to call from an editor inspector on every
|
|
840
|
+
* selection, though a details panel should still build its rows once rather
|
|
841
|
+
* than per repaint.
|
|
842
|
+
*/
|
|
843
|
+
declare function describeBundle(bundle: Bundle): BundleDescription;
|
|
844
|
+
|
|
708
845
|
/** The author-defined gameData fields declared for a node TYPE in a bundle (empty when none). */
|
|
709
846
|
declare function gameDataFields(bundle: Bundle, kind: GameDataNodeKind): GameDataField[];
|
|
710
847
|
/** One node's effective value for a field: its sparse OVERRIDE if present, else the field's declared
|
|
@@ -722,4 +859,4 @@ declare function effectiveGameData(fields: GameDataField[], node: GameData | und
|
|
|
722
859
|
*/
|
|
723
860
|
declare function buildTagIndex(bundle: Bundle): Map<string, string[]>;
|
|
724
861
|
|
|
725
|
-
export { type AdvanceToStopResult, type BeatInfo, type ChoiceOption, Engine, type EngineOptions, type EngineSave, type FlatBeat, Flow, type FlowSnapshot, type OpenFlowOptions, type OutlineBlock, type OutlineNode, type OutlineScene, type PropertyRow, type SaveGame, type SavedChoice, type SelectorSnapshot, type StackFrame, type StepResult, type WorldResolver, buildTagIndex, effectiveGameData, gameDataFields, gameDataValue };
|
|
862
|
+
export { type AddressSummary, type AdvanceToStopResult, type BeatInfo, type BundleCounts, type BundleDescription, type BundleIdentity, type ChoiceOption, Engine, type EngineOptions, type EngineSave, type FlatBeat, Flow, type FlowSnapshot, type GameDataFieldSummary, type GameDataSummary, type HostScopeSummary, type OpenFlowOptions, type OutlineBlock, type OutlineNode, type OutlineScene, type OwnedProperties, type PropertyRow, type PropertySummary, type SaveGame, type SavedChoice, type SelectorSnapshot, type StackFrame, type StepResult, type WorldResolver, buildTagIndex, describeBundle, effectiveGameData, gameDataFields, gameDataValue };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ScalarValue } from '@wildwinter/expr';
|
|
2
2
|
import { ScopeResolver, ScopeRegistry, ScopeDeclaration } from '@wildwinter/scoperegistry';
|
|
3
|
-
import { GameData, Bundle, CompiledGroup, CompiledSnippet, CompiledBlock, PropertyType,
|
|
3
|
+
import { GameData, Bundle, CompiledGroup, CompiledSnippet, CompiledBlock, PropertyType, ScalarValue as ScalarValue$1, GameDataNodeKind, GameDataField } from '@patterkit/model';
|
|
4
4
|
export { Bundle } from '@patterkit/model';
|
|
5
5
|
|
|
6
6
|
type SelectableNode = CompiledGroup | CompiledSnippet;
|
|
@@ -705,6 +705,143 @@ declare class Flow {
|
|
|
705
705
|
private seedScene;
|
|
706
706
|
}
|
|
707
707
|
|
|
708
|
+
/** Which bundle this is: identity, staleness fingerprints, and how it ships. */
|
|
709
|
+
interface BundleIdentity {
|
|
710
|
+
/** The bundle schema tag ("patter/bundle@0"). */
|
|
711
|
+
schema: string;
|
|
712
|
+
/** The project name. A save must agree with this. */
|
|
713
|
+
project: string;
|
|
714
|
+
/** The authored bundle version, if the project stamps one. */
|
|
715
|
+
version?: string;
|
|
716
|
+
/** Fingerprint over the WHOLE bundle: what binds saves and gates staleness. */
|
|
717
|
+
hash?: string;
|
|
718
|
+
/** The same fingerprint with the string tables left out. Equal structureHash
|
|
719
|
+
* plus a different hash means a TEXT-ONLY edit, which is what makes a live
|
|
720
|
+
* hot-swap safe. Showing both lets an integrator tell those apart at sight. */
|
|
721
|
+
structureHash?: string;
|
|
722
|
+
/** Project-wide VO mode. */
|
|
723
|
+
voiced: boolean;
|
|
724
|
+
defaultLocale: string;
|
|
725
|
+
locales: string[];
|
|
726
|
+
/** How strings ship: "embedded" (the runtime resolves text) or "ids" (the
|
|
727
|
+
* runtime emits beat IDs and the game localises them itself). */
|
|
728
|
+
localisation: "embedded" | "ids";
|
|
729
|
+
/** True when the source locale was embedded purely for debug playback. Such a
|
|
730
|
+
* build is NOT shippable, which is worth saying loudly in an inspector. */
|
|
731
|
+
sourceDebug: boolean;
|
|
732
|
+
}
|
|
733
|
+
/** One scene, and the addresses game code may aim at inside it. */
|
|
734
|
+
interface AddressSummary {
|
|
735
|
+
/** The host-facing scene address: what `runFlow` / `goto` take. Derived from
|
|
736
|
+
* the name when the author set no explicit gameId, exactly as the runtime
|
|
737
|
+
* resolves it, so this list is the truth rather than an approximation. */
|
|
738
|
+
gameId: string;
|
|
739
|
+
/** The authored scene name, for recognising the row. */
|
|
740
|
+
name: string;
|
|
741
|
+
/** Block addresses within this scene. A block address is SCENE-SCOPED: the
|
|
742
|
+
* pair is the address, which is why these are nested rather than flattened. */
|
|
743
|
+
blocks: {
|
|
744
|
+
gameId: string;
|
|
745
|
+
name: string;
|
|
746
|
+
}[];
|
|
747
|
+
}
|
|
748
|
+
/** One author-defined gameData field: part of the host-facing data surface. */
|
|
749
|
+
interface GameDataFieldSummary {
|
|
750
|
+
name: string;
|
|
751
|
+
type: string;
|
|
752
|
+
/** Whether the schema carries a fallback. Sparse storage means a node that
|
|
753
|
+
* sets nothing reads this, so a field with no default can arrive absent. */
|
|
754
|
+
hasDefault: boolean;
|
|
755
|
+
/** Allowed values for an enum field: the set host code switches on. */
|
|
756
|
+
values?: string[];
|
|
757
|
+
purpose?: string;
|
|
758
|
+
}
|
|
759
|
+
/** The gameData fields declared for one kind of node. */
|
|
760
|
+
interface GameDataSummary {
|
|
761
|
+
kind: GameDataNodeKind;
|
|
762
|
+
fields: GameDataFieldSummary[];
|
|
763
|
+
}
|
|
764
|
+
/** One declared property. `hasDefault` rather than the value itself: an
|
|
765
|
+
* inspector wants to know whether the host MUST supply something. */
|
|
766
|
+
interface PropertySummary {
|
|
767
|
+
name: string;
|
|
768
|
+
type: PropertyType;
|
|
769
|
+
hasDefault: boolean;
|
|
770
|
+
default?: ScalarValue$1;
|
|
771
|
+
/** Shared across all flows, or kept per-flow. Defaults differ by scope
|
|
772
|
+
* (`@patter` shared, `@scene` per-flow), so it is resolved here. */
|
|
773
|
+
shared: boolean;
|
|
774
|
+
}
|
|
775
|
+
/** A host scope (`@world` and friends): what the GAME must supply.
|
|
776
|
+
*
|
|
777
|
+
* The highest-value section of the whole description. Today an integrator
|
|
778
|
+
* discovers a missing world property when a condition silently reads a
|
|
779
|
+
* self-backed default and a branch never fires. */
|
|
780
|
+
interface HostScopeSummary {
|
|
781
|
+
/** The token after `@`, e.g. "world". */
|
|
782
|
+
token: string;
|
|
783
|
+
/** Scope-level read/write default for its declarations. */
|
|
784
|
+
writable: boolean;
|
|
785
|
+
/** An OPAQUE scope declares no names: any name is accepted, unchecked. The
|
|
786
|
+
* host contract is then "anything", which is worth showing as such rather
|
|
787
|
+
* than as an empty property list. */
|
|
788
|
+
opaque: boolean;
|
|
789
|
+
properties: PropertySummary[];
|
|
790
|
+
}
|
|
791
|
+
/** Story-owned declarations, for orientation rather than for calling. */
|
|
792
|
+
interface OwnedProperties {
|
|
793
|
+
/** Project-level (`@patter`). */
|
|
794
|
+
patter: PropertySummary[];
|
|
795
|
+
/** Per scene (`@scene`), keyed by the scene's host address. */
|
|
796
|
+
scene: {
|
|
797
|
+
gameId: string;
|
|
798
|
+
properties: PropertySummary[];
|
|
799
|
+
}[];
|
|
800
|
+
}
|
|
801
|
+
/** "Is this the right build?" at a glance. */
|
|
802
|
+
interface BundleCounts {
|
|
803
|
+
scenes: number;
|
|
804
|
+
blocks: number;
|
|
805
|
+
groups: number;
|
|
806
|
+
snippets: number;
|
|
807
|
+
/** Snippet beats. This is the SAME population `Engine.getBeatSequence` walks, deliberately, so a
|
|
808
|
+
* tool that lists beats and an inspector that counts them never disagree. Choice prompts are not
|
|
809
|
+
* in it - see `prompts`. */
|
|
810
|
+
beats: number;
|
|
811
|
+
/** Choice-option prompts: beats that live on a group rather than in a snippet.
|
|
812
|
+
*
|
|
813
|
+
* Counted separately rather than folded into `beats` because folding them in would make this
|
|
814
|
+
* number disagree with `getBeatSequence`, and leaving them out entirely would understate a
|
|
815
|
+
* choice-heavy story - a branching script could report a handful of beats and look like the wrong
|
|
816
|
+
* build. Neither silence nor a redefinition; a second row. */
|
|
817
|
+
prompts: number;
|
|
818
|
+
/** Beats that fire a game event rather than producing player-facing words. */
|
|
819
|
+
gameEvents: number;
|
|
820
|
+
/** Cast members the bundle carries (player-facing only; the compiler strips
|
|
821
|
+
* the authoring fields). */
|
|
822
|
+
cast: number;
|
|
823
|
+
}
|
|
824
|
+
interface BundleDescription {
|
|
825
|
+
identity: BundleIdentity;
|
|
826
|
+
/** Everything game code may aim at, in bundle order. */
|
|
827
|
+
addresses: AddressSummary[];
|
|
828
|
+
/** What the host must supply. */
|
|
829
|
+
hostScopes: HostScopeSummary[];
|
|
830
|
+
/** What the story owns. */
|
|
831
|
+
properties: OwnedProperties;
|
|
832
|
+
/** The author-defined data surface, grouped by node kind. */
|
|
833
|
+
gameData: GameDataSummary[];
|
|
834
|
+
counts: BundleCounts;
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* Describe a compiled bundle: what it is, and what a game may call on it.
|
|
838
|
+
*
|
|
839
|
+
* Pure and allocation-light. Safe to call from an editor inspector on every
|
|
840
|
+
* selection, though a details panel should still build its rows once rather
|
|
841
|
+
* than per repaint.
|
|
842
|
+
*/
|
|
843
|
+
declare function describeBundle(bundle: Bundle): BundleDescription;
|
|
844
|
+
|
|
708
845
|
/** The author-defined gameData fields declared for a node TYPE in a bundle (empty when none). */
|
|
709
846
|
declare function gameDataFields(bundle: Bundle, kind: GameDataNodeKind): GameDataField[];
|
|
710
847
|
/** One node's effective value for a field: its sparse OVERRIDE if present, else the field's declared
|
|
@@ -722,4 +859,4 @@ declare function effectiveGameData(fields: GameDataField[], node: GameData | und
|
|
|
722
859
|
*/
|
|
723
860
|
declare function buildTagIndex(bundle: Bundle): Map<string, string[]>;
|
|
724
861
|
|
|
725
|
-
export { type AdvanceToStopResult, type BeatInfo, type ChoiceOption, Engine, type EngineOptions, type EngineSave, type FlatBeat, Flow, type FlowSnapshot, type OpenFlowOptions, type OutlineBlock, type OutlineNode, type OutlineScene, type PropertyRow, type SaveGame, type SavedChoice, type SelectorSnapshot, type StackFrame, type StepResult, type WorldResolver, buildTagIndex, effectiveGameData, gameDataFields, gameDataValue };
|
|
862
|
+
export { type AddressSummary, type AdvanceToStopResult, type BeatInfo, type BundleCounts, type BundleDescription, type BundleIdentity, type ChoiceOption, Engine, type EngineOptions, type EngineSave, type FlatBeat, Flow, type FlowSnapshot, type GameDataFieldSummary, type GameDataSummary, type HostScopeSummary, type OpenFlowOptions, type OutlineBlock, type OutlineNode, type OutlineScene, type OwnedProperties, type PropertyRow, type PropertySummary, type SaveGame, type SavedChoice, type SelectorSnapshot, type StackFrame, type StepResult, type WorldResolver, buildTagIndex, describeBundle, effectiveGameData, gameDataFields, gameDataValue };
|
package/dist/index.js
CHANGED
|
@@ -1380,12 +1380,13 @@ function hostScopeDefault(decl) {
|
|
|
1380
1380
|
}
|
|
1381
1381
|
}
|
|
1382
1382
|
function selfBackedResolver(decls) {
|
|
1383
|
+
const key = (name) => name.toLowerCase();
|
|
1383
1384
|
const bag = /* @__PURE__ */ new Map();
|
|
1384
|
-
for (const d of decls) bag.set(d.name, hostScopeDefault(d));
|
|
1385
|
+
for (const d of decls) bag.set(key(d.name), hostScopeDefault(d));
|
|
1385
1386
|
return {
|
|
1386
|
-
get: (name) => bag.get(name),
|
|
1387
|
+
get: (name) => bag.get(key(name)),
|
|
1387
1388
|
set: (name, value) => {
|
|
1388
|
-
bag.set(name, value);
|
|
1389
|
+
bag.set(key(name), value);
|
|
1389
1390
|
}
|
|
1390
1391
|
};
|
|
1391
1392
|
}
|
|
@@ -1411,6 +1412,109 @@ function truthy(v) {
|
|
|
1411
1412
|
return v.length > 0;
|
|
1412
1413
|
}
|
|
1413
1414
|
|
|
1415
|
+
// src/describe.ts
|
|
1416
|
+
import { effectiveGameId as effectiveGameId2 } from "@patterkit/model";
|
|
1417
|
+
var isShared = (d, scopeDefault) => d.shared ?? scopeDefault;
|
|
1418
|
+
function summariseProperty(d, scopeDefault) {
|
|
1419
|
+
return {
|
|
1420
|
+
name: d.name,
|
|
1421
|
+
type: d.type,
|
|
1422
|
+
hasDefault: d.default !== void 0,
|
|
1423
|
+
...d.default !== void 0 ? { default: d.default } : {},
|
|
1424
|
+
shared: isShared(d, scopeDefault)
|
|
1425
|
+
};
|
|
1426
|
+
}
|
|
1427
|
+
function summariseField(f) {
|
|
1428
|
+
return {
|
|
1429
|
+
name: f.name,
|
|
1430
|
+
type: f.type,
|
|
1431
|
+
hasDefault: f.default !== void 0,
|
|
1432
|
+
...f.values ? { values: [...f.values] } : {},
|
|
1433
|
+
...f.purpose ? { purpose: f.purpose } : {}
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1436
|
+
function countBlock(block, counts) {
|
|
1437
|
+
counts.blocks++;
|
|
1438
|
+
const stack = [...block.children];
|
|
1439
|
+
while (stack.length) {
|
|
1440
|
+
const node = stack.pop();
|
|
1441
|
+
if (node.type === "group") {
|
|
1442
|
+
counts.groups++;
|
|
1443
|
+
if (node.prompt) counts.prompts++;
|
|
1444
|
+
stack.push(...node.children);
|
|
1445
|
+
continue;
|
|
1446
|
+
}
|
|
1447
|
+
counts.snippets++;
|
|
1448
|
+
for (const beat of node.beats ?? []) {
|
|
1449
|
+
counts.beats++;
|
|
1450
|
+
if (beat.kind === "gameEvent") counts.gameEvents++;
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
function describeBundle(bundle) {
|
|
1455
|
+
const counts = {
|
|
1456
|
+
scenes: 0,
|
|
1457
|
+
blocks: 0,
|
|
1458
|
+
groups: 0,
|
|
1459
|
+
snippets: 0,
|
|
1460
|
+
beats: 0,
|
|
1461
|
+
prompts: 0,
|
|
1462
|
+
gameEvents: 0,
|
|
1463
|
+
cast: bundle.cast?.length ?? 0
|
|
1464
|
+
};
|
|
1465
|
+
const addresses = [];
|
|
1466
|
+
const sceneProps = [];
|
|
1467
|
+
for (const scene of Object.values(bundle.scenes)) {
|
|
1468
|
+
counts.scenes++;
|
|
1469
|
+
const gameId = effectiveGameId2(scene);
|
|
1470
|
+
addresses.push({
|
|
1471
|
+
gameId,
|
|
1472
|
+
name: scene.name,
|
|
1473
|
+
blocks: scene.blocks.map((b) => ({ gameId: effectiveGameId2(b), name: b.name }))
|
|
1474
|
+
});
|
|
1475
|
+
for (const block of scene.blocks) countBlock(block, counts);
|
|
1476
|
+
if (scene.sceneProps?.length) {
|
|
1477
|
+
sceneProps.push({ gameId, properties: scene.sceneProps.map((d) => summariseProperty(d, false)) });
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
const hostScopes = (bundle.scopeRegistry?.scopes ?? []).map((s) => ({
|
|
1481
|
+
token: s.token,
|
|
1482
|
+
writable: s.writable ?? true,
|
|
1483
|
+
opaque: s.declarations === void 0,
|
|
1484
|
+
// A host scope's values live outside the story, so "shared" is not a choice
|
|
1485
|
+
// its declarations make; they are world-wide by nature.
|
|
1486
|
+
properties: (s.declarations ?? []).map((d) => summariseProperty(d, true))
|
|
1487
|
+
}));
|
|
1488
|
+
const gameData = Object.entries(bundle.gameDataFields ?? {}).filter(([, fields]) => (fields?.length ?? 0) > 0).map(([kind, fields]) => ({
|
|
1489
|
+
kind,
|
|
1490
|
+
fields: (fields ?? []).map(summariseField)
|
|
1491
|
+
}));
|
|
1492
|
+
return {
|
|
1493
|
+
identity: {
|
|
1494
|
+
schema: bundle.schema,
|
|
1495
|
+
project: bundle.content.project,
|
|
1496
|
+
...bundle.content.version !== void 0 ? { version: bundle.content.version } : {},
|
|
1497
|
+
...bundle.content.hash !== void 0 ? { hash: bundle.content.hash } : {},
|
|
1498
|
+
...bundle.content.structureHash !== void 0 ? { structureHash: bundle.content.structureHash } : {},
|
|
1499
|
+
voiced: bundle.voiced,
|
|
1500
|
+
defaultLocale: bundle.locales.default,
|
|
1501
|
+
locales: [...bundle.locales.included],
|
|
1502
|
+
// Absent means "embedded": the back-compat default a bundle written before
|
|
1503
|
+
// the field existed relies on.
|
|
1504
|
+
localisation: bundle.localisation?.mode ?? "embedded",
|
|
1505
|
+
sourceDebug: bundle.localisation?.sourceDebug ?? false
|
|
1506
|
+
},
|
|
1507
|
+
addresses,
|
|
1508
|
+
hostScopes,
|
|
1509
|
+
properties: {
|
|
1510
|
+
patter: (bundle.properties ?? []).map((d) => summariseProperty(d, true)),
|
|
1511
|
+
scene: sceneProps
|
|
1512
|
+
},
|
|
1513
|
+
gameData,
|
|
1514
|
+
counts
|
|
1515
|
+
};
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1414
1518
|
// src/gamedata.ts
|
|
1415
1519
|
function gameDataFields(bundle, kind) {
|
|
1416
1520
|
return bundle.gameDataFields?.[kind] ?? [];
|
|
@@ -1432,6 +1536,7 @@ export {
|
|
|
1432
1536
|
Engine,
|
|
1433
1537
|
Flow,
|
|
1434
1538
|
buildTagIndex,
|
|
1539
|
+
describeBundle,
|
|
1435
1540
|
effectiveGameData,
|
|
1436
1541
|
gameDataFields,
|
|
1437
1542
|
gameDataValue
|