@suss/adapter-python 0.18.0 → 0.20.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
@@ -15,6 +15,9 @@ function rangeOf(node) {
15
15
  end: node.endPosition.row + 1
16
16
  };
17
17
  }
18
+ function spanOf(node) {
19
+ return { start: node.startIndex, end: node.endIndex };
20
+ }
18
21
  function field(node, name) {
19
22
  return node.childForFieldName(name);
20
23
  }
@@ -1879,8 +1882,8 @@ function assertNever(_x) {
1879
1882
  function assert(_) {
1880
1883
  }
1881
1884
  function getEnumValues(entries) {
1882
- const numericValues = Object.values(entries).filter((v2) => typeof v2 === "number");
1883
- const values = Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v2]) => v2);
1885
+ const numericValues = Object.values(entries).filter((v3) => typeof v3 === "number");
1886
+ const values = Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v3]) => v3);
1884
1887
  return values;
1885
1888
  }
1886
1889
  function joinValues(array2, separator = "|") {
@@ -1934,9 +1937,9 @@ function defineLazy(object2, key, getter) {
1934
1937
  }
1935
1938
  return value;
1936
1939
  },
1937
- set(v2) {
1940
+ set(v3) {
1938
1941
  Object.defineProperty(object2, key, {
1939
- value: v2
1942
+ value: v3
1940
1943
  // configurable: true,
1941
1944
  });
1942
1945
  },
@@ -3623,10 +3626,10 @@ var $ZodUUID = /* @__PURE__ */ $constructor("$ZodUUID", (inst, def) => {
3623
3626
  v7: 7,
3624
3627
  v8: 8
3625
3628
  };
3626
- const v2 = versionMap[def.version];
3627
- if (v2 === void 0)
3629
+ const v3 = versionMap[def.version];
3630
+ if (v3 === void 0)
3628
3631
  throw new Error(`Invalid UUID version: "${def.version}"`);
3629
- def.pattern ?? (def.pattern = uuid(v2));
3632
+ def.pattern ?? (def.pattern = uuid(v3));
3630
3633
  } else
3631
3634
  def.pattern ?? (def.pattern = uuid());
3632
3635
  $ZodStringFormat.init(inst, def);
@@ -4231,8 +4234,8 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
4231
4234
  const field2 = shape[key]._zod;
4232
4235
  if (field2.values) {
4233
4236
  propValues[key] ?? (propValues[key] = /* @__PURE__ */ new Set());
4234
- for (const v2 of field2.values)
4235
- propValues[key].add(v2);
4237
+ for (const v3 of field2.values)
4238
+ propValues[key].add(v3);
4236
4239
  }
4237
4240
  }
4238
4241
  return propValues;
@@ -4527,10 +4530,10 @@ var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnio
4527
4530
  const pv = option._zod.propValues;
4528
4531
  if (!pv || Object.keys(pv).length === 0)
4529
4532
  throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(option)}"`);
4530
- for (const [k, v2] of Object.entries(pv)) {
4533
+ for (const [k, v3] of Object.entries(pv)) {
4531
4534
  if (!propValues[k])
4532
4535
  propValues[k] = /* @__PURE__ */ new Set();
4533
- for (const val of v2) {
4536
+ for (const val of v3) {
4534
4537
  propValues[k].add(val);
4535
4538
  }
4536
4539
  }
@@ -4544,11 +4547,11 @@ var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnio
4544
4547
  const values = o._zod.propValues?.[def.discriminator];
4545
4548
  if (!values || values.size === 0)
4546
4549
  throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(o)}"`);
4547
- for (const v2 of values) {
4548
- if (map2.has(v2)) {
4549
- throw new Error(`Duplicate discriminator value "${String(v2)}"`);
4550
+ for (const v3 of values) {
4551
+ if (map2.has(v3)) {
4552
+ throw new Error(`Duplicate discriminator value "${String(v3)}"`);
4550
4553
  }
4551
- map2.set(v2, o);
4554
+ map2.set(v3, o);
4552
4555
  }
4553
4556
  }
4554
4557
  return map2;
@@ -5187,8 +5190,8 @@ var $ZodPrefault = /* @__PURE__ */ $constructor("$ZodPrefault", (inst, def) => {
5187
5190
  var $ZodNonOptional = /* @__PURE__ */ $constructor("$ZodNonOptional", (inst, def) => {
5188
5191
  $ZodType.init(inst, def);
5189
5192
  defineLazy(inst._zod, "values", () => {
5190
- const v2 = def.innerType._zod.values;
5191
- return v2 ? new Set([...v2].filter((x) => x !== void 0)) : void 0;
5193
+ const v3 = def.innerType._zod.values;
5194
+ return v3 ? new Set([...v3].filter((x) => x !== void 0)) : void 0;
5192
5195
  });
5193
5196
  inst._zod.parse = (payload, ctx) => {
5194
5197
  const result = def.innerType._zod.run(payload, ctx);
@@ -7585,7 +7588,7 @@ var error17 = () => {
7585
7588
  if (issue2.values.length === 1) {
7586
7589
  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])}`;
7587
7590
  }
7588
- const stringified = issue2.values.map((v2) => stringifyPrimitive(v2));
7591
+ const stringified = issue2.values.map((v3) => stringifyPrimitive(v3));
7589
7592
  if (issue2.values.length === 2) {
7590
7593
  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]}`;
7591
7594
  }
@@ -12340,7 +12343,7 @@ function _set(Class2, valueType, params) {
12340
12343
  }
12341
12344
  // @__NO_SIDE_EFFECTS__
12342
12345
  function _enum(Class2, values, params) {
12343
- const entries = Array.isArray(values) ? Object.fromEntries(values.map((v2) => [v2, v2])) : values;
12346
+ const entries = Array.isArray(values) ? Object.fromEntries(values.map((v3) => [v3, v3])) : values;
12344
12347
  return new Class2({
12345
12348
  type: "enum",
12346
12349
  entries,
@@ -12545,8 +12548,8 @@ function _stringbool(Classes, _params) {
12545
12548
  let truthyArray = params.truthy ?? ["true", "1", "yes", "on", "y", "enabled"];
12546
12549
  let falsyArray = params.falsy ?? ["false", "0", "no", "off", "n", "disabled"];
12547
12550
  if (params.case !== "sensitive") {
12548
- truthyArray = truthyArray.map((v2) => typeof v2 === "string" ? v2.toLowerCase() : v2);
12549
- falsyArray = falsyArray.map((v2) => typeof v2 === "string" ? v2.toLowerCase() : v2);
12551
+ truthyArray = truthyArray.map((v3) => typeof v3 === "string" ? v3.toLowerCase() : v3);
12552
+ falsyArray = falsyArray.map((v3) => typeof v3 === "string" ? v3.toLowerCase() : v3);
12550
12553
  }
12551
12554
  const truthySet = new Set(truthyArray);
12552
12555
  const falsySet = new Set(falsyArray);
@@ -13088,9 +13091,9 @@ var dateProcessor = (_schema, ctx, _json, _params) => {
13088
13091
  var enumProcessor = (schema, _ctx, json2, _params) => {
13089
13092
  const def = schema._zod.def;
13090
13093
  const values = getEnumValues(def.entries);
13091
- if (values.every((v2) => typeof v2 === "number"))
13094
+ if (values.every((v3) => typeof v3 === "number"))
13092
13095
  json2.type = "number";
13093
- if (values.every((v2) => typeof v2 === "string"))
13096
+ if (values.every((v3) => typeof v3 === "string"))
13094
13097
  json2.type = "string";
13095
13098
  json2.enum = values;
13096
13099
  };
@@ -13123,13 +13126,13 @@ var literalProcessor = (schema, ctx, json2, _params) => {
13123
13126
  json2.const = val;
13124
13127
  }
13125
13128
  } else {
13126
- if (vals.every((v2) => typeof v2 === "number"))
13129
+ if (vals.every((v3) => typeof v3 === "number"))
13127
13130
  json2.type = "number";
13128
- if (vals.every((v2) => typeof v2 === "string"))
13131
+ if (vals.every((v3) => typeof v3 === "string"))
13129
13132
  json2.type = "string";
13130
- if (vals.every((v2) => typeof v2 === "boolean"))
13133
+ if (vals.every((v3) => typeof v3 === "boolean"))
13131
13134
  json2.type = "boolean";
13132
- if (vals.every((v2) => v2 === null))
13135
+ if (vals.every((v3) => v3 === null))
13133
13136
  json2.type = "null";
13134
13137
  json2.enum = vals;
13135
13138
  }
@@ -13227,11 +13230,11 @@ var objectProcessor = (schema, ctx, _json, params) => {
13227
13230
  }
13228
13231
  const allKeys = new Set(Object.keys(shape));
13229
13232
  const requiredKeys = new Set([...allKeys].filter((key) => {
13230
- const v2 = def.shape[key]._zod;
13233
+ const v3 = def.shape[key]._zod;
13231
13234
  if (ctx.io === "input") {
13232
- return v2.optin === void 0;
13235
+ return v3.optin === void 0;
13233
13236
  } else {
13234
- return v2.optout === void 0;
13237
+ return v3.optout === void 0;
13235
13238
  }
13236
13239
  }));
13237
13240
  if (requiredKeys.size > 0) {
@@ -13351,7 +13354,7 @@ var recordProcessor = (schema, ctx, _json, params) => {
13351
13354
  }
13352
13355
  const keyValues = keyType._zod.values;
13353
13356
  if (keyValues) {
13354
- const validKeyValues = [...keyValues].filter((v2) => typeof v2 === "string" || typeof v2 === "number");
13357
+ const validKeyValues = [...keyValues].filter((v3) => typeof v3 === "string" || typeof v3 === "number");
13355
13358
  if (validKeyValues.length > 0) {
13356
13359
  json2.required = validKeyValues;
13357
13360
  }
@@ -13916,12 +13919,12 @@ function _installLazyMethods(inst, group, methods) {
13916
13919
  });
13917
13920
  return bound;
13918
13921
  },
13919
- set(v2) {
13922
+ set(v3) {
13920
13923
  Object.defineProperty(this, key, {
13921
13924
  configurable: true,
13922
13925
  writable: true,
13923
13926
  enumerable: true,
13924
- value: v2
13927
+ value: v3
13925
13928
  });
13926
13929
  }
13927
13930
  });
@@ -14809,7 +14812,7 @@ var ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => {
14809
14812
  };
14810
14813
  });
14811
14814
  function _enum2(values, params) {
14812
- const entries = Array.isArray(values) ? Object.fromEntries(values.map((v2) => [v2, v2])) : values;
14815
+ const entries = Array.isArray(values) ? Object.fromEntries(values.map((v3) => [v3, v3])) : values;
14813
14816
  return new ZodEnum({
14814
14817
  type: "enum",
14815
14818
  entries,
@@ -15363,10 +15366,10 @@ function convertBaseSchema(schema, ctx) {
15363
15366
  if (enumValues.length === 1) {
15364
15367
  return z.literal(enumValues[0]);
15365
15368
  }
15366
- if (enumValues.every((v2) => typeof v2 === "string")) {
15369
+ if (enumValues.every((v3) => typeof v3 === "string")) {
15367
15370
  return z.enum(enumValues);
15368
15371
  }
15369
- const literalSchemas = enumValues.map((v2) => z.literal(v2));
15372
+ const literalSchemas = enumValues.map((v3) => z.literal(v3));
15370
15373
  if (literalSchemas.length < 2) {
15371
15374
  return literalSchemas[0];
15372
15375
  }
@@ -15713,7 +15716,7 @@ function date4(params) {
15713
15716
  // ../../../node_modules/zod/v4/classic/external.js
15714
15717
  config(en_default());
15715
15718
 
15716
- // ../../ir-core/dist/chunk-HSJYPBJU.js
15719
+ // ../../ir-core/dist/chunk-52CH76PE.js
15717
15720
  function gqlIdentityKey(typeName, fieldName) {
15718
15721
  return `gql:${typeName}.${fieldName}`;
15719
15722
  }
@@ -15777,14 +15780,24 @@ var functionCallSemantics = defineBoundarySemantics({
15777
15780
  */
15778
15781
  canPair: () => true,
15779
15782
  /**
15780
- * `"fn:<package>::<exportPath>"` when both are set. Other in-process
15781
- * function-call units, such as components and bare handlers inside
15782
- * one repo, have no key at all.
15783
+ * `"fn:<package>::<exportPath>"` when both are set, and
15784
+ * `"fn:<module>::<exportName>"` for an in-repo unit that states its
15785
+ * module, the way a server action does. Components and bare
15786
+ * handlers state neither and have no key at all.
15783
15787
  */
15788
+ rewritePaths(semantics, rewrite) {
15789
+ if (semantics.module === void 0) {
15790
+ return semantics;
15791
+ }
15792
+ return { ...semantics, module: rewrite(semantics.module) };
15793
+ },
15784
15794
  identityKey(semantics) {
15785
15795
  if (semantics.package !== void 0 && semantics.exportPath !== void 0 && semantics.exportPath.length > 0) {
15786
15796
  return fnIdentityKey(semantics.package, semantics.exportPath);
15787
15797
  }
15798
+ if (semantics.module !== void 0 && semantics.exportName !== void 0) {
15799
+ return fnIdentityKey(semantics.module, [semantics.exportName]);
15800
+ }
15788
15801
  return null;
15789
15802
  }
15790
15803
  }
@@ -16295,7 +16308,16 @@ var ConfidenceInfoSchema = external_exports.object({
16295
16308
  });
16296
16309
  var SourceLocationSchema = external_exports.object({
16297
16310
  file: external_exports.string(),
16311
+ /** Line numbers, for a person reading the summary or an editor link. */
16298
16312
  range: external_exports.object({ start: external_exports.number(), end: external_exports.number() }),
16313
+ /**
16314
+ * Character offsets of the unit in its file. Identity and joins
16315
+ * measure with these, since two functions can share a line and never
16316
+ * an offset range; the line `range` above is the presentation of the
16317
+ * same place. Absent on summaries no source position backs, a
16318
+ * contract artifact's say.
16319
+ */
16320
+ span: external_exports.object({ start: external_exports.number(), end: external_exports.number() }).optional(),
16299
16321
  exportName: external_exports.string().nullable(),
16300
16322
  /**
16301
16323
  * The project the extract was pointed at, by the name that project
@@ -16503,7 +16525,48 @@ import { deriveOnDemand, evaluate } from "@suss/datalog";
16503
16525
  // ../../resolution/dist/index.js
16504
16526
  import { ruleLabel } from "@suss/datalog";
16505
16527
  import { constant, lit, rule, variable as v } from "@suss/datalog";
16528
+ function joinMountedPath(prefix, path4) {
16529
+ const trimmed = prefix.endsWith("/") ? prefix.slice(0, -1) : prefix;
16530
+ return trimmed === "" ? path4 : trimmed + path4;
16531
+ }
16532
+ function mountPathsOf(edges, childId) {
16533
+ return pathsOf(edges, /* @__PURE__ */ new Map(), childId, /* @__PURE__ */ new Set());
16534
+ }
16535
+ function pathsOf(edges, memo, childId, visiting) {
16536
+ const cached2 = memo.get(childId);
16537
+ if (cached2 !== void 0) {
16538
+ return cached2;
16539
+ }
16540
+ if (visiting.has(childId)) {
16541
+ memo.set(childId, null);
16542
+ return null;
16543
+ }
16544
+ const own = edges.get(childId);
16545
+ if (own === void 0 || own.length === 0) {
16546
+ memo.set(childId, [""]);
16547
+ return [""];
16548
+ }
16549
+ visiting.add(childId);
16550
+ const composed = /* @__PURE__ */ new Set();
16551
+ let unstated = false;
16552
+ for (const edge of own) {
16553
+ const parentPaths = pathsOf(edges, memo, edge.parentId, visiting);
16554
+ if (parentPaths === null) {
16555
+ unstated = true;
16556
+ break;
16557
+ }
16558
+ for (const parentPath of parentPaths) {
16559
+ composed.add(joinMountedPath(parentPath, edge.prefix));
16560
+ }
16561
+ }
16562
+ visiting.delete(childId);
16563
+ const result = unstated ? null : [...composed];
16564
+ memo.set(childId, result);
16565
+ return result;
16566
+ }
16506
16567
  var VALUE_STEP = constant("value");
16568
+ var NAMESPACE_IMPORT_NAME = "*";
16569
+ var NAMESPACE_IMPORT = constant(NAMESPACE_IMPORT_NAME);
16507
16570
  var RESULT_STEP = constant("result");
16508
16571
  var RESOLUTION_RULES = [
16509
16572
  // Aliasing: const x = y, or an identifier referencing a declaration.
@@ -16723,6 +16786,21 @@ var RESOLUTION_RULES = [
16723
16786
  lit("callKeywordArg", v("r"), v("n"), v("a"))
16724
16787
  ]
16725
16788
  ),
16789
+ // Which module's export a re-exported name forwards to, however
16790
+ // many barrels deep the forwarding runs.
16791
+ rule(
16792
+ "moduleForwards",
16793
+ [v("m"), v("n"), v("m2"), v("n2")],
16794
+ [lit("reExports", v("m"), v("n"), v("m2"), v("n2"))]
16795
+ ),
16796
+ rule(
16797
+ "moduleForwards",
16798
+ [v("m"), v("n"), v("m3"), v("n3")],
16799
+ [
16800
+ lit("reExports", v("m"), v("n"), v("m2"), v("n2")),
16801
+ lit("moduleForwards", v("m2"), v("n2"), v("m3"), v("n3"))
16802
+ ]
16803
+ ),
16726
16804
  // What a module exports: directly, or through re-export chains.
16727
16805
  rule(
16728
16806
  "moduleExport",
@@ -16902,15 +16980,9 @@ var RESOLUTION_RULES = [
16902
16980
  lit("imports", v("y"), v("m"), v("n"))
16903
16981
  ]
16904
16982
  ),
16905
- // Calling f ends up calling the name n that module m exports. One hop
16906
- // is f's own body, including the closures it declares; the other hop
16907
- // is a function f's body calls, so a wrapper of a wrapper answers
16908
- // with what the innermost one reaches.
16909
- //
16910
- // Several answers for one function is the normal case, not an
16911
- // ambiguity: a project decorator that composes two library decorators
16912
- // applies both. A caller asks whether a particular (m, n) is among
16913
- // them.
16983
+ // Calling f ends up calling the name n that module m exports, one
16984
+ // hop through f's own body or deeper through a wrapper of a wrapper.
16985
+ // Several results is normal: a composed decorator applies them all.
16914
16986
  rule(
16915
16987
  "callsInto",
16916
16988
  [v("f"), v("m"), v("n")],
@@ -16978,6 +17050,155 @@ var RESOLUTION_QUESTIONS = [
16978
17050
  [v("x"), v("m"), v("n")],
16979
17051
  [lit("wantedOrigin", v("x")), lit("comesFrom", v("x"), v("m"), v("n"))]
16980
17052
  ),
17053
+ // Call-origin questions, for attribution, in their own demand
17054
+ // class. Attribution stops at the import declaration, so nothing
17055
+ // here demands reaches or callsInto. The chains are closures with
17056
+ // no depth bound: an alias run of any length resolves.
17057
+ rule("callOriginChain", [v("x"), v("x")], [lit("wantedCallOrigin", v("x"))]),
17058
+ rule(
17059
+ "callOriginChain",
17060
+ [v("x"), v("z")],
17061
+ [lit("callOriginChain", v("x"), v("y")), lit("binds", v("y"), v("z"))]
17062
+ ),
17063
+ rule(
17064
+ "callOriginChain",
17065
+ [v("x"), v("z")],
17066
+ [
17067
+ lit("callOriginChain", v("x"), v("y")),
17068
+ lit("endsHolding", v("y"), v("z"))
17069
+ ]
17070
+ ),
17071
+ rule(
17072
+ "callOriginChain",
17073
+ [v("x"), v("z")],
17074
+ [
17075
+ lit("callOriginChain", v("x"), v("y")),
17076
+ lit("fallbackBranch", v("y"), v("z"))
17077
+ ]
17078
+ ),
17079
+ // The chain with at least one hop taken, which is what tells a
17080
+ // destructured binding apart from asking about a node directly.
17081
+ rule(
17082
+ "callOriginChainStepped",
17083
+ [v("x"), v("z")],
17084
+ [lit("callOriginChain", v("x"), v("y")), lit("binds", v("y"), v("z"))]
17085
+ ),
17086
+ rule(
17087
+ "callOriginChainStepped",
17088
+ [v("x"), v("z")],
17089
+ [
17090
+ lit("callOriginChain", v("x"), v("y")),
17091
+ lit("endsHolding", v("y"), v("z"))
17092
+ ]
17093
+ ),
17094
+ rule(
17095
+ "callOriginChainStepped",
17096
+ [v("x"), v("z")],
17097
+ [
17098
+ lit("callOriginChain", v("x"), v("y")),
17099
+ lit("fallbackBranch", v("y"), v("z"))
17100
+ ]
17101
+ ),
17102
+ rule(
17103
+ "wantedCallOriginPair",
17104
+ [v("x"), v("m"), v("n")],
17105
+ [
17106
+ lit("callOriginChain", v("x"), v("y")),
17107
+ lit("imports", v("y"), v("m"), v("n"))
17108
+ ]
17109
+ ),
17110
+ // An import of a project barrel is an import of what the barrel
17111
+ // forwards, so the pair surfaces the module behind the chain.
17112
+ rule(
17113
+ "wantedCallOriginPair",
17114
+ [v("x"), v("m2"), v("n2")],
17115
+ [
17116
+ lit("callOriginChain", v("x"), v("y")),
17117
+ lit("imports", v("y"), v("m"), v("n")),
17118
+ lit("moduleForwards", v("m"), v("n"), v("m2"), v("n2"))
17119
+ ]
17120
+ ),
17121
+ // A namespace member: the module's export of the member's own name.
17122
+ // The imports literal leads, since it is the smallest relation.
17123
+ rule(
17124
+ "wantedCallOriginPair",
17125
+ [v("x"), v("m"), v("p")],
17126
+ [
17127
+ lit("imports", v("o"), v("m"), NAMESPACE_IMPORT),
17128
+ lit("readsProperty", v("y"), v("o"), v("p")),
17129
+ lit("callOriginChain", v("x"), v("y"))
17130
+ ]
17131
+ ),
17132
+ rule(
17133
+ "wantedCallOriginPair",
17134
+ [v("x"), v("m"), v("p")],
17135
+ [
17136
+ lit("imports", v("d"), v("m"), NAMESPACE_IMPORT),
17137
+ lit("binds", v("o"), v("d")),
17138
+ lit("readsProperty", v("y"), v("o"), v("p")),
17139
+ lit("callOriginChain", v("x"), v("y"))
17140
+ ]
17141
+ ),
17142
+ // What a call made: through the call to its callee, whose own alias
17143
+ // chain leads to the import.
17144
+ rule(
17145
+ "callMadeChain",
17146
+ [v("x"), v("f")],
17147
+ [lit("callOriginChain", v("x"), v("c")), lit("call", v("c"), v("f"))]
17148
+ ),
17149
+ rule(
17150
+ "callMadeChain",
17151
+ [v("x"), v("z")],
17152
+ [lit("callMadeChain", v("x"), v("y")), lit("binds", v("y"), v("z"))]
17153
+ ),
17154
+ rule(
17155
+ "callMadeChain",
17156
+ [v("x"), v("z")],
17157
+ [lit("callMadeChain", v("x"), v("y")), lit("endsHolding", v("y"), v("z"))]
17158
+ ),
17159
+ rule(
17160
+ "wantedCallOriginPair",
17161
+ [v("x"), v("m"), v("n")],
17162
+ [
17163
+ lit("callMadeChain", v("x"), v("y")),
17164
+ lit("imports", v("y"), v("m"), v("n"))
17165
+ ]
17166
+ ),
17167
+ // A member destructured off what a call made keeps the member name
17168
+ // as one more path segment.
17169
+ rule(
17170
+ "callMemberChain",
17171
+ [v("x"), v("f"), v("p")],
17172
+ [
17173
+ lit("callOriginChainStepped", v("x"), v("e")),
17174
+ lit("readsProperty", v("e"), v("c"), v("p")),
17175
+ lit("call", v("c"), v("f"))
17176
+ ]
17177
+ ),
17178
+ rule(
17179
+ "callMemberChain",
17180
+ [v("x"), v("z"), v("p")],
17181
+ [
17182
+ lit("callMemberChain", v("x"), v("y"), v("p")),
17183
+ lit("binds", v("y"), v("z"))
17184
+ ]
17185
+ ),
17186
+ rule(
17187
+ "callMemberChain",
17188
+ [v("x"), v("z"), v("p")],
17189
+ [
17190
+ lit("callMemberChain", v("x"), v("y"), v("p")),
17191
+ lit("endsHolding", v("y"), v("z"))
17192
+ ]
17193
+ ),
17194
+ rule(
17195
+ "wantedCallOriginMember",
17196
+ [v("x"), v("m"), v("n"), v("p")],
17197
+ [
17198
+ lit("callMemberChain", v("x"), v("y"), v("p")),
17199
+ lit("imports", v("y"), v("m"), v("n"))
17200
+ ]
17201
+ ),
16981
17202
  rule(
16982
17203
  "wantedCallsInto",
16983
17204
  [v("g"), v("m"), v("n")],
@@ -16986,6 +17207,81 @@ var RESOLUTION_QUESTIONS = [
16986
17207
  lit("comesTo", v("x"), v("g")),
16987
17208
  lit("callsInto", v("g"), v("m"), v("n"))
16988
17209
  ]
17210
+ ),
17211
+ // The export table of one module, keyed by the module asked about.
17212
+ // The moduleExport rules flatten re-export chains of any length, and
17213
+ // the demand cone stays on export facts alone.
17214
+ rule(
17215
+ "wantedModuleExport",
17216
+ [v("m"), v("n"), v("value")],
17217
+ [
17218
+ lit("wantedExportsOf", v("m")),
17219
+ lit("moduleExport", v("m"), v("n"), v("value"))
17220
+ ]
17221
+ ),
17222
+ // The calls behind a receiver, for a pack that wants the anchor a
17223
+ // chain hangs off; the README's anchor section says which hops and
17224
+ // why the asking side applies the single-answer policy.
17225
+ // A class's ancestry, one hop per extends through the binding that
17226
+ // says which class the written base is; the names on the way out
17227
+ // are what a storage pack matches its library's bases against.
17228
+ rule("ancestryChain", [v("c"), v("c")], [lit("wantedAncestry", v("c"))]),
17229
+ rule(
17230
+ "ancestryChain",
17231
+ [v("c"), v("b2")],
17232
+ [
17233
+ lit("ancestryChain", v("c"), v("b")),
17234
+ lit("extends", v("b"), v("x")),
17235
+ lit("binds", v("x"), v("b2"))
17236
+ ]
17237
+ ),
17238
+ rule(
17239
+ "wantedBaseName",
17240
+ [v("c"), v("n")],
17241
+ [lit("ancestryChain", v("c"), v("b")), lit("extendsNamed", v("b"), v("n"))]
17242
+ ),
17243
+ rule("anchorChain", [v("x"), v("x")], [lit("wantedAnchor", v("x"))]),
17244
+ rule(
17245
+ "anchorChain",
17246
+ [v("x"), v("z")],
17247
+ [lit("anchorChain", v("x"), v("y")), lit("binds", v("y"), v("z"))]
17248
+ ),
17249
+ rule(
17250
+ "anchorChain",
17251
+ [v("x"), v("z")],
17252
+ [lit("anchorChain", v("x"), v("y")), lit("endsHolding", v("y"), v("z"))]
17253
+ ),
17254
+ rule(
17255
+ "anchorChain",
17256
+ [v("x"), v("z")],
17257
+ [lit("anchorChain", v("x"), v("y")), lit("fallbackBranch", v("y"), v("z"))]
17258
+ ),
17259
+ rule(
17260
+ "anchorChain",
17261
+ [v("x"), v("z")],
17262
+ [
17263
+ lit("anchorChain", v("x"), v("y")),
17264
+ lit("imports", v("y"), v("m"), v("n")),
17265
+ lit("moduleExport", v("m"), v("n"), v("z"))
17266
+ ]
17267
+ ),
17268
+ rule(
17269
+ "anchorChain",
17270
+ [v("x"), v("c")],
17271
+ [lit("anchorChain", v("x"), v("r")), lit("call", v("r"), v("c"))]
17272
+ ),
17273
+ rule(
17274
+ "anchorChain",
17275
+ [v("x"), v("o")],
17276
+ [
17277
+ lit("anchorChain", v("x"), v("y")),
17278
+ lit("readsProperty", v("y"), v("o"), v("n"))
17279
+ ]
17280
+ ),
17281
+ rule(
17282
+ "wantedAnchorCall",
17283
+ [v("x"), v("r")],
17284
+ [lit("anchorChain", v("x"), v("r")), lit("call", v("r"), v("c"))]
16989
17285
  )
16990
17286
  ];
16991
17287
  var ANSWER_RELATIONS = [
@@ -17752,7 +18048,7 @@ function classRouteUnits(pattern, pack, classification, classNode, module, optio
17752
18048
  if (className === void 0 || bodyNode === null || classScope === void 0) {
17753
18049
  return [];
17754
18050
  }
17755
- const routePath = readRoutePath(
18051
+ const entries = readRoutePaths(
17756
18052
  pattern,
17757
18053
  pathArgument,
17758
18054
  classification,
@@ -17770,32 +18066,35 @@ function classRouteUnits(pattern, pack, classification, classNode, module, optio
17770
18066
  if (verb === void 0 || methodName2 === void 0) {
17771
18067
  continue;
17772
18068
  }
17773
- units.push(
17774
- ...routeUnitOrAbstention(
17775
- {
17776
- pack,
17777
- name: `${className}.${methodName2}`,
17778
- exportPath: [className, methodName2],
17779
- method: verb,
17780
- routePath,
17781
- requestBodyFromAnnotatedClass: pattern.annotatedClassIsRequestBody === true,
17782
- readsReturnedStatus: pattern.statusFromReturnedTuple === true,
17783
- injectedCallees: new Set(pattern.injectedParameterCallees ?? []),
17784
- definitionNode: maybeMethod,
17785
- enclosingScope: classScope,
17786
- module,
17787
- filePath: options.filePath,
17788
- skipReceiverParam: true,
17789
- responseShape: absentReading,
17790
- statusCode: defaultedStatus(
17791
- readReturnedStatus(pattern, maybeMethod),
17792
- pattern
17793
- ),
17794
- storage: options.storage
17795
- },
17796
- options
17797
- )
17798
- );
18069
+ for (const entry of entries) {
18070
+ units.push(
18071
+ ...routeUnitOrAbstention(
18072
+ {
18073
+ pack,
18074
+ name: `${className}.${methodName2}`,
18075
+ exportPath: [className, methodName2],
18076
+ method: verb,
18077
+ routePath: entry.routePath,
18078
+ ...entry.mount !== void 0 ? { mount: entry.mount } : {},
18079
+ requestBodyFromAnnotatedClass: pattern.annotatedClassIsRequestBody === true,
18080
+ readsReturnedStatus: pattern.statusFromReturnedTuple === true,
18081
+ injectedCallees: new Set(pattern.injectedParameterCallees ?? []),
18082
+ definitionNode: maybeMethod,
18083
+ enclosingScope: classScope,
18084
+ module,
18085
+ filePath: options.filePath,
18086
+ skipReceiverParam: true,
18087
+ responseShape: absentReading,
18088
+ statusCode: defaultedStatus(
18089
+ readReturnedStatus(pattern, maybeMethod),
18090
+ pattern
18091
+ ),
18092
+ storage: options.storage
18093
+ },
18094
+ options
18095
+ )
18096
+ );
18097
+ }
17799
18098
  }
17800
18099
  return units;
17801
18100
  }
@@ -17809,6 +18108,47 @@ function readRoutePath(pattern, pathArgument, classification, module, options) {
17809
18108
  (path4, range) => readPathTemplate(pattern, path4, range)
17810
18109
  );
17811
18110
  }
18111
+ function readRoutePaths(pattern, pathArgument, classification, module, options) {
18112
+ const resolution = routerResolutionOf(
18113
+ pattern,
18114
+ classification,
18115
+ module,
18116
+ options
18117
+ );
18118
+ if (resolution?.kind !== "composedMany") {
18119
+ return [
18120
+ {
18121
+ routePath: readRoutePath(
18122
+ pattern,
18123
+ pathArgument,
18124
+ classification,
18125
+ module,
18126
+ options
18127
+ )
18128
+ }
18129
+ ];
18130
+ }
18131
+ return resolution.values.map((prefix) => ({
18132
+ routePath: andThenReading(
18133
+ andThenReading(
18134
+ pathArgument,
18135
+ (literal2, range) => writtenReading(servedSpelling(pattern, prefix + literal2), range)
18136
+ ),
18137
+ (path4, range) => readPathTemplate(pattern, path4, range)
18138
+ ),
18139
+ mount: { siblings: resolution.values.length, prefix }
18140
+ }));
18141
+ }
18142
+ function routerResolutionOf(pattern, classification, module, options) {
18143
+ if (pattern.routerComposition === void 0 || options.routerIndex === void 0 || classification.objectName === null) {
18144
+ return null;
18145
+ }
18146
+ return options.routerIndex.resolve(
18147
+ pattern,
18148
+ classification.objectModule ?? module,
18149
+ classification.objectName
18150
+ );
18151
+ }
17812
18152
  function composeRoutePath(pattern, classification, module, options, literal2, range) {
17813
18153
  const prefix = readRouterPrefix(
17814
18154
  pattern,
@@ -18062,39 +18402,42 @@ function functionRouteUnits(pattern, pack, verb, classification, functionNode, m
18062
18402
  return [];
18063
18403
  }
18064
18404
  const ctx = createAnnotationContext(module.scopeFor);
18065
- return routeUnitOrAbstention(
18066
- {
18067
- pack,
18068
- name: functionName,
18069
- exportPath: [functionName],
18070
- method: verb,
18071
- routePath: readRoutePath(
18072
- pattern,
18073
- readPathArgument(classification),
18074
- classification,
18405
+ return readRoutePaths(
18406
+ pattern,
18407
+ readPathArgument(classification),
18408
+ classification,
18409
+ module,
18410
+ options
18411
+ ).flatMap(
18412
+ (entry) => routeUnitOrAbstention(
18413
+ {
18414
+ pack,
18415
+ name: functionName,
18416
+ exportPath: [functionName],
18417
+ method: verb,
18418
+ routePath: entry.routePath,
18419
+ ...entry.mount !== void 0 ? { mount: entry.mount } : {},
18420
+ requestBodyFromAnnotatedClass: pattern.annotatedClassIsRequestBody === true,
18421
+ readsReturnedStatus: pattern.statusFromReturnedTuple === true,
18422
+ injectedCallees: new Set(pattern.injectedParameterCallees ?? []),
18423
+ definitionNode: functionNode,
18424
+ enclosingScope: module.moduleScope,
18075
18425
  module,
18076
- options
18077
- ),
18078
- requestBodyFromAnnotatedClass: pattern.annotatedClassIsRequestBody === true,
18079
- readsReturnedStatus: pattern.statusFromReturnedTuple === true,
18080
- injectedCallees: new Set(pattern.injectedParameterCallees ?? []),
18081
- definitionNode: functionNode,
18082
- enclosingScope: module.moduleScope,
18083
- module,
18084
- filePath: options.filePath,
18085
- skipReceiverParam: false,
18086
- responseShape: readResponseModel(pattern, classification, module, ctx),
18087
- statusCode: defaultedStatus(
18088
- declaredOrReturnedStatus(
18089
- readStatusCode(pattern, classification),
18090
- readReturnedStatus(pattern, functionNode)
18426
+ filePath: options.filePath,
18427
+ skipReceiverParam: false,
18428
+ responseShape: readResponseModel(pattern, classification, module, ctx),
18429
+ statusCode: defaultedStatus(
18430
+ declaredOrReturnedStatus(
18431
+ readStatusCode(pattern, classification),
18432
+ readReturnedStatus(pattern, functionNode)
18433
+ ),
18434
+ pattern
18091
18435
  ),
18092
- pattern
18093
- ),
18094
- definitionsCtx: ctx,
18095
- storage: options.storage
18096
- },
18097
- options
18436
+ definitionsCtx: ctx,
18437
+ storage: options.storage
18438
+ },
18439
+ options
18440
+ )
18098
18441
  );
18099
18442
  }
18100
18443
  function readResponseShape(declared, readAnnotation) {
@@ -18237,6 +18580,7 @@ function buildRouteUnit(options) {
18237
18580
  kind: "handler",
18238
18581
  file: filePath,
18239
18582
  range: rangeOf(definitionNode),
18583
+ span: spanOf(definitionNode),
18240
18584
  exportName: exportPath[0] ?? name,
18241
18585
  exportPath
18242
18586
  },
@@ -18256,7 +18600,8 @@ function buildRouteUnit(options) {
18256
18600
  ...unreadRoleReadings(parameters, rangeOf(definitionNode)),
18257
18601
  ...responseShape.passedOver
18258
18602
  ],
18259
- ...collectedDefinitions(ctx) !== null ? { definitions: collectedDefinitions(ctx) } : {}
18603
+ ...collectedDefinitions(ctx) !== null ? { definitions: collectedDefinitions(ctx) } : {},
18604
+ ...options.mount !== void 0 ? { mount: options.mount } : {}
18260
18605
  };
18261
18606
  }
18262
18607
  function unreadRoleReadings(parameters, range) {
@@ -18579,7 +18924,7 @@ async function parsePython(source) {
18579
18924
  // src/project.ts
18580
18925
  import fs3 from "fs";
18581
18926
  import path3 from "path";
18582
- import { Database } from "@suss/datalog";
18927
+ import { Database, evaluate as evaluate2, lit as lit2, rule as rule2, variable as v2 } from "@suss/datalog";
18583
18928
  import { assembleSummary } from "@suss/extractor";
18584
18929
 
18585
18930
  // src/routers.ts
@@ -18649,24 +18994,90 @@ function buildRouterIndex(files, packs, resolverOptions) {
18649
18994
  return ownPrefix;
18650
18995
  }
18651
18996
  const routerPath = displayPaths.get(module);
18652
- const mount = index.mounts.get(construction);
18653
- if (mount === void 0) {
18997
+ const states = index.mounts.get(construction);
18998
+ if (states === void 0 || states.length === 0) {
18654
18999
  return { kind: "abstain", reason: unmountedReason(index, routerPath) };
18655
19000
  }
18656
- if (mount.kind === "abstain") {
18657
- return { kind: "abstain", reason: mount.reason };
19001
+ for (const state of states) {
19002
+ if (state.kind === "abstain") {
19003
+ return { kind: "abstain", reason: state.reason };
19004
+ }
19005
+ const rivalled = rivalRegistration(index, state.site, routerPath);
19006
+ if (rivalled !== null) {
19007
+ return { kind: "abstain", reason: rivalled };
19008
+ }
19009
+ }
19010
+ const composed = composedMountPrefix(index, construction);
19011
+ if (composed.kind === "abstain") {
19012
+ return composed;
18658
19013
  }
18659
- const rivalled = rivalRegistration(index, mount.site, routerPath);
18660
- if (rivalled !== null) {
18661
- return { kind: "abstain", reason: rivalled };
19014
+ if (composed.kind === "composedMany") {
19015
+ return {
19016
+ kind: "composedMany",
19017
+ values: composed.values.map((value) => value + ownPrefix.value)
19018
+ };
18662
19019
  }
18663
19020
  return {
18664
19021
  kind: "composed",
18665
- value: mount.includePrefix + ownPrefix.value
19022
+ value: composed.value + ownPrefix.value
18666
19023
  };
18667
19024
  }
18668
19025
  };
18669
19026
  }
19027
+ function composedMountPrefix(index, construction) {
19028
+ const paths = mountPathsOf(mountEdgesOf(index), construction.valueKey);
19029
+ if (paths === null) {
19030
+ return {
19031
+ kind: "abstain",
19032
+ reason: "is mounted through a chain of routers this reading cannot compose"
19033
+ };
19034
+ }
19035
+ const distinct = [...new Set(paths)];
19036
+ const only = distinct[0];
19037
+ if (only === void 0) {
19038
+ return {
19039
+ kind: "abstain",
19040
+ reason: "is mounted through a chain of routers this reading cannot compose"
19041
+ };
19042
+ }
19043
+ if (distinct.length > 1) {
19044
+ return { kind: "composedMany", values: distinct };
19045
+ }
19046
+ return { kind: "composed", value: only };
19047
+ }
19048
+ function mountEdgesOf(index) {
19049
+ if (index.mountEdges !== void 0) {
19050
+ return index.mountEdges;
19051
+ }
19052
+ const edges = /* @__PURE__ */ new Map();
19053
+ const push = (childKey, edge) => {
19054
+ const list = edges.get(childKey) ?? [];
19055
+ list.push(edge);
19056
+ edges.set(childKey, list);
19057
+ };
19058
+ for (const [target, states] of index.mounts) {
19059
+ for (const state of states) {
19060
+ if (state.kind === "abstain") {
19061
+ push(target.valueKey, { parentId: target.valueKey, prefix: "" });
19062
+ continue;
19063
+ }
19064
+ push(target.valueKey, {
19065
+ parentId: state.parentValueKey ?? rootKeyOf(target),
19066
+ prefix: state.includePrefix
19067
+ });
19068
+ }
19069
+ }
19070
+ for (const [valueKey2, construction] of index.byValueKey) {
19071
+ if (!index.mounts.has(construction)) {
19072
+ push(valueKey2, { parentId: valueKey2, prefix: "" });
19073
+ }
19074
+ }
19075
+ index.mountEdges = edges;
19076
+ return edges;
19077
+ }
19078
+ function rootKeyOf(target) {
19079
+ return `root:${target.valueKey}`;
19080
+ }
18670
19081
  function declaredOnMountObject(index, module, objectName) {
18671
19082
  const objectPrefix = index.objectPrefixes.get(module)?.get(objectName);
18672
19083
  if (objectPrefix === void 0) {
@@ -19007,7 +19418,8 @@ var MOUNT_STATE_BY_EFFECT = {
19007
19418
  prefixes: (statedPrefix, site) => ({
19008
19419
  kind: "mounted",
19009
19420
  includePrefix: statedPrefix,
19010
- site
19421
+ site,
19422
+ parentValueKey: null
19011
19423
  }),
19012
19424
  replaces: () => ({
19013
19425
  kind: "abstain",
@@ -19015,14 +19427,9 @@ var MOUNT_STATE_BY_EFFECT = {
19015
19427
  })
19016
19428
  };
19017
19429
  function recordMount(index, target, state) {
19018
- if (index.mounts.has(target)) {
19019
- index.mounts.set(target, {
19020
- kind: "abstain",
19021
- reason: "is mounted more than once"
19022
- });
19023
- return;
19024
- }
19025
- index.mounts.set(target, state);
19430
+ const states = index.mounts.get(target) ?? [];
19431
+ states.push(state);
19432
+ index.mounts.set(target, states);
19026
19433
  }
19027
19434
  function collectMounts(bound, byFile, importModule, composition, resolverOptions, index) {
19028
19435
  const scan = {
@@ -19051,7 +19458,7 @@ var WALK_DESCENTS = {
19051
19458
  decorated_definition: (stmt, position, scan, visit) => {
19052
19459
  walkStatements([stripDecorators(stmt).definition], position, scan, visit);
19053
19460
  },
19054
- function_definition: (stmt, position, scan, visit) => {
19461
+ function_definition: (stmt, _position, scan, visit) => {
19055
19462
  const scope = scan.bound.module.scopeFor.get(stmt.id);
19056
19463
  if (scope === void 0) {
19057
19464
  return;
@@ -19282,8 +19689,10 @@ function recordMountStatement(stmt, position, scan) {
19282
19689
  position.scope,
19283
19690
  scan
19284
19691
  );
19692
+ const includerKey = nodeId(scan.bound.file, mountCall.includerCall);
19285
19693
  const state = mountStateOf(
19286
19694
  mountCall.includerConstructorName,
19695
+ scan.index.byValueKey.get(includerKey) ?? null,
19287
19696
  keywordArgs,
19288
19697
  objectPrefix,
19289
19698
  scan.composition,
@@ -19295,18 +19704,15 @@ function recordMountStatement(stmt, position, scan) {
19295
19704
  recordMount(scan.index, target, state);
19296
19705
  }
19297
19706
  }
19298
- function mountStateOf(includerConstructorName, keywordArgs, objectPrefix, composition, site, scope) {
19299
- if (includerConstructorName === composition.routerConstructorName) {
19300
- return {
19301
- kind: "abstain",
19302
- reason: "is mounted onto another router, one hop past what this reading follows"
19303
- };
19304
- }
19305
- if (objectPrefix.kind === "abstain") {
19306
- return {
19307
- kind: "abstain",
19308
- reason: `is mounted on an object that ${objectPrefix.reason}`
19309
- };
19707
+ function mountStateOf(includerConstructorName, includer, keywordArgs, objectPrefix, composition, site, scope) {
19708
+ const base = mountBaseOf(
19709
+ includerConstructorName,
19710
+ includer,
19711
+ objectPrefix,
19712
+ composition
19713
+ );
19714
+ if (base.kind === "abstain") {
19715
+ return base;
19310
19716
  }
19311
19717
  const mountPrefix = readPrefixKeyword(
19312
19718
  keywordArgs,
@@ -19321,14 +19727,56 @@ function mountStateOf(includerConstructorName, keywordArgs, objectPrefix, compos
19321
19727
  };
19322
19728
  }
19323
19729
  if (mountPrefix.kind === "unstated") {
19324
- return { kind: "mounted", includePrefix: objectPrefix.value, site };
19730
+ return {
19731
+ kind: "mounted",
19732
+ includePrefix: base.value,
19733
+ site,
19734
+ parentValueKey: base.parentValueKey
19735
+ };
19325
19736
  }
19326
19737
  const effect = composition.mountPrefixEffect ?? "prefixes";
19327
19738
  const state = MOUNT_STATE_BY_EFFECT[effect](mountPrefix.value, site);
19328
19739
  if (state.kind === "abstain") {
19329
19740
  return state;
19330
19741
  }
19331
- return { ...state, includePrefix: objectPrefix.value + state.includePrefix };
19742
+ return {
19743
+ ...state,
19744
+ includePrefix: base.value + state.includePrefix,
19745
+ parentValueKey: base.parentValueKey
19746
+ };
19747
+ }
19748
+ function mountBaseOf(includerConstructorName, includer, objectPrefix, composition) {
19749
+ if (includerConstructorName !== composition.routerConstructorName) {
19750
+ if (objectPrefix.kind === "abstain") {
19751
+ return {
19752
+ kind: "abstain",
19753
+ reason: `is mounted on an object that ${objectPrefix.reason}`
19754
+ };
19755
+ }
19756
+ return {
19757
+ kind: "composed",
19758
+ value: objectPrefix.value,
19759
+ parentValueKey: null
19760
+ };
19761
+ }
19762
+ if (includer === null) {
19763
+ return {
19764
+ kind: "abstain",
19765
+ reason: "is mounted onto a router this reading never saw constructed"
19766
+ };
19767
+ }
19768
+ const parentOwn = composedOwnPrefix(includer.prefix, composition);
19769
+ if (parentOwn.kind === "abstain") {
19770
+ return {
19771
+ kind: "abstain",
19772
+ reason: `is mounted onto a router that ${parentOwn.reason}`
19773
+ };
19774
+ }
19775
+ return {
19776
+ kind: "composed",
19777
+ value: parentOwn.value,
19778
+ parentValueKey: includer.valueKey
19779
+ };
19332
19780
  }
19333
19781
  function collectCarrierCalls(carrier, scan) {
19334
19782
  walkStatements(
@@ -19606,7 +20054,11 @@ async function extractPythonProject(options) {
19606
20054
  ...couldMatch,
19607
20055
  ...storagePatterns.flatMap((pattern) => pattern.queryFunctions ?? [])
19608
20056
  ]);
19609
- const leadsToStorage = functionsReachingStorage(definitions, startsAQuery);
20057
+ const leadsToStorage = functionsReachingStorage(
20058
+ db,
20059
+ definitions,
20060
+ startsAQuery
20061
+ );
19610
20062
  const routerIndex = buildRouterIndex(bound, options.packs, {
19611
20063
  roots: options.roots,
19612
20064
  ...mountsRouters ? { facts: db } : {}
@@ -19735,32 +20187,33 @@ function callsUnder(node, found = []) {
19735
20187
  }
19736
20188
  return found;
19737
20189
  }
19738
- function functionsReachingStorage(definitions, couldMatch) {
19739
- const bodies = [];
20190
+ var REACHES_STORAGE_RULES = [
20191
+ rule2(
20192
+ "reachesStorage",
20193
+ [v2("f")],
20194
+ [lit2("defCallsName", v2("f"), v2("m")), lit2("queryStart", v2("m"))]
20195
+ ),
20196
+ rule2(
20197
+ "reachesStorage",
20198
+ [v2("f")],
20199
+ [lit2("defCallsName", v2("f"), v2("m")), lit2("reachesStorage", v2("m"))]
20200
+ )
20201
+ ];
20202
+ function functionsReachingStorage(db, definitions, couldMatch) {
19740
20203
  for (const node of definitions.values()) {
19741
20204
  const name = field(node, "name");
19742
20205
  if (name === null) {
19743
20206
  continue;
19744
20207
  }
19745
- bodies.push({ name: name.text, calls: callsUnder(node).map(calledName) });
19746
- }
19747
- const reaching = /* @__PURE__ */ new Set();
19748
- for (const body of bodies) {
19749
- if (body.calls.some((called) => couldMatch.has(called))) {
19750
- reaching.add(body.name);
20208
+ for (const called of callsUnder(node).map(calledName)) {
20209
+ db.add("defCallsName", [name.text, called]);
19751
20210
  }
19752
20211
  }
19753
- for (let grew = true; grew; ) {
19754
- grew = false;
19755
- for (const body of bodies) {
19756
- if (reaching.has(body.name) || !body.calls.some((c) => reaching.has(c))) {
19757
- continue;
19758
- }
19759
- reaching.add(body.name);
19760
- grew = true;
19761
- }
20212
+ for (const name of couldMatch) {
20213
+ db.add("queryStart", [name]);
19762
20214
  }
19763
- return reaching;
20215
+ evaluate2(db, REACHES_STORAGE_RULES);
20216
+ return new Set(db.facts("reachesStorage").map((row) => String(row[0])));
19764
20217
  }
19765
20218
  export {
19766
20219
  annotationToShape,