@suss/adapter-ruby 0.21.0 → 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
  }
@@ -15319,7 +15540,7 @@ function date4(params) {
15319
15540
  // ../../../node_modules/zod/v4/classic/external.js
15320
15541
  config(en_default());
15321
15542
 
15322
- // ../../ir-core/dist/chunk-QHFMZPEG.js
15543
+ // ../../ir-core/dist/chunk-PPQWK62O.js
15323
15544
  function gqlIdentityKey(typeName, fieldName) {
15324
15545
  return `gql:${typeName}.${fieldName}`;
15325
15546
  }
@@ -15605,6 +15826,42 @@ var metricSemantics = defineBoundarySemantics({
15605
15826
  }
15606
15827
  }
15607
15828
  });
15829
+ var HOLE_SPLIT = /(\{[^}]*\})/;
15830
+ function isHole(piece) {
15831
+ return piece.startsWith("{") && piece.endsWith("}");
15832
+ }
15833
+ function parseBoundaryName(name) {
15834
+ const parts = name.split(HOLE_SPLIT).filter((piece) => piece !== "").map(
15835
+ (piece) => isHole(piece) ? { type: "hole", label: piece.slice(1, -1) } : { type: "text", text: piece }
15836
+ );
15837
+ const only = parts.length === 1 ? parts[0] : void 0;
15838
+ if (only !== void 0 && only.type === "hole") {
15839
+ return { type: "reference", path: only.label.split(".") };
15840
+ }
15841
+ if (parts.some((part) => part.type === "hole")) {
15842
+ return { type: "pattern", parts };
15843
+ }
15844
+ return { type: "literal", value: name };
15845
+ }
15846
+ function patternHole(label) {
15847
+ return `{${label}}`;
15848
+ }
15849
+ function namesNothing(name) {
15850
+ return parseBoundaryName(name).type === "reference";
15851
+ }
15852
+ function referenceOf(name) {
15853
+ if (name.type !== "reference") {
15854
+ return null;
15855
+ }
15856
+ const root = name.path[0];
15857
+ if (root === void 0 || name.path.some((part) => part === "")) {
15858
+ return null;
15859
+ }
15860
+ return { root, fields: name.path.slice(1) };
15861
+ }
15862
+ function referenceFromName(name) {
15863
+ return referenceOf(parseBoundaryName(name));
15864
+ }
15608
15865
  var SCHEME_ORIGIN = /^[a-zA-Z][a-zA-Z\d+.-]*:\/\/[^/]*/;
15609
15866
  var PROTOCOL_RELATIVE_ORIGIN = /^\/\/[^/]*/;
15610
15867
  function pathAfterOrigin(text) {
@@ -15631,12 +15888,12 @@ var RestSemanticsSchema = external_exports.object({
15631
15888
  declaredResponses: external_exports.array(external_exports.number()).optional()
15632
15889
  });
15633
15890
  var OPENING_HOLE = /^\{([^{}]+)\}(.*)$/;
15634
- function variableOf(label) {
15635
- const parts = label.split(".");
15636
- return parts[parts.length - 1] ?? label;
15891
+ function baseUrlReference(semantics) {
15892
+ const label = OPENING_HOLE.exec(semantics.path ?? "")?.[1];
15893
+ return label === void 0 ? null : referenceFromName(patternHole(label));
15637
15894
  }
15638
- function normalizePath(path4) {
15639
- 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}");
15640
15897
  if (normalized.length > 1 && normalized.endsWith("/")) {
15641
15898
  normalized = normalized.slice(0, -1);
15642
15899
  }
@@ -15646,8 +15903,8 @@ function normalizePath(path4) {
15646
15903
  );
15647
15904
  return normalized;
15648
15905
  }
15649
- function pathShape(path4) {
15650
- return normalizePath(path4).replace(/\{[^}]*\}/g, "{}");
15906
+ function pathShape(path7) {
15907
+ return normalizePath(path7).replace(/\{[^}]*\}/g, "{}");
15651
15908
  }
15652
15909
  function methodsAgree(a, b) {
15653
15910
  if (a === null || b === null) {
@@ -15725,8 +15982,8 @@ var restSemantics = defineBoundarySemantics({
15725
15982
  return null;
15726
15983
  }
15727
15984
  const method = semantics.method === null ? "ANY" : semantics.method.toUpperCase();
15728
- const path4 = semantics.path === null ? "?" : normalizePath(semantics.path);
15729
- return `${method} ${path4}`;
15985
+ const path7 = semantics.path === null ? "?" : normalizePath(semantics.path);
15986
+ return `${method} ${path7}`;
15730
15987
  },
15731
15988
  /**
15732
15989
  * A route with both halves stated decides for itself: the method
@@ -15735,14 +15992,14 @@ var restSemantics = defineBoundarySemantics({
15735
15992
  * half might still be the one that handles the request, and nothing
15736
15993
  * here can settle that, so it abstains instead of refusing.
15737
15994
  */
15738
- servesRequest(semantics, method, path4) {
15995
+ servesRequest(semantics, method, path7) {
15739
15996
  if (semantics.method === null || semantics.path === null) {
15740
15997
  return "unknown";
15741
15998
  }
15742
15999
  if (!methodsAgree(semantics.method, method.toUpperCase())) {
15743
16000
  return "nomatch";
15744
16001
  }
15745
- return routePathAdmits(semantics.path, path4) ? "match" : "nomatch";
16002
+ return routePathAdmits(semantics.path, path7) ? "match" : "nomatch";
15746
16003
  },
15747
16004
  /**
15748
16005
  * A route the registration pattern admits is inside it. A route
@@ -15767,22 +16024,20 @@ var restSemantics = defineBoundarySemantics({
15767
16024
  * route parameter, and `/orders/{id}` means every id rather than a
15768
16025
  * variable somebody set.
15769
16026
  */
15770
- groundName(semantics, deployedAs) {
15771
- if (semantics.path === null) {
15772
- return null;
15773
- }
15774
- const opening = OPENING_HOLE.exec(semantics.path);
15775
- if (opening === null) {
16027
+ groundName(semantics, deployment) {
16028
+ const reference = baseUrlReference(semantics);
16029
+ if (reference === null) {
15776
16030
  return null;
15777
16031
  }
15778
- const [, label, rest] = opening;
15779
- const base = deployedAs(variableOf(label));
16032
+ const base = deployment.setTo(reference);
15780
16033
  if (base === null) {
15781
16034
  return null;
15782
16035
  }
16036
+ const rest = OPENING_HOLE.exec(semantics.path ?? "")?.[2] ?? "";
15783
16037
  const grounded = pathAfterOrigin(`${base}${rest}`);
15784
16038
  return { ...semantics, path: grounded === "" ? "/" : grounded };
15785
16039
  },
16040
+ nameReference: baseUrlReference,
15786
16041
  ruleBoundary: {
15787
16042
  // "METHOD /path": one leading token, then an absolute path.
15788
16043
  claims(raw) {
@@ -15858,6 +16113,9 @@ var StorageSemanticsSchema = external_exports.object({
15858
16113
  */
15859
16114
  accessPath: external_exports.string().nullable()
15860
16115
  });
16116
+ function containerReference(semantics) {
16117
+ return semantics.container === null ? null : referenceFromName(semantics.container);
16118
+ }
15861
16119
  var storageSemantics = defineBoundarySemantics({
15862
16120
  name: "storage",
15863
16121
  schema: StorageSemanticsSchema,
@@ -15874,7 +16132,21 @@ var storageSemantics = defineBoundarySemantics({
15874
16132
  exchangesHttpResponses: false,
15875
16133
  reportsUnpairedItself: false,
15876
16134
  identityKey: () => null,
15877
- displayLabel: storageLabel
16135
+ displayLabel: storageLabel,
16136
+ /**
16137
+ * A container the source states as a variable is whatever the
16138
+ * deployment sets that variable to. `{SUBSCRIBERS_TABLE}` in the
16139
+ * code and `prod-subscribers-v1` in the manifest are one table.
16140
+ */
16141
+ groundName(semantics, deployment) {
16142
+ const reference = containerReference(semantics);
16143
+ if (reference === null) {
16144
+ return null;
16145
+ }
16146
+ const name = deployment.setTo(reference);
16147
+ return name === null ? null : { ...semantics, container: name };
16148
+ },
16149
+ nameReference: containerReference
15878
16150
  }
15879
16151
  });
15880
16152
  function storageLabel(semantics) {
@@ -15889,6 +16161,9 @@ var UnitInvocationSemanticsSchema = DeployableUnitSchema.extend({
15889
16161
  name: external_exports.literal("unit-invocation"),
15890
16162
  instanceName: DeployableUnitSchema.shape.instanceName.nullable()
15891
16163
  });
16164
+ function calleeReference(semantics) {
16165
+ return semantics.instanceName === null ? null : referenceFromName(semantics.instanceName);
16166
+ }
15892
16167
  var unitInvocationSemantics = defineBoundarySemantics({
15893
16168
  name: "unit-invocation",
15894
16169
  schema: UnitInvocationSemanticsSchema,
@@ -15911,8 +16186,13 @@ var unitInvocationSemantics = defineBoundarySemantics({
15911
16186
  * being reported as a problem here.
15912
16187
  */
15913
16188
  reportsUnpairedItself: false,
16189
+ /**
16190
+ * A callee the source states only as a variable is not a name for
16191
+ * anything until the deployment fills it in, so it keys as nothing
16192
+ * rather than as a bucket that would agree with itself alone.
16193
+ */
15914
16194
  identityKey(semantics) {
15915
- if (semantics.instanceName === null) {
16195
+ if (semantics.instanceName === null || namesNothing(semantics.instanceName)) {
15916
16196
  return null;
15917
16197
  }
15918
16198
  return unitIdentityKey(
@@ -15928,7 +16208,23 @@ var unitInvocationSemantics = defineBoundarySemantics({
15928
16208
  semantics.deploymentTarget,
15929
16209
  semantics.instanceName
15930
16210
  );
15931
- }
16211
+ },
16212
+ /**
16213
+ * A call that reads its callee's name out of the environment
16214
+ * reaches whichever resource the template wires that variable to.
16215
+ * The logical id is the answer rather than the deployed name,
16216
+ * because the invoked unit's own summary is keyed by the logical
16217
+ * id and neither side ever writes the other's string.
16218
+ */
16219
+ groundName(semantics, deployment) {
16220
+ const reference = calleeReference(semantics);
16221
+ if (reference === null) {
16222
+ return null;
16223
+ }
16224
+ const logicalId = deployment.pointsAt(reference);
16225
+ return logicalId === null ? null : { ...semantics, instanceName: logicalId };
16226
+ },
16227
+ nameReference: calleeReference
15932
16228
  }
15933
16229
  });
15934
16230
  var SemanticsSchema = external_exports.discriminatedUnion("name", [
@@ -16123,323 +16419,619 @@ function storageBinding(opts) {
16123
16419
  // ../../resolution/dist/index.js
16124
16420
  var import_datalog = require("@suss/datalog");
16125
16421
  var import_datalog2 = require("@suss/datalog");
16126
- 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");
16127
16707
  var NAMESPACE_IMPORT_NAME = "*";
16128
- var NAMESPACE_IMPORT = (0, import_datalog2.constant)(NAMESPACE_IMPORT_NAME);
16129
- 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");
16130
16710
  var RESOLUTION_RULES = [
16131
16711
  // Aliasing: const x = y, or an identifier referencing a declaration.
16132
16712
  // A language with a hop of its own, like JavaScript's `.bind`, states
16133
16713
  // it as a step too, or every question but `comesTo` misses it.
16134
- (0, import_datalog2.rule)(
16714
+ (0, import_datalog3.rule)(
16135
16715
  "stepsTo",
16136
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), VALUE_STEP],
16137
- [(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"))],
16138
16718
  "alias"
16139
16719
  ),
16140
16720
  // A name written more than once has the value the last write left
16141
16721
  // there. The adapter works out which write that is and stays quiet
16142
16722
  // when control flow decides, so such a name steps nowhere at all.
16143
- (0, import_datalog2.rule)(
16723
+ (0, import_datalog3.rule)(
16144
16724
  "stepsTo",
16145
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), VALUE_STEP],
16146
- [(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"))],
16147
16727
  "last write"
16148
16728
  ),
16149
16729
  // A fallback says the value is one of its branches, so each branch is
16150
16730
  // a step. A branch that resolves to nothing makes no claim, and two
16151
16731
  // branches resolving to different things fail the single-answer policy.
16152
- (0, import_datalog2.rule)(
16732
+ (0, import_datalog3.rule)(
16153
16733
  "stepsTo",
16154
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("b"), VALUE_STEP],
16155
- [(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"))],
16156
16736
  "fallback"
16157
16737
  ),
16158
16738
  // An import steps to what the module exports under that name.
16159
- (0, import_datalog2.rule)(
16739
+ (0, import_datalog3.rule)(
16160
16740
  "stepsTo",
16161
- [(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],
16162
16742
  [
16163
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")),
16164
- (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"))
16165
16745
  ],
16166
16746
  "import"
16167
16747
  ),
16168
16748
  // A parameter steps to what a call passes it. A function called from
16169
16749
  // several places leaves its parameter with more than one value, and a
16170
16750
  // caller that needs those apart asks `paramAt`.
16171
- (0, import_datalog2.rule)(
16751
+ (0, import_datalog3.rule)(
16172
16752
  "stepsTo",
16173
- [(0, import_datalog2.variable)("p"), (0, import_datalog2.variable)("a"), VALUE_STEP],
16174
- [(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"))],
16175
16755
  "argument"
16176
16756
  ),
16177
16757
  // Reading a property steps to what the object contains under that
16178
16758
  // name, whichever way the object arrived: `routes.list` off a name,
16179
16759
  // or `make(body).handle` off a call.
16180
- (0, import_datalog2.rule)(
16760
+ (0, import_datalog3.rule)(
16181
16761
  "stepsTo",
16182
- [(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],
16183
16763
  [
16184
- (0, import_datalog2.lit)("readsProperty", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("n")),
16185
- (0, import_datalog2.lit)("objectOf", (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("obj")),
16186
- (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"))
16187
16767
  ],
16188
16768
  "property read"
16189
16769
  ),
16190
16770
  // Calling a class makes one of it, so the call steps to the class and
16191
16771
  // a method read off the result is the one the class declares. The
16192
16772
  // caveat below is about a factory function, and a class is not one.
16193
- (0, import_datalog2.rule)(
16773
+ (0, import_datalog3.rule)(
16194
16774
  "stepsTo",
16195
- [(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],
16196
16776
  [
16197
- (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c")),
16198
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("cls")),
16199
- (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"))
16200
16780
  ],
16201
16781
  "class instance"
16202
16782
  ),
16203
16783
  // Wrapper transparency, derived: calling a factory that returns a
16204
16784
  // function which calls its parameter k steps to argument k.
16205
- (0, import_datalog2.rule)(
16785
+ (0, import_datalog3.rule)(
16206
16786
  "stepsTo",
16207
- [(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],
16208
16788
  [
16209
- (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c")),
16210
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("f")),
16211
- (0, import_datalog2.lit)("unwraps", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("k")),
16212
- (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"))
16213
16793
  ],
16214
16794
  "factory unwrap"
16215
16795
  ),
16216
16796
  // Wrapper transparency, declared: a pack says this callee wraps
16217
16797
  // argument k. The callee has to come from the library the pack said,
16218
16798
  // so a local object spelled the same way is not mistaken for it.
16219
- (0, import_datalog2.rule)(
16799
+ (0, import_datalog3.rule)(
16220
16800
  "stepsTo",
16221
- [(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],
16222
16802
  [
16223
- (0, import_datalog2.lit)("calleeName", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("n")),
16224
- (0, import_datalog2.lit)("unwrapsByName", (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("k")),
16225
- (0, import_datalog2.lit)("wrapperModule", (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("m")),
16226
- (0, import_datalog2.lit)("calleeOrigin", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("m")),
16227
- (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"))
16228
16808
  ],
16229
16809
  "declared wrapper"
16230
16810
  ),
16231
16811
  // The one step that runs a function forwards: a call steps to what
16232
16812
  // the function it invokes returns.
16233
- (0, import_datalog2.rule)(
16813
+ (0, import_datalog3.rule)(
16234
16814
  "stepsTo",
16235
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("ret"), RESULT_STEP],
16236
- [(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"))],
16237
16817
  "call result"
16238
16818
  ),
16239
- // Where a walk gets to, and whether it ran a call on the way. A value
16240
- // step keeps whatever the rest of the walk was, and a result step
16241
- // makes the whole walk one that ran a call.
16242
- (0, import_datalog2.rule)(
16819
+ // Where a walk gets to, and whether it ran a call on the way. The walk
16820
+ // so far comes first, so demand stays on the value asked about; the
16821
+ // README says what the other order cost.
16822
+ (0, import_datalog3.rule)(
16243
16823
  "reaches",
16244
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), (0, import_datalog2.variable)("kind")],
16245
- [(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"))]
16246
16826
  ),
16247
- (0, import_datalog2.rule)(
16827
+ (0, import_datalog3.rule)(
16248
16828
  "reaches",
16249
- [(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")],
16250
16830
  [
16251
- (0, import_datalog2.lit)("stepsTo", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), VALUE_STEP),
16252
- (0, import_datalog2.lit)("reaches", (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"))
16253
16833
  ]
16254
16834
  ),
16255
- // Two rules rather than one leaving the rest of the walk's kind free.
16256
- // A free kind is a second question about the same relation, and a
16835
+ // Two rules rather than one leaving the next step's kind free. A free
16836
+ // kind is a second question about the same relation, and a
16257
16837
  // demand-driven run then derives both to answer either.
16258
- (0, import_datalog2.rule)(
16838
+ (0, import_datalog3.rule)(
16259
16839
  "reaches",
16260
- [(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],
16261
16841
  [
16262
- (0, import_datalog2.lit)("stepsTo", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), RESULT_STEP),
16263
- (0, import_datalog2.lit)("reaches", (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)
16264
16844
  ]
16265
16845
  ),
16266
- (0, import_datalog2.rule)(
16846
+ (0, import_datalog3.rule)(
16267
16847
  "reaches",
16268
- [(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],
16269
16849
  [
16270
- (0, import_datalog2.lit)("stepsTo", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), RESULT_STEP),
16271
- (0, import_datalog2.lit)("reaches", (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)
16272
16852
  ]
16273
16853
  ),
16274
16854
  // What a value comes down to: the walk that never ran a call, stopped
16275
16855
  // at a function or an object. Something already written out comes to
16276
16856
  // itself, and every other walk ends at one of those.
16277
- (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"))]),
16278
- (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"))]),
16279
- (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)(
16280
16860
  "comesTo",
16281
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16282
- [(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"))]
16283
16863
  ),
16284
- (0, import_datalog2.rule)(
16864
+ (0, import_datalog3.rule)(
16285
16865
  "comesTo",
16286
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16287
- [(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"))]
16288
16868
  ),
16289
16869
  // The same stopping condition, for the walk that ran a call. A call
16290
16870
  // gets no `comesTo` answer on purpose: coming back with what a
16291
16871
  // factory returned would fight the unwrapping answer.
16292
- (0, import_datalog2.rule)(
16872
+ (0, import_datalog3.rule)(
16293
16873
  "givesBack",
16294
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16295
- [(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"))]
16296
16876
  ),
16297
- (0, import_datalog2.rule)(
16877
+ (0, import_datalog3.rule)(
16298
16878
  "givesBack",
16299
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16300
- [(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"))]
16301
16881
  ),
16302
16882
  // Following a value to the expression it is written as, whatever kind
16303
16883
  // that is. A GraphQL document is neither a function nor an object, so
16304
16884
  // `comesTo` never reaches one.
16305
- (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"))]),
16306
- (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"))]),
16307
- (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)(
16308
16893
  "isWrittenAs",
16309
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16310
- [(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"))]
16311
16896
  ),
16312
- (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)(
16313
16901
  "isWrittenAs",
16314
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16315
- [(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
+ ]
16316
16908
  ),
16317
16909
  // What one call site put in a parameter, told apart from what the
16318
16910
  // other callers passed.
16319
- (0, import_datalog2.rule)(
16911
+ (0, import_datalog3.rule)(
16320
16912
  "paramAt",
16321
- [(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")],
16322
16914
  [
16323
- (0, import_datalog2.lit)("passesArgument", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("p"), (0, import_datalog2.variable)("a")),
16324
- (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"))
16325
16917
  ]
16326
16918
  ),
16327
16919
  // An argument arriving at the parameter it is passed to, by position
16328
16920
  // or by the name the caller wrote, keeping the call it went through
16329
16921
  // so `paramAt` can tell two call sites apart.
16330
- (0, import_datalog2.rule)(
16922
+ (0, import_datalog3.rule)(
16331
16923
  "passesArgument",
16332
- [(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")],
16333
16925
  [
16334
- (0, import_datalog2.lit)("paramOf", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("k"), (0, import_datalog2.variable)("p")),
16335
- (0, import_datalog2.lit)("callsFunction", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")),
16336
- (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"))
16337
16929
  ]
16338
16930
  ),
16339
- (0, import_datalog2.rule)(
16931
+ (0, import_datalog3.rule)(
16340
16932
  "passesArgument",
16341
- [(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")],
16342
16934
  [
16343
- (0, import_datalog2.lit)("paramNamed", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("p")),
16344
- (0, import_datalog2.lit)("callsFunction", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")),
16345
- (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"))
16346
16938
  ]
16347
16939
  ),
16348
16940
  // Which module's export a re-exported name forwards to, however
16349
16941
  // many barrels deep the forwarding runs.
16350
- (0, import_datalog2.rule)(
16942
+ (0, import_datalog3.rule)(
16351
16943
  "moduleForwards",
16352
- [(0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("m2"), (0, import_datalog2.variable)("n2")],
16353
- [(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"))]
16354
16946
  ),
16355
- (0, import_datalog2.rule)(
16947
+ (0, import_datalog3.rule)(
16356
16948
  "moduleForwards",
16357
- [(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")],
16358
16950
  [
16359
- (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")),
16360
- (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"))
16361
16953
  ]
16362
16954
  ),
16363
16955
  // What a module exports: directly, or through re-export chains.
16364
- (0, import_datalog2.rule)(
16956
+ (0, import_datalog3.rule)(
16365
16957
  "moduleExport",
16366
- [(0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("value")],
16367
- [(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"))],
16368
16960
  "export"
16369
16961
  ),
16370
- (0, import_datalog2.rule)(
16962
+ (0, import_datalog3.rule)(
16371
16963
  "moduleExport",
16372
- [(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")],
16373
16965
  [
16374
- (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")),
16375
- (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"))
16376
16968
  ],
16377
16969
  "re-export"
16378
16970
  ),
16379
- (0, import_datalog2.rule)(
16971
+ (0, import_datalog3.rule)(
16380
16972
  "moduleExport",
16381
- [(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")],
16382
16974
  [
16383
- (0, import_datalog2.lit)("reExportsAll", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("m2")),
16384
- (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"))
16385
16977
  ],
16386
16978
  "re-export all"
16387
16979
  ),
16388
16980
  // The function a call runs, written from the call's side because a
16389
16981
  // caller asking what a call gives back has the call in hand.
16390
- (0, import_datalog2.rule)(
16982
+ (0, import_datalog3.rule)(
16391
16983
  "invokes",
16392
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")],
16393
- [(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"))]
16394
16986
  ),
16395
16987
  // The callee is itself a call: `daoBuilder()()`.
16396
- (0, import_datalog2.rule)(
16988
+ (0, import_datalog3.rule)(
16397
16989
  "invokes",
16398
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")],
16399
- [(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"))]
16400
16992
  ),
16401
16993
  // The object an expression refers to: a name through `comesTo`, a
16402
16994
  // factory call through what it gives back. Naming the step is what
16403
16995
  // makes `routes.list` and `make(body).handle` one rule.
16404
- (0, import_datalog2.rule)(
16996
+ (0, import_datalog3.rule)(
16405
16997
  "objectOf",
16406
- [(0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("obj")],
16407
- [(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"))]
16408
17000
  ),
16409
- (0, import_datalog2.rule)(
17001
+ (0, import_datalog3.rule)(
16410
17002
  "objectOf",
16411
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("obj")],
16412
- [(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"))]
16413
17005
  ),
16414
17006
  // Which calls a function, found by the name the call is written as
16415
17007
  // rather than by resolving every callee in the project. A caller knows
16416
17008
  // the function and wants its call sites, so both of these start from
16417
17009
  // the function. Starting from `call` instead asks what every call in
16418
17010
  // the project imports, which was 72% of everything derived.
16419
- (0, import_datalog2.rule)(
17011
+ (0, import_datalog3.rule)(
16420
17012
  "callsFunction",
16421
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")],
16422
- [(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"))]
16423
17015
  ),
16424
- (0, import_datalog2.rule)(
17016
+ (0, import_datalog3.rule)(
16425
17017
  "callsFunction",
16426
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")],
17018
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("f")],
16427
17019
  [
16428
- (0, import_datalog2.lit)("moduleExport", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("f")),
16429
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")),
16430
- (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"))
16431
17023
  ]
16432
17024
  ),
16433
17025
  // The same, for a language whose adapter writes the import down as a
16434
17026
  // declaration and the call's callee as the name referring to it.
16435
- (0, import_datalog2.rule)(
17027
+ (0, import_datalog3.rule)(
16436
17028
  "callsFunction",
16437
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")],
17029
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("f")],
16438
17030
  [
16439
- (0, import_datalog2.lit)("moduleExport", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("f")),
16440
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("d"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")),
16441
- (0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("d")),
16442
- (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"))
16443
17035
  ]
16444
17036
  ),
16445
17037
  // What an object contains, its base class included, so a method the base
@@ -16447,47 +17039,47 @@ var RESOLUTION_RULES = [
16447
17039
  // declare gives two, and the caller decides. This is its own relation
16448
17040
  // rather than more `holdsProperty`, which stays something an adapter
16449
17041
  // states and the rules only read.
16450
- (0, import_datalog2.rule)(
17042
+ (0, import_datalog3.rule)(
16451
17043
  "contains",
16452
- [(0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("held")],
16453
- [(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"))]
16454
17046
  ),
16455
- (0, import_datalog2.rule)(
17047
+ (0, import_datalog3.rule)(
16456
17048
  "contains",
16457
- [(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")],
16458
17050
  [
16459
- (0, import_datalog2.lit)("extends", (0, import_datalog2.variable)("cls"), (0, import_datalog2.variable)("base")),
16460
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("base"), (0, import_datalog2.variable)("baseCls")),
16461
- (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"))
16462
17054
  ]
16463
17055
  ),
16464
17056
  // Which function a factory returns, and which of its parameters that
16465
17057
  // function calls: together they are what makes it a wrapper.
16466
- (0, import_datalog2.rule)(
17058
+ (0, import_datalog3.rule)(
16467
17059
  "returnsFunc",
16468
- [(0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("g")],
17060
+ [(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("g")],
16469
17061
  [
16470
- (0, import_datalog2.lit)("returnsValue", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("value")),
16471
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("value"), (0, import_datalog2.variable)("g")),
16472
- (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"))
16473
17065
  ]
16474
17066
  ),
16475
17067
  // A call made by a nested closure counts as made by the function
16476
17068
  // that declares it; the closure runs as part of that function.
16477
- (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"))]),
16478
- (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)(
16479
17071
  "bodyCallsDeep",
16480
- [(0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("c")],
16481
- [(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"))]
16482
17074
  ),
16483
- (0, import_datalog2.rule)(
17075
+ (0, import_datalog3.rule)(
16484
17076
  "unwraps",
16485
- [(0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("k")],
17077
+ [(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("k")],
16486
17078
  [
16487
- (0, import_datalog2.lit)("returnsFunc", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("g")),
16488
- (0, import_datalog2.lit)("bodyCallsDeep", (0, import_datalog2.variable)("g"), (0, import_datalog2.variable)("c")),
16489
- (0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("p")),
16490
- (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"))
16491
17083
  ]
16492
17084
  ),
16493
17085
  // Argument flow: which parameter a value traces back to. Directly
@@ -16495,304 +17087,289 @@ var RESOLUTION_RULES = [
16495
17087
  // another unwrapping factory. This is what lets
16496
17088
  // `createProtected(h) { return service.withAuth(h); }` unwrap:
16497
17089
  // the returned call passes h through withAuth, which unwraps.
16498
- (0, import_datalog2.rule)(
17090
+ (0, import_datalog3.rule)(
16499
17091
  "flowsToParam",
16500
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("p")],
17092
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("p")],
16501
17093
  [
16502
- (0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("p")),
16503
- (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"))
16504
17096
  ]
16505
17097
  ),
16506
- (0, import_datalog2.rule)(
17098
+ (0, import_datalog3.rule)(
16507
17099
  "flowsToParam",
16508
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("p")],
17100
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("p")],
16509
17101
  [
16510
- (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c")),
16511
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("f")),
16512
- (0, import_datalog2.lit)("unwraps", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("k")),
16513
- (0, import_datalog2.lit)("callArg", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("k"), (0, import_datalog2.variable)("a")),
16514
- (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"))
16515
17107
  ]
16516
17108
  ),
16517
- (0, import_datalog2.rule)(
17109
+ (0, import_datalog3.rule)(
16518
17110
  "unwraps",
16519
- [(0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("k")],
17111
+ [(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("k")],
16520
17112
  [
16521
- (0, import_datalog2.lit)("returnsValue", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("value")),
16522
- (0, import_datalog2.lit)("flowsToParam", (0, import_datalog2.variable)("value"), (0, import_datalog2.variable)("p")),
16523
- (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"))
16524
17116
  ]
16525
17117
  ),
16526
17118
  // Where a name comes from, when what it refers to lives outside the
16527
17119
  // source being read. A walk ends at something written out in source,
16528
17120
  // so it never reaches a library's own function.
16529
- (0, import_datalog2.rule)(
17121
+ (0, import_datalog3.rule)(
16530
17122
  "comesFrom",
16531
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
16532
- [(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"))]
16533
17125
  ),
16534
- (0, import_datalog2.rule)(
17126
+ (0, import_datalog3.rule)(
16535
17127
  "comesFrom",
16536
- [(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")],
16537
17129
  [
16538
- (0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), VALUE_STEP),
16539
- (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"))
16540
17132
  ]
16541
17133
  ),
16542
17134
  // Calling f ends up calling the name n that module m exports, one
16543
17135
  // hop through f's own body or deeper through a wrapper of a wrapper.
16544
17136
  // Several results is normal: a composed decorator applies them all.
16545
- (0, import_datalog2.rule)(
17137
+ (0, import_datalog3.rule)(
16546
17138
  "callsInto",
16547
- [(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")],
16548
17140
  [
16549
- (0, import_datalog2.lit)("bodyCallsDeep", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("c")),
16550
- (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"))
16551
17143
  ]
16552
17144
  ),
16553
- (0, import_datalog2.rule)(
17145
+ (0, import_datalog3.rule)(
16554
17146
  "callsInto",
16555
- [(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")],
16556
17148
  [
16557
- (0, import_datalog2.lit)("bodyCallsDeep", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("c")),
16558
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("g")),
16559
- (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"))
16560
17152
  ]
16561
17153
  ),
16562
17154
  // The question callers ask: what a value comes to, narrowed to the
16563
17155
  // functions. Objects appear in the middle of chains and never in an
16564
17156
  // answer.
16565
- (0, import_datalog2.rule)(
17157
+ (0, import_datalog3.rule)(
16566
17158
  "resolves",
16567
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16568
- [(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"))]
16569
17161
  )
16570
17162
  ];
16571
17163
  var RESOLUTION_QUESTIONS = [
16572
- (0, import_datalog2.rule)(
17164
+ (0, import_datalog3.rule)(
16573
17165
  "wantedResolves",
16574
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16575
- [(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"))]
16576
17168
  ),
16577
- (0, import_datalog2.rule)(
17169
+ (0, import_datalog3.rule)(
16578
17170
  "wantedComesTo",
16579
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16580
- [(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"))]
16581
17173
  ),
16582
- (0, import_datalog2.rule)(
17174
+ (0, import_datalog3.rule)(
16583
17175
  "wantedComesTo",
16584
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16585
- [(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"))]
16586
17178
  ),
16587
- (0, import_datalog2.rule)(
17179
+ (0, import_datalog3.rule)(
16588
17180
  "wantedIsWrittenAs",
16589
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16590
- [(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"))]
16591
17183
  ),
16592
17184
  // A call is given no `comesTo`, so this is the only way to ask what
16593
17185
  // object one arrives at, and without it a demand-driven run derives
16594
17186
  // `objectOf` nowhere.
16595
- (0, import_datalog2.rule)(
17187
+ (0, import_datalog3.rule)(
16596
17188
  "wantedObjectOf",
16597
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16598
- [(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"))]
16599
17191
  ),
16600
17192
  // Keyed by the parameter, since that is what a caller has in hand
16601
17193
  // when it wants the call sites told apart.
16602
- (0, import_datalog2.rule)(
17194
+ (0, import_datalog3.rule)(
16603
17195
  "wantedParamAt",
16604
- [(0, import_datalog2.variable)("p"), (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("z")],
16605
- [(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"))]
16606
17198
  ),
16607
- (0, import_datalog2.rule)(
17199
+ (0, import_datalog3.rule)(
16608
17200
  "wantedComesFrom",
16609
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
16610
- [(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"))]
16611
17203
  ),
16612
17204
  // Call-origin questions, for attribution, in their own demand
16613
17205
  // class. Attribution stops at the import declaration, so nothing
16614
17206
  // here demands reaches or callsInto. The chains are closures with
16615
17207
  // no depth bound: an alias run of any length resolves.
16616
- (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"))]),
16617
- (0, import_datalog2.rule)(
16618
- "callOriginChain",
16619
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16620
- [(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"))]
16621
- ),
16622
- (0, import_datalog2.rule)(
16623
- "callOriginChain",
16624
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16625
- [
16626
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
16627
- (0, import_datalog2.lit)("endsHolding", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))
16628
- ]
16629
- ),
16630
- (0, import_datalog2.rule)(
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"))]),
17209
+ // The chain with at least one hop taken, which is what tells a
17210
+ // destructured binding apart from asking about a node directly. The
17211
+ // whole chain is the seed plus those hops.
17212
+ (0, import_datalog3.rule)(
16631
17213
  "callOriginChain",
16632
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16633
- [
16634
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
16635
- (0, import_datalog2.lit)("fallbackBranch", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))
16636
- ]
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"))]
16637
17216
  ),
16638
- // The chain with at least one hop taken, which is what tells a
16639
- // destructured binding apart from asking about a node directly.
16640
- (0, import_datalog2.rule)(
17217
+ (0, import_datalog3.rule)(
16641
17218
  "callOriginChainStepped",
16642
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16643
- [(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"))]
16644
17221
  ),
16645
- (0, import_datalog2.rule)(
17222
+ (0, import_datalog3.rule)(
16646
17223
  "callOriginChainStepped",
16647
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
17224
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
16648
17225
  [
16649
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
16650
- (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"))
16651
17228
  ]
16652
17229
  ),
16653
- (0, import_datalog2.rule)(
17230
+ (0, import_datalog3.rule)(
16654
17231
  "callOriginChainStepped",
16655
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
17232
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
16656
17233
  [
16657
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
16658
- (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"))
16659
17236
  ]
16660
17237
  ),
16661
- (0, import_datalog2.rule)(
17238
+ (0, import_datalog3.rule)(
16662
17239
  "wantedCallOriginPair",
16663
- [(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")],
16664
17241
  [
16665
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
16666
- (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"))
16667
17244
  ]
16668
17245
  ),
16669
17246
  // An import of a project barrel is an import of what the barrel
16670
17247
  // forwards, so the pair surfaces the module behind the chain.
16671
- (0, import_datalog2.rule)(
17248
+ (0, import_datalog3.rule)(
16672
17249
  "wantedCallOriginPair",
16673
- [(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")],
16674
17251
  [
16675
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
16676
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")),
16677
- (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"))
16678
17255
  ]
16679
17256
  ),
16680
17257
  // A namespace member: the module's export of the member's own name.
16681
17258
  // The imports literal leads, since it is the smallest relation.
16682
- (0, import_datalog2.rule)(
17259
+ (0, import_datalog3.rule)(
16683
17260
  "wantedCallOriginPair",
16684
- [(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")],
16685
17262
  [
16686
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("m"), NAMESPACE_IMPORT),
16687
- (0, import_datalog2.lit)("readsProperty", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("p")),
16688
- (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"))
16689
17266
  ]
16690
17267
  ),
16691
- (0, import_datalog2.rule)(
17268
+ (0, import_datalog3.rule)(
16692
17269
  "wantedCallOriginPair",
16693
- [(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")],
16694
17271
  [
16695
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("d"), (0, import_datalog2.variable)("m"), NAMESPACE_IMPORT),
16696
- (0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("d")),
16697
- (0, import_datalog2.lit)("readsProperty", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("p")),
16698
- (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"))
16699
17276
  ]
16700
17277
  ),
16701
17278
  // What a call made: through the call to its callee, whose own alias
16702
17279
  // chain leads to the import.
16703
- (0, import_datalog2.rule)(
17280
+ (0, import_datalog3.rule)(
16704
17281
  "callMadeChain",
16705
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("f")],
16706
- [(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"))]
16707
17284
  ),
16708
- (0, import_datalog2.rule)(
17285
+ (0, import_datalog3.rule)(
16709
17286
  "callMadeChain",
16710
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16711
- [(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"))]
16712
17289
  ),
16713
- (0, import_datalog2.rule)(
17290
+ (0, import_datalog3.rule)(
16714
17291
  "callMadeChain",
16715
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16716
- [(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"))]
16717
17294
  ),
16718
- (0, import_datalog2.rule)(
17295
+ (0, import_datalog3.rule)(
16719
17296
  "wantedCallOriginPair",
16720
- [(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")],
16721
17298
  [
16722
- (0, import_datalog2.lit)("callMadeChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
16723
- (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"))
16724
17301
  ]
16725
17302
  ),
16726
17303
  // A member destructured off what a call made keeps the member name
16727
17304
  // as one more path segment.
16728
- (0, import_datalog2.rule)(
17305
+ (0, import_datalog3.rule)(
16729
17306
  "callMemberChain",
16730
- [(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")],
16731
17308
  [
16732
- (0, import_datalog2.lit)("callOriginChainStepped", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("e")),
16733
- (0, import_datalog2.lit)("readsProperty", (0, import_datalog2.variable)("e"), (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("p")),
16734
- (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"))
16735
17312
  ]
16736
17313
  ),
16737
- (0, import_datalog2.rule)(
17314
+ (0, import_datalog3.rule)(
16738
17315
  "callMemberChain",
16739
- [(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")],
16740
17317
  [
16741
- (0, import_datalog2.lit)("callMemberChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("p")),
16742
- (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"))
16743
17320
  ]
16744
17321
  ),
16745
- (0, import_datalog2.rule)(
17322
+ (0, import_datalog3.rule)(
16746
17323
  "callMemberChain",
16747
- [(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")],
16748
17325
  [
16749
- (0, import_datalog2.lit)("callMemberChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("p")),
16750
- (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"))
16751
17328
  ]
16752
17329
  ),
16753
- (0, import_datalog2.rule)(
17330
+ (0, import_datalog3.rule)(
16754
17331
  "wantedCallOriginMember",
16755
- [(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")],
16756
17333
  [
16757
- (0, import_datalog2.lit)("callMemberChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("p")),
16758
- (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"))
16759
17336
  ]
16760
17337
  ),
16761
- (0, import_datalog2.rule)(
17338
+ (0, import_datalog3.rule)(
16762
17339
  "wantedCallsInto",
16763
- [(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")],
16764
17341
  [
16765
- (0, import_datalog2.lit)("wantedOrigin", (0, import_datalog2.variable)("x")),
16766
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("g")),
16767
- (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"))
16768
17345
  ]
16769
17346
  ),
16770
17347
  // Subject identity, its own demand class; the README's subject
16771
17348
  // section says why the origin pair rides on the written-value walk.
16772
- (0, import_datalog2.rule)(
17349
+ (0, import_datalog3.rule)(
16773
17350
  "wantedSubjectWritten",
16774
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("r")],
16775
- [(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"))]
16776
17353
  ),
16777
- (0, import_datalog2.rule)(
17354
+ (0, import_datalog3.rule)(
16778
17355
  "wantedSubjectConstruction",
16779
- [(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")],
16780
17357
  [
16781
- (0, import_datalog2.lit)("wantedSubject", (0, import_datalog2.variable)("x")),
16782
- (0, import_datalog2.lit)("isWrittenAs", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("r")),
16783
- (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c")),
16784
- (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"))
16785
17362
  ]
16786
17363
  ),
16787
17364
  // The export table of one module, keyed by the module asked about.
16788
17365
  // The moduleExport rules flatten re-export chains of any length, and
16789
17366
  // the demand cone stays on export facts alone.
16790
- (0, import_datalog2.rule)(
17367
+ (0, import_datalog3.rule)(
16791
17368
  "wantedModuleExport",
16792
- [(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")],
16793
17370
  [
16794
- (0, import_datalog2.lit)("wantedExportsOf", (0, import_datalog2.variable)("m")),
16795
- (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"))
16796
17373
  ]
16797
17374
  ),
16798
17375
  // The calls behind a receiver, for a pack that wants the anchor a
@@ -16801,63 +17378,63 @@ var RESOLUTION_QUESTIONS = [
16801
17378
  // A class's ancestry, one hop per extends through the binding that
16802
17379
  // says which class the written base is; the names on the way out
16803
17380
  // are what a storage pack matches its library's bases against.
16804
- (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"))]),
16805
- (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)(
16806
17383
  "ancestryChain",
16807
- [(0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("b2")],
17384
+ [(0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("b2")],
16808
17385
  [
16809
- (0, import_datalog2.lit)("ancestryChain", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("b")),
16810
- (0, import_datalog2.lit)("extends", (0, import_datalog2.variable)("b"), (0, import_datalog2.variable)("x")),
16811
- (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"))
16812
17389
  ]
16813
17390
  ),
16814
- (0, import_datalog2.rule)(
17391
+ (0, import_datalog3.rule)(
16815
17392
  "wantedBaseName",
16816
- [(0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("n")],
16817
- [(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"))]
16818
17395
  ),
16819
- (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"))]),
16820
- (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)(
16821
17398
  "anchorChain",
16822
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16823
- [(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"))]
16824
17401
  ),
16825
- (0, import_datalog2.rule)(
17402
+ (0, import_datalog3.rule)(
16826
17403
  "anchorChain",
16827
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16828
- [(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"))]
16829
17406
  ),
16830
- (0, import_datalog2.rule)(
17407
+ (0, import_datalog3.rule)(
16831
17408
  "anchorChain",
16832
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
16833
- [(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"))]
16834
17411
  ),
16835
- (0, import_datalog2.rule)(
17412
+ (0, import_datalog3.rule)(
16836
17413
  "anchorChain",
16837
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
17414
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
16838
17415
  [
16839
- (0, import_datalog2.lit)("anchorChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
16840
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")),
16841
- (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"))
16842
17419
  ]
16843
17420
  ),
16844
- (0, import_datalog2.rule)(
17421
+ (0, import_datalog3.rule)(
16845
17422
  "anchorChain",
16846
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("c")],
16847
- [(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"))]
16848
17425
  ),
16849
- (0, import_datalog2.rule)(
17426
+ (0, import_datalog3.rule)(
16850
17427
  "anchorChain",
16851
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("o")],
17428
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("o")],
16852
17429
  [
16853
- (0, import_datalog2.lit)("anchorChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
16854
- (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"))
16855
17432
  ]
16856
17433
  ),
16857
- (0, import_datalog2.rule)(
17434
+ (0, import_datalog3.rule)(
16858
17435
  "wantedAnchorCall",
16859
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("r")],
16860
- [(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"))]
16861
17438
  )
16862
17439
  ];
16863
17440
  var ANSWER_RELATIONS = [
@@ -16884,17 +17461,17 @@ function rootConstant(node) {
16884
17461
  }
16885
17462
  return rootConstant(receiver);
16886
17463
  }
16887
- var ANCESTRY_PROGRAM = (0, import_datalog3.deriveOnDemand)(
17464
+ var ANCESTRY_PROGRAM = (0, import_datalog4.deriveOnDemand)(
16888
17465
  [...RESOLUTION_RULES, ...RESOLUTION_QUESTIONS],
16889
17466
  ANSWER_RELATIONS
16890
17467
  );
16891
17468
  function reachesBase(facts, classKey, bases) {
16892
17469
  facts.add("wantedAncestry", [classKey]);
16893
- (0, import_datalog3.evaluate)(facts, ANCESTRY_PROGRAM.rules);
17470
+ (0, import_datalog4.evaluate)(facts, ANCESTRY_PROGRAM.rules);
16894
17471
  return facts.lookup("wantedBaseName", 0, classKey).some((row) => bases.includes(String(row[1])));
16895
17472
  }
16896
- function classBehind(facts, constant2) {
16897
- const wanted = `#${constant2.text}`;
17473
+ function classBehind(facts, constant3) {
17474
+ const wanted = `#${constant3.text}`;
16898
17475
  const bound = new Set(
16899
17476
  facts.facts("binds").filter((row) => String(row[0]).endsWith(wanted)).map((row) => String(row[1]))
16900
17477
  );
@@ -16937,11 +17514,11 @@ function storageEffects(calls, options) {
16937
17514
  if (partOfOne.has(call.id)) {
16938
17515
  continue;
16939
17516
  }
16940
- const constant2 = rootConstant(call);
16941
- if (constant2 === null) {
17517
+ const constant3 = rootConstant(call);
17518
+ if (constant3 === null) {
16942
17519
  continue;
16943
17520
  }
16944
- const classKey = classBehind(options.facts, constant2);
17521
+ const classKey = classBehind(options.facts, constant3);
16945
17522
  if (classKey === void 0) {
16946
17523
  continue;
16947
17524
  }
@@ -16959,7 +17536,7 @@ function storageEffects(calls, options) {
16959
17536
  recognition: "ruby-storage",
16960
17537
  storageSystem: pattern.storageSystem,
16961
17538
  scope: pattern.baseClasses[0] ?? "",
16962
- container: constant2.text
17539
+ container: constant3.text
16963
17540
  }),
16964
17541
  callee: call.text,
16965
17542
  interaction: {
@@ -17075,7 +17652,8 @@ async function discoverUnits(root, options) {
17075
17652
  const knownClasses = new Set(classes.map((info) => info.qualifiedName));
17076
17653
  const fileBlocks = classes.map((info) => ({
17077
17654
  info,
17078
- knownClasses
17655
+ knownClasses,
17656
+ file: options.absoluteFile ?? options.filePath
17079
17657
  }));
17080
17658
  const units = [];
17081
17659
  for (const info of classes) {
@@ -17099,16 +17677,17 @@ async function discoverUnits(root, options) {
17099
17677
  }
17100
17678
  return units;
17101
17679
  }
17102
- function reachesConfiguredBase(ancestry, self, pattern) {
17680
+ function reachesConfiguredBase(ancestry, self, baseClassNames) {
17103
17681
  return ancestry.some(
17104
- (entry) => entry.name !== self && pattern.baseClassNames.includes(entry.name)
17682
+ (entry) => entry.name !== self && baseClassNames.includes(entry.name)
17105
17683
  );
17106
17684
  }
17107
17685
  function unitsFor(pattern, pack, info, ownBlocks, fileBlocks, options) {
17108
17686
  const table = {
17109
- 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)
17110
17689
  };
17111
- return (0, import_behavioral_ir.dispatchByType)(table, pattern);
17690
+ return (0, import_behavioral_ir2.dispatchByType)(table, pattern);
17112
17691
  }
17113
17692
  async function graphqlObjectFieldUnits(pattern, pack, info, ownBlocks, fileBlocks, options) {
17114
17693
  if (info.bodyNode === null || pattern.baseClassNames.includes(info.qualifiedName)) {
@@ -17121,7 +17700,7 @@ async function graphqlObjectFieldUnits(pattern, pack, info, ownBlocks, fileBlock
17121
17700
  options.storage
17122
17701
  );
17123
17702
  const ancestry = await ancestryOf(info.qualifiedName, ownBlocks, ctx.lookup);
17124
- if (!reachesConfiguredBase(ancestry, info.qualifiedName, pattern)) {
17703
+ if (!reachesConfiguredBase(ancestry, info.qualifiedName, pattern.baseClassNames)) {
17125
17704
  return [];
17126
17705
  }
17127
17706
  const typeName = graphqlTypeNameFromQualified(
@@ -17140,26 +17719,162 @@ async function graphqlObjectFieldUnits(pattern, pack, info, ownBlocks, fileBlock
17140
17719
  declsByName.set(decl.fieldName, decl);
17141
17720
  }
17142
17721
  }
17143
- return [...declsByName.values()].map(
17144
- (decl) => buildFieldUnit(pack, typeName, decl, options.filePath)
17145
- );
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
+ });
17146
17729
  }
17147
- function blockConfiguresCall(pattern) {
17148
- const names = /* @__PURE__ */ new Set([
17149
- pattern.fieldCallName,
17150
- pattern.typeCallName,
17151
- pattern.argumentCallName
17152
- ]);
17153
- return (call) => {
17154
- const method = field(call, "method")?.text;
17155
- return field(call, "receiver") === null && method !== void 0 && names.has(method);
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)
17156
17740
  };
17157
- }
17158
- function branchesFor(body, range) {
17159
- if (body.effects === void 0 && body.extraEffects === void 0) {
17741
+ const ancestry = await ancestryOf(info.qualifiedName, ownBlocks, lookup);
17742
+ if (!reachesConfiguredBase(ancestry, info.qualifiedName, pattern.baseClassNames)) {
17160
17743
  return [];
17161
17744
  }
17162
- return [
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
+ };
17861
+ }
17862
+ function blockConfiguresCall(pattern) {
17863
+ const names = /* @__PURE__ */ new Set([
17864
+ pattern.fieldCallName,
17865
+ pattern.typeCallName,
17866
+ pattern.argumentCallName
17867
+ ]);
17868
+ return (call) => {
17869
+ const method = field(call, "method")?.text;
17870
+ return field(call, "receiver") === null && method !== void 0 && names.has(method);
17871
+ };
17872
+ }
17873
+ function branchesFor(body, range) {
17874
+ if (body.effects === void 0 && body.extraEffects === void 0) {
17875
+ return [];
17876
+ }
17877
+ return [
17163
17878
  {
17164
17879
  conditions: [],
17165
17880
  terminal: {
@@ -17183,12 +17898,15 @@ function branchesFor(body, range) {
17183
17898
  }
17184
17899
  function bodyOfMethod(method, storage) {
17185
17900
  const effects = invocationEffects(method);
17186
- const database = storage === void 0 ? [] : storageEffects(callsUnder(method), storage);
17901
+ const extra = [
17902
+ ...envReadEffects(method),
17903
+ ...storage === void 0 ? [] : storageEffects(callsUnder(method), storage)
17904
+ ];
17187
17905
  return {
17188
17906
  bodyContent: methodHasStatements(method) ? "statements" : "empty",
17189
17907
  readings: [],
17190
17908
  ...effects.length > 0 ? { effects } : {},
17191
- ...database.length > 0 ? { extraEffects: database } : {}
17909
+ ...extra.length > 0 ? { extraEffects: extra } : {}
17192
17910
  };
17193
17911
  }
17194
17912
  function callsUnder(node, found = []) {
@@ -17208,18 +17926,25 @@ var NO_METHOD_BEHIND_IT = {
17208
17926
  readings: []
17209
17927
  };
17210
17928
  function methodNotSettled(reason, range) {
17211
- return { readings: [(0, import_extractor3.unreadableReading)(reason, range)] };
17929
+ return { readings: [(0, import_extractor4.unreadableReading)(reason, range)] };
17212
17930
  }
17213
17931
  function bodyFromLookup(found, range, subject, nothingThere, storage) {
17214
17932
  const table = {
17215
- 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
+ }),
17216
17941
  unsettled: (lookup) => methodNotSettled(
17217
17942
  `${subject} could be answered by a method ${lookup.reason}, so whether one exists was not settled here`,
17218
17943
  range
17219
17944
  ),
17220
17945
  none: () => nothingThere
17221
17946
  };
17222
- return (0, import_behavioral_ir.dispatchByType)(table, found);
17947
+ return (0, import_behavioral_ir2.dispatchByType)(table, found);
17223
17948
  }
17224
17949
  async function readFieldCall(stmt, scope, ctx, ancestry) {
17225
17950
  if (stmt.type !== "call" || field(stmt, "receiver") !== null) {
@@ -17262,7 +17987,7 @@ function computedNameDeclaration(stmt, nameArg) {
17262
17987
  contract: null,
17263
17988
  body: {
17264
17989
  readings: [
17265
- (0, import_extractor3.unreadableReading)(
17990
+ (0, import_extractor4.unreadableReading)(
17266
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`,
17267
17992
  range
17268
17993
  )
@@ -17488,7 +18213,7 @@ function buildFieldUnit(pack, typeName, decl, filePath) {
17488
18213
  exportName: null,
17489
18214
  exportPath: null
17490
18215
  },
17491
- boundaryBinding: decl.namedOnTheWire ? (0, import_behavioral_ir.graphqlResolverBinding)({
18216
+ boundaryBinding: decl.namedOnTheWire ? (0, import_behavioral_ir2.graphqlResolverBinding)({
17492
18217
  transport: pack.protocol,
17493
18218
  recognition: pack.name,
17494
18219
  typeName,
@@ -17504,59 +18229,6 @@ function buildFieldUnit(pack, typeName, decl, filePath) {
17504
18229
  };
17505
18230
  }
17506
18231
 
17507
- // src/facts.ts
17508
- function unitKey(filePath, range, name) {
17509
- return `${filePath}:${range.start}-${range.end}#${name}`;
17510
- }
17511
- function emitEntryFact(db, filePath, range, name) {
17512
- db.add("entry", [unitKey(filePath, range, name)]);
17513
- }
17514
-
17515
- // src/parser.ts
17516
- var import_node_fs2 = __toESM(require("fs"), 1);
17517
- var import_node_path2 = __toESM(require("path"), 1);
17518
- var import_node_url = require("url");
17519
- var import_web_tree_sitter = require("web-tree-sitter");
17520
- var GRAMMAR_PATH = import_node_path2.default.join(
17521
- import_node_path2.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl)),
17522
- "..",
17523
- "grammar",
17524
- "tree-sitter-ruby.wasm"
17525
- );
17526
- var languagePromise = null;
17527
- function loadLanguage() {
17528
- languagePromise ??= (async () => {
17529
- if (!import_node_fs2.default.existsSync(GRAMMAR_PATH)) {
17530
- throw new Error(
17531
- `Ruby grammar not found at ${GRAMMAR_PATH}. See grammar/README.md.`
17532
- );
17533
- }
17534
- await import_web_tree_sitter.Parser.init();
17535
- return import_web_tree_sitter.Language.load(GRAMMAR_PATH);
17536
- })();
17537
- return languagePromise;
17538
- }
17539
- async function parseRuby(source) {
17540
- const language = await loadLanguage();
17541
- const parser = new import_web_tree_sitter.Parser();
17542
- parser.setLanguage(language);
17543
- try {
17544
- const tree = parser.parse(source);
17545
- if (tree === null) {
17546
- throw new Error("tree-sitter produced no tree for this source");
17547
- }
17548
- return tree;
17549
- } finally {
17550
- parser.delete();
17551
- }
17552
- }
17553
-
17554
- // src/project.ts
17555
- var import_node_fs3 = __toESM(require("fs"), 1);
17556
- var import_node_path3 = __toESM(require("path"), 1);
17557
- var import_datalog4 = require("@suss/datalog");
17558
- var import_extractor4 = require("@suss/extractor");
17559
-
17560
18232
  // src/facts/values.ts
17561
18233
  function nodeId(filePath, node) {
17562
18234
  return `${filePath}:${node.startIndex}-${node.endIndex}`;
@@ -17564,6 +18236,33 @@ function nodeId(filePath, node) {
17564
18236
  function nameId(filePath, name) {
17565
18237
  return `${filePath}#${name}`;
17566
18238
  }
18239
+ function paramNameOf(param) {
18240
+ return param.type === "identifier" ? param : field(param, "name") ?? null;
18241
+ }
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);
18249
+ }
18250
+ }
18251
+ return declared;
18252
+ }
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);
18265
+ }
17567
18266
  var WRITTEN_VALUE_TYPES = /* @__PURE__ */ new Set([
17568
18267
  "string",
17569
18268
  "integer",
@@ -17724,6 +18423,9 @@ function emitExpressionFacts(emitter, node) {
17724
18423
  if (WRITTEN_VALUE_TYPES.has(child.type)) {
17725
18424
  add(emitter, "writtenValue", nodeId(emitter.filePath, child));
17726
18425
  }
18426
+ if (child.type === "nil") {
18427
+ add(emitter, "placeholderValue", nodeId(emitter.filePath, child));
18428
+ }
17727
18429
  });
17728
18430
  }
17729
18431
  function implicitReturn(body) {
@@ -17740,7 +18442,7 @@ function emitMethodFacts(emitter, method) {
17740
18442
  const declared = /* @__PURE__ */ new Set();
17741
18443
  let position = 0;
17742
18444
  for (const param of params === null ? [] : children3(params)) {
17743
- const paramName = param.type === "identifier" ? param : field(param, "name") ?? null;
18445
+ const paramName = paramNameOf(param);
17744
18446
  if (paramName !== null) {
17745
18447
  declared.add(paramName.text);
17746
18448
  const paramKey = `${funcKey}#${paramName.text}`;
@@ -17835,6 +18537,10 @@ function emitClassFacts(emitter, cls) {
17835
18537
  }
17836
18538
  continue;
17837
18539
  }
18540
+ if (NESTING_TYPES.has(statement.type)) {
18541
+ emitClassFacts(emitter, statement);
18542
+ continue;
18543
+ }
17838
18544
  if (!METHOD_TYPES.has(statement.type)) {
17839
18545
  continue;
17840
18546
  }
@@ -17858,7 +18564,7 @@ function emitValueFacts(db, filePath, root) {
17858
18564
  };
17859
18565
  const walk = (node) => {
17860
18566
  for (const child of children3(node)) {
17861
- if (child.type === "class") {
18567
+ if (NESTING_TYPES.has(child.type)) {
17862
18568
  declaresName(child, emitClassFacts(emitter, child));
17863
18569
  continue;
17864
18570
  }
@@ -17876,7 +18582,6 @@ function emitValueFacts(db, filePath, root) {
17876
18582
  }
17877
18583
 
17878
18584
  // src/facts/constants.ts
17879
- var NESTING_TYPES = /* @__PURE__ */ new Set(["class", "module"]);
17880
18585
  function children4(node) {
17881
18586
  return node.namedChildren.filter((child) => child !== null);
17882
18587
  }
@@ -17954,16 +18659,18 @@ function collectFileConstants(filePath, root) {
17954
18659
  }
17955
18660
  };
17956
18661
  walk(root, null, []);
17957
- return { definitions, references };
18662
+ return { filePath, definitions, references };
17958
18663
  }
17959
18664
  function emitConstantBindings(db, perFile) {
17960
18665
  const byName = /* @__PURE__ */ new Map();
18666
+ const fileOfDefinition = /* @__PURE__ */ new Map();
17961
18667
  const files = [...perFile];
17962
18668
  for (const file2 of files) {
17963
18669
  for (const definition of file2.definitions) {
17964
18670
  const found = byName.get(definition.qualifiedName) ?? [];
17965
18671
  found.push(definition.key);
17966
18672
  byName.set(definition.qualifiedName, found);
18673
+ fileOfDefinition.set(definition.key, file2.filePath);
17967
18674
  }
17968
18675
  }
17969
18676
  const settles = (candidate) => {
@@ -17980,6 +18687,10 @@ function emitConstantBindings(db, perFile) {
17980
18687
  const key = settles(candidate);
17981
18688
  if (key !== null) {
17982
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
+ }
17983
18694
  break;
17984
18695
  }
17985
18696
  }
@@ -17987,10 +18698,652 @@ function emitConstantBindings(db, perFile) {
17987
18698
  }
17988
18699
  }
17989
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
+
17990
19319
  // src/project.ts
17991
19320
  async function extractRubyProject(options) {
17992
- 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();
17993
19345
  const summaries = [];
19346
+ const tallies = (0, import_extractor5.createPackTallies)(options.packs);
17994
19347
  const constants = [];
17995
19348
  const cache = createFileCache(
17996
19349
  (source) => parseRuby(source).then((tree) => tree.rootNode),
@@ -17998,33 +19351,178 @@ async function extractRubyProject(options) {
17998
19351
  );
17999
19352
  const parsed = [];
18000
19353
  for (const file2 of options.files) {
18001
- const root = await cache.get(file2);
18002
- if (root === null) {
18003
- continue;
18004
- }
18005
- parsed.push({ file: file2, root });
18006
- emitValueFacts(db, file2, root);
18007
- 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
+ });
18008
19363
  }
18009
- 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
+ });
18010
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();
18011
19375
  for (const { file: file2, root } of parsed) {
18012
- const displayPath = options.workspaceRoot !== void 0 ? import_node_path3.default.relative(options.workspaceRoot, file2) : file2;
18013
- const rawUnits = await discoverUnits(root, {
18014
- packs: options.packs,
18015
- filePath: displayPath,
18016
- cache,
18017
- ...storagePatterns.length > 0 ? { storage: { facts: db, patterns: storagePatterns } } : {}
18018
- });
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
+ );
18019
19389
  for (const raw of rawUnits) {
18020
- 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
+ );
18021
19394
  summary.confidence = { source: "inferred_static", level: "low" };
18022
19395
  summaries.push(summary);
18023
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);
18024
19432
  }
18025
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());
18026
19509
  return { summaries, facts: db };
18027
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
+ }
18028
19526
  var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set(["vendor", "node_modules", "tmp", ".git"]);
18029
19527
  function findRubyFiles(root) {
18030
19528
  const found = [];
@@ -18032,33 +19530,300 @@ function findRubyFiles(root) {
18032
19530
  for (const entry of import_node_fs3.default.readdirSync(dir, { withFileTypes: true })) {
18033
19531
  if (entry.isDirectory()) {
18034
19532
  if (!SKIPPED_DIRECTORIES.has(entry.name)) {
18035
- walk(import_node_path3.default.join(dir, entry.name));
19533
+ walk(import_node_path4.default.join(dir, entry.name));
18036
19534
  }
18037
19535
  continue;
18038
19536
  }
18039
19537
  if (entry.isFile() && entry.name.endsWith(".rb")) {
18040
- found.push(import_node_path3.default.join(dir, entry.name));
19538
+ found.push(import_node_path4.default.join(dir, entry.name));
18041
19539
  }
18042
19540
  }
18043
19541
  };
18044
19542
  walk(root);
18045
19543
  return found.sort();
18046
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
+ }
18047
19794
  // Annotate the CommonJS export names for ESM import in node:
18048
19795
  0 && (module.exports = {
19796
+ ADAPTER_VERSION,
19797
+ RubyWhySession,
18049
19798
  ancestryOf,
19799
+ bodyStatements,
19800
+ booleanLiteralValue,
19801
+ collectFileConstants,
18050
19802
  createFileCache,
18051
19803
  discoverUnits,
19804
+ emitConstantBindings,
18052
19805
  emitEntryFact,
19806
+ emitValueFacts,
18053
19807
  extractRubyProject,
19808
+ field,
18054
19809
  findRubyFiles,
18055
19810
  graphqlTypeNameFromQualified,
19811
+ hashKeySymbolName,
18056
19812
  inheritedStatements,
18057
19813
  methodInAncestry,
19814
+ nodeId,
18058
19815
  parseRuby,
19816
+ parseRubySync,
19817
+ preloadRubyGrammar,
18059
19818
  qualifyConstantRef,
18060
19819
  reachDefinition,
19820
+ readCallArgs,
19821
+ readKey,
18061
19822
  resolveConstantFile,
19823
+ rubyStubEvidence,
19824
+ runStatements,
19825
+ stringLiteralValue,
19826
+ symbolValue,
18062
19827
  typeShapeFromNode,
18063
19828
  underscoreConstantPath,
18064
19829
  unitKey,