@patterkit/runtime 0.4.5 → 0.5.1

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/index.d.cts CHANGED
@@ -236,6 +236,8 @@ interface PropertyRow {
236
236
  value: ScalarValue | undefined;
237
237
  default: ScalarValue;
238
238
  values?: string[];
239
+ /** A quality's ordered stage ladder (lets an inspector offer stages instead of free text). */
240
+ stages?: string[];
239
241
  }
240
242
  /** Options for opening a flow. */
241
243
  interface OpenFlowOptions {
@@ -439,6 +441,23 @@ declare class Engine {
439
441
  tagsForScene(sceneRef: string): string[];
440
442
  /** A block's accumulated tags (scene + block), by scene + block ref (id or gameId). Empty when none / unknown. */
441
443
  tagsForBlock(sceneRef: string, blockRef: string): string[];
444
+ /**
445
+ * Every cast member the PROJECT declares, in authored order - the same list `describeBundle` counts.
446
+ * A superset of any scene's cast: the validator holds a beat's `character` to a declared member, so
447
+ * {@link castForScene} and {@link castForBlock} only ever return names that appear here.
448
+ */
449
+ getCast(): string[];
450
+ /**
451
+ * A scene's cast: the `character` token of every speaker with a line anywhere in it, deduped, in
452
+ * first-appearance order. Static, like {@link getOutline}: it walks the authored structure, so a
453
+ * speaker behind a condition, inside any group, or voicing a choice prompt counts - this is who CAN
454
+ * speak in the scene, not who a given playthrough heard. Empty for an unknown ref, or a scene with no
455
+ * dialogue. Tokens, not display names: resolve those through the delivered step (`characterName`),
456
+ * which is what follows `setLocale`.
457
+ */
458
+ castForScene(sceneRef: string): string[];
459
+ /** One block's cast, by scene + block ref (id or gameId). {@link castForScene} scoped to a block. */
460
+ castForBlock(sceneRef: string, blockRef: string): string[];
442
461
  /**
443
462
  * The authored structure as a nested tree: scenes -> blocks -> children (groups + snippets, groups
444
463
  * preserved) -> a snippet's beats. Static (no flow / play state); per-beat data is read at the source
@@ -516,6 +535,9 @@ declare class Flow {
516
535
  private readonly sceneResolver;
517
536
  private readonly evalCtx;
518
537
  constructor(id: string, host: FlowHost, seed: number);
538
+ /** The stage ladder of `@scope.name` when it is a declared quality, else undefined. Names compare
539
+ * lowercase, as the compiler emits references (the selfBackedResolver lesson). */
540
+ private stagesFor;
519
541
  /** Begin this flow at a scene (and optionally a specific block within it). */
520
542
  start(sceneId?: string, blockId?: string): void;
521
543
  /**
package/dist/index.d.ts CHANGED
@@ -236,6 +236,8 @@ interface PropertyRow {
236
236
  value: ScalarValue | undefined;
237
237
  default: ScalarValue;
238
238
  values?: string[];
239
+ /** A quality's ordered stage ladder (lets an inspector offer stages instead of free text). */
240
+ stages?: string[];
239
241
  }
240
242
  /** Options for opening a flow. */
241
243
  interface OpenFlowOptions {
@@ -439,6 +441,23 @@ declare class Engine {
439
441
  tagsForScene(sceneRef: string): string[];
440
442
  /** A block's accumulated tags (scene + block), by scene + block ref (id or gameId). Empty when none / unknown. */
441
443
  tagsForBlock(sceneRef: string, blockRef: string): string[];
444
+ /**
445
+ * Every cast member the PROJECT declares, in authored order - the same list `describeBundle` counts.
446
+ * A superset of any scene's cast: the validator holds a beat's `character` to a declared member, so
447
+ * {@link castForScene} and {@link castForBlock} only ever return names that appear here.
448
+ */
449
+ getCast(): string[];
450
+ /**
451
+ * A scene's cast: the `character` token of every speaker with a line anywhere in it, deduped, in
452
+ * first-appearance order. Static, like {@link getOutline}: it walks the authored structure, so a
453
+ * speaker behind a condition, inside any group, or voicing a choice prompt counts - this is who CAN
454
+ * speak in the scene, not who a given playthrough heard. Empty for an unknown ref, or a scene with no
455
+ * dialogue. Tokens, not display names: resolve those through the delivered step (`characterName`),
456
+ * which is what follows `setLocale`.
457
+ */
458
+ castForScene(sceneRef: string): string[];
459
+ /** One block's cast, by scene + block ref (id or gameId). {@link castForScene} scoped to a block. */
460
+ castForBlock(sceneRef: string, blockRef: string): string[];
442
461
  /**
443
462
  * The authored structure as a nested tree: scenes -> blocks -> children (groups + snippets, groups
444
463
  * preserved) -> a snippet's beats. Static (no flow / play state); per-beat data is read at the source
@@ -516,6 +535,9 @@ declare class Flow {
516
535
  private readonly sceneResolver;
517
536
  private readonly evalCtx;
518
537
  constructor(id: string, host: FlowHost, seed: number);
538
+ /** The stage ladder of `@scope.name` when it is a declared quality, else undefined. Names compare
539
+ * lowercase, as the compiler emits references (the selfBackedResolver lesson). */
540
+ private stagesFor;
519
541
  /** Begin this flow at a scene (and optionally a specific block within it). */
520
542
  start(sceneId?: string, blockId?: string): void;
521
543
  /**
package/dist/index.js CHANGED
@@ -328,6 +328,42 @@ var Engine = class _Engine {
328
328
  const id = this.resolveBlockRef(sceneId, blockRef);
329
329
  return (id != null ? this.host.tagIndex.get(id) : void 0) ?? [];
330
330
  }
331
+ /**
332
+ * Every cast member the PROJECT declares, in authored order - the same list `describeBundle` counts.
333
+ * A superset of any scene's cast: the validator holds a beat's `character` to a declared member, so
334
+ * {@link castForScene} and {@link castForBlock} only ever return names that appear here.
335
+ */
336
+ getCast() {
337
+ const names = [];
338
+ for (const c of this.host.bundle.cast ?? []) if (c?.name) names.push(c.name);
339
+ return names;
340
+ }
341
+ /**
342
+ * A scene's cast: the `character` token of every speaker with a line anywhere in it, deduped, in
343
+ * first-appearance order. Static, like {@link getOutline}: it walks the authored structure, so a
344
+ * speaker behind a condition, inside any group, or voicing a choice prompt counts - this is who CAN
345
+ * speak in the scene, not who a given playthrough heard. Empty for an unknown ref, or a scene with no
346
+ * dialogue. Tokens, not display names: resolve those through the delivered step (`characterName`),
347
+ * which is what follows `setLocale`.
348
+ */
349
+ castForScene(sceneRef) {
350
+ const id = this.resolveSceneRef(sceneRef);
351
+ const scene = id != null ? this.host.bundle.scenes[id] : void 0;
352
+ if (!scene) return [];
353
+ const out = /* @__PURE__ */ new Set();
354
+ for (const block of scene.blocks) collectCast(block.children, out);
355
+ return [...out];
356
+ }
357
+ /** One block's cast, by scene + block ref (id or gameId). {@link castForScene} scoped to a block. */
358
+ castForBlock(sceneRef, blockRef) {
359
+ const sceneId = this.resolveSceneRef(sceneRef);
360
+ const id = this.resolveBlockRef(sceneId, blockRef);
361
+ const block = id != null ? this.host.blockById.get(id) : void 0;
362
+ if (!block) return [];
363
+ const out = /* @__PURE__ */ new Set();
364
+ collectCast(block.children, out);
365
+ return [...out];
366
+ }
331
367
  /**
332
368
  * The authored structure as a nested tree: scenes -> blocks -> children (groups + snippets, groups
333
369
  * preserved) -> a snippet's beats. Static (no flow / play state); per-beat data is read at the source
@@ -457,6 +493,7 @@ var Engine = class _Engine {
457
493
  ref: `@${d.name}`,
458
494
  type: d.type,
459
495
  values: d.values,
496
+ stages: d.stages,
460
497
  value: this.getProperty(`@${d.name}`),
461
498
  default: declDefault(d)
462
499
  }));
@@ -589,9 +626,28 @@ var Flow = class {
589
626
  nextRandom: this.rng,
590
627
  visits: (id2) => this.visitCounts.get(id2) ?? 0,
591
628
  patterVisits: (id2) => this.host.sharedVisits.get(id2) ?? 0
592
- }
629
+ },
630
+ // The quality channel (expr 0.4.0): hands the evaluator a property's stage ladder, which is what
631
+ // makes ordering compare by position and advance() step. Wired by hand because this context takes
632
+ // only the registry's SCOPES (the patter/scene resolvers here are the flow's own merged views),
633
+ // and because @scene declarations belong to whichever scene the flow is in RIGHT NOW.
634
+ qualities: (scope, name) => this.stagesFor(scope, name)
593
635
  };
594
636
  }
637
+ /** The stage ladder of `@scope.name` when it is a declared quality, else undefined. Names compare
638
+ * lowercase, as the compiler emits references (the selfBackedResolver lesson). */
639
+ stagesFor(scope, name) {
640
+ const key = name.toLowerCase();
641
+ const fromDecls = (decls) => decls?.find((d) => d.name.toLowerCase() === key && d.type === "quality")?.stages;
642
+ if (scope === "patter") {
643
+ return fromDecls(this.host.patterSharedDecls) ?? fromDecls(this.host.patterLocalDecls);
644
+ }
645
+ if (scope === "scene") {
646
+ const scene = this.currentSceneId != null ? this.host.bundle.scenes[this.currentSceneId] : void 0;
647
+ return fromDecls(scene?.sceneProps);
648
+ }
649
+ return fromDecls(this.host.bundle.scopeRegistry?.scopes.find((s) => s.token === scope)?.declarations);
650
+ }
595
651
  // -- Host API -------------------------------------------------------------
596
652
  /** Begin this flow at a scene (and optionally a specific block within it). */
597
653
  start(sceneId, blockId) {
@@ -1321,6 +1377,15 @@ var Flow = class {
1321
1377
  }
1322
1378
  }
1323
1379
  };
1380
+ function collectCast(nodes, out) {
1381
+ walkNodes(nodes, (n) => {
1382
+ if (n.type === "group") {
1383
+ if (n.prompt?.kind === "line" && n.prompt.character) out.add(n.prompt.character);
1384
+ return;
1385
+ }
1386
+ for (const beat of n.beats ?? []) if (beat.kind === "line" && beat.character) out.add(beat.character);
1387
+ });
1388
+ }
1324
1389
  function serialiseSelectors(map) {
1325
1390
  const out = {};
1326
1391
  for (const [id, st] of map) {
@@ -1344,7 +1409,7 @@ function deserialiseSelectors(rec) {
1344
1409
  return map;
1345
1410
  }
1346
1411
  function toDecl(decl) {
1347
- return { name: decl.name, type: decl.type, values: decl.values, default: decl.default };
1412
+ return { name: decl.name, type: decl.type, values: decl.values, stages: decl.stages, default: decl.default };
1348
1413
  }
1349
1414
  function declDefault(d) {
1350
1415
  if (d.default !== void 0) return d.default;
@@ -1357,12 +1422,14 @@ function declDefault(d) {
1357
1422
  return [];
1358
1423
  case "enum":
1359
1424
  return d.values?.[0] ?? "";
1425
+ case "quality":
1426
+ return d.stages?.[0] ?? "";
1360
1427
  default:
1361
1428
  return false;
1362
1429
  }
1363
1430
  }
1364
1431
  function toForeignDecl(decl) {
1365
- return { name: decl.name, type: decl.type, values: decl.values, default: decl.default, writable: decl.writable };
1432
+ return { name: decl.name, type: decl.type, values: decl.values, stages: decl.stages, default: decl.default, writable: decl.writable };
1366
1433
  }
1367
1434
  function hostScopeDefault(decl) {
1368
1435
  if (decl.default !== void 0) return decl.default;
@@ -1377,6 +1444,8 @@ function hostScopeDefault(decl) {
1377
1444
  return [];
1378
1445
  case "enum":
1379
1446
  return decl.values?.[0] ?? "";
1447
+ case "quality":
1448
+ return decl.stages?.[0] ?? "";
1380
1449
  }
1381
1450
  }
1382
1451
  function selfBackedResolver(decls) {
@@ -1403,6 +1472,8 @@ function sceneDefault(decl) {
1403
1472
  return [];
1404
1473
  case "enum":
1405
1474
  return decl.values?.[0] ?? "";
1475
+ case "quality":
1476
+ return decl.stages?.[0] ?? "";
1406
1477
  }
1407
1478
  }
1408
1479
  function truthy(v) {