@suss/adapter-ruby 0.19.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/dist/index.js CHANGED
@@ -5,25 +5,53 @@ var __export = (target, all) => {
5
5
  };
6
6
 
7
7
  // src/ast.ts
8
- import { IdMap, IdSet } from "@suss/extractor";
8
+ import { IdMap, IdSet, SKIP_CHILDREN, walkDescendants } from "@suss/extractor";
9
9
  function rangeOf(node) {
10
10
  return {
11
11
  start: node.startPosition.row + 1,
12
12
  end: node.endPosition.row + 1
13
13
  };
14
14
  }
15
+ function spanOf(node) {
16
+ return { start: node.startIndex, end: node.endIndex };
17
+ }
15
18
  function field(node, name) {
16
19
  return node.childForFieldName(name);
17
20
  }
18
21
  function bodyStatements(body) {
19
22
  return body.namedChildren.filter((child) => child !== null);
20
23
  }
24
+ var OWN_BODY_TYPES = /* @__PURE__ */ new Set([
25
+ "method",
26
+ "singleton_method",
27
+ "lambda",
28
+ "class",
29
+ "module",
30
+ "singleton_class"
31
+ ]);
32
+ var ARGUMENT_LIST_TYPE = "argument_list";
33
+ function runStatements(body, blockConfigures = () => false) {
34
+ const found = [];
35
+ const readsItsChildren = (node) => {
36
+ if (OWN_BODY_TYPES.has(node.type) || node.type === ARGUMENT_LIST_TYPE) {
37
+ return false;
38
+ }
39
+ return !(node.type === "call" && blockConfigures(node));
40
+ };
41
+ walkDescendants(body, null, {
42
+ at: (node) => {
43
+ found.push(node);
44
+ },
45
+ into: (node) => readsItsChildren(node) ? null : SKIP_CHILDREN
46
+ });
47
+ return found;
48
+ }
21
49
  function symbolValue(node) {
22
50
  return node.type === "simple_symbol" ? node.text.slice(1) : null;
23
51
  }
24
52
  function instanceMethodsByName(body) {
25
53
  const methods = /* @__PURE__ */ new Map();
26
- for (const stmt of bodyStatements(body)) {
54
+ for (const stmt of runStatements(body)) {
27
55
  if (stmt.type !== "method") {
28
56
  continue;
29
57
  }
@@ -36,7 +64,7 @@ function instanceMethodsByName(body) {
36
64
  }
37
65
  function bareCallArgumentGroups(body, name) {
38
66
  const groups = [];
39
- for (const stmt of bodyStatements(body)) {
67
+ for (const stmt of runStatements(body)) {
40
68
  if (stmt.type !== "call" || field(stmt, "receiver") !== null) {
41
69
  continue;
42
70
  }
@@ -139,7 +167,7 @@ function walkClasses(root, visit) {
139
167
  });
140
168
  }
141
169
  function walkDefinitions(root, visit) {
142
- walkBody(bodyStatements(root), [], visit);
170
+ walkBody(runStatements(root), [], visit);
143
171
  }
144
172
  function walkBody(statements, nesting, visit) {
145
173
  for (const stmt of statements) {
@@ -178,7 +206,7 @@ function visitClass(node, nesting, visit) {
178
206
  bodyNesting: identity.bodyNesting
179
207
  });
180
208
  if (bodyNode !== null) {
181
- walkBody(bodyStatements(bodyNode), identity.bodyNesting, visit);
209
+ walkBody(runStatements(bodyNode), identity.bodyNesting, visit);
182
210
  }
183
211
  }
184
212
  function visitModule(node, nesting, visit) {
@@ -197,7 +225,7 @@ function visitModule(node, nesting, visit) {
197
225
  bodyNesting: identity.bodyNesting
198
226
  });
199
227
  if (bodyNode !== null) {
200
- walkBody(bodyStatements(bodyNode), identity.bodyNesting, visit);
228
+ walkBody(runStatements(bodyNode), identity.bodyNesting, visit);
201
229
  }
202
230
  }
203
231
  function stripTypeSuffixName(qualifiedName) {
@@ -353,7 +381,7 @@ function definitionIn(blocks, name) {
353
381
  }
354
382
  return { method, dynamic };
355
383
  }
356
- function inheritedStatements(ancestry) {
384
+ function inheritedStatements(ancestry, blockConfigures) {
357
385
  const statements = [];
358
386
  for (const entry of [...ancestry].reverse()) {
359
387
  if (entry.type !== "bodies") {
@@ -364,7 +392,7 @@ function inheritedStatements(ancestry) {
364
392
  if (body === null) {
365
393
  continue;
366
394
  }
367
- for (const statement of bodyStatements(body)) {
395
+ for (const statement of runStatements(body, blockConfigures)) {
368
396
  statements.push({ block, statement });
369
397
  }
370
398
  }
@@ -590,14 +618,6 @@ function lowerRubyBody(body, terminals) {
590
618
  }
591
619
 
592
620
  // src/paths/effects.ts
593
- var DECLARATION_TYPES = /* @__PURE__ */ new Set([
594
- "method",
595
- "singleton_method",
596
- "lambda",
597
- "class",
598
- "module",
599
- "singleton_class"
600
- ]);
601
621
  var RAISE_NAMES2 = /* @__PURE__ */ new Set(["raise", "fail"]);
602
622
  var BLOCK_TYPES = /* @__PURE__ */ new Set([
603
623
  "body_statement",
@@ -645,7 +665,7 @@ function isRaise2(node) {
645
665
  }
646
666
  function bodyCalls(node, found = []) {
647
667
  for (const child of children(node)) {
648
- if (DECLARATION_TYPES.has(child.type)) {
668
+ if (OWN_BODY_TYPES.has(child.type)) {
649
669
  continue;
650
670
  }
651
671
  if (child.type === "call" && !isPropertyRead(child) && !isRaise2(child)) {
@@ -731,6 +751,9 @@ function invocationEffects(definitionNode) {
731
751
  });
732
752
  }
733
753
 
754
+ // src/storage.ts
755
+ import { deriveOnDemand, evaluate } from "@suss/datalog";
756
+
734
757
  // ../../../node_modules/zod/v4/classic/external.js
735
758
  var external_exports = {};
736
759
  __export(external_exports, {
@@ -1411,8 +1434,8 @@ function assertNever(_x) {
1411
1434
  function assert(_) {
1412
1435
  }
1413
1436
  function getEnumValues(entries) {
1414
- const numericValues = Object.values(entries).filter((v) => typeof v === "number");
1415
- const values = Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v]) => v);
1437
+ const numericValues = Object.values(entries).filter((v2) => typeof v2 === "number");
1438
+ const values = Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v2]) => v2);
1416
1439
  return values;
1417
1440
  }
1418
1441
  function joinValues(array2, separator = "|") {
@@ -1466,9 +1489,9 @@ function defineLazy(object2, key, getter) {
1466
1489
  }
1467
1490
  return value;
1468
1491
  },
1469
- set(v) {
1492
+ set(v2) {
1470
1493
  Object.defineProperty(object2, key, {
1471
- value: v
1494
+ value: v2
1472
1495
  // configurable: true,
1473
1496
  });
1474
1497
  },
@@ -3155,10 +3178,10 @@ var $ZodUUID = /* @__PURE__ */ $constructor("$ZodUUID", (inst, def) => {
3155
3178
  v7: 7,
3156
3179
  v8: 8
3157
3180
  };
3158
- const v = versionMap[def.version];
3159
- if (v === void 0)
3181
+ const v2 = versionMap[def.version];
3182
+ if (v2 === void 0)
3160
3183
  throw new Error(`Invalid UUID version: "${def.version}"`);
3161
- def.pattern ?? (def.pattern = uuid(v));
3184
+ def.pattern ?? (def.pattern = uuid(v2));
3162
3185
  } else
3163
3186
  def.pattern ?? (def.pattern = uuid());
3164
3187
  $ZodStringFormat.init(inst, def);
@@ -3763,8 +3786,8 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
3763
3786
  const field2 = shape[key]._zod;
3764
3787
  if (field2.values) {
3765
3788
  propValues[key] ?? (propValues[key] = /* @__PURE__ */ new Set());
3766
- for (const v of field2.values)
3767
- propValues[key].add(v);
3789
+ for (const v2 of field2.values)
3790
+ propValues[key].add(v2);
3768
3791
  }
3769
3792
  }
3770
3793
  return propValues;
@@ -4059,10 +4082,10 @@ var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnio
4059
4082
  const pv = option._zod.propValues;
4060
4083
  if (!pv || Object.keys(pv).length === 0)
4061
4084
  throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(option)}"`);
4062
- for (const [k, v] of Object.entries(pv)) {
4085
+ for (const [k, v2] of Object.entries(pv)) {
4063
4086
  if (!propValues[k])
4064
4087
  propValues[k] = /* @__PURE__ */ new Set();
4065
- for (const val of v) {
4088
+ for (const val of v2) {
4066
4089
  propValues[k].add(val);
4067
4090
  }
4068
4091
  }
@@ -4076,11 +4099,11 @@ var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnio
4076
4099
  const values = o._zod.propValues?.[def.discriminator];
4077
4100
  if (!values || values.size === 0)
4078
4101
  throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(o)}"`);
4079
- for (const v of values) {
4080
- if (map2.has(v)) {
4081
- throw new Error(`Duplicate discriminator value "${String(v)}"`);
4102
+ for (const v2 of values) {
4103
+ if (map2.has(v2)) {
4104
+ throw new Error(`Duplicate discriminator value "${String(v2)}"`);
4082
4105
  }
4083
- map2.set(v, o);
4106
+ map2.set(v2, o);
4084
4107
  }
4085
4108
  }
4086
4109
  return map2;
@@ -4719,8 +4742,8 @@ var $ZodPrefault = /* @__PURE__ */ $constructor("$ZodPrefault", (inst, def) => {
4719
4742
  var $ZodNonOptional = /* @__PURE__ */ $constructor("$ZodNonOptional", (inst, def) => {
4720
4743
  $ZodType.init(inst, def);
4721
4744
  defineLazy(inst._zod, "values", () => {
4722
- const v = def.innerType._zod.values;
4723
- return v ? new Set([...v].filter((x) => x !== void 0)) : void 0;
4745
+ const v2 = def.innerType._zod.values;
4746
+ return v2 ? new Set([...v2].filter((x) => x !== void 0)) : void 0;
4724
4747
  });
4725
4748
  inst._zod.parse = (payload, ctx) => {
4726
4749
  const result = def.innerType._zod.run(payload, ctx);
@@ -7117,7 +7140,7 @@ var error17 = () => {
7117
7140
  if (issue2.values.length === 1) {
7118
7141
  return `\u05E2\u05E8\u05DA \u05DC\u05D0 \u05EA\u05E7\u05D9\u05DF: \u05D4\u05E2\u05E8\u05DA \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA ${stringifyPrimitive(issue2.values[0])}`;
7119
7142
  }
7120
- const stringified = issue2.values.map((v) => stringifyPrimitive(v));
7143
+ const stringified = issue2.values.map((v2) => stringifyPrimitive(v2));
7121
7144
  if (issue2.values.length === 2) {
7122
7145
  return `\u05E2\u05E8\u05DA \u05DC\u05D0 \u05EA\u05E7\u05D9\u05DF: \u05D4\u05D0\u05E4\u05E9\u05E8\u05D5\u05D9\u05D5\u05EA \u05D4\u05DE\u05EA\u05D0\u05D9\u05DE\u05D5\u05EA \u05D4\u05DF ${stringified[0]} \u05D0\u05D5 ${stringified[1]}`;
7123
7146
  }
@@ -11872,7 +11895,7 @@ function _set(Class2, valueType, params) {
11872
11895
  }
11873
11896
  // @__NO_SIDE_EFFECTS__
11874
11897
  function _enum(Class2, values, params) {
11875
- const entries = Array.isArray(values) ? Object.fromEntries(values.map((v) => [v, v])) : values;
11898
+ const entries = Array.isArray(values) ? Object.fromEntries(values.map((v2) => [v2, v2])) : values;
11876
11899
  return new Class2({
11877
11900
  type: "enum",
11878
11901
  entries,
@@ -12077,8 +12100,8 @@ function _stringbool(Classes, _params) {
12077
12100
  let truthyArray = params.truthy ?? ["true", "1", "yes", "on", "y", "enabled"];
12078
12101
  let falsyArray = params.falsy ?? ["false", "0", "no", "off", "n", "disabled"];
12079
12102
  if (params.case !== "sensitive") {
12080
- truthyArray = truthyArray.map((v) => typeof v === "string" ? v.toLowerCase() : v);
12081
- falsyArray = falsyArray.map((v) => typeof v === "string" ? v.toLowerCase() : v);
12103
+ truthyArray = truthyArray.map((v2) => typeof v2 === "string" ? v2.toLowerCase() : v2);
12104
+ falsyArray = falsyArray.map((v2) => typeof v2 === "string" ? v2.toLowerCase() : v2);
12082
12105
  }
12083
12106
  const truthySet = new Set(truthyArray);
12084
12107
  const falsySet = new Set(falsyArray);
@@ -12620,9 +12643,9 @@ var dateProcessor = (_schema, ctx, _json, _params) => {
12620
12643
  var enumProcessor = (schema, _ctx, json2, _params) => {
12621
12644
  const def = schema._zod.def;
12622
12645
  const values = getEnumValues(def.entries);
12623
- if (values.every((v) => typeof v === "number"))
12646
+ if (values.every((v2) => typeof v2 === "number"))
12624
12647
  json2.type = "number";
12625
- if (values.every((v) => typeof v === "string"))
12648
+ if (values.every((v2) => typeof v2 === "string"))
12626
12649
  json2.type = "string";
12627
12650
  json2.enum = values;
12628
12651
  };
@@ -12655,13 +12678,13 @@ var literalProcessor = (schema, ctx, json2, _params) => {
12655
12678
  json2.const = val;
12656
12679
  }
12657
12680
  } else {
12658
- if (vals.every((v) => typeof v === "number"))
12681
+ if (vals.every((v2) => typeof v2 === "number"))
12659
12682
  json2.type = "number";
12660
- if (vals.every((v) => typeof v === "string"))
12683
+ if (vals.every((v2) => typeof v2 === "string"))
12661
12684
  json2.type = "string";
12662
- if (vals.every((v) => typeof v === "boolean"))
12685
+ if (vals.every((v2) => typeof v2 === "boolean"))
12663
12686
  json2.type = "boolean";
12664
- if (vals.every((v) => v === null))
12687
+ if (vals.every((v2) => v2 === null))
12665
12688
  json2.type = "null";
12666
12689
  json2.enum = vals;
12667
12690
  }
@@ -12759,11 +12782,11 @@ var objectProcessor = (schema, ctx, _json, params) => {
12759
12782
  }
12760
12783
  const allKeys = new Set(Object.keys(shape));
12761
12784
  const requiredKeys = new Set([...allKeys].filter((key) => {
12762
- const v = def.shape[key]._zod;
12785
+ const v2 = def.shape[key]._zod;
12763
12786
  if (ctx.io === "input") {
12764
- return v.optin === void 0;
12787
+ return v2.optin === void 0;
12765
12788
  } else {
12766
- return v.optout === void 0;
12789
+ return v2.optout === void 0;
12767
12790
  }
12768
12791
  }));
12769
12792
  if (requiredKeys.size > 0) {
@@ -12883,7 +12906,7 @@ var recordProcessor = (schema, ctx, _json, params) => {
12883
12906
  }
12884
12907
  const keyValues = keyType._zod.values;
12885
12908
  if (keyValues) {
12886
- const validKeyValues = [...keyValues].filter((v) => typeof v === "string" || typeof v === "number");
12909
+ const validKeyValues = [...keyValues].filter((v2) => typeof v2 === "string" || typeof v2 === "number");
12887
12910
  if (validKeyValues.length > 0) {
12888
12911
  json2.required = validKeyValues;
12889
12912
  }
@@ -13448,12 +13471,12 @@ function _installLazyMethods(inst, group, methods) {
13448
13471
  });
13449
13472
  return bound;
13450
13473
  },
13451
- set(v) {
13474
+ set(v2) {
13452
13475
  Object.defineProperty(this, key, {
13453
13476
  configurable: true,
13454
13477
  writable: true,
13455
13478
  enumerable: true,
13456
- value: v
13479
+ value: v2
13457
13480
  });
13458
13481
  }
13459
13482
  });
@@ -14341,7 +14364,7 @@ var ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => {
14341
14364
  };
14342
14365
  });
14343
14366
  function _enum2(values, params) {
14344
- const entries = Array.isArray(values) ? Object.fromEntries(values.map((v) => [v, v])) : values;
14367
+ const entries = Array.isArray(values) ? Object.fromEntries(values.map((v2) => [v2, v2])) : values;
14345
14368
  return new ZodEnum({
14346
14369
  type: "enum",
14347
14370
  entries,
@@ -14895,10 +14918,10 @@ function convertBaseSchema(schema, ctx) {
14895
14918
  if (enumValues.length === 1) {
14896
14919
  return z.literal(enumValues[0]);
14897
14920
  }
14898
- if (enumValues.every((v) => typeof v === "string")) {
14921
+ if (enumValues.every((v2) => typeof v2 === "string")) {
14899
14922
  return z.enum(enumValues);
14900
14923
  }
14901
- const literalSchemas = enumValues.map((v) => z.literal(v));
14924
+ const literalSchemas = enumValues.map((v2) => z.literal(v2));
14902
14925
  if (literalSchemas.length < 2) {
14903
14926
  return literalSchemas[0];
14904
14927
  }
@@ -15245,7 +15268,7 @@ function date4(params) {
15245
15268
  // ../../../node_modules/zod/v4/classic/external.js
15246
15269
  config(en_default());
15247
15270
 
15248
- // ../../ir-core/dist/chunk-HSJYPBJU.js
15271
+ // ../../ir-core/dist/chunk-QHFMZPEG.js
15249
15272
  function gqlIdentityKey(typeName, fieldName) {
15250
15273
  return `gql:${typeName}.${fieldName}`;
15251
15274
  }
@@ -15255,6 +15278,9 @@ function fnIdentityKey(packageName, exportPath) {
15255
15278
  function busIdentityKey(messageBus, subject) {
15256
15279
  return `bus:${messageBus} ${subject}`;
15257
15280
  }
15281
+ function unitIdentityKey(deploymentTarget, instanceName) {
15282
+ return `unit:${deploymentTarget} ${instanceName}`;
15283
+ }
15258
15284
  function metricIdentityKey(metricSystem, metricType) {
15259
15285
  return `metric:${metricSystem} ${metricType}`;
15260
15286
  }
@@ -15309,14 +15335,24 @@ var functionCallSemantics = defineBoundarySemantics({
15309
15335
  */
15310
15336
  canPair: () => true,
15311
15337
  /**
15312
- * `"fn:<package>::<exportPath>"` when both are set. Other in-process
15313
- * function-call units, such as components and bare handlers inside
15314
- * one repo, have no key at all.
15338
+ * `"fn:<package>::<exportPath>"` when both are set, and
15339
+ * `"fn:<module>::<exportName>"` for an in-repo unit that states its
15340
+ * module, the way a server action does. Components and bare
15341
+ * handlers state neither and have no key at all.
15315
15342
  */
15343
+ rewritePaths(semantics, rewrite) {
15344
+ if (semantics.module === void 0) {
15345
+ return semantics;
15346
+ }
15347
+ return { ...semantics, module: rewrite(semantics.module) };
15348
+ },
15316
15349
  identityKey(semantics) {
15317
15350
  if (semantics.package !== void 0 && semantics.exportPath !== void 0 && semantics.exportPath.length > 0) {
15318
15351
  return fnIdentityKey(semantics.package, semantics.exportPath);
15319
15352
  }
15353
+ if (semantics.module !== void 0 && semantics.exportName !== void 0) {
15354
+ return fnIdentityKey(semantics.module, [semantics.exportName]);
15355
+ }
15320
15356
  return null;
15321
15357
  }
15322
15358
  }
@@ -15657,6 +15693,14 @@ var restSemantics = defineBoundarySemantics({
15657
15693
  }
15658
15694
  return routePathAdmits(semantics.path, path4) ? "match" : "nomatch";
15659
15695
  },
15696
+ /**
15697
+ * A route the registration pattern admits is inside it. A route
15698
+ * whose path this source never gave is left outside, because
15699
+ * nothing here can show it is one the pattern covers.
15700
+ */
15701
+ withinScope(semantics, scope) {
15702
+ return semantics.path !== null && routePathAdmits(scope, semantics.path);
15703
+ },
15660
15704
  /**
15661
15705
  * A call whose base URL the deployment fills in, resolved to the
15662
15706
  * path it reaches.
@@ -15778,7 +15822,62 @@ var storageSemantics = defineBoundarySemantics({
15778
15822
  /** A query returns rows or items, not a status and a body. */
15779
15823
  exchangesHttpResponses: false,
15780
15824
  reportsUnpairedItself: false,
15781
- identityKey: () => null
15825
+ identityKey: () => null,
15826
+ displayLabel: storageLabel
15827
+ }
15828
+ });
15829
+ function storageLabel(semantics) {
15830
+ return `${semantics.storageSystem}:${storageContainerLabel(semantics)}`;
15831
+ }
15832
+ function storageContainerLabel(semantics) {
15833
+ const container = semantics.container ?? "<unnamed container>";
15834
+ const addressed = semantics.accessPath === null ? container : `${container}#${semantics.accessPath}`;
15835
+ return semantics.scope === "default" ? addressed : `${semantics.scope}/${addressed}`;
15836
+ }
15837
+ var UnitInvocationSemanticsSchema = DeployableUnitSchema.extend({
15838
+ name: external_exports.literal("unit-invocation"),
15839
+ instanceName: DeployableUnitSchema.shape.instanceName.nullable()
15840
+ });
15841
+ var unitInvocationSemantics = defineBoundarySemantics({
15842
+ name: "unit-invocation",
15843
+ schema: UnitInvocationSemanticsSchema,
15844
+ // faas.name is the deployed function's own name and instanceName is
15845
+ // the deployment template's logical id, which is a different string.
15846
+ // Runtime config leaves the pair off for the same reason.
15847
+ semconv: {},
15848
+ behavior: {
15849
+ /**
15850
+ * A synchronous invoke gives back whatever the handler returned,
15851
+ * which is a value rather than a status and a body. A handler's
15852
+ * return only becomes an HTTP response under a proxy integration,
15853
+ * and that route gets a REST binding instead of this one.
15854
+ */
15855
+ exchangesHttpResponses: false,
15856
+ /**
15857
+ * A unit nothing in the run invokes is the ordinary case, since
15858
+ * most services are reached from a stack suss never read. So an
15859
+ * uninvoked unit stays in the generic unmatched list rather than
15860
+ * being reported as a problem here.
15861
+ */
15862
+ reportsUnpairedItself: false,
15863
+ identityKey(semantics) {
15864
+ if (semantics.instanceName === null) {
15865
+ return null;
15866
+ }
15867
+ return unitIdentityKey(
15868
+ semantics.deploymentTarget,
15869
+ semantics.instanceName
15870
+ );
15871
+ },
15872
+ displayLabel(semantics) {
15873
+ if (semantics.instanceName === null) {
15874
+ return `unit:${semantics.deploymentTarget} (named at runtime)`;
15875
+ }
15876
+ return unitIdentityKey(
15877
+ semantics.deploymentTarget,
15878
+ semantics.instanceName
15879
+ );
15880
+ }
15782
15881
  }
15783
15882
  });
15784
15883
  var SemanticsSchema = external_exports.discriminatedUnion("name", [
@@ -15789,7 +15888,8 @@ var SemanticsSchema = external_exports.discriminatedUnion("name", [
15789
15888
  runtimeConfigSemantics.schema,
15790
15889
  storageSemantics.schema,
15791
15890
  messageBusSemantics.schema,
15792
- metricSemantics.schema
15891
+ metricSemantics.schema,
15892
+ unitInvocationSemantics.schema
15793
15893
  ]);
15794
15894
  var DEFINITIONS = [
15795
15895
  restSemantics,
@@ -15799,7 +15899,8 @@ var DEFINITIONS = [
15799
15899
  runtimeConfigSemantics,
15800
15900
  storageSemantics,
15801
15901
  messageBusSemantics,
15802
- metricSemantics
15902
+ metricSemantics,
15903
+ unitInvocationSemantics
15803
15904
  ];
15804
15905
  var BY_NAME = new Map(
15805
15906
  DEFINITIONS.map((d) => [d.name, d])
@@ -15827,7 +15928,16 @@ var ConfidenceInfoSchema = external_exports.object({
15827
15928
  });
15828
15929
  var SourceLocationSchema = external_exports.object({
15829
15930
  file: external_exports.string(),
15931
+ /** Line numbers, for a person reading the summary or an editor link. */
15830
15932
  range: external_exports.object({ start: external_exports.number(), end: external_exports.number() }),
15933
+ /**
15934
+ * Character offsets of the unit in its file. Identity and joins
15935
+ * measure with these, since two functions can share a line and never
15936
+ * an offset range; the line `range` above is the presentation of the
15937
+ * same place. Absent on summaries no source position backs, a
15938
+ * contract artifact's say.
15939
+ */
15940
+ span: external_exports.object({ start: external_exports.number(), end: external_exports.number() }).optional(),
15831
15941
  exportName: external_exports.string().nullable(),
15832
15942
  /**
15833
15943
  * The project the extract was pointed at, by the name that project
@@ -15880,6 +15990,13 @@ var TypeShapeSchema = external_exports.lazy(
15880
15990
  );
15881
15991
 
15882
15992
  // ../../ir-core/dist/index.js
15993
+ var RelationSchema = external_exports.enum([
15994
+ "provides",
15995
+ "reads",
15996
+ "writes",
15997
+ "invokes"
15998
+ ]);
15999
+ var EffectRelationSchema = RelationSchema.exclude(["provides"]);
15883
16000
  var SuppressionSideSchema = external_exports.object({
15884
16001
  summary: external_exports.string().optional(),
15885
16002
  transitionId: external_exports.string().optional()
@@ -15952,6 +16069,750 @@ function storageBinding(opts) {
15952
16069
  };
15953
16070
  }
15954
16071
 
16072
+ // ../../resolution/dist/index.js
16073
+ import { ruleLabel } from "@suss/datalog";
16074
+ import { constant, lit, rule, variable as v } from "@suss/datalog";
16075
+ var VALUE_STEP = constant("value");
16076
+ var NAMESPACE_IMPORT_NAME = "*";
16077
+ var NAMESPACE_IMPORT = constant(NAMESPACE_IMPORT_NAME);
16078
+ var RESULT_STEP = constant("result");
16079
+ var RESOLUTION_RULES = [
16080
+ // Aliasing: const x = y, or an identifier referencing a declaration.
16081
+ // A language with a hop of its own, like JavaScript's `.bind`, states
16082
+ // it as a step too, or every question but `comesTo` misses it.
16083
+ rule(
16084
+ "stepsTo",
16085
+ [v("x"), v("y"), VALUE_STEP],
16086
+ [lit("binds", v("x"), v("y"))],
16087
+ "alias"
16088
+ ),
16089
+ // A name written more than once has the value the last write left
16090
+ // there. The adapter works out which write that is and stays quiet
16091
+ // when control flow decides, so such a name steps nowhere at all.
16092
+ rule(
16093
+ "stepsTo",
16094
+ [v("x"), v("y"), VALUE_STEP],
16095
+ [lit("endsHolding", v("x"), v("y"))],
16096
+ "last write"
16097
+ ),
16098
+ // A fallback says the value is one of its branches, so each branch is
16099
+ // a step. A branch that resolves to nothing makes no claim, and two
16100
+ // branches resolving to different things fail the single-answer policy.
16101
+ rule(
16102
+ "stepsTo",
16103
+ [v("x"), v("b"), VALUE_STEP],
16104
+ [lit("fallbackBranch", v("x"), v("b"))],
16105
+ "fallback"
16106
+ ),
16107
+ // An import steps to what the module exports under that name.
16108
+ rule(
16109
+ "stepsTo",
16110
+ [v("x"), v("value"), VALUE_STEP],
16111
+ [
16112
+ lit("imports", v("x"), v("m"), v("n")),
16113
+ lit("moduleExport", v("m"), v("n"), v("value"))
16114
+ ],
16115
+ "import"
16116
+ ),
16117
+ // A parameter steps to what a call passes it. A function called from
16118
+ // several places leaves its parameter with more than one value, and a
16119
+ // caller that needs those apart asks `paramAt`.
16120
+ rule(
16121
+ "stepsTo",
16122
+ [v("p"), v("a"), VALUE_STEP],
16123
+ [lit("passesArgument", v("r"), v("p"), v("a"))],
16124
+ "argument"
16125
+ ),
16126
+ // Reading a property steps to what the object contains under that
16127
+ // name, whichever way the object arrived: `routes.list` off a name,
16128
+ // or `make(body).handle` off a call.
16129
+ rule(
16130
+ "stepsTo",
16131
+ [v("x"), v("held"), VALUE_STEP],
16132
+ [
16133
+ lit("readsProperty", v("x"), v("o"), v("n")),
16134
+ lit("objectOf", v("o"), v("obj")),
16135
+ lit("contains", v("obj"), v("n"), v("held"))
16136
+ ],
16137
+ "property read"
16138
+ ),
16139
+ // Calling a class makes one of it, so the call steps to the class and
16140
+ // a method read off the result is the one the class declares. The
16141
+ // caveat below is about a factory function, and a class is not one.
16142
+ rule(
16143
+ "stepsTo",
16144
+ [v("r"), v("cls"), VALUE_STEP],
16145
+ [
16146
+ lit("call", v("r"), v("c")),
16147
+ lit("comesTo", v("c"), v("cls")),
16148
+ lit("objectValue", v("cls"))
16149
+ ],
16150
+ "class instance"
16151
+ ),
16152
+ // Wrapper transparency, derived: calling a factory that returns a
16153
+ // function which calls its parameter k steps to argument k.
16154
+ rule(
16155
+ "stepsTo",
16156
+ [v("r"), v("a"), VALUE_STEP],
16157
+ [
16158
+ lit("call", v("r"), v("c")),
16159
+ lit("comesTo", v("c"), v("f")),
16160
+ lit("unwraps", v("f"), v("k")),
16161
+ lit("callArg", v("r"), v("k"), v("a"))
16162
+ ],
16163
+ "factory unwrap"
16164
+ ),
16165
+ // Wrapper transparency, declared: a pack says this callee wraps
16166
+ // argument k. The callee has to come from the library the pack said,
16167
+ // so a local object spelled the same way is not mistaken for it.
16168
+ rule(
16169
+ "stepsTo",
16170
+ [v("r"), v("a"), VALUE_STEP],
16171
+ [
16172
+ lit("calleeName", v("r"), v("n")),
16173
+ lit("unwrapsByName", v("n"), v("k")),
16174
+ lit("wrapperModule", v("n"), v("m")),
16175
+ lit("calleeOrigin", v("r"), v("m")),
16176
+ lit("callArg", v("r"), v("k"), v("a"))
16177
+ ],
16178
+ "declared wrapper"
16179
+ ),
16180
+ // The one step that runs a function forwards: a call steps to what
16181
+ // the function it invokes returns.
16182
+ rule(
16183
+ "stepsTo",
16184
+ [v("r"), v("ret"), RESULT_STEP],
16185
+ [lit("invokes", v("r"), v("f")), lit("returnsValue", v("f"), v("ret"))],
16186
+ "call result"
16187
+ ),
16188
+ // Where a walk gets to, and whether it ran a call on the way. A value
16189
+ // step keeps whatever the rest of the walk was, and a result step
16190
+ // makes the whole walk one that ran a call.
16191
+ rule(
16192
+ "reaches",
16193
+ [v("x"), v("z"), v("kind")],
16194
+ [lit("stepsTo", v("x"), v("z"), v("kind"))]
16195
+ ),
16196
+ rule(
16197
+ "reaches",
16198
+ [v("x"), v("z"), v("kind")],
16199
+ [
16200
+ lit("stepsTo", v("x"), v("y"), VALUE_STEP),
16201
+ lit("reaches", v("y"), v("z"), v("kind"))
16202
+ ]
16203
+ ),
16204
+ // Two rules rather than one leaving the rest of the walk's kind free.
16205
+ // A free kind is a second question about the same relation, and a
16206
+ // demand-driven run then derives both to answer either.
16207
+ rule(
16208
+ "reaches",
16209
+ [v("x"), v("z"), RESULT_STEP],
16210
+ [
16211
+ lit("stepsTo", v("x"), v("y"), RESULT_STEP),
16212
+ lit("reaches", v("y"), v("z"), VALUE_STEP)
16213
+ ]
16214
+ ),
16215
+ rule(
16216
+ "reaches",
16217
+ [v("x"), v("z"), RESULT_STEP],
16218
+ [
16219
+ lit("stepsTo", v("x"), v("y"), RESULT_STEP),
16220
+ lit("reaches", v("y"), v("z"), RESULT_STEP)
16221
+ ]
16222
+ ),
16223
+ // What a value comes down to: the walk that never ran a call, stopped
16224
+ // at a function or an object. Something already written out comes to
16225
+ // itself, and every other walk ends at one of those.
16226
+ rule("comesTo", [v("x"), v("x")], [lit("func", v("x"))]),
16227
+ rule("comesTo", [v("x"), v("x")], [lit("objectValue", v("x"))]),
16228
+ rule(
16229
+ "comesTo",
16230
+ [v("x"), v("z")],
16231
+ [lit("reaches", v("x"), v("z"), VALUE_STEP), lit("func", v("z"))]
16232
+ ),
16233
+ rule(
16234
+ "comesTo",
16235
+ [v("x"), v("z")],
16236
+ [lit("reaches", v("x"), v("z"), VALUE_STEP), lit("objectValue", v("z"))]
16237
+ ),
16238
+ // The same stopping condition, for the walk that ran a call. A call
16239
+ // gets no `comesTo` answer on purpose: coming back with what a
16240
+ // factory returned would fight the unwrapping answer.
16241
+ rule(
16242
+ "givesBack",
16243
+ [v("x"), v("z")],
16244
+ [lit("reaches", v("x"), v("z"), RESULT_STEP), lit("func", v("z"))]
16245
+ ),
16246
+ rule(
16247
+ "givesBack",
16248
+ [v("x"), v("z")],
16249
+ [lit("reaches", v("x"), v("z"), RESULT_STEP), lit("objectValue", v("z"))]
16250
+ ),
16251
+ // Following a value to the expression it is written as, whatever kind
16252
+ // that is. A GraphQL document is neither a function nor an object, so
16253
+ // `comesTo` never reaches one.
16254
+ rule("isWrittenAs", [v("x"), v("x")], [lit("writtenValue", v("x"))]),
16255
+ rule("isWrittenAs", [v("x"), v("x")], [lit("objectValue", v("x"))]),
16256
+ rule(
16257
+ "isWrittenAs",
16258
+ [v("x"), v("z")],
16259
+ [lit("reaches", v("x"), v("z"), VALUE_STEP), lit("writtenValue", v("z"))]
16260
+ ),
16261
+ rule(
16262
+ "isWrittenAs",
16263
+ [v("x"), v("z")],
16264
+ [lit("reaches", v("x"), v("z"), VALUE_STEP), lit("objectValue", v("z"))]
16265
+ ),
16266
+ // What one call site put in a parameter, told apart from what the
16267
+ // other callers passed.
16268
+ rule(
16269
+ "paramAt",
16270
+ [v("r"), v("p"), v("z")],
16271
+ [
16272
+ lit("passesArgument", v("r"), v("p"), v("a")),
16273
+ lit("comesTo", v("a"), v("z"))
16274
+ ]
16275
+ ),
16276
+ // An argument arriving at the parameter it is passed to, by position
16277
+ // or by the name the caller wrote, keeping the call it went through
16278
+ // so `paramAt` can tell two call sites apart.
16279
+ rule(
16280
+ "passesArgument",
16281
+ [v("r"), v("p"), v("a")],
16282
+ [
16283
+ lit("paramOf", v("f"), v("k"), v("p")),
16284
+ lit("callsFunction", v("r"), v("f")),
16285
+ lit("callArg", v("r"), v("k"), v("a"))
16286
+ ]
16287
+ ),
16288
+ rule(
16289
+ "passesArgument",
16290
+ [v("r"), v("p"), v("a")],
16291
+ [
16292
+ lit("paramNamed", v("f"), v("n"), v("p")),
16293
+ lit("callsFunction", v("r"), v("f")),
16294
+ lit("callKeywordArg", v("r"), v("n"), v("a"))
16295
+ ]
16296
+ ),
16297
+ // Which module's export a re-exported name forwards to, however
16298
+ // many barrels deep the forwarding runs.
16299
+ rule(
16300
+ "moduleForwards",
16301
+ [v("m"), v("n"), v("m2"), v("n2")],
16302
+ [lit("reExports", v("m"), v("n"), v("m2"), v("n2"))]
16303
+ ),
16304
+ rule(
16305
+ "moduleForwards",
16306
+ [v("m"), v("n"), v("m3"), v("n3")],
16307
+ [
16308
+ lit("reExports", v("m"), v("n"), v("m2"), v("n2")),
16309
+ lit("moduleForwards", v("m2"), v("n2"), v("m3"), v("n3"))
16310
+ ]
16311
+ ),
16312
+ // What a module exports: directly, or through re-export chains.
16313
+ rule(
16314
+ "moduleExport",
16315
+ [v("m"), v("n"), v("value")],
16316
+ [lit("exportsAs", v("m"), v("n"), v("value"))],
16317
+ "export"
16318
+ ),
16319
+ rule(
16320
+ "moduleExport",
16321
+ [v("m"), v("n"), v("value")],
16322
+ [
16323
+ lit("reExports", v("m"), v("n"), v("m2"), v("n2")),
16324
+ lit("moduleExport", v("m2"), v("n2"), v("value"))
16325
+ ],
16326
+ "re-export"
16327
+ ),
16328
+ rule(
16329
+ "moduleExport",
16330
+ [v("m"), v("n"), v("value")],
16331
+ [
16332
+ lit("reExportsAll", v("m"), v("m2")),
16333
+ lit("moduleExport", v("m2"), v("n"), v("value"))
16334
+ ],
16335
+ "re-export all"
16336
+ ),
16337
+ // The function a call runs, written from the call's side because a
16338
+ // caller asking what a call gives back has the call in hand.
16339
+ rule(
16340
+ "invokes",
16341
+ [v("r"), v("f")],
16342
+ [lit("call", v("r"), v("c")), lit("comesTo", v("c"), v("f"))]
16343
+ ),
16344
+ // The callee is itself a call: `daoBuilder()()`.
16345
+ rule(
16346
+ "invokes",
16347
+ [v("r"), v("f")],
16348
+ [lit("call", v("r"), v("c")), lit("givesBack", v("c"), v("f"))]
16349
+ ),
16350
+ // The object an expression refers to: a name through `comesTo`, a
16351
+ // factory call through what it gives back. Naming the step is what
16352
+ // makes `routes.list` and `make(body).handle` one rule.
16353
+ rule(
16354
+ "objectOf",
16355
+ [v("o"), v("obj")],
16356
+ [lit("comesTo", v("o"), v("obj")), lit("objectValue", v("obj"))]
16357
+ ),
16358
+ rule(
16359
+ "objectOf",
16360
+ [v("x"), v("obj")],
16361
+ [lit("givesBack", v("x"), v("obj")), lit("objectValue", v("obj"))]
16362
+ ),
16363
+ // Which calls a function, found by the name the call is written as
16364
+ // rather than by resolving every callee in the project. A caller knows
16365
+ // the function and wants its call sites, so both of these start from
16366
+ // the function. Starting from `call` instead asks what every call in
16367
+ // the project imports, which was 72% of everything derived.
16368
+ rule(
16369
+ "callsFunction",
16370
+ [v("r"), v("f")],
16371
+ [lit("binds", v("c"), v("f")), lit("call", v("r"), v("c"))]
16372
+ ),
16373
+ rule(
16374
+ "callsFunction",
16375
+ [v("r"), v("f")],
16376
+ [
16377
+ lit("moduleExport", v("m"), v("n"), v("f")),
16378
+ lit("imports", v("c"), v("m"), v("n")),
16379
+ lit("call", v("r"), v("c"))
16380
+ ]
16381
+ ),
16382
+ // The same, for a language whose adapter writes the import down as a
16383
+ // declaration and the call's callee as the name referring to it.
16384
+ rule(
16385
+ "callsFunction",
16386
+ [v("r"), v("f")],
16387
+ [
16388
+ lit("moduleExport", v("m"), v("n"), v("f")),
16389
+ lit("imports", v("d"), v("m"), v("n")),
16390
+ lit("binds", v("c"), v("d")),
16391
+ lit("call", v("r"), v("c"))
16392
+ ]
16393
+ ),
16394
+ // What an object contains, its base class included, so a method the base
16395
+ // declares is found on a subclass that never overrode it. A method both
16396
+ // declare gives two, and the caller decides. This is its own relation
16397
+ // rather than more `holdsProperty`, which stays something an adapter
16398
+ // states and the rules only read.
16399
+ rule(
16400
+ "contains",
16401
+ [v("o"), v("n"), v("held")],
16402
+ [lit("holdsProperty", v("o"), v("n"), v("held"))]
16403
+ ),
16404
+ rule(
16405
+ "contains",
16406
+ [v("cls"), v("n"), v("held")],
16407
+ [
16408
+ lit("extends", v("cls"), v("base")),
16409
+ lit("comesTo", v("base"), v("baseCls")),
16410
+ lit("contains", v("baseCls"), v("n"), v("held"))
16411
+ ]
16412
+ ),
16413
+ // Which function a factory returns, and which of its parameters that
16414
+ // function calls: together they are what makes it a wrapper.
16415
+ rule(
16416
+ "returnsFunc",
16417
+ [v("f"), v("g")],
16418
+ [
16419
+ lit("returnsValue", v("f"), v("value")),
16420
+ lit("comesTo", v("value"), v("g")),
16421
+ lit("func", v("g"))
16422
+ ]
16423
+ ),
16424
+ // A call made by a nested closure counts as made by the function
16425
+ // that declares it; the closure runs as part of that function.
16426
+ rule("bodyCallsDeep", [v("f"), v("c")], [lit("bodyCalls", v("f"), v("c"))]),
16427
+ rule(
16428
+ "bodyCallsDeep",
16429
+ [v("f"), v("c")],
16430
+ [lit("containsFn", v("f"), v("g")), lit("bodyCallsDeep", v("g"), v("c"))]
16431
+ ),
16432
+ rule(
16433
+ "unwraps",
16434
+ [v("f"), v("k")],
16435
+ [
16436
+ lit("returnsFunc", v("f"), v("g")),
16437
+ lit("bodyCallsDeep", v("g"), v("c")),
16438
+ lit("binds", v("c"), v("p")),
16439
+ lit("paramOf", v("f"), v("k"), v("p"))
16440
+ ]
16441
+ ),
16442
+ // Argument flow: which parameter a value traces back to. Directly
16443
+ // (an identifier bound to the parameter), or through a call to
16444
+ // another unwrapping factory. This is what lets
16445
+ // `createProtected(h) { return service.withAuth(h); }` unwrap:
16446
+ // the returned call passes h through withAuth, which unwraps.
16447
+ rule(
16448
+ "flowsToParam",
16449
+ [v("x"), v("p")],
16450
+ [
16451
+ lit("binds", v("x"), v("p")),
16452
+ lit("paramOf", v("anyF"), v("anyK"), v("p"))
16453
+ ]
16454
+ ),
16455
+ rule(
16456
+ "flowsToParam",
16457
+ [v("r"), v("p")],
16458
+ [
16459
+ lit("call", v("r"), v("c")),
16460
+ lit("comesTo", v("c"), v("f")),
16461
+ lit("unwraps", v("f"), v("k")),
16462
+ lit("callArg", v("r"), v("k"), v("a")),
16463
+ lit("flowsToParam", v("a"), v("p"))
16464
+ ]
16465
+ ),
16466
+ rule(
16467
+ "unwraps",
16468
+ [v("f"), v("k")],
16469
+ [
16470
+ lit("returnsValue", v("f"), v("value")),
16471
+ lit("flowsToParam", v("value"), v("p")),
16472
+ lit("paramOf", v("f"), v("k"), v("p"))
16473
+ ]
16474
+ ),
16475
+ // Where a name comes from, when what it refers to lives outside the
16476
+ // source being read. A walk ends at something written out in source,
16477
+ // so it never reaches a library's own function.
16478
+ rule(
16479
+ "comesFrom",
16480
+ [v("x"), v("m"), v("n")],
16481
+ [lit("imports", v("x"), v("m"), v("n"))]
16482
+ ),
16483
+ rule(
16484
+ "comesFrom",
16485
+ [v("x"), v("m"), v("n")],
16486
+ [
16487
+ lit("reaches", v("x"), v("y"), VALUE_STEP),
16488
+ lit("imports", v("y"), v("m"), v("n"))
16489
+ ]
16490
+ ),
16491
+ // Calling f ends up calling the name n that module m exports, one
16492
+ // hop through f's own body or deeper through a wrapper of a wrapper.
16493
+ // Several results is normal: a composed decorator applies them all.
16494
+ rule(
16495
+ "callsInto",
16496
+ [v("f"), v("m"), v("n")],
16497
+ [
16498
+ lit("bodyCallsDeep", v("f"), v("c")),
16499
+ lit("comesFrom", v("c"), v("m"), v("n"))
16500
+ ]
16501
+ ),
16502
+ rule(
16503
+ "callsInto",
16504
+ [v("f"), v("m"), v("n")],
16505
+ [
16506
+ lit("bodyCallsDeep", v("f"), v("c")),
16507
+ lit("comesTo", v("c"), v("g")),
16508
+ lit("callsInto", v("g"), v("m"), v("n"))
16509
+ ]
16510
+ ),
16511
+ // The question callers ask: what a value comes to, narrowed to the
16512
+ // functions. Objects appear in the middle of chains and never in an
16513
+ // answer.
16514
+ rule(
16515
+ "resolves",
16516
+ [v("x"), v("z")],
16517
+ [lit("comesTo", v("x"), v("z")), lit("func", v("z"))]
16518
+ )
16519
+ ];
16520
+ var RESOLUTION_QUESTIONS = [
16521
+ rule(
16522
+ "wantedResolves",
16523
+ [v("x"), v("z")],
16524
+ [lit("wanted", v("x")), lit("resolves", v("x"), v("z"))]
16525
+ ),
16526
+ rule(
16527
+ "wantedComesTo",
16528
+ [v("x"), v("z")],
16529
+ [lit("wanted", v("x")), lit("comesTo", v("x"), v("z"))]
16530
+ ),
16531
+ rule(
16532
+ "wantedComesTo",
16533
+ [v("x"), v("z")],
16534
+ [lit("wantedOrigin", v("x")), lit("comesTo", v("x"), v("z"))]
16535
+ ),
16536
+ rule(
16537
+ "wantedIsWrittenAs",
16538
+ [v("x"), v("z")],
16539
+ [lit("wanted", v("x")), lit("isWrittenAs", v("x"), v("z"))]
16540
+ ),
16541
+ // A call is given no `comesTo`, so this is the only way to ask what
16542
+ // object one arrives at, and without it a demand-driven run derives
16543
+ // `objectOf` nowhere.
16544
+ rule(
16545
+ "wantedObjectOf",
16546
+ [v("x"), v("z")],
16547
+ [lit("wanted", v("x")), lit("objectOf", v("x"), v("z"))]
16548
+ ),
16549
+ // Keyed by the parameter, since that is what a caller has in hand
16550
+ // when it wants the call sites told apart.
16551
+ rule(
16552
+ "wantedParamAt",
16553
+ [v("p"), v("r"), v("z")],
16554
+ [lit("wanted", v("p")), lit("paramAt", v("r"), v("p"), v("z"))]
16555
+ ),
16556
+ rule(
16557
+ "wantedComesFrom",
16558
+ [v("x"), v("m"), v("n")],
16559
+ [lit("wantedOrigin", v("x")), lit("comesFrom", v("x"), v("m"), v("n"))]
16560
+ ),
16561
+ // Call-origin questions, for attribution, in their own demand
16562
+ // class. Attribution stops at the import declaration, so nothing
16563
+ // here demands reaches or callsInto. The chains are closures with
16564
+ // no depth bound: an alias run of any length resolves.
16565
+ rule("callOriginChain", [v("x"), v("x")], [lit("wantedCallOrigin", v("x"))]),
16566
+ rule(
16567
+ "callOriginChain",
16568
+ [v("x"), v("z")],
16569
+ [lit("callOriginChain", v("x"), v("y")), lit("binds", v("y"), v("z"))]
16570
+ ),
16571
+ rule(
16572
+ "callOriginChain",
16573
+ [v("x"), v("z")],
16574
+ [
16575
+ lit("callOriginChain", v("x"), v("y")),
16576
+ lit("endsHolding", v("y"), v("z"))
16577
+ ]
16578
+ ),
16579
+ rule(
16580
+ "callOriginChain",
16581
+ [v("x"), v("z")],
16582
+ [
16583
+ lit("callOriginChain", v("x"), v("y")),
16584
+ lit("fallbackBranch", v("y"), v("z"))
16585
+ ]
16586
+ ),
16587
+ // The chain with at least one hop taken, which is what tells a
16588
+ // destructured binding apart from asking about a node directly.
16589
+ rule(
16590
+ "callOriginChainStepped",
16591
+ [v("x"), v("z")],
16592
+ [lit("callOriginChain", v("x"), v("y")), lit("binds", v("y"), v("z"))]
16593
+ ),
16594
+ rule(
16595
+ "callOriginChainStepped",
16596
+ [v("x"), v("z")],
16597
+ [
16598
+ lit("callOriginChain", v("x"), v("y")),
16599
+ lit("endsHolding", v("y"), v("z"))
16600
+ ]
16601
+ ),
16602
+ rule(
16603
+ "callOriginChainStepped",
16604
+ [v("x"), v("z")],
16605
+ [
16606
+ lit("callOriginChain", v("x"), v("y")),
16607
+ lit("fallbackBranch", v("y"), v("z"))
16608
+ ]
16609
+ ),
16610
+ rule(
16611
+ "wantedCallOriginPair",
16612
+ [v("x"), v("m"), v("n")],
16613
+ [
16614
+ lit("callOriginChain", v("x"), v("y")),
16615
+ lit("imports", v("y"), v("m"), v("n"))
16616
+ ]
16617
+ ),
16618
+ // An import of a project barrel is an import of what the barrel
16619
+ // forwards, so the pair surfaces the module behind the chain.
16620
+ rule(
16621
+ "wantedCallOriginPair",
16622
+ [v("x"), v("m2"), v("n2")],
16623
+ [
16624
+ lit("callOriginChain", v("x"), v("y")),
16625
+ lit("imports", v("y"), v("m"), v("n")),
16626
+ lit("moduleForwards", v("m"), v("n"), v("m2"), v("n2"))
16627
+ ]
16628
+ ),
16629
+ // A namespace member: the module's export of the member's own name.
16630
+ // The imports literal leads, since it is the smallest relation.
16631
+ rule(
16632
+ "wantedCallOriginPair",
16633
+ [v("x"), v("m"), v("p")],
16634
+ [
16635
+ lit("imports", v("o"), v("m"), NAMESPACE_IMPORT),
16636
+ lit("readsProperty", v("y"), v("o"), v("p")),
16637
+ lit("callOriginChain", v("x"), v("y"))
16638
+ ]
16639
+ ),
16640
+ rule(
16641
+ "wantedCallOriginPair",
16642
+ [v("x"), v("m"), v("p")],
16643
+ [
16644
+ lit("imports", v("d"), v("m"), NAMESPACE_IMPORT),
16645
+ lit("binds", v("o"), v("d")),
16646
+ lit("readsProperty", v("y"), v("o"), v("p")),
16647
+ lit("callOriginChain", v("x"), v("y"))
16648
+ ]
16649
+ ),
16650
+ // What a call made: through the call to its callee, whose own alias
16651
+ // chain leads to the import.
16652
+ rule(
16653
+ "callMadeChain",
16654
+ [v("x"), v("f")],
16655
+ [lit("callOriginChain", v("x"), v("c")), lit("call", v("c"), v("f"))]
16656
+ ),
16657
+ rule(
16658
+ "callMadeChain",
16659
+ [v("x"), v("z")],
16660
+ [lit("callMadeChain", v("x"), v("y")), lit("binds", v("y"), v("z"))]
16661
+ ),
16662
+ rule(
16663
+ "callMadeChain",
16664
+ [v("x"), v("z")],
16665
+ [lit("callMadeChain", v("x"), v("y")), lit("endsHolding", v("y"), v("z"))]
16666
+ ),
16667
+ rule(
16668
+ "wantedCallOriginPair",
16669
+ [v("x"), v("m"), v("n")],
16670
+ [
16671
+ lit("callMadeChain", v("x"), v("y")),
16672
+ lit("imports", v("y"), v("m"), v("n"))
16673
+ ]
16674
+ ),
16675
+ // A member destructured off what a call made keeps the member name
16676
+ // as one more path segment.
16677
+ rule(
16678
+ "callMemberChain",
16679
+ [v("x"), v("f"), v("p")],
16680
+ [
16681
+ lit("callOriginChainStepped", v("x"), v("e")),
16682
+ lit("readsProperty", v("e"), v("c"), v("p")),
16683
+ lit("call", v("c"), v("f"))
16684
+ ]
16685
+ ),
16686
+ rule(
16687
+ "callMemberChain",
16688
+ [v("x"), v("z"), v("p")],
16689
+ [
16690
+ lit("callMemberChain", v("x"), v("y"), v("p")),
16691
+ lit("binds", v("y"), v("z"))
16692
+ ]
16693
+ ),
16694
+ rule(
16695
+ "callMemberChain",
16696
+ [v("x"), v("z"), v("p")],
16697
+ [
16698
+ lit("callMemberChain", v("x"), v("y"), v("p")),
16699
+ lit("endsHolding", v("y"), v("z"))
16700
+ ]
16701
+ ),
16702
+ rule(
16703
+ "wantedCallOriginMember",
16704
+ [v("x"), v("m"), v("n"), v("p")],
16705
+ [
16706
+ lit("callMemberChain", v("x"), v("y"), v("p")),
16707
+ lit("imports", v("y"), v("m"), v("n"))
16708
+ ]
16709
+ ),
16710
+ rule(
16711
+ "wantedCallsInto",
16712
+ [v("g"), v("m"), v("n")],
16713
+ [
16714
+ lit("wantedOrigin", v("x")),
16715
+ lit("comesTo", v("x"), v("g")),
16716
+ lit("callsInto", v("g"), v("m"), v("n"))
16717
+ ]
16718
+ ),
16719
+ // Subject identity, its own demand class; the README's subject
16720
+ // section says why the origin pair rides on the written-value walk.
16721
+ rule(
16722
+ "wantedSubjectWritten",
16723
+ [v("x"), v("r")],
16724
+ [lit("wantedSubject", v("x")), lit("isWrittenAs", v("x"), v("r"))]
16725
+ ),
16726
+ rule(
16727
+ "wantedSubjectConstruction",
16728
+ [v("x"), v("r"), v("m"), v("n")],
16729
+ [
16730
+ lit("wantedSubject", v("x")),
16731
+ lit("isWrittenAs", v("x"), v("r")),
16732
+ lit("call", v("r"), v("c")),
16733
+ lit("comesFrom", v("c"), v("m"), v("n"))
16734
+ ]
16735
+ ),
16736
+ // The export table of one module, keyed by the module asked about.
16737
+ // The moduleExport rules flatten re-export chains of any length, and
16738
+ // the demand cone stays on export facts alone.
16739
+ rule(
16740
+ "wantedModuleExport",
16741
+ [v("m"), v("n"), v("value")],
16742
+ [
16743
+ lit("wantedExportsOf", v("m")),
16744
+ lit("moduleExport", v("m"), v("n"), v("value"))
16745
+ ]
16746
+ ),
16747
+ // The calls behind a receiver, for a pack that wants the anchor a
16748
+ // chain hangs off; the README's anchor section says which hops and
16749
+ // why the asking side applies the single-answer policy.
16750
+ // A class's ancestry, one hop per extends through the binding that
16751
+ // says which class the written base is; the names on the way out
16752
+ // are what a storage pack matches its library's bases against.
16753
+ rule("ancestryChain", [v("c"), v("c")], [lit("wantedAncestry", v("c"))]),
16754
+ rule(
16755
+ "ancestryChain",
16756
+ [v("c"), v("b2")],
16757
+ [
16758
+ lit("ancestryChain", v("c"), v("b")),
16759
+ lit("extends", v("b"), v("x")),
16760
+ lit("binds", v("x"), v("b2"))
16761
+ ]
16762
+ ),
16763
+ rule(
16764
+ "wantedBaseName",
16765
+ [v("c"), v("n")],
16766
+ [lit("ancestryChain", v("c"), v("b")), lit("extendsNamed", v("b"), v("n"))]
16767
+ ),
16768
+ rule("anchorChain", [v("x"), v("x")], [lit("wantedAnchor", v("x"))]),
16769
+ rule(
16770
+ "anchorChain",
16771
+ [v("x"), v("z")],
16772
+ [lit("anchorChain", v("x"), v("y")), lit("binds", v("y"), v("z"))]
16773
+ ),
16774
+ rule(
16775
+ "anchorChain",
16776
+ [v("x"), v("z")],
16777
+ [lit("anchorChain", v("x"), v("y")), lit("endsHolding", v("y"), v("z"))]
16778
+ ),
16779
+ rule(
16780
+ "anchorChain",
16781
+ [v("x"), v("z")],
16782
+ [lit("anchorChain", v("x"), v("y")), lit("fallbackBranch", v("y"), v("z"))]
16783
+ ),
16784
+ rule(
16785
+ "anchorChain",
16786
+ [v("x"), v("z")],
16787
+ [
16788
+ lit("anchorChain", v("x"), v("y")),
16789
+ lit("imports", v("y"), v("m"), v("n")),
16790
+ lit("moduleExport", v("m"), v("n"), v("z"))
16791
+ ]
16792
+ ),
16793
+ rule(
16794
+ "anchorChain",
16795
+ [v("x"), v("c")],
16796
+ [lit("anchorChain", v("x"), v("r")), lit("call", v("r"), v("c"))]
16797
+ ),
16798
+ rule(
16799
+ "anchorChain",
16800
+ [v("x"), v("o")],
16801
+ [
16802
+ lit("anchorChain", v("x"), v("y")),
16803
+ lit("readsProperty", v("y"), v("o"), v("n"))
16804
+ ]
16805
+ ),
16806
+ rule(
16807
+ "wantedAnchorCall",
16808
+ [v("x"), v("r")],
16809
+ [lit("anchorChain", v("x"), v("r")), lit("call", v("r"), v("c"))]
16810
+ )
16811
+ ];
16812
+ var ANSWER_RELATIONS = [
16813
+ ...new Set(RESOLUTION_QUESTIONS.map((r) => r.head.relation))
16814
+ ];
16815
+
15955
16816
  // src/storage.ts
15956
16817
  function children2(node) {
15957
16818
  return node.namedChildren.filter((child) => child !== null);
@@ -15972,21 +16833,17 @@ function rootConstant(node) {
15972
16833
  }
15973
16834
  return rootConstant(receiver);
15974
16835
  }
15975
- function reachesBase(facts, classKey, bases, seen = /* @__PURE__ */ new Set()) {
15976
- if (seen.has(classKey)) {
15977
- return false;
15978
- }
15979
- seen.add(classKey);
15980
- const named = facts.facts("extendsNamed").filter((row) => String(row[0]) === classKey).map((row) => String(row[1]));
15981
- if (named.some((name) => bases.includes(name))) {
15982
- return true;
15983
- }
15984
- return facts.facts("extends").filter((row) => String(row[0]) === classKey).flatMap(
15985
- (row) => facts.facts("binds").filter((bound) => String(bound[0]) === String(row[1])).map((bound) => String(bound[1]))
15986
- ).some((next) => reachesBase(facts, next, bases, seen));
16836
+ var ANCESTRY_PROGRAM = deriveOnDemand(
16837
+ [...RESOLUTION_RULES, ...RESOLUTION_QUESTIONS],
16838
+ ANSWER_RELATIONS
16839
+ );
16840
+ function reachesBase(facts, classKey, bases) {
16841
+ facts.add("wantedAncestry", [classKey]);
16842
+ evaluate(facts, ANCESTRY_PROGRAM.rules);
16843
+ return facts.lookup("wantedBaseName", 0, classKey).some((row) => bases.includes(String(row[1])));
15987
16844
  }
15988
- function classBehind(facts, constant) {
15989
- const wanted = `#${constant.text}`;
16845
+ function classBehind(facts, constant2) {
16846
+ const wanted = `#${constant2.text}`;
15990
16847
  const bound = new Set(
15991
16848
  facts.facts("binds").filter((row) => String(row[0]).endsWith(wanted)).map((row) => String(row[1]))
15992
16849
  );
@@ -16029,11 +16886,11 @@ function storageEffects(calls, options) {
16029
16886
  if (partOfOne.has(call.id)) {
16030
16887
  continue;
16031
16888
  }
16032
- const constant = rootConstant(call);
16033
- if (constant === null) {
16889
+ const constant2 = rootConstant(call);
16890
+ if (constant2 === null) {
16034
16891
  continue;
16035
16892
  }
16036
- const classKey = classBehind(options.facts, constant);
16893
+ const classKey = classBehind(options.facts, constant2);
16037
16894
  if (classKey === void 0) {
16038
16895
  continue;
16039
16896
  }
@@ -16051,7 +16908,7 @@ function storageEffects(calls, options) {
16051
16908
  recognition: "ruby-storage",
16052
16909
  storageSystem: pattern.storageSystem,
16053
16910
  scope: pattern.baseClasses[0] ?? "",
16054
- container: constant.text
16911
+ container: constant2.text
16055
16912
  }),
16056
16913
  callee: call.text,
16057
16914
  interaction: {
@@ -16223,7 +17080,10 @@ async function graphqlObjectFieldUnits(pattern, pack, info, ownBlocks, fileBlock
16223
17080
  const knownClasses = ownBlocks[0]?.knownClasses ?? /* @__PURE__ */ new Set();
16224
17081
  const scope = { nesting: info.bodyNesting, knownClasses };
16225
17082
  const declsByName = /* @__PURE__ */ new Map();
16226
- for (const stmt of bodyStatements(info.bodyNode)) {
17083
+ for (const stmt of runStatements(
17084
+ info.bodyNode,
17085
+ blockConfiguresCall(pattern)
17086
+ )) {
16227
17087
  const decl = await readFieldCall(stmt, scope, ctx, ancestry);
16228
17088
  if (decl !== null) {
16229
17089
  declsByName.set(decl.fieldName, decl);
@@ -16233,6 +17093,17 @@ async function graphqlObjectFieldUnits(pattern, pack, info, ownBlocks, fileBlock
16233
17093
  (decl) => buildFieldUnit(pack, typeName, decl, options.filePath)
16234
17094
  );
16235
17095
  }
17096
+ function blockConfiguresCall(pattern) {
17097
+ const names = /* @__PURE__ */ new Set([
17098
+ pattern.fieldCallName,
17099
+ pattern.typeCallName,
17100
+ pattern.argumentCallName
17101
+ ]);
17102
+ return (call) => {
17103
+ const method = field(call, "method")?.text;
17104
+ return field(call, "receiver") === null && method !== void 0 && names.has(method);
17105
+ };
17106
+ }
16236
17107
  function branchesFor(body, range) {
16237
17108
  if (body.effects === void 0 && body.extraEffects === void 0) {
16238
17109
  return [];
@@ -16308,10 +17179,13 @@ async function readFieldCall(stmt, scope, ctx, ancestry) {
16308
17179
  }
16309
17180
  const callArgs = readCallArgs(field(stmt, "arguments"));
16310
17181
  const nameArg = callArgs.positional[0];
16311
- const symbol2 = nameArg !== void 0 ? symbolValue(nameArg) : null;
16312
- if (symbol2 === null) {
17182
+ if (nameArg === void 0) {
16313
17183
  return null;
16314
17184
  }
17185
+ const symbol2 = symbolValue(nameArg);
17186
+ if (symbol2 === null) {
17187
+ return computedNameDeclaration(stmt, nameArg);
17188
+ }
16315
17189
  const read = await readFieldShape(
16316
17190
  symbol2,
16317
17191
  callArgs,
@@ -16322,11 +17196,29 @@ async function readFieldCall(stmt, scope, ctx, ancestry) {
16322
17196
  );
16323
17197
  return {
16324
17198
  fieldName: resolvedName(symbol2, callArgs, ctx.pattern),
17199
+ namedOnTheWire: true,
16325
17200
  node: stmt,
16326
17201
  contract: read.contract,
16327
17202
  body: read.body
16328
17203
  };
16329
17204
  }
17205
+ function computedNameDeclaration(stmt, nameArg) {
17206
+ const range = rangeOf(stmt);
17207
+ return {
17208
+ fieldName: nameArg.text,
17209
+ namedOnTheWire: false,
17210
+ node: stmt,
17211
+ contract: null,
17212
+ body: {
17213
+ readings: [
17214
+ unreadableReading(
17215
+ `This field is named by ${nameArg.text}, which is worked out when the class body runs, so the name the schema exposes it under was not read here`,
17216
+ range
17217
+ )
17218
+ ]
17219
+ }
17220
+ };
17221
+ }
16330
17222
  function wiringReference(callArgs, wiringKeywords) {
16331
17223
  for (const keyword of wiringKeywords) {
16332
17224
  const ref = callArgs.keyword[keyword];
@@ -16451,7 +17343,10 @@ function readClassContract(ancestry, pattern) {
16451
17343
  args: /* @__PURE__ */ new Map()
16452
17344
  };
16453
17345
  const handlers = classCallHandlers(pattern);
16454
- for (const { block, statement } of inheritedStatements(ancestry)) {
17346
+ for (const { block, statement } of inheritedStatements(
17347
+ ancestry,
17348
+ blockConfiguresCall(pattern)
17349
+ )) {
16455
17350
  if (statement.type !== "call" || field(statement, "receiver") !== null) {
16456
17351
  continue;
16457
17352
  }
@@ -16538,15 +17433,16 @@ function buildFieldUnit(pack, typeName, decl, filePath) {
16538
17433
  kind: "resolver",
16539
17434
  file: filePath,
16540
17435
  range: rangeOf(decl.node),
17436
+ span: spanOf(decl.node),
16541
17437
  exportName: null,
16542
17438
  exportPath: null
16543
17439
  },
16544
- boundaryBinding: graphqlResolverBinding({
17440
+ boundaryBinding: decl.namedOnTheWire ? graphqlResolverBinding({
16545
17441
  transport: pack.protocol,
16546
17442
  recognition: pack.name,
16547
17443
  typeName,
16548
17444
  fieldName: decl.fieldName
16549
- }),
17445
+ }) : null,
16550
17446
  parameters,
16551
17447
  branches: branchesFor(decl.body, rangeOf(decl.node)),
16552
17448
  ...decl.body.bodyContent !== void 0 ? { bodyContent: decl.body.bodyContent } : {},
@@ -16617,14 +17513,6 @@ function nodeId(filePath, node) {
16617
17513
  function nameId(filePath, name) {
16618
17514
  return `${filePath}#${name}`;
16619
17515
  }
16620
- var DECLARATION_TYPES2 = /* @__PURE__ */ new Set([
16621
- "method",
16622
- "singleton_method",
16623
- "lambda",
16624
- "class",
16625
- "module",
16626
- "singleton_class"
16627
- ]);
16628
17516
  var WRITTEN_VALUE_TYPES = /* @__PURE__ */ new Set([
16629
17517
  "string",
16630
17518
  "integer",
@@ -16762,7 +17650,7 @@ function emitHash(emitter, hash2) {
16762
17650
  }
16763
17651
  function walkExpressions(node, visit) {
16764
17652
  for (const child of children3(node)) {
16765
- if (DECLARATION_TYPES2.has(child.type)) {
17653
+ if (OWN_BODY_TYPES.has(child.type)) {
16766
17654
  continue;
16767
17655
  }
16768
17656
  visit(child);
@@ -16820,7 +17708,7 @@ function emitMethodFacts(emitter, method) {
16820
17708
  }
16821
17709
  const recordNested = (node) => {
16822
17710
  for (const child of children3(node)) {
16823
- if (DECLARATION_TYPES2.has(child.type)) {
17711
+ if (OWN_BODY_TYPES.has(child.type)) {
16824
17712
  add(emitter, "containsFn", funcKey, nodeId(emitter.filePath, child));
16825
17713
  continue;
16826
17714
  }