@suss/adapter-python 0.21.1 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -0
- package/dist/index.cjs +2183 -689
- package/dist/index.d.cts +148 -3
- package/dist/index.d.ts +148 -3
- package/dist/index.js +1831 -309
- package/package.json +5 -5
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
|
|
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
|
|
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
|
-
|
|
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 === "" ?
|
|
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
|
-
|
|
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,
|
|
862
|
-
var RESULT_STEP = (0,
|
|
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,
|
|
1335
|
+
(0, import_datalog3.rule)(
|
|
868
1336
|
"stepsTo",
|
|
869
|
-
[(0,
|
|
870
|
-
[(0,
|
|
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,
|
|
1344
|
+
(0, import_datalog3.rule)(
|
|
877
1345
|
"stepsTo",
|
|
878
|
-
[(0,
|
|
879
|
-
[(0,
|
|
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,
|
|
1353
|
+
(0, import_datalog3.rule)(
|
|
886
1354
|
"stepsTo",
|
|
887
|
-
[(0,
|
|
888
|
-
[(0,
|
|
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,
|
|
1360
|
+
(0, import_datalog3.rule)(
|
|
893
1361
|
"stepsTo",
|
|
894
|
-
[(0,
|
|
1362
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("value"), VALUE_STEP],
|
|
895
1363
|
[
|
|
896
|
-
(0,
|
|
897
|
-
(0,
|
|
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,
|
|
1372
|
+
(0, import_datalog3.rule)(
|
|
905
1373
|
"stepsTo",
|
|
906
|
-
[(0,
|
|
907
|
-
[(0,
|
|
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,
|
|
1381
|
+
(0, import_datalog3.rule)(
|
|
914
1382
|
"stepsTo",
|
|
915
|
-
[(0,
|
|
1383
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("held"), VALUE_STEP],
|
|
916
1384
|
[
|
|
917
|
-
(0,
|
|
918
|
-
(0,
|
|
919
|
-
(0,
|
|
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,
|
|
1394
|
+
(0, import_datalog3.rule)(
|
|
927
1395
|
"stepsTo",
|
|
928
|
-
[(0,
|
|
1396
|
+
[(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("cls"), VALUE_STEP],
|
|
929
1397
|
[
|
|
930
|
-
(0,
|
|
931
|
-
(0,
|
|
932
|
-
(0,
|
|
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,
|
|
1406
|
+
(0, import_datalog3.rule)(
|
|
939
1407
|
"stepsTo",
|
|
940
|
-
[(0,
|
|
1408
|
+
[(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("a"), VALUE_STEP],
|
|
941
1409
|
[
|
|
942
|
-
(0,
|
|
943
|
-
(0,
|
|
944
|
-
(0,
|
|
945
|
-
(0,
|
|
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,
|
|
1420
|
+
(0, import_datalog3.rule)(
|
|
953
1421
|
"stepsTo",
|
|
954
|
-
[(0,
|
|
1422
|
+
[(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("a"), VALUE_STEP],
|
|
955
1423
|
[
|
|
956
|
-
(0,
|
|
957
|
-
(0,
|
|
958
|
-
(0,
|
|
959
|
-
(0,
|
|
960
|
-
(0,
|
|
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,
|
|
1434
|
+
(0, import_datalog3.rule)(
|
|
967
1435
|
"stepsTo",
|
|
968
|
-
[(0,
|
|
969
|
-
[(0,
|
|
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
1440
|
// Where a walk gets to, and whether it ran a call on the way. The walk
|
|
973
1441
|
// so far comes first, so demand stays on the value asked about; the
|
|
974
1442
|
// README says what the other order cost.
|
|
975
|
-
(0,
|
|
1443
|
+
(0, import_datalog3.rule)(
|
|
976
1444
|
"reaches",
|
|
977
|
-
[(0,
|
|
978
|
-
[(0,
|
|
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,
|
|
1448
|
+
(0, import_datalog3.rule)(
|
|
981
1449
|
"reaches",
|
|
982
|
-
[(0,
|
|
1450
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), (0, import_datalog3.variable)("kind")],
|
|
983
1451
|
[
|
|
984
|
-
(0,
|
|
985
|
-
(0,
|
|
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
1456
|
// Two rules rather than one leaving the next step's kind free. A free
|
|
989
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,
|
|
1459
|
+
(0, import_datalog3.rule)(
|
|
992
1460
|
"reaches",
|
|
993
|
-
[(0,
|
|
1461
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), RESULT_STEP],
|
|
994
1462
|
[
|
|
995
|
-
(0,
|
|
996
|
-
(0,
|
|
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,
|
|
1467
|
+
(0, import_datalog3.rule)(
|
|
1000
1468
|
"reaches",
|
|
1001
|
-
[(0,
|
|
1469
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), RESULT_STEP],
|
|
1002
1470
|
[
|
|
1003
|
-
(0,
|
|
1004
|
-
(0,
|
|
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,
|
|
1011
|
-
(0,
|
|
1012
|
-
(0,
|
|
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,
|
|
1015
|
-
[(0,
|
|
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,
|
|
1485
|
+
(0, import_datalog3.rule)(
|
|
1018
1486
|
"comesTo",
|
|
1019
|
-
[(0,
|
|
1020
|
-
[(0,
|
|
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,
|
|
1493
|
+
(0, import_datalog3.rule)(
|
|
1026
1494
|
"givesBack",
|
|
1027
|
-
[(0,
|
|
1028
|
-
[(0,
|
|
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,
|
|
1498
|
+
(0, import_datalog3.rule)(
|
|
1031
1499
|
"givesBack",
|
|
1032
|
-
[(0,
|
|
1033
|
-
[(0,
|
|
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,
|
|
1039
|
-
(0,
|
|
1040
|
-
(0,
|
|
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,
|
|
1043
|
-
[(0,
|
|
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
|
-
|
|
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,
|
|
1048
|
-
[
|
|
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,
|
|
1532
|
+
(0, import_datalog3.rule)(
|
|
1053
1533
|
"paramAt",
|
|
1054
|
-
[(0,
|
|
1534
|
+
[(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("p"), (0, import_datalog3.variable)("z")],
|
|
1055
1535
|
[
|
|
1056
|
-
(0,
|
|
1057
|
-
(0,
|
|
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,
|
|
1543
|
+
(0, import_datalog3.rule)(
|
|
1064
1544
|
"passesArgument",
|
|
1065
|
-
[(0,
|
|
1545
|
+
[(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("p"), (0, import_datalog3.variable)("a")],
|
|
1066
1546
|
[
|
|
1067
|
-
(0,
|
|
1068
|
-
(0,
|
|
1069
|
-
(0,
|
|
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,
|
|
1552
|
+
(0, import_datalog3.rule)(
|
|
1073
1553
|
"passesArgument",
|
|
1074
|
-
[(0,
|
|
1554
|
+
[(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("p"), (0, import_datalog3.variable)("a")],
|
|
1075
1555
|
[
|
|
1076
|
-
(0,
|
|
1077
|
-
(0,
|
|
1078
|
-
(0,
|
|
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,
|
|
1563
|
+
(0, import_datalog3.rule)(
|
|
1084
1564
|
"moduleForwards",
|
|
1085
|
-
[(0,
|
|
1086
|
-
[(0,
|
|
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,
|
|
1568
|
+
(0, import_datalog3.rule)(
|
|
1089
1569
|
"moduleForwards",
|
|
1090
|
-
[(0,
|
|
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,
|
|
1093
|
-
(0,
|
|
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,
|
|
1577
|
+
(0, import_datalog3.rule)(
|
|
1098
1578
|
"moduleExport",
|
|
1099
|
-
[(0,
|
|
1100
|
-
[(0,
|
|
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,
|
|
1583
|
+
(0, import_datalog3.rule)(
|
|
1104
1584
|
"moduleExport",
|
|
1105
|
-
[(0,
|
|
1585
|
+
[(0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("value")],
|
|
1106
1586
|
[
|
|
1107
|
-
(0,
|
|
1108
|
-
(0,
|
|
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,
|
|
1592
|
+
(0, import_datalog3.rule)(
|
|
1113
1593
|
"moduleExport",
|
|
1114
|
-
[(0,
|
|
1594
|
+
[(0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("value")],
|
|
1115
1595
|
[
|
|
1116
|
-
(0,
|
|
1117
|
-
(0,
|
|
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,
|
|
1603
|
+
(0, import_datalog3.rule)(
|
|
1124
1604
|
"invokes",
|
|
1125
|
-
[(0,
|
|
1126
|
-
[(0,
|
|
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,
|
|
1609
|
+
(0, import_datalog3.rule)(
|
|
1130
1610
|
"invokes",
|
|
1131
|
-
[(0,
|
|
1132
|
-
[(0,
|
|
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,
|
|
1617
|
+
(0, import_datalog3.rule)(
|
|
1138
1618
|
"objectOf",
|
|
1139
|
-
[(0,
|
|
1140
|
-
[(0,
|
|
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,
|
|
1622
|
+
(0, import_datalog3.rule)(
|
|
1143
1623
|
"objectOf",
|
|
1144
|
-
[(0,
|
|
1145
|
-
[(0,
|
|
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,
|
|
1632
|
+
(0, import_datalog3.rule)(
|
|
1153
1633
|
"callsFunction",
|
|
1154
|
-
[(0,
|
|
1155
|
-
[(0,
|
|
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,
|
|
1637
|
+
(0, import_datalog3.rule)(
|
|
1158
1638
|
"callsFunction",
|
|
1159
|
-
[(0,
|
|
1639
|
+
[(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("f")],
|
|
1160
1640
|
[
|
|
1161
|
-
(0,
|
|
1162
|
-
(0,
|
|
1163
|
-
(0,
|
|
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,
|
|
1648
|
+
(0, import_datalog3.rule)(
|
|
1169
1649
|
"callsFunction",
|
|
1170
|
-
[(0,
|
|
1650
|
+
[(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("f")],
|
|
1171
1651
|
[
|
|
1172
|
-
(0,
|
|
1173
|
-
(0,
|
|
1174
|
-
(0,
|
|
1175
|
-
(0,
|
|
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,
|
|
1663
|
+
(0, import_datalog3.rule)(
|
|
1184
1664
|
"contains",
|
|
1185
|
-
[(0,
|
|
1186
|
-
[(0,
|
|
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,
|
|
1668
|
+
(0, import_datalog3.rule)(
|
|
1189
1669
|
"contains",
|
|
1190
|
-
[(0,
|
|
1670
|
+
[(0, import_datalog3.variable)("cls"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("held")],
|
|
1191
1671
|
[
|
|
1192
|
-
(0,
|
|
1193
|
-
(0,
|
|
1194
|
-
(0,
|
|
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,
|
|
1679
|
+
(0, import_datalog3.rule)(
|
|
1200
1680
|
"returnsFunc",
|
|
1201
|
-
[(0,
|
|
1681
|
+
[(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("g")],
|
|
1202
1682
|
[
|
|
1203
|
-
(0,
|
|
1204
|
-
(0,
|
|
1205
|
-
(0,
|
|
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,
|
|
1211
|
-
(0,
|
|
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,
|
|
1214
|
-
[(0,
|
|
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,
|
|
1696
|
+
(0, import_datalog3.rule)(
|
|
1217
1697
|
"unwraps",
|
|
1218
|
-
[(0,
|
|
1698
|
+
[(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("k")],
|
|
1219
1699
|
[
|
|
1220
|
-
(0,
|
|
1221
|
-
(0,
|
|
1222
|
-
(0,
|
|
1223
|
-
(0,
|
|
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,289 +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,
|
|
1711
|
+
(0, import_datalog3.rule)(
|
|
1232
1712
|
"flowsToParam",
|
|
1233
|
-
[(0,
|
|
1713
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("p")],
|
|
1234
1714
|
[
|
|
1235
|
-
(0,
|
|
1236
|
-
(0,
|
|
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,
|
|
1719
|
+
(0, import_datalog3.rule)(
|
|
1240
1720
|
"flowsToParam",
|
|
1241
|
-
[(0,
|
|
1721
|
+
[(0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("p")],
|
|
1242
1722
|
[
|
|
1243
|
-
(0,
|
|
1244
|
-
(0,
|
|
1245
|
-
(0,
|
|
1246
|
-
(0,
|
|
1247
|
-
(0,
|
|
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,
|
|
1730
|
+
(0, import_datalog3.rule)(
|
|
1251
1731
|
"unwraps",
|
|
1252
|
-
[(0,
|
|
1732
|
+
[(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("k")],
|
|
1253
1733
|
[
|
|
1254
|
-
(0,
|
|
1255
|
-
(0,
|
|
1256
|
-
(0,
|
|
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,
|
|
1742
|
+
(0, import_datalog3.rule)(
|
|
1263
1743
|
"comesFrom",
|
|
1264
|
-
[(0,
|
|
1265
|
-
[(0,
|
|
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,
|
|
1747
|
+
(0, import_datalog3.rule)(
|
|
1268
1748
|
"comesFrom",
|
|
1269
|
-
[(0,
|
|
1749
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
|
|
1270
1750
|
[
|
|
1271
|
-
(0,
|
|
1272
|
-
(0,
|
|
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,
|
|
1758
|
+
(0, import_datalog3.rule)(
|
|
1279
1759
|
"callsInto",
|
|
1280
|
-
[(0,
|
|
1760
|
+
[(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
|
|
1281
1761
|
[
|
|
1282
|
-
(0,
|
|
1283
|
-
(0,
|
|
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,
|
|
1766
|
+
(0, import_datalog3.rule)(
|
|
1287
1767
|
"callsInto",
|
|
1288
|
-
[(0,
|
|
1768
|
+
[(0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
|
|
1289
1769
|
[
|
|
1290
|
-
(0,
|
|
1291
|
-
(0,
|
|
1292
|
-
(0,
|
|
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,
|
|
1778
|
+
(0, import_datalog3.rule)(
|
|
1299
1779
|
"resolves",
|
|
1300
|
-
[(0,
|
|
1301
|
-
[(0,
|
|
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,
|
|
1785
|
+
(0, import_datalog3.rule)(
|
|
1306
1786
|
"wantedResolves",
|
|
1307
|
-
[(0,
|
|
1308
|
-
[(0,
|
|
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,
|
|
1790
|
+
(0, import_datalog3.rule)(
|
|
1311
1791
|
"wantedComesTo",
|
|
1312
|
-
[(0,
|
|
1313
|
-
[(0,
|
|
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,
|
|
1795
|
+
(0, import_datalog3.rule)(
|
|
1316
1796
|
"wantedComesTo",
|
|
1317
|
-
[(0,
|
|
1318
|
-
[(0,
|
|
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,
|
|
1800
|
+
(0, import_datalog3.rule)(
|
|
1321
1801
|
"wantedIsWrittenAs",
|
|
1322
|
-
[(0,
|
|
1323
|
-
[(0,
|
|
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,
|
|
1808
|
+
(0, import_datalog3.rule)(
|
|
1329
1809
|
"wantedObjectOf",
|
|
1330
|
-
[(0,
|
|
1331
|
-
[(0,
|
|
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,
|
|
1815
|
+
(0, import_datalog3.rule)(
|
|
1336
1816
|
"wantedParamAt",
|
|
1337
|
-
[(0,
|
|
1338
|
-
[(0,
|
|
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,
|
|
1820
|
+
(0, import_datalog3.rule)(
|
|
1341
1821
|
"wantedComesFrom",
|
|
1342
|
-
[(0,
|
|
1343
|
-
[(0,
|
|
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,
|
|
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"))]),
|
|
1350
1830
|
// The chain with at least one hop taken, which is what tells a
|
|
1351
1831
|
// destructured binding apart from asking about a node directly. The
|
|
1352
1832
|
// whole chain is the seed plus those hops.
|
|
1353
|
-
(0,
|
|
1833
|
+
(0, import_datalog3.rule)(
|
|
1354
1834
|
"callOriginChain",
|
|
1355
|
-
[(0,
|
|
1356
|
-
[(0,
|
|
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"))]
|
|
1357
1837
|
),
|
|
1358
|
-
(0,
|
|
1838
|
+
(0, import_datalog3.rule)(
|
|
1359
1839
|
"callOriginChainStepped",
|
|
1360
|
-
[(0,
|
|
1361
|
-
[(0,
|
|
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"))]
|
|
1362
1842
|
),
|
|
1363
|
-
(0,
|
|
1843
|
+
(0, import_datalog3.rule)(
|
|
1364
1844
|
"callOriginChainStepped",
|
|
1365
|
-
[(0,
|
|
1845
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
|
|
1366
1846
|
[
|
|
1367
|
-
(0,
|
|
1368
|
-
(0,
|
|
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"))
|
|
1369
1849
|
]
|
|
1370
1850
|
),
|
|
1371
|
-
(0,
|
|
1851
|
+
(0, import_datalog3.rule)(
|
|
1372
1852
|
"callOriginChainStepped",
|
|
1373
|
-
[(0,
|
|
1853
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
|
|
1374
1854
|
[
|
|
1375
|
-
(0,
|
|
1376
|
-
(0,
|
|
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"))
|
|
1377
1857
|
]
|
|
1378
1858
|
),
|
|
1379
|
-
(0,
|
|
1859
|
+
(0, import_datalog3.rule)(
|
|
1380
1860
|
"wantedCallOriginPair",
|
|
1381
|
-
[(0,
|
|
1861
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
|
|
1382
1862
|
[
|
|
1383
|
-
(0,
|
|
1384
|
-
(0,
|
|
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"))
|
|
1385
1865
|
]
|
|
1386
1866
|
),
|
|
1387
1867
|
// An import of a project barrel is an import of what the barrel
|
|
1388
1868
|
// forwards, so the pair surfaces the module behind the chain.
|
|
1389
|
-
(0,
|
|
1869
|
+
(0, import_datalog3.rule)(
|
|
1390
1870
|
"wantedCallOriginPair",
|
|
1391
|
-
[(0,
|
|
1871
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m2"), (0, import_datalog3.variable)("n2")],
|
|
1392
1872
|
[
|
|
1393
|
-
(0,
|
|
1394
|
-
(0,
|
|
1395
|
-
(0,
|
|
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"))
|
|
1396
1876
|
]
|
|
1397
1877
|
),
|
|
1398
1878
|
// A namespace member: the module's export of the member's own name.
|
|
1399
1879
|
// The imports literal leads, since it is the smallest relation.
|
|
1400
|
-
(0,
|
|
1880
|
+
(0, import_datalog3.rule)(
|
|
1401
1881
|
"wantedCallOriginPair",
|
|
1402
|
-
[(0,
|
|
1882
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("p")],
|
|
1403
1883
|
[
|
|
1404
|
-
(0,
|
|
1405
|
-
(0,
|
|
1406
|
-
(0,
|
|
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"))
|
|
1407
1887
|
]
|
|
1408
1888
|
),
|
|
1409
|
-
(0,
|
|
1889
|
+
(0, import_datalog3.rule)(
|
|
1410
1890
|
"wantedCallOriginPair",
|
|
1411
|
-
[(0,
|
|
1891
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("p")],
|
|
1412
1892
|
[
|
|
1413
|
-
(0,
|
|
1414
|
-
(0,
|
|
1415
|
-
(0,
|
|
1416
|
-
(0,
|
|
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"))
|
|
1417
1897
|
]
|
|
1418
1898
|
),
|
|
1419
1899
|
// What a call made: through the call to its callee, whose own alias
|
|
1420
1900
|
// chain leads to the import.
|
|
1421
|
-
(0,
|
|
1901
|
+
(0, import_datalog3.rule)(
|
|
1422
1902
|
"callMadeChain",
|
|
1423
|
-
[(0,
|
|
1424
|
-
[(0,
|
|
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"))]
|
|
1425
1905
|
),
|
|
1426
|
-
(0,
|
|
1906
|
+
(0, import_datalog3.rule)(
|
|
1427
1907
|
"callMadeChain",
|
|
1428
|
-
[(0,
|
|
1429
|
-
[(0,
|
|
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"))]
|
|
1430
1910
|
),
|
|
1431
|
-
(0,
|
|
1911
|
+
(0, import_datalog3.rule)(
|
|
1432
1912
|
"callMadeChain",
|
|
1433
|
-
[(0,
|
|
1434
|
-
[(0,
|
|
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"))]
|
|
1435
1915
|
),
|
|
1436
|
-
(0,
|
|
1916
|
+
(0, import_datalog3.rule)(
|
|
1437
1917
|
"wantedCallOriginPair",
|
|
1438
|
-
[(0,
|
|
1918
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
|
|
1439
1919
|
[
|
|
1440
|
-
(0,
|
|
1441
|
-
(0,
|
|
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"))
|
|
1442
1922
|
]
|
|
1443
1923
|
),
|
|
1444
1924
|
// A member destructured off what a call made keeps the member name
|
|
1445
1925
|
// as one more path segment.
|
|
1446
|
-
(0,
|
|
1926
|
+
(0, import_datalog3.rule)(
|
|
1447
1927
|
"callMemberChain",
|
|
1448
|
-
[(0,
|
|
1928
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("p")],
|
|
1449
1929
|
[
|
|
1450
|
-
(0,
|
|
1451
|
-
(0,
|
|
1452
|
-
(0,
|
|
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"))
|
|
1453
1933
|
]
|
|
1454
1934
|
),
|
|
1455
|
-
(0,
|
|
1935
|
+
(0, import_datalog3.rule)(
|
|
1456
1936
|
"callMemberChain",
|
|
1457
|
-
[(0,
|
|
1937
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), (0, import_datalog3.variable)("p")],
|
|
1458
1938
|
[
|
|
1459
|
-
(0,
|
|
1460
|
-
(0,
|
|
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"))
|
|
1461
1941
|
]
|
|
1462
1942
|
),
|
|
1463
|
-
(0,
|
|
1943
|
+
(0, import_datalog3.rule)(
|
|
1464
1944
|
"callMemberChain",
|
|
1465
|
-
[(0,
|
|
1945
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), (0, import_datalog3.variable)("p")],
|
|
1466
1946
|
[
|
|
1467
|
-
(0,
|
|
1468
|
-
(0,
|
|
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"))
|
|
1469
1949
|
]
|
|
1470
1950
|
),
|
|
1471
|
-
(0,
|
|
1951
|
+
(0, import_datalog3.rule)(
|
|
1472
1952
|
"wantedCallOriginMember",
|
|
1473
|
-
[(0,
|
|
1953
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("p")],
|
|
1474
1954
|
[
|
|
1475
|
-
(0,
|
|
1476
|
-
(0,
|
|
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"))
|
|
1477
1957
|
]
|
|
1478
1958
|
),
|
|
1479
|
-
(0,
|
|
1959
|
+
(0, import_datalog3.rule)(
|
|
1480
1960
|
"wantedCallsInto",
|
|
1481
|
-
[(0,
|
|
1961
|
+
[(0, import_datalog3.variable)("g"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
|
|
1482
1962
|
[
|
|
1483
|
-
(0,
|
|
1484
|
-
(0,
|
|
1485
|
-
(0,
|
|
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"))
|
|
1486
1966
|
]
|
|
1487
1967
|
),
|
|
1488
1968
|
// Subject identity, its own demand class; the README's subject
|
|
1489
1969
|
// section says why the origin pair rides on the written-value walk.
|
|
1490
|
-
(0,
|
|
1970
|
+
(0, import_datalog3.rule)(
|
|
1491
1971
|
"wantedSubjectWritten",
|
|
1492
|
-
[(0,
|
|
1493
|
-
[(0,
|
|
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"))]
|
|
1494
1974
|
),
|
|
1495
|
-
(0,
|
|
1975
|
+
(0, import_datalog3.rule)(
|
|
1496
1976
|
"wantedSubjectConstruction",
|
|
1497
|
-
[(0,
|
|
1977
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
|
|
1498
1978
|
[
|
|
1499
|
-
(0,
|
|
1500
|
-
(0,
|
|
1501
|
-
(0,
|
|
1502
|
-
(0,
|
|
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"))
|
|
1503
1983
|
]
|
|
1504
1984
|
),
|
|
1505
1985
|
// The export table of one module, keyed by the module asked about.
|
|
1506
1986
|
// The moduleExport rules flatten re-export chains of any length, and
|
|
1507
1987
|
// the demand cone stays on export facts alone.
|
|
1508
|
-
(0,
|
|
1988
|
+
(0, import_datalog3.rule)(
|
|
1509
1989
|
"wantedModuleExport",
|
|
1510
|
-
[(0,
|
|
1990
|
+
[(0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("value")],
|
|
1511
1991
|
[
|
|
1512
|
-
(0,
|
|
1513
|
-
(0,
|
|
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"))
|
|
1514
1994
|
]
|
|
1515
1995
|
),
|
|
1516
1996
|
// The calls behind a receiver, for a pack that wants the anchor a
|
|
@@ -1519,63 +1999,63 @@ var RESOLUTION_QUESTIONS = [
|
|
|
1519
1999
|
// A class's ancestry, one hop per extends through the binding that
|
|
1520
2000
|
// says which class the written base is; the names on the way out
|
|
1521
2001
|
// are what a storage pack matches its library's bases against.
|
|
1522
|
-
(0,
|
|
1523
|
-
(0,
|
|
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)(
|
|
1524
2004
|
"ancestryChain",
|
|
1525
|
-
[(0,
|
|
2005
|
+
[(0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("b2")],
|
|
1526
2006
|
[
|
|
1527
|
-
(0,
|
|
1528
|
-
(0,
|
|
1529
|
-
(0,
|
|
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"))
|
|
1530
2010
|
]
|
|
1531
2011
|
),
|
|
1532
|
-
(0,
|
|
2012
|
+
(0, import_datalog3.rule)(
|
|
1533
2013
|
"wantedBaseName",
|
|
1534
|
-
[(0,
|
|
1535
|
-
[(0,
|
|
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"))]
|
|
1536
2016
|
),
|
|
1537
|
-
(0,
|
|
1538
|
-
(0,
|
|
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)(
|
|
1539
2019
|
"anchorChain",
|
|
1540
|
-
[(0,
|
|
1541
|
-
[(0,
|
|
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"))]
|
|
1542
2022
|
),
|
|
1543
|
-
(0,
|
|
2023
|
+
(0, import_datalog3.rule)(
|
|
1544
2024
|
"anchorChain",
|
|
1545
|
-
[(0,
|
|
1546
|
-
[(0,
|
|
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"))]
|
|
1547
2027
|
),
|
|
1548
|
-
(0,
|
|
2028
|
+
(0, import_datalog3.rule)(
|
|
1549
2029
|
"anchorChain",
|
|
1550
|
-
[(0,
|
|
1551
|
-
[(0,
|
|
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"))]
|
|
1552
2032
|
),
|
|
1553
|
-
(0,
|
|
2033
|
+
(0, import_datalog3.rule)(
|
|
1554
2034
|
"anchorChain",
|
|
1555
|
-
[(0,
|
|
2035
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
|
|
1556
2036
|
[
|
|
1557
|
-
(0,
|
|
1558
|
-
(0,
|
|
1559
|
-
(0,
|
|
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"))
|
|
1560
2040
|
]
|
|
1561
2041
|
),
|
|
1562
|
-
(0,
|
|
2042
|
+
(0, import_datalog3.rule)(
|
|
1563
2043
|
"anchorChain",
|
|
1564
|
-
[(0,
|
|
1565
|
-
[(0,
|
|
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"))]
|
|
1566
2046
|
),
|
|
1567
|
-
(0,
|
|
2047
|
+
(0, import_datalog3.rule)(
|
|
1568
2048
|
"anchorChain",
|
|
1569
|
-
[(0,
|
|
2049
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("o")],
|
|
1570
2050
|
[
|
|
1571
|
-
(0,
|
|
1572
|
-
(0,
|
|
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"))
|
|
1573
2053
|
]
|
|
1574
2054
|
),
|
|
1575
|
-
(0,
|
|
2055
|
+
(0, import_datalog3.rule)(
|
|
1576
2056
|
"wantedAnchorCall",
|
|
1577
|
-
[(0,
|
|
1578
|
-
[(0,
|
|
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"))]
|
|
1579
2059
|
)
|
|
1580
2060
|
];
|
|
1581
2061
|
var ANSWER_RELATIONS = [
|
|
@@ -1583,7 +2063,7 @@ var ANSWER_RELATIONS = [
|
|
|
1583
2063
|
];
|
|
1584
2064
|
|
|
1585
2065
|
// src/facts/resolve.ts
|
|
1586
|
-
var RESOLUTION_PROGRAM = (0,
|
|
2066
|
+
var RESOLUTION_PROGRAM = (0, import_datalog4.deriveOnDemand)(
|
|
1587
2067
|
[...RESOLUTION_RULES, ...RESOLUTION_QUESTIONS],
|
|
1588
2068
|
ANSWER_RELATIONS
|
|
1589
2069
|
);
|
|
@@ -1594,23 +2074,33 @@ function resolveCalls(db, callKeys) {
|
|
|
1594
2074
|
for (const callKey of callKeys) {
|
|
1595
2075
|
db.add("wanted", [callKey]);
|
|
1596
2076
|
}
|
|
1597
|
-
(0,
|
|
2077
|
+
(0, import_datalog4.evaluate)(db, RESOLUTION_PROGRAM.rules);
|
|
1598
2078
|
}
|
|
1599
2079
|
function subjectConstructions(db, valueKeys) {
|
|
1600
2080
|
const found = /* @__PURE__ */ new Map();
|
|
1601
2081
|
if (valueKeys.length === 0) {
|
|
1602
2082
|
return found;
|
|
1603
2083
|
}
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
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);
|
|
1613
2099
|
}
|
|
2100
|
+
const writtenThroughCall = singleAnswers(
|
|
2101
|
+
db.facts("wantedSubjectWritten"),
|
|
2102
|
+
placeholders
|
|
2103
|
+
);
|
|
1614
2104
|
const origins = /* @__PURE__ */ new Map();
|
|
1615
2105
|
for (const row of db.facts("wantedSubjectConstruction")) {
|
|
1616
2106
|
const key = `${String(row[0])}|${String(row[1])}`;
|
|
@@ -1619,12 +2109,14 @@ function subjectConstructions(db, valueKeys) {
|
|
|
1619
2109
|
origins.set(key, listed);
|
|
1620
2110
|
}
|
|
1621
2111
|
for (const valueKey2 of valueKeys) {
|
|
1622
|
-
const
|
|
1623
|
-
if (
|
|
2112
|
+
const direct = written.get(valueKey2);
|
|
2113
|
+
if (direct === void 0) {
|
|
1624
2114
|
continue;
|
|
1625
2115
|
}
|
|
1626
|
-
const
|
|
1627
|
-
const
|
|
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}`);
|
|
1628
2120
|
if (from !== void 0) {
|
|
1629
2121
|
found.set(valueKey2, { constructionKey, origins: from });
|
|
1630
2122
|
}
|
|
@@ -1820,6 +2312,9 @@ function emitExpressionFact(emitter, child) {
|
|
|
1820
2312
|
if (WRITTEN_VALUE_TYPES.has(child.type)) {
|
|
1821
2313
|
add(emitter, "writtenValue", nodeId(emitter.filePath, child));
|
|
1822
2314
|
}
|
|
2315
|
+
if (child.type === "none") {
|
|
2316
|
+
add(emitter, "placeholderValue", nodeId(emitter.filePath, child));
|
|
2317
|
+
}
|
|
1823
2318
|
}
|
|
1824
2319
|
function emitExpressionFacts(emitter, node) {
|
|
1825
2320
|
walkExpressions(emitter, node, (child) => {
|
|
@@ -2014,7 +2509,7 @@ function emitValueFacts(db, filePath, root) {
|
|
|
2014
2509
|
}
|
|
2015
2510
|
|
|
2016
2511
|
// src/paths/effects.ts
|
|
2017
|
-
var
|
|
2512
|
+
var import_extractor3 = require("@suss/extractor");
|
|
2018
2513
|
|
|
2019
2514
|
// src/paths/lowering.ts
|
|
2020
2515
|
var EXIT_KINDS = {
|
|
@@ -2278,7 +2773,7 @@ function predicateOf(node) {
|
|
|
2278
2773
|
}
|
|
2279
2774
|
|
|
2280
2775
|
// src/paths/effects.ts
|
|
2281
|
-
var
|
|
2776
|
+
var NESTED_DEFINITION_TYPES = /* @__PURE__ */ new Set(["function_definition"]);
|
|
2282
2777
|
var LITERAL_ARGS = {
|
|
2283
2778
|
string: (node) => ({ kind: "string", value: node.text.slice(1, -1) }),
|
|
2284
2779
|
integer: (node) => {
|
|
@@ -2294,7 +2789,7 @@ var LITERAL_ARGS = {
|
|
|
2294
2789
|
};
|
|
2295
2790
|
function bodyCalls(node, found = []) {
|
|
2296
2791
|
for (const child of node.namedChildren) {
|
|
2297
|
-
if (child === null ||
|
|
2792
|
+
if (child === null || NESTED_DEFINITION_TYPES.has(child.type)) {
|
|
2298
2793
|
continue;
|
|
2299
2794
|
}
|
|
2300
2795
|
if (child.type === "call") {
|
|
@@ -2336,26 +2831,12 @@ function argsOf(call) {
|
|
|
2336
2831
|
function calleeText(call) {
|
|
2337
2832
|
return field(call, "function")?.text ?? call.text;
|
|
2338
2833
|
}
|
|
2339
|
-
function withoutChainLinks(calls) {
|
|
2340
|
-
const isLink = /* @__PURE__ */ new Set();
|
|
2341
|
-
for (const call of calls) {
|
|
2342
|
-
const callee = field(call, "function");
|
|
2343
|
-
if (callee === null || callee.type !== "attribute") {
|
|
2344
|
-
continue;
|
|
2345
|
-
}
|
|
2346
|
-
const object2 = field(callee, "object");
|
|
2347
|
-
if (object2 !== null && object2.type === "call") {
|
|
2348
|
-
isLink.add(object2.id);
|
|
2349
|
-
}
|
|
2350
|
-
}
|
|
2351
|
-
return calls.filter((call) => !isLink.has(call.id));
|
|
2352
|
-
}
|
|
2353
2834
|
function invocationEffects(definitionNode) {
|
|
2354
2835
|
const body = field(definitionNode, "body");
|
|
2355
2836
|
if (body === null) {
|
|
2356
2837
|
return [];
|
|
2357
2838
|
}
|
|
2358
|
-
const calls =
|
|
2839
|
+
const calls = bodyCalls(body).sort((a, b) => a.endIndex - b.endIndex);
|
|
2359
2840
|
if (calls.length === 0) {
|
|
2360
2841
|
return [];
|
|
2361
2842
|
}
|
|
@@ -2370,7 +2851,7 @@ function invocationEffects(definitionNode) {
|
|
|
2370
2851
|
statements.push(statement);
|
|
2371
2852
|
}
|
|
2372
2853
|
const lowered = lowerPythonBody(body, statements);
|
|
2373
|
-
const enumerated = (0,
|
|
2854
|
+
const enumerated = (0, import_extractor3.enumerateOrDegrade)(
|
|
2374
2855
|
{
|
|
2375
2856
|
statements: lowered.statements,
|
|
2376
2857
|
terminalsByStmt: lowered.terminalsByStmt
|
|
@@ -2379,7 +2860,7 @@ function invocationEffects(definitionNode) {
|
|
|
2379
2860
|
);
|
|
2380
2861
|
return calls.map((call) => {
|
|
2381
2862
|
const statement = statementOf.get(call.id);
|
|
2382
|
-
const conditions = (0,
|
|
2863
|
+
const conditions = (0, import_extractor3.sharedGatingConditions)(
|
|
2383
2864
|
statement === void 0 ? void 0 : enumerated.byTerminal.get(statement),
|
|
2384
2865
|
predicateOf
|
|
2385
2866
|
);
|
|
@@ -3233,10 +3714,10 @@ function mergeDefs(...defs) {
|
|
|
3233
3714
|
function cloneDef(schema) {
|
|
3234
3715
|
return mergeDefs(schema._zod.def);
|
|
3235
3716
|
}
|
|
3236
|
-
function getElementAtPath(obj,
|
|
3237
|
-
if (!
|
|
3717
|
+
function getElementAtPath(obj, path6) {
|
|
3718
|
+
if (!path6)
|
|
3238
3719
|
return obj;
|
|
3239
|
-
return
|
|
3720
|
+
return path6.reduce((acc, key) => acc?.[key], obj);
|
|
3240
3721
|
}
|
|
3241
3722
|
function promiseAllObject(promisesObj) {
|
|
3242
3723
|
const keys = Object.keys(promisesObj);
|
|
@@ -3645,11 +4126,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
3645
4126
|
}
|
|
3646
4127
|
return false;
|
|
3647
4128
|
}
|
|
3648
|
-
function prefixIssues(
|
|
4129
|
+
function prefixIssues(path6, issues) {
|
|
3649
4130
|
return issues.map((iss) => {
|
|
3650
4131
|
var _a3;
|
|
3651
4132
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
3652
|
-
iss.path.unshift(
|
|
4133
|
+
iss.path.unshift(path6);
|
|
3653
4134
|
return iss;
|
|
3654
4135
|
});
|
|
3655
4136
|
}
|
|
@@ -3796,16 +4277,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
3796
4277
|
}
|
|
3797
4278
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
3798
4279
|
const fieldErrors = { _errors: [] };
|
|
3799
|
-
const processError = (error52,
|
|
4280
|
+
const processError = (error52, path6 = []) => {
|
|
3800
4281
|
for (const issue2 of error52.issues) {
|
|
3801
4282
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
3802
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
4283
|
+
issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
|
|
3803
4284
|
} else if (issue2.code === "invalid_key") {
|
|
3804
|
-
processError({ issues: issue2.issues }, [...
|
|
4285
|
+
processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
|
|
3805
4286
|
} else if (issue2.code === "invalid_element") {
|
|
3806
|
-
processError({ issues: issue2.issues }, [...
|
|
4287
|
+
processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
|
|
3807
4288
|
} else {
|
|
3808
|
-
const fullpath = [...
|
|
4289
|
+
const fullpath = [...path6, ...issue2.path];
|
|
3809
4290
|
if (fullpath.length === 0) {
|
|
3810
4291
|
fieldErrors._errors.push(mapper(issue2));
|
|
3811
4292
|
} else {
|
|
@@ -3832,17 +4313,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
3832
4313
|
}
|
|
3833
4314
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
3834
4315
|
const result = { errors: [] };
|
|
3835
|
-
const processError = (error52,
|
|
4316
|
+
const processError = (error52, path6 = []) => {
|
|
3836
4317
|
var _a3, _b;
|
|
3837
4318
|
for (const issue2 of error52.issues) {
|
|
3838
4319
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
3839
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
4320
|
+
issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
|
|
3840
4321
|
} else if (issue2.code === "invalid_key") {
|
|
3841
|
-
processError({ issues: issue2.issues }, [...
|
|
4322
|
+
processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
|
|
3842
4323
|
} else if (issue2.code === "invalid_element") {
|
|
3843
|
-
processError({ issues: issue2.issues }, [...
|
|
4324
|
+
processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
|
|
3844
4325
|
} else {
|
|
3845
|
-
const fullpath = [...
|
|
4326
|
+
const fullpath = [...path6, ...issue2.path];
|
|
3846
4327
|
if (fullpath.length === 0) {
|
|
3847
4328
|
result.errors.push(mapper(issue2));
|
|
3848
4329
|
continue;
|
|
@@ -3874,8 +4355,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
3874
4355
|
}
|
|
3875
4356
|
function toDotPath(_path) {
|
|
3876
4357
|
const segs = [];
|
|
3877
|
-
const
|
|
3878
|
-
for (const seg of
|
|
4358
|
+
const path6 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
4359
|
+
for (const seg of path6) {
|
|
3879
4360
|
if (typeof seg === "number")
|
|
3880
4361
|
segs.push(`[${seg}]`);
|
|
3881
4362
|
else if (typeof seg === "symbol")
|
|
@@ -16567,13 +17048,13 @@ function resolveRef(ref, ctx) {
|
|
|
16567
17048
|
if (!ref.startsWith("#")) {
|
|
16568
17049
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
16569
17050
|
}
|
|
16570
|
-
const
|
|
16571
|
-
if (
|
|
17051
|
+
const path6 = ref.slice(1).split("/").filter(Boolean);
|
|
17052
|
+
if (path6.length === 0) {
|
|
16572
17053
|
return ctx.rootSchema;
|
|
16573
17054
|
}
|
|
16574
17055
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
16575
|
-
if (
|
|
16576
|
-
const key =
|
|
17056
|
+
if (path6[0] === defsKey) {
|
|
17057
|
+
const key = path6[1];
|
|
16577
17058
|
if (!key || !ctx.defs[key]) {
|
|
16578
17059
|
throw new Error(`Reference not found: ${ref}`);
|
|
16579
17060
|
}
|
|
@@ -17333,8 +17814,8 @@ function baseUrlReference(semantics) {
|
|
|
17333
17814
|
const label = OPENING_HOLE.exec(semantics.path ?? "")?.[1];
|
|
17334
17815
|
return label === void 0 ? null : referenceFromName(patternHole(label));
|
|
17335
17816
|
}
|
|
17336
|
-
function normalizePath(
|
|
17337
|
-
let normalized =
|
|
17817
|
+
function normalizePath(path6) {
|
|
17818
|
+
let normalized = path6.replace(/:([a-zA-Z_]\w*)/g, "{$1}");
|
|
17338
17819
|
if (normalized.length > 1 && normalized.endsWith("/")) {
|
|
17339
17820
|
normalized = normalized.slice(0, -1);
|
|
17340
17821
|
}
|
|
@@ -17344,8 +17825,8 @@ function normalizePath(path4) {
|
|
|
17344
17825
|
);
|
|
17345
17826
|
return normalized;
|
|
17346
17827
|
}
|
|
17347
|
-
function pathShape(
|
|
17348
|
-
return normalizePath(
|
|
17828
|
+
function pathShape(path6) {
|
|
17829
|
+
return normalizePath(path6).replace(/\{[^}]*\}/g, "{}");
|
|
17349
17830
|
}
|
|
17350
17831
|
function methodsAgree(a, b) {
|
|
17351
17832
|
if (a === null || b === null) {
|
|
@@ -17423,8 +17904,8 @@ var restSemantics = defineBoundarySemantics({
|
|
|
17423
17904
|
return null;
|
|
17424
17905
|
}
|
|
17425
17906
|
const method = semantics.method === null ? "ANY" : semantics.method.toUpperCase();
|
|
17426
|
-
const
|
|
17427
|
-
return `${method} ${
|
|
17907
|
+
const path6 = semantics.path === null ? "?" : normalizePath(semantics.path);
|
|
17908
|
+
return `${method} ${path6}`;
|
|
17428
17909
|
},
|
|
17429
17910
|
/**
|
|
17430
17911
|
* A route with both halves stated decides for itself: the method
|
|
@@ -17433,14 +17914,14 @@ var restSemantics = defineBoundarySemantics({
|
|
|
17433
17914
|
* half might still be the one that handles the request, and nothing
|
|
17434
17915
|
* here can settle that, so it abstains instead of refusing.
|
|
17435
17916
|
*/
|
|
17436
|
-
servesRequest(semantics, method,
|
|
17917
|
+
servesRequest(semantics, method, path6) {
|
|
17437
17918
|
if (semantics.method === null || semantics.path === null) {
|
|
17438
17919
|
return "unknown";
|
|
17439
17920
|
}
|
|
17440
17921
|
if (!methodsAgree(semantics.method, method.toUpperCase())) {
|
|
17441
17922
|
return "nomatch";
|
|
17442
17923
|
}
|
|
17443
|
-
return routePathAdmits(semantics.path,
|
|
17924
|
+
return routePathAdmits(semantics.path, path6) ? "match" : "nomatch";
|
|
17444
17925
|
},
|
|
17445
17926
|
/**
|
|
17446
17927
|
* A route the registration pattern admits is inside it. A route
|
|
@@ -18077,71 +18558,10 @@ function returnTypeName(node) {
|
|
|
18077
18558
|
}
|
|
18078
18559
|
return annotation.type === "subscript" ? field(annotation, "value")?.text ?? null : annotation.text;
|
|
18079
18560
|
}
|
|
18080
|
-
function callsIn(node, found = []) {
|
|
18081
|
-
for (const child of node.namedChildren) {
|
|
18082
|
-
if (child === null) {
|
|
18083
|
-
continue;
|
|
18084
|
-
}
|
|
18085
|
-
if (child.type === "call") {
|
|
18086
|
-
found.push(child);
|
|
18087
|
-
}
|
|
18088
|
-
callsIn(child, found);
|
|
18089
|
-
}
|
|
18090
|
-
return found;
|
|
18091
|
-
}
|
|
18092
|
-
function storageEffects(calls, options) {
|
|
18093
|
-
const seen = /* @__PURE__ */ new Set();
|
|
18094
|
-
const asked = new Set(
|
|
18095
|
-
options.facts.facts("wanted").map((row) => String(row[0]))
|
|
18096
|
-
);
|
|
18097
|
-
const gather = (inCalls, filePath) => {
|
|
18098
|
-
const found = [...directStorageEffects(inCalls, { ...options, filePath })];
|
|
18099
|
-
resolveCalls(
|
|
18100
|
-
options.facts,
|
|
18101
|
-
inCalls.filter((call) => options.leadsToStorage.has(methodName(call))).map((call) => field(call, "function")).filter((callee) => callee !== null).map((callee) => calleeKeyOf(filePath, callee)).filter((key) => {
|
|
18102
|
-
const fresh = !asked.has(key);
|
|
18103
|
-
asked.add(key);
|
|
18104
|
-
return fresh;
|
|
18105
|
-
})
|
|
18106
|
-
);
|
|
18107
|
-
for (const call of inCalls) {
|
|
18108
|
-
const callee = field(call, "function");
|
|
18109
|
-
if (callee === null || !options.leadsToStorage.has(methodName(call))) {
|
|
18110
|
-
continue;
|
|
18111
|
-
}
|
|
18112
|
-
const key = resolvedOnce(options, calleeKeyOf(filePath, callee));
|
|
18113
|
-
const body = key === void 0 ? void 0 : options.definitionAt(key);
|
|
18114
|
-
if (key === void 0 || body === void 0 || seen.has(key)) {
|
|
18115
|
-
continue;
|
|
18116
|
-
}
|
|
18117
|
-
seen.add(key);
|
|
18118
|
-
const name = field(body, "name")?.text;
|
|
18119
|
-
const origin = {
|
|
18120
|
-
file: fileOf(key),
|
|
18121
|
-
line: body.startPosition.row + 1,
|
|
18122
|
-
...name === void 0 ? {} : { function: name }
|
|
18123
|
-
};
|
|
18124
|
-
found.push(
|
|
18125
|
-
...gather(callsIn(body), fileOf(key)).map(
|
|
18126
|
-
(effect) => effect.type === "interaction" && effect.origin === void 0 ? { ...effect, origin } : effect
|
|
18127
|
-
)
|
|
18128
|
-
);
|
|
18129
|
-
}
|
|
18130
|
-
return found;
|
|
18131
|
-
};
|
|
18132
|
-
return gather(calls, options.filePath);
|
|
18133
|
-
}
|
|
18134
|
-
function calleeKeyOf(filePath, callee) {
|
|
18135
|
-
return callee.type === "identifier" ? `${filePath}#${callee.text}` : nodeId(filePath, callee);
|
|
18136
|
-
}
|
|
18137
|
-
function resolvedOnce(options, calleeKey) {
|
|
18138
|
-
const resolved = options.facts.facts("wantedResolves").filter((row) => String(row[0]) === calleeKey).map((row) => String(row[1]));
|
|
18139
|
-
return resolved.length === 1 ? resolved[0] : void 0;
|
|
18140
|
-
}
|
|
18141
18561
|
function storageCallees(calls, filePath, couldMatch) {
|
|
18142
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));
|
|
18143
18563
|
}
|
|
18144
|
-
function
|
|
18564
|
+
function storageEffects(calls, options) {
|
|
18145
18565
|
if (options.patterns.length === 0) {
|
|
18146
18566
|
return [];
|
|
18147
18567
|
}
|
|
@@ -18199,7 +18619,7 @@ function directStorageEffects(calls, options) {
|
|
|
18199
18619
|
// src/discovery.ts
|
|
18200
18620
|
function decoratedStatements(root, module2) {
|
|
18201
18621
|
const found = [];
|
|
18202
|
-
(0,
|
|
18622
|
+
(0, import_extractor4.walkDescendants)(
|
|
18203
18623
|
root,
|
|
18204
18624
|
{ scope: module2.moduleScope, enclosingFunction: null },
|
|
18205
18625
|
{
|
|
@@ -18238,21 +18658,21 @@ function builtSubjects(decorated, options) {
|
|
|
18238
18658
|
}
|
|
18239
18659
|
const factsPath = options.absoluteFile ?? options.filePath;
|
|
18240
18660
|
const asked = /* @__PURE__ */ new Set();
|
|
18241
|
-
for (const { enclosingFunction, decorators } of decorated) {
|
|
18661
|
+
for (const { enclosingFunction: enclosingFunction2, decorators } of decorated) {
|
|
18242
18662
|
for (const { node, direct } of decorators) {
|
|
18243
18663
|
if (direct.module !== null && acceptedByAnyPattern(direct.module, options)) {
|
|
18244
18664
|
continue;
|
|
18245
18665
|
}
|
|
18246
18666
|
const written = decoratorReceiver(node);
|
|
18247
18667
|
if (written !== null) {
|
|
18248
|
-
asked.add(readKey(factsPath, written.object,
|
|
18668
|
+
asked.add(readKey(factsPath, written.object, enclosingFunction2));
|
|
18249
18669
|
}
|
|
18250
18670
|
}
|
|
18251
18671
|
}
|
|
18252
18672
|
return subjectConstructions(facts, [...asked]);
|
|
18253
18673
|
}
|
|
18254
18674
|
function decoratedUnits(decoratedStatement, module2, options, subjects) {
|
|
18255
|
-
const { stmt, scope, enclosingFunction, decorators } = decoratedStatement;
|
|
18675
|
+
const { stmt, scope, enclosingFunction: enclosingFunction2, decorators } = decoratedStatement;
|
|
18256
18676
|
const units = [];
|
|
18257
18677
|
const { definition } = stripDecorators(stmt);
|
|
18258
18678
|
for (const { node: decoratorNode, direct } of decorators) {
|
|
@@ -18268,7 +18688,7 @@ function decoratedUnits(decoratedStatement, module2, options, subjects) {
|
|
|
18268
18688
|
) ?? null
|
|
18269
18689
|
) ?? builtSubjectClassification(
|
|
18270
18690
|
decoratorNode,
|
|
18271
|
-
|
|
18691
|
+
enclosingFunction2,
|
|
18272
18692
|
subjects,
|
|
18273
18693
|
options
|
|
18274
18694
|
)
|
|
@@ -18304,14 +18724,14 @@ function acceptedByAnyPattern(module2, options) {
|
|
|
18304
18724
|
(pack) => pack.discovery.some((pattern) => pattern.importModule.includes(module2))
|
|
18305
18725
|
);
|
|
18306
18726
|
}
|
|
18307
|
-
function builtSubjectClassification(decoratorNode,
|
|
18727
|
+
function builtSubjectClassification(decoratorNode, enclosingFunction2, subjects, options) {
|
|
18308
18728
|
const written = decoratorReceiver(decoratorNode);
|
|
18309
18729
|
if (written === null) {
|
|
18310
18730
|
return null;
|
|
18311
18731
|
}
|
|
18312
18732
|
const factsPath = options.absoluteFile ?? options.filePath;
|
|
18313
18733
|
const built = subjects.get(
|
|
18314
|
-
readKey(factsPath, written.object,
|
|
18734
|
+
readKey(factsPath, written.object, enclosingFunction2)
|
|
18315
18735
|
);
|
|
18316
18736
|
const origin = built?.origins.find(
|
|
18317
18737
|
(candidate) => acceptedByAnyPattern(candidate.module, options)
|
|
@@ -18370,23 +18790,23 @@ function unitsFor(pattern, pack, decoratorModule, classification, definition, mo
|
|
|
18370
18790
|
);
|
|
18371
18791
|
}
|
|
18372
18792
|
};
|
|
18373
|
-
return (0,
|
|
18793
|
+
return (0, import_behavioral_ir2.dispatchByType)(table, pattern);
|
|
18374
18794
|
}
|
|
18375
18795
|
function readPathArgument(classification) {
|
|
18376
18796
|
const first = classification.args[0];
|
|
18377
18797
|
if (first?.kind === "string") {
|
|
18378
|
-
return (0,
|
|
18798
|
+
return (0, import_extractor4.writtenReading)(first.value, classification.range);
|
|
18379
18799
|
}
|
|
18380
|
-
return (0,
|
|
18800
|
+
return (0, import_extractor4.unreadableReading)(
|
|
18381
18801
|
"The path in this route's decorator is not a string literal, so the binding names no path and nothing pairs with it",
|
|
18382
18802
|
classification.range
|
|
18383
18803
|
);
|
|
18384
18804
|
}
|
|
18385
18805
|
var NO_PATH_PARAMS = /* @__PURE__ */ new Set();
|
|
18386
18806
|
function templateReader(template) {
|
|
18387
|
-
return (
|
|
18807
|
+
return (path6) => {
|
|
18388
18808
|
const names = [];
|
|
18389
|
-
const canonical =
|
|
18809
|
+
const canonical = path6.replace(template, (_match, name) => {
|
|
18390
18810
|
names.push(name);
|
|
18391
18811
|
return `{${name}}`;
|
|
18392
18812
|
});
|
|
@@ -18399,19 +18819,19 @@ var PATH_TEMPLATE_READERS = {
|
|
|
18399
18819
|
/<(?:[A-Za-z_]\w*(?:\(.*?\))?:)?([A-Za-z_]\w*)>/g
|
|
18400
18820
|
)
|
|
18401
18821
|
};
|
|
18402
|
-
function readPathTemplate(pattern,
|
|
18822
|
+
function readPathTemplate(pattern, path6, range) {
|
|
18403
18823
|
const syntax = pattern.pathParamSyntax;
|
|
18404
18824
|
if (syntax === void 0) {
|
|
18405
|
-
return (0,
|
|
18825
|
+
return (0, import_extractor4.writtenReading)({ path: path6, paramNames: NO_PATH_PARAMS }, range);
|
|
18406
18826
|
}
|
|
18407
18827
|
const reader = PATH_TEMPLATE_READERS[syntax];
|
|
18408
18828
|
if (reader === void 0) {
|
|
18409
|
-
return (0,
|
|
18829
|
+
return (0, import_extractor4.unreadableReading)(
|
|
18410
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`,
|
|
18411
18831
|
range
|
|
18412
18832
|
);
|
|
18413
18833
|
}
|
|
18414
|
-
return (0,
|
|
18834
|
+
return (0, import_extractor4.writtenReading)(reader(path6), range);
|
|
18415
18835
|
}
|
|
18416
18836
|
function classRouteUnits(pattern, pack, classification, classNode, module2, options) {
|
|
18417
18837
|
const pathArgument = readPathArgument(classification);
|
|
@@ -18460,7 +18880,7 @@ function classRouteUnits(pattern, pack, classification, classNode, module2, opti
|
|
|
18460
18880
|
module: module2,
|
|
18461
18881
|
filePath: options.filePath,
|
|
18462
18882
|
skipReceiverParam: true,
|
|
18463
|
-
responseShape:
|
|
18883
|
+
responseShape: import_extractor4.absentReading,
|
|
18464
18884
|
statusCode: defaultedStatus(
|
|
18465
18885
|
readReturnedStatus(pattern, maybeMethod),
|
|
18466
18886
|
pattern
|
|
@@ -18475,13 +18895,13 @@ function classRouteUnits(pattern, pack, classification, classNode, module2, opti
|
|
|
18475
18895
|
return units;
|
|
18476
18896
|
}
|
|
18477
18897
|
function readRoutePath(pattern, pathArgument, classification, module2, options) {
|
|
18478
|
-
const composed = (0,
|
|
18898
|
+
const composed = (0, import_extractor4.andThenReading)(
|
|
18479
18899
|
pathArgument,
|
|
18480
18900
|
(literal2, range) => composeRoutePath(pattern, classification, module2, options, literal2, range)
|
|
18481
18901
|
);
|
|
18482
|
-
return (0,
|
|
18902
|
+
return (0, import_extractor4.andThenReading)(
|
|
18483
18903
|
composed,
|
|
18484
|
-
(
|
|
18904
|
+
(path6, range) => readPathTemplate(pattern, path6, range)
|
|
18485
18905
|
);
|
|
18486
18906
|
}
|
|
18487
18907
|
function readRoutePaths(pattern, pathArgument, classification, module2, options) {
|
|
@@ -18505,12 +18925,12 @@ function readRoutePaths(pattern, pathArgument, classification, module2, options)
|
|
|
18505
18925
|
];
|
|
18506
18926
|
}
|
|
18507
18927
|
return resolution.values.map((prefix) => ({
|
|
18508
|
-
routePath: (0,
|
|
18509
|
-
(0,
|
|
18928
|
+
routePath: (0, import_extractor4.andThenReading)(
|
|
18929
|
+
(0, import_extractor4.andThenReading)(
|
|
18510
18930
|
pathArgument,
|
|
18511
|
-
(literal2, range) => (0,
|
|
18931
|
+
(literal2, range) => (0, import_extractor4.writtenReading)(servedSpelling(pattern, prefix + literal2), range)
|
|
18512
18932
|
),
|
|
18513
|
-
(
|
|
18933
|
+
(path6, range) => readPathTemplate(pattern, path6, range)
|
|
18514
18934
|
),
|
|
18515
18935
|
mount: { siblings: resolution.values.length, prefix }
|
|
18516
18936
|
}));
|
|
@@ -18544,19 +18964,19 @@ function composeRoutePath(pattern, classification, module2, options, literal2, r
|
|
|
18544
18964
|
range
|
|
18545
18965
|
);
|
|
18546
18966
|
if (prefix.kind === "absent") {
|
|
18547
|
-
return (0,
|
|
18967
|
+
return (0, import_extractor4.writtenReading)(servedSpelling(pattern, literal2), range);
|
|
18548
18968
|
}
|
|
18549
|
-
return (0,
|
|
18969
|
+
return (0, import_extractor4.mapReading)(
|
|
18550
18970
|
prefix,
|
|
18551
18971
|
(value) => servedSpelling(pattern, value + literal2)
|
|
18552
18972
|
);
|
|
18553
18973
|
}
|
|
18554
18974
|
var REPEATED_SLASH_READERS = {
|
|
18555
|
-
kept: (
|
|
18556
|
-
merged: (
|
|
18975
|
+
kept: (path6) => path6,
|
|
18976
|
+
merged: (path6) => path6.replace(/\/{2,}/g, "/")
|
|
18557
18977
|
};
|
|
18558
|
-
function servedSpelling(pattern,
|
|
18559
|
-
return REPEATED_SLASH_READERS[pattern.pathRepeatedSlashes ?? "kept"](
|
|
18978
|
+
function servedSpelling(pattern, path6) {
|
|
18979
|
+
return REPEATED_SLASH_READERS[pattern.pathRepeatedSlashes ?? "kept"](path6);
|
|
18560
18980
|
}
|
|
18561
18981
|
function readRouterPrefix(pattern, classification, module2, options, range) {
|
|
18562
18982
|
const resolution = routerResolutionOf(
|
|
@@ -18566,31 +18986,31 @@ function readRouterPrefix(pattern, classification, module2, options, range) {
|
|
|
18566
18986
|
options
|
|
18567
18987
|
);
|
|
18568
18988
|
if (resolution === null) {
|
|
18569
|
-
return
|
|
18989
|
+
return import_extractor4.absentReading;
|
|
18570
18990
|
}
|
|
18571
18991
|
if (resolution.kind === "abstain") {
|
|
18572
|
-
return (0,
|
|
18992
|
+
return (0, import_extractor4.unreadableReading)(
|
|
18573
18993
|
`The router this route is declared on ${resolution.reason}, so the binding names no path and nothing pairs with it`,
|
|
18574
18994
|
range
|
|
18575
18995
|
);
|
|
18576
18996
|
}
|
|
18577
18997
|
if (resolution.kind === "composed") {
|
|
18578
|
-
return (0,
|
|
18998
|
+
return (0, import_extractor4.writtenReading)(resolution.value, range);
|
|
18579
18999
|
}
|
|
18580
|
-
return
|
|
19000
|
+
return import_extractor4.absentReading;
|
|
18581
19001
|
}
|
|
18582
19002
|
function readStatusCode(pattern, classification) {
|
|
18583
19003
|
if (pattern.statusCodeKeyword === void 0) {
|
|
18584
|
-
return
|
|
19004
|
+
return import_extractor4.absentReading;
|
|
18585
19005
|
}
|
|
18586
19006
|
const arg = classification.keywordArgs[pattern.statusCodeKeyword];
|
|
18587
19007
|
if (arg === void 0) {
|
|
18588
|
-
return
|
|
19008
|
+
return import_extractor4.absentReading;
|
|
18589
19009
|
}
|
|
18590
19010
|
if (arg.kind === "number") {
|
|
18591
|
-
return (0,
|
|
19011
|
+
return (0, import_extractor4.writtenReading)(arg.value, classification.range);
|
|
18592
19012
|
}
|
|
18593
|
-
return (0,
|
|
19013
|
+
return (0, import_extractor4.unreadableReading)(
|
|
18594
19014
|
"The status this route's decorator states is not a literal number, so the response claims no status",
|
|
18595
19015
|
classification.range
|
|
18596
19016
|
);
|
|
@@ -18635,7 +19055,7 @@ function statusOfReturn(statement) {
|
|
|
18635
19055
|
}
|
|
18636
19056
|
function effectsReaching(effects, conditions) {
|
|
18637
19057
|
return effects.filter(
|
|
18638
|
-
(effect) => (0,
|
|
19058
|
+
(effect) => (0, import_extractor4.guardsHoldOn)(effect.preconditions, conditions)
|
|
18639
19059
|
);
|
|
18640
19060
|
}
|
|
18641
19061
|
function branchesFromReturns(readsReturnedStatus, definitionNode, effects, responseShape, declaredStatus) {
|
|
@@ -18648,7 +19068,7 @@ function branchesFromReturns(readsReturnedStatus, definitionNode, effects, respo
|
|
|
18648
19068
|
return null;
|
|
18649
19069
|
}
|
|
18650
19070
|
const lowered = lowerPythonBody(body, returns);
|
|
18651
|
-
const enumerated = (0,
|
|
19071
|
+
const enumerated = (0, import_extractor4.enumerateOrDegrade)(
|
|
18652
19072
|
{
|
|
18653
19073
|
statements: lowered.statements,
|
|
18654
19074
|
terminalsByStmt: lowered.terminalsByStmt
|
|
@@ -18664,12 +19084,12 @@ function branchesFromReturns(readsReturnedStatus, definitionNode, effects, respo
|
|
|
18664
19084
|
const read = statusOfReturn(statement);
|
|
18665
19085
|
const range = rangeOf(statement);
|
|
18666
19086
|
const writtenBody = returnedBodyShape(statement);
|
|
18667
|
-
const statusReading = read.kind === "status" ? (0,
|
|
19087
|
+
const statusReading = read.kind === "status" ? (0, import_extractor4.writtenReading)(read.value, range) : read.kind === "none" ? import_extractor4.absentReading : (0, import_extractor4.unreadableReading)(
|
|
18668
19088
|
"This return gives a status this reading cannot resolve to a number, so this outcome claims none",
|
|
18669
19089
|
range
|
|
18670
19090
|
);
|
|
18671
|
-
for (const
|
|
18672
|
-
const conditions =
|
|
19091
|
+
for (const path6 of paths) {
|
|
19092
|
+
const conditions = path6.map((condition) => ({
|
|
18673
19093
|
sourceText: condition.sourceText,
|
|
18674
19094
|
structured: condition.expression === null ? null : predicateOf(condition.expression),
|
|
18675
19095
|
polarity: condition.polarity,
|
|
@@ -18694,11 +19114,11 @@ function branchesFromReturns(readsReturnedStatus, definitionNode, effects, respo
|
|
|
18694
19114
|
...declaredStatus.libraryDefault !== void 0 ? { libraryDefault: declaredStatus.libraryDefault } : {}
|
|
18695
19115
|
},
|
|
18696
19116
|
bodyShapeReading: {
|
|
18697
|
-
reading: writtenBody === null ? responseShape.reading : (0,
|
|
19117
|
+
reading: writtenBody === null ? responseShape.reading : (0, import_extractor4.writtenReading)(writtenBody, range)
|
|
18698
19118
|
},
|
|
18699
19119
|
effects: effectsReaching(effects, conditions),
|
|
18700
19120
|
location: range,
|
|
18701
|
-
isDefault:
|
|
19121
|
+
isDefault: path6.length === 0
|
|
18702
19122
|
});
|
|
18703
19123
|
}
|
|
18704
19124
|
}
|
|
@@ -18706,7 +19126,7 @@ function branchesFromReturns(readsReturnedStatus, definitionNode, effects, respo
|
|
|
18706
19126
|
}
|
|
18707
19127
|
function readReturnedStatus(pattern, definitionNode) {
|
|
18708
19128
|
if (pattern.statusFromReturnedTuple !== true) {
|
|
18709
|
-
return
|
|
19129
|
+
return import_extractor4.absentReading;
|
|
18710
19130
|
}
|
|
18711
19131
|
const range = rangeOf(definitionNode);
|
|
18712
19132
|
const statuses = /* @__PURE__ */ new Set();
|
|
@@ -18723,23 +19143,23 @@ function readReturnedStatus(pattern, definitionNode) {
|
|
|
18723
19143
|
}
|
|
18724
19144
|
}
|
|
18725
19145
|
if (unreadable > 0) {
|
|
18726
|
-
return (0,
|
|
19146
|
+
return (0, import_extractor4.unreadableReading)(
|
|
18727
19147
|
"This route returns a status this reading cannot resolve to a number, so no status is claimed for it",
|
|
18728
19148
|
range
|
|
18729
19149
|
);
|
|
18730
19150
|
}
|
|
18731
19151
|
if (statuses.size === 0) {
|
|
18732
|
-
return
|
|
19152
|
+
return import_extractor4.absentReading;
|
|
18733
19153
|
}
|
|
18734
19154
|
const candidates = [...statuses];
|
|
18735
19155
|
if (statuses.size > 1 || plainReturns > 0) {
|
|
18736
|
-
return (0,
|
|
19156
|
+
return (0, import_extractor4.ambiguousReading)(
|
|
18737
19157
|
candidates,
|
|
18738
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",
|
|
18739
19159
|
range
|
|
18740
19160
|
);
|
|
18741
19161
|
}
|
|
18742
|
-
return (0,
|
|
19162
|
+
return (0, import_extractor4.writtenReading)(candidates[0], range);
|
|
18743
19163
|
}
|
|
18744
19164
|
function declaredOrReturnedStatus(declared, returned) {
|
|
18745
19165
|
return declared.kind === "absent" ? returned : declared;
|
|
@@ -18752,19 +19172,19 @@ function defaultedStatus(reading, pattern) {
|
|
|
18752
19172
|
}
|
|
18753
19173
|
function readResponseModel(pattern, classification, module2, ctx) {
|
|
18754
19174
|
if (pattern.responseModelKeyword === void 0) {
|
|
18755
|
-
return
|
|
19175
|
+
return import_extractor4.absentReading;
|
|
18756
19176
|
}
|
|
18757
19177
|
const arg = classification.keywordArgs[pattern.responseModelKeyword];
|
|
18758
19178
|
if (arg === void 0) {
|
|
18759
|
-
return
|
|
19179
|
+
return import_extractor4.absentReading;
|
|
18760
19180
|
}
|
|
18761
19181
|
if (arg.kind === "identifier") {
|
|
18762
|
-
return (0,
|
|
19182
|
+
return (0, import_extractor4.writtenReading)(
|
|
18763
19183
|
shapeFromName(arg.name, module2.moduleScope, ctx),
|
|
18764
19184
|
classification.range
|
|
18765
19185
|
);
|
|
18766
19186
|
}
|
|
18767
|
-
return (0,
|
|
19187
|
+
return (0, import_extractor4.unreadableReading)(
|
|
18768
19188
|
"The response model this route's decorator states is not a name, so the response claims no body shape",
|
|
18769
19189
|
classification.range
|
|
18770
19190
|
);
|
|
@@ -18772,9 +19192,9 @@ function readResponseModel(pattern, classification, module2, ctx) {
|
|
|
18772
19192
|
function readReturnAnnotation(definitionNode, scope, ctx) {
|
|
18773
19193
|
const returnTypeNode = field(definitionNode, "return_type");
|
|
18774
19194
|
if (returnTypeNode === null) {
|
|
18775
|
-
return
|
|
19195
|
+
return import_extractor4.absentReading;
|
|
18776
19196
|
}
|
|
18777
|
-
return (0,
|
|
19197
|
+
return (0, import_extractor4.writtenReading)(
|
|
18778
19198
|
annotationToShape(returnTypeNode, scope, ctx),
|
|
18779
19199
|
rangeOf(returnTypeNode)
|
|
18780
19200
|
);
|
|
@@ -18827,7 +19247,7 @@ function readResponseShape(declared, readAnnotation) {
|
|
|
18827
19247
|
if (declared.kind === "written") {
|
|
18828
19248
|
return { reading: declared, passedOver: [] };
|
|
18829
19249
|
}
|
|
18830
|
-
return (0,
|
|
19250
|
+
return (0, import_extractor4.firstWrittenReading)([declared, readAnnotation()]);
|
|
18831
19251
|
}
|
|
18832
19252
|
function routeUnitOrAbstention(unitOptions, options) {
|
|
18833
19253
|
try {
|
|
@@ -18855,7 +19275,7 @@ function unbuiltRouteUnit(unitOptions, error51) {
|
|
|
18855
19275
|
exportName: unitOptions.exportPath[0] ?? unitOptions.name,
|
|
18856
19276
|
exportPath: unitOptions.exportPath
|
|
18857
19277
|
},
|
|
18858
|
-
boundaryBinding: (0,
|
|
19278
|
+
boundaryBinding: (0, import_behavioral_ir2.restBinding)({
|
|
18859
19279
|
transport: unitOptions.pack.protocol,
|
|
18860
19280
|
method: nullIfEmpty(unitOptions.method),
|
|
18861
19281
|
path: null,
|
|
@@ -18867,7 +19287,7 @@ function unbuiltRouteUnit(unitOptions, error51) {
|
|
|
18867
19287
|
dependencyCalls: [],
|
|
18868
19288
|
declaredContract: null,
|
|
18869
19289
|
readings: [
|
|
18870
|
-
(0,
|
|
19290
|
+
(0, import_extractor4.unreadableReading)(
|
|
18871
19291
|
`This route could not be read into a unit (${message}), so the binding names no path and nothing pairs with it`,
|
|
18872
19292
|
range
|
|
18873
19293
|
)
|
|
@@ -18893,7 +19313,7 @@ function buildRouteUnit(options) {
|
|
|
18893
19313
|
definitionsCtx,
|
|
18894
19314
|
storage: storageLookup
|
|
18895
19315
|
} = options;
|
|
18896
|
-
const template = (0,
|
|
19316
|
+
const template = (0, import_extractor4.valueToReadFurtherFrom)(routePath);
|
|
18897
19317
|
const ctx = definitionsCtx ?? createAnnotationContext(module2.scopeFor);
|
|
18898
19318
|
const parameters = readParameters(
|
|
18899
19319
|
definitionNode,
|
|
@@ -18909,17 +19329,7 @@ function buildRouteUnit(options) {
|
|
|
18909
19329
|
() => readReturnAnnotation(definitionNode, enclosingScope, ctx)
|
|
18910
19330
|
);
|
|
18911
19331
|
const effects = invocationEffects(definitionNode);
|
|
18912
|
-
const
|
|
18913
|
-
...storageEffects(bodyCalls(definitionNode), {
|
|
18914
|
-
...storageLookup,
|
|
18915
|
-
filePath: storageLookup.factsPath
|
|
18916
|
-
}),
|
|
18917
|
-
...rawSqlEffects(bodyCalls(definitionNode), {
|
|
18918
|
-
facts: storageLookup.facts,
|
|
18919
|
-
filePath: storageLookup.factsPath,
|
|
18920
|
-
patterns: storageLookup.rawSql ?? []
|
|
18921
|
-
})
|
|
18922
|
-
];
|
|
19332
|
+
const extra = recognizedBodyEffects(definitionNode, module2, storageLookup);
|
|
18923
19333
|
const perReturn = branchesFromReturns(
|
|
18924
19334
|
readsReturnedStatus,
|
|
18925
19335
|
definitionNode,
|
|
@@ -18928,9 +19338,9 @@ function buildRouteUnit(options) {
|
|
|
18928
19338
|
statusCode
|
|
18929
19339
|
);
|
|
18930
19340
|
const branches = (perReturn ?? []).map(
|
|
18931
|
-
(branch) =>
|
|
19341
|
+
(branch) => extra.length === 0 ? branch : { ...branch, extraEffects: extra }
|
|
18932
19342
|
);
|
|
18933
|
-
if (perReturn === null && (responseShape.reading.kind !== "absent" || statusCode.reading.kind !== "absent" ||
|
|
19343
|
+
if (perReturn === null && (responseShape.reading.kind !== "absent" || statusCode.reading.kind !== "absent" || extra.length > 0 || effects.length > 0)) {
|
|
18934
19344
|
branches.push({
|
|
18935
19345
|
conditions: [],
|
|
18936
19346
|
terminal: {
|
|
@@ -18950,7 +19360,7 @@ function buildRouteUnit(options) {
|
|
|
18950
19360
|
statusCodeReading: statusCode,
|
|
18951
19361
|
bodyShapeReading: { reading: responseShape.reading },
|
|
18952
19362
|
effects,
|
|
18953
|
-
...
|
|
19363
|
+
...extra.length === 0 ? {} : { extraEffects: extra },
|
|
18954
19364
|
location: rangeOf(definitionNode),
|
|
18955
19365
|
isDefault: true
|
|
18956
19366
|
});
|
|
@@ -18967,7 +19377,7 @@ function buildRouteUnit(options) {
|
|
|
18967
19377
|
exportName: exportPath[0] ?? name,
|
|
18968
19378
|
exportPath
|
|
18969
19379
|
},
|
|
18970
|
-
boundaryBinding: (0,
|
|
19380
|
+
boundaryBinding: (0, import_behavioral_ir2.restBinding)({
|
|
18971
19381
|
transport: pack.protocol,
|
|
18972
19382
|
method,
|
|
18973
19383
|
path: template?.path ?? null,
|
|
@@ -18992,12 +19402,26 @@ function unreadRoleReadings(parameters, range) {
|
|
|
18992
19402
|
return [];
|
|
18993
19403
|
}
|
|
18994
19404
|
return [
|
|
18995
|
-
(0,
|
|
19405
|
+
(0, import_extractor4.unreadableReading)(
|
|
18996
19406
|
"Nothing read this route's path, so its parameters name no role and a path parameter here does not read as one",
|
|
18997
19407
|
range
|
|
18998
19408
|
)
|
|
18999
19409
|
];
|
|
19000
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
|
+
}
|
|
19001
19425
|
function bodyContentOf(bodyNode) {
|
|
19002
19426
|
for (const stmt of bodyStatements(bodyNode)) {
|
|
19003
19427
|
if (stmt.type === "pass_statement") {
|
|
@@ -19133,6 +19557,11 @@ function parameterNameAndType(param) {
|
|
|
19133
19557
|
return null;
|
|
19134
19558
|
}
|
|
19135
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
|
+
|
|
19136
19565
|
// src/moduleResolver.ts
|
|
19137
19566
|
var import_node_fs = __toESM(require("fs"), 1);
|
|
19138
19567
|
var import_node_path = __toESM(require("path"), 1);
|
|
@@ -19225,43 +19654,38 @@ function importedModuleText(module2, relativeLevel) {
|
|
|
19225
19654
|
return relativeLevel > 0 ? `${".".repeat(relativeLevel)}${module2}` : module2;
|
|
19226
19655
|
}
|
|
19227
19656
|
function emitModuleImportFacts(db, filePath, module2, resolverOptions) {
|
|
19228
|
-
const
|
|
19229
|
-
|
|
19230
|
-
|
|
19231
|
-
|
|
19232
|
-
|
|
19233
|
-
|
|
19234
|
-
|
|
19235
|
-
|
|
19236
|
-
|
|
19237
|
-
|
|
19238
|
-
|
|
19239
|
-
|
|
19240
|
-
|
|
19241
|
-
|
|
19242
|
-
|
|
19243
|
-
|
|
19244
|
-
|
|
19245
|
-
|
|
19246
|
-
|
|
19247
|
-
resolution.status === "resolved" ? "resolved" : resolution.reason
|
|
19248
|
-
]);
|
|
19249
|
-
const importedName = binding.kind === "import" ? binding.localName : binding.importedName;
|
|
19250
|
-
db.add("pyImportedName", [
|
|
19251
|
-
`${filePath}#${localName}`,
|
|
19252
|
-
moduleText,
|
|
19253
|
-
importedName
|
|
19254
|
-
]);
|
|
19255
|
-
if (resolution.status === "resolved") {
|
|
19256
|
-
db.add("pyImportResolved", [filePath, moduleText, resolution.file]);
|
|
19257
|
-
db.add("imports", [
|
|
19258
|
-
`${filePath}#${localName}`,
|
|
19259
|
-
resolution.file,
|
|
19260
|
-
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
|
|
19261
19676
|
]);
|
|
19262
|
-
|
|
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]);
|
|
19263
19688
|
}
|
|
19264
|
-
db.add("imports", [`${filePath}#${localName}`, moduleText, importedName]);
|
|
19265
19689
|
}
|
|
19266
19690
|
for (const openModule of module2.openImports) {
|
|
19267
19691
|
db.add("pyOpenImport", [filePath, openModule]);
|
|
@@ -19280,6 +19704,7 @@ var GRAMMAR_PATH = import_node_path2.default.join(
|
|
|
19280
19704
|
"tree-sitter-python.wasm"
|
|
19281
19705
|
);
|
|
19282
19706
|
var languagePromise = null;
|
|
19707
|
+
var loadedLanguage = null;
|
|
19283
19708
|
function loadLanguage() {
|
|
19284
19709
|
languagePromise ??= (async () => {
|
|
19285
19710
|
if (!import_node_fs2.default.existsSync(GRAMMAR_PATH)) {
|
|
@@ -19288,12 +19713,28 @@ function loadLanguage() {
|
|
|
19288
19713
|
);
|
|
19289
19714
|
}
|
|
19290
19715
|
await import_web_tree_sitter.Parser.init();
|
|
19291
|
-
|
|
19716
|
+
const language = await import_web_tree_sitter.Language.load(GRAMMAR_PATH);
|
|
19717
|
+
loadedLanguage = language;
|
|
19718
|
+
return language;
|
|
19292
19719
|
})();
|
|
19293
19720
|
return languagePromise;
|
|
19294
19721
|
}
|
|
19295
19722
|
async function parsePython(source) {
|
|
19296
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) {
|
|
19297
19738
|
const parser = new import_web_tree_sitter.Parser();
|
|
19298
19739
|
parser.setLanguage(language);
|
|
19299
19740
|
try {
|
|
@@ -19310,8 +19751,671 @@ async function parsePython(source) {
|
|
|
19310
19751
|
// src/project.ts
|
|
19311
19752
|
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
19312
19753
|
var import_node_path3 = __toESM(require("path"), 1);
|
|
19313
|
-
var
|
|
19314
|
-
var
|
|
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
|
+
}
|
|
19315
20419
|
|
|
19316
20420
|
// src/routers.ts
|
|
19317
20421
|
var UNSTATED_PREFIX = { kind: "unstated" };
|
|
@@ -19586,6 +20690,9 @@ function buildPatternIndex(files, importModule, composition, resolverOptions) {
|
|
|
19586
20690
|
for (const bound of files) {
|
|
19587
20691
|
collectConstructions(bound, importModule, composition, index);
|
|
19588
20692
|
}
|
|
20693
|
+
for (const bound of files) {
|
|
20694
|
+
collectReturnedConstructions(bound, importModule, composition, index);
|
|
20695
|
+
}
|
|
19589
20696
|
if (objectPrefix?.carrier !== void 0) {
|
|
19590
20697
|
const carrier = objectPrefix.carrier;
|
|
19591
20698
|
for (const bound of files) {
|
|
@@ -19761,6 +20868,37 @@ function collectConstructions(bound, importModule, composition, index) {
|
|
|
19761
20868
|
);
|
|
19762
20869
|
}
|
|
19763
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
|
+
}
|
|
19764
20902
|
function collectCarrierConstructions(carrier, composition, scan) {
|
|
19765
20903
|
walkStatements(
|
|
19766
20904
|
bodyStatements(scan.bound.root),
|
|
@@ -19819,6 +20957,21 @@ function constructionNamed(name, scope, scan, constructions = scan.index.constru
|
|
|
19819
20957
|
};
|
|
19820
20958
|
return resolvers[binding.kind]?.() ?? null;
|
|
19821
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
|
+
}
|
|
19822
20975
|
var MOUNT_STATE_BY_EFFECT = {
|
|
19823
20976
|
prefixes: (statedPrefix, site) => ({
|
|
19824
20977
|
kind: "mounted",
|
|
@@ -19988,10 +21141,10 @@ function constructionsReturnedBy(target, index) {
|
|
|
19988
21141
|
return { kind: "unread" };
|
|
19989
21142
|
}
|
|
19990
21143
|
const contained = containedValues(facts, returned);
|
|
19991
|
-
|
|
21144
|
+
const settled = subjectConstructions(facts, contained);
|
|
19992
21145
|
const found = [];
|
|
19993
21146
|
for (const value of contained) {
|
|
19994
|
-
const resolved =
|
|
21147
|
+
const resolved = settled.get(value)?.constructionKey ?? value;
|
|
19995
21148
|
const construction = index.byValueKey.get(resolved);
|
|
19996
21149
|
if (construction === void 0) {
|
|
19997
21150
|
return {
|
|
@@ -20006,10 +21159,6 @@ function constructionsReturnedBy(target, index) {
|
|
|
20006
21159
|
}
|
|
20007
21160
|
return { kind: "settled", found };
|
|
20008
21161
|
}
|
|
20009
|
-
function resolvedValueKey(facts, value) {
|
|
20010
|
-
const row = facts.facts("wantedIsWrittenAs").find((entry) => String(entry[0]) === value);
|
|
20011
|
-
return row === void 0 ? value : String(row[1]);
|
|
20012
|
-
}
|
|
20013
21162
|
function mountedConstructions(arg, position, scan) {
|
|
20014
21163
|
if (arg?.kind === "attribute") {
|
|
20015
21164
|
const construction = constructionThroughModule(arg, position.scope, scan);
|
|
@@ -20019,7 +21168,7 @@ function mountedConstructions(arg, position, scan) {
|
|
|
20019
21168
|
return [];
|
|
20020
21169
|
}
|
|
20021
21170
|
const named = (name) => {
|
|
20022
|
-
const construction = constructionNamed(name, position.scope, scan);
|
|
21171
|
+
const construction = constructionNamed(name, position.scope, scan) ?? constructionThroughFacts(name, position.scope, scan);
|
|
20023
21172
|
return construction === null ? [] : [construction];
|
|
20024
21173
|
};
|
|
20025
21174
|
const target = position.loopBindings.get(arg.name);
|
|
@@ -20406,36 +21555,69 @@ function carrierPrefix(carrier, constructorArg, objectName, scope, scan) {
|
|
|
20406
21555
|
return readings[construction.prefix.kind]();
|
|
20407
21556
|
}
|
|
20408
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
|
+
|
|
20409
21566
|
// src/project.ts
|
|
20410
|
-
function reportUnresolvedProjectModules(options) {
|
|
21567
|
+
function reportUnresolvedProjectModules(options, db) {
|
|
21568
|
+
const imported = new Set(db.facts("pyImport").map((row) => String(row[1])));
|
|
20411
21569
|
for (const pack of options.packs) {
|
|
20412
21570
|
for (const module2 of pack.projectModules ?? []) {
|
|
20413
|
-
|
|
20414
|
-
if (resolved.status === "resolved") {
|
|
21571
|
+
if (imported.has(module2)) {
|
|
20415
21572
|
continue;
|
|
20416
21573
|
}
|
|
20417
21574
|
process.stderr.write(
|
|
20418
|
-
`[suss] ${pack.name}:
|
|
21575
|
+
`[suss] ${pack.name}: no file under ${options.roots.join(", ")} imports ${module2}, so the stub for it changes nothing.
|
|
20419
21576
|
`
|
|
20420
21577
|
);
|
|
20421
21578
|
}
|
|
20422
21579
|
}
|
|
20423
21580
|
}
|
|
20424
21581
|
async function extractPythonProject(options) {
|
|
20425
|
-
const
|
|
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();
|
|
20426
21606
|
const summaries = [];
|
|
20427
21607
|
const gapHandling = options.gapHandling ?? "permissive";
|
|
21608
|
+
const tallies = (0, import_extractor5.createPackTallies)(options.packs);
|
|
20428
21609
|
const displayPathOf = (file2) => options.workspaceRoot !== void 0 ? import_node_path3.default.relative(options.workspaceRoot, file2) : file2;
|
|
20429
|
-
reportUnresolvedProjectModules(options);
|
|
20430
21610
|
const bound = [];
|
|
20431
21611
|
for (const file2 of options.files) {
|
|
20432
|
-
|
|
20433
|
-
|
|
20434
|
-
|
|
20435
|
-
|
|
20436
|
-
|
|
20437
|
-
|
|
20438
|
-
|
|
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
|
+
});
|
|
20439
21621
|
});
|
|
20440
21622
|
}
|
|
20441
21623
|
const mountsRouters = options.packs.some(
|
|
@@ -20446,81 +21628,172 @@ async function extractPythonProject(options) {
|
|
|
20446
21628
|
const discovers = options.packs.some((pack) => pack.discovery.length > 0);
|
|
20447
21629
|
const needsValues = discovers || mountsRouters || storagePatterns.length > 0;
|
|
20448
21630
|
const definitions = /* @__PURE__ */ new Map();
|
|
20449
|
-
|
|
20450
|
-
|
|
20451
|
-
|
|
20452
|
-
|
|
20453
|
-
|
|
20454
|
-
|
|
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
|
+
}
|
|
20455
21637
|
indexDefinitions(definitions, file2, root);
|
|
20456
21638
|
}
|
|
20457
|
-
}
|
|
20458
|
-
const couldMatch = methodsDeclaredNear(db, storagePatterns, definitions);
|
|
20459
|
-
const startsAQuery = /* @__PURE__ */ new Set([
|
|
20460
|
-
...couldMatch,
|
|
20461
|
-
...storagePatterns.flatMap((pattern) => pattern.queryFunctions ?? [])
|
|
20462
|
-
]);
|
|
20463
|
-
const leadsToStorage = functionsReachingStorage(
|
|
20464
|
-
db,
|
|
20465
|
-
definitions,
|
|
20466
|
-
startsAQuery
|
|
20467
|
-
);
|
|
20468
|
-
const routerIndex = buildRouterIndex(bound, options.packs, {
|
|
20469
|
-
roots: options.roots,
|
|
20470
|
-
...mountsRouters ? { facts: db } : {}
|
|
20471
21639
|
});
|
|
20472
|
-
|
|
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;
|
|
20473
21664
|
const displayPath = displayPathOf(file2);
|
|
20474
|
-
const
|
|
20475
|
-
|
|
20476
|
-
|
|
20477
|
-
|
|
20478
|
-
|
|
20479
|
-
|
|
20480
|
-
|
|
20481
|
-
|
|
20482
|
-
|
|
20483
|
-
|
|
20484
|
-
|
|
20485
|
-
|
|
20486
|
-
|
|
20487
|
-
couldMatch,
|
|
20488
|
-
leadsToStorage,
|
|
20489
|
-
rawSql: rawSqlPatterns
|
|
20490
|
-
}
|
|
20491
|
-
} : {}
|
|
20492
|
-
});
|
|
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
|
+
);
|
|
20493
21678
|
for (const raw of rawUnits) {
|
|
20494
|
-
const summary =
|
|
21679
|
+
const summary = timer.time(
|
|
21680
|
+
"summarize",
|
|
21681
|
+
() => (0, import_extractor8.assembleSummary)(raw, { gapHandling })
|
|
21682
|
+
);
|
|
20495
21683
|
summary.confidence = { source: "inferred_static", level: "low" };
|
|
20496
21684
|
summaries.push(summary);
|
|
20497
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);
|
|
21720
|
+
}
|
|
21721
|
+
}
|
|
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));
|
|
20498
21741
|
}
|
|
20499
21742
|
}
|
|
20500
|
-
|
|
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());
|
|
20501
21783
|
return { summaries, facts: db };
|
|
20502
21784
|
}
|
|
20503
|
-
function
|
|
21785
|
+
function resolvedImportsOf(db, displayPathOf) {
|
|
20504
21786
|
const importsByFile = /* @__PURE__ */ new Map();
|
|
20505
21787
|
for (const [from, , to] of db.facts("pyImportResolved")) {
|
|
20506
21788
|
if (typeof from !== "string" || typeof to !== "string") {
|
|
20507
21789
|
continue;
|
|
20508
21790
|
}
|
|
20509
21791
|
const key = displayPathOf(from);
|
|
20510
|
-
const seen = importsByFile.get(key) ??
|
|
20511
|
-
seen.
|
|
21792
|
+
const seen = importsByFile.get(key) ?? [];
|
|
21793
|
+
seen.push(displayPathOf(to));
|
|
20512
21794
|
importsByFile.set(key, seen);
|
|
20513
21795
|
}
|
|
20514
|
-
|
|
20515
|
-
const imports = importsByFile.get(summary.location.file);
|
|
20516
|
-
if (imports === void 0 || imports.size === 0) {
|
|
20517
|
-
continue;
|
|
20518
|
-
}
|
|
20519
|
-
summary.metadata = {
|
|
20520
|
-
...summary.metadata ?? {},
|
|
20521
|
-
moduleImports: [...imports].sort()
|
|
20522
|
-
};
|
|
20523
|
-
}
|
|
21796
|
+
return importsByFile;
|
|
20524
21797
|
}
|
|
20525
21798
|
var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
20526
21799
|
"__pycache__",
|
|
@@ -20575,55 +21848,272 @@ function methodsDeclaredNear(db, patterns, definitions) {
|
|
|
20575
21848
|
}
|
|
20576
21849
|
return found;
|
|
20577
21850
|
}
|
|
20578
|
-
|
|
20579
|
-
|
|
20580
|
-
|
|
20581
|
-
|
|
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
|
+
}
|
|
20582
21871
|
}
|
|
20583
|
-
return callee.type === "attribute" ? field(callee, "attribute")?.text ?? "" : callee.text;
|
|
20584
21872
|
}
|
|
20585
|
-
function
|
|
20586
|
-
|
|
20587
|
-
|
|
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
|
+
}
|
|
20588
22044
|
continue;
|
|
20589
22045
|
}
|
|
20590
|
-
if (
|
|
20591
|
-
|
|
22046
|
+
if (nameNode.type === "dotted_name") {
|
|
22047
|
+
modules.push(nameNode.text);
|
|
20592
22048
|
}
|
|
20593
|
-
callsUnder(child, found);
|
|
20594
22049
|
}
|
|
20595
|
-
return
|
|
22050
|
+
return modules;
|
|
20596
22051
|
}
|
|
20597
|
-
|
|
20598
|
-
(
|
|
20599
|
-
|
|
20600
|
-
[
|
|
20601
|
-
|
|
20602
|
-
|
|
20603
|
-
|
|
20604
|
-
|
|
20605
|
-
|
|
20606
|
-
|
|
20607
|
-
|
|
20608
|
-
|
|
20609
|
-
|
|
20610
|
-
for (const node of definitions.values()) {
|
|
20611
|
-
const name = field(node, "name");
|
|
20612
|
-
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
|
+
}
|
|
20613
22065
|
continue;
|
|
20614
22066
|
}
|
|
20615
|
-
|
|
20616
|
-
|
|
22067
|
+
if (nameNode.type === "dotted_name") {
|
|
22068
|
+
entries.push({ module: module2, name: nameNode.text });
|
|
20617
22069
|
}
|
|
20618
22070
|
}
|
|
20619
|
-
|
|
20620
|
-
|
|
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
|
+
}
|
|
20621
22110
|
}
|
|
20622
|
-
(
|
|
20623
|
-
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 }));
|
|
20624
22112
|
}
|
|
20625
22113
|
// Annotate the CommonJS export names for ESM import in node:
|
|
20626
22114
|
0 && (module.exports = {
|
|
22115
|
+
ADAPTER_VERSION,
|
|
22116
|
+
PythonWhySession,
|
|
20627
22117
|
annotationToShape,
|
|
20628
22118
|
bindModule,
|
|
20629
22119
|
buildRouterIndex,
|
|
@@ -20638,6 +22128,10 @@ function functionsReachingStorage(db, definitions, couldMatch) {
|
|
|
20638
22128
|
nodeId,
|
|
20639
22129
|
objectReturnedBy,
|
|
20640
22130
|
parsePython,
|
|
22131
|
+
parsePythonSync,
|
|
22132
|
+
preloadPythonGrammar,
|
|
22133
|
+
pythonImportEvidence,
|
|
22134
|
+
readKey,
|
|
20641
22135
|
resolveAbsoluteModule,
|
|
20642
22136
|
resolveCalls,
|
|
20643
22137
|
resolveModule,
|