@suss/adapter-python 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -0
- package/dist/index.cjs +2287 -733
- package/dist/index.d.cts +148 -3
- package/dist/index.d.ts +148 -3
- package/dist/index.js +1938 -356
- 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
|
-
// Where a walk gets to, and whether it ran a call on the way.
|
|
973
|
-
//
|
|
974
|
-
//
|
|
975
|
-
(0,
|
|
1440
|
+
// Where a walk gets to, and whether it ran a call on the way. The walk
|
|
1441
|
+
// so far comes first, so demand stays on the value asked about; the
|
|
1442
|
+
// README says what the other order cost.
|
|
1443
|
+
(0, import_datalog3.rule)(
|
|
976
1444
|
"reaches",
|
|
977
|
-
[(0,
|
|
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
|
-
// Two rules rather than one leaving the
|
|
989
|
-
//
|
|
1456
|
+
// Two rules rather than one leaving the next step's kind free. A free
|
|
1457
|
+
// kind is a second question about the same relation, and a
|
|
990
1458
|
// demand-driven run then derives both to answer either.
|
|
991
|
-
(0,
|
|
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,304 +1708,289 @@ var RESOLUTION_RULES = [
|
|
|
1228
1708
|
// another unwrapping factory. This is what lets
|
|
1229
1709
|
// `createProtected(h) { return service.withAuth(h); }` unwrap:
|
|
1230
1710
|
// the returned call passes h through withAuth, which unwraps.
|
|
1231
|
-
(0,
|
|
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,
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
),
|
|
1355
|
-
(0, import_datalog2.rule)(
|
|
1356
|
-
"callOriginChain",
|
|
1357
|
-
[(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
|
|
1358
|
-
[
|
|
1359
|
-
(0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
|
|
1360
|
-
(0, import_datalog2.lit)("endsHolding", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))
|
|
1361
|
-
]
|
|
1362
|
-
),
|
|
1363
|
-
(0, import_datalog2.rule)(
|
|
1829
|
+
(0, import_datalog3.rule)("callOriginChain", [(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("x")], [(0, import_datalog3.lit)("wantedCallOrigin", (0, import_datalog3.variable)("x"))]),
|
|
1830
|
+
// The chain with at least one hop taken, which is what tells a
|
|
1831
|
+
// destructured binding apart from asking about a node directly. The
|
|
1832
|
+
// whole chain is the seed plus those hops.
|
|
1833
|
+
(0, import_datalog3.rule)(
|
|
1364
1834
|
"callOriginChain",
|
|
1365
|
-
[(0,
|
|
1366
|
-
[
|
|
1367
|
-
(0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
|
|
1368
|
-
(0, import_datalog2.lit)("fallbackBranch", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))
|
|
1369
|
-
]
|
|
1835
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
|
|
1836
|
+
[(0, import_datalog3.lit)("callOriginChainStepped", (0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"))]
|
|
1370
1837
|
),
|
|
1371
|
-
|
|
1372
|
-
// destructured binding apart from asking about a node directly.
|
|
1373
|
-
(0, import_datalog2.rule)(
|
|
1838
|
+
(0, import_datalog3.rule)(
|
|
1374
1839
|
"callOriginChainStepped",
|
|
1375
|
-
[(0,
|
|
1376
|
-
[(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"))]
|
|
1377
1842
|
),
|
|
1378
|
-
(0,
|
|
1843
|
+
(0, import_datalog3.rule)(
|
|
1379
1844
|
"callOriginChainStepped",
|
|
1380
|
-
[(0,
|
|
1845
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
|
|
1381
1846
|
[
|
|
1382
|
-
(0,
|
|
1383
|
-
(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"))
|
|
1384
1849
|
]
|
|
1385
1850
|
),
|
|
1386
|
-
(0,
|
|
1851
|
+
(0, import_datalog3.rule)(
|
|
1387
1852
|
"callOriginChainStepped",
|
|
1388
|
-
[(0,
|
|
1853
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
|
|
1389
1854
|
[
|
|
1390
|
-
(0,
|
|
1391
|
-
(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"))
|
|
1392
1857
|
]
|
|
1393
1858
|
),
|
|
1394
|
-
(0,
|
|
1859
|
+
(0, import_datalog3.rule)(
|
|
1395
1860
|
"wantedCallOriginPair",
|
|
1396
|
-
[(0,
|
|
1861
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
|
|
1397
1862
|
[
|
|
1398
|
-
(0,
|
|
1399
|
-
(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"))
|
|
1400
1865
|
]
|
|
1401
1866
|
),
|
|
1402
1867
|
// An import of a project barrel is an import of what the barrel
|
|
1403
1868
|
// forwards, so the pair surfaces the module behind the chain.
|
|
1404
|
-
(0,
|
|
1869
|
+
(0, import_datalog3.rule)(
|
|
1405
1870
|
"wantedCallOriginPair",
|
|
1406
|
-
[(0,
|
|
1871
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m2"), (0, import_datalog3.variable)("n2")],
|
|
1407
1872
|
[
|
|
1408
|
-
(0,
|
|
1409
|
-
(0,
|
|
1410
|
-
(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"))
|
|
1411
1876
|
]
|
|
1412
1877
|
),
|
|
1413
1878
|
// A namespace member: the module's export of the member's own name.
|
|
1414
1879
|
// The imports literal leads, since it is the smallest relation.
|
|
1415
|
-
(0,
|
|
1880
|
+
(0, import_datalog3.rule)(
|
|
1416
1881
|
"wantedCallOriginPair",
|
|
1417
|
-
[(0,
|
|
1882
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("p")],
|
|
1418
1883
|
[
|
|
1419
|
-
(0,
|
|
1420
|
-
(0,
|
|
1421
|
-
(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"))
|
|
1422
1887
|
]
|
|
1423
1888
|
),
|
|
1424
|
-
(0,
|
|
1889
|
+
(0, import_datalog3.rule)(
|
|
1425
1890
|
"wantedCallOriginPair",
|
|
1426
|
-
[(0,
|
|
1891
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("p")],
|
|
1427
1892
|
[
|
|
1428
|
-
(0,
|
|
1429
|
-
(0,
|
|
1430
|
-
(0,
|
|
1431
|
-
(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"))
|
|
1432
1897
|
]
|
|
1433
1898
|
),
|
|
1434
1899
|
// What a call made: through the call to its callee, whose own alias
|
|
1435
1900
|
// chain leads to the import.
|
|
1436
|
-
(0,
|
|
1901
|
+
(0, import_datalog3.rule)(
|
|
1437
1902
|
"callMadeChain",
|
|
1438
|
-
[(0,
|
|
1439
|
-
[(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"))]
|
|
1440
1905
|
),
|
|
1441
|
-
(0,
|
|
1906
|
+
(0, import_datalog3.rule)(
|
|
1442
1907
|
"callMadeChain",
|
|
1443
|
-
[(0,
|
|
1444
|
-
[(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"))]
|
|
1445
1910
|
),
|
|
1446
|
-
(0,
|
|
1911
|
+
(0, import_datalog3.rule)(
|
|
1447
1912
|
"callMadeChain",
|
|
1448
|
-
[(0,
|
|
1449
|
-
[(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"))]
|
|
1450
1915
|
),
|
|
1451
|
-
(0,
|
|
1916
|
+
(0, import_datalog3.rule)(
|
|
1452
1917
|
"wantedCallOriginPair",
|
|
1453
|
-
[(0,
|
|
1918
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
|
|
1454
1919
|
[
|
|
1455
|
-
(0,
|
|
1456
|
-
(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"))
|
|
1457
1922
|
]
|
|
1458
1923
|
),
|
|
1459
1924
|
// A member destructured off what a call made keeps the member name
|
|
1460
1925
|
// as one more path segment.
|
|
1461
|
-
(0,
|
|
1926
|
+
(0, import_datalog3.rule)(
|
|
1462
1927
|
"callMemberChain",
|
|
1463
|
-
[(0,
|
|
1928
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("f"), (0, import_datalog3.variable)("p")],
|
|
1464
1929
|
[
|
|
1465
|
-
(0,
|
|
1466
|
-
(0,
|
|
1467
|
-
(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"))
|
|
1468
1933
|
]
|
|
1469
1934
|
),
|
|
1470
|
-
(0,
|
|
1935
|
+
(0, import_datalog3.rule)(
|
|
1471
1936
|
"callMemberChain",
|
|
1472
|
-
[(0,
|
|
1937
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), (0, import_datalog3.variable)("p")],
|
|
1473
1938
|
[
|
|
1474
|
-
(0,
|
|
1475
|
-
(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"))
|
|
1476
1941
|
]
|
|
1477
1942
|
),
|
|
1478
|
-
(0,
|
|
1943
|
+
(0, import_datalog3.rule)(
|
|
1479
1944
|
"callMemberChain",
|
|
1480
|
-
[(0,
|
|
1945
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z"), (0, import_datalog3.variable)("p")],
|
|
1481
1946
|
[
|
|
1482
|
-
(0,
|
|
1483
|
-
(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"))
|
|
1484
1949
|
]
|
|
1485
1950
|
),
|
|
1486
|
-
(0,
|
|
1951
|
+
(0, import_datalog3.rule)(
|
|
1487
1952
|
"wantedCallOriginMember",
|
|
1488
|
-
[(0,
|
|
1953
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("p")],
|
|
1489
1954
|
[
|
|
1490
|
-
(0,
|
|
1491
|
-
(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"))
|
|
1492
1957
|
]
|
|
1493
1958
|
),
|
|
1494
|
-
(0,
|
|
1959
|
+
(0, import_datalog3.rule)(
|
|
1495
1960
|
"wantedCallsInto",
|
|
1496
|
-
[(0,
|
|
1961
|
+
[(0, import_datalog3.variable)("g"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
|
|
1497
1962
|
[
|
|
1498
|
-
(0,
|
|
1499
|
-
(0,
|
|
1500
|
-
(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"))
|
|
1501
1966
|
]
|
|
1502
1967
|
),
|
|
1503
1968
|
// Subject identity, its own demand class; the README's subject
|
|
1504
1969
|
// section says why the origin pair rides on the written-value walk.
|
|
1505
|
-
(0,
|
|
1970
|
+
(0, import_datalog3.rule)(
|
|
1506
1971
|
"wantedSubjectWritten",
|
|
1507
|
-
[(0,
|
|
1508
|
-
[(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"))]
|
|
1509
1974
|
),
|
|
1510
|
-
(0,
|
|
1975
|
+
(0, import_datalog3.rule)(
|
|
1511
1976
|
"wantedSubjectConstruction",
|
|
1512
|
-
[(0,
|
|
1977
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("r"), (0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n")],
|
|
1513
1978
|
[
|
|
1514
|
-
(0,
|
|
1515
|
-
(0,
|
|
1516
|
-
(0,
|
|
1517
|
-
(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"))
|
|
1518
1983
|
]
|
|
1519
1984
|
),
|
|
1520
1985
|
// The export table of one module, keyed by the module asked about.
|
|
1521
1986
|
// The moduleExport rules flatten re-export chains of any length, and
|
|
1522
1987
|
// the demand cone stays on export facts alone.
|
|
1523
|
-
(0,
|
|
1988
|
+
(0, import_datalog3.rule)(
|
|
1524
1989
|
"wantedModuleExport",
|
|
1525
|
-
[(0,
|
|
1990
|
+
[(0, import_datalog3.variable)("m"), (0, import_datalog3.variable)("n"), (0, import_datalog3.variable)("value")],
|
|
1526
1991
|
[
|
|
1527
|
-
(0,
|
|
1528
|
-
(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"))
|
|
1529
1994
|
]
|
|
1530
1995
|
),
|
|
1531
1996
|
// The calls behind a receiver, for a pack that wants the anchor a
|
|
@@ -1534,63 +1999,63 @@ var RESOLUTION_QUESTIONS = [
|
|
|
1534
1999
|
// A class's ancestry, one hop per extends through the binding that
|
|
1535
2000
|
// says which class the written base is; the names on the way out
|
|
1536
2001
|
// are what a storage pack matches its library's bases against.
|
|
1537
|
-
(0,
|
|
1538
|
-
(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)(
|
|
1539
2004
|
"ancestryChain",
|
|
1540
|
-
[(0,
|
|
2005
|
+
[(0, import_datalog3.variable)("c"), (0, import_datalog3.variable)("b2")],
|
|
1541
2006
|
[
|
|
1542
|
-
(0,
|
|
1543
|
-
(0,
|
|
1544
|
-
(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"))
|
|
1545
2010
|
]
|
|
1546
2011
|
),
|
|
1547
|
-
(0,
|
|
2012
|
+
(0, import_datalog3.rule)(
|
|
1548
2013
|
"wantedBaseName",
|
|
1549
|
-
[(0,
|
|
1550
|
-
[(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"))]
|
|
1551
2016
|
),
|
|
1552
|
-
(0,
|
|
1553
|
-
(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)(
|
|
1554
2019
|
"anchorChain",
|
|
1555
|
-
[(0,
|
|
1556
|
-
[(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"))]
|
|
1557
2022
|
),
|
|
1558
|
-
(0,
|
|
2023
|
+
(0, import_datalog3.rule)(
|
|
1559
2024
|
"anchorChain",
|
|
1560
|
-
[(0,
|
|
1561
|
-
[(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"))]
|
|
1562
2027
|
),
|
|
1563
|
-
(0,
|
|
2028
|
+
(0, import_datalog3.rule)(
|
|
1564
2029
|
"anchorChain",
|
|
1565
|
-
[(0,
|
|
1566
|
-
[(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"))]
|
|
1567
2032
|
),
|
|
1568
|
-
(0,
|
|
2033
|
+
(0, import_datalog3.rule)(
|
|
1569
2034
|
"anchorChain",
|
|
1570
|
-
[(0,
|
|
2035
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("z")],
|
|
1571
2036
|
[
|
|
1572
|
-
(0,
|
|
1573
|
-
(0,
|
|
1574
|
-
(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"))
|
|
1575
2040
|
]
|
|
1576
2041
|
),
|
|
1577
|
-
(0,
|
|
2042
|
+
(0, import_datalog3.rule)(
|
|
1578
2043
|
"anchorChain",
|
|
1579
|
-
[(0,
|
|
1580
|
-
[(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"))]
|
|
1581
2046
|
),
|
|
1582
|
-
(0,
|
|
2047
|
+
(0, import_datalog3.rule)(
|
|
1583
2048
|
"anchorChain",
|
|
1584
|
-
[(0,
|
|
2049
|
+
[(0, import_datalog3.variable)("x"), (0, import_datalog3.variable)("o")],
|
|
1585
2050
|
[
|
|
1586
|
-
(0,
|
|
1587
|
-
(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"))
|
|
1588
2053
|
]
|
|
1589
2054
|
),
|
|
1590
|
-
(0,
|
|
2055
|
+
(0, import_datalog3.rule)(
|
|
1591
2056
|
"wantedAnchorCall",
|
|
1592
|
-
[(0,
|
|
1593
|
-
[(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"))]
|
|
1594
2059
|
)
|
|
1595
2060
|
];
|
|
1596
2061
|
var ANSWER_RELATIONS = [
|
|
@@ -1598,7 +2063,7 @@ var ANSWER_RELATIONS = [
|
|
|
1598
2063
|
];
|
|
1599
2064
|
|
|
1600
2065
|
// src/facts/resolve.ts
|
|
1601
|
-
var RESOLUTION_PROGRAM = (0,
|
|
2066
|
+
var RESOLUTION_PROGRAM = (0, import_datalog4.deriveOnDemand)(
|
|
1602
2067
|
[...RESOLUTION_RULES, ...RESOLUTION_QUESTIONS],
|
|
1603
2068
|
ANSWER_RELATIONS
|
|
1604
2069
|
);
|
|
@@ -1609,23 +2074,33 @@ function resolveCalls(db, callKeys) {
|
|
|
1609
2074
|
for (const callKey of callKeys) {
|
|
1610
2075
|
db.add("wanted", [callKey]);
|
|
1611
2076
|
}
|
|
1612
|
-
(0,
|
|
2077
|
+
(0, import_datalog4.evaluate)(db, RESOLUTION_PROGRAM.rules);
|
|
1613
2078
|
}
|
|
1614
2079
|
function subjectConstructions(db, valueKeys) {
|
|
1615
2080
|
const found = /* @__PURE__ */ new Map();
|
|
1616
2081
|
if (valueKeys.length === 0) {
|
|
1617
2082
|
return found;
|
|
1618
2083
|
}
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
2084
|
+
const askSubjects = (keys) => {
|
|
2085
|
+
for (const key of keys) {
|
|
2086
|
+
db.add("wantedSubject", [key]);
|
|
2087
|
+
}
|
|
2088
|
+
(0, import_datalog4.evaluate)(db, RESOLUTION_PROGRAM.rules);
|
|
2089
|
+
};
|
|
2090
|
+
askSubjects(valueKeys);
|
|
2091
|
+
const placeholders = placeholderValues(db);
|
|
2092
|
+
const written = singleAnswers(db.facts("wantedSubjectWritten"), placeholders);
|
|
2093
|
+
const calls = new Set(db.facts("call").map((row) => String(row[0])));
|
|
2094
|
+
const throughCalls = new Set(
|
|
2095
|
+
[...written.values()].filter((candidate) => calls.has(candidate))
|
|
2096
|
+
);
|
|
2097
|
+
if (throughCalls.size > 0) {
|
|
2098
|
+
askSubjects(throughCalls);
|
|
1628
2099
|
}
|
|
2100
|
+
const writtenThroughCall = singleAnswers(
|
|
2101
|
+
db.facts("wantedSubjectWritten"),
|
|
2102
|
+
placeholders
|
|
2103
|
+
);
|
|
1629
2104
|
const origins = /* @__PURE__ */ new Map();
|
|
1630
2105
|
for (const row of db.facts("wantedSubjectConstruction")) {
|
|
1631
2106
|
const key = `${String(row[0])}|${String(row[1])}`;
|
|
@@ -1634,12 +2109,14 @@ function subjectConstructions(db, valueKeys) {
|
|
|
1634
2109
|
origins.set(key, listed);
|
|
1635
2110
|
}
|
|
1636
2111
|
for (const valueKey2 of valueKeys) {
|
|
1637
|
-
const
|
|
1638
|
-
if (
|
|
2112
|
+
const direct = written.get(valueKey2);
|
|
2113
|
+
if (direct === void 0) {
|
|
1639
2114
|
continue;
|
|
1640
2115
|
}
|
|
1641
|
-
const
|
|
1642
|
-
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}`);
|
|
1643
2120
|
if (from !== void 0) {
|
|
1644
2121
|
found.set(valueKey2, { constructionKey, origins: from });
|
|
1645
2122
|
}
|
|
@@ -1835,6 +2312,9 @@ function emitExpressionFact(emitter, child) {
|
|
|
1835
2312
|
if (WRITTEN_VALUE_TYPES.has(child.type)) {
|
|
1836
2313
|
add(emitter, "writtenValue", nodeId(emitter.filePath, child));
|
|
1837
2314
|
}
|
|
2315
|
+
if (child.type === "none") {
|
|
2316
|
+
add(emitter, "placeholderValue", nodeId(emitter.filePath, child));
|
|
2317
|
+
}
|
|
1838
2318
|
}
|
|
1839
2319
|
function emitExpressionFacts(emitter, node) {
|
|
1840
2320
|
walkExpressions(emitter, node, (child) => {
|
|
@@ -2029,7 +2509,7 @@ function emitValueFacts(db, filePath, root) {
|
|
|
2029
2509
|
}
|
|
2030
2510
|
|
|
2031
2511
|
// src/paths/effects.ts
|
|
2032
|
-
var
|
|
2512
|
+
var import_extractor3 = require("@suss/extractor");
|
|
2033
2513
|
|
|
2034
2514
|
// src/paths/lowering.ts
|
|
2035
2515
|
var EXIT_KINDS = {
|
|
@@ -2293,7 +2773,7 @@ function predicateOf(node) {
|
|
|
2293
2773
|
}
|
|
2294
2774
|
|
|
2295
2775
|
// src/paths/effects.ts
|
|
2296
|
-
var
|
|
2776
|
+
var NESTED_DEFINITION_TYPES = /* @__PURE__ */ new Set(["function_definition"]);
|
|
2297
2777
|
var LITERAL_ARGS = {
|
|
2298
2778
|
string: (node) => ({ kind: "string", value: node.text.slice(1, -1) }),
|
|
2299
2779
|
integer: (node) => {
|
|
@@ -2309,7 +2789,7 @@ var LITERAL_ARGS = {
|
|
|
2309
2789
|
};
|
|
2310
2790
|
function bodyCalls(node, found = []) {
|
|
2311
2791
|
for (const child of node.namedChildren) {
|
|
2312
|
-
if (child === null ||
|
|
2792
|
+
if (child === null || NESTED_DEFINITION_TYPES.has(child.type)) {
|
|
2313
2793
|
continue;
|
|
2314
2794
|
}
|
|
2315
2795
|
if (child.type === "call") {
|
|
@@ -2351,26 +2831,12 @@ function argsOf(call) {
|
|
|
2351
2831
|
function calleeText(call) {
|
|
2352
2832
|
return field(call, "function")?.text ?? call.text;
|
|
2353
2833
|
}
|
|
2354
|
-
function withoutChainLinks(calls) {
|
|
2355
|
-
const isLink = /* @__PURE__ */ new Set();
|
|
2356
|
-
for (const call of calls) {
|
|
2357
|
-
const callee = field(call, "function");
|
|
2358
|
-
if (callee === null || callee.type !== "attribute") {
|
|
2359
|
-
continue;
|
|
2360
|
-
}
|
|
2361
|
-
const object2 = field(callee, "object");
|
|
2362
|
-
if (object2 !== null && object2.type === "call") {
|
|
2363
|
-
isLink.add(object2.id);
|
|
2364
|
-
}
|
|
2365
|
-
}
|
|
2366
|
-
return calls.filter((call) => !isLink.has(call.id));
|
|
2367
|
-
}
|
|
2368
2834
|
function invocationEffects(definitionNode) {
|
|
2369
2835
|
const body = field(definitionNode, "body");
|
|
2370
2836
|
if (body === null) {
|
|
2371
2837
|
return [];
|
|
2372
2838
|
}
|
|
2373
|
-
const calls =
|
|
2839
|
+
const calls = bodyCalls(body).sort((a, b) => a.endIndex - b.endIndex);
|
|
2374
2840
|
if (calls.length === 0) {
|
|
2375
2841
|
return [];
|
|
2376
2842
|
}
|
|
@@ -2385,7 +2851,7 @@ function invocationEffects(definitionNode) {
|
|
|
2385
2851
|
statements.push(statement);
|
|
2386
2852
|
}
|
|
2387
2853
|
const lowered = lowerPythonBody(body, statements);
|
|
2388
|
-
const enumerated = (0,
|
|
2854
|
+
const enumerated = (0, import_extractor3.enumerateOrDegrade)(
|
|
2389
2855
|
{
|
|
2390
2856
|
statements: lowered.statements,
|
|
2391
2857
|
terminalsByStmt: lowered.terminalsByStmt
|
|
@@ -2394,7 +2860,7 @@ function invocationEffects(definitionNode) {
|
|
|
2394
2860
|
);
|
|
2395
2861
|
return calls.map((call) => {
|
|
2396
2862
|
const statement = statementOf.get(call.id);
|
|
2397
|
-
const conditions = (0,
|
|
2863
|
+
const conditions = (0, import_extractor3.sharedGatingConditions)(
|
|
2398
2864
|
statement === void 0 ? void 0 : enumerated.byTerminal.get(statement),
|
|
2399
2865
|
predicateOf
|
|
2400
2866
|
);
|
|
@@ -3248,10 +3714,10 @@ function mergeDefs(...defs) {
|
|
|
3248
3714
|
function cloneDef(schema) {
|
|
3249
3715
|
return mergeDefs(schema._zod.def);
|
|
3250
3716
|
}
|
|
3251
|
-
function getElementAtPath(obj,
|
|
3252
|
-
if (!
|
|
3717
|
+
function getElementAtPath(obj, path6) {
|
|
3718
|
+
if (!path6)
|
|
3253
3719
|
return obj;
|
|
3254
|
-
return
|
|
3720
|
+
return path6.reduce((acc, key) => acc?.[key], obj);
|
|
3255
3721
|
}
|
|
3256
3722
|
function promiseAllObject(promisesObj) {
|
|
3257
3723
|
const keys = Object.keys(promisesObj);
|
|
@@ -3660,11 +4126,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
3660
4126
|
}
|
|
3661
4127
|
return false;
|
|
3662
4128
|
}
|
|
3663
|
-
function prefixIssues(
|
|
4129
|
+
function prefixIssues(path6, issues) {
|
|
3664
4130
|
return issues.map((iss) => {
|
|
3665
4131
|
var _a3;
|
|
3666
4132
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
3667
|
-
iss.path.unshift(
|
|
4133
|
+
iss.path.unshift(path6);
|
|
3668
4134
|
return iss;
|
|
3669
4135
|
});
|
|
3670
4136
|
}
|
|
@@ -3811,16 +4277,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
3811
4277
|
}
|
|
3812
4278
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
3813
4279
|
const fieldErrors = { _errors: [] };
|
|
3814
|
-
const processError = (error52,
|
|
4280
|
+
const processError = (error52, path6 = []) => {
|
|
3815
4281
|
for (const issue2 of error52.issues) {
|
|
3816
4282
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
3817
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
4283
|
+
issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
|
|
3818
4284
|
} else if (issue2.code === "invalid_key") {
|
|
3819
|
-
processError({ issues: issue2.issues }, [...
|
|
4285
|
+
processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
|
|
3820
4286
|
} else if (issue2.code === "invalid_element") {
|
|
3821
|
-
processError({ issues: issue2.issues }, [...
|
|
4287
|
+
processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
|
|
3822
4288
|
} else {
|
|
3823
|
-
const fullpath = [...
|
|
4289
|
+
const fullpath = [...path6, ...issue2.path];
|
|
3824
4290
|
if (fullpath.length === 0) {
|
|
3825
4291
|
fieldErrors._errors.push(mapper(issue2));
|
|
3826
4292
|
} else {
|
|
@@ -3847,17 +4313,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
3847
4313
|
}
|
|
3848
4314
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
3849
4315
|
const result = { errors: [] };
|
|
3850
|
-
const processError = (error52,
|
|
4316
|
+
const processError = (error52, path6 = []) => {
|
|
3851
4317
|
var _a3, _b;
|
|
3852
4318
|
for (const issue2 of error52.issues) {
|
|
3853
4319
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
3854
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
4320
|
+
issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
|
|
3855
4321
|
} else if (issue2.code === "invalid_key") {
|
|
3856
|
-
processError({ issues: issue2.issues }, [...
|
|
4322
|
+
processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
|
|
3857
4323
|
} else if (issue2.code === "invalid_element") {
|
|
3858
|
-
processError({ issues: issue2.issues }, [...
|
|
4324
|
+
processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
|
|
3859
4325
|
} else {
|
|
3860
|
-
const fullpath = [...
|
|
4326
|
+
const fullpath = [...path6, ...issue2.path];
|
|
3861
4327
|
if (fullpath.length === 0) {
|
|
3862
4328
|
result.errors.push(mapper(issue2));
|
|
3863
4329
|
continue;
|
|
@@ -3889,8 +4355,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
3889
4355
|
}
|
|
3890
4356
|
function toDotPath(_path) {
|
|
3891
4357
|
const segs = [];
|
|
3892
|
-
const
|
|
3893
|
-
for (const seg of
|
|
4358
|
+
const path6 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
4359
|
+
for (const seg of path6) {
|
|
3894
4360
|
if (typeof seg === "number")
|
|
3895
4361
|
segs.push(`[${seg}]`);
|
|
3896
4362
|
else if (typeof seg === "symbol")
|
|
@@ -16582,13 +17048,13 @@ function resolveRef(ref, ctx) {
|
|
|
16582
17048
|
if (!ref.startsWith("#")) {
|
|
16583
17049
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
16584
17050
|
}
|
|
16585
|
-
const
|
|
16586
|
-
if (
|
|
17051
|
+
const path6 = ref.slice(1).split("/").filter(Boolean);
|
|
17052
|
+
if (path6.length === 0) {
|
|
16587
17053
|
return ctx.rootSchema;
|
|
16588
17054
|
}
|
|
16589
17055
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
16590
|
-
if (
|
|
16591
|
-
const key =
|
|
17056
|
+
if (path6[0] === defsKey) {
|
|
17057
|
+
const key = path6[1];
|
|
16592
17058
|
if (!key || !ctx.defs[key]) {
|
|
16593
17059
|
throw new Error(`Reference not found: ${ref}`);
|
|
16594
17060
|
}
|
|
@@ -16996,7 +17462,7 @@ function date4(params) {
|
|
|
16996
17462
|
// ../../../node_modules/zod/v4/classic/external.js
|
|
16997
17463
|
config(en_default());
|
|
16998
17464
|
|
|
16999
|
-
// ../../ir-core/dist/chunk-
|
|
17465
|
+
// ../../ir-core/dist/chunk-PPQWK62O.js
|
|
17000
17466
|
function gqlIdentityKey(typeName, fieldName) {
|
|
17001
17467
|
return `gql:${typeName}.${fieldName}`;
|
|
17002
17468
|
}
|
|
@@ -17282,6 +17748,42 @@ var metricSemantics = defineBoundarySemantics({
|
|
|
17282
17748
|
}
|
|
17283
17749
|
}
|
|
17284
17750
|
});
|
|
17751
|
+
var HOLE_SPLIT = /(\{[^}]*\})/;
|
|
17752
|
+
function isHole(piece) {
|
|
17753
|
+
return piece.startsWith("{") && piece.endsWith("}");
|
|
17754
|
+
}
|
|
17755
|
+
function parseBoundaryName(name) {
|
|
17756
|
+
const parts = name.split(HOLE_SPLIT).filter((piece) => piece !== "").map(
|
|
17757
|
+
(piece) => isHole(piece) ? { type: "hole", label: piece.slice(1, -1) } : { type: "text", text: piece }
|
|
17758
|
+
);
|
|
17759
|
+
const only = parts.length === 1 ? parts[0] : void 0;
|
|
17760
|
+
if (only !== void 0 && only.type === "hole") {
|
|
17761
|
+
return { type: "reference", path: only.label.split(".") };
|
|
17762
|
+
}
|
|
17763
|
+
if (parts.some((part) => part.type === "hole")) {
|
|
17764
|
+
return { type: "pattern", parts };
|
|
17765
|
+
}
|
|
17766
|
+
return { type: "literal", value: name };
|
|
17767
|
+
}
|
|
17768
|
+
function patternHole(label) {
|
|
17769
|
+
return `{${label}}`;
|
|
17770
|
+
}
|
|
17771
|
+
function namesNothing(name) {
|
|
17772
|
+
return parseBoundaryName(name).type === "reference";
|
|
17773
|
+
}
|
|
17774
|
+
function referenceOf(name) {
|
|
17775
|
+
if (name.type !== "reference") {
|
|
17776
|
+
return null;
|
|
17777
|
+
}
|
|
17778
|
+
const root = name.path[0];
|
|
17779
|
+
if (root === void 0 || name.path.some((part) => part === "")) {
|
|
17780
|
+
return null;
|
|
17781
|
+
}
|
|
17782
|
+
return { root, fields: name.path.slice(1) };
|
|
17783
|
+
}
|
|
17784
|
+
function referenceFromName(name) {
|
|
17785
|
+
return referenceOf(parseBoundaryName(name));
|
|
17786
|
+
}
|
|
17285
17787
|
var SCHEME_ORIGIN = /^[a-zA-Z][a-zA-Z\d+.-]*:\/\/[^/]*/;
|
|
17286
17788
|
var PROTOCOL_RELATIVE_ORIGIN = /^\/\/[^/]*/;
|
|
17287
17789
|
function pathAfterOrigin(text) {
|
|
@@ -17308,12 +17810,12 @@ var RestSemanticsSchema = external_exports.object({
|
|
|
17308
17810
|
declaredResponses: external_exports.array(external_exports.number()).optional()
|
|
17309
17811
|
});
|
|
17310
17812
|
var OPENING_HOLE = /^\{([^{}]+)\}(.*)$/;
|
|
17311
|
-
function
|
|
17312
|
-
const
|
|
17313
|
-
return
|
|
17813
|
+
function baseUrlReference(semantics) {
|
|
17814
|
+
const label = OPENING_HOLE.exec(semantics.path ?? "")?.[1];
|
|
17815
|
+
return label === void 0 ? null : referenceFromName(patternHole(label));
|
|
17314
17816
|
}
|
|
17315
|
-
function normalizePath(
|
|
17316
|
-
let normalized =
|
|
17817
|
+
function normalizePath(path6) {
|
|
17818
|
+
let normalized = path6.replace(/:([a-zA-Z_]\w*)/g, "{$1}");
|
|
17317
17819
|
if (normalized.length > 1 && normalized.endsWith("/")) {
|
|
17318
17820
|
normalized = normalized.slice(0, -1);
|
|
17319
17821
|
}
|
|
@@ -17323,8 +17825,8 @@ function normalizePath(path4) {
|
|
|
17323
17825
|
);
|
|
17324
17826
|
return normalized;
|
|
17325
17827
|
}
|
|
17326
|
-
function pathShape(
|
|
17327
|
-
return normalizePath(
|
|
17828
|
+
function pathShape(path6) {
|
|
17829
|
+
return normalizePath(path6).replace(/\{[^}]*\}/g, "{}");
|
|
17328
17830
|
}
|
|
17329
17831
|
function methodsAgree(a, b) {
|
|
17330
17832
|
if (a === null || b === null) {
|
|
@@ -17402,8 +17904,8 @@ var restSemantics = defineBoundarySemantics({
|
|
|
17402
17904
|
return null;
|
|
17403
17905
|
}
|
|
17404
17906
|
const method = semantics.method === null ? "ANY" : semantics.method.toUpperCase();
|
|
17405
|
-
const
|
|
17406
|
-
return `${method} ${
|
|
17907
|
+
const path6 = semantics.path === null ? "?" : normalizePath(semantics.path);
|
|
17908
|
+
return `${method} ${path6}`;
|
|
17407
17909
|
},
|
|
17408
17910
|
/**
|
|
17409
17911
|
* A route with both halves stated decides for itself: the method
|
|
@@ -17412,14 +17914,14 @@ var restSemantics = defineBoundarySemantics({
|
|
|
17412
17914
|
* half might still be the one that handles the request, and nothing
|
|
17413
17915
|
* here can settle that, so it abstains instead of refusing.
|
|
17414
17916
|
*/
|
|
17415
|
-
servesRequest(semantics, method,
|
|
17917
|
+
servesRequest(semantics, method, path6) {
|
|
17416
17918
|
if (semantics.method === null || semantics.path === null) {
|
|
17417
17919
|
return "unknown";
|
|
17418
17920
|
}
|
|
17419
17921
|
if (!methodsAgree(semantics.method, method.toUpperCase())) {
|
|
17420
17922
|
return "nomatch";
|
|
17421
17923
|
}
|
|
17422
|
-
return routePathAdmits(semantics.path,
|
|
17924
|
+
return routePathAdmits(semantics.path, path6) ? "match" : "nomatch";
|
|
17423
17925
|
},
|
|
17424
17926
|
/**
|
|
17425
17927
|
* A route the registration pattern admits is inside it. A route
|
|
@@ -17444,22 +17946,20 @@ var restSemantics = defineBoundarySemantics({
|
|
|
17444
17946
|
* route parameter, and `/orders/{id}` means every id rather than a
|
|
17445
17947
|
* variable somebody set.
|
|
17446
17948
|
*/
|
|
17447
|
-
groundName(semantics,
|
|
17448
|
-
|
|
17449
|
-
|
|
17450
|
-
}
|
|
17451
|
-
const opening = OPENING_HOLE.exec(semantics.path);
|
|
17452
|
-
if (opening === null) {
|
|
17949
|
+
groundName(semantics, deployment) {
|
|
17950
|
+
const reference = baseUrlReference(semantics);
|
|
17951
|
+
if (reference === null) {
|
|
17453
17952
|
return null;
|
|
17454
17953
|
}
|
|
17455
|
-
const
|
|
17456
|
-
const base = deployedAs(variableOf(label));
|
|
17954
|
+
const base = deployment.setTo(reference);
|
|
17457
17955
|
if (base === null) {
|
|
17458
17956
|
return null;
|
|
17459
17957
|
}
|
|
17958
|
+
const rest = OPENING_HOLE.exec(semantics.path ?? "")?.[2] ?? "";
|
|
17460
17959
|
const grounded = pathAfterOrigin(`${base}${rest}`);
|
|
17461
17960
|
return { ...semantics, path: grounded === "" ? "/" : grounded };
|
|
17462
17961
|
},
|
|
17962
|
+
nameReference: baseUrlReference,
|
|
17463
17963
|
ruleBoundary: {
|
|
17464
17964
|
// "METHOD /path": one leading token, then an absolute path.
|
|
17465
17965
|
claims(raw) {
|
|
@@ -17535,6 +18035,9 @@ var StorageSemanticsSchema = external_exports.object({
|
|
|
17535
18035
|
*/
|
|
17536
18036
|
accessPath: external_exports.string().nullable()
|
|
17537
18037
|
});
|
|
18038
|
+
function containerReference(semantics) {
|
|
18039
|
+
return semantics.container === null ? null : referenceFromName(semantics.container);
|
|
18040
|
+
}
|
|
17538
18041
|
var storageSemantics = defineBoundarySemantics({
|
|
17539
18042
|
name: "storage",
|
|
17540
18043
|
schema: StorageSemanticsSchema,
|
|
@@ -17551,7 +18054,21 @@ var storageSemantics = defineBoundarySemantics({
|
|
|
17551
18054
|
exchangesHttpResponses: false,
|
|
17552
18055
|
reportsUnpairedItself: false,
|
|
17553
18056
|
identityKey: () => null,
|
|
17554
|
-
displayLabel: storageLabel
|
|
18057
|
+
displayLabel: storageLabel,
|
|
18058
|
+
/**
|
|
18059
|
+
* A container the source states as a variable is whatever the
|
|
18060
|
+
* deployment sets that variable to. `{SUBSCRIBERS_TABLE}` in the
|
|
18061
|
+
* code and `prod-subscribers-v1` in the manifest are one table.
|
|
18062
|
+
*/
|
|
18063
|
+
groundName(semantics, deployment) {
|
|
18064
|
+
const reference = containerReference(semantics);
|
|
18065
|
+
if (reference === null) {
|
|
18066
|
+
return null;
|
|
18067
|
+
}
|
|
18068
|
+
const name = deployment.setTo(reference);
|
|
18069
|
+
return name === null ? null : { ...semantics, container: name };
|
|
18070
|
+
},
|
|
18071
|
+
nameReference: containerReference
|
|
17555
18072
|
}
|
|
17556
18073
|
});
|
|
17557
18074
|
function storageLabel(semantics) {
|
|
@@ -17566,6 +18083,9 @@ var UnitInvocationSemanticsSchema = DeployableUnitSchema.extend({
|
|
|
17566
18083
|
name: external_exports.literal("unit-invocation"),
|
|
17567
18084
|
instanceName: DeployableUnitSchema.shape.instanceName.nullable()
|
|
17568
18085
|
});
|
|
18086
|
+
function calleeReference(semantics) {
|
|
18087
|
+
return semantics.instanceName === null ? null : referenceFromName(semantics.instanceName);
|
|
18088
|
+
}
|
|
17569
18089
|
var unitInvocationSemantics = defineBoundarySemantics({
|
|
17570
18090
|
name: "unit-invocation",
|
|
17571
18091
|
schema: UnitInvocationSemanticsSchema,
|
|
@@ -17588,8 +18108,13 @@ var unitInvocationSemantics = defineBoundarySemantics({
|
|
|
17588
18108
|
* being reported as a problem here.
|
|
17589
18109
|
*/
|
|
17590
18110
|
reportsUnpairedItself: false,
|
|
18111
|
+
/**
|
|
18112
|
+
* A callee the source states only as a variable is not a name for
|
|
18113
|
+
* anything until the deployment fills it in, so it keys as nothing
|
|
18114
|
+
* rather than as a bucket that would agree with itself alone.
|
|
18115
|
+
*/
|
|
17591
18116
|
identityKey(semantics) {
|
|
17592
|
-
if (semantics.instanceName === null) {
|
|
18117
|
+
if (semantics.instanceName === null || namesNothing(semantics.instanceName)) {
|
|
17593
18118
|
return null;
|
|
17594
18119
|
}
|
|
17595
18120
|
return unitIdentityKey(
|
|
@@ -17605,7 +18130,23 @@ var unitInvocationSemantics = defineBoundarySemantics({
|
|
|
17605
18130
|
semantics.deploymentTarget,
|
|
17606
18131
|
semantics.instanceName
|
|
17607
18132
|
);
|
|
17608
|
-
}
|
|
18133
|
+
},
|
|
18134
|
+
/**
|
|
18135
|
+
* A call that reads its callee's name out of the environment
|
|
18136
|
+
* reaches whichever resource the template wires that variable to.
|
|
18137
|
+
* The logical id is the answer rather than the deployed name,
|
|
18138
|
+
* because the invoked unit's own summary is keyed by the logical
|
|
18139
|
+
* id and neither side ever writes the other's string.
|
|
18140
|
+
*/
|
|
18141
|
+
groundName(semantics, deployment) {
|
|
18142
|
+
const reference = calleeReference(semantics);
|
|
18143
|
+
if (reference === null) {
|
|
18144
|
+
return null;
|
|
18145
|
+
}
|
|
18146
|
+
const logicalId = deployment.pointsAt(reference);
|
|
18147
|
+
return logicalId === null ? null : { ...semantics, instanceName: logicalId };
|
|
18148
|
+
},
|
|
18149
|
+
nameReference: calleeReference
|
|
17609
18150
|
}
|
|
17610
18151
|
});
|
|
17611
18152
|
var SemanticsSchema = external_exports.discriminatedUnion("name", [
|
|
@@ -18017,76 +18558,15 @@ function returnTypeName(node) {
|
|
|
18017
18558
|
}
|
|
18018
18559
|
return annotation.type === "subscript" ? field(annotation, "value")?.text ?? null : annotation.text;
|
|
18019
18560
|
}
|
|
18020
|
-
function
|
|
18021
|
-
|
|
18022
|
-
if (child === null) {
|
|
18023
|
-
continue;
|
|
18024
|
-
}
|
|
18025
|
-
if (child.type === "call") {
|
|
18026
|
-
found.push(child);
|
|
18027
|
-
}
|
|
18028
|
-
callsIn(child, found);
|
|
18029
|
-
}
|
|
18030
|
-
return found;
|
|
18561
|
+
function storageCallees(calls, filePath, couldMatch) {
|
|
18562
|
+
return chainsIn(calls).filter((chain) => couldMatch.has(methodName(chain.root))).map((chain) => field(chain.root, "function")).filter((callee) => callee !== null).map((callee) => nodeId(filePath, callee));
|
|
18031
18563
|
}
|
|
18032
18564
|
function storageEffects(calls, options) {
|
|
18033
|
-
|
|
18034
|
-
|
|
18035
|
-
|
|
18036
|
-
|
|
18037
|
-
|
|
18038
|
-
const found = [...directStorageEffects(inCalls, { ...options, filePath })];
|
|
18039
|
-
resolveCalls(
|
|
18040
|
-
options.facts,
|
|
18041
|
-
inCalls.filter((call) => options.leadsToStorage.has(methodName(call))).map((call) => field(call, "function")).filter((callee) => callee !== null).map((callee) => calleeKeyOf(filePath, callee)).filter((key) => {
|
|
18042
|
-
const fresh = !asked.has(key);
|
|
18043
|
-
asked.add(key);
|
|
18044
|
-
return fresh;
|
|
18045
|
-
})
|
|
18046
|
-
);
|
|
18047
|
-
for (const call of inCalls) {
|
|
18048
|
-
const callee = field(call, "function");
|
|
18049
|
-
if (callee === null || !options.leadsToStorage.has(methodName(call))) {
|
|
18050
|
-
continue;
|
|
18051
|
-
}
|
|
18052
|
-
const key = resolvedOnce(options, calleeKeyOf(filePath, callee));
|
|
18053
|
-
const body = key === void 0 ? void 0 : options.definitionAt(key);
|
|
18054
|
-
if (key === void 0 || body === void 0 || seen.has(key)) {
|
|
18055
|
-
continue;
|
|
18056
|
-
}
|
|
18057
|
-
seen.add(key);
|
|
18058
|
-
const name = field(body, "name")?.text;
|
|
18059
|
-
const origin = {
|
|
18060
|
-
file: fileOf(key),
|
|
18061
|
-
line: body.startPosition.row + 1,
|
|
18062
|
-
...name === void 0 ? {} : { function: name }
|
|
18063
|
-
};
|
|
18064
|
-
found.push(
|
|
18065
|
-
...gather(callsIn(body), fileOf(key)).map(
|
|
18066
|
-
(effect) => effect.type === "interaction" && effect.origin === void 0 ? { ...effect, origin } : effect
|
|
18067
|
-
)
|
|
18068
|
-
);
|
|
18069
|
-
}
|
|
18070
|
-
return found;
|
|
18071
|
-
};
|
|
18072
|
-
return gather(calls, options.filePath);
|
|
18073
|
-
}
|
|
18074
|
-
function calleeKeyOf(filePath, callee) {
|
|
18075
|
-
return callee.type === "identifier" ? `${filePath}#${callee.text}` : nodeId(filePath, callee);
|
|
18076
|
-
}
|
|
18077
|
-
function resolvedOnce(options, calleeKey) {
|
|
18078
|
-
const resolved = options.facts.facts("wantedResolves").filter((row) => String(row[0]) === calleeKey).map((row) => String(row[1]));
|
|
18079
|
-
return resolved.length === 1 ? resolved[0] : void 0;
|
|
18080
|
-
}
|
|
18081
|
-
function storageCallees(calls, filePath, couldMatch) {
|
|
18082
|
-
return chainsIn(calls).filter((chain) => couldMatch.has(methodName(chain.root))).map((chain) => field(chain.root, "function")).filter((callee) => callee !== null).map((callee) => nodeId(filePath, callee));
|
|
18083
|
-
}
|
|
18084
|
-
function directStorageEffects(calls, options) {
|
|
18085
|
-
if (options.patterns.length === 0) {
|
|
18086
|
-
return [];
|
|
18087
|
-
}
|
|
18088
|
-
const named = new Set(
|
|
18089
|
-
options.patterns.flatMap((pattern) => pattern.queryFunctions ?? [])
|
|
18565
|
+
if (options.patterns.length === 0) {
|
|
18566
|
+
return [];
|
|
18567
|
+
}
|
|
18568
|
+
const named = new Set(
|
|
18569
|
+
options.patterns.flatMap((pattern) => pattern.queryFunctions ?? [])
|
|
18090
18570
|
);
|
|
18091
18571
|
const chains = chainsIn(calls).filter(
|
|
18092
18572
|
(chain) => options.couldMatch.has(methodName(chain.root)) || named.has(methodName(chain.root))
|
|
@@ -18139,7 +18619,7 @@ function directStorageEffects(calls, options) {
|
|
|
18139
18619
|
// src/discovery.ts
|
|
18140
18620
|
function decoratedStatements(root, module2) {
|
|
18141
18621
|
const found = [];
|
|
18142
|
-
(0,
|
|
18622
|
+
(0, import_extractor4.walkDescendants)(
|
|
18143
18623
|
root,
|
|
18144
18624
|
{ scope: module2.moduleScope, enclosingFunction: null },
|
|
18145
18625
|
{
|
|
@@ -18178,21 +18658,21 @@ function builtSubjects(decorated, options) {
|
|
|
18178
18658
|
}
|
|
18179
18659
|
const factsPath = options.absoluteFile ?? options.filePath;
|
|
18180
18660
|
const asked = /* @__PURE__ */ new Set();
|
|
18181
|
-
for (const { enclosingFunction, decorators } of decorated) {
|
|
18661
|
+
for (const { enclosingFunction: enclosingFunction2, decorators } of decorated) {
|
|
18182
18662
|
for (const { node, direct } of decorators) {
|
|
18183
18663
|
if (direct.module !== null && acceptedByAnyPattern(direct.module, options)) {
|
|
18184
18664
|
continue;
|
|
18185
18665
|
}
|
|
18186
18666
|
const written = decoratorReceiver(node);
|
|
18187
18667
|
if (written !== null) {
|
|
18188
|
-
asked.add(readKey(factsPath, written.object,
|
|
18668
|
+
asked.add(readKey(factsPath, written.object, enclosingFunction2));
|
|
18189
18669
|
}
|
|
18190
18670
|
}
|
|
18191
18671
|
}
|
|
18192
18672
|
return subjectConstructions(facts, [...asked]);
|
|
18193
18673
|
}
|
|
18194
18674
|
function decoratedUnits(decoratedStatement, module2, options, subjects) {
|
|
18195
|
-
const { stmt, scope, enclosingFunction, decorators } = decoratedStatement;
|
|
18675
|
+
const { stmt, scope, enclosingFunction: enclosingFunction2, decorators } = decoratedStatement;
|
|
18196
18676
|
const units = [];
|
|
18197
18677
|
const { definition } = stripDecorators(stmt);
|
|
18198
18678
|
for (const { node: decoratorNode, direct } of decorators) {
|
|
@@ -18208,7 +18688,7 @@ function decoratedUnits(decoratedStatement, module2, options, subjects) {
|
|
|
18208
18688
|
) ?? null
|
|
18209
18689
|
) ?? builtSubjectClassification(
|
|
18210
18690
|
decoratorNode,
|
|
18211
|
-
|
|
18691
|
+
enclosingFunction2,
|
|
18212
18692
|
subjects,
|
|
18213
18693
|
options
|
|
18214
18694
|
)
|
|
@@ -18244,14 +18724,14 @@ function acceptedByAnyPattern(module2, options) {
|
|
|
18244
18724
|
(pack) => pack.discovery.some((pattern) => pattern.importModule.includes(module2))
|
|
18245
18725
|
);
|
|
18246
18726
|
}
|
|
18247
|
-
function builtSubjectClassification(decoratorNode,
|
|
18727
|
+
function builtSubjectClassification(decoratorNode, enclosingFunction2, subjects, options) {
|
|
18248
18728
|
const written = decoratorReceiver(decoratorNode);
|
|
18249
18729
|
if (written === null) {
|
|
18250
18730
|
return null;
|
|
18251
18731
|
}
|
|
18252
18732
|
const factsPath = options.absoluteFile ?? options.filePath;
|
|
18253
18733
|
const built = subjects.get(
|
|
18254
|
-
readKey(factsPath, written.object,
|
|
18734
|
+
readKey(factsPath, written.object, enclosingFunction2)
|
|
18255
18735
|
);
|
|
18256
18736
|
const origin = built?.origins.find(
|
|
18257
18737
|
(candidate) => acceptedByAnyPattern(candidate.module, options)
|
|
@@ -18310,23 +18790,23 @@ function unitsFor(pattern, pack, decoratorModule, classification, definition, mo
|
|
|
18310
18790
|
);
|
|
18311
18791
|
}
|
|
18312
18792
|
};
|
|
18313
|
-
return (0,
|
|
18793
|
+
return (0, import_behavioral_ir2.dispatchByType)(table, pattern);
|
|
18314
18794
|
}
|
|
18315
18795
|
function readPathArgument(classification) {
|
|
18316
18796
|
const first = classification.args[0];
|
|
18317
18797
|
if (first?.kind === "string") {
|
|
18318
|
-
return (0,
|
|
18798
|
+
return (0, import_extractor4.writtenReading)(first.value, classification.range);
|
|
18319
18799
|
}
|
|
18320
|
-
return (0,
|
|
18800
|
+
return (0, import_extractor4.unreadableReading)(
|
|
18321
18801
|
"The path in this route's decorator is not a string literal, so the binding names no path and nothing pairs with it",
|
|
18322
18802
|
classification.range
|
|
18323
18803
|
);
|
|
18324
18804
|
}
|
|
18325
18805
|
var NO_PATH_PARAMS = /* @__PURE__ */ new Set();
|
|
18326
18806
|
function templateReader(template) {
|
|
18327
|
-
return (
|
|
18807
|
+
return (path6) => {
|
|
18328
18808
|
const names = [];
|
|
18329
|
-
const canonical =
|
|
18809
|
+
const canonical = path6.replace(template, (_match, name) => {
|
|
18330
18810
|
names.push(name);
|
|
18331
18811
|
return `{${name}}`;
|
|
18332
18812
|
});
|
|
@@ -18339,19 +18819,19 @@ var PATH_TEMPLATE_READERS = {
|
|
|
18339
18819
|
/<(?:[A-Za-z_]\w*(?:\(.*?\))?:)?([A-Za-z_]\w*)>/g
|
|
18340
18820
|
)
|
|
18341
18821
|
};
|
|
18342
|
-
function readPathTemplate(pattern,
|
|
18822
|
+
function readPathTemplate(pattern, path6, range) {
|
|
18343
18823
|
const syntax = pattern.pathParamSyntax;
|
|
18344
18824
|
if (syntax === void 0) {
|
|
18345
|
-
return (0,
|
|
18825
|
+
return (0, import_extractor4.writtenReading)({ path: path6, paramNames: NO_PATH_PARAMS }, range);
|
|
18346
18826
|
}
|
|
18347
18827
|
const reader = PATH_TEMPLATE_READERS[syntax];
|
|
18348
18828
|
if (reader === void 0) {
|
|
18349
|
-
return (0,
|
|
18829
|
+
return (0, import_extractor4.unreadableReading)(
|
|
18350
18830
|
`The route's pack declares path-parameter syntax "${syntax}", which this adapter has no reader for, so the binding names no path and nothing pairs with it`,
|
|
18351
18831
|
range
|
|
18352
18832
|
);
|
|
18353
18833
|
}
|
|
18354
|
-
return (0,
|
|
18834
|
+
return (0, import_extractor4.writtenReading)(reader(path6), range);
|
|
18355
18835
|
}
|
|
18356
18836
|
function classRouteUnits(pattern, pack, classification, classNode, module2, options) {
|
|
18357
18837
|
const pathArgument = readPathArgument(classification);
|
|
@@ -18400,7 +18880,7 @@ function classRouteUnits(pattern, pack, classification, classNode, module2, opti
|
|
|
18400
18880
|
module: module2,
|
|
18401
18881
|
filePath: options.filePath,
|
|
18402
18882
|
skipReceiverParam: true,
|
|
18403
|
-
responseShape:
|
|
18883
|
+
responseShape: import_extractor4.absentReading,
|
|
18404
18884
|
statusCode: defaultedStatus(
|
|
18405
18885
|
readReturnedStatus(pattern, maybeMethod),
|
|
18406
18886
|
pattern
|
|
@@ -18415,13 +18895,13 @@ function classRouteUnits(pattern, pack, classification, classNode, module2, opti
|
|
|
18415
18895
|
return units;
|
|
18416
18896
|
}
|
|
18417
18897
|
function readRoutePath(pattern, pathArgument, classification, module2, options) {
|
|
18418
|
-
const composed = (0,
|
|
18898
|
+
const composed = (0, import_extractor4.andThenReading)(
|
|
18419
18899
|
pathArgument,
|
|
18420
18900
|
(literal2, range) => composeRoutePath(pattern, classification, module2, options, literal2, range)
|
|
18421
18901
|
);
|
|
18422
|
-
return (0,
|
|
18902
|
+
return (0, import_extractor4.andThenReading)(
|
|
18423
18903
|
composed,
|
|
18424
|
-
(
|
|
18904
|
+
(path6, range) => readPathTemplate(pattern, path6, range)
|
|
18425
18905
|
);
|
|
18426
18906
|
}
|
|
18427
18907
|
function readRoutePaths(pattern, pathArgument, classification, module2, options) {
|
|
@@ -18445,12 +18925,12 @@ function readRoutePaths(pattern, pathArgument, classification, module2, options)
|
|
|
18445
18925
|
];
|
|
18446
18926
|
}
|
|
18447
18927
|
return resolution.values.map((prefix) => ({
|
|
18448
|
-
routePath: (0,
|
|
18449
|
-
(0,
|
|
18928
|
+
routePath: (0, import_extractor4.andThenReading)(
|
|
18929
|
+
(0, import_extractor4.andThenReading)(
|
|
18450
18930
|
pathArgument,
|
|
18451
|
-
(literal2, range) => (0,
|
|
18931
|
+
(literal2, range) => (0, import_extractor4.writtenReading)(servedSpelling(pattern, prefix + literal2), range)
|
|
18452
18932
|
),
|
|
18453
|
-
(
|
|
18933
|
+
(path6, range) => readPathTemplate(pattern, path6, range)
|
|
18454
18934
|
),
|
|
18455
18935
|
mount: { siblings: resolution.values.length, prefix }
|
|
18456
18936
|
}));
|
|
@@ -18484,19 +18964,19 @@ function composeRoutePath(pattern, classification, module2, options, literal2, r
|
|
|
18484
18964
|
range
|
|
18485
18965
|
);
|
|
18486
18966
|
if (prefix.kind === "absent") {
|
|
18487
|
-
return (0,
|
|
18967
|
+
return (0, import_extractor4.writtenReading)(servedSpelling(pattern, literal2), range);
|
|
18488
18968
|
}
|
|
18489
|
-
return (0,
|
|
18969
|
+
return (0, import_extractor4.mapReading)(
|
|
18490
18970
|
prefix,
|
|
18491
18971
|
(value) => servedSpelling(pattern, value + literal2)
|
|
18492
18972
|
);
|
|
18493
18973
|
}
|
|
18494
18974
|
var REPEATED_SLASH_READERS = {
|
|
18495
|
-
kept: (
|
|
18496
|
-
merged: (
|
|
18975
|
+
kept: (path6) => path6,
|
|
18976
|
+
merged: (path6) => path6.replace(/\/{2,}/g, "/")
|
|
18497
18977
|
};
|
|
18498
|
-
function servedSpelling(pattern,
|
|
18499
|
-
return REPEATED_SLASH_READERS[pattern.pathRepeatedSlashes ?? "kept"](
|
|
18978
|
+
function servedSpelling(pattern, path6) {
|
|
18979
|
+
return REPEATED_SLASH_READERS[pattern.pathRepeatedSlashes ?? "kept"](path6);
|
|
18500
18980
|
}
|
|
18501
18981
|
function readRouterPrefix(pattern, classification, module2, options, range) {
|
|
18502
18982
|
const resolution = routerResolutionOf(
|
|
@@ -18506,31 +18986,31 @@ function readRouterPrefix(pattern, classification, module2, options, range) {
|
|
|
18506
18986
|
options
|
|
18507
18987
|
);
|
|
18508
18988
|
if (resolution === null) {
|
|
18509
|
-
return
|
|
18989
|
+
return import_extractor4.absentReading;
|
|
18510
18990
|
}
|
|
18511
18991
|
if (resolution.kind === "abstain") {
|
|
18512
|
-
return (0,
|
|
18992
|
+
return (0, import_extractor4.unreadableReading)(
|
|
18513
18993
|
`The router this route is declared on ${resolution.reason}, so the binding names no path and nothing pairs with it`,
|
|
18514
18994
|
range
|
|
18515
18995
|
);
|
|
18516
18996
|
}
|
|
18517
18997
|
if (resolution.kind === "composed") {
|
|
18518
|
-
return (0,
|
|
18998
|
+
return (0, import_extractor4.writtenReading)(resolution.value, range);
|
|
18519
18999
|
}
|
|
18520
|
-
return
|
|
19000
|
+
return import_extractor4.absentReading;
|
|
18521
19001
|
}
|
|
18522
19002
|
function readStatusCode(pattern, classification) {
|
|
18523
19003
|
if (pattern.statusCodeKeyword === void 0) {
|
|
18524
|
-
return
|
|
19004
|
+
return import_extractor4.absentReading;
|
|
18525
19005
|
}
|
|
18526
19006
|
const arg = classification.keywordArgs[pattern.statusCodeKeyword];
|
|
18527
19007
|
if (arg === void 0) {
|
|
18528
|
-
return
|
|
19008
|
+
return import_extractor4.absentReading;
|
|
18529
19009
|
}
|
|
18530
19010
|
if (arg.kind === "number") {
|
|
18531
|
-
return (0,
|
|
19011
|
+
return (0, import_extractor4.writtenReading)(arg.value, classification.range);
|
|
18532
19012
|
}
|
|
18533
|
-
return (0,
|
|
19013
|
+
return (0, import_extractor4.unreadableReading)(
|
|
18534
19014
|
"The status this route's decorator states is not a literal number, so the response claims no status",
|
|
18535
19015
|
classification.range
|
|
18536
19016
|
);
|
|
@@ -18575,7 +19055,7 @@ function statusOfReturn(statement) {
|
|
|
18575
19055
|
}
|
|
18576
19056
|
function effectsReaching(effects, conditions) {
|
|
18577
19057
|
return effects.filter(
|
|
18578
|
-
(effect) => (0,
|
|
19058
|
+
(effect) => (0, import_extractor4.guardsHoldOn)(effect.preconditions, conditions)
|
|
18579
19059
|
);
|
|
18580
19060
|
}
|
|
18581
19061
|
function branchesFromReturns(readsReturnedStatus, definitionNode, effects, responseShape, declaredStatus) {
|
|
@@ -18588,7 +19068,7 @@ function branchesFromReturns(readsReturnedStatus, definitionNode, effects, respo
|
|
|
18588
19068
|
return null;
|
|
18589
19069
|
}
|
|
18590
19070
|
const lowered = lowerPythonBody(body, returns);
|
|
18591
|
-
const enumerated = (0,
|
|
19071
|
+
const enumerated = (0, import_extractor4.enumerateOrDegrade)(
|
|
18592
19072
|
{
|
|
18593
19073
|
statements: lowered.statements,
|
|
18594
19074
|
terminalsByStmt: lowered.terminalsByStmt
|
|
@@ -18604,12 +19084,12 @@ function branchesFromReturns(readsReturnedStatus, definitionNode, effects, respo
|
|
|
18604
19084
|
const read = statusOfReturn(statement);
|
|
18605
19085
|
const range = rangeOf(statement);
|
|
18606
19086
|
const writtenBody = returnedBodyShape(statement);
|
|
18607
|
-
const statusReading = read.kind === "status" ? (0,
|
|
19087
|
+
const statusReading = read.kind === "status" ? (0, import_extractor4.writtenReading)(read.value, range) : read.kind === "none" ? import_extractor4.absentReading : (0, import_extractor4.unreadableReading)(
|
|
18608
19088
|
"This return gives a status this reading cannot resolve to a number, so this outcome claims none",
|
|
18609
19089
|
range
|
|
18610
19090
|
);
|
|
18611
|
-
for (const
|
|
18612
|
-
const conditions =
|
|
19091
|
+
for (const path6 of paths) {
|
|
19092
|
+
const conditions = path6.map((condition) => ({
|
|
18613
19093
|
sourceText: condition.sourceText,
|
|
18614
19094
|
structured: condition.expression === null ? null : predicateOf(condition.expression),
|
|
18615
19095
|
polarity: condition.polarity,
|
|
@@ -18634,11 +19114,11 @@ function branchesFromReturns(readsReturnedStatus, definitionNode, effects, respo
|
|
|
18634
19114
|
...declaredStatus.libraryDefault !== void 0 ? { libraryDefault: declaredStatus.libraryDefault } : {}
|
|
18635
19115
|
},
|
|
18636
19116
|
bodyShapeReading: {
|
|
18637
|
-
reading: writtenBody === null ? responseShape.reading : (0,
|
|
19117
|
+
reading: writtenBody === null ? responseShape.reading : (0, import_extractor4.writtenReading)(writtenBody, range)
|
|
18638
19118
|
},
|
|
18639
19119
|
effects: effectsReaching(effects, conditions),
|
|
18640
19120
|
location: range,
|
|
18641
|
-
isDefault:
|
|
19121
|
+
isDefault: path6.length === 0
|
|
18642
19122
|
});
|
|
18643
19123
|
}
|
|
18644
19124
|
}
|
|
@@ -18646,7 +19126,7 @@ function branchesFromReturns(readsReturnedStatus, definitionNode, effects, respo
|
|
|
18646
19126
|
}
|
|
18647
19127
|
function readReturnedStatus(pattern, definitionNode) {
|
|
18648
19128
|
if (pattern.statusFromReturnedTuple !== true) {
|
|
18649
|
-
return
|
|
19129
|
+
return import_extractor4.absentReading;
|
|
18650
19130
|
}
|
|
18651
19131
|
const range = rangeOf(definitionNode);
|
|
18652
19132
|
const statuses = /* @__PURE__ */ new Set();
|
|
@@ -18663,23 +19143,23 @@ function readReturnedStatus(pattern, definitionNode) {
|
|
|
18663
19143
|
}
|
|
18664
19144
|
}
|
|
18665
19145
|
if (unreadable > 0) {
|
|
18666
|
-
return (0,
|
|
19146
|
+
return (0, import_extractor4.unreadableReading)(
|
|
18667
19147
|
"This route returns a status this reading cannot resolve to a number, so no status is claimed for it",
|
|
18668
19148
|
range
|
|
18669
19149
|
);
|
|
18670
19150
|
}
|
|
18671
19151
|
if (statuses.size === 0) {
|
|
18672
|
-
return
|
|
19152
|
+
return import_extractor4.absentReading;
|
|
18673
19153
|
}
|
|
18674
19154
|
const candidates = [...statuses];
|
|
18675
19155
|
if (statuses.size > 1 || plainReturns > 0) {
|
|
18676
|
-
return (0,
|
|
19156
|
+
return (0, import_extractor4.ambiguousReading)(
|
|
18677
19157
|
candidates,
|
|
18678
19158
|
"This route returns more than one status depending on which branch runs, and nothing here reads which, so no status is claimed for it",
|
|
18679
19159
|
range
|
|
18680
19160
|
);
|
|
18681
19161
|
}
|
|
18682
|
-
return (0,
|
|
19162
|
+
return (0, import_extractor4.writtenReading)(candidates[0], range);
|
|
18683
19163
|
}
|
|
18684
19164
|
function declaredOrReturnedStatus(declared, returned) {
|
|
18685
19165
|
return declared.kind === "absent" ? returned : declared;
|
|
@@ -18692,19 +19172,19 @@ function defaultedStatus(reading, pattern) {
|
|
|
18692
19172
|
}
|
|
18693
19173
|
function readResponseModel(pattern, classification, module2, ctx) {
|
|
18694
19174
|
if (pattern.responseModelKeyword === void 0) {
|
|
18695
|
-
return
|
|
19175
|
+
return import_extractor4.absentReading;
|
|
18696
19176
|
}
|
|
18697
19177
|
const arg = classification.keywordArgs[pattern.responseModelKeyword];
|
|
18698
19178
|
if (arg === void 0) {
|
|
18699
|
-
return
|
|
19179
|
+
return import_extractor4.absentReading;
|
|
18700
19180
|
}
|
|
18701
19181
|
if (arg.kind === "identifier") {
|
|
18702
|
-
return (0,
|
|
19182
|
+
return (0, import_extractor4.writtenReading)(
|
|
18703
19183
|
shapeFromName(arg.name, module2.moduleScope, ctx),
|
|
18704
19184
|
classification.range
|
|
18705
19185
|
);
|
|
18706
19186
|
}
|
|
18707
|
-
return (0,
|
|
19187
|
+
return (0, import_extractor4.unreadableReading)(
|
|
18708
19188
|
"The response model this route's decorator states is not a name, so the response claims no body shape",
|
|
18709
19189
|
classification.range
|
|
18710
19190
|
);
|
|
@@ -18712,9 +19192,9 @@ function readResponseModel(pattern, classification, module2, ctx) {
|
|
|
18712
19192
|
function readReturnAnnotation(definitionNode, scope, ctx) {
|
|
18713
19193
|
const returnTypeNode = field(definitionNode, "return_type");
|
|
18714
19194
|
if (returnTypeNode === null) {
|
|
18715
|
-
return
|
|
19195
|
+
return import_extractor4.absentReading;
|
|
18716
19196
|
}
|
|
18717
|
-
return (0,
|
|
19197
|
+
return (0, import_extractor4.writtenReading)(
|
|
18718
19198
|
annotationToShape(returnTypeNode, scope, ctx),
|
|
18719
19199
|
rangeOf(returnTypeNode)
|
|
18720
19200
|
);
|
|
@@ -18767,7 +19247,7 @@ function readResponseShape(declared, readAnnotation) {
|
|
|
18767
19247
|
if (declared.kind === "written") {
|
|
18768
19248
|
return { reading: declared, passedOver: [] };
|
|
18769
19249
|
}
|
|
18770
|
-
return (0,
|
|
19250
|
+
return (0, import_extractor4.firstWrittenReading)([declared, readAnnotation()]);
|
|
18771
19251
|
}
|
|
18772
19252
|
function routeUnitOrAbstention(unitOptions, options) {
|
|
18773
19253
|
try {
|
|
@@ -18795,7 +19275,7 @@ function unbuiltRouteUnit(unitOptions, error51) {
|
|
|
18795
19275
|
exportName: unitOptions.exportPath[0] ?? unitOptions.name,
|
|
18796
19276
|
exportPath: unitOptions.exportPath
|
|
18797
19277
|
},
|
|
18798
|
-
boundaryBinding: (0,
|
|
19278
|
+
boundaryBinding: (0, import_behavioral_ir2.restBinding)({
|
|
18799
19279
|
transport: unitOptions.pack.protocol,
|
|
18800
19280
|
method: nullIfEmpty(unitOptions.method),
|
|
18801
19281
|
path: null,
|
|
@@ -18807,7 +19287,7 @@ function unbuiltRouteUnit(unitOptions, error51) {
|
|
|
18807
19287
|
dependencyCalls: [],
|
|
18808
19288
|
declaredContract: null,
|
|
18809
19289
|
readings: [
|
|
18810
|
-
(0,
|
|
19290
|
+
(0, import_extractor4.unreadableReading)(
|
|
18811
19291
|
`This route could not be read into a unit (${message}), so the binding names no path and nothing pairs with it`,
|
|
18812
19292
|
range
|
|
18813
19293
|
)
|
|
@@ -18833,7 +19313,7 @@ function buildRouteUnit(options) {
|
|
|
18833
19313
|
definitionsCtx,
|
|
18834
19314
|
storage: storageLookup
|
|
18835
19315
|
} = options;
|
|
18836
|
-
const template = (0,
|
|
19316
|
+
const template = (0, import_extractor4.valueToReadFurtherFrom)(routePath);
|
|
18837
19317
|
const ctx = definitionsCtx ?? createAnnotationContext(module2.scopeFor);
|
|
18838
19318
|
const parameters = readParameters(
|
|
18839
19319
|
definitionNode,
|
|
@@ -18849,17 +19329,7 @@ function buildRouteUnit(options) {
|
|
|
18849
19329
|
() => readReturnAnnotation(definitionNode, enclosingScope, ctx)
|
|
18850
19330
|
);
|
|
18851
19331
|
const effects = invocationEffects(definitionNode);
|
|
18852
|
-
const
|
|
18853
|
-
...storageEffects(bodyCalls(definitionNode), {
|
|
18854
|
-
...storageLookup,
|
|
18855
|
-
filePath: storageLookup.factsPath
|
|
18856
|
-
}),
|
|
18857
|
-
...rawSqlEffects(bodyCalls(definitionNode), {
|
|
18858
|
-
facts: storageLookup.facts,
|
|
18859
|
-
filePath: storageLookup.factsPath,
|
|
18860
|
-
patterns: storageLookup.rawSql ?? []
|
|
18861
|
-
})
|
|
18862
|
-
];
|
|
19332
|
+
const extra = recognizedBodyEffects(definitionNode, module2, storageLookup);
|
|
18863
19333
|
const perReturn = branchesFromReturns(
|
|
18864
19334
|
readsReturnedStatus,
|
|
18865
19335
|
definitionNode,
|
|
@@ -18868,9 +19338,9 @@ function buildRouteUnit(options) {
|
|
|
18868
19338
|
statusCode
|
|
18869
19339
|
);
|
|
18870
19340
|
const branches = (perReturn ?? []).map(
|
|
18871
|
-
(branch) =>
|
|
19341
|
+
(branch) => extra.length === 0 ? branch : { ...branch, extraEffects: extra }
|
|
18872
19342
|
);
|
|
18873
|
-
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)) {
|
|
18874
19344
|
branches.push({
|
|
18875
19345
|
conditions: [],
|
|
18876
19346
|
terminal: {
|
|
@@ -18890,7 +19360,7 @@ function buildRouteUnit(options) {
|
|
|
18890
19360
|
statusCodeReading: statusCode,
|
|
18891
19361
|
bodyShapeReading: { reading: responseShape.reading },
|
|
18892
19362
|
effects,
|
|
18893
|
-
...
|
|
19363
|
+
...extra.length === 0 ? {} : { extraEffects: extra },
|
|
18894
19364
|
location: rangeOf(definitionNode),
|
|
18895
19365
|
isDefault: true
|
|
18896
19366
|
});
|
|
@@ -18907,7 +19377,7 @@ function buildRouteUnit(options) {
|
|
|
18907
19377
|
exportName: exportPath[0] ?? name,
|
|
18908
19378
|
exportPath
|
|
18909
19379
|
},
|
|
18910
|
-
boundaryBinding: (0,
|
|
19380
|
+
boundaryBinding: (0, import_behavioral_ir2.restBinding)({
|
|
18911
19381
|
transport: pack.protocol,
|
|
18912
19382
|
method,
|
|
18913
19383
|
path: template?.path ?? null,
|
|
@@ -18932,12 +19402,26 @@ function unreadRoleReadings(parameters, range) {
|
|
|
18932
19402
|
return [];
|
|
18933
19403
|
}
|
|
18934
19404
|
return [
|
|
18935
|
-
(0,
|
|
19405
|
+
(0, import_extractor4.unreadableReading)(
|
|
18936
19406
|
"Nothing read this route's path, so its parameters name no role and a path parameter here does not read as one",
|
|
18937
19407
|
range
|
|
18938
19408
|
)
|
|
18939
19409
|
];
|
|
18940
19410
|
}
|
|
19411
|
+
function recognizedBodyEffects(definitionNode, module2, storageLookup) {
|
|
19412
|
+
const storage = storageLookup === void 0 ? [] : [
|
|
19413
|
+
...storageEffects(bodyCalls(definitionNode), {
|
|
19414
|
+
...storageLookup,
|
|
19415
|
+
filePath: storageLookup.factsPath
|
|
19416
|
+
}),
|
|
19417
|
+
...rawSqlEffects(bodyCalls(definitionNode), {
|
|
19418
|
+
facts: storageLookup.facts,
|
|
19419
|
+
filePath: storageLookup.factsPath,
|
|
19420
|
+
patterns: storageLookup.rawSql ?? []
|
|
19421
|
+
})
|
|
19422
|
+
];
|
|
19423
|
+
return [...envReadEffects(definitionNode, module2), ...storage];
|
|
19424
|
+
}
|
|
18941
19425
|
function bodyContentOf(bodyNode) {
|
|
18942
19426
|
for (const stmt of bodyStatements(bodyNode)) {
|
|
18943
19427
|
if (stmt.type === "pass_statement") {
|
|
@@ -19073,6 +19557,11 @@ function parameterNameAndType(param) {
|
|
|
19073
19557
|
return null;
|
|
19074
19558
|
}
|
|
19075
19559
|
|
|
19560
|
+
// src/facts/why.ts
|
|
19561
|
+
var import_node_fs4 = __toESM(require("fs"), 1);
|
|
19562
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
19563
|
+
var import_datalog7 = require("@suss/datalog");
|
|
19564
|
+
|
|
19076
19565
|
// src/moduleResolver.ts
|
|
19077
19566
|
var import_node_fs = __toESM(require("fs"), 1);
|
|
19078
19567
|
var import_node_path = __toESM(require("path"), 1);
|
|
@@ -19165,43 +19654,38 @@ function importedModuleText(module2, relativeLevel) {
|
|
|
19165
19654
|
return relativeLevel > 0 ? `${".".repeat(relativeLevel)}${module2}` : module2;
|
|
19166
19655
|
}
|
|
19167
19656
|
function emitModuleImportFacts(db, filePath, module2, resolverOptions) {
|
|
19168
|
-
const
|
|
19169
|
-
|
|
19170
|
-
|
|
19171
|
-
|
|
19172
|
-
|
|
19173
|
-
|
|
19174
|
-
|
|
19175
|
-
|
|
19176
|
-
|
|
19177
|
-
|
|
19178
|
-
|
|
19179
|
-
|
|
19180
|
-
|
|
19181
|
-
|
|
19182
|
-
|
|
19183
|
-
|
|
19184
|
-
|
|
19185
|
-
|
|
19186
|
-
|
|
19187
|
-
resolution.status === "resolved" ? "resolved" : resolution.reason
|
|
19188
|
-
]);
|
|
19189
|
-
const importedName = binding.kind === "import" ? binding.localName : binding.importedName;
|
|
19190
|
-
db.add("pyImportedName", [
|
|
19191
|
-
`${filePath}#${localName}`,
|
|
19192
|
-
moduleText,
|
|
19193
|
-
importedName
|
|
19194
|
-
]);
|
|
19195
|
-
if (resolution.status === "resolved") {
|
|
19196
|
-
db.add("pyImportResolved", [filePath, moduleText, resolution.file]);
|
|
19197
|
-
db.add("imports", [
|
|
19198
|
-
`${filePath}#${localName}`,
|
|
19199
|
-
resolution.file,
|
|
19200
|
-
importedName
|
|
19657
|
+
for (const scope of module2.scopeFor.values()) {
|
|
19658
|
+
for (const [localName, binding] of scope.bindings) {
|
|
19659
|
+
if (binding.kind !== "import" && binding.kind !== "importFrom") {
|
|
19660
|
+
continue;
|
|
19661
|
+
}
|
|
19662
|
+
const nameKey = `${filePath}#${localName}`;
|
|
19663
|
+
const moduleText = importedModuleText(
|
|
19664
|
+
binding.module,
|
|
19665
|
+
binding.relativeLevel
|
|
19666
|
+
);
|
|
19667
|
+
const resolution = resolveModule(
|
|
19668
|
+
filePath,
|
|
19669
|
+
{ module: binding.module, relativeLevel: binding.relativeLevel },
|
|
19670
|
+
resolverOptions
|
|
19671
|
+
);
|
|
19672
|
+
db.add("pyImport", [
|
|
19673
|
+
filePath,
|
|
19674
|
+
moduleText,
|
|
19675
|
+
resolution.status === "resolved" ? "resolved" : resolution.reason
|
|
19201
19676
|
]);
|
|
19202
|
-
|
|
19677
|
+
const importedName = binding.kind === "import" ? binding.localName : binding.importedName;
|
|
19678
|
+
db.add("pyImportedName", [nameKey, moduleText, importedName]);
|
|
19679
|
+
if (scope.kind === "module") {
|
|
19680
|
+
db.add("exportsAs", [filePath, localName, nameKey]);
|
|
19681
|
+
}
|
|
19682
|
+
if (resolution.status === "resolved") {
|
|
19683
|
+
db.add("pyImportResolved", [filePath, moduleText, resolution.file]);
|
|
19684
|
+
db.add("imports", [nameKey, resolution.file, importedName]);
|
|
19685
|
+
continue;
|
|
19686
|
+
}
|
|
19687
|
+
db.add("imports", [nameKey, moduleText, importedName]);
|
|
19203
19688
|
}
|
|
19204
|
-
db.add("imports", [`${filePath}#${localName}`, moduleText, importedName]);
|
|
19205
19689
|
}
|
|
19206
19690
|
for (const openModule of module2.openImports) {
|
|
19207
19691
|
db.add("pyOpenImport", [filePath, openModule]);
|
|
@@ -19220,6 +19704,7 @@ var GRAMMAR_PATH = import_node_path2.default.join(
|
|
|
19220
19704
|
"tree-sitter-python.wasm"
|
|
19221
19705
|
);
|
|
19222
19706
|
var languagePromise = null;
|
|
19707
|
+
var loadedLanguage = null;
|
|
19223
19708
|
function loadLanguage() {
|
|
19224
19709
|
languagePromise ??= (async () => {
|
|
19225
19710
|
if (!import_node_fs2.default.existsSync(GRAMMAR_PATH)) {
|
|
@@ -19228,12 +19713,28 @@ function loadLanguage() {
|
|
|
19228
19713
|
);
|
|
19229
19714
|
}
|
|
19230
19715
|
await import_web_tree_sitter.Parser.init();
|
|
19231
|
-
|
|
19716
|
+
const language = await import_web_tree_sitter.Language.load(GRAMMAR_PATH);
|
|
19717
|
+
loadedLanguage = language;
|
|
19718
|
+
return language;
|
|
19232
19719
|
})();
|
|
19233
19720
|
return languagePromise;
|
|
19234
19721
|
}
|
|
19235
19722
|
async function parsePython(source) {
|
|
19236
19723
|
const language = await loadLanguage();
|
|
19724
|
+
return parseWith(language, source);
|
|
19725
|
+
}
|
|
19726
|
+
async function preloadPythonGrammar() {
|
|
19727
|
+
await loadLanguage();
|
|
19728
|
+
}
|
|
19729
|
+
function parsePythonSync(source) {
|
|
19730
|
+
if (loadedLanguage === null) {
|
|
19731
|
+
throw new Error(
|
|
19732
|
+
"the Python grammar has not been loaded yet; call preloadPythonGrammar first"
|
|
19733
|
+
);
|
|
19734
|
+
}
|
|
19735
|
+
return parseWith(loadedLanguage, source);
|
|
19736
|
+
}
|
|
19737
|
+
function parseWith(language, source) {
|
|
19237
19738
|
const parser = new import_web_tree_sitter.Parser();
|
|
19238
19739
|
parser.setLanguage(language);
|
|
19239
19740
|
try {
|
|
@@ -19250,8 +19751,671 @@ async function parsePython(source) {
|
|
|
19250
19751
|
// src/project.ts
|
|
19251
19752
|
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
19252
19753
|
var import_node_path3 = __toESM(require("path"), 1);
|
|
19253
|
-
var
|
|
19254
|
-
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
|
+
}
|
|
19255
20419
|
|
|
19256
20420
|
// src/routers.ts
|
|
19257
20421
|
var UNSTATED_PREFIX = { kind: "unstated" };
|
|
@@ -19526,6 +20690,9 @@ function buildPatternIndex(files, importModule, composition, resolverOptions) {
|
|
|
19526
20690
|
for (const bound of files) {
|
|
19527
20691
|
collectConstructions(bound, importModule, composition, index);
|
|
19528
20692
|
}
|
|
20693
|
+
for (const bound of files) {
|
|
20694
|
+
collectReturnedConstructions(bound, importModule, composition, index);
|
|
20695
|
+
}
|
|
19529
20696
|
if (objectPrefix?.carrier !== void 0) {
|
|
19530
20697
|
const carrier = objectPrefix.carrier;
|
|
19531
20698
|
for (const bound of files) {
|
|
@@ -19701,6 +20868,37 @@ function collectConstructions(bound, importModule, composition, index) {
|
|
|
19701
20868
|
);
|
|
19702
20869
|
}
|
|
19703
20870
|
}
|
|
20871
|
+
function collectReturnedConstructions(bound, importModule, composition, index) {
|
|
20872
|
+
for (const stmt of bodyStatements(bound.root)) {
|
|
20873
|
+
const definition = stripDecorators(stmt).definition;
|
|
20874
|
+
if (definition.type !== "function_definition") {
|
|
20875
|
+
continue;
|
|
20876
|
+
}
|
|
20877
|
+
const scope = bound.module.scopeFor.get(definition.id);
|
|
20878
|
+
for (const inner of nestedStatements(definition)) {
|
|
20879
|
+
if (inner.type !== "return_statement" || scope === void 0) {
|
|
20880
|
+
continue;
|
|
20881
|
+
}
|
|
20882
|
+
const returned = inner.namedChildren[0];
|
|
20883
|
+
if (returned?.type !== "call") {
|
|
20884
|
+
continue;
|
|
20885
|
+
}
|
|
20886
|
+
const callee = field(returned, "function");
|
|
20887
|
+
const constructorName = callee === null ? null : importedConstructorName(callee, scope, importModule);
|
|
20888
|
+
if (constructorName !== composition.routerConstructorName) {
|
|
20889
|
+
continue;
|
|
20890
|
+
}
|
|
20891
|
+
const { keywordArgs } = readCallArguments(field(returned, "arguments"));
|
|
20892
|
+
const valueKey2 = nodeId(bound.file, returned);
|
|
20893
|
+
index.byValueKey.set(valueKey2, {
|
|
20894
|
+
constructorName,
|
|
20895
|
+
valueKey: valueKey2,
|
|
20896
|
+
prefix: constructorPrefix(keywordArgs, composition, scope),
|
|
20897
|
+
reassigned: false
|
|
20898
|
+
});
|
|
20899
|
+
}
|
|
20900
|
+
}
|
|
20901
|
+
}
|
|
19704
20902
|
function collectCarrierConstructions(carrier, composition, scan) {
|
|
19705
20903
|
walkStatements(
|
|
19706
20904
|
bodyStatements(scan.bound.root),
|
|
@@ -19759,6 +20957,21 @@ function constructionNamed(name, scope, scan, constructions = scan.index.constru
|
|
|
19759
20957
|
};
|
|
19760
20958
|
return resolvers[binding.kind]?.() ?? null;
|
|
19761
20959
|
}
|
|
20960
|
+
function constructionThroughFacts(name, scope, scan) {
|
|
20961
|
+
const facts = scan.index.facts;
|
|
20962
|
+
const binding = resolveName(scope, name);
|
|
20963
|
+
if (facts === void 0 || binding === null) {
|
|
20964
|
+
return null;
|
|
20965
|
+
}
|
|
20966
|
+
if (binding.kind !== "assignment" && binding.kind !== "importFrom") {
|
|
20967
|
+
return null;
|
|
20968
|
+
}
|
|
20969
|
+
const nameKey = `${scan.bound.file}#${name}`;
|
|
20970
|
+
const constructionKey = subjectConstructions(facts, [nameKey]).get(
|
|
20971
|
+
nameKey
|
|
20972
|
+
)?.constructionKey;
|
|
20973
|
+
return constructionKey === void 0 ? null : scan.index.byValueKey.get(constructionKey) ?? null;
|
|
20974
|
+
}
|
|
19762
20975
|
var MOUNT_STATE_BY_EFFECT = {
|
|
19763
20976
|
prefixes: (statedPrefix, site) => ({
|
|
19764
20977
|
kind: "mounted",
|
|
@@ -19928,10 +21141,10 @@ function constructionsReturnedBy(target, index) {
|
|
|
19928
21141
|
return { kind: "unread" };
|
|
19929
21142
|
}
|
|
19930
21143
|
const contained = containedValues(facts, returned);
|
|
19931
|
-
|
|
21144
|
+
const settled = subjectConstructions(facts, contained);
|
|
19932
21145
|
const found = [];
|
|
19933
21146
|
for (const value of contained) {
|
|
19934
|
-
const resolved =
|
|
21147
|
+
const resolved = settled.get(value)?.constructionKey ?? value;
|
|
19935
21148
|
const construction = index.byValueKey.get(resolved);
|
|
19936
21149
|
if (construction === void 0) {
|
|
19937
21150
|
return {
|
|
@@ -19946,10 +21159,6 @@ function constructionsReturnedBy(target, index) {
|
|
|
19946
21159
|
}
|
|
19947
21160
|
return { kind: "settled", found };
|
|
19948
21161
|
}
|
|
19949
|
-
function resolvedValueKey(facts, value) {
|
|
19950
|
-
const row = facts.facts("wantedIsWrittenAs").find((entry) => String(entry[0]) === value);
|
|
19951
|
-
return row === void 0 ? value : String(row[1]);
|
|
19952
|
-
}
|
|
19953
21162
|
function mountedConstructions(arg, position, scan) {
|
|
19954
21163
|
if (arg?.kind === "attribute") {
|
|
19955
21164
|
const construction = constructionThroughModule(arg, position.scope, scan);
|
|
@@ -19959,7 +21168,7 @@ function mountedConstructions(arg, position, scan) {
|
|
|
19959
21168
|
return [];
|
|
19960
21169
|
}
|
|
19961
21170
|
const named = (name) => {
|
|
19962
|
-
const construction = constructionNamed(name, position.scope, scan);
|
|
21171
|
+
const construction = constructionNamed(name, position.scope, scan) ?? constructionThroughFacts(name, position.scope, scan);
|
|
19963
21172
|
return construction === null ? [] : [construction];
|
|
19964
21173
|
};
|
|
19965
21174
|
const target = position.loopBindings.get(arg.name);
|
|
@@ -20346,36 +21555,69 @@ function carrierPrefix(carrier, constructorArg, objectName, scope, scan) {
|
|
|
20346
21555
|
return readings[construction.prefix.kind]();
|
|
20347
21556
|
}
|
|
20348
21557
|
|
|
21558
|
+
// src/version.ts
|
|
21559
|
+
var import_extractor7 = require("@suss/extractor");
|
|
21560
|
+
var ADAPTER_VERSION = "0.1.0";
|
|
21561
|
+
var adapterStamp = (0, import_extractor7.createAdapterStamp)({
|
|
21562
|
+
moduleUrl: importMetaUrl,
|
|
21563
|
+
version: ADAPTER_VERSION
|
|
21564
|
+
});
|
|
21565
|
+
|
|
20349
21566
|
// src/project.ts
|
|
20350
|
-
function reportUnresolvedProjectModules(options) {
|
|
21567
|
+
function reportUnresolvedProjectModules(options, db) {
|
|
21568
|
+
const imported = new Set(db.facts("pyImport").map((row) => String(row[1])));
|
|
20351
21569
|
for (const pack of options.packs) {
|
|
20352
21570
|
for (const module2 of pack.projectModules ?? []) {
|
|
20353
|
-
|
|
20354
|
-
if (resolved.status === "resolved") {
|
|
21571
|
+
if (imported.has(module2)) {
|
|
20355
21572
|
continue;
|
|
20356
21573
|
}
|
|
20357
21574
|
process.stderr.write(
|
|
20358
|
-
`[suss] ${pack.name}:
|
|
21575
|
+
`[suss] ${pack.name}: no file under ${options.roots.join(", ")} imports ${module2}, so the stub for it changes nothing.
|
|
20359
21576
|
`
|
|
20360
21577
|
);
|
|
20361
21578
|
}
|
|
20362
21579
|
}
|
|
20363
21580
|
}
|
|
20364
21581
|
async function extractPythonProject(options) {
|
|
20365
|
-
const
|
|
21582
|
+
const timer = options.onTiming !== void 0 ? (0, import_extractor8.createTimer)() : (0, import_extractor8.noopTimer)();
|
|
21583
|
+
const cacheDir = adapterStamp.declineWhenRunFromSource(
|
|
21584
|
+
options.cacheDir === null ? null : options.cacheDir ?? (options.projectRoot !== void 0 ? import_node_path3.default.join(options.projectRoot, ".suss", "cache") : null)
|
|
21585
|
+
);
|
|
21586
|
+
const cache = (0, import_extractor8.createCacheLayer)(cacheDir);
|
|
21587
|
+
const packsDigest = adapterStamp.packsDigest(
|
|
21588
|
+
options.packs.map(
|
|
21589
|
+
(pack) => pack.version !== void 0 ? { name: pack.name, version: pack.version } : { name: pack.name }
|
|
21590
|
+
)
|
|
21591
|
+
);
|
|
21592
|
+
const cacheInput = {
|
|
21593
|
+
files: cacheDir === null ? [] : options.files,
|
|
21594
|
+
adapterPacksDigest: cacheDir === null ? packsDigest : (0, import_extractor8.runDigest)(packsDigest, options.packs, options.files)
|
|
21595
|
+
};
|
|
21596
|
+
const lookup = await timer.timeAsync(
|
|
21597
|
+
"cache.lookup",
|
|
21598
|
+
() => cache.lookup(cacheInput)
|
|
21599
|
+
);
|
|
21600
|
+
options.onCacheDiagnostic?.(lookup.diagnostic);
|
|
21601
|
+
if (lookup.kind === "hit") {
|
|
21602
|
+
options.onTiming?.(timer.report());
|
|
21603
|
+
return { summaries: lookup.summaries, facts: new import_datalog6.Database() };
|
|
21604
|
+
}
|
|
21605
|
+
const db = new import_datalog6.Database();
|
|
20366
21606
|
const summaries = [];
|
|
20367
21607
|
const gapHandling = options.gapHandling ?? "permissive";
|
|
21608
|
+
const tallies = (0, import_extractor5.createPackTallies)(options.packs);
|
|
20368
21609
|
const displayPathOf = (file2) => options.workspaceRoot !== void 0 ? import_node_path3.default.relative(options.workspaceRoot, file2) : file2;
|
|
20369
|
-
reportUnresolvedProjectModules(options);
|
|
20370
21610
|
const bound = [];
|
|
20371
21611
|
for (const file2 of options.files) {
|
|
20372
|
-
|
|
20373
|
-
|
|
20374
|
-
|
|
20375
|
-
|
|
20376
|
-
|
|
20377
|
-
|
|
20378
|
-
|
|
21612
|
+
await timer.timeAsync("parse", async () => {
|
|
21613
|
+
const source = import_node_fs3.default.readFileSync(file2, "utf8");
|
|
21614
|
+
const tree = await parsePython(source);
|
|
21615
|
+
bound.push({
|
|
21616
|
+
file: file2,
|
|
21617
|
+
displayPath: displayPathOf(file2),
|
|
21618
|
+
root: tree.rootNode,
|
|
21619
|
+
module: bindModule(tree.rootNode)
|
|
21620
|
+
});
|
|
20379
21621
|
});
|
|
20380
21622
|
}
|
|
20381
21623
|
const mountsRouters = options.packs.some(
|
|
@@ -20386,81 +21628,172 @@ async function extractPythonProject(options) {
|
|
|
20386
21628
|
const discovers = options.packs.some((pack) => pack.discovery.length > 0);
|
|
20387
21629
|
const needsValues = discovers || mountsRouters || storagePatterns.length > 0;
|
|
20388
21630
|
const definitions = /* @__PURE__ */ new Map();
|
|
20389
|
-
|
|
20390
|
-
|
|
20391
|
-
|
|
20392
|
-
|
|
20393
|
-
|
|
20394
|
-
|
|
21631
|
+
timer.time("discover", () => {
|
|
21632
|
+
for (const { file: file2, root, module: moduleBinding } of bound) {
|
|
21633
|
+
emitModuleImportFacts(db, file2, moduleBinding, { roots: options.roots });
|
|
21634
|
+
if (needsValues) {
|
|
21635
|
+
emitValueFacts(db, file2, root);
|
|
21636
|
+
}
|
|
20395
21637
|
indexDefinitions(definitions, file2, root);
|
|
20396
21638
|
}
|
|
20397
|
-
}
|
|
20398
|
-
const couldMatch = methodsDeclaredNear(db, storagePatterns, definitions);
|
|
20399
|
-
const startsAQuery = /* @__PURE__ */ new Set([
|
|
20400
|
-
...couldMatch,
|
|
20401
|
-
...storagePatterns.flatMap((pattern) => pattern.queryFunctions ?? [])
|
|
20402
|
-
]);
|
|
20403
|
-
const leadsToStorage = functionsReachingStorage(
|
|
20404
|
-
db,
|
|
20405
|
-
definitions,
|
|
20406
|
-
startsAQuery
|
|
20407
|
-
);
|
|
20408
|
-
const routerIndex = buildRouterIndex(bound, options.packs, {
|
|
20409
|
-
roots: options.roots,
|
|
20410
|
-
...mountsRouters ? { facts: db } : {}
|
|
20411
21639
|
});
|
|
20412
|
-
|
|
21640
|
+
reportUnresolvedProjectModules(options, db);
|
|
21641
|
+
const couldMatch = timer.time(
|
|
21642
|
+
"discover",
|
|
21643
|
+
() => methodsDeclaredNear(db, storagePatterns, definitions)
|
|
21644
|
+
);
|
|
21645
|
+
const routerIndex = timer.time(
|
|
21646
|
+
"discover",
|
|
21647
|
+
() => buildRouterIndex(bound, options.packs, {
|
|
21648
|
+
roots: options.roots,
|
|
21649
|
+
...mountsRouters ? { facts: db } : {}
|
|
21650
|
+
})
|
|
21651
|
+
);
|
|
21652
|
+
const storageFor = (file2) => storagePatterns.length > 0 || rawSqlPatterns.length > 0 ? {
|
|
21653
|
+
facts: db,
|
|
21654
|
+
factsPath: file2.file,
|
|
21655
|
+
patterns: storagePatterns,
|
|
21656
|
+
definitionAt: (key) => definitions.get(key),
|
|
21657
|
+
couldMatch,
|
|
21658
|
+
rawSql: rawSqlPatterns
|
|
21659
|
+
} : void 0;
|
|
21660
|
+
const seeds = [];
|
|
21661
|
+
const summariesBySeed = /* @__PURE__ */ new Map();
|
|
21662
|
+
for (const boundFile of bound) {
|
|
21663
|
+
const { file: file2, root, module: moduleBinding } = boundFile;
|
|
20413
21664
|
const displayPath = displayPathOf(file2);
|
|
20414
|
-
const
|
|
20415
|
-
|
|
20416
|
-
|
|
20417
|
-
|
|
20418
|
-
|
|
20419
|
-
|
|
20420
|
-
|
|
20421
|
-
|
|
20422
|
-
|
|
20423
|
-
|
|
20424
|
-
|
|
20425
|
-
|
|
20426
|
-
|
|
20427
|
-
couldMatch,
|
|
20428
|
-
leadsToStorage,
|
|
20429
|
-
rawSql: rawSqlPatterns
|
|
20430
|
-
}
|
|
20431
|
-
} : {}
|
|
20432
|
-
});
|
|
21665
|
+
const storage = storageFor(boundFile);
|
|
21666
|
+
const rawUnits = timer.time(
|
|
21667
|
+
"discover",
|
|
21668
|
+
() => discoverUnits(root, moduleBinding, {
|
|
21669
|
+
packs: options.packs,
|
|
21670
|
+
filePath: displayPath,
|
|
21671
|
+
absoluteFile: file2,
|
|
21672
|
+
routerIndex,
|
|
21673
|
+
gapHandling,
|
|
21674
|
+
...needsValues ? { facts: db } : {},
|
|
21675
|
+
...storage === void 0 ? {} : { storage }
|
|
21676
|
+
})
|
|
21677
|
+
);
|
|
20433
21678
|
for (const raw of rawUnits) {
|
|
20434
|
-
const summary =
|
|
21679
|
+
const summary = timer.time(
|
|
21680
|
+
"summarize",
|
|
21681
|
+
() => (0, import_extractor8.assembleSummary)(raw, { gapHandling })
|
|
21682
|
+
);
|
|
20435
21683
|
summary.confidence = { source: "inferred_static", level: "low" };
|
|
20436
21684
|
summaries.push(summary);
|
|
20437
21685
|
emitEntryFact(db, file2, raw.identity.range, raw.identity.name);
|
|
21686
|
+
(0, import_extractor5.tallyUnit)(tallies, raw.boundaryBinding?.recognition);
|
|
21687
|
+
const span = raw.identity.span;
|
|
21688
|
+
const key = span === void 0 ? null : `${file2}:${span.start}-${span.end}`;
|
|
21689
|
+
const node = key === null ? void 0 : definitions.get(key);
|
|
21690
|
+
if (key === null || node === void 0) {
|
|
21691
|
+
continue;
|
|
21692
|
+
}
|
|
21693
|
+
const sharing = summariesBySeed.get(key);
|
|
21694
|
+
if (sharing === void 0) {
|
|
21695
|
+
seeds.push({ key, file: boundFile, node });
|
|
21696
|
+
summariesBySeed.set(key, [summary]);
|
|
21697
|
+
} else {
|
|
21698
|
+
sharing.push(summary);
|
|
21699
|
+
}
|
|
21700
|
+
}
|
|
21701
|
+
const loadTimeReads = timer.time(
|
|
21702
|
+
"discover",
|
|
21703
|
+
() => envReadEffects(root, moduleBinding)
|
|
21704
|
+
);
|
|
21705
|
+
if (loadTimeReads.length > 0) {
|
|
21706
|
+
const summary = timer.time(
|
|
21707
|
+
"summarize",
|
|
21708
|
+
() => (0, import_extractor8.assembleSummary)(
|
|
21709
|
+
(0, import_extractor8.moduleInitStructure)({
|
|
21710
|
+
name: import_node_path3.default.basename(displayPath),
|
|
21711
|
+
file: displayPath,
|
|
21712
|
+
range: rangeOf(root),
|
|
21713
|
+
effects: loadTimeReads
|
|
21714
|
+
}),
|
|
21715
|
+
{ gapHandling }
|
|
21716
|
+
)
|
|
21717
|
+
);
|
|
21718
|
+
summary.confidence = { source: "inferred_static", level: "low" };
|
|
21719
|
+
summaries.push(summary);
|
|
20438
21720
|
}
|
|
20439
21721
|
}
|
|
20440
|
-
|
|
21722
|
+
const reached = timer.time(
|
|
21723
|
+
"summarize",
|
|
21724
|
+
() => reachedFunctions(seeds, {
|
|
21725
|
+
files: bound,
|
|
21726
|
+
roots: options.roots,
|
|
21727
|
+
gapHandling,
|
|
21728
|
+
storageFor
|
|
21729
|
+
})
|
|
21730
|
+
);
|
|
21731
|
+
for (const [key, owners] of summariesBySeed) {
|
|
21732
|
+
for (const summary of owners) {
|
|
21733
|
+
if (gapHandling !== "silent") {
|
|
21734
|
+
summary.gaps.push(
|
|
21735
|
+
...(reached.stopsByKey.get(key) ?? []).map(import_behavioral_ir4.unfollowedCallGap)
|
|
21736
|
+
);
|
|
21737
|
+
}
|
|
21738
|
+
(0, import_behavioral_ir4.placeCalls)(summary, reached.targetsByKey.get(key));
|
|
21739
|
+
(0, import_behavioral_ir4.placeArgTargets)(summary, reached.argTargetsByKey.get(key));
|
|
21740
|
+
(0, import_behavioral_ir4.placeCalleeParameters)(summary, reached.parameterCallsByKey.get(key));
|
|
21741
|
+
}
|
|
21742
|
+
}
|
|
21743
|
+
if (gapHandling !== "silent") {
|
|
21744
|
+
(0, import_behavioral_ir4.recordParameterGaps)(
|
|
21745
|
+
reached.parameterCallsByKey,
|
|
21746
|
+
summariesBySeed,
|
|
21747
|
+
reached.passedPositions
|
|
21748
|
+
);
|
|
21749
|
+
}
|
|
21750
|
+
summaries.push(...reached.summaries);
|
|
21751
|
+
const resolvedImports = resolvedImportsOf(db, displayPathOf);
|
|
21752
|
+
(0, import_extractor8.stampModuleImports)(summaries, (file2) => resolvedImports.get(file2) ?? []);
|
|
21753
|
+
const idRoot = options.projectRoot ?? options.workspaceRoot;
|
|
21754
|
+
for (const summary of summaries) {
|
|
21755
|
+
const absoluteFile = options.workspaceRoot === void 0 ? summary.location.file : import_node_path3.default.resolve(options.workspaceRoot, summary.location.file);
|
|
21756
|
+
summary.identity.id = (0, import_behavioral_ir4.summaryIdFromParts)({
|
|
21757
|
+
workspace: void 0,
|
|
21758
|
+
file: idRoot === void 0 ? absoluteFile : import_node_path3.default.relative(idRoot, absoluteFile),
|
|
21759
|
+
name: summary.identity.name,
|
|
21760
|
+
exportPath: summary.identity.exportPath
|
|
21761
|
+
});
|
|
21762
|
+
}
|
|
21763
|
+
(0, import_behavioral_ir4.disambiguateSummaryIds)(summaries);
|
|
21764
|
+
(0, import_behavioral_ir4.linkCallsToSummaries)(summaries);
|
|
21765
|
+
await timer.timeAsync("cache.write", async () => {
|
|
21766
|
+
if (cacheDir === null || summaries.length === 0) {
|
|
21767
|
+
return;
|
|
21768
|
+
}
|
|
21769
|
+
try {
|
|
21770
|
+
await cache.write(cacheInput, summaries);
|
|
21771
|
+
} catch {
|
|
21772
|
+
}
|
|
21773
|
+
});
|
|
21774
|
+
options.onExtractionReport?.(
|
|
21775
|
+
buildPythonExtractionReport({
|
|
21776
|
+
packs: options.packs,
|
|
21777
|
+
tallies,
|
|
21778
|
+
filesWalked: options.files.length,
|
|
21779
|
+
summaries
|
|
21780
|
+
})
|
|
21781
|
+
);
|
|
21782
|
+
options.onTiming?.(timer.report());
|
|
20441
21783
|
return { summaries, facts: db };
|
|
20442
21784
|
}
|
|
20443
|
-
function
|
|
21785
|
+
function resolvedImportsOf(db, displayPathOf) {
|
|
20444
21786
|
const importsByFile = /* @__PURE__ */ new Map();
|
|
20445
21787
|
for (const [from, , to] of db.facts("pyImportResolved")) {
|
|
20446
21788
|
if (typeof from !== "string" || typeof to !== "string") {
|
|
20447
21789
|
continue;
|
|
20448
21790
|
}
|
|
20449
21791
|
const key = displayPathOf(from);
|
|
20450
|
-
const seen = importsByFile.get(key) ??
|
|
20451
|
-
seen.
|
|
21792
|
+
const seen = importsByFile.get(key) ?? [];
|
|
21793
|
+
seen.push(displayPathOf(to));
|
|
20452
21794
|
importsByFile.set(key, seen);
|
|
20453
21795
|
}
|
|
20454
|
-
|
|
20455
|
-
const imports = importsByFile.get(summary.location.file);
|
|
20456
|
-
if (imports === void 0 || imports.size === 0) {
|
|
20457
|
-
continue;
|
|
20458
|
-
}
|
|
20459
|
-
summary.metadata = {
|
|
20460
|
-
...summary.metadata ?? {},
|
|
20461
|
-
moduleImports: [...imports].sort()
|
|
20462
|
-
};
|
|
20463
|
-
}
|
|
21796
|
+
return importsByFile;
|
|
20464
21797
|
}
|
|
20465
21798
|
var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
20466
21799
|
"__pycache__",
|
|
@@ -20515,55 +21848,272 @@ function methodsDeclaredNear(db, patterns, definitions) {
|
|
|
20515
21848
|
}
|
|
20516
21849
|
return found;
|
|
20517
21850
|
}
|
|
20518
|
-
|
|
20519
|
-
|
|
20520
|
-
|
|
20521
|
-
|
|
21851
|
+
|
|
21852
|
+
// src/facts/why.ts
|
|
21853
|
+
var FUNCTION_TYPES2 = /* @__PURE__ */ new Set(["function_definition", "lambda"]);
|
|
21854
|
+
var IMPORT_TYPES = /* @__PURE__ */ new Set(["import_statement", "import_from_statement"]);
|
|
21855
|
+
function namedChildrenOf(node) {
|
|
21856
|
+
return node.namedChildren.filter((child) => child !== null);
|
|
21857
|
+
}
|
|
21858
|
+
function indexImportNames(file2, stmt, locations) {
|
|
21859
|
+
for (const nameNode of fields(stmt, "name")) {
|
|
21860
|
+
if (nameNode.type === "aliased_import") {
|
|
21861
|
+
const alias = field(nameNode, "alias");
|
|
21862
|
+
if (alias !== null) {
|
|
21863
|
+
locations.set(`${file2}#${alias.text}`, { file: file2, node: alias });
|
|
21864
|
+
}
|
|
21865
|
+
continue;
|
|
21866
|
+
}
|
|
21867
|
+
const local = nameNode.type === "dotted_name" ? nameNode.namedChild(0) : nameNode;
|
|
21868
|
+
if (local !== null) {
|
|
21869
|
+
locations.set(`${file2}#${local.text}`, { file: file2, node: local });
|
|
21870
|
+
}
|
|
20522
21871
|
}
|
|
20523
|
-
return callee.type === "attribute" ? field(callee, "attribute")?.text ?? "" : callee.text;
|
|
20524
21872
|
}
|
|
20525
|
-
function
|
|
20526
|
-
|
|
20527
|
-
|
|
21873
|
+
function enclosingFunction(node) {
|
|
21874
|
+
let current = node.parent;
|
|
21875
|
+
while (current !== null) {
|
|
21876
|
+
if (FUNCTION_TYPES2.has(current.type)) {
|
|
21877
|
+
return current;
|
|
21878
|
+
}
|
|
21879
|
+
current = current.parent;
|
|
21880
|
+
}
|
|
21881
|
+
return null;
|
|
21882
|
+
}
|
|
21883
|
+
function indexFile(file2, root, locations) {
|
|
21884
|
+
const walk = (node) => {
|
|
21885
|
+
locations.set(nodeId(file2, node), { file: file2, node });
|
|
21886
|
+
if (IMPORT_TYPES.has(node.type)) {
|
|
21887
|
+
indexImportNames(file2, node, locations);
|
|
21888
|
+
}
|
|
21889
|
+
if (FUNCTION_TYPES2.has(node.type) || node.type === "class_definition") {
|
|
21890
|
+
const name = field(node, "name");
|
|
21891
|
+
if (name !== null) {
|
|
21892
|
+
locations.set(`${file2}#${name.text}`, { file: file2, node: name });
|
|
21893
|
+
}
|
|
21894
|
+
}
|
|
21895
|
+
if (node.type === "assignment") {
|
|
21896
|
+
const left = field(node, "left");
|
|
21897
|
+
if (left !== null && left.type === "identifier") {
|
|
21898
|
+
locations.set(`${file2}#${left.text}`, { file: file2, node: left });
|
|
21899
|
+
}
|
|
21900
|
+
}
|
|
21901
|
+
for (const child of namedChildrenOf(node)) {
|
|
21902
|
+
walk(child);
|
|
21903
|
+
}
|
|
21904
|
+
};
|
|
21905
|
+
walk(root);
|
|
21906
|
+
}
|
|
21907
|
+
function displayNameOf(node) {
|
|
21908
|
+
if (node.type === "identifier") {
|
|
21909
|
+
return node.text;
|
|
21910
|
+
}
|
|
21911
|
+
if (node.type === "call") {
|
|
21912
|
+
const callee = field(node, "function");
|
|
21913
|
+
return `${callee?.text ?? "call"}(...)`;
|
|
21914
|
+
}
|
|
21915
|
+
if (node.type === "function_definition" || node.type === "class_definition") {
|
|
21916
|
+
return field(node, "name")?.text ?? node.text;
|
|
21917
|
+
}
|
|
21918
|
+
const text = node.text.split("\n")[0].trim();
|
|
21919
|
+
return text.length > 40 ? `${text.slice(0, 40)}...` : text;
|
|
21920
|
+
}
|
|
21921
|
+
function width(node) {
|
|
21922
|
+
return node.endIndex - node.startIndex;
|
|
21923
|
+
}
|
|
21924
|
+
var PythonWhySession = class {
|
|
21925
|
+
root;
|
|
21926
|
+
db = new import_datalog7.Database();
|
|
21927
|
+
locations = /* @__PURE__ */ new Map();
|
|
21928
|
+
trees = /* @__PURE__ */ new Map();
|
|
21929
|
+
constructor(options) {
|
|
21930
|
+
this.root = import_node_path4.default.resolve(options.dir);
|
|
21931
|
+
const roots = [this.root];
|
|
21932
|
+
for (const file2 of findPythonFiles(this.root)) {
|
|
21933
|
+
const source = import_node_fs4.default.readFileSync(file2, "utf8");
|
|
21934
|
+
const root = parsePythonSync(source).rootNode;
|
|
21935
|
+
this.trees.set(file2, root);
|
|
21936
|
+
emitModuleImportFacts(this.db, file2, bindModule(root), { roots });
|
|
21937
|
+
emitValueFacts(this.db, file2, root);
|
|
21938
|
+
indexFile(file2, root, this.locations);
|
|
21939
|
+
}
|
|
21940
|
+
}
|
|
21941
|
+
/**
|
|
21942
|
+
* The smallest expression on `line` of `file` whose text is exactly
|
|
21943
|
+
* `text`, or null.
|
|
21944
|
+
*/
|
|
21945
|
+
findExpression(file2, line, text) {
|
|
21946
|
+
const root = this.rootOf(file2);
|
|
21947
|
+
if (root === null) {
|
|
21948
|
+
return null;
|
|
21949
|
+
}
|
|
21950
|
+
let found = null;
|
|
21951
|
+
const visit = (node) => {
|
|
21952
|
+
if (node.startPosition.row + 1 === line && node.text === text) {
|
|
21953
|
+
if (found === null || width(node) <= width(found)) {
|
|
21954
|
+
found = node;
|
|
21955
|
+
}
|
|
21956
|
+
}
|
|
21957
|
+
for (const child of namedChildrenOf(node)) {
|
|
21958
|
+
visit(child);
|
|
21959
|
+
}
|
|
21960
|
+
};
|
|
21961
|
+
visit(root);
|
|
21962
|
+
return found === null ? null : { file: this.pathOf(file2), node: found };
|
|
21963
|
+
}
|
|
21964
|
+
/**
|
|
21965
|
+
* The callee of the call written as `calleeText` between `startLine`
|
|
21966
|
+
* and `endLine` of `file`, or null.
|
|
21967
|
+
*/
|
|
21968
|
+
findCallee(file2, startLine, endLine, calleeText2) {
|
|
21969
|
+
const root = this.rootOf(file2);
|
|
21970
|
+
if (root === null) {
|
|
21971
|
+
return null;
|
|
21972
|
+
}
|
|
21973
|
+
let found = null;
|
|
21974
|
+
const visit = (node) => {
|
|
21975
|
+
if (node.type === "call") {
|
|
21976
|
+
const line = node.startPosition.row + 1;
|
|
21977
|
+
const callee = field(node, "function");
|
|
21978
|
+
if (line >= startLine && line <= endLine && callee !== null && callee.text === calleeText2) {
|
|
21979
|
+
found = callee;
|
|
21980
|
+
}
|
|
21981
|
+
}
|
|
21982
|
+
for (const child of namedChildrenOf(node)) {
|
|
21983
|
+
visit(child);
|
|
21984
|
+
}
|
|
21985
|
+
};
|
|
21986
|
+
visit(root);
|
|
21987
|
+
return found === null ? null : { file: this.pathOf(file2), node: found };
|
|
21988
|
+
}
|
|
21989
|
+
/**
|
|
21990
|
+
* Why `value` resolves to what it does: the witness proof, flattened
|
|
21991
|
+
* to the chain and rendered. Null when the value does not resolve,
|
|
21992
|
+
* which the caller says in its own words.
|
|
21993
|
+
*/
|
|
21994
|
+
explain(value, options = {}) {
|
|
21995
|
+
return explainResolvedKey({
|
|
21996
|
+
db: this.db,
|
|
21997
|
+
rules: RESOLUTION_RULES,
|
|
21998
|
+
key: readKey(value.file, value.node, enclosingFunction(value.node)),
|
|
21999
|
+
locate: (key) => this.locate(key),
|
|
22000
|
+
displayPath: (key) => this.displayPath(key),
|
|
22001
|
+
...options
|
|
22002
|
+
});
|
|
22003
|
+
}
|
|
22004
|
+
locate(key) {
|
|
22005
|
+
const located = this.locations.get(key);
|
|
22006
|
+
if (located === void 0) {
|
|
22007
|
+
return null;
|
|
22008
|
+
}
|
|
22009
|
+
return {
|
|
22010
|
+
name: displayNameOf(located.node),
|
|
22011
|
+
file: this.displayPath(located.file),
|
|
22012
|
+
line: located.node.startPosition.row + 1
|
|
22013
|
+
};
|
|
22014
|
+
}
|
|
22015
|
+
rootOf(file2) {
|
|
22016
|
+
return this.trees.get(this.pathOf(file2)) ?? null;
|
|
22017
|
+
}
|
|
22018
|
+
pathOf(file2) {
|
|
22019
|
+
return import_node_path4.default.isAbsolute(file2) ? file2 : import_node_path4.default.resolve(this.root, file2);
|
|
22020
|
+
}
|
|
22021
|
+
/** A file path said relative to the root, or as given when it is outside the root. */
|
|
22022
|
+
displayPath(key) {
|
|
22023
|
+
if (key.startsWith(this.root)) {
|
|
22024
|
+
return import_node_path4.default.relative(this.root, key);
|
|
22025
|
+
}
|
|
22026
|
+
return key;
|
|
22027
|
+
}
|
|
22028
|
+
};
|
|
22029
|
+
|
|
22030
|
+
// src/stubEvidence.ts
|
|
22031
|
+
var import_node_fs5 = __toESM(require("fs"), 1);
|
|
22032
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
22033
|
+
function importsSubmoduleOf(module2, packageName) {
|
|
22034
|
+
return module2 === packageName || module2.startsWith(`${packageName}.`);
|
|
22035
|
+
}
|
|
22036
|
+
function importStatementModules(stmt) {
|
|
22037
|
+
const modules = [];
|
|
22038
|
+
for (const nameNode of fields(stmt, "name")) {
|
|
22039
|
+
if (nameNode.type === "aliased_import") {
|
|
22040
|
+
const dotted = field(nameNode, "name");
|
|
22041
|
+
if (dotted !== null) {
|
|
22042
|
+
modules.push(dotted.text);
|
|
22043
|
+
}
|
|
20528
22044
|
continue;
|
|
20529
22045
|
}
|
|
20530
|
-
if (
|
|
20531
|
-
|
|
22046
|
+
if (nameNode.type === "dotted_name") {
|
|
22047
|
+
modules.push(nameNode.text);
|
|
20532
22048
|
}
|
|
20533
|
-
callsUnder(child, found);
|
|
20534
22049
|
}
|
|
20535
|
-
return
|
|
22050
|
+
return modules;
|
|
20536
22051
|
}
|
|
20537
|
-
|
|
20538
|
-
(
|
|
20539
|
-
|
|
20540
|
-
[
|
|
20541
|
-
|
|
20542
|
-
|
|
20543
|
-
|
|
20544
|
-
|
|
20545
|
-
|
|
20546
|
-
|
|
20547
|
-
|
|
20548
|
-
|
|
20549
|
-
|
|
20550
|
-
for (const node of definitions.values()) {
|
|
20551
|
-
const name = field(node, "name");
|
|
20552
|
-
if (name === null) {
|
|
22052
|
+
function importFromStatementEntries(stmt) {
|
|
22053
|
+
const moduleNode = field(stmt, "module_name");
|
|
22054
|
+
if (moduleNode === null || moduleNode.type === "relative_import") {
|
|
22055
|
+
return [];
|
|
22056
|
+
}
|
|
22057
|
+
const module2 = moduleNode.text;
|
|
22058
|
+
const entries = [];
|
|
22059
|
+
for (const nameNode of fields(stmt, "name")) {
|
|
22060
|
+
if (nameNode.type === "aliased_import") {
|
|
22061
|
+
const original = field(nameNode, "name");
|
|
22062
|
+
if (original !== null) {
|
|
22063
|
+
entries.push({ module: module2, name: original.text });
|
|
22064
|
+
}
|
|
20553
22065
|
continue;
|
|
20554
22066
|
}
|
|
20555
|
-
|
|
20556
|
-
|
|
22067
|
+
if (nameNode.type === "dotted_name") {
|
|
22068
|
+
entries.push({ module: module2, name: nameNode.text });
|
|
20557
22069
|
}
|
|
20558
22070
|
}
|
|
20559
|
-
|
|
20560
|
-
|
|
22071
|
+
return entries;
|
|
22072
|
+
}
|
|
22073
|
+
function importSitesIn(root) {
|
|
22074
|
+
const found = [];
|
|
22075
|
+
const visit = (node) => {
|
|
22076
|
+
if (node.type === "import_statement") {
|
|
22077
|
+
const line = rangeOf(node).start;
|
|
22078
|
+
for (const module2 of importStatementModules(node)) {
|
|
22079
|
+
found.push({ module: module2, name: null, line });
|
|
22080
|
+
}
|
|
22081
|
+
} else if (node.type === "import_from_statement") {
|
|
22082
|
+
const line = rangeOf(node).start;
|
|
22083
|
+
for (const entry of importFromStatementEntries(node)) {
|
|
22084
|
+
found.push({ module: entry.module, name: entry.name, line });
|
|
22085
|
+
}
|
|
22086
|
+
}
|
|
22087
|
+
for (const child of node.namedChildren) {
|
|
22088
|
+
if (child !== null) {
|
|
22089
|
+
visit(child);
|
|
22090
|
+
}
|
|
22091
|
+
}
|
|
22092
|
+
};
|
|
22093
|
+
visit(root);
|
|
22094
|
+
return found;
|
|
22095
|
+
}
|
|
22096
|
+
async function pythonImportEvidence(options) {
|
|
22097
|
+
const byModule = /* @__PURE__ */ new Map();
|
|
22098
|
+
for (const file2 of findPythonFiles(options.directory)) {
|
|
22099
|
+
const source = import_node_fs5.default.readFileSync(file2, "utf8");
|
|
22100
|
+
const tree = await parsePython(source);
|
|
22101
|
+
const displayPath = import_node_path5.default.relative(options.directory, file2);
|
|
22102
|
+
for (const site of importSitesIn(tree.rootNode)) {
|
|
22103
|
+
if (!importsSubmoduleOf(site.module, options.packageName)) {
|
|
22104
|
+
continue;
|
|
22105
|
+
}
|
|
22106
|
+
const sites = byModule.get(site.module) ?? [];
|
|
22107
|
+
sites.push({ name: site.name, file: displayPath, line: site.line });
|
|
22108
|
+
byModule.set(site.module, sites);
|
|
22109
|
+
}
|
|
20561
22110
|
}
|
|
20562
|
-
(
|
|
20563
|
-
return new Set(db.facts("reachesStorage").map((row) => String(row[0])));
|
|
22111
|
+
return [...byModule.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([module2, sites]) => ({ module: module2, sites }));
|
|
20564
22112
|
}
|
|
20565
22113
|
// Annotate the CommonJS export names for ESM import in node:
|
|
20566
22114
|
0 && (module.exports = {
|
|
22115
|
+
ADAPTER_VERSION,
|
|
22116
|
+
PythonWhySession,
|
|
20567
22117
|
annotationToShape,
|
|
20568
22118
|
bindModule,
|
|
20569
22119
|
buildRouterIndex,
|
|
@@ -20578,6 +22128,10 @@ function functionsReachingStorage(db, definitions, couldMatch) {
|
|
|
20578
22128
|
nodeId,
|
|
20579
22129
|
objectReturnedBy,
|
|
20580
22130
|
parsePython,
|
|
22131
|
+
parsePythonSync,
|
|
22132
|
+
preloadPythonGrammar,
|
|
22133
|
+
pythonImportEvidence,
|
|
22134
|
+
readKey,
|
|
20581
22135
|
resolveAbsoluteModule,
|
|
20582
22136
|
resolveCalls,
|
|
20583
22137
|
resolveModule,
|