@mark1russell7/coeval 0.20.0 → 0.21.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/README.md +1 -0
- package/build/index.d.ts +420 -236
- package/build/index.d.ts.map +1 -1
- package/build/index.js +746 -76
- 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 +31 -5
- package/src/index.ts +5 -0
- package/src/instances.ts +50 -1
- package/src/parts.ts +30 -1
- package/src/providers.ts +209 -29
- package/src/reference.ts +52 -2
- package/src/static.ts +79 -19
- package/src/stdlib.ts +88 -2
- package/src/steps.ts +181 -0
- package/src/types.ts +12 -4
- package/src/world.ts +50 -0
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,26 @@ 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
|
+
/**
|
|
406
431
|
* 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
432
|
* else the type `of` of the shape `rest` of a record. The plan, the reference and `check` read it with this one function.
|
|
408
433
|
*
|
|
@@ -1584,8 +1609,10 @@ function valueStep(value, key) {
|
|
|
1584
1609
|
*
|
|
1585
1610
|
* - A record gives the type of its field. A closed record without the field has no such step. An open record gives
|
|
1586
1611
|
* `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`).
|
|
1612
|
+
* - A list gives the type of its items for an index, and `number` for `length`. Another key has no such step.
|
|
1613
|
+
* - A base type reads the steps of its domain, then of each parent (`Domain.steps`). A base type of the kernel
|
|
1614
|
+
* without such a step has no step, because its values are not objects (TYPE.NO-STEP, D120).
|
|
1615
|
+
* - A function type has no step, because a step into a function reaches nothing.
|
|
1589
1616
|
* - A union joins the steps of its types. `one` gives the values that the step reaches.
|
|
1590
1617
|
* - Each other step gives `unknown`, and `never` gives `never`.
|
|
1591
1618
|
*
|
|
@@ -1604,10 +1631,11 @@ function stepType(type, key, domains, examine, depth = 0) {
|
|
|
1604
1631
|
const found = steps[name];
|
|
1605
1632
|
return { type: examine === void 0 ? found : examine(found, `type of the step ${name} of the domain ${each}`) };
|
|
1606
1633
|
}
|
|
1607
|
-
return { type: "unknown" };
|
|
1634
|
+
return Object.hasOwn(STD_DOMAINS, form.name) ? NO_STEP : { type: "unknown" };
|
|
1635
|
+
case "fn": return NO_STEP;
|
|
1608
1636
|
case "list":
|
|
1609
1637
|
if (key === "length") return { type: "number" };
|
|
1610
|
-
return
|
|
1638
|
+
return indexOf(key) >= 0 ? { type: form.item } : NO_STEP;
|
|
1611
1639
|
case "record":
|
|
1612
1640
|
if (Object.hasOwn(form.fields, name)) return { type: form.fields[name] };
|
|
1613
1641
|
return form.closed ? { missing: Object.keys(form.fields) } : { type: "unknown" };
|
|
@@ -1634,6 +1662,8 @@ function stepType(type, key, domains, examine, depth = 0) {
|
|
|
1634
1662
|
default: return { type: "unknown" };
|
|
1635
1663
|
}
|
|
1636
1664
|
}
|
|
1665
|
+
/** The answer of `stepType` for a type whose members have no step with the key, and no fields to name. */
|
|
1666
|
+
const NO_STEP = { missing: [] };
|
|
1637
1667
|
/**
|
|
1638
1668
|
* This function lists the problems of a value type (TYPE.ISSUES). A problem is a term that is not a value type, a
|
|
1639
1669
|
* base type without a domain, or a term that is too deep. `fits` and `member` read each such term as `unknown`.
|
|
@@ -2436,6 +2466,143 @@ function ask(world, doc, verb, options = {}) {
|
|
|
2436
2466
|
steps
|
|
2437
2467
|
};
|
|
2438
2468
|
}
|
|
2469
|
+
// src/steps.ts
|
|
2470
|
+
/**
|
|
2471
|
+
* This function makes a ladder of steps, and it checks the declaration (STEPS.LADDER). The list of steps must have one
|
|
2472
|
+
* step or more, with no name two times. The step of each construct must be a step of the list.
|
|
2473
|
+
*
|
|
2474
|
+
* @param steps - The names of the steps, from the lowest to the highest.
|
|
2475
|
+
* @param constructs - The step that each construct needs.
|
|
2476
|
+
* @returns The ladder, frozen.
|
|
2477
|
+
* @throws TypeError for a declaration that is not valid, because it is a defect of the language.
|
|
2478
|
+
*/
|
|
2479
|
+
function stepLadder(steps, constructs) {
|
|
2480
|
+
if (steps.length === 0) throw new TypeError("a ladder of steps needs one step or more");
|
|
2481
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2482
|
+
for (const step of steps) {
|
|
2483
|
+
if (typeof step !== "string") throw new TypeError(`the step ${String(step)} is not a name`);
|
|
2484
|
+
if (seen.has(step)) throw new TypeError(`the step "${step}" is in the ladder two times`);
|
|
2485
|
+
seen.add(step);
|
|
2486
|
+
}
|
|
2487
|
+
for (const [construct, step] of Object.entries(constructs)) if (!seen.has(step)) throw new TypeError(`the construct "${construct}" needs the step "${String(step)}", which is not a step of the ladder`);
|
|
2488
|
+
return Object.freeze({
|
|
2489
|
+
steps: Object.freeze([...steps]),
|
|
2490
|
+
constructs: Object.freeze({ ...constructs })
|
|
2491
|
+
});
|
|
2492
|
+
}
|
|
2493
|
+
/**
|
|
2494
|
+
* This function tells if a value is a step of a ladder. A host uses it to check its option for the highest step.
|
|
2495
|
+
*
|
|
2496
|
+
* @param ladder - The ladder.
|
|
2497
|
+
* @param value - The value.
|
|
2498
|
+
* @returns `true` when the value is the name of a step of the ladder.
|
|
2499
|
+
*/
|
|
2500
|
+
function isStep(ladder, value) {
|
|
2501
|
+
return typeof value === "string" && ladder.steps.includes(value);
|
|
2502
|
+
}
|
|
2503
|
+
/**
|
|
2504
|
+
* This function gives the position of a step in its ladder. The lowest step has the position 0.
|
|
2505
|
+
*
|
|
2506
|
+
* @param ladder - The ladder.
|
|
2507
|
+
* @param step - The step.
|
|
2508
|
+
* @returns The position.
|
|
2509
|
+
* @throws TypeError for a name that is not a step of the ladder.
|
|
2510
|
+
*/
|
|
2511
|
+
function stepRank(ladder, step) {
|
|
2512
|
+
const rank = ladder.steps.indexOf(step);
|
|
2513
|
+
if (rank < 0) throw new TypeError(`"${String(step)}" is not a step of the ladder. The steps are ${ladder.steps.join(", ")}`);
|
|
2514
|
+
return rank;
|
|
2515
|
+
}
|
|
2516
|
+
function pathOf(visit) {
|
|
2517
|
+
const path = [];
|
|
2518
|
+
for (let v = visit; v?.key !== void 0; v = v.parent) path.push(v.key);
|
|
2519
|
+
return path.reverse();
|
|
2520
|
+
}
|
|
2521
|
+
/**
|
|
2522
|
+
* This function gives the lowest step that a document needs, with the reason (STEPS.LOWEST, STEPS.REASON). The step is
|
|
2523
|
+
* the highest step of the constructs of its nodes. The reason is the first node in document order with that step. The
|
|
2524
|
+
* walk uses its own stack, thus a deep document does not overflow (STEPS.LINEAR). It visits a shared node one time,
|
|
2525
|
+
* and it stops at the first node with the highest step of the ladder.
|
|
2526
|
+
*
|
|
2527
|
+
* @param ladder - The ladder of the language.
|
|
2528
|
+
* @param walk - The construct and the child nodes of a node.
|
|
2529
|
+
* @param root - The root node of the document.
|
|
2530
|
+
* @returns The step, and the reason when the step is not the lowest step.
|
|
2531
|
+
*/
|
|
2532
|
+
function stepOf(ladder, walk, root) {
|
|
2533
|
+
const top = ladder.steps.length - 1;
|
|
2534
|
+
let best = 0;
|
|
2535
|
+
let reason;
|
|
2536
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2537
|
+
const todo = [{
|
|
2538
|
+
node: root,
|
|
2539
|
+
key: void 0,
|
|
2540
|
+
parent: void 0
|
|
2541
|
+
}];
|
|
2542
|
+
for (let visit = todo.pop(); visit !== void 0; visit = todo.pop()) {
|
|
2543
|
+
const { node } = visit;
|
|
2544
|
+
if (typeof node === "object" && node !== null) {
|
|
2545
|
+
if (seen.has(node)) continue;
|
|
2546
|
+
seen.add(node);
|
|
2547
|
+
}
|
|
2548
|
+
const construct = walk.construct(node);
|
|
2549
|
+
const step = construct === void 0 || !Object.hasOwn(ladder.constructs, construct) ? void 0 : ladder.constructs[construct];
|
|
2550
|
+
const rank = step === void 0 ? 0 : ladder.steps.indexOf(step);
|
|
2551
|
+
if (rank > best) {
|
|
2552
|
+
best = rank;
|
|
2553
|
+
reason = {
|
|
2554
|
+
construct,
|
|
2555
|
+
step,
|
|
2556
|
+
path: pathOf(visit),
|
|
2557
|
+
node
|
|
2558
|
+
};
|
|
2559
|
+
if (best === top) break;
|
|
2560
|
+
}
|
|
2561
|
+
const kids = [...walk.children(node)];
|
|
2562
|
+
for (let i = kids.length - 1; i >= 0; i--) {
|
|
2563
|
+
const [key, child] = kids[i];
|
|
2564
|
+
todo.push({
|
|
2565
|
+
node: child,
|
|
2566
|
+
key,
|
|
2567
|
+
parent: visit
|
|
2568
|
+
});
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2571
|
+
const step = ladder.steps[best];
|
|
2572
|
+
return reason === void 0 ? { step } : {
|
|
2573
|
+
step,
|
|
2574
|
+
reason
|
|
2575
|
+
};
|
|
2576
|
+
}
|
|
2577
|
+
/**
|
|
2578
|
+
* This function compares the step of a document with the highest step that the host accepts (STEPS.MAX). The limit
|
|
2579
|
+
* changes only which documents the host accepts. The language evaluates an accepted document as before, thus a limit
|
|
2580
|
+
* does not change a value.
|
|
2581
|
+
*
|
|
2582
|
+
* @param ladder - The ladder of the language.
|
|
2583
|
+
* @param need - The step of the document, from `stepOf`.
|
|
2584
|
+
* @param maxStep - The highest step that the host accepts.
|
|
2585
|
+
* @returns `undefined` when the host accepts the document, or the refusal that names the needed step.
|
|
2586
|
+
* @throws TypeError when `maxStep` or the step of `need` is not a step of the ladder.
|
|
2587
|
+
*/
|
|
2588
|
+
function checkStep(ladder, need, maxStep) {
|
|
2589
|
+
const limit = stepRank(ladder, maxStep);
|
|
2590
|
+
if (stepRank(ladder, need.step) <= limit) return void 0;
|
|
2591
|
+
const head = `the document needs the step ${need.step}, and the host accepts the steps up to ${maxStep}`;
|
|
2592
|
+
const reason = need.reason;
|
|
2593
|
+
if (reason === void 0) return {
|
|
2594
|
+
needed: need.step,
|
|
2595
|
+
maxStep,
|
|
2596
|
+
message: head
|
|
2597
|
+
};
|
|
2598
|
+
const where = reason.path.length === 0 ? "at the root" : `at the path ${JSON.stringify(reason.path)}`;
|
|
2599
|
+
return {
|
|
2600
|
+
needed: need.step,
|
|
2601
|
+
maxStep,
|
|
2602
|
+
reason,
|
|
2603
|
+
message: `${head}. The construct "${reason.construct}" ${where} needs the step ${reason.step}`
|
|
2604
|
+
};
|
|
2605
|
+
}
|
|
2439
2606
|
// src/deref.ts
|
|
2440
2607
|
/**
|
|
2441
2608
|
* The brand of a host thing: an object of the host that answers the steps of a path itself. The brand is a
|
|
@@ -3283,6 +3450,34 @@ function pathMatches(path, pattern) {
|
|
|
3283
3450
|
}
|
|
3284
3451
|
return true;
|
|
3285
3452
|
}
|
|
3453
|
+
/**
|
|
3454
|
+
* This function tells if a list of rules in the form of the lazy rules covers a part (D24, D119). A rule without
|
|
3455
|
+
* `in` covers each part. With `after: n`, a rule covers only the parts after the first `n` parts that it matches.
|
|
3456
|
+
*
|
|
3457
|
+
* @param rules - The rules.
|
|
3458
|
+
* @param shape - The shape of the parts of the parent.
|
|
3459
|
+
* @param value - The value of the parent.
|
|
3460
|
+
* @param slot - The path of the part in the value.
|
|
3461
|
+
* @returns `true` when a rule covers the part.
|
|
3462
|
+
*/
|
|
3463
|
+
function rulesCover(rules, shape, value, slot) {
|
|
3464
|
+
for (const rule of rules) {
|
|
3465
|
+
if (rule.in !== void 0 && !rule.in.some((pattern) => pathMatches(slot, pattern))) continue;
|
|
3466
|
+
const after = rule.after ?? 0;
|
|
3467
|
+
if (after <= 0) return true;
|
|
3468
|
+
const split = splitParts(shape, value);
|
|
3469
|
+
let count = 0;
|
|
3470
|
+
for (const part of split.ok ? split.parts : []) {
|
|
3471
|
+
if (rule.in !== void 0 && !rule.in.some((pattern) => pathMatches(part.path, pattern))) continue;
|
|
3472
|
+
if (part.path.length === slot.length && pathMatches(part.path, slot)) {
|
|
3473
|
+
if (count >= after) return true;
|
|
3474
|
+
break;
|
|
3475
|
+
}
|
|
3476
|
+
count += 1;
|
|
3477
|
+
}
|
|
3478
|
+
}
|
|
3479
|
+
return false;
|
|
3480
|
+
}
|
|
3286
3481
|
function valueAt(value, path) {
|
|
3287
3482
|
let here = value;
|
|
3288
3483
|
for (const key of path) if (Array.isArray(here)) here = here[Number(key)];
|
|
@@ -4446,6 +4641,7 @@ function pureCode(c, envelope, kind, typePath, name, quick) {
|
|
|
4446
4641
|
} catch {
|
|
4447
4642
|
return false;
|
|
4448
4643
|
}
|
|
4644
|
+
if (answer?.effects !== void 0 && answer.effects.length > 0) return false;
|
|
4449
4645
|
const described = c.verb === "eval" && (envelope === void 0 || quick?.rung !== "own" || name === answerOf(c.machine.world, void 0, kind, c.verb)?.name);
|
|
4450
4646
|
const pure = described ? answer?.pure ?? kind.pure : answer?.pure;
|
|
4451
4647
|
const volatile = described ? answer?.volatile ?? kind.volatile : answer?.volatile;
|
|
@@ -5288,6 +5484,14 @@ const STD_WORLD = {
|
|
|
5288
5484
|
pure: true,
|
|
5289
5485
|
summary: "A step of a path: it follows a key again and again, until it reaches a node of a type."
|
|
5290
5486
|
},
|
|
5487
|
+
tree: { kinds: { named: {
|
|
5488
|
+
verbs: {
|
|
5489
|
+
step: "walk.named",
|
|
5490
|
+
view: "view.card"
|
|
5491
|
+
},
|
|
5492
|
+
pure: true,
|
|
5493
|
+
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)."
|
|
5494
|
+
} } },
|
|
5291
5495
|
panel: {
|
|
5292
5496
|
verbs: {
|
|
5293
5497
|
eval: "tree.node",
|
|
@@ -5527,6 +5731,12 @@ const WORLD_SYNTAX = /* @__PURE__ */ Object.freeze({
|
|
|
5527
5731
|
"self"
|
|
5528
5732
|
]
|
|
5529
5733
|
},
|
|
5734
|
+
{
|
|
5735
|
+
name: "tree.named",
|
|
5736
|
+
kind: "tree.named",
|
|
5737
|
+
args: "named",
|
|
5738
|
+
fields: ["name", "in"]
|
|
5739
|
+
},
|
|
5530
5740
|
{
|
|
5531
5741
|
name: "add",
|
|
5532
5742
|
kind: "add"
|
|
@@ -6066,6 +6276,58 @@ function plainOf(value, path) {
|
|
|
6066
6276
|
}
|
|
6067
6277
|
}
|
|
6068
6278
|
/**
|
|
6279
|
+
* This function gives the collection of an attribute of a node (TREE.COLLECT, D122). It visits the node, then each node
|
|
6280
|
+
* of the same tree in each list `children`, in the order of the lists. Each node is visited one time.
|
|
6281
|
+
* The registry of names (TREE.NAMED) gives a record from each binding name to its node.
|
|
6282
|
+
*/
|
|
6283
|
+
function collected(root, key, declared) {
|
|
6284
|
+
const top = stateOf(root);
|
|
6285
|
+
const rule = collectOf(declared);
|
|
6286
|
+
if (!rule.ok) return fail("#VALUE!", `The attribute ${attributeText(key, top.type, top.place)} has a bad declaration collect. ${rule.reason}`);
|
|
6287
|
+
const registry = {};
|
|
6288
|
+
const owners = /* @__PURE__ */ new Map();
|
|
6289
|
+
let acc = rule.names ? ok(registry) : top.equation(rule.unit, NO_NAMES$1);
|
|
6290
|
+
if (!acc.ok) return acc;
|
|
6291
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6292
|
+
const stack = [root];
|
|
6293
|
+
while (stack.length > 0) {
|
|
6294
|
+
const thing = stack.pop();
|
|
6295
|
+
const at = stateOf(thing);
|
|
6296
|
+
if (at === void 0 || at.build !== top.build || seen.has(at)) continue;
|
|
6297
|
+
seen.add(at);
|
|
6298
|
+
if (rule.names) {
|
|
6299
|
+
const name = at.name;
|
|
6300
|
+
const earlier = name === void 0 ? void 0 : owners.get(name);
|
|
6301
|
+
if (earlier !== void 0) {
|
|
6302
|
+
const both = `${earlier.type} at [${earlier.place.join(", ")}] and ${at.type} at [${at.place.join(", ")}]`;
|
|
6303
|
+
return fail("#VALUE!", `Two nodes have the name ${name} in the registry ${attributeText(key, top.type, top.place)}: ${both}.`);
|
|
6304
|
+
}
|
|
6305
|
+
if (name !== void 0) {
|
|
6306
|
+
owners.set(name, at);
|
|
6307
|
+
putField(registry, name, thing);
|
|
6308
|
+
}
|
|
6309
|
+
} else {
|
|
6310
|
+
const term = entryOf(at.tree?.contributes, key);
|
|
6311
|
+
if (term !== void 0) {
|
|
6312
|
+
const item = at.equation(term, NO_NAMES$1);
|
|
6313
|
+
if (!item.ok) return item;
|
|
6314
|
+
acc = top.equation(rule.combine, {
|
|
6315
|
+
acc: acc.value,
|
|
6316
|
+
item: item.value
|
|
6317
|
+
});
|
|
6318
|
+
if (!acc.ok) return acc;
|
|
6319
|
+
}
|
|
6320
|
+
}
|
|
6321
|
+
const children = at.read("children");
|
|
6322
|
+
if (children === void 0) continue;
|
|
6323
|
+
if (!children.ok) return children;
|
|
6324
|
+
if (!Array.isArray(children.value)) return fail("#VALUE!", `The collection of ${key} needs a list in children of ${at.type} at [${at.place.join(", ")}].`);
|
|
6325
|
+
const list = children.value;
|
|
6326
|
+
for (let index = list.length - 1; index >= 0; index -= 1) stack.push(list[index]);
|
|
6327
|
+
}
|
|
6328
|
+
return acc;
|
|
6329
|
+
}
|
|
6330
|
+
/**
|
|
6069
6331
|
* This function makes a node of the decorated tree. A step `parent` gives the self of the context of the node, and a
|
|
6070
6332
|
* step `type` gives its type. Another step reads an attribute through its ladder (TREE.LADDER). The rungs are a part of
|
|
6071
6333
|
* the node, an equation of its kind and an equation `down` of the kind of its parent. A copy from the parent, then a
|
|
@@ -6142,6 +6404,10 @@ function treeThing(input, place, build, outer, host) {
|
|
|
6142
6404
|
result: fold(key, declared.fold),
|
|
6143
6405
|
by: "default"
|
|
6144
6406
|
};
|
|
6407
|
+
if (declared?.collect !== void 0) return {
|
|
6408
|
+
result: collected(node, key, declared.collect),
|
|
6409
|
+
by: "default"
|
|
6410
|
+
};
|
|
6145
6411
|
if (declared?.default !== void 0) return {
|
|
6146
6412
|
result: state.equation(declared.default, NO_NAMES$1),
|
|
6147
6413
|
by: "default"
|
|
@@ -6220,6 +6486,7 @@ function treeThing(input, place, build, outer, host) {
|
|
|
6220
6486
|
};
|
|
6221
6487
|
const state = {
|
|
6222
6488
|
build,
|
|
6489
|
+
name: input.doc.name,
|
|
6223
6490
|
type,
|
|
6224
6491
|
place,
|
|
6225
6492
|
tree,
|
|
@@ -6401,8 +6668,45 @@ function nearestWalker(options = {}) {
|
|
|
6401
6668
|
};
|
|
6402
6669
|
};
|
|
6403
6670
|
}
|
|
6671
|
+
const nearest = /* @__PURE__ */ nearestWalker();
|
|
6672
|
+
/**
|
|
6673
|
+
* The walker of the step `tree.named` (TREE.NAMED, D122). It goes up from the thing before the step through the key
|
|
6674
|
+
* `parent`, to the first thing that answers the registry. The field `in` names the registry, and the default is
|
|
6675
|
+
* `names`. The walker gives the node with the field `name` in that registry.
|
|
6676
|
+
*/
|
|
6677
|
+
const named$2 = ({ data, here, deref }) => {
|
|
6678
|
+
const name = isRecord(data) ? field(data, "name") : void 0;
|
|
6679
|
+
if (typeof name !== "string") return {
|
|
6680
|
+
ok: false,
|
|
6681
|
+
code: "#VALUE!",
|
|
6682
|
+
reason: "The step tree.named needs a text name."
|
|
6683
|
+
};
|
|
6684
|
+
const registry = isRecord(data) && typeof field(data, "in") === "string" ? String(field(data, "in")) : "names";
|
|
6685
|
+
let at = here;
|
|
6686
|
+
for (let hops = 0; hops < 256 && at !== void 0 && at !== null; hops += 1) {
|
|
6687
|
+
const found = deref(at, registry);
|
|
6688
|
+
if (found !== void 0) {
|
|
6689
|
+
if (!isRecord(found) || !Object.hasOwn(found, name)) return {
|
|
6690
|
+
ok: false,
|
|
6691
|
+
reason: `The registry ${registry} has no node with the name ${name}.`
|
|
6692
|
+
};
|
|
6693
|
+
return {
|
|
6694
|
+
ok: true,
|
|
6695
|
+
thing: field(found, name)
|
|
6696
|
+
};
|
|
6697
|
+
}
|
|
6698
|
+
at = deref(at, "parent");
|
|
6699
|
+
}
|
|
6700
|
+
return {
|
|
6701
|
+
ok: false,
|
|
6702
|
+
reason: `No registry ${registry} is on the way.`
|
|
6703
|
+
};
|
|
6704
|
+
};
|
|
6404
6705
|
/** The walkers of the standard world, by name. */
|
|
6405
|
-
const STD_WALKERS = {
|
|
6706
|
+
const STD_WALKERS = {
|
|
6707
|
+
"walk.nearest": nearest,
|
|
6708
|
+
"walk.named": named$2
|
|
6709
|
+
};
|
|
6406
6710
|
/** This function evaluates parts one after the other, and stops at the first error. */
|
|
6407
6711
|
function* inOrder(parts) {
|
|
6408
6712
|
const values = [];
|
|
@@ -7387,7 +7691,7 @@ function factsOf(machine, doc, options = {}) {
|
|
|
7387
7691
|
at: tight(place.at)
|
|
7388
7692
|
});
|
|
7389
7693
|
}
|
|
7390
|
-
const declared = declaredEffects(v, verb);
|
|
7694
|
+
const declared = verb === "eval" && answer?.effects !== void 0 ? effectKeys(v, answer.effects) : declaredEffects(v, verb);
|
|
7391
7695
|
if (verb === "eval" ? kind.side === "run" : declared.length > 0) {
|
|
7392
7696
|
if (node === void 0) side = "run";
|
|
7393
7697
|
else pure = false;
|
|
@@ -8108,8 +8412,57 @@ function rungReads(b, id) {
|
|
|
8108
8412
|
});
|
|
8109
8413
|
return;
|
|
8110
8414
|
}
|
|
8415
|
+
const collect = declared?.collect === void 0 ? void 0 : collectOf(declared.collect);
|
|
8416
|
+
if (collect?.ok === true) {
|
|
8417
|
+
collectReads(b, node, key, collect, later);
|
|
8418
|
+
return;
|
|
8419
|
+
}
|
|
8111
8420
|
if (declared?.default !== void 0) termReads(b, termRefs(b, node.kind, `tree.attributes.${key}.default`, declared.default), node, void 0, later);
|
|
8112
8421
|
}
|
|
8422
|
+
/** This function gives the list children of a node before the run. A node without a rung for it has no children. */
|
|
8423
|
+
function childrenOf(b, at) {
|
|
8424
|
+
const part = at.parts.get("children");
|
|
8425
|
+
if (part !== void 0) return valueOf$1(part);
|
|
8426
|
+
const tree = at.kind.tree;
|
|
8427
|
+
if (hasOwnEntry(tree?.equations, "children") || hasOwnEntry(tree?.attributes, "children")) return "unknown";
|
|
8428
|
+
if (at.up === void 0) return downNames(b.machine.world).has("children") ? "unknown" : "data";
|
|
8429
|
+
return at.up !== null && hasOwnEntry(at.up.kind.tree?.down, "children") ? "unknown" : "data";
|
|
8430
|
+
}
|
|
8431
|
+
/**
|
|
8432
|
+
* This function adds the reads of a collection (TREE.COLLECT, D122), in the order of the run. Each node of the subtree
|
|
8433
|
+
* gives the reads of its contribution and of its list `children`. A list that only the run knows gives an edge with an
|
|
8434
|
+
* unknown source. The registry of names reads only the lists `children`.
|
|
8435
|
+
*/
|
|
8436
|
+
function collectReads(b, node, key, rule, later) {
|
|
8437
|
+
if (!rule.names) termReads(b, termRefs(b, node.kind, `tree.attributes.${key}.collect.unit`, rule.unit), node, void 0, later);
|
|
8438
|
+
let combined = false;
|
|
8439
|
+
const done = /* @__PURE__ */ new Set();
|
|
8440
|
+
const stack = [node];
|
|
8441
|
+
while (stack.length > 0) {
|
|
8442
|
+
const at = stack.pop();
|
|
8443
|
+
if (done.has(at)) continue;
|
|
8444
|
+
done.add(at);
|
|
8445
|
+
const term = rule.names || !hasOwnEntry(at.kind.tree?.contributes, key) ? void 0 : at.kind.tree?.contributes?.[key];
|
|
8446
|
+
if (term !== void 0) {
|
|
8447
|
+
termReads(b, termRefs(b, at.kind, `tree.contributes.${key}`, term), at, void 0, later);
|
|
8448
|
+
combined = true;
|
|
8449
|
+
}
|
|
8450
|
+
edge(b, vertexOf(b, at, "children"), later);
|
|
8451
|
+
const children = childrenOf(b, at);
|
|
8452
|
+
if (children === "unknown") edge(b, void 0, later);
|
|
8453
|
+
else if (typeof children === "object" && "list" in children) {
|
|
8454
|
+
const items = itemsOf(children.list);
|
|
8455
|
+
for (let index = items.length - 1; index >= 0; index -= 1) {
|
|
8456
|
+
const child = items[index]?.node;
|
|
8457
|
+
if (child !== void 0 && child.up === at) stack.push(child);
|
|
8458
|
+
}
|
|
8459
|
+
}
|
|
8460
|
+
}
|
|
8461
|
+
if (!rule.names) termReads(b, termRefs(b, node.kind, `tree.attributes.${key}.collect.combine`, rule.combine), node, void 0, combined ? later : {
|
|
8462
|
+
...later,
|
|
8463
|
+
lazy: true
|
|
8464
|
+
});
|
|
8465
|
+
}
|
|
8113
8466
|
function build(machine, doc, declaredType) {
|
|
8114
8467
|
const b = {
|
|
8115
8468
|
machine,
|
|
@@ -8595,21 +8948,56 @@ function mapRefs(world, doc, change, options = {}) {
|
|
|
8595
8948
|
}
|
|
8596
8949
|
return out;
|
|
8597
8950
|
}
|
|
8951
|
+
/**
|
|
8952
|
+
* This function gives the parts that the code of a runner evaluates itself, without a wait (RUN.DRIVES, D119). The
|
|
8953
|
+
* answer of the hook `facts` for the code wins over the contract. The contract describes only the code of its kind for
|
|
8954
|
+
* `eval`. Without a declaration, the runner passes each wait of its parts through.
|
|
8955
|
+
*/
|
|
8956
|
+
function driveRules(machine, v, kind, name, rung, verb) {
|
|
8957
|
+
if (verb !== "eval") return void 0;
|
|
8958
|
+
const hook = machine.facts?.(v.typePath ?? [], name)?.drives;
|
|
8959
|
+
if (hook !== void 0) return hook;
|
|
8960
|
+
return v.declared || rung !== "own" || name === answerOf(machine.world, void 0, kind, verb)?.name ? kind.drives : void 0;
|
|
8961
|
+
}
|
|
8598
8962
|
/** The least authority: the capability `[]` permits each effect (CAP.KEYS). */
|
|
8599
8963
|
const EACH$1 = /* @__PURE__ */ Object.freeze([[]]);
|
|
8600
8964
|
/** No declared effect. One list serves each visit without effects. */
|
|
8601
8965
|
const NO_EFFECTS = /* @__PURE__ */ Object.freeze([]);
|
|
8602
8966
|
/**
|
|
8603
|
-
* This function gives the effects that the
|
|
8604
|
-
*
|
|
8605
|
-
*
|
|
8967
|
+
* This function gives the effects that the code of a visit declares for a verb, as keys (FACTS.EFFECTS, VERB.EFFECTS).
|
|
8968
|
+
* The text `"type"` gives the type of the document after each alias. A visit without a kind declares no effect.
|
|
8969
|
+
* `check`, `factsOf`, `effectsOf` and `checkLatent` read the declarations with this one function (D27).
|
|
8970
|
+
*
|
|
8971
|
+
* For `eval`, the answer of the hook `facts` of the machine for the code of the visit wins over the contract of the
|
|
8972
|
+
* kind (CAP.OWN-EFFECTS, D118). Thus a language gives the effects of an own entry for another evaluator. Without a
|
|
8973
|
+
* machine, or without the field `effects` in the answer, the contract gives the effects.
|
|
8606
8974
|
*
|
|
8607
8975
|
* @param v - The visit.
|
|
8608
8976
|
* @param verb - The verb. The default is `eval`. A kind without a declaration for the verb gives no effect.
|
|
8609
|
-
* @
|
|
8977
|
+
* @param machine - The machine with the hook `facts`, when the caller has it.
|
|
8978
|
+
* @param name - The name of the evaluator of the visit, when the caller knows it. Else the ladder gives it.
|
|
8979
|
+
* @returns The keys of each declared effect, in the order of the declaration.
|
|
8980
|
+
*/
|
|
8981
|
+
function declaredEffects(v, verb = "eval", machine, name) {
|
|
8982
|
+
return hookEffects(v, verb, machine, name) ?? verbDeclared(v, verb) ?? NO_EFFECTS;
|
|
8983
|
+
}
|
|
8984
|
+
/**
|
|
8985
|
+
* This function gives the effects that the hook `facts` gives for the code of a visit, as keys (D118). The result is
|
|
8986
|
+
* `undefined` for another verb than `eval`, without the hook, or when the answer has no field `effects`.
|
|
8987
|
+
*/
|
|
8988
|
+
function hookEffects(v, verb, machine, name) {
|
|
8989
|
+
if (verb !== "eval" || machine?.facts === void 0 || v.kind === void 0) return void 0;
|
|
8990
|
+
const code = name ?? answerOf(machine.world, v.declared ? void 0 : v.doc.own, v.kind, "eval")?.name;
|
|
8991
|
+
const effects = code === void 0 ? void 0 : machine.facts(v.typePath ?? [], code)?.effects;
|
|
8992
|
+
return effects === void 0 ? void 0 : effectKeys(v, effects);
|
|
8993
|
+
}
|
|
8994
|
+
/**
|
|
8995
|
+
* This function gives the keys of a declaration of effects at a visit (D27). The text `"type"` gives the type of the
|
|
8996
|
+
* document after each alias.
|
|
8610
8997
|
*/
|
|
8611
|
-
function
|
|
8612
|
-
|
|
8998
|
+
function effectKeys(v, effects) {
|
|
8999
|
+
if (effects.length === 0) return NO_EFFECTS;
|
|
9000
|
+
return effects === "type" ? [v.typePath ?? []] : effects.map((kind) => kind.split("."));
|
|
8613
9001
|
}
|
|
8614
9002
|
/**
|
|
8615
9003
|
* This function gives the effects that the contract of the kind of a visit declares for a verb, as keys. The result
|
|
@@ -8620,8 +9008,7 @@ function verbDeclared(v, verb) {
|
|
|
8620
9008
|
if (v.kind === void 0) return verb === "eval" ? NO_EFFECTS : void 0;
|
|
8621
9009
|
const effects = effectsOfVerb(v.kind, verb);
|
|
8622
9010
|
if (effects === void 0) return void 0;
|
|
8623
|
-
|
|
8624
|
-
return effects === "type" ? [v.typePath ?? []] : effects.map((kind) => kind.split("."));
|
|
9011
|
+
return effectKeys(v, effects);
|
|
8625
9012
|
}
|
|
8626
9013
|
/**
|
|
8627
9014
|
* This function gives the rule of a machine for an effect, for the static kit (CAP.PERMITS). The rule is the hook
|
|
@@ -8770,7 +9157,8 @@ const DOWN_NAMES = /* @__PURE__ */ Object.freeze([
|
|
|
8770
9157
|
const FOLD_NAMES = /* @__PURE__ */ Object.freeze(["acc", "item"]);
|
|
8771
9158
|
/**
|
|
8772
9159
|
* This function gives each equation of the tree contract of a kind, with the names that it sees (D42). An equation of
|
|
8773
|
-
* `equations`, a `unit
|
|
9160
|
+
* `equations`, a `unit`, a `default` and a contribution see no names. `check` and `factsOf` read the equations with
|
|
9161
|
+
* this one function.
|
|
8774
9162
|
*/
|
|
8775
9163
|
function equationsOf(kind) {
|
|
8776
9164
|
const tree = kind.tree;
|
|
@@ -8814,7 +9202,32 @@ function equationsOf(kind) {
|
|
|
8814
9202
|
attribute: name,
|
|
8815
9203
|
down: false
|
|
8816
9204
|
});
|
|
9205
|
+
const collect = declared.collect === void 0 ? void 0 : collectOf(declared.collect);
|
|
9206
|
+
if (collect?.ok === true && !collect.names) {
|
|
9207
|
+
out.push({
|
|
9208
|
+
label: `tree.attributes.${name}.collect.unit`,
|
|
9209
|
+
term: collect.unit,
|
|
9210
|
+
names: [],
|
|
9211
|
+
attribute: name,
|
|
9212
|
+
down: false
|
|
9213
|
+
});
|
|
9214
|
+
out.push({
|
|
9215
|
+
label: `tree.attributes.${name}.collect.combine`,
|
|
9216
|
+
term: collect.combine,
|
|
9217
|
+
names: FOLD_NAMES,
|
|
9218
|
+
attribute: name,
|
|
9219
|
+
down: false
|
|
9220
|
+
});
|
|
9221
|
+
}
|
|
8817
9222
|
}
|
|
9223
|
+
for (const [name, term] of Object.entries(tree.contributes ?? {})) out.push({
|
|
9224
|
+
label: `tree.contributes.${name}`,
|
|
9225
|
+
term,
|
|
9226
|
+
names: [],
|
|
9227
|
+
attribute: name,
|
|
9228
|
+
down: false,
|
|
9229
|
+
contributes: true
|
|
9230
|
+
});
|
|
8818
9231
|
return out;
|
|
8819
9232
|
}
|
|
8820
9233
|
/**
|
|
@@ -8936,7 +9349,7 @@ function answered(world, node, name) {
|
|
|
8936
9349
|
if (hasEntry(tree?.equations, name)) return true;
|
|
8937
9350
|
if (node.parent === void 0 ? downNames(world).has(name) : hasEntry(node.parent.kind.tree?.down, name)) return true;
|
|
8938
9351
|
const declared = tree?.attributes !== void 0 && Object.hasOwn(tree.attributes, name) ? tree.attributes[name] : void 0;
|
|
8939
|
-
return declared !== void 0 && (declared.copy === true || declared.fold !== void 0 || declared.default !== void 0);
|
|
9352
|
+
return declared !== void 0 && (declared.copy === true || declared.fold !== void 0 || declared.collect !== void 0 || declared.default !== void 0);
|
|
8940
9353
|
}
|
|
8941
9354
|
/**
|
|
8942
9355
|
* This function checks the equations of the tree contract of a kind, each with the names of its rung (TREE.DOWN-NAMES).
|
|
@@ -8960,7 +9373,7 @@ function equationIssues(machine, kind, kindText, options, state) {
|
|
|
8960
9373
|
own: void 0,
|
|
8961
9374
|
parent: void 0
|
|
8962
9375
|
};
|
|
8963
|
-
for (const { label, term, names, attribute, down } of equationsOf(kind)) {
|
|
9376
|
+
for (const { label, term, names, attribute, down, contributes } of equationsOf(kind)) {
|
|
8964
9377
|
const inner = {
|
|
8965
9378
|
names,
|
|
8966
9379
|
...of === void 0 ? {} : { declaredType: of },
|
|
@@ -8970,7 +9383,7 @@ function equationIssues(machine, kind, kindText, options, state) {
|
|
|
8970
9383
|
needs.push({
|
|
8971
9384
|
name,
|
|
8972
9385
|
why: `the equation ${label} reads it`,
|
|
8973
|
-
hidden: down ? void 0 : attribute
|
|
9386
|
+
hidden: down || contributes === true ? void 0 : attribute
|
|
8974
9387
|
});
|
|
8975
9388
|
};
|
|
8976
9389
|
for (const issue of checkAll(machine, term, inner, void 0, state, {
|
|
@@ -8987,7 +9400,8 @@ function equationIssues(machine, kind, kindText, options, state) {
|
|
|
8987
9400
|
/**
|
|
8988
9401
|
* This function finds the issues of the contract of a tree kind (TREE.CHECK-RESERVED). An attribute with the name of a
|
|
8989
9402
|
* structural step gets no read. A tree kind of the run side contradicts the evaluation on demand of its attributes. A
|
|
8990
|
-
* declaration `circular` without a start value or with a bad limit gives `#VALUE!` (TREE.CIRCULAR-CHECK).
|
|
9403
|
+
* declaration `circular` without a start value or with a bad limit gives `#VALUE!` (TREE.CIRCULAR-CHECK). A declaration
|
|
9404
|
+
* `collect` without its form gives `#VALUE!` too (TREE.COLLECT).
|
|
8991
9405
|
*/
|
|
8992
9406
|
function contractIssues(kind, kindText) {
|
|
8993
9407
|
const out = [];
|
|
@@ -8995,7 +9409,8 @@ function contractIssues(kind, kindText) {
|
|
|
8995
9409
|
for (const table of [
|
|
8996
9410
|
"equations",
|
|
8997
9411
|
"down",
|
|
8998
|
-
"attributes"
|
|
9412
|
+
"attributes",
|
|
9413
|
+
"contributes"
|
|
8999
9414
|
]) for (const name of Object.keys(tree?.[table] ?? {})) {
|
|
9000
9415
|
const why = Object.hasOwn(STRUCTURAL, name) ? STRUCTURAL[name] : void 0;
|
|
9001
9416
|
if (why !== void 0) out.push({
|
|
@@ -9011,6 +9426,12 @@ function contractIssues(kind, kindText) {
|
|
|
9011
9426
|
place: [],
|
|
9012
9427
|
reason: `The kind ${kindText} has a bad declaration tree.attributes.${name}.circular. ${rule.reason}`
|
|
9013
9428
|
});
|
|
9429
|
+
const collect = declared.collect === void 0 ? void 0 : collectOf(declared.collect);
|
|
9430
|
+
if (collect !== void 0 && !collect.ok) out.push({
|
|
9431
|
+
code: "#VALUE!",
|
|
9432
|
+
place: [],
|
|
9433
|
+
reason: `The kind ${kindText} has a bad declaration tree.attributes.${name}.collect. ${collect.reason}`
|
|
9434
|
+
});
|
|
9014
9435
|
}
|
|
9015
9436
|
if (kind.side === "run") out.push({
|
|
9016
9437
|
code: "#CALC!",
|
|
@@ -9098,6 +9519,7 @@ function checkAll(machine, doc, options, nodes, state = {
|
|
|
9098
9519
|
};
|
|
9099
9520
|
const allowed = options.caps === void 0 ? void 0 : permitsOf(machine);
|
|
9100
9521
|
const waits = options.run === true ? /* @__PURE__ */ new Map() : void 0;
|
|
9522
|
+
const driven = /* @__PURE__ */ new Map();
|
|
9101
9523
|
const drives = [];
|
|
9102
9524
|
const maxDepth = machine.maxDepth ?? 1e3;
|
|
9103
9525
|
const anyName = options.names === "any";
|
|
@@ -9174,7 +9596,7 @@ function checkAll(machine, doc, options, nodes, state = {
|
|
|
9174
9596
|
});
|
|
9175
9597
|
}
|
|
9176
9598
|
const caps = v.caps;
|
|
9177
|
-
const stated = verbDeclared(v, verb);
|
|
9599
|
+
const stated = hookEffects(v, verb, machine, name) ?? verbDeclared(v, verb);
|
|
9178
9600
|
const declared = stated ?? NO_EFFECTS;
|
|
9179
9601
|
if (allowed !== void 0 && caps !== void 0) {
|
|
9180
9602
|
for (const kind of declared) if (!allowed(caps, kind)) push({
|
|
@@ -9185,7 +9607,9 @@ function checkAll(machine, doc, options, nodes, state = {
|
|
|
9185
9607
|
});
|
|
9186
9608
|
}
|
|
9187
9609
|
if (waits !== void 0 && coded) {
|
|
9188
|
-
|
|
9610
|
+
let up = v.parent === void 0 ? true : waits.get(v.parent);
|
|
9611
|
+
const rules = v.parent === void 0 ? void 0 : driven.get(v.parent);
|
|
9612
|
+
if (up !== false && rules !== void 0 && v.parent !== void 0 && rulesCover(rules, v.parent.kind?.parts, v.parent.doc.value, v.slot)) up = false;
|
|
9189
9613
|
let chain = false;
|
|
9190
9614
|
if (runner && up === false) {
|
|
9191
9615
|
chain = {
|
|
@@ -9202,6 +9626,10 @@ function checkAll(machine, doc, options, nodes, state = {
|
|
|
9202
9626
|
drives.push(chain);
|
|
9203
9627
|
} else if (runner) chain = up ?? true;
|
|
9204
9628
|
waits.set(v, chain);
|
|
9629
|
+
if (runner && v.kind !== void 0) {
|
|
9630
|
+
const own = driveRules(machine, v, v.kind, name, answer.rung, verb);
|
|
9631
|
+
if (own !== void 0 && own.length > 0) driven.set(v, own);
|
|
9632
|
+
}
|
|
9205
9633
|
if (typeof chain === "object" && !chain.wait) {
|
|
9206
9634
|
const rule = allowed ?? permits;
|
|
9207
9635
|
chain.wait = stated === void 0 || declared.some((kind) => caps === void 0 || rule(caps, kind));
|
|
@@ -9307,7 +9735,7 @@ function reaching(machine, doc, options) {
|
|
|
9307
9735
|
const rule = options.caps === void 0 ? permits : permitsOf(machine);
|
|
9308
9736
|
walk(machine.world, doc, (v) => {
|
|
9309
9737
|
const caps = v.caps ?? EACH;
|
|
9310
|
-
for (const kind of declaredEffects(v)) if (rule(caps, kind)) out.push({
|
|
9738
|
+
for (const kind of declaredEffects(v, "eval", machine)) if (rule(caps, kind)) out.push({
|
|
9311
9739
|
kind,
|
|
9312
9740
|
visit: v
|
|
9313
9741
|
});
|
|
@@ -9328,7 +9756,9 @@ function reaching(machine, doc, options) {
|
|
|
9328
9756
|
*
|
|
9329
9757
|
* The result covers each effect that an evaluation or a run gives the host (CAP.EFFECTS-SOUND). A procedure value keeps
|
|
9330
9758
|
* the capabilities of the document that made it, thus the effects of its body count at the body (CAP.LATENT). The
|
|
9331
|
-
* contract describes the code of its kind. The code of an own entry for another
|
|
9759
|
+
* contract describes the code of its kind. The contract does not describe the code of an own entry for another
|
|
9760
|
+
* evaluator. The answer of the hook `facts` for that code gives its effects (CAP.OWN-EFFECTS, D118). Without an
|
|
9761
|
+
* answer, its effects are outside the result.
|
|
9332
9762
|
*
|
|
9333
9763
|
* @param machine - The world and its contracts, and the hook `permits`.
|
|
9334
9764
|
* @param doc - The document, as JSON.
|
|
@@ -9828,6 +10258,30 @@ function paramsOf(value) {
|
|
|
9828
10258
|
const params = isRecord(value) ? value["params"] : void 0;
|
|
9829
10259
|
return Array.isArray(params) ? params.filter((param) => typeof param === "string") : [];
|
|
9830
10260
|
}
|
|
10261
|
+
/** This function gives the text of a step of a path: a key, or the kind of a step document in parentheses. */
|
|
10262
|
+
function stepText(step) {
|
|
10263
|
+
if (isKey(step)) return String(step);
|
|
10264
|
+
return isRecord(step) ? `(${typeName(step["type"])})` : "(step)";
|
|
10265
|
+
}
|
|
10266
|
+
/**
|
|
10267
|
+
* This function gives the type of what a step document reaches (TYPE.WALKER, D121). The type rule of its walker gives
|
|
10268
|
+
* it. A step document with parts gets its data in the run, thus its type is `unknown`, as for a walker without a rule.
|
|
10269
|
+
*
|
|
10270
|
+
* @param input - The input of the rule of the reference.
|
|
10271
|
+
* @param step - The step document.
|
|
10272
|
+
* @param here - The type before the step.
|
|
10273
|
+
* @returns The type of what the step reaches.
|
|
10274
|
+
*/
|
|
10275
|
+
function walkType(input, step, here) {
|
|
10276
|
+
const rule = walkerOf(input.machine, step)?.type;
|
|
10277
|
+
if (rule === void 0) return "unknown";
|
|
10278
|
+
const read = partsOf(input.machine.world, step);
|
|
10279
|
+
if (!read.ok || !read.split.ok || read.split.parts.length > 0) return "unknown";
|
|
10280
|
+
return input.contract(rule({
|
|
10281
|
+
data: read.doc.value,
|
|
10282
|
+
here
|
|
10283
|
+
}), `type of the step ${typeName(read.doc.type)}`);
|
|
10284
|
+
}
|
|
9831
10285
|
/**
|
|
9832
10286
|
* This function makes the type rules of the formula kit for one profile (TYPE.SYNTH, D25). Each evaluator of the kit
|
|
9833
10287
|
* holds its rule. The rules read the rules of the profile that change a type: `truthy`, `truthType`, `logic`,
|
|
@@ -9968,11 +10422,14 @@ function formulaTypes(profile) {
|
|
|
9968
10422
|
if (isUnknown(type, domains) || !plain && holdsEnvelope(type, domains)) return "unknown";
|
|
9969
10423
|
if (index >= path.length) return type;
|
|
9970
10424
|
const step = path[index];
|
|
9971
|
-
if (!isKey(step))
|
|
10425
|
+
if (!isKey(step)) {
|
|
10426
|
+
type = walkType(input, step, type);
|
|
10427
|
+
continue;
|
|
10428
|
+
}
|
|
9972
10429
|
const next = stepType(type, step, domains, input.contract);
|
|
9973
10430
|
if ("missing" in next) {
|
|
9974
10431
|
const fields = next.missing.length === 0 ? "" : ` Its fields are ${listText(next.missing)}.`;
|
|
9975
|
-
report({ reason: `The value at ${path.slice(0, index).map(
|
|
10432
|
+
report({ reason: `The value at ${path.slice(0, index).map(stepText).join(".")} has no field ${String(step)}.${fields}` });
|
|
9976
10433
|
return "unknown";
|
|
9977
10434
|
}
|
|
9978
10435
|
type = next.type;
|
|
@@ -12501,6 +12958,55 @@ function foldOf(node, name, fold) {
|
|
|
12501
12958
|
return acc;
|
|
12502
12959
|
}
|
|
12503
12960
|
/**
|
|
12961
|
+
* TREE.COLLECT and TREE.NAMED: the node, then each node of this tree in each list `children`, in the order of the
|
|
12962
|
+
* lists. Each node counts one time. The registry `names` maps each binding name to its node.
|
|
12963
|
+
*/
|
|
12964
|
+
function collectIn(node, name, declared) {
|
|
12965
|
+
const rule = collectOf(declared);
|
|
12966
|
+
if (!rule.ok) return fail("#VALUE!", `The attribute ${nameOfAttribute(node, name)} has a bad declaration collect. ${rule.reason}`);
|
|
12967
|
+
const registry = {};
|
|
12968
|
+
const first = /* @__PURE__ */ new Map();
|
|
12969
|
+
let acc = rule.names ? ok(registry) : equationOf(node, rule.unit, {});
|
|
12970
|
+
if (!acc.ok) return acc;
|
|
12971
|
+
const done = [];
|
|
12972
|
+
const visit = (at) => {
|
|
12973
|
+
if (done.includes(at)) return void 0;
|
|
12974
|
+
done.push(at);
|
|
12975
|
+
if (rule.names && at.name !== void 0) {
|
|
12976
|
+
const earlier = first.get(at.name);
|
|
12977
|
+
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(", ")}].`);
|
|
12978
|
+
first.set(at.name, at);
|
|
12979
|
+
Object.defineProperty(registry, at.name, {
|
|
12980
|
+
value: at.thing,
|
|
12981
|
+
enumerable: true,
|
|
12982
|
+
writable: true,
|
|
12983
|
+
configurable: true
|
|
12984
|
+
});
|
|
12985
|
+
}
|
|
12986
|
+
const term = rule.names ? void 0 : termIn(at.contract?.contributes, name);
|
|
12987
|
+
if (!rule.names && term !== void 0) {
|
|
12988
|
+
const item = equationOf(at, term, {});
|
|
12989
|
+
if (!item.ok) return item;
|
|
12990
|
+
acc = equationOf(node, rule.combine, {
|
|
12991
|
+
acc: acc.ok ? acc.value : null,
|
|
12992
|
+
item: item.value
|
|
12993
|
+
});
|
|
12994
|
+
if (!acc.ok) return acc;
|
|
12995
|
+
}
|
|
12996
|
+
const children = attributeOf(at, "children");
|
|
12997
|
+
if (children === void 0) return void 0;
|
|
12998
|
+
if (!children.ok) return children;
|
|
12999
|
+
if (!Array.isArray(children.value)) return fail("#VALUE!", `The collection of ${name} needs a list in children of ${at.kind} at [${at.place.join(", ")}].`);
|
|
13000
|
+
for (const item of children.value) {
|
|
13001
|
+
const child = refNodeOf(item);
|
|
13002
|
+
if (child === void 0 || child.tree !== node.tree) continue;
|
|
13003
|
+
const failed = visit(child);
|
|
13004
|
+
if (failed !== void 0) return failed;
|
|
13005
|
+
}
|
|
13006
|
+
};
|
|
13007
|
+
return visit(node) ?? acc;
|
|
13008
|
+
}
|
|
13009
|
+
/**
|
|
12504
13010
|
* TREE.LADDER: the rungs of the ladder of an attribute, in their order. A rung gives `undefined` when it does not
|
|
12505
13011
|
* answer, and the next rung then tries.
|
|
12506
13012
|
*/
|
|
@@ -12524,6 +13030,7 @@ const REF_RUNGS = [
|
|
|
12524
13030
|
["default", (node, name) => {
|
|
12525
13031
|
const declared = termIn(node.contract?.attributes, name);
|
|
12526
13032
|
if (declared?.fold !== void 0) return foldOf(node, name, declared.fold);
|
|
13033
|
+
if (declared?.collect !== void 0) return collectIn(node, name, declared.collect);
|
|
12527
13034
|
return declared?.default === void 0 ? void 0 : equationOf(node, declared.default, {});
|
|
12528
13035
|
}]
|
|
12529
13036
|
];
|
|
@@ -12711,7 +13218,7 @@ function plainValue(value, open) {
|
|
|
12711
13218
|
* tree gives its JSON. A step on the thing reads an attribute, and a failed attribute throws its own error. The node
|
|
12712
13219
|
* reads `self` only through `resolve` (C4, TREE.SELF).
|
|
12713
13220
|
*/
|
|
12714
|
-
const treeDefinition = ({ parts, context, kind, place, machine, typePath, resolve: walk }) => {
|
|
13221
|
+
const treeDefinition = ({ parts, context, kind, place, machine, typePath, resolve: walk, doc }) => {
|
|
12715
13222
|
const reached = walk(["self"]);
|
|
12716
13223
|
const parent = reached.ok ? reached.thing : void 0;
|
|
12717
13224
|
const outer = refNodeOf(parent);
|
|
@@ -12722,6 +13229,7 @@ const treeDefinition = ({ parts, context, kind, place, machine, typePath, resolv
|
|
|
12722
13229
|
const node = {
|
|
12723
13230
|
tree: nested ? outer.tree : { open: true },
|
|
12724
13231
|
kind,
|
|
13232
|
+
name: doc.name,
|
|
12725
13233
|
place,
|
|
12726
13234
|
parts,
|
|
12727
13235
|
ctx: context,
|
|
@@ -15045,6 +15553,7 @@ var Shot = class {
|
|
|
15045
15553
|
scenario;
|
|
15046
15554
|
context;
|
|
15047
15555
|
keys;
|
|
15556
|
+
driven;
|
|
15048
15557
|
perform;
|
|
15049
15558
|
replay;
|
|
15050
15559
|
calls = [];
|
|
@@ -15058,12 +15567,13 @@ var Shot = class {
|
|
|
15058
15567
|
result = NO_RESULT;
|
|
15059
15568
|
afterwards = false;
|
|
15060
15569
|
running;
|
|
15061
|
-
constructor(machine, runner, scenario, context, keys, perform, replay) {
|
|
15570
|
+
constructor(machine, runner, scenario, context, keys, driven, perform, replay) {
|
|
15062
15571
|
this.machine = machine;
|
|
15063
15572
|
this.runner = runner;
|
|
15064
15573
|
this.scenario = scenario;
|
|
15065
15574
|
this.context = context;
|
|
15066
15575
|
this.keys = keys;
|
|
15576
|
+
this.driven = driven;
|
|
15067
15577
|
this.perform = perform;
|
|
15068
15578
|
this.replay = replay;
|
|
15069
15579
|
this.running = scenario.running;
|
|
@@ -15087,7 +15597,7 @@ var Shot = class {
|
|
|
15087
15597
|
});
|
|
15088
15598
|
const key = this.keys[part] ?? String(part);
|
|
15089
15599
|
if (via === "run" && !this.runner) this.problems.push(`The code of an evaluator starts the steps of the part ${key}. Only a runner waits.`);
|
|
15090
|
-
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 (
|
|
15600
|
+
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).`);
|
|
15091
15601
|
return this.scenario.results[part] ?? NO_RESULT;
|
|
15092
15602
|
}
|
|
15093
15603
|
/** This function records a call of a part, and gives the steps of the probe part. In a run, the part can wait. */
|
|
@@ -15280,13 +15790,14 @@ function typesNaming(world, name, verb) {
|
|
|
15280
15790
|
/** This function gives the facts of the kind of a type. The hook `facts` of the machine wins over the contract. */
|
|
15281
15791
|
function contractOf(env, kind, typePath, caps) {
|
|
15282
15792
|
const facts = env.machine.facts?.(typePath, env.name);
|
|
15283
|
-
const own = effectsOfVerb(kind, env.verb);
|
|
15793
|
+
const own = (env.verb === "eval" ? facts?.effects : void 0) ?? effectsOfVerb(kind, env.verb);
|
|
15284
15794
|
const effects = own ?? kind.effects;
|
|
15285
15795
|
const declared = effects === void 0 ? [] : effects === "type" ? [typePath] : effects;
|
|
15286
15796
|
return {
|
|
15287
15797
|
declared,
|
|
15288
15798
|
pure: (facts?.pure ?? kind.pure) === true,
|
|
15289
15799
|
lazy: facts?.lazy ?? kind.lazy,
|
|
15800
|
+
drives: env.verb === "eval" ? facts?.drives ?? kind.drives : void 0,
|
|
15290
15801
|
describes: env.verb === "eval",
|
|
15291
15802
|
declares: own !== void 0,
|
|
15292
15803
|
caps: caps ?? [...declared, "probe"]
|
|
@@ -15434,6 +15945,7 @@ function samplesOf(type, typePath, kind, contract, extra) {
|
|
|
15434
15945
|
},
|
|
15435
15946
|
otherSplit,
|
|
15436
15947
|
lazy: split.parts.map((_slot, index) => contract.lazy?.some((rule) => covers(rule, split.parts, index)) === true),
|
|
15948
|
+
driven: split.parts.map((_slot, index) => contract.drives?.some((rule) => covers(rule, split.parts, index)) === true),
|
|
15437
15949
|
names: scopesOf(kind.scope, value, split.parts).sees
|
|
15438
15950
|
});
|
|
15439
15951
|
}
|
|
@@ -15580,7 +16092,7 @@ function instanceOf(env, under, doc, split, sample) {
|
|
|
15580
16092
|
/** This function evaluates a probe document one time in a new shot. */
|
|
15581
16093
|
function shoot(env, instance, sample, scenario, more = {}) {
|
|
15582
16094
|
const context = more.context ?? rootContext(env.machine, makeContext(env.names, scenario.caps));
|
|
15583
|
-
const shot = new Shot(env.machine, env.runner, scenario, context, sample.split.parts.map((slot) => slot.key), env.perform, more.replay);
|
|
16095
|
+
const shot = new Shot(env.machine, env.runner, scenario, context, sample.split.parts.map((slot) => slot.key), sample.driven, env.perform, more.replay);
|
|
15584
16096
|
instance(shot);
|
|
15585
16097
|
return shot;
|
|
15586
16098
|
}
|
|
@@ -17052,18 +17564,89 @@ const READ = /* @__PURE__ */ new Set([
|
|
|
17052
17564
|
"enum",
|
|
17053
17565
|
"const",
|
|
17054
17566
|
"anyOf",
|
|
17055
|
-
"oneOf"
|
|
17567
|
+
"oneOf",
|
|
17568
|
+
"allOf",
|
|
17569
|
+
"$ref"
|
|
17056
17570
|
]);
|
|
17057
17571
|
/**
|
|
17058
|
-
* The keywords that can permit more values than the other keywords permit.
|
|
17059
|
-
*
|
|
17572
|
+
* The keywords that can permit more values than the other keywords permit. A dynamic reference can reach a schema
|
|
17573
|
+
* outside this schema, and `nullable` of OpenAPI 3.0 permits `null`. Thus a schema with one of them reads as `unknown`.
|
|
17060
17574
|
*/
|
|
17061
17575
|
const WIDENING = /* @__PURE__ */ new Set([
|
|
17062
|
-
"$ref",
|
|
17063
17576
|
"$dynamicRef",
|
|
17064
17577
|
"$recursiveRef",
|
|
17065
17578
|
"nullable"
|
|
17066
17579
|
]);
|
|
17580
|
+
/** The keywords of an object without the keyword `type`. They test only the values that are records. */
|
|
17581
|
+
const OBJECT_KEYS = [
|
|
17582
|
+
"properties",
|
|
17583
|
+
"required",
|
|
17584
|
+
"additionalProperties"
|
|
17585
|
+
];
|
|
17586
|
+
/** The form of a local reference: a definition in `$defs` or `definitions` of the root schema. */
|
|
17587
|
+
const LOCAL_REF = /^#\/(\$defs|definitions)\/([^/]*)$/;
|
|
17588
|
+
/** The most pairs of members that the meet of two unions builds. A larger meet keeps the first type, which is sound. */
|
|
17589
|
+
const MAX_MEET_PAIRS = 64;
|
|
17590
|
+
/** This function tells if a field of a record type can be absent. */
|
|
17591
|
+
function isOptional(type, key) {
|
|
17592
|
+
return type.optional?.includes(key) === true;
|
|
17593
|
+
}
|
|
17594
|
+
/**
|
|
17595
|
+
* This function gives the meet of two types of a reading: a type that holds each value of both types. A schema is
|
|
17596
|
+
* the conjunction of its keywords, thus its type is the meet of their types. The meet is exact for the forms that a
|
|
17597
|
+
* reading makes: base types, lists, records, unions and `one`. A meet of two different forms is `never`.
|
|
17598
|
+
*/
|
|
17599
|
+
function meet(a, b, depth) {
|
|
17600
|
+
if (depth > MAX_SCHEMA_DEPTH) return a;
|
|
17601
|
+
if (isUnknown(a, void 0)) return b;
|
|
17602
|
+
if (isUnknown(b, void 0)) return a;
|
|
17603
|
+
if (a === "never" || b === "never") return "never";
|
|
17604
|
+
if (typeof a !== "string" && "one" in a) return { one: a.one.filter((value) => member(value, b)) };
|
|
17605
|
+
if (typeof b !== "string" && "one" in b) return { one: b.one.filter((value) => member(value, a)) };
|
|
17606
|
+
if (typeof b !== "string" && "union" in b && !(typeof a !== "string" && "union" in a)) return meet(b, a, depth);
|
|
17607
|
+
if (typeof a !== "string" && "union" in a) {
|
|
17608
|
+
const others = typeof b !== "string" && "union" in b ? b.union : [b];
|
|
17609
|
+
if (a.union.length * others.length > MAX_MEET_PAIRS) return a;
|
|
17610
|
+
return unionOf(a.union.flatMap((item) => others.map((other) => meet(item, other, depth + 1))));
|
|
17611
|
+
}
|
|
17612
|
+
if (typeof a === "string" || typeof b === "string") return a === b ? a : "never";
|
|
17613
|
+
if ("list" in a && "list" in b) return { list: meet(a.list, b.list, depth + 1) };
|
|
17614
|
+
if ("record" in a && "record" in b) return meetRecords(a, b, depth + 1);
|
|
17615
|
+
return ("list" in a || "record" in a) && ("list" in b || "record" in b) ? "never" : a;
|
|
17616
|
+
}
|
|
17617
|
+
/**
|
|
17618
|
+
* This function gives the meet of two record types. A field of both records gets the meet of its types, and it is
|
|
17619
|
+
* optional only when both records permit its absence. A closed record has no other field, thus a field of only the
|
|
17620
|
+
* other record is absent. When the other record needs that field, no value fits both records.
|
|
17621
|
+
*/
|
|
17622
|
+
function meetRecords(a, b, depth) {
|
|
17623
|
+
const fields = {};
|
|
17624
|
+
const optional = [];
|
|
17625
|
+
const keys = [...Object.keys(a.record), ...Object.keys(b.record).filter((key) => !Object.hasOwn(a.record, key))];
|
|
17626
|
+
for (const key of keys) {
|
|
17627
|
+
const inA = Object.hasOwn(a.record, key);
|
|
17628
|
+
const inB = Object.hasOwn(b.record, key);
|
|
17629
|
+
if (!inA && a.closed === true || !inB && b.closed === true) {
|
|
17630
|
+
if (inA && !isOptional(a, key) || inB && !isOptional(b, key)) return "never";
|
|
17631
|
+
continue;
|
|
17632
|
+
}
|
|
17633
|
+
setOwn(fields, key, inA && inB ? meet(a.record[key], b.record[key], depth) : inA ? a.record[key] : b.record[key]);
|
|
17634
|
+
if ((!inA || isOptional(a, key)) && (!inB || isOptional(b, key))) optional.push(key);
|
|
17635
|
+
}
|
|
17636
|
+
const closed = a.closed === true || b.closed === true;
|
|
17637
|
+
return {
|
|
17638
|
+
record: fields,
|
|
17639
|
+
...optional.length === 0 ? {} : { optional },
|
|
17640
|
+
...closed ? { closed: true } : {}
|
|
17641
|
+
};
|
|
17642
|
+
}
|
|
17643
|
+
/** This function applies a condition to a type: each member of the JSON type of the condition meets its type. */
|
|
17644
|
+
function narrow$1(type, condition) {
|
|
17645
|
+
if (typeof type === "string") return type;
|
|
17646
|
+
if ("union" in type) return unionOf(type.union.map((item) => narrow$1(item, condition)));
|
|
17647
|
+
if ("one" in type) return { one: type.one.filter((value) => !(condition.on === "list" ? Array.isArray(value) : isRecord(value)) || member(value, condition.type)) };
|
|
17648
|
+
return condition.on in type ? meet(type, condition.type, 0) : type;
|
|
17649
|
+
}
|
|
17067
17650
|
/** The base type of each name of the keyword `type`. */
|
|
17068
17651
|
const BASES = {
|
|
17069
17652
|
null: "null",
|
|
@@ -17086,26 +17669,57 @@ function setOwn(target, key, value) {
|
|
|
17086
17669
|
function unionOf(types) {
|
|
17087
17670
|
return types.reduce((all, type) => join(all, type), "never");
|
|
17088
17671
|
}
|
|
17089
|
-
/** The state of one reading of a schema: the issues that it
|
|
17672
|
+
/** The state of one reading of a schema: the root, the issues and the definitions that it read. */
|
|
17090
17673
|
var SchemaReader = class {
|
|
17674
|
+
root;
|
|
17091
17675
|
issues = [];
|
|
17676
|
+
/** The type of each definition that a reference reached. Each reading of a definition is sound, thus the first stays. */
|
|
17677
|
+
defs = /* @__PURE__ */ new Map();
|
|
17678
|
+
/** The definitions that the reading has not finished. A reference to one of them is a cycle. */
|
|
17679
|
+
open = /* @__PURE__ */ new Set();
|
|
17680
|
+
/** The number of schemas with an own `$id` around the current schema. A reference inside them has another base. */
|
|
17681
|
+
inner = 0;
|
|
17682
|
+
constructor(root) {
|
|
17683
|
+
this.root = root;
|
|
17684
|
+
}
|
|
17092
17685
|
issue(at, reason) {
|
|
17093
17686
|
this.issues.push({
|
|
17094
17687
|
at,
|
|
17095
17688
|
reason
|
|
17096
17689
|
});
|
|
17097
17690
|
}
|
|
17098
|
-
/** This method reads one schema. */
|
|
17691
|
+
/** This method reads one schema: the meet of the types of its keywords, then its conditions. */
|
|
17099
17692
|
read(schema, at, depth) {
|
|
17693
|
+
const types = [];
|
|
17694
|
+
const conditions = [];
|
|
17695
|
+
this.parts(schema, at, depth, types, conditions);
|
|
17696
|
+
let type = types.reduce((all, item) => meet(all, item, 0), "unknown");
|
|
17697
|
+
for (const condition of conditions) {
|
|
17698
|
+
if (isUnknown(type, void 0)) {
|
|
17699
|
+
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.");
|
|
17700
|
+
break;
|
|
17701
|
+
}
|
|
17702
|
+
type = narrow$1(type, condition);
|
|
17703
|
+
}
|
|
17704
|
+
return type;
|
|
17705
|
+
}
|
|
17706
|
+
/**
|
|
17707
|
+
* This method adds the type of each keyword of a schema to `types`, and its conditions to `conditions`. Each type
|
|
17708
|
+
* holds each value that the schema accepts. The parts of `allOf` add their keywords too.
|
|
17709
|
+
*/
|
|
17710
|
+
parts(schema, at, depth, types, conditions) {
|
|
17100
17711
|
if (depth > MAX_SCHEMA_DEPTH) {
|
|
17101
17712
|
this.issue(at, `The schema is deeper than ${MAX_SCHEMA_DEPTH} levels. The type reads it as unknown.`);
|
|
17102
|
-
return
|
|
17713
|
+
return;
|
|
17714
|
+
}
|
|
17715
|
+
if (schema === true) return;
|
|
17716
|
+
if (schema === false) {
|
|
17717
|
+
types.push("never");
|
|
17718
|
+
return;
|
|
17103
17719
|
}
|
|
17104
|
-
if (schema === true) return "unknown";
|
|
17105
|
-
if (schema === false) return "never";
|
|
17106
17720
|
if (!isRecord(schema)) {
|
|
17107
17721
|
this.issue(at, "A schema is a record or a truth value. The type reads this value as unknown.");
|
|
17108
|
-
return
|
|
17722
|
+
return;
|
|
17109
17723
|
}
|
|
17110
17724
|
let widens = false;
|
|
17111
17725
|
for (const key of Object.keys(schema)) {
|
|
@@ -17115,46 +17729,99 @@ var SchemaReader = class {
|
|
|
17115
17729
|
widens = true;
|
|
17116
17730
|
} else this.issue([...at, key], `The type does not read the keyword ${key}. It does not test what the keyword tests.`);
|
|
17117
17731
|
}
|
|
17118
|
-
if (widens) return
|
|
17119
|
-
const
|
|
17120
|
-
if (
|
|
17121
|
-
|
|
17122
|
-
|
|
17123
|
-
}
|
|
17124
|
-
|
|
17125
|
-
|
|
17126
|
-
|
|
17127
|
-
|
|
17128
|
-
|
|
17129
|
-
|
|
17130
|
-
"
|
|
17131
|
-
|
|
17732
|
+
if (widens) return;
|
|
17733
|
+
const nested = schema !== this.root && Object.hasOwn(schema, "$id");
|
|
17734
|
+
if (nested) this.inner += 1;
|
|
17735
|
+
try {
|
|
17736
|
+
this.keywords(schema, at, depth, types, conditions);
|
|
17737
|
+
} finally {
|
|
17738
|
+
if (nested) this.inner -= 1;
|
|
17739
|
+
}
|
|
17740
|
+
}
|
|
17741
|
+
/** This method reads the keywords of a schema that does not permit more values (WIDENING). */
|
|
17742
|
+
keywords(schema, at, depth, types, conditions) {
|
|
17743
|
+
if (Object.hasOwn(schema, "$ref")) {
|
|
17744
|
+
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.`);
|
|
17745
|
+
const type = this.target(schema["$ref"], [...at, "$ref"], depth);
|
|
17746
|
+
if (type !== void 0) types.push(type);
|
|
17747
|
+
return;
|
|
17748
|
+
}
|
|
17749
|
+
if (Object.hasOwn(schema, "type")) types.push(this.byType(schema, at, depth));
|
|
17750
|
+
else {
|
|
17751
|
+
if (OBJECT_KEYS.some((key) => Object.hasOwn(schema, key))) conditions.push({
|
|
17752
|
+
on: "record",
|
|
17753
|
+
type: this.object(schema, at, depth),
|
|
17754
|
+
at
|
|
17755
|
+
});
|
|
17756
|
+
if (Object.hasOwn(schema, "items")) conditions.push({
|
|
17757
|
+
on: "list",
|
|
17758
|
+
type: this.array(schema, at, depth),
|
|
17759
|
+
at
|
|
17760
|
+
});
|
|
17761
|
+
}
|
|
17762
|
+
for (const key of [
|
|
17132
17763
|
"anyOf",
|
|
17133
|
-
"oneOf"
|
|
17134
|
-
|
|
17135
|
-
|
|
17764
|
+
"oneOf",
|
|
17765
|
+
"allOf"
|
|
17766
|
+
]) {
|
|
17136
17767
|
if (!Object.hasOwn(schema, key)) continue;
|
|
17137
17768
|
const items = schema[key];
|
|
17138
17769
|
if (!Array.isArray(items)) {
|
|
17139
17770
|
this.issue([...at, key], `The value of ${key} is a list of schemas.`);
|
|
17140
17771
|
continue;
|
|
17141
17772
|
}
|
|
17142
|
-
|
|
17773
|
+
if (key === "allOf") for (const [index, item] of items.entries()) this.parts(item, [
|
|
17774
|
+
...at,
|
|
17143
17775
|
key,
|
|
17144
|
-
|
|
17145
|
-
|
|
17146
|
-
|
|
17147
|
-
|
|
17148
|
-
|
|
17149
|
-
|
|
17776
|
+
index
|
|
17777
|
+
], depth + 1, types, conditions);
|
|
17778
|
+
else types.push(unionOf(items.map((item, index) => this.read(item, [
|
|
17779
|
+
...at,
|
|
17780
|
+
key,
|
|
17781
|
+
index
|
|
17782
|
+
], depth + 1))));
|
|
17150
17783
|
}
|
|
17151
17784
|
const values = this.values(schema, at);
|
|
17152
|
-
if (values !== void 0)
|
|
17153
|
-
|
|
17154
|
-
|
|
17155
|
-
|
|
17156
|
-
|
|
17157
|
-
|
|
17785
|
+
if (values !== void 0) types.push({ one: values });
|
|
17786
|
+
}
|
|
17787
|
+
/** This method reads the target of a reference: a definition of the root schema, or `undefined` for each value. */
|
|
17788
|
+
target(ref, at, depth) {
|
|
17789
|
+
const match = typeof ref === "string" ? LOCAL_REF.exec(ref) : null;
|
|
17790
|
+
let name;
|
|
17791
|
+
try {
|
|
17792
|
+
name = match === null ? void 0 : decodeURIComponent(match[2] ?? "").replace(/~1/g, "/").replace(/~0/g, "~");
|
|
17793
|
+
} catch {
|
|
17794
|
+
name = void 0;
|
|
17795
|
+
}
|
|
17796
|
+
if (match === null || name === void 0) {
|
|
17797
|
+
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.");
|
|
17798
|
+
return;
|
|
17799
|
+
}
|
|
17800
|
+
if (this.inner > 0) {
|
|
17801
|
+
this.issue(at, "A $ref inside a schema with its own $id has another base. Thus the type reads the schema as unknown.");
|
|
17802
|
+
return;
|
|
17803
|
+
}
|
|
17804
|
+
const group = match[1];
|
|
17805
|
+
const defs = isRecord(this.root) ? this.root[group] : void 0;
|
|
17806
|
+
if (!isRecord(defs) || !Object.hasOwn(defs, name)) {
|
|
17807
|
+
this.issue(at, `The schema has no definition ${String(ref)}. Thus the type reads the reference as unknown.`);
|
|
17808
|
+
return;
|
|
17809
|
+
}
|
|
17810
|
+
const key = `${group}/${name}`;
|
|
17811
|
+
const known = this.defs.get(key);
|
|
17812
|
+
if (known !== void 0) return known;
|
|
17813
|
+
if (this.open.has(key)) {
|
|
17814
|
+
this.issue(at, `The reference ${String(ref)} is in a cycle. The type reads this reference as unknown.`);
|
|
17815
|
+
return;
|
|
17816
|
+
}
|
|
17817
|
+
this.open.add(key);
|
|
17818
|
+
try {
|
|
17819
|
+
const type = this.read(defs[name], [group, name], depth + 1);
|
|
17820
|
+
this.defs.set(key, type);
|
|
17821
|
+
return type;
|
|
17822
|
+
} finally {
|
|
17823
|
+
this.open.delete(key);
|
|
17824
|
+
}
|
|
17158
17825
|
}
|
|
17159
17826
|
/** This method reads `enum` and `const`: the values that the schema permits, or `undefined` without them. */
|
|
17160
17827
|
values(schema, at) {
|
|
@@ -17242,17 +17909,20 @@ var SchemaReader = class {
|
|
|
17242
17909
|
* - `properties`, `required` and `additionalProperties` give a record. `false` closes it, and a property that is not
|
|
17243
17910
|
* in `required` is optional.
|
|
17244
17911
|
* - `items` gives a list. `enum` and `const` give `one`. `anyOf` and `oneOf` give a union.
|
|
17912
|
+
* - `$ref` reads a definition in `$defs` or `definitions` of the same schema (TYPE.SCHEMA-REF). Another reference, a
|
|
17913
|
+
* missing definition and a reference in a cycle read as `unknown`.
|
|
17914
|
+
* - `allOf` and the other keywords of a schema give the meet of their types (TYPE.SCHEMA-ALLOF). Records merge their
|
|
17915
|
+
* fields, and a closed part keeps the merge closed.
|
|
17245
17916
|
*
|
|
17246
17917
|
* The type holds each value that the schema accepts. Each keyword that the function does not read tests nothing, as
|
|
17247
|
-
* `unknown`, and the issues name it. Examples are `minimum
|
|
17248
|
-
* reads as `unknown`, because these keywords can permit more values.
|
|
17249
|
-
* and `oneOf` gives the type of the first, and an issue for each other. The function does not throw.
|
|
17918
|
+
* `unknown`, and the issues name it. Examples are `minimum` and `pattern`. A schema with `nullable` or `$dynamicRef`
|
|
17919
|
+
* reads as `unknown`, because these keywords can permit more values. The function does not throw.
|
|
17250
17920
|
*
|
|
17251
17921
|
* @param schema - The schema, as JSON.
|
|
17252
17922
|
* @returns The type, and the problems of the reading with their keys in the schema.
|
|
17253
17923
|
*/
|
|
17254
17924
|
function typeFromSchema(schema) {
|
|
17255
|
-
const reader = new SchemaReader();
|
|
17925
|
+
const reader = new SchemaReader(schema);
|
|
17256
17926
|
try {
|
|
17257
17927
|
return {
|
|
17258
17928
|
type: reader.read(schema, [], 0),
|
|
@@ -17332,6 +18002,6 @@ function samplesAt(values, closed, depth) {
|
|
|
17332
18002
|
function typeFromSamples(values, options = {}) {
|
|
17333
18003
|
return samplesAt(values, options.closed === true, 0);
|
|
17334
18004
|
}
|
|
17335
|
-
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, 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, 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, stored, syntaxFormat, tag, thrown, toJson, treeNodeEvaluator, typeCheck, typeFromSamples, typeFromSchema, typeIssues, typeName, typePath, typeText, typed, typesOf, valueOfThing, verifyReads, walk, worldThing };
|
|
18005
|
+
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, 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 };
|
|
17336
18006
|
|
|
17337
18007
|
//# sourceMappingURL=index.js.map
|