@mark1russell7/coeval 0.15.0 → 0.17.0

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/facts.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { type Json, type Key, isEnvelope, isKey } from "./doc.ts";
2
- import { type Kind, type LazyRule, type Side, type World, lookupKind } from "./world.ts";
2
+ import { type Kind, type LazyRule, type Side, type World, equationType, lookupKind } from "./world.ts";
3
3
  import { answerOf } from "./ladder.ts";
4
4
  import { pathMatches, splitParts } from "./parts.ts";
5
5
  import { type Root, ROOTS, isRef } from "./deref.ts";
6
6
  import type { Machine } from "./evaluate.ts";
7
- import { type DocVisit, declaredEffects, walk } from "./static.ts";
7
+ import { type DocVisit, type WalkOptions, declaredEffects, equationsOf, walk } from "./static.ts";
8
8
 
9
9
  /**
10
10
  * One read of a document: a free reference, with its marks (FACTS.READS). A plan resolves the path of the reference
@@ -27,9 +27,12 @@ export interface StaticRead {
27
27
  readonly address: boolean;
28
28
  /** The path of the reference: its root and its steps. */
29
29
  readonly path: readonly Json[];
30
- /** The keys from the root document to the reference document, through the parts. */
30
+ /**
31
+ * The keys from the root document to the reference document, through the parts. A read of an equation has the
32
+ * place of the first document of its tree kind (FACTS.EQUATIONS).
33
+ */
31
34
  readonly place: readonly Key[];
32
- /** The keys from the root JSON value to the reference document. */
35
+ /** The keys from the root JSON value to the reference document, or to the document of the kind for an equation. */
33
36
  readonly at: readonly Key[];
34
37
  }
35
38
 
@@ -151,9 +154,11 @@ function partLazy(above: Above, parent: DocVisit, slot: readonly Key[]): boolean
151
154
  *
152
155
  * - `reads`: each free reference, with the root and the keys of its path. A read under a lazy part has the mark
153
156
  * `lazy`, for example a read in a branch of `if`. A read after a step document has `exact: false`. A kind that
154
- * declares `reads` adds a read of each of its roots at each document of the kind.
157
+ * declares `reads` adds a read of each of its roots at each document of the kind. The first document of a tree
158
+ * kind also gets the lazy reads of the equations of its kind (FACTS.EQUATIONS). A read from `self` or from a name
159
+ * of a rung is not one of them, because it is not free (READS.EQUATION).
155
160
  * - `side` and `effects`: from the contract of each kind.
156
- * - `pure`: each kind declares `pure`, and the document has no effect and is not volatile.
161
+ * - `pure`: each kind declares `pure`, also in an equation, and the document has no effect and is not volatile.
157
162
  * - `volatile`: a kind, an operation or a step document declares `volatile`, or the host marks a read.
158
163
  *
159
164
  * The hook `facts` of the machine answers for a name that a fallback kind covers, for example an operation. Its
@@ -177,7 +182,6 @@ function partLazy(above: Above, parent: DocVisit, slot: readonly Key[]): boolean
177
182
  export function factsOf(machine: Machine, doc: unknown, options: FactsOptions = {}): DocFacts {
178
183
  const world = machine.world;
179
184
  const hook = machine.facts;
180
- const verb = options.verb ?? "eval";
181
185
  const reads: StaticRead[] = [];
182
186
  const effects: string[] = [];
183
187
  const above = new Map<DocVisit, Above>();
@@ -185,82 +189,113 @@ export function factsOf(machine: Machine, doc: unknown, options: FactsOptions =
185
189
  let pure = true;
186
190
  let volatile = false;
187
191
  let size = 0;
192
+ // The tree kinds whose equations the facts walked. The first document of each such kind gets their reads (FACTS.EQUATIONS).
193
+ let seen: Set<Kind> | undefined;
188
194
  const note = (isPure: boolean | undefined, isVolatile: boolean | undefined): void => {
189
195
  if (isPure !== true) pure = false;
190
196
  if (isVolatile === true) volatile = true;
191
197
  };
192
- walk(
193
- world,
194
- doc,
195
- (v) => {
196
- size += 1;
197
- const up = v.parent === undefined ? undefined : above.get(v.parent);
198
- const lazy = up !== undefined && v.parent !== undefined && (up.lazy || partLazy(up, v.parent, v.slot));
199
- const kind = v.kind;
200
- if (kind === undefined) {
201
- // A kind that the world does not have gives #KIND?, and the walk does not visit its value.
202
- pure = false;
203
- above.set(v, { lazy, rules: undefined });
204
- return undefined;
205
- }
206
- const code = codeOf(world, v.declared ? undefined : v.doc.own, kind, verb, "eval");
207
- const answer = code.name === undefined ? undefined : hook?.(v.typePath ?? [], code.name);
208
- let roots: readonly Root[] | undefined;
209
- if (code.described) {
210
- note(answer?.pure ?? kind.pure, answer?.volatile ?? kind.volatile);
211
- above.set(v, { lazy, rules: answer?.lazy ?? kind.lazy });
212
- roots = answer?.reads ?? kind.reads;
213
- } else {
214
- // The contract of the kind does not describe this code. Only the hook can.
215
- note(answer?.pure, answer?.volatile);
216
- above.set(v, { lazy, rules: answer?.lazy ?? EACH });
217
- roots = answer?.reads;
218
- }
219
- // The code of the kind resolves each of these roots as a whole, at the place of its document (FACTS.KIND-READS).
220
- for (const root of roots ?? NONE) {
221
- const read: StaticRead = { root, keys: NONE, exact: true, lazy, address: false, path: [root], place: tight(v.place), at: tight(v.at) };
222
- reads.push(read);
223
- if (options.volatile?.(read) === true) volatile = true;
224
- }
225
- if (kind.side === "run") side = "run";
226
- // check and effectsOf read the declared effects with the same function (D27).
227
- for (const keys of declaredEffects(v)) {
228
- const text = keys.join(".");
229
- if (!effects.includes(text)) effects.push(text);
230
- }
231
- if (!isRef(v.doc)) return undefined;
232
- const path = v.doc.value;
233
- const root = path[0];
234
- if (typeof root !== "string" || !(ROOTS as readonly string[]).includes(root)) return undefined;
235
- let exact = true;
236
- const keys: Key[] = [];
237
- for (let index = 1; index < path.length; index += 1) {
238
- const step = path[index];
239
- if (exact && isKey(step)) {
240
- keys.push(step);
241
- continue;
242
- }
243
- exact = false;
244
- // A step document runs the walker that the ladder finds for the verb step.
245
- const found = isEnvelope(step) ? lookupKind(world, step.type) : undefined;
246
- if (found?.ok !== true) {
198
+ const add = (read: StaticRead): void => {
199
+ reads.push(read);
200
+ if (options.volatile?.(read) === true) volatile = true;
201
+ };
202
+ /**
203
+ * This function walks a document. Without `node`, it walks the document of the facts. With `node`, it walks an
204
+ * equation of a tree kind, and each read gets the place of that node: the first document of the kind.
205
+ */
206
+ const scan = (term: unknown, walkOptions: WalkOptions, verb: string, node: DocVisit | undefined): void => {
207
+ walk(
208
+ world,
209
+ term,
210
+ (v) => {
211
+ if (node === undefined) size += 1;
212
+ const up = v.parent === undefined ? undefined : above.get(v.parent);
213
+ // An equation evaluates only when a demand reaches its attribute, thus each read of an equation is lazy (TREE.LAZY).
214
+ const lazy = node !== undefined || (up !== undefined && v.parent !== undefined && (up.lazy || partLazy(up, v.parent, v.slot)));
215
+ const place = node ?? v;
216
+ const kind = v.kind;
217
+ if (kind === undefined) {
218
+ // A kind that the world does not have gives #KIND?, and the walk does not visit its value.
247
219
  pure = false;
248
- continue;
220
+ above.set(v, { lazy, rules: undefined });
221
+ return undefined;
222
+ }
223
+ const code = codeOf(world, v.declared ? undefined : v.doc.own, kind, verb, "eval");
224
+ const answer = code.name === undefined ? undefined : hook?.(v.typePath ?? [], code.name);
225
+ let roots: readonly Root[] | undefined;
226
+ if (code.described) {
227
+ note(answer?.pure ?? kind.pure, answer?.volatile ?? kind.volatile);
228
+ above.set(v, { lazy, rules: answer?.lazy ?? kind.lazy });
229
+ roots = answer?.reads ?? kind.reads;
230
+ } else {
231
+ // The contract of the kind does not describe this code. Only the hook can.
232
+ note(answer?.pure, answer?.volatile);
233
+ above.set(v, { lazy, rules: answer?.lazy ?? EACH });
234
+ roots = answer?.reads;
249
235
  }
250
- const walker = codeOf(world, (step as { readonly own?: Readonly<Record<string, string>> }).own, found.kind, "step", "step");
251
- const stepAnswer = walker.name === undefined ? undefined : hook?.(found.path, walker.name);
252
- if (walker.described) note(stepAnswer?.pure ?? found.kind.pure, stepAnswer?.volatile ?? found.kind.volatile);
253
- else note(stepAnswer?.pure, stepAnswer?.volatile);
254
- }
255
- const first = path[1];
256
- // A reference to a name that a kind around it binds reads inside the document: it is not a read.
257
- if (root === "names" && isKey(first) && v.names.has(String(first))) return undefined;
258
- const read: StaticRead = { root: root as Root, keys: tight(keys), exact, lazy, address: v.address === true, path, place: tight(v.place), at: tight(v.at) };
259
- reads.push(read);
260
- if (options.volatile?.(read) === true) volatile = true;
261
- return undefined;
262
- },
263
- options.declaredType === undefined ? {} : { declaredType: options.declaredType },
264
- );
236
+ // The code of the kind resolves each of these roots as a whole, at the place of its document (FACTS.KIND-READS).
237
+ for (const root of roots ?? NONE) {
238
+ // In an equation, the root self is the node, thus its read is not free (READS.EQUATION).
239
+ if (node !== undefined && root === "self") continue;
240
+ add({ root, keys: NONE, exact: true, lazy, address: false, path: [root], place: tight(place.place), at: tight(place.at) });
241
+ }
242
+ // An equation evaluates without capabilities, thus an effect in it never reaches the host. It is still not pure.
243
+ if (kind.side === "run") {
244
+ if (node === undefined) side = "run";
245
+ else pure = false;
246
+ }
247
+ // check and effectsOf read the declared effects with the same function (D27).
248
+ for (const keys of declaredEffects(v)) {
249
+ if (node !== undefined) {
250
+ pure = false;
251
+ continue;
252
+ }
253
+ const text = keys.join(".");
254
+ if (!effects.includes(text)) effects.push(text);
255
+ }
256
+ // The equations of a tree kind are code of the kind. The first document of the kind gets their reads (FACTS.EQUATIONS).
257
+ if (kind.tree !== undefined && !(seen ??= new Set()).has(kind)) {
258
+ seen.add(kind);
259
+ const of = equationType(kind);
260
+ for (const { term: equation, names } of equationsOf(kind)) scan(equation, of === undefined ? { names } : { names, declaredType: of }, "eval", place);
261
+ }
262
+ if (!isRef(v.doc)) return undefined;
263
+ const path = v.doc.value;
264
+ const root = path[0];
265
+ if (typeof root !== "string" || !(ROOTS as readonly string[]).includes(root)) return undefined;
266
+ // In an equation, the root self is the node, thus its read is not free. A step out of the tree reads the outer
267
+ // self through the node, and the read of the whole root self that the tree node makes covers it (TREE.SELF).
268
+ if (node !== undefined && root === "self") return undefined;
269
+ let exact = true;
270
+ const keys: Key[] = [];
271
+ for (let index = 1; index < path.length; index += 1) {
272
+ const step = path[index];
273
+ if (exact && isKey(step)) {
274
+ keys.push(step);
275
+ continue;
276
+ }
277
+ exact = false;
278
+ // A step document runs the walker that the ladder finds for the verb step.
279
+ const found = isEnvelope(step) ? lookupKind(world, step.type) : undefined;
280
+ if (found?.ok !== true) {
281
+ pure = false;
282
+ continue;
283
+ }
284
+ const walker = codeOf(world, (step as { readonly own?: Readonly<Record<string, string>> }).own, found.kind, "step", "step");
285
+ const stepAnswer = walker.name === undefined ? undefined : hook?.(found.path, walker.name);
286
+ if (walker.described) note(stepAnswer?.pure ?? found.kind.pure, stepAnswer?.volatile ?? found.kind.volatile);
287
+ else note(stepAnswer?.pure, stepAnswer?.volatile);
288
+ }
289
+ const first = path[1];
290
+ // A reference to a name that a kind around it binds reads inside the document: it is not a read. The names of
291
+ // an equation are names that its rung binds (TREE.DOWN, TREE.FOLD).
292
+ if (root === "names" && isKey(first) && v.names.has(String(first))) return undefined;
293
+ add({ root: root as Root, keys: tight(keys), exact, lazy, address: v.address === true, path, place: tight(place.place), at: tight(place.at) });
294
+ return undefined;
295
+ },
296
+ walkOptions,
297
+ );
298
+ };
299
+ scan(doc, options.declaredType === undefined ? {} : { declaredType: options.declaredType }, options.verb ?? "eval", undefined);
265
300
  return { reads: tight(reads), side, effects: tight(effects), pure: pure && !volatile && effects.length === 0 && side === "derive", volatile, size };
266
301
  }
package/src/formula.ts CHANGED
@@ -4,8 +4,8 @@ import { type CompiledPath, type Context, type Resolution, compilePath, valueOfT
4
4
  import { type EvalError, type Failed, type Result, Failure, fail, ok, thrown } from "./errors.ts";
5
5
  import { type Code, type CompileInput, type CompiledEvaluator, type CompiledPart, type Evaluator, type Machine, type Runtime, resolveCompiled, totalCode } from "./evaluate.ts";
6
6
  import { type MachinePart, mergeMachines } from "./merge.ts";
7
- import { type Domain, type ValueType, HEADER_KEYS, STD_DOMAINS, callable, fieldOf, fits, fnOf, holdsEnvelope, isPrecise, isUnknown, itemOf, join, member, stepType, typeText } from "./types.ts";
8
- import type { TypeInput, TypeRule } from "./typing.ts";
7
+ import { type Domain, type ValueType, HEADER_KEYS, STD_DOMAINS, callable, fieldOf, fits, fnOf, holdsEnvelope, isPrecise, isUnknown, itemOf, join, member, stepType, typeIssues, typeText } from "./types.ts";
8
+ import type { PartType, TypeInput, TypeRule } from "./typing.ts";
9
9
  import { decodeDomain, domainTypeOf } from "./codec.ts";
10
10
  import { type StaticRead, factsOf } from "./facts.ts";
11
11
 
@@ -33,6 +33,9 @@ export type ExtFn = (data: Json, context: Context, domains?: Readonly<Record<str
33
33
  * `ext.domain`.
34
34
  * - `truthy`: the truth of a value for `if`, `and` and `or`. `undefined` is an error `#VALUE!`. The default
35
35
  * accepts only `true` and `false`.
36
+ * - `truthType`: the value type of a truth for the own `truthy`, for a check of types (TYPE.TRUTH, D81). A test of
37
+ * `if` and each term of `and` and `or` must fit it. Without it, the check accepts each type there. A profile without
38
+ * `truthy` ignores it, because the default truth needs `bool`.
36
39
  * - `otherwise`: the value of an `if` without `else`. The default is `null`. A profile with this key gives its value,
37
40
  * also `undefined`.
38
41
  * - `logic`: what `and` and `or` give: a truth value (the default), or the value that decided.
@@ -50,13 +53,15 @@ export type ExtFn = (data: Json, context: Context, domains?: Readonly<Record<str
50
53
  * overloads. An operation without a signature takes and gives `unknown` (TYPE.GRADUAL).
51
54
  *
52
55
  * A check of types trusts the signatures. Each operation must give a member of the result of each signature that
53
- * its arguments match. The hook `check` must keep each result in that type.
56
+ * its arguments match. The hook `check` must keep each result in that type. The function `truthy` must give a truth
57
+ * for each member of `truthType`.
54
58
  */
55
59
  export interface FormulaProfile {
56
60
  readonly ops?: Readonly<Record<string, OpFn>> | ((name: string) => OpFn | undefined);
57
61
  readonly lazy?: Readonly<Record<string, LazyOp>>;
58
62
  readonly ext?: Readonly<Record<string, ExtFn>>;
59
63
  readonly truthy?: (value: unknown) => boolean | undefined;
64
+ readonly truthType?: ValueType;
60
65
  readonly otherwise?: unknown;
61
66
  readonly logic?: "boolean" | "value";
62
67
  readonly omit?: (error: EvalError) => boolean;
@@ -266,12 +271,23 @@ function paramsOf(value: unknown): readonly string[] {
266
271
 
267
272
  /**
268
273
  * This function makes the type rules of the formula kit for one profile (TYPE.SYNTH, D25). Each evaluator of the kit
269
- * holds its rule. The rules read the rules of the profile that change a type: `truthy`, `logic`, `otherwise`, `omit`
270
- * and `sigs`.
274
+ * holds its rule. The rules read the rules of the profile that change a type: `truthy`, `truthType`, `logic`,
275
+ * `otherwise`, `omit` and `sigs`.
271
276
  */
272
277
  function formulaTypes(profile: FormulaProfile): Readonly<Record<string, TypeRule>> {
273
- // Only the default truth accepts nothing but a truth value. A truth of the profile accepts each value.
274
- const truth: ValueType | undefined = profile.truthy === undefined ? "bool" : undefined;
278
+ // The default truth needs a truth value. An own truth needs its declared type, or nothing without a declaration (D81).
279
+ const declared = profile.truthy !== undefined && profile.truthType !== undefined;
280
+ const truth: ValueType | undefined = profile.truthy === undefined ? "bool" : profile.truthType;
281
+ /**
282
+ * The need of a test or a term. The check examines a declared type of a truth as a contract, one time. A declared
283
+ * type with a problem needs nothing, thus one problem gives one issue.
284
+ */
285
+ const truthPart = (input: TypeInput, what: string): PartType => {
286
+ if (truth === undefined) return {};
287
+ if (!declared) return { expect: truth, what };
288
+ const type = input.contract(truth, "truth type of the profile");
289
+ return typeIssues(type, input.machine.domains).length > 0 ? {} : { expect: type, what };
290
+ };
275
291
  const logicValue = profile.logic === "value";
276
292
  const otherwise = Object.hasOwn(profile, "otherwise") ? valueType(profile.otherwise) : "null";
277
293
  const lookup = (name: string): readonly unknown[] | undefined => {
@@ -307,7 +323,7 @@ function formulaTypes(profile: FormulaProfile): Readonly<Record<string, TypeRule
307
323
  return { sigs, bad: sigs.length !== raw.length };
308
324
  };
309
325
  const logic = (word: "and" | "or"): TypeRule => ({
310
- part: (_input, path) => (truth === undefined ? {} : { expect: truth, what: `term ${Number(path[0]) + 1} of ${word}` }),
326
+ part: (input, path) => truthPart(input, `term ${Number(path[0]) + 1} of ${word}`),
311
327
  synth: (input) => {
312
328
  if (!logicValue) return "bool";
313
329
  // With the logic "value", the result is the term that decided, or the last term.
@@ -438,7 +454,7 @@ function formulaTypes(profile: FormulaProfile): Readonly<Record<string, TypeRule
438
454
 
439
455
  "formula.if": {
440
456
  part: (input, path) => {
441
- if (path[0] === "test") return truth === undefined ? {} : { expect: truth, what: "test of if" };
457
+ if (path[0] === "test") return truthPart(input, "test of if");
442
458
  return isUnknown(input.expected, input.machine.domains) ? {} : { expect: input.expected, what: `${String(path[0])} branch of if` };
443
459
  },
444
460
  synth: (input) => {
@@ -518,15 +534,43 @@ export function formulaEvaluators(profile: FormulaProfile = {}): Readonly<Record
518
534
  return { ...kitOf(profile).evaluators };
519
535
  }
520
536
 
537
+ /** The declared truth of a profile: its own `truthy` and its `truthType` (D81). */
538
+ export interface DeclaredTruth {
539
+ readonly truthy: (value: unknown) => boolean | undefined;
540
+ readonly truthType: ValueType;
541
+ }
542
+
543
+ /** The evaluators of the kit that read the truth of a value. */
544
+ const TRUTH_READERS: readonly string[] = ["formula.if", "formula.and", "formula.or"];
545
+
546
+ /** The declared truth of each evaluator of the kit that reads a truth, for `conforms` (D86). */
547
+ const truthByCode = /* @__PURE__ */ new WeakMap<object, DeclaredTruth>();
548
+
549
+ /**
550
+ * This function gives the declared truth of the profile of an evaluator of the kit (D86). Only `formula.if`,
551
+ * `formula.and` and `formula.or` of a profile with an own `truthy` and a `truthType` have one. The kernel does not
552
+ * export the function.
553
+ *
554
+ * @param code - The evaluator or the runner.
555
+ * @returns The declared truth, or `undefined`.
556
+ */
557
+ export function declaredTruthOf(code: unknown): DeclaredTruth | undefined {
558
+ return (typeof code === "object" || typeof code === "function") && code !== null ? truthByCode.get(code) : undefined;
559
+ }
560
+
521
561
  /** This function makes new evaluators of the formula kit for the fields of one profile. */
522
562
  function makeEvaluators(profile: FormulaProfile): Readonly<Record<string, Evaluator>> {
523
563
  const evaluators = formulaCode(profile);
524
564
  const types = formulaTypes(profile);
565
+ const { truthy, truthType } = profile;
566
+ const truth = truthy === undefined || truthType === undefined ? undefined : { truthy, truthType };
525
567
  const out: Record<string, Evaluator> = {};
526
568
  for (const name of Object.keys(evaluators)) {
527
569
  const evaluator = evaluators[name] as CompiledEvaluator;
528
570
  const type = Object.hasOwn(types, name) ? types[name] : undefined;
529
- out[name] = Object.freeze(type === undefined ? evaluator : { compile: evaluator.compile, type });
571
+ const made = Object.freeze(type === undefined ? evaluator : { compile: evaluator.compile, type });
572
+ if (truth !== undefined && TRUTH_READERS.includes(name)) truthByCode.set(made, truth);
573
+ out[name] = made;
530
574
  }
531
575
  return Object.freeze(out);
532
576
  }
@@ -537,6 +581,7 @@ const PROFILE_KEYS = /* @__PURE__ */ Object.freeze([
537
581
  "lazy",
538
582
  "ext",
539
583
  "truthy",
584
+ "truthType",
540
585
  "otherwise",
541
586
  "logic",
542
587
  "omit",
package/src/index.ts CHANGED
@@ -174,8 +174,10 @@ export {
174
174
  STD_RUNNERS,
175
175
  STD_WALKERS,
176
176
  STD_WORLD,
177
+ WORLD_SYNTAX,
177
178
  attributeTrace,
178
179
  nearestWalker,
180
+ placeOf,
179
181
  } from "./stdlib.ts";
180
182
  export {
181
183
  type Edge,
@@ -237,8 +239,11 @@ export {
237
239
  type ParseResult,
238
240
  type SyntaxAssoc,
239
241
  type SyntaxCalls,
242
+ type SyntaxEnvelopes,
240
243
  type SyntaxFixity,
241
244
  type SyntaxForm,
245
+ type SyntaxFormArgs,
246
+ type SyntaxHeader,
242
247
  type SyntaxIssue,
243
248
  type SyntaxLiterals,
244
249
  type SyntaxOperator,
@@ -266,8 +271,35 @@ export {
266
271
  edgesOf,
267
272
  schedule,
268
273
  } from "./schedule.ts";
274
+ export {
275
+ type AgreeScheduleOptions,
276
+ type ScheduleAgreement,
277
+ type ScheduleAgreementCounts,
278
+ type ScheduleEngine,
279
+ type ScheduleEngineFactory,
280
+ type ScheduleEngineStart,
281
+ agreeSchedule,
282
+ } from "./meaning.ts";
269
283
  export { type GraphCycle, type GraphEdge, type GraphNode, type GraphOptions, type NodeGraph, components, cycles, heights, necessary, nodeLayers } from "./graph.ts";
270
- export { type Recorder, type ReplayEntry, type ReplayLog, type ReplayOptions, type ReplaySettle, recorder, replayer } from "./replay.ts";
284
+ export {
285
+ type Recorder,
286
+ type ReplayCausePartsJson,
287
+ type ReplayEntry,
288
+ type ReplayEntryJson,
289
+ type ReplayErrorJson,
290
+ type ReplayExceptionJson,
291
+ type ReplayLog,
292
+ type ReplayLogJson,
293
+ type ReplayPartJson,
294
+ type ReplayPartsJson,
295
+ type ReplayOptions,
296
+ type ReplayResultJson,
297
+ type ReplaySettle,
298
+ decodeLog,
299
+ encodeLog,
300
+ recorder,
301
+ replayer,
302
+ } from "./replay.ts";
271
303
  export { type GenerateOptions, type Random, generate, random, typesOf } from "./generate.ts";
272
304
  export { type Domain, type DomainCodec, type TypeIssue, type ValueType, STD_DOMAINS, fits, join, member, typeIssues, typeText } from "./types.ts";
273
305
  export { type PartType, type RootTypes, type TypeInput, type TypeProblem, type TypeRule, type Typed, CAPS_TYPE } from "./typing.ts";