@suss/adapter-python 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,6 +30,8 @@ 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
+ PythonWhySession: () => PythonWhySession,
33
35
  annotationToShape: () => annotationToShape,
34
36
  bindModule: () => bindModule,
35
37
  buildRouterIndex: () => buildRouterIndex,
@@ -44,6 +46,10 @@ __export(index_exports, {
44
46
  nodeId: () => nodeId,
45
47
  objectReturnedBy: () => objectReturnedBy,
46
48
  parsePython: () => parsePython,
49
+ parsePythonSync: () => parsePythonSync,
50
+ preloadPythonGrammar: () => preloadPythonGrammar,
51
+ pythonImportEvidence: () => pythonImportEvidence,
52
+ readKey: () => readKey,
47
53
  resolveAbsoluteModule: () => resolveAbsoluteModule,
48
54
  resolveCalls: () => resolveCalls,
49
55
  resolveModule: () => resolveModule,
@@ -808,18 +814,398 @@ function passesParametersThrough(def, inner) {
808
814
  }
809
815
 
810
816
  // src/discovery.ts
817
+ var import_behavioral_ir2 = require("@suss/behavioral-ir");
818
+ var import_extractor4 = require("@suss/extractor");
819
+
820
+ // src/envReads.ts
811
821
  var import_behavioral_ir = require("@suss/behavioral-ir");
812
- var import_extractor3 = require("@suss/extractor");
822
+ var import_extractor2 = require("@suss/extractor");
823
+ var PYTHON_ENV_RECOGNITION = "python-env";
824
+ var DEFERRED_BODY_TYPES = /* @__PURE__ */ new Set(["function_definition", "lambda"]);
825
+ function envReadEffects(root, module2) {
826
+ const effects = [];
827
+ const startScope = module2.scopeFor.get(root.id) ?? module2.moduleScope;
828
+ (0, import_extractor2.walkDescendants)(root, startScope, {
829
+ at: (node, scope) => {
830
+ const read = envReadAt(node, scope);
831
+ if (read !== null) {
832
+ effects.push(configReadEffect(read));
833
+ }
834
+ },
835
+ into: (node, scope) => {
836
+ if (DEFERRED_BODY_TYPES.has(node.type)) {
837
+ return import_extractor2.SKIP_CHILDREN;
838
+ }
839
+ return module2.scopeFor.get(node.id) ?? scope;
840
+ }
841
+ });
842
+ return effects;
843
+ }
844
+ function configReadEffect(read) {
845
+ return {
846
+ type: "interaction",
847
+ binding: (0, import_behavioral_ir.runtimeConfigBinding)({
848
+ recognition: PYTHON_ENV_RECOGNITION,
849
+ deploymentTarget: "lambda",
850
+ instanceName: "<unknown>"
851
+ }),
852
+ callee: `os.environ["${read.name}"]`,
853
+ interaction: {
854
+ class: "config-read",
855
+ name: read.name,
856
+ defaulted: read.defaulted
857
+ }
858
+ };
859
+ }
860
+ function envReadAt(node, scope) {
861
+ if (node.type === "subscript") {
862
+ return subscriptRead(node, scope);
863
+ }
864
+ if (node.type === "call") {
865
+ return callRead(node, scope);
866
+ }
867
+ return null;
868
+ }
869
+ function subscriptRead(node, scope) {
870
+ const value = field(node, "value");
871
+ const index = field(node, "subscript");
872
+ if (value === null || index === null || !isEnviron(value, scope)) {
873
+ return null;
874
+ }
875
+ const name = stringLiteralValue(index);
876
+ if (name === null || isAssignedTo(node)) {
877
+ return null;
878
+ }
879
+ return { name, defaulted: isDefaultedAt(node) };
880
+ }
881
+ function isAssignedTo(node) {
882
+ const parent = node.parent;
883
+ if (parent === null) {
884
+ return false;
885
+ }
886
+ if (parent.type === "delete_statement") {
887
+ return true;
888
+ }
889
+ return (parent.type === "assignment" || parent.type === "augmented_assignment") && field(parent, "left")?.id === node.id;
890
+ }
891
+ function callRead(node, scope) {
892
+ const callee = field(node, "function");
893
+ const args = field(node, "arguments");
894
+ if (callee === null || args === null || !isEnvGetter(callee, scope)) {
895
+ return null;
896
+ }
897
+ const positional = args.namedChildren.filter(
898
+ (arg) => arg !== null && arg.type !== "keyword_argument"
899
+ );
900
+ const name = positional[0] === void 0 ? null : stringLiteralValue(positional[0]);
901
+ if (name === null) {
902
+ return null;
903
+ }
904
+ const keywords = args.namedChildren.filter(
905
+ (arg) => arg !== null && arg.type === "keyword_argument"
906
+ );
907
+ const hasDefault = positional.length > 1 || keywords.some((arg) => field(arg, "name")?.text === "default");
908
+ return { name, defaulted: hasDefault || isDefaultedAt(node) };
909
+ }
910
+ function isEnvGetter(callee, scope) {
911
+ if (callee.type === "attribute") {
912
+ const object2 = field(callee, "object");
913
+ const attribute = field(callee, "attribute")?.text;
914
+ if (object2 === null) {
915
+ return false;
916
+ }
917
+ if (attribute === "get") {
918
+ return isEnviron(object2, scope);
919
+ }
920
+ return attribute === "getenv" && isOsModule(object2, scope);
921
+ }
922
+ return isImportedFromOs(callee, scope, "getenv");
923
+ }
924
+ function isEnviron(node, scope) {
925
+ if (node.type === "attribute") {
926
+ const object2 = field(node, "object");
927
+ return object2 !== null && field(node, "attribute")?.text === "environ" && isOsModule(object2, scope);
928
+ }
929
+ return isImportedFromOs(node, scope, "environ");
930
+ }
931
+ function isOsModule(node, scope) {
932
+ if (node.type !== "identifier") {
933
+ return false;
934
+ }
935
+ const binding = resolveName(scope, node.text);
936
+ return binding?.kind === "import" && binding.module === "os" && binding.relativeLevel === 0;
937
+ }
938
+ function isImportedFromOs(node, scope, name) {
939
+ if (node.type !== "identifier") {
940
+ return false;
941
+ }
942
+ const binding = resolveName(scope, node.text);
943
+ return binding?.kind === "importFrom" && binding.module === "os" && binding.relativeLevel === 0 && binding.importedName === name;
944
+ }
945
+ function isDefaultedAt(node) {
946
+ let child = node;
947
+ let parent = node.parent;
948
+ while (parent !== null) {
949
+ if (parent.type === "parenthesized_expression") {
950
+ child = parent;
951
+ parent = parent.parent;
952
+ continue;
953
+ }
954
+ if (parent.type !== "boolean_operator" || field(parent, "operator")?.text !== "or") {
955
+ return false;
956
+ }
957
+ if (field(parent, "left")?.id === child.id) {
958
+ return true;
959
+ }
960
+ child = parent;
961
+ parent = parent.parent;
962
+ }
963
+ return false;
964
+ }
813
965
 
814
966
  // src/facts/resolve.ts
815
- var import_datalog3 = require("@suss/datalog");
967
+ var import_datalog4 = require("@suss/datalog");
816
968
 
817
969
  // ../../resolution/dist/index.js
818
970
  var import_datalog = require("@suss/datalog");
819
971
  var import_datalog2 = require("@suss/datalog");
820
- function joinMountedPath(prefix, path4) {
972
+ var import_datalog3 = require("@suss/datalog");
973
+ function exportTrail(proof, describe3) {
974
+ if (proof.kind !== "derived") {
975
+ return [];
976
+ }
977
+ const name = (0, import_datalog.ruleLabel)(proof.rule);
978
+ if (name === "re-export") {
979
+ const [m, n, m2, n2] = proof.premises[0].tuple;
980
+ return [
981
+ `${describe3(m)} takes ${String(n)} from ${describe3(m2)}, where it is called ${String(n2)}`,
982
+ ...exportTrail(proof.premises[1], describe3)
983
+ ];
984
+ }
985
+ if (name === "re-export all") {
986
+ const [m, m2] = proof.premises[0].tuple;
987
+ return [
988
+ `${describe3(m)} forwards everything ${describe3(m2)} exports`,
989
+ ...exportTrail(proof.premises[1], describe3)
990
+ ];
991
+ }
992
+ return [];
993
+ }
994
+ function argumentReason(proof, describe3) {
995
+ const [, p, a] = proof.tuple;
996
+ if (proof.kind !== "derived") {
997
+ return `${describe3(p)} is a parameter, and a call passes it ${describe3(a)}`;
998
+ }
999
+ const f = proof.premises[0].tuple[0];
1000
+ return `${describe3(p)} is a parameter of ${describe3(f)}, and a call passes it ${describe3(a)}`;
1001
+ }
1002
+ var DEFAULT_PHRASES = {
1003
+ alias: ({ tuple: tuple2, describe: describe3 }) => ({
1004
+ reason: `${describe3(tuple2[0])} is declared as ${describe3(tuple2[1])}`
1005
+ }),
1006
+ "last write": ({ tuple: tuple2, describe: describe3 }) => ({
1007
+ reason: `${describe3(tuple2[0])} is written more than once, and the last write leaves it as ${describe3(tuple2[1])}`
1008
+ }),
1009
+ fallback: ({ tuple: tuple2, describe: describe3 }) => ({
1010
+ reason: `${describe3(tuple2[0])} is a fallback expression, and ${describe3(tuple2[1])} is the branch that resolves`
1011
+ }),
1012
+ import: ({ tuple: tuple2, premises, describe: describe3 }) => {
1013
+ const [, module2, name] = premises[0].tuple;
1014
+ return {
1015
+ reason: `${describe3(tuple2[0])} is imported from ${describe3(module2)} under the name ${String(name)}`,
1016
+ notes: exportTrail(premises[1], describe3)
1017
+ };
1018
+ },
1019
+ argument: ({ premises, describe: describe3 }) => ({
1020
+ reason: argumentReason(premises[0], describe3)
1021
+ }),
1022
+ "property read": ({ tuple: tuple2, premises, describe: describe3 }) => {
1023
+ const [, object2, name] = premises[0].tuple;
1024
+ const contains = premises[2];
1025
+ const inherited = contains.kind === "derived" && contains.premises.length > 1;
1026
+ return {
1027
+ reason: `${describe3(tuple2[0])} reads ${String(name)} off ${describe3(object2)}, which contains ${describe3(tuple2[1])}`,
1028
+ notes: inherited ? [`${String(name)} comes from a base class`] : []
1029
+ };
1030
+ },
1031
+ "class instance": ({ tuple: tuple2, premises, describe: describe3, inline }) => ({
1032
+ reason: `${describe3(tuple2[0])} makes an instance of ${describe3(tuple2[1])}`,
1033
+ notes: inline(premises[1])
1034
+ }),
1035
+ "factory unwrap": ({ tuple: tuple2, premises, describe: describe3, inline }) => {
1036
+ const factory = premises[1].tuple[1];
1037
+ return {
1038
+ reason: `${describe3(tuple2[0])} calls ${describe3(factory)}, a factory that passes its argument through, so it comes down to ${describe3(tuple2[1])}`,
1039
+ notes: inline(premises[1])
1040
+ };
1041
+ },
1042
+ "declared wrapper": ({ tuple: tuple2, premises, describe: describe3 }) => {
1043
+ const callee = String(premises[0].tuple[1]);
1044
+ const module2 = String(premises[2].tuple[1]);
1045
+ const argument = String(premises[1].tuple[1]);
1046
+ return {
1047
+ reason: `${describe3(tuple2[0])} calls ${callee} from ${module2}, which passes argument ${argument} through, so it comes down to ${describe3(tuple2[1])}`,
1048
+ assumptions: [
1049
+ `a pack declares that ${callee} from ${module2} passes argument ${argument} through to its result`
1050
+ ]
1051
+ };
1052
+ },
1053
+ "call result": ({ tuple: tuple2, premises, describe: describe3, inline }) => {
1054
+ const invokes = premises[0];
1055
+ const invoked = invokes.tuple[1];
1056
+ const calleeWalks = invokes.kind === "derived" ? invokes.premises.filter(
1057
+ (premise) => premise.kind === "derived" && (premise.relation === "comesTo" || premise.relation === "givesBack")
1058
+ ) : [];
1059
+ return {
1060
+ reason: `${describe3(tuple2[0])} runs ${describe3(invoked)}, which returns ${describe3(tuple2[1])}`,
1061
+ notes: calleeWalks.flatMap((premise) => inline(premise))
1062
+ };
1063
+ }
1064
+ };
1065
+ var CHAIN_RELATIONS = /* @__PURE__ */ new Set([
1066
+ "resolves",
1067
+ "comesTo",
1068
+ "givesBack",
1069
+ "isWrittenAs",
1070
+ "comesFrom",
1071
+ "reaches",
1072
+ "stepsTo"
1073
+ ]);
1074
+ function inlineChain(proof, state) {
1075
+ const explained = explainResolutionProof(proof, {
1076
+ describe: state.describe,
1077
+ phrases: state.phrases
1078
+ });
1079
+ if (explained === null || explained.steps.length === 0) {
1080
+ return [];
1081
+ }
1082
+ if (explained.truncated) {
1083
+ state.truncated = true;
1084
+ }
1085
+ return explained.steps.map((step) => step.reason);
1086
+ }
1087
+ function stepFrom(proof, state) {
1088
+ const name = (0, import_datalog.ruleLabel)(proof.rule);
1089
+ const phrase = state.phrases[name];
1090
+ const from = proof.tuple[0];
1091
+ const to = proof.tuple[1];
1092
+ if (phrase === void 0) {
1093
+ return {
1094
+ from,
1095
+ to,
1096
+ rule: name,
1097
+ reason: `${state.describe(from)} steps to ${state.describe(to)} (${name})`,
1098
+ notes: [],
1099
+ assumptions: []
1100
+ };
1101
+ }
1102
+ const said = phrase({
1103
+ tuple: proof.tuple,
1104
+ premises: proof.premises,
1105
+ describe: state.describe,
1106
+ inline: (nested) => inlineChain(nested, state)
1107
+ });
1108
+ return {
1109
+ from,
1110
+ to,
1111
+ rule: name,
1112
+ reason: said.reason,
1113
+ notes: said.notes ?? [],
1114
+ assumptions: said.assumptions ?? []
1115
+ };
1116
+ }
1117
+ function importStep(proof, state) {
1118
+ const [x, module2, name] = proof.tuple;
1119
+ return {
1120
+ from: x,
1121
+ to: module2,
1122
+ rule: "import",
1123
+ reason: `${state.describe(x)} is imported from ${state.describe(module2)} under the name ${String(name)}`,
1124
+ notes: [],
1125
+ assumptions: []
1126
+ };
1127
+ }
1128
+ var flattenInto = (proof, state) => {
1129
+ if (proof.kind === "truncated") {
1130
+ state.truncated = true;
1131
+ return;
1132
+ }
1133
+ if (proof.kind !== "derived") {
1134
+ return;
1135
+ }
1136
+ const relation = proof.relation;
1137
+ if (relation === "stepsTo") {
1138
+ state.steps.push(stepFrom(proof, state));
1139
+ return;
1140
+ }
1141
+ if (relation === "reaches") {
1142
+ for (const p of proof.premises) {
1143
+ flattenInto(p, state);
1144
+ }
1145
+ return;
1146
+ }
1147
+ if (relation === "comesFrom") {
1148
+ if (proof.premises.length === 2) {
1149
+ flattenInto(proof.premises[0], state);
1150
+ state.steps.push(importStep(proof.premises[1], state));
1151
+ } else {
1152
+ state.steps.push(importStep(proof.premises[0], state));
1153
+ }
1154
+ return;
1155
+ }
1156
+ for (const p of proof.premises) {
1157
+ if (p.kind === "derived" && (p.relation === "reaches" || p.relation === "comesTo")) {
1158
+ flattenInto(p, state);
1159
+ }
1160
+ if (p.kind === "truncated") {
1161
+ state.truncated = true;
1162
+ }
1163
+ }
1164
+ };
1165
+ function explainResolutionProof(proof, options) {
1166
+ if (proof.kind === "absence") {
1167
+ return null;
1168
+ }
1169
+ if (proof.kind === "derived" && !CHAIN_RELATIONS.has(proof.relation)) {
1170
+ return null;
1171
+ }
1172
+ const state = {
1173
+ steps: [],
1174
+ truncated: proof.kind === "truncated",
1175
+ describe: options.describe,
1176
+ phrases: { ...DEFAULT_PHRASES, ...options.phrases }
1177
+ };
1178
+ flattenInto(proof, state);
1179
+ const atoms = proof.kind === "fact" || proof.kind === "truncated" ? [proof.tuple[0]] : [proof.tuple[0], ...state.steps.map((step) => step.to)];
1180
+ return {
1181
+ atoms,
1182
+ steps: state.steps,
1183
+ assumptions: state.steps.flatMap((step) => step.assumptions),
1184
+ truncated: state.truncated
1185
+ };
1186
+ }
1187
+ function renderExplanation(explanation, describe3) {
1188
+ const lines = [];
1189
+ if (explanation.steps.length > 0) {
1190
+ lines.push(explanation.atoms.map((atom) => describe3(atom)).join(" -> "));
1191
+ }
1192
+ for (const step of explanation.steps) {
1193
+ lines.push(` ${step.reason}`);
1194
+ for (const note of step.notes) {
1195
+ lines.push(` ${note}`);
1196
+ }
1197
+ }
1198
+ for (const assumption of explanation.assumptions) {
1199
+ lines.push(` assuming ${assumption}`);
1200
+ }
1201
+ if (explanation.truncated) {
1202
+ lines.push(" the chain goes on past the proof depth cap");
1203
+ }
1204
+ return lines;
1205
+ }
1206
+ function joinMountedPath(prefix, path6) {
821
1207
  const trimmed = prefix.endsWith("/") ? prefix.slice(0, -1) : prefix;
822
- return trimmed === "" ? path4 : trimmed + path4;
1208
+ return trimmed === "" ? path6 : trimmed + path6;
823
1209
  }
824
1210
  function mountPathsOf(edges, childId) {
825
1211
  return pathsOf(edges, /* @__PURE__ */ new Map(), childId, /* @__PURE__ */ new Set());
@@ -856,323 +1242,417 @@ function pathsOf(edges, memo, childId, visiting) {
856
1242
  memo.set(childId, result);
857
1243
  return result;
858
1244
  }
859
- var VALUE_STEP = (0, import_datalog2.constant)("value");
1245
+ function explainResolvedKey(options) {
1246
+ const { db, rules, key, locate, displayPath } = options;
1247
+ const proofDb = new import_datalog2.Database();
1248
+ let baseFacts = 0;
1249
+ for (const relation of db.relationNames()) {
1250
+ for (const tuple2 of db.facts(relation)) {
1251
+ proofDb.add(relation, tuple2);
1252
+ baseFacts++;
1253
+ }
1254
+ }
1255
+ const started = performance.now();
1256
+ (0, import_datalog2.evaluate)(proofDb, rules, import_datalog2.witnesses);
1257
+ const evaluateMs = performance.now() - started;
1258
+ const derivedFacts = proofDb.relationNames().reduce((count, relation) => count + proofDb.size(relation), 0) - baseFacts;
1259
+ const targets = new Set(
1260
+ proofDb.lookup("resolves", 0, key).map((tuple2) => String(tuple2[1]))
1261
+ );
1262
+ if (targets.size !== 1) {
1263
+ return null;
1264
+ }
1265
+ const target = [...targets][0];
1266
+ const proof = (0, import_datalog2.proofOf)(
1267
+ proofDb,
1268
+ "resolves",
1269
+ [key, target],
1270
+ options.maxDepth === void 0 ? {} : { maxDepth: options.maxDepth }
1271
+ );
1272
+ const describe3 = (atom) => {
1273
+ const location = locate(String(atom));
1274
+ return location === null ? displayPath(String(atom)) : `${location.name} (${location.file}:${location.line})`;
1275
+ };
1276
+ const explanation = explainResolutionProof(proof, {
1277
+ describe: describe3,
1278
+ ...options.phrases === void 0 ? {} : { phrases: options.phrases }
1279
+ });
1280
+ if (explanation === null) {
1281
+ return null;
1282
+ }
1283
+ const targetLocation = locate(target);
1284
+ if (targetLocation === null) {
1285
+ return null;
1286
+ }
1287
+ return {
1288
+ explanation,
1289
+ chain: explanation.atoms.map(describe3),
1290
+ lines: renderExplanation(explanation, describe3),
1291
+ target: targetLocation,
1292
+ stats: { baseFacts, derivedFacts, evaluateMs }
1293
+ };
1294
+ }
1295
+ var NO_PLACEHOLDERS = /* @__PURE__ */ new Set();
1296
+ function singleAnswers(rows, placeholders = NO_PLACEHOLDERS) {
1297
+ const candidates = /* @__PURE__ */ new Map();
1298
+ for (const row of rows) {
1299
+ const key = String(row[0]);
1300
+ const answer = String(row[1]);
1301
+ if (answer === key) {
1302
+ continue;
1303
+ }
1304
+ const set2 = candidates.get(key) ?? /* @__PURE__ */ new Set();
1305
+ set2.add(answer);
1306
+ candidates.set(key, set2);
1307
+ }
1308
+ const settled = /* @__PURE__ */ new Map();
1309
+ for (const [key, set2] of candidates) {
1310
+ const answers = withoutPlaceholders(set2, placeholders);
1311
+ if (answers.length === 1) {
1312
+ settled.set(key, answers[0]);
1313
+ }
1314
+ }
1315
+ return settled;
1316
+ }
1317
+ function placeholderValues(db) {
1318
+ return new Set(db.facts("placeholderValue").map((row) => String(row[0])));
1319
+ }
1320
+ function withoutPlaceholders(answers, placeholders) {
1321
+ const kept = [...answers].filter((answer) => !placeholders.has(answer));
1322
+ if (kept.length === 0) {
1323
+ return [...answers];
1324
+ }
1325
+ return kept;
1326
+ }
1327
+ var VALUE_STEP = (0, import_datalog3.constant)("value");
860
1328
  var NAMESPACE_IMPORT_NAME = "*";
861
- var NAMESPACE_IMPORT = (0, import_datalog2.constant)(NAMESPACE_IMPORT_NAME);
862
- var RESULT_STEP = (0, import_datalog2.constant)("result");
1329
+ var NAMESPACE_IMPORT = (0, import_datalog3.constant)(NAMESPACE_IMPORT_NAME);
1330
+ var RESULT_STEP = (0, import_datalog3.constant)("result");
863
1331
  var RESOLUTION_RULES = [
864
1332
  // Aliasing: const x = y, or an identifier referencing a declaration.
865
1333
  // A language with a hop of its own, like JavaScript's `.bind`, states
866
1334
  // it as a step too, or every question but `comesTo` misses it.
867
- (0, import_datalog2.rule)(
1335
+ (0, import_datalog3.rule)(
868
1336
  "stepsTo",
869
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), VALUE_STEP],
870
- [(0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"))],
1337
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"), VALUE_STEP],
1338
+ [(0, import_datalog3.lit)("binds", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"))],
871
1339
  "alias"
872
1340
  ),
873
1341
  // A name written more than once has the value the last write left
874
1342
  // there. The adapter works out which write that is and stays quiet
875
1343
  // when control flow decides, so such a name steps nowhere at all.
876
- (0, import_datalog2.rule)(
1344
+ (0, import_datalog3.rule)(
877
1345
  "stepsTo",
878
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), VALUE_STEP],
879
- [(0, import_datalog2.lit)("endsHolding", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"))],
1346
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"), VALUE_STEP],
1347
+ [(0, import_datalog3.lit)("endsHolding", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"))],
880
1348
  "last write"
881
1349
  ),
882
1350
  // A fallback says the value is one of its branches, so each branch is
883
1351
  // a step. A branch that resolves to nothing makes no claim, and two
884
1352
  // branches resolving to different things fail the single-answer policy.
885
- (0, import_datalog2.rule)(
1353
+ (0, import_datalog3.rule)(
886
1354
  "stepsTo",
887
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("b"), VALUE_STEP],
888
- [(0, import_datalog2.lit)("fallbackBranch", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("b"))],
1355
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("b"), VALUE_STEP],
1356
+ [(0, import_datalog3.lit)("fallbackBranch", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("b"))],
889
1357
  "fallback"
890
1358
  ),
891
1359
  // An import steps to what the module exports under that name.
892
- (0, import_datalog2.rule)(
1360
+ (0, import_datalog3.rule)(
893
1361
  "stepsTo",
894
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("value"), VALUE_STEP],
1362
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("value"), VALUE_STEP],
895
1363
  [
896
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")),
897
- (0, import_datalog2.lit)("moduleExport", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("value"))
1364
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")),
1365
+ (0, import_datalog3.lit)("moduleExport", (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("value"))
898
1366
  ],
899
1367
  "import"
900
1368
  ),
901
1369
  // A parameter steps to what a call passes it. A function called from
902
1370
  // several places leaves its parameter with more than one value, and a
903
1371
  // caller that needs those apart asks `paramAt`.
904
- (0, import_datalog2.rule)(
1372
+ (0, import_datalog3.rule)(
905
1373
  "stepsTo",
906
- [(0, import_datalog2.variable)("p"), (0, import_datalog2.variable)("a"), VALUE_STEP],
907
- [(0, import_datalog2.lit)("passesArgument", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("p"), (0, import_datalog2.variable)("a"))],
1374
+ [(0, import_datalog3.variable)("p"), (0, import_datalog3.variable)("a"), VALUE_STEP],
1375
+ [(0, import_datalog3.lit)("passesArgument", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("p"), (0, import_datalog3.variable)("a"))],
908
1376
  "argument"
909
1377
  ),
910
1378
  // Reading a property steps to what the object contains under that
911
1379
  // name, whichever way the object arrived: `routes.list` off a name,
912
1380
  // or `make(body).handle` off a call.
913
- (0, import_datalog2.rule)(
1381
+ (0, import_datalog3.rule)(
914
1382
  "stepsTo",
915
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("held"), VALUE_STEP],
1383
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("held"), VALUE_STEP],
916
1384
  [
917
- (0, import_datalog2.lit)("readsProperty", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("n")),
918
- (0, import_datalog2.lit)("objectOf", (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("obj")),
919
- (0, import_datalog2.lit)("contains", (0, import_datalog2.variable)("obj"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("held"))
1385
+ (0, import_datalog3.lit)("readsProperty", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("n")),
1386
+ (0, import_datalog3.lit)("objectOf", (0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("obj")),
1387
+ (0, import_datalog3.lit)("contains", (0, import_datalog3.variable)("obj"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("held"))
920
1388
  ],
921
1389
  "property read"
922
1390
  ),
923
1391
  // Calling a class makes one of it, so the call steps to the class and
924
1392
  // a method read off the result is the one the class declares. The
925
1393
  // caveat below is about a factory function, and a class is not one.
926
- (0, import_datalog2.rule)(
1394
+ (0, import_datalog3.rule)(
927
1395
  "stepsTo",
928
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("cls"), VALUE_STEP],
1396
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("cls"), VALUE_STEP],
929
1397
  [
930
- (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c")),
931
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("cls")),
932
- (0, import_datalog2.lit)("objectValue", (0, import_datalog2.variable)("cls"))
1398
+ (0, import_datalog3.lit)("call", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("c")),
1399
+ (0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("cls")),
1400
+ (0, import_datalog3.lit)("objectValue", (0, import_datalog3.variable)("cls"))
933
1401
  ],
934
1402
  "class instance"
935
1403
  ),
936
1404
  // Wrapper transparency, derived: calling a factory that returns a
937
1405
  // function which calls its parameter k steps to argument k.
938
- (0, import_datalog2.rule)(
1406
+ (0, import_datalog3.rule)(
939
1407
  "stepsTo",
940
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("a"), VALUE_STEP],
1408
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("a"), VALUE_STEP],
941
1409
  [
942
- (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c")),
943
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("f")),
944
- (0, import_datalog2.lit)("unwraps", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("k")),
945
- (0, import_datalog2.lit)("callArg", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("k"), (0, import_datalog2.variable)("a"))
1410
+ (0, import_datalog3.lit)("call", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("c")),
1411
+ (0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("f")),
1412
+ (0, import_datalog3.lit)("unwraps", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("k")),
1413
+ (0, import_datalog3.lit)("callArg", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("k"), (0, import_datalog3.variable)("a"))
946
1414
  ],
947
1415
  "factory unwrap"
948
1416
  ),
949
1417
  // Wrapper transparency, declared: a pack says this callee wraps
950
1418
  // argument k. The callee has to come from the library the pack said,
951
1419
  // so a local object spelled the same way is not mistaken for it.
952
- (0, import_datalog2.rule)(
1420
+ (0, import_datalog3.rule)(
953
1421
  "stepsTo",
954
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("a"), VALUE_STEP],
1422
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("a"), VALUE_STEP],
955
1423
  [
956
- (0, import_datalog2.lit)("calleeName", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("n")),
957
- (0, import_datalog2.lit)("unwrapsByName", (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("k")),
958
- (0, import_datalog2.lit)("wrapperModule", (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("m")),
959
- (0, import_datalog2.lit)("calleeOrigin", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("m")),
960
- (0, import_datalog2.lit)("callArg", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("k"), (0, import_datalog2.variable)("a"))
1424
+ (0, import_datalog3.lit)("calleeName", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("n")),
1425
+ (0, import_datalog3.lit)("unwrapsByName", (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("k")),
1426
+ (0, import_datalog3.lit)("wrapperModule", (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("m")),
1427
+ (0, import_datalog3.lit)("calleeOrigin", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("m")),
1428
+ (0, import_datalog3.lit)("callArg", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("k"), (0, import_datalog3.variable)("a"))
961
1429
  ],
962
1430
  "declared wrapper"
963
1431
  ),
964
1432
  // The one step that runs a function forwards: a call steps to what
965
1433
  // the function it invokes returns.
966
- (0, import_datalog2.rule)(
1434
+ (0, import_datalog3.rule)(
967
1435
  "stepsTo",
968
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("ret"), RESULT_STEP],
969
- [(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"))],
1436
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("ret"), RESULT_STEP],
1437
+ [(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"))],
970
1438
  "call result"
971
1439
  ),
972
- // Where a walk gets to, and whether it ran a call on the way. A value
973
- // step keeps whatever the rest of the walk was, and a result step
974
- // makes the whole walk one that ran a call.
975
- (0, import_datalog2.rule)(
1440
+ // Where a walk gets to, and whether it ran a call on the way. The walk
1441
+ // so far comes first, so demand stays on the value asked about; the
1442
+ // README says what the other order cost.
1443
+ (0, import_datalog3.rule)(
976
1444
  "reaches",
977
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), (0, import_datalog2.variable)("kind")],
978
- [(0, import_datalog2.lit)("stepsTo", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), (0, import_datalog2.variable)("kind"))]
1445
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), (0, import_datalog3.variable)("kind")],
1446
+ [(0, import_datalog3.lit)("stepsTo", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), (0, import_datalog3.variable)("kind"))]
979
1447
  ),
980
- (0, import_datalog2.rule)(
1448
+ (0, import_datalog3.rule)(
981
1449
  "reaches",
982
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), (0, import_datalog2.variable)("kind")],
1450
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), (0, import_datalog3.variable)("kind")],
983
1451
  [
984
- (0, import_datalog2.lit)("stepsTo", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), VALUE_STEP),
985
- (0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"), (0, import_datalog2.variable)("kind"))
1452
+ (0, import_datalog3.lit)("reaches", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"), VALUE_STEP),
1453
+ (0, import_datalog3.lit)("stepsTo", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("z"), (0, import_datalog3.variable)("kind"))
986
1454
  ]
987
1455
  ),
988
- // Two rules rather than one leaving the rest of the walk's kind free.
989
- // A free kind is a second question about the same relation, and a
1456
+ // Two rules rather than one leaving the next step's kind free. A free
1457
+ // kind is a second question about the same relation, and a
990
1458
  // demand-driven run then derives both to answer either.
991
- (0, import_datalog2.rule)(
1459
+ (0, import_datalog3.rule)(
992
1460
  "reaches",
993
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), RESULT_STEP],
1461
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), RESULT_STEP],
994
1462
  [
995
- (0, import_datalog2.lit)("stepsTo", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), RESULT_STEP),
996
- (0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"), VALUE_STEP)
1463
+ (0, import_datalog3.lit)("reaches", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"), RESULT_STEP),
1464
+ (0, import_datalog3.lit)("stepsTo", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("z"), VALUE_STEP)
997
1465
  ]
998
1466
  ),
999
- (0, import_datalog2.rule)(
1467
+ (0, import_datalog3.rule)(
1000
1468
  "reaches",
1001
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), RESULT_STEP],
1469
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), RESULT_STEP],
1002
1470
  [
1003
- (0, import_datalog2.lit)("stepsTo", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), RESULT_STEP),
1004
- (0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"), RESULT_STEP)
1471
+ (0, import_datalog3.lit)("reaches", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"), RESULT_STEP),
1472
+ (0, import_datalog3.lit)("stepsTo", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("z"), RESULT_STEP)
1005
1473
  ]
1006
1474
  ),
1007
1475
  // What a value comes down to: the walk that never ran a call, stopped
1008
1476
  // at a function or an object. Something already written out comes to
1009
1477
  // itself, and every other walk ends at one of those.
1010
- (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"))]),
1011
- (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"))]),
1012
- (0, import_datalog2.rule)(
1478
+ (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"))]),
1479
+ (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"))]),
1480
+ (0, import_datalog3.rule)(
1013
1481
  "comesTo",
1014
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1015
- [(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"))]
1482
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
1483
+ [(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"))]
1016
1484
  ),
1017
- (0, import_datalog2.rule)(
1485
+ (0, import_datalog3.rule)(
1018
1486
  "comesTo",
1019
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1020
- [(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"))]
1487
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
1488
+ [(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"))]
1021
1489
  ),
1022
1490
  // The same stopping condition, for the walk that ran a call. A call
1023
1491
  // gets no `comesTo` answer on purpose: coming back with what a
1024
1492
  // factory returned would fight the unwrapping answer.
1025
- (0, import_datalog2.rule)(
1493
+ (0, import_datalog3.rule)(
1026
1494
  "givesBack",
1027
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1028
- [(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"))]
1495
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
1496
+ [(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"))]
1029
1497
  ),
1030
- (0, import_datalog2.rule)(
1498
+ (0, import_datalog3.rule)(
1031
1499
  "givesBack",
1032
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1033
- [(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"))]
1500
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
1501
+ [(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"))]
1034
1502
  ),
1035
1503
  // Following a value to the expression it is written as, whatever kind
1036
1504
  // that is. A GraphQL document is neither a function nor an object, so
1037
1505
  // `comesTo` never reaches one.
1038
- (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"))]),
1039
- (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"))]),
1040
- (0, import_datalog2.rule)(
1506
+ (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"))]),
1507
+ (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"))]),
1508
+ (0, import_datalog3.rule)(
1509
+ "isWrittenAs",
1510
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
1511
+ [(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"))]
1512
+ ),
1513
+ (0, import_datalog3.rule)(
1041
1514
  "isWrittenAs",
1042
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1043
- [(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"))]
1515
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
1516
+ [(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"))]
1044
1517
  ),
1045
- (0, import_datalog2.rule)(
1518
+ // A call is written as whatever its callee's return value is written
1519
+ // as. Unlike `comesTo`, this has nothing to protect: which expression
1520
+ // a value was written as does not compete with unwrapping it.
1521
+ (0, import_datalog3.rule)(
1046
1522
  "isWrittenAs",
1047
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1048
- [(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"))]
1523
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
1524
+ [
1525
+ (0, import_datalog3.lit)("invokes", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("f")),
1526
+ (0, import_datalog3.lit)("returnsValue", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("ret")),
1527
+ (0, import_datalog3.lit)("isWrittenAs", (0, import_datalog3.variable)("ret"), (0, import_datalog3.variable)("z"))
1528
+ ]
1049
1529
  ),
1050
1530
  // What one call site put in a parameter, told apart from what the
1051
1531
  // other callers passed.
1052
- (0, import_datalog2.rule)(
1532
+ (0, import_datalog3.rule)(
1053
1533
  "paramAt",
1054
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("p"), (0, import_datalog2.variable)("z")],
1534
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("p"), (0, import_datalog3.variable)("z")],
1055
1535
  [
1056
- (0, import_datalog2.lit)("passesArgument", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("p"), (0, import_datalog2.variable)("a")),
1057
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("a"), (0, import_datalog2.variable)("z"))
1536
+ (0, import_datalog3.lit)("passesArgument", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("p"), (0, import_datalog3.variable)("a")),
1537
+ (0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("a"), (0, import_datalog3.variable)("z"))
1058
1538
  ]
1059
1539
  ),
1060
1540
  // An argument arriving at the parameter it is passed to, by position
1061
1541
  // or by the name the caller wrote, keeping the call it went through
1062
1542
  // so `paramAt` can tell two call sites apart.
1063
- (0, import_datalog2.rule)(
1543
+ (0, import_datalog3.rule)(
1064
1544
  "passesArgument",
1065
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("p"), (0, import_datalog2.variable)("a")],
1545
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("p"), (0, import_datalog3.variable)("a")],
1066
1546
  [
1067
- (0, import_datalog2.lit)("paramOf", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("k"), (0, import_datalog2.variable)("p")),
1068
- (0, import_datalog2.lit)("callsFunction", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")),
1069
- (0, import_datalog2.lit)("callArg", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("k"), (0, import_datalog2.variable)("a"))
1547
+ (0, import_datalog3.lit)("paramOf", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("k"), (0, import_datalog3.variable)("p")),
1548
+ (0, import_datalog3.lit)("callsFunction", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("f")),
1549
+ (0, import_datalog3.lit)("callArg", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("k"), (0, import_datalog3.variable)("a"))
1070
1550
  ]
1071
1551
  ),
1072
- (0, import_datalog2.rule)(
1552
+ (0, import_datalog3.rule)(
1073
1553
  "passesArgument",
1074
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("p"), (0, import_datalog2.variable)("a")],
1554
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("p"), (0, import_datalog3.variable)("a")],
1075
1555
  [
1076
- (0, import_datalog2.lit)("paramNamed", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("p")),
1077
- (0, import_datalog2.lit)("callsFunction", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")),
1078
- (0, import_datalog2.lit)("callKeywordArg", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("a"))
1556
+ (0, import_datalog3.lit)("paramNamed", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("p")),
1557
+ (0, import_datalog3.lit)("callsFunction", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("f")),
1558
+ (0, import_datalog3.lit)("callKeywordArg", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("a"))
1079
1559
  ]
1080
1560
  ),
1081
1561
  // Which module's export a re-exported name forwards to, however
1082
1562
  // many barrels deep the forwarding runs.
1083
- (0, import_datalog2.rule)(
1563
+ (0, import_datalog3.rule)(
1084
1564
  "moduleForwards",
1085
- [(0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("m2"), (0, import_datalog2.variable)("n2")],
1086
- [(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"))]
1565
+ [(0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("m2"), (0, import_datalog3.variable)("n2")],
1566
+ [(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"))]
1087
1567
  ),
1088
- (0, import_datalog2.rule)(
1568
+ (0, import_datalog3.rule)(
1089
1569
  "moduleForwards",
1090
- [(0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("m3"), (0, import_datalog2.variable)("n3")],
1570
+ [(0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("m3"), (0, import_datalog3.variable)("n3")],
1091
1571
  [
1092
- (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")),
1093
- (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"))
1572
+ (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")),
1573
+ (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"))
1094
1574
  ]
1095
1575
  ),
1096
1576
  // What a module exports: directly, or through re-export chains.
1097
- (0, import_datalog2.rule)(
1577
+ (0, import_datalog3.rule)(
1098
1578
  "moduleExport",
1099
- [(0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("value")],
1100
- [(0, import_datalog2.lit)("exportsAs", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("value"))],
1579
+ [(0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("value")],
1580
+ [(0, import_datalog3.lit)("exportsAs", (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("value"))],
1101
1581
  "export"
1102
1582
  ),
1103
- (0, import_datalog2.rule)(
1583
+ (0, import_datalog3.rule)(
1104
1584
  "moduleExport",
1105
- [(0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("value")],
1585
+ [(0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("value")],
1106
1586
  [
1107
- (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")),
1108
- (0, import_datalog2.lit)("moduleExport", (0, import_datalog2.variable)("m2"), (0, import_datalog2.variable)("n2"), (0, import_datalog2.variable)("value"))
1587
+ (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")),
1588
+ (0, import_datalog3.lit)("moduleExport", (0, import_datalog3.variable)("m2"), (0, import_datalog3.variable)("n2"), (0, import_datalog3.variable)("value"))
1109
1589
  ],
1110
1590
  "re-export"
1111
1591
  ),
1112
- (0, import_datalog2.rule)(
1592
+ (0, import_datalog3.rule)(
1113
1593
  "moduleExport",
1114
- [(0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("value")],
1594
+ [(0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("value")],
1115
1595
  [
1116
- (0, import_datalog2.lit)("reExportsAll", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("m2")),
1117
- (0, import_datalog2.lit)("moduleExport", (0, import_datalog2.variable)("m2"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("value"))
1596
+ (0, import_datalog3.lit)("reExportsAll", (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("m2")),
1597
+ (0, import_datalog3.lit)("moduleExport", (0, import_datalog3.variable)("m2"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("value"))
1118
1598
  ],
1119
1599
  "re-export all"
1120
1600
  ),
1121
1601
  // The function a call runs, written from the call's side because a
1122
1602
  // caller asking what a call gives back has the call in hand.
1123
- (0, import_datalog2.rule)(
1603
+ (0, import_datalog3.rule)(
1124
1604
  "invokes",
1125
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")],
1126
- [(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"))]
1605
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("f")],
1606
+ [(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"))]
1127
1607
  ),
1128
1608
  // The callee is itself a call: `daoBuilder()()`.
1129
- (0, import_datalog2.rule)(
1609
+ (0, import_datalog3.rule)(
1130
1610
  "invokes",
1131
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")],
1132
- [(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"))]
1611
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("f")],
1612
+ [(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"))]
1133
1613
  ),
1134
1614
  // The object an expression refers to: a name through `comesTo`, a
1135
1615
  // factory call through what it gives back. Naming the step is what
1136
1616
  // makes `routes.list` and `make(body).handle` one rule.
1137
- (0, import_datalog2.rule)(
1617
+ (0, import_datalog3.rule)(
1138
1618
  "objectOf",
1139
- [(0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("obj")],
1140
- [(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"))]
1619
+ [(0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("obj")],
1620
+ [(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"))]
1141
1621
  ),
1142
- (0, import_datalog2.rule)(
1622
+ (0, import_datalog3.rule)(
1143
1623
  "objectOf",
1144
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("obj")],
1145
- [(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"))]
1624
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("obj")],
1625
+ [(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"))]
1146
1626
  ),
1147
1627
  // Which calls a function, found by the name the call is written as
1148
1628
  // rather than by resolving every callee in the project. A caller knows
1149
1629
  // the function and wants its call sites, so both of these start from
1150
1630
  // the function. Starting from `call` instead asks what every call in
1151
1631
  // the project imports, which was 72% of everything derived.
1152
- (0, import_datalog2.rule)(
1632
+ (0, import_datalog3.rule)(
1153
1633
  "callsFunction",
1154
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")],
1155
- [(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"))]
1634
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("f")],
1635
+ [(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"))]
1156
1636
  ),
1157
- (0, import_datalog2.rule)(
1637
+ (0, import_datalog3.rule)(
1158
1638
  "callsFunction",
1159
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")],
1639
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("f")],
1160
1640
  [
1161
- (0, import_datalog2.lit)("moduleExport", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("f")),
1162
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")),
1163
- (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c"))
1641
+ (0, import_datalog3.lit)("moduleExport", (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("f")),
1642
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")),
1643
+ (0, import_datalog3.lit)("call", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("c"))
1164
1644
  ]
1165
1645
  ),
1166
1646
  // The same, for a language whose adapter writes the import down as a
1167
1647
  // declaration and the call's callee as the name referring to it.
1168
- (0, import_datalog2.rule)(
1648
+ (0, import_datalog3.rule)(
1169
1649
  "callsFunction",
1170
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")],
1650
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("f")],
1171
1651
  [
1172
- (0, import_datalog2.lit)("moduleExport", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("f")),
1173
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("d"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")),
1174
- (0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("d")),
1175
- (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c"))
1652
+ (0, import_datalog3.lit)("moduleExport", (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("f")),
1653
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("d"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")),
1654
+ (0, import_datalog3.lit)("binds", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("d")),
1655
+ (0, import_datalog3.lit)("call", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("c"))
1176
1656
  ]
1177
1657
  ),
1178
1658
  // What an object contains, its base class included, so a method the base
@@ -1180,47 +1660,47 @@ var RESOLUTION_RULES = [
1180
1660
  // declare gives two, and the caller decides. This is its own relation
1181
1661
  // rather than more `holdsProperty`, which stays something an adapter
1182
1662
  // states and the rules only read.
1183
- (0, import_datalog2.rule)(
1663
+ (0, import_datalog3.rule)(
1184
1664
  "contains",
1185
- [(0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("held")],
1186
- [(0, import_datalog2.lit)("holdsProperty", (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("held"))]
1665
+ [(0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("held")],
1666
+ [(0, import_datalog3.lit)("holdsProperty", (0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("held"))]
1187
1667
  ),
1188
- (0, import_datalog2.rule)(
1668
+ (0, import_datalog3.rule)(
1189
1669
  "contains",
1190
- [(0, import_datalog2.variable)("cls"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("held")],
1670
+ [(0, import_datalog3.variable)("cls"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("held")],
1191
1671
  [
1192
- (0, import_datalog2.lit)("extends", (0, import_datalog2.variable)("cls"), (0, import_datalog2.variable)("base")),
1193
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("base"), (0, import_datalog2.variable)("baseCls")),
1194
- (0, import_datalog2.lit)("contains", (0, import_datalog2.variable)("baseCls"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("held"))
1672
+ (0, import_datalog3.lit)("extends", (0, import_datalog3.variable)("cls"), (0, import_datalog3.variable)("base")),
1673
+ (0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("base"), (0, import_datalog3.variable)("baseCls")),
1674
+ (0, import_datalog3.lit)("contains", (0, import_datalog3.variable)("baseCls"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("held"))
1195
1675
  ]
1196
1676
  ),
1197
1677
  // Which function a factory returns, and which of its parameters that
1198
1678
  // function calls: together they are what makes it a wrapper.
1199
- (0, import_datalog2.rule)(
1679
+ (0, import_datalog3.rule)(
1200
1680
  "returnsFunc",
1201
- [(0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("g")],
1681
+ [(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("g")],
1202
1682
  [
1203
- (0, import_datalog2.lit)("returnsValue", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("value")),
1204
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("value"), (0, import_datalog2.variable)("g")),
1205
- (0, import_datalog2.lit)("func", (0, import_datalog2.variable)("g"))
1683
+ (0, import_datalog3.lit)("returnsValue", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("value")),
1684
+ (0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("value"), (0, import_datalog3.variable)("g")),
1685
+ (0, import_datalog3.lit)("func", (0, import_datalog3.variable)("g"))
1206
1686
  ]
1207
1687
  ),
1208
1688
  // A call made by a nested closure counts as made by the function
1209
1689
  // that declares it; the closure runs as part of that function.
1210
- (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"))]),
1211
- (0, import_datalog2.rule)(
1690
+ (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"))]),
1691
+ (0, import_datalog3.rule)(
1212
1692
  "bodyCallsDeep",
1213
- [(0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("c")],
1214
- [(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"))]
1693
+ [(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("c")],
1694
+ [(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"))]
1215
1695
  ),
1216
- (0, import_datalog2.rule)(
1696
+ (0, import_datalog3.rule)(
1217
1697
  "unwraps",
1218
- [(0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("k")],
1698
+ [(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("k")],
1219
1699
  [
1220
- (0, import_datalog2.lit)("returnsFunc", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("g")),
1221
- (0, import_datalog2.lit)("bodyCallsDeep", (0, import_datalog2.variable)("g"), (0, import_datalog2.variable)("c")),
1222
- (0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("p")),
1223
- (0, import_datalog2.lit)("paramOf", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("k"), (0, import_datalog2.variable)("p"))
1700
+ (0, import_datalog3.lit)("returnsFunc", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("g")),
1701
+ (0, import_datalog3.lit)("bodyCallsDeep", (0, import_datalog3.variable)("g"), (0, import_datalog3.variable)("c")),
1702
+ (0, import_datalog3.lit)("binds", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("p")),
1703
+ (0, import_datalog3.lit)("paramOf", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("k"), (0, import_datalog3.variable)("p"))
1224
1704
  ]
1225
1705
  ),
1226
1706
  // Argument flow: which parameter a value traces back to. Directly
@@ -1228,304 +1708,289 @@ var RESOLUTION_RULES = [
1228
1708
  // another unwrapping factory. This is what lets
1229
1709
  // `createProtected(h) { return service.withAuth(h); }` unwrap:
1230
1710
  // the returned call passes h through withAuth, which unwraps.
1231
- (0, import_datalog2.rule)(
1711
+ (0, import_datalog3.rule)(
1232
1712
  "flowsToParam",
1233
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("p")],
1713
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("p")],
1234
1714
  [
1235
- (0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("p")),
1236
- (0, import_datalog2.lit)("paramOf", (0, import_datalog2.variable)("anyF"), (0, import_datalog2.variable)("anyK"), (0, import_datalog2.variable)("p"))
1715
+ (0, import_datalog3.lit)("binds", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("p")),
1716
+ (0, import_datalog3.lit)("paramOf", (0, import_datalog3.variable)("anyF"), (0, import_datalog3.variable)("anyK"), (0, import_datalog3.variable)("p"))
1237
1717
  ]
1238
1718
  ),
1239
- (0, import_datalog2.rule)(
1719
+ (0, import_datalog3.rule)(
1240
1720
  "flowsToParam",
1241
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("p")],
1721
+ [(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("p")],
1242
1722
  [
1243
- (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c")),
1244
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("f")),
1245
- (0, import_datalog2.lit)("unwraps", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("k")),
1246
- (0, import_datalog2.lit)("callArg", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("k"), (0, import_datalog2.variable)("a")),
1247
- (0, import_datalog2.lit)("flowsToParam", (0, import_datalog2.variable)("a"), (0, import_datalog2.variable)("p"))
1723
+ (0, import_datalog3.lit)("call", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("c")),
1724
+ (0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("f")),
1725
+ (0, import_datalog3.lit)("unwraps", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("k")),
1726
+ (0, import_datalog3.lit)("callArg", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("k"), (0, import_datalog3.variable)("a")),
1727
+ (0, import_datalog3.lit)("flowsToParam", (0, import_datalog3.variable)("a"), (0, import_datalog3.variable)("p"))
1248
1728
  ]
1249
1729
  ),
1250
- (0, import_datalog2.rule)(
1730
+ (0, import_datalog3.rule)(
1251
1731
  "unwraps",
1252
- [(0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("k")],
1732
+ [(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("k")],
1253
1733
  [
1254
- (0, import_datalog2.lit)("returnsValue", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("value")),
1255
- (0, import_datalog2.lit)("flowsToParam", (0, import_datalog2.variable)("value"), (0, import_datalog2.variable)("p")),
1256
- (0, import_datalog2.lit)("paramOf", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("k"), (0, import_datalog2.variable)("p"))
1734
+ (0, import_datalog3.lit)("returnsValue", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("value")),
1735
+ (0, import_datalog3.lit)("flowsToParam", (0, import_datalog3.variable)("value"), (0, import_datalog3.variable)("p")),
1736
+ (0, import_datalog3.lit)("paramOf", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("k"), (0, import_datalog3.variable)("p"))
1257
1737
  ]
1258
1738
  ),
1259
1739
  // Where a name comes from, when what it refers to lives outside the
1260
1740
  // source being read. A walk ends at something written out in source,
1261
1741
  // so it never reaches a library's own function.
1262
- (0, import_datalog2.rule)(
1742
+ (0, import_datalog3.rule)(
1263
1743
  "comesFrom",
1264
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
1265
- [(0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))]
1744
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
1745
+ [(0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"))]
1266
1746
  ),
1267
- (0, import_datalog2.rule)(
1747
+ (0, import_datalog3.rule)(
1268
1748
  "comesFrom",
1269
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
1749
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
1270
1750
  [
1271
- (0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), VALUE_STEP),
1272
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))
1751
+ (0, import_datalog3.lit)("reaches", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"), VALUE_STEP),
1752
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"))
1273
1753
  ]
1274
1754
  ),
1275
1755
  // Calling f ends up calling the name n that module m exports, one
1276
1756
  // hop through f's own body or deeper through a wrapper of a wrapper.
1277
1757
  // Several results is normal: a composed decorator applies them all.
1278
- (0, import_datalog2.rule)(
1758
+ (0, import_datalog3.rule)(
1279
1759
  "callsInto",
1280
- [(0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
1760
+ [(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
1281
1761
  [
1282
- (0, import_datalog2.lit)("bodyCallsDeep", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("c")),
1283
- (0, import_datalog2.lit)("comesFrom", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))
1762
+ (0, import_datalog3.lit)("bodyCallsDeep", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("c")),
1763
+ (0, import_datalog3.lit)("comesFrom", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"))
1284
1764
  ]
1285
1765
  ),
1286
- (0, import_datalog2.rule)(
1766
+ (0, import_datalog3.rule)(
1287
1767
  "callsInto",
1288
- [(0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
1768
+ [(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
1289
1769
  [
1290
- (0, import_datalog2.lit)("bodyCallsDeep", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("c")),
1291
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("g")),
1292
- (0, import_datalog2.lit)("callsInto", (0, import_datalog2.variable)("g"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))
1770
+ (0, import_datalog3.lit)("bodyCallsDeep", (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("c")),
1771
+ (0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("g")),
1772
+ (0, import_datalog3.lit)("callsInto", (0, import_datalog3.variable)("g"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"))
1293
1773
  ]
1294
1774
  ),
1295
1775
  // The question callers ask: what a value comes to, narrowed to the
1296
1776
  // functions. Objects appear in the middle of chains and never in an
1297
1777
  // answer.
1298
- (0, import_datalog2.rule)(
1778
+ (0, import_datalog3.rule)(
1299
1779
  "resolves",
1300
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1301
- [(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"))]
1780
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
1781
+ [(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"))]
1302
1782
  )
1303
1783
  ];
1304
1784
  var RESOLUTION_QUESTIONS = [
1305
- (0, import_datalog2.rule)(
1785
+ (0, import_datalog3.rule)(
1306
1786
  "wantedResolves",
1307
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1308
- [(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"))]
1787
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
1788
+ [(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"))]
1309
1789
  ),
1310
- (0, import_datalog2.rule)(
1790
+ (0, import_datalog3.rule)(
1311
1791
  "wantedComesTo",
1312
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1313
- [(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"))]
1792
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
1793
+ [(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"))]
1314
1794
  ),
1315
- (0, import_datalog2.rule)(
1795
+ (0, import_datalog3.rule)(
1316
1796
  "wantedComesTo",
1317
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1318
- [(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"))]
1797
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
1798
+ [(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"))]
1319
1799
  ),
1320
- (0, import_datalog2.rule)(
1800
+ (0, import_datalog3.rule)(
1321
1801
  "wantedIsWrittenAs",
1322
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1323
- [(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"))]
1802
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
1803
+ [(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"))]
1324
1804
  ),
1325
1805
  // A call is given no `comesTo`, so this is the only way to ask what
1326
1806
  // object one arrives at, and without it a demand-driven run derives
1327
1807
  // `objectOf` nowhere.
1328
- (0, import_datalog2.rule)(
1808
+ (0, import_datalog3.rule)(
1329
1809
  "wantedObjectOf",
1330
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1331
- [(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"))]
1810
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
1811
+ [(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"))]
1332
1812
  ),
1333
1813
  // Keyed by the parameter, since that is what a caller has in hand
1334
1814
  // when it wants the call sites told apart.
1335
- (0, import_datalog2.rule)(
1815
+ (0, import_datalog3.rule)(
1336
1816
  "wantedParamAt",
1337
- [(0, import_datalog2.variable)("p"), (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("z")],
1338
- [(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"))]
1817
+ [(0, import_datalog3.variable)("p"), (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("z")],
1818
+ [(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"))]
1339
1819
  ),
1340
- (0, import_datalog2.rule)(
1820
+ (0, import_datalog3.rule)(
1341
1821
  "wantedComesFrom",
1342
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
1343
- [(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"))]
1822
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
1823
+ [(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"))]
1344
1824
  ),
1345
1825
  // Call-origin questions, for attribution, in their own demand
1346
1826
  // class. Attribution stops at the import declaration, so nothing
1347
1827
  // here demands reaches or callsInto. The chains are closures with
1348
1828
  // no depth bound: an alias run of any length resolves.
1349
- (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"))]),
1350
- (0, import_datalog2.rule)(
1351
- "callOriginChain",
1352
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1353
- [(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"))]
1354
- ),
1355
- (0, import_datalog2.rule)(
1356
- "callOriginChain",
1357
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1358
- [
1359
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
1360
- (0, import_datalog2.lit)("endsHolding", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))
1361
- ]
1362
- ),
1363
- (0, import_datalog2.rule)(
1829
+ (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"))]),
1830
+ // The chain with at least one hop taken, which is what tells a
1831
+ // destructured binding apart from asking about a node directly. The
1832
+ // whole chain is the seed plus those hops.
1833
+ (0, import_datalog3.rule)(
1364
1834
  "callOriginChain",
1365
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1366
- [
1367
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
1368
- (0, import_datalog2.lit)("fallbackBranch", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))
1369
- ]
1835
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
1836
+ [(0, import_datalog3.lit)("callOriginChainStepped", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"))]
1370
1837
  ),
1371
- // The chain with at least one hop taken, which is what tells a
1372
- // destructured binding apart from asking about a node directly.
1373
- (0, import_datalog2.rule)(
1838
+ (0, import_datalog3.rule)(
1374
1839
  "callOriginChainStepped",
1375
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1376
- [(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"))]
1840
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
1841
+ [(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"))]
1377
1842
  ),
1378
- (0, import_datalog2.rule)(
1843
+ (0, import_datalog3.rule)(
1379
1844
  "callOriginChainStepped",
1380
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1845
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
1381
1846
  [
1382
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
1383
- (0, import_datalog2.lit)("endsHolding", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))
1847
+ (0, import_datalog3.lit)("callOriginChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y")),
1848
+ (0, import_datalog3.lit)("endsHolding", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("z"))
1384
1849
  ]
1385
1850
  ),
1386
- (0, import_datalog2.rule)(
1851
+ (0, import_datalog3.rule)(
1387
1852
  "callOriginChainStepped",
1388
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1853
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
1389
1854
  [
1390
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
1391
- (0, import_datalog2.lit)("fallbackBranch", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))
1855
+ (0, import_datalog3.lit)("callOriginChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y")),
1856
+ (0, import_datalog3.lit)("fallbackBranch", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("z"))
1392
1857
  ]
1393
1858
  ),
1394
- (0, import_datalog2.rule)(
1859
+ (0, import_datalog3.rule)(
1395
1860
  "wantedCallOriginPair",
1396
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
1861
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
1397
1862
  [
1398
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
1399
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))
1863
+ (0, import_datalog3.lit)("callOriginChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y")),
1864
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"))
1400
1865
  ]
1401
1866
  ),
1402
1867
  // An import of a project barrel is an import of what the barrel
1403
1868
  // forwards, so the pair surfaces the module behind the chain.
1404
- (0, import_datalog2.rule)(
1869
+ (0, import_datalog3.rule)(
1405
1870
  "wantedCallOriginPair",
1406
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m2"), (0, import_datalog2.variable)("n2")],
1871
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m2"), (0, import_datalog3.variable)("n2")],
1407
1872
  [
1408
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
1409
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")),
1410
- (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"))
1873
+ (0, import_datalog3.lit)("callOriginChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y")),
1874
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")),
1875
+ (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"))
1411
1876
  ]
1412
1877
  ),
1413
1878
  // A namespace member: the module's export of the member's own name.
1414
1879
  // The imports literal leads, since it is the smallest relation.
1415
- (0, import_datalog2.rule)(
1880
+ (0, import_datalog3.rule)(
1416
1881
  "wantedCallOriginPair",
1417
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("p")],
1882
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("p")],
1418
1883
  [
1419
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("m"), NAMESPACE_IMPORT),
1420
- (0, import_datalog2.lit)("readsProperty", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("p")),
1421
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"))
1884
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("m"), NAMESPACE_IMPORT),
1885
+ (0, import_datalog3.lit)("readsProperty", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("p")),
1886
+ (0, import_datalog3.lit)("callOriginChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"))
1422
1887
  ]
1423
1888
  ),
1424
- (0, import_datalog2.rule)(
1889
+ (0, import_datalog3.rule)(
1425
1890
  "wantedCallOriginPair",
1426
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("p")],
1891
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("p")],
1427
1892
  [
1428
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("d"), (0, import_datalog2.variable)("m"), NAMESPACE_IMPORT),
1429
- (0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("d")),
1430
- (0, import_datalog2.lit)("readsProperty", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("p")),
1431
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"))
1893
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("d"), (0, import_datalog3.variable)("m"), NAMESPACE_IMPORT),
1894
+ (0, import_datalog3.lit)("binds", (0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("d")),
1895
+ (0, import_datalog3.lit)("readsProperty", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("p")),
1896
+ (0, import_datalog3.lit)("callOriginChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"))
1432
1897
  ]
1433
1898
  ),
1434
1899
  // What a call made: through the call to its callee, whose own alias
1435
1900
  // chain leads to the import.
1436
- (0, import_datalog2.rule)(
1901
+ (0, import_datalog3.rule)(
1437
1902
  "callMadeChain",
1438
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("f")],
1439
- [(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"))]
1903
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("f")],
1904
+ [(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"))]
1440
1905
  ),
1441
- (0, import_datalog2.rule)(
1906
+ (0, import_datalog3.rule)(
1442
1907
  "callMadeChain",
1443
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1444
- [(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"))]
1908
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
1909
+ [(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"))]
1445
1910
  ),
1446
- (0, import_datalog2.rule)(
1911
+ (0, import_datalog3.rule)(
1447
1912
  "callMadeChain",
1448
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1449
- [(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"))]
1913
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
1914
+ [(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"))]
1450
1915
  ),
1451
- (0, import_datalog2.rule)(
1916
+ (0, import_datalog3.rule)(
1452
1917
  "wantedCallOriginPair",
1453
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
1918
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
1454
1919
  [
1455
- (0, import_datalog2.lit)("callMadeChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
1456
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))
1920
+ (0, import_datalog3.lit)("callMadeChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y")),
1921
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"))
1457
1922
  ]
1458
1923
  ),
1459
1924
  // A member destructured off what a call made keeps the member name
1460
1925
  // as one more path segment.
1461
- (0, import_datalog2.rule)(
1926
+ (0, import_datalog3.rule)(
1462
1927
  "callMemberChain",
1463
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("p")],
1928
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("p")],
1464
1929
  [
1465
- (0, import_datalog2.lit)("callOriginChainStepped", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("e")),
1466
- (0, import_datalog2.lit)("readsProperty", (0, import_datalog2.variable)("e"), (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("p")),
1467
- (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("f"))
1930
+ (0, import_datalog3.lit)("callOriginChainStepped", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("e")),
1931
+ (0, import_datalog3.lit)("readsProperty", (0, import_datalog3.variable)("e"), (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("p")),
1932
+ (0, import_datalog3.lit)("call", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("f"))
1468
1933
  ]
1469
1934
  ),
1470
- (0, import_datalog2.rule)(
1935
+ (0, import_datalog3.rule)(
1471
1936
  "callMemberChain",
1472
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), (0, import_datalog2.variable)("p")],
1937
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), (0, import_datalog3.variable)("p")],
1473
1938
  [
1474
- (0, import_datalog2.lit)("callMemberChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("p")),
1475
- (0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))
1939
+ (0, import_datalog3.lit)("callMemberChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("p")),
1940
+ (0, import_datalog3.lit)("binds", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("z"))
1476
1941
  ]
1477
1942
  ),
1478
- (0, import_datalog2.rule)(
1943
+ (0, import_datalog3.rule)(
1479
1944
  "callMemberChain",
1480
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), (0, import_datalog2.variable)("p")],
1945
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), (0, import_datalog3.variable)("p")],
1481
1946
  [
1482
- (0, import_datalog2.lit)("callMemberChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("p")),
1483
- (0, import_datalog2.lit)("endsHolding", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))
1947
+ (0, import_datalog3.lit)("callMemberChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("p")),
1948
+ (0, import_datalog3.lit)("endsHolding", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("z"))
1484
1949
  ]
1485
1950
  ),
1486
- (0, import_datalog2.rule)(
1951
+ (0, import_datalog3.rule)(
1487
1952
  "wantedCallOriginMember",
1488
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("p")],
1953
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("p")],
1489
1954
  [
1490
- (0, import_datalog2.lit)("callMemberChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("p")),
1491
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))
1955
+ (0, import_datalog3.lit)("callMemberChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("p")),
1956
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"))
1492
1957
  ]
1493
1958
  ),
1494
- (0, import_datalog2.rule)(
1959
+ (0, import_datalog3.rule)(
1495
1960
  "wantedCallsInto",
1496
- [(0, import_datalog2.variable)("g"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
1961
+ [(0, import_datalog3.variable)("g"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
1497
1962
  [
1498
- (0, import_datalog2.lit)("wantedOrigin", (0, import_datalog2.variable)("x")),
1499
- (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("g")),
1500
- (0, import_datalog2.lit)("callsInto", (0, import_datalog2.variable)("g"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))
1963
+ (0, import_datalog3.lit)("wantedOrigin", (0, import_datalog3.variable)("x")),
1964
+ (0, import_datalog3.lit)("comesTo", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("g")),
1965
+ (0, import_datalog3.lit)("callsInto", (0, import_datalog3.variable)("g"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"))
1501
1966
  ]
1502
1967
  ),
1503
1968
  // Subject identity, its own demand class; the README's subject
1504
1969
  // section says why the origin pair rides on the written-value walk.
1505
- (0, import_datalog2.rule)(
1970
+ (0, import_datalog3.rule)(
1506
1971
  "wantedSubjectWritten",
1507
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("r")],
1508
- [(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"))]
1972
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("r")],
1973
+ [(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"))]
1509
1974
  ),
1510
- (0, import_datalog2.rule)(
1975
+ (0, import_datalog3.rule)(
1511
1976
  "wantedSubjectConstruction",
1512
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
1977
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
1513
1978
  [
1514
- (0, import_datalog2.lit)("wantedSubject", (0, import_datalog2.variable)("x")),
1515
- (0, import_datalog2.lit)("isWrittenAs", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("r")),
1516
- (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c")),
1517
- (0, import_datalog2.lit)("comesFrom", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))
1979
+ (0, import_datalog3.lit)("wantedSubject", (0, import_datalog3.variable)("x")),
1980
+ (0, import_datalog3.lit)("isWrittenAs", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("r")),
1981
+ (0, import_datalog3.lit)("call", (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("c")),
1982
+ (0, import_datalog3.lit)("comesFrom", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"))
1518
1983
  ]
1519
1984
  ),
1520
1985
  // The export table of one module, keyed by the module asked about.
1521
1986
  // The moduleExport rules flatten re-export chains of any length, and
1522
1987
  // the demand cone stays on export facts alone.
1523
- (0, import_datalog2.rule)(
1988
+ (0, import_datalog3.rule)(
1524
1989
  "wantedModuleExport",
1525
- [(0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("value")],
1990
+ [(0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("value")],
1526
1991
  [
1527
- (0, import_datalog2.lit)("wantedExportsOf", (0, import_datalog2.variable)("m")),
1528
- (0, import_datalog2.lit)("moduleExport", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("value"))
1992
+ (0, import_datalog3.lit)("wantedExportsOf", (0, import_datalog3.variable)("m")),
1993
+ (0, import_datalog3.lit)("moduleExport", (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("value"))
1529
1994
  ]
1530
1995
  ),
1531
1996
  // The calls behind a receiver, for a pack that wants the anchor a
@@ -1534,63 +1999,63 @@ var RESOLUTION_QUESTIONS = [
1534
1999
  // A class's ancestry, one hop per extends through the binding that
1535
2000
  // says which class the written base is; the names on the way out
1536
2001
  // are what a storage pack matches its library's bases against.
1537
- (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"))]),
1538
- (0, import_datalog2.rule)(
2002
+ (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"))]),
2003
+ (0, import_datalog3.rule)(
1539
2004
  "ancestryChain",
1540
- [(0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("b2")],
2005
+ [(0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("b2")],
1541
2006
  [
1542
- (0, import_datalog2.lit)("ancestryChain", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("b")),
1543
- (0, import_datalog2.lit)("extends", (0, import_datalog2.variable)("b"), (0, import_datalog2.variable)("x")),
1544
- (0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("b2"))
2007
+ (0, import_datalog3.lit)("ancestryChain", (0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("b")),
2008
+ (0, import_datalog3.lit)("extends", (0, import_datalog3.variable)("b"), (0, import_datalog3.variable)("x")),
2009
+ (0, import_datalog3.lit)("binds", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("b2"))
1545
2010
  ]
1546
2011
  ),
1547
- (0, import_datalog2.rule)(
2012
+ (0, import_datalog3.rule)(
1548
2013
  "wantedBaseName",
1549
- [(0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("n")],
1550
- [(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"))]
2014
+ [(0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("n")],
2015
+ [(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"))]
1551
2016
  ),
1552
- (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"))]),
1553
- (0, import_datalog2.rule)(
2017
+ (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"))]),
2018
+ (0, import_datalog3.rule)(
1554
2019
  "anchorChain",
1555
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1556
- [(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"))]
2020
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
2021
+ [(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"))]
1557
2022
  ),
1558
- (0, import_datalog2.rule)(
2023
+ (0, import_datalog3.rule)(
1559
2024
  "anchorChain",
1560
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1561
- [(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"))]
2025
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
2026
+ [(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"))]
1562
2027
  ),
1563
- (0, import_datalog2.rule)(
2028
+ (0, import_datalog3.rule)(
1564
2029
  "anchorChain",
1565
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1566
- [(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"))]
2030
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
2031
+ [(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"))]
1567
2032
  ),
1568
- (0, import_datalog2.rule)(
2033
+ (0, import_datalog3.rule)(
1569
2034
  "anchorChain",
1570
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
2035
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
1571
2036
  [
1572
- (0, import_datalog2.lit)("anchorChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
1573
- (0, import_datalog2.lit)("imports", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")),
1574
- (0, import_datalog2.lit)("moduleExport", (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"), (0, import_datalog2.variable)("z"))
2037
+ (0, import_datalog3.lit)("anchorChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y")),
2038
+ (0, import_datalog3.lit)("imports", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")),
2039
+ (0, import_datalog3.lit)("moduleExport", (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("z"))
1575
2040
  ]
1576
2041
  ),
1577
- (0, import_datalog2.rule)(
2042
+ (0, import_datalog3.rule)(
1578
2043
  "anchorChain",
1579
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("c")],
1580
- [(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"))]
2044
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("c")],
2045
+ [(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"))]
1581
2046
  ),
1582
- (0, import_datalog2.rule)(
2047
+ (0, import_datalog3.rule)(
1583
2048
  "anchorChain",
1584
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("o")],
2049
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("o")],
1585
2050
  [
1586
- (0, import_datalog2.lit)("anchorChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
1587
- (0, import_datalog2.lit)("readsProperty", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("o"), (0, import_datalog2.variable)("n"))
2051
+ (0, import_datalog3.lit)("anchorChain", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("y")),
2052
+ (0, import_datalog3.lit)("readsProperty", (0, import_datalog3.variable)("y"), (0, import_datalog3.variable)("o"), (0, import_datalog3.variable)("n"))
1588
2053
  ]
1589
2054
  ),
1590
- (0, import_datalog2.rule)(
2055
+ (0, import_datalog3.rule)(
1591
2056
  "wantedAnchorCall",
1592
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("r")],
1593
- [(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"))]
2057
+ [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("r")],
2058
+ [(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"))]
1594
2059
  )
1595
2060
  ];
1596
2061
  var ANSWER_RELATIONS = [
@@ -1598,7 +2063,7 @@ var ANSWER_RELATIONS = [
1598
2063
  ];
1599
2064
 
1600
2065
  // src/facts/resolve.ts
1601
- var RESOLUTION_PROGRAM = (0, import_datalog3.deriveOnDemand)(
2066
+ var RESOLUTION_PROGRAM = (0, import_datalog4.deriveOnDemand)(
1602
2067
  [...RESOLUTION_RULES, ...RESOLUTION_QUESTIONS],
1603
2068
  ANSWER_RELATIONS
1604
2069
  );
@@ -1609,23 +2074,33 @@ function resolveCalls(db, callKeys) {
1609
2074
  for (const callKey of callKeys) {
1610
2075
  db.add("wanted", [callKey]);
1611
2076
  }
1612
- (0, import_datalog3.evaluate)(db, RESOLUTION_PROGRAM.rules);
2077
+ (0, import_datalog4.evaluate)(db, RESOLUTION_PROGRAM.rules);
1613
2078
  }
1614
2079
  function subjectConstructions(db, valueKeys) {
1615
2080
  const found = /* @__PURE__ */ new Map();
1616
2081
  if (valueKeys.length === 0) {
1617
2082
  return found;
1618
2083
  }
1619
- for (const valueKey2 of valueKeys) {
1620
- db.add("wantedSubject", [valueKey2]);
1621
- }
1622
- (0, import_datalog3.evaluate)(db, RESOLUTION_PROGRAM.rules);
1623
- const writtenAs = /* @__PURE__ */ new Map();
1624
- for (const row of db.facts("wantedSubjectWritten")) {
1625
- const written = writtenAs.get(String(row[0])) ?? /* @__PURE__ */ new Set();
1626
- written.add(String(row[1]));
1627
- writtenAs.set(String(row[0]), written);
2084
+ const askSubjects = (keys) => {
2085
+ for (const key of keys) {
2086
+ db.add("wantedSubject", [key]);
2087
+ }
2088
+ (0, import_datalog4.evaluate)(db, RESOLUTION_PROGRAM.rules);
2089
+ };
2090
+ askSubjects(valueKeys);
2091
+ const placeholders = placeholderValues(db);
2092
+ const written = singleAnswers(db.facts("wantedSubjectWritten"), placeholders);
2093
+ const calls = new Set(db.facts("call").map((row) => String(row[0])));
2094
+ const throughCalls = new Set(
2095
+ [...written.values()].filter((candidate) => calls.has(candidate))
2096
+ );
2097
+ if (throughCalls.size > 0) {
2098
+ askSubjects(throughCalls);
1628
2099
  }
2100
+ const writtenThroughCall = singleAnswers(
2101
+ db.facts("wantedSubjectWritten"),
2102
+ placeholders
2103
+ );
1629
2104
  const origins = /* @__PURE__ */ new Map();
1630
2105
  for (const row of db.facts("wantedSubjectConstruction")) {
1631
2106
  const key = `${String(row[0])}|${String(row[1])}`;
@@ -1634,12 +2109,14 @@ function subjectConstructions(db, valueKeys) {
1634
2109
  origins.set(key, listed);
1635
2110
  }
1636
2111
  for (const valueKey2 of valueKeys) {
1637
- const written = writtenAs.get(valueKey2);
1638
- if (written === void 0 || written.size !== 1) {
2112
+ const direct = written.get(valueKey2);
2113
+ if (direct === void 0) {
1639
2114
  continue;
1640
2115
  }
1641
- const constructionKey = [...written][0];
1642
- const from = origins.get(`${valueKey2}|${constructionKey}`);
2116
+ const deeper = calls.has(direct) ? writtenThroughCall.get(direct) : void 0;
2117
+ const constructionKey = deeper ?? direct;
2118
+ const originOf = deeper === void 0 ? valueKey2 : direct;
2119
+ const from = origins.get(`${originOf}|${constructionKey}`);
1643
2120
  if (from !== void 0) {
1644
2121
  found.set(valueKey2, { constructionKey, origins: from });
1645
2122
  }
@@ -1835,6 +2312,9 @@ function emitExpressionFact(emitter, child) {
1835
2312
  if (WRITTEN_VALUE_TYPES.has(child.type)) {
1836
2313
  add(emitter, "writtenValue", nodeId(emitter.filePath, child));
1837
2314
  }
2315
+ if (child.type === "none") {
2316
+ add(emitter, "placeholderValue", nodeId(emitter.filePath, child));
2317
+ }
1838
2318
  }
1839
2319
  function emitExpressionFacts(emitter, node) {
1840
2320
  walkExpressions(emitter, node, (child) => {
@@ -2029,7 +2509,7 @@ function emitValueFacts(db, filePath, root) {
2029
2509
  }
2030
2510
 
2031
2511
  // src/paths/effects.ts
2032
- var import_extractor2 = require("@suss/extractor");
2512
+ var import_extractor3 = require("@suss/extractor");
2033
2513
 
2034
2514
  // src/paths/lowering.ts
2035
2515
  var EXIT_KINDS = {
@@ -2293,7 +2773,7 @@ function predicateOf(node) {
2293
2773
  }
2294
2774
 
2295
2775
  // src/paths/effects.ts
2296
- var NESTED_FUNCTION_TYPES2 = /* @__PURE__ */ new Set(["function_definition", "lambda"]);
2776
+ var NESTED_DEFINITION_TYPES = /* @__PURE__ */ new Set(["function_definition"]);
2297
2777
  var LITERAL_ARGS = {
2298
2778
  string: (node) => ({ kind: "string", value: node.text.slice(1, -1) }),
2299
2779
  integer: (node) => {
@@ -2309,7 +2789,7 @@ var LITERAL_ARGS = {
2309
2789
  };
2310
2790
  function bodyCalls(node, found = []) {
2311
2791
  for (const child of node.namedChildren) {
2312
- if (child === null || NESTED_FUNCTION_TYPES2.has(child.type)) {
2792
+ if (child === null || NESTED_DEFINITION_TYPES.has(child.type)) {
2313
2793
  continue;
2314
2794
  }
2315
2795
  if (child.type === "call") {
@@ -2351,26 +2831,12 @@ function argsOf(call) {
2351
2831
  function calleeText(call) {
2352
2832
  return field(call, "function")?.text ?? call.text;
2353
2833
  }
2354
- function withoutChainLinks(calls) {
2355
- const isLink = /* @__PURE__ */ new Set();
2356
- for (const call of calls) {
2357
- const callee = field(call, "function");
2358
- if (callee === null || callee.type !== "attribute") {
2359
- continue;
2360
- }
2361
- const object2 = field(callee, "object");
2362
- if (object2 !== null && object2.type === "call") {
2363
- isLink.add(object2.id);
2364
- }
2365
- }
2366
- return calls.filter((call) => !isLink.has(call.id));
2367
- }
2368
2834
  function invocationEffects(definitionNode) {
2369
2835
  const body = field(definitionNode, "body");
2370
2836
  if (body === null) {
2371
2837
  return [];
2372
2838
  }
2373
- const calls = withoutChainLinks(bodyCalls(body));
2839
+ const calls = bodyCalls(body).sort((a, b) => a.endIndex - b.endIndex);
2374
2840
  if (calls.length === 0) {
2375
2841
  return [];
2376
2842
  }
@@ -2385,7 +2851,7 @@ function invocationEffects(definitionNode) {
2385
2851
  statements.push(statement);
2386
2852
  }
2387
2853
  const lowered = lowerPythonBody(body, statements);
2388
- const enumerated = (0, import_extractor2.enumerateOrDegrade)(
2854
+ const enumerated = (0, import_extractor3.enumerateOrDegrade)(
2389
2855
  {
2390
2856
  statements: lowered.statements,
2391
2857
  terminalsByStmt: lowered.terminalsByStmt
@@ -2394,7 +2860,7 @@ function invocationEffects(definitionNode) {
2394
2860
  );
2395
2861
  return calls.map((call) => {
2396
2862
  const statement = statementOf.get(call.id);
2397
- const conditions = (0, import_extractor2.sharedGatingConditions)(
2863
+ const conditions = (0, import_extractor3.sharedGatingConditions)(
2398
2864
  statement === void 0 ? void 0 : enumerated.byTerminal.get(statement),
2399
2865
  predicateOf
2400
2866
  );
@@ -3248,10 +3714,10 @@ function mergeDefs(...defs) {
3248
3714
  function cloneDef(schema) {
3249
3715
  return mergeDefs(schema._zod.def);
3250
3716
  }
3251
- function getElementAtPath(obj, path4) {
3252
- if (!path4)
3717
+ function getElementAtPath(obj, path6) {
3718
+ if (!path6)
3253
3719
  return obj;
3254
- return path4.reduce((acc, key) => acc?.[key], obj);
3720
+ return path6.reduce((acc, key) => acc?.[key], obj);
3255
3721
  }
3256
3722
  function promiseAllObject(promisesObj) {
3257
3723
  const keys = Object.keys(promisesObj);
@@ -3660,11 +4126,11 @@ function explicitlyAborted(x, startIndex = 0) {
3660
4126
  }
3661
4127
  return false;
3662
4128
  }
3663
- function prefixIssues(path4, issues) {
4129
+ function prefixIssues(path6, issues) {
3664
4130
  return issues.map((iss) => {
3665
4131
  var _a3;
3666
4132
  (_a3 = iss).path ?? (_a3.path = []);
3667
- iss.path.unshift(path4);
4133
+ iss.path.unshift(path6);
3668
4134
  return iss;
3669
4135
  });
3670
4136
  }
@@ -3811,16 +4277,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
3811
4277
  }
3812
4278
  function formatError(error51, mapper = (issue2) => issue2.message) {
3813
4279
  const fieldErrors = { _errors: [] };
3814
- const processError = (error52, path4 = []) => {
4280
+ const processError = (error52, path6 = []) => {
3815
4281
  for (const issue2 of error52.issues) {
3816
4282
  if (issue2.code === "invalid_union" && issue2.errors.length) {
3817
- issue2.errors.map((issues) => processError({ issues }, [...path4, ...issue2.path]));
4283
+ issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
3818
4284
  } else if (issue2.code === "invalid_key") {
3819
- processError({ issues: issue2.issues }, [...path4, ...issue2.path]);
4285
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
3820
4286
  } else if (issue2.code === "invalid_element") {
3821
- processError({ issues: issue2.issues }, [...path4, ...issue2.path]);
4287
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
3822
4288
  } else {
3823
- const fullpath = [...path4, ...issue2.path];
4289
+ const fullpath = [...path6, ...issue2.path];
3824
4290
  if (fullpath.length === 0) {
3825
4291
  fieldErrors._errors.push(mapper(issue2));
3826
4292
  } else {
@@ -3847,17 +4313,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
3847
4313
  }
3848
4314
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
3849
4315
  const result = { errors: [] };
3850
- const processError = (error52, path4 = []) => {
4316
+ const processError = (error52, path6 = []) => {
3851
4317
  var _a3, _b;
3852
4318
  for (const issue2 of error52.issues) {
3853
4319
  if (issue2.code === "invalid_union" && issue2.errors.length) {
3854
- issue2.errors.map((issues) => processError({ issues }, [...path4, ...issue2.path]));
4320
+ issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
3855
4321
  } else if (issue2.code === "invalid_key") {
3856
- processError({ issues: issue2.issues }, [...path4, ...issue2.path]);
4322
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
3857
4323
  } else if (issue2.code === "invalid_element") {
3858
- processError({ issues: issue2.issues }, [...path4, ...issue2.path]);
4324
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
3859
4325
  } else {
3860
- const fullpath = [...path4, ...issue2.path];
4326
+ const fullpath = [...path6, ...issue2.path];
3861
4327
  if (fullpath.length === 0) {
3862
4328
  result.errors.push(mapper(issue2));
3863
4329
  continue;
@@ -3889,8 +4355,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
3889
4355
  }
3890
4356
  function toDotPath(_path) {
3891
4357
  const segs = [];
3892
- const path4 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
3893
- for (const seg of path4) {
4358
+ const path6 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
4359
+ for (const seg of path6) {
3894
4360
  if (typeof seg === "number")
3895
4361
  segs.push(`[${seg}]`);
3896
4362
  else if (typeof seg === "symbol")
@@ -16582,13 +17048,13 @@ function resolveRef(ref, ctx) {
16582
17048
  if (!ref.startsWith("#")) {
16583
17049
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
16584
17050
  }
16585
- const path4 = ref.slice(1).split("/").filter(Boolean);
16586
- if (path4.length === 0) {
17051
+ const path6 = ref.slice(1).split("/").filter(Boolean);
17052
+ if (path6.length === 0) {
16587
17053
  return ctx.rootSchema;
16588
17054
  }
16589
17055
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
16590
- if (path4[0] === defsKey) {
16591
- const key = path4[1];
17056
+ if (path6[0] === defsKey) {
17057
+ const key = path6[1];
16592
17058
  if (!key || !ctx.defs[key]) {
16593
17059
  throw new Error(`Reference not found: ${ref}`);
16594
17060
  }
@@ -16996,7 +17462,7 @@ function date4(params) {
16996
17462
  // ../../../node_modules/zod/v4/classic/external.js
16997
17463
  config(en_default());
16998
17464
 
16999
- // ../../ir-core/dist/chunk-QHFMZPEG.js
17465
+ // ../../ir-core/dist/chunk-PPQWK62O.js
17000
17466
  function gqlIdentityKey(typeName, fieldName) {
17001
17467
  return `gql:${typeName}.${fieldName}`;
17002
17468
  }
@@ -17282,6 +17748,42 @@ var metricSemantics = defineBoundarySemantics({
17282
17748
  }
17283
17749
  }
17284
17750
  });
17751
+ var HOLE_SPLIT = /(\{[^}]*\})/;
17752
+ function isHole(piece) {
17753
+ return piece.startsWith("{") && piece.endsWith("}");
17754
+ }
17755
+ function parseBoundaryName(name) {
17756
+ const parts = name.split(HOLE_SPLIT).filter((piece) => piece !== "").map(
17757
+ (piece) => isHole(piece) ? { type: "hole", label: piece.slice(1, -1) } : { type: "text", text: piece }
17758
+ );
17759
+ const only = parts.length === 1 ? parts[0] : void 0;
17760
+ if (only !== void 0 && only.type === "hole") {
17761
+ return { type: "reference", path: only.label.split(".") };
17762
+ }
17763
+ if (parts.some((part) => part.type === "hole")) {
17764
+ return { type: "pattern", parts };
17765
+ }
17766
+ return { type: "literal", value: name };
17767
+ }
17768
+ function patternHole(label) {
17769
+ return `{${label}}`;
17770
+ }
17771
+ function namesNothing(name) {
17772
+ return parseBoundaryName(name).type === "reference";
17773
+ }
17774
+ function referenceOf(name) {
17775
+ if (name.type !== "reference") {
17776
+ return null;
17777
+ }
17778
+ const root = name.path[0];
17779
+ if (root === void 0 || name.path.some((part) => part === "")) {
17780
+ return null;
17781
+ }
17782
+ return { root, fields: name.path.slice(1) };
17783
+ }
17784
+ function referenceFromName(name) {
17785
+ return referenceOf(parseBoundaryName(name));
17786
+ }
17285
17787
  var SCHEME_ORIGIN = /^[a-zA-Z][a-zA-Z\d+.-]*:\/\/[^/]*/;
17286
17788
  var PROTOCOL_RELATIVE_ORIGIN = /^\/\/[^/]*/;
17287
17789
  function pathAfterOrigin(text) {
@@ -17308,12 +17810,12 @@ var RestSemanticsSchema = external_exports.object({
17308
17810
  declaredResponses: external_exports.array(external_exports.number()).optional()
17309
17811
  });
17310
17812
  var OPENING_HOLE = /^\{([^{}]+)\}(.*)$/;
17311
- function variableOf(label) {
17312
- const parts = label.split(".");
17313
- return parts[parts.length - 1] ?? label;
17813
+ function baseUrlReference(semantics) {
17814
+ const label = OPENING_HOLE.exec(semantics.path ?? "")?.[1];
17815
+ return label === void 0 ? null : referenceFromName(patternHole(label));
17314
17816
  }
17315
- function normalizePath(path4) {
17316
- let normalized = path4.replace(/:([a-zA-Z_]\w*)/g, "{$1}");
17817
+ function normalizePath(path6) {
17818
+ let normalized = path6.replace(/:([a-zA-Z_]\w*)/g, "{$1}");
17317
17819
  if (normalized.length > 1 && normalized.endsWith("/")) {
17318
17820
  normalized = normalized.slice(0, -1);
17319
17821
  }
@@ -17323,8 +17825,8 @@ function normalizePath(path4) {
17323
17825
  );
17324
17826
  return normalized;
17325
17827
  }
17326
- function pathShape(path4) {
17327
- return normalizePath(path4).replace(/\{[^}]*\}/g, "{}");
17828
+ function pathShape(path6) {
17829
+ return normalizePath(path6).replace(/\{[^}]*\}/g, "{}");
17328
17830
  }
17329
17831
  function methodsAgree(a, b) {
17330
17832
  if (a === null || b === null) {
@@ -17402,8 +17904,8 @@ var restSemantics = defineBoundarySemantics({
17402
17904
  return null;
17403
17905
  }
17404
17906
  const method = semantics.method === null ? "ANY" : semantics.method.toUpperCase();
17405
- const path4 = semantics.path === null ? "?" : normalizePath(semantics.path);
17406
- return `${method} ${path4}`;
17907
+ const path6 = semantics.path === null ? "?" : normalizePath(semantics.path);
17908
+ return `${method} ${path6}`;
17407
17909
  },
17408
17910
  /**
17409
17911
  * A route with both halves stated decides for itself: the method
@@ -17412,14 +17914,14 @@ var restSemantics = defineBoundarySemantics({
17412
17914
  * half might still be the one that handles the request, and nothing
17413
17915
  * here can settle that, so it abstains instead of refusing.
17414
17916
  */
17415
- servesRequest(semantics, method, path4) {
17917
+ servesRequest(semantics, method, path6) {
17416
17918
  if (semantics.method === null || semantics.path === null) {
17417
17919
  return "unknown";
17418
17920
  }
17419
17921
  if (!methodsAgree(semantics.method, method.toUpperCase())) {
17420
17922
  return "nomatch";
17421
17923
  }
17422
- return routePathAdmits(semantics.path, path4) ? "match" : "nomatch";
17924
+ return routePathAdmits(semantics.path, path6) ? "match" : "nomatch";
17423
17925
  },
17424
17926
  /**
17425
17927
  * A route the registration pattern admits is inside it. A route
@@ -17444,22 +17946,20 @@ var restSemantics = defineBoundarySemantics({
17444
17946
  * route parameter, and `/orders/{id}` means every id rather than a
17445
17947
  * variable somebody set.
17446
17948
  */
17447
- groundName(semantics, deployedAs) {
17448
- if (semantics.path === null) {
17449
- return null;
17450
- }
17451
- const opening = OPENING_HOLE.exec(semantics.path);
17452
- if (opening === null) {
17949
+ groundName(semantics, deployment) {
17950
+ const reference = baseUrlReference(semantics);
17951
+ if (reference === null) {
17453
17952
  return null;
17454
17953
  }
17455
- const [, label, rest] = opening;
17456
- const base = deployedAs(variableOf(label));
17954
+ const base = deployment.setTo(reference);
17457
17955
  if (base === null) {
17458
17956
  return null;
17459
17957
  }
17958
+ const rest = OPENING_HOLE.exec(semantics.path ?? "")?.[2] ?? "";
17460
17959
  const grounded = pathAfterOrigin(`${base}${rest}`);
17461
17960
  return { ...semantics, path: grounded === "" ? "/" : grounded };
17462
17961
  },
17962
+ nameReference: baseUrlReference,
17463
17963
  ruleBoundary: {
17464
17964
  // "METHOD /path": one leading token, then an absolute path.
17465
17965
  claims(raw) {
@@ -17535,6 +18035,9 @@ var StorageSemanticsSchema = external_exports.object({
17535
18035
  */
17536
18036
  accessPath: external_exports.string().nullable()
17537
18037
  });
18038
+ function containerReference(semantics) {
18039
+ return semantics.container === null ? null : referenceFromName(semantics.container);
18040
+ }
17538
18041
  var storageSemantics = defineBoundarySemantics({
17539
18042
  name: "storage",
17540
18043
  schema: StorageSemanticsSchema,
@@ -17551,7 +18054,21 @@ var storageSemantics = defineBoundarySemantics({
17551
18054
  exchangesHttpResponses: false,
17552
18055
  reportsUnpairedItself: false,
17553
18056
  identityKey: () => null,
17554
- displayLabel: storageLabel
18057
+ displayLabel: storageLabel,
18058
+ /**
18059
+ * A container the source states as a variable is whatever the
18060
+ * deployment sets that variable to. `{SUBSCRIBERS_TABLE}` in the
18061
+ * code and `prod-subscribers-v1` in the manifest are one table.
18062
+ */
18063
+ groundName(semantics, deployment) {
18064
+ const reference = containerReference(semantics);
18065
+ if (reference === null) {
18066
+ return null;
18067
+ }
18068
+ const name = deployment.setTo(reference);
18069
+ return name === null ? null : { ...semantics, container: name };
18070
+ },
18071
+ nameReference: containerReference
17555
18072
  }
17556
18073
  });
17557
18074
  function storageLabel(semantics) {
@@ -17566,6 +18083,9 @@ var UnitInvocationSemanticsSchema = DeployableUnitSchema.extend({
17566
18083
  name: external_exports.literal("unit-invocation"),
17567
18084
  instanceName: DeployableUnitSchema.shape.instanceName.nullable()
17568
18085
  });
18086
+ function calleeReference(semantics) {
18087
+ return semantics.instanceName === null ? null : referenceFromName(semantics.instanceName);
18088
+ }
17569
18089
  var unitInvocationSemantics = defineBoundarySemantics({
17570
18090
  name: "unit-invocation",
17571
18091
  schema: UnitInvocationSemanticsSchema,
@@ -17588,8 +18108,13 @@ var unitInvocationSemantics = defineBoundarySemantics({
17588
18108
  * being reported as a problem here.
17589
18109
  */
17590
18110
  reportsUnpairedItself: false,
18111
+ /**
18112
+ * A callee the source states only as a variable is not a name for
18113
+ * anything until the deployment fills it in, so it keys as nothing
18114
+ * rather than as a bucket that would agree with itself alone.
18115
+ */
17591
18116
  identityKey(semantics) {
17592
- if (semantics.instanceName === null) {
18117
+ if (semantics.instanceName === null || namesNothing(semantics.instanceName)) {
17593
18118
  return null;
17594
18119
  }
17595
18120
  return unitIdentityKey(
@@ -17605,7 +18130,23 @@ var unitInvocationSemantics = defineBoundarySemantics({
17605
18130
  semantics.deploymentTarget,
17606
18131
  semantics.instanceName
17607
18132
  );
17608
- }
18133
+ },
18134
+ /**
18135
+ * A call that reads its callee's name out of the environment
18136
+ * reaches whichever resource the template wires that variable to.
18137
+ * The logical id is the answer rather than the deployed name,
18138
+ * because the invoked unit's own summary is keyed by the logical
18139
+ * id and neither side ever writes the other's string.
18140
+ */
18141
+ groundName(semantics, deployment) {
18142
+ const reference = calleeReference(semantics);
18143
+ if (reference === null) {
18144
+ return null;
18145
+ }
18146
+ const logicalId = deployment.pointsAt(reference);
18147
+ return logicalId === null ? null : { ...semantics, instanceName: logicalId };
18148
+ },
18149
+ nameReference: calleeReference
17609
18150
  }
17610
18151
  });
17611
18152
  var SemanticsSchema = external_exports.discriminatedUnion("name", [
@@ -18017,76 +18558,15 @@ function returnTypeName(node) {
18017
18558
  }
18018
18559
  return annotation.type === "subscript" ? field(annotation, "value")?.text ?? null : annotation.text;
18019
18560
  }
18020
- function callsIn(node, found = []) {
18021
- for (const child of node.namedChildren) {
18022
- if (child === null) {
18023
- continue;
18024
- }
18025
- if (child.type === "call") {
18026
- found.push(child);
18027
- }
18028
- callsIn(child, found);
18029
- }
18030
- return found;
18561
+ function storageCallees(calls, filePath, couldMatch) {
18562
+ return chainsIn(calls).filter((chain) => couldMatch.has(methodName(chain.root))).map((chain) => field(chain.root, "function")).filter((callee) => callee !== null).map((callee) => nodeId(filePath, callee));
18031
18563
  }
18032
18564
  function storageEffects(calls, options) {
18033
- const seen = /* @__PURE__ */ new Set();
18034
- const asked = new Set(
18035
- options.facts.facts("wanted").map((row) => String(row[0]))
18036
- );
18037
- const gather = (inCalls, filePath) => {
18038
- const found = [...directStorageEffects(inCalls, { ...options, filePath })];
18039
- resolveCalls(
18040
- options.facts,
18041
- inCalls.filter((call) => options.leadsToStorage.has(methodName(call))).map((call) => field(call, "function")).filter((callee) => callee !== null).map((callee) => calleeKeyOf(filePath, callee)).filter((key) => {
18042
- const fresh = !asked.has(key);
18043
- asked.add(key);
18044
- return fresh;
18045
- })
18046
- );
18047
- for (const call of inCalls) {
18048
- const callee = field(call, "function");
18049
- if (callee === null || !options.leadsToStorage.has(methodName(call))) {
18050
- continue;
18051
- }
18052
- const key = resolvedOnce(options, calleeKeyOf(filePath, callee));
18053
- const body = key === void 0 ? void 0 : options.definitionAt(key);
18054
- if (key === void 0 || body === void 0 || seen.has(key)) {
18055
- continue;
18056
- }
18057
- seen.add(key);
18058
- const name = field(body, "name")?.text;
18059
- const origin = {
18060
- file: fileOf(key),
18061
- line: body.startPosition.row + 1,
18062
- ...name === void 0 ? {} : { function: name }
18063
- };
18064
- found.push(
18065
- ...gather(callsIn(body), fileOf(key)).map(
18066
- (effect) => effect.type === "interaction" && effect.origin === void 0 ? { ...effect, origin } : effect
18067
- )
18068
- );
18069
- }
18070
- return found;
18071
- };
18072
- return gather(calls, options.filePath);
18073
- }
18074
- function calleeKeyOf(filePath, callee) {
18075
- return callee.type === "identifier" ? `${filePath}#${callee.text}` : nodeId(filePath, callee);
18076
- }
18077
- function resolvedOnce(options, calleeKey) {
18078
- const resolved = options.facts.facts("wantedResolves").filter((row) => String(row[0]) === calleeKey).map((row) => String(row[1]));
18079
- return resolved.length === 1 ? resolved[0] : void 0;
18080
- }
18081
- function storageCallees(calls, filePath, couldMatch) {
18082
- return chainsIn(calls).filter((chain) => couldMatch.has(methodName(chain.root))).map((chain) => field(chain.root, "function")).filter((callee) => callee !== null).map((callee) => nodeId(filePath, callee));
18083
- }
18084
- function directStorageEffects(calls, options) {
18085
- if (options.patterns.length === 0) {
18086
- return [];
18087
- }
18088
- const named = new Set(
18089
- options.patterns.flatMap((pattern) => pattern.queryFunctions ?? [])
18565
+ if (options.patterns.length === 0) {
18566
+ return [];
18567
+ }
18568
+ const named = new Set(
18569
+ options.patterns.flatMap((pattern) => pattern.queryFunctions ?? [])
18090
18570
  );
18091
18571
  const chains = chainsIn(calls).filter(
18092
18572
  (chain) => options.couldMatch.has(methodName(chain.root)) || named.has(methodName(chain.root))
@@ -18139,7 +18619,7 @@ function directStorageEffects(calls, options) {
18139
18619
  // src/discovery.ts
18140
18620
  function decoratedStatements(root, module2) {
18141
18621
  const found = [];
18142
- (0, import_extractor3.walkDescendants)(
18622
+ (0, import_extractor4.walkDescendants)(
18143
18623
  root,
18144
18624
  { scope: module2.moduleScope, enclosingFunction: null },
18145
18625
  {
@@ -18178,21 +18658,21 @@ function builtSubjects(decorated, options) {
18178
18658
  }
18179
18659
  const factsPath = options.absoluteFile ?? options.filePath;
18180
18660
  const asked = /* @__PURE__ */ new Set();
18181
- for (const { enclosingFunction, decorators } of decorated) {
18661
+ for (const { enclosingFunction: enclosingFunction2, decorators } of decorated) {
18182
18662
  for (const { node, direct } of decorators) {
18183
18663
  if (direct.module !== null && acceptedByAnyPattern(direct.module, options)) {
18184
18664
  continue;
18185
18665
  }
18186
18666
  const written = decoratorReceiver(node);
18187
18667
  if (written !== null) {
18188
- asked.add(readKey(factsPath, written.object, enclosingFunction));
18668
+ asked.add(readKey(factsPath, written.object, enclosingFunction2));
18189
18669
  }
18190
18670
  }
18191
18671
  }
18192
18672
  return subjectConstructions(facts, [...asked]);
18193
18673
  }
18194
18674
  function decoratedUnits(decoratedStatement, module2, options, subjects) {
18195
- const { stmt, scope, enclosingFunction, decorators } = decoratedStatement;
18675
+ const { stmt, scope, enclosingFunction: enclosingFunction2, decorators } = decoratedStatement;
18196
18676
  const units = [];
18197
18677
  const { definition } = stripDecorators(stmt);
18198
18678
  for (const { node: decoratorNode, direct } of decorators) {
@@ -18208,7 +18688,7 @@ function decoratedUnits(decoratedStatement, module2, options, subjects) {
18208
18688
  ) ?? null
18209
18689
  ) ?? builtSubjectClassification(
18210
18690
  decoratorNode,
18211
- enclosingFunction,
18691
+ enclosingFunction2,
18212
18692
  subjects,
18213
18693
  options
18214
18694
  )
@@ -18244,14 +18724,14 @@ function acceptedByAnyPattern(module2, options) {
18244
18724
  (pack) => pack.discovery.some((pattern) => pattern.importModule.includes(module2))
18245
18725
  );
18246
18726
  }
18247
- function builtSubjectClassification(decoratorNode, enclosingFunction, subjects, options) {
18727
+ function builtSubjectClassification(decoratorNode, enclosingFunction2, subjects, options) {
18248
18728
  const written = decoratorReceiver(decoratorNode);
18249
18729
  if (written === null) {
18250
18730
  return null;
18251
18731
  }
18252
18732
  const factsPath = options.absoluteFile ?? options.filePath;
18253
18733
  const built = subjects.get(
18254
- readKey(factsPath, written.object, enclosingFunction)
18734
+ readKey(factsPath, written.object, enclosingFunction2)
18255
18735
  );
18256
18736
  const origin = built?.origins.find(
18257
18737
  (candidate) => acceptedByAnyPattern(candidate.module, options)
@@ -18310,23 +18790,23 @@ function unitsFor(pattern, pack, decoratorModule, classification, definition, mo
18310
18790
  );
18311
18791
  }
18312
18792
  };
18313
- return (0, import_behavioral_ir.dispatchByType)(table, pattern);
18793
+ return (0, import_behavioral_ir2.dispatchByType)(table, pattern);
18314
18794
  }
18315
18795
  function readPathArgument(classification) {
18316
18796
  const first = classification.args[0];
18317
18797
  if (first?.kind === "string") {
18318
- return (0, import_extractor3.writtenReading)(first.value, classification.range);
18798
+ return (0, import_extractor4.writtenReading)(first.value, classification.range);
18319
18799
  }
18320
- return (0, import_extractor3.unreadableReading)(
18800
+ return (0, import_extractor4.unreadableReading)(
18321
18801
  "The path in this route's decorator is not a string literal, so the binding names no path and nothing pairs with it",
18322
18802
  classification.range
18323
18803
  );
18324
18804
  }
18325
18805
  var NO_PATH_PARAMS = /* @__PURE__ */ new Set();
18326
18806
  function templateReader(template) {
18327
- return (path4) => {
18807
+ return (path6) => {
18328
18808
  const names = [];
18329
- const canonical = path4.replace(template, (_match, name) => {
18809
+ const canonical = path6.replace(template, (_match, name) => {
18330
18810
  names.push(name);
18331
18811
  return `{${name}}`;
18332
18812
  });
@@ -18339,19 +18819,19 @@ var PATH_TEMPLATE_READERS = {
18339
18819
  /<(?:[A-Za-z_]\w*(?:\(.*?\))?:)?([A-Za-z_]\w*)>/g
18340
18820
  )
18341
18821
  };
18342
- function readPathTemplate(pattern, path4, range) {
18822
+ function readPathTemplate(pattern, path6, range) {
18343
18823
  const syntax = pattern.pathParamSyntax;
18344
18824
  if (syntax === void 0) {
18345
- return (0, import_extractor3.writtenReading)({ path: path4, paramNames: NO_PATH_PARAMS }, range);
18825
+ return (0, import_extractor4.writtenReading)({ path: path6, paramNames: NO_PATH_PARAMS }, range);
18346
18826
  }
18347
18827
  const reader = PATH_TEMPLATE_READERS[syntax];
18348
18828
  if (reader === void 0) {
18349
- return (0, import_extractor3.unreadableReading)(
18829
+ return (0, import_extractor4.unreadableReading)(
18350
18830
  `The route's pack declares path-parameter syntax "${syntax}", which this adapter has no reader for, so the binding names no path and nothing pairs with it`,
18351
18831
  range
18352
18832
  );
18353
18833
  }
18354
- return (0, import_extractor3.writtenReading)(reader(path4), range);
18834
+ return (0, import_extractor4.writtenReading)(reader(path6), range);
18355
18835
  }
18356
18836
  function classRouteUnits(pattern, pack, classification, classNode, module2, options) {
18357
18837
  const pathArgument = readPathArgument(classification);
@@ -18400,7 +18880,7 @@ function classRouteUnits(pattern, pack, classification, classNode, module2, opti
18400
18880
  module: module2,
18401
18881
  filePath: options.filePath,
18402
18882
  skipReceiverParam: true,
18403
- responseShape: import_extractor3.absentReading,
18883
+ responseShape: import_extractor4.absentReading,
18404
18884
  statusCode: defaultedStatus(
18405
18885
  readReturnedStatus(pattern, maybeMethod),
18406
18886
  pattern
@@ -18415,13 +18895,13 @@ function classRouteUnits(pattern, pack, classification, classNode, module2, opti
18415
18895
  return units;
18416
18896
  }
18417
18897
  function readRoutePath(pattern, pathArgument, classification, module2, options) {
18418
- const composed = (0, import_extractor3.andThenReading)(
18898
+ const composed = (0, import_extractor4.andThenReading)(
18419
18899
  pathArgument,
18420
18900
  (literal2, range) => composeRoutePath(pattern, classification, module2, options, literal2, range)
18421
18901
  );
18422
- return (0, import_extractor3.andThenReading)(
18902
+ return (0, import_extractor4.andThenReading)(
18423
18903
  composed,
18424
- (path4, range) => readPathTemplate(pattern, path4, range)
18904
+ (path6, range) => readPathTemplate(pattern, path6, range)
18425
18905
  );
18426
18906
  }
18427
18907
  function readRoutePaths(pattern, pathArgument, classification, module2, options) {
@@ -18445,12 +18925,12 @@ function readRoutePaths(pattern, pathArgument, classification, module2, options)
18445
18925
  ];
18446
18926
  }
18447
18927
  return resolution.values.map((prefix) => ({
18448
- routePath: (0, import_extractor3.andThenReading)(
18449
- (0, import_extractor3.andThenReading)(
18928
+ routePath: (0, import_extractor4.andThenReading)(
18929
+ (0, import_extractor4.andThenReading)(
18450
18930
  pathArgument,
18451
- (literal2, range) => (0, import_extractor3.writtenReading)(servedSpelling(pattern, prefix + literal2), range)
18931
+ (literal2, range) => (0, import_extractor4.writtenReading)(servedSpelling(pattern, prefix + literal2), range)
18452
18932
  ),
18453
- (path4, range) => readPathTemplate(pattern, path4, range)
18933
+ (path6, range) => readPathTemplate(pattern, path6, range)
18454
18934
  ),
18455
18935
  mount: { siblings: resolution.values.length, prefix }
18456
18936
  }));
@@ -18484,19 +18964,19 @@ function composeRoutePath(pattern, classification, module2, options, literal2, r
18484
18964
  range
18485
18965
  );
18486
18966
  if (prefix.kind === "absent") {
18487
- return (0, import_extractor3.writtenReading)(servedSpelling(pattern, literal2), range);
18967
+ return (0, import_extractor4.writtenReading)(servedSpelling(pattern, literal2), range);
18488
18968
  }
18489
- return (0, import_extractor3.mapReading)(
18969
+ return (0, import_extractor4.mapReading)(
18490
18970
  prefix,
18491
18971
  (value) => servedSpelling(pattern, value + literal2)
18492
18972
  );
18493
18973
  }
18494
18974
  var REPEATED_SLASH_READERS = {
18495
- kept: (path4) => path4,
18496
- merged: (path4) => path4.replace(/\/{2,}/g, "/")
18975
+ kept: (path6) => path6,
18976
+ merged: (path6) => path6.replace(/\/{2,}/g, "/")
18497
18977
  };
18498
- function servedSpelling(pattern, path4) {
18499
- return REPEATED_SLASH_READERS[pattern.pathRepeatedSlashes ?? "kept"](path4);
18978
+ function servedSpelling(pattern, path6) {
18979
+ return REPEATED_SLASH_READERS[pattern.pathRepeatedSlashes ?? "kept"](path6);
18500
18980
  }
18501
18981
  function readRouterPrefix(pattern, classification, module2, options, range) {
18502
18982
  const resolution = routerResolutionOf(
@@ -18506,31 +18986,31 @@ function readRouterPrefix(pattern, classification, module2, options, range) {
18506
18986
  options
18507
18987
  );
18508
18988
  if (resolution === null) {
18509
- return import_extractor3.absentReading;
18989
+ return import_extractor4.absentReading;
18510
18990
  }
18511
18991
  if (resolution.kind === "abstain") {
18512
- return (0, import_extractor3.unreadableReading)(
18992
+ return (0, import_extractor4.unreadableReading)(
18513
18993
  `The router this route is declared on ${resolution.reason}, so the binding names no path and nothing pairs with it`,
18514
18994
  range
18515
18995
  );
18516
18996
  }
18517
18997
  if (resolution.kind === "composed") {
18518
- return (0, import_extractor3.writtenReading)(resolution.value, range);
18998
+ return (0, import_extractor4.writtenReading)(resolution.value, range);
18519
18999
  }
18520
- return import_extractor3.absentReading;
19000
+ return import_extractor4.absentReading;
18521
19001
  }
18522
19002
  function readStatusCode(pattern, classification) {
18523
19003
  if (pattern.statusCodeKeyword === void 0) {
18524
- return import_extractor3.absentReading;
19004
+ return import_extractor4.absentReading;
18525
19005
  }
18526
19006
  const arg = classification.keywordArgs[pattern.statusCodeKeyword];
18527
19007
  if (arg === void 0) {
18528
- return import_extractor3.absentReading;
19008
+ return import_extractor4.absentReading;
18529
19009
  }
18530
19010
  if (arg.kind === "number") {
18531
- return (0, import_extractor3.writtenReading)(arg.value, classification.range);
19011
+ return (0, import_extractor4.writtenReading)(arg.value, classification.range);
18532
19012
  }
18533
- return (0, import_extractor3.unreadableReading)(
19013
+ return (0, import_extractor4.unreadableReading)(
18534
19014
  "The status this route's decorator states is not a literal number, so the response claims no status",
18535
19015
  classification.range
18536
19016
  );
@@ -18575,7 +19055,7 @@ function statusOfReturn(statement) {
18575
19055
  }
18576
19056
  function effectsReaching(effects, conditions) {
18577
19057
  return effects.filter(
18578
- (effect) => (0, import_extractor3.guardsHoldOn)(effect.preconditions, conditions)
19058
+ (effect) => (0, import_extractor4.guardsHoldOn)(effect.preconditions, conditions)
18579
19059
  );
18580
19060
  }
18581
19061
  function branchesFromReturns(readsReturnedStatus, definitionNode, effects, responseShape, declaredStatus) {
@@ -18588,7 +19068,7 @@ function branchesFromReturns(readsReturnedStatus, definitionNode, effects, respo
18588
19068
  return null;
18589
19069
  }
18590
19070
  const lowered = lowerPythonBody(body, returns);
18591
- const enumerated = (0, import_extractor3.enumerateOrDegrade)(
19071
+ const enumerated = (0, import_extractor4.enumerateOrDegrade)(
18592
19072
  {
18593
19073
  statements: lowered.statements,
18594
19074
  terminalsByStmt: lowered.terminalsByStmt
@@ -18604,12 +19084,12 @@ function branchesFromReturns(readsReturnedStatus, definitionNode, effects, respo
18604
19084
  const read = statusOfReturn(statement);
18605
19085
  const range = rangeOf(statement);
18606
19086
  const writtenBody = returnedBodyShape(statement);
18607
- const statusReading = read.kind === "status" ? (0, import_extractor3.writtenReading)(read.value, range) : read.kind === "none" ? import_extractor3.absentReading : (0, import_extractor3.unreadableReading)(
19087
+ const statusReading = read.kind === "status" ? (0, import_extractor4.writtenReading)(read.value, range) : read.kind === "none" ? import_extractor4.absentReading : (0, import_extractor4.unreadableReading)(
18608
19088
  "This return gives a status this reading cannot resolve to a number, so this outcome claims none",
18609
19089
  range
18610
19090
  );
18611
- for (const path4 of paths) {
18612
- const conditions = path4.map((condition) => ({
19091
+ for (const path6 of paths) {
19092
+ const conditions = path6.map((condition) => ({
18613
19093
  sourceText: condition.sourceText,
18614
19094
  structured: condition.expression === null ? null : predicateOf(condition.expression),
18615
19095
  polarity: condition.polarity,
@@ -18634,11 +19114,11 @@ function branchesFromReturns(readsReturnedStatus, definitionNode, effects, respo
18634
19114
  ...declaredStatus.libraryDefault !== void 0 ? { libraryDefault: declaredStatus.libraryDefault } : {}
18635
19115
  },
18636
19116
  bodyShapeReading: {
18637
- reading: writtenBody === null ? responseShape.reading : (0, import_extractor3.writtenReading)(writtenBody, range)
19117
+ reading: writtenBody === null ? responseShape.reading : (0, import_extractor4.writtenReading)(writtenBody, range)
18638
19118
  },
18639
19119
  effects: effectsReaching(effects, conditions),
18640
19120
  location: range,
18641
- isDefault: path4.length === 0
19121
+ isDefault: path6.length === 0
18642
19122
  });
18643
19123
  }
18644
19124
  }
@@ -18646,7 +19126,7 @@ function branchesFromReturns(readsReturnedStatus, definitionNode, effects, respo
18646
19126
  }
18647
19127
  function readReturnedStatus(pattern, definitionNode) {
18648
19128
  if (pattern.statusFromReturnedTuple !== true) {
18649
- return import_extractor3.absentReading;
19129
+ return import_extractor4.absentReading;
18650
19130
  }
18651
19131
  const range = rangeOf(definitionNode);
18652
19132
  const statuses = /* @__PURE__ */ new Set();
@@ -18663,23 +19143,23 @@ function readReturnedStatus(pattern, definitionNode) {
18663
19143
  }
18664
19144
  }
18665
19145
  if (unreadable > 0) {
18666
- return (0, import_extractor3.unreadableReading)(
19146
+ return (0, import_extractor4.unreadableReading)(
18667
19147
  "This route returns a status this reading cannot resolve to a number, so no status is claimed for it",
18668
19148
  range
18669
19149
  );
18670
19150
  }
18671
19151
  if (statuses.size === 0) {
18672
- return import_extractor3.absentReading;
19152
+ return import_extractor4.absentReading;
18673
19153
  }
18674
19154
  const candidates = [...statuses];
18675
19155
  if (statuses.size > 1 || plainReturns > 0) {
18676
- return (0, import_extractor3.ambiguousReading)(
19156
+ return (0, import_extractor4.ambiguousReading)(
18677
19157
  candidates,
18678
19158
  "This route returns more than one status depending on which branch runs, and nothing here reads which, so no status is claimed for it",
18679
19159
  range
18680
19160
  );
18681
19161
  }
18682
- return (0, import_extractor3.writtenReading)(candidates[0], range);
19162
+ return (0, import_extractor4.writtenReading)(candidates[0], range);
18683
19163
  }
18684
19164
  function declaredOrReturnedStatus(declared, returned) {
18685
19165
  return declared.kind === "absent" ? returned : declared;
@@ -18692,19 +19172,19 @@ function defaultedStatus(reading, pattern) {
18692
19172
  }
18693
19173
  function readResponseModel(pattern, classification, module2, ctx) {
18694
19174
  if (pattern.responseModelKeyword === void 0) {
18695
- return import_extractor3.absentReading;
19175
+ return import_extractor4.absentReading;
18696
19176
  }
18697
19177
  const arg = classification.keywordArgs[pattern.responseModelKeyword];
18698
19178
  if (arg === void 0) {
18699
- return import_extractor3.absentReading;
19179
+ return import_extractor4.absentReading;
18700
19180
  }
18701
19181
  if (arg.kind === "identifier") {
18702
- return (0, import_extractor3.writtenReading)(
19182
+ return (0, import_extractor4.writtenReading)(
18703
19183
  shapeFromName(arg.name, module2.moduleScope, ctx),
18704
19184
  classification.range
18705
19185
  );
18706
19186
  }
18707
- return (0, import_extractor3.unreadableReading)(
19187
+ return (0, import_extractor4.unreadableReading)(
18708
19188
  "The response model this route's decorator states is not a name, so the response claims no body shape",
18709
19189
  classification.range
18710
19190
  );
@@ -18712,9 +19192,9 @@ function readResponseModel(pattern, classification, module2, ctx) {
18712
19192
  function readReturnAnnotation(definitionNode, scope, ctx) {
18713
19193
  const returnTypeNode = field(definitionNode, "return_type");
18714
19194
  if (returnTypeNode === null) {
18715
- return import_extractor3.absentReading;
19195
+ return import_extractor4.absentReading;
18716
19196
  }
18717
- return (0, import_extractor3.writtenReading)(
19197
+ return (0, import_extractor4.writtenReading)(
18718
19198
  annotationToShape(returnTypeNode, scope, ctx),
18719
19199
  rangeOf(returnTypeNode)
18720
19200
  );
@@ -18767,7 +19247,7 @@ function readResponseShape(declared, readAnnotation) {
18767
19247
  if (declared.kind === "written") {
18768
19248
  return { reading: declared, passedOver: [] };
18769
19249
  }
18770
- return (0, import_extractor3.firstWrittenReading)([declared, readAnnotation()]);
19250
+ return (0, import_extractor4.firstWrittenReading)([declared, readAnnotation()]);
18771
19251
  }
18772
19252
  function routeUnitOrAbstention(unitOptions, options) {
18773
19253
  try {
@@ -18795,7 +19275,7 @@ function unbuiltRouteUnit(unitOptions, error51) {
18795
19275
  exportName: unitOptions.exportPath[0] ?? unitOptions.name,
18796
19276
  exportPath: unitOptions.exportPath
18797
19277
  },
18798
- boundaryBinding: (0, import_behavioral_ir.restBinding)({
19278
+ boundaryBinding: (0, import_behavioral_ir2.restBinding)({
18799
19279
  transport: unitOptions.pack.protocol,
18800
19280
  method: nullIfEmpty(unitOptions.method),
18801
19281
  path: null,
@@ -18807,7 +19287,7 @@ function unbuiltRouteUnit(unitOptions, error51) {
18807
19287
  dependencyCalls: [],
18808
19288
  declaredContract: null,
18809
19289
  readings: [
18810
- (0, import_extractor3.unreadableReading)(
19290
+ (0, import_extractor4.unreadableReading)(
18811
19291
  `This route could not be read into a unit (${message}), so the binding names no path and nothing pairs with it`,
18812
19292
  range
18813
19293
  )
@@ -18833,7 +19313,7 @@ function buildRouteUnit(options) {
18833
19313
  definitionsCtx,
18834
19314
  storage: storageLookup
18835
19315
  } = options;
18836
- const template = (0, import_extractor3.valueToReadFurtherFrom)(routePath);
19316
+ const template = (0, import_extractor4.valueToReadFurtherFrom)(routePath);
18837
19317
  const ctx = definitionsCtx ?? createAnnotationContext(module2.scopeFor);
18838
19318
  const parameters = readParameters(
18839
19319
  definitionNode,
@@ -18849,17 +19329,7 @@ function buildRouteUnit(options) {
18849
19329
  () => readReturnAnnotation(definitionNode, enclosingScope, ctx)
18850
19330
  );
18851
19331
  const effects = invocationEffects(definitionNode);
18852
- const storage = storageLookup === void 0 ? [] : [
18853
- ...storageEffects(bodyCalls(definitionNode), {
18854
- ...storageLookup,
18855
- filePath: storageLookup.factsPath
18856
- }),
18857
- ...rawSqlEffects(bodyCalls(definitionNode), {
18858
- facts: storageLookup.facts,
18859
- filePath: storageLookup.factsPath,
18860
- patterns: storageLookup.rawSql ?? []
18861
- })
18862
- ];
19332
+ const extra = recognizedBodyEffects(definitionNode, module2, storageLookup);
18863
19333
  const perReturn = branchesFromReturns(
18864
19334
  readsReturnedStatus,
18865
19335
  definitionNode,
@@ -18868,9 +19338,9 @@ function buildRouteUnit(options) {
18868
19338
  statusCode
18869
19339
  );
18870
19340
  const branches = (perReturn ?? []).map(
18871
- (branch) => storage.length === 0 ? branch : { ...branch, extraEffects: storage }
19341
+ (branch) => extra.length === 0 ? branch : { ...branch, extraEffects: extra }
18872
19342
  );
18873
- if (perReturn === null && (responseShape.reading.kind !== "absent" || statusCode.reading.kind !== "absent" || storage.length > 0 || effects.length > 0)) {
19343
+ if (perReturn === null && (responseShape.reading.kind !== "absent" || statusCode.reading.kind !== "absent" || extra.length > 0 || effects.length > 0)) {
18874
19344
  branches.push({
18875
19345
  conditions: [],
18876
19346
  terminal: {
@@ -18890,7 +19360,7 @@ function buildRouteUnit(options) {
18890
19360
  statusCodeReading: statusCode,
18891
19361
  bodyShapeReading: { reading: responseShape.reading },
18892
19362
  effects,
18893
- ...storage.length === 0 ? {} : { extraEffects: storage },
19363
+ ...extra.length === 0 ? {} : { extraEffects: extra },
18894
19364
  location: rangeOf(definitionNode),
18895
19365
  isDefault: true
18896
19366
  });
@@ -18907,7 +19377,7 @@ function buildRouteUnit(options) {
18907
19377
  exportName: exportPath[0] ?? name,
18908
19378
  exportPath
18909
19379
  },
18910
- boundaryBinding: (0, import_behavioral_ir.restBinding)({
19380
+ boundaryBinding: (0, import_behavioral_ir2.restBinding)({
18911
19381
  transport: pack.protocol,
18912
19382
  method,
18913
19383
  path: template?.path ?? null,
@@ -18932,12 +19402,26 @@ function unreadRoleReadings(parameters, range) {
18932
19402
  return [];
18933
19403
  }
18934
19404
  return [
18935
- (0, import_extractor3.unreadableReading)(
19405
+ (0, import_extractor4.unreadableReading)(
18936
19406
  "Nothing read this route's path, so its parameters name no role and a path parameter here does not read as one",
18937
19407
  range
18938
19408
  )
18939
19409
  ];
18940
19410
  }
19411
+ function recognizedBodyEffects(definitionNode, module2, storageLookup) {
19412
+ const storage = storageLookup === void 0 ? [] : [
19413
+ ...storageEffects(bodyCalls(definitionNode), {
19414
+ ...storageLookup,
19415
+ filePath: storageLookup.factsPath
19416
+ }),
19417
+ ...rawSqlEffects(bodyCalls(definitionNode), {
19418
+ facts: storageLookup.facts,
19419
+ filePath: storageLookup.factsPath,
19420
+ patterns: storageLookup.rawSql ?? []
19421
+ })
19422
+ ];
19423
+ return [...envReadEffects(definitionNode, module2), ...storage];
19424
+ }
18941
19425
  function bodyContentOf(bodyNode) {
18942
19426
  for (const stmt of bodyStatements(bodyNode)) {
18943
19427
  if (stmt.type === "pass_statement") {
@@ -19073,6 +19557,11 @@ function parameterNameAndType(param) {
19073
19557
  return null;
19074
19558
  }
19075
19559
 
19560
+ // src/facts/why.ts
19561
+ var import_node_fs4 = __toESM(require("fs"), 1);
19562
+ var import_node_path4 = __toESM(require("path"), 1);
19563
+ var import_datalog7 = require("@suss/datalog");
19564
+
19076
19565
  // src/moduleResolver.ts
19077
19566
  var import_node_fs = __toESM(require("fs"), 1);
19078
19567
  var import_node_path = __toESM(require("path"), 1);
@@ -19165,43 +19654,38 @@ function importedModuleText(module2, relativeLevel) {
19165
19654
  return relativeLevel > 0 ? `${".".repeat(relativeLevel)}${module2}` : module2;
19166
19655
  }
19167
19656
  function emitModuleImportFacts(db, filePath, module2, resolverOptions) {
19168
- const everyBinding = [...module2.scopeFor.values()].flatMap((scope) => [
19169
- ...scope.bindings
19170
- ]);
19171
- for (const [localName, binding] of everyBinding) {
19172
- if (binding.kind !== "import" && binding.kind !== "importFrom") {
19173
- continue;
19174
- }
19175
- const moduleText = importedModuleText(
19176
- binding.module,
19177
- binding.relativeLevel
19178
- );
19179
- const resolution = resolveModule(
19180
- filePath,
19181
- { module: binding.module, relativeLevel: binding.relativeLevel },
19182
- resolverOptions
19183
- );
19184
- db.add("pyImport", [
19185
- filePath,
19186
- moduleText,
19187
- resolution.status === "resolved" ? "resolved" : resolution.reason
19188
- ]);
19189
- const importedName = binding.kind === "import" ? binding.localName : binding.importedName;
19190
- db.add("pyImportedName", [
19191
- `${filePath}#${localName}`,
19192
- moduleText,
19193
- importedName
19194
- ]);
19195
- if (resolution.status === "resolved") {
19196
- db.add("pyImportResolved", [filePath, moduleText, resolution.file]);
19197
- db.add("imports", [
19198
- `${filePath}#${localName}`,
19199
- resolution.file,
19200
- importedName
19657
+ for (const scope of module2.scopeFor.values()) {
19658
+ for (const [localName, binding] of scope.bindings) {
19659
+ if (binding.kind !== "import" && binding.kind !== "importFrom") {
19660
+ continue;
19661
+ }
19662
+ const nameKey = `${filePath}#${localName}`;
19663
+ const moduleText = importedModuleText(
19664
+ binding.module,
19665
+ binding.relativeLevel
19666
+ );
19667
+ const resolution = resolveModule(
19668
+ filePath,
19669
+ { module: binding.module, relativeLevel: binding.relativeLevel },
19670
+ resolverOptions
19671
+ );
19672
+ db.add("pyImport", [
19673
+ filePath,
19674
+ moduleText,
19675
+ resolution.status === "resolved" ? "resolved" : resolution.reason
19201
19676
  ]);
19202
- continue;
19677
+ const importedName = binding.kind === "import" ? binding.localName : binding.importedName;
19678
+ db.add("pyImportedName", [nameKey, moduleText, importedName]);
19679
+ if (scope.kind === "module") {
19680
+ db.add("exportsAs", [filePath, localName, nameKey]);
19681
+ }
19682
+ if (resolution.status === "resolved") {
19683
+ db.add("pyImportResolved", [filePath, moduleText, resolution.file]);
19684
+ db.add("imports", [nameKey, resolution.file, importedName]);
19685
+ continue;
19686
+ }
19687
+ db.add("imports", [nameKey, moduleText, importedName]);
19203
19688
  }
19204
- db.add("imports", [`${filePath}#${localName}`, moduleText, importedName]);
19205
19689
  }
19206
19690
  for (const openModule of module2.openImports) {
19207
19691
  db.add("pyOpenImport", [filePath, openModule]);
@@ -19220,6 +19704,7 @@ var GRAMMAR_PATH = import_node_path2.default.join(
19220
19704
  "tree-sitter-python.wasm"
19221
19705
  );
19222
19706
  var languagePromise = null;
19707
+ var loadedLanguage = null;
19223
19708
  function loadLanguage() {
19224
19709
  languagePromise ??= (async () => {
19225
19710
  if (!import_node_fs2.default.existsSync(GRAMMAR_PATH)) {
@@ -19228,12 +19713,28 @@ function loadLanguage() {
19228
19713
  );
19229
19714
  }
19230
19715
  await import_web_tree_sitter.Parser.init();
19231
- return import_web_tree_sitter.Language.load(GRAMMAR_PATH);
19716
+ const language = await import_web_tree_sitter.Language.load(GRAMMAR_PATH);
19717
+ loadedLanguage = language;
19718
+ return language;
19232
19719
  })();
19233
19720
  return languagePromise;
19234
19721
  }
19235
19722
  async function parsePython(source) {
19236
19723
  const language = await loadLanguage();
19724
+ return parseWith(language, source);
19725
+ }
19726
+ async function preloadPythonGrammar() {
19727
+ await loadLanguage();
19728
+ }
19729
+ function parsePythonSync(source) {
19730
+ if (loadedLanguage === null) {
19731
+ throw new Error(
19732
+ "the Python grammar has not been loaded yet; call preloadPythonGrammar first"
19733
+ );
19734
+ }
19735
+ return parseWith(loadedLanguage, source);
19736
+ }
19737
+ function parseWith(language, source) {
19237
19738
  const parser = new import_web_tree_sitter.Parser();
19238
19739
  parser.setLanguage(language);
19239
19740
  try {
@@ -19250,8 +19751,671 @@ async function parsePython(source) {
19250
19751
  // src/project.ts
19251
19752
  var import_node_fs3 = __toESM(require("fs"), 1);
19252
19753
  var import_node_path3 = __toESM(require("path"), 1);
19253
- var import_datalog4 = require("@suss/datalog");
19254
- var import_extractor4 = require("@suss/extractor");
19754
+ var import_behavioral_ir4 = require("@suss/behavioral-ir");
19755
+ var import_datalog6 = require("@suss/datalog");
19756
+ var import_extractor8 = require("@suss/extractor");
19757
+
19758
+ // src/diagnostics.ts
19759
+ var import_extractor5 = require("@suss/extractor");
19760
+ function buildPythonExtractionReport(args) {
19761
+ return (0, import_extractor5.buildUngatedExtractionReport)({
19762
+ packs: args.packs.map((pack) => ({
19763
+ name: pack.name,
19764
+ version: pack.version ?? null,
19765
+ discovers: pack.discovery.length > 0
19766
+ })),
19767
+ tallies: args.tallies,
19768
+ filesWalked: args.filesWalked,
19769
+ summaries: args.summaries
19770
+ });
19771
+ }
19772
+
19773
+ // src/reach/closure.ts
19774
+ var import_behavioral_ir3 = require("@suss/behavioral-ir");
19775
+ var import_datalog5 = require("@suss/datalog");
19776
+ var import_extractor6 = require("@suss/extractor");
19777
+
19778
+ // src/reach/resolveCallee.ts
19779
+ var stop = (reason) => ({ kind: "stop", reason });
19780
+ var MODULE_STOP = {
19781
+ ambiguous: "multipleSources",
19782
+ outsideRoots: "outsideRun"
19783
+ };
19784
+ function resolveCallee2(call, site, ctx) {
19785
+ const callee = field(call, "function");
19786
+ if (callee === null) {
19787
+ return { kind: "stopped", reason: "noDeclaration" };
19788
+ }
19789
+ return asCallee(resolveExpression(callee, site, ctx), ctx);
19790
+ }
19791
+ function resolveNamedFunctionArgument(name, site, ctx) {
19792
+ if (site.rebound.has(name)) {
19793
+ return null;
19794
+ }
19795
+ const binding = resolveName(site.scope, name);
19796
+ if (binding !== null && binding.kind === "assignment") {
19797
+ return null;
19798
+ }
19799
+ const resolved = binding === null ? throughOpenImports(site.file, name, ctx, /* @__PURE__ */ new Set()) : resolveBinding(binding, site.file, site.scope, ctx, /* @__PURE__ */ new Set());
19800
+ return resolved.kind === "function" ? resolved.target : null;
19801
+ }
19802
+ function asCallee(resolved, ctx) {
19803
+ if (resolved.kind === "function") {
19804
+ return { kind: "followed", target: resolved.target };
19805
+ }
19806
+ if (resolved.kind === "class") {
19807
+ return asCallee(
19808
+ memberOfClass(resolved.file, resolved.node, "__init__", ctx),
19809
+ ctx
19810
+ );
19811
+ }
19812
+ if (resolved.kind === "stop") {
19813
+ return { kind: "stopped", reason: resolved.reason };
19814
+ }
19815
+ if (resolved.kind === "package") {
19816
+ return { kind: "stopped", reason: "outsideRun" };
19817
+ }
19818
+ return { kind: "stopped", reason: "noDeclaration" };
19819
+ }
19820
+ var EXPRESSION_RESOLVERS = {
19821
+ identifier: (node, site, ctx) => resolveIdentifier(node.text, site, ctx),
19822
+ attribute: (node, site, ctx) => {
19823
+ const object2 = field(node, "object");
19824
+ const attribute = field(node, "attribute");
19825
+ if (object2 === null || attribute === null) {
19826
+ return stop("noDeclaration");
19827
+ }
19828
+ return memberOf(resolveExpression(object2, site, ctx), attribute.text, ctx);
19829
+ },
19830
+ // `Service().run()` runs a method on whatever the constructor built.
19831
+ call: (node, site, ctx) => {
19832
+ const callee = field(node, "function");
19833
+ if (callee === null) {
19834
+ return stop("noDeclaration");
19835
+ }
19836
+ const built = resolveExpression(callee, site, ctx);
19837
+ return built.kind === "class" ? built : stop("noDeclaration");
19838
+ },
19839
+ parenthesized_expression: (node, site, ctx) => {
19840
+ const inner = node.namedChildren[0];
19841
+ return inner === null || inner === void 0 ? stop("noDeclaration") : resolveExpression(inner, site, ctx);
19842
+ }
19843
+ };
19844
+ function resolveExpression(node, site, ctx) {
19845
+ const resolver = EXPRESSION_RESOLVERS[node.type];
19846
+ return resolver === void 0 ? stop("noDeclaration") : resolver(node, site, ctx);
19847
+ }
19848
+ function resolveIdentifier(name, site, ctx) {
19849
+ if (site.rebound.has(name)) {
19850
+ return stop("unsettledValue");
19851
+ }
19852
+ if (isReceiver(name, site.scope)) {
19853
+ return receiverClass(site);
19854
+ }
19855
+ const binding = resolveName(site.scope, name);
19856
+ if (binding === null) {
19857
+ return throughOpenImports(site.file, name, ctx, /* @__PURE__ */ new Set());
19858
+ }
19859
+ return resolveBinding(binding, site.file, site.scope, ctx, /* @__PURE__ */ new Set());
19860
+ }
19861
+ function isReceiver(name, scope) {
19862
+ return (name === "self" || name === "cls") && scope.kind === "function" && scope.parent?.kind === "class";
19863
+ }
19864
+ function receiverClass(site) {
19865
+ const classScope = site.scope.parent;
19866
+ if (classScope === null || classScope === void 0) {
19867
+ return stop("noDeclaration");
19868
+ }
19869
+ return { kind: "class", file: site.file, node: classScope.node };
19870
+ }
19871
+ var BINDING_RESOLVERS = {
19872
+ functionDef: (binding, file2) => ({
19873
+ kind: "function",
19874
+ target: reachedFunction(file2, binding.node)
19875
+ }),
19876
+ classDef: (binding, file2) => ({ kind: "class", file: file2, node: binding.node }),
19877
+ parameter: () => stop("callerSupplied"),
19878
+ // `import a.b.c` binds `a`, and `import a.b.c as m` binds `m` to `a.b.c`.
19879
+ import: (binding, file2, _scope, ctx) => moduleNamed(
19880
+ file2,
19881
+ binding.localName === binding.module.split(".")[0] ? binding.localName : binding.module,
19882
+ 0,
19883
+ ctx
19884
+ ),
19885
+ importFrom: (binding, file2, _scope, ctx, visited) => memberOf(
19886
+ moduleNamed(file2, binding.module, binding.relativeLevel, ctx),
19887
+ binding.importedName,
19888
+ ctx,
19889
+ visited
19890
+ ),
19891
+ // `run = load` is an alias worth one hop; anything else is a value.
19892
+ assignment: (binding, file2, scope, ctx, visited) => aliasedValue(binding.value, file2, scope, ctx, visited),
19893
+ global: () => stop("unsettledValue"),
19894
+ nonlocal: () => stop("unsettledValue")
19895
+ };
19896
+ function resolveBinding(binding, file2, scope, ctx, visited) {
19897
+ const resolver = BINDING_RESOLVERS[binding.kind];
19898
+ return resolver(binding, file2, scope, ctx, visited);
19899
+ }
19900
+ function aliasedValue(value, file2, scope, ctx, visited) {
19901
+ if (value === null) {
19902
+ return stop("unsettledValue");
19903
+ }
19904
+ if (value.type === "identifier") {
19905
+ const binding = resolveName(scope, value.text);
19906
+ if (binding === null || binding.kind === "assignment") {
19907
+ return stop("unsettledValue");
19908
+ }
19909
+ return resolveBinding(binding, file2, scope, ctx, visited);
19910
+ }
19911
+ if (value.type === "call") {
19912
+ const callee = field(value, "function");
19913
+ const built = callee === null ? stop("unsettledValue") : aliasedValue(callee, file2, scope, ctx, visited);
19914
+ return built.kind === "class" ? built : stop("unsettledValue");
19915
+ }
19916
+ if (value.type === "attribute") {
19917
+ const object2 = field(value, "object");
19918
+ const attribute = field(value, "attribute");
19919
+ if (object2 === null || attribute === null) {
19920
+ return stop("unsettledValue");
19921
+ }
19922
+ return memberOf(
19923
+ aliasedValue(object2, file2, scope, ctx, visited),
19924
+ attribute.text,
19925
+ ctx
19926
+ );
19927
+ }
19928
+ return stop("unsettledValue");
19929
+ }
19930
+ function reachedFunction(file2, node, owner) {
19931
+ const name = field(node, "name")?.text ?? "<anon>";
19932
+ const ownerName = owner === void 0 ? null : field(owner, "name")?.text;
19933
+ return {
19934
+ file: file2,
19935
+ node,
19936
+ name,
19937
+ exportPath: ownerName === null || ownerName === void 0 ? [name] : [ownerName, name]
19938
+ };
19939
+ }
19940
+ function moduleNamed(from, module2, relativeLevel, ctx) {
19941
+ const resolution = resolveModule(
19942
+ from.file,
19943
+ { module: module2, relativeLevel },
19944
+ { roots: ctx.roots }
19945
+ );
19946
+ if (resolution.status !== "resolved") {
19947
+ return resolution.reason === "external" ? { kind: "package", dotted: module2, relativeLevel, from } : stop(MODULE_STOP[resolution.reason]);
19948
+ }
19949
+ const file2 = ctx.filesByPath.get(resolution.file);
19950
+ return file2 === void 0 ? stop("outsideRun") : { kind: "module", file: file2 };
19951
+ }
19952
+ function memberOf(base, name, ctx, visited = /* @__PURE__ */ new Set()) {
19953
+ if (base.kind === "module") {
19954
+ return memberOfModule(base.file, name, ctx, visited);
19955
+ }
19956
+ if (base.kind === "package") {
19957
+ return moduleNamed(
19958
+ base.from,
19959
+ base.dotted === "" ? name : `${base.dotted}.${name}`,
19960
+ base.relativeLevel,
19961
+ ctx
19962
+ );
19963
+ }
19964
+ if (base.kind === "class") {
19965
+ return memberOfClass(base.file, base.node, name, ctx);
19966
+ }
19967
+ if (base.kind === "stop") {
19968
+ return base;
19969
+ }
19970
+ return stop("noDeclaration");
19971
+ }
19972
+ function memberOfClass(file2, classNode, name, ctx) {
19973
+ const classScope = file2.module.scopeFor.get(classNode.id);
19974
+ const binding = classScope?.bindings.get(name);
19975
+ if (binding === void 0) {
19976
+ return stop("noDeclaration");
19977
+ }
19978
+ if (binding.kind === "functionDef") {
19979
+ return {
19980
+ kind: "function",
19981
+ target: reachedFunction(file2, binding.node, classNode)
19982
+ };
19983
+ }
19984
+ return resolveBinding(binding, file2, classScope, ctx, /* @__PURE__ */ new Set());
19985
+ }
19986
+ function memberOfModule(file2, name, ctx, visited) {
19987
+ const key = `${file2.file}#${name}`;
19988
+ if (visited.has(key)) {
19989
+ return stop("unsettledValue");
19990
+ }
19991
+ visited.add(key);
19992
+ const binding = file2.module.moduleScope.bindings.get(name);
19993
+ if (binding !== void 0) {
19994
+ return resolveBinding(binding, file2, file2.module.moduleScope, ctx, visited);
19995
+ }
19996
+ if (file2.file.endsWith("__init__.py")) {
19997
+ const submodule = moduleNamed(file2, name, 1, ctx);
19998
+ if (submodule.kind === "module") {
19999
+ return submodule;
20000
+ }
20001
+ }
20002
+ return throughOpenImports(file2, name, ctx, visited);
20003
+ }
20004
+ function throughOpenImports(file2, name, ctx, visited) {
20005
+ const found = [];
20006
+ for (const spec of file2.module.openImports) {
20007
+ const dots = spec.length - spec.replace(/^\.+/, "").length;
20008
+ const opened = moduleNamed(file2, spec.slice(dots), dots, ctx);
20009
+ if (opened.kind !== "module") {
20010
+ continue;
20011
+ }
20012
+ const member = memberOfModule(opened.file, name, ctx, visited);
20013
+ if (member.kind !== "stop") {
20014
+ found.push(member);
20015
+ }
20016
+ }
20017
+ if (found.length > 1) {
20018
+ return stop("multipleSources");
20019
+ }
20020
+ return found[0] ?? stop("noDeclaration");
20021
+ }
20022
+
20023
+ // src/reach/closure.ts
20024
+ var REACHABLE_RULES = [
20025
+ (0, import_datalog5.rule)("reachable", [(0, import_datalog5.variable)("f")], [(0, import_datalog5.lit)("entry", (0, import_datalog5.variable)("f"))]),
20026
+ (0, import_datalog5.rule)(
20027
+ "reachable",
20028
+ [(0, import_datalog5.variable)("g")],
20029
+ [(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"))]
20030
+ )
20031
+ ];
20032
+ function reachedFunctions(seeds, options) {
20033
+ const ctx = {
20034
+ filesByPath: new Map(options.files.map((file2) => [file2.file, file2])),
20035
+ roots: options.roots
20036
+ };
20037
+ const db = new import_datalog5.Database();
20038
+ const functionByKey = /* @__PURE__ */ new Map();
20039
+ const seedKeys = /* @__PURE__ */ new Set();
20040
+ const scanned = /* @__PURE__ */ new Set();
20041
+ const targetsByKey = /* @__PURE__ */ new Map();
20042
+ const stopsByKey = /* @__PURE__ */ new Map();
20043
+ const argTargetsByKey = /* @__PURE__ */ new Map();
20044
+ const parameterCallsByKey = /* @__PURE__ */ new Map();
20045
+ const passedPositions = /* @__PURE__ */ new Set();
20046
+ for (const seed of seeds) {
20047
+ seedKeys.add(seed.key);
20048
+ functionByKey.set(seed.key, {
20049
+ file: seed.file,
20050
+ node: seed.node,
20051
+ name: field(seed.node, "name")?.text ?? "<anon>",
20052
+ exportPath: []
20053
+ });
20054
+ db.add("entry", [seed.key]);
20055
+ }
20056
+ for (; ; ) {
20057
+ (0, import_datalog5.evaluate)(db, REACHABLE_RULES);
20058
+ const frontier = db.facts("reachable").map(([key]) => String(key)).filter((key) => !scanned.has(key));
20059
+ if (frontier.length === 0) {
20060
+ break;
20061
+ }
20062
+ for (const key of frontier) {
20063
+ scanned.add(key);
20064
+ const source = functionByKey.get(key);
20065
+ if (source === void 0) {
20066
+ continue;
20067
+ }
20068
+ const scan = scanBody(source, ctx);
20069
+ if (scan.stops.length > 0) {
20070
+ stopsByKey.set(key, scan.stops);
20071
+ }
20072
+ targetsByKey.set(key, scan.targets);
20073
+ argTargetsByKey.set(key, scan.argTargets);
20074
+ if (scan.parameterCalls.length > 0) {
20075
+ parameterCallsByKey.set(key, scan.parameterCalls);
20076
+ }
20077
+ for (const position of scan.passedPositions) {
20078
+ passedPositions.add(position);
20079
+ }
20080
+ for (const target of scan.followed) {
20081
+ const calleeKey = keyOf(target);
20082
+ if (!functionByKey.has(calleeKey)) {
20083
+ functionByKey.set(calleeKey, target);
20084
+ }
20085
+ db.add("calls", [key, calleeKey]);
20086
+ }
20087
+ }
20088
+ }
20089
+ const summaries = [];
20090
+ const summariesByKey = /* @__PURE__ */ new Map();
20091
+ for (const [keyAtom] of db.facts("reachable")) {
20092
+ const key = String(keyAtom);
20093
+ const target = functionByKey.get(key);
20094
+ if (seedKeys.has(key) || target === void 0) {
20095
+ continue;
20096
+ }
20097
+ const summary = (0, import_extractor6.assembleSummary)(libraryUnit(target, options), {
20098
+ gapHandling: options.gapHandling
20099
+ });
20100
+ summary.confidence = { source: "inferred_static", level: "low" };
20101
+ if (options.gapHandling !== "silent") {
20102
+ summary.gaps.push(...(stopsByKey.get(key) ?? []).map(import_behavioral_ir3.unfollowedCallGap));
20103
+ }
20104
+ (0, import_behavioral_ir3.placeCalls)(summary, targetsByKey.get(key));
20105
+ (0, import_behavioral_ir3.placeArgTargets)(summary, argTargetsByKey.get(key));
20106
+ (0, import_behavioral_ir3.placeCalleeParameters)(summary, parameterCallsByKey.get(key));
20107
+ summariesByKey.set(key, [summary]);
20108
+ summaries.push(summary);
20109
+ }
20110
+ if (options.gapHandling !== "silent") {
20111
+ (0, import_behavioral_ir3.recordParameterGaps)(parameterCallsByKey, summariesByKey, passedPositions);
20112
+ }
20113
+ return {
20114
+ summaries,
20115
+ targetsByKey,
20116
+ stopsByKey,
20117
+ argTargetsByKey,
20118
+ parameterCallsByKey,
20119
+ passedPositions
20120
+ };
20121
+ }
20122
+ function keyOf(target) {
20123
+ return nodeId(target.file.file, target.node);
20124
+ }
20125
+ var EMPTY_SCAN = {
20126
+ followed: [],
20127
+ stops: [],
20128
+ targets: /* @__PURE__ */ new Map(),
20129
+ argTargets: /* @__PURE__ */ new Map(),
20130
+ parameterCalls: [],
20131
+ passedPositions: /* @__PURE__ */ new Set()
20132
+ };
20133
+ function scanBody(source, ctx) {
20134
+ const followed = [];
20135
+ const stops = [];
20136
+ const placements = new import_behavioral_ir3.TargetPlacements();
20137
+ const parameterCalls = [];
20138
+ const passedPositions = /* @__PURE__ */ new Set();
20139
+ const seen = /* @__PURE__ */ new Set();
20140
+ const parameterCallsSeen = /* @__PURE__ */ new Set();
20141
+ const { file: file2, node } = source;
20142
+ const body = field(node, "body");
20143
+ if (body === null) {
20144
+ return EMPTY_SCAN;
20145
+ }
20146
+ const ownParameters = callParameterNames(node, source.exportPath.length > 1);
20147
+ const recordPassedArgs = (call, callee, calleeKey, where) => {
20148
+ const args = field(call, "arguments");
20149
+ if (args === null) {
20150
+ return;
20151
+ }
20152
+ args.namedChildren.forEach((arg, position) => {
20153
+ if (arg === null || arg.type !== "identifier") {
20154
+ return;
20155
+ }
20156
+ const resolved = resolveNamedFunctionArgument(
20157
+ arg.text,
20158
+ { file: file2, scope: where.scope, rebound: where.rebound },
20159
+ ctx
20160
+ );
20161
+ if (resolved === null) {
20162
+ return;
20163
+ }
20164
+ const key = keyOf(resolved);
20165
+ if (!seen.has(key)) {
20166
+ seen.add(key);
20167
+ followed.push(resolved);
20168
+ }
20169
+ placements.placeArg(callee, position, {
20170
+ file: resolved.file.displayPath,
20171
+ span: spanOf(resolved.node)
20172
+ });
20173
+ if (calleeKey !== null) {
20174
+ passedPositions.add(`${calleeKey}#${position}`);
20175
+ }
20176
+ });
20177
+ };
20178
+ const record2 = (call, where) => {
20179
+ const callee = calleeText(call);
20180
+ const outcome = resolveCallee2(
20181
+ call,
20182
+ { file: file2, scope: where.scope, rebound: where.rebound },
20183
+ ctx
20184
+ );
20185
+ const placed = outcome.kind === "followed" ? {
20186
+ file: outcome.target.file.displayPath,
20187
+ span: spanOf(outcome.target.node)
20188
+ } : outcome.reason === "noDeclaration" ? null : { file: file2.displayPath, span: spanOf(call) };
20189
+ placements.place(callee, placed);
20190
+ recordPassedArgs(
20191
+ call,
20192
+ callee,
20193
+ outcome.kind === "followed" ? keyOf(outcome.target) : null,
20194
+ where
20195
+ );
20196
+ if (outcome.kind === "stopped") {
20197
+ const stopKey = `${outcome.reason}:${callee}`;
20198
+ if (!seen.has(stopKey) && (0, import_behavioral_ir3.worthRecording)(outcome.reason)) {
20199
+ seen.add(stopKey);
20200
+ stops.push({ callee, reason: outcome.reason });
20201
+ }
20202
+ if (outcome.reason === "callerSupplied" && !parameterCallsSeen.has(callee)) {
20203
+ const parameterIndex = ownParameters.indexOf(callee);
20204
+ if (parameterIndex !== -1) {
20205
+ parameterCallsSeen.add(callee);
20206
+ parameterCalls.push({ callee, parameterIndex });
20207
+ }
20208
+ }
20209
+ return;
20210
+ }
20211
+ const key = keyOf(outcome.target);
20212
+ if (!seen.has(key)) {
20213
+ seen.add(key);
20214
+ followed.push(outcome.target);
20215
+ }
20216
+ };
20217
+ (0, import_extractor6.walkDescendants)(
20218
+ body,
20219
+ { scope: scopeAt(file2, node), rebound: reboundNames(body) },
20220
+ {
20221
+ at: (child, where) => {
20222
+ if (child.type === "call") {
20223
+ record2(child, where);
20224
+ }
20225
+ },
20226
+ into: (child, where) => {
20227
+ if (child.type === "function_definition") {
20228
+ return import_extractor6.SKIP_CHILDREN;
20229
+ }
20230
+ if (child.type === "lambda") {
20231
+ return {
20232
+ scope: where.scope,
20233
+ rebound: /* @__PURE__ */ new Set([...where.rebound, ...lambdaParameters(child)])
20234
+ };
20235
+ }
20236
+ return {
20237
+ scope: file2.module.scopeFor.get(child.id) ?? where.scope,
20238
+ rebound: where.rebound
20239
+ };
20240
+ }
20241
+ }
20242
+ );
20243
+ return {
20244
+ followed,
20245
+ stops,
20246
+ targets: placements.targets,
20247
+ argTargets: placements.argTargets,
20248
+ parameterCalls,
20249
+ passedPositions
20250
+ };
20251
+ }
20252
+ function scopeAt(file2, node) {
20253
+ let current = node;
20254
+ while (current !== null) {
20255
+ const scope = file2.module.scopeFor.get(current.id);
20256
+ if (scope !== void 0) {
20257
+ return scope;
20258
+ }
20259
+ current = current.parent;
20260
+ }
20261
+ return file2.module.moduleScope;
20262
+ }
20263
+ var REBINDING_FIELDS = {
20264
+ assignment: "left",
20265
+ augmented_assignment: "left",
20266
+ named_expression: "name",
20267
+ for_statement: "left",
20268
+ for_in_clause: "left",
20269
+ as_pattern: "alias"
20270
+ };
20271
+ function reboundNames(body) {
20272
+ const names = /* @__PURE__ */ new Set();
20273
+ (0, import_extractor6.walkDescendants)(body, null, {
20274
+ at: (node) => {
20275
+ const target = REBINDING_FIELDS[node.type];
20276
+ if (target === void 0 || boundByBinder(node, body)) {
20277
+ return;
20278
+ }
20279
+ const written = field(node, target);
20280
+ if (written !== null) {
20281
+ for (const name of identifiersUnder(written)) {
20282
+ names.add(name);
20283
+ }
20284
+ }
20285
+ },
20286
+ into: (node) => node.type === "function_definition" ? import_extractor6.SKIP_CHILDREN : null
20287
+ });
20288
+ return names;
20289
+ }
20290
+ function boundByBinder(node, body) {
20291
+ if (node.type !== "assignment") {
20292
+ return false;
20293
+ }
20294
+ const statement = node.parent;
20295
+ return field(node, "left")?.type === "identifier" && statement?.type === "expression_statement" && statement.parent?.id === body.id;
20296
+ }
20297
+ function identifiersUnder(node, found = []) {
20298
+ if (node.type === "identifier") {
20299
+ found.push(node.text);
20300
+ return found;
20301
+ }
20302
+ for (const child of node.namedChildren) {
20303
+ if (child !== null && child.type !== "attribute" && child.type !== "subscript") {
20304
+ identifiersUnder(child, found);
20305
+ }
20306
+ }
20307
+ return found;
20308
+ }
20309
+ function lambdaParameters(lambda) {
20310
+ const parameters = field(lambda, "parameters");
20311
+ return parameters === null ? [] : identifiersUnder(parameters);
20312
+ }
20313
+ function libraryUnit(target, options) {
20314
+ const { file: file2, node, name, exportPath } = target;
20315
+ const body = field(node, "body");
20316
+ const extra = recognizedBodyEffects(
20317
+ node,
20318
+ file2.module,
20319
+ options.storageFor(file2)
20320
+ );
20321
+ const range = rangeOf(node);
20322
+ return {
20323
+ identity: {
20324
+ name,
20325
+ nameKind: "binding",
20326
+ kind: "library",
20327
+ file: file2.displayPath,
20328
+ range,
20329
+ span: spanOf(node),
20330
+ exportName: exportPath[0] ?? name,
20331
+ exportPath
20332
+ },
20333
+ boundaryBinding: (0, import_behavioral_ir3.functionCallBinding)({
20334
+ transport: "in-process",
20335
+ recognition: "reachable"
20336
+ }),
20337
+ parameters: positionalParameters(node, exportPath.length > 1),
20338
+ branches: [
20339
+ {
20340
+ conditions: [],
20341
+ terminal: {
20342
+ kind: "return",
20343
+ statusCode: null,
20344
+ body: null,
20345
+ exceptionType: null,
20346
+ message: null,
20347
+ component: null,
20348
+ renderTree: null,
20349
+ delegateTarget: null,
20350
+ emitEvent: null,
20351
+ location: range
20352
+ },
20353
+ effects: invocationEffects(node),
20354
+ ...extra.length === 0 ? {} : { extraEffects: extra },
20355
+ location: range,
20356
+ isDefault: true
20357
+ }
20358
+ ],
20359
+ bodyContent: body === null ? "absent" : bodyContentOf(body),
20360
+ dependencyCalls: [],
20361
+ declaredContract: null
20362
+ };
20363
+ }
20364
+ function positionalParameters(node, isMethod) {
20365
+ const parameters = field(node, "parameters");
20366
+ if (parameters === null) {
20367
+ return [];
20368
+ }
20369
+ const out = [];
20370
+ let position = 0;
20371
+ for (const param of parameters.namedChildren) {
20372
+ if (param === null) {
20373
+ continue;
20374
+ }
20375
+ const name = parameterName3(param);
20376
+ if (name === null) {
20377
+ continue;
20378
+ }
20379
+ if (isMethod && position === 0 && (name === "self" || name === "cls")) {
20380
+ position += 1;
20381
+ continue;
20382
+ }
20383
+ out.push({ name, position, role: name, typeText: null });
20384
+ position += 1;
20385
+ }
20386
+ return out;
20387
+ }
20388
+ function callParameterNames(node, isMethod) {
20389
+ const parameters = field(node, "parameters");
20390
+ if (parameters === null) {
20391
+ return [];
20392
+ }
20393
+ const names = [];
20394
+ for (const param of parameters.namedChildren) {
20395
+ if (param === null) {
20396
+ continue;
20397
+ }
20398
+ const name = parameterName3(param);
20399
+ if (name === null) {
20400
+ continue;
20401
+ }
20402
+ if (isMethod && names.length === 0 && (name === "self" || name === "cls")) {
20403
+ continue;
20404
+ }
20405
+ names.push(name);
20406
+ }
20407
+ return names;
20408
+ }
20409
+ function parameterName3(param) {
20410
+ if (param.type === "identifier") {
20411
+ return param.text;
20412
+ }
20413
+ const named = field(param, "name");
20414
+ if (named !== null && named.type === "identifier") {
20415
+ return named.text;
20416
+ }
20417
+ return identifiersUnder(param)[0] ?? null;
20418
+ }
19255
20419
 
19256
20420
  // src/routers.ts
19257
20421
  var UNSTATED_PREFIX = { kind: "unstated" };
@@ -19526,6 +20690,9 @@ function buildPatternIndex(files, importModule, composition, resolverOptions) {
19526
20690
  for (const bound of files) {
19527
20691
  collectConstructions(bound, importModule, composition, index);
19528
20692
  }
20693
+ for (const bound of files) {
20694
+ collectReturnedConstructions(bound, importModule, composition, index);
20695
+ }
19529
20696
  if (objectPrefix?.carrier !== void 0) {
19530
20697
  const carrier = objectPrefix.carrier;
19531
20698
  for (const bound of files) {
@@ -19701,6 +20868,37 @@ function collectConstructions(bound, importModule, composition, index) {
19701
20868
  );
19702
20869
  }
19703
20870
  }
20871
+ function collectReturnedConstructions(bound, importModule, composition, index) {
20872
+ for (const stmt of bodyStatements(bound.root)) {
20873
+ const definition = stripDecorators(stmt).definition;
20874
+ if (definition.type !== "function_definition") {
20875
+ continue;
20876
+ }
20877
+ const scope = bound.module.scopeFor.get(definition.id);
20878
+ for (const inner of nestedStatements(definition)) {
20879
+ if (inner.type !== "return_statement" || scope === void 0) {
20880
+ continue;
20881
+ }
20882
+ const returned = inner.namedChildren[0];
20883
+ if (returned?.type !== "call") {
20884
+ continue;
20885
+ }
20886
+ const callee = field(returned, "function");
20887
+ const constructorName = callee === null ? null : importedConstructorName(callee, scope, importModule);
20888
+ if (constructorName !== composition.routerConstructorName) {
20889
+ continue;
20890
+ }
20891
+ const { keywordArgs } = readCallArguments(field(returned, "arguments"));
20892
+ const valueKey2 = nodeId(bound.file, returned);
20893
+ index.byValueKey.set(valueKey2, {
20894
+ constructorName,
20895
+ valueKey: valueKey2,
20896
+ prefix: constructorPrefix(keywordArgs, composition, scope),
20897
+ reassigned: false
20898
+ });
20899
+ }
20900
+ }
20901
+ }
19704
20902
  function collectCarrierConstructions(carrier, composition, scan) {
19705
20903
  walkStatements(
19706
20904
  bodyStatements(scan.bound.root),
@@ -19759,6 +20957,21 @@ function constructionNamed(name, scope, scan, constructions = scan.index.constru
19759
20957
  };
19760
20958
  return resolvers[binding.kind]?.() ?? null;
19761
20959
  }
20960
+ function constructionThroughFacts(name, scope, scan) {
20961
+ const facts = scan.index.facts;
20962
+ const binding = resolveName(scope, name);
20963
+ if (facts === void 0 || binding === null) {
20964
+ return null;
20965
+ }
20966
+ if (binding.kind !== "assignment" && binding.kind !== "importFrom") {
20967
+ return null;
20968
+ }
20969
+ const nameKey = `${scan.bound.file}#${name}`;
20970
+ const constructionKey = subjectConstructions(facts, [nameKey]).get(
20971
+ nameKey
20972
+ )?.constructionKey;
20973
+ return constructionKey === void 0 ? null : scan.index.byValueKey.get(constructionKey) ?? null;
20974
+ }
19762
20975
  var MOUNT_STATE_BY_EFFECT = {
19763
20976
  prefixes: (statedPrefix, site) => ({
19764
20977
  kind: "mounted",
@@ -19928,10 +21141,10 @@ function constructionsReturnedBy(target, index) {
19928
21141
  return { kind: "unread" };
19929
21142
  }
19930
21143
  const contained = containedValues(facts, returned);
19931
- resolveCalls(facts, contained);
21144
+ const settled = subjectConstructions(facts, contained);
19932
21145
  const found = [];
19933
21146
  for (const value of contained) {
19934
- const resolved = resolvedValueKey(facts, value);
21147
+ const resolved = settled.get(value)?.constructionKey ?? value;
19935
21148
  const construction = index.byValueKey.get(resolved);
19936
21149
  if (construction === void 0) {
19937
21150
  return {
@@ -19946,10 +21159,6 @@ function constructionsReturnedBy(target, index) {
19946
21159
  }
19947
21160
  return { kind: "settled", found };
19948
21161
  }
19949
- function resolvedValueKey(facts, value) {
19950
- const row = facts.facts("wantedIsWrittenAs").find((entry) => String(entry[0]) === value);
19951
- return row === void 0 ? value : String(row[1]);
19952
- }
19953
21162
  function mountedConstructions(arg, position, scan) {
19954
21163
  if (arg?.kind === "attribute") {
19955
21164
  const construction = constructionThroughModule(arg, position.scope, scan);
@@ -19959,7 +21168,7 @@ function mountedConstructions(arg, position, scan) {
19959
21168
  return [];
19960
21169
  }
19961
21170
  const named = (name) => {
19962
- const construction = constructionNamed(name, position.scope, scan);
21171
+ const construction = constructionNamed(name, position.scope, scan) ?? constructionThroughFacts(name, position.scope, scan);
19963
21172
  return construction === null ? [] : [construction];
19964
21173
  };
19965
21174
  const target = position.loopBindings.get(arg.name);
@@ -20346,36 +21555,69 @@ function carrierPrefix(carrier, constructorArg, objectName, scope, scan) {
20346
21555
  return readings[construction.prefix.kind]();
20347
21556
  }
20348
21557
 
21558
+ // src/version.ts
21559
+ var import_extractor7 = require("@suss/extractor");
21560
+ var ADAPTER_VERSION = "0.1.0";
21561
+ var adapterStamp = (0, import_extractor7.createAdapterStamp)({
21562
+ moduleUrl: importMetaUrl,
21563
+ version: ADAPTER_VERSION
21564
+ });
21565
+
20349
21566
  // src/project.ts
20350
- function reportUnresolvedProjectModules(options) {
21567
+ function reportUnresolvedProjectModules(options, db) {
21568
+ const imported = new Set(db.facts("pyImport").map((row) => String(row[1])));
20351
21569
  for (const pack of options.packs) {
20352
21570
  for (const module2 of pack.projectModules ?? []) {
20353
- const resolved = resolveAbsoluteModule(module2, { roots: options.roots });
20354
- if (resolved.status === "resolved") {
21571
+ if (imported.has(module2)) {
20355
21572
  continue;
20356
21573
  }
20357
21574
  process.stderr.write(
20358
- `[suss] ${pack.name}: the configured module ${module2} does not resolve under ${options.roots.join(", ")}, so nothing it wraps will be discovered.
21575
+ `[suss] ${pack.name}: no file under ${options.roots.join(", ")} imports ${module2}, so the stub for it changes nothing.
20359
21576
  `
20360
21577
  );
20361
21578
  }
20362
21579
  }
20363
21580
  }
20364
21581
  async function extractPythonProject(options) {
20365
- const db = new import_datalog4.Database();
21582
+ const timer = options.onTiming !== void 0 ? (0, import_extractor8.createTimer)() : (0, import_extractor8.noopTimer)();
21583
+ const cacheDir = adapterStamp.declineWhenRunFromSource(
21584
+ options.cacheDir === null ? null : options.cacheDir ?? (options.projectRoot !== void 0 ? import_node_path3.default.join(options.projectRoot, ".suss", "cache") : null)
21585
+ );
21586
+ const cache = (0, import_extractor8.createCacheLayer)(cacheDir);
21587
+ const packsDigest = adapterStamp.packsDigest(
21588
+ options.packs.map(
21589
+ (pack) => pack.version !== void 0 ? { name: pack.name, version: pack.version } : { name: pack.name }
21590
+ )
21591
+ );
21592
+ const cacheInput = {
21593
+ files: cacheDir === null ? [] : options.files,
21594
+ adapterPacksDigest: cacheDir === null ? packsDigest : (0, import_extractor8.runDigest)(packsDigest, options.packs, options.files)
21595
+ };
21596
+ const lookup = await timer.timeAsync(
21597
+ "cache.lookup",
21598
+ () => cache.lookup(cacheInput)
21599
+ );
21600
+ options.onCacheDiagnostic?.(lookup.diagnostic);
21601
+ if (lookup.kind === "hit") {
21602
+ options.onTiming?.(timer.report());
21603
+ return { summaries: lookup.summaries, facts: new import_datalog6.Database() };
21604
+ }
21605
+ const db = new import_datalog6.Database();
20366
21606
  const summaries = [];
20367
21607
  const gapHandling = options.gapHandling ?? "permissive";
21608
+ const tallies = (0, import_extractor5.createPackTallies)(options.packs);
20368
21609
  const displayPathOf = (file2) => options.workspaceRoot !== void 0 ? import_node_path3.default.relative(options.workspaceRoot, file2) : file2;
20369
- reportUnresolvedProjectModules(options);
20370
21610
  const bound = [];
20371
21611
  for (const file2 of options.files) {
20372
- const source = import_node_fs3.default.readFileSync(file2, "utf8");
20373
- const tree = await parsePython(source);
20374
- bound.push({
20375
- file: file2,
20376
- displayPath: displayPathOf(file2),
20377
- root: tree.rootNode,
20378
- module: bindModule(tree.rootNode)
21612
+ await timer.timeAsync("parse", async () => {
21613
+ const source = import_node_fs3.default.readFileSync(file2, "utf8");
21614
+ const tree = await parsePython(source);
21615
+ bound.push({
21616
+ file: file2,
21617
+ displayPath: displayPathOf(file2),
21618
+ root: tree.rootNode,
21619
+ module: bindModule(tree.rootNode)
21620
+ });
20379
21621
  });
20380
21622
  }
20381
21623
  const mountsRouters = options.packs.some(
@@ -20386,81 +21628,172 @@ async function extractPythonProject(options) {
20386
21628
  const discovers = options.packs.some((pack) => pack.discovery.length > 0);
20387
21629
  const needsValues = discovers || mountsRouters || storagePatterns.length > 0;
20388
21630
  const definitions = /* @__PURE__ */ new Map();
20389
- for (const { file: file2, root, module: moduleBinding } of bound) {
20390
- emitModuleImportFacts(db, file2, moduleBinding, { roots: options.roots });
20391
- if (needsValues) {
20392
- emitValueFacts(db, file2, root);
20393
- }
20394
- if (storagePatterns.length > 0) {
21631
+ timer.time("discover", () => {
21632
+ for (const { file: file2, root, module: moduleBinding } of bound) {
21633
+ emitModuleImportFacts(db, file2, moduleBinding, { roots: options.roots });
21634
+ if (needsValues) {
21635
+ emitValueFacts(db, file2, root);
21636
+ }
20395
21637
  indexDefinitions(definitions, file2, root);
20396
21638
  }
20397
- }
20398
- const couldMatch = methodsDeclaredNear(db, storagePatterns, definitions);
20399
- const startsAQuery = /* @__PURE__ */ new Set([
20400
- ...couldMatch,
20401
- ...storagePatterns.flatMap((pattern) => pattern.queryFunctions ?? [])
20402
- ]);
20403
- const leadsToStorage = functionsReachingStorage(
20404
- db,
20405
- definitions,
20406
- startsAQuery
20407
- );
20408
- const routerIndex = buildRouterIndex(bound, options.packs, {
20409
- roots: options.roots,
20410
- ...mountsRouters ? { facts: db } : {}
20411
21639
  });
20412
- for (const { file: file2, root, module: moduleBinding } of bound) {
21640
+ reportUnresolvedProjectModules(options, db);
21641
+ const couldMatch = timer.time(
21642
+ "discover",
21643
+ () => methodsDeclaredNear(db, storagePatterns, definitions)
21644
+ );
21645
+ const routerIndex = timer.time(
21646
+ "discover",
21647
+ () => buildRouterIndex(bound, options.packs, {
21648
+ roots: options.roots,
21649
+ ...mountsRouters ? { facts: db } : {}
21650
+ })
21651
+ );
21652
+ const storageFor = (file2) => storagePatterns.length > 0 || rawSqlPatterns.length > 0 ? {
21653
+ facts: db,
21654
+ factsPath: file2.file,
21655
+ patterns: storagePatterns,
21656
+ definitionAt: (key) => definitions.get(key),
21657
+ couldMatch,
21658
+ rawSql: rawSqlPatterns
21659
+ } : void 0;
21660
+ const seeds = [];
21661
+ const summariesBySeed = /* @__PURE__ */ new Map();
21662
+ for (const boundFile of bound) {
21663
+ const { file: file2, root, module: moduleBinding } = boundFile;
20413
21664
  const displayPath = displayPathOf(file2);
20414
- const rawUnits = discoverUnits(root, moduleBinding, {
20415
- packs: options.packs,
20416
- filePath: displayPath,
20417
- absoluteFile: file2,
20418
- routerIndex,
20419
- gapHandling,
20420
- ...needsValues ? { facts: db } : {},
20421
- ...storagePatterns.length > 0 || rawSqlPatterns.length > 0 ? {
20422
- storage: {
20423
- facts: db,
20424
- factsPath: file2,
20425
- patterns: storagePatterns,
20426
- definitionAt: (key) => definitions.get(key),
20427
- couldMatch,
20428
- leadsToStorage,
20429
- rawSql: rawSqlPatterns
20430
- }
20431
- } : {}
20432
- });
21665
+ const storage = storageFor(boundFile);
21666
+ const rawUnits = timer.time(
21667
+ "discover",
21668
+ () => discoverUnits(root, moduleBinding, {
21669
+ packs: options.packs,
21670
+ filePath: displayPath,
21671
+ absoluteFile: file2,
21672
+ routerIndex,
21673
+ gapHandling,
21674
+ ...needsValues ? { facts: db } : {},
21675
+ ...storage === void 0 ? {} : { storage }
21676
+ })
21677
+ );
20433
21678
  for (const raw of rawUnits) {
20434
- const summary = (0, import_extractor4.assembleSummary)(raw, { gapHandling });
21679
+ const summary = timer.time(
21680
+ "summarize",
21681
+ () => (0, import_extractor8.assembleSummary)(raw, { gapHandling })
21682
+ );
20435
21683
  summary.confidence = { source: "inferred_static", level: "low" };
20436
21684
  summaries.push(summary);
20437
21685
  emitEntryFact(db, file2, raw.identity.range, raw.identity.name);
21686
+ (0, import_extractor5.tallyUnit)(tallies, raw.boundaryBinding?.recognition);
21687
+ const span = raw.identity.span;
21688
+ const key = span === void 0 ? null : `${file2}:${span.start}-${span.end}`;
21689
+ const node = key === null ? void 0 : definitions.get(key);
21690
+ if (key === null || node === void 0) {
21691
+ continue;
21692
+ }
21693
+ const sharing = summariesBySeed.get(key);
21694
+ if (sharing === void 0) {
21695
+ seeds.push({ key, file: boundFile, node });
21696
+ summariesBySeed.set(key, [summary]);
21697
+ } else {
21698
+ sharing.push(summary);
21699
+ }
21700
+ }
21701
+ const loadTimeReads = timer.time(
21702
+ "discover",
21703
+ () => envReadEffects(root, moduleBinding)
21704
+ );
21705
+ if (loadTimeReads.length > 0) {
21706
+ const summary = timer.time(
21707
+ "summarize",
21708
+ () => (0, import_extractor8.assembleSummary)(
21709
+ (0, import_extractor8.moduleInitStructure)({
21710
+ name: import_node_path3.default.basename(displayPath),
21711
+ file: displayPath,
21712
+ range: rangeOf(root),
21713
+ effects: loadTimeReads
21714
+ }),
21715
+ { gapHandling }
21716
+ )
21717
+ );
21718
+ summary.confidence = { source: "inferred_static", level: "low" };
21719
+ summaries.push(summary);
20438
21720
  }
20439
21721
  }
20440
- stampModuleImports(summaries, db, displayPathOf);
21722
+ const reached = timer.time(
21723
+ "summarize",
21724
+ () => reachedFunctions(seeds, {
21725
+ files: bound,
21726
+ roots: options.roots,
21727
+ gapHandling,
21728
+ storageFor
21729
+ })
21730
+ );
21731
+ for (const [key, owners] of summariesBySeed) {
21732
+ for (const summary of owners) {
21733
+ if (gapHandling !== "silent") {
21734
+ summary.gaps.push(
21735
+ ...(reached.stopsByKey.get(key) ?? []).map(import_behavioral_ir4.unfollowedCallGap)
21736
+ );
21737
+ }
21738
+ (0, import_behavioral_ir4.placeCalls)(summary, reached.targetsByKey.get(key));
21739
+ (0, import_behavioral_ir4.placeArgTargets)(summary, reached.argTargetsByKey.get(key));
21740
+ (0, import_behavioral_ir4.placeCalleeParameters)(summary, reached.parameterCallsByKey.get(key));
21741
+ }
21742
+ }
21743
+ if (gapHandling !== "silent") {
21744
+ (0, import_behavioral_ir4.recordParameterGaps)(
21745
+ reached.parameterCallsByKey,
21746
+ summariesBySeed,
21747
+ reached.passedPositions
21748
+ );
21749
+ }
21750
+ summaries.push(...reached.summaries);
21751
+ const resolvedImports = resolvedImportsOf(db, displayPathOf);
21752
+ (0, import_extractor8.stampModuleImports)(summaries, (file2) => resolvedImports.get(file2) ?? []);
21753
+ const idRoot = options.projectRoot ?? options.workspaceRoot;
21754
+ for (const summary of summaries) {
21755
+ const absoluteFile = options.workspaceRoot === void 0 ? summary.location.file : import_node_path3.default.resolve(options.workspaceRoot, summary.location.file);
21756
+ summary.identity.id = (0, import_behavioral_ir4.summaryIdFromParts)({
21757
+ workspace: void 0,
21758
+ file: idRoot === void 0 ? absoluteFile : import_node_path3.default.relative(idRoot, absoluteFile),
21759
+ name: summary.identity.name,
21760
+ exportPath: summary.identity.exportPath
21761
+ });
21762
+ }
21763
+ (0, import_behavioral_ir4.disambiguateSummaryIds)(summaries);
21764
+ (0, import_behavioral_ir4.linkCallsToSummaries)(summaries);
21765
+ await timer.timeAsync("cache.write", async () => {
21766
+ if (cacheDir === null || summaries.length === 0) {
21767
+ return;
21768
+ }
21769
+ try {
21770
+ await cache.write(cacheInput, summaries);
21771
+ } catch {
21772
+ }
21773
+ });
21774
+ options.onExtractionReport?.(
21775
+ buildPythonExtractionReport({
21776
+ packs: options.packs,
21777
+ tallies,
21778
+ filesWalked: options.files.length,
21779
+ summaries
21780
+ })
21781
+ );
21782
+ options.onTiming?.(timer.report());
20441
21783
  return { summaries, facts: db };
20442
21784
  }
20443
- function stampModuleImports(summaries, db, displayPathOf) {
21785
+ function resolvedImportsOf(db, displayPathOf) {
20444
21786
  const importsByFile = /* @__PURE__ */ new Map();
20445
21787
  for (const [from, , to] of db.facts("pyImportResolved")) {
20446
21788
  if (typeof from !== "string" || typeof to !== "string") {
20447
21789
  continue;
20448
21790
  }
20449
21791
  const key = displayPathOf(from);
20450
- const seen = importsByFile.get(key) ?? /* @__PURE__ */ new Set();
20451
- seen.add(displayPathOf(to));
21792
+ const seen = importsByFile.get(key) ?? [];
21793
+ seen.push(displayPathOf(to));
20452
21794
  importsByFile.set(key, seen);
20453
21795
  }
20454
- for (const summary of summaries) {
20455
- const imports = importsByFile.get(summary.location.file);
20456
- if (imports === void 0 || imports.size === 0) {
20457
- continue;
20458
- }
20459
- summary.metadata = {
20460
- ...summary.metadata ?? {},
20461
- moduleImports: [...imports].sort()
20462
- };
20463
- }
21796
+ return importsByFile;
20464
21797
  }
20465
21798
  var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set([
20466
21799
  "__pycache__",
@@ -20515,55 +21848,272 @@ function methodsDeclaredNear(db, patterns, definitions) {
20515
21848
  }
20516
21849
  return found;
20517
21850
  }
20518
- function calledName(call) {
20519
- const callee = field(call, "function");
20520
- if (callee === null) {
20521
- return "";
21851
+
21852
+ // src/facts/why.ts
21853
+ var FUNCTION_TYPES2 = /* @__PURE__ */ new Set(["function_definition", "lambda"]);
21854
+ var IMPORT_TYPES = /* @__PURE__ */ new Set(["import_statement", "import_from_statement"]);
21855
+ function namedChildrenOf(node) {
21856
+ return node.namedChildren.filter((child) => child !== null);
21857
+ }
21858
+ function indexImportNames(file2, stmt, locations) {
21859
+ for (const nameNode of fields(stmt, "name")) {
21860
+ if (nameNode.type === "aliased_import") {
21861
+ const alias = field(nameNode, "alias");
21862
+ if (alias !== null) {
21863
+ locations.set(`${file2}#${alias.text}`, { file: file2, node: alias });
21864
+ }
21865
+ continue;
21866
+ }
21867
+ const local = nameNode.type === "dotted_name" ? nameNode.namedChild(0) : nameNode;
21868
+ if (local !== null) {
21869
+ locations.set(`${file2}#${local.text}`, { file: file2, node: local });
21870
+ }
20522
21871
  }
20523
- return callee.type === "attribute" ? field(callee, "attribute")?.text ?? "" : callee.text;
20524
21872
  }
20525
- function callsUnder(node, found = []) {
20526
- for (const child of node.namedChildren) {
20527
- if (child === null) {
21873
+ function enclosingFunction(node) {
21874
+ let current = node.parent;
21875
+ while (current !== null) {
21876
+ if (FUNCTION_TYPES2.has(current.type)) {
21877
+ return current;
21878
+ }
21879
+ current = current.parent;
21880
+ }
21881
+ return null;
21882
+ }
21883
+ function indexFile(file2, root, locations) {
21884
+ const walk = (node) => {
21885
+ locations.set(nodeId(file2, node), { file: file2, node });
21886
+ if (IMPORT_TYPES.has(node.type)) {
21887
+ indexImportNames(file2, node, locations);
21888
+ }
21889
+ if (FUNCTION_TYPES2.has(node.type) || node.type === "class_definition") {
21890
+ const name = field(node, "name");
21891
+ if (name !== null) {
21892
+ locations.set(`${file2}#${name.text}`, { file: file2, node: name });
21893
+ }
21894
+ }
21895
+ if (node.type === "assignment") {
21896
+ const left = field(node, "left");
21897
+ if (left !== null && left.type === "identifier") {
21898
+ locations.set(`${file2}#${left.text}`, { file: file2, node: left });
21899
+ }
21900
+ }
21901
+ for (const child of namedChildrenOf(node)) {
21902
+ walk(child);
21903
+ }
21904
+ };
21905
+ walk(root);
21906
+ }
21907
+ function displayNameOf(node) {
21908
+ if (node.type === "identifier") {
21909
+ return node.text;
21910
+ }
21911
+ if (node.type === "call") {
21912
+ const callee = field(node, "function");
21913
+ return `${callee?.text ?? "call"}(...)`;
21914
+ }
21915
+ if (node.type === "function_definition" || node.type === "class_definition") {
21916
+ return field(node, "name")?.text ?? node.text;
21917
+ }
21918
+ const text = node.text.split("\n")[0].trim();
21919
+ return text.length > 40 ? `${text.slice(0, 40)}...` : text;
21920
+ }
21921
+ function width(node) {
21922
+ return node.endIndex - node.startIndex;
21923
+ }
21924
+ var PythonWhySession = class {
21925
+ root;
21926
+ db = new import_datalog7.Database();
21927
+ locations = /* @__PURE__ */ new Map();
21928
+ trees = /* @__PURE__ */ new Map();
21929
+ constructor(options) {
21930
+ this.root = import_node_path4.default.resolve(options.dir);
21931
+ const roots = [this.root];
21932
+ for (const file2 of findPythonFiles(this.root)) {
21933
+ const source = import_node_fs4.default.readFileSync(file2, "utf8");
21934
+ const root = parsePythonSync(source).rootNode;
21935
+ this.trees.set(file2, root);
21936
+ emitModuleImportFacts(this.db, file2, bindModule(root), { roots });
21937
+ emitValueFacts(this.db, file2, root);
21938
+ indexFile(file2, root, this.locations);
21939
+ }
21940
+ }
21941
+ /**
21942
+ * The smallest expression on `line` of `file` whose text is exactly
21943
+ * `text`, or null.
21944
+ */
21945
+ findExpression(file2, line, text) {
21946
+ const root = this.rootOf(file2);
21947
+ if (root === null) {
21948
+ return null;
21949
+ }
21950
+ let found = null;
21951
+ const visit = (node) => {
21952
+ if (node.startPosition.row + 1 === line && node.text === text) {
21953
+ if (found === null || width(node) <= width(found)) {
21954
+ found = node;
21955
+ }
21956
+ }
21957
+ for (const child of namedChildrenOf(node)) {
21958
+ visit(child);
21959
+ }
21960
+ };
21961
+ visit(root);
21962
+ return found === null ? null : { file: this.pathOf(file2), node: found };
21963
+ }
21964
+ /**
21965
+ * The callee of the call written as `calleeText` between `startLine`
21966
+ * and `endLine` of `file`, or null.
21967
+ */
21968
+ findCallee(file2, startLine, endLine, calleeText2) {
21969
+ const root = this.rootOf(file2);
21970
+ if (root === null) {
21971
+ return null;
21972
+ }
21973
+ let found = null;
21974
+ const visit = (node) => {
21975
+ if (node.type === "call") {
21976
+ const line = node.startPosition.row + 1;
21977
+ const callee = field(node, "function");
21978
+ if (line >= startLine && line <= endLine && callee !== null && callee.text === calleeText2) {
21979
+ found = callee;
21980
+ }
21981
+ }
21982
+ for (const child of namedChildrenOf(node)) {
21983
+ visit(child);
21984
+ }
21985
+ };
21986
+ visit(root);
21987
+ return found === null ? null : { file: this.pathOf(file2), node: found };
21988
+ }
21989
+ /**
21990
+ * Why `value` resolves to what it does: the witness proof, flattened
21991
+ * to the chain and rendered. Null when the value does not resolve,
21992
+ * which the caller says in its own words.
21993
+ */
21994
+ explain(value, options = {}) {
21995
+ return explainResolvedKey({
21996
+ db: this.db,
21997
+ rules: RESOLUTION_RULES,
21998
+ key: readKey(value.file, value.node, enclosingFunction(value.node)),
21999
+ locate: (key) => this.locate(key),
22000
+ displayPath: (key) => this.displayPath(key),
22001
+ ...options
22002
+ });
22003
+ }
22004
+ locate(key) {
22005
+ const located = this.locations.get(key);
22006
+ if (located === void 0) {
22007
+ return null;
22008
+ }
22009
+ return {
22010
+ name: displayNameOf(located.node),
22011
+ file: this.displayPath(located.file),
22012
+ line: located.node.startPosition.row + 1
22013
+ };
22014
+ }
22015
+ rootOf(file2) {
22016
+ return this.trees.get(this.pathOf(file2)) ?? null;
22017
+ }
22018
+ pathOf(file2) {
22019
+ return import_node_path4.default.isAbsolute(file2) ? file2 : import_node_path4.default.resolve(this.root, file2);
22020
+ }
22021
+ /** A file path said relative to the root, or as given when it is outside the root. */
22022
+ displayPath(key) {
22023
+ if (key.startsWith(this.root)) {
22024
+ return import_node_path4.default.relative(this.root, key);
22025
+ }
22026
+ return key;
22027
+ }
22028
+ };
22029
+
22030
+ // src/stubEvidence.ts
22031
+ var import_node_fs5 = __toESM(require("fs"), 1);
22032
+ var import_node_path5 = __toESM(require("path"), 1);
22033
+ function importsSubmoduleOf(module2, packageName) {
22034
+ return module2 === packageName || module2.startsWith(`${packageName}.`);
22035
+ }
22036
+ function importStatementModules(stmt) {
22037
+ const modules = [];
22038
+ for (const nameNode of fields(stmt, "name")) {
22039
+ if (nameNode.type === "aliased_import") {
22040
+ const dotted = field(nameNode, "name");
22041
+ if (dotted !== null) {
22042
+ modules.push(dotted.text);
22043
+ }
20528
22044
  continue;
20529
22045
  }
20530
- if (child.type === "call") {
20531
- found.push(child);
22046
+ if (nameNode.type === "dotted_name") {
22047
+ modules.push(nameNode.text);
20532
22048
  }
20533
- callsUnder(child, found);
20534
22049
  }
20535
- return found;
22050
+ return modules;
20536
22051
  }
20537
- var REACHES_STORAGE_RULES = [
20538
- (0, import_datalog4.rule)(
20539
- "reachesStorage",
20540
- [(0, import_datalog4.variable)("f")],
20541
- [(0, import_datalog4.lit)("defCallsName", (0, import_datalog4.variable)("f"), (0, import_datalog4.variable)("m")), (0, import_datalog4.lit)("queryStart", (0, import_datalog4.variable)("m"))]
20542
- ),
20543
- (0, import_datalog4.rule)(
20544
- "reachesStorage",
20545
- [(0, import_datalog4.variable)("f")],
20546
- [(0, import_datalog4.lit)("defCallsName", (0, import_datalog4.variable)("f"), (0, import_datalog4.variable)("m")), (0, import_datalog4.lit)("reachesStorage", (0, import_datalog4.variable)("m"))]
20547
- )
20548
- ];
20549
- function functionsReachingStorage(db, definitions, couldMatch) {
20550
- for (const node of definitions.values()) {
20551
- const name = field(node, "name");
20552
- if (name === null) {
22052
+ function importFromStatementEntries(stmt) {
22053
+ const moduleNode = field(stmt, "module_name");
22054
+ if (moduleNode === null || moduleNode.type === "relative_import") {
22055
+ return [];
22056
+ }
22057
+ const module2 = moduleNode.text;
22058
+ const entries = [];
22059
+ for (const nameNode of fields(stmt, "name")) {
22060
+ if (nameNode.type === "aliased_import") {
22061
+ const original = field(nameNode, "name");
22062
+ if (original !== null) {
22063
+ entries.push({ module: module2, name: original.text });
22064
+ }
20553
22065
  continue;
20554
22066
  }
20555
- for (const called of callsUnder(node).map(calledName)) {
20556
- db.add("defCallsName", [name.text, called]);
22067
+ if (nameNode.type === "dotted_name") {
22068
+ entries.push({ module: module2, name: nameNode.text });
20557
22069
  }
20558
22070
  }
20559
- for (const name of couldMatch) {
20560
- db.add("queryStart", [name]);
22071
+ return entries;
22072
+ }
22073
+ function importSitesIn(root) {
22074
+ const found = [];
22075
+ const visit = (node) => {
22076
+ if (node.type === "import_statement") {
22077
+ const line = rangeOf(node).start;
22078
+ for (const module2 of importStatementModules(node)) {
22079
+ found.push({ module: module2, name: null, line });
22080
+ }
22081
+ } else if (node.type === "import_from_statement") {
22082
+ const line = rangeOf(node).start;
22083
+ for (const entry of importFromStatementEntries(node)) {
22084
+ found.push({ module: entry.module, name: entry.name, line });
22085
+ }
22086
+ }
22087
+ for (const child of node.namedChildren) {
22088
+ if (child !== null) {
22089
+ visit(child);
22090
+ }
22091
+ }
22092
+ };
22093
+ visit(root);
22094
+ return found;
22095
+ }
22096
+ async function pythonImportEvidence(options) {
22097
+ const byModule = /* @__PURE__ */ new Map();
22098
+ for (const file2 of findPythonFiles(options.directory)) {
22099
+ const source = import_node_fs5.default.readFileSync(file2, "utf8");
22100
+ const tree = await parsePython(source);
22101
+ const displayPath = import_node_path5.default.relative(options.directory, file2);
22102
+ for (const site of importSitesIn(tree.rootNode)) {
22103
+ if (!importsSubmoduleOf(site.module, options.packageName)) {
22104
+ continue;
22105
+ }
22106
+ const sites = byModule.get(site.module) ?? [];
22107
+ sites.push({ name: site.name, file: displayPath, line: site.line });
22108
+ byModule.set(site.module, sites);
22109
+ }
20561
22110
  }
20562
- (0, import_datalog4.evaluate)(db, REACHES_STORAGE_RULES);
20563
- return new Set(db.facts("reachesStorage").map((row) => String(row[0])));
22111
+ return [...byModule.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([module2, sites]) => ({ module: module2, sites }));
20564
22112
  }
20565
22113
  // Annotate the CommonJS export names for ESM import in node:
20566
22114
  0 && (module.exports = {
22115
+ ADAPTER_VERSION,
22116
+ PythonWhySession,
20567
22117
  annotationToShape,
20568
22118
  bindModule,
20569
22119
  buildRouterIndex,
@@ -20578,6 +22128,10 @@ function functionsReachingStorage(db, definitions, couldMatch) {
20578
22128
  nodeId,
20579
22129
  objectReturnedBy,
20580
22130
  parsePython,
22131
+ parsePythonSync,
22132
+ preloadPythonGrammar,
22133
+ pythonImportEvidence,
22134
+ readKey,
20581
22135
  resolveAbsoluteModule,
20582
22136
  resolveCalls,
20583
22137
  resolveModule,