@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.d.ts +379 -236
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1017 -98
- package/build/index.js.map +1 -1
- package/package.json +1 -1
- package/src/conform.ts +13 -4
- package/src/deref.ts +32 -2
- package/src/effects.ts +4 -2
- package/src/evaluate.ts +2 -0
- package/src/facts.ts +3 -2
- package/src/formula.ts +53 -10
- package/src/index.ts +10 -0
- package/src/instances.ts +94 -5
- package/src/parts.ts +30 -1
- package/src/providers.ts +209 -29
- package/src/reference.ts +119 -9
- package/src/static.ts +144 -23
- package/src/stdlib.ts +189 -2
- package/src/types.ts +12 -4
- package/src/world.ts +135 -1
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
|
|
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 = {
|
|
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?.
|
|
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
|
|
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
|
|
8741
|
-
*
|
|
8742
|
-
*
|
|
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
|
-
* @
|
|
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
|
|
8749
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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))
|
|
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(
|
|
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
|
|
10615
|
-
|
|
10616
|
-
|
|
10617
|
-
|
|
10618
|
-
names
|
|
10619
|
-
|
|
10620
|
-
|
|
10621
|
-
|
|
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
|
-
|
|
13021
|
-
|
|
13022
|
-
|
|
13023
|
-
|
|
13024
|
-
|
|
13025
|
-
names
|
|
13026
|
-
|
|
13027
|
-
|
|
13028
|
-
|
|
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 (
|
|
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.
|
|
17196
|
-
*
|
|
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
|
|
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
|
|
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
|
|
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
|
|
17256
|
-
const
|
|
17257
|
-
if (
|
|
17258
|
-
|
|
17259
|
-
|
|
17260
|
-
}
|
|
17261
|
-
|
|
17262
|
-
|
|
17263
|
-
|
|
17264
|
-
|
|
17265
|
-
|
|
17266
|
-
|
|
17267
|
-
"
|
|
17268
|
-
|
|
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
|
-
|
|
17272
|
-
|
|
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
|
-
|
|
18159
|
+
if (key === "allOf") for (const [index, item] of items.entries()) this.parts(item, [
|
|
18160
|
+
...at,
|
|
17280
18161
|
key,
|
|
17281
|
-
|
|
17282
|
-
|
|
17283
|
-
|
|
17284
|
-
|
|
17285
|
-
|
|
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)
|
|
17290
|
-
|
|
17291
|
-
|
|
17292
|
-
|
|
17293
|
-
|
|
17294
|
-
|
|
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
|
|
17385
|
-
* reads as `unknown`, because these keywords can permit more values.
|
|
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
|