@mark1russell7/coeval 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js CHANGED
@@ -1281,6 +1281,52 @@ function narrow(parent, next) {
1281
1281
  caps
1282
1282
  };
1283
1283
  }
1284
+ /** No capabilities. One list serves each masked part. */
1285
+ const NO_CAPS = Object.freeze([]);
1286
+ /** No capability rules. One list serves each part that no rule narrows. */
1287
+ const NO_RULES = Object.freeze([]);
1288
+ /**
1289
+ * This function gives the capabilities that two lists both permit. An effect is permitted by the result when each
1290
+ * list permits it. When the list `b` permits each capability of `a`, the result is the list `a` itself.
1291
+ *
1292
+ * @param a - The first list, for example the capabilities of a document.
1293
+ * @param b - The second list, for example the list of a rule `only`.
1294
+ * @returns The capabilities that both lists permit.
1295
+ */
1296
+ function intersectCaps(a, b) {
1297
+ if (a.every((cap) => permits(b, cap))) return a;
1298
+ const out = [];
1299
+ for (const cap of b) if (permits(a, cap)) out.push(cap);
1300
+ for (const cap of a) if (permits(b, cap) && !permits(out, cap)) out.push(cap);
1301
+ return out;
1302
+ }
1303
+ /** This function gives the capability rules of a kind that cover a part and change its capabilities. */
1304
+ function rulesFor(rules, path) {
1305
+ if (rules === void 0 || rules.length === 0) return NO_RULES;
1306
+ const out = rules.filter((rule) => rule.rule !== "same" && (rule.in === void 0 || rule.in.some((pattern) => pathMatches(path, pattern))));
1307
+ return out.length === 0 ? NO_RULES : out;
1308
+ }
1309
+ /** This function applies the rules that cover a part to the capabilities of its document. */
1310
+ function capsUnder(rules, caps) {
1311
+ let out = caps;
1312
+ for (const rule of rules) {
1313
+ if (rule.rule === "mask") return NO_CAPS;
1314
+ if (rule.rule === "only") out = intersectCaps(out, rule.caps);
1315
+ }
1316
+ return out;
1317
+ }
1318
+ /**
1319
+ * This function gives the capabilities that a kind gives one of its parts, by the capability rules of its contract.
1320
+ * The kernel and the static kit both use it, thus a run and a check narrow the same way.
1321
+ *
1322
+ * @param rules - The capability rules of the kind (`Kind.caps`).
1323
+ * @param path - The path of the part in the value of the document.
1324
+ * @param caps - The capabilities of the document.
1325
+ * @returns The capabilities of the part: the same list or a smaller one.
1326
+ */
1327
+ function partCaps(rules, path, caps) {
1328
+ return capsUnder(rulesFor(rules, path), caps);
1329
+ }
1284
1330
  function selfLabel(self) {
1285
1331
  try {
1286
1332
  if (isHostThing(self)) return self.label;
@@ -1676,7 +1722,9 @@ function compileNode(c, value, place, declared, depth, address = false) {
1676
1722
  }
1677
1723
  const parts = split.parts.map((slot) => {
1678
1724
  const item = slot.item;
1679
- const compiled = compileNode(c, item, place.concat(slot.path), slot.of, depth + 1, slot.address === true);
1725
+ const own = compileNode(c, item, place.concat(slot.path), slot.of, depth + 1, slot.address === true);
1726
+ const rules = rulesFor(kind?.caps, slot.path);
1727
+ const compiled = rules.length === 0 ? own : gated(rules, own);
1680
1728
  const header = typeof item?.name === "string" && isEnvelope(item) ? item.name : void 0;
1681
1729
  return header === void 0 ? {
1682
1730
  key: slot.key,
@@ -1720,6 +1768,25 @@ function placedCode(inner, place, name) {
1720
1768
  }
1721
1769
  };
1722
1770
  }
1771
+ /**
1772
+ * This function gives the code of a part that capability rules cover. The code narrows the context of the part by
1773
+ * the rules before the part starts.
1774
+ */
1775
+ function gated(rules, part) {
1776
+ const inner = part.code;
1777
+ const steps = part.run;
1778
+ const under = (ctx) => {
1779
+ const caps = capsUnder(rules, ctx.caps);
1780
+ return caps === ctx.caps || caps.length === 0 && ctx.caps.length === 0 ? ctx : {
1781
+ ...ctx,
1782
+ caps
1783
+ };
1784
+ };
1785
+ return {
1786
+ code: (ctx, rt) => inner(under(ctx), rt),
1787
+ run: (ctx, rt) => steps(under(ctx), rt)
1788
+ };
1789
+ }
1723
1790
  /** This function gives the steps of a runner, with the place of each error and of each exception. */
1724
1791
  function placedRun(inner, place, name) {
1725
1792
  return function* (ctx, rt) {
@@ -2146,6 +2213,7 @@ const STD_WORLD = {
2146
2213
  view: "view.op"
2147
2214
  },
2148
2215
  parts: { shape: "list" },
2216
+ caps: [{ rule: "mask" }],
2149
2217
  summary: "It evaluates its part without capabilities, thus an effect in it fails."
2150
2218
  },
2151
2219
  log: {
@@ -2158,6 +2226,7 @@ const STD_WORLD = {
2158
2226
  of: "text"
2159
2227
  },
2160
2228
  side: "run",
2229
+ effects: ["log"],
2161
2230
  summary: "It writes the result of its part to the log. This is an effect."
2162
2231
  },
2163
2232
  write: {
@@ -2170,6 +2239,7 @@ const STD_WORLD = {
2170
2239
  fields: ["value"]
2171
2240
  },
2172
2241
  side: "run",
2242
+ effects: ["write"],
2173
2243
  summary: "It writes the result of its part to the store, at its key. This is an effect."
2174
2244
  }
2175
2245
  },
@@ -2347,13 +2417,10 @@ const STD_RUNNERS = {
2347
2417
  }
2348
2418
  return ok(last);
2349
2419
  },
2350
- "control.pure": function* ({ parts, context }) {
2420
+ "control.pure": function* ({ parts }) {
2351
2421
  const only = parts[0];
2352
2422
  if (only === void 0) return fail("#VALUE!", "pure needs one part.");
2353
- return yield* only.evaluate({
2354
- ...context,
2355
- caps: []
2356
- });
2423
+ return yield* only.evaluate();
2357
2424
  },
2358
2425
  "control.if": function* ({ parts }) {
2359
2426
  const test = parts.find((part) => part.key === "test");
@@ -2878,9 +2945,10 @@ var Visit = class {
2878
2945
  kind;
2879
2946
  typePath;
2880
2947
  address;
2948
+ caps;
2881
2949
  #place;
2882
2950
  #at;
2883
- constructor(place, at, doc, declared, depth, names, later, slot, parent, kind, typePath, address) {
2951
+ constructor(place, at, doc, declared, depth, names, later, slot, parent, kind, typePath, address, caps) {
2884
2952
  this.doc = doc;
2885
2953
  this.declared = declared;
2886
2954
  this.depth = depth;
@@ -2891,6 +2959,7 @@ var Visit = class {
2891
2959
  this.kind = kind;
2892
2960
  this.typePath = typePath;
2893
2961
  this.address = address;
2962
+ this.caps = caps;
2894
2963
  this.#place = place;
2895
2964
  this.#at = at;
2896
2965
  }
@@ -2903,14 +2972,15 @@ var Visit = class {
2903
2972
  };
2904
2973
  /**
2905
2974
  * This function visits each document of a document: the root and each part at each depth, by the contracts of the
2906
- * kinds. A part of a kind that the world does not have is not visited. The walk uses no stack of the host for the
2975
+ * kinds. A part of a kind that the world does not have is not visited. With capabilities in the options, the walk
2976
+ * narrows them for each part by the rules of its kind, as a run does. The walk uses no stack of the host for the
2907
2977
  * depth, thus a deep document cannot overflow it. The time and the memory of a walk are linear in the size of the
2908
2978
  * document. A visit makes the keys of its place and of its path only when a reader asks for them.
2909
2979
  *
2910
2980
  * @param world - The world of the kinds.
2911
2981
  * @param doc - The document, as JSON.
2912
2982
  * @param visit - The function that gets each document. It gives `"skip"` to not visit the parts of a document.
2913
- * @param options - The type of a bare root value, the names of the host, and a function for the problems.
2983
+ * @param options - The type of a bare root value, the names, the capabilities and a function for the problems.
2914
2984
  */
2915
2985
  function walk(world, doc, visit, options = {}) {
2916
2986
  const stack = [{
@@ -2923,7 +2993,8 @@ function walk(world, doc, visit, options = {}) {
2923
2993
  later: NO_NAMES,
2924
2994
  address: false,
2925
2995
  slot: [],
2926
- parent: void 0
2996
+ parent: void 0,
2997
+ caps: options.caps
2927
2998
  }];
2928
2999
  while (stack.length > 0) {
2929
3000
  const item = stack.pop();
@@ -2943,7 +3014,7 @@ function walk(world, doc, visit, options = {}) {
2943
3014
  };
2944
3015
  const found = lookupKind(world, doc.type);
2945
3016
  const kind = found.ok ? found.kind : void 0;
2946
- const here = new Visit(item.place, item.at, doc, envelope === void 0, item.depth, item.names, item.later, item.slot, item.parent, kind, found.ok ? found.path : void 0, item.address ? true : void 0);
3017
+ const here = new Visit(item.place, item.at, doc, envelope === void 0, item.depth, item.names, item.later, item.slot, item.parent, kind, found.ok ? found.path : void 0, item.address ? true : void 0, item.caps);
2947
3018
  if (visit(here) === "skip" || kind === void 0) continue;
2948
3019
  const split = splitParts(kind.parts, doc.value);
2949
3020
  const base = envelope === void 0 ? item.at : {
@@ -2985,7 +3056,8 @@ function walk(world, doc, visit, options = {}) {
2985
3056
  later: hidden.length === 0 ? item.later : /* @__PURE__ */ new Set([...item.later, ...hidden]),
2986
3057
  address: slot.address === true,
2987
3058
  slot: slot.path,
2988
- parent: here
3059
+ parent: here,
3060
+ caps: item.caps === void 0 || kind.caps === void 0 ? item.caps : partCaps(kind.caps, slot.path, item.caps)
2989
3061
  });
2990
3062
  }
2991
3063
  }
@@ -3073,6 +3145,15 @@ function mapRefs(world, doc, change, options = {}) {
3073
3145
  return out;
3074
3146
  }
3075
3147
  /**
3148
+ * This function gives the reason of a `#CAP!`. When a kind around the document narrowed the capabilities, the
3149
+ * reason names the nearest such kind.
3150
+ */
3151
+ function capReason(v, kind) {
3152
+ const text = kind.join(".");
3153
+ for (let up = v.parent; up !== void 0; up = up.parent) if (up.caps !== void 0 && permits(up.caps, kind)) return `The capabilities do not permit the effect ${text} here. The kind ${typeName(up.doc.type)} around it narrows them for its parts.`;
3154
+ return `The capabilities do not permit the effect ${text}.`;
3155
+ }
3156
+ /**
3076
3157
  * This function checks a document before an evaluation, by the contracts of its kinds. It finds the problems
3077
3158
  * that an evaluation finds when it reaches them:
3078
3159
  *
@@ -3083,7 +3164,7 @@ function mapRefs(world, doc, change, options = {}) {
3083
3164
  * - `#DEPTH!`: too much nesting.
3084
3165
  * - `#REF!` and `#STEP?`: a bad path.
3085
3166
  * - `#NAME?`: a name that nothing binds.
3086
- * - `#CAP!`: an effect that the capabilities do not permit.
3167
+ * - `#CAP!`: an effect that the capabilities of its document do not permit. A kind around the document can narrow them.
3087
3168
  *
3088
3169
  * @param machine - The world and the code of the evaluators.
3089
3170
  * @param doc - The document, as JSON.
@@ -3124,12 +3205,13 @@ function check(machine, doc, options = {}) {
3124
3205
  reason: `No rung gives an evaluator for ${typeName(v.doc.type)}.`,
3125
3206
  at: v.at
3126
3207
  });
3127
- if (options.caps !== void 0 && v.kind?.effects !== void 0) {
3208
+ const caps = v.caps;
3209
+ if (caps !== void 0 && v.kind?.effects !== void 0) {
3128
3210
  const kinds = v.kind.effects === "type" ? [v.typePath ?? []] : v.kind.effects.map((kind) => kind.split("."));
3129
- for (const kind of kinds) if (!permits(options.caps, kind)) issues.push({
3211
+ for (const kind of kinds) if (!permits(caps, kind)) issues.push({
3130
3212
  code: "#CAP!",
3131
3213
  place: v.place,
3132
- reason: `The capabilities do not permit the effect ${kind.join(".")}.`,
3214
+ reason: capReason(v, kind),
3133
3215
  at: v.at
3134
3216
  });
3135
3217
  }
@@ -3187,6 +3269,7 @@ function check(machine, doc, options = {}) {
3187
3269
  }, {
3188
3270
  ...options.declaredType === void 0 ? {} : { declaredType: options.declaredType },
3189
3271
  ...Array.isArray(options.names) ? { names: options.names } : {},
3272
+ ...options.caps === void 0 ? {} : { caps: options.caps },
3190
3273
  problem: (problem) => issues.push({
3191
3274
  code: problem.code,
3192
3275
  place: problem.place,
@@ -3712,6 +3795,6 @@ function formulaMachine(profile = {}, more = {}) {
3712
3795
  };
3713
3796
  }
3714
3797
  //#endregion
3715
- export { CONSTRUCTS, ENVELOPE_KEYS, Failure, Held, PARTS, PART_INFO, ROOTS, RUNGS, STD_CAPS, STD_EVALUATORS, STD_EXT, STD_MACHINE, STD_RUNNERS, STD_WALKERS, STD_WORLD, THING, ask, capKeys, check, checkSteps, classify, context, dataEdges, derefStep, describe, docEquals, effectEdges, entriesAsJson, evaluate, fail, failures, field, flatten, formulaEvaluators, formulaKinds, formulaMachine, fromJson, isAlias, isAllowedOrder, isClosure, isEnvelope, isHostThing, isKey, isKind, isNamespace, isRecord, isRef, isStackOverflow, isTypeRef, jsTruthy, kindDocument, kindNamed, kindOf, layers, looksLikeKind, lookupKind, makeContext, mapRefs, narrow, nearestWalker, nodeAt, ok, pathMatches, permits, placed, planner, prepare, ref, refsOf, resolve, run, splitParts, stored, tag, thrown, toJson, typeName, typePath, typed, valueOfThing, walk, worldThing };
3798
+ export { CONSTRUCTS, ENVELOPE_KEYS, Failure, Held, PARTS, PART_INFO, ROOTS, RUNGS, STD_CAPS, STD_EVALUATORS, STD_EXT, STD_MACHINE, STD_RUNNERS, STD_WALKERS, STD_WORLD, THING, ask, capKeys, check, checkSteps, classify, context, dataEdges, derefStep, describe, docEquals, effectEdges, entriesAsJson, evaluate, fail, failures, field, flatten, formulaEvaluators, formulaKinds, formulaMachine, fromJson, intersectCaps, isAlias, isAllowedOrder, isClosure, isEnvelope, isHostThing, isKey, isKind, isNamespace, isRecord, isRef, isStackOverflow, isTypeRef, jsTruthy, kindDocument, kindNamed, kindOf, layers, looksLikeKind, lookupKind, makeContext, mapRefs, narrow, nearestWalker, nodeAt, ok, partCaps, pathMatches, permits, placed, planner, prepare, ref, refsOf, resolve, run, splitParts, stored, tag, thrown, toJson, typeName, typePath, typed, valueOfThing, walk, worldThing };
3716
3799
 
3717
3800
  //# sourceMappingURL=index.js.map