@suss/adapter-ruby 0.21.1 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -30,19 +30,37 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ ADAPTER_VERSION: () => ADAPTER_VERSION,
34
+ RubyWhySession: () => RubyWhySession,
33
35
  ancestryOf: () => ancestryOf,
36
+ bodyStatements: () => bodyStatements,
37
+ booleanLiteralValue: () => booleanLiteralValue,
38
+ collectFileConstants: () => collectFileConstants,
34
39
  createFileCache: () => createFileCache,
35
40
  discoverUnits: () => discoverUnits,
41
+ emitConstantBindings: () => emitConstantBindings,
36
42
  emitEntryFact: () => emitEntryFact,
43
+ emitValueFacts: () => emitValueFacts,
37
44
  extractRubyProject: () => extractRubyProject,
45
+ field: () => field,
38
46
  findRubyFiles: () => findRubyFiles,
39
47
  graphqlTypeNameFromQualified: () => graphqlTypeNameFromQualified,
48
+ hashKeySymbolName: () => hashKeySymbolName,
40
49
  inheritedStatements: () => inheritedStatements,
41
50
  methodInAncestry: () => methodInAncestry,
51
+ nodeId: () => nodeId,
42
52
  parseRuby: () => parseRuby,
53
+ parseRubySync: () => parseRubySync,
54
+ preloadRubyGrammar: () => preloadRubyGrammar,
43
55
  qualifyConstantRef: () => qualifyConstantRef,
44
56
  reachDefinition: () => reachDefinition,
57
+ readCallArgs: () => readCallArgs,
58
+ readKey: () => readKey,
45
59
  resolveConstantFile: () => resolveConstantFile,
60
+ rubyStubEvidence: () => rubyStubEvidence,
61
+ runStatements: () => runStatements,
62
+ stringLiteralValue: () => stringLiteralValue,
63
+ symbolValue: () => symbolValue,
46
64
  typeShapeFromNode: () => typeShapeFromNode,
47
65
  underscoreConstantPath: () => underscoreConstantPath,
48
66
  unitKey: () => unitKey,
@@ -80,6 +98,7 @@ var OWN_BODY_TYPES = /* @__PURE__ */ new Set([
80
98
  "module",
81
99
  "singleton_class"
82
100
  ]);
101
+ var NESTING_TYPES = /* @__PURE__ */ new Set(["class", "module"]);
83
102
  var ARGUMENT_LIST_TYPE = "argument_list";
84
103
  function runStatements(body, blockConfigures = () => false) {
85
104
  const found = [];
@@ -97,6 +116,22 @@ function runStatements(body, blockConfigures = () => false) {
97
116
  });
98
117
  return found;
99
118
  }
119
+ function stringLiteralValue(node) {
120
+ if (node.type !== "string") {
121
+ return null;
122
+ }
123
+ let content = "";
124
+ for (const child of bodyStatements(node)) {
125
+ if (child.type === "string_content") {
126
+ content += child.text;
127
+ continue;
128
+ }
129
+ if (child.type === "interpolation") {
130
+ return null;
131
+ }
132
+ }
133
+ return content;
134
+ }
100
135
  function symbolValue(node) {
101
136
  return node.type === "simple_symbol" ? node.text.slice(1) : null;
102
137
  }
@@ -113,6 +148,71 @@ function instanceMethodsByName(body) {
113
148
  }
114
149
  return methods;
115
150
  }
151
+ var VISIBILITY_KEYWORDS = /* @__PURE__ */ new Set([
152
+ "private",
153
+ "protected",
154
+ "public"
155
+ ]);
156
+ function visibilityKeyword(text) {
157
+ return VISIBILITY_KEYWORDS.has(text) ? text : null;
158
+ }
159
+ function setVisibility(visibility, name, keyword) {
160
+ if (keyword === "public") {
161
+ visibility.delete(name);
162
+ return;
163
+ }
164
+ visibility.set(name, keyword);
165
+ }
166
+ function markCalledOutMethods(call, keyword, visibility) {
167
+ const argumentList = field(call, "arguments");
168
+ if (argumentList === null) {
169
+ return;
170
+ }
171
+ for (const arg of bodyStatements(argumentList)) {
172
+ const name = arg.type === "method" ? field(arg, "name")?.text : symbolValue(arg);
173
+ if (name !== void 0 && name !== null) {
174
+ setVisibility(visibility, name, keyword);
175
+ }
176
+ }
177
+ }
178
+ function instanceMethodVisibility(body) {
179
+ const visibility = /* @__PURE__ */ new Map();
180
+ let mode = "public";
181
+ for (const stmt of bodyStatements(body)) {
182
+ if (stmt.type === "method") {
183
+ const name = field(stmt, "name")?.text;
184
+ if (name !== void 0) {
185
+ setVisibility(visibility, name, mode);
186
+ }
187
+ continue;
188
+ }
189
+ if (stmt.type === "identifier") {
190
+ mode = visibilityKeyword(stmt.text) ?? mode;
191
+ continue;
192
+ }
193
+ if (stmt.type !== "call" || field(stmt, "receiver") !== null) {
194
+ continue;
195
+ }
196
+ const keyword = visibilityKeyword(field(stmt, "method")?.text ?? "");
197
+ if (keyword !== null) {
198
+ markCalledOutMethods(stmt, keyword, visibility);
199
+ }
200
+ }
201
+ return visibility;
202
+ }
203
+ function singletonMethodsByName(body) {
204
+ const methods = /* @__PURE__ */ new Map();
205
+ for (const stmt of runStatements(body)) {
206
+ if (stmt.type !== "singleton_method") {
207
+ continue;
208
+ }
209
+ const name = field(stmt, "name")?.text;
210
+ if (name !== void 0) {
211
+ methods.set(name, stmt);
212
+ }
213
+ }
214
+ return methods;
215
+ }
116
216
  function bareCallArgumentGroups(body, name) {
117
217
  const groups = [];
118
218
  for (const stmt of runStatements(body)) {
@@ -300,7 +400,10 @@ async function reachDefinition(qualifiedName, lookup) {
300
400
  qualifiedName,
301
401
  lookup.pathConvention
302
402
  );
303
- const fileRoot = filePath === null ? null : await lookup.parsedFile(filePath);
403
+ if (filePath === null) {
404
+ return null;
405
+ }
406
+ const fileRoot = await lookup.parsedFile(filePath);
304
407
  if (fileRoot === null) {
305
408
  return null;
306
409
  }
@@ -311,7 +414,7 @@ async function reachDefinition(qualifiedName, lookup) {
311
414
  return null;
312
415
  }
313
416
  const knownClasses = new Set(all.map((info) => info.qualifiedName));
314
- return matches.map((info) => ({ info, knownClasses }));
417
+ return matches.map((info) => ({ info, knownClasses, file: filePath }));
315
418
  }
316
419
  function ancestryOf(name, blocks, lookup) {
317
420
  return chainOf(
@@ -403,17 +506,19 @@ function methodInAncestry(ancestry, name) {
403
506
  if (entry.type === "unfollowed") {
404
507
  return {
405
508
  type: "unsettled",
406
- reason: `inherited from ${entry.name}, which this run did not read`
509
+ reason: `inherited from ${entry.name}, which this run did not read`,
510
+ cause: "unreadAncestor"
407
511
  };
408
512
  }
409
513
  const found = definitionIn(entry.blocks, name);
410
- if (found.method !== null) {
411
- return { type: "found", method: found.method };
514
+ if (found.method !== null && found.block !== null) {
515
+ return { type: "found", method: found.method, block: found.block };
412
516
  }
413
517
  if (found.dynamic) {
414
518
  return {
415
519
  type: "unsettled",
416
- reason: "defined with define_method, which this reader does not follow"
520
+ reason: "defined with define_method, which this reader does not follow",
521
+ cause: "dynamicDefine"
417
522
  };
418
523
  }
419
524
  }
@@ -421,16 +526,21 @@ function methodInAncestry(ancestry, name) {
421
526
  }
422
527
  function definitionIn(blocks, name) {
423
528
  let method = null;
529
+ let block = null;
424
530
  let dynamic = false;
425
- for (const block of blocks) {
426
- const body = block.info.bodyNode;
531
+ for (const candidate of blocks) {
532
+ const body = candidate.info.bodyNode;
427
533
  if (body === null) {
428
534
  continue;
429
535
  }
430
- method = instanceMethodsByName(body).get(name) ?? method;
536
+ const found = instanceMethodsByName(body).get(name);
537
+ if (found !== void 0) {
538
+ method = found;
539
+ block = candidate;
540
+ }
431
541
  dynamic ||= bareCallArgumentGroups(body, DEFINE_METHOD_CALL).length > 0;
432
542
  }
433
- return { method, dynamic };
543
+ return { method, block, dynamic };
434
544
  }
435
545
  function inheritedStatements(ancestry, blockConfigures) {
436
546
  const statements = [];
@@ -452,11 +562,112 @@ function inheritedStatements(ancestry, blockConfigures) {
452
562
  }
453
563
 
454
564
  // src/discovery.ts
565
+ var import_behavioral_ir2 = require("@suss/behavioral-ir");
566
+ var import_extractor4 = require("@suss/extractor");
567
+
568
+ // src/envReads.ts
455
569
  var import_behavioral_ir = require("@suss/behavioral-ir");
456
- var import_extractor3 = require("@suss/extractor");
570
+ var import_extractor2 = require("@suss/extractor");
571
+ var RUBY_ENV_RECOGNITION = "ruby-env";
572
+ var DEFERRED_BODY_TYPES = /* @__PURE__ */ new Set(["method", "singleton_method", "lambda"]);
573
+ function envReadEffects(root) {
574
+ const effects = [];
575
+ (0, import_extractor2.walkDescendants)(root, null, {
576
+ at: (node) => {
577
+ const read = envReadAt(node);
578
+ if (read !== null) {
579
+ effects.push(configReadEffect(read));
580
+ }
581
+ },
582
+ into: (node) => DEFERRED_BODY_TYPES.has(node.type) ? import_extractor2.SKIP_CHILDREN : null
583
+ });
584
+ return effects;
585
+ }
586
+ function configReadEffect(read) {
587
+ return {
588
+ type: "interaction",
589
+ binding: (0, import_behavioral_ir.runtimeConfigBinding)({
590
+ recognition: RUBY_ENV_RECOGNITION,
591
+ deploymentTarget: "lambda",
592
+ instanceName: "<unknown>"
593
+ }),
594
+ callee: `ENV["${read.name}"]`,
595
+ interaction: {
596
+ class: "config-read",
597
+ name: read.name,
598
+ defaulted: read.defaulted
599
+ }
600
+ };
601
+ }
602
+ function envReadAt(node) {
603
+ if (node.type === "element_reference") {
604
+ return elementRead(node);
605
+ }
606
+ if (node.type === "call") {
607
+ return fetchRead(node);
608
+ }
609
+ return null;
610
+ }
611
+ function elementRead(node) {
612
+ const object2 = field(node, "object");
613
+ if (object2 === null || !isEnv(object2) || isAssignedTo(node)) {
614
+ return null;
615
+ }
616
+ const index = node.namedChildren.find(
617
+ (child) => child !== null && child.id !== object2.id
618
+ );
619
+ const name = index === void 0 ? null : stringLiteralValue(index);
620
+ if (name === null) {
621
+ return null;
622
+ }
623
+ return { name, defaulted: isDefaultedAt(node) };
624
+ }
625
+ function fetchRead(node) {
626
+ const receiver = field(node, "receiver");
627
+ if (receiver === null || !isEnv(receiver) || field(node, "method")?.text !== "fetch") {
628
+ return null;
629
+ }
630
+ const { positional } = readCallArgs(field(node, "arguments"));
631
+ const name = positional[0] === void 0 ? null : stringLiteralValue(positional[0]);
632
+ if (name === null) {
633
+ return null;
634
+ }
635
+ const hasDefault = positional.length > 1 || field(node, "block") !== null;
636
+ return { name, defaulted: hasDefault || isDefaultedAt(node) };
637
+ }
638
+ function isEnv(node) {
639
+ if (node.type === "constant") {
640
+ return node.text === "ENV";
641
+ }
642
+ return node.type === "scope_resolution" && field(node, "scope") === null && field(node, "name")?.text === "ENV";
643
+ }
644
+ function isAssignedTo(node) {
645
+ const parent = node.parent;
646
+ return parent !== null && (parent.type === "assignment" || parent.type === "operator_assignment") && field(parent, "left")?.id === node.id;
647
+ }
648
+ function isDefaultedAt(node) {
649
+ let child = node;
650
+ let parent = node.parent;
651
+ while (parent !== null) {
652
+ if (parent.type === "parenthesized_statements") {
653
+ child = parent;
654
+ parent = parent.parent;
655
+ continue;
656
+ }
657
+ if (parent.type !== "binary" || field(parent, "operator")?.text !== "||") {
658
+ return false;
659
+ }
660
+ if (field(parent, "left")?.id === child.id) {
661
+ return true;
662
+ }
663
+ child = parent;
664
+ parent = parent.parent;
665
+ }
666
+ return false;
667
+ }
457
668
 
458
669
  // src/paths/effects.ts
459
- var import_extractor2 = require("@suss/extractor");
670
+ var import_extractor3 = require("@suss/extractor");
460
671
 
461
672
  // src/paths/lowering.ts
462
673
  var RAISE_NAMES = /* @__PURE__ */ new Set(["raise", "fail"]);
@@ -707,8 +918,18 @@ function withoutChainLinks(calls) {
707
918
  }
708
919
  return calls.filter((call) => !isLink.has(call.id));
709
920
  }
921
+ function calleeMethodName(call) {
922
+ const method = field(call, "method");
923
+ if (method !== null) {
924
+ return method.text;
925
+ }
926
+ return field(call, "receiver") !== null ? "call" : children(call)[0]?.text;
927
+ }
710
928
  function isPropertyRead(node) {
711
- return field(node, "receiver") !== null && field(node, "arguments") === null;
929
+ if (field(node, "receiver") === null || field(node, "arguments") !== null) {
930
+ return false;
931
+ }
932
+ return calleeMethodName(node) !== "call";
712
933
  }
713
934
  function isRaise2(node) {
714
935
  const method = field(node, "method") ?? children(node)[0] ?? null;
@@ -728,11 +949,11 @@ function bodyCalls(node, found = []) {
728
949
  }
729
950
  function calleeText(call) {
730
951
  const receiver = field(call, "receiver");
731
- const method = field(call, "method") ?? children(call)[0];
952
+ const method = calleeMethodName(call);
732
953
  if (method === void 0) {
733
954
  return call.text;
734
955
  }
735
- return receiver === null ? method.text : `${receiver.text}.${method.text}`;
956
+ return receiver === null ? method : `${receiver.text}.${method}`;
736
957
  }
737
958
  function argOf(node) {
738
959
  const literal2 = LITERAL_ARGS[node.type]?.(node);
@@ -780,7 +1001,7 @@ function invocationEffects(definitionNode) {
780
1001
  statements.push(statement);
781
1002
  }
782
1003
  const lowered = lowerRubyBody(body, statements);
783
- const enumerated = (0, import_extractor2.enumerateOrDegrade)(
1004
+ const enumerated = (0, import_extractor3.enumerateOrDegrade)(
784
1005
  {
785
1006
  statements: lowered.statements,
786
1007
  terminalsByStmt: lowered.terminalsByStmt
@@ -789,7 +1010,7 @@ function invocationEffects(definitionNode) {
789
1010
  );
790
1011
  return calls.map((call) => {
791
1012
  const statement = statementOf.get(call.id);
792
- const conditions = (0, import_extractor2.sharedGatingConditions)(
1013
+ const conditions = (0, import_extractor3.sharedGatingConditions)(
793
1014
  statement === void 0 ? void 0 : enumerated.byTerminal.get(statement)
794
1015
  );
795
1016
  return {
@@ -803,7 +1024,7 @@ function invocationEffects(definitionNode) {
803
1024
  }
804
1025
 
805
1026
  // src/storage.ts
806
- var import_datalog3 = require("@suss/datalog");
1027
+ var import_datalog4 = require("@suss/datalog");
807
1028
 
808
1029
  // ../../../node_modules/zod/v4/classic/external.js
809
1030
  var external_exports = {};
@@ -1485,8 +1706,8 @@ function assertNever(_x) {
1485
1706
  function assert(_) {
1486
1707
  }
1487
1708
  function getEnumValues(entries) {
1488
- const numericValues = Object.values(entries).filter((v2) => typeof v2 === "number");
1489
- const values = Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v2]) => v2);
1709
+ const numericValues = Object.values(entries).filter((v4) => typeof v4 === "number");
1710
+ const values = Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v4]) => v4);
1490
1711
  return values;
1491
1712
  }
1492
1713
  function joinValues(array2, separator = "|") {
@@ -1540,9 +1761,9 @@ function defineLazy(object2, key, getter) {
1540
1761
  }
1541
1762
  return value;
1542
1763
  },
1543
- set(v2) {
1764
+ set(v4) {
1544
1765
  Object.defineProperty(object2, key, {
1545
- value: v2
1766
+ value: v4
1546
1767
  // configurable: true,
1547
1768
  });
1548
1769
  },
@@ -1571,10 +1792,10 @@ function mergeDefs(...defs) {
1571
1792
  function cloneDef(schema) {
1572
1793
  return mergeDefs(schema._zod.def);
1573
1794
  }
1574
- function getElementAtPath(obj, path4) {
1575
- if (!path4)
1795
+ function getElementAtPath(obj, path7) {
1796
+ if (!path7)
1576
1797
  return obj;
1577
- return path4.reduce((acc, key) => acc?.[key], obj);
1798
+ return path7.reduce((acc, key) => acc?.[key], obj);
1578
1799
  }
1579
1800
  function promiseAllObject(promisesObj) {
1580
1801
  const keys = Object.keys(promisesObj);
@@ -1983,11 +2204,11 @@ function explicitlyAborted(x, startIndex = 0) {
1983
2204
  }
1984
2205
  return false;
1985
2206
  }
1986
- function prefixIssues(path4, issues) {
2207
+ function prefixIssues(path7, issues) {
1987
2208
  return issues.map((iss) => {
1988
2209
  var _a3;
1989
2210
  (_a3 = iss).path ?? (_a3.path = []);
1990
- iss.path.unshift(path4);
2211
+ iss.path.unshift(path7);
1991
2212
  return iss;
1992
2213
  });
1993
2214
  }
@@ -2134,16 +2355,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
2134
2355
  }
2135
2356
  function formatError(error51, mapper = (issue2) => issue2.message) {
2136
2357
  const fieldErrors = { _errors: [] };
2137
- const processError = (error52, path4 = []) => {
2358
+ const processError = (error52, path7 = []) => {
2138
2359
  for (const issue2 of error52.issues) {
2139
2360
  if (issue2.code === "invalid_union" && issue2.errors.length) {
2140
- issue2.errors.map((issues) => processError({ issues }, [...path4, ...issue2.path]));
2361
+ issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
2141
2362
  } else if (issue2.code === "invalid_key") {
2142
- processError({ issues: issue2.issues }, [...path4, ...issue2.path]);
2363
+ processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
2143
2364
  } else if (issue2.code === "invalid_element") {
2144
- processError({ issues: issue2.issues }, [...path4, ...issue2.path]);
2365
+ processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
2145
2366
  } else {
2146
- const fullpath = [...path4, ...issue2.path];
2367
+ const fullpath = [...path7, ...issue2.path];
2147
2368
  if (fullpath.length === 0) {
2148
2369
  fieldErrors._errors.push(mapper(issue2));
2149
2370
  } else {
@@ -2170,17 +2391,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
2170
2391
  }
2171
2392
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
2172
2393
  const result = { errors: [] };
2173
- const processError = (error52, path4 = []) => {
2394
+ const processError = (error52, path7 = []) => {
2174
2395
  var _a3, _b;
2175
2396
  for (const issue2 of error52.issues) {
2176
2397
  if (issue2.code === "invalid_union" && issue2.errors.length) {
2177
- issue2.errors.map((issues) => processError({ issues }, [...path4, ...issue2.path]));
2398
+ issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
2178
2399
  } else if (issue2.code === "invalid_key") {
2179
- processError({ issues: issue2.issues }, [...path4, ...issue2.path]);
2400
+ processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
2180
2401
  } else if (issue2.code === "invalid_element") {
2181
- processError({ issues: issue2.issues }, [...path4, ...issue2.path]);
2402
+ processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
2182
2403
  } else {
2183
- const fullpath = [...path4, ...issue2.path];
2404
+ const fullpath = [...path7, ...issue2.path];
2184
2405
  if (fullpath.length === 0) {
2185
2406
  result.errors.push(mapper(issue2));
2186
2407
  continue;
@@ -2212,8 +2433,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
2212
2433
  }
2213
2434
  function toDotPath(_path) {
2214
2435
  const segs = [];
2215
- const path4 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2216
- for (const seg of path4) {
2436
+ const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2437
+ for (const seg of path7) {
2217
2438
  if (typeof seg === "number")
2218
2439
  segs.push(`[${seg}]`);
2219
2440
  else if (typeof seg === "symbol")
@@ -3229,10 +3450,10 @@ var $ZodUUID = /* @__PURE__ */ $constructor("$ZodUUID", (inst, def) => {
3229
3450
  v7: 7,
3230
3451
  v8: 8
3231
3452
  };
3232
- const v2 = versionMap[def.version];
3233
- if (v2 === void 0)
3453
+ const v4 = versionMap[def.version];
3454
+ if (v4 === void 0)
3234
3455
  throw new Error(`Invalid UUID version: "${def.version}"`);
3235
- def.pattern ?? (def.pattern = uuid(v2));
3456
+ def.pattern ?? (def.pattern = uuid(v4));
3236
3457
  } else
3237
3458
  def.pattern ?? (def.pattern = uuid());
3238
3459
  $ZodStringFormat.init(inst, def);
@@ -3837,8 +4058,8 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
3837
4058
  const field2 = shape[key]._zod;
3838
4059
  if (field2.values) {
3839
4060
  propValues[key] ?? (propValues[key] = /* @__PURE__ */ new Set());
3840
- for (const v2 of field2.values)
3841
- propValues[key].add(v2);
4061
+ for (const v4 of field2.values)
4062
+ propValues[key].add(v4);
3842
4063
  }
3843
4064
  }
3844
4065
  return propValues;
@@ -4133,10 +4354,10 @@ var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnio
4133
4354
  const pv = option._zod.propValues;
4134
4355
  if (!pv || Object.keys(pv).length === 0)
4135
4356
  throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(option)}"`);
4136
- for (const [k, v2] of Object.entries(pv)) {
4357
+ for (const [k, v4] of Object.entries(pv)) {
4137
4358
  if (!propValues[k])
4138
4359
  propValues[k] = /* @__PURE__ */ new Set();
4139
- for (const val of v2) {
4360
+ for (const val of v4) {
4140
4361
  propValues[k].add(val);
4141
4362
  }
4142
4363
  }
@@ -4150,11 +4371,11 @@ var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnio
4150
4371
  const values = o._zod.propValues?.[def.discriminator];
4151
4372
  if (!values || values.size === 0)
4152
4373
  throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(o)}"`);
4153
- for (const v2 of values) {
4154
- if (map2.has(v2)) {
4155
- throw new Error(`Duplicate discriminator value "${String(v2)}"`);
4374
+ for (const v4 of values) {
4375
+ if (map2.has(v4)) {
4376
+ throw new Error(`Duplicate discriminator value "${String(v4)}"`);
4156
4377
  }
4157
- map2.set(v2, o);
4378
+ map2.set(v4, o);
4158
4379
  }
4159
4380
  }
4160
4381
  return map2;
@@ -4793,8 +5014,8 @@ var $ZodPrefault = /* @__PURE__ */ $constructor("$ZodPrefault", (inst, def) => {
4793
5014
  var $ZodNonOptional = /* @__PURE__ */ $constructor("$ZodNonOptional", (inst, def) => {
4794
5015
  $ZodType.init(inst, def);
4795
5016
  defineLazy(inst._zod, "values", () => {
4796
- const v2 = def.innerType._zod.values;
4797
- return v2 ? new Set([...v2].filter((x) => x !== void 0)) : void 0;
5017
+ const v4 = def.innerType._zod.values;
5018
+ return v4 ? new Set([...v4].filter((x) => x !== void 0)) : void 0;
4798
5019
  });
4799
5020
  inst._zod.parse = (payload, ctx) => {
4800
5021
  const result = def.innerType._zod.run(payload, ctx);
@@ -7191,7 +7412,7 @@ var error17 = () => {
7191
7412
  if (issue2.values.length === 1) {
7192
7413
  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])}`;
7193
7414
  }
7194
- const stringified = issue2.values.map((v2) => stringifyPrimitive(v2));
7415
+ const stringified = issue2.values.map((v4) => stringifyPrimitive(v4));
7195
7416
  if (issue2.values.length === 2) {
7196
7417
  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]}`;
7197
7418
  }
@@ -11946,7 +12167,7 @@ function _set(Class2, valueType, params) {
11946
12167
  }
11947
12168
  // @__NO_SIDE_EFFECTS__
11948
12169
  function _enum(Class2, values, params) {
11949
- const entries = Array.isArray(values) ? Object.fromEntries(values.map((v2) => [v2, v2])) : values;
12170
+ const entries = Array.isArray(values) ? Object.fromEntries(values.map((v4) => [v4, v4])) : values;
11950
12171
  return new Class2({
11951
12172
  type: "enum",
11952
12173
  entries,
@@ -12151,8 +12372,8 @@ function _stringbool(Classes, _params) {
12151
12372
  let truthyArray = params.truthy ?? ["true", "1", "yes", "on", "y", "enabled"];
12152
12373
  let falsyArray = params.falsy ?? ["false", "0", "no", "off", "n", "disabled"];
12153
12374
  if (params.case !== "sensitive") {
12154
- truthyArray = truthyArray.map((v2) => typeof v2 === "string" ? v2.toLowerCase() : v2);
12155
- falsyArray = falsyArray.map((v2) => typeof v2 === "string" ? v2.toLowerCase() : v2);
12375
+ truthyArray = truthyArray.map((v4) => typeof v4 === "string" ? v4.toLowerCase() : v4);
12376
+ falsyArray = falsyArray.map((v4) => typeof v4 === "string" ? v4.toLowerCase() : v4);
12156
12377
  }
12157
12378
  const truthySet = new Set(truthyArray);
12158
12379
  const falsySet = new Set(falsyArray);
@@ -12694,9 +12915,9 @@ var dateProcessor = (_schema, ctx, _json, _params) => {
12694
12915
  var enumProcessor = (schema, _ctx, json2, _params) => {
12695
12916
  const def = schema._zod.def;
12696
12917
  const values = getEnumValues(def.entries);
12697
- if (values.every((v2) => typeof v2 === "number"))
12918
+ if (values.every((v4) => typeof v4 === "number"))
12698
12919
  json2.type = "number";
12699
- if (values.every((v2) => typeof v2 === "string"))
12920
+ if (values.every((v4) => typeof v4 === "string"))
12700
12921
  json2.type = "string";
12701
12922
  json2.enum = values;
12702
12923
  };
@@ -12729,13 +12950,13 @@ var literalProcessor = (schema, ctx, json2, _params) => {
12729
12950
  json2.const = val;
12730
12951
  }
12731
12952
  } else {
12732
- if (vals.every((v2) => typeof v2 === "number"))
12953
+ if (vals.every((v4) => typeof v4 === "number"))
12733
12954
  json2.type = "number";
12734
- if (vals.every((v2) => typeof v2 === "string"))
12955
+ if (vals.every((v4) => typeof v4 === "string"))
12735
12956
  json2.type = "string";
12736
- if (vals.every((v2) => typeof v2 === "boolean"))
12957
+ if (vals.every((v4) => typeof v4 === "boolean"))
12737
12958
  json2.type = "boolean";
12738
- if (vals.every((v2) => v2 === null))
12959
+ if (vals.every((v4) => v4 === null))
12739
12960
  json2.type = "null";
12740
12961
  json2.enum = vals;
12741
12962
  }
@@ -12833,11 +13054,11 @@ var objectProcessor = (schema, ctx, _json, params) => {
12833
13054
  }
12834
13055
  const allKeys = new Set(Object.keys(shape));
12835
13056
  const requiredKeys = new Set([...allKeys].filter((key) => {
12836
- const v2 = def.shape[key]._zod;
13057
+ const v4 = def.shape[key]._zod;
12837
13058
  if (ctx.io === "input") {
12838
- return v2.optin === void 0;
13059
+ return v4.optin === void 0;
12839
13060
  } else {
12840
- return v2.optout === void 0;
13061
+ return v4.optout === void 0;
12841
13062
  }
12842
13063
  }));
12843
13064
  if (requiredKeys.size > 0) {
@@ -12957,7 +13178,7 @@ var recordProcessor = (schema, ctx, _json, params) => {
12957
13178
  }
12958
13179
  const keyValues = keyType._zod.values;
12959
13180
  if (keyValues) {
12960
- const validKeyValues = [...keyValues].filter((v2) => typeof v2 === "string" || typeof v2 === "number");
13181
+ const validKeyValues = [...keyValues].filter((v4) => typeof v4 === "string" || typeof v4 === "number");
12961
13182
  if (validKeyValues.length > 0) {
12962
13183
  json2.required = validKeyValues;
12963
13184
  }
@@ -13522,12 +13743,12 @@ function _installLazyMethods(inst, group, methods) {
13522
13743
  });
13523
13744
  return bound;
13524
13745
  },
13525
- set(v2) {
13746
+ set(v4) {
13526
13747
  Object.defineProperty(this, key, {
13527
13748
  configurable: true,
13528
13749
  writable: true,
13529
13750
  enumerable: true,
13530
- value: v2
13751
+ value: v4
13531
13752
  });
13532
13753
  }
13533
13754
  });
@@ -14415,7 +14636,7 @@ var ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => {
14415
14636
  };
14416
14637
  });
14417
14638
  function _enum2(values, params) {
14418
- const entries = Array.isArray(values) ? Object.fromEntries(values.map((v2) => [v2, v2])) : values;
14639
+ const entries = Array.isArray(values) ? Object.fromEntries(values.map((v4) => [v4, v4])) : values;
14419
14640
  return new ZodEnum({
14420
14641
  type: "enum",
14421
14642
  entries,
@@ -14905,13 +15126,13 @@ function resolveRef(ref, ctx) {
14905
15126
  if (!ref.startsWith("#")) {
14906
15127
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
14907
15128
  }
14908
- const path4 = ref.slice(1).split("/").filter(Boolean);
14909
- if (path4.length === 0) {
15129
+ const path7 = ref.slice(1).split("/").filter(Boolean);
15130
+ if (path7.length === 0) {
14910
15131
  return ctx.rootSchema;
14911
15132
  }
14912
15133
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14913
- if (path4[0] === defsKey) {
14914
- const key = path4[1];
15134
+ if (path7[0] === defsKey) {
15135
+ const key = path7[1];
14915
15136
  if (!key || !ctx.defs[key]) {
14916
15137
  throw new Error(`Reference not found: ${ref}`);
14917
15138
  }
@@ -14969,10 +15190,10 @@ function convertBaseSchema(schema, ctx) {
14969
15190
  if (enumValues.length === 1) {
14970
15191
  return z.literal(enumValues[0]);
14971
15192
  }
14972
- if (enumValues.every((v2) => typeof v2 === "string")) {
15193
+ if (enumValues.every((v4) => typeof v4 === "string")) {
14973
15194
  return z.enum(enumValues);
14974
15195
  }
14975
- const literalSchemas = enumValues.map((v2) => z.literal(v2));
15196
+ const literalSchemas = enumValues.map((v4) => z.literal(v4));
14976
15197
  if (literalSchemas.length < 2) {
14977
15198
  return literalSchemas[0];
14978
15199
  }
@@ -15671,8 +15892,8 @@ function baseUrlReference(semantics) {
15671
15892
  const label = OPENING_HOLE.exec(semantics.path ?? "")?.[1];
15672
15893
  return label === void 0 ? null : referenceFromName(patternHole(label));
15673
15894
  }
15674
- function normalizePath(path4) {
15675
- let normalized = path4.replace(/:([a-zA-Z_]\w*)/g, "{$1}");
15895
+ function normalizePath(path7) {
15896
+ let normalized = path7.replace(/:([a-zA-Z_]\w*)/g, "{$1}");
15676
15897
  if (normalized.length > 1 && normalized.endsWith("/")) {
15677
15898
  normalized = normalized.slice(0, -1);
15678
15899
  }
@@ -15682,8 +15903,8 @@ function normalizePath(path4) {
15682
15903
  );
15683
15904
  return normalized;
15684
15905
  }
15685
- function pathShape(path4) {
15686
- return normalizePath(path4).replace(/\{[^}]*\}/g, "{}");
15906
+ function pathShape(path7) {
15907
+ return normalizePath(path7).replace(/\{[^}]*\}/g, "{}");
15687
15908
  }
15688
15909
  function methodsAgree(a, b) {
15689
15910
  if (a === null || b === null) {
@@ -15761,8 +15982,8 @@ var restSemantics = defineBoundarySemantics({
15761
15982
  return null;
15762
15983
  }
15763
15984
  const method = semantics.method === null ? "ANY" : semantics.method.toUpperCase();
15764
- const path4 = semantics.path === null ? "?" : normalizePath(semantics.path);
15765
- return `${method} ${path4}`;
15985
+ const path7 = semantics.path === null ? "?" : normalizePath(semantics.path);
15986
+ return `${method} ${path7}`;
15766
15987
  },
15767
15988
  /**
15768
15989
  * A route with both halves stated decides for itself: the method
@@ -15771,14 +15992,14 @@ var restSemantics = defineBoundarySemantics({
15771
15992
  * half might still be the one that handles the request, and nothing
15772
15993
  * here can settle that, so it abstains instead of refusing.
15773
15994
  */
15774
- servesRequest(semantics, method, path4) {
15995
+ servesRequest(semantics, method, path7) {
15775
15996
  if (semantics.method === null || semantics.path === null) {
15776
15997
  return "unknown";
15777
15998
  }
15778
15999
  if (!methodsAgree(semantics.method, method.toUpperCase())) {
15779
16000
  return "nomatch";
15780
16001
  }
15781
- return routePathAdmits(semantics.path, path4) ? "match" : "nomatch";
16002
+ return routePathAdmits(semantics.path, path7) ? "match" : "nomatch";
15782
16003
  },
15783
16004
  /**
15784
16005
  * A route the registration pattern admits is inside it. A route
@@ -16198,323 +16419,619 @@ function storageBinding(opts) {
16198
16419
  // ../../resolution/dist/index.js
16199
16420
  var import_datalog = require("@suss/datalog");
16200
16421
  var import_datalog2 = require("@suss/datalog");
16201
- var VALUE_STEP = (0, import_datalog2.constant)("value");
16422
+ var import_datalog3 = require("@suss/datalog");
16423
+ function exportTrail(proof, describe3) {
16424
+ if (proof.kind !== "derived") {
16425
+ return [];
16426
+ }
16427
+ const name = (0, import_datalog.ruleLabel)(proof.rule);
16428
+ if (name === "re-export") {
16429
+ const [m, n, m2, n2] = proof.premises[0].tuple;
16430
+ return [
16431
+ `${describe3(m)} takes ${String(n)} from ${describe3(m2)}, where it is called ${String(n2)}`,
16432
+ ...exportTrail(proof.premises[1], describe3)
16433
+ ];
16434
+ }
16435
+ if (name === "re-export all") {
16436
+ const [m, m2] = proof.premises[0].tuple;
16437
+ return [
16438
+ `${describe3(m)} forwards everything ${describe3(m2)} exports`,
16439
+ ...exportTrail(proof.premises[1], describe3)
16440
+ ];
16441
+ }
16442
+ return [];
16443
+ }
16444
+ function argumentReason(proof, describe3) {
16445
+ const [, p, a] = proof.tuple;
16446
+ if (proof.kind !== "derived") {
16447
+ return `${describe3(p)} is a parameter, and a call passes it ${describe3(a)}`;
16448
+ }
16449
+ const f = proof.premises[0].tuple[0];
16450
+ return `${describe3(p)} is a parameter of ${describe3(f)}, and a call passes it ${describe3(a)}`;
16451
+ }
16452
+ var DEFAULT_PHRASES = {
16453
+ alias: ({ tuple: tuple2, describe: describe3 }) => ({
16454
+ reason: `${describe3(tuple2[0])} is declared as ${describe3(tuple2[1])}`
16455
+ }),
16456
+ "last write": ({ tuple: tuple2, describe: describe3 }) => ({
16457
+ reason: `${describe3(tuple2[0])} is written more than once, and the last write leaves it as ${describe3(tuple2[1])}`
16458
+ }),
16459
+ fallback: ({ tuple: tuple2, describe: describe3 }) => ({
16460
+ reason: `${describe3(tuple2[0])} is a fallback expression, and ${describe3(tuple2[1])} is the branch that resolves`
16461
+ }),
16462
+ import: ({ tuple: tuple2, premises, describe: describe3 }) => {
16463
+ const [, module2, name] = premises[0].tuple;
16464
+ return {
16465
+ reason: `${describe3(tuple2[0])} is imported from ${describe3(module2)} under the name ${String(name)}`,
16466
+ notes: exportTrail(premises[1], describe3)
16467
+ };
16468
+ },
16469
+ argument: ({ premises, describe: describe3 }) => ({
16470
+ reason: argumentReason(premises[0], describe3)
16471
+ }),
16472
+ "property read": ({ tuple: tuple2, premises, describe: describe3 }) => {
16473
+ const [, object2, name] = premises[0].tuple;
16474
+ const contains = premises[2];
16475
+ const inherited = contains.kind === "derived" && contains.premises.length > 1;
16476
+ return {
16477
+ reason: `${describe3(tuple2[0])} reads ${String(name)} off ${describe3(object2)}, which contains ${describe3(tuple2[1])}`,
16478
+ notes: inherited ? [`${String(name)} comes from a base class`] : []
16479
+ };
16480
+ },
16481
+ "class instance": ({ tuple: tuple2, premises, describe: describe3, inline }) => ({
16482
+ reason: `${describe3(tuple2[0])} makes an instance of ${describe3(tuple2[1])}`,
16483
+ notes: inline(premises[1])
16484
+ }),
16485
+ "factory unwrap": ({ tuple: tuple2, premises, describe: describe3, inline }) => {
16486
+ const factory = premises[1].tuple[1];
16487
+ return {
16488
+ reason: `${describe3(tuple2[0])} calls ${describe3(factory)}, a factory that passes its argument through, so it comes down to ${describe3(tuple2[1])}`,
16489
+ notes: inline(premises[1])
16490
+ };
16491
+ },
16492
+ "declared wrapper": ({ tuple: tuple2, premises, describe: describe3 }) => {
16493
+ const callee = String(premises[0].tuple[1]);
16494
+ const module2 = String(premises[2].tuple[1]);
16495
+ const argument = String(premises[1].tuple[1]);
16496
+ return {
16497
+ reason: `${describe3(tuple2[0])} calls ${callee} from ${module2}, which passes argument ${argument} through, so it comes down to ${describe3(tuple2[1])}`,
16498
+ assumptions: [
16499
+ `a pack declares that ${callee} from ${module2} passes argument ${argument} through to its result`
16500
+ ]
16501
+ };
16502
+ },
16503
+ "call result": ({ tuple: tuple2, premises, describe: describe3, inline }) => {
16504
+ const invokes = premises[0];
16505
+ const invoked = invokes.tuple[1];
16506
+ const calleeWalks = invokes.kind === "derived" ? invokes.premises.filter(
16507
+ (premise) => premise.kind === "derived" && (premise.relation === "comesTo" || premise.relation === "givesBack")
16508
+ ) : [];
16509
+ return {
16510
+ reason: `${describe3(tuple2[0])} runs ${describe3(invoked)}, which returns ${describe3(tuple2[1])}`,
16511
+ notes: calleeWalks.flatMap((premise) => inline(premise))
16512
+ };
16513
+ }
16514
+ };
16515
+ var CHAIN_RELATIONS = /* @__PURE__ */ new Set([
16516
+ "resolves",
16517
+ "comesTo",
16518
+ "givesBack",
16519
+ "isWrittenAs",
16520
+ "comesFrom",
16521
+ "reaches",
16522
+ "stepsTo"
16523
+ ]);
16524
+ function inlineChain(proof, state) {
16525
+ const explained = explainResolutionProof(proof, {
16526
+ describe: state.describe,
16527
+ phrases: state.phrases
16528
+ });
16529
+ if (explained === null || explained.steps.length === 0) {
16530
+ return [];
16531
+ }
16532
+ if (explained.truncated) {
16533
+ state.truncated = true;
16534
+ }
16535
+ return explained.steps.map((step) => step.reason);
16536
+ }
16537
+ function stepFrom(proof, state) {
16538
+ const name = (0, import_datalog.ruleLabel)(proof.rule);
16539
+ const phrase = state.phrases[name];
16540
+ const from = proof.tuple[0];
16541
+ const to = proof.tuple[1];
16542
+ if (phrase === void 0) {
16543
+ return {
16544
+ from,
16545
+ to,
16546
+ rule: name,
16547
+ reason: `${state.describe(from)} steps to ${state.describe(to)} (${name})`,
16548
+ notes: [],
16549
+ assumptions: []
16550
+ };
16551
+ }
16552
+ const said = phrase({
16553
+ tuple: proof.tuple,
16554
+ premises: proof.premises,
16555
+ describe: state.describe,
16556
+ inline: (nested) => inlineChain(nested, state)
16557
+ });
16558
+ return {
16559
+ from,
16560
+ to,
16561
+ rule: name,
16562
+ reason: said.reason,
16563
+ notes: said.notes ?? [],
16564
+ assumptions: said.assumptions ?? []
16565
+ };
16566
+ }
16567
+ function importStep(proof, state) {
16568
+ const [x, module2, name] = proof.tuple;
16569
+ return {
16570
+ from: x,
16571
+ to: module2,
16572
+ rule: "import",
16573
+ reason: `${state.describe(x)} is imported from ${state.describe(module2)} under the name ${String(name)}`,
16574
+ notes: [],
16575
+ assumptions: []
16576
+ };
16577
+ }
16578
+ var flattenInto = (proof, state) => {
16579
+ if (proof.kind === "truncated") {
16580
+ state.truncated = true;
16581
+ return;
16582
+ }
16583
+ if (proof.kind !== "derived") {
16584
+ return;
16585
+ }
16586
+ const relation = proof.relation;
16587
+ if (relation === "stepsTo") {
16588
+ state.steps.push(stepFrom(proof, state));
16589
+ return;
16590
+ }
16591
+ if (relation === "reaches") {
16592
+ for (const p of proof.premises) {
16593
+ flattenInto(p, state);
16594
+ }
16595
+ return;
16596
+ }
16597
+ if (relation === "comesFrom") {
16598
+ if (proof.premises.length === 2) {
16599
+ flattenInto(proof.premises[0], state);
16600
+ state.steps.push(importStep(proof.premises[1], state));
16601
+ } else {
16602
+ state.steps.push(importStep(proof.premises[0], state));
16603
+ }
16604
+ return;
16605
+ }
16606
+ for (const p of proof.premises) {
16607
+ if (p.kind === "derived" && (p.relation === "reaches" || p.relation === "comesTo")) {
16608
+ flattenInto(p, state);
16609
+ }
16610
+ if (p.kind === "truncated") {
16611
+ state.truncated = true;
16612
+ }
16613
+ }
16614
+ };
16615
+ function explainResolutionProof(proof, options) {
16616
+ if (proof.kind === "absence") {
16617
+ return null;
16618
+ }
16619
+ if (proof.kind === "derived" && !CHAIN_RELATIONS.has(proof.relation)) {
16620
+ return null;
16621
+ }
16622
+ const state = {
16623
+ steps: [],
16624
+ truncated: proof.kind === "truncated",
16625
+ describe: options.describe,
16626
+ phrases: { ...DEFAULT_PHRASES, ...options.phrases }
16627
+ };
16628
+ flattenInto(proof, state);
16629
+ const atoms = proof.kind === "fact" || proof.kind === "truncated" ? [proof.tuple[0]] : [proof.tuple[0], ...state.steps.map((step) => step.to)];
16630
+ return {
16631
+ atoms,
16632
+ steps: state.steps,
16633
+ assumptions: state.steps.flatMap((step) => step.assumptions),
16634
+ truncated: state.truncated
16635
+ };
16636
+ }
16637
+ function renderExplanation(explanation, describe3) {
16638
+ const lines = [];
16639
+ if (explanation.steps.length > 0) {
16640
+ lines.push(explanation.atoms.map((atom) => describe3(atom)).join(" -> "));
16641
+ }
16642
+ for (const step of explanation.steps) {
16643
+ lines.push(` ${step.reason}`);
16644
+ for (const note of step.notes) {
16645
+ lines.push(` ${note}`);
16646
+ }
16647
+ }
16648
+ for (const assumption of explanation.assumptions) {
16649
+ lines.push(` assuming ${assumption}`);
16650
+ }
16651
+ if (explanation.truncated) {
16652
+ lines.push(" the chain goes on past the proof depth cap");
16653
+ }
16654
+ return lines;
16655
+ }
16656
+ function explainResolvedKey(options) {
16657
+ const { db, rules, key, locate, displayPath } = options;
16658
+ const proofDb = new import_datalog2.Database();
16659
+ let baseFacts = 0;
16660
+ for (const relation of db.relationNames()) {
16661
+ for (const tuple2 of db.facts(relation)) {
16662
+ proofDb.add(relation, tuple2);
16663
+ baseFacts++;
16664
+ }
16665
+ }
16666
+ const started = performance.now();
16667
+ (0, import_datalog2.evaluate)(proofDb, rules, import_datalog2.witnesses);
16668
+ const evaluateMs = performance.now() - started;
16669
+ const derivedFacts = proofDb.relationNames().reduce((count, relation) => count + proofDb.size(relation), 0) - baseFacts;
16670
+ const targets = new Set(
16671
+ proofDb.lookup("resolves", 0, key).map((tuple2) => String(tuple2[1]))
16672
+ );
16673
+ if (targets.size !== 1) {
16674
+ return null;
16675
+ }
16676
+ const target = [...targets][0];
16677
+ const proof = (0, import_datalog2.proofOf)(
16678
+ proofDb,
16679
+ "resolves",
16680
+ [key, target],
16681
+ options.maxDepth === void 0 ? {} : { maxDepth: options.maxDepth }
16682
+ );
16683
+ const describe3 = (atom) => {
16684
+ const location = locate(String(atom));
16685
+ return location === null ? displayPath(String(atom)) : `${location.name} (${location.file}:${location.line})`;
16686
+ };
16687
+ const explanation = explainResolutionProof(proof, {
16688
+ describe: describe3,
16689
+ ...options.phrases === void 0 ? {} : { phrases: options.phrases }
16690
+ });
16691
+ if (explanation === null) {
16692
+ return null;
16693
+ }
16694
+ const targetLocation = locate(target);
16695
+ if (targetLocation === null) {
16696
+ return null;
16697
+ }
16698
+ return {
16699
+ explanation,
16700
+ chain: explanation.atoms.map(describe3),
16701
+ lines: renderExplanation(explanation, describe3),
16702
+ target: targetLocation,
16703
+ stats: { baseFacts, derivedFacts, evaluateMs }
16704
+ };
16705
+ }
16706
+ var VALUE_STEP = (0, import_datalog3.constant)("value");
16202
16707
  var NAMESPACE_IMPORT_NAME = "*";
16203
- var NAMESPACE_IMPORT = (0, import_datalog2.constant)(NAMESPACE_IMPORT_NAME);
16204
- var RESULT_STEP = (0, import_datalog2.constant)("result");
16708
+ var NAMESPACE_IMPORT = (0, import_datalog3.constant)(NAMESPACE_IMPORT_NAME);
16709
+ var RESULT_STEP = (0, import_datalog3.constant)("result");
16205
16710
  var RESOLUTION_RULES = [
16206
16711
  // Aliasing: const x = y, or an identifier referencing a declaration.
16207
16712
  // A language with a hop of its own, like JavaScript's `.bind`, states
16208
16713
  // it as a step too, or every question but `comesTo` misses it.
16209
- (0, import_datalog2.rule)(
16714
+ (0, import_datalog3.rule)(
16210
16715
  "stepsTo",
16211
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), VALUE_STEP],
16212
- [(0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"))],
16716
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"), VALUE_STEP],
16717
+ [(0, import_datalog3.lit)("binds", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"))],
16213
16718
  "alias"
16214
16719
  ),
16215
16720
  // A name written more than once has the value the last write left
16216
16721
  // there. The adapter works out which write that is and stays quiet
16217
16722
  // when control flow decides, so such a name steps nowhere at all.
16218
- (0, import_datalog2.rule)(
16723
+ (0, import_datalog3.rule)(
16219
16724
  "stepsTo",
16220
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), VALUE_STEP],
16221
- [(0, import_datalog2.lit)("endsHolding", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"))],
16725
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"), VALUE_STEP],
16726
+ [(0, import_datalog3.lit)("endsHolding", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"))],
16222
16727
  "last write"
16223
16728
  ),
16224
16729
  // A fallback says the value is one of its branches, so each branch is
16225
16730
  // a step. A branch that resolves to nothing makes no claim, and two
16226
16731
  // branches resolving to different things fail the single-answer policy.
16227
- (0, import_datalog2.rule)(
16732
+ (0, import_datalog3.rule)(
16228
16733
  "stepsTo",
16229
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("b"), VALUE_STEP],
16230
- [(0, import_datalog2.lit)("fallbackBranch", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("b"))],
16734
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("b"), VALUE_STEP],
16735
+ [(0, import_datalog3.lit)("fallbackBranch", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("b"))],
16231
16736
  "fallback"
16232
16737
  ),
16233
16738
  // An import steps to what the module exports under that name.
16234
- (0, import_datalog2.rule)(
16739
+ (0, import_datalog3.rule)(
16235
16740
  "stepsTo",
16236
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("value"), VALUE_STEP],
16741
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("value"), VALUE_STEP],
16237
16742
  [
16238
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")),
16239
- (0, import_datalog2.lit)("moduleExport", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("value"))
16743
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")),
16744
+ (0, import_datalog3.lit)("moduleExport", (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("value"))
16240
16745
  ],
16241
16746
  "import"
16242
16747
  ),
16243
16748
  // A parameter steps to what a call passes it. A function called from
16244
16749
  // several places leaves its parameter with more than one value, and a
16245
16750
  // caller that needs those apart asks `paramAt`.
16246
- (0, import_datalog2.rule)(
16751
+ (0, import_datalog3.rule)(
16247
16752
  "stepsTo",
16248
- [(0, import_datalog2.variable)("p"), (0, import_datalog2.variable)("a"), VALUE_STEP],
16249
- [(0, import_datalog2.lit)("passesArgument", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("p"), (0, import_datalog2.variable)("a"))],
16753
+ [(0, import_datalog3.variable)("p"), (0, import_datalog3.variable)("a"), VALUE_STEP],
16754
+ [(0, import_datalog3.lit)("passesArgument", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("p"), (0, import_datalog3.variable)("a"))],
16250
16755
  "argument"
16251
16756
  ),
16252
16757
  // Reading a property steps to what the object contains under that
16253
16758
  // name, whichever way the object arrived: `routes.list` off a name,
16254
16759
  // or `make(body).handle` off a call.
16255
- (0, import_datalog2.rule)(
16760
+ (0, import_datalog3.rule)(
16256
16761
  "stepsTo",
16257
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("held"), VALUE_STEP],
16762
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("held"), VALUE_STEP],
16258
16763
  [
16259
- (0, import_datalog2.lit)("readsProperty", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("n")),
16260
- (0, import_datalog2.lit)("objectOf", (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("obj")),
16261
- (0, import_datalog2.lit)("contains", (0, import_datalog2.variable)("obj"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("held"))
16764
+ (0, import_datalog3.lit)("readsProperty", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("n")),
16765
+ (0, import_datalog3.lit)("objectOf", (0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("obj")),
16766
+ (0, import_datalog3.lit)("contains", (0, import_datalog3.variable)("obj"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("held"))
16262
16767
  ],
16263
16768
  "property read"
16264
16769
  ),
16265
16770
  // Calling a class makes one of it, so the call steps to the class and
16266
16771
  // a method read off the result is the one the class declares. The
16267
16772
  // caveat below is about a factory function, and a class is not one.
16268
- (0, import_datalog2.rule)(
16773
+ (0, import_datalog3.rule)(
16269
16774
  "stepsTo",
16270
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("cls"), VALUE_STEP],
16775
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("cls"), VALUE_STEP],
16271
16776
  [
16272
- (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c")),
16273
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("cls")),
16274
- (0, import_datalog2.lit)("objectValue", (0, import_datalog2.variable)("cls"))
16777
+ (0, import_datalog3.lit)("call", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("c")),
16778
+ (0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("cls")),
16779
+ (0, import_datalog3.lit)("objectValue", (0, import_datalog3.variable)("cls"))
16275
16780
  ],
16276
16781
  "class instance"
16277
16782
  ),
16278
16783
  // Wrapper transparency, derived: calling a factory that returns a
16279
16784
  // function which calls its parameter k steps to argument k.
16280
- (0, import_datalog2.rule)(
16785
+ (0, import_datalog3.rule)(
16281
16786
  "stepsTo",
16282
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("a"), VALUE_STEP],
16787
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("a"), VALUE_STEP],
16283
16788
  [
16284
- (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c")),
16285
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("f")),
16286
- (0, import_datalog2.lit)("unwraps", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("k")),
16287
- (0, import_datalog2.lit)("callArg", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("k"), (0, import_datalog2.variable)("a"))
16789
+ (0, import_datalog3.lit)("call", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("c")),
16790
+ (0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("f")),
16791
+ (0, import_datalog3.lit)("unwraps", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("k")),
16792
+ (0, import_datalog3.lit)("callArg", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("k"), (0, import_datalog3.variable)("a"))
16288
16793
  ],
16289
16794
  "factory unwrap"
16290
16795
  ),
16291
16796
  // Wrapper transparency, declared: a pack says this callee wraps
16292
16797
  // argument k. The callee has to come from the library the pack said,
16293
16798
  // so a local object spelled the same way is not mistaken for it.
16294
- (0, import_datalog2.rule)(
16799
+ (0, import_datalog3.rule)(
16295
16800
  "stepsTo",
16296
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("a"), VALUE_STEP],
16801
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("a"), VALUE_STEP],
16297
16802
  [
16298
- (0, import_datalog2.lit)("calleeName", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("n")),
16299
- (0, import_datalog2.lit)("unwrapsByName", (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("k")),
16300
- (0, import_datalog2.lit)("wrapperModule", (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("m")),
16301
- (0, import_datalog2.lit)("calleeOrigin", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("m")),
16302
- (0, import_datalog2.lit)("callArg", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("k"), (0, import_datalog2.variable)("a"))
16803
+ (0, import_datalog3.lit)("calleeName", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("n")),
16804
+ (0, import_datalog3.lit)("unwrapsByName", (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("k")),
16805
+ (0, import_datalog3.lit)("wrapperModule", (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("m")),
16806
+ (0, import_datalog3.lit)("calleeOrigin", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("m")),
16807
+ (0, import_datalog3.lit)("callArg", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("k"), (0, import_datalog3.variable)("a"))
16303
16808
  ],
16304
16809
  "declared wrapper"
16305
16810
  ),
16306
16811
  // The one step that runs a function forwards: a call steps to what
16307
16812
  // the function it invokes returns.
16308
- (0, import_datalog2.rule)(
16813
+ (0, import_datalog3.rule)(
16309
16814
  "stepsTo",
16310
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("ret"), RESULT_STEP],
16311
- [(0, import_datalog2.lit)("invokes", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")), (0, import_datalog2.lit)("returnsValue", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("ret"))],
16815
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("ret"), RESULT_STEP],
16816
+ [(0, import_datalog3.lit)("invokes", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("f")), (0, import_datalog3.lit)("returnsValue", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("ret"))],
16312
16817
  "call result"
16313
16818
  ),
16314
16819
  // Where a walk gets to, and whether it ran a call on the way. The walk
16315
16820
  // so far comes first, so demand stays on the value asked about; the
16316
16821
  // README says what the other order cost.
16317
- (0, import_datalog2.rule)(
16822
+ (0, import_datalog3.rule)(
16318
16823
  "reaches",
16319
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), (0, import_datalog2.variable)("kind")],
16320
- [(0, import_datalog2.lit)("stepsTo", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), (0, import_datalog2.variable)("kind"))]
16824
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), (0, import_datalog3.variable)("kind")],
16825
+ [(0, import_datalog3.lit)("stepsTo", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), (0, import_datalog3.variable)("kind"))]
16321
16826
  ),
16322
- (0, import_datalog2.rule)(
16827
+ (0, import_datalog3.rule)(
16323
16828
  "reaches",
16324
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), (0, import_datalog2.variable)("kind")],
16829
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), (0, import_datalog3.variable)("kind")],
16325
16830
  [
16326
- (0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), VALUE_STEP),
16327
- (0, import_datalog2.lit)("stepsTo", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"), (0, import_datalog2.variable)("kind"))
16831
+ (0, import_datalog3.lit)("reaches", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"), VALUE_STEP),
16832
+ (0, import_datalog3.lit)("stepsTo", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("z"), (0, import_datalog3.variable)("kind"))
16328
16833
  ]
16329
16834
  ),
16330
16835
  // Two rules rather than one leaving the next step's kind free. A free
16331
16836
  // kind is a second question about the same relation, and a
16332
16837
  // demand-driven run then derives both to answer either.
16333
- (0, import_datalog2.rule)(
16838
+ (0, import_datalog3.rule)(
16334
16839
  "reaches",
16335
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), RESULT_STEP],
16840
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), RESULT_STEP],
16336
16841
  [
16337
- (0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), RESULT_STEP),
16338
- (0, import_datalog2.lit)("stepsTo", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"), VALUE_STEP)
16842
+ (0, import_datalog3.lit)("reaches", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"), RESULT_STEP),
16843
+ (0, import_datalog3.lit)("stepsTo", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("z"), VALUE_STEP)
16339
16844
  ]
16340
16845
  ),
16341
- (0, import_datalog2.rule)(
16846
+ (0, import_datalog3.rule)(
16342
16847
  "reaches",
16343
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), RESULT_STEP],
16848
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), RESULT_STEP],
16344
16849
  [
16345
- (0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), RESULT_STEP),
16346
- (0, import_datalog2.lit)("stepsTo", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"), RESULT_STEP)
16850
+ (0, import_datalog3.lit)("reaches", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"), RESULT_STEP),
16851
+ (0, import_datalog3.lit)("stepsTo", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("z"), RESULT_STEP)
16347
16852
  ]
16348
16853
  ),
16349
16854
  // What a value comes down to: the walk that never ran a call, stopped
16350
16855
  // at a function or an object. Something already written out comes to
16351
16856
  // itself, and every other walk ends at one of those.
16352
- (0, import_datalog2.rule)("comesTo", [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("x")], [(0, import_datalog2.lit)("func", (0, import_datalog2.variable)("x"))]),
16353
- (0, import_datalog2.rule)("comesTo", [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("x")], [(0, import_datalog2.lit)("objectValue", (0, import_datalog2.variable)("x"))]),
16354
- (0, import_datalog2.rule)(
16857
+ (0, import_datalog3.rule)("comesTo", [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("x")], [(0, import_datalog3.lit)("func", (0, import_datalog3.variable)("x"))]),
16858
+ (0, import_datalog3.rule)("comesTo", [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("x")], [(0, import_datalog3.lit)("objectValue", (0, import_datalog3.variable)("x"))]),
16859
+ (0, import_datalog3.rule)(
16355
16860
  "comesTo",
16356
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16357
- [(0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), VALUE_STEP), (0, import_datalog2.lit)("func", (0, import_datalog2.variable)("z"))]
16861
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
16862
+ [(0, import_datalog3.lit)("reaches", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), VALUE_STEP), (0, import_datalog3.lit)("func", (0, import_datalog3.variable)("z"))]
16358
16863
  ),
16359
- (0, import_datalog2.rule)(
16864
+ (0, import_datalog3.rule)(
16360
16865
  "comesTo",
16361
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16362
- [(0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), VALUE_STEP), (0, import_datalog2.lit)("objectValue", (0, import_datalog2.variable)("z"))]
16866
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
16867
+ [(0, import_datalog3.lit)("reaches", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), VALUE_STEP), (0, import_datalog3.lit)("objectValue", (0, import_datalog3.variable)("z"))]
16363
16868
  ),
16364
16869
  // The same stopping condition, for the walk that ran a call. A call
16365
16870
  // gets no `comesTo` answer on purpose: coming back with what a
16366
16871
  // factory returned would fight the unwrapping answer.
16367
- (0, import_datalog2.rule)(
16872
+ (0, import_datalog3.rule)(
16368
16873
  "givesBack",
16369
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16370
- [(0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), RESULT_STEP), (0, import_datalog2.lit)("func", (0, import_datalog2.variable)("z"))]
16874
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
16875
+ [(0, import_datalog3.lit)("reaches", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), RESULT_STEP), (0, import_datalog3.lit)("func", (0, import_datalog3.variable)("z"))]
16371
16876
  ),
16372
- (0, import_datalog2.rule)(
16877
+ (0, import_datalog3.rule)(
16373
16878
  "givesBack",
16374
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16375
- [(0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), RESULT_STEP), (0, import_datalog2.lit)("objectValue", (0, import_datalog2.variable)("z"))]
16879
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
16880
+ [(0, import_datalog3.lit)("reaches", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), RESULT_STEP), (0, import_datalog3.lit)("objectValue", (0, import_datalog3.variable)("z"))]
16376
16881
  ),
16377
16882
  // Following a value to the expression it is written as, whatever kind
16378
16883
  // that is. A GraphQL document is neither a function nor an object, so
16379
16884
  // `comesTo` never reaches one.
16380
- (0, import_datalog2.rule)("isWrittenAs", [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("x")], [(0, import_datalog2.lit)("writtenValue", (0, import_datalog2.variable)("x"))]),
16381
- (0, import_datalog2.rule)("isWrittenAs", [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("x")], [(0, import_datalog2.lit)("objectValue", (0, import_datalog2.variable)("x"))]),
16382
- (0, import_datalog2.rule)(
16885
+ (0, import_datalog3.rule)("isWrittenAs", [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("x")], [(0, import_datalog3.lit)("writtenValue", (0, import_datalog3.variable)("x"))]),
16886
+ (0, import_datalog3.rule)("isWrittenAs", [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("x")], [(0, import_datalog3.lit)("objectValue", (0, import_datalog3.variable)("x"))]),
16887
+ (0, import_datalog3.rule)(
16888
+ "isWrittenAs",
16889
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
16890
+ [(0, import_datalog3.lit)("reaches", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), VALUE_STEP), (0, import_datalog3.lit)("writtenValue", (0, import_datalog3.variable)("z"))]
16891
+ ),
16892
+ (0, import_datalog3.rule)(
16383
16893
  "isWrittenAs",
16384
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16385
- [(0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), VALUE_STEP), (0, import_datalog2.lit)("writtenValue", (0, import_datalog2.variable)("z"))]
16894
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
16895
+ [(0, import_datalog3.lit)("reaches", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), VALUE_STEP), (0, import_datalog3.lit)("objectValue", (0, import_datalog3.variable)("z"))]
16386
16896
  ),
16387
- (0, import_datalog2.rule)(
16897
+ // A call is written as whatever its callee's return value is written
16898
+ // as. Unlike `comesTo`, this has nothing to protect: which expression
16899
+ // a value was written as does not compete with unwrapping it.
16900
+ (0, import_datalog3.rule)(
16388
16901
  "isWrittenAs",
16389
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16390
- [(0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), VALUE_STEP), (0, import_datalog2.lit)("objectValue", (0, import_datalog2.variable)("z"))]
16902
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
16903
+ [
16904
+ (0, import_datalog3.lit)("invokes", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("f")),
16905
+ (0, import_datalog3.lit)("returnsValue", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("ret")),
16906
+ (0, import_datalog3.lit)("isWrittenAs", (0, import_datalog3.variable)("ret"), (0, import_datalog3.variable)("z"))
16907
+ ]
16391
16908
  ),
16392
16909
  // What one call site put in a parameter, told apart from what the
16393
16910
  // other callers passed.
16394
- (0, import_datalog2.rule)(
16911
+ (0, import_datalog3.rule)(
16395
16912
  "paramAt",
16396
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("p"), (0, import_datalog2.variable)("z")],
16913
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("p"), (0, import_datalog3.variable)("z")],
16397
16914
  [
16398
- (0, import_datalog2.lit)("passesArgument", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("p"), (0, import_datalog2.variable)("a")),
16399
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("a"), (0, import_datalog2.variable)("z"))
16915
+ (0, import_datalog3.lit)("passesArgument", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("p"), (0, import_datalog3.variable)("a")),
16916
+ (0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("a"), (0, import_datalog3.variable)("z"))
16400
16917
  ]
16401
16918
  ),
16402
16919
  // An argument arriving at the parameter it is passed to, by position
16403
16920
  // or by the name the caller wrote, keeping the call it went through
16404
16921
  // so `paramAt` can tell two call sites apart.
16405
- (0, import_datalog2.rule)(
16922
+ (0, import_datalog3.rule)(
16406
16923
  "passesArgument",
16407
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("p"), (0, import_datalog2.variable)("a")],
16924
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("p"), (0, import_datalog3.variable)("a")],
16408
16925
  [
16409
- (0, import_datalog2.lit)("paramOf", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("k"), (0, import_datalog2.variable)("p")),
16410
- (0, import_datalog2.lit)("callsFunction", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")),
16411
- (0, import_datalog2.lit)("callArg", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("k"), (0, import_datalog2.variable)("a"))
16926
+ (0, import_datalog3.lit)("paramOf", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("k"), (0, import_datalog3.variable)("p")),
16927
+ (0, import_datalog3.lit)("callsFunction", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("f")),
16928
+ (0, import_datalog3.lit)("callArg", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("k"), (0, import_datalog3.variable)("a"))
16412
16929
  ]
16413
16930
  ),
16414
- (0, import_datalog2.rule)(
16931
+ (0, import_datalog3.rule)(
16415
16932
  "passesArgument",
16416
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("p"), (0, import_datalog2.variable)("a")],
16933
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("p"), (0, import_datalog3.variable)("a")],
16417
16934
  [
16418
- (0, import_datalog2.lit)("paramNamed", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("p")),
16419
- (0, import_datalog2.lit)("callsFunction", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")),
16420
- (0, import_datalog2.lit)("callKeywordArg", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("a"))
16935
+ (0, import_datalog3.lit)("paramNamed", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("p")),
16936
+ (0, import_datalog3.lit)("callsFunction", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("f")),
16937
+ (0, import_datalog3.lit)("callKeywordArg", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("a"))
16421
16938
  ]
16422
16939
  ),
16423
16940
  // Which module's export a re-exported name forwards to, however
16424
16941
  // many barrels deep the forwarding runs.
16425
- (0, import_datalog2.rule)(
16942
+ (0, import_datalog3.rule)(
16426
16943
  "moduleForwards",
16427
- [(0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("m2"), (0, import_datalog2.variable)("n2")],
16428
- [(0, import_datalog2.lit)("reExports", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("m2"), (0, import_datalog2.variable)("n2"))]
16944
+ [(0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("m2"), (0, import_datalog3.variable)("n2")],
16945
+ [(0, import_datalog3.lit)("reExports", (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("m2"), (0, import_datalog3.variable)("n2"))]
16429
16946
  ),
16430
- (0, import_datalog2.rule)(
16947
+ (0, import_datalog3.rule)(
16431
16948
  "moduleForwards",
16432
- [(0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("m3"), (0, import_datalog2.variable)("n3")],
16949
+ [(0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("m3"), (0, import_datalog3.variable)("n3")],
16433
16950
  [
16434
- (0, import_datalog2.lit)("reExports", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("m2"), (0, import_datalog2.variable)("n2")),
16435
- (0, import_datalog2.lit)("moduleForwards", (0, import_datalog2.variable)("m2"), (0, import_datalog2.variable)("n2"), (0, import_datalog2.variable)("m3"), (0, import_datalog2.variable)("n3"))
16951
+ (0, import_datalog3.lit)("reExports", (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("m2"), (0, import_datalog3.variable)("n2")),
16952
+ (0, import_datalog3.lit)("moduleForwards", (0, import_datalog3.variable)("m2"), (0, import_datalog3.variable)("n2"), (0, import_datalog3.variable)("m3"), (0, import_datalog3.variable)("n3"))
16436
16953
  ]
16437
16954
  ),
16438
16955
  // What a module exports: directly, or through re-export chains.
16439
- (0, import_datalog2.rule)(
16956
+ (0, import_datalog3.rule)(
16440
16957
  "moduleExport",
16441
- [(0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("value")],
16442
- [(0, import_datalog2.lit)("exportsAs", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("value"))],
16958
+ [(0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("value")],
16959
+ [(0, import_datalog3.lit)("exportsAs", (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("value"))],
16443
16960
  "export"
16444
16961
  ),
16445
- (0, import_datalog2.rule)(
16962
+ (0, import_datalog3.rule)(
16446
16963
  "moduleExport",
16447
- [(0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("value")],
16964
+ [(0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("value")],
16448
16965
  [
16449
- (0, import_datalog2.lit)("reExports", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("m2"), (0, import_datalog2.variable)("n2")),
16450
- (0, import_datalog2.lit)("moduleExport", (0, import_datalog2.variable)("m2"), (0, import_datalog2.variable)("n2"), (0, import_datalog2.variable)("value"))
16966
+ (0, import_datalog3.lit)("reExports", (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("m2"), (0, import_datalog3.variable)("n2")),
16967
+ (0, import_datalog3.lit)("moduleExport", (0, import_datalog3.variable)("m2"), (0, import_datalog3.variable)("n2"), (0, import_datalog3.variable)("value"))
16451
16968
  ],
16452
16969
  "re-export"
16453
16970
  ),
16454
- (0, import_datalog2.rule)(
16971
+ (0, import_datalog3.rule)(
16455
16972
  "moduleExport",
16456
- [(0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("value")],
16973
+ [(0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("value")],
16457
16974
  [
16458
- (0, import_datalog2.lit)("reExportsAll", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("m2")),
16459
- (0, import_datalog2.lit)("moduleExport", (0, import_datalog2.variable)("m2"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("value"))
16975
+ (0, import_datalog3.lit)("reExportsAll", (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("m2")),
16976
+ (0, import_datalog3.lit)("moduleExport", (0, import_datalog3.variable)("m2"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("value"))
16460
16977
  ],
16461
16978
  "re-export all"
16462
16979
  ),
16463
16980
  // The function a call runs, written from the call's side because a
16464
16981
  // caller asking what a call gives back has the call in hand.
16465
- (0, import_datalog2.rule)(
16982
+ (0, import_datalog3.rule)(
16466
16983
  "invokes",
16467
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")],
16468
- [(0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c")), (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("f"))]
16984
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("f")],
16985
+ [(0, import_datalog3.lit)("call", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("c")), (0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("f"))]
16469
16986
  ),
16470
16987
  // The callee is itself a call: `daoBuilder()()`.
16471
- (0, import_datalog2.rule)(
16988
+ (0, import_datalog3.rule)(
16472
16989
  "invokes",
16473
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")],
16474
- [(0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c")), (0, import_datalog2.lit)("givesBack", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("f"))]
16990
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("f")],
16991
+ [(0, import_datalog3.lit)("call", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("c")), (0, import_datalog3.lit)("givesBack", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("f"))]
16475
16992
  ),
16476
16993
  // The object an expression refers to: a name through `comesTo`, a
16477
16994
  // factory call through what it gives back. Naming the step is what
16478
16995
  // makes `routes.list` and `make(body).handle` one rule.
16479
- (0, import_datalog2.rule)(
16996
+ (0, import_datalog3.rule)(
16480
16997
  "objectOf",
16481
- [(0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("obj")],
16482
- [(0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("obj")), (0, import_datalog2.lit)("objectValue", (0, import_datalog2.variable)("obj"))]
16998
+ [(0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("obj")],
16999
+ [(0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("obj")), (0, import_datalog3.lit)("objectValue", (0, import_datalog3.variable)("obj"))]
16483
17000
  ),
16484
- (0, import_datalog2.rule)(
17001
+ (0, import_datalog3.rule)(
16485
17002
  "objectOf",
16486
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("obj")],
16487
- [(0, import_datalog2.lit)("givesBack", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("obj")), (0, import_datalog2.lit)("objectValue", (0, import_datalog2.variable)("obj"))]
17003
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("obj")],
17004
+ [(0, import_datalog3.lit)("givesBack", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("obj")), (0, import_datalog3.lit)("objectValue", (0, import_datalog3.variable)("obj"))]
16488
17005
  ),
16489
17006
  // Which calls a function, found by the name the call is written as
16490
17007
  // rather than by resolving every callee in the project. A caller knows
16491
17008
  // the function and wants its call sites, so both of these start from
16492
17009
  // the function. Starting from `call` instead asks what every call in
16493
17010
  // the project imports, which was 72% of everything derived.
16494
- (0, import_datalog2.rule)(
17011
+ (0, import_datalog3.rule)(
16495
17012
  "callsFunction",
16496
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")],
16497
- [(0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("f")), (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c"))]
17013
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("f")],
17014
+ [(0, import_datalog3.lit)("binds", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("f")), (0, import_datalog3.lit)("call", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("c"))]
16498
17015
  ),
16499
- (0, import_datalog2.rule)(
17016
+ (0, import_datalog3.rule)(
16500
17017
  "callsFunction",
16501
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")],
17018
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("f")],
16502
17019
  [
16503
- (0, import_datalog2.lit)("moduleExport", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("f")),
16504
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")),
16505
- (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c"))
17020
+ (0, import_datalog3.lit)("moduleExport", (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("f")),
17021
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")),
17022
+ (0, import_datalog3.lit)("call", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("c"))
16506
17023
  ]
16507
17024
  ),
16508
17025
  // The same, for a language whose adapter writes the import down as a
16509
17026
  // declaration and the call's callee as the name referring to it.
16510
- (0, import_datalog2.rule)(
17027
+ (0, import_datalog3.rule)(
16511
17028
  "callsFunction",
16512
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")],
17029
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("f")],
16513
17030
  [
16514
- (0, import_datalog2.lit)("moduleExport", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("f")),
16515
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("d"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")),
16516
- (0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("d")),
16517
- (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c"))
17031
+ (0, import_datalog3.lit)("moduleExport", (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("f")),
17032
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("d"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")),
17033
+ (0, import_datalog3.lit)("binds", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("d")),
17034
+ (0, import_datalog3.lit)("call", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("c"))
16518
17035
  ]
16519
17036
  ),
16520
17037
  // What an object contains, its base class included, so a method the base
@@ -16522,47 +17039,47 @@ var RESOLUTION_RULES = [
16522
17039
  // declare gives two, and the caller decides. This is its own relation
16523
17040
  // rather than more `holdsProperty`, which stays something an adapter
16524
17041
  // states and the rules only read.
16525
- (0, import_datalog2.rule)(
17042
+ (0, import_datalog3.rule)(
16526
17043
  "contains",
16527
- [(0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("held")],
16528
- [(0, import_datalog2.lit)("holdsProperty", (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("held"))]
17044
+ [(0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("held")],
17045
+ [(0, import_datalog3.lit)("holdsProperty", (0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("held"))]
16529
17046
  ),
16530
- (0, import_datalog2.rule)(
17047
+ (0, import_datalog3.rule)(
16531
17048
  "contains",
16532
- [(0, import_datalog2.variable)("cls"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("held")],
17049
+ [(0, import_datalog3.variable)("cls"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("held")],
16533
17050
  [
16534
- (0, import_datalog2.lit)("extends", (0, import_datalog2.variable)("cls"), (0, import_datalog2.variable)("base")),
16535
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("base"), (0, import_datalog2.variable)("baseCls")),
16536
- (0, import_datalog2.lit)("contains", (0, import_datalog2.variable)("baseCls"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("held"))
17051
+ (0, import_datalog3.lit)("extends", (0, import_datalog3.variable)("cls"), (0, import_datalog3.variable)("base")),
17052
+ (0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("base"), (0, import_datalog3.variable)("baseCls")),
17053
+ (0, import_datalog3.lit)("contains", (0, import_datalog3.variable)("baseCls"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("held"))
16537
17054
  ]
16538
17055
  ),
16539
17056
  // Which function a factory returns, and which of its parameters that
16540
17057
  // function calls: together they are what makes it a wrapper.
16541
- (0, import_datalog2.rule)(
17058
+ (0, import_datalog3.rule)(
16542
17059
  "returnsFunc",
16543
- [(0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("g")],
17060
+ [(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("g")],
16544
17061
  [
16545
- (0, import_datalog2.lit)("returnsValue", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("value")),
16546
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("value"), (0, import_datalog2.variable)("g")),
16547
- (0, import_datalog2.lit)("func", (0, import_datalog2.variable)("g"))
17062
+ (0, import_datalog3.lit)("returnsValue", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("value")),
17063
+ (0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("value"), (0, import_datalog3.variable)("g")),
17064
+ (0, import_datalog3.lit)("func", (0, import_datalog3.variable)("g"))
16548
17065
  ]
16549
17066
  ),
16550
17067
  // A call made by a nested closure counts as made by the function
16551
17068
  // that declares it; the closure runs as part of that function.
16552
- (0, import_datalog2.rule)("bodyCallsDeep", [(0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("c")], [(0, import_datalog2.lit)("bodyCalls", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("c"))]),
16553
- (0, import_datalog2.rule)(
17069
+ (0, import_datalog3.rule)("bodyCallsDeep", [(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("c")], [(0, import_datalog3.lit)("bodyCalls", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("c"))]),
17070
+ (0, import_datalog3.rule)(
16554
17071
  "bodyCallsDeep",
16555
- [(0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("c")],
16556
- [(0, import_datalog2.lit)("containsFn", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("g")), (0, import_datalog2.lit)("bodyCallsDeep", (0, import_datalog2.variable)("g"), (0, import_datalog2.variable)("c"))]
17072
+ [(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("c")],
17073
+ [(0, import_datalog3.lit)("containsFn", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("g")), (0, import_datalog3.lit)("bodyCallsDeep", (0, import_datalog3.variable)("g"), (0, import_datalog3.variable)("c"))]
16557
17074
  ),
16558
- (0, import_datalog2.rule)(
17075
+ (0, import_datalog3.rule)(
16559
17076
  "unwraps",
16560
- [(0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("k")],
17077
+ [(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("k")],
16561
17078
  [
16562
- (0, import_datalog2.lit)("returnsFunc", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("g")),
16563
- (0, import_datalog2.lit)("bodyCallsDeep", (0, import_datalog2.variable)("g"), (0, import_datalog2.variable)("c")),
16564
- (0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("p")),
16565
- (0, import_datalog2.lit)("paramOf", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("k"), (0, import_datalog2.variable)("p"))
17079
+ (0, import_datalog3.lit)("returnsFunc", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("g")),
17080
+ (0, import_datalog3.lit)("bodyCallsDeep", (0, import_datalog3.variable)("g"), (0, import_datalog3.variable)("c")),
17081
+ (0, import_datalog3.lit)("binds", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("p")),
17082
+ (0, import_datalog3.lit)("paramOf", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("k"), (0, import_datalog3.variable)("p"))
16566
17083
  ]
16567
17084
  ),
16568
17085
  // Argument flow: which parameter a value traces back to. Directly
@@ -16570,289 +17087,289 @@ var RESOLUTION_RULES = [
16570
17087
  // another unwrapping factory. This is what lets
16571
17088
  // `createProtected(h) { return service.withAuth(h); }` unwrap:
16572
17089
  // the returned call passes h through withAuth, which unwraps.
16573
- (0, import_datalog2.rule)(
17090
+ (0, import_datalog3.rule)(
16574
17091
  "flowsToParam",
16575
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("p")],
17092
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("p")],
16576
17093
  [
16577
- (0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("p")),
16578
- (0, import_datalog2.lit)("paramOf", (0, import_datalog2.variable)("anyF"), (0, import_datalog2.variable)("anyK"), (0, import_datalog2.variable)("p"))
17094
+ (0, import_datalog3.lit)("binds", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("p")),
17095
+ (0, import_datalog3.lit)("paramOf", (0, import_datalog3.variable)("anyF"), (0, import_datalog3.variable)("anyK"), (0, import_datalog3.variable)("p"))
16579
17096
  ]
16580
17097
  ),
16581
- (0, import_datalog2.rule)(
17098
+ (0, import_datalog3.rule)(
16582
17099
  "flowsToParam",
16583
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("p")],
17100
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("p")],
16584
17101
  [
16585
- (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c")),
16586
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("f")),
16587
- (0, import_datalog2.lit)("unwraps", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("k")),
16588
- (0, import_datalog2.lit)("callArg", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("k"), (0, import_datalog2.variable)("a")),
16589
- (0, import_datalog2.lit)("flowsToParam", (0, import_datalog2.variable)("a"), (0, import_datalog2.variable)("p"))
17102
+ (0, import_datalog3.lit)("call", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("c")),
17103
+ (0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("f")),
17104
+ (0, import_datalog3.lit)("unwraps", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("k")),
17105
+ (0, import_datalog3.lit)("callArg", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("k"), (0, import_datalog3.variable)("a")),
17106
+ (0, import_datalog3.lit)("flowsToParam", (0, import_datalog3.variable)("a"), (0, import_datalog3.variable)("p"))
16590
17107
  ]
16591
17108
  ),
16592
- (0, import_datalog2.rule)(
17109
+ (0, import_datalog3.rule)(
16593
17110
  "unwraps",
16594
- [(0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("k")],
17111
+ [(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("k")],
16595
17112
  [
16596
- (0, import_datalog2.lit)("returnsValue", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("value")),
16597
- (0, import_datalog2.lit)("flowsToParam", (0, import_datalog2.variable)("value"), (0, import_datalog2.variable)("p")),
16598
- (0, import_datalog2.lit)("paramOf", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("k"), (0, import_datalog2.variable)("p"))
17113
+ (0, import_datalog3.lit)("returnsValue", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("value")),
17114
+ (0, import_datalog3.lit)("flowsToParam", (0, import_datalog3.variable)("value"), (0, import_datalog3.variable)("p")),
17115
+ (0, import_datalog3.lit)("paramOf", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("k"), (0, import_datalog3.variable)("p"))
16599
17116
  ]
16600
17117
  ),
16601
17118
  // Where a name comes from, when what it refers to lives outside the
16602
17119
  // source being read. A walk ends at something written out in source,
16603
17120
  // so it never reaches a library's own function.
16604
- (0, import_datalog2.rule)(
17121
+ (0, import_datalog3.rule)(
16605
17122
  "comesFrom",
16606
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
16607
- [(0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))]
17123
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
17124
+ [(0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"))]
16608
17125
  ),
16609
- (0, import_datalog2.rule)(
17126
+ (0, import_datalog3.rule)(
16610
17127
  "comesFrom",
16611
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
17128
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
16612
17129
  [
16613
- (0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), VALUE_STEP),
16614
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))
17130
+ (0, import_datalog3.lit)("reaches", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"), VALUE_STEP),
17131
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"))
16615
17132
  ]
16616
17133
  ),
16617
17134
  // Calling f ends up calling the name n that module m exports, one
16618
17135
  // hop through f's own body or deeper through a wrapper of a wrapper.
16619
17136
  // Several results is normal: a composed decorator applies them all.
16620
- (0, import_datalog2.rule)(
17137
+ (0, import_datalog3.rule)(
16621
17138
  "callsInto",
16622
- [(0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
17139
+ [(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
16623
17140
  [
16624
- (0, import_datalog2.lit)("bodyCallsDeep", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("c")),
16625
- (0, import_datalog2.lit)("comesFrom", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))
17141
+ (0, import_datalog3.lit)("bodyCallsDeep", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("c")),
17142
+ (0, import_datalog3.lit)("comesFrom", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"))
16626
17143
  ]
16627
17144
  ),
16628
- (0, import_datalog2.rule)(
17145
+ (0, import_datalog3.rule)(
16629
17146
  "callsInto",
16630
- [(0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
17147
+ [(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
16631
17148
  [
16632
- (0, import_datalog2.lit)("bodyCallsDeep", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("c")),
16633
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("g")),
16634
- (0, import_datalog2.lit)("callsInto", (0, import_datalog2.variable)("g"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))
17149
+ (0, import_datalog3.lit)("bodyCallsDeep", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("c")),
17150
+ (0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("g")),
17151
+ (0, import_datalog3.lit)("callsInto", (0, import_datalog3.variable)("g"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"))
16635
17152
  ]
16636
17153
  ),
16637
17154
  // The question callers ask: what a value comes to, narrowed to the
16638
17155
  // functions. Objects appear in the middle of chains and never in an
16639
17156
  // answer.
16640
- (0, import_datalog2.rule)(
17157
+ (0, import_datalog3.rule)(
16641
17158
  "resolves",
16642
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16643
- [(0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")), (0, import_datalog2.lit)("func", (0, import_datalog2.variable)("z"))]
17159
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
17160
+ [(0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")), (0, import_datalog3.lit)("func", (0, import_datalog3.variable)("z"))]
16644
17161
  )
16645
17162
  ];
16646
17163
  var RESOLUTION_QUESTIONS = [
16647
- (0, import_datalog2.rule)(
17164
+ (0, import_datalog3.rule)(
16648
17165
  "wantedResolves",
16649
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16650
- [(0, import_datalog2.lit)("wanted", (0, import_datalog2.variable)("x")), (0, import_datalog2.lit)("resolves", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"))]
17166
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
17167
+ [(0, import_datalog3.lit)("wanted", (0, import_datalog3.variable)("x")), (0, import_datalog3.lit)("resolves", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"))]
16651
17168
  ),
16652
- (0, import_datalog2.rule)(
17169
+ (0, import_datalog3.rule)(
16653
17170
  "wantedComesTo",
16654
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16655
- [(0, import_datalog2.lit)("wanted", (0, import_datalog2.variable)("x")), (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"))]
17171
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
17172
+ [(0, import_datalog3.lit)("wanted", (0, import_datalog3.variable)("x")), (0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"))]
16656
17173
  ),
16657
- (0, import_datalog2.rule)(
17174
+ (0, import_datalog3.rule)(
16658
17175
  "wantedComesTo",
16659
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16660
- [(0, import_datalog2.lit)("wantedOrigin", (0, import_datalog2.variable)("x")), (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"))]
17176
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
17177
+ [(0, import_datalog3.lit)("wantedOrigin", (0, import_datalog3.variable)("x")), (0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"))]
16661
17178
  ),
16662
- (0, import_datalog2.rule)(
17179
+ (0, import_datalog3.rule)(
16663
17180
  "wantedIsWrittenAs",
16664
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16665
- [(0, import_datalog2.lit)("wanted", (0, import_datalog2.variable)("x")), (0, import_datalog2.lit)("isWrittenAs", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"))]
17181
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
17182
+ [(0, import_datalog3.lit)("wanted", (0, import_datalog3.variable)("x")), (0, import_datalog3.lit)("isWrittenAs", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"))]
16666
17183
  ),
16667
17184
  // A call is given no `comesTo`, so this is the only way to ask what
16668
17185
  // object one arrives at, and without it a demand-driven run derives
16669
17186
  // `objectOf` nowhere.
16670
- (0, import_datalog2.rule)(
17187
+ (0, import_datalog3.rule)(
16671
17188
  "wantedObjectOf",
16672
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16673
- [(0, import_datalog2.lit)("wanted", (0, import_datalog2.variable)("x")), (0, import_datalog2.lit)("objectOf", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"))]
17189
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
17190
+ [(0, import_datalog3.lit)("wanted", (0, import_datalog3.variable)("x")), (0, import_datalog3.lit)("objectOf", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"))]
16674
17191
  ),
16675
17192
  // Keyed by the parameter, since that is what a caller has in hand
16676
17193
  // when it wants the call sites told apart.
16677
- (0, import_datalog2.rule)(
17194
+ (0, import_datalog3.rule)(
16678
17195
  "wantedParamAt",
16679
- [(0, import_datalog2.variable)("p"), (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("z")],
16680
- [(0, import_datalog2.lit)("wanted", (0, import_datalog2.variable)("p")), (0, import_datalog2.lit)("paramAt", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("p"), (0, import_datalog2.variable)("z"))]
17196
+ [(0, import_datalog3.variable)("p"), (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("z")],
17197
+ [(0, import_datalog3.lit)("wanted", (0, import_datalog3.variable)("p")), (0, import_datalog3.lit)("paramAt", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("p"), (0, import_datalog3.variable)("z"))]
16681
17198
  ),
16682
- (0, import_datalog2.rule)(
17199
+ (0, import_datalog3.rule)(
16683
17200
  "wantedComesFrom",
16684
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
16685
- [(0, import_datalog2.lit)("wantedOrigin", (0, import_datalog2.variable)("x")), (0, import_datalog2.lit)("comesFrom", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))]
17201
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
17202
+ [(0, import_datalog3.lit)("wantedOrigin", (0, import_datalog3.variable)("x")), (0, import_datalog3.lit)("comesFrom", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"))]
16686
17203
  ),
16687
17204
  // Call-origin questions, for attribution, in their own demand
16688
17205
  // class. Attribution stops at the import declaration, so nothing
16689
17206
  // here demands reaches or callsInto. The chains are closures with
16690
17207
  // no depth bound: an alias run of any length resolves.
16691
- (0, import_datalog2.rule)("callOriginChain", [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("x")], [(0, import_datalog2.lit)("wantedCallOrigin", (0, import_datalog2.variable)("x"))]),
17208
+ (0, import_datalog3.rule)("callOriginChain", [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("x")], [(0, import_datalog3.lit)("wantedCallOrigin", (0, import_datalog3.variable)("x"))]),
16692
17209
  // The chain with at least one hop taken, which is what tells a
16693
17210
  // destructured binding apart from asking about a node directly. The
16694
17211
  // whole chain is the seed plus those hops.
16695
- (0, import_datalog2.rule)(
17212
+ (0, import_datalog3.rule)(
16696
17213
  "callOriginChain",
16697
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16698
- [(0, import_datalog2.lit)("callOriginChainStepped", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"))]
17214
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
17215
+ [(0, import_datalog3.lit)("callOriginChainStepped", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"))]
16699
17216
  ),
16700
- (0, import_datalog2.rule)(
17217
+ (0, import_datalog3.rule)(
16701
17218
  "callOriginChainStepped",
16702
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16703
- [(0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")), (0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))]
17219
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
17220
+ [(0, import_datalog3.lit)("callOriginChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y")), (0, import_datalog3.lit)("binds", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("z"))]
16704
17221
  ),
16705
- (0, import_datalog2.rule)(
17222
+ (0, import_datalog3.rule)(
16706
17223
  "callOriginChainStepped",
16707
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
17224
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
16708
17225
  [
16709
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
16710
- (0, import_datalog2.lit)("endsHolding", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))
17226
+ (0, import_datalog3.lit)("callOriginChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y")),
17227
+ (0, import_datalog3.lit)("endsHolding", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("z"))
16711
17228
  ]
16712
17229
  ),
16713
- (0, import_datalog2.rule)(
17230
+ (0, import_datalog3.rule)(
16714
17231
  "callOriginChainStepped",
16715
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
17232
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
16716
17233
  [
16717
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
16718
- (0, import_datalog2.lit)("fallbackBranch", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))
17234
+ (0, import_datalog3.lit)("callOriginChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y")),
17235
+ (0, import_datalog3.lit)("fallbackBranch", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("z"))
16719
17236
  ]
16720
17237
  ),
16721
- (0, import_datalog2.rule)(
17238
+ (0, import_datalog3.rule)(
16722
17239
  "wantedCallOriginPair",
16723
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
17240
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
16724
17241
  [
16725
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
16726
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))
17242
+ (0, import_datalog3.lit)("callOriginChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y")),
17243
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"))
16727
17244
  ]
16728
17245
  ),
16729
17246
  // An import of a project barrel is an import of what the barrel
16730
17247
  // forwards, so the pair surfaces the module behind the chain.
16731
- (0, import_datalog2.rule)(
17248
+ (0, import_datalog3.rule)(
16732
17249
  "wantedCallOriginPair",
16733
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m2"), (0, import_datalog2.variable)("n2")],
17250
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m2"), (0, import_datalog3.variable)("n2")],
16734
17251
  [
16735
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
16736
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")),
16737
- (0, import_datalog2.lit)("moduleForwards", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("m2"), (0, import_datalog2.variable)("n2"))
17252
+ (0, import_datalog3.lit)("callOriginChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y")),
17253
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")),
17254
+ (0, import_datalog3.lit)("moduleForwards", (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("m2"), (0, import_datalog3.variable)("n2"))
16738
17255
  ]
16739
17256
  ),
16740
17257
  // A namespace member: the module's export of the member's own name.
16741
17258
  // The imports literal leads, since it is the smallest relation.
16742
- (0, import_datalog2.rule)(
17259
+ (0, import_datalog3.rule)(
16743
17260
  "wantedCallOriginPair",
16744
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("p")],
17261
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("p")],
16745
17262
  [
16746
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("m"), NAMESPACE_IMPORT),
16747
- (0, import_datalog2.lit)("readsProperty", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("p")),
16748
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"))
17263
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("m"), NAMESPACE_IMPORT),
17264
+ (0, import_datalog3.lit)("readsProperty", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("p")),
17265
+ (0, import_datalog3.lit)("callOriginChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"))
16749
17266
  ]
16750
17267
  ),
16751
- (0, import_datalog2.rule)(
17268
+ (0, import_datalog3.rule)(
16752
17269
  "wantedCallOriginPair",
16753
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("p")],
17270
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("p")],
16754
17271
  [
16755
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("d"), (0, import_datalog2.variable)("m"), NAMESPACE_IMPORT),
16756
- (0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("d")),
16757
- (0, import_datalog2.lit)("readsProperty", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("p")),
16758
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"))
17272
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("d"), (0, import_datalog3.variable)("m"), NAMESPACE_IMPORT),
17273
+ (0, import_datalog3.lit)("binds", (0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("d")),
17274
+ (0, import_datalog3.lit)("readsProperty", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("p")),
17275
+ (0, import_datalog3.lit)("callOriginChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"))
16759
17276
  ]
16760
17277
  ),
16761
17278
  // What a call made: through the call to its callee, whose own alias
16762
17279
  // chain leads to the import.
16763
- (0, import_datalog2.rule)(
17280
+ (0, import_datalog3.rule)(
16764
17281
  "callMadeChain",
16765
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("f")],
16766
- [(0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("c")), (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("f"))]
17282
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("f")],
17283
+ [(0, import_datalog3.lit)("callOriginChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("c")), (0, import_datalog3.lit)("call", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("f"))]
16767
17284
  ),
16768
- (0, import_datalog2.rule)(
17285
+ (0, import_datalog3.rule)(
16769
17286
  "callMadeChain",
16770
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16771
- [(0, import_datalog2.lit)("callMadeChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")), (0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))]
17287
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
17288
+ [(0, import_datalog3.lit)("callMadeChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y")), (0, import_datalog3.lit)("binds", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("z"))]
16772
17289
  ),
16773
- (0, import_datalog2.rule)(
17290
+ (0, import_datalog3.rule)(
16774
17291
  "callMadeChain",
16775
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16776
- [(0, import_datalog2.lit)("callMadeChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")), (0, import_datalog2.lit)("endsHolding", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))]
17292
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
17293
+ [(0, import_datalog3.lit)("callMadeChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y")), (0, import_datalog3.lit)("endsHolding", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("z"))]
16777
17294
  ),
16778
- (0, import_datalog2.rule)(
17295
+ (0, import_datalog3.rule)(
16779
17296
  "wantedCallOriginPair",
16780
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
17297
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
16781
17298
  [
16782
- (0, import_datalog2.lit)("callMadeChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
16783
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))
17299
+ (0, import_datalog3.lit)("callMadeChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y")),
17300
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"))
16784
17301
  ]
16785
17302
  ),
16786
17303
  // A member destructured off what a call made keeps the member name
16787
17304
  // as one more path segment.
16788
- (0, import_datalog2.rule)(
17305
+ (0, import_datalog3.rule)(
16789
17306
  "callMemberChain",
16790
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("p")],
17307
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("p")],
16791
17308
  [
16792
- (0, import_datalog2.lit)("callOriginChainStepped", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("e")),
16793
- (0, import_datalog2.lit)("readsProperty", (0, import_datalog2.variable)("e"), (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("p")),
16794
- (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("f"))
17309
+ (0, import_datalog3.lit)("callOriginChainStepped", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("e")),
17310
+ (0, import_datalog3.lit)("readsProperty", (0, import_datalog3.variable)("e"), (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("p")),
17311
+ (0, import_datalog3.lit)("call", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("f"))
16795
17312
  ]
16796
17313
  ),
16797
- (0, import_datalog2.rule)(
17314
+ (0, import_datalog3.rule)(
16798
17315
  "callMemberChain",
16799
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), (0, import_datalog2.variable)("p")],
17316
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), (0, import_datalog3.variable)("p")],
16800
17317
  [
16801
- (0, import_datalog2.lit)("callMemberChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("p")),
16802
- (0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))
17318
+ (0, import_datalog3.lit)("callMemberChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("p")),
17319
+ (0, import_datalog3.lit)("binds", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("z"))
16803
17320
  ]
16804
17321
  ),
16805
- (0, import_datalog2.rule)(
17322
+ (0, import_datalog3.rule)(
16806
17323
  "callMemberChain",
16807
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), (0, import_datalog2.variable)("p")],
17324
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), (0, import_datalog3.variable)("p")],
16808
17325
  [
16809
- (0, import_datalog2.lit)("callMemberChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("p")),
16810
- (0, import_datalog2.lit)("endsHolding", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))
17326
+ (0, import_datalog3.lit)("callMemberChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("p")),
17327
+ (0, import_datalog3.lit)("endsHolding", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("z"))
16811
17328
  ]
16812
17329
  ),
16813
- (0, import_datalog2.rule)(
17330
+ (0, import_datalog3.rule)(
16814
17331
  "wantedCallOriginMember",
16815
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("p")],
17332
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("p")],
16816
17333
  [
16817
- (0, import_datalog2.lit)("callMemberChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("p")),
16818
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))
17334
+ (0, import_datalog3.lit)("callMemberChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("p")),
17335
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"))
16819
17336
  ]
16820
17337
  ),
16821
- (0, import_datalog2.rule)(
17338
+ (0, import_datalog3.rule)(
16822
17339
  "wantedCallsInto",
16823
- [(0, import_datalog2.variable)("g"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
17340
+ [(0, import_datalog3.variable)("g"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
16824
17341
  [
16825
- (0, import_datalog2.lit)("wantedOrigin", (0, import_datalog2.variable)("x")),
16826
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("g")),
16827
- (0, import_datalog2.lit)("callsInto", (0, import_datalog2.variable)("g"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))
17342
+ (0, import_datalog3.lit)("wantedOrigin", (0, import_datalog3.variable)("x")),
17343
+ (0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("g")),
17344
+ (0, import_datalog3.lit)("callsInto", (0, import_datalog3.variable)("g"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"))
16828
17345
  ]
16829
17346
  ),
16830
17347
  // Subject identity, its own demand class; the README's subject
16831
17348
  // section says why the origin pair rides on the written-value walk.
16832
- (0, import_datalog2.rule)(
17349
+ (0, import_datalog3.rule)(
16833
17350
  "wantedSubjectWritten",
16834
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("r")],
16835
- [(0, import_datalog2.lit)("wantedSubject", (0, import_datalog2.variable)("x")), (0, import_datalog2.lit)("isWrittenAs", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("r"))]
17351
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("r")],
17352
+ [(0, import_datalog3.lit)("wantedSubject", (0, import_datalog3.variable)("x")), (0, import_datalog3.lit)("isWrittenAs", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("r"))]
16836
17353
  ),
16837
- (0, import_datalog2.rule)(
17354
+ (0, import_datalog3.rule)(
16838
17355
  "wantedSubjectConstruction",
16839
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
17356
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
16840
17357
  [
16841
- (0, import_datalog2.lit)("wantedSubject", (0, import_datalog2.variable)("x")),
16842
- (0, import_datalog2.lit)("isWrittenAs", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("r")),
16843
- (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c")),
16844
- (0, import_datalog2.lit)("comesFrom", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))
17358
+ (0, import_datalog3.lit)("wantedSubject", (0, import_datalog3.variable)("x")),
17359
+ (0, import_datalog3.lit)("isWrittenAs", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("r")),
17360
+ (0, import_datalog3.lit)("call", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("c")),
17361
+ (0, import_datalog3.lit)("comesFrom", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"))
16845
17362
  ]
16846
17363
  ),
16847
17364
  // The export table of one module, keyed by the module asked about.
16848
17365
  // The moduleExport rules flatten re-export chains of any length, and
16849
17366
  // the demand cone stays on export facts alone.
16850
- (0, import_datalog2.rule)(
17367
+ (0, import_datalog3.rule)(
16851
17368
  "wantedModuleExport",
16852
- [(0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("value")],
17369
+ [(0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("value")],
16853
17370
  [
16854
- (0, import_datalog2.lit)("wantedExportsOf", (0, import_datalog2.variable)("m")),
16855
- (0, import_datalog2.lit)("moduleExport", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("value"))
17371
+ (0, import_datalog3.lit)("wantedExportsOf", (0, import_datalog3.variable)("m")),
17372
+ (0, import_datalog3.lit)("moduleExport", (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("value"))
16856
17373
  ]
16857
17374
  ),
16858
17375
  // The calls behind a receiver, for a pack that wants the anchor a
@@ -16861,63 +17378,63 @@ var RESOLUTION_QUESTIONS = [
16861
17378
  // A class's ancestry, one hop per extends through the binding that
16862
17379
  // says which class the written base is; the names on the way out
16863
17380
  // are what a storage pack matches its library's bases against.
16864
- (0, import_datalog2.rule)("ancestryChain", [(0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("c")], [(0, import_datalog2.lit)("wantedAncestry", (0, import_datalog2.variable)("c"))]),
16865
- (0, import_datalog2.rule)(
17381
+ (0, import_datalog3.rule)("ancestryChain", [(0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("c")], [(0, import_datalog3.lit)("wantedAncestry", (0, import_datalog3.variable)("c"))]),
17382
+ (0, import_datalog3.rule)(
16866
17383
  "ancestryChain",
16867
- [(0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("b2")],
17384
+ [(0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("b2")],
16868
17385
  [
16869
- (0, import_datalog2.lit)("ancestryChain", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("b")),
16870
- (0, import_datalog2.lit)("extends", (0, import_datalog2.variable)("b"), (0, import_datalog2.variable)("x")),
16871
- (0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("b2"))
17386
+ (0, import_datalog3.lit)("ancestryChain", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("b")),
17387
+ (0, import_datalog3.lit)("extends", (0, import_datalog3.variable)("b"), (0, import_datalog3.variable)("x")),
17388
+ (0, import_datalog3.lit)("binds", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("b2"))
16872
17389
  ]
16873
17390
  ),
16874
- (0, import_datalog2.rule)(
17391
+ (0, import_datalog3.rule)(
16875
17392
  "wantedBaseName",
16876
- [(0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("n")],
16877
- [(0, import_datalog2.lit)("ancestryChain", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("b")), (0, import_datalog2.lit)("extendsNamed", (0, import_datalog2.variable)("b"), (0, import_datalog2.variable)("n"))]
17393
+ [(0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("n")],
17394
+ [(0, import_datalog3.lit)("ancestryChain", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("b")), (0, import_datalog3.lit)("extendsNamed", (0, import_datalog3.variable)("b"), (0, import_datalog3.variable)("n"))]
16878
17395
  ),
16879
- (0, import_datalog2.rule)("anchorChain", [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("x")], [(0, import_datalog2.lit)("wantedAnchor", (0, import_datalog2.variable)("x"))]),
16880
- (0, import_datalog2.rule)(
17396
+ (0, import_datalog3.rule)("anchorChain", [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("x")], [(0, import_datalog3.lit)("wantedAnchor", (0, import_datalog3.variable)("x"))]),
17397
+ (0, import_datalog3.rule)(
16881
17398
  "anchorChain",
16882
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16883
- [(0, import_datalog2.lit)("anchorChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")), (0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))]
17399
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
17400
+ [(0, import_datalog3.lit)("anchorChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y")), (0, import_datalog3.lit)("binds", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("z"))]
16884
17401
  ),
16885
- (0, import_datalog2.rule)(
17402
+ (0, import_datalog3.rule)(
16886
17403
  "anchorChain",
16887
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16888
- [(0, import_datalog2.lit)("anchorChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")), (0, import_datalog2.lit)("endsHolding", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))]
17404
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
17405
+ [(0, import_datalog3.lit)("anchorChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y")), (0, import_datalog3.lit)("endsHolding", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("z"))]
16889
17406
  ),
16890
- (0, import_datalog2.rule)(
17407
+ (0, import_datalog3.rule)(
16891
17408
  "anchorChain",
16892
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16893
- [(0, import_datalog2.lit)("anchorChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")), (0, import_datalog2.lit)("fallbackBranch", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))]
17409
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
17410
+ [(0, import_datalog3.lit)("anchorChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y")), (0, import_datalog3.lit)("fallbackBranch", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("z"))]
16894
17411
  ),
16895
- (0, import_datalog2.rule)(
17412
+ (0, import_datalog3.rule)(
16896
17413
  "anchorChain",
16897
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
17414
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
16898
17415
  [
16899
- (0, import_datalog2.lit)("anchorChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
16900
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")),
16901
- (0, import_datalog2.lit)("moduleExport", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("z"))
17416
+ (0, import_datalog3.lit)("anchorChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y")),
17417
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")),
17418
+ (0, import_datalog3.lit)("moduleExport", (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("z"))
16902
17419
  ]
16903
17420
  ),
16904
- (0, import_datalog2.rule)(
17421
+ (0, import_datalog3.rule)(
16905
17422
  "anchorChain",
16906
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("c")],
16907
- [(0, import_datalog2.lit)("anchorChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("r")), (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c"))]
17423
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("c")],
17424
+ [(0, import_datalog3.lit)("anchorChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("r")), (0, import_datalog3.lit)("call", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("c"))]
16908
17425
  ),
16909
- (0, import_datalog2.rule)(
17426
+ (0, import_datalog3.rule)(
16910
17427
  "anchorChain",
16911
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("o")],
17428
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("o")],
16912
17429
  [
16913
- (0, import_datalog2.lit)("anchorChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
16914
- (0, import_datalog2.lit)("readsProperty", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("n"))
17430
+ (0, import_datalog3.lit)("anchorChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y")),
17431
+ (0, import_datalog3.lit)("readsProperty", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("n"))
16915
17432
  ]
16916
17433
  ),
16917
- (0, import_datalog2.rule)(
17434
+ (0, import_datalog3.rule)(
16918
17435
  "wantedAnchorCall",
16919
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("r")],
16920
- [(0, import_datalog2.lit)("anchorChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("r")), (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c"))]
17436
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("r")],
17437
+ [(0, import_datalog3.lit)("anchorChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("r")), (0, import_datalog3.lit)("call", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("c"))]
16921
17438
  )
16922
17439
  ];
16923
17440
  var ANSWER_RELATIONS = [
@@ -16944,17 +17461,17 @@ function rootConstant(node) {
16944
17461
  }
16945
17462
  return rootConstant(receiver);
16946
17463
  }
16947
- var ANCESTRY_PROGRAM = (0, import_datalog3.deriveOnDemand)(
17464
+ var ANCESTRY_PROGRAM = (0, import_datalog4.deriveOnDemand)(
16948
17465
  [...RESOLUTION_RULES, ...RESOLUTION_QUESTIONS],
16949
17466
  ANSWER_RELATIONS
16950
17467
  );
16951
17468
  function reachesBase(facts, classKey, bases) {
16952
17469
  facts.add("wantedAncestry", [classKey]);
16953
- (0, import_datalog3.evaluate)(facts, ANCESTRY_PROGRAM.rules);
17470
+ (0, import_datalog4.evaluate)(facts, ANCESTRY_PROGRAM.rules);
16954
17471
  return facts.lookup("wantedBaseName", 0, classKey).some((row) => bases.includes(String(row[1])));
16955
17472
  }
16956
- function classBehind(facts, constant2) {
16957
- const wanted = `#${constant2.text}`;
17473
+ function classBehind(facts, constant3) {
17474
+ const wanted = `#${constant3.text}`;
16958
17475
  const bound = new Set(
16959
17476
  facts.facts("binds").filter((row) => String(row[0]).endsWith(wanted)).map((row) => String(row[1]))
16960
17477
  );
@@ -16997,11 +17514,11 @@ function storageEffects(calls, options) {
16997
17514
  if (partOfOne.has(call.id)) {
16998
17515
  continue;
16999
17516
  }
17000
- const constant2 = rootConstant(call);
17001
- if (constant2 === null) {
17517
+ const constant3 = rootConstant(call);
17518
+ if (constant3 === null) {
17002
17519
  continue;
17003
17520
  }
17004
- const classKey = classBehind(options.facts, constant2);
17521
+ const classKey = classBehind(options.facts, constant3);
17005
17522
  if (classKey === void 0) {
17006
17523
  continue;
17007
17524
  }
@@ -17019,7 +17536,7 @@ function storageEffects(calls, options) {
17019
17536
  recognition: "ruby-storage",
17020
17537
  storageSystem: pattern.storageSystem,
17021
17538
  scope: pattern.baseClasses[0] ?? "",
17022
- container: constant2.text
17539
+ container: constant3.text
17023
17540
  }),
17024
17541
  callee: call.text,
17025
17542
  interaction: {
@@ -17135,7 +17652,8 @@ async function discoverUnits(root, options) {
17135
17652
  const knownClasses = new Set(classes.map((info) => info.qualifiedName));
17136
17653
  const fileBlocks = classes.map((info) => ({
17137
17654
  info,
17138
- knownClasses
17655
+ knownClasses,
17656
+ file: options.absoluteFile ?? options.filePath
17139
17657
  }));
17140
17658
  const units = [];
17141
17659
  for (const info of classes) {
@@ -17159,16 +17677,17 @@ async function discoverUnits(root, options) {
17159
17677
  }
17160
17678
  return units;
17161
17679
  }
17162
- function reachesConfiguredBase(ancestry, self, pattern) {
17680
+ function reachesConfiguredBase(ancestry, self, baseClassNames) {
17163
17681
  return ancestry.some(
17164
- (entry) => entry.name !== self && pattern.baseClassNames.includes(entry.name)
17682
+ (entry) => entry.name !== self && baseClassNames.includes(entry.name)
17165
17683
  );
17166
17684
  }
17167
17685
  function unitsFor(pattern, pack, info, ownBlocks, fileBlocks, options) {
17168
17686
  const table = {
17169
- graphqlObjectFields: (p) => graphqlObjectFieldUnits(p, pack, info, ownBlocks, fileBlocks, options)
17687
+ graphqlObjectFields: (p) => graphqlObjectFieldUnits(p, pack, info, ownBlocks, fileBlocks, options),
17688
+ controllerActions: (p) => controllerActionUnits(p, pack, info, ownBlocks, fileBlocks, options)
17170
17689
  };
17171
- return (0, import_behavioral_ir.dispatchByType)(table, pattern);
17690
+ return (0, import_behavioral_ir2.dispatchByType)(table, pattern);
17172
17691
  }
17173
17692
  async function graphqlObjectFieldUnits(pattern, pack, info, ownBlocks, fileBlocks, options) {
17174
17693
  if (info.bodyNode === null || pattern.baseClassNames.includes(info.qualifiedName)) {
@@ -17181,7 +17700,7 @@ async function graphqlObjectFieldUnits(pattern, pack, info, ownBlocks, fileBlock
17181
17700
  options.storage
17182
17701
  );
17183
17702
  const ancestry = await ancestryOf(info.qualifiedName, ownBlocks, ctx.lookup);
17184
- if (!reachesConfiguredBase(ancestry, info.qualifiedName, pattern)) {
17703
+ if (!reachesConfiguredBase(ancestry, info.qualifiedName, pattern.baseClassNames)) {
17185
17704
  return [];
17186
17705
  }
17187
17706
  const typeName = graphqlTypeNameFromQualified(
@@ -17200,9 +17719,145 @@ async function graphqlObjectFieldUnits(pattern, pack, info, ownBlocks, fileBlock
17200
17719
  declsByName.set(decl.fieldName, decl);
17201
17720
  }
17202
17721
  }
17203
- return [...declsByName.values()].map(
17204
- (decl) => buildFieldUnit(pack, typeName, decl, options.filePath)
17205
- );
17722
+ return [...declsByName.values()].map((decl) => {
17723
+ const raw = buildFieldUnit(pack, typeName, decl, options.filePath);
17724
+ if (decl.body.reachSeed !== void 0) {
17725
+ options.onReachSeed?.(raw, decl.body.reachSeed);
17726
+ }
17727
+ return raw;
17728
+ });
17729
+ }
17730
+ async function controllerActionUnits(pattern, pack, info, ownBlocks, fileBlocks, options) {
17731
+ if (info.bodyNode === null || pattern.baseClassNames.includes(info.qualifiedName)) {
17732
+ return [];
17733
+ }
17734
+ const lookup = {
17735
+ root: pattern.root,
17736
+ pathConvention: pattern.pathConvention,
17737
+ ancestryRootClassNames: pattern.ancestryRootClassNames,
17738
+ parsedFile: (absPath) => options.cache.get(absPath),
17739
+ localDefinition: (name) => sameFileBlocks(name, fileBlocks)
17740
+ };
17741
+ const ancestry = await ancestryOf(info.qualifiedName, ownBlocks, lookup);
17742
+ if (!reachesConfiguredBase(ancestry, info.qualifiedName, pattern.baseClassNames)) {
17743
+ return [];
17744
+ }
17745
+ const units = [];
17746
+ for (const block of ownBlocks) {
17747
+ if (block.info.bodyNode === null) {
17748
+ continue;
17749
+ }
17750
+ const visibility = instanceMethodVisibility(block.info.bodyNode);
17751
+ for (const [actionName, method] of instanceMethodsByName(
17752
+ block.info.bodyNode
17753
+ )) {
17754
+ if ((visibility.get(actionName) ?? "public") !== "public") {
17755
+ continue;
17756
+ }
17757
+ const raw = buildControllerActionUnit(
17758
+ pack,
17759
+ pattern,
17760
+ info.qualifiedName,
17761
+ actionName,
17762
+ method,
17763
+ options.filePath,
17764
+ options.storage
17765
+ );
17766
+ units.push(raw);
17767
+ options.onReachSeed?.(raw, {
17768
+ file: block.file,
17769
+ node: method,
17770
+ enclosingQualifiedName: info.qualifiedName
17771
+ });
17772
+ }
17773
+ }
17774
+ return units;
17775
+ }
17776
+ function buildControllerActionUnit(pack, pattern, controllerQualifiedName, actionName, method, filePath, storage) {
17777
+ const range = rangeOf(method);
17778
+ const route = pattern.routeFor(controllerQualifiedName, actionName);
17779
+ const body = bodyOfMethod(method, storage);
17780
+ return {
17781
+ identity: {
17782
+ name: actionName,
17783
+ nameKind: "binding",
17784
+ kind: "handler",
17785
+ file: filePath,
17786
+ range,
17787
+ span: spanOf(method),
17788
+ exportName: actionName,
17789
+ exportPath: [controllerQualifiedName, actionName]
17790
+ },
17791
+ boundaryBinding: route === null ? null : (0, import_behavioral_ir2.restBinding)({
17792
+ transport: pack.protocol,
17793
+ method: route.method,
17794
+ path: route.path,
17795
+ recognition: pack.name
17796
+ }),
17797
+ parameters: [],
17798
+ branches: [
17799
+ {
17800
+ conditions: [],
17801
+ terminal: {
17802
+ kind: "response",
17803
+ statusCode: { type: "literal", value: pattern.defaultStatusCode },
17804
+ body: null,
17805
+ exceptionType: null,
17806
+ message: null,
17807
+ component: null,
17808
+ renderTree: null,
17809
+ delegateTarget: null,
17810
+ emitEvent: null,
17811
+ location: range
17812
+ },
17813
+ effects: body.effects ?? [],
17814
+ ...body.extraEffects === void 0 ? {} : { extraEffects: body.extraEffects },
17815
+ location: range,
17816
+ isDefault: true
17817
+ }
17818
+ ],
17819
+ bodyContent: body.bodyContent ?? "absent",
17820
+ dependencyCalls: [],
17821
+ declaredContract: null
17822
+ };
17823
+ }
17824
+ function routingGapUnit(pattern, gaps) {
17825
+ const range = { start: 1, end: 1 };
17826
+ return {
17827
+ identity: {
17828
+ name: "routes",
17829
+ kind: "module-init",
17830
+ file: pattern.routesFile,
17831
+ range,
17832
+ exportName: null,
17833
+ exportPath: null
17834
+ },
17835
+ boundaryBinding: null,
17836
+ parameters: [],
17837
+ branches: [
17838
+ {
17839
+ conditions: [],
17840
+ terminal: {
17841
+ kind: "void",
17842
+ statusCode: null,
17843
+ body: null,
17844
+ exceptionType: null,
17845
+ message: null,
17846
+ component: null,
17847
+ renderTree: null,
17848
+ delegateTarget: null,
17849
+ emitEvent: null,
17850
+ location: range
17851
+ },
17852
+ effects: [],
17853
+ location: range,
17854
+ isDefault: true
17855
+ }
17856
+ ],
17857
+ readings: gaps.map((gap) => (0, import_extractor4.unreadableReading)(gap, range)),
17858
+ dependencyCalls: [],
17859
+ declaredContract: null
17860
+ };
17206
17861
  }
17207
17862
  function blockConfiguresCall(pattern) {
17208
17863
  const names = /* @__PURE__ */ new Set([
@@ -17243,12 +17898,15 @@ function branchesFor(body, range) {
17243
17898
  }
17244
17899
  function bodyOfMethod(method, storage) {
17245
17900
  const effects = invocationEffects(method);
17246
- const database = storage === void 0 ? [] : storageEffects(callsUnder(method), storage);
17901
+ const extra = [
17902
+ ...envReadEffects(method),
17903
+ ...storage === void 0 ? [] : storageEffects(callsUnder(method), storage)
17904
+ ];
17247
17905
  return {
17248
17906
  bodyContent: methodHasStatements(method) ? "statements" : "empty",
17249
17907
  readings: [],
17250
17908
  ...effects.length > 0 ? { effects } : {},
17251
- ...database.length > 0 ? { extraEffects: database } : {}
17909
+ ...extra.length > 0 ? { extraEffects: extra } : {}
17252
17910
  };
17253
17911
  }
17254
17912
  function callsUnder(node, found = []) {
@@ -17268,18 +17926,25 @@ var NO_METHOD_BEHIND_IT = {
17268
17926
  readings: []
17269
17927
  };
17270
17928
  function methodNotSettled(reason, range) {
17271
- return { readings: [(0, import_extractor3.unreadableReading)(reason, range)] };
17929
+ return { readings: [(0, import_extractor4.unreadableReading)(reason, range)] };
17272
17930
  }
17273
17931
  function bodyFromLookup(found, range, subject, nothingThere, storage) {
17274
17932
  const table = {
17275
- found: (lookup) => bodyOfMethod(lookup.method, storage),
17933
+ found: (lookup) => ({
17934
+ ...bodyOfMethod(lookup.method, storage),
17935
+ reachSeed: {
17936
+ file: lookup.block.file,
17937
+ node: lookup.method,
17938
+ enclosingQualifiedName: lookup.block.info.qualifiedName
17939
+ }
17940
+ }),
17276
17941
  unsettled: (lookup) => methodNotSettled(
17277
17942
  `${subject} could be answered by a method ${lookup.reason}, so whether one exists was not settled here`,
17278
17943
  range
17279
17944
  ),
17280
17945
  none: () => nothingThere
17281
17946
  };
17282
- return (0, import_behavioral_ir.dispatchByType)(table, found);
17947
+ return (0, import_behavioral_ir2.dispatchByType)(table, found);
17283
17948
  }
17284
17949
  async function readFieldCall(stmt, scope, ctx, ancestry) {
17285
17950
  if (stmt.type !== "call" || field(stmt, "receiver") !== null) {
@@ -17322,7 +17987,7 @@ function computedNameDeclaration(stmt, nameArg) {
17322
17987
  contract: null,
17323
17988
  body: {
17324
17989
  readings: [
17325
- (0, import_extractor3.unreadableReading)(
17990
+ (0, import_extractor4.unreadableReading)(
17326
17991
  `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`,
17327
17992
  range
17328
17993
  )
@@ -17548,7 +18213,7 @@ function buildFieldUnit(pack, typeName, decl, filePath) {
17548
18213
  exportName: null,
17549
18214
  exportPath: null
17550
18215
  },
17551
- boundaryBinding: decl.namedOnTheWire ? (0, import_behavioral_ir.graphqlResolverBinding)({
18216
+ boundaryBinding: decl.namedOnTheWire ? (0, import_behavioral_ir2.graphqlResolverBinding)({
17552
18217
  transport: pack.protocol,
17553
18218
  recognition: pack.name,
17554
18219
  typeName,
@@ -17564,65 +18229,39 @@ function buildFieldUnit(pack, typeName, decl, filePath) {
17564
18229
  };
17565
18230
  }
17566
18231
 
17567
- // src/facts.ts
17568
- function unitKey(filePath, range, name) {
17569
- return `${filePath}:${range.start}-${range.end}#${name}`;
18232
+ // src/facts/values.ts
18233
+ function nodeId(filePath, node) {
18234
+ return `${filePath}:${node.startIndex}-${node.endIndex}`;
17570
18235
  }
17571
- function emitEntryFact(db, filePath, range, name) {
17572
- db.add("entry", [unitKey(filePath, range, name)]);
18236
+ function nameId(filePath, name) {
18237
+ return `${filePath}#${name}`;
17573
18238
  }
17574
-
17575
- // src/parser.ts
17576
- var import_node_fs2 = __toESM(require("fs"), 1);
17577
- var import_node_path2 = __toESM(require("path"), 1);
17578
- var import_node_url = require("url");
17579
- var import_web_tree_sitter = require("web-tree-sitter");
17580
- var GRAMMAR_PATH = import_node_path2.default.join(
17581
- import_node_path2.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl)),
17582
- "..",
17583
- "grammar",
17584
- "tree-sitter-ruby.wasm"
17585
- );
17586
- var languagePromise = null;
17587
- function loadLanguage() {
17588
- languagePromise ??= (async () => {
17589
- if (!import_node_fs2.default.existsSync(GRAMMAR_PATH)) {
17590
- throw new Error(
17591
- `Ruby grammar not found at ${GRAMMAR_PATH}. See grammar/README.md.`
17592
- );
17593
- }
17594
- await import_web_tree_sitter.Parser.init();
17595
- return import_web_tree_sitter.Language.load(GRAMMAR_PATH);
17596
- })();
17597
- return languagePromise;
18239
+ function paramNameOf(param) {
18240
+ return param.type === "identifier" ? param : field(param, "name") ?? null;
17598
18241
  }
17599
- async function parseRuby(source) {
17600
- const language = await loadLanguage();
17601
- const parser = new import_web_tree_sitter.Parser();
17602
- parser.setLanguage(language);
17603
- try {
17604
- const tree = parser.parse(source);
17605
- if (tree === null) {
17606
- throw new Error("tree-sitter produced no tree for this source");
18242
+ function declaredParamNames(method) {
18243
+ const params = field(method, "parameters");
18244
+ const declared = /* @__PURE__ */ new Set();
18245
+ for (const param of params === null ? [] : children3(params)) {
18246
+ const name = paramNameOf(param);
18247
+ if (name !== null) {
18248
+ declared.add(name.text);
17607
18249
  }
17608
- return tree;
17609
- } finally {
17610
- parser.delete();
17611
18250
  }
18251
+ return declared;
17612
18252
  }
17613
-
17614
- // src/project.ts
17615
- var import_node_fs3 = __toESM(require("fs"), 1);
17616
- var import_node_path3 = __toESM(require("path"), 1);
17617
- var import_datalog4 = require("@suss/datalog");
17618
- var import_extractor4 = require("@suss/extractor");
17619
-
17620
- // src/facts/values.ts
17621
- function nodeId(filePath, node) {
17622
- return `${filePath}:${node.startIndex}-${node.endIndex}`;
17623
- }
17624
- function nameId(filePath, name) {
17625
- return `${filePath}#${name}`;
18253
+ function readKey(filePath, node, enclosing) {
18254
+ if (node.type !== "identifier" && node.type !== "constant") {
18255
+ return nodeId(filePath, node);
18256
+ }
18257
+ const parent = node.parent;
18258
+ if (parent !== null && parent.type === "call" && field(parent, "method")?.id === node.id && field(parent, "receiver") !== null) {
18259
+ return isPropertyRead2(parent) ? nodeId(filePath, parent) : nodeId(filePath, node);
18260
+ }
18261
+ if (enclosing !== null && declaredParamNames(enclosing).has(node.text)) {
18262
+ return `${nodeId(filePath, enclosing)}#${node.text}`;
18263
+ }
18264
+ return nameId(filePath, node.text);
17626
18265
  }
17627
18266
  var WRITTEN_VALUE_TYPES = /* @__PURE__ */ new Set([
17628
18267
  "string",
@@ -17784,6 +18423,9 @@ function emitExpressionFacts(emitter, node) {
17784
18423
  if (WRITTEN_VALUE_TYPES.has(child.type)) {
17785
18424
  add(emitter, "writtenValue", nodeId(emitter.filePath, child));
17786
18425
  }
18426
+ if (child.type === "nil") {
18427
+ add(emitter, "placeholderValue", nodeId(emitter.filePath, child));
18428
+ }
17787
18429
  });
17788
18430
  }
17789
18431
  function implicitReturn(body) {
@@ -17800,7 +18442,7 @@ function emitMethodFacts(emitter, method) {
17800
18442
  const declared = /* @__PURE__ */ new Set();
17801
18443
  let position = 0;
17802
18444
  for (const param of params === null ? [] : children3(params)) {
17803
- const paramName = param.type === "identifier" ? param : field(param, "name") ?? null;
18445
+ const paramName = paramNameOf(param);
17804
18446
  if (paramName !== null) {
17805
18447
  declared.add(paramName.text);
17806
18448
  const paramKey = `${funcKey}#${paramName.text}`;
@@ -17895,6 +18537,10 @@ function emitClassFacts(emitter, cls) {
17895
18537
  }
17896
18538
  continue;
17897
18539
  }
18540
+ if (NESTING_TYPES.has(statement.type)) {
18541
+ emitClassFacts(emitter, statement);
18542
+ continue;
18543
+ }
17898
18544
  if (!METHOD_TYPES.has(statement.type)) {
17899
18545
  continue;
17900
18546
  }
@@ -17918,7 +18564,7 @@ function emitValueFacts(db, filePath, root) {
17918
18564
  };
17919
18565
  const walk = (node) => {
17920
18566
  for (const child of children3(node)) {
17921
- if (child.type === "class") {
18567
+ if (NESTING_TYPES.has(child.type)) {
17922
18568
  declaresName(child, emitClassFacts(emitter, child));
17923
18569
  continue;
17924
18570
  }
@@ -17936,7 +18582,6 @@ function emitValueFacts(db, filePath, root) {
17936
18582
  }
17937
18583
 
17938
18584
  // src/facts/constants.ts
17939
- var NESTING_TYPES = /* @__PURE__ */ new Set(["class", "module"]);
17940
18585
  function children4(node) {
17941
18586
  return node.namedChildren.filter((child) => child !== null);
17942
18587
  }
@@ -18014,16 +18659,18 @@ function collectFileConstants(filePath, root) {
18014
18659
  }
18015
18660
  };
18016
18661
  walk(root, null, []);
18017
- return { definitions, references };
18662
+ return { filePath, definitions, references };
18018
18663
  }
18019
18664
  function emitConstantBindings(db, perFile) {
18020
18665
  const byName = /* @__PURE__ */ new Map();
18666
+ const fileOfDefinition = /* @__PURE__ */ new Map();
18021
18667
  const files = [...perFile];
18022
18668
  for (const file2 of files) {
18023
18669
  for (const definition of file2.definitions) {
18024
18670
  const found = byName.get(definition.qualifiedName) ?? [];
18025
18671
  found.push(definition.key);
18026
18672
  byName.set(definition.qualifiedName, found);
18673
+ fileOfDefinition.set(definition.key, file2.filePath);
18027
18674
  }
18028
18675
  }
18029
18676
  const settles = (candidate) => {
@@ -18040,6 +18687,10 @@ function emitConstantBindings(db, perFile) {
18040
18687
  const key = settles(candidate);
18041
18688
  if (key !== null) {
18042
18689
  db.add("binds", [reference.key, key]);
18690
+ const definedIn = fileOfDefinition.get(key);
18691
+ if (definedIn !== void 0 && definedIn !== file2.filePath) {
18692
+ db.add("rbConstantFrom", [file2.filePath, definedIn]);
18693
+ }
18043
18694
  break;
18044
18695
  }
18045
18696
  }
@@ -18047,10 +18698,652 @@ function emitConstantBindings(db, perFile) {
18047
18698
  }
18048
18699
  }
18049
18700
 
18701
+ // src/facts/why.ts
18702
+ var import_node_fs4 = __toESM(require("fs"), 1);
18703
+ var import_node_path5 = __toESM(require("path"), 1);
18704
+ var import_datalog8 = require("@suss/datalog");
18705
+
18706
+ // src/parser.ts
18707
+ var import_node_fs2 = __toESM(require("fs"), 1);
18708
+ var import_node_path2 = __toESM(require("path"), 1);
18709
+ var import_node_url = require("url");
18710
+ var import_web_tree_sitter = require("web-tree-sitter");
18711
+ var GRAMMAR_PATH = import_node_path2.default.join(
18712
+ import_node_path2.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl)),
18713
+ "..",
18714
+ "grammar",
18715
+ "tree-sitter-ruby.wasm"
18716
+ );
18717
+ var languagePromise = null;
18718
+ var loadedLanguage = null;
18719
+ function loadLanguage() {
18720
+ languagePromise ??= (async () => {
18721
+ if (!import_node_fs2.default.existsSync(GRAMMAR_PATH)) {
18722
+ throw new Error(
18723
+ `Ruby grammar not found at ${GRAMMAR_PATH}. See grammar/README.md.`
18724
+ );
18725
+ }
18726
+ await import_web_tree_sitter.Parser.init();
18727
+ const language = await import_web_tree_sitter.Language.load(GRAMMAR_PATH);
18728
+ loadedLanguage = language;
18729
+ return language;
18730
+ })();
18731
+ return languagePromise;
18732
+ }
18733
+ async function parseRuby(source) {
18734
+ const language = await loadLanguage();
18735
+ return parseWith(language, source);
18736
+ }
18737
+ async function preloadRubyGrammar() {
18738
+ await loadLanguage();
18739
+ }
18740
+ function parseRubySync(source) {
18741
+ if (loadedLanguage === null) {
18742
+ throw new Error(
18743
+ "the Ruby grammar has not been loaded yet; call preloadRubyGrammar first"
18744
+ );
18745
+ }
18746
+ return parseWith(loadedLanguage, source);
18747
+ }
18748
+ function parseWith(language, source) {
18749
+ const parser = new import_web_tree_sitter.Parser();
18750
+ parser.setLanguage(language);
18751
+ try {
18752
+ const tree = parser.parse(source);
18753
+ if (tree === null) {
18754
+ throw new Error("tree-sitter produced no tree for this source");
18755
+ }
18756
+ return tree;
18757
+ } finally {
18758
+ parser.delete();
18759
+ }
18760
+ }
18761
+
18762
+ // src/project.ts
18763
+ var import_node_fs3 = __toESM(require("fs"), 1);
18764
+ var import_node_path4 = __toESM(require("path"), 1);
18765
+ var import_behavioral_ir4 = require("@suss/behavioral-ir");
18766
+ var import_datalog6 = require("@suss/datalog");
18767
+ var import_extractor9 = require("@suss/extractor");
18768
+
18769
+ // src/diagnostics.ts
18770
+ var import_extractor5 = require("@suss/extractor");
18771
+ function buildRubyExtractionReport(args) {
18772
+ return (0, import_extractor5.buildUngatedExtractionReport)({
18773
+ packs: args.packs.map((pack) => ({
18774
+ name: pack.name,
18775
+ version: pack.version ?? null,
18776
+ discovers: pack.discovery.length > 0
18777
+ })),
18778
+ tallies: args.tallies,
18779
+ filesWalked: args.filesWalked,
18780
+ summaries: args.summaries
18781
+ });
18782
+ }
18783
+
18784
+ // src/facts.ts
18785
+ var import_node_path3 = __toESM(require("path"), 1);
18786
+ var import_extractor6 = require("@suss/extractor");
18787
+ function unitKey(filePath, range, name) {
18788
+ return `${filePath}:${range.start}-${range.end}#${name}`;
18789
+ }
18790
+ function emitEntryFact(db, filePath, range, name) {
18791
+ db.add("entry", [unitKey(filePath, range, name)]);
18792
+ }
18793
+ function emitRequireFacts(db, filePath, root, known) {
18794
+ (0, import_extractor6.walkDescendants)(root, null, {
18795
+ at: (node) => {
18796
+ const target = requiredRelativePath(node);
18797
+ if (target === null) {
18798
+ return;
18799
+ }
18800
+ const resolved = import_node_path3.default.resolve(
18801
+ import_node_path3.default.dirname(filePath),
18802
+ target.endsWith(".rb") ? target : `${target}.rb`
18803
+ );
18804
+ if (known.has(resolved)) {
18805
+ db.add("rbRequires", [filePath, resolved]);
18806
+ }
18807
+ },
18808
+ into: (node) => node.type === "argument_list" ? import_extractor6.SKIP_CHILDREN : null
18809
+ });
18810
+ }
18811
+ function requiredRelativePath(node) {
18812
+ if (node.type !== "call" || field(node, "receiver") !== null || field(node, "method")?.text !== "require_relative") {
18813
+ return null;
18814
+ }
18815
+ const { positional } = readCallArgs(field(node, "arguments"));
18816
+ return positional[0] === void 0 ? null : stringLiteralValue(positional[0]);
18817
+ }
18818
+
18819
+ // src/reach/closure.ts
18820
+ var import_behavioral_ir3 = require("@suss/behavioral-ir");
18821
+ var import_datalog5 = require("@suss/datalog");
18822
+ var import_extractor7 = require("@suss/extractor");
18823
+
18824
+ // src/reach/resolveCallee.ts
18825
+ var DYNAMIC_SEND_NAMES = /* @__PURE__ */ new Set(["send", "public_send", "__send__"]);
18826
+ var stop = (reason) => ({
18827
+ kind: "stopped",
18828
+ reason
18829
+ });
18830
+ function followed(target) {
18831
+ return { kind: "followed", target };
18832
+ }
18833
+ async function resolveCallee(call, site, ctx) {
18834
+ const methodName = calleeMethodName(call);
18835
+ if (methodName === void 0) {
18836
+ return stop("noDeclaration");
18837
+ }
18838
+ if (DYNAMIC_SEND_NAMES.has(methodName)) {
18839
+ return stop("unsettledValue");
18840
+ }
18841
+ const receiver = field(call, "receiver");
18842
+ if (receiver === null || receiver.type === "self") {
18843
+ return resolveImplicitSelf(methodName, site, ctx);
18844
+ }
18845
+ if (receiver.type === "identifier" && methodName === "call" && site.ownParameters.includes(receiver.text)) {
18846
+ return stop("callerSupplied");
18847
+ }
18848
+ return resolveOnReceiver(receiver, methodName, site, ctx);
18849
+ }
18850
+ async function resolveMethodReference(name, site, ctx) {
18851
+ const resolved = await resolveImplicitSelf(name, site, ctx);
18852
+ return resolved.kind === "followed" ? resolved.target : null;
18853
+ }
18854
+ function leavesRoomForATopLevelMethod(reason) {
18855
+ return reason === "noDeclaration" || reason === "outsideRun";
18856
+ }
18857
+ async function resolveImplicitSelf(methodName, site, ctx) {
18858
+ if (site.enclosingQualifiedName !== null) {
18859
+ const onClass = await methodOnAncestryOf(
18860
+ site.enclosingQualifiedName,
18861
+ methodName,
18862
+ ctx
18863
+ );
18864
+ if (onClass.kind === "followed" || !leavesRoomForATopLevelMethod(onClass.reason)) {
18865
+ return onClass;
18866
+ }
18867
+ }
18868
+ return resolveTopLevelName(methodName, ctx);
18869
+ }
18870
+ function resolveTopLevelName(methodName, ctx) {
18871
+ const candidates = ctx.topLevelMethods.get(methodName);
18872
+ if (candidates === void 0 || candidates.length === 0) {
18873
+ return stop("noDeclaration");
18874
+ }
18875
+ if (candidates.length > 1) {
18876
+ return stop("multipleSources");
18877
+ }
18878
+ return followed(candidates[0]);
18879
+ }
18880
+ async function resolveOnReceiver(receiver, methodName, site, ctx) {
18881
+ if (receiver.type === "call") {
18882
+ const innerName = calleeMethodName(receiver);
18883
+ const innerReceiver = field(receiver, "receiver");
18884
+ if (innerName === "new" && innerReceiver !== null) {
18885
+ const classRef = classRefOf(innerReceiver, site, ctx);
18886
+ return classRef === null ? stop("unsettledValue") : methodOnAncestryOf(classRef, methodName, ctx);
18887
+ }
18888
+ const root = rootConstantOf(receiver);
18889
+ if (root === null) {
18890
+ return stop("unsettledValue");
18891
+ }
18892
+ return classRefOf(root, site, ctx) === null ? stop("outsideRun") : stop("unsettledValue");
18893
+ }
18894
+ if (receiver.type === "constant" || receiver.type === "scope_resolution") {
18895
+ const classRef = classRefOf(receiver, site, ctx);
18896
+ return classRef === null ? stop("outsideRun") : singletonMethodOn(classRef, methodName, ctx);
18897
+ }
18898
+ return stop("unsettledValue");
18899
+ }
18900
+ function rootConstantOf(node) {
18901
+ if (node.type === "constant" || node.type === "scope_resolution") {
18902
+ return node;
18903
+ }
18904
+ if (node.type !== "call") {
18905
+ return null;
18906
+ }
18907
+ const receiver = field(node, "receiver");
18908
+ return receiver === null ? null : rootConstantOf(receiver);
18909
+ }
18910
+ function classRefOf(node, site, ctx) {
18911
+ if (node.type === "constant") {
18912
+ const shadow = shadowingClassFor(node, site.nesting, ctx.knownClasses);
18913
+ if (shadow !== null) {
18914
+ return shadow;
18915
+ }
18916
+ const qualified = qualifyConstantRef(node, site.nesting);
18917
+ return qualified !== null && ctx.knownClasses.has(qualified) ? qualified : null;
18918
+ }
18919
+ if (node.type === "scope_resolution") {
18920
+ const qualified = qualifyConstantRef(node, site.nesting);
18921
+ return qualified !== null && ctx.knownClasses.has(qualified) ? qualified : null;
18922
+ }
18923
+ return null;
18924
+ }
18925
+ async function methodOnAncestryOf(qualifiedName, methodName, ctx) {
18926
+ const ownBlocks = ctx.lookup.localDefinition?.(qualifiedName) ?? null;
18927
+ if (ownBlocks === null) {
18928
+ return stop("outsideRun");
18929
+ }
18930
+ const ancestry = await ancestryOf(qualifiedName, ownBlocks, ctx.lookup);
18931
+ const found = methodInAncestry(ancestry, methodName);
18932
+ if (found.type === "found") {
18933
+ return followed(reachedMethod(found.method, found.block, methodName));
18934
+ }
18935
+ if (found.type === "unsettled") {
18936
+ return stop(
18937
+ found.cause === "dynamicDefine" ? "unsettledValue" : "outsideRun"
18938
+ );
18939
+ }
18940
+ return stop("noDeclaration");
18941
+ }
18942
+ function reachedMethod(node, block, name) {
18943
+ return {
18944
+ file: block.file,
18945
+ node,
18946
+ name,
18947
+ exportPath: [block.info.qualifiedName, name],
18948
+ enclosingQualifiedName: block.info.qualifiedName
18949
+ };
18950
+ }
18951
+ function singletonMethodOn(qualifiedName, methodName, ctx) {
18952
+ const ownBlocks = ctx.lookup.localDefinition?.(qualifiedName) ?? null;
18953
+ if (ownBlocks === null) {
18954
+ return stop("outsideRun");
18955
+ }
18956
+ for (const block of ownBlocks) {
18957
+ if (block.info.bodyNode === null) {
18958
+ continue;
18959
+ }
18960
+ const found = singletonMethodsByName(block.info.bodyNode).get(methodName);
18961
+ if (found !== void 0) {
18962
+ return followed(reachedMethod(found, block, methodName));
18963
+ }
18964
+ }
18965
+ return stop("noDeclaration");
18966
+ }
18967
+
18968
+ // src/reach/closure.ts
18969
+ var REACHABLE_RULES = [
18970
+ (0, import_datalog5.rule)("reachable", [(0, import_datalog5.variable)("f")], [(0, import_datalog5.lit)("entry", (0, import_datalog5.variable)("f"))]),
18971
+ (0, import_datalog5.rule)(
18972
+ "reachable",
18973
+ [(0, import_datalog5.variable)("g")],
18974
+ [(0, import_datalog5.lit)("reachable", (0, import_datalog5.variable)("f")), (0, import_datalog5.lit)("calls", (0, import_datalog5.variable)("f"), (0, import_datalog5.variable)("g"))]
18975
+ )
18976
+ ];
18977
+ async function reachedFunctions(seeds, options) {
18978
+ const ctx = buildReachContext(options.files);
18979
+ const db = new import_datalog5.Database();
18980
+ const functionByKey = /* @__PURE__ */ new Map();
18981
+ const seedKeys = /* @__PURE__ */ new Set();
18982
+ const scanned = /* @__PURE__ */ new Set();
18983
+ const targetsByKey = /* @__PURE__ */ new Map();
18984
+ const stopsByKey = /* @__PURE__ */ new Map();
18985
+ const argTargetsByKey = /* @__PURE__ */ new Map();
18986
+ const parameterCallsByKey = /* @__PURE__ */ new Map();
18987
+ const passedPositions = /* @__PURE__ */ new Set();
18988
+ for (const seed of seeds) {
18989
+ seedKeys.add(seed.key);
18990
+ functionByKey.set(seed.key, {
18991
+ file: seed.file,
18992
+ node: seed.node,
18993
+ name: field(seed.node, "name")?.text ?? "<anon>",
18994
+ exportPath: [],
18995
+ enclosingQualifiedName: seed.enclosingQualifiedName
18996
+ });
18997
+ db.add("entry", [seed.key]);
18998
+ }
18999
+ for (; ; ) {
19000
+ (0, import_datalog5.evaluate)(db, REACHABLE_RULES);
19001
+ const frontier = db.facts("reachable").map(([key]) => String(key)).filter((key) => !scanned.has(key));
19002
+ if (frontier.length === 0) {
19003
+ break;
19004
+ }
19005
+ for (const key of frontier) {
19006
+ scanned.add(key);
19007
+ const source = functionByKey.get(key);
19008
+ if (source === void 0) {
19009
+ continue;
19010
+ }
19011
+ const scan = await scanBody(source, ctx, options.displayPathOf);
19012
+ if (scan.stops.length > 0) {
19013
+ stopsByKey.set(key, scan.stops);
19014
+ }
19015
+ targetsByKey.set(key, scan.targets);
19016
+ argTargetsByKey.set(key, scan.argTargets);
19017
+ if (scan.parameterCalls.length > 0) {
19018
+ parameterCallsByKey.set(key, scan.parameterCalls);
19019
+ }
19020
+ for (const position of scan.passedPositions) {
19021
+ passedPositions.add(position);
19022
+ }
19023
+ for (const target of scan.followed) {
19024
+ const calleeKey = keyOf(target);
19025
+ if (!functionByKey.has(calleeKey)) {
19026
+ functionByKey.set(calleeKey, target);
19027
+ }
19028
+ db.add("calls", [key, calleeKey]);
19029
+ }
19030
+ }
19031
+ }
19032
+ const summaries = [];
19033
+ const summariesByKey = /* @__PURE__ */ new Map();
19034
+ for (const [keyAtom] of db.facts("reachable")) {
19035
+ const key = String(keyAtom);
19036
+ const target = functionByKey.get(key);
19037
+ if (seedKeys.has(key) || target === void 0) {
19038
+ continue;
19039
+ }
19040
+ const summary = (0, import_extractor7.assembleSummary)(libraryUnit(target, options), {
19041
+ gapHandling: "permissive"
19042
+ });
19043
+ summary.confidence = { source: "inferred_static", level: "low" };
19044
+ summary.gaps.push(...(stopsByKey.get(key) ?? []).map(import_behavioral_ir3.unfollowedCallGap));
19045
+ (0, import_behavioral_ir3.placeCalls)(summary, targetsByKey.get(key));
19046
+ (0, import_behavioral_ir3.placeArgTargets)(summary, argTargetsByKey.get(key));
19047
+ (0, import_behavioral_ir3.placeCalleeParameters)(summary, parameterCallsByKey.get(key));
19048
+ summariesByKey.set(key, [summary]);
19049
+ summaries.push(summary);
19050
+ }
19051
+ (0, import_behavioral_ir3.recordParameterGaps)(parameterCallsByKey, summariesByKey, passedPositions);
19052
+ return {
19053
+ summaries,
19054
+ targetsByKey,
19055
+ stopsByKey,
19056
+ argTargetsByKey,
19057
+ parameterCallsByKey,
19058
+ passedPositions
19059
+ };
19060
+ }
19061
+ function keyOf(target) {
19062
+ return nodeId(target.file, target.node);
19063
+ }
19064
+ function buildReachContext(files) {
19065
+ const blocksByQualifiedName = /* @__PURE__ */ new Map();
19066
+ const classes = [];
19067
+ for (const { file: file2, root } of files) {
19068
+ walkDefinitions(root, (info) => classes.push({ file: file2, info }));
19069
+ }
19070
+ const knownClasses = new Set(classes.map(({ info }) => info.qualifiedName));
19071
+ for (const { file: file2, info } of classes) {
19072
+ const list = blocksByQualifiedName.get(info.qualifiedName) ?? [];
19073
+ list.push({ info, knownClasses, file: file2 });
19074
+ blocksByQualifiedName.set(info.qualifiedName, list);
19075
+ }
19076
+ const topLevelMethods = /* @__PURE__ */ new Map();
19077
+ for (const { file: file2, root } of files) {
19078
+ for (const method of topLevelMethodNodes(root)) {
19079
+ const name = field(method, "name")?.text;
19080
+ if (name === void 0) {
19081
+ continue;
19082
+ }
19083
+ const list = topLevelMethods.get(name) ?? [];
19084
+ list.push({
19085
+ file: file2,
19086
+ node: method,
19087
+ name,
19088
+ exportPath: [name],
19089
+ enclosingQualifiedName: null
19090
+ });
19091
+ topLevelMethods.set(name, list);
19092
+ }
19093
+ }
19094
+ const lookup = {
19095
+ root: "",
19096
+ pathConvention: "railsUnderscore",
19097
+ ancestryRootClassNames: [],
19098
+ // Every class the run defines is already in `blocksByQualifiedName`
19099
+ // above, so a name that misses there is outside the run and this
19100
+ // never has a file on disk to read.
19101
+ parsedFile: async () => null,
19102
+ localDefinition: (name) => blocksByQualifiedName.get(name) ?? null
19103
+ };
19104
+ return { lookup, knownClasses, topLevelMethods };
19105
+ }
19106
+ function topLevelMethodNodes(root, found = []) {
19107
+ for (const child of bodyStatements(root)) {
19108
+ if (child.type === "method") {
19109
+ found.push(child);
19110
+ continue;
19111
+ }
19112
+ if (OWN_BODY_TYPES.has(child.type)) {
19113
+ continue;
19114
+ }
19115
+ topLevelMethodNodes(child, found);
19116
+ }
19117
+ return found;
19118
+ }
19119
+ function nestingOf(qualifiedName) {
19120
+ const parts = qualifiedName.split("::");
19121
+ const out = [];
19122
+ for (let depth = parts.length; depth >= 1; depth--) {
19123
+ out.push(parts.slice(0, depth).join("::"));
19124
+ }
19125
+ return out;
19126
+ }
19127
+ var EMPTY_SCAN = {
19128
+ followed: [],
19129
+ stops: [],
19130
+ targets: /* @__PURE__ */ new Map(),
19131
+ argTargets: /* @__PURE__ */ new Map(),
19132
+ parameterCalls: [],
19133
+ passedPositions: /* @__PURE__ */ new Set()
19134
+ };
19135
+ function methodReferenceSymbol(node) {
19136
+ const target = node.type === "block_argument" ? bodyStatements(node)[0] : node;
19137
+ if (target === void 0 || target.type !== "call" || field(target, "receiver") !== null || field(target, "method")?.text !== "method") {
19138
+ return null;
19139
+ }
19140
+ const args = field(target, "arguments");
19141
+ const argChildren = args === null ? [] : bodyStatements(args);
19142
+ return argChildren.length === 1 && argChildren[0]?.type === "simple_symbol" ? argChildren[0] : null;
19143
+ }
19144
+ async function scanBody(source, ctx, displayPathOf) {
19145
+ const body = field(source.node, "body");
19146
+ if (body === null) {
19147
+ return EMPTY_SCAN;
19148
+ }
19149
+ const calls = withoutChainLinks(bodyCalls(body));
19150
+ const ownParameters = positionalParameters(source.node).map((p) => p.name);
19151
+ const site = {
19152
+ enclosingQualifiedName: source.enclosingQualifiedName,
19153
+ nesting: source.enclosingQualifiedName === null ? [] : nestingOf(source.enclosingQualifiedName),
19154
+ ownParameters
19155
+ };
19156
+ const followed2 = [];
19157
+ const stops = [];
19158
+ const placements = new import_behavioral_ir3.TargetPlacements();
19159
+ const parameterCalls = [];
19160
+ const passedPositions = /* @__PURE__ */ new Set();
19161
+ const seen = /* @__PURE__ */ new Set();
19162
+ const parameterCallsSeen = /* @__PURE__ */ new Set();
19163
+ const recordPassedArgs = async (call, callee, calleeKey) => {
19164
+ const args = field(call, "arguments");
19165
+ if (args === null) {
19166
+ return;
19167
+ }
19168
+ const argNodes = bodyStatements(args);
19169
+ for (let position = 0; position < argNodes.length; position += 1) {
19170
+ const symbol2 = methodReferenceSymbol(argNodes[position]);
19171
+ if (symbol2 === null) {
19172
+ continue;
19173
+ }
19174
+ const resolved = await resolveMethodReference(
19175
+ symbol2.text.slice(1),
19176
+ site,
19177
+ ctx
19178
+ );
19179
+ if (resolved === null) {
19180
+ continue;
19181
+ }
19182
+ const key = keyOf(resolved);
19183
+ if (!seen.has(key)) {
19184
+ seen.add(key);
19185
+ followed2.push(resolved);
19186
+ }
19187
+ placements.placeArg(callee, position, {
19188
+ file: displayPathOf(resolved.file),
19189
+ span: spanOf(resolved.node)
19190
+ });
19191
+ if (calleeKey !== null) {
19192
+ passedPositions.add(`${calleeKey}#${position}`);
19193
+ }
19194
+ }
19195
+ };
19196
+ for (const call of calls) {
19197
+ const callee = calleeText(call);
19198
+ const outcome = await resolveCallee(call, site, ctx);
19199
+ const placed = outcome.kind === "followed" ? {
19200
+ file: displayPathOf(outcome.target.file),
19201
+ span: spanOf(outcome.target.node)
19202
+ } : outcome.reason === "noDeclaration" ? null : { file: displayPathOf(source.file), span: spanOf(call) };
19203
+ placements.place(callee, placed);
19204
+ await recordPassedArgs(
19205
+ call,
19206
+ callee,
19207
+ outcome.kind === "followed" ? keyOf(outcome.target) : null
19208
+ );
19209
+ if (outcome.kind === "stopped") {
19210
+ const stopKey = `${outcome.reason}:${callee}`;
19211
+ if (!seen.has(stopKey) && (0, import_behavioral_ir3.worthRecording)(outcome.reason)) {
19212
+ seen.add(stopKey);
19213
+ stops.push({ callee, reason: outcome.reason });
19214
+ }
19215
+ if (outcome.reason === "callerSupplied" && !parameterCallsSeen.has(callee)) {
19216
+ const receiverName = field(call, "receiver")?.text;
19217
+ const parameterIndex = receiverName === void 0 ? -1 : ownParameters.indexOf(receiverName);
19218
+ if (parameterIndex !== -1) {
19219
+ parameterCallsSeen.add(callee);
19220
+ parameterCalls.push({ callee, parameterIndex });
19221
+ }
19222
+ }
19223
+ continue;
19224
+ }
19225
+ const key = keyOf(outcome.target);
19226
+ if (!seen.has(key)) {
19227
+ seen.add(key);
19228
+ followed2.push(outcome.target);
19229
+ }
19230
+ }
19231
+ return {
19232
+ followed: followed2,
19233
+ stops,
19234
+ targets: placements.targets,
19235
+ argTargets: placements.argTargets,
19236
+ parameterCalls,
19237
+ passedPositions
19238
+ };
19239
+ }
19240
+ function libraryUnit(target, options) {
19241
+ const { file: file2, node, name, exportPath } = target;
19242
+ const body = bodyOfMethod(node, options.storage);
19243
+ const range = rangeOf(node);
19244
+ return {
19245
+ identity: {
19246
+ name,
19247
+ nameKind: "binding",
19248
+ kind: "library",
19249
+ file: options.displayPathOf(file2),
19250
+ range,
19251
+ span: spanOf(node),
19252
+ exportName: exportPath[0] ?? name,
19253
+ exportPath
19254
+ },
19255
+ boundaryBinding: (0, import_behavioral_ir3.functionCallBinding)({
19256
+ transport: "in-process",
19257
+ recognition: "reachable"
19258
+ }),
19259
+ parameters: positionalParameters(node),
19260
+ branches: [
19261
+ {
19262
+ conditions: [],
19263
+ terminal: {
19264
+ kind: "return",
19265
+ statusCode: null,
19266
+ body: null,
19267
+ exceptionType: null,
19268
+ message: null,
19269
+ component: null,
19270
+ renderTree: null,
19271
+ delegateTarget: null,
19272
+ emitEvent: null,
19273
+ location: range
19274
+ },
19275
+ effects: body.effects ?? [],
19276
+ ...body.extraEffects === void 0 ? {} : { extraEffects: body.extraEffects },
19277
+ location: range,
19278
+ isDefault: true
19279
+ }
19280
+ ],
19281
+ bodyContent: body.bodyContent ?? "absent",
19282
+ dependencyCalls: [],
19283
+ declaredContract: null
19284
+ };
19285
+ }
19286
+ function positionalParameters(node) {
19287
+ const parameters = field(node, "parameters");
19288
+ if (parameters === null) {
19289
+ return [];
19290
+ }
19291
+ const out = [];
19292
+ let position = 0;
19293
+ for (const param of bodyStatements(parameters)) {
19294
+ const name = parameterName(param);
19295
+ if (name === null) {
19296
+ continue;
19297
+ }
19298
+ out.push({ name, position, role: name, typeText: null });
19299
+ position += 1;
19300
+ }
19301
+ return out;
19302
+ }
19303
+ function parameterName(param) {
19304
+ if (param.type === "identifier") {
19305
+ return param.text;
19306
+ }
19307
+ const named = field(param, "name");
19308
+ return named !== null && named.type === "identifier" ? named.text : null;
19309
+ }
19310
+
19311
+ // src/version.ts
19312
+ var import_extractor8 = require("@suss/extractor");
19313
+ var ADAPTER_VERSION = "0.1.0";
19314
+ var adapterStamp = (0, import_extractor8.createAdapterStamp)({
19315
+ moduleUrl: importMetaUrl,
19316
+ version: ADAPTER_VERSION
19317
+ });
19318
+
18050
19319
  // src/project.ts
18051
19320
  async function extractRubyProject(options) {
18052
- const db = new import_datalog4.Database();
19321
+ const timer = options.onTiming !== void 0 ? (0, import_extractor9.createTimer)() : (0, import_extractor9.noopTimer)();
19322
+ const cacheDir = adapterStamp.declineWhenRunFromSource(
19323
+ options.cacheDir === null ? null : options.cacheDir ?? (options.projectRoot !== void 0 ? import_node_path4.default.join(options.projectRoot, ".suss", "cache") : null)
19324
+ );
19325
+ const extractionCache = (0, import_extractor9.createCacheLayer)(cacheDir);
19326
+ const packsDigest = adapterStamp.packsDigest(
19327
+ options.packs.map(
19328
+ (pack) => pack.version !== void 0 ? { name: pack.name, version: pack.version } : { name: pack.name }
19329
+ )
19330
+ );
19331
+ const cacheInput = {
19332
+ files: cacheDir === null ? [] : options.files,
19333
+ adapterPacksDigest: cacheDir === null ? packsDigest : (0, import_extractor9.runDigest)(packsDigest, options.packs, options.files)
19334
+ };
19335
+ const lookup = await timer.timeAsync(
19336
+ "cache.lookup",
19337
+ () => extractionCache.lookup(cacheInput)
19338
+ );
19339
+ options.onCacheDiagnostic?.(lookup.diagnostic);
19340
+ if (lookup.kind === "hit") {
19341
+ options.onTiming?.(timer.report());
19342
+ return { summaries: lookup.summaries, facts: new import_datalog6.Database() };
19343
+ }
19344
+ const db = new import_datalog6.Database();
18053
19345
  const summaries = [];
19346
+ const tallies = (0, import_extractor5.createPackTallies)(options.packs);
18054
19347
  const constants = [];
18055
19348
  const cache = createFileCache(
18056
19349
  (source) => parseRuby(source).then((tree) => tree.rootNode),
@@ -18058,33 +19351,178 @@ async function extractRubyProject(options) {
18058
19351
  );
18059
19352
  const parsed = [];
18060
19353
  for (const file2 of options.files) {
18061
- const root = await cache.get(file2);
18062
- if (root === null) {
18063
- continue;
18064
- }
18065
- parsed.push({ file: file2, root });
18066
- emitValueFacts(db, file2, root);
18067
- constants.push(collectFileConstants(file2, root));
19354
+ await timer.timeAsync("parse", async () => {
19355
+ const root = await cache.get(file2);
19356
+ if (root === null) {
19357
+ return;
19358
+ }
19359
+ parsed.push({ file: file2, root });
19360
+ emitValueFacts(db, file2, root);
19361
+ constants.push(collectFileConstants(file2, root));
19362
+ });
18068
19363
  }
18069
- emitConstantBindings(db, constants);
19364
+ timer.time("discover", () => {
19365
+ emitConstantBindings(db, constants);
19366
+ const known = new Set(parsed.map(({ file: file2 }) => file2));
19367
+ for (const { file: file2, root } of parsed) {
19368
+ emitRequireFacts(db, file2, root, known);
19369
+ }
19370
+ });
18070
19371
  const storagePatterns = options.packs.flatMap((pack) => pack.storage ?? []);
19372
+ const displayPathOf = (file2) => options.workspaceRoot !== void 0 ? import_node_path4.default.relative(options.workspaceRoot, file2) : file2;
19373
+ const seeds = [];
19374
+ const summariesBySeed = /* @__PURE__ */ new Map();
18071
19375
  for (const { file: file2, root } of parsed) {
18072
- const displayPath = options.workspaceRoot !== void 0 ? import_node_path3.default.relative(options.workspaceRoot, file2) : file2;
18073
- const rawUnits = await discoverUnits(root, {
18074
- packs: options.packs,
18075
- filePath: displayPath,
18076
- cache,
18077
- ...storagePatterns.length > 0 ? { storage: { facts: db, patterns: storagePatterns } } : {}
18078
- });
19376
+ const displayPath = displayPathOf(file2);
19377
+ const seedByRaw = /* @__PURE__ */ new Map();
19378
+ const rawUnits = await timer.timeAsync(
19379
+ "discover",
19380
+ () => discoverUnits(root, {
19381
+ packs: options.packs,
19382
+ filePath: displayPath,
19383
+ absoluteFile: file2,
19384
+ cache,
19385
+ ...storagePatterns.length > 0 ? { storage: { facts: db, patterns: storagePatterns } } : {},
19386
+ onReachSeed: (raw, seed) => seedByRaw.set(raw, seed)
19387
+ })
19388
+ );
18079
19389
  for (const raw of rawUnits) {
18080
- const summary = (0, import_extractor4.assembleSummary)(raw, { gapHandling: "permissive" });
19390
+ const summary = timer.time(
19391
+ "summarize",
19392
+ () => (0, import_extractor9.assembleSummary)(raw, { gapHandling: "permissive" })
19393
+ );
18081
19394
  summary.confidence = { source: "inferred_static", level: "low" };
18082
19395
  summaries.push(summary);
18083
19396
  emitEntryFact(db, file2, raw.identity.range, raw.identity.name);
19397
+ (0, import_extractor5.tallyUnit)(tallies, raw.boundaryBinding?.recognition);
19398
+ const seed = seedByRaw.get(raw);
19399
+ if (seed === void 0) {
19400
+ continue;
19401
+ }
19402
+ const key = nodeId(seed.file, seed.node);
19403
+ const sharing = summariesBySeed.get(key);
19404
+ if (sharing === void 0) {
19405
+ seeds.push({
19406
+ key,
19407
+ file: seed.file,
19408
+ node: seed.node,
19409
+ enclosingQualifiedName: seed.enclosingQualifiedName
19410
+ });
19411
+ summariesBySeed.set(key, [summary]);
19412
+ } else {
19413
+ sharing.push(summary);
19414
+ }
19415
+ }
19416
+ const loadTimeReads = timer.time("discover", () => envReadEffects(root));
19417
+ if (loadTimeReads.length > 0) {
19418
+ const summary = timer.time(
19419
+ "summarize",
19420
+ () => (0, import_extractor9.assembleSummary)(
19421
+ (0, import_extractor9.moduleInitStructure)({
19422
+ name: import_node_path4.default.basename(displayPath),
19423
+ file: displayPath,
19424
+ range: rangeOf(root),
19425
+ effects: loadTimeReads
19426
+ }),
19427
+ { gapHandling: "permissive" }
19428
+ )
19429
+ );
19430
+ summary.confidence = { source: "inferred_static", level: "low" };
19431
+ summaries.push(summary);
18084
19432
  }
18085
19433
  }
19434
+ for (const pack of options.packs) {
19435
+ for (const pattern of pack.discovery) {
19436
+ if (pattern.type !== "controllerActions") {
19437
+ continue;
19438
+ }
19439
+ const gaps = pattern.routingGaps?.() ?? [];
19440
+ if (gaps.length === 0) {
19441
+ continue;
19442
+ }
19443
+ const summary = timer.time(
19444
+ "summarize",
19445
+ () => (0, import_extractor9.assembleSummary)(routingGapUnit(pattern, gaps), {
19446
+ gapHandling: "permissive"
19447
+ })
19448
+ );
19449
+ summary.confidence = { source: "inferred_static", level: "low" };
19450
+ summaries.push(summary);
19451
+ }
19452
+ }
19453
+ const reached = await timer.timeAsync(
19454
+ "summarize",
19455
+ () => reachedFunctions(seeds, {
19456
+ files: parsed,
19457
+ displayPathOf,
19458
+ ...storagePatterns.length > 0 ? { storage: { facts: db, patterns: storagePatterns } } : {}
19459
+ })
19460
+ );
19461
+ for (const [key, owners] of summariesBySeed) {
19462
+ for (const summary of owners) {
19463
+ summary.gaps.push(
19464
+ ...(reached.stopsByKey.get(key) ?? []).map(import_behavioral_ir4.unfollowedCallGap)
19465
+ );
19466
+ (0, import_behavioral_ir4.placeCalls)(summary, reached.targetsByKey.get(key));
19467
+ (0, import_behavioral_ir4.placeArgTargets)(summary, reached.argTargetsByKey.get(key));
19468
+ (0, import_behavioral_ir4.placeCalleeParameters)(summary, reached.parameterCallsByKey.get(key));
19469
+ }
19470
+ }
19471
+ (0, import_behavioral_ir4.recordParameterGaps)(
19472
+ reached.parameterCallsByKey,
19473
+ summariesBySeed,
19474
+ reached.passedPositions
19475
+ );
19476
+ summaries.push(...reached.summaries);
19477
+ const dependencies = fileDependenciesOf(db, displayPathOf);
19478
+ (0, import_extractor9.stampModuleImports)(summaries, (file2) => dependencies.get(file2) ?? []);
19479
+ const idRoot = options.projectRoot ?? options.workspaceRoot;
19480
+ for (const summary of summaries) {
19481
+ const absoluteFile = options.workspaceRoot === void 0 ? summary.location.file : import_node_path4.default.resolve(options.workspaceRoot, summary.location.file);
19482
+ summary.identity.id = (0, import_behavioral_ir4.summaryIdFromParts)({
19483
+ workspace: void 0,
19484
+ file: idRoot === void 0 ? absoluteFile : import_node_path4.default.relative(idRoot, absoluteFile),
19485
+ name: summary.identity.name,
19486
+ exportPath: summary.identity.exportPath
19487
+ });
19488
+ }
19489
+ (0, import_behavioral_ir4.disambiguateSummaryIds)(summaries);
19490
+ (0, import_behavioral_ir4.linkCallsToSummaries)(summaries);
19491
+ await timer.timeAsync("cache.write", async () => {
19492
+ if (cacheDir === null || summaries.length === 0) {
19493
+ return;
19494
+ }
19495
+ try {
19496
+ await extractionCache.write(cacheInput, summaries);
19497
+ } catch {
19498
+ }
19499
+ });
19500
+ options.onExtractionReport?.(
19501
+ buildRubyExtractionReport({
19502
+ packs: options.packs,
19503
+ tallies,
19504
+ filesWalked: options.files.length,
19505
+ summaries
19506
+ })
19507
+ );
19508
+ options.onTiming?.(timer.report());
18086
19509
  return { summaries, facts: db };
18087
19510
  }
19511
+ function fileDependenciesOf(db, displayPathOf) {
19512
+ const byFile = /* @__PURE__ */ new Map();
19513
+ for (const relation of ["rbRequires", "rbConstantFrom"]) {
19514
+ for (const [from, to] of db.facts(relation)) {
19515
+ if (typeof from !== "string" || typeof to !== "string") {
19516
+ continue;
19517
+ }
19518
+ const key = displayPathOf(from);
19519
+ const seen = byFile.get(key) ?? [];
19520
+ seen.push(displayPathOf(to));
19521
+ byFile.set(key, seen);
19522
+ }
19523
+ }
19524
+ return byFile;
19525
+ }
18088
19526
  var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set(["vendor", "node_modules", "tmp", ".git"]);
18089
19527
  function findRubyFiles(root) {
18090
19528
  const found = [];
@@ -18092,33 +19530,300 @@ function findRubyFiles(root) {
18092
19530
  for (const entry of import_node_fs3.default.readdirSync(dir, { withFileTypes: true })) {
18093
19531
  if (entry.isDirectory()) {
18094
19532
  if (!SKIPPED_DIRECTORIES.has(entry.name)) {
18095
- walk(import_node_path3.default.join(dir, entry.name));
19533
+ walk(import_node_path4.default.join(dir, entry.name));
18096
19534
  }
18097
19535
  continue;
18098
19536
  }
18099
19537
  if (entry.isFile() && entry.name.endsWith(".rb")) {
18100
- found.push(import_node_path3.default.join(dir, entry.name));
19538
+ found.push(import_node_path4.default.join(dir, entry.name));
18101
19539
  }
18102
19540
  }
18103
19541
  };
18104
19542
  walk(root);
18105
19543
  return found.sort();
18106
19544
  }
19545
+
19546
+ // src/facts/resolve.ts
19547
+ var import_datalog7 = require("@suss/datalog");
19548
+ var RUBY_RULES = [
19549
+ // `Loader.new` makes one of the class, which the shared rules already say
19550
+ // about calling a class. Ruby writes it as a method read off the constant
19551
+ // instead, so the read is what steps to the class here.
19552
+ (0, import_datalog7.rule)(
19553
+ "stepsTo",
19554
+ [(0, import_datalog7.variable)("x"), (0, import_datalog7.variable)("cls"), VALUE_STEP],
19555
+ [
19556
+ (0, import_datalog7.lit)("readsProperty", (0, import_datalog7.variable)("x"), (0, import_datalog7.variable)("o"), (0, import_datalog7.constant)("new")),
19557
+ (0, import_datalog7.lit)("comesTo", (0, import_datalog7.variable)("o"), (0, import_datalog7.variable)("cls")),
19558
+ (0, import_datalog7.lit)("objectValue", (0, import_datalog7.variable)("cls"))
19559
+ ]
19560
+ )
19561
+ ];
19562
+ var RESOLUTION_PROGRAM = (0, import_datalog7.deriveOnDemand)(
19563
+ [...RESOLUTION_RULES, ...RUBY_RULES, ...RESOLUTION_QUESTIONS],
19564
+ ANSWER_RELATIONS
19565
+ );
19566
+
19567
+ // src/facts/why.ts
19568
+ var WITNESS_RULES = [...RESOLUTION_RULES, ...RUBY_RULES];
19569
+ var METHOD_TYPES2 = /* @__PURE__ */ new Set(["method", "singleton_method"]);
19570
+ function namedChildrenOf(node) {
19571
+ return node.namedChildren.filter((child) => child !== null);
19572
+ }
19573
+ function enclosingMethod(node) {
19574
+ let current = node.parent;
19575
+ while (current !== null) {
19576
+ if (METHOD_TYPES2.has(current.type)) {
19577
+ return current;
19578
+ }
19579
+ current = current.parent;
19580
+ }
19581
+ return null;
19582
+ }
19583
+ function indexFile(file2, root, locations) {
19584
+ const walk = (node) => {
19585
+ locations.set(nodeId(file2, node), { file: file2, node });
19586
+ if (node.type === "constant") {
19587
+ locations.set(`${file2}#${node.text}`, { file: file2, node });
19588
+ }
19589
+ if (node.type === "assignment") {
19590
+ const left = field(node, "left");
19591
+ if (left !== null && left.type === "identifier") {
19592
+ locations.set(`${file2}#${left.text}`, { file: file2, node: left });
19593
+ }
19594
+ }
19595
+ for (const child of namedChildrenOf(node)) {
19596
+ walk(child);
19597
+ }
19598
+ };
19599
+ walk(root);
19600
+ }
19601
+ function displayNameOf(node) {
19602
+ if (node.type === "identifier" || node.type === "constant") {
19603
+ return node.text;
19604
+ }
19605
+ if (node.type === "method" || node.type === "singleton_method") {
19606
+ return field(node, "name")?.text ?? node.text;
19607
+ }
19608
+ if (node.type === "class" || node.type === "module") {
19609
+ return field(node, "name")?.text ?? node.text;
19610
+ }
19611
+ const text = node.text.split("\n")[0].trim();
19612
+ return text.length > 40 ? `${text.slice(0, 40)}...` : text;
19613
+ }
19614
+ function width(node) {
19615
+ return node.endIndex - node.startIndex;
19616
+ }
19617
+ var RubyWhySession = class {
19618
+ root;
19619
+ db = new import_datalog8.Database();
19620
+ locations = /* @__PURE__ */ new Map();
19621
+ trees = /* @__PURE__ */ new Map();
19622
+ constructor(options) {
19623
+ this.root = import_node_path5.default.resolve(options.dir);
19624
+ const constants = [];
19625
+ for (const file2 of findRubyFiles(this.root)) {
19626
+ const source = import_node_fs4.default.readFileSync(file2, "utf8");
19627
+ const root = parseRubySync(source).rootNode;
19628
+ this.trees.set(file2, root);
19629
+ emitValueFacts(this.db, file2, root);
19630
+ constants.push(collectFileConstants(file2, root));
19631
+ indexFile(file2, root, this.locations);
19632
+ }
19633
+ emitConstantBindings(this.db, constants);
19634
+ }
19635
+ /**
19636
+ * The smallest expression on `line` of `file` whose text is exactly
19637
+ * `text`, or null.
19638
+ */
19639
+ findExpression(file2, line, text) {
19640
+ const root = this.rootOf(file2);
19641
+ if (root === null) {
19642
+ return null;
19643
+ }
19644
+ let found = null;
19645
+ const visit = (node) => {
19646
+ if (node.startPosition.row + 1 === line && node.text === text) {
19647
+ if (found === null || width(node) <= width(found)) {
19648
+ found = node;
19649
+ }
19650
+ }
19651
+ for (const child of namedChildrenOf(node)) {
19652
+ visit(child);
19653
+ }
19654
+ };
19655
+ visit(root);
19656
+ return found === null ? null : { file: this.pathOf(file2), node: found };
19657
+ }
19658
+ /**
19659
+ * The callee of the call written as `calleeText` between `startLine`
19660
+ * and `endLine` of `file`, or null.
19661
+ */
19662
+ findCallee(file2, startLine, endLine, calleeText2) {
19663
+ const root = this.rootOf(file2);
19664
+ if (root === null) {
19665
+ return null;
19666
+ }
19667
+ let found = null;
19668
+ const visit = (node) => {
19669
+ if (node.type === "call") {
19670
+ const line = node.startPosition.row + 1;
19671
+ const callee = field(node, "method");
19672
+ if (line >= startLine && line <= endLine && callee !== null && callee.text === calleeText2) {
19673
+ found = callee;
19674
+ }
19675
+ }
19676
+ for (const child of namedChildrenOf(node)) {
19677
+ visit(child);
19678
+ }
19679
+ };
19680
+ visit(root);
19681
+ return found === null ? null : { file: this.pathOf(file2), node: found };
19682
+ }
19683
+ /**
19684
+ * Why `value` resolves to what it does: the witness proof, flattened
19685
+ * to the chain and rendered. Null when the value does not resolve,
19686
+ * which the caller says in its own words.
19687
+ */
19688
+ explain(value, options = {}) {
19689
+ return explainResolvedKey({
19690
+ db: this.db,
19691
+ rules: WITNESS_RULES,
19692
+ key: readKey(value.file, value.node, enclosingMethod(value.node)),
19693
+ locate: (key) => this.locate(key),
19694
+ displayPath: (key) => this.displayPath(key),
19695
+ ...options
19696
+ });
19697
+ }
19698
+ locate(key) {
19699
+ const located = this.locations.get(key);
19700
+ if (located === void 0) {
19701
+ return null;
19702
+ }
19703
+ return {
19704
+ name: displayNameOf(located.node),
19705
+ file: this.displayPath(located.file),
19706
+ line: located.node.startPosition.row + 1
19707
+ };
19708
+ }
19709
+ rootOf(file2) {
19710
+ return this.trees.get(this.pathOf(file2)) ?? null;
19711
+ }
19712
+ pathOf(file2) {
19713
+ return import_node_path5.default.isAbsolute(file2) ? file2 : import_node_path5.default.resolve(this.root, file2);
19714
+ }
19715
+ /** A file path said relative to the root, or as given when it is outside the root. */
19716
+ displayPath(key) {
19717
+ if (key.startsWith(this.root)) {
19718
+ return import_node_path5.default.relative(this.root, key);
19719
+ }
19720
+ return key;
19721
+ }
19722
+ };
19723
+
19724
+ // src/stubEvidence.ts
19725
+ var import_node_fs5 = __toESM(require("fs"), 1);
19726
+ var import_node_path6 = __toESM(require("path"), 1);
19727
+ var import_extractor10 = require("@suss/extractor");
19728
+ function bareLetters(name) {
19729
+ return name.replaceAll(/[-_]/g, "").toLowerCase();
19730
+ }
19731
+ function isSpelledFrom(qualifiedName, packageName) {
19732
+ const wanted = bareLetters(packageName);
19733
+ const constants = qualifiedName.split("::");
19734
+ return constants.some(
19735
+ (_, end) => bareLetters(constants.slice(0, end + 1).join("")) === wanted
19736
+ );
19737
+ }
19738
+ function isPackageRequire(target, packageName) {
19739
+ const bundlerName = packageName.replaceAll("-", "_");
19740
+ return target === bundlerName || target.startsWith(`${bundlerName}/`) || target === packageName || target.startsWith(`${packageName}/`);
19741
+ }
19742
+ function requireTarget(node) {
19743
+ if (node.type !== "call" || field(node, "receiver") !== null || field(node, "method")?.text !== "require" && field(node, "method")?.text !== "require_relative") {
19744
+ return null;
19745
+ }
19746
+ const { positional } = readCallArgs(field(node, "arguments"));
19747
+ return positional[0] === void 0 ? null : stringLiteralValue(positional[0]);
19748
+ }
19749
+ function requireSitesIn(root, file2) {
19750
+ const found = [];
19751
+ (0, import_extractor10.walkDescendants)(root, null, {
19752
+ at: (node) => {
19753
+ const target = requireTarget(node);
19754
+ if (target !== null) {
19755
+ found.push({ target, file: file2, line: rangeOf(node).start });
19756
+ }
19757
+ },
19758
+ into: (node) => node.type === "argument_list" ? import_extractor10.SKIP_CHILDREN : null
19759
+ });
19760
+ return found;
19761
+ }
19762
+ function extendsSitesIn(root, file2, packageName) {
19763
+ const found = [];
19764
+ walkClasses(root, (info) => {
19765
+ if (info.superclassQualifiedName !== null && isSpelledFrom(info.superclassQualifiedName, packageName)) {
19766
+ found.push({
19767
+ className: info.qualifiedName,
19768
+ superclassName: info.superclassQualifiedName,
19769
+ file: file2,
19770
+ line: rangeOf(info.node).start
19771
+ });
19772
+ }
19773
+ });
19774
+ return found;
19775
+ }
19776
+ async function rubyStubEvidence(options) {
19777
+ const requires = [];
19778
+ const extendsSites = [];
19779
+ for (const file2 of findRubyFiles(options.directory)) {
19780
+ const source = import_node_fs5.default.readFileSync(file2, "utf8");
19781
+ const tree = await parseRuby(source);
19782
+ const displayPath = import_node_path6.default.relative(options.directory, file2);
19783
+ for (const site of requireSitesIn(tree.rootNode, displayPath)) {
19784
+ if (isPackageRequire(site.target, options.packageName)) {
19785
+ requires.push(site);
19786
+ }
19787
+ }
19788
+ extendsSites.push(
19789
+ ...extendsSitesIn(tree.rootNode, displayPath, options.packageName)
19790
+ );
19791
+ }
19792
+ return { requires, extendsSites };
19793
+ }
18107
19794
  // Annotate the CommonJS export names for ESM import in node:
18108
19795
  0 && (module.exports = {
19796
+ ADAPTER_VERSION,
19797
+ RubyWhySession,
18109
19798
  ancestryOf,
19799
+ bodyStatements,
19800
+ booleanLiteralValue,
19801
+ collectFileConstants,
18110
19802
  createFileCache,
18111
19803
  discoverUnits,
19804
+ emitConstantBindings,
18112
19805
  emitEntryFact,
19806
+ emitValueFacts,
18113
19807
  extractRubyProject,
19808
+ field,
18114
19809
  findRubyFiles,
18115
19810
  graphqlTypeNameFromQualified,
19811
+ hashKeySymbolName,
18116
19812
  inheritedStatements,
18117
19813
  methodInAncestry,
19814
+ nodeId,
18118
19815
  parseRuby,
19816
+ parseRubySync,
19817
+ preloadRubyGrammar,
18119
19818
  qualifyConstantRef,
18120
19819
  reachDefinition,
19820
+ readCallArgs,
19821
+ readKey,
18121
19822
  resolveConstantFile,
19823
+ rubyStubEvidence,
19824
+ runStatements,
19825
+ stringLiteralValue,
19826
+ symbolValue,
18122
19827
  typeShapeFromNode,
18123
19828
  underscoreConstantPath,
18124
19829
  unitKey,