@mark1russell7/coeval 0.6.1 → 0.6.3

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/src/evaluate.ts CHANGED
@@ -2,7 +2,7 @@ import { type Envelope, type Json, type Key, type TypeRef, isEnvelope, typeName
2
2
  import { type Split, partsOf, pathMatches } from "./parts.ts";
3
3
  import { ask, type Answer } from "./ladder.ts";
4
4
  import type { CapsRule, Kind, Side, World } from "./world.ts";
5
- import { type ErrorCode, type EvalError, type Result, fail, ok, placed, thrown, describe } from "./errors.ts";
5
+ import { type ErrorCode, type EvalError, type Result, Failure, fail, ok, placed, thrown, describe } from "./errors.ts";
6
6
  import {
7
7
  type Cap,
8
8
  type Context,
@@ -75,10 +75,10 @@ export function narrow(parent: Context, next: Context): Context {
75
75
  }
76
76
 
77
77
  /** No capabilities. One list serves each masked part. */
78
- const NO_CAPS: readonly Cap[] = Object.freeze([]);
78
+ const NO_CAPS: readonly Cap[] = /* @__PURE__ */ Object.freeze([]);
79
79
 
80
80
  /** No capability rules. One list serves each part that no rule narrows. */
81
- const NO_RULES: readonly CapsRule[] = Object.freeze([]);
81
+ const NO_RULES: readonly CapsRule[] = /* @__PURE__ */ Object.freeze([]);
82
82
 
83
83
  /**
84
84
  * This function gives the capabilities that two lists both permit. An effect is permitted by the result when each
@@ -135,6 +135,7 @@ export type Steps = Generator<Promise<unknown>, Result, unknown>;
135
135
 
136
136
  /** An effect that an evaluation caused, in the order of the effects. */
137
137
  export interface Effect {
138
+ /** The number of effects before this effect. Under `all`, this number follows the order of the host. */
138
139
  readonly index: number;
139
140
  /** The kind of the effect, as a text with dots. */
140
141
  readonly kind: string;
@@ -149,11 +150,100 @@ export interface Effect {
149
150
  readonly place: readonly Key[];
150
151
  /** The context of the document that caused the effect: its names, its node and its capabilities. */
151
152
  readonly context: Context;
153
+ /**
154
+ * The stable address of the effect (RUN.ADDRESS). The order of the host does not change it. The address has the
155
+ * keys of the place, a `#` and the count of the earlier effects at that place in its scope. An example is
156
+ * `1/bind/x#0`. Each item of `all` is a scope, and its prefix comes first: `all0.1/` is the item 1 of the first `all`
157
+ * of the scope. The kernel gives each effect its address.
158
+ */
159
+ readonly address?: string;
160
+ /**
161
+ * The outcome of the effect: the result that it gave its document (RUN.OUTCOME). The kernel sets it when the answer
162
+ * comes. It stays `undefined` when the run stops first, for example at an abort.
163
+ */
164
+ readonly outcome?: Result;
152
165
  }
153
166
 
154
- /** The host side of a run: it does one effect, and gives its result. A throw or a rejection is an error value. */
167
+ /**
168
+ * The host side of a run: it does one effect, and gives its result. A throw or a rejection is an error value, and a
169
+ * `Failure` gives its own error value. In an evaluation, this function is a mock: it answers at once, and a promise
170
+ * from it gives `#CALC!` (RUN.MOCK).
171
+ */
155
172
  export type Perform = (effect: Effect) => unknown;
156
173
 
174
+ /** The key of the journal of a recorder or of a replayer, on its function. Two copies of the kernel share it. */
175
+ export const JOURNAL: unique symbol = /* @__PURE__ */ Symbol.for("coeval.journal") as never;
176
+
177
+ /**
178
+ * The journal of a recorder or of a replayer, on its function `perform`. The kernel tells it the order in which the
179
+ * waits of each `all` settle. In a replay, the kernel asks the journal for that order (RUN.RECORD, RUN.REPLAY).
180
+ */
181
+ export interface Journal {
182
+ /**
183
+ * This function gets the item whose wait settled.
184
+ *
185
+ * @param all - The address of the `all`, for example `all0` or `all0.1/all0`.
186
+ * @param item - The index of the item.
187
+ */
188
+ readonly settled?: (all: string, item: number) => void;
189
+ /**
190
+ * This function gives the item whose wait settles next.
191
+ *
192
+ * @param all - The address of the `all`.
193
+ * @param waiting - The indices of the items that wait.
194
+ * @returns The index of an item that waits, or `undefined` for the order of the host.
195
+ */
196
+ readonly next?: (all: string, waiting: readonly number[]) => number | undefined;
197
+ }
198
+
199
+ /** This function gives the journal of a function `perform`, when it has one. */
200
+ function journalOf(perform: Perform | undefined): Journal | undefined {
201
+ return perform === undefined ? undefined : (perform as { readonly [JOURNAL]?: Journal })[JOURNAL];
202
+ }
203
+
204
+ /**
205
+ * This function gives the outcome of an effect that the host failed. A `Failure` gives its own error value, for
206
+ * example the recorded error of a replay or `#REPLAY!`. Each other exception gives `#CALC!`, with the exception as the
207
+ * cause (RUN.CAUSE).
208
+ */
209
+ function hostFailed(kind: string, place: readonly Key[], error: unknown): Result {
210
+ if (error instanceof Failure) return placed({ ok: false, error: error.error }, place);
211
+ return fail("#CALC!", `The host failed the effect ${kind}: ${describe(error)}`, { place, cause: error });
212
+ }
213
+
214
+ /**
215
+ * The scope of the addresses of effects (RUN.ADDRESS). The root of an evaluation is one scope, and each item of `all`
216
+ * is a scope. The code of one scope does not interleave with itself, thus its counts do not depend on the host.
217
+ */
218
+ interface Scope {
219
+ /** The text before each address of the scope, for example `all0.1/`. */
220
+ readonly prefix: string;
221
+ /** The number of earlier effects at each place, by the text of the place. It is made at the first effect. */
222
+ counts: Map<string, number> | undefined;
223
+ /** The number of earlier uses of `all` in the scope. */
224
+ alls: number;
225
+ }
226
+
227
+ /**
228
+ * This function gives the text of a place in an address: each key, with a slash between two keys. A text key with
229
+ * other characters than letters, digits, `_`, `$` and `-` gets quotes.
230
+ *
231
+ * @param place - The keys from the root document to a document.
232
+ * @returns The text of the place.
233
+ */
234
+ export function placeText(place: readonly Key[]): string {
235
+ let text = "";
236
+ for (let index = 0; index < place.length; index += 1) {
237
+ const key = place[index] as Key;
238
+ if (index > 0) text += "/";
239
+ text += typeof key === "number" || /^[\w$-]+$/.test(key) ? String(key) : JSON.stringify(key);
240
+ }
241
+ return text;
242
+ }
243
+
244
+ /** An effect while the kernel waits for its outcome. */
245
+ type Recorded = { -readonly [K in keyof Effect]: Effect[K] };
246
+
157
247
  /**
158
248
  * The runtime of one evaluation or run. Compiled code gets it with the context, and asks it to resolve paths and
159
249
  * to cause effects.
@@ -179,7 +269,7 @@ export interface Runtime {
179
269
  * @param kind - The kind of the effect.
180
270
  * @param payload - The data of the effect.
181
271
  * @param place - The place of the document.
182
- * @returns The payload, or an error value.
272
+ * @returns The answer of the mock, the payload without a mock, or an error value.
183
273
  */
184
274
  effect(ctx: Context, kind: Cap, payload: unknown, place: readonly Key[]): Result;
185
275
  /**
@@ -316,7 +406,7 @@ export interface EvalInput {
316
406
  *
317
407
  * @param kind - The kind of the effect, for example `log`.
318
408
  * @param payload - The data of the effect.
319
- * @returns The payload, or the error `#CAP!`.
409
+ * @returns The answer of the mock, the payload without a mock, or an error value, for example `#CAP!`.
320
410
  */
321
411
  effect(kind: Cap, payload: unknown): Result;
322
412
  /**
@@ -360,7 +450,7 @@ export interface RunInput {
360
450
  resolve(path: readonly unknown[], options?: ResolveOptions): Resolution;
361
451
  /**
362
452
  * This function causes an effect. In a run, the host does the effect, and the steps wait when the host waits. In
363
- * an evaluation, the effect gives its payload. Take its result with `yield*`.
453
+ * an evaluation, a mock answers the effect at once, or the effect gives its payload. Take its result with `yield*`.
364
454
  *
365
455
  * @param kind - The kind of the effect, for example `log`.
366
456
  * @param payload - The data of the effect.
@@ -547,11 +637,24 @@ export interface RunOptions {
547
637
  export interface EvalOptions {
548
638
  /** A list that gets each effect, in its order. */
549
639
  readonly effects?: Effect[];
640
+ /**
641
+ * The mock of the host (RUN.MOCK). It answers each effect at once, and its answer is the result of the effect.
642
+ * Without it, an effect gives its payload (RUN.EVAL).
643
+ */
644
+ readonly perform?: Perform;
645
+ }
646
+
647
+ /** The options of `evaluate`. */
648
+ export interface EvaluateOptions {
649
+ /** The type of a bare root value. */
650
+ readonly declaredType?: string;
651
+ /** The mock of the host (RUN.MOCK). Without it, an effect gives its payload (RUN.EVAL). */
652
+ readonly perform?: Perform;
550
653
  }
551
654
 
552
655
  /** The options of a resolution without a record of hops, and with one. One object of each serves each call. */
553
- const WITHOUT_HOPS: ResolveOptions = Object.freeze({ hops: false });
554
- const WITH_HOPS: ResolveOptions = Object.freeze({ hops: true });
656
+ const WITHOUT_HOPS: ResolveOptions = /* @__PURE__ */ Object.freeze({ hops: false });
657
+ const WITH_HOPS: ResolveOptions = /* @__PURE__ */ Object.freeze({ hops: true });
555
658
 
556
659
  /** This class holds the state of one evaluation or run: the machine, the effects, the clock and the trace. */
557
660
  class Session implements Runtime {
@@ -561,6 +664,11 @@ class Session implements Runtime {
561
664
  nextId = 0;
562
665
  current: Building | undefined;
563
666
  readonly holder: Building | undefined;
667
+ /**
668
+ * The scope of the addresses of the code that runs at this time (RUN.ADDRESS). `all` changes it for each item. The
669
+ * root scope is made at the first effect or `all`, thus an evaluation without effects makes no scope.
670
+ */
671
+ private scope: Scope | undefined;
564
672
 
565
673
  constructor(
566
674
  readonly machine: Machine,
@@ -589,45 +697,90 @@ class Session implements Runtime {
589
697
  return this.machine.permits === undefined ? permits(ctx.caps, keys) : this.machine.permits(ctx.caps, keys, ctx);
590
698
  }
591
699
 
592
- private record(ctx: Context, kind: Cap, payload: unknown, place: readonly Key[]): Result | Effect {
700
+ /** This function checks the capability of an effect, and records the effect with its address (RUN.ADDRESS). */
701
+ private record(ctx: Context, kind: Cap, payload: unknown, place: readonly Key[]): Result | Recorded {
593
702
  const keys = typeof kind === "string" ? kind.split(".") : kind;
594
703
  const text = keys.join(".");
595
704
  if (!this.permitted(ctx, keys)) return fail("#CAP!", `The context has no capability for the effect ${text}.`, { place });
596
705
  const node = this.current;
597
706
  const list = this.effects;
598
- const effect: Effect = { index: list.length, kind: text, path: keys, payload, node: node?.id ?? -1, at: this.tick, place, context: ctx };
707
+ const scope = (this.scope ??= { prefix: "", counts: undefined, alls: 0 });
708
+ const at = placeText(place);
709
+ const counts = (scope.counts ??= new Map<string, number>());
710
+ const count = counts.get(at) ?? 0;
711
+ counts.set(at, count + 1);
712
+ const effect: Recorded = {
713
+ index: list.length,
714
+ kind: text,
715
+ path: keys,
716
+ payload,
717
+ node: node?.id ?? -1,
718
+ at: this.tick,
719
+ place,
720
+ context: ctx,
721
+ address: `${scope.prefix}${at}#${count}`,
722
+ };
599
723
  list.push(effect);
600
724
  if (node !== undefined) node.effects.push(effect.index);
601
725
  return effect;
602
726
  }
603
727
 
728
+ /**
729
+ * This function answers an effect at once, without a wait: the mock gives the result, or the effect gives its
730
+ * payload without a mock (RUN.MOCK, RUN.EVAL). A promise from the mock gives `#CALC!`.
731
+ */
732
+ private answer(effect: Recorded, place: readonly Key[]): Result {
733
+ const perform = this.perform;
734
+ if (perform === undefined) return (effect.outcome = ok(effect.payload));
735
+ let done: unknown;
736
+ try {
737
+ done = perform(effect);
738
+ } catch (error) {
739
+ return (effect.outcome = hostFailed(effect.kind, place, error));
740
+ }
741
+ if (!(done instanceof Promise)) return (effect.outcome = ok(done));
742
+ // The evaluation does not read the promise, thus its rejection must not be unhandled.
743
+ void done.catch(() => undefined);
744
+ return (effect.outcome = fail("#CALC!", `The mock gave a promise for the effect ${effect.kind}, and an evaluation does not wait.`, { place }));
745
+ }
746
+
604
747
  effect(ctx: Context, kind: Cap, payload: unknown, place: readonly Key[]): Result {
605
748
  const text = typeof kind === "string" ? kind : kind.join(".");
606
749
  if (this.running) return fail("#CALC!", `The effect ${text} needs a runner: in a run, the host does each effect.`, { place });
607
750
  const made = this.record(ctx, kind, payload, place);
608
- return "ok" in made ? made : ok(payload);
751
+ return "ok" in made ? made : this.answer(made, place);
609
752
  }
610
753
 
611
754
  *runEffect(ctx: Context, kind: Cap, payload: unknown, place: readonly Key[]): Steps {
612
755
  const made = this.record(ctx, kind, payload, place);
613
756
  if ("ok" in made) return made;
614
757
  const perform = this.perform;
615
- if (!this.running || perform === undefined) return ok(payload);
616
- const failed = (error: unknown): Result => fail("#CALC!", `The host failed the effect ${made.kind}: ${describe(error)}`, { place, cause: error });
758
+ if (!this.running || perform === undefined) return this.answer(made, place);
617
759
  let done: unknown;
618
760
  try {
619
761
  done = perform(made);
620
762
  } catch (error) {
621
- return failed(error);
763
+ return (made.outcome = hostFailed(made.kind, place, error));
622
764
  }
623
- if (!(done instanceof Promise)) return ok(done);
624
- return (yield done.then((value: unknown) => ok(value), failed)) as Result;
765
+ if (!(done instanceof Promise)) return (made.outcome = ok(done));
766
+ const result = (yield done.then(
767
+ (value: unknown) => ok(value),
768
+ (error: unknown) => hostFailed(made.kind, place, error),
769
+ )) as Result;
770
+ // A run that stops at this wait does not reach this line, thus the effect keeps no outcome (RUN.OUTCOME).
771
+ return (made.outcome = result);
625
772
  }
626
773
 
627
774
  *all(list: readonly (() => Steps)[], options: AllOptions = {}): Generator<Promise<unknown>, readonly Result[], unknown> {
628
775
  const results: Result[] = new Array<Result>(list.length);
629
776
  const limit = Math.max(1, options.concurrency ?? list.length);
630
777
  const failFast = options.failFast === true;
778
+ // The address of this call, and a scope for each item (RUN.ADDRESS). The journal of a replay reads the address.
779
+ const outer = (this.scope ??= { prefix: "", counts: undefined, alls: 0 });
780
+ const address = `${outer.prefix}all${outer.alls}`;
781
+ outer.alls += 1;
782
+ const scopes: Scope[] = new Array<Scope>(list.length);
783
+ const journal = journalOf(this.perform);
631
784
  let failed = false;
632
785
  interface Active {
633
786
  readonly index: number;
@@ -642,11 +795,15 @@ class Session implements Runtime {
642
795
  };
643
796
  const advance = (index: number, steps: Steps, input: { readonly value?: unknown; readonly error?: unknown; readonly threw: boolean }): void => {
644
797
  let step: IteratorResult<Promise<unknown>, Result>;
798
+ const before = this.scope;
799
+ this.scope = scopes[index] as Scope;
645
800
  try {
646
801
  step = input.threw ? steps.throw(input.error) : steps.next(input.value);
647
802
  } catch (error) {
648
803
  settle(index, thrown(error, "a part"));
649
804
  return;
805
+ } finally {
806
+ this.scope = before;
650
807
  }
651
808
  if (step.done === true) {
652
809
  settle(index, step.value);
@@ -663,25 +820,35 @@ class Session implements Runtime {
663
820
  while (!failed && active.length < limit && next < list.length) {
664
821
  const index = next;
665
822
  next += 1;
823
+ const scope: Scope = { prefix: `${address}.${index}/`, counts: undefined, alls: 0 };
824
+ scopes[index] = scope;
666
825
  const begin = list[index] as () => Steps;
667
826
  let steps: Steps;
827
+ const before = this.scope;
828
+ this.scope = scope;
668
829
  try {
669
830
  steps = begin();
670
831
  } catch (error) {
671
832
  settle(index, thrown(error, "a part"));
672
833
  continue;
834
+ } finally {
835
+ this.scope = before;
673
836
  }
674
837
  advance(index, steps, { threw: false });
675
838
  }
676
839
  };
677
840
  start();
678
841
  while (active.length > 0 && !failed) {
679
- const settled = (yield Promise.race(active.map((item) => item.pending))) as {
842
+ // A replay settles the waits in the recorded order. Each other run takes the first wait that settles.
843
+ const chosen = journal?.next?.(address, active.map((item) => item.index));
844
+ const pick = chosen === undefined ? undefined : active.find((item) => item.index === chosen);
845
+ const settled = (yield pick === undefined ? Promise.race(active.map((item) => item.pending)) : pick.pending) as {
680
846
  readonly item: Active;
681
847
  readonly value?: unknown;
682
848
  readonly error?: unknown;
683
849
  readonly threw: boolean;
684
850
  };
851
+ journal?.settled?.(address, settled.item.index);
685
852
  active.splice(active.indexOf(settled.item), 1);
686
853
  advance(settled.item.index, settled.item.steps, settled);
687
854
  start();
@@ -759,7 +926,7 @@ function drive(steps: Steps): Result {
759
926
  return fail("#CALC!", "A part waited, and its parent cannot wait.");
760
927
  }
761
928
 
762
- const ABORTED = Symbol("aborted");
929
+ const ABORTED = /* @__PURE__ */ Symbol("aborted");
763
930
 
764
931
  /** This function drives steps that can wait. The steps before the first wait happen at once, in the call. */
765
932
  async function driveWaiting(steps: Steps, signal: StopSignal | undefined): Promise<Result> {
@@ -819,10 +986,11 @@ export interface Plan {
819
986
  /** The compiled root document. */
820
987
  readonly root: CompiledPart;
821
988
  /**
822
- * This function evaluates the document. It does not wait, and the host does no effect.
989
+ * This function evaluates the document. It does not wait, and the host does no effect. A mock can answer each
990
+ * effect at once (RUN.MOCK).
823
991
  *
824
992
  * @param context - The names and the capabilities at the root.
825
- * @param options - A list that gets the effects.
993
+ * @param options - A list that gets the effects, and the mock of the host.
826
994
  * @returns The result.
827
995
  */
828
996
  evaluate(context?: Context, options?: EvalOptions): Result;
@@ -916,7 +1084,7 @@ function evaluatorOf(world: World, envelope: Envelope | undefined, kind: Kind |
916
1084
  }
917
1085
 
918
1086
  /** The meta of a node of a compilation without a trace. Only a trace reads the meta of a node. */
919
- const NO_META: Meta = Object.freeze({ path: [], doc: { type: "?", value: null }, declared: false, answer: NO_ANSWER, side: "derive" });
1087
+ const NO_META: Meta = /* @__PURE__ */ Object.freeze({ path: [], doc: { type: "?", value: null }, declared: false, answer: NO_ANSWER, side: "derive" });
920
1088
 
921
1089
  function compileNode(c: Compiler, value: unknown, place: readonly Key[], declared: string | undefined, depth: number, address = false): { readonly code: Code; readonly run: RunCode } {
922
1090
  const world = c.machine.world;
@@ -1161,7 +1329,7 @@ function planOf(machine: Machine, traced: boolean, root: CompiledPart): Plan {
1161
1329
  traced,
1162
1330
  root,
1163
1331
  evaluate(context: Context = makeContext(), evalOptions?: EvalOptions): Result {
1164
- const s = new Session(machine, false, traced, undefined, undefined, evalOptions?.effects);
1332
+ const s = new Session(machine, false, traced, evalOptions?.perform, undefined, evalOptions?.effects);
1165
1333
  return root.code(rootContext(machine, context), s);
1166
1334
  },
1167
1335
  run(context: Context = makeContext(), runOptions: RunOptions = {}): Promise<Result> {
@@ -1212,17 +1380,20 @@ function record(s: Session, result: Result): Run {
1212
1380
  *
1213
1381
  * The verb `eval` goes up the ladder for each document. The kind of the document tells where its parts are. The
1214
1382
  * evaluator gets each part sealed: it can evaluate the part, and it cannot read its value. A failure gives an error
1215
- * value, and the function does not throw. An effect is recorded in its order, and nothing does it.
1383
+ * value, and the function does not throw. An effect is recorded in its order, and the host does not do it. A mock
1384
+ * can answer each effect at once (RUN.MOCK).
1216
1385
  *
1217
1386
  * @param machine - The world and the code of the evaluators.
1218
1387
  * @param doc - The document, as JSON.
1219
1388
  * @param context - The names and the capabilities at the root.
1220
- * @param declaredType - The type of a bare root value.
1389
+ * @param options - The type of a bare root value, or the options: that type and the mock of the host.
1221
1390
  * @returns The result, the trace and the effects in their order.
1222
1391
  */
1223
- export function evaluate(machine: Machine, doc: unknown, context: Context = makeContext(), declaredType?: string): Run {
1392
+ export function evaluate(machine: Machine, doc: unknown, context: Context = makeContext(), options?: string | EvaluateOptions): Run {
1393
+ const given: EvaluateOptions = typeof options === "string" ? { declaredType: options } : (options ?? {});
1394
+ const declaredType = given.declaredType;
1224
1395
  const plan = prepare(machine, doc, { trace: true, ...(declaredType === undefined ? {} : { declaredType }) });
1225
- const s = new Session(machine, false, true, undefined, undefined, undefined);
1396
+ const s = new Session(machine, false, true, given.perform, undefined, undefined);
1226
1397
  const result = plan.root.code(rootContext(machine, context), s);
1227
1398
  return record(s, result);
1228
1399
  }
package/src/formula.ts CHANGED
@@ -48,14 +48,14 @@ export interface FormulaProfile {
48
48
  }
49
49
 
50
50
  /** The mark of a field that the profile leaves out of a record. */
51
- const SKIPPED: unique symbol = Symbol("skipped");
51
+ const SKIPPED: unique symbol = /* @__PURE__ */ Symbol("skipped");
52
52
 
53
53
  /** The value of a name whose binding failed. A reference to the name gives the error. */
54
54
  export class Held {
55
55
  constructor(readonly error: EvalError) {}
56
56
  }
57
57
 
58
- const CLOSURE: unique symbol = Symbol.for("coeval.closure") as never;
58
+ const CLOSURE: unique symbol = /* @__PURE__ */ Symbol.for("coeval.closure") as never;
59
59
 
60
60
  /** A function that the construct `fn` made. It throws a `Failure` when its body fails. */
61
61
  export type Closure = ((...args: readonly unknown[]) => unknown) & { readonly [CLOSURE]: { readonly params: readonly string[] } };
package/src/index.ts CHANGED
@@ -118,7 +118,9 @@ export {
118
118
  type EvalFn,
119
119
  type EvalInput,
120
120
  type EvalOptions,
121
+ type EvaluateOptions,
121
122
  type Evaluator,
123
+ type Journal,
122
124
  type Machine,
123
125
  type Part,
124
126
  type Perform,
@@ -135,6 +137,7 @@ export {
135
137
  type Steps,
136
138
  type StopSignal,
137
139
  type TraceNode,
140
+ JOURNAL,
138
141
  capKeys,
139
142
  evaluate,
140
143
  failures,
@@ -198,5 +201,7 @@ export {
198
201
  jsTruthy,
199
202
  } from "./formula.ts";
200
203
  export { type Definitions, type ReferenceOptions, STD_DEFINITIONS, formulaDefinitions, reference } from "./reference.ts";
201
- export { type AgreeOptions, type Agreement, type Tier, type TierResult, agree, sameValue } from "./agree.ts";
204
+ export { type AgreeOptions, type Agreement, type Tier, type TierInput, type TierResult, agree, sameValue } from "./agree.ts";
205
+ export { sameResult } from "./same.ts";
206
+ export { type Recorder, type ReplayEntry, type ReplayLog, type ReplayOptions, type ReplaySettle, recorder, replayer } from "./replay.ts";
202
207
  export { type GenerateOptions, type Random, generate, random, typesOf } from "./generate.ts";
package/src/merge.ts CHANGED
@@ -55,7 +55,7 @@ export class MergeError extends Error {
55
55
 
56
56
  type Known = NonNullable<Machine["known"]>;
57
57
 
58
- const NONE: ReadonlySet<string> = new Set();
58
+ const NONE: ReadonlySet<string> = /* @__PURE__ */ new Set();
59
59
 
60
60
  function keyOf(path: MergePath): string {
61
61
  return JSON.stringify(path.map(String));
@@ -246,7 +246,7 @@ export function mergeWorlds(...parts: readonly (WorldPart | ((prev: World) => Wo
246
246
  }
247
247
 
248
248
  /** The fields of a machine that merge by their own rules. Each other field is one value, or a conflict. */
249
- const TABLES = new Set(["world", "evaluators", "runners", "derefs", "walkers", "known", "replaces"]);
249
+ const TABLES = /* @__PURE__ */ new Set(["world", "evaluators", "runners", "derefs", "walkers", "known", "replaces"]);
250
250
 
251
251
  interface MachineDraft {
252
252
  readonly world: WorldDraft;
package/src/parts.ts CHANGED
@@ -50,7 +50,7 @@ function setOwn(target: Record<string, unknown>, key: string, value: unknown): v
50
50
  else target[key] = value;
51
51
  }
52
52
 
53
- const NO_SLOTS: readonly PartSlot[] = Object.freeze([]);
53
+ const NO_SLOTS: readonly PartSlot[] = /* @__PURE__ */ Object.freeze([]);
54
54
 
55
55
  function hasSlots(template: Template): boolean {
56
56
  return template.t !== "data";