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