@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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [614eaa8]
|
|
8
|
+
- @patterkit/model@0.3.0
|
|
9
|
+
- @patterkit/dialect@0.1.5
|
|
10
|
+
|
|
3
11
|
## 0.2.1
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
|
@@ -17,9 +25,31 @@ version number always means the same runtime behaviour. This package is versione
|
|
|
17
25
|
|
|
18
26
|
## [Unreleased]
|
|
19
27
|
|
|
28
|
+
## [0.4.2] - 2026-08-19
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- Version bump only, to keep the four Patterplay runtimes in lockstep. This release brings Unity,
|
|
33
|
+
Unreal and Godot up to the JavaScript runtime's declared-host-scope behaviour; the JavaScript
|
|
34
|
+
runtime itself is unchanged since 0.4.1.
|
|
35
|
+
|
|
36
|
+
## [0.4.1] - 2026-08-19
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- **A declared host-scope property whose name carried a capital letter could never be read.** With no
|
|
41
|
+
host resolver bound for a scope, `@world` is self-backed from its declaration defaults - and that bag
|
|
42
|
+
was seeded with the declared name VERBATIM, while the compiler folds every property reference to
|
|
43
|
+
lower case. So a bundle declaring `@world.isNight` compiled a reference to `isnight`, the bag held
|
|
44
|
+
`isNight`, and the two never met: the read returned `undefined` and the gate took the falsy branch,
|
|
45
|
+
silently playing a different story from the same bundle. Only all-lowercase names ever worked. The
|
|
46
|
+
bag is now keyed lower case on seed, get and set. (`@patter` and `@scene` already normalised; this
|
|
47
|
+
resolver was the one that did not.) Declaring such a name is now refused at compile time as well.
|
|
48
|
+
|
|
20
49
|
## [0.4.0] - 2026-07-30
|
|
21
50
|
|
|
22
51
|
### Added
|
|
52
|
+
|
|
23
53
|
- **State logger** (parity: previously JS-only). Watches the mutable runtime state - `@patter`
|
|
24
54
|
globals, per-scene `@scene` props, and visit counts (shared + per-flow) - and reports what changed
|
|
25
55
|
between captures, plus a per-step trace including `gameData`. Built on the engine's save-game, so
|
|
@@ -27,18 +57,21 @@ version number always means the same runtime behaviour. This package is versione
|
|
|
27
57
|
every runtime.
|
|
28
58
|
|
|
29
59
|
### Fixed
|
|
60
|
+
|
|
30
61
|
- The download now includes the **MIT `LICENSE` file**; previously the zip shipped with no licence
|
|
31
62
|
text at all.
|
|
32
63
|
|
|
33
64
|
## [0.3.1] - 2026-07-22
|
|
34
65
|
|
|
35
66
|
### Changed
|
|
67
|
+
|
|
36
68
|
- Version bump only, to keep the four Patterplay runtimes in lockstep. This release fixes
|
|
37
69
|
Unreal-only build issues (see the Unreal changelog and #25); the JavaScript runtime is unchanged.
|
|
38
70
|
|
|
39
71
|
## [0.3.0] - 2026-07-21
|
|
40
72
|
|
|
41
73
|
### Added
|
|
74
|
+
|
|
42
75
|
- **Host navigation.** `flow.goto(scene, block?)` sends a running flow to a Game ID address, behaving
|
|
43
76
|
exactly like an authored `go` jump: the target scene's `onEntry` runs, arriving counts as a visit, and
|
|
44
77
|
the callstack is replaced (pending call-returns discarded). Being a host action it lands immediately -
|
|
@@ -54,6 +87,7 @@ version number always means the same runtime behaviour. This package is versione
|
|
|
54
87
|
(they were JS-only).
|
|
55
88
|
|
|
56
89
|
### Changed
|
|
90
|
+
|
|
57
91
|
- Dropping a flow now FINISHES it. `closeFlow`, `engine.reset()` and re-opening a name all leave the old
|
|
58
92
|
`Flow` inert (`advance()` reports the end, `goto()` refuses), so a stale reference a game still holds
|
|
59
93
|
can no longer keep running scene entry effects and moving shared state. Re-opening a name still
|
|
@@ -62,6 +96,7 @@ version number always means the same runtime behaviour. This package is versione
|
|
|
62
96
|
## [0.2.2] - 2026-07-13
|
|
63
97
|
|
|
64
98
|
### Changed
|
|
99
|
+
|
|
65
100
|
- Internal: the Best match (`specificity`) selection metric now uses the shared
|
|
66
101
|
`@wildwinter/expr-specificity` package instead of a per-engine inline copy. Behaviour is
|
|
67
102
|
unchanged and conformance-verified across all four engines.
|
package/dist/index.cjs
CHANGED
|
@@ -23,6 +23,7 @@ __export(index_exports, {
|
|
|
23
23
|
Engine: () => Engine,
|
|
24
24
|
Flow: () => Flow,
|
|
25
25
|
buildTagIndex: () => buildTagIndex,
|
|
26
|
+
describeBundle: () => describeBundle,
|
|
26
27
|
effectiveGameData: () => effectiveGameData,
|
|
27
28
|
gameDataFields: () => gameDataFields,
|
|
28
29
|
gameDataValue: () => gameDataValue
|
|
@@ -1411,12 +1412,13 @@ function hostScopeDefault(decl) {
|
|
|
1411
1412
|
}
|
|
1412
1413
|
}
|
|
1413
1414
|
function selfBackedResolver(decls) {
|
|
1415
|
+
const key = (name) => name.toLowerCase();
|
|
1414
1416
|
const bag = /* @__PURE__ */ new Map();
|
|
1415
|
-
for (const d of decls) bag.set(d.name, hostScopeDefault(d));
|
|
1417
|
+
for (const d of decls) bag.set(key(d.name), hostScopeDefault(d));
|
|
1416
1418
|
return {
|
|
1417
|
-
get: (name) => bag.get(name),
|
|
1419
|
+
get: (name) => bag.get(key(name)),
|
|
1418
1420
|
set: (name, value) => {
|
|
1419
|
-
bag.set(name, value);
|
|
1421
|
+
bag.set(key(name), value);
|
|
1420
1422
|
}
|
|
1421
1423
|
};
|
|
1422
1424
|
}
|
|
@@ -1442,6 +1444,109 @@ function truthy(v) {
|
|
|
1442
1444
|
return v.length > 0;
|
|
1443
1445
|
}
|
|
1444
1446
|
|
|
1447
|
+
// src/describe.ts
|
|
1448
|
+
var import_model2 = require("@patterkit/model");
|
|
1449
|
+
var isShared = (d, scopeDefault) => d.shared ?? scopeDefault;
|
|
1450
|
+
function summariseProperty(d, scopeDefault) {
|
|
1451
|
+
return {
|
|
1452
|
+
name: d.name,
|
|
1453
|
+
type: d.type,
|
|
1454
|
+
hasDefault: d.default !== void 0,
|
|
1455
|
+
...d.default !== void 0 ? { default: d.default } : {},
|
|
1456
|
+
shared: isShared(d, scopeDefault)
|
|
1457
|
+
};
|
|
1458
|
+
}
|
|
1459
|
+
function summariseField(f) {
|
|
1460
|
+
return {
|
|
1461
|
+
name: f.name,
|
|
1462
|
+
type: f.type,
|
|
1463
|
+
hasDefault: f.default !== void 0,
|
|
1464
|
+
...f.values ? { values: [...f.values] } : {},
|
|
1465
|
+
...f.purpose ? { purpose: f.purpose } : {}
|
|
1466
|
+
};
|
|
1467
|
+
}
|
|
1468
|
+
function countBlock(block, counts) {
|
|
1469
|
+
counts.blocks++;
|
|
1470
|
+
const stack = [...block.children];
|
|
1471
|
+
while (stack.length) {
|
|
1472
|
+
const node = stack.pop();
|
|
1473
|
+
if (node.type === "group") {
|
|
1474
|
+
counts.groups++;
|
|
1475
|
+
if (node.prompt) counts.prompts++;
|
|
1476
|
+
stack.push(...node.children);
|
|
1477
|
+
continue;
|
|
1478
|
+
}
|
|
1479
|
+
counts.snippets++;
|
|
1480
|
+
for (const beat of node.beats ?? []) {
|
|
1481
|
+
counts.beats++;
|
|
1482
|
+
if (beat.kind === "gameEvent") counts.gameEvents++;
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
function describeBundle(bundle) {
|
|
1487
|
+
const counts = {
|
|
1488
|
+
scenes: 0,
|
|
1489
|
+
blocks: 0,
|
|
1490
|
+
groups: 0,
|
|
1491
|
+
snippets: 0,
|
|
1492
|
+
beats: 0,
|
|
1493
|
+
prompts: 0,
|
|
1494
|
+
gameEvents: 0,
|
|
1495
|
+
cast: bundle.cast?.length ?? 0
|
|
1496
|
+
};
|
|
1497
|
+
const addresses = [];
|
|
1498
|
+
const sceneProps = [];
|
|
1499
|
+
for (const scene of Object.values(bundle.scenes)) {
|
|
1500
|
+
counts.scenes++;
|
|
1501
|
+
const gameId = (0, import_model2.effectiveGameId)(scene);
|
|
1502
|
+
addresses.push({
|
|
1503
|
+
gameId,
|
|
1504
|
+
name: scene.name,
|
|
1505
|
+
blocks: scene.blocks.map((b) => ({ gameId: (0, import_model2.effectiveGameId)(b), name: b.name }))
|
|
1506
|
+
});
|
|
1507
|
+
for (const block of scene.blocks) countBlock(block, counts);
|
|
1508
|
+
if (scene.sceneProps?.length) {
|
|
1509
|
+
sceneProps.push({ gameId, properties: scene.sceneProps.map((d) => summariseProperty(d, false)) });
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
const hostScopes = (bundle.scopeRegistry?.scopes ?? []).map((s) => ({
|
|
1513
|
+
token: s.token,
|
|
1514
|
+
writable: s.writable ?? true,
|
|
1515
|
+
opaque: s.declarations === void 0,
|
|
1516
|
+
// A host scope's values live outside the story, so "shared" is not a choice
|
|
1517
|
+
// its declarations make; they are world-wide by nature.
|
|
1518
|
+
properties: (s.declarations ?? []).map((d) => summariseProperty(d, true))
|
|
1519
|
+
}));
|
|
1520
|
+
const gameData = Object.entries(bundle.gameDataFields ?? {}).filter(([, fields]) => (fields?.length ?? 0) > 0).map(([kind, fields]) => ({
|
|
1521
|
+
kind,
|
|
1522
|
+
fields: (fields ?? []).map(summariseField)
|
|
1523
|
+
}));
|
|
1524
|
+
return {
|
|
1525
|
+
identity: {
|
|
1526
|
+
schema: bundle.schema,
|
|
1527
|
+
project: bundle.content.project,
|
|
1528
|
+
...bundle.content.version !== void 0 ? { version: bundle.content.version } : {},
|
|
1529
|
+
...bundle.content.hash !== void 0 ? { hash: bundle.content.hash } : {},
|
|
1530
|
+
...bundle.content.structureHash !== void 0 ? { structureHash: bundle.content.structureHash } : {},
|
|
1531
|
+
voiced: bundle.voiced,
|
|
1532
|
+
defaultLocale: bundle.locales.default,
|
|
1533
|
+
locales: [...bundle.locales.included],
|
|
1534
|
+
// Absent means "embedded": the back-compat default a bundle written before
|
|
1535
|
+
// the field existed relies on.
|
|
1536
|
+
localisation: bundle.localisation?.mode ?? "embedded",
|
|
1537
|
+
sourceDebug: bundle.localisation?.sourceDebug ?? false
|
|
1538
|
+
},
|
|
1539
|
+
addresses,
|
|
1540
|
+
hostScopes,
|
|
1541
|
+
properties: {
|
|
1542
|
+
patter: (bundle.properties ?? []).map((d) => summariseProperty(d, true)),
|
|
1543
|
+
scene: sceneProps
|
|
1544
|
+
},
|
|
1545
|
+
gameData,
|
|
1546
|
+
counts
|
|
1547
|
+
};
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1445
1550
|
// src/gamedata.ts
|
|
1446
1551
|
function gameDataFields(bundle, kind) {
|
|
1447
1552
|
return bundle.gameDataFields?.[kind] ?? [];
|
|
@@ -1464,6 +1569,7 @@ function effectiveGameData(fields, node) {
|
|
|
1464
1569
|
Engine,
|
|
1465
1570
|
Flow,
|
|
1466
1571
|
buildTagIndex,
|
|
1572
|
+
describeBundle,
|
|
1467
1573
|
effectiveGameData,
|
|
1468
1574
|
gameDataFields,
|
|
1469
1575
|
gameDataValue
|