@mark1russell7/coeval 0.20.1 → 0.22.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/build/index.js CHANGED
@@ -354,6 +354,11 @@ function describe(value) {
354
354
  }
355
355
  }
356
356
  // src/world.ts
357
+ /** The rule of the registry of binding names. */
358
+ const NAMES_RULE = /* @__PURE__ */ Object.freeze({
359
+ ok: true,
360
+ names: true
361
+ });
357
362
  /** The most rounds of a circular attribute without its own `limit` (TREE.CIRCULAR-LIMIT, D113). */
358
363
  const CIRCULAR_LIMIT = 100;
359
364
  /** This function tells if a value is JSON data: `null`, a truth value, a finite number, a text, or a container of them. */
@@ -403,6 +408,112 @@ function circularOf(declared) {
403
408
  };
404
409
  }
405
410
  /**
411
+ * This function reads the declaration `collect` of an attribute (D122). The tree kit, the reference, `check` and the
412
+ * graph of attribute instances read it with this one function.
413
+ *
414
+ * @param declared - The value of the field `collect`.
415
+ * @returns The rule of the collection, or the reason when the declaration has no correct form.
416
+ */
417
+ function collectOf(declared) {
418
+ if (declared === "names") return NAMES_RULE;
419
+ if (!isRecord(declared) || !Object.hasOwn(declared, "unit") || !Object.hasOwn(declared, "combine")) return {
420
+ ok: false,
421
+ reason: "The declaration collect needs the text \"names\" or a record with the fields unit and combine."
422
+ };
423
+ return {
424
+ ok: true,
425
+ names: false,
426
+ unit: field(declared, "unit"),
427
+ combine: field(declared, "combine")
428
+ };
429
+ }
430
+ /**
431
+ * This function reads an entry of the table `tree.at` (D124). The tree kit, the reference, `check` and the graph of
432
+ * attribute instances read it with this one function.
433
+ *
434
+ * @param declared - The entry.
435
+ * @returns The rule, or the reason when the entry has no correct form.
436
+ */
437
+ function atRuleOf(declared) {
438
+ const params = isRecord(declared) ? field(declared, "params") : void 0;
439
+ if (!(Array.isArray(params) && params.every((name, index) => typeof name === "string" && params.indexOf(name) === index)) || !Object.hasOwn(declared, "equation")) return {
440
+ ok: false,
441
+ reason: "An entry of tree.at needs a list params of different texts and the field equation."
442
+ };
443
+ return {
444
+ ok: true,
445
+ params,
446
+ equation: field(declared, "equation")
447
+ };
448
+ }
449
+ /**
450
+ * This function examines the arguments of a step `tree.at` (D124). The step gives an argument for each parameter, and
451
+ * no other argument. Each argument is JSON data. The key is the text of `argsKey`, thus two equal arguments give one key.
452
+ *
453
+ * @param params - The parameters of the attribute.
454
+ * @param args - The field `args` of the step.
455
+ * @returns The names of the equation and the key, or the reason.
456
+ */
457
+ function atArgsOf(params, args) {
458
+ if (!isRecord(args)) return {
459
+ ok: false,
460
+ reason: "The arguments are a record."
461
+ };
462
+ const extra = Object.keys(args).find((name) => !params.includes(name));
463
+ if (extra !== void 0) return {
464
+ ok: false,
465
+ reason: `The attribute has no parameter ${extra}.`
466
+ };
467
+ const names = {};
468
+ for (const name of params) {
469
+ if (!Object.hasOwn(args, name)) return {
470
+ ok: false,
471
+ reason: `The step gives no argument ${name}.`
472
+ };
473
+ const value = field(args, name);
474
+ if (argsKey(value) === void 0) return {
475
+ ok: false,
476
+ reason: `The argument ${name} is not JSON data.`
477
+ };
478
+ Object.defineProperty(names, name, {
479
+ value,
480
+ enumerable: true,
481
+ writable: true,
482
+ configurable: true
483
+ });
484
+ }
485
+ return {
486
+ ok: true,
487
+ names,
488
+ key: argsKey(names)
489
+ };
490
+ }
491
+ /**
492
+ * This function gives the key of a JSON value (D124). The fields of a record are in the order of their names. Two
493
+ * values have the same key only when they are equal by DOC.EQUALS, thus `-0` and `0` have different keys.
494
+ *
495
+ * @param value - The value.
496
+ * @returns The JSON text, or `undefined` for a value that is not JSON data: a number that is not finite, a host value or a cycle.
497
+ */
498
+ function argsKey(value) {
499
+ return keyOf$1(value, /* @__PURE__ */ new Set());
500
+ }
501
+ function keyOf$1(value, open) {
502
+ if (value === null || typeof value === "boolean" || typeof value === "string") return JSON.stringify(value);
503
+ if (typeof value === "number") return !Number.isFinite(value) ? void 0 : Object.is(value, -0) ? "-0" : JSON.stringify(value);
504
+ if (typeof value !== "object" || open.has(value) || !Array.isArray(value) && !isRecord(value)) return void 0;
505
+ open.add(value);
506
+ try {
507
+ const list = Array.isArray(value);
508
+ const names = list ? [] : Object.keys(value).sort();
509
+ const items = list ? value.map((item) => keyOf$1(item, open)) : names.map((name) => keyOf$1(field(value, name), open));
510
+ if (items.includes(void 0)) return void 0;
511
+ return list ? `[${items.join(",")}]` : `{${names.map((name, index) => `${JSON.stringify(name)}:${String(items[index])}`).join(",")}}`;
512
+ } finally {
513
+ open.delete(value);
514
+ }
515
+ }
516
+ /**
406
517
  * This function gives the type of a bare equation of a kind (D42). It is the type `of` of the shape of its parts, or
407
518
  * else the type `of` of the shape `rest` of a record. The plan, the reference and `check` read it with this one function.
408
519
  *
@@ -1584,8 +1695,10 @@ function valueStep(value, key) {
1584
1695
  *
1585
1696
  * - A record gives the type of its field. A closed record without the field has no such step. An open record gives
1586
1697
  * `unknown`.
1587
- * - A list gives the type of its items for an index, and `number` for `length`.
1588
- * - A base type reads the steps of its domain, then of each parent (`Domain.steps`).
1698
+ * - A list gives the type of its items for an index, and `number` for `length`. Another key has no such step.
1699
+ * - A base type reads the steps of its domain, then of each parent (`Domain.steps`). A base type of the kernel
1700
+ * without such a step has no step, because its values are not objects (TYPE.NO-STEP, D120).
1701
+ * - A function type has no step, because a step into a function reaches nothing.
1589
1702
  * - A union joins the steps of its types. `one` gives the values that the step reaches.
1590
1703
  * - Each other step gives `unknown`, and `never` gives `never`.
1591
1704
  *
@@ -1604,10 +1717,11 @@ function stepType(type, key, domains, examine, depth = 0) {
1604
1717
  const found = steps[name];
1605
1718
  return { type: examine === void 0 ? found : examine(found, `type of the step ${name} of the domain ${each}`) };
1606
1719
  }
1607
- return { type: "unknown" };
1720
+ return Object.hasOwn(STD_DOMAINS, form.name) ? NO_STEP : { type: "unknown" };
1721
+ case "fn": return NO_STEP;
1608
1722
  case "list":
1609
1723
  if (key === "length") return { type: "number" };
1610
- return { type: indexOf(key) >= 0 ? form.item : "unknown" };
1724
+ return indexOf(key) >= 0 ? { type: form.item } : NO_STEP;
1611
1725
  case "record":
1612
1726
  if (Object.hasOwn(form.fields, name)) return { type: form.fields[name] };
1613
1727
  return form.closed ? { missing: Object.keys(form.fields) } : { type: "unknown" };
@@ -1634,6 +1748,8 @@ function stepType(type, key, domains, examine, depth = 0) {
1634
1748
  default: return { type: "unknown" };
1635
1749
  }
1636
1750
  }
1751
+ /** The answer of `stepType` for a type whose members have no step with the key, and no fields to name. */
1752
+ const NO_STEP = { missing: [] };
1637
1753
  /**
1638
1754
  * This function lists the problems of a value type (TYPE.ISSUES). A problem is a term that is not a value type, a
1639
1755
  * base type without a domain, or a term that is too deep. `fits` and `member` read each such term as `unknown`.
@@ -3420,6 +3536,34 @@ function pathMatches(path, pattern) {
3420
3536
  }
3421
3537
  return true;
3422
3538
  }
3539
+ /**
3540
+ * This function tells if a list of rules in the form of the lazy rules covers a part (D24, D119). A rule without
3541
+ * `in` covers each part. With `after: n`, a rule covers only the parts after the first `n` parts that it matches.
3542
+ *
3543
+ * @param rules - The rules.
3544
+ * @param shape - The shape of the parts of the parent.
3545
+ * @param value - The value of the parent.
3546
+ * @param slot - The path of the part in the value.
3547
+ * @returns `true` when a rule covers the part.
3548
+ */
3549
+ function rulesCover(rules, shape, value, slot) {
3550
+ for (const rule of rules) {
3551
+ if (rule.in !== void 0 && !rule.in.some((pattern) => pathMatches(slot, pattern))) continue;
3552
+ const after = rule.after ?? 0;
3553
+ if (after <= 0) return true;
3554
+ const split = splitParts(shape, value);
3555
+ let count = 0;
3556
+ for (const part of split.ok ? split.parts : []) {
3557
+ if (rule.in !== void 0 && !rule.in.some((pattern) => pathMatches(part.path, pattern))) continue;
3558
+ if (part.path.length === slot.length && pathMatches(part.path, slot)) {
3559
+ if (count >= after) return true;
3560
+ break;
3561
+ }
3562
+ count += 1;
3563
+ }
3564
+ }
3565
+ return false;
3566
+ }
3423
3567
  function valueAt(value, path) {
3424
3568
  let here = value;
3425
3569
  for (const key of path) if (Array.isArray(here)) here = here[Number(key)];
@@ -4583,6 +4727,7 @@ function pureCode(c, envelope, kind, typePath, name, quick) {
4583
4727
  } catch {
4584
4728
  return false;
4585
4729
  }
4730
+ if (answer?.effects !== void 0 && answer.effects.length > 0) return false;
4586
4731
  const described = c.verb === "eval" && (envelope === void 0 || quick?.rung !== "own" || name === answerOf(c.machine.world, void 0, kind, c.verb)?.name);
4587
4732
  const pure = described ? answer?.pure ?? kind.pure : answer?.pure;
4588
4733
  const volatile = described ? answer?.volatile ?? kind.volatile : answer?.volatile;
@@ -5425,6 +5570,24 @@ const STD_WORLD = {
5425
5570
  pure: true,
5426
5571
  summary: "A step of a path: it follows a key again and again, until it reaches a node of a type."
5427
5572
  },
5573
+ tree: { kinds: {
5574
+ named: {
5575
+ verbs: {
5576
+ step: "walk.named",
5577
+ view: "view.card"
5578
+ },
5579
+ pure: true,
5580
+ summary: "A step of a path: it goes up to the nearest registry of names, and it gives the node with the name (TREE.NAMED)."
5581
+ },
5582
+ at: {
5583
+ verbs: {
5584
+ step: "walk.tree.at",
5585
+ view: "view.card"
5586
+ },
5587
+ pure: true,
5588
+ summary: "A step of a path: it reads an attribute with parameters of the node before it, with the arguments of the step (TREE.AT)."
5589
+ }
5590
+ } },
5428
5591
  panel: {
5429
5592
  verbs: {
5430
5593
  eval: "tree.node",
@@ -5664,6 +5827,18 @@ const WORLD_SYNTAX = /* @__PURE__ */ Object.freeze({
5664
5827
  "self"
5665
5828
  ]
5666
5829
  },
5830
+ {
5831
+ name: "tree.named",
5832
+ kind: "tree.named",
5833
+ args: "named",
5834
+ fields: ["name", "in"]
5835
+ },
5836
+ {
5837
+ name: "tree.at",
5838
+ kind: "tree.at",
5839
+ args: "named",
5840
+ fields: ["attr", "args"]
5841
+ },
5667
5842
  {
5668
5843
  name: "add",
5669
5844
  kind: "add"
@@ -6203,6 +6378,132 @@ function plainOf(value, path) {
6203
6378
  }
6204
6379
  }
6205
6380
  /**
6381
+ * This function gives the collection of an attribute of a node (TREE.COLLECT, D122). It visits the node, then each node
6382
+ * of the same tree in each list `children`, in the order of the lists. Each node is visited one time.
6383
+ * The registry of names (TREE.NAMED) gives a record from each binding name to its node.
6384
+ */
6385
+ function collected(root, key, declared) {
6386
+ const top = stateOf(root);
6387
+ const rule = collectOf(declared);
6388
+ if (!rule.ok) return fail("#VALUE!", `The attribute ${attributeText(key, top.type, top.place)} has a bad declaration collect. ${rule.reason}`);
6389
+ const registry = {};
6390
+ const owners = /* @__PURE__ */ new Map();
6391
+ let acc = rule.names ? ok(registry) : top.equation(rule.unit, NO_NAMES$1);
6392
+ if (!acc.ok) return acc;
6393
+ const seen = /* @__PURE__ */ new Set();
6394
+ const stack = [root];
6395
+ while (stack.length > 0) {
6396
+ const thing = stack.pop();
6397
+ const at = stateOf(thing);
6398
+ if (at === void 0 || at.build !== top.build || seen.has(at)) continue;
6399
+ seen.add(at);
6400
+ if (rule.names) {
6401
+ const name = at.name;
6402
+ const earlier = name === void 0 ? void 0 : owners.get(name);
6403
+ if (earlier !== void 0) {
6404
+ const both = `${earlier.type} at [${earlier.place.join(", ")}] and ${at.type} at [${at.place.join(", ")}]`;
6405
+ return fail("#VALUE!", `Two nodes have the name ${name} in the registry ${attributeText(key, top.type, top.place)}: ${both}.`);
6406
+ }
6407
+ if (name !== void 0) {
6408
+ owners.set(name, at);
6409
+ putField(registry, name, thing);
6410
+ }
6411
+ } else {
6412
+ const term = entryOf(at.tree?.contributes, key);
6413
+ if (term !== void 0) {
6414
+ const item = at.equation(term, NO_NAMES$1);
6415
+ if (!item.ok) return item;
6416
+ acc = top.equation(rule.combine, {
6417
+ acc: acc.value,
6418
+ item: item.value
6419
+ });
6420
+ if (!acc.ok) return acc;
6421
+ }
6422
+ }
6423
+ const children = at.read("children");
6424
+ if (children === void 0) continue;
6425
+ if (!children.ok) return children;
6426
+ if (!Array.isArray(children.value)) return fail("#VALUE!", `The collection of ${key} needs a list in children of ${at.type} at [${at.place.join(", ")}].`);
6427
+ const list = children.value;
6428
+ for (let index = list.length - 1; index >= 0; index -= 1) stack.push(list[index]);
6429
+ }
6430
+ return acc;
6431
+ }
6432
+ /**
6433
+ * The host things that answer the step `tree.at` with their own function (D124). A node of the reference is in it, and
6434
+ * its fields do not change. The walker reads the state of a node of the kit.
6435
+ */
6436
+ const AT_READERS = /* @__PURE__ */ new WeakMap();
6437
+ /** The memo of the instances of the attributes with parameters of each node, without the cells of a host (TREE.AT). */
6438
+ const atMemos = /* @__PURE__ */ new WeakMap();
6439
+ /** The second key of each key of a node, for the cells of the attributes with parameters (TREE.AT-CELL). */
6440
+ const atPlaces = /* @__PURE__ */ new WeakMap();
6441
+ /**
6442
+ * This function gives an instance of an attribute with parameters of a node (TREE.AT, D124). The equation in
6443
+ * `tree.at` of the kind of the node evaluates with the arguments as names. The memo keeps one result for each key of
6444
+ * the arguments, and a demand of an instance in evaluation gives `#CYCLE!`. The function is outside the code of
6445
+ * `read`, thus a node without such attributes does no new work.
6446
+ */
6447
+ function atRead(n, attr, args) {
6448
+ const declared = entryOf(n.tree?.at, attr);
6449
+ if (declared === void 0) return void 0;
6450
+ const rule = atRuleOf(declared);
6451
+ if (!rule.ok) return fail("#VALUE!", `The attribute ${attributeText(attr, n.type, n.place)} has a bad entry tree.at. ${rule.reason}`);
6452
+ const given = atArgsOf(rule.params, args);
6453
+ if (!given.ok) return fail("#VALUE!", `The step tree.at of ${attributeText(attr, n.type, n.place)} has bad arguments. ${given.reason}`);
6454
+ const host = openPoint === void 0 ? n.host : void 0;
6455
+ const place = n.host === void 0 ? n.place : keptAt(atPlaces, n.place, () => Object.freeze([...n.place]));
6456
+ let marks = n.host === void 0 ? atMemos.get(n) : keptAt(marksByPlace, place, () => /* @__PURE__ */ new Map());
6457
+ if (marks === void 0) {
6458
+ marks = /* @__PURE__ */ new Map();
6459
+ atMemos.set(n, marks);
6460
+ }
6461
+ const key = `[${JSON.stringify(attr)},${given.key}]`;
6462
+ const text = attributeText(`${attr} with ${given.key}`, n.type, n.place);
6463
+ const cell = marks.get(key);
6464
+ if (cell !== void 0) return cell.busy ? cycleAt(marks, key, text) : cell.result;
6465
+ const demand = {
6466
+ cells: marks,
6467
+ key,
6468
+ text
6469
+ };
6470
+ const loop = openPoint;
6471
+ const compute = () => ({
6472
+ result: n.equation(rule.equation, given.names),
6473
+ by: "kind"
6474
+ });
6475
+ marks.set(key, BUSY);
6476
+ demands.push(demand);
6477
+ let thrown = NOT_THROWN;
6478
+ let answer;
6479
+ try {
6480
+ answer = host === void 0 ? compute() : host(place, key, () => {
6481
+ try {
6482
+ return compute();
6483
+ } catch (error) {
6484
+ thrown = error;
6485
+ throw error;
6486
+ }
6487
+ });
6488
+ } catch (error) {
6489
+ marks.delete(key);
6490
+ if (host === void 0 || error === thrown) throw error;
6491
+ answer = {
6492
+ result: fail("#CYCLE!", `The cells of the host found a cycle in the demands: ${demands.map((item) => item.text).join(" -> ")}.`, { cause: error }),
6493
+ by: void 0
6494
+ };
6495
+ } finally {
6496
+ demands.pop();
6497
+ }
6498
+ if (n.host !== void 0 || loop?.tentative.has(demand) === true) marks.delete(key);
6499
+ else marks.set(key, {
6500
+ busy: false,
6501
+ result: answer.result,
6502
+ by: answer.by
6503
+ });
6504
+ return answer.result;
6505
+ }
6506
+ /**
6206
6507
  * This function makes a node of the decorated tree. A step `parent` gives the self of the context of the node, and a
6207
6508
  * step `type` gives its type. Another step reads an attribute through its ladder (TREE.LADDER). The rungs are a part of
6208
6509
  * the node, an equation of its kind and an equation `down` of the kind of its parent. A copy from the parent, then a
@@ -6279,6 +6580,10 @@ function treeThing(input, place, build, outer, host) {
6279
6580
  result: fold(key, declared.fold),
6280
6581
  by: "default"
6281
6582
  };
6583
+ if (declared?.collect !== void 0) return {
6584
+ result: collected(node, key, declared.collect),
6585
+ by: "default"
6586
+ };
6282
6587
  if (declared?.default !== void 0) return {
6283
6588
  result: state.equation(declared.default, NO_NAMES$1),
6284
6589
  by: "default"
@@ -6357,6 +6662,7 @@ function treeThing(input, place, build, outer, host) {
6357
6662
  };
6358
6663
  const state = {
6359
6664
  build,
6665
+ name: input.doc.name,
6360
6666
  type,
6361
6667
  place,
6362
6668
  tree,
@@ -6538,8 +6844,75 @@ function nearestWalker(options = {}) {
6538
6844
  };
6539
6845
  };
6540
6846
  }
6847
+ const nearest = /* @__PURE__ */ nearestWalker();
6848
+ /**
6849
+ * The walker of the step `tree.named` (TREE.NAMED, D122). It goes up from the thing before the step through the key
6850
+ * `parent`, to the first thing that answers the registry. The field `in` names the registry, and the default is
6851
+ * `names`. The walker gives the node with the field `name` in that registry.
6852
+ */
6853
+ const named$2 = ({ data, here, deref }) => {
6854
+ const name = isRecord(data) ? field(data, "name") : void 0;
6855
+ if (typeof name !== "string") return {
6856
+ ok: false,
6857
+ code: "#VALUE!",
6858
+ reason: "The step tree.named needs a text name."
6859
+ };
6860
+ const registry = isRecord(data) && typeof field(data, "in") === "string" ? String(field(data, "in")) : "names";
6861
+ let at = here;
6862
+ for (let hops = 0; hops < 256 && at !== void 0 && at !== null; hops += 1) {
6863
+ const found = deref(at, registry);
6864
+ if (found !== void 0) {
6865
+ if (!isRecord(found) || !Object.hasOwn(found, name)) return {
6866
+ ok: false,
6867
+ reason: `The registry ${registry} has no node with the name ${name}.`
6868
+ };
6869
+ return {
6870
+ ok: true,
6871
+ thing: field(found, name)
6872
+ };
6873
+ }
6874
+ at = deref(at, "parent");
6875
+ }
6876
+ return {
6877
+ ok: false,
6878
+ reason: `No registry ${registry} is on the way.`
6879
+ };
6880
+ };
6881
+ /**
6882
+ * The walker of the step `tree.at` (TREE.AT, D124). The field `attr` names an attribute with parameters, and the
6883
+ * field `args` gives the arguments. The thing before the step is a node. A failed instance throws its own error.
6884
+ */
6885
+ const at = ({ data, here }) => {
6886
+ const attr = isRecord(data) ? field(data, "attr") : void 0;
6887
+ if (typeof attr !== "string") return {
6888
+ ok: false,
6889
+ code: "#VALUE!",
6890
+ reason: "The step tree.at needs a text attr."
6891
+ };
6892
+ const args = isRecord(data) && Object.hasOwn(data, "args") ? field(data, "args") : {};
6893
+ const state = stateOf(here);
6894
+ const reader = state === void 0 && typeof here === "object" && here !== null ? AT_READERS.get(here) : void 0;
6895
+ if (state === void 0 && reader === void 0) return {
6896
+ ok: false,
6897
+ reason: `The step tree.at reads ${attr} of a thing that is not a node of a tree.`
6898
+ };
6899
+ const result = state === void 0 ? reader(attr, args) : atRead(state, attr, args);
6900
+ if (result === void 0) return {
6901
+ ok: false,
6902
+ reason: `No rung gives the attribute ${attr} with parameters.`
6903
+ };
6904
+ if (!result.ok) throw new Failure(result.error);
6905
+ return {
6906
+ ok: true,
6907
+ thing: result.value
6908
+ };
6909
+ };
6541
6910
  /** The walkers of the standard world, by name. */
6542
- const STD_WALKERS = { "walk.nearest": /* @__PURE__ */ nearestWalker() };
6911
+ const STD_WALKERS = {
6912
+ "walk.nearest": nearest,
6913
+ "walk.named": named$2,
6914
+ "walk.tree.at": at
6915
+ };
6543
6916
  /** This function evaluates parts one after the other, and stops at the first error. */
6544
6917
  function* inOrder(parts) {
6545
6918
  const values = [];
@@ -7524,7 +7897,7 @@ function factsOf(machine, doc, options = {}) {
7524
7897
  at: tight(place.at)
7525
7898
  });
7526
7899
  }
7527
- const declared = declaredEffects(v, verb);
7900
+ const declared = verb === "eval" && answer?.effects !== void 0 ? effectKeys(v, answer.effects) : declaredEffects(v, verb);
7528
7901
  if (verb === "eval" ? kind.side === "run" : declared.length > 0) {
7529
7902
  if (node === void 0) side = "run";
7530
7903
  else pure = false;
@@ -7996,6 +8369,25 @@ function vertexOf(b, node, attribute) {
7996
8369
  }
7997
8370
  return id;
7998
8371
  }
8372
+ /**
8373
+ * This function gives the vertex of an instance of an attribute with parameters (TREE.AT-CHECK, D124). Its name is the
8374
+ * name of a plain vertex with the key of the arguments after the name of the attribute.
8375
+ */
8376
+ function atVertexOf(b, node, at) {
8377
+ const id = `${attributeVertexId(node.visit.place, at.attr).slice(0, -1)},${at.key}]`;
8378
+ if (!b.vertices.has(id)) {
8379
+ b.vertices.set(id, {
8380
+ id,
8381
+ place: node.visit.place,
8382
+ attribute: at.attr,
8383
+ type: node.text,
8384
+ args: at.names
8385
+ });
8386
+ b.nodes.set(id, node);
8387
+ b.work.push(id);
8388
+ }
8389
+ return id;
8390
+ }
7999
8391
  function edge(b, from, r, lazy = false) {
8000
8392
  b.edges.push({
8001
8393
  from,
@@ -8085,6 +8477,14 @@ function follow(b, start, path, from, r) {
8085
8477
  }
8086
8478
  continue;
8087
8479
  }
8480
+ if (isAtStep(b.machine, step)) {
8481
+ const at = atStepOf(node.kind, node.text, step.value);
8482
+ if (at.kind === "unknown") edge(b, void 0, r);
8483
+ if (at.kind !== "exact") return;
8484
+ edge(b, atVertexOf(b, node, at), r);
8485
+ here = "unknown";
8486
+ continue;
8487
+ }
8088
8488
  if (walkerOf(b.machine, step) !== STD_WALKERS["walk.nearest"]) {
8089
8489
  edge(b, void 0, r);
8090
8490
  return;
@@ -8160,7 +8560,10 @@ function termReads(b, refs, self, names, r) {
8160
8560
  const name = String(ref.path[1]);
8161
8561
  let start;
8162
8562
  if (ref.bound.has(name)) start = "unknown";
8163
- else if (names?.child !== void 0 && name === "child") start = { node: names.child };
8563
+ else if (names?.params !== void 0) {
8564
+ if (!names.params.includes(name)) continue;
8565
+ start = "data";
8566
+ } else if (names?.child !== void 0 && name === "child") start = { node: names.child };
8164
8567
  else if (names?.prev !== void 0 && name === "prev") start = names.prev;
8165
8568
  else if (name === "index") start = "data";
8166
8569
  else if (name === "acc" || name === "item") start = "unknown";
@@ -8184,7 +8587,8 @@ function prevOf(parent, child) {
8184
8587
  */
8185
8588
  function rungReads(b, id) {
8186
8589
  const node = b.nodes.get(id);
8187
- const key = b.vertices.get(id).attribute;
8590
+ const vertex = b.vertices.get(id);
8591
+ const key = vertex.attribute;
8188
8592
  const tree = node.kind.tree;
8189
8593
  const r = {
8190
8594
  to: id,
@@ -8192,6 +8596,14 @@ function rungReads(b, id) {
8192
8596
  place: node.visit.place,
8193
8597
  at: node.visit.at
8194
8598
  };
8599
+ if (vertex.args !== void 0) {
8600
+ const at = atStepOf(node.kind, node.text, {
8601
+ attr: key,
8602
+ args: vertex.args
8603
+ });
8604
+ if (at.kind === "exact") termReads(b, termRefs(b, node.kind, `tree.at.${key}`, at.equation), node, { params: at.params }, r);
8605
+ return;
8606
+ }
8195
8607
  const equation = hasOwnEntry(tree?.equations, key) ? tree?.equations?.[key] : void 0;
8196
8608
  if (equation !== void 0) {
8197
8609
  termReads(b, termRefs(b, node.kind, `tree.equations.${key}`, equation), node, void 0, r);
@@ -8245,8 +8657,57 @@ function rungReads(b, id) {
8245
8657
  });
8246
8658
  return;
8247
8659
  }
8660
+ const collect = declared?.collect === void 0 ? void 0 : collectOf(declared.collect);
8661
+ if (collect?.ok === true) {
8662
+ collectReads(b, node, key, collect, later);
8663
+ return;
8664
+ }
8248
8665
  if (declared?.default !== void 0) termReads(b, termRefs(b, node.kind, `tree.attributes.${key}.default`, declared.default), node, void 0, later);
8249
8666
  }
8667
+ /** This function gives the list children of a node before the run. A node without a rung for it has no children. */
8668
+ function childrenOf(b, at) {
8669
+ const part = at.parts.get("children");
8670
+ if (part !== void 0) return valueOf$1(part);
8671
+ const tree = at.kind.tree;
8672
+ if (hasOwnEntry(tree?.equations, "children") || hasOwnEntry(tree?.attributes, "children")) return "unknown";
8673
+ if (at.up === void 0) return downNames(b.machine.world).has("children") ? "unknown" : "data";
8674
+ return at.up !== null && hasOwnEntry(at.up.kind.tree?.down, "children") ? "unknown" : "data";
8675
+ }
8676
+ /**
8677
+ * This function adds the reads of a collection (TREE.COLLECT, D122), in the order of the run. Each node of the subtree
8678
+ * gives the reads of its contribution and of its list `children`. A list that only the run knows gives an edge with an
8679
+ * unknown source. The registry of names reads only the lists `children`.
8680
+ */
8681
+ function collectReads(b, node, key, rule, later) {
8682
+ if (!rule.names) termReads(b, termRefs(b, node.kind, `tree.attributes.${key}.collect.unit`, rule.unit), node, void 0, later);
8683
+ let combined = false;
8684
+ const done = /* @__PURE__ */ new Set();
8685
+ const stack = [node];
8686
+ while (stack.length > 0) {
8687
+ const at = stack.pop();
8688
+ if (done.has(at)) continue;
8689
+ done.add(at);
8690
+ const term = rule.names || !hasOwnEntry(at.kind.tree?.contributes, key) ? void 0 : at.kind.tree?.contributes?.[key];
8691
+ if (term !== void 0) {
8692
+ termReads(b, termRefs(b, at.kind, `tree.contributes.${key}`, term), at, void 0, later);
8693
+ combined = true;
8694
+ }
8695
+ edge(b, vertexOf(b, at, "children"), later);
8696
+ const children = childrenOf(b, at);
8697
+ if (children === "unknown") edge(b, void 0, later);
8698
+ else if (typeof children === "object" && "list" in children) {
8699
+ const items = itemsOf(children.list);
8700
+ for (let index = items.length - 1; index >= 0; index -= 1) {
8701
+ const child = items[index]?.node;
8702
+ if (child !== void 0 && child.up === at) stack.push(child);
8703
+ }
8704
+ }
8705
+ }
8706
+ if (!rule.names) termReads(b, termRefs(b, node.kind, `tree.attributes.${key}.collect.combine`, rule.combine), node, void 0, combined ? later : {
8707
+ ...later,
8708
+ lazy: true
8709
+ });
8710
+ }
8250
8711
  function build(machine, doc, declaredType) {
8251
8712
  const b = {
8252
8713
  machine,
@@ -8406,7 +8867,7 @@ function allCircular(b, ids) {
8406
8867
  return ids.every((id) => b.vertices.get(id)?.circular === true);
8407
8868
  }
8408
8869
  function vertexText(vertex) {
8409
- return `${vertex.attribute} of ${vertex.type} at [${vertex.place.join(", ")}]`;
8870
+ return `${vertex.args === void 0 ? vertex.attribute : `${vertex.attribute} with ${String(argsKey(vertex.args))}`} of ${vertex.type} at [${vertex.place.join(", ")}]`;
8410
8871
  }
8411
8872
  /**
8412
8873
  * This function finds each certain cycle of the attributes of a document before a run (TREE.GRAPH-CYCLE, D107). A run
@@ -8732,21 +9193,56 @@ function mapRefs(world, doc, change, options = {}) {
8732
9193
  }
8733
9194
  return out;
8734
9195
  }
9196
+ /**
9197
+ * This function gives the parts that the code of a runner evaluates itself, without a wait (RUN.DRIVES, D119). The
9198
+ * answer of the hook `facts` for the code wins over the contract. The contract describes only the code of its kind for
9199
+ * `eval`. Without a declaration, the runner passes each wait of its parts through.
9200
+ */
9201
+ function driveRules(machine, v, kind, name, rung, verb) {
9202
+ if (verb !== "eval") return void 0;
9203
+ const hook = machine.facts?.(v.typePath ?? [], name)?.drives;
9204
+ if (hook !== void 0) return hook;
9205
+ return v.declared || rung !== "own" || name === answerOf(machine.world, void 0, kind, verb)?.name ? kind.drives : void 0;
9206
+ }
8735
9207
  /** The least authority: the capability `[]` permits each effect (CAP.KEYS). */
8736
9208
  const EACH$1 = /* @__PURE__ */ Object.freeze([[]]);
8737
9209
  /** No declared effect. One list serves each visit without effects. */
8738
9210
  const NO_EFFECTS = /* @__PURE__ */ Object.freeze([]);
8739
9211
  /**
8740
- * This function gives the effects that the contract of the kind of a visit declares for a verb, as keys
8741
- * (FACTS.EFFECTS, VERB.EFFECTS). The text `"type"` gives the type of the document after each alias. A visit without a
8742
- * kind declares no effect. `check`, `factsOf` and `effectsOf` read the declarations with this one function (D27).
9212
+ * This function gives the effects that the code of a visit declares for a verb, as keys (FACTS.EFFECTS, VERB.EFFECTS).
9213
+ * The text `"type"` gives the type of the document after each alias. A visit without a kind declares no effect.
9214
+ * `check`, `factsOf`, `effectsOf` and `checkLatent` read the declarations with this one function (D27).
9215
+ *
9216
+ * For `eval`, the answer of the hook `facts` of the machine for the code of the visit wins over the contract of the
9217
+ * kind (CAP.OWN-EFFECTS, D118). Thus a language gives the effects of an own entry for another evaluator. Without a
9218
+ * machine, or without the field `effects` in the answer, the contract gives the effects.
8743
9219
  *
8744
9220
  * @param v - The visit.
8745
9221
  * @param verb - The verb. The default is `eval`. A kind without a declaration for the verb gives no effect.
8746
- * @returns The keys of each declared effect, in the order of the contract.
9222
+ * @param machine - The machine with the hook `facts`, when the caller has it.
9223
+ * @param name - The name of the evaluator of the visit, when the caller knows it. Else the ladder gives it.
9224
+ * @returns The keys of each declared effect, in the order of the declaration.
9225
+ */
9226
+ function declaredEffects(v, verb = "eval", machine, name) {
9227
+ return hookEffects(v, verb, machine, name) ?? verbDeclared(v, verb) ?? NO_EFFECTS;
9228
+ }
9229
+ /**
9230
+ * This function gives the effects that the hook `facts` gives for the code of a visit, as keys (D118). The result is
9231
+ * `undefined` for another verb than `eval`, without the hook, or when the answer has no field `effects`.
9232
+ */
9233
+ function hookEffects(v, verb, machine, name) {
9234
+ if (verb !== "eval" || machine?.facts === void 0 || v.kind === void 0) return void 0;
9235
+ const code = name ?? answerOf(machine.world, v.declared ? void 0 : v.doc.own, v.kind, "eval")?.name;
9236
+ const effects = code === void 0 ? void 0 : machine.facts(v.typePath ?? [], code)?.effects;
9237
+ return effects === void 0 ? void 0 : effectKeys(v, effects);
9238
+ }
9239
+ /**
9240
+ * This function gives the keys of a declaration of effects at a visit (D27). The text `"type"` gives the type of the
9241
+ * document after each alias.
8747
9242
  */
8748
- function declaredEffects(v, verb = "eval") {
8749
- return verbDeclared(v, verb) ?? NO_EFFECTS;
9243
+ function effectKeys(v, effects) {
9244
+ if (effects.length === 0) return NO_EFFECTS;
9245
+ return effects === "type" ? [v.typePath ?? []] : effects.map((kind) => kind.split("."));
8750
9246
  }
8751
9247
  /**
8752
9248
  * This function gives the effects that the contract of the kind of a visit declares for a verb, as keys. The result
@@ -8757,8 +9253,7 @@ function verbDeclared(v, verb) {
8757
9253
  if (v.kind === void 0) return verb === "eval" ? NO_EFFECTS : void 0;
8758
9254
  const effects = effectsOfVerb(v.kind, verb);
8759
9255
  if (effects === void 0) return void 0;
8760
- if (effects.length === 0) return NO_EFFECTS;
8761
- return effects === "type" ? [v.typePath ?? []] : effects.map((kind) => kind.split("."));
9256
+ return effectKeys(v, effects);
8762
9257
  }
8763
9258
  /**
8764
9259
  * This function gives the rule of a machine for an effect, for the static kit (CAP.PERMITS). The rule is the hook
@@ -8907,7 +9402,8 @@ const DOWN_NAMES = /* @__PURE__ */ Object.freeze([
8907
9402
  const FOLD_NAMES = /* @__PURE__ */ Object.freeze(["acc", "item"]);
8908
9403
  /**
8909
9404
  * This function gives each equation of the tree contract of a kind, with the names that it sees (D42). An equation of
8910
- * `equations`, a `unit` and a `default` see no names. `check` and `factsOf` read the equations with this one function.
9405
+ * `equations`, a `unit`, a `default` and a contribution see no names. `check` and `factsOf` read the equations with
9406
+ * this one function.
8911
9407
  */
8912
9408
  function equationsOf(kind) {
8913
9409
  const tree = kind.tree;
@@ -8951,6 +9447,42 @@ function equationsOf(kind) {
8951
9447
  attribute: name,
8952
9448
  down: false
8953
9449
  });
9450
+ const collect = declared.collect === void 0 ? void 0 : collectOf(declared.collect);
9451
+ if (collect?.ok === true && !collect.names) {
9452
+ out.push({
9453
+ label: `tree.attributes.${name}.collect.unit`,
9454
+ term: collect.unit,
9455
+ names: [],
9456
+ attribute: name,
9457
+ down: false
9458
+ });
9459
+ out.push({
9460
+ label: `tree.attributes.${name}.collect.combine`,
9461
+ term: collect.combine,
9462
+ names: FOLD_NAMES,
9463
+ attribute: name,
9464
+ down: false
9465
+ });
9466
+ }
9467
+ }
9468
+ for (const [name, term] of Object.entries(tree.contributes ?? {})) out.push({
9469
+ label: `tree.contributes.${name}`,
9470
+ term,
9471
+ names: [],
9472
+ attribute: name,
9473
+ down: false,
9474
+ contributes: true
9475
+ });
9476
+ for (const [name, declared] of Object.entries(tree.at ?? {})) {
9477
+ const rule = atRuleOf(declared);
9478
+ if (rule.ok) out.push({
9479
+ label: `tree.at.${name}`,
9480
+ term: rule.equation,
9481
+ names: rule.params,
9482
+ attribute: name,
9483
+ down: false,
9484
+ at: true
9485
+ });
8954
9486
  }
8955
9487
  return out;
8956
9488
  }
@@ -9073,7 +9605,7 @@ function answered(world, node, name) {
9073
9605
  if (hasEntry(tree?.equations, name)) return true;
9074
9606
  if (node.parent === void 0 ? downNames(world).has(name) : hasEntry(node.parent.kind.tree?.down, name)) return true;
9075
9607
  const declared = tree?.attributes !== void 0 && Object.hasOwn(tree.attributes, name) ? tree.attributes[name] : void 0;
9076
- return declared !== void 0 && (declared.copy === true || declared.fold !== void 0 || declared.default !== void 0);
9608
+ return declared !== void 0 && (declared.copy === true || declared.fold !== void 0 || declared.collect !== void 0 || declared.default !== void 0);
9077
9609
  }
9078
9610
  /**
9079
9611
  * This function checks the equations of the tree contract of a kind, each with the names of its rung (TREE.DOWN-NAMES).
@@ -9097,7 +9629,7 @@ function equationIssues(machine, kind, kindText, options, state) {
9097
9629
  own: void 0,
9098
9630
  parent: void 0
9099
9631
  };
9100
- for (const { label, term, names, attribute, down } of equationsOf(kind)) {
9632
+ for (const { label, term, names, attribute, down, contributes, at } of equationsOf(kind)) {
9101
9633
  const inner = {
9102
9634
  names,
9103
9635
  ...of === void 0 ? {} : { declaredType: of },
@@ -9107,7 +9639,7 @@ function equationIssues(machine, kind, kindText, options, state) {
9107
9639
  needs.push({
9108
9640
  name,
9109
9641
  why: `the equation ${label} reads it`,
9110
- hidden: down ? void 0 : attribute
9642
+ hidden: down || contributes === true || at === true ? void 0 : attribute
9111
9643
  });
9112
9644
  };
9113
9645
  for (const issue of checkAll(machine, term, inner, void 0, state, {
@@ -9124,7 +9656,8 @@ function equationIssues(machine, kind, kindText, options, state) {
9124
9656
  /**
9125
9657
  * This function finds the issues of the contract of a tree kind (TREE.CHECK-RESERVED). An attribute with the name of a
9126
9658
  * structural step gets no read. A tree kind of the run side contradicts the evaluation on demand of its attributes. A
9127
- * declaration `circular` without a start value or with a bad limit gives `#VALUE!` (TREE.CIRCULAR-CHECK).
9659
+ * declaration `circular` without a start value or with a bad limit gives `#VALUE!` (TREE.CIRCULAR-CHECK). A declaration
9660
+ * `collect` without its form gives `#VALUE!` too (TREE.COLLECT). So does an entry of `at` without its form (TREE.AT-CHECK).
9128
9661
  */
9129
9662
  function contractIssues(kind, kindText) {
9130
9663
  const out = [];
@@ -9132,7 +9665,9 @@ function contractIssues(kind, kindText) {
9132
9665
  for (const table of [
9133
9666
  "equations",
9134
9667
  "down",
9135
- "attributes"
9668
+ "attributes",
9669
+ "contributes",
9670
+ "at"
9136
9671
  ]) for (const name of Object.keys(tree?.[table] ?? {})) {
9137
9672
  const why = Object.hasOwn(STRUCTURAL, name) ? STRUCTURAL[name] : void 0;
9138
9673
  if (why !== void 0) out.push({
@@ -9148,6 +9683,20 @@ function contractIssues(kind, kindText) {
9148
9683
  place: [],
9149
9684
  reason: `The kind ${kindText} has a bad declaration tree.attributes.${name}.circular. ${rule.reason}`
9150
9685
  });
9686
+ const collect = declared.collect === void 0 ? void 0 : collectOf(declared.collect);
9687
+ if (collect !== void 0 && !collect.ok) out.push({
9688
+ code: "#VALUE!",
9689
+ place: [],
9690
+ reason: `The kind ${kindText} has a bad declaration tree.attributes.${name}.collect. ${collect.reason}`
9691
+ });
9692
+ }
9693
+ for (const [name, declared] of Object.entries(tree?.at ?? {})) {
9694
+ const rule = atRuleOf(declared);
9695
+ if (!rule.ok) out.push({
9696
+ code: "#VALUE!",
9697
+ place: [],
9698
+ reason: `The kind ${kindText} has a bad entry tree.at.${name}. ${rule.reason}`
9699
+ });
9151
9700
  }
9152
9701
  if (kind.side === "run") out.push({
9153
9702
  code: "#CALC!",
@@ -9194,7 +9743,7 @@ function nodeIssues(machine, node, state, v) {
9194
9743
  * This function examines a reference from the root `self` (TREE.CHECK-UNKNOWN). The steps `parent` go up the known
9195
9744
  * nodes. The first other key names an attribute of the node that they reach. When no rung answers the attribute, the
9196
9745
  * function gives the index of the step and the reason. In an equation, a read of the node of the equation goes to the
9197
- * needs of its kind.
9746
+ * needs of its kind. A step `tree.at` with literal arguments gets the checks of TREE.AT-CHECK.
9198
9747
  */
9199
9748
  function readIssue(machine, self, path, rootSelf) {
9200
9749
  let node = self;
@@ -9204,6 +9753,14 @@ function readIssue(machine, self, path, rootSelf) {
9204
9753
  index += 1;
9205
9754
  }
9206
9755
  const step = path[index];
9756
+ if (node !== void 0 && isAtStep(machine, step)) {
9757
+ const at = atStepOf(node.kind, node.text, step.value);
9758
+ return at.kind === "issue" ? {
9759
+ index,
9760
+ reason: at.reason,
9761
+ code: at.code
9762
+ } : void 0;
9763
+ }
9207
9764
  if (node === void 0 || !isKey(step) || Object.hasOwn(STRUCTURAL, String(step))) return void 0;
9208
9765
  const name = String(step);
9209
9766
  if (node.own === void 0) {
@@ -9215,6 +9772,52 @@ function readIssue(machine, self, path, rootSelf) {
9215
9772
  reason: `No rung gives the attribute ${name} of the kind ${node.text}.`
9216
9773
  };
9217
9774
  }
9775
+ /** This function tells if a step of a path is a step `tree.at` of the standard walker (TREE.AT, D124). */
9776
+ function isAtStep(machine, step) {
9777
+ return isEnvelope(step) && walkerOf(machine, step) === STD_WALKERS["walk.tree.at"];
9778
+ }
9779
+ /**
9780
+ * This function examines the data of a step `tree.at` on a node of a known kind (TREE.AT-CHECK, D124). `check` and the
9781
+ * graph of attribute instances read the step with this one function.
9782
+ */
9783
+ function atStepOf(kind, kindText, data) {
9784
+ if (holdsDocument(data)) return { kind: "unknown" };
9785
+ const attr = isRecord(data) ? field(data, "attr") : void 0;
9786
+ if (typeof attr !== "string") return {
9787
+ kind: "issue",
9788
+ code: "#VALUE!",
9789
+ reason: "The step tree.at needs a text attr."
9790
+ };
9791
+ const table = kind.tree?.at;
9792
+ const declared = table !== void 0 && Object.hasOwn(table, attr) ? table[attr] : void 0;
9793
+ if (declared === void 0) return {
9794
+ kind: "issue",
9795
+ code: "#N/A",
9796
+ reason: `No rung gives the attribute ${attr} with parameters of the kind ${kindText}.`
9797
+ };
9798
+ const rule = atRuleOf(declared);
9799
+ if (!rule.ok) return { kind: "unknown" };
9800
+ const given = atArgsOf(rule.params, isRecord(data) && Object.hasOwn(data, "args") ? field(data, "args") : {});
9801
+ if (!given.ok) return {
9802
+ kind: "issue",
9803
+ code: "#VALUE!",
9804
+ reason: `The step tree.at of ${attr} of the kind ${kindText} has bad arguments. ${given.reason}`
9805
+ };
9806
+ return {
9807
+ kind: "exact",
9808
+ attr,
9809
+ key: given.key,
9810
+ equation: rule.equation,
9811
+ params: rule.params,
9812
+ names: given.names
9813
+ };
9814
+ }
9815
+ /** This function tells if a value holds a document. A document in the data of a step can be a part, thus only the run knows its value. */
9816
+ function holdsDocument(value) {
9817
+ if (isEnvelope(value)) return true;
9818
+ if (Array.isArray(value)) return value.some(holdsDocument);
9819
+ return isRecord(value) && Object.values(value).some(holdsDocument);
9820
+ }
9218
9821
  /**
9219
9822
  * This function finds the issues of `check`. With a list of nodes, it also records each document that it visits for
9220
9823
  * the pass of types. It marks each document with an issue. The state holds the kinds whose equations the check
@@ -9235,6 +9838,7 @@ function checkAll(machine, doc, options, nodes, state = {
9235
9838
  };
9236
9839
  const allowed = options.caps === void 0 ? void 0 : permitsOf(machine);
9237
9840
  const waits = options.run === true ? /* @__PURE__ */ new Map() : void 0;
9841
+ const driven = /* @__PURE__ */ new Map();
9238
9842
  const drives = [];
9239
9843
  const maxDepth = machine.maxDepth ?? 1e3;
9240
9844
  const anyName = options.names === "any";
@@ -9311,7 +9915,7 @@ function checkAll(machine, doc, options, nodes, state = {
9311
9915
  });
9312
9916
  }
9313
9917
  const caps = v.caps;
9314
- const stated = verbDeclared(v, verb);
9918
+ const stated = hookEffects(v, verb, machine, name) ?? verbDeclared(v, verb);
9315
9919
  const declared = stated ?? NO_EFFECTS;
9316
9920
  if (allowed !== void 0 && caps !== void 0) {
9317
9921
  for (const kind of declared) if (!allowed(caps, kind)) push({
@@ -9322,7 +9926,9 @@ function checkAll(machine, doc, options, nodes, state = {
9322
9926
  });
9323
9927
  }
9324
9928
  if (waits !== void 0 && coded) {
9325
- const up = v.parent === void 0 ? true : waits.get(v.parent);
9929
+ let up = v.parent === void 0 ? true : waits.get(v.parent);
9930
+ const rules = v.parent === void 0 ? void 0 : driven.get(v.parent);
9931
+ if (up !== false && rules !== void 0 && v.parent !== void 0 && rulesCover(rules, v.parent.kind?.parts, v.parent.doc.value, v.slot)) up = false;
9326
9932
  let chain = false;
9327
9933
  if (runner && up === false) {
9328
9934
  chain = {
@@ -9339,6 +9945,10 @@ function checkAll(machine, doc, options, nodes, state = {
9339
9945
  drives.push(chain);
9340
9946
  } else if (runner) chain = up ?? true;
9341
9947
  waits.set(v, chain);
9948
+ if (runner && v.kind !== void 0) {
9949
+ const own = driveRules(machine, v, v.kind, name, answer.rung, verb);
9950
+ if (own !== void 0 && own.length > 0) driven.set(v, own);
9951
+ }
9342
9952
  if (typeof chain === "object" && !chain.wait) {
9343
9953
  const rule = allowed ?? permits;
9344
9954
  chain.wait = stated === void 0 || declared.some((kind) => caps === void 0 || rule(caps, kind));
@@ -9394,7 +10004,7 @@ function checkAll(machine, doc, options, nodes, state = {
9394
10004
  if (attributes && root === "self" && v.address !== true && name === "ref.resolve") {
9395
10005
  const issue = readIssue(machine, self, path, rootSelf);
9396
10006
  if (issue !== void 0) push({
9397
- code: "#N/A",
10007
+ code: issue.code ?? "#N/A",
9398
10008
  place: v.place,
9399
10009
  reason: issue.reason,
9400
10010
  at: stepAt(issue.index)
@@ -9444,7 +10054,7 @@ function reaching(machine, doc, options) {
9444
10054
  const rule = options.caps === void 0 ? permits : permitsOf(machine);
9445
10055
  walk(machine.world, doc, (v) => {
9446
10056
  const caps = v.caps ?? EACH;
9447
- for (const kind of declaredEffects(v)) if (rule(caps, kind)) out.push({
10057
+ for (const kind of declaredEffects(v, "eval", machine)) if (rule(caps, kind)) out.push({
9448
10058
  kind,
9449
10059
  visit: v
9450
10060
  });
@@ -9465,7 +10075,9 @@ function reaching(machine, doc, options) {
9465
10075
  *
9466
10076
  * The result covers each effect that an evaluation or a run gives the host (CAP.EFFECTS-SOUND). A procedure value keeps
9467
10077
  * the capabilities of the document that made it, thus the effects of its body count at the body (CAP.LATENT). The
9468
- * contract describes the code of its kind. The code of an own entry for another evaluator is outside the result.
10078
+ * contract describes the code of its kind. The contract does not describe the code of an own entry for another
10079
+ * evaluator. The answer of the hook `facts` for that code gives its effects (CAP.OWN-EFFECTS, D118). Without an
10080
+ * answer, its effects are outside the result.
9469
10081
  *
9470
10082
  * @param machine - The world and its contracts, and the hook `permits`.
9471
10083
  * @param doc - The document, as JSON.
@@ -9965,6 +10577,30 @@ function paramsOf(value) {
9965
10577
  const params = isRecord(value) ? value["params"] : void 0;
9966
10578
  return Array.isArray(params) ? params.filter((param) => typeof param === "string") : [];
9967
10579
  }
10580
+ /** This function gives the text of a step of a path: a key, or the kind of a step document in parentheses. */
10581
+ function stepText(step) {
10582
+ if (isKey(step)) return String(step);
10583
+ return isRecord(step) ? `(${typeName(step["type"])})` : "(step)";
10584
+ }
10585
+ /**
10586
+ * This function gives the type of what a step document reaches (TYPE.WALKER, D121). The type rule of its walker gives
10587
+ * it. A step document with parts gets its data in the run, thus its type is `unknown`, as for a walker without a rule.
10588
+ *
10589
+ * @param input - The input of the rule of the reference.
10590
+ * @param step - The step document.
10591
+ * @param here - The type before the step.
10592
+ * @returns The type of what the step reaches.
10593
+ */
10594
+ function walkType(input, step, here) {
10595
+ const rule = walkerOf(input.machine, step)?.type;
10596
+ if (rule === void 0) return "unknown";
10597
+ const read = partsOf(input.machine.world, step);
10598
+ if (!read.ok || !read.split.ok || read.split.parts.length > 0) return "unknown";
10599
+ return input.contract(rule({
10600
+ data: read.doc.value,
10601
+ here
10602
+ }), `type of the step ${typeName(read.doc.type)}`);
10603
+ }
9968
10604
  /**
9969
10605
  * This function makes the type rules of the formula kit for one profile (TYPE.SYNTH, D25). Each evaluator of the kit
9970
10606
  * holds its rule. The rules read the rules of the profile that change a type: `truthy`, `truthType`, `logic`,
@@ -10105,11 +10741,14 @@ function formulaTypes(profile) {
10105
10741
  if (isUnknown(type, domains) || !plain && holdsEnvelope(type, domains)) return "unknown";
10106
10742
  if (index >= path.length) return type;
10107
10743
  const step = path[index];
10108
- if (!isKey(step)) return "unknown";
10744
+ if (!isKey(step)) {
10745
+ type = walkType(input, step, type);
10746
+ continue;
10747
+ }
10109
10748
  const next = stepType(type, step, domains, input.contract);
10110
10749
  if ("missing" in next) {
10111
10750
  const fields = next.missing.length === 0 ? "" : ` Its fields are ${listText(next.missing)}.`;
10112
- report({ reason: `The value at ${path.slice(0, index).map(String).join(".")} has no field ${String(step)}.${fields}` });
10751
+ report({ reason: `The value at ${path.slice(0, index).map(stepText).join(".")} has no field ${String(step)}.${fields}` });
10113
10752
  return "unknown";
10114
10753
  }
10115
10754
  type = next.type;
@@ -10608,17 +11247,26 @@ function formulaCode(profile) {
10608
11247
  }
10609
11248
  return known;
10610
11249
  };
11250
+ const limit = Math.ceil((machine.maxDepth ?? 1e3) / 4);
10611
11251
  return (ctx, rt) => {
10612
11252
  rt.keepsContext?.(ctx, reads);
11253
+ const clock = rt;
10613
11254
  const closure = (...args) => {
10614
- const scope = { ...ctx.names };
10615
- names.forEach((name, index) => setOwn$2(scope, name, args[index]));
10616
- const result = body.code({
10617
- ...ctx,
10618
- names: scope
10619
- }, rt);
10620
- if (!result.ok) throw new Failure(result.error);
10621
- return result.value;
11255
+ const level = (clock.applying ?? 0) + 1;
11256
+ if (level > limit) throw new Failure(fail("#DEPTH!", `The applications of functions nest deeper than ${limit} levels.`).error);
11257
+ clock.applying = level;
11258
+ try {
11259
+ const scope = { ...ctx.names };
11260
+ names.forEach((name, index) => setOwn$2(scope, name, args[index]));
11261
+ const result = body.code({
11262
+ ...ctx,
11263
+ names: scope
11264
+ }, rt);
11265
+ if (!result.ok) throw new Failure(result.error);
11266
+ return result.value;
11267
+ } finally {
11268
+ clock.applying = level - 1;
11269
+ }
10622
11270
  };
10623
11271
  Object.defineProperty(closure, CLOSURE$2, { value: { params: names } });
10624
11272
  return ok(closure);
@@ -12505,6 +13153,7 @@ function envOf(machine, options, running, root, outer) {
12505
13153
  alls: 0
12506
13154
  },
12507
13155
  held: 0,
13156
+ applying: 0,
12508
13157
  reading: outer ?? (options.reads === void 0 ? void 0 : {
12509
13158
  list: options.reads,
12510
13159
  root
@@ -12638,6 +13287,55 @@ function foldOf(node, name, fold) {
12638
13287
  return acc;
12639
13288
  }
12640
13289
  /**
13290
+ * TREE.COLLECT and TREE.NAMED: the node, then each node of this tree in each list `children`, in the order of the
13291
+ * lists. Each node counts one time. The registry `names` maps each binding name to its node.
13292
+ */
13293
+ function collectIn(node, name, declared) {
13294
+ const rule = collectOf(declared);
13295
+ if (!rule.ok) return fail("#VALUE!", `The attribute ${nameOfAttribute(node, name)} has a bad declaration collect. ${rule.reason}`);
13296
+ const registry = {};
13297
+ const first = /* @__PURE__ */ new Map();
13298
+ let acc = rule.names ? ok(registry) : equationOf(node, rule.unit, {});
13299
+ if (!acc.ok) return acc;
13300
+ const done = [];
13301
+ const visit = (at) => {
13302
+ if (done.includes(at)) return void 0;
13303
+ done.push(at);
13304
+ if (rule.names && at.name !== void 0) {
13305
+ const earlier = first.get(at.name);
13306
+ if (earlier !== void 0) return fail("#VALUE!", `Two nodes have the name ${at.name} in the registry ${nameOfAttribute(node, name)}: ${earlier.kind} at [${earlier.place.join(", ")}] and ${at.kind} at [${at.place.join(", ")}].`);
13307
+ first.set(at.name, at);
13308
+ Object.defineProperty(registry, at.name, {
13309
+ value: at.thing,
13310
+ enumerable: true,
13311
+ writable: true,
13312
+ configurable: true
13313
+ });
13314
+ }
13315
+ const term = rule.names ? void 0 : termIn(at.contract?.contributes, name);
13316
+ if (!rule.names && term !== void 0) {
13317
+ const item = equationOf(at, term, {});
13318
+ if (!item.ok) return item;
13319
+ acc = equationOf(node, rule.combine, {
13320
+ acc: acc.ok ? acc.value : null,
13321
+ item: item.value
13322
+ });
13323
+ if (!acc.ok) return acc;
13324
+ }
13325
+ const children = attributeOf(at, "children");
13326
+ if (children === void 0) return void 0;
13327
+ if (!children.ok) return children;
13328
+ if (!Array.isArray(children.value)) return fail("#VALUE!", `The collection of ${name} needs a list in children of ${at.kind} at [${at.place.join(", ")}].`);
13329
+ for (const item of children.value) {
13330
+ const child = refNodeOf(item);
13331
+ if (child === void 0 || child.tree !== node.tree) continue;
13332
+ const failed = visit(child);
13333
+ if (failed !== void 0) return failed;
13334
+ }
13335
+ };
13336
+ return visit(node) ?? acc;
13337
+ }
13338
+ /**
12641
13339
  * TREE.LADDER: the rungs of the ladder of an attribute, in their order. A rung gives `undefined` when it does not
12642
13340
  * answer, and the next rung then tries.
12643
13341
  */
@@ -12661,6 +13359,7 @@ const REF_RUNGS = [
12661
13359
  ["default", (node, name) => {
12662
13360
  const declared = termIn(node.contract?.attributes, name);
12663
13361
  if (declared?.fold !== void 0) return foldOf(node, name, declared.fold);
13362
+ if (declared?.collect !== void 0) return collectIn(node, name, declared.collect);
12664
13363
  return declared?.default === void 0 ? void 0 : equationOf(node, declared.default, {});
12665
13364
  }]
12666
13365
  ];
@@ -12805,6 +13504,51 @@ function attributeOf(node, name) {
12805
13504
  if (!entry.tentative && result !== void 0) node.values.set(name, result);
12806
13505
  return result;
12807
13506
  }
13507
+ /** TREE.AT: the instances of each node of the reference. Two arguments are the same instance by DOC.EQUALS. */
13508
+ const refInstances = /* @__PURE__ */ new WeakMap();
13509
+ /**
13510
+ * TREE.AT: the instance of an attribute with parameters, or `undefined` when the kind has no entry in `tree.at`. The
13511
+ * equation sees the arguments as names. A demand of an instance in evaluation gives `#CYCLE!`, also in a fixed point.
13512
+ */
13513
+ function instanceOf$1(node, attr, args) {
13514
+ const declared = termIn(node.contract?.at, attr);
13515
+ if (declared === void 0) return void 0;
13516
+ const rule = atRuleOf(declared);
13517
+ if (!rule.ok) return fail("#VALUE!", `The attribute ${nameOfAttribute(node, attr)} has a bad entry tree.at. ${rule.reason}`);
13518
+ const given = atArgsOf(rule.params, args);
13519
+ if (!given.ok) return fail("#VALUE!", `The step tree.at of ${nameOfAttribute(node, attr)} has bad arguments. ${given.reason}`);
13520
+ const name = `${attr} with ${given.key}`;
13521
+ const list = refInstances.get(node) ?? [];
13522
+ refInstances.set(node, list);
13523
+ const found = list.find((item) => item.attr === attr && docEquals(item.names, given.names));
13524
+ if (found?.result !== void 0) return found.result;
13525
+ if (found !== void 0) {
13526
+ const from = inEvaluation.findIndex((entry) => entry.node === node && entry.name === name);
13527
+ return fail("#CYCLE!", `The attributes form a cycle: ${[...inEvaluation.slice(from).map((entry) => nameOfAttribute(entry.node, entry.name)), nameOfAttribute(node, name)].join(" -> ")}.`);
13528
+ }
13529
+ const item = {
13530
+ attr,
13531
+ names: given.names,
13532
+ result: void 0
13533
+ };
13534
+ list.push(item);
13535
+ const entry = {
13536
+ node,
13537
+ name,
13538
+ circular: false,
13539
+ tentative: false
13540
+ };
13541
+ inEvaluation.push(entry);
13542
+ let result;
13543
+ try {
13544
+ result = equationOf(node, rule.equation, given.names);
13545
+ } finally {
13546
+ inEvaluation.pop();
13547
+ if (result === void 0 || entry.tentative) list.splice(list.indexOf(item), 1);
13548
+ else item.result = result;
13549
+ }
13550
+ return result;
13551
+ }
12808
13552
  /** TREE.RESULT: the JSON of a node. `open` holds the nodes and the containers whose JSON is in progress. */
12809
13553
  function jsonOfNode(node, self, open) {
12810
13554
  const record = {};
@@ -12848,7 +13592,7 @@ function plainValue(value, open) {
12848
13592
  * tree gives its JSON. A step on the thing reads an attribute, and a failed attribute throws its own error. The node
12849
13593
  * reads `self` only through `resolve` (C4, TREE.SELF).
12850
13594
  */
12851
- const treeDefinition = ({ parts, context, kind, place, machine, typePath, resolve: walk }) => {
13595
+ const treeDefinition = ({ parts, context, kind, place, machine, typePath, resolve: walk, doc }) => {
12852
13596
  const reached = walk(["self"]);
12853
13597
  const parent = reached.ok ? reached.thing : void 0;
12854
13598
  const outer = refNodeOf(parent);
@@ -12859,6 +13603,7 @@ const treeDefinition = ({ parts, context, kind, place, machine, typePath, resolv
12859
13603
  const node = {
12860
13604
  tree: nested ? outer.tree : { open: true },
12861
13605
  kind,
13606
+ name: doc.name,
12862
13607
  place,
12863
13608
  parts,
12864
13609
  ctx: context,
@@ -12890,6 +13635,7 @@ const treeDefinition = ({ parts, context, kind, place, machine, typePath, resolv
12890
13635
  };
12891
13636
  node.thing = self;
12892
13637
  refNodes.set(self, node);
13638
+ AT_READERS.set(self, (attr, args) => instanceOf$1(node, attr, args));
12893
13639
  if (nested) return ok(self);
12894
13640
  try {
12895
13641
  return jsonOfNode(node, self, []);
@@ -13016,16 +13762,27 @@ function formulaDefinitions(profile = {}) {
13016
13762
  if (!Array.isArray(params) || !params.every((param) => typeof param === "string") || new Set(params).size !== params.length) return fail("#VALUE!", "The params of fn are a list of different texts.");
13017
13763
  const names = params;
13018
13764
  const body = partNamed(parts, "body");
13765
+ const clock = activeEnvs[activeEnvs.length - 1] ?? {
13766
+ applying: 0,
13767
+ maxDepth: 1e3
13768
+ };
13769
+ const limit = Math.ceil(clock.maxDepth / 4);
13019
13770
  const closure = (...args) => {
13020
- const scope = {};
13021
- for (const key of Object.keys(context.names)) setField$1(scope, key, context.names[key]);
13022
- names.forEach((name, index) => setField$1(scope, name, args[index]));
13023
- const result = body.evaluate({
13024
- ...context,
13025
- names: scope
13026
- });
13027
- if (!result.ok) throw new Failure(result.error);
13028
- return result.value;
13771
+ if (clock.applying >= limit) throw new Failure(fail("#DEPTH!", `The applications of functions nest deeper than ${limit} levels.`).error);
13772
+ clock.applying += 1;
13773
+ try {
13774
+ const scope = {};
13775
+ for (const key of Object.keys(context.names)) setField$1(scope, key, context.names[key]);
13776
+ names.forEach((name, index) => setField$1(scope, name, args[index]));
13777
+ const result = body.evaluate({
13778
+ ...context,
13779
+ names: scope
13780
+ });
13781
+ if (!result.ok) throw new Failure(result.error);
13782
+ return result.value;
13783
+ } finally {
13784
+ clock.applying -= 1;
13785
+ }
13029
13786
  };
13030
13787
  Object.defineProperty(closure, CLOSURE$1, { value: { params: names } });
13031
13788
  return ok(closure);
@@ -15182,6 +15939,7 @@ var Shot = class {
15182
15939
  scenario;
15183
15940
  context;
15184
15941
  keys;
15942
+ driven;
15185
15943
  perform;
15186
15944
  replay;
15187
15945
  calls = [];
@@ -15195,12 +15953,13 @@ var Shot = class {
15195
15953
  result = NO_RESULT;
15196
15954
  afterwards = false;
15197
15955
  running;
15198
- constructor(machine, runner, scenario, context, keys, perform, replay) {
15956
+ constructor(machine, runner, scenario, context, keys, driven, perform, replay) {
15199
15957
  this.machine = machine;
15200
15958
  this.runner = runner;
15201
15959
  this.scenario = scenario;
15202
15960
  this.context = context;
15203
15961
  this.keys = keys;
15962
+ this.driven = driven;
15204
15963
  this.perform = perform;
15205
15964
  this.replay = replay;
15206
15965
  this.running = scenario.running;
@@ -15224,7 +15983,7 @@ var Shot = class {
15224
15983
  });
15225
15984
  const key = this.keys[part] ?? String(part);
15226
15985
  if (via === "run" && !this.runner) this.problems.push(`The code of an evaluator starts the steps of the part ${key}. Only a runner waits.`);
15227
- if (via === "code" && this.runner && this.running) this.problems.push(`The runner evaluates the part ${key} with its code, and that code cannot wait. A runner evaluates a part with its steps (K65).`);
15986
+ if (via === "code" && this.runner && this.running && this.driven[part] !== true) this.problems.push(`The runner evaluates the part ${key} with its code, and that code cannot wait. A runner evaluates a part with its steps, or its contract declares the part in drives (D119).`);
15228
15987
  return this.scenario.results[part] ?? NO_RESULT;
15229
15988
  }
15230
15989
  /** This function records a call of a part, and gives the steps of the probe part. In a run, the part can wait. */
@@ -15417,13 +16176,14 @@ function typesNaming(world, name, verb) {
15417
16176
  /** This function gives the facts of the kind of a type. The hook `facts` of the machine wins over the contract. */
15418
16177
  function contractOf(env, kind, typePath, caps) {
15419
16178
  const facts = env.machine.facts?.(typePath, env.name);
15420
- const own = effectsOfVerb(kind, env.verb);
16179
+ const own = (env.verb === "eval" ? facts?.effects : void 0) ?? effectsOfVerb(kind, env.verb);
15421
16180
  const effects = own ?? kind.effects;
15422
16181
  const declared = effects === void 0 ? [] : effects === "type" ? [typePath] : effects;
15423
16182
  return {
15424
16183
  declared,
15425
16184
  pure: (facts?.pure ?? kind.pure) === true,
15426
16185
  lazy: facts?.lazy ?? kind.lazy,
16186
+ drives: env.verb === "eval" ? facts?.drives ?? kind.drives : void 0,
15427
16187
  describes: env.verb === "eval",
15428
16188
  declares: own !== void 0,
15429
16189
  caps: caps ?? [...declared, "probe"]
@@ -15571,6 +16331,7 @@ function samplesOf(type, typePath, kind, contract, extra) {
15571
16331
  },
15572
16332
  otherSplit,
15573
16333
  lazy: split.parts.map((_slot, index) => contract.lazy?.some((rule) => covers(rule, split.parts, index)) === true),
16334
+ driven: split.parts.map((_slot, index) => contract.drives?.some((rule) => covers(rule, split.parts, index)) === true),
15574
16335
  names: scopesOf(kind.scope, value, split.parts).sees
15575
16336
  });
15576
16337
  }
@@ -15717,7 +16478,7 @@ function instanceOf(env, under, doc, split, sample) {
15717
16478
  /** This function evaluates a probe document one time in a new shot. */
15718
16479
  function shoot(env, instance, sample, scenario, more = {}) {
15719
16480
  const context = more.context ?? rootContext(env.machine, makeContext(env.names, scenario.caps));
15720
- const shot = new Shot(env.machine, env.runner, scenario, context, sample.split.parts.map((slot) => slot.key), env.perform, more.replay);
16481
+ const shot = new Shot(env.machine, env.runner, scenario, context, sample.split.parts.map((slot) => slot.key), sample.driven, env.perform, more.replay);
15721
16482
  instance(shot);
15722
16483
  return shot;
15723
16484
  }
@@ -17189,18 +17950,89 @@ const READ = /* @__PURE__ */ new Set([
17189
17950
  "enum",
17190
17951
  "const",
17191
17952
  "anyOf",
17192
- "oneOf"
17953
+ "oneOf",
17954
+ "allOf",
17955
+ "$ref"
17193
17956
  ]);
17194
17957
  /**
17195
- * The keywords that can permit more values than the other keywords permit. Older drafts ignore each keyword beside
17196
- * `$ref`, and `nullable` of OpenAPI 3.0 permits `null`. Thus a schema with one of them reads as `unknown`.
17958
+ * The keywords that can permit more values than the other keywords permit. A dynamic reference can reach a schema
17959
+ * outside this schema, and `nullable` of OpenAPI 3.0 permits `null`. Thus a schema with one of them reads as `unknown`.
17197
17960
  */
17198
17961
  const WIDENING = /* @__PURE__ */ new Set([
17199
- "$ref",
17200
17962
  "$dynamicRef",
17201
17963
  "$recursiveRef",
17202
17964
  "nullable"
17203
17965
  ]);
17966
+ /** The keywords of an object without the keyword `type`. They test only the values that are records. */
17967
+ const OBJECT_KEYS = [
17968
+ "properties",
17969
+ "required",
17970
+ "additionalProperties"
17971
+ ];
17972
+ /** The form of a local reference: a definition in `$defs` or `definitions` of the root schema. */
17973
+ const LOCAL_REF = /^#\/(\$defs|definitions)\/([^/]*)$/;
17974
+ /** The most pairs of members that the meet of two unions builds. A larger meet keeps the first type, which is sound. */
17975
+ const MAX_MEET_PAIRS = 64;
17976
+ /** This function tells if a field of a record type can be absent. */
17977
+ function isOptional(type, key) {
17978
+ return type.optional?.includes(key) === true;
17979
+ }
17980
+ /**
17981
+ * This function gives the meet of two types of a reading: a type that holds each value of both types. A schema is
17982
+ * the conjunction of its keywords, thus its type is the meet of their types. The meet is exact for the forms that a
17983
+ * reading makes: base types, lists, records, unions and `one`. A meet of two different forms is `never`.
17984
+ */
17985
+ function meet(a, b, depth) {
17986
+ if (depth > MAX_SCHEMA_DEPTH) return a;
17987
+ if (isUnknown(a, void 0)) return b;
17988
+ if (isUnknown(b, void 0)) return a;
17989
+ if (a === "never" || b === "never") return "never";
17990
+ if (typeof a !== "string" && "one" in a) return { one: a.one.filter((value) => member(value, b)) };
17991
+ if (typeof b !== "string" && "one" in b) return { one: b.one.filter((value) => member(value, a)) };
17992
+ if (typeof b !== "string" && "union" in b && !(typeof a !== "string" && "union" in a)) return meet(b, a, depth);
17993
+ if (typeof a !== "string" && "union" in a) {
17994
+ const others = typeof b !== "string" && "union" in b ? b.union : [b];
17995
+ if (a.union.length * others.length > MAX_MEET_PAIRS) return a;
17996
+ return unionOf(a.union.flatMap((item) => others.map((other) => meet(item, other, depth + 1))));
17997
+ }
17998
+ if (typeof a === "string" || typeof b === "string") return a === b ? a : "never";
17999
+ if ("list" in a && "list" in b) return { list: meet(a.list, b.list, depth + 1) };
18000
+ if ("record" in a && "record" in b) return meetRecords(a, b, depth + 1);
18001
+ return ("list" in a || "record" in a) && ("list" in b || "record" in b) ? "never" : a;
18002
+ }
18003
+ /**
18004
+ * This function gives the meet of two record types. A field of both records gets the meet of its types, and it is
18005
+ * optional only when both records permit its absence. A closed record has no other field, thus a field of only the
18006
+ * other record is absent. When the other record needs that field, no value fits both records.
18007
+ */
18008
+ function meetRecords(a, b, depth) {
18009
+ const fields = {};
18010
+ const optional = [];
18011
+ const keys = [...Object.keys(a.record), ...Object.keys(b.record).filter((key) => !Object.hasOwn(a.record, key))];
18012
+ for (const key of keys) {
18013
+ const inA = Object.hasOwn(a.record, key);
18014
+ const inB = Object.hasOwn(b.record, key);
18015
+ if (!inA && a.closed === true || !inB && b.closed === true) {
18016
+ if (inA && !isOptional(a, key) || inB && !isOptional(b, key)) return "never";
18017
+ continue;
18018
+ }
18019
+ setOwn(fields, key, inA && inB ? meet(a.record[key], b.record[key], depth) : inA ? a.record[key] : b.record[key]);
18020
+ if ((!inA || isOptional(a, key)) && (!inB || isOptional(b, key))) optional.push(key);
18021
+ }
18022
+ const closed = a.closed === true || b.closed === true;
18023
+ return {
18024
+ record: fields,
18025
+ ...optional.length === 0 ? {} : { optional },
18026
+ ...closed ? { closed: true } : {}
18027
+ };
18028
+ }
18029
+ /** This function applies a condition to a type: each member of the JSON type of the condition meets its type. */
18030
+ function narrow$1(type, condition) {
18031
+ if (typeof type === "string") return type;
18032
+ if ("union" in type) return unionOf(type.union.map((item) => narrow$1(item, condition)));
18033
+ if ("one" in type) return { one: type.one.filter((value) => !(condition.on === "list" ? Array.isArray(value) : isRecord(value)) || member(value, condition.type)) };
18034
+ return condition.on in type ? meet(type, condition.type, 0) : type;
18035
+ }
17204
18036
  /** The base type of each name of the keyword `type`. */
17205
18037
  const BASES = {
17206
18038
  null: "null",
@@ -17223,26 +18055,57 @@ function setOwn(target, key, value) {
17223
18055
  function unionOf(types) {
17224
18056
  return types.reduce((all, type) => join(all, type), "never");
17225
18057
  }
17226
- /** The state of one reading of a schema: the issues that it found. */
18058
+ /** The state of one reading of a schema: the root, the issues and the definitions that it read. */
17227
18059
  var SchemaReader = class {
18060
+ root;
17228
18061
  issues = [];
18062
+ /** The type of each definition that a reference reached. Each reading of a definition is sound, thus the first stays. */
18063
+ defs = /* @__PURE__ */ new Map();
18064
+ /** The definitions that the reading has not finished. A reference to one of them is a cycle. */
18065
+ open = /* @__PURE__ */ new Set();
18066
+ /** The number of schemas with an own `$id` around the current schema. A reference inside them has another base. */
18067
+ inner = 0;
18068
+ constructor(root) {
18069
+ this.root = root;
18070
+ }
17229
18071
  issue(at, reason) {
17230
18072
  this.issues.push({
17231
18073
  at,
17232
18074
  reason
17233
18075
  });
17234
18076
  }
17235
- /** This method reads one schema. */
18077
+ /** This method reads one schema: the meet of the types of its keywords, then its conditions. */
17236
18078
  read(schema, at, depth) {
18079
+ const types = [];
18080
+ const conditions = [];
18081
+ this.parts(schema, at, depth, types, conditions);
18082
+ let type = types.reduce((all, item) => meet(all, item, 0), "unknown");
18083
+ for (const condition of conditions) {
18084
+ if (isUnknown(type, void 0)) {
18085
+ this.issue(condition.at, "The schema has no keyword type. Thus a value of each JSON type fits it, and the type reads it as unknown.");
18086
+ break;
18087
+ }
18088
+ type = narrow$1(type, condition);
18089
+ }
18090
+ return type;
18091
+ }
18092
+ /**
18093
+ * This method adds the type of each keyword of a schema to `types`, and its conditions to `conditions`. Each type
18094
+ * holds each value that the schema accepts. The parts of `allOf` add their keywords too.
18095
+ */
18096
+ parts(schema, at, depth, types, conditions) {
17237
18097
  if (depth > MAX_SCHEMA_DEPTH) {
17238
18098
  this.issue(at, `The schema is deeper than ${MAX_SCHEMA_DEPTH} levels. The type reads it as unknown.`);
17239
- return "unknown";
18099
+ return;
18100
+ }
18101
+ if (schema === true) return;
18102
+ if (schema === false) {
18103
+ types.push("never");
18104
+ return;
17240
18105
  }
17241
- if (schema === true) return "unknown";
17242
- if (schema === false) return "never";
17243
18106
  if (!isRecord(schema)) {
17244
18107
  this.issue(at, "A schema is a record or a truth value. The type reads this value as unknown.");
17245
- return "unknown";
18108
+ return;
17246
18109
  }
17247
18110
  let widens = false;
17248
18111
  for (const key of Object.keys(schema)) {
@@ -17252,46 +18115,99 @@ var SchemaReader = class {
17252
18115
  widens = true;
17253
18116
  } else this.issue([...at, key], `The type does not read the keyword ${key}. It does not test what the keyword tests.`);
17254
18117
  }
17255
- if (widens) return "unknown";
17256
- const sides = [];
17257
- if (Object.hasOwn(schema, "type")) sides.push({
17258
- key: "type",
17259
- type: this.byType(schema, at, depth)
17260
- });
17261
- else if ([
17262
- "properties",
17263
- "required",
17264
- "additionalProperties",
17265
- "items"
17266
- ].some((key) => Object.hasOwn(schema, key)) && ![
17267
- "enum",
17268
- "const",
18118
+ if (widens) return;
18119
+ const nested = schema !== this.root && Object.hasOwn(schema, "$id");
18120
+ if (nested) this.inner += 1;
18121
+ try {
18122
+ this.keywords(schema, at, depth, types, conditions);
18123
+ } finally {
18124
+ if (nested) this.inner -= 1;
18125
+ }
18126
+ }
18127
+ /** This method reads the keywords of a schema that does not permit more values (WIDENING). */
18128
+ keywords(schema, at, depth, types, conditions) {
18129
+ if (Object.hasOwn(schema, "$ref")) {
18130
+ for (const key of Object.keys(schema)) if (READ.has(key) && key !== "$ref") this.issue([...at, key], `The type reads only the target of $ref. It does not test the keyword ${key} beside it.`);
18131
+ const type = this.target(schema["$ref"], [...at, "$ref"], depth);
18132
+ if (type !== void 0) types.push(type);
18133
+ return;
18134
+ }
18135
+ if (Object.hasOwn(schema, "type")) types.push(this.byType(schema, at, depth));
18136
+ else {
18137
+ if (OBJECT_KEYS.some((key) => Object.hasOwn(schema, key))) conditions.push({
18138
+ on: "record",
18139
+ type: this.object(schema, at, depth),
18140
+ at
18141
+ });
18142
+ if (Object.hasOwn(schema, "items")) conditions.push({
18143
+ on: "list",
18144
+ type: this.array(schema, at, depth),
18145
+ at
18146
+ });
18147
+ }
18148
+ for (const key of [
17269
18149
  "anyOf",
17270
- "oneOf"
17271
- ].some((key) => Object.hasOwn(schema, key))) this.issue(at, "The schema has no keyword type. Thus a value of each JSON type fits it, and the type reads it as unknown.");
17272
- for (const key of ["anyOf", "oneOf"]) {
18150
+ "oneOf",
18151
+ "allOf"
18152
+ ]) {
17273
18153
  if (!Object.hasOwn(schema, key)) continue;
17274
18154
  const items = schema[key];
17275
18155
  if (!Array.isArray(items)) {
17276
18156
  this.issue([...at, key], `The value of ${key} is a list of schemas.`);
17277
18157
  continue;
17278
18158
  }
17279
- sides.push({
18159
+ if (key === "allOf") for (const [index, item] of items.entries()) this.parts(item, [
18160
+ ...at,
17280
18161
  key,
17281
- type: unionOf(items.map((item, index) => this.read(item, [
17282
- ...at,
17283
- key,
17284
- index
17285
- ], depth + 1)))
17286
- });
18162
+ index
18163
+ ], depth + 1, types, conditions);
18164
+ else types.push(unionOf(items.map((item, index) => this.read(item, [
18165
+ ...at,
18166
+ key,
18167
+ index
18168
+ ], depth + 1))));
17287
18169
  }
17288
18170
  const values = this.values(schema, at);
17289
- if (values !== void 0) return { one: values.filter((value) => sides.every((side) => member(value, side.type))) };
17290
- const known = sides.filter((side) => !isUnknown(side.type, void 0));
17291
- const kept = known[0];
17292
- if (kept === void 0) return "unknown";
17293
- for (const side of known.slice(1)) this.issue([...at, side.key], `The type reads the keyword ${kept.key}, and not the keyword ${side.key}.`);
17294
- return kept.type;
18171
+ if (values !== void 0) types.push({ one: values });
18172
+ }
18173
+ /** This method reads the target of a reference: a definition of the root schema, or `undefined` for each value. */
18174
+ target(ref, at, depth) {
18175
+ const match = typeof ref === "string" ? LOCAL_REF.exec(ref) : null;
18176
+ let name;
18177
+ try {
18178
+ name = match === null ? void 0 : decodeURIComponent(match[2] ?? "").replace(/~1/g, "/").replace(/~0/g, "~");
18179
+ } catch {
18180
+ name = void 0;
18181
+ }
18182
+ if (match === null || name === void 0) {
18183
+ this.issue(at, "The type reads only a $ref to #/$defs/<name> or #/definitions/<name> of the same schema. Thus it reads the schema as unknown.");
18184
+ return;
18185
+ }
18186
+ if (this.inner > 0) {
18187
+ this.issue(at, "A $ref inside a schema with its own $id has another base. Thus the type reads the schema as unknown.");
18188
+ return;
18189
+ }
18190
+ const group = match[1];
18191
+ const defs = isRecord(this.root) ? this.root[group] : void 0;
18192
+ if (!isRecord(defs) || !Object.hasOwn(defs, name)) {
18193
+ this.issue(at, `The schema has no definition ${String(ref)}. Thus the type reads the reference as unknown.`);
18194
+ return;
18195
+ }
18196
+ const key = `${group}/${name}`;
18197
+ const known = this.defs.get(key);
18198
+ if (known !== void 0) return known;
18199
+ if (this.open.has(key)) {
18200
+ this.issue(at, `The reference ${String(ref)} is in a cycle. The type reads this reference as unknown.`);
18201
+ return;
18202
+ }
18203
+ this.open.add(key);
18204
+ try {
18205
+ const type = this.read(defs[name], [group, name], depth + 1);
18206
+ this.defs.set(key, type);
18207
+ return type;
18208
+ } finally {
18209
+ this.open.delete(key);
18210
+ }
17295
18211
  }
17296
18212
  /** This method reads `enum` and `const`: the values that the schema permits, or `undefined` without them. */
17297
18213
  values(schema, at) {
@@ -17379,17 +18295,20 @@ var SchemaReader = class {
17379
18295
  * - `properties`, `required` and `additionalProperties` give a record. `false` closes it, and a property that is not
17380
18296
  * in `required` is optional.
17381
18297
  * - `items` gives a list. `enum` and `const` give `one`. `anyOf` and `oneOf` give a union.
18298
+ * - `$ref` reads a definition in `$defs` or `definitions` of the same schema (TYPE.SCHEMA-REF). Another reference, a
18299
+ * missing definition and a reference in a cycle read as `unknown`.
18300
+ * - `allOf` and the other keywords of a schema give the meet of their types (TYPE.SCHEMA-ALLOF). Records merge their
18301
+ * fields, and a closed part keeps the merge closed.
17382
18302
  *
17383
18303
  * The type holds each value that the schema accepts. Each keyword that the function does not read tests nothing, as
17384
- * `unknown`, and the issues name it. Examples are `minimum`, `pattern` and `allOf`. A schema with `$ref` or `nullable`
17385
- * reads as `unknown`, because these keywords can permit more values. A schema with more than one of `type`, `anyOf`
17386
- * and `oneOf` gives the type of the first, and an issue for each other. The function does not throw.
18304
+ * `unknown`, and the issues name it. Examples are `minimum` and `pattern`. A schema with `nullable` or `$dynamicRef`
18305
+ * reads as `unknown`, because these keywords can permit more values. The function does not throw.
17387
18306
  *
17388
18307
  * @param schema - The schema, as JSON.
17389
18308
  * @returns The type, and the problems of the reading with their keys in the schema.
17390
18309
  */
17391
18310
  function typeFromSchema(schema) {
17392
- const reader = new SchemaReader();
18311
+ const reader = new SchemaReader(schema);
17393
18312
  try {
17394
18313
  return {
17395
18314
  type: reader.read(schema, [], 0),
@@ -17469,6 +18388,6 @@ function samplesAt(values, closed, depth) {
17469
18388
  function typeFromSamples(values, options = {}) {
17470
18389
  return samplesAt(values, options.closed === true, 0);
17471
18390
  }
17472
- export { ATTRIBUTE_RUNGS, CAPS_TYPE, CIRCULAR_LIMIT, CONSTRUCTS, ENVELOPE_KEYS, Failure, Held, JOURNAL, MergeError, PARTS, PART_INFO, ROOTS, RUNGS, STD_CAPS, STD_DEFINITIONS, STD_DOMAINS, STD_EVALUATORS, STD_EXT, STD_MACHINE, STD_RUNNERS, STD_SYNTAX, STD_WALKERS, STD_WORLD, THING, WORLD_SYNTAX, agree, agreeRun, agreeSchedule, ask, attributeGraph, attributeTrace, attributeVertexId, capKeys, check, checkLatent, checkStep, checkSteps, checkWorld, circularOf, classify, components, conforms, context, cycles, dataEdges, decodeDomain, decodeLog, decodeValue, derefStep, describe, docEquals, durable, edgesOf, effectEdges, effectsOf, effectsOfVerb, encodeLog, encodeValue, entriesAsJson, equationType, evaluate, extendDomain, factsOf, fail, failures, field, fits, flatten, formulaDefinitions, formulaEvaluators, formulaFacts, formulaKinds, formulaKnown, formulaMachine, fromJson, generate, heights, intersectCaps, isAlias, isAllowedOrder, isClosure, isEnvelope, isHostThing, isKey, isKind, isNamespace, isRecord, isRef, isStackOverflow, isStep, isTypeRef, join, jsTruthy, kindDocument, kindNamed, kindOf, layers, looksLikeKind, lookupKind, makeContext, mapRefs, member, mergeMachines, mergeWorlds, narrow, nearestWalker, necessary, nodeAt, nodeLayers, ok, parse, partCaps, partsOf, pathMatches, permits, placeOf, placed, planner, prepare, print, printReads, random, recorder, ref, reference, referenceRun, refsOf, replayer, resolve, restrictMachine, restrictWorld, run, sameResult, sameValue, schedule, splitParts, stepLadder, stepOf, stepRank, stored, syntaxFormat, tag, thrown, toJson, treeNodeEvaluator, typeCheck, typeFromSamples, typeFromSchema, typeIssues, typeName, typePath, typeText, typed, typesOf, valueOfThing, verifyReads, walk, worldThing };
18391
+ export { ATTRIBUTE_RUNGS, CAPS_TYPE, CIRCULAR_LIMIT, CONSTRUCTS, ENVELOPE_KEYS, Failure, Held, JOURNAL, MergeError, PARTS, PART_INFO, ROOTS, RUNGS, STD_CAPS, STD_DEFINITIONS, STD_DOMAINS, STD_EVALUATORS, STD_EXT, STD_MACHINE, STD_RUNNERS, STD_SYNTAX, STD_WALKERS, STD_WORLD, THING, WORLD_SYNTAX, agree, agreeRun, agreeSchedule, argsKey, ask, atArgsOf, atRuleOf, attributeGraph, attributeTrace, attributeVertexId, capKeys, check, checkLatent, checkStep, checkSteps, checkWorld, circularOf, classify, collectOf, components, conforms, context, cycles, dataEdges, decodeDomain, decodeLog, decodeValue, derefStep, describe, docEquals, durable, edgesOf, effectEdges, effectsOf, effectsOfVerb, encodeLog, encodeValue, entriesAsJson, equationType, evaluate, extendDomain, factsOf, fail, failures, field, fits, flatten, formulaDefinitions, formulaEvaluators, formulaFacts, formulaKinds, formulaKnown, formulaMachine, fromJson, generate, heights, intersectCaps, isAlias, isAllowedOrder, isClosure, isEnvelope, isHostThing, isKey, isKind, isNamespace, isRecord, isRef, isStackOverflow, isStep, isTypeRef, join, jsTruthy, kindDocument, kindNamed, kindOf, layers, looksLikeKind, lookupKind, makeContext, mapRefs, member, mergeMachines, mergeWorlds, narrow, nearestWalker, necessary, nodeAt, nodeLayers, ok, parse, partCaps, partsOf, pathMatches, permits, placeOf, placed, planner, prepare, print, printReads, random, recorder, ref, reference, referenceRun, refsOf, replayer, resolve, restrictMachine, restrictWorld, run, sameResult, sameValue, schedule, splitParts, stepLadder, stepOf, stepRank, stored, syntaxFormat, tag, thrown, toJson, treeNodeEvaluator, typeCheck, typeFromSamples, typeFromSchema, typeIssues, typeName, typePath, typeText, typed, typesOf, valueOfThing, verifyReads, walk, worldThing };
17473
18392
 
17474
18393
  //# sourceMappingURL=index.js.map