@suss/adapter-ruby 0.35.1 → 0.36.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 +1 -1
- package/dist/index.cjs +1087 -474
- package/dist/index.d.cts +57 -12
- package/dist/index.d.ts +57 -12
- package/dist/index.js +1089 -456
- package/package.json +8 -8
package/dist/index.cjs
CHANGED
|
@@ -785,6 +785,8 @@ var INVOKE_METHOD = "call";
|
|
|
785
785
|
var BLOCK_WRAPPERS = /* @__PURE__ */ new Set(["proc", "lambda"]);
|
|
786
786
|
var PROC_CLASS = "Proc";
|
|
787
787
|
var CONSTRUCTOR = "new";
|
|
788
|
+
var INITIALIZE_METHOD = "initialize";
|
|
789
|
+
var CLASS_OF_INSTANCE = "class";
|
|
788
790
|
|
|
789
791
|
// src/facts/resolve.ts
|
|
790
792
|
var import_resolution2 = require("@suss/resolution");
|
|
@@ -812,6 +814,26 @@ var RUBY_RULES = (0, import_resolution.alsoSteps)([
|
|
|
812
814
|
(0, import_datalog.lit)("readsProperty", (0, import_datalog.variable)("c"), (0, import_datalog.variable)("o"), (0, import_datalog.constant)(CONSTRUCTOR)),
|
|
813
815
|
(0, import_datalog.lit)("call", (0, import_datalog.variable)("r"), (0, import_datalog.variable)("c"))
|
|
814
816
|
]
|
|
817
|
+
),
|
|
818
|
+
// `new` in a class method makes one of the class the method runs on,
|
|
819
|
+
// and `self.class` in an instance method is that class.
|
|
820
|
+
(0, import_datalog.rule)(
|
|
821
|
+
"selfBehind",
|
|
822
|
+
[(0, import_datalog.variable)("r"), (0, import_datalog.variable)("s"), import_resolution.SELF_AS_INSTANCE],
|
|
823
|
+
[
|
|
824
|
+
(0, import_datalog.lit)("call", (0, import_datalog.variable)("r"), (0, import_datalog.variable)("c")),
|
|
825
|
+
(0, import_datalog.lit)("readsProperty", (0, import_datalog.variable)("c"), (0, import_datalog.variable)("o"), (0, import_datalog.constant)(CONSTRUCTOR)),
|
|
826
|
+
(0, import_datalog.lit)("selfBehind", (0, import_datalog.variable)("o"), (0, import_datalog.variable)("s"), import_resolution.SELF_AS_CLASS)
|
|
827
|
+
]
|
|
828
|
+
),
|
|
829
|
+
(0, import_datalog.rule)(
|
|
830
|
+
"selfBehind",
|
|
831
|
+
[(0, import_datalog.variable)("r"), (0, import_datalog.variable)("s"), import_resolution.SELF_AS_CLASS],
|
|
832
|
+
[
|
|
833
|
+
(0, import_datalog.lit)("call", (0, import_datalog.variable)("r"), (0, import_datalog.variable)("c")),
|
|
834
|
+
(0, import_datalog.lit)("readsProperty", (0, import_datalog.variable)("c"), (0, import_datalog.variable)("o"), (0, import_datalog.constant)(CLASS_OF_INSTANCE)),
|
|
835
|
+
(0, import_datalog.lit)("selfBehind", (0, import_datalog.variable)("o"), (0, import_datalog.variable)("s"), import_resolution.SELF_AS_INSTANCE)
|
|
836
|
+
]
|
|
815
837
|
)
|
|
816
838
|
]);
|
|
817
839
|
var RUBY_PROGRAM = (0, import_resolution.resolutionProgram)(RUBY_RULES);
|
|
@@ -2541,9 +2563,8 @@ function emitCandidates(emitter, key, group) {
|
|
|
2541
2563
|
add(emitter, "writesAllStated", key);
|
|
2542
2564
|
}
|
|
2543
2565
|
}
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
return definesClassMethod(method, emitter.bodyBlocks) ? classKey : `${nodeId(emitter.filePath, method)}#self`;
|
|
2566
|
+
function receiverKeyOf(file, method) {
|
|
2567
|
+
return `${nodeId(file, method)}#self`;
|
|
2547
2568
|
}
|
|
2548
2569
|
var CONSTANT_REF_TYPES = /* @__PURE__ */ new Set(["constant", "scope_resolution"]);
|
|
2549
2570
|
function mixedInConstants(body, callName, statements) {
|
|
@@ -2563,11 +2584,20 @@ function emitMixinFacts(emitter, classKey, body) {
|
|
|
2563
2584
|
}
|
|
2564
2585
|
function emitMethodOfClass(within, classKey, method, offeredOnClass) {
|
|
2565
2586
|
const stored = /* @__PURE__ */ new Map();
|
|
2566
|
-
const receiverKey = receiverKeyOf(within, method
|
|
2567
|
-
const onInstance =
|
|
2587
|
+
const receiverKey = receiverKeyOf(within.filePath, method);
|
|
2588
|
+
const onInstance = !definesClassMethod(method, within.bodyBlocks);
|
|
2568
2589
|
if (onInstance) {
|
|
2569
2590
|
add(within, "instanceOf", receiverKey, classKey);
|
|
2591
|
+
} else {
|
|
2592
|
+
add(within, "binds", receiverKey, classKey);
|
|
2570
2593
|
}
|
|
2594
|
+
add(
|
|
2595
|
+
within,
|
|
2596
|
+
"selfReceiver",
|
|
2597
|
+
nodeId(within.filePath, method),
|
|
2598
|
+
receiverKey,
|
|
2599
|
+
onInstance ? import_resolution4.SELF_AS_INSTANCE_NAME : import_resolution4.SELF_AS_CLASS_NAME
|
|
2600
|
+
);
|
|
2571
2601
|
const funcKey = emitMethodFacts(
|
|
2572
2602
|
{
|
|
2573
2603
|
...within,
|
|
@@ -4250,7 +4280,10 @@ async function definedInFileOf(fileConstant, qualifiedName, lookup) {
|
|
|
4250
4280
|
if (filePath === null) {
|
|
4251
4281
|
return null;
|
|
4252
4282
|
}
|
|
4253
|
-
|
|
4283
|
+
return blocksDefinedIn(filePath, qualifiedName, lookup.parsedFile);
|
|
4284
|
+
}
|
|
4285
|
+
async function blocksDefinedIn(filePath, qualifiedName, parsedFile) {
|
|
4286
|
+
const fileRoot = await parsedFile(filePath);
|
|
4254
4287
|
if (fileRoot === null) {
|
|
4255
4288
|
return null;
|
|
4256
4289
|
}
|
|
@@ -4330,9 +4363,16 @@ function unreadConstant(candidates) {
|
|
|
4330
4363
|
const bare = candidates.at(-1);
|
|
4331
4364
|
return bare === void 0 ? [] : [{ type: "unfollowed", name: bare }];
|
|
4332
4365
|
}
|
|
4333
|
-
function definitionOf(qualifiedName, lookup) {
|
|
4366
|
+
async function definitionOf(qualifiedName, lookup) {
|
|
4334
4367
|
const local = lookup.localDefinition?.(qualifiedName);
|
|
4335
|
-
|
|
4368
|
+
if (local !== void 0 && local !== null) {
|
|
4369
|
+
return local;
|
|
4370
|
+
}
|
|
4371
|
+
const inRun = await lookup.definedInRun?.(qualifiedName);
|
|
4372
|
+
if (inRun !== void 0 && inRun !== null) {
|
|
4373
|
+
return inRun;
|
|
4374
|
+
}
|
|
4375
|
+
return reachDefinition(qualifiedName, lookup);
|
|
4336
4376
|
}
|
|
4337
4377
|
async function mixinChain(self, callName, lookup, active, present) {
|
|
4338
4378
|
let chain = [];
|
|
@@ -4473,7 +4513,69 @@ function inheritedStatements(ancestry, blockConfigures) {
|
|
|
4473
4513
|
|
|
4474
4514
|
// src/discovery.ts
|
|
4475
4515
|
var import_behavioral_ir6 = require("@suss/behavioral-ir");
|
|
4476
|
-
var
|
|
4516
|
+
var import_extractor12 = require("@suss/extractor");
|
|
4517
|
+
|
|
4518
|
+
// src/baseClass.ts
|
|
4519
|
+
var import_resolution7 = require("@suss/resolution");
|
|
4520
|
+
function classBehind(facts, file, constant2) {
|
|
4521
|
+
const key = constant2.type === "constant" ? `${file}#${constant2.text}` : nodeId(file, constant2);
|
|
4522
|
+
const bound = new Set(
|
|
4523
|
+
facts.lookup("binds", 0, key).map((row) => String(row[1]))
|
|
4524
|
+
);
|
|
4525
|
+
return bound.size === 1 ? [...bound][0] : void 0;
|
|
4526
|
+
}
|
|
4527
|
+
function classSettledOn(facts, key) {
|
|
4528
|
+
(0, import_resolution7.askResolution)(facts, [key], "wanted", RUBY_PROGRAM);
|
|
4529
|
+
const objects = (0, import_resolution7.answersFor)(facts, "wantedObjectOf", key);
|
|
4530
|
+
return objects.length === 1 ? objects[0] : void 0;
|
|
4531
|
+
}
|
|
4532
|
+
function declaredName(facts, classKey) {
|
|
4533
|
+
const names = new Set(
|
|
4534
|
+
facts.lookup("rbConstantName", 0, classKey).map((row) => String(row[1]))
|
|
4535
|
+
);
|
|
4536
|
+
return names.size === 1 ? [...names][0] : void 0;
|
|
4537
|
+
}
|
|
4538
|
+
function classesDeclaredInRun(facts, parsedFile) {
|
|
4539
|
+
const known = /* @__PURE__ */ new Map();
|
|
4540
|
+
const read = async (qualifiedName) => {
|
|
4541
|
+
const files = /* @__PURE__ */ new Set();
|
|
4542
|
+
for (const row of facts.lookup("rbConstantName", 1, qualifiedName)) {
|
|
4543
|
+
const span = (0, import_resolution7.spanOfKey)(String(row[0]));
|
|
4544
|
+
if (span !== null) {
|
|
4545
|
+
files.add(span.file);
|
|
4546
|
+
}
|
|
4547
|
+
}
|
|
4548
|
+
const blocks = [];
|
|
4549
|
+
for (const file of files) {
|
|
4550
|
+
blocks.push(
|
|
4551
|
+
...await blocksDefinedIn(file, qualifiedName, parsedFile) ?? []
|
|
4552
|
+
);
|
|
4553
|
+
}
|
|
4554
|
+
return blocks.length === 0 ? null : blocks;
|
|
4555
|
+
};
|
|
4556
|
+
return (qualifiedName) => {
|
|
4557
|
+
let found = known.get(qualifiedName);
|
|
4558
|
+
if (found === void 0) {
|
|
4559
|
+
found = read(qualifiedName);
|
|
4560
|
+
known.set(qualifiedName, found);
|
|
4561
|
+
}
|
|
4562
|
+
return found;
|
|
4563
|
+
};
|
|
4564
|
+
}
|
|
4565
|
+
function reachesBase(facts, classKey, bases) {
|
|
4566
|
+
(0, import_resolution7.askResolution)(facts, [classKey], "wantedAncestry", RUBY_PROGRAM);
|
|
4567
|
+
return facts.lookup("wantedBaseName", 0, classKey).some((row) => bases.includes(String(row[1])));
|
|
4568
|
+
}
|
|
4569
|
+
function enclosingClassKey(node, file) {
|
|
4570
|
+
let current = node.parent;
|
|
4571
|
+
while (current !== null) {
|
|
4572
|
+
if (NESTING_TYPES.has(current.type)) {
|
|
4573
|
+
return nodeId(file, current);
|
|
4574
|
+
}
|
|
4575
|
+
current = current.parent;
|
|
4576
|
+
}
|
|
4577
|
+
return null;
|
|
4578
|
+
}
|
|
4477
4579
|
|
|
4478
4580
|
// src/clientCalls.ts
|
|
4479
4581
|
var import_behavioral_ir2 = require("@suss/behavioral-ir");
|
|
@@ -4481,7 +4583,7 @@ var import_values14 = require("@suss/values");
|
|
|
4481
4583
|
|
|
4482
4584
|
// src/paths/effects.ts
|
|
4483
4585
|
var import_extractor2 = require("@suss/extractor");
|
|
4484
|
-
var
|
|
4586
|
+
var import_values8 = require("@suss/values");
|
|
4485
4587
|
|
|
4486
4588
|
// src/paths/lowering.ts
|
|
4487
4589
|
var RAISE_NAMES = /* @__PURE__ */ new Set(["raise", "fail"]);
|
|
@@ -4692,6 +4794,7 @@ var Lowerer = class {
|
|
|
4692
4794
|
);
|
|
4693
4795
|
return {
|
|
4694
4796
|
kind: "try",
|
|
4797
|
+
lines: rangeOf(node),
|
|
4695
4798
|
tryBody: tryBody.map((statement) => this.lower(statement)),
|
|
4696
4799
|
catchBody: rescues2.length > 0 ? rescues2.flatMap((clause) => this.lowerBlock(field(clause, "body"))) : null,
|
|
4697
4800
|
finallyBody: ensureClause === null ? null : this.lowerBlock(ensureClause),
|
|
@@ -4783,7 +4886,8 @@ var Lowerer = class {
|
|
|
4783
4886
|
kind: "loop",
|
|
4784
4887
|
condition: handleOf(header),
|
|
4785
4888
|
body: this.lowerBlock(field(node, "body")),
|
|
4786
|
-
exitKind: exitKindOf(node)
|
|
4889
|
+
exitKind: exitKindOf(node),
|
|
4890
|
+
lines: rangeOf(node)
|
|
4787
4891
|
},
|
|
4788
4892
|
[header]
|
|
4789
4893
|
);
|
|
@@ -4799,7 +4903,8 @@ var Lowerer = class {
|
|
|
4799
4903
|
kind: "loop",
|
|
4800
4904
|
condition: callHeaderOf(node, attachedBlock),
|
|
4801
4905
|
body: this.lowerBlock(field(attachedBlock, "body") ?? attachedBlock),
|
|
4802
|
-
exitKind: exitKindOf(node)
|
|
4906
|
+
exitKind: exitKindOf(node),
|
|
4907
|
+
lines: rangeOf(node)
|
|
4803
4908
|
},
|
|
4804
4909
|
[node]
|
|
4805
4910
|
);
|
|
@@ -4843,12 +4948,15 @@ var BLOCK_TYPES5 = /* @__PURE__ */ new Set([
|
|
|
4843
4948
|
"block"
|
|
4844
4949
|
]);
|
|
4845
4950
|
function literalArgOf(node, facts) {
|
|
4951
|
+
if (node.type === "nil") {
|
|
4952
|
+
return { kind: "null" };
|
|
4953
|
+
}
|
|
4846
4954
|
const value = evaluatedValue(node, facts);
|
|
4847
|
-
const text3 = (0,
|
|
4955
|
+
const text3 = (0, import_values8.literalOf)(value);
|
|
4848
4956
|
if (text3 !== null) {
|
|
4849
4957
|
return { kind: "string", value: text3 };
|
|
4850
4958
|
}
|
|
4851
|
-
const constant2 = (0,
|
|
4959
|
+
const constant2 = (0, import_values8.constantOf)(value);
|
|
4852
4960
|
if (typeof constant2 === "number") {
|
|
4853
4961
|
return { kind: "number", value: constant2 };
|
|
4854
4962
|
}
|
|
@@ -4980,13 +5088,21 @@ function argsOf(call, facts) {
|
|
|
4980
5088
|
function enclosingStatement(call, body) {
|
|
4981
5089
|
let current = call;
|
|
4982
5090
|
while (current.parent !== null) {
|
|
4983
|
-
if (
|
|
5091
|
+
if (listsStatements(current.parent, body)) {
|
|
4984
5092
|
return current;
|
|
4985
5093
|
}
|
|
4986
5094
|
current = current.parent;
|
|
4987
5095
|
}
|
|
4988
5096
|
return current;
|
|
4989
5097
|
}
|
|
5098
|
+
function listsStatements(node, body) {
|
|
5099
|
+
if (BLOCK_TYPES5.has(node.type) || node.id === body.id) {
|
|
5100
|
+
return true;
|
|
5101
|
+
}
|
|
5102
|
+
const begin = node.type === "ensure" ? node.parent : node;
|
|
5103
|
+
const around = begin?.type === "begin" ? begin.parent : null;
|
|
5104
|
+
return around !== null && around !== void 0 && (BLOCK_TYPES5.has(around.type) || around.id === body.id);
|
|
5105
|
+
}
|
|
4990
5106
|
function invocationEffects(definitionNode, inherited = NO_INHERITED_METHODS, keepsArglessCall = NO_ARGLESS_CALLS, facts) {
|
|
4991
5107
|
return invocationSites(
|
|
4992
5108
|
definitionNode,
|
|
@@ -5011,36 +5127,13 @@ function moduleScopeInvocationEffects(root, inherited = NO_INHERITED_METHODS, ke
|
|
|
5011
5127
|
).map((site) => site.effect);
|
|
5012
5128
|
}
|
|
5013
5129
|
function effectsOfBody(read, inherited, keepsArglessCall, facts) {
|
|
5014
|
-
const body = read.body;
|
|
5015
5130
|
const calls = callsReported(bodyCalls(read, inherited), keepsArglessCall);
|
|
5016
5131
|
if (calls.length === 0) {
|
|
5017
5132
|
return [];
|
|
5018
5133
|
}
|
|
5019
|
-
const
|
|
5020
|
-
const byStatement = new NodeMap();
|
|
5021
|
-
const statements = [];
|
|
5022
|
-
for (const call of calls) {
|
|
5023
|
-
const written = enclosingStatement(call, body);
|
|
5024
|
-
const statement = byStatement.get(written);
|
|
5025
|
-
if (statement === void 0) {
|
|
5026
|
-
byStatement.set(written, written);
|
|
5027
|
-
statements.push(written);
|
|
5028
|
-
}
|
|
5029
|
-
statementOf2.set(call.id, statement ?? written);
|
|
5030
|
-
}
|
|
5031
|
-
const lowered = lowerRubyBody(body, statements);
|
|
5032
|
-
const enumerated = (0, import_extractor2.enumerateOrDegrade)(
|
|
5033
|
-
{
|
|
5034
|
-
statements: lowered.statements,
|
|
5035
|
-
terminalsByStmt: lowered.terminalsByStmt
|
|
5036
|
-
},
|
|
5037
|
-
statements
|
|
5038
|
-
);
|
|
5134
|
+
const sites = sitesIn(read.body, calls);
|
|
5039
5135
|
return calls.map((call) => {
|
|
5040
|
-
const
|
|
5041
|
-
const conditions = (0, import_extractor2.sharedGatingConditions)(
|
|
5042
|
-
statement === void 0 ? void 0 : enumerated.byTerminal.get(statement)
|
|
5043
|
-
);
|
|
5136
|
+
const conditions = (0, import_extractor2.sharedGatingConditions)(sites.pathsTo(call));
|
|
5044
5137
|
return {
|
|
5045
5138
|
call,
|
|
5046
5139
|
effect: {
|
|
@@ -5048,11 +5141,26 @@ function effectsOfBody(read, inherited, keepsArglessCall, facts) {
|
|
|
5048
5141
|
callee: calleeText(call),
|
|
5049
5142
|
args: argsOf(call, facts),
|
|
5050
5143
|
async: false,
|
|
5051
|
-
...conditions.length > 0 ? { preconditions: conditions } : {}
|
|
5052
|
-
|
|
5144
|
+
...conditions.length > 0 ? { preconditions: conditions } : {},
|
|
5145
|
+
location: rangeOf(call)
|
|
5146
|
+
},
|
|
5147
|
+
site: sites.siteOf(call, conditions)
|
|
5053
5148
|
};
|
|
5054
5149
|
});
|
|
5055
5150
|
}
|
|
5151
|
+
function sitesIn(body, nodes) {
|
|
5152
|
+
return (0, import_extractor2.statementSites)(nodes, {
|
|
5153
|
+
statementOf: (node) => enclosingStatement(node, body),
|
|
5154
|
+
lower: (statements) => lowerRubyBody(body, statements),
|
|
5155
|
+
firstLine: (node) => rangeOf(node).start
|
|
5156
|
+
});
|
|
5157
|
+
}
|
|
5158
|
+
function effectSitesIn(read, nodes) {
|
|
5159
|
+
if (read === null || nodes.length === 0) {
|
|
5160
|
+
return (node) => ({ line: rangeOf(node).start });
|
|
5161
|
+
}
|
|
5162
|
+
return sitesIn(read.body, nodes).plainSiteOf;
|
|
5163
|
+
}
|
|
5056
5164
|
|
|
5057
5165
|
// src/paths/predicates.ts
|
|
5058
5166
|
var OPERATORS = {
|
|
@@ -5439,15 +5547,10 @@ function raiseTerminal(call) {
|
|
|
5439
5547
|
}
|
|
5440
5548
|
function throughResponseHelpers(branches, sites, options) {
|
|
5441
5549
|
const handOffs = [];
|
|
5442
|
-
for (const { call,
|
|
5550
|
+
for (const { call, site } of sites) {
|
|
5443
5551
|
const helper = helperBranchesAt(call, options);
|
|
5444
5552
|
if (helper !== null) {
|
|
5445
|
-
handOffs.push({
|
|
5446
|
-
helper,
|
|
5447
|
-
preconditions: effect.preconditions,
|
|
5448
|
-
line: rangeOf(call).start,
|
|
5449
|
-
at: rangeOf(call)
|
|
5450
|
-
});
|
|
5553
|
+
handOffs.push({ ...site, helper, at: rangeOf(call) });
|
|
5451
5554
|
}
|
|
5452
5555
|
}
|
|
5453
5556
|
return handOffs.length === 0 ? [...branches] : branches.flatMap((branch) => (0, import_extractor3.splitAtHandOffs)(branch, handOffs));
|
|
@@ -5519,30 +5622,6 @@ var import_values11 = require("@suss/values");
|
|
|
5519
5622
|
var import_ir_core2 = require("@suss/ir-core");
|
|
5520
5623
|
var import_resolution8 = require("@suss/resolution");
|
|
5521
5624
|
|
|
5522
|
-
// src/baseClass.ts
|
|
5523
|
-
var import_resolution7 = require("@suss/resolution");
|
|
5524
|
-
function classBehind(facts, file, constant2) {
|
|
5525
|
-
const key = constant2.type === "constant" ? `${file}#${constant2.text}` : nodeId(file, constant2);
|
|
5526
|
-
const bound = new Set(
|
|
5527
|
-
facts.lookup("binds", 0, key).map((row) => String(row[1]))
|
|
5528
|
-
);
|
|
5529
|
-
return bound.size === 1 ? [...bound][0] : void 0;
|
|
5530
|
-
}
|
|
5531
|
-
function reachesBase(facts, classKey, bases) {
|
|
5532
|
-
(0, import_resolution7.askResolution)(facts, [classKey], "wantedAncestry", RUBY_PROGRAM);
|
|
5533
|
-
return facts.lookup("wantedBaseName", 0, classKey).some((row) => bases.includes(String(row[1])));
|
|
5534
|
-
}
|
|
5535
|
-
function enclosingClassKey(node, file) {
|
|
5536
|
-
let current = node.parent;
|
|
5537
|
-
while (current !== null) {
|
|
5538
|
-
if (NESTING_TYPES.has(current.type)) {
|
|
5539
|
-
return nodeId(file, current);
|
|
5540
|
-
}
|
|
5541
|
-
current = current.parent;
|
|
5542
|
-
}
|
|
5543
|
-
return null;
|
|
5544
|
-
}
|
|
5545
|
-
|
|
5546
5625
|
// src/loaders.ts
|
|
5547
5626
|
function receiverOf(node) {
|
|
5548
5627
|
return node.type === "call" ? field(node, "receiver") : null;
|
|
@@ -5686,7 +5765,8 @@ function effectOf(call, store, address, access) {
|
|
|
5686
5765
|
fields: access.fields,
|
|
5687
5766
|
operation,
|
|
5688
5767
|
...access.selector.length > 0 ? { selector: access.selector } : {}
|
|
5689
|
-
}
|
|
5768
|
+
},
|
|
5769
|
+
location: rangeOf(call)
|
|
5690
5770
|
};
|
|
5691
5771
|
}
|
|
5692
5772
|
function addressBehind(receiver, pattern, options, hops) {
|
|
@@ -5997,20 +6077,10 @@ function storageEffect(call, container, pattern, kind, selector, fields) {
|
|
|
5997
6077
|
fields,
|
|
5998
6078
|
operation,
|
|
5999
6079
|
...selector.length > 0 ? { selector } : {}
|
|
6000
|
-
}
|
|
6080
|
+
},
|
|
6081
|
+
location: rangeOf(call)
|
|
6001
6082
|
};
|
|
6002
6083
|
}
|
|
6003
|
-
function classSettledOn(facts, key) {
|
|
6004
|
-
(0, import_resolution8.askResolution)(facts, [key], "wanted", RUBY_PROGRAM);
|
|
6005
|
-
const objects = (0, import_resolution8.answersFor)(facts, "wantedObjectOf", key);
|
|
6006
|
-
return objects.length === 1 ? objects[0] : void 0;
|
|
6007
|
-
}
|
|
6008
|
-
function declaredName(facts, classKey) {
|
|
6009
|
-
const names = new Set(
|
|
6010
|
-
facts.lookup("rbConstantName", 0, classKey).map((row) => String(row[1]))
|
|
6011
|
-
);
|
|
6012
|
-
return names.size === 1 ? [...names][0] : void 0;
|
|
6013
|
-
}
|
|
6014
6084
|
function projectDeclares(facts, classKey, method) {
|
|
6015
6085
|
const spellings = /* @__PURE__ */ new Set([method, (0, import_resolution8.classMemberName)(method)]);
|
|
6016
6086
|
return facts.lookup("wantedDeclaredName", 0, classKey).some((row) => spellings.has(String(row[1])));
|
|
@@ -6067,12 +6137,13 @@ function callbacksRunBy(facts, classKey, pattern, writeMethod) {
|
|
|
6067
6137
|
}
|
|
6068
6138
|
return [...found.values()];
|
|
6069
6139
|
}
|
|
6070
|
-
function callbackEffect(callback) {
|
|
6140
|
+
function callbackEffect(callback, write) {
|
|
6071
6141
|
return {
|
|
6072
6142
|
type: "invocation",
|
|
6073
6143
|
callee: callback.name,
|
|
6074
6144
|
args: [],
|
|
6075
|
-
async: false
|
|
6145
|
+
async: false,
|
|
6146
|
+
location: rangeOf(write)
|
|
6076
6147
|
};
|
|
6077
6148
|
}
|
|
6078
6149
|
function modelCallEffects(call, file, options, enclosing) {
|
|
@@ -6111,7 +6182,7 @@ function modelCallEffects(call, file, options, enclosing) {
|
|
|
6111
6182
|
options.statesSlots(access, slots);
|
|
6112
6183
|
}
|
|
6113
6184
|
}
|
|
6114
|
-
return [access, ...ran.map(callbackEffect)];
|
|
6185
|
+
return [access, ...ran.map((callback) => callbackEffect(callback, worked))];
|
|
6115
6186
|
}
|
|
6116
6187
|
return [];
|
|
6117
6188
|
}
|
|
@@ -6249,11 +6320,12 @@ function storageEffects(calls, file, options, enclosing = null) {
|
|
|
6249
6320
|
"wanted",
|
|
6250
6321
|
RUBY_PROGRAM
|
|
6251
6322
|
);
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6323
|
+
return chains.flatMap(
|
|
6324
|
+
(call) => effectsOfCall(call, file, options, enclosing).map((effect) => ({
|
|
6325
|
+
effect,
|
|
6326
|
+
at: call
|
|
6327
|
+
}))
|
|
6328
|
+
);
|
|
6257
6329
|
}
|
|
6258
6330
|
|
|
6259
6331
|
// src/provenance.ts
|
|
@@ -6642,13 +6714,13 @@ function readingOfCall(call, declaration, names, options) {
|
|
|
6642
6714
|
}
|
|
6643
6715
|
return (0, import_extractor6.writtenReading)(status, rangeOf(argument));
|
|
6644
6716
|
}
|
|
6645
|
-
function
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6717
|
+
function withEffectsThatRun(branch, body) {
|
|
6718
|
+
const extra = (0, import_extractor6.effectsFiringOn)(body.extraEffects ?? [], branch);
|
|
6719
|
+
return {
|
|
6720
|
+
...branch,
|
|
6721
|
+
effects: (0, import_extractor6.effectsFiringOn)(body.effects, branch),
|
|
6722
|
+
...extra.length === 0 ? {} : { extraEffects: extra }
|
|
6723
|
+
};
|
|
6652
6724
|
}
|
|
6653
6725
|
function conditionOf(condition, inputs) {
|
|
6654
6726
|
return {
|
|
@@ -6708,57 +6780,66 @@ function helperResponse(helper, pattern, facts, boundStatuses = /* @__PURE__ */
|
|
|
6708
6780
|
rangeOf(helper)
|
|
6709
6781
|
);
|
|
6710
6782
|
}
|
|
6711
|
-
function branchOf(outcome, pattern,
|
|
6783
|
+
function branchOf(outcome, pattern, body, options) {
|
|
6712
6784
|
if (outcome.fellThrough === true && options.fallthrough === "handOn") {
|
|
6713
|
-
return handsOnBranch(outcome,
|
|
6785
|
+
return handsOnBranch(outcome, body);
|
|
6714
6786
|
}
|
|
6715
|
-
return
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
|
|
6731
|
-
|
|
6787
|
+
return withEffectsThatRun(
|
|
6788
|
+
{
|
|
6789
|
+
conditions: outcome.conditions,
|
|
6790
|
+
terminal: {
|
|
6791
|
+
kind: "response",
|
|
6792
|
+
statusCode: null,
|
|
6793
|
+
body: null,
|
|
6794
|
+
exceptionType: null,
|
|
6795
|
+
message: null,
|
|
6796
|
+
component: null,
|
|
6797
|
+
renderTree: null,
|
|
6798
|
+
delegateTarget: null,
|
|
6799
|
+
emitEvent: null,
|
|
6800
|
+
location: outcome.location
|
|
6801
|
+
},
|
|
6802
|
+
statusCodeReading: {
|
|
6803
|
+
reading: outcome.reading,
|
|
6804
|
+
libraryDefault: pattern.defaultStatusCode
|
|
6805
|
+
},
|
|
6806
|
+
...outcome.body === void 0 ? {} : { bodyShapeReading: { reading: outcome.body } },
|
|
6807
|
+
effects: [],
|
|
6808
|
+
location: outcome.location,
|
|
6809
|
+
...loopAroundOf(outcome),
|
|
6810
|
+
isDefault: outcome.conditions.length === 0
|
|
6732
6811
|
},
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
...extraEffects === void 0 ? {} : { extraEffects },
|
|
6736
|
-
location: outcome.location,
|
|
6737
|
-
isDefault: outcome.conditions.length === 0
|
|
6738
|
-
};
|
|
6812
|
+
body
|
|
6813
|
+
);
|
|
6739
6814
|
}
|
|
6740
|
-
function handsOnBranch(outcome,
|
|
6741
|
-
return
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
|
|
6750
|
-
|
|
6751
|
-
|
|
6752
|
-
|
|
6753
|
-
|
|
6815
|
+
function handsOnBranch(outcome, body) {
|
|
6816
|
+
return withEffectsThatRun(
|
|
6817
|
+
{
|
|
6818
|
+
conditions: outcome.conditions,
|
|
6819
|
+
terminal: {
|
|
6820
|
+
kind: "delegate",
|
|
6821
|
+
statusCode: null,
|
|
6822
|
+
body: null,
|
|
6823
|
+
exceptionType: null,
|
|
6824
|
+
message: null,
|
|
6825
|
+
component: null,
|
|
6826
|
+
renderTree: null,
|
|
6827
|
+
delegateTarget: null,
|
|
6828
|
+
emitEvent: null,
|
|
6829
|
+
location: outcome.location
|
|
6830
|
+
},
|
|
6831
|
+
effects: [],
|
|
6832
|
+
location: outcome.location,
|
|
6833
|
+
...loopAroundOf(outcome),
|
|
6834
|
+
isDefault: outcome.conditions.length === 0
|
|
6754
6835
|
},
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
location: outcome.location,
|
|
6758
|
-
isDefault: outcome.conditions.length === 0
|
|
6759
|
-
};
|
|
6836
|
+
body
|
|
6837
|
+
);
|
|
6760
6838
|
}
|
|
6761
|
-
function
|
|
6839
|
+
function loopAroundOf(placed) {
|
|
6840
|
+
return placed.loopAround === void 0 ? {} : { loopAround: placed.loopAround };
|
|
6841
|
+
}
|
|
6842
|
+
function returnPathBranches(method, effects, exits = [], facts, keepsArms, raises2 = [], endingOfReturn = (_statement, location) => returnTerminal(location)) {
|
|
6762
6843
|
const body = field(method, "body");
|
|
6763
6844
|
if (body === null) {
|
|
6764
6845
|
return null;
|
|
@@ -6785,30 +6866,42 @@ function returnPathBranches(method, effects, exits = [], facts, keepsArms, raise
|
|
|
6785
6866
|
facts
|
|
6786
6867
|
);
|
|
6787
6868
|
const branches = [];
|
|
6788
|
-
const push = (paths, terminal) => {
|
|
6869
|
+
const push = (paths, terminal, at) => {
|
|
6870
|
+
const placement = at === null ? void 0 : enumerated.placement.get(at);
|
|
6789
6871
|
for (const path7 of paths) {
|
|
6790
6872
|
const conditions = path7.map(
|
|
6791
6873
|
(condition) => conditionOf(condition, inputs)
|
|
6792
6874
|
);
|
|
6793
|
-
branches.push(
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
6799
|
-
|
|
6875
|
+
branches.push(
|
|
6876
|
+
withEffectsThatRun(
|
|
6877
|
+
{
|
|
6878
|
+
conditions,
|
|
6879
|
+
terminal,
|
|
6880
|
+
effects: [],
|
|
6881
|
+
location: terminal.location,
|
|
6882
|
+
...loopAroundOf({ loopAround: placement?.loopAround }),
|
|
6883
|
+
isDefault: conditions.length === 0
|
|
6884
|
+
},
|
|
6885
|
+
{ effects }
|
|
6886
|
+
)
|
|
6887
|
+
);
|
|
6800
6888
|
}
|
|
6801
6889
|
};
|
|
6802
6890
|
for (const statement of returns) {
|
|
6803
6891
|
push(
|
|
6804
6892
|
enumerated.byTerminal.get(statement) ?? [],
|
|
6805
|
-
|
|
6893
|
+
endingOfReturn(statement, rangeOf(statement)),
|
|
6894
|
+
statement
|
|
6806
6895
|
);
|
|
6807
6896
|
}
|
|
6808
6897
|
for (const ending of [...exits, ...raises2]) {
|
|
6809
|
-
push(
|
|
6898
|
+
push(
|
|
6899
|
+
enumerated.byTerminal.get(ending.call) ?? [],
|
|
6900
|
+
ending.terminal,
|
|
6901
|
+
ending.call
|
|
6902
|
+
);
|
|
6810
6903
|
}
|
|
6811
|
-
push(enumerated.fallthrough,
|
|
6904
|
+
push(enumerated.fallthrough, endingOfReturn(null, rangeOf(method)), null);
|
|
6812
6905
|
return branches.length === 0 ? null : branches;
|
|
6813
6906
|
}
|
|
6814
6907
|
function returnTerminal(location) {
|
|
@@ -6868,12 +6961,14 @@ function responseBranches(method, pattern, effects, extraEffects, options = {})
|
|
|
6868
6961
|
const responder = responderOf(terminal, responders);
|
|
6869
6962
|
const reading = responder === void 0 ? import_extractor6.absentReading : readingOfResponder(terminal, responder, statusNames, options);
|
|
6870
6963
|
const body2 = responder?.kind === "declared" ? bodyReadingOfCall(terminal, responder.declaration, options.facts) : void 0;
|
|
6964
|
+
const loopAround = enumerated.placement.get(terminal)?.loopAround;
|
|
6871
6965
|
for (const path7 of enumerated.byTerminal.get(terminal) ?? []) {
|
|
6872
6966
|
outcomes.push({
|
|
6873
6967
|
conditions: conditionsOf(path7),
|
|
6874
6968
|
reading,
|
|
6875
6969
|
...body2 === void 0 ? {} : { body: body2 },
|
|
6876
6970
|
location: rangeOf(terminal),
|
|
6971
|
+
loopAround,
|
|
6877
6972
|
// A bare `return` wrote no response, so a filter that takes it
|
|
6878
6973
|
// hands the request on the same as one that reaches its end.
|
|
6879
6974
|
...responder === void 0 ? { fellThrough: true } : {}
|
|
@@ -6889,6 +6984,7 @@ function responseBranches(method, pattern, effects, extraEffects, options = {})
|
|
|
6889
6984
|
});
|
|
6890
6985
|
}
|
|
6891
6986
|
const read = options.raises;
|
|
6987
|
+
const placed = { effects, extraEffects };
|
|
6892
6988
|
const raised = raises2.flatMap((call) => {
|
|
6893
6989
|
const terminal = raisedTerminal(
|
|
6894
6990
|
pattern,
|
|
@@ -6896,25 +6992,26 @@ function responseBranches(method, pattern, effects, extraEffects, options = {})
|
|
|
6896
6992
|
read?.handlers ?? [],
|
|
6897
6993
|
rangeOf(call)
|
|
6898
6994
|
);
|
|
6899
|
-
|
|
6900
|
-
|
|
6901
|
-
|
|
6902
|
-
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6995
|
+
const loopAround = enumerated.placement.get(call)?.loopAround;
|
|
6996
|
+
return (enumerated.byTerminal.get(call) ?? []).map(
|
|
6997
|
+
(path7) => withEffectsThatRun(
|
|
6998
|
+
{
|
|
6999
|
+
conditions: conditionsOf(path7),
|
|
7000
|
+
terminal,
|
|
7001
|
+
effects: [],
|
|
7002
|
+
location: terminal.location,
|
|
7003
|
+
...loopAroundOf({ loopAround }),
|
|
7004
|
+
isDefault: false
|
|
7005
|
+
},
|
|
7006
|
+
placed
|
|
7007
|
+
)
|
|
7008
|
+
);
|
|
6910
7009
|
});
|
|
6911
7010
|
if (outcomes.length === 0 && raised.length === 0) {
|
|
6912
7011
|
return null;
|
|
6913
7012
|
}
|
|
6914
7013
|
return [
|
|
6915
|
-
...outcomes.map(
|
|
6916
|
-
(outcome) => branchOf(outcome, pattern, effects, extraEffects, options)
|
|
6917
|
-
),
|
|
7014
|
+
...outcomes.map((outcome) => branchOf(outcome, pattern, placed, options)),
|
|
6918
7015
|
...raised
|
|
6919
7016
|
];
|
|
6920
7017
|
}
|
|
@@ -7182,7 +7279,7 @@ function callerBranches(method, reading) {
|
|
|
7182
7279
|
const keepsArms = (condition) => (0, import_behavioral_ir2.testsStatus)(predicateOf(condition), reading.statusMembers);
|
|
7183
7280
|
const found = returnPathBranches(
|
|
7184
7281
|
method,
|
|
7185
|
-
|
|
7282
|
+
sites,
|
|
7186
7283
|
[],
|
|
7187
7284
|
reading.facts,
|
|
7188
7285
|
keepsArms,
|
|
@@ -7641,7 +7738,7 @@ function envReadEffects(root, facts) {
|
|
|
7641
7738
|
at: (node) => {
|
|
7642
7739
|
const read = envReadAt(node);
|
|
7643
7740
|
if (read !== null) {
|
|
7644
|
-
slots.push({ read });
|
|
7741
|
+
slots.push({ read, at: node });
|
|
7645
7742
|
return;
|
|
7646
7743
|
}
|
|
7647
7744
|
if (helpers !== null && node.type === "call") {
|
|
@@ -7654,9 +7751,12 @@ function envReadEffects(root, facts) {
|
|
|
7654
7751
|
const throughHelpers = helpers === null ? new NodeMap() : helperReads(calls, helpers);
|
|
7655
7752
|
return slots.flatMap((slot) => {
|
|
7656
7753
|
if ("read" in slot) {
|
|
7657
|
-
return [configReadEffect(slot.read)];
|
|
7754
|
+
return [{ effect: configReadEffect(slot.read, slot.at), at: slot.at }];
|
|
7658
7755
|
}
|
|
7659
|
-
return (throughHelpers.get(slot.call) ?? []).map(
|
|
7756
|
+
return (throughHelpers.get(slot.call) ?? []).map((read) => ({
|
|
7757
|
+
effect: configReadEffect(read, slot.call),
|
|
7758
|
+
at: slot.call
|
|
7759
|
+
}));
|
|
7660
7760
|
});
|
|
7661
7761
|
}
|
|
7662
7762
|
function helperFactsOf(facts) {
|
|
@@ -7812,16 +7912,17 @@ function readsAtCall(db, call, args) {
|
|
|
7812
7912
|
}
|
|
7813
7913
|
return [...byName].map(([name, defaulted]) => ({ name, defaulted }));
|
|
7814
7914
|
}
|
|
7815
|
-
function configReadEffect(read) {
|
|
7915
|
+
function configReadEffect(read, at) {
|
|
7816
7916
|
return {
|
|
7817
7917
|
type: "interaction",
|
|
7818
7918
|
binding: (0, import_behavioral_ir3.runtimeConfigBinding)({ recognition: RUBY_ENV_RECOGNITION }),
|
|
7819
|
-
callee: `ENV["${read.name}"]`,
|
|
7919
|
+
callee: read.name === null ? at.text : `ENV["${read.name}"]`,
|
|
7820
7920
|
interaction: {
|
|
7821
7921
|
class: "config-read",
|
|
7822
7922
|
name: read.name,
|
|
7823
7923
|
defaulted: read.defaulted
|
|
7824
|
-
}
|
|
7924
|
+
},
|
|
7925
|
+
location: rangeOf(at)
|
|
7825
7926
|
};
|
|
7826
7927
|
}
|
|
7827
7928
|
function envReadAt(node) {
|
|
@@ -7829,8 +7930,7 @@ function envReadAt(node) {
|
|
|
7829
7930
|
if (site === null) {
|
|
7830
7931
|
return null;
|
|
7831
7932
|
}
|
|
7832
|
-
|
|
7833
|
-
return name === null ? null : { name, defaulted: site.defaulted };
|
|
7933
|
+
return { name: stringLiteralValue(site.name), defaulted: site.defaulted };
|
|
7834
7934
|
}
|
|
7835
7935
|
function envSiteAt(node) {
|
|
7836
7936
|
const spelling = envSpellingAt(node);
|
|
@@ -8026,25 +8126,27 @@ function filterUnit(filter, pattern, displayPath, body, reading = {}) {
|
|
|
8026
8126
|
};
|
|
8027
8127
|
}
|
|
8028
8128
|
function handsOn(range, body) {
|
|
8029
|
-
return
|
|
8030
|
-
|
|
8031
|
-
|
|
8032
|
-
|
|
8033
|
-
|
|
8034
|
-
|
|
8035
|
-
|
|
8036
|
-
|
|
8037
|
-
|
|
8038
|
-
|
|
8039
|
-
|
|
8040
|
-
|
|
8041
|
-
|
|
8129
|
+
return withEffectsThatRun(
|
|
8130
|
+
{
|
|
8131
|
+
conditions: [],
|
|
8132
|
+
terminal: {
|
|
8133
|
+
kind: "delegate",
|
|
8134
|
+
statusCode: null,
|
|
8135
|
+
body: null,
|
|
8136
|
+
exceptionType: null,
|
|
8137
|
+
message: null,
|
|
8138
|
+
component: null,
|
|
8139
|
+
renderTree: null,
|
|
8140
|
+
delegateTarget: null,
|
|
8141
|
+
emitEvent: null,
|
|
8142
|
+
location: range
|
|
8143
|
+
},
|
|
8144
|
+
effects: [],
|
|
8145
|
+
location: range,
|
|
8146
|
+
isDefault: true
|
|
8042
8147
|
},
|
|
8043
|
-
effects: body.effects ?? [],
|
|
8044
|
-
|
|
8045
|
-
location: range,
|
|
8046
|
-
isDefault: true
|
|
8047
|
-
};
|
|
8148
|
+
{ effects: body.effects ?? [], extraEffects: body.extraEffects }
|
|
8149
|
+
);
|
|
8048
8150
|
}
|
|
8049
8151
|
function calledName(statement) {
|
|
8050
8152
|
if (statement.type !== "call" || field(statement, "receiver") !== null) {
|
|
@@ -8181,35 +8283,206 @@ function actionsUnder(node, facts) {
|
|
|
8181
8283
|
return found === null ? null : new Set(found);
|
|
8182
8284
|
}
|
|
8183
8285
|
|
|
8184
|
-
// src/
|
|
8185
|
-
var import_behavioral_ir4 = require("@suss/behavioral-ir");
|
|
8286
|
+
// src/resolverHooks.ts
|
|
8186
8287
|
var import_extractor8 = require("@suss/extractor");
|
|
8187
|
-
var
|
|
8188
|
-
|
|
8189
|
-
[
|
|
8190
|
-
[
|
|
8191
|
-
|
|
8192
|
-
|
|
8193
|
-
|
|
8194
|
-
|
|
8195
|
-
|
|
8196
|
-
|
|
8197
|
-
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
|
|
8201
|
-
|
|
8202
|
-
|
|
8203
|
-
|
|
8204
|
-
|
|
8205
|
-
|
|
8206
|
-
|
|
8207
|
-
|
|
8208
|
-
|
|
8209
|
-
|
|
8210
|
-
|
|
8211
|
-
|
|
8212
|
-
|
|
8288
|
+
var import_values17 = require("@suss/values");
|
|
8289
|
+
function hooksRun(ancestry, hooks, read) {
|
|
8290
|
+
const definitions = [];
|
|
8291
|
+
const unsettled = [];
|
|
8292
|
+
for (const name of hooks.methods) {
|
|
8293
|
+
const found = definitionsRun(ancestry, name, read);
|
|
8294
|
+
definitions.push(...found.definitions);
|
|
8295
|
+
if (found.unsettled !== null) {
|
|
8296
|
+
unsettled.push({ name, reason: found.unsettled });
|
|
8297
|
+
}
|
|
8298
|
+
}
|
|
8299
|
+
return { definitions, unsettled };
|
|
8300
|
+
}
|
|
8301
|
+
function definitionsRun(ancestry, name, read) {
|
|
8302
|
+
const definitions = [];
|
|
8303
|
+
let rest = ancestry;
|
|
8304
|
+
while (rest.length > 0) {
|
|
8305
|
+
const lookup = methodInAncestry(rest, name, read);
|
|
8306
|
+
if (lookup.type !== "found") {
|
|
8307
|
+
return { definitions, unsettled: unsettledReason(lookup) };
|
|
8308
|
+
}
|
|
8309
|
+
definitions.push({ name, method: lookup.method, block: lookup.block });
|
|
8310
|
+
if (!callsSuper(lookup.method)) {
|
|
8311
|
+
break;
|
|
8312
|
+
}
|
|
8313
|
+
const at = rest.findIndex(
|
|
8314
|
+
(entry) => entry.type === "bodies" && entry.blocks.includes(lookup.block)
|
|
8315
|
+
);
|
|
8316
|
+
rest = rest.slice(Math.max(at, 0) + 1);
|
|
8317
|
+
}
|
|
8318
|
+
return { definitions, unsettled: null };
|
|
8319
|
+
}
|
|
8320
|
+
function unsettledReason(lookup) {
|
|
8321
|
+
if (lookup.type !== "unsettled") {
|
|
8322
|
+
return null;
|
|
8323
|
+
}
|
|
8324
|
+
return lookup.cause === "dynamicDefine" || lookup.definedLater === true ? lookup.reason : null;
|
|
8325
|
+
}
|
|
8326
|
+
function callsSuper(method) {
|
|
8327
|
+
let found = false;
|
|
8328
|
+
(0, import_extractor8.walkDescendants)(method, null, children, {
|
|
8329
|
+
at: (node) => {
|
|
8330
|
+
found ||= isSuper(node);
|
|
8331
|
+
},
|
|
8332
|
+
into: (node) => node !== method && METHOD_TYPES.has(node.type) ? import_extractor8.SKIP_CHILDREN : null
|
|
8333
|
+
});
|
|
8334
|
+
return found;
|
|
8335
|
+
}
|
|
8336
|
+
function isSuper(node) {
|
|
8337
|
+
return node.type === "super" || node.type === "call" && field(node, "method")?.type === "super";
|
|
8338
|
+
}
|
|
8339
|
+
function hookUnit(hook, input) {
|
|
8340
|
+
const { body, facts } = input;
|
|
8341
|
+
const range = rangeOf(hook.method);
|
|
8342
|
+
const effects = body.effects ?? [];
|
|
8343
|
+
const branches = (returnPathBranches(
|
|
8344
|
+
hook.method,
|
|
8345
|
+
effects,
|
|
8346
|
+
[],
|
|
8347
|
+
facts,
|
|
8348
|
+
void 0,
|
|
8349
|
+
raiseEndings(hook.method),
|
|
8350
|
+
(statement, location) => hookEnding(hook.method, statement, location, input)
|
|
8351
|
+
) ?? [emptyBodyBranch(range)]).map(
|
|
8352
|
+
(branch) => withEffectsThatRun(branch, {
|
|
8353
|
+
effects,
|
|
8354
|
+
extraEffects: body.extraEffects
|
|
8355
|
+
})
|
|
8356
|
+
);
|
|
8357
|
+
return {
|
|
8358
|
+
identity: {
|
|
8359
|
+
name: hook.name,
|
|
8360
|
+
nameKind: "binding",
|
|
8361
|
+
kind: "middleware",
|
|
8362
|
+
file: input.displayPath,
|
|
8363
|
+
range,
|
|
8364
|
+
span: spanOf(hook.method),
|
|
8365
|
+
exportName: hook.name,
|
|
8366
|
+
exportPath: [hook.block.info.qualifiedName, hook.name]
|
|
8367
|
+
},
|
|
8368
|
+
boundaryBinding: null,
|
|
8369
|
+
parameters: [],
|
|
8370
|
+
branches: withSlotSources(branches, body.provenance),
|
|
8371
|
+
bodyContent: body.bodyContent ?? "absent",
|
|
8372
|
+
dependencyCalls: [],
|
|
8373
|
+
declaredContract: null
|
|
8374
|
+
};
|
|
8375
|
+
}
|
|
8376
|
+
function hookReference(hook, displayPath) {
|
|
8377
|
+
return {
|
|
8378
|
+
file: displayPath,
|
|
8379
|
+
name: hook.name,
|
|
8380
|
+
line: rangeOf(hook.method).start
|
|
8381
|
+
};
|
|
8382
|
+
}
|
|
8383
|
+
function unsettledHookReading(className, unsettled, range) {
|
|
8384
|
+
return (0, import_extractor8.unreadableReading)(
|
|
8385
|
+
`This field's ${className} could be stopped by a ${unsettled.name} hook ${unsettled.reason}, so whether one runs was not settled here`,
|
|
8386
|
+
range
|
|
8387
|
+
);
|
|
8388
|
+
}
|
|
8389
|
+
function hookEnding(method, statement, location, input) {
|
|
8390
|
+
const values = statement === null ? lastStatement(method) : returnedValues(statement);
|
|
8391
|
+
return stopsTheField(values, input) ? endingTerminal("return", location) : goOn(location);
|
|
8392
|
+
}
|
|
8393
|
+
function lastStatement(method) {
|
|
8394
|
+
const body = field(method, "body");
|
|
8395
|
+
const last = body === null ? void 0 : bodyStatements(body).at(-1);
|
|
8396
|
+
return last === void 0 ? [] : [last];
|
|
8397
|
+
}
|
|
8398
|
+
function returnedValues(statement) {
|
|
8399
|
+
const list = children(statement)[0];
|
|
8400
|
+
if (list === void 0) {
|
|
8401
|
+
return [];
|
|
8402
|
+
}
|
|
8403
|
+
return list.type === "argument_list" ? children(list) : [list];
|
|
8404
|
+
}
|
|
8405
|
+
function stopsTheField(values, input) {
|
|
8406
|
+
const first = values[0];
|
|
8407
|
+
if (first === void 0) {
|
|
8408
|
+
return true;
|
|
8409
|
+
}
|
|
8410
|
+
const listHead = input.hooks.answerIsListHead === true;
|
|
8411
|
+
if (values.length > 1) {
|
|
8412
|
+
return listHead && isFalsy(evaluatedValue(first, input.facts));
|
|
8413
|
+
}
|
|
8414
|
+
const value = evaluatedValue(first, input.facts);
|
|
8415
|
+
if (value.kind !== "sequence") {
|
|
8416
|
+
return isFalsy(value);
|
|
8417
|
+
}
|
|
8418
|
+
const head = value.items[0];
|
|
8419
|
+
return listHead && head !== void 0 && isFalsy(head.value);
|
|
8420
|
+
}
|
|
8421
|
+
function isFalsy(value) {
|
|
8422
|
+
const settled = (0, import_values17.constantOf)(value);
|
|
8423
|
+
return settled === false || settled === null;
|
|
8424
|
+
}
|
|
8425
|
+
function emptyBodyBranch(location) {
|
|
8426
|
+
return {
|
|
8427
|
+
conditions: [],
|
|
8428
|
+
terminal: endingTerminal("return", location),
|
|
8429
|
+
effects: [],
|
|
8430
|
+
location,
|
|
8431
|
+
isDefault: true
|
|
8432
|
+
};
|
|
8433
|
+
}
|
|
8434
|
+
function goOn(location) {
|
|
8435
|
+
return endingTerminal("delegate", location);
|
|
8436
|
+
}
|
|
8437
|
+
function endingTerminal(kind, location) {
|
|
8438
|
+
return {
|
|
8439
|
+
kind,
|
|
8440
|
+
statusCode: null,
|
|
8441
|
+
body: null,
|
|
8442
|
+
exceptionType: null,
|
|
8443
|
+
message: null,
|
|
8444
|
+
component: null,
|
|
8445
|
+
renderTree: null,
|
|
8446
|
+
delegateTarget: null,
|
|
8447
|
+
emitEvent: null,
|
|
8448
|
+
location
|
|
8449
|
+
};
|
|
8450
|
+
}
|
|
8451
|
+
|
|
8452
|
+
// src/streamWrites.ts
|
|
8453
|
+
var import_behavioral_ir4 = require("@suss/behavioral-ir");
|
|
8454
|
+
var import_extractor9 = require("@suss/extractor");
|
|
8455
|
+
var RUBY_STREAM_RECOGNITION = "ruby-stdlib";
|
|
8456
|
+
var KERNEL_WRITES = /* @__PURE__ */ new Map([
|
|
8457
|
+
["puts", "stdout"],
|
|
8458
|
+
["print", "stdout"],
|
|
8459
|
+
["warn", "stderr"],
|
|
8460
|
+
["abort", "stderr"]
|
|
8461
|
+
]);
|
|
8462
|
+
var STREAM_RECEIVERS = /* @__PURE__ */ new Map([
|
|
8463
|
+
["$stdout", "stdout"],
|
|
8464
|
+
["STDOUT", "stdout"],
|
|
8465
|
+
["$stderr", "stderr"],
|
|
8466
|
+
["STDERR", "stderr"]
|
|
8467
|
+
]);
|
|
8468
|
+
var STREAM_METHODS = /* @__PURE__ */ new Set(["puts", "print", "write", "<<"]);
|
|
8469
|
+
var DEFERRED_BODY_TYPES2 = /* @__PURE__ */ new Set(["method", "singleton_method", "lambda"]);
|
|
8470
|
+
function streamWriteEffects(root) {
|
|
8471
|
+
return (0, import_extractor9.numberRepeatedCallSites)(
|
|
8472
|
+
writesUnder2(root).map((write) => [write])
|
|
8473
|
+
).flat();
|
|
8474
|
+
}
|
|
8475
|
+
function writesUnder2(root) {
|
|
8476
|
+
const found = [];
|
|
8477
|
+
(0, import_extractor9.walkDescendants)(root, null, children, {
|
|
8478
|
+
at: (node) => {
|
|
8479
|
+
const write = node.type === "call" ? streamWriteAt(node) : null;
|
|
8480
|
+
if (write !== null) {
|
|
8481
|
+
found.push({ effect: write, at: node });
|
|
8482
|
+
}
|
|
8483
|
+
},
|
|
8484
|
+
into: (node) => DEFERRED_BODY_TYPES2.has(node.type) ? import_extractor9.SKIP_CHILDREN : null
|
|
8485
|
+
});
|
|
8213
8486
|
return found;
|
|
8214
8487
|
}
|
|
8215
8488
|
function streamWrittenBy(call) {
|
|
@@ -8237,13 +8510,14 @@ function streamWriteAt(call) {
|
|
|
8237
8510
|
function writeEffect(call, target, args) {
|
|
8238
8511
|
const receiver = field(call, "receiver");
|
|
8239
8512
|
const method = field(call, "method")?.text ?? "";
|
|
8240
|
-
|
|
8513
|
+
const effect = {
|
|
8241
8514
|
type: "interaction",
|
|
8242
8515
|
binding: (0, import_behavioral_ir4.ioBinding)({ recognition: RUBY_STREAM_RECOGNITION, target }),
|
|
8243
8516
|
callee: receiver === null ? method : `${receiver.text}.${method}`,
|
|
8244
|
-
|
|
8245
|
-
|
|
8517
|
+
interaction: { class: "stream-write", ...payloadOf(args) },
|
|
8518
|
+
location: rangeOf(call)
|
|
8246
8519
|
};
|
|
8520
|
+
return { ...effect, groupId: (0, import_extractor9.callSiteKey)(effect) };
|
|
8247
8521
|
}
|
|
8248
8522
|
function payloadOf(args) {
|
|
8249
8523
|
const only = args[0];
|
|
@@ -8321,9 +8595,9 @@ function keyName(key) {
|
|
|
8321
8595
|
|
|
8322
8596
|
// src/testCases.ts
|
|
8323
8597
|
var import_behavioral_ir5 = require("@suss/behavioral-ir");
|
|
8324
|
-
var
|
|
8598
|
+
var import_extractor10 = require("@suss/extractor");
|
|
8325
8599
|
var import_resolution10 = require("@suss/resolution");
|
|
8326
|
-
var
|
|
8600
|
+
var import_values18 = require("@suss/values");
|
|
8327
8601
|
var BLOCK_TYPES6 = /* @__PURE__ */ new Set(["block", "do_block"]);
|
|
8328
8602
|
function testPatternsIn(packs) {
|
|
8329
8603
|
return packs.flatMap((pack) => pack.tests ?? []);
|
|
@@ -8507,7 +8781,7 @@ function groupStatements(group) {
|
|
|
8507
8781
|
}
|
|
8508
8782
|
function patternForFile(file, patterns) {
|
|
8509
8783
|
return patterns.find(
|
|
8510
|
-
(pattern) => (0,
|
|
8784
|
+
(pattern) => (0, import_extractor10.matchesTestFileName)(file, pattern.filePatterns) && (0, import_extractor10.isListedTestFile)(file, pattern.files)
|
|
8511
8785
|
) ?? null;
|
|
8512
8786
|
}
|
|
8513
8787
|
function groupNamesIn(pattern) {
|
|
@@ -8799,7 +9073,7 @@ function exampleCalls(run, inherited) {
|
|
|
8799
9073
|
}
|
|
8800
9074
|
function testCaseUnits(root, patterns, options) {
|
|
8801
9075
|
return patterns.flatMap((pattern) => {
|
|
8802
|
-
if (!(0,
|
|
9076
|
+
if (!(0, import_extractor10.matchesTestFileName)(options.absoluteFile, pattern.filePatterns) || !(0, import_extractor10.isListedTestFile)(options.absoluteFile, pattern.files)) {
|
|
8803
9077
|
return [];
|
|
8804
9078
|
}
|
|
8805
9079
|
return examplesIn(root, options.absoluteFile, pattern, options.shared).map(
|
|
@@ -8918,7 +9192,7 @@ function titleOf(call, facts) {
|
|
|
8918
9192
|
if (first.type === "constant" || first.type === "scope_resolution") {
|
|
8919
9193
|
return { text: first.text, unresolved: false };
|
|
8920
9194
|
}
|
|
8921
|
-
const read = (0,
|
|
9195
|
+
const read = (0, import_values18.literalOf)(evaluatedValue(first, facts));
|
|
8922
9196
|
return read === null ? { text: first.text, unresolved: true } : { text: read, unresolved: false };
|
|
8923
9197
|
}
|
|
8924
9198
|
function isSkipped(example, pattern) {
|
|
@@ -9059,7 +9333,7 @@ function moduleOfConstant(node, options) {
|
|
|
9059
9333
|
const key = classBehind(facts, options.absoluteFile, node);
|
|
9060
9334
|
return key === void 0 ? null : options.displayPathOf((0, import_resolution10.fileOfKey)(key));
|
|
9061
9335
|
}
|
|
9062
|
-
const name = (0,
|
|
9336
|
+
const name = (0, import_values18.literalOf)(evaluatedValue(node, facts));
|
|
9063
9337
|
const keys = name === null ? [] : facts.lookup("rbConstantName", 1, name.replace(/^::/, "")).map((row) => String(row[0]));
|
|
9064
9338
|
const files = [...new Set(keys.map(import_resolution10.fileOfKey))];
|
|
9065
9339
|
return files.length === 1 ? options.displayPathOf(files[0]) : null;
|
|
@@ -9069,8 +9343,8 @@ function oneLine(text3) {
|
|
|
9069
9343
|
}
|
|
9070
9344
|
|
|
9071
9345
|
// src/testClasses.ts
|
|
9072
|
-
var
|
|
9073
|
-
var
|
|
9346
|
+
var import_extractor11 = require("@suss/extractor");
|
|
9347
|
+
var import_values20 = require("@suss/values");
|
|
9074
9348
|
var BLOCK_TYPES7 = /* @__PURE__ */ new Set(["block", "do_block"]);
|
|
9075
9349
|
function testClassPatternsIn(packs) {
|
|
9076
9350
|
return packs.flatMap((pack) => pack.testClasses ?? []);
|
|
@@ -9113,7 +9387,7 @@ function testClassUnits(root, patterns, options) {
|
|
|
9113
9387
|
});
|
|
9114
9388
|
}
|
|
9115
9389
|
function readsFile(file, pattern) {
|
|
9116
|
-
return (0,
|
|
9390
|
+
return (0, import_extractor11.matchesTestFileName)(file, pattern.filePatterns) && (0, import_extractor11.isListedTestFile)(file, pattern.files);
|
|
9117
9391
|
}
|
|
9118
9392
|
function testClassesIn(root, file, pattern, facts) {
|
|
9119
9393
|
const found = [];
|
|
@@ -9159,7 +9433,7 @@ function testBlockOf(statement, pattern) {
|
|
|
9159
9433
|
}
|
|
9160
9434
|
function descriptionOf(call, facts) {
|
|
9161
9435
|
const first = firstArgument(call);
|
|
9162
|
-
return first === null ? null : (0,
|
|
9436
|
+
return first === null ? null : (0, import_values20.literalOf)(evaluatedValue(first, facts));
|
|
9163
9437
|
}
|
|
9164
9438
|
function anchorOf2(node) {
|
|
9165
9439
|
return BLOCK_TYPES7.has(node.type) ? node.parent ?? node : node;
|
|
@@ -9323,16 +9597,19 @@ function createFileCache(parse, readFile) {
|
|
|
9323
9597
|
}
|
|
9324
9598
|
};
|
|
9325
9599
|
}
|
|
9326
|
-
function fieldReadContext(pattern, cache, fileBlocks,
|
|
9600
|
+
function fieldReadContext(pattern, cache, fileBlocks, options) {
|
|
9601
|
+
const facts = options.facts;
|
|
9602
|
+
const parsedFile = (absPath) => cache.get(absPath);
|
|
9327
9603
|
return {
|
|
9328
9604
|
pattern,
|
|
9329
9605
|
cache,
|
|
9330
|
-
bodyRead,
|
|
9606
|
+
bodyRead: options,
|
|
9331
9607
|
facts,
|
|
9608
|
+
file: options.absoluteFile ?? options.filePath,
|
|
9332
9609
|
read: {
|
|
9333
9610
|
facts,
|
|
9334
|
-
bodyBlocks:
|
|
9335
|
-
dynamicNames:
|
|
9611
|
+
bodyBlocks: options.bodyBlocks,
|
|
9612
|
+
dynamicNames: options.dynamicNames
|
|
9336
9613
|
},
|
|
9337
9614
|
lookup: {
|
|
9338
9615
|
root: pattern.root,
|
|
@@ -9341,8 +9618,9 @@ function fieldReadContext(pattern, cache, fileBlocks, bodyRead, facts) {
|
|
|
9341
9618
|
acronyms: pattern.acronyms ?? [],
|
|
9342
9619
|
ancestryRootClassNames: pattern.ancestryRootClassNames,
|
|
9343
9620
|
constantFiles: cache.constantFiles,
|
|
9344
|
-
parsedFile
|
|
9345
|
-
localDefinition: (name) => sameFileBlocks(name, fileBlocks)
|
|
9621
|
+
parsedFile,
|
|
9622
|
+
localDefinition: (name) => sameFileBlocks(name, fileBlocks),
|
|
9623
|
+
...facts === void 0 ? {} : { definedInRun: classesDeclaredInRun(facts, parsedFile) }
|
|
9346
9624
|
}
|
|
9347
9625
|
};
|
|
9348
9626
|
}
|
|
@@ -9451,13 +9729,7 @@ async function graphqlObjectFieldUnits(pattern, pack, info, ownBlocks, fileBlock
|
|
|
9451
9729
|
if (info.bodyNode === null || pattern.baseClassNames.includes(info.qualifiedName)) {
|
|
9452
9730
|
return [];
|
|
9453
9731
|
}
|
|
9454
|
-
const ctx = fieldReadContext(
|
|
9455
|
-
pattern,
|
|
9456
|
-
options.cache,
|
|
9457
|
-
fileBlocks,
|
|
9458
|
-
options,
|
|
9459
|
-
options.facts
|
|
9460
|
-
);
|
|
9732
|
+
const ctx = fieldReadContext(pattern, options.cache, fileBlocks, options);
|
|
9461
9733
|
const ancestry = await ancestryOf(info.qualifiedName, ownBlocks, ctx.lookup);
|
|
9462
9734
|
if (!reachesConfiguredBase(ancestry, info.qualifiedName, pattern.baseClassNames)) {
|
|
9463
9735
|
return [];
|
|
@@ -9478,13 +9750,47 @@ async function graphqlObjectFieldUnits(pattern, pack, info, ownBlocks, fileBlock
|
|
|
9478
9750
|
declsByName.set(decl.fieldName, decl);
|
|
9479
9751
|
}
|
|
9480
9752
|
}
|
|
9481
|
-
|
|
9482
|
-
|
|
9753
|
+
const decls = [...declsByName.values()];
|
|
9754
|
+
const fields = decls.map((decl) => {
|
|
9755
|
+
const raw = buildFieldUnit(pack, typeName, decl, options);
|
|
9483
9756
|
if (decl.body.reachSeed !== void 0) {
|
|
9484
9757
|
options.onReachSeed?.(raw, decl.body.reachSeed);
|
|
9485
9758
|
}
|
|
9486
9759
|
return raw;
|
|
9487
9760
|
});
|
|
9761
|
+
return [...fields, ...hookUnitsOf(decls, pattern, options)];
|
|
9762
|
+
}
|
|
9763
|
+
function hookUnitsOf(decls, pattern, options) {
|
|
9764
|
+
const hooks = pattern.resolverHooks;
|
|
9765
|
+
if (hooks === void 0) {
|
|
9766
|
+
return [];
|
|
9767
|
+
}
|
|
9768
|
+
const units = /* @__PURE__ */ new Map();
|
|
9769
|
+
for (const hook of decls.flatMap((decl) => decl.hooks)) {
|
|
9770
|
+
const key = nodeId(hook.block.file, hook.method);
|
|
9771
|
+
if (units.has(key)) {
|
|
9772
|
+
continue;
|
|
9773
|
+
}
|
|
9774
|
+
const raw = hookUnit(hook, {
|
|
9775
|
+
hooks,
|
|
9776
|
+
body: bodyOfMethod(hook.method, hook.block.file, options),
|
|
9777
|
+
displayPath: displayPathIn(options, hook.block.file),
|
|
9778
|
+
facts: options.facts
|
|
9779
|
+
});
|
|
9780
|
+
units.set(key, raw);
|
|
9781
|
+
options.onReachSeed?.(raw, {
|
|
9782
|
+
file: hook.block.file,
|
|
9783
|
+
node: hook.method,
|
|
9784
|
+
enclosingQualifiedName: hook.block.info.qualifiedName
|
|
9785
|
+
});
|
|
9786
|
+
}
|
|
9787
|
+
return [...units.values()];
|
|
9788
|
+
}
|
|
9789
|
+
function displayPathIn(options, file) {
|
|
9790
|
+
if (file === (options.absoluteFile ?? options.filePath)) {
|
|
9791
|
+
return options.filePath;
|
|
9792
|
+
}
|
|
9793
|
+
return options.displayPathOf?.(file) ?? file;
|
|
9488
9794
|
}
|
|
9489
9795
|
async function controllerActionUnits(pattern, pack, info, ownBlocks, fileBlocks, options) {
|
|
9490
9796
|
if (info.bodyNode === null || pattern.baseClassNames.includes(info.qualifiedName)) {
|
|
@@ -9561,7 +9867,7 @@ async function controllerActionUnits(pattern, pack, info, ownBlocks, fileBlocks,
|
|
|
9561
9867
|
raised: raisedStatusBranches(
|
|
9562
9868
|
pattern,
|
|
9563
9869
|
options.storage?.patterns ?? [],
|
|
9564
|
-
body.extraEffects,
|
|
9870
|
+
everyEffect(body.extraEffects),
|
|
9565
9871
|
"eachRoute",
|
|
9566
9872
|
rangeOf(filter.method)
|
|
9567
9873
|
)
|
|
@@ -9594,10 +9900,7 @@ async function controllerActionUnits(pattern, pack, info, ownBlocks, fileBlocks,
|
|
|
9594
9900
|
actionName,
|
|
9595
9901
|
route,
|
|
9596
9902
|
method,
|
|
9597
|
-
{
|
|
9598
|
-
display: block.file === (options.absoluteFile ?? options.filePath) ? options.filePath : options.displayPathOf?.(block.file) ?? block.file,
|
|
9599
|
-
absolute: block.file
|
|
9600
|
-
},
|
|
9903
|
+
{ display: displayPathIn(options, block.file), absolute: block.file },
|
|
9601
9904
|
options,
|
|
9602
9905
|
around,
|
|
9603
9906
|
respondingHelper,
|
|
@@ -9763,11 +10066,11 @@ function buildControllerActionUnit(pack, pattern, controllerQualifiedName, actio
|
|
|
9763
10066
|
location: range
|
|
9764
10067
|
},
|
|
9765
10068
|
statusCodeReading: {
|
|
9766
|
-
reading:
|
|
10069
|
+
reading: import_extractor12.absentReading,
|
|
9767
10070
|
libraryDefault: pattern.defaultStatusCode
|
|
9768
10071
|
},
|
|
9769
|
-
effects: body.effects
|
|
9770
|
-
...body.extraEffects === void 0 ? {} : { extraEffects: body.extraEffects },
|
|
10072
|
+
effects: everyEffect(body.effects),
|
|
10073
|
+
...body.extraEffects === void 0 ? {} : { extraEffects: everyEffect(body.extraEffects) },
|
|
9771
10074
|
location: range,
|
|
9772
10075
|
isDefault: true
|
|
9773
10076
|
}
|
|
@@ -9777,7 +10080,7 @@ function buildControllerActionUnit(pack, pattern, controllerQualifiedName, actio
|
|
|
9777
10080
|
raisedStatusBranches(
|
|
9778
10081
|
pattern,
|
|
9779
10082
|
bodyRead.storage?.patterns ?? [],
|
|
9780
|
-
body.extraEffects,
|
|
10083
|
+
everyEffect(body.extraEffects),
|
|
9781
10084
|
raises2.handlers,
|
|
9782
10085
|
range
|
|
9783
10086
|
)
|
|
@@ -9822,7 +10125,7 @@ function routingGapUnit(pattern, gaps) {
|
|
|
9822
10125
|
isDefault: true
|
|
9823
10126
|
}
|
|
9824
10127
|
],
|
|
9825
|
-
readings: gaps.map((gap) => (0,
|
|
10128
|
+
readings: gaps.map((gap) => (0, import_extractor12.unreadableReading)(gap, range)),
|
|
9826
10129
|
dependencyCalls: [],
|
|
9827
10130
|
declaredContract: null
|
|
9828
10131
|
};
|
|
@@ -9856,15 +10159,18 @@ function branchesFor(body, range) {
|
|
|
9856
10159
|
emitEvent: null,
|
|
9857
10160
|
location: range
|
|
9858
10161
|
},
|
|
9859
|
-
effects: body.effects
|
|
9860
|
-
...body.extraEffects === void 0 ? {} : { extraEffects: body.extraEffects },
|
|
10162
|
+
effects: everyEffect(body.effects),
|
|
10163
|
+
...body.extraEffects === void 0 ? {} : { extraEffects: everyEffect(body.extraEffects) },
|
|
9861
10164
|
location: range,
|
|
9862
10165
|
isDefault: true
|
|
9863
10166
|
};
|
|
9864
10167
|
return withSlotSources([branch], body.provenance);
|
|
9865
10168
|
}
|
|
10169
|
+
function everyEffect(placed) {
|
|
10170
|
+
return (placed ?? []).map((one) => one.effect);
|
|
10171
|
+
}
|
|
9866
10172
|
function bodyOfMethod(method, file, bodyRead = {}) {
|
|
9867
|
-
const effects =
|
|
10173
|
+
const effects = invocationSites(
|
|
9868
10174
|
method,
|
|
9869
10175
|
bodyRead.inheritedMethods,
|
|
9870
10176
|
EVERY_ARGLESS_CALL,
|
|
@@ -9873,7 +10179,7 @@ function bodyOfMethod(method, file, bodyRead = {}) {
|
|
|
9873
10179
|
const storage = bodyRead.storage;
|
|
9874
10180
|
const facts = bodyRead.facts;
|
|
9875
10181
|
const database = storage === void 0 ? { effects: [], slots: [] } : methodStorage(method, file, storage);
|
|
9876
|
-
const
|
|
10182
|
+
const found = [
|
|
9877
10183
|
...envReadEffects(
|
|
9878
10184
|
method,
|
|
9879
10185
|
facts === void 0 ? void 0 : { db: facts, file }
|
|
@@ -9881,6 +10187,11 @@ function bodyOfMethod(method, file, bodyRead = {}) {
|
|
|
9881
10187
|
...database.effects,
|
|
9882
10188
|
...streamWriteEffects(method)
|
|
9883
10189
|
];
|
|
10190
|
+
const siteOf3 = effectSitesIn(
|
|
10191
|
+
methodBody(method),
|
|
10192
|
+
found.map((one) => one.at)
|
|
10193
|
+
);
|
|
10194
|
+
const extra = found.map(({ effect, at }) => ({ effect, site: siteOf3(at) }));
|
|
9884
10195
|
const provenance = database.slots.length === 0 || storage === void 0 ? [] : slotProvenance(database.slots, { facts: storage.facts, unit: method });
|
|
9885
10196
|
return {
|
|
9886
10197
|
bodyContent: methodHasStatements(method) ? "statements" : "empty",
|
|
@@ -9895,7 +10206,7 @@ var NO_METHOD_BEHIND_IT = {
|
|
|
9895
10206
|
readings: []
|
|
9896
10207
|
};
|
|
9897
10208
|
function methodNotSettled(reason, range) {
|
|
9898
|
-
return { readings: [(0,
|
|
10209
|
+
return { readings: [(0, import_extractor12.unreadableReading)(reason, range)] };
|
|
9899
10210
|
}
|
|
9900
10211
|
function bodyFromLookup(found, range, subject, nothingThere, bodyRead) {
|
|
9901
10212
|
const table = {
|
|
@@ -9944,7 +10255,8 @@ async function readFieldCall(stmt, scope, ctx, ancestry) {
|
|
|
9944
10255
|
namedOnTheWire: true,
|
|
9945
10256
|
node: stmt,
|
|
9946
10257
|
contract: read.contract,
|
|
9947
|
-
body: read.body
|
|
10258
|
+
body: read.body,
|
|
10259
|
+
hooks: read.hooks ?? []
|
|
9948
10260
|
};
|
|
9949
10261
|
}
|
|
9950
10262
|
function computedNameDeclaration(stmt, nameArg) {
|
|
@@ -9954,9 +10266,10 @@ function computedNameDeclaration(stmt, nameArg) {
|
|
|
9954
10266
|
namedOnTheWire: false,
|
|
9955
10267
|
node: stmt,
|
|
9956
10268
|
contract: null,
|
|
10269
|
+
hooks: [],
|
|
9957
10270
|
body: {
|
|
9958
10271
|
readings: [
|
|
9959
|
-
(0,
|
|
10272
|
+
(0, import_extractor12.unreadableReading)(
|
|
9960
10273
|
`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`,
|
|
9961
10274
|
range
|
|
9962
10275
|
)
|
|
@@ -9980,14 +10293,38 @@ async function readFieldShape(symbol, callArgs, scope, ctx, ancestry, range) {
|
|
|
9980
10293
|
}
|
|
9981
10294
|
return {
|
|
9982
10295
|
contract: literalContract(callArgs, scope, ctx),
|
|
9983
|
-
body:
|
|
10296
|
+
body: methodBehindField(symbol, callArgs, ctx, ancestry, range)
|
|
10297
|
+
};
|
|
10298
|
+
}
|
|
10299
|
+
function methodBehindField(symbol, callArgs, ctx, ancestry, range) {
|
|
10300
|
+
const keyword = ctx.pattern.resolverMethodKeyword;
|
|
10301
|
+
const written = keyword === void 0 ? void 0 : callArgs.keyword[keyword];
|
|
10302
|
+
if (written === void 0) {
|
|
10303
|
+
return bodyFromLookup(
|
|
9984
10304
|
methodInAncestry(ancestry, symbol, ctx.read),
|
|
9985
10305
|
range,
|
|
9986
10306
|
"This field",
|
|
9987
10307
|
NO_METHOD_BEHIND_IT,
|
|
9988
10308
|
ctx.bodyRead
|
|
9989
|
-
)
|
|
9990
|
-
}
|
|
10309
|
+
);
|
|
10310
|
+
}
|
|
10311
|
+
const name = stringValueOf(written, ctx.facts);
|
|
10312
|
+
if (name === null) {
|
|
10313
|
+
return methodNotSettled(
|
|
10314
|
+
`This field is resolved by the method ${written.text}, which is worked out at run time, so nothing about what it does was read here`,
|
|
10315
|
+
range
|
|
10316
|
+
);
|
|
10317
|
+
}
|
|
10318
|
+
return bodyFromLookup(
|
|
10319
|
+
methodInAncestry(ancestry, name, ctx.read),
|
|
10320
|
+
range,
|
|
10321
|
+
"This field",
|
|
10322
|
+
methodNotSettled(
|
|
10323
|
+
`This field is resolved by ${name}, which nothing in its type's ancestry defines, so nothing about what it does was read here`,
|
|
10324
|
+
range
|
|
10325
|
+
),
|
|
10326
|
+
ctx.bodyRead
|
|
10327
|
+
);
|
|
9991
10328
|
}
|
|
9992
10329
|
function literalContract(callArgs, scope, ctx) {
|
|
9993
10330
|
const typeArg = callArgs.positional[1];
|
|
@@ -10003,21 +10340,12 @@ function literalContract(callArgs, scope, ctx) {
|
|
|
10003
10340
|
async function readWiredClass(ref, scope, ctx) {
|
|
10004
10341
|
const range = rangeOf(ref);
|
|
10005
10342
|
const candidates = constantRefCandidates(ref, scope.nesting);
|
|
10006
|
-
|
|
10007
|
-
return {
|
|
10008
|
-
contract: null,
|
|
10009
|
-
body: methodNotSettled(
|
|
10010
|
-
`This field is wired to ${ref.text}, which is not a constant path this reader follows, so nothing about what it does was read here`,
|
|
10011
|
-
range
|
|
10012
|
-
)
|
|
10013
|
-
};
|
|
10014
|
-
}
|
|
10015
|
-
const reached = await reachConstant(candidates, ctx.lookup);
|
|
10343
|
+
const reached = await wiredClassInRun(ref, ctx) ?? (candidates.length === 0 ? null : await reachConstant(candidates, ctx.lookup));
|
|
10016
10344
|
if (reached === null) {
|
|
10017
10345
|
return {
|
|
10018
10346
|
contract: null,
|
|
10019
10347
|
body: methodNotSettled(
|
|
10020
|
-
`This field is wired to ${ref.text}, which this run did not read, so nothing about what it does was read here`,
|
|
10348
|
+
candidates.length === 0 ? `This field is wired to ${ref.text}, which is not a constant path this reader follows, so nothing about what it does was read here` : `This field is wired to ${ref.text}, which this run did not read, so nothing about what it does was read here`,
|
|
10021
10349
|
range
|
|
10022
10350
|
)
|
|
10023
10351
|
};
|
|
@@ -10028,20 +10356,44 @@ async function readWiredClass(ref, scope, ctx) {
|
|
|
10028
10356
|
reached.blocks,
|
|
10029
10357
|
ctx.lookup
|
|
10030
10358
|
);
|
|
10359
|
+
const body = bodyFromLookup(
|
|
10360
|
+
methodInAncestry(ancestry, ctx.pattern.resolverMethodName, ctx.read),
|
|
10361
|
+
range,
|
|
10362
|
+
`This field's ${targetQualifiedName}`,
|
|
10363
|
+
methodNotSettled(
|
|
10364
|
+
`This field is wired to ${targetQualifiedName}, which defines no ${ctx.pattern.resolverMethodName} method anywhere in its ancestry, so nothing about what it does was read here`,
|
|
10365
|
+
range
|
|
10366
|
+
),
|
|
10367
|
+
ctx.bodyRead
|
|
10368
|
+
);
|
|
10369
|
+
const hooks = ctx.pattern.resolverHooks === void 0 ? { definitions: [], unsettled: [] } : hooksRun(ancestry, ctx.pattern.resolverHooks, ctx.read);
|
|
10031
10370
|
return {
|
|
10032
10371
|
contract: readClassContract(ancestry, ctx.pattern),
|
|
10033
|
-
body:
|
|
10034
|
-
|
|
10035
|
-
|
|
10036
|
-
|
|
10037
|
-
|
|
10038
|
-
|
|
10039
|
-
|
|
10040
|
-
|
|
10041
|
-
|
|
10042
|
-
|
|
10372
|
+
body: {
|
|
10373
|
+
...body,
|
|
10374
|
+
readings: [
|
|
10375
|
+
...body.readings,
|
|
10376
|
+
...hooks.unsettled.map(
|
|
10377
|
+
(one) => unsettledHookReading(targetQualifiedName, one, range)
|
|
10378
|
+
)
|
|
10379
|
+
]
|
|
10380
|
+
},
|
|
10381
|
+
hooks: hooks.definitions
|
|
10043
10382
|
};
|
|
10044
10383
|
}
|
|
10384
|
+
async function wiredClassInRun(ref, ctx) {
|
|
10385
|
+
const inRun = ctx.lookup.definedInRun;
|
|
10386
|
+
if (ctx.facts === void 0 || inRun === void 0) {
|
|
10387
|
+
return null;
|
|
10388
|
+
}
|
|
10389
|
+
const classKey = classSettledOn(ctx.facts, readKey(ctx.file, ref, null));
|
|
10390
|
+
const name = classKey === void 0 ? void 0 : declaredName(ctx.facts, classKey);
|
|
10391
|
+
if (name === void 0) {
|
|
10392
|
+
return null;
|
|
10393
|
+
}
|
|
10394
|
+
const blocks = await inRun(name);
|
|
10395
|
+
return blocks === null ? null : { name, blocks };
|
|
10396
|
+
}
|
|
10045
10397
|
function readTypeCall(callArgs, scope, pattern, out) {
|
|
10046
10398
|
const typeArg = callArgs.positional[0];
|
|
10047
10399
|
if (typeArg !== void 0) {
|
|
@@ -10159,7 +10511,11 @@ function toCamelCase(name) {
|
|
|
10159
10511
|
...rest.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
10160
10512
|
].join("");
|
|
10161
10513
|
}
|
|
10162
|
-
function buildFieldUnit(pack, typeName, decl,
|
|
10514
|
+
function buildFieldUnit(pack, typeName, decl, options) {
|
|
10515
|
+
const filePath = options.filePath;
|
|
10516
|
+
const wrappers = decl.hooks.map(
|
|
10517
|
+
(hook) => hookReference(hook, displayPathIn(options, hook.block.file))
|
|
10518
|
+
);
|
|
10163
10519
|
const parameters = (decl.contract?.methodArgs ?? decl.contract?.args ?? []).map((arg, position) => ({
|
|
10164
10520
|
name: arg.name,
|
|
10165
10521
|
position,
|
|
@@ -10199,7 +10555,8 @@ function buildFieldUnit(pack, typeName, decl, filePath) {
|
|
|
10199
10555
|
dependencyCalls: [],
|
|
10200
10556
|
declaredContract: null,
|
|
10201
10557
|
...decl.body.readings.length > 0 ? { readings: decl.body.readings } : {},
|
|
10202
|
-
...graphqlDeclaredContract !== void 0 ? { graphqlDeclaredContract } : {}
|
|
10558
|
+
...graphqlDeclaredContract !== void 0 ? { graphqlDeclaredContract } : {},
|
|
10559
|
+
...wrappers.length > 0 ? { wrappers } : {}
|
|
10203
10560
|
};
|
|
10204
10561
|
}
|
|
10205
10562
|
|
|
@@ -10605,13 +10962,13 @@ var import_node_fs3 = __toESM(require("fs"), 1);
|
|
|
10605
10962
|
var import_node_path4 = __toESM(require("path"), 1);
|
|
10606
10963
|
var import_behavioral_ir9 = require("@suss/behavioral-ir");
|
|
10607
10964
|
var import_datalog3 = require("@suss/datalog");
|
|
10608
|
-
var
|
|
10965
|
+
var import_extractor20 = require("@suss/extractor");
|
|
10609
10966
|
var import_resolution16 = require("@suss/resolution");
|
|
10610
10967
|
|
|
10611
10968
|
// src/diagnostics.ts
|
|
10612
|
-
var
|
|
10969
|
+
var import_extractor13 = require("@suss/extractor");
|
|
10613
10970
|
function buildRubyExtractionReport(args) {
|
|
10614
|
-
return (0,
|
|
10971
|
+
return (0, import_extractor13.buildUngatedExtractionReport)({
|
|
10615
10972
|
packs: args.packs.map((pack) => ({
|
|
10616
10973
|
name: pack.name,
|
|
10617
10974
|
version: pack.version ?? null,
|
|
@@ -10623,10 +10980,16 @@ function buildRubyExtractionReport(args) {
|
|
|
10623
10980
|
});
|
|
10624
10981
|
}
|
|
10625
10982
|
|
|
10983
|
+
// src/reach/closure.ts
|
|
10984
|
+
var import_behavioral_ir7 = require("@suss/behavioral-ir");
|
|
10985
|
+
var import_datalog2 = require("@suss/datalog");
|
|
10986
|
+
var import_extractor16 = require("@suss/extractor");
|
|
10987
|
+
var import_resolution13 = require("@suss/resolution");
|
|
10988
|
+
|
|
10626
10989
|
// src/exits.ts
|
|
10627
|
-
var
|
|
10990
|
+
var import_extractor14 = require("@suss/extractor");
|
|
10628
10991
|
var import_resolution11 = require("@suss/resolution");
|
|
10629
|
-
var
|
|
10992
|
+
var import_values24 = require("@suss/values");
|
|
10630
10993
|
var EXIT_METHODS = /* @__PURE__ */ new Map([
|
|
10631
10994
|
["exit", 0],
|
|
10632
10995
|
["exit!", 1],
|
|
@@ -10635,14 +10998,14 @@ var EXIT_METHODS = /* @__PURE__ */ new Map([
|
|
|
10635
10998
|
var DEFERRED_BODY_TYPES3 = /* @__PURE__ */ new Set(["method", "singleton_method", "lambda"]);
|
|
10636
10999
|
function exitSites(root) {
|
|
10637
11000
|
const found = [];
|
|
10638
|
-
(0,
|
|
11001
|
+
(0, import_extractor14.walkDescendants)(root, null, children, {
|
|
10639
11002
|
at: (node) => {
|
|
10640
11003
|
const site = node.type === "call" ? exitSiteAt(node) : null;
|
|
10641
11004
|
if (site !== null) {
|
|
10642
11005
|
found.push(site);
|
|
10643
11006
|
}
|
|
10644
11007
|
},
|
|
10645
|
-
into: (node) => DEFERRED_BODY_TYPES3.has(node.type) ?
|
|
11008
|
+
into: (node) => DEFERRED_BODY_TYPES3.has(node.type) ? import_extractor14.SKIP_CHILDREN : null
|
|
10646
11009
|
});
|
|
10647
11010
|
return found;
|
|
10648
11011
|
}
|
|
@@ -10679,7 +11042,7 @@ function exitCodeOf(site, facts) {
|
|
|
10679
11042
|
if (written !== void 0) {
|
|
10680
11043
|
return { type: "literal", value: written };
|
|
10681
11044
|
}
|
|
10682
|
-
const value = (0,
|
|
11045
|
+
const value = (0, import_values24.constantOf)(evaluatedValue(code, facts));
|
|
10683
11046
|
return typeof value === "number" ? { type: "literal", value } : { type: "dynamic", sourceText: code.text };
|
|
10684
11047
|
}
|
|
10685
11048
|
function exitingBranches(method, effects, facts) {
|
|
@@ -10700,93 +11063,13 @@ function markExitCodeFunctions(summaries, exits, facts, workspaceRoot) {
|
|
|
10700
11063
|
(site) => site.code === null ? [] : [nodeId(file, site.code)]
|
|
10701
11064
|
)
|
|
10702
11065
|
);
|
|
10703
|
-
(0,
|
|
11066
|
+
(0, import_extractor14.markReturnsAsExitCode)(
|
|
10704
11067
|
summaries,
|
|
10705
11068
|
(0, import_resolution11.exitCodeFunctions)(facts, sinks),
|
|
10706
11069
|
workspaceRoot
|
|
10707
11070
|
);
|
|
10708
11071
|
}
|
|
10709
11072
|
|
|
10710
|
-
// src/facts/callbacks.ts
|
|
10711
|
-
function callbacksIn(patterns) {
|
|
10712
|
-
return patterns.flatMap(
|
|
10713
|
-
(pattern) => pattern.callbacks === void 0 ? [] : [pattern.callbacks]
|
|
10714
|
-
);
|
|
10715
|
-
}
|
|
10716
|
-
function emitClassCallbacks(db, file, classNode, declared) {
|
|
10717
|
-
const body = field(classNode, "body");
|
|
10718
|
-
if (body === null || declared.length === 0) {
|
|
10719
|
-
return;
|
|
10720
|
-
}
|
|
10721
|
-
const classKey = nodeId(file, classNode);
|
|
10722
|
-
for (const statement of runStatements(body)) {
|
|
10723
|
-
if (statement.type !== "call" || field(statement, "receiver") !== null) {
|
|
10724
|
-
continue;
|
|
10725
|
-
}
|
|
10726
|
-
const called = field(statement, "method")?.text ?? "";
|
|
10727
|
-
const args = readCallArgs(field(statement, "arguments"));
|
|
10728
|
-
for (const callbacks of declared) {
|
|
10729
|
-
const events = eventsOf(args, called, callbacks, db);
|
|
10730
|
-
for (const event of events) {
|
|
10731
|
-
for (const method of symbolArgumentNames(args, db)) {
|
|
10732
|
-
db.add("classCallback", [classKey, event, method]);
|
|
10733
|
-
}
|
|
10734
|
-
}
|
|
10735
|
-
}
|
|
10736
|
-
}
|
|
10737
|
-
}
|
|
10738
|
-
function eventsOf(args, called, callbacks, db) {
|
|
10739
|
-
const covered = callbacks.registeredBy[called];
|
|
10740
|
-
if (covered === void 0) {
|
|
10741
|
-
return [];
|
|
10742
|
-
}
|
|
10743
|
-
const written = args.keyword[callbacks.eventKeyword];
|
|
10744
|
-
const narrowed = written === void 0 ? null : stringValueOf(written, db);
|
|
10745
|
-
if (narrowed === null) {
|
|
10746
|
-
return covered;
|
|
10747
|
-
}
|
|
10748
|
-
return covered.filter((event) => event === narrowed);
|
|
10749
|
-
}
|
|
10750
|
-
|
|
10751
|
-
// src/facts.ts
|
|
10752
|
-
var import_node_path3 = __toESM(require("path"), 1);
|
|
10753
|
-
var import_extractor14 = require("@suss/extractor");
|
|
10754
|
-
function emitRequireFacts(db, filePath, root, known) {
|
|
10755
|
-
(0, import_extractor14.walkDescendants)(root, null, children, {
|
|
10756
|
-
at: (node) => {
|
|
10757
|
-
const target = requiredRelativePath(node);
|
|
10758
|
-
if (target === null) {
|
|
10759
|
-
return;
|
|
10760
|
-
}
|
|
10761
|
-
const resolved = import_node_path3.default.resolve(
|
|
10762
|
-
import_node_path3.default.dirname(filePath),
|
|
10763
|
-
target.endsWith(".rb") ? target : `${target}.rb`
|
|
10764
|
-
);
|
|
10765
|
-
if (known.has(resolved)) {
|
|
10766
|
-
db.add("importsFile", [filePath, resolved]);
|
|
10767
|
-
}
|
|
10768
|
-
},
|
|
10769
|
-
into: (node) => node.type === "argument_list" ? import_extractor14.SKIP_CHILDREN : null
|
|
10770
|
-
});
|
|
10771
|
-
}
|
|
10772
|
-
function requiredRelativePath(node) {
|
|
10773
|
-
if (node.type !== "call" || field(node, "receiver") !== null || field(node, "method")?.text !== "require_relative") {
|
|
10774
|
-
return null;
|
|
10775
|
-
}
|
|
10776
|
-
const { positional } = readCallArgs(field(node, "arguments"));
|
|
10777
|
-
return positional[0] === void 0 ? null : stringLiteralValue(positional[0]);
|
|
10778
|
-
}
|
|
10779
|
-
|
|
10780
|
-
// src/moduleSurface.ts
|
|
10781
|
-
var import_behavioral_ir8 = require("@suss/behavioral-ir");
|
|
10782
|
-
var import_extractor17 = require("@suss/extractor");
|
|
10783
|
-
|
|
10784
|
-
// src/reach/closure.ts
|
|
10785
|
-
var import_behavioral_ir7 = require("@suss/behavioral-ir");
|
|
10786
|
-
var import_datalog2 = require("@suss/datalog");
|
|
10787
|
-
var import_extractor16 = require("@suss/extractor");
|
|
10788
|
-
var import_resolution13 = require("@suss/resolution");
|
|
10789
|
-
|
|
10790
11073
|
// src/flags.ts
|
|
10791
11074
|
var import_extractor15 = require("@suss/extractor");
|
|
10792
11075
|
var PARSE_METHODS = /* @__PURE__ */ new Set(["parse", "parse!", "permute", "permute!"]);
|
|
@@ -10887,6 +11170,9 @@ function parserCalledOn(receiver, parserNamed) {
|
|
|
10887
11170
|
|
|
10888
11171
|
// src/reach/resolveCallee.ts
|
|
10889
11172
|
var import_resolution12 = require("@suss/resolution");
|
|
11173
|
+
function selfClassOf(site) {
|
|
11174
|
+
return site.receiverClass?.name ?? site.enclosingQualifiedName;
|
|
11175
|
+
}
|
|
10890
11176
|
var STOP_FOR = {
|
|
10891
11177
|
severalSources: "multipleSources",
|
|
10892
11178
|
outsideRun: "outsideRun",
|
|
@@ -11083,6 +11369,24 @@ function asCallee(spelling, outcome, site, ctx) {
|
|
|
11083
11369
|
if (objects.length > 1) {
|
|
11084
11370
|
return stop("multipleSources");
|
|
11085
11371
|
}
|
|
11372
|
+
const fromSelf = ownReceiverForm(spelling.key, site, ctx);
|
|
11373
|
+
const selfClass = selfClassOf(site);
|
|
11374
|
+
if (fromSelf !== null && selfClass !== null) {
|
|
11375
|
+
return methodOfClass(
|
|
11376
|
+
{ ...spelling, onClassItself: fromSelf === import_resolution12.SELF_AS_CLASS_NAME },
|
|
11377
|
+
selfClass,
|
|
11378
|
+
ctx
|
|
11379
|
+
);
|
|
11380
|
+
}
|
|
11381
|
+
const returned = (0, import_resolution12.selfResultOf)(ctx.facts, spelling.key);
|
|
11382
|
+
const sentTo = returned === null ? null : classSentTo(returned.receiver, site, ctx);
|
|
11383
|
+
if (returned !== null && sentTo !== null) {
|
|
11384
|
+
return methodOfClass(
|
|
11385
|
+
{ ...spelling, onClassItself: returned.form === import_resolution12.SELF_AS_CLASS_NAME },
|
|
11386
|
+
sentTo,
|
|
11387
|
+
ctx
|
|
11388
|
+
);
|
|
11389
|
+
}
|
|
11086
11390
|
const objectKey = objects[0] ?? (outcome.kind === "object" ? outcome.key : void 0);
|
|
11087
11391
|
if (objectKey !== void 0) {
|
|
11088
11392
|
return methodOnObject(spelling, objectKey, ctx);
|
|
@@ -11092,6 +11396,17 @@ function asCallee(spelling, outcome, site, ctx) {
|
|
|
11092
11396
|
}
|
|
11093
11397
|
return stop(STOP_FOR[outcome.kind] ?? "noDeclaration");
|
|
11094
11398
|
}
|
|
11399
|
+
function ownReceiverForm(key, site, ctx) {
|
|
11400
|
+
return site.method === null ? null : (0, import_resolution12.selfFormOf)(ctx.facts, key, receiverKeyOf(site.file, site.method));
|
|
11401
|
+
}
|
|
11402
|
+
function classSentTo(receiver, site, ctx) {
|
|
11403
|
+
resolveValues(ctx.facts, [receiver]);
|
|
11404
|
+
if (ownReceiverForm(receiver, site, ctx) !== null) {
|
|
11405
|
+
return selfClassOf(site);
|
|
11406
|
+
}
|
|
11407
|
+
const [only, ...more] = objectsBehind(ctx.facts, receiver);
|
|
11408
|
+
return only === void 0 || more.length > 0 ? null : ctx.classNames.get(only) ?? null;
|
|
11409
|
+
}
|
|
11095
11410
|
function objectsBehind(facts, key) {
|
|
11096
11411
|
return (0, import_resolution12.answersFor)(facts, "wantedObjectOf", key);
|
|
11097
11412
|
}
|
|
@@ -11109,11 +11424,18 @@ function methodOfClass(spelling, qualifiedName, ctx) {
|
|
|
11109
11424
|
if (!spelling.onClassItself) {
|
|
11110
11425
|
return methodOnAncestryOf(qualifiedName, spelling.method, ctx);
|
|
11111
11426
|
}
|
|
11112
|
-
if (spelling.method ===
|
|
11113
|
-
return methodOnAncestryOf(qualifiedName,
|
|
11427
|
+
if (spelling.method === CONSTRUCTOR) {
|
|
11428
|
+
return methodOnAncestryOf(qualifiedName, INITIALIZE_METHOD, ctx);
|
|
11429
|
+
}
|
|
11430
|
+
return classMethodOn(qualifiedName, spelling.method, ctx);
|
|
11431
|
+
}
|
|
11432
|
+
function classMethodOn(qualifiedName, method, ctx) {
|
|
11433
|
+
const written = singletonMethodOn(qualifiedName, method, ctx);
|
|
11434
|
+
if (written.kind === "followed") {
|
|
11435
|
+
return written;
|
|
11114
11436
|
}
|
|
11115
|
-
const
|
|
11116
|
-
return
|
|
11437
|
+
const inherited = scopeOn(qualifiedName, method, ctx);
|
|
11438
|
+
return inherited === null ? written : followed(runningOn(qualifiedName, inherited, ctx));
|
|
11117
11439
|
}
|
|
11118
11440
|
function scopeOn(qualifiedName, method, ctx) {
|
|
11119
11441
|
const spelled = (0, import_resolution12.classMemberName)(method);
|
|
@@ -11125,7 +11447,7 @@ function scopeOn(qualifiedName, method, ctx) {
|
|
|
11125
11447
|
for (const row of ctx.facts.lookup("holdsProperty", 0, classKey)) {
|
|
11126
11448
|
const target = row[1] === spelled ? ctx.definitions.get(String(row[2])) : void 0;
|
|
11127
11449
|
if (target !== void 0) {
|
|
11128
|
-
return
|
|
11450
|
+
return target;
|
|
11129
11451
|
}
|
|
11130
11452
|
}
|
|
11131
11453
|
}
|
|
@@ -11149,7 +11471,8 @@ function leavesRoomForATopLevelMethod(reason) {
|
|
|
11149
11471
|
return reason === "noDeclaration" || reason === "outsideRun";
|
|
11150
11472
|
}
|
|
11151
11473
|
function resolveImplicitSelf(methodName, site, ctx) {
|
|
11152
|
-
const
|
|
11474
|
+
const selfClass = selfClassOf(site);
|
|
11475
|
+
const onClass = selfClass === null ? null : methodOnSelf(site, selfClass, methodName, ctx);
|
|
11153
11476
|
if (onClass !== null && (onClass.kind === "followed" || !leavesRoomForATopLevelMethod(onClass.reason))) {
|
|
11154
11477
|
return onClass;
|
|
11155
11478
|
}
|
|
@@ -11164,7 +11487,7 @@ function resolveImplicitSelf(methodName, site, ctx) {
|
|
|
11164
11487
|
return readWholeAncestry && !OBJECT_METHODS.has(methodName) && inModuleInstanceMethod(site, ctx) ? SELF_CALL_IN_MIXIN : UNSETTLED_ON_SELF;
|
|
11165
11488
|
}
|
|
11166
11489
|
function inModuleInstanceMethod(site, ctx) {
|
|
11167
|
-
const qualifiedName = site
|
|
11490
|
+
const qualifiedName = selfClassOf(site);
|
|
11168
11491
|
if (qualifiedName === null || site.method === null || inClassMethod(site, ctx)) {
|
|
11169
11492
|
return false;
|
|
11170
11493
|
}
|
|
@@ -11172,7 +11495,7 @@ function inModuleInstanceMethod(site, ctx) {
|
|
|
11172
11495
|
return own?.type === "bodies" && own.blocks.every((block) => block.info.kind === "module");
|
|
11173
11496
|
}
|
|
11174
11497
|
function declaredForTheOtherSelf(site, methodName, ctx) {
|
|
11175
|
-
const qualifiedName = site
|
|
11498
|
+
const qualifiedName = selfClassOf(site);
|
|
11176
11499
|
if (qualifiedName === null) {
|
|
11177
11500
|
return false;
|
|
11178
11501
|
}
|
|
@@ -11183,10 +11506,10 @@ function inClassMethod(site, ctx) {
|
|
|
11183
11506
|
return site.method !== null && definesClassMethod(site.method, ctx.bodyBlocks);
|
|
11184
11507
|
}
|
|
11185
11508
|
function methodOnSelf(site, qualifiedName, methodName, ctx) {
|
|
11186
|
-
if (inClassMethod(site, ctx)) {
|
|
11187
|
-
return
|
|
11509
|
+
if (!inClassMethod(site, ctx)) {
|
|
11510
|
+
return methodOnAncestryOf(qualifiedName, methodName, ctx);
|
|
11188
11511
|
}
|
|
11189
|
-
return methodOnAncestryOf(qualifiedName, methodName, ctx);
|
|
11512
|
+
return methodName === CONSTRUCTOR ? methodOnAncestryOf(qualifiedName, INITIALIZE_METHOD, ctx) : classMethodOn(qualifiedName, methodName, ctx);
|
|
11190
11513
|
}
|
|
11191
11514
|
function resolveTopLevelName(methodName, ctx) {
|
|
11192
11515
|
const candidates = ctx.topLevelMethods.get(methodName);
|
|
@@ -11209,14 +11532,37 @@ function methodOnAncestryOf(qualifiedName, methodName, ctx) {
|
|
|
11209
11532
|
dynamicNames: ctx.dynamicNames
|
|
11210
11533
|
});
|
|
11211
11534
|
if (found.type === "found") {
|
|
11212
|
-
return followed(
|
|
11535
|
+
return followed(
|
|
11536
|
+
runningOn(
|
|
11537
|
+
qualifiedName,
|
|
11538
|
+
reachedMethod(found.method, found.block, methodName),
|
|
11539
|
+
ctx
|
|
11540
|
+
)
|
|
11541
|
+
);
|
|
11213
11542
|
}
|
|
11214
11543
|
if (found.type === "unsettled") {
|
|
11215
|
-
return stop(
|
|
11544
|
+
return stop(unsettledReason2(found));
|
|
11216
11545
|
}
|
|
11217
11546
|
return NO_DECLARATION;
|
|
11218
11547
|
}
|
|
11219
|
-
function
|
|
11548
|
+
function runningOn(qualifiedName, target, ctx) {
|
|
11549
|
+
if (target.enclosingQualifiedName === qualifiedName) {
|
|
11550
|
+
return target;
|
|
11551
|
+
}
|
|
11552
|
+
const own = (ctx.ancestries.get(qualifiedName) ?? []).find(
|
|
11553
|
+
(entry) => entry.type === "bodies" && entry.name === qualifiedName
|
|
11554
|
+
);
|
|
11555
|
+
const file = own?.type === "bodies" ? own.blocks[0]?.file : void 0;
|
|
11556
|
+
if (file === void 0) {
|
|
11557
|
+
return target;
|
|
11558
|
+
}
|
|
11559
|
+
return {
|
|
11560
|
+
...target,
|
|
11561
|
+
exportPath: [qualifiedName, target.name],
|
|
11562
|
+
receiverClass: { name: qualifiedName, file }
|
|
11563
|
+
};
|
|
11564
|
+
}
|
|
11565
|
+
function unsettledReason2(found) {
|
|
11220
11566
|
if (found.cause === "dynamicDefine") {
|
|
11221
11567
|
return "definedAtLoadTime";
|
|
11222
11568
|
}
|
|
@@ -11279,11 +11625,12 @@ async function reachedFunctions(seeds, options) {
|
|
|
11279
11625
|
const charges = /* @__PURE__ */ new Map();
|
|
11280
11626
|
const beforeGaps = /* @__PURE__ */ new Map();
|
|
11281
11627
|
const functionFor = (target) => {
|
|
11282
|
-
const node = replay?.nodeOf(target.key) ?? null;
|
|
11283
|
-
|
|
11628
|
+
const node = replay?.nodeOf((0, import_resolution13.plainKeyOf)(target.key)) ?? null;
|
|
11629
|
+
const found = node === null ? null : { ...target, node };
|
|
11630
|
+
if (found === null || keyOf(found) !== target.key) {
|
|
11284
11631
|
throw new ReplayFailed(target.key);
|
|
11285
11632
|
}
|
|
11286
|
-
return
|
|
11633
|
+
return found;
|
|
11287
11634
|
};
|
|
11288
11635
|
for (const seed of seeds) {
|
|
11289
11636
|
seedKeys.add(seed.key);
|
|
@@ -11343,7 +11690,10 @@ async function reachedFunctions(seeds, options) {
|
|
|
11343
11690
|
if (scan.followed.length > 0) {
|
|
11344
11691
|
followedKeys.add(key);
|
|
11345
11692
|
}
|
|
11346
|
-
|
|
11693
|
+
const calledHere = scan.followed.flatMap(
|
|
11694
|
+
(target) => target.receiverClass === void 0 ? [target] : [plainOf(target), target]
|
|
11695
|
+
);
|
|
11696
|
+
for (const target of calledHere) {
|
|
11347
11697
|
const calleeKey = keyOf(target);
|
|
11348
11698
|
if (!functionByKey.has(calleeKey)) {
|
|
11349
11699
|
functionByKey.set(calleeKey, target);
|
|
@@ -11364,12 +11714,22 @@ async function reachedFunctions(seeds, options) {
|
|
|
11364
11714
|
options.storage
|
|
11365
11715
|
);
|
|
11366
11716
|
}
|
|
11717
|
+
const placementsOf = (key) => ({
|
|
11718
|
+
targets: targetsByKey.get(key),
|
|
11719
|
+
argTargets: argTargetsByKey.get(key),
|
|
11720
|
+
possibleTargets: possibleTargetsByKey.get(key)
|
|
11721
|
+
});
|
|
11722
|
+
const onSubclass = (0, import_resolution13.keptVariants)(
|
|
11723
|
+
[...functionByKey].flatMap(
|
|
11724
|
+
([key, target]) => target.receiverClass === void 0 ? [] : [variantOf(key, scans, placementsOf)]
|
|
11725
|
+
)
|
|
11726
|
+
);
|
|
11367
11727
|
const summaries = [];
|
|
11368
11728
|
const summariesByKey = /* @__PURE__ */ new Map();
|
|
11369
11729
|
for (const [keyAtom] of db.facts("reachable")) {
|
|
11370
11730
|
const key = String(keyAtom);
|
|
11371
11731
|
const target = functionByKey.get(key);
|
|
11372
|
-
if (seedKeys.has(key) || target === void 0) {
|
|
11732
|
+
if (seedKeys.has(key) || target === void 0 || target.receiverClass !== void 0 && !onSubclass.has(key)) {
|
|
11373
11733
|
continue;
|
|
11374
11734
|
}
|
|
11375
11735
|
const kept = replay?.summaryOf(key);
|
|
@@ -11384,6 +11744,12 @@ async function reachedFunctions(seeds, options) {
|
|
|
11384
11744
|
const raw = libraryUnit(target, options);
|
|
11385
11745
|
dropPropertyReads(raw, propertyReadsByKey.get(key));
|
|
11386
11746
|
const summary2 = (0, import_extractor16.assembleSummary)(raw, { gapHandling });
|
|
11747
|
+
if (target.receiverClass !== void 0) {
|
|
11748
|
+
summary2.receiverClass = subclassAt(
|
|
11749
|
+
target.receiverClass,
|
|
11750
|
+
options.displayPathOf
|
|
11751
|
+
);
|
|
11752
|
+
}
|
|
11387
11753
|
if (gapHandling !== "silent") {
|
|
11388
11754
|
summary2.gaps.push(
|
|
11389
11755
|
...(stopsByKey.get(key) ?? []).map(import_behavioral_ir7.unfollowedCallGap)
|
|
@@ -11425,6 +11791,16 @@ async function reachedFunctions(seeds, options) {
|
|
|
11425
11791
|
beforeGaps
|
|
11426
11792
|
};
|
|
11427
11793
|
}
|
|
11794
|
+
function variantOf(key, scans, placementsOf) {
|
|
11795
|
+
return {
|
|
11796
|
+
key,
|
|
11797
|
+
differs: !(0, import_behavioral_ir7.sameDeclarations)(
|
|
11798
|
+
placementsOf(key),
|
|
11799
|
+
placementsOf((0, import_resolution13.plainKeyOf)(key))
|
|
11800
|
+
),
|
|
11801
|
+
calls: scans.get(key)?.followed.map((target) => target.key) ?? []
|
|
11802
|
+
};
|
|
11803
|
+
}
|
|
11428
11804
|
var ReplayFailed = class extends Error {
|
|
11429
11805
|
constructor(key) {
|
|
11430
11806
|
super(`The cache stored a method at ${key}, and nothing is there now.`);
|
|
@@ -11515,7 +11891,8 @@ function storedScan(scan) {
|
|
|
11515
11891
|
file: target.file,
|
|
11516
11892
|
name: target.name,
|
|
11517
11893
|
exportPath: target.exportPath,
|
|
11518
|
-
enclosingQualifiedName: target.enclosingQualifiedName
|
|
11894
|
+
enclosingQualifiedName: target.enclosingQualifiedName,
|
|
11895
|
+
...target.receiverClass === void 0 ? {} : { receiverClass: target.receiverClass }
|
|
11519
11896
|
})),
|
|
11520
11897
|
stops: scan.stops,
|
|
11521
11898
|
targets: [...scan.targets],
|
|
@@ -11552,7 +11929,25 @@ function scanFromStored(stored, functionFor) {
|
|
|
11552
11929
|
};
|
|
11553
11930
|
}
|
|
11554
11931
|
function keyOf(target) {
|
|
11555
|
-
|
|
11932
|
+
const key = nodeId(target.file, target.node);
|
|
11933
|
+
return target.receiverClass === void 0 ? key : (0, import_resolution13.variantKey)(key, target.receiverClass);
|
|
11934
|
+
}
|
|
11935
|
+
function plainOf(target) {
|
|
11936
|
+
const { receiverClass: _, ...plain } = target;
|
|
11937
|
+
return plain.enclosingQualifiedName === null ? plain : { ...plain, exportPath: [plain.enclosingQualifiedName, plain.name] };
|
|
11938
|
+
}
|
|
11939
|
+
function placeOf(target, displayPathOf) {
|
|
11940
|
+
const place = {
|
|
11941
|
+
file: displayPathOf(target.file),
|
|
11942
|
+
span: spanOf(target.node)
|
|
11943
|
+
};
|
|
11944
|
+
return target.receiverClass === void 0 ? place : {
|
|
11945
|
+
...place,
|
|
11946
|
+
receiverClass: subclassAt(target.receiverClass, displayPathOf)
|
|
11947
|
+
};
|
|
11948
|
+
}
|
|
11949
|
+
function subclassAt(subclass, displayPathOf) {
|
|
11950
|
+
return { name: subclass.name, file: displayPathOf(subclass.file) };
|
|
11556
11951
|
}
|
|
11557
11952
|
function dropPropertyReads(raw, callees) {
|
|
11558
11953
|
if (callees === void 0) {
|
|
@@ -11625,8 +12020,9 @@ function siteOf2(source) {
|
|
|
11625
12020
|
return {
|
|
11626
12021
|
file: source.file,
|
|
11627
12022
|
method: localsOwnerOf(source.node),
|
|
11628
|
-
owner:
|
|
11629
|
-
enclosingQualifiedName: source.enclosingQualifiedName
|
|
12023
|
+
owner: nodeId(source.file, source.node),
|
|
12024
|
+
enclosingQualifiedName: source.enclosingQualifiedName,
|
|
12025
|
+
receiverClass: source.receiverClass
|
|
11630
12026
|
};
|
|
11631
12027
|
}
|
|
11632
12028
|
function localsOwnerOf(node) {
|
|
@@ -11669,17 +12065,21 @@ function scanBody(source, ctx, options, read) {
|
|
|
11669
12065
|
const seen = /* @__PURE__ */ new Set();
|
|
11670
12066
|
const parameterCallsSeen = /* @__PURE__ */ new Set();
|
|
11671
12067
|
const keptArgless = /* @__PURE__ */ new Set();
|
|
11672
|
-
const recordPassedArgs = (call, callee,
|
|
12068
|
+
const recordPassedArgs = (call, callee, target) => {
|
|
11673
12069
|
const args = field(call, "arguments");
|
|
11674
12070
|
if (args === null) {
|
|
11675
12071
|
return;
|
|
11676
12072
|
}
|
|
12073
|
+
const calleeKeys = target === null ? [] : [keyOf(target), keyOf(plainOf(target))];
|
|
12074
|
+
const passes = (position) => {
|
|
12075
|
+
for (const calleeKey of calleeKeys) {
|
|
12076
|
+
passedPositions.add(`${calleeKey}#${position}`);
|
|
12077
|
+
}
|
|
12078
|
+
};
|
|
11677
12079
|
const argNodes = bodyStatements(args);
|
|
11678
12080
|
for (let position = 0; position < argNodes.length; position += 1) {
|
|
11679
12081
|
if (argNodes[position]?.type === LAMBDA_TYPE) {
|
|
11680
|
-
|
|
11681
|
-
passedPositions.add(`${calleeKey}#${position}`);
|
|
11682
|
-
}
|
|
12082
|
+
passes(position);
|
|
11683
12083
|
continue;
|
|
11684
12084
|
}
|
|
11685
12085
|
const symbol = methodReferenceSymbol(argNodes[position]);
|
|
@@ -11695,13 +12095,8 @@ function scanBody(source, ctx, options, read) {
|
|
|
11695
12095
|
seen.add(key);
|
|
11696
12096
|
followed2.push(resolved);
|
|
11697
12097
|
}
|
|
11698
|
-
placements.placeArg(callee, position,
|
|
11699
|
-
|
|
11700
|
-
span: spanOf(resolved.node)
|
|
11701
|
-
});
|
|
11702
|
-
if (calleeKey !== null) {
|
|
11703
|
-
passedPositions.add(`${calleeKey}#${position}`);
|
|
11704
|
-
}
|
|
12098
|
+
placements.placeArg(callee, position, placeOf(resolved, displayPathOf));
|
|
12099
|
+
passes(position);
|
|
11705
12100
|
}
|
|
11706
12101
|
};
|
|
11707
12102
|
const followCallback = (name, key) => {
|
|
@@ -11737,10 +12132,7 @@ function scanBody(source, ctx, options, read) {
|
|
|
11737
12132
|
dispatched.targets.forEach(follow);
|
|
11738
12133
|
placements.placePossible(
|
|
11739
12134
|
callee,
|
|
11740
|
-
dispatched.targets.map((target) => (
|
|
11741
|
-
file: displayPathOf(target.file),
|
|
11742
|
-
span: spanOf(target.node)
|
|
11743
|
-
}))
|
|
12135
|
+
dispatched.targets.map((target) => placeOf(target, displayPathOf))
|
|
11744
12136
|
);
|
|
11745
12137
|
if (dispatched.unresolved > 0) {
|
|
11746
12138
|
stops.add({ callee, reason: "unsettledValue" });
|
|
@@ -11772,7 +12164,7 @@ function scanBody(source, ctx, options, read) {
|
|
|
11772
12164
|
recordPassedArgs(
|
|
11773
12165
|
call,
|
|
11774
12166
|
callee,
|
|
11775
|
-
outcome.kind === "followed" ?
|
|
12167
|
+
outcome.kind === "followed" ? outcome.target : null
|
|
11776
12168
|
);
|
|
11777
12169
|
if (outcome.kind === "stopped") {
|
|
11778
12170
|
const claimed = options.storage !== void 0 && storageClaims(call, callSite.file, options.storage, callSite.method);
|
|
@@ -11813,10 +12205,7 @@ function scanBody(source, ctx, options, read) {
|
|
|
11813
12205
|
function placeCallee(placements, outcome, call, where) {
|
|
11814
12206
|
const callee = calleeText(call);
|
|
11815
12207
|
if (outcome.kind === "followed") {
|
|
11816
|
-
placements.place(callee,
|
|
11817
|
-
file: where.displayPathOf(outcome.target.file),
|
|
11818
|
-
span: spanOf(outcome.target.node)
|
|
11819
|
-
});
|
|
12208
|
+
placements.place(callee, placeOf(outcome.target, where.displayPathOf));
|
|
11820
12209
|
return;
|
|
11821
12210
|
}
|
|
11822
12211
|
if (outcome.matchByName === true) {
|
|
@@ -11870,7 +12259,7 @@ function libraryUnit(target, options, binding = (0, import_behavioral_ir7.functi
|
|
|
11870
12259
|
emitEvent: null,
|
|
11871
12260
|
location: range
|
|
11872
12261
|
},
|
|
11873
|
-
effects,
|
|
12262
|
+
effects: [],
|
|
11874
12263
|
location: range,
|
|
11875
12264
|
isDefault: true
|
|
11876
12265
|
}
|
|
@@ -11890,7 +12279,10 @@ function libraryUnit(target, options, binding = (0, import_behavioral_ir7.functi
|
|
|
11890
12279
|
parameters,
|
|
11891
12280
|
branches: withSlotSources(
|
|
11892
12281
|
branches.map(
|
|
11893
|
-
(branch) =>
|
|
12282
|
+
(branch) => withEffectsThatRun(branch, {
|
|
12283
|
+
effects,
|
|
12284
|
+
extraEffects: body.extraEffects
|
|
12285
|
+
})
|
|
11894
12286
|
),
|
|
11895
12287
|
body.provenance
|
|
11896
12288
|
),
|
|
@@ -11925,12 +12317,205 @@ function parameterName(param) {
|
|
|
11925
12317
|
return named2 !== null && named2.type === "identifier" ? named2.text : null;
|
|
11926
12318
|
}
|
|
11927
12319
|
|
|
12320
|
+
// src/entryPoints.ts
|
|
12321
|
+
function declaredEntryUnits(root, file, options) {
|
|
12322
|
+
const units = [];
|
|
12323
|
+
for (const pack of options.packs) {
|
|
12324
|
+
for (const entry of pack.entryPoints?.(file) ?? []) {
|
|
12325
|
+
const method = entryMethod(root, entry.name, options);
|
|
12326
|
+
if (method === null) {
|
|
12327
|
+
continue;
|
|
12328
|
+
}
|
|
12329
|
+
for (const declared of entry.units) {
|
|
12330
|
+
const raw = libraryUnit(
|
|
12331
|
+
{
|
|
12332
|
+
file,
|
|
12333
|
+
node: method.node,
|
|
12334
|
+
name: declared.name,
|
|
12335
|
+
exportPath: method.exportPath
|
|
12336
|
+
},
|
|
12337
|
+
options,
|
|
12338
|
+
declared.binding
|
|
12339
|
+
);
|
|
12340
|
+
const unit = {
|
|
12341
|
+
...raw,
|
|
12342
|
+
identity: { ...raw.identity, kind: declared.kind },
|
|
12343
|
+
deployableUnit: declared.deployableUnit,
|
|
12344
|
+
...declared.metadata !== void 0 ? { packMetadata: declared.metadata } : {}
|
|
12345
|
+
};
|
|
12346
|
+
units.push(unit);
|
|
12347
|
+
options.onReachSeed(unit, {
|
|
12348
|
+
file,
|
|
12349
|
+
node: method.node,
|
|
12350
|
+
enclosingQualifiedName: method.enclosingQualifiedName
|
|
12351
|
+
});
|
|
12352
|
+
}
|
|
12353
|
+
}
|
|
12354
|
+
}
|
|
12355
|
+
return units;
|
|
12356
|
+
}
|
|
12357
|
+
function entryMethod(root, name, options) {
|
|
12358
|
+
const dot = name.lastIndexOf(".");
|
|
12359
|
+
if (dot === -1) {
|
|
12360
|
+
const node = instanceMethodsByName(root, options.bodyBlocks).get(name);
|
|
12361
|
+
return node === void 0 ? null : { node, exportPath: [name], enclosingQualifiedName: null };
|
|
12362
|
+
}
|
|
12363
|
+
const className = name.slice(0, dot);
|
|
12364
|
+
const methodName = name.slice(dot + 1);
|
|
12365
|
+
let found = null;
|
|
12366
|
+
walkDefinitions(root, (info) => {
|
|
12367
|
+
if (found !== null || info.qualifiedName !== className) {
|
|
12368
|
+
return;
|
|
12369
|
+
}
|
|
12370
|
+
const node = info.bodyNode === null ? void 0 : singletonMethodsByName(info.bodyNode, options.bodyBlocks).get(
|
|
12371
|
+
methodName
|
|
12372
|
+
);
|
|
12373
|
+
if (node !== void 0) {
|
|
12374
|
+
found = {
|
|
12375
|
+
node,
|
|
12376
|
+
exportPath: [className, methodName],
|
|
12377
|
+
enclosingQualifiedName: className
|
|
12378
|
+
};
|
|
12379
|
+
}
|
|
12380
|
+
});
|
|
12381
|
+
return found;
|
|
12382
|
+
}
|
|
12383
|
+
|
|
12384
|
+
// src/erbTemplate.ts
|
|
12385
|
+
var OPEN = "<%";
|
|
12386
|
+
var CLOSE = "%>";
|
|
12387
|
+
var LITERAL_OPEN = "<%%";
|
|
12388
|
+
var COMMENT_MARK = "#";
|
|
12389
|
+
var OUTPUT_MARK = "=";
|
|
12390
|
+
var TRIM_OPEN_MARK = "-";
|
|
12391
|
+
var TRIM_CLOSE_MARK = "-";
|
|
12392
|
+
var CODE_CLOSE = "; ";
|
|
12393
|
+
var OUTPUT_CLOSE = "];";
|
|
12394
|
+
var OUTPUT_OPEN = "[";
|
|
12395
|
+
function rubyInErbTemplate(template) {
|
|
12396
|
+
const parts = [];
|
|
12397
|
+
let at = 0;
|
|
12398
|
+
while (at < template.length) {
|
|
12399
|
+
const open = template.indexOf(OPEN, at);
|
|
12400
|
+
if (open === -1) {
|
|
12401
|
+
parts.push(blanked(template.slice(at)));
|
|
12402
|
+
break;
|
|
12403
|
+
}
|
|
12404
|
+
parts.push(blanked(template.slice(at, open)));
|
|
12405
|
+
if (template.startsWith(LITERAL_OPEN, open)) {
|
|
12406
|
+
parts.push(blanked(LITERAL_OPEN));
|
|
12407
|
+
at = open + LITERAL_OPEN.length;
|
|
12408
|
+
continue;
|
|
12409
|
+
}
|
|
12410
|
+
const close = template.indexOf(CLOSE, open + OPEN.length);
|
|
12411
|
+
if (close === -1) {
|
|
12412
|
+
parts.push(blanked(template.slice(open)));
|
|
12413
|
+
break;
|
|
12414
|
+
}
|
|
12415
|
+
parts.push(tagAsRuby(template.slice(open, close + CLOSE.length)));
|
|
12416
|
+
at = close + CLOSE.length;
|
|
12417
|
+
}
|
|
12418
|
+
return parts.join("");
|
|
12419
|
+
}
|
|
12420
|
+
function tagAsRuby(tag) {
|
|
12421
|
+
const mark = tag.charAt(OPEN.length);
|
|
12422
|
+
if (mark === COMMENT_MARK) {
|
|
12423
|
+
return blanked(tag);
|
|
12424
|
+
}
|
|
12425
|
+
const prints = mark === OUTPUT_MARK;
|
|
12426
|
+
const codeStart = OPEN.length + (prints || mark === TRIM_OPEN_MARK ? mark.length : 0);
|
|
12427
|
+
const beforeClose = tag.length - CLOSE.length;
|
|
12428
|
+
const codeEnd = beforeClose > codeStart && tag.charAt(beforeClose - 1) === TRIM_CLOSE_MARK ? beforeClose - 1 : beforeClose;
|
|
12429
|
+
const opening = blanked(tag.slice(0, codeStart));
|
|
12430
|
+
return [
|
|
12431
|
+
prints ? `${OUTPUT_OPEN}${opening.slice(OUTPUT_OPEN.length)}` : opening,
|
|
12432
|
+
tag.slice(codeStart, codeEnd),
|
|
12433
|
+
blanked(tag.slice(codeEnd, beforeClose)),
|
|
12434
|
+
prints ? OUTPUT_CLOSE : CODE_CLOSE
|
|
12435
|
+
].join("");
|
|
12436
|
+
}
|
|
12437
|
+
function blanked(text3) {
|
|
12438
|
+
return text3.replace(/[^\r\n]/g, " ");
|
|
12439
|
+
}
|
|
12440
|
+
|
|
12441
|
+
// src/facts/callbacks.ts
|
|
12442
|
+
function callbacksIn(patterns) {
|
|
12443
|
+
return patterns.flatMap(
|
|
12444
|
+
(pattern) => pattern.callbacks === void 0 ? [] : [pattern.callbacks]
|
|
12445
|
+
);
|
|
12446
|
+
}
|
|
12447
|
+
function emitClassCallbacks(db, file, classNode, declared) {
|
|
12448
|
+
const body = field(classNode, "body");
|
|
12449
|
+
if (body === null || declared.length === 0) {
|
|
12450
|
+
return;
|
|
12451
|
+
}
|
|
12452
|
+
const classKey = nodeId(file, classNode);
|
|
12453
|
+
for (const statement of runStatements(body)) {
|
|
12454
|
+
if (statement.type !== "call" || field(statement, "receiver") !== null) {
|
|
12455
|
+
continue;
|
|
12456
|
+
}
|
|
12457
|
+
const called = field(statement, "method")?.text ?? "";
|
|
12458
|
+
const args = readCallArgs(field(statement, "arguments"));
|
|
12459
|
+
for (const callbacks of declared) {
|
|
12460
|
+
const events = eventsOf(args, called, callbacks, db);
|
|
12461
|
+
for (const event of events) {
|
|
12462
|
+
for (const method of symbolArgumentNames(args, db)) {
|
|
12463
|
+
db.add("classCallback", [classKey, event, method]);
|
|
12464
|
+
}
|
|
12465
|
+
}
|
|
12466
|
+
}
|
|
12467
|
+
}
|
|
12468
|
+
}
|
|
12469
|
+
function eventsOf(args, called, callbacks, db) {
|
|
12470
|
+
const covered = callbacks.registeredBy[called];
|
|
12471
|
+
if (covered === void 0) {
|
|
12472
|
+
return [];
|
|
12473
|
+
}
|
|
12474
|
+
const written = args.keyword[callbacks.eventKeyword];
|
|
12475
|
+
const narrowed = written === void 0 ? null : stringValueOf(written, db);
|
|
12476
|
+
if (narrowed === null) {
|
|
12477
|
+
return covered;
|
|
12478
|
+
}
|
|
12479
|
+
return covered.filter((event) => event === narrowed);
|
|
12480
|
+
}
|
|
12481
|
+
|
|
12482
|
+
// src/facts.ts
|
|
12483
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
12484
|
+
var import_extractor17 = require("@suss/extractor");
|
|
12485
|
+
function emitRequireFacts(db, filePath, root, known) {
|
|
12486
|
+
(0, import_extractor17.walkDescendants)(root, null, children, {
|
|
12487
|
+
at: (node) => {
|
|
12488
|
+
const target = requiredRelativePath(node);
|
|
12489
|
+
if (target === null) {
|
|
12490
|
+
return;
|
|
12491
|
+
}
|
|
12492
|
+
const resolved = import_node_path3.default.resolve(
|
|
12493
|
+
import_node_path3.default.dirname(filePath),
|
|
12494
|
+
target.endsWith(".rb") ? target : `${target}.rb`
|
|
12495
|
+
);
|
|
12496
|
+
if (known.has(resolved)) {
|
|
12497
|
+
db.add("importsFile", [filePath, resolved]);
|
|
12498
|
+
}
|
|
12499
|
+
},
|
|
12500
|
+
into: (node) => node.type === "argument_list" ? import_extractor17.SKIP_CHILDREN : null
|
|
12501
|
+
});
|
|
12502
|
+
}
|
|
12503
|
+
function requiredRelativePath(node) {
|
|
12504
|
+
if (node.type !== "call" || field(node, "receiver") !== null || field(node, "method")?.text !== "require_relative") {
|
|
12505
|
+
return null;
|
|
12506
|
+
}
|
|
12507
|
+
const { positional } = readCallArgs(field(node, "arguments"));
|
|
12508
|
+
return positional[0] === void 0 ? null : stringLiteralValue(positional[0]);
|
|
12509
|
+
}
|
|
12510
|
+
|
|
11928
12511
|
// src/moduleSurface.ts
|
|
12512
|
+
var import_behavioral_ir8 = require("@suss/behavioral-ir");
|
|
12513
|
+
var import_extractor18 = require("@suss/extractor");
|
|
11929
12514
|
function settleRubyModules(modules) {
|
|
11930
|
-
return (0,
|
|
12515
|
+
return (0, import_extractor18.settleModules)(modules, ["{name}.rb", "../{name}.rb"]);
|
|
11931
12516
|
}
|
|
11932
12517
|
function moduleExportUnits(root, file, options) {
|
|
11933
|
-
const module2 = (0,
|
|
12518
|
+
const module2 = (0, import_extractor18.moduleOfFile)(options.modules, file);
|
|
11934
12519
|
if (module2 === void 0 || !module2.public.includes(file)) {
|
|
11935
12520
|
return [];
|
|
11936
12521
|
}
|
|
@@ -11958,7 +12543,7 @@ function moduleExportUnits(root, file, options) {
|
|
|
11958
12543
|
},
|
|
11959
12544
|
options,
|
|
11960
12545
|
(0, import_behavioral_ir8.moduleExportBinding)({
|
|
11961
|
-
recognition:
|
|
12546
|
+
recognition: import_extractor18.MODULE_SURFACE_RECOGNITION,
|
|
11962
12547
|
module: module2.name,
|
|
11963
12548
|
exportName: name
|
|
11964
12549
|
})
|
|
@@ -12266,7 +12851,7 @@ var WalkReplay = class {
|
|
|
12266
12851
|
};
|
|
12267
12852
|
|
|
12268
12853
|
// src/testFactories.ts
|
|
12269
|
-
var
|
|
12854
|
+
var import_values31 = require("@suss/values");
|
|
12270
12855
|
function factoriesIn(packs) {
|
|
12271
12856
|
return packs.flatMap((pack) => pack.factories ?? []);
|
|
12272
12857
|
}
|
|
@@ -12328,7 +12913,7 @@ function classRefOf(db, file, node) {
|
|
|
12328
12913
|
if (node.type === "constant" || node.type === "scope_resolution") {
|
|
12329
12914
|
return { key: readKey(file, node, null) };
|
|
12330
12915
|
}
|
|
12331
|
-
const written = (0,
|
|
12916
|
+
const written = (0, import_values31.literalOf)(evaluatedValue(node, db));
|
|
12332
12917
|
if (written === null) {
|
|
12333
12918
|
return null;
|
|
12334
12919
|
}
|
|
@@ -12337,7 +12922,7 @@ function classRefOf(db, file, node) {
|
|
|
12337
12922
|
};
|
|
12338
12923
|
}
|
|
12339
12924
|
function nameOf(db, node) {
|
|
12340
|
-
return symbolValue(node) ?? (0,
|
|
12925
|
+
return symbolValue(node) ?? (0, import_values31.literalOf)(evaluatedValue(node, db));
|
|
12341
12926
|
}
|
|
12342
12927
|
var FactoryClasses = class {
|
|
12343
12928
|
constructor(db, definitions, inflections) {
|
|
@@ -12409,7 +12994,7 @@ function builtAt(db, call, pattern) {
|
|
|
12409
12994
|
|
|
12410
12995
|
// src/testSharedGroups.ts
|
|
12411
12996
|
var import_resolution15 = require("@suss/resolution");
|
|
12412
|
-
var
|
|
12997
|
+
var import_values33 = require("@suss/values");
|
|
12413
12998
|
var ByNode = class {
|
|
12414
12999
|
byTree = /* @__PURE__ */ new WeakMap();
|
|
12415
13000
|
set(node, value) {
|
|
@@ -12513,7 +13098,7 @@ var SharedGroupIndex = class {
|
|
|
12513
13098
|
}
|
|
12514
13099
|
nameOf(call) {
|
|
12515
13100
|
const first = firstArgument(call);
|
|
12516
|
-
return first === null ? null : (0,
|
|
13101
|
+
return first === null ? null : (0, import_values33.literalOf)(evaluatedValue(first, this.db));
|
|
12517
13102
|
}
|
|
12518
13103
|
noteRead(definition) {
|
|
12519
13104
|
if (definition !== null) {
|
|
@@ -12523,12 +13108,12 @@ var SharedGroupIndex = class {
|
|
|
12523
13108
|
};
|
|
12524
13109
|
function emitSharedGroupBinds(db, index, files) {
|
|
12525
13110
|
for (const at of files) {
|
|
12526
|
-
for (const site of
|
|
13111
|
+
for (const site of sitesIn2(index, at)) {
|
|
12527
13112
|
emitSiteBinds(db, index, site, at.pattern);
|
|
12528
13113
|
}
|
|
12529
13114
|
}
|
|
12530
13115
|
}
|
|
12531
|
-
function
|
|
13116
|
+
function sitesIn2(index, at) {
|
|
12532
13117
|
const found = [];
|
|
12533
13118
|
const visit = (node) => {
|
|
12534
13119
|
for (const child of children(node)) {
|
|
@@ -12590,16 +13175,16 @@ function visibleAt(index, site, pattern) {
|
|
|
12590
13175
|
}
|
|
12591
13176
|
|
|
12592
13177
|
// src/version.ts
|
|
12593
|
-
var
|
|
13178
|
+
var import_extractor19 = require("@suss/extractor");
|
|
12594
13179
|
var ADAPTER_VERSION = "0.1.0";
|
|
12595
|
-
var adapterStamp = (0,
|
|
13180
|
+
var adapterStamp = (0, import_extractor19.createAdapterStamp)({
|
|
12596
13181
|
moduleUrl: importMetaUrl,
|
|
12597
13182
|
version: ADAPTER_VERSION
|
|
12598
13183
|
});
|
|
12599
13184
|
|
|
12600
13185
|
// src/project.ts
|
|
12601
13186
|
function keptRubyParses() {
|
|
12602
|
-
return new
|
|
13187
|
+
return new import_extractor20.KeptParses((root) => root.tree.delete());
|
|
12603
13188
|
}
|
|
12604
13189
|
async function parseRubyAhead(files, kept) {
|
|
12605
13190
|
for (const file of files) {
|
|
@@ -12704,7 +13289,7 @@ var RunFacts = class {
|
|
|
12704
13289
|
...this.testFiles.map(({ file }) => file),
|
|
12705
13290
|
...this.parsed.map(({ file }) => file).filter(
|
|
12706
13291
|
(file) => classTests.some(
|
|
12707
|
-
(one) => (0,
|
|
13292
|
+
(one) => (0, import_extractor20.matchesTestFileName)(file, one.filePatterns)
|
|
12708
13293
|
)
|
|
12709
13294
|
)
|
|
12710
13295
|
]);
|
|
@@ -12739,7 +13324,7 @@ function factsForFile(options) {
|
|
|
12739
13324
|
return facts.db;
|
|
12740
13325
|
}
|
|
12741
13326
|
function moduleInitUnit(options) {
|
|
12742
|
-
const raw = (0,
|
|
13327
|
+
const raw = (0, import_extractor20.moduleInitStructure)({
|
|
12743
13328
|
name: options.name,
|
|
12744
13329
|
file: options.file,
|
|
12745
13330
|
range: options.range,
|
|
@@ -12769,31 +13354,49 @@ function replaysCleanly(units, discovered) {
|
|
|
12769
13354
|
}
|
|
12770
13355
|
return true;
|
|
12771
13356
|
}
|
|
13357
|
+
function walkedFilesOf(options) {
|
|
13358
|
+
const given = new Set(options.files);
|
|
13359
|
+
const templates = [
|
|
13360
|
+
...new Set(options.packs.flatMap((pack) => pack.bootTemplates?.() ?? []))
|
|
13361
|
+
].filter((file) => !given.has(file)).sort();
|
|
13362
|
+
return {
|
|
13363
|
+
files: [...options.files, ...templates],
|
|
13364
|
+
templates: new Set(templates)
|
|
13365
|
+
};
|
|
13366
|
+
}
|
|
13367
|
+
function rubySourceOf(absPath, templates) {
|
|
13368
|
+
if (!import_node_fs3.default.existsSync(absPath)) {
|
|
13369
|
+
return null;
|
|
13370
|
+
}
|
|
13371
|
+
const text3 = import_node_fs3.default.readFileSync(absPath, "utf8");
|
|
13372
|
+
return templates.has(absPath) ? rubyInErbTemplate(text3) : text3;
|
|
13373
|
+
}
|
|
12772
13374
|
async function extractRubyProject(options) {
|
|
12773
|
-
const
|
|
13375
|
+
const walked = walkedFilesOf(options);
|
|
13376
|
+
const timer = options.onTiming !== void 0 ? (0, import_extractor20.createTimer)() : (0, import_extractor20.noopTimer)();
|
|
12774
13377
|
const cacheDir = adapterStamp.declineWhenRunFromSource(
|
|
12775
|
-
options.cacheDir === null ? null : options.cacheDir ?? (options.projectRoot !== void 0 ? (0,
|
|
13378
|
+
options.cacheDir === null ? null : options.cacheDir ?? (options.projectRoot !== void 0 ? (0, import_extractor20.extractionCacheDirFor)(options.projectRoot) : null)
|
|
12776
13379
|
);
|
|
12777
|
-
const layer = (0,
|
|
13380
|
+
const layer = (0, import_extractor20.createCacheLayer)(cacheDir);
|
|
12778
13381
|
const packsDigest = `${adapterStamp.packsDigest(
|
|
12779
13382
|
options.packs.map(
|
|
12780
13383
|
(pack) => pack.version !== void 0 ? { name: pack.name, version: pack.version } : { name: pack.name }
|
|
12781
13384
|
)
|
|
12782
|
-
)}|${(0,
|
|
13385
|
+
)}|${(0, import_extractor20.extractionConfigStamp)({
|
|
12783
13386
|
gapHandling: options.gapHandling,
|
|
12784
13387
|
workspaceRoot: options.workspaceRoot,
|
|
12785
13388
|
projectRoot: options.projectRoot,
|
|
12786
13389
|
modules: settleRubyModules(options.modules)
|
|
12787
13390
|
})}`;
|
|
12788
13391
|
const input = {
|
|
12789
|
-
files: cacheDir === null ? [] :
|
|
12790
|
-
adapterPacksDigest: cacheDir === null ? packsDigest : (0,
|
|
13392
|
+
files: cacheDir === null ? [] : walked.files,
|
|
13393
|
+
adapterPacksDigest: cacheDir === null ? packsDigest : (0, import_extractor20.runDigest)(packsDigest, options.packs, walked.files)
|
|
12791
13394
|
};
|
|
12792
13395
|
const lookup = await timer.timeAsync(
|
|
12793
13396
|
"cache.lookup",
|
|
12794
13397
|
() => layer.lookup(input)
|
|
12795
13398
|
);
|
|
12796
|
-
const composed = (stored) => (0,
|
|
13399
|
+
const composed = (stored) => (0, import_extractor20.composeWrappers)(stored, {
|
|
12797
13400
|
gapHandling: options.gapHandling ?? "permissive"
|
|
12798
13401
|
});
|
|
12799
13402
|
if (lookup.kind === "hit") {
|
|
@@ -12815,7 +13418,7 @@ async function extractRubyProject(options) {
|
|
|
12815
13418
|
const records = plan === null ? null : (0, import_resolution16.recordsToReplay)(plan.roots, plan.changed, plan.removed);
|
|
12816
13419
|
if (plan !== null && records !== null) {
|
|
12817
13420
|
try {
|
|
12818
|
-
return await runRuby(options, cache, { plan, records });
|
|
13421
|
+
return await runRuby(options, walked, cache, { plan, records });
|
|
12819
13422
|
} catch (error) {
|
|
12820
13423
|
if (!(error instanceof ReplayFailed)) {
|
|
12821
13424
|
throw error;
|
|
@@ -12823,7 +13426,7 @@ async function extractRubyProject(options) {
|
|
|
12823
13426
|
}
|
|
12824
13427
|
}
|
|
12825
13428
|
options.onCacheDiagnostic?.(lookup.diagnostic);
|
|
12826
|
-
return runRuby(options, cache, null);
|
|
13429
|
+
return runRuby(options, walked, cache, null);
|
|
12827
13430
|
}
|
|
12828
13431
|
function seedFromStored(seed, nodeOf) {
|
|
12829
13432
|
const node = nodeOf(seed.key);
|
|
@@ -12840,13 +13443,13 @@ function seedFromStored(seed, nodeOf) {
|
|
|
12840
13443
|
function addForSeed(bySeed, seedKey, summary) {
|
|
12841
13444
|
bySeed.set(seedKey, [...bySeed.get(seedKey) ?? [], summary]);
|
|
12842
13445
|
}
|
|
12843
|
-
async function runRuby(options, cache, previous) {
|
|
13446
|
+
async function runRuby(options, walked, cache, previous) {
|
|
12844
13447
|
const { timer, cacheDir } = cache;
|
|
12845
13448
|
const db = new import_datalog3.Database();
|
|
12846
13449
|
const summaries = [];
|
|
12847
13450
|
const gapHandling = options.gapHandling ?? "permissive";
|
|
12848
|
-
const tallies = (0,
|
|
12849
|
-
const ledger = cacheDir === null ? null : new import_resolution16.DependencyLedger(
|
|
13451
|
+
const tallies = (0, import_extractor13.createPackTallies)(options.packs);
|
|
13452
|
+
const ledger = cacheDir === null ? null : new import_resolution16.DependencyLedger(walked.files);
|
|
12850
13453
|
const log = ledger === null ? null : new import_resolution16.FactLog(db, ledger);
|
|
12851
13454
|
if (ledger !== null) {
|
|
12852
13455
|
(0, import_resolution16.observeDemand)(db, ledger);
|
|
@@ -12854,12 +13457,12 @@ async function runRuby(options, cache, previous) {
|
|
|
12854
13457
|
const parses = options.keptParses ?? keptRubyParses();
|
|
12855
13458
|
const trees = createFileCache(
|
|
12856
13459
|
(source, absPath) => parses.parse(absPath, source, parseRubyRoot),
|
|
12857
|
-
(absPath) =>
|
|
13460
|
+
(absPath) => rubySourceOf(absPath, walked.templates)
|
|
12858
13461
|
);
|
|
12859
13462
|
const fileCache = ledger === null ? trees : watchFileCache(trees, ledger);
|
|
12860
13463
|
const facts = new RunFacts(db, options.packs);
|
|
12861
13464
|
const { parsed, bodyBlocks, scopeCalls } = facts;
|
|
12862
|
-
for (const file of
|
|
13465
|
+
for (const file of walked.files) {
|
|
12863
13466
|
await timer.timeAsync("parse", async () => {
|
|
12864
13467
|
const root = await trees.get(file);
|
|
12865
13468
|
if (root !== null) {
|
|
@@ -12869,7 +13472,7 @@ async function runRuby(options, cache, previous) {
|
|
|
12869
13472
|
}
|
|
12870
13473
|
});
|
|
12871
13474
|
}
|
|
12872
|
-
options.keptParses?.keepOnly(
|
|
13475
|
+
options.keptParses?.keepOnly(walked.files);
|
|
12873
13476
|
const rootsByFile = new Map(parsed.map(({ file, root }) => [file, root]));
|
|
12874
13477
|
const dynamicNames = timer.time("discover", () => {
|
|
12875
13478
|
log?.startJoined();
|
|
@@ -12947,7 +13550,7 @@ async function runRuby(options, cache, previous) {
|
|
|
12947
13550
|
continue;
|
|
12948
13551
|
}
|
|
12949
13552
|
discovered.add(unit.dedup);
|
|
12950
|
-
(0,
|
|
13553
|
+
(0, import_extractor13.tallyUnit)(tallies, unit.recognition);
|
|
12951
13554
|
found.push({
|
|
12952
13555
|
replayed: unit.summary ?? null,
|
|
12953
13556
|
seedKey: unit.seed?.key ?? null
|
|
@@ -12995,6 +13598,16 @@ async function runRuby(options, cache, previous) {
|
|
|
12995
13598
|
displayPathOf,
|
|
12996
13599
|
facts: db,
|
|
12997
13600
|
onReachSeed
|
|
13601
|
+
}),
|
|
13602
|
+
...declaredEntryUnits(root, file, {
|
|
13603
|
+
packs: options.packs,
|
|
13604
|
+
...storage === void 0 ? {} : { storage },
|
|
13605
|
+
inheritedMethods,
|
|
13606
|
+
bodyBlocks,
|
|
13607
|
+
dynamicNames: watchedNames,
|
|
13608
|
+
displayPathOf,
|
|
13609
|
+
facts: db,
|
|
13610
|
+
onReachSeed
|
|
12998
13611
|
})
|
|
12999
13612
|
];
|
|
13000
13613
|
const rawUnits = await timer.timeAsync(
|
|
@@ -13028,7 +13641,7 @@ async function runRuby(options, cache, previous) {
|
|
|
13028
13641
|
continue;
|
|
13029
13642
|
}
|
|
13030
13643
|
discovered.add(dedup);
|
|
13031
|
-
(0,
|
|
13644
|
+
(0, import_extractor13.tallyUnit)(tallies, recognition);
|
|
13032
13645
|
found.push({ raw, seedKey, draft: units[units.length - 1] });
|
|
13033
13646
|
if (seed !== void 0 && seedKey !== null && !seedKeys.has(seedKey)) {
|
|
13034
13647
|
seedKeys.add(seedKey);
|
|
@@ -13043,7 +13656,7 @@ async function runRuby(options, cache, previous) {
|
|
|
13043
13656
|
seedKeys.add(moduleKey);
|
|
13044
13657
|
seeds.push(moduleSeed);
|
|
13045
13658
|
const readLoadTime = () => ({
|
|
13046
|
-
reads: envReadEffects(root, { db, file }),
|
|
13659
|
+
reads: envReadEffects(root, { db, file }).map((one) => one.effect),
|
|
13047
13660
|
calls: moduleScopeInvocationEffects(
|
|
13048
13661
|
root,
|
|
13049
13662
|
inheritedMethods,
|
|
@@ -13091,7 +13704,7 @@ async function runRuby(options, cache, previous) {
|
|
|
13091
13704
|
}
|
|
13092
13705
|
const summary = timer.time(
|
|
13093
13706
|
"summarize",
|
|
13094
|
-
() => (0,
|
|
13707
|
+
() => (0, import_extractor20.assembleSummary)(routingGapUnit(pattern, gaps), { gapHandling })
|
|
13095
13708
|
);
|
|
13096
13709
|
summary.confidence = { source: "inferred_static", level: "low" };
|
|
13097
13710
|
found.push({ summary });
|
|
@@ -13147,7 +13760,7 @@ async function runRuby(options, cache, previous) {
|
|
|
13147
13760
|
}
|
|
13148
13761
|
const summary = timer.time(
|
|
13149
13762
|
"summarize",
|
|
13150
|
-
() => (0,
|
|
13763
|
+
() => (0, import_extractor20.assembleSummary)(raw, { gapHandling })
|
|
13151
13764
|
);
|
|
13152
13765
|
summaries.push(summary);
|
|
13153
13766
|
assembledHere.add(summary);
|
|
@@ -13194,8 +13807,8 @@ async function runRuby(options, cache, previous) {
|
|
|
13194
13807
|
throw new ReplayFailed("");
|
|
13195
13808
|
}
|
|
13196
13809
|
const dependencies = (0, import_resolution16.importedFilesByFile)(db, displayPathOf);
|
|
13197
|
-
(0,
|
|
13198
|
-
(0,
|
|
13810
|
+
(0, import_extractor20.stampModuleImports)(summaries, (file) => dependencies.get(file) ?? []);
|
|
13811
|
+
(0, import_extractor20.stampModules)(summaries, declaredModules, options.workspaceRoot);
|
|
13199
13812
|
const idRoot = options.projectRoot ?? options.workspaceRoot;
|
|
13200
13813
|
for (const summary of summaries) {
|
|
13201
13814
|
const absoluteFile = options.workspaceRoot === void 0 ? summary.location.file : import_node_path4.default.resolve(options.workspaceRoot, summary.location.file);
|
|
@@ -13215,7 +13828,7 @@ async function runRuby(options, cache, previous) {
|
|
|
13215
13828
|
db,
|
|
13216
13829
|
options.workspaceRoot
|
|
13217
13830
|
);
|
|
13218
|
-
return (0,
|
|
13831
|
+
return (0, import_extractor20.composeWrappers)(summaries, { gapHandling });
|
|
13219
13832
|
});
|
|
13220
13833
|
const walkedFiles = new Map(
|
|
13221
13834
|
parsed.map(({ file }) => [displayPathOf(file), file])
|
|
@@ -13275,7 +13888,7 @@ async function runRuby(options, cache, previous) {
|
|
|
13275
13888
|
buildRubyExtractionReport({
|
|
13276
13889
|
packs: options.packs,
|
|
13277
13890
|
tallies,
|
|
13278
|
-
filesWalked:
|
|
13891
|
+
filesWalked: walked.files.length,
|
|
13279
13892
|
summaries: composed
|
|
13280
13893
|
})
|
|
13281
13894
|
);
|
|
@@ -13307,7 +13920,7 @@ function rubyAttribution(args) {
|
|
|
13307
13920
|
}));
|
|
13308
13921
|
return {
|
|
13309
13922
|
roots,
|
|
13310
|
-
owners: (0,
|
|
13923
|
+
owners: (0, import_extractor20.ownersWhereWritten)(args.summaries, args.walkedFileOf)
|
|
13311
13924
|
};
|
|
13312
13925
|
}
|
|
13313
13926
|
var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set(["vendor", "node_modules", "tmp", ".git"]);
|
|
@@ -13501,7 +14114,7 @@ var RubyWhySession = class {
|
|
|
13501
14114
|
// src/stubEvidence.ts
|
|
13502
14115
|
var import_node_fs5 = __toESM(require("fs"), 1);
|
|
13503
14116
|
var import_node_path6 = __toESM(require("path"), 1);
|
|
13504
|
-
var
|
|
14117
|
+
var import_extractor21 = require("@suss/extractor");
|
|
13505
14118
|
function bareLetters(name) {
|
|
13506
14119
|
return name.replaceAll(/[-_]/g, "").toLowerCase();
|
|
13507
14120
|
}
|
|
@@ -13525,14 +14138,14 @@ function requireTarget(node) {
|
|
|
13525
14138
|
}
|
|
13526
14139
|
function requireSitesIn(root, file) {
|
|
13527
14140
|
const found = [];
|
|
13528
|
-
(0,
|
|
14141
|
+
(0, import_extractor21.walkDescendants)(root, null, children, {
|
|
13529
14142
|
at: (node) => {
|
|
13530
14143
|
const target = requireTarget(node);
|
|
13531
14144
|
if (target !== null) {
|
|
13532
14145
|
found.push({ target, file, line: rangeOf(node).start });
|
|
13533
14146
|
}
|
|
13534
14147
|
},
|
|
13535
|
-
into: (node) => node.type === "argument_list" ?
|
|
14148
|
+
into: (node) => node.type === "argument_list" ? import_extractor21.SKIP_CHILDREN : null
|
|
13536
14149
|
});
|
|
13537
14150
|
return found;
|
|
13538
14151
|
}
|