@suss/adapter-typescript 0.21.1 → 0.22.1
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 -35
- package/dist/index.cjs +934 -1508
- package/dist/index.d.cts +74 -414
- package/dist/index.d.ts +74 -414
- package/dist/index.js +868 -1424
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/adapter.ts
|
|
2
|
-
import
|
|
2
|
+
import path10 from "path";
|
|
3
3
|
import {
|
|
4
4
|
Node as Node64,
|
|
5
5
|
Project,
|
|
@@ -21,7 +21,10 @@ import {
|
|
|
21
21
|
import { Database as Database5 } from "@suss/datalog";
|
|
22
22
|
import {
|
|
23
23
|
assembleSummary as assembleSummary3,
|
|
24
|
-
composeWrappers
|
|
24
|
+
composeWrappers,
|
|
25
|
+
createCacheLayer,
|
|
26
|
+
runDigest,
|
|
27
|
+
stampModuleImports
|
|
25
28
|
} from "@suss/extractor";
|
|
26
29
|
|
|
27
30
|
// src/assembly.ts
|
|
@@ -40,6 +43,7 @@ import { Node as Node5, SyntaxKind as SyntaxKind2 } from "ts-morph";
|
|
|
40
43
|
import { Node as Node2, SyntaxKind } from "ts-morph";
|
|
41
44
|
|
|
42
45
|
// src/walk/nodeKeys.ts
|
|
46
|
+
import { declarationKey } from "@suss/behavioral-ir";
|
|
43
47
|
function offsetKeyOf(node) {
|
|
44
48
|
return offsetKeyFor(node.getSourceFile().getFilePath(), {
|
|
45
49
|
start: node.getStart(),
|
|
@@ -47,7 +51,7 @@ function offsetKeyOf(node) {
|
|
|
47
51
|
});
|
|
48
52
|
}
|
|
49
53
|
function offsetKeyFor(file, span) {
|
|
50
|
-
return
|
|
54
|
+
return declarationKey(file, span);
|
|
51
55
|
}
|
|
52
56
|
function lineRangeKey(file, startLine, endLine) {
|
|
53
57
|
return `${file}:${startLine}-${endLine}`;
|
|
@@ -1867,8 +1871,8 @@ function loadImportGraphsDepthFirstFromPaths(project, rootPaths) {
|
|
|
1867
1871
|
stack.pop();
|
|
1868
1872
|
loadOrder.push(top.path);
|
|
1869
1873
|
let deepest = 0;
|
|
1870
|
-
for (const
|
|
1871
|
-
deepest = Math.max(deepest, chainDepth.get(
|
|
1874
|
+
for (const path14 of top.deps) {
|
|
1875
|
+
deepest = Math.max(deepest, chainDepth.get(path14) ?? 0);
|
|
1872
1876
|
}
|
|
1873
1877
|
chainDepth.set(top.path, deepest + 1);
|
|
1874
1878
|
}
|
|
@@ -2220,11 +2224,11 @@ function walkAndWarm(root, reach) {
|
|
|
2220
2224
|
if (warmedFiles.get(target) !== void 0) {
|
|
2221
2225
|
continue;
|
|
2222
2226
|
}
|
|
2223
|
-
const
|
|
2224
|
-
if (visited.has(
|
|
2227
|
+
const path14 = target.getFilePath();
|
|
2228
|
+
if (visited.has(path14)) {
|
|
2225
2229
|
continue;
|
|
2226
2230
|
}
|
|
2227
|
-
visited.add(
|
|
2231
|
+
visited.add(path14);
|
|
2228
2232
|
stack.push(frameOf(target, reach));
|
|
2229
2233
|
continue;
|
|
2230
2234
|
}
|
|
@@ -2241,7 +2245,7 @@ function sitsOnWarmChains(file) {
|
|
|
2241
2245
|
return false;
|
|
2242
2246
|
}
|
|
2243
2247
|
const imported = importedFilePathsOf(project, file.getFilePath());
|
|
2244
|
-
return imported.length > 0 && imported.every((
|
|
2248
|
+
return imported.length > 0 && imported.every((path14) => warmed.has(path14));
|
|
2245
2249
|
}
|
|
2246
2250
|
function markWarmed(file) {
|
|
2247
2251
|
warmedFiles.set(file, true);
|
|
@@ -2558,6 +2562,32 @@ function writesToBindingUncached(declaration) {
|
|
|
2558
2562
|
}
|
|
2559
2563
|
return { values, inOrder: writesRunInOrder(declaration, writes) };
|
|
2560
2564
|
}
|
|
2565
|
+
function sameConstructionAcrossWrites(values) {
|
|
2566
|
+
const candidates = values.filter((value) => !isNotYetPlaceholder(value));
|
|
2567
|
+
if (candidates.length === 0) {
|
|
2568
|
+
return null;
|
|
2569
|
+
}
|
|
2570
|
+
let construction = null;
|
|
2571
|
+
for (const value of candidates) {
|
|
2572
|
+
if (!isConstruction(value)) {
|
|
2573
|
+
return null;
|
|
2574
|
+
}
|
|
2575
|
+
if (construction !== null && sourceOf(value) !== sourceOf(construction)) {
|
|
2576
|
+
return null;
|
|
2577
|
+
}
|
|
2578
|
+
construction = value;
|
|
2579
|
+
}
|
|
2580
|
+
return construction;
|
|
2581
|
+
}
|
|
2582
|
+
function isNotYetPlaceholder(value) {
|
|
2583
|
+
return value.getKind() === SyntaxKind3.NullKeyword || Node13.isIdentifier(value) && value.getText() === "undefined";
|
|
2584
|
+
}
|
|
2585
|
+
function isConstruction(value) {
|
|
2586
|
+
return Node13.isCallExpression(value) || Node13.isNewExpression(value);
|
|
2587
|
+
}
|
|
2588
|
+
function sourceOf(node) {
|
|
2589
|
+
return node.getText().replace(/\s+/g, " ").trim();
|
|
2590
|
+
}
|
|
2561
2591
|
function writesToField(declaration) {
|
|
2562
2592
|
const remembered = byField.get(declaration);
|
|
2563
2593
|
if (remembered !== void 0) {
|
|
@@ -2648,6 +2678,9 @@ function assignmentsInFile(sourceFile) {
|
|
|
2648
2678
|
function isAssignmentOperator(kind) {
|
|
2649
2679
|
return kind >= SyntaxKind3.FirstAssignment && kind <= SyntaxKind3.LastAssignment;
|
|
2650
2680
|
}
|
|
2681
|
+
function writesItsWholeValue(kind) {
|
|
2682
|
+
return kind === SyntaxKind3.EqualsToken || kind === SyntaxKind3.QuestionQuestionEqualsToken || kind === SyntaxKind3.BarBarEqualsToken;
|
|
2683
|
+
}
|
|
2651
2684
|
function writeAt(node) {
|
|
2652
2685
|
if (Node13.isBinaryExpression(node)) {
|
|
2653
2686
|
const operator = node.getOperatorToken().getKind();
|
|
@@ -2655,7 +2688,7 @@ function writeAt(node) {
|
|
|
2655
2688
|
if (!isAssignmentOperator(operator) || !(Node13.isIdentifier(target) || Node13.isPropertyAccessExpression(target))) {
|
|
2656
2689
|
return null;
|
|
2657
2690
|
}
|
|
2658
|
-
const value = operator
|
|
2691
|
+
const value = writesItsWholeValue(operator) ? node.getRight() : null;
|
|
2659
2692
|
return { target, write: { value, node } };
|
|
2660
2693
|
}
|
|
2661
2694
|
if (Node13.isPrefixUnaryExpression(node) || Node13.isPostfixUnaryExpression(node)) {
|
|
@@ -3046,11 +3079,16 @@ function emitBindingValues(db, table, declaration) {
|
|
|
3046
3079
|
}
|
|
3047
3080
|
const { values, inOrder } = writesToBinding(declaration);
|
|
3048
3081
|
const last = values[values.length - 1];
|
|
3049
|
-
if (
|
|
3050
|
-
|
|
3082
|
+
if (inOrder && last !== void 0) {
|
|
3083
|
+
fact(db, "endsHolding", declarationId, emitValue(db, table, last));
|
|
3084
|
+
return;
|
|
3085
|
+
}
|
|
3086
|
+
const construction = sameConstructionAcrossWrites(values);
|
|
3087
|
+
if (construction !== null) {
|
|
3088
|
+
fact(db, "endsHolding", declarationId, emitValue(db, table, construction));
|
|
3051
3089
|
return;
|
|
3052
3090
|
}
|
|
3053
|
-
|
|
3091
|
+
reassignedUnstated.add(declarationId);
|
|
3054
3092
|
}
|
|
3055
3093
|
var reassignedUnstated = /* @__PURE__ */ new Set();
|
|
3056
3094
|
function reassignedNamesUnstated() {
|
|
@@ -3062,23 +3100,31 @@ function forgetReassignedNamesUnstated() {
|
|
|
3062
3100
|
function emitFieldValues(db, table, declaration) {
|
|
3063
3101
|
const { values, inOrder } = writesToField(declaration);
|
|
3064
3102
|
const last = values[values.length - 1];
|
|
3065
|
-
if (
|
|
3103
|
+
if (inOrder && last !== void 0 && Node14.isExpression(last)) {
|
|
3104
|
+
fact(db, "binds", nodeId(declaration), emitValue(db, table, last));
|
|
3066
3105
|
return;
|
|
3067
3106
|
}
|
|
3068
|
-
|
|
3107
|
+
const construction = sameConstructionAcrossWrites(values);
|
|
3108
|
+
if (construction !== null) {
|
|
3109
|
+
fact(db, "binds", nodeId(declaration), emitValue(db, table, construction));
|
|
3110
|
+
}
|
|
3069
3111
|
}
|
|
3070
3112
|
function emitParameterPropertyRead(db, table, referenceId, declaration) {
|
|
3071
3113
|
const { values, inOrder } = writesToField(declaration);
|
|
3072
3114
|
const last = values[values.length - 1];
|
|
3073
|
-
if (
|
|
3115
|
+
if (inOrder && last !== void 0 && Node14.isExpression(last)) {
|
|
3116
|
+
fact(db, "binds", referenceId, emitValue(db, table, last));
|
|
3074
3117
|
return;
|
|
3075
3118
|
}
|
|
3076
|
-
if (
|
|
3119
|
+
if (inOrder && last !== void 0) {
|
|
3077
3120
|
table.byId.set(nodeId(last), last);
|
|
3078
3121
|
fact(db, "binds", referenceId, nodeId(last));
|
|
3079
3122
|
return;
|
|
3080
3123
|
}
|
|
3081
|
-
|
|
3124
|
+
const construction = sameConstructionAcrossWrites(values);
|
|
3125
|
+
if (construction !== null) {
|
|
3126
|
+
fact(db, "binds", referenceId, emitValue(db, table, construction));
|
|
3127
|
+
}
|
|
3082
3128
|
}
|
|
3083
3129
|
function emitBindingElementFacts(db, table, element) {
|
|
3084
3130
|
const id = nodeId(element);
|
|
@@ -3542,7 +3588,8 @@ var JS_RULES = [
|
|
|
3542
3588
|
];
|
|
3543
3589
|
var RESOLUTION_PROGRAM = process.env.SUSS_RESOLUTION_ON_DEMAND === "0" ? {
|
|
3544
3590
|
rules: [...SHARED_RULES, ...JS_RULES, ...RESOLUTION_QUESTIONS],
|
|
3545
|
-
demandDriven: []
|
|
3591
|
+
demandDriven: [],
|
|
3592
|
+
demands: []
|
|
3546
3593
|
} : deriveOnDemand(
|
|
3547
3594
|
[...SHARED_RULES, ...JS_RULES, ...RESOLUTION_QUESTIONS],
|
|
3548
3595
|
ANSWER_RELATIONS
|
|
@@ -3569,7 +3616,9 @@ var QUERY_FACTS = RESOLUTION_PROGRAM.demandDriven.length === 0 ? [] : [
|
|
|
3569
3616
|
"wantedAnchor",
|
|
3570
3617
|
"wantedSubject"
|
|
3571
3618
|
];
|
|
3572
|
-
var
|
|
3619
|
+
var MODULE_DEMANDS = RESOLUTION_PROGRAM.demands.filter(
|
|
3620
|
+
(one) => (one.relation === "moduleExport" || one.relation === "moduleForwards") && one.bound[0] === true
|
|
3621
|
+
).map((one) => one.demand);
|
|
3573
3622
|
var ResolutionStore = class {
|
|
3574
3623
|
db = new Database2();
|
|
3575
3624
|
table = createNodeTable();
|
|
@@ -3585,7 +3634,7 @@ var ResolutionStore = class {
|
|
|
3585
3634
|
* extraction elsewhere cannot change an entry.
|
|
3586
3635
|
*/
|
|
3587
3636
|
exportTables = /* @__PURE__ */ new Map();
|
|
3588
|
-
/** Files the most recent
|
|
3637
|
+
/** Files the most recent query read, for the memo to keep. */
|
|
3589
3638
|
lastQueryWalked = [];
|
|
3590
3639
|
declarations = /* @__PURE__ */ new Map();
|
|
3591
3640
|
graph = new ModuleGraph();
|
|
@@ -3616,19 +3665,19 @@ var ResolutionStore = class {
|
|
|
3616
3665
|
*/
|
|
3617
3666
|
resolveCallableSources(value, alsoFrom) {
|
|
3618
3667
|
const target = factKeyOf(value);
|
|
3619
|
-
return this.
|
|
3668
|
+
return this.askAbout(
|
|
3620
3669
|
target,
|
|
3621
3670
|
"wanted",
|
|
3622
3671
|
() => this.lookupSources(target),
|
|
3623
3672
|
alsoFrom
|
|
3624
|
-
)
|
|
3673
|
+
);
|
|
3625
3674
|
}
|
|
3626
3675
|
/**
|
|
3627
3676
|
* The witness proof behind `resolveCallable`'s answer. Resolves the
|
|
3628
|
-
* value first, which
|
|
3629
|
-
*
|
|
3630
|
-
*
|
|
3631
|
-
*
|
|
3677
|
+
* value first, which extracts the files the question demands, then
|
|
3678
|
+
* re-evaluates the rules over those base facts under the witness
|
|
3679
|
+
* algebra and rebuilds the proof of the answer. Null when the value
|
|
3680
|
+
* does not resolve at all.
|
|
3632
3681
|
*/
|
|
3633
3682
|
explainCallable(value, options = {}) {
|
|
3634
3683
|
const resolved = this.resolveCallable(value, options.alsoFrom);
|
|
@@ -3665,11 +3714,7 @@ var ResolutionStore = class {
|
|
|
3665
3714
|
}
|
|
3666
3715
|
resolveObject(value) {
|
|
3667
3716
|
const target = factKeyOf(value);
|
|
3668
|
-
return this.
|
|
3669
|
-
target,
|
|
3670
|
-
"wanted",
|
|
3671
|
-
() => this.lookupObject(target)
|
|
3672
|
-
);
|
|
3717
|
+
return this.askAbout(target, "wanted", () => this.lookupObject(target));
|
|
3673
3718
|
}
|
|
3674
3719
|
/**
|
|
3675
3720
|
* For a value that is neither a function nor an object, such as a
|
|
@@ -3685,17 +3730,17 @@ var ResolutionStore = class {
|
|
|
3685
3730
|
}
|
|
3686
3731
|
return cached.written;
|
|
3687
3732
|
}
|
|
3688
|
-
const
|
|
3733
|
+
const written = this.askAbout(
|
|
3689
3734
|
target,
|
|
3690
3735
|
"wanted",
|
|
3691
3736
|
() => this.lookupWritten(target)
|
|
3692
3737
|
);
|
|
3693
3738
|
this.writtenValues.set(key, {
|
|
3694
|
-
written
|
|
3739
|
+
written,
|
|
3695
3740
|
walked: [...this.lastQueryWalked],
|
|
3696
3741
|
extractedAt: this.fullyExtracted.size
|
|
3697
3742
|
});
|
|
3698
|
-
return
|
|
3743
|
+
return written;
|
|
3699
3744
|
}
|
|
3700
3745
|
/**
|
|
3701
3746
|
* The construction behind a registration subject: the call or `new`
|
|
@@ -3715,18 +3760,29 @@ var ResolutionStore = class {
|
|
|
3715
3760
|
}
|
|
3716
3761
|
return cached.construction;
|
|
3717
3762
|
}
|
|
3718
|
-
const settled2 = this.
|
|
3763
|
+
const settled2 = this.askAbout(
|
|
3719
3764
|
target,
|
|
3720
3765
|
"wantedSubject",
|
|
3721
3766
|
() => this.lookupSubjectConstruction(target, importModule, importName)
|
|
3722
3767
|
);
|
|
3768
|
+
const walked = [...this.lastQueryWalked];
|
|
3769
|
+
let resolved = settled2;
|
|
3770
|
+
if (settled2.construction === null && settled2.candidate !== null && Node15.isCallExpression(settled2.candidate) && this.resolveCallable(settled2.candidate.getExpression()) !== null) {
|
|
3771
|
+
const call = settled2.candidate;
|
|
3772
|
+
resolved = this.askAbout(
|
|
3773
|
+
call,
|
|
3774
|
+
"wantedSubject",
|
|
3775
|
+
() => this.lookupSubjectConstruction(call, importModule, importName)
|
|
3776
|
+
);
|
|
3777
|
+
walked.push(...this.lastQueryWalked);
|
|
3778
|
+
}
|
|
3723
3779
|
this.subjectConstructions.set(key, {
|
|
3724
|
-
construction:
|
|
3725
|
-
candidates:
|
|
3726
|
-
walked
|
|
3780
|
+
construction: resolved.construction,
|
|
3781
|
+
candidates: resolved.candidates,
|
|
3782
|
+
walked,
|
|
3727
3783
|
extractedAt: this.fullyExtracted.size
|
|
3728
3784
|
});
|
|
3729
|
-
return
|
|
3785
|
+
return resolved.construction;
|
|
3730
3786
|
}
|
|
3731
3787
|
/**
|
|
3732
3788
|
* How many constructions this value was written as, which is what
|
|
@@ -3740,10 +3796,8 @@ var ResolutionStore = class {
|
|
|
3740
3796
|
)?.candidates ?? 0;
|
|
3741
3797
|
}
|
|
3742
3798
|
/**
|
|
3743
|
-
* The single-answer policy over the written-value
|
|
3744
|
-
* origin check on the one candidate.
|
|
3745
|
-
* is settled refusal rather than a reason to widen: its own file's
|
|
3746
|
-
* import facts are already in, and more files only add candidates.
|
|
3799
|
+
* The single-answer policy over the written-value chain, then the
|
|
3800
|
+
* origin check on the one candidate.
|
|
3747
3801
|
*/
|
|
3748
3802
|
lookupSubjectConstruction(value, importModule, importName) {
|
|
3749
3803
|
this.derive();
|
|
@@ -3759,6 +3813,7 @@ var ResolutionStore = class {
|
|
|
3759
3813
|
if (candidates.size > 1) {
|
|
3760
3814
|
return {
|
|
3761
3815
|
construction: null,
|
|
3816
|
+
candidate: null,
|
|
3762
3817
|
candidates: [...candidates].filter(
|
|
3763
3818
|
(one) => this.constructionComesFrom(valueId, one, importModule, importName)
|
|
3764
3819
|
).length
|
|
@@ -3766,7 +3821,7 @@ var ResolutionStore = class {
|
|
|
3766
3821
|
}
|
|
3767
3822
|
const single = [...candidates][0];
|
|
3768
3823
|
if (single === void 0) {
|
|
3769
|
-
return
|
|
3824
|
+
return { construction: null, candidate: null, candidates: 0 };
|
|
3770
3825
|
}
|
|
3771
3826
|
return {
|
|
3772
3827
|
construction: this.constructionComesFrom(
|
|
@@ -3775,6 +3830,7 @@ var ResolutionStore = class {
|
|
|
3775
3830
|
importModule,
|
|
3776
3831
|
importName
|
|
3777
3832
|
) ? single : null,
|
|
3833
|
+
candidate: single,
|
|
3778
3834
|
candidates: 1
|
|
3779
3835
|
};
|
|
3780
3836
|
}
|
|
@@ -3834,11 +3890,11 @@ var ResolutionStore = class {
|
|
|
3834
3890
|
return cached.names;
|
|
3835
3891
|
}
|
|
3836
3892
|
const target = factKeyOf(value);
|
|
3837
|
-
const found = this.
|
|
3893
|
+
const found = this.askAbout(
|
|
3838
3894
|
target,
|
|
3839
3895
|
"wantedOrigin",
|
|
3840
3896
|
() => this.lookupImportedNames(target, modules)
|
|
3841
|
-
)
|
|
3897
|
+
);
|
|
3842
3898
|
this.importedNames.set(declaration, {
|
|
3843
3899
|
names: found,
|
|
3844
3900
|
walked: [...this.lastQueryWalked]
|
|
@@ -3857,8 +3913,8 @@ var ResolutionStore = class {
|
|
|
3857
3913
|
return this.importOriginsOfMany([value], modules).get(value) ?? [];
|
|
3858
3914
|
}
|
|
3859
3915
|
/**
|
|
3860
|
-
* The batched form: one demand set, one derivation, one
|
|
3861
|
-
*
|
|
3916
|
+
* The batched form: one demand set, one derivation, one round of
|
|
3917
|
+
* extraction shared by every value. A discovery pass asks about every
|
|
3862
3918
|
* callee in a file, and per-value queries would re-pay demand
|
|
3863
3919
|
* clearing and re-derivation once per call site.
|
|
3864
3920
|
*/
|
|
@@ -3886,49 +3942,12 @@ var ResolutionStore = class {
|
|
|
3886
3942
|
this.wantValue("wantedCallOrigin", one.target);
|
|
3887
3943
|
this.seedValue(one.target);
|
|
3888
3944
|
}
|
|
3889
|
-
|
|
3890
|
-
this.lastQueryWalked = [];
|
|
3891
|
-
let frontier = [];
|
|
3945
|
+
this.extractDemanded(pending.map((one) => one.target.getSourceFile()));
|
|
3892
3946
|
for (const one of pending) {
|
|
3893
|
-
const
|
|
3894
|
-
|
|
3895
|
-
frontier.push(file);
|
|
3896
|
-
}
|
|
3897
|
-
}
|
|
3898
|
-
const open = new Set(pending);
|
|
3899
|
-
for (let hop = 0; hop <= MAX_MODULE_HOPS && open.size > 0; hop++) {
|
|
3900
|
-
const next = [];
|
|
3901
|
-
for (const sourceFile of frontier) {
|
|
3902
|
-
if (walked.has(sourceFile.getFilePath())) {
|
|
3903
|
-
continue;
|
|
3904
|
-
}
|
|
3905
|
-
walked.add(sourceFile.getFilePath());
|
|
3906
|
-
this.lastQueryWalked.push(sourceFile.getFilePath());
|
|
3907
|
-
recordFileDependency(sourceFile.getFilePath());
|
|
3908
|
-
this.extractFile(sourceFile);
|
|
3909
|
-
next.push(...this.graph.importedFilesOf(sourceFile));
|
|
3910
|
-
}
|
|
3911
|
-
for (const one of [...open]) {
|
|
3912
|
-
const found = this.lookupImportOrigins(one.target, modules);
|
|
3913
|
-
if (found !== null) {
|
|
3914
|
-
results.set(one.value, found);
|
|
3915
|
-
this.importOrigins.set(one.key, {
|
|
3916
|
-
origins: found,
|
|
3917
|
-
walked: [...this.lastQueryWalked],
|
|
3918
|
-
extractedAt: this.fullyExtracted.size
|
|
3919
|
-
});
|
|
3920
|
-
open.delete(one);
|
|
3921
|
-
}
|
|
3922
|
-
}
|
|
3923
|
-
if (next.length === 0) {
|
|
3924
|
-
break;
|
|
3925
|
-
}
|
|
3926
|
-
frontier = next;
|
|
3927
|
-
}
|
|
3928
|
-
for (const one of open) {
|
|
3929
|
-
results.set(one.value, []);
|
|
3947
|
+
const origins = this.lookupImportOrigins(one.target, modules);
|
|
3948
|
+
results.set(one.value, origins);
|
|
3930
3949
|
this.importOrigins.set(one.key, {
|
|
3931
|
-
origins
|
|
3950
|
+
origins,
|
|
3932
3951
|
walked: [...this.lastQueryWalked],
|
|
3933
3952
|
extractedAt: this.fullyExtracted.size
|
|
3934
3953
|
});
|
|
@@ -3987,67 +4006,89 @@ var ResolutionStore = class {
|
|
|
3987
4006
|
const refined = new Set(
|
|
3988
4007
|
[...byPath.values()].filter((one) => one.path.length > 1).map((one) => tupleKey(one.path.slice(0, -1)))
|
|
3989
4008
|
);
|
|
3990
|
-
|
|
3991
|
-
if (origins.length > 0) {
|
|
3992
|
-
return origins;
|
|
3993
|
-
}
|
|
3994
|
-
return all.some((one) => namesAPackage(one.module)) ? [] : null;
|
|
4009
|
+
return [...byPath.values()].filter((one) => !refined.has(tupleKey(one.path))).sort((a, b) => a.path.join(".").localeCompare(b.path.join(".")));
|
|
3995
4010
|
}
|
|
3996
|
-
/**
|
|
3997
|
-
* Null tells the walk to keep widening. A value that landed in a
|
|
3998
|
-
* package returns empty instead, because a library's own body is not
|
|
3999
|
-
* here to read and widening would never find anything.
|
|
4000
|
-
*/
|
|
4001
4011
|
lookupImportedNames(value, modules) {
|
|
4002
4012
|
this.derive();
|
|
4003
|
-
const
|
|
4004
|
-
|
|
4013
|
+
const reached = new Set(
|
|
4014
|
+
this.answerPairsFor("wantedComesFrom", nodeId(value))
|
|
4015
|
+
);
|
|
4005
4016
|
for (const target of this.answersFor("wantedComesTo", nodeId(value))) {
|
|
4006
4017
|
for (const entry of this.answerPairsFor("wantedCallsInto", target)) {
|
|
4007
4018
|
reached.add(entry);
|
|
4008
4019
|
}
|
|
4009
4020
|
}
|
|
4010
|
-
|
|
4011
|
-
if (names.length > 0) {
|
|
4012
|
-
return names;
|
|
4013
|
-
}
|
|
4014
|
-
return origins.some((pair) => namesAPackage(pairHalves(pair).module)) ? [] : null;
|
|
4021
|
+
return namesFrom([...reached], modules);
|
|
4015
4022
|
}
|
|
4016
|
-
|
|
4023
|
+
askAbout(value, question, read2, alsoFrom) {
|
|
4017
4024
|
try {
|
|
4018
|
-
|
|
4025
|
+
this.wantValue(question, value);
|
|
4026
|
+
this.seedValue(value);
|
|
4027
|
+
this.extractDemanded(
|
|
4028
|
+
alsoFrom === void 0 ? [value.getSourceFile()] : [value.getSourceFile(), alsoFrom]
|
|
4029
|
+
);
|
|
4030
|
+
return read2();
|
|
4019
4031
|
} finally {
|
|
4020
4032
|
this.forgetQuery();
|
|
4021
4033
|
}
|
|
4022
4034
|
}
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4035
|
+
/**
|
|
4036
|
+
* Extract the seed files, then every module the rules ask for, until
|
|
4037
|
+
* they ask for nothing new. The files a question reads are then fixed
|
|
4038
|
+
* by the question alone, so its answer does not depend on what an
|
|
4039
|
+
* earlier question left in the store.
|
|
4040
|
+
*/
|
|
4041
|
+
extractDemanded(seeds) {
|
|
4042
|
+
const project = seeds[0]?.getProject();
|
|
4043
|
+
if (project === void 0) {
|
|
4044
|
+
return;
|
|
4045
|
+
}
|
|
4046
|
+
const read2 = /* @__PURE__ */ new Set();
|
|
4047
|
+
const considered = /* @__PURE__ */ new Set();
|
|
4027
4048
|
this.lastQueryWalked = [];
|
|
4028
|
-
let
|
|
4029
|
-
|
|
4030
|
-
const
|
|
4031
|
-
for (const sourceFile of
|
|
4032
|
-
|
|
4049
|
+
let pending = [...seeds];
|
|
4050
|
+
while (pending.length > 0) {
|
|
4051
|
+
const readThisRound = [];
|
|
4052
|
+
for (const sourceFile of pending) {
|
|
4053
|
+
const filePath = sourceFile.getFilePath();
|
|
4054
|
+
if (read2.has(filePath)) {
|
|
4033
4055
|
continue;
|
|
4034
4056
|
}
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4057
|
+
read2.add(filePath);
|
|
4058
|
+
readThisRound.push(filePath);
|
|
4059
|
+
this.lastQueryWalked.push(filePath);
|
|
4060
|
+
recordFileDependency(filePath);
|
|
4038
4061
|
this.extractFile(sourceFile);
|
|
4039
|
-
next.push(...this.graph.importedFilesOf(sourceFile));
|
|
4040
|
-
}
|
|
4041
|
-
const found = ask();
|
|
4042
|
-
if (found !== null) {
|
|
4043
|
-
return found;
|
|
4044
4062
|
}
|
|
4045
|
-
|
|
4046
|
-
|
|
4063
|
+
this.derive();
|
|
4064
|
+
pending = [];
|
|
4065
|
+
for (const moduleKey of this.demandedModules(readThisRound)) {
|
|
4066
|
+
if (considered.has(moduleKey)) {
|
|
4067
|
+
continue;
|
|
4068
|
+
}
|
|
4069
|
+
considered.add(moduleKey);
|
|
4070
|
+
const sourceFile = sourceFileFor(project, moduleKey);
|
|
4071
|
+
if (sourceFile !== void 0 && !read2.has(sourceFile.getFilePath())) {
|
|
4072
|
+
pending.push(sourceFile);
|
|
4073
|
+
}
|
|
4047
4074
|
}
|
|
4048
|
-
frontier = next;
|
|
4049
4075
|
}
|
|
4050
|
-
|
|
4076
|
+
}
|
|
4077
|
+
/**
|
|
4078
|
+
* Module keys the rules are waiting on. Demand facts are cleared
|
|
4079
|
+
* between queries, so the demand relations contain this query's
|
|
4080
|
+
* alone; the unrestricted program has none, and follows the imports
|
|
4081
|
+
* of the files read this round instead.
|
|
4082
|
+
*/
|
|
4083
|
+
demandedModules(readThisRound) {
|
|
4084
|
+
if (RESOLUTION_PROGRAM.demands.length === 0) {
|
|
4085
|
+
return readThisRound.flatMap(
|
|
4086
|
+
(filePath) => this.db.lookup("importsModule", 0, filePath).map((tuple) => String(tuple[1]))
|
|
4087
|
+
);
|
|
4088
|
+
}
|
|
4089
|
+
return MODULE_DEMANDS.flatMap(
|
|
4090
|
+
(relation) => this.db.facts(relation).map((tuple) => String(tuple[0]))
|
|
4091
|
+
);
|
|
4051
4092
|
}
|
|
4052
4093
|
/**
|
|
4053
4094
|
* The question and the chain that settled it are dropped. The files
|
|
@@ -4066,6 +4107,27 @@ var ResolutionStore = class {
|
|
|
4066
4107
|
this.stale = true;
|
|
4067
4108
|
}
|
|
4068
4109
|
}
|
|
4110
|
+
wantExportsOf(filePath) {
|
|
4111
|
+
if (this.db.add("wantedExportsOf", [filePath]) === "added") {
|
|
4112
|
+
this.stale = true;
|
|
4113
|
+
}
|
|
4114
|
+
}
|
|
4115
|
+
/**
|
|
4116
|
+
* Discovery walks the table in order, and the rounds derive it in
|
|
4117
|
+
* the order files arrived. Deriving it again from the demand alone,
|
|
4118
|
+
* over the loaded closure, orders it by the file's own statements.
|
|
4119
|
+
*/
|
|
4120
|
+
rederiveExportsOf(filePath) {
|
|
4121
|
+
if (QUERY_FACTS.length === 0) {
|
|
4122
|
+
return;
|
|
4123
|
+
}
|
|
4124
|
+
this.db.retract("wantedModuleExport", [
|
|
4125
|
+
...this.db.lookup("wantedModuleExport", 0, filePath)
|
|
4126
|
+
]);
|
|
4127
|
+
this.forgetQuery();
|
|
4128
|
+
this.wantExportsOf(filePath);
|
|
4129
|
+
this.derive();
|
|
4130
|
+
}
|
|
4069
4131
|
/**
|
|
4070
4132
|
* File extraction only reaches values hanging off exports, and a query
|
|
4071
4133
|
* can be rooted anywhere, so the queried value gets its own facts.
|
|
@@ -4115,24 +4177,18 @@ var ResolutionStore = class {
|
|
|
4115
4177
|
}
|
|
4116
4178
|
candidates.add(node);
|
|
4117
4179
|
}
|
|
4118
|
-
if (candidates.size
|
|
4119
|
-
return
|
|
4120
|
-
}
|
|
4121
|
-
if (candidates.size > 1) {
|
|
4122
|
-
return { written: null };
|
|
4123
|
-
}
|
|
4124
|
-
if (neverWritable(value)) {
|
|
4125
|
-
return { written: null };
|
|
4180
|
+
if (candidates.size !== 1) {
|
|
4181
|
+
return null;
|
|
4126
4182
|
}
|
|
4127
|
-
return
|
|
4183
|
+
return [...candidates][0];
|
|
4128
4184
|
}
|
|
4129
4185
|
/**
|
|
4130
4186
|
* Read these files' facts now, before anything asks a question.
|
|
4131
4187
|
*
|
|
4132
|
-
* A query
|
|
4133
|
-
*
|
|
4188
|
+
* A query follows the imports of the file it starts in, which is
|
|
4189
|
+
* where a value's definition is. What a caller passed is the other
|
|
4134
4190
|
* direction, so a question about a parameter is answered only by
|
|
4135
|
-
* files the
|
|
4191
|
+
* files the query never reaches on its own.
|
|
4136
4192
|
*/
|
|
4137
4193
|
extractFiles(sourceFiles) {
|
|
4138
4194
|
for (const sourceFile of sourceFiles) {
|
|
@@ -4148,15 +4204,14 @@ var ResolutionStore = class {
|
|
|
4148
4204
|
return this.graph.filesReachingAnyPackage(fileSets);
|
|
4149
4205
|
}
|
|
4150
4206
|
/**
|
|
4151
|
-
* The calls behind a receiver that `matches` accepts
|
|
4152
|
-
*
|
|
4153
|
-
*
|
|
4154
|
-
*
|
|
4155
|
-
* cannot rank a nearer call above a farther one.
|
|
4207
|
+
* The calls behind a receiver that `matches` accepts. The caller
|
|
4208
|
+
* applies the single-answer policy to the set; the resolution
|
|
4209
|
+
* README's anchor section says why the rules cannot rank a nearer
|
|
4210
|
+
* call above a farther one.
|
|
4156
4211
|
*/
|
|
4157
4212
|
anchorCallsOf(value, matches) {
|
|
4158
4213
|
const target = factKeyOf(value);
|
|
4159
|
-
return this.
|
|
4214
|
+
return this.askAbout(target, "wantedAnchor", () => {
|
|
4160
4215
|
this.derive();
|
|
4161
4216
|
const found = [];
|
|
4162
4217
|
for (const id of this.answersFor("wantedAnchorCall", nodeId(target))) {
|
|
@@ -4165,12 +4220,12 @@ var ResolutionStore = class {
|
|
|
4165
4220
|
found.push(node);
|
|
4166
4221
|
}
|
|
4167
4222
|
}
|
|
4168
|
-
return found
|
|
4169
|
-
})
|
|
4223
|
+
return found;
|
|
4224
|
+
});
|
|
4170
4225
|
}
|
|
4171
4226
|
/**
|
|
4172
4227
|
* Every name a module exports and the values behind each, with
|
|
4173
|
-
* re-export chains flattened by the rules. The
|
|
4228
|
+
* re-export chains flattened by the rules. The demand follows
|
|
4174
4229
|
* re-export targets only, so a barrel of barrels extracts its own
|
|
4175
4230
|
* chain and nothing beside it, to any depth.
|
|
4176
4231
|
*/
|
|
@@ -4190,33 +4245,10 @@ var ResolutionStore = class {
|
|
|
4190
4245
|
}
|
|
4191
4246
|
}
|
|
4192
4247
|
collectExports(sourceFile) {
|
|
4193
|
-
const project = sourceFile.getProject();
|
|
4194
|
-
const walked = /* @__PURE__ */ new Set();
|
|
4195
|
-
let frontier = [sourceFile];
|
|
4196
|
-
while (frontier.length > 0) {
|
|
4197
|
-
const next = [];
|
|
4198
|
-
for (const file of frontier) {
|
|
4199
|
-
const filePath2 = file.getFilePath();
|
|
4200
|
-
if (walked.has(filePath2)) {
|
|
4201
|
-
continue;
|
|
4202
|
-
}
|
|
4203
|
-
walked.add(filePath2);
|
|
4204
|
-
recordFileDependency(filePath2);
|
|
4205
|
-
this.extractFile(file);
|
|
4206
|
-
for (const target of this.reExportTargetsOf(filePath2)) {
|
|
4207
|
-
const targetFile = sourceFileFor(project, target);
|
|
4208
|
-
if (targetFile !== void 0) {
|
|
4209
|
-
next.push(targetFile);
|
|
4210
|
-
}
|
|
4211
|
-
}
|
|
4212
|
-
}
|
|
4213
|
-
frontier = next;
|
|
4214
|
-
}
|
|
4215
4248
|
const filePath = sourceFile.getFilePath();
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
this.derive();
|
|
4249
|
+
this.wantExportsOf(filePath);
|
|
4250
|
+
this.extractDemanded([sourceFile]);
|
|
4251
|
+
this.rederiveExportsOf(filePath);
|
|
4220
4252
|
const exports = /* @__PURE__ */ new Map();
|
|
4221
4253
|
for (const tuple of this.db.lookup("wantedModuleExport", 0, filePath)) {
|
|
4222
4254
|
const node = this.table.byId.get(String(tuple[2]));
|
|
@@ -4233,22 +4265,9 @@ var ResolutionStore = class {
|
|
|
4233
4265
|
}
|
|
4234
4266
|
return exports;
|
|
4235
4267
|
}
|
|
4236
|
-
/** Module keys this file re-exports from, read off its own facts. */
|
|
4237
|
-
reExportTargetsOf(filePath) {
|
|
4238
|
-
const targets = /* @__PURE__ */ new Set();
|
|
4239
|
-
for (const tuple of this.db.lookup("reExports", 0, filePath)) {
|
|
4240
|
-
targets.add(String(tuple[2]));
|
|
4241
|
-
}
|
|
4242
|
-
for (const tuple of this.db.lookup("reExportsAll", 0, filePath)) {
|
|
4243
|
-
targets.add(String(tuple[1]));
|
|
4244
|
-
}
|
|
4245
|
-
return [...targets];
|
|
4246
|
-
}
|
|
4247
4268
|
/**
|
|
4248
|
-
*
|
|
4249
|
-
*
|
|
4250
|
-
* single-answer policy stays with the callers: picking one of two
|
|
4251
|
-
* would make the result depend on the order the facts came in.
|
|
4269
|
+
* The single-answer policy stays with the callers: a value with two
|
|
4270
|
+
* sources is something to say at the site, not something to pick from.
|
|
4252
4271
|
*/
|
|
4253
4272
|
lookupSources(value) {
|
|
4254
4273
|
this.derive();
|
|
@@ -4262,7 +4281,7 @@ var ResolutionStore = class {
|
|
|
4262
4281
|
candidates.add(resolved);
|
|
4263
4282
|
}
|
|
4264
4283
|
}
|
|
4265
|
-
return
|
|
4284
|
+
return [...candidates];
|
|
4266
4285
|
}
|
|
4267
4286
|
derive() {
|
|
4268
4287
|
if (!this.stale) {
|
|
@@ -4321,18 +4340,6 @@ function pairHalves(pair) {
|
|
|
4321
4340
|
const [module = "", name = ""] = tupleKeyParts(pair);
|
|
4322
4341
|
return { module, name };
|
|
4323
4342
|
}
|
|
4324
|
-
function namesAPackage(moduleKey) {
|
|
4325
|
-
return !moduleKey.startsWith("/") || moduleKey.includes("/node_modules/");
|
|
4326
|
-
}
|
|
4327
|
-
function neverWritable(value) {
|
|
4328
|
-
if (!Node15.isIdentifier(value)) {
|
|
4329
|
-
return false;
|
|
4330
|
-
}
|
|
4331
|
-
const declarations = value.getSymbol()?.getDeclarations() ?? [];
|
|
4332
|
-
return declarations.some(
|
|
4333
|
-
(declaration) => declaration.getSourceFile().getFilePath().includes("/node_modules/")
|
|
4334
|
-
);
|
|
4335
|
-
}
|
|
4336
4343
|
function namesPackage2(moduleKey, packages) {
|
|
4337
4344
|
return namesAnyPackage(
|
|
4338
4345
|
[moduleKey, ...packagesDeclaring(moduleKey)],
|
|
@@ -4353,35 +4360,12 @@ import path3 from "path";
|
|
|
4353
4360
|
// src/diagnostics.ts
|
|
4354
4361
|
import path2 from "path";
|
|
4355
4362
|
import { ts as ts3 } from "ts-morph";
|
|
4356
|
-
import {
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
unitsClaimed: 0,
|
|
4363
|
-
selfCollisions: 0,
|
|
4364
|
-
summariesProduced: 0,
|
|
4365
|
-
failures: [],
|
|
4366
|
-
helpersMatched: /* @__PURE__ */ new Set()
|
|
4367
|
-
});
|
|
4368
|
-
function recordPackFailure(tally, failure) {
|
|
4369
|
-
const message = failure.error instanceof Error ? failure.error.message : String(failure.error);
|
|
4370
|
-
tally?.failures.push({
|
|
4371
|
-
hook: failure.hook,
|
|
4372
|
-
file: failure.file,
|
|
4373
|
-
message
|
|
4374
|
-
});
|
|
4375
|
-
return `[suss] pack "${failure.pack}" threw from ${failure.hook} while reading ${failure.file}: ${message}
|
|
4376
|
-
`;
|
|
4377
|
-
}
|
|
4378
|
-
function createPackTallies(packs) {
|
|
4379
|
-
const tallies = /* @__PURE__ */ new Map();
|
|
4380
|
-
for (const pack of packs) {
|
|
4381
|
-
tallies.set(pack.name, emptyTally());
|
|
4382
|
-
}
|
|
4383
|
-
return tallies;
|
|
4384
|
-
}
|
|
4363
|
+
import {
|
|
4364
|
+
createPackTallies,
|
|
4365
|
+
emptyTally,
|
|
4366
|
+
recordPackFailure,
|
|
4367
|
+
summaryCountsByPack
|
|
4368
|
+
} from "@suss/extractor";
|
|
4385
4369
|
function commonDirectoryOf(files) {
|
|
4386
4370
|
const absolute = files.filter((f) => path2.isAbsolute(f));
|
|
4387
4371
|
const first = absolute[0];
|
|
@@ -4458,30 +4442,6 @@ function unresolvedGatesFor(gates, args) {
|
|
|
4458
4442
|
}
|
|
4459
4443
|
return unresolved;
|
|
4460
4444
|
}
|
|
4461
|
-
var emptyCounts = () => ({
|
|
4462
|
-
bound: 0,
|
|
4463
|
-
providers: 0,
|
|
4464
|
-
withBehavior: 0
|
|
4465
|
-
});
|
|
4466
|
-
function summaryCountsByPack(summaries) {
|
|
4467
|
-
const counts = /* @__PURE__ */ new Map();
|
|
4468
|
-
for (const summary of summaries) {
|
|
4469
|
-
const recognition = summary.identity.boundaryBinding?.recognition;
|
|
4470
|
-
if (recognition === void 0 || recognition === null) {
|
|
4471
|
-
continue;
|
|
4472
|
-
}
|
|
4473
|
-
const entry = counts.get(recognition) ?? emptyCounts();
|
|
4474
|
-
entry.bound += 1;
|
|
4475
|
-
if (BOUNDARY_ROLE[summary.kind] === "provider") {
|
|
4476
|
-
entry.providers += 1;
|
|
4477
|
-
}
|
|
4478
|
-
if (summary.transitions.length > 0) {
|
|
4479
|
-
entry.withBehavior += 1;
|
|
4480
|
-
}
|
|
4481
|
-
counts.set(recognition, entry);
|
|
4482
|
-
}
|
|
4483
|
-
return counts;
|
|
4484
|
-
}
|
|
4485
4445
|
function helpersWithNoCall(patterns, matched, projectRoot) {
|
|
4486
4446
|
const missing = [];
|
|
4487
4447
|
for (const pattern of patterns) {
|
|
@@ -4506,7 +4466,11 @@ function buildExtractionReport(args) {
|
|
|
4506
4466
|
const packFunnels = args.packs.map((pack) => {
|
|
4507
4467
|
const gates = packIsUngated(pack) ? [] : collectPackGates(pack);
|
|
4508
4468
|
const tally = args.tallies.get(pack.name) ?? emptyTally();
|
|
4509
|
-
const counted = bySummary.get(pack.name) ??
|
|
4469
|
+
const counted = bySummary.get(pack.name) ?? {
|
|
4470
|
+
bound: 0,
|
|
4471
|
+
providers: 0,
|
|
4472
|
+
withBehavior: 0
|
|
4473
|
+
};
|
|
4510
4474
|
return {
|
|
4511
4475
|
pack: pack.name,
|
|
4512
4476
|
version: pack.version ?? null,
|
|
@@ -4735,13 +4699,26 @@ function propertiesReached(object, resolution, seen) {
|
|
|
4735
4699
|
}
|
|
4736
4700
|
function writtenNodeOf(value, resolution) {
|
|
4737
4701
|
const written = factKeyOf(value);
|
|
4738
|
-
if (Node16.
|
|
4702
|
+
if (Node16.isNewExpression(written)) {
|
|
4739
4703
|
return written;
|
|
4740
4704
|
}
|
|
4705
|
+
if (Node16.isCallExpression(written)) {
|
|
4706
|
+
return writtenThroughCall(written, resolution);
|
|
4707
|
+
}
|
|
4741
4708
|
if (resolution === void 0 || !couldNameAValue(written)) {
|
|
4742
4709
|
return null;
|
|
4743
4710
|
}
|
|
4744
|
-
|
|
4711
|
+
const resolved = resolution.resolveWrittenValue(written);
|
|
4712
|
+
return resolved !== null && Node16.isCallExpression(resolved) ? writtenThroughCall(resolved, resolution) : resolved;
|
|
4713
|
+
}
|
|
4714
|
+
function writtenThroughCall(call, resolution) {
|
|
4715
|
+
if (resolution !== void 0 && resolution.resolveCallable(call.getExpression()) !== null) {
|
|
4716
|
+
const resolved = resolution.resolveWrittenValue(call);
|
|
4717
|
+
if (resolved !== null) {
|
|
4718
|
+
return resolved;
|
|
4719
|
+
}
|
|
4720
|
+
}
|
|
4721
|
+
return call;
|
|
4745
4722
|
}
|
|
4746
4723
|
function stringValueOf(value, resolution) {
|
|
4747
4724
|
const written = factKeyOf(value);
|
|
@@ -4803,7 +4780,7 @@ function discoverClientCalls(sourceFile, match, kind, resolution) {
|
|
|
4803
4780
|
}
|
|
4804
4781
|
} else if (Node17.isPropertyAccessExpression(callee)) {
|
|
4805
4782
|
const subject = callee.getExpression();
|
|
4806
|
-
if (Node17.isIdentifier(subject) && (isClientImport(subject, match, resolution, true) || clientVarNames.has(subject.getText()) || resolvesToKnownInstance(subject, match, resolution))
|
|
4783
|
+
if (Node17.isIdentifier(subject) && (isClientImport(subject, match, resolution, true) || clientVarNames.has(subject.getText())) || resolvesToKnownInstance(subject, match, resolution)) {
|
|
4807
4784
|
methodName = callee.getName();
|
|
4808
4785
|
if (methodFilter === null || methodFilter.has(methodName)) {
|
|
4809
4786
|
matched = true;
|
|
@@ -6413,14 +6390,14 @@ function unitForJsxRoute(node, match, routeNames, kind, resolution) {
|
|
|
6413
6390
|
}
|
|
6414
6391
|
return routeUnit(node, kind, match.method, resolved.path, target, resolution);
|
|
6415
6392
|
}
|
|
6416
|
-
function routeUnit(at, kind, method,
|
|
6417
|
-
const routeInfo = { method, path:
|
|
6393
|
+
function routeUnit(at, kind, method, path14, target, resolution) {
|
|
6394
|
+
const routeInfo = { method, path: path14 };
|
|
6418
6395
|
if (target.kind === "unreadable") {
|
|
6419
6396
|
return {
|
|
6420
6397
|
func: null,
|
|
6421
6398
|
announcedAt: at,
|
|
6422
6399
|
kind,
|
|
6423
|
-
name:
|
|
6400
|
+
name: path14,
|
|
6424
6401
|
nameKind: "label",
|
|
6425
6402
|
routeInfo
|
|
6426
6403
|
};
|
|
@@ -6619,7 +6596,6 @@ function labelOfExpression(node) {
|
|
|
6619
6596
|
}
|
|
6620
6597
|
|
|
6621
6598
|
// src/discovery/packageExports.ts
|
|
6622
|
-
import fs4 from "fs";
|
|
6623
6599
|
import { Node as Node29 } from "ts-morph";
|
|
6624
6600
|
|
|
6625
6601
|
// src/packageExports.ts
|
|
@@ -6648,7 +6624,8 @@ function resolvePackageExports(packageJsonPath, opts = {}) {
|
|
|
6648
6624
|
packageName,
|
|
6649
6625
|
subPath,
|
|
6650
6626
|
exportPathPrefix: subPathToPrefix(subPath),
|
|
6651
|
-
sourceFile: src
|
|
6627
|
+
sourceFile: src,
|
|
6628
|
+
publishedFile: path5.resolve(pkgDir, distPath)
|
|
6652
6629
|
});
|
|
6653
6630
|
};
|
|
6654
6631
|
const exportsField = pkg.exports;
|
|
@@ -6668,6 +6645,53 @@ function resolvePackageExports(packageJsonPath, opts = {}) {
|
|
|
6668
6645
|
}
|
|
6669
6646
|
return { packageName, entries, warnings };
|
|
6670
6647
|
}
|
|
6648
|
+
var packageExportsCache = /* @__PURE__ */ new Map();
|
|
6649
|
+
var PATH_STAMP_SEPARATOR = "";
|
|
6650
|
+
function packageJsonStamp(packageJsonPath) {
|
|
6651
|
+
try {
|
|
6652
|
+
const stat = fs3.statSync(packageJsonPath);
|
|
6653
|
+
return `${stat.mtimeMs}:${stat.size}`;
|
|
6654
|
+
} catch {
|
|
6655
|
+
return "unreadable";
|
|
6656
|
+
}
|
|
6657
|
+
}
|
|
6658
|
+
function resolvePackageExportsCached(packageJsonPath) {
|
|
6659
|
+
const stamp2 = packageJsonStamp(packageJsonPath);
|
|
6660
|
+
const key = `${packageJsonPath}${PATH_STAMP_SEPARATOR}${stamp2}`;
|
|
6661
|
+
const cached = packageExportsCache.get(key);
|
|
6662
|
+
if (cached !== void 0) {
|
|
6663
|
+
return cached;
|
|
6664
|
+
}
|
|
6665
|
+
const fresh = resolvePackageExports(packageJsonPath);
|
|
6666
|
+
packageExportsCache.set(key, fresh);
|
|
6667
|
+
return fresh;
|
|
6668
|
+
}
|
|
6669
|
+
function namedPackageDirAbove(start) {
|
|
6670
|
+
let at = path5.resolve(start);
|
|
6671
|
+
for (let up = 0; up < 12; up += 1) {
|
|
6672
|
+
if (packageNameAt(at) !== null) {
|
|
6673
|
+
return at;
|
|
6674
|
+
}
|
|
6675
|
+
const parent = path5.dirname(at);
|
|
6676
|
+
if (parent === at) {
|
|
6677
|
+
break;
|
|
6678
|
+
}
|
|
6679
|
+
at = parent;
|
|
6680
|
+
}
|
|
6681
|
+
return null;
|
|
6682
|
+
}
|
|
6683
|
+
function packageNameAt(dir) {
|
|
6684
|
+
try {
|
|
6685
|
+
const manifest = JSON.parse(
|
|
6686
|
+
fs3.readFileSync(path5.join(dir, "package.json"), "utf8")
|
|
6687
|
+
);
|
|
6688
|
+
if (typeof manifest.name === "string" && manifest.name.length > 0) {
|
|
6689
|
+
return manifest.name;
|
|
6690
|
+
}
|
|
6691
|
+
} catch {
|
|
6692
|
+
}
|
|
6693
|
+
return null;
|
|
6694
|
+
}
|
|
6671
6695
|
function pickConditional(value, warnings, key) {
|
|
6672
6696
|
if (value === void 0 || value === null) {
|
|
6673
6697
|
if (value === null) {
|
|
@@ -6717,8 +6741,55 @@ function resolveSourceFor(pkgDir, distPath, srcRoot) {
|
|
|
6717
6741
|
return null;
|
|
6718
6742
|
}
|
|
6719
6743
|
|
|
6744
|
+
// src/resolve/sourceDeclaration.ts
|
|
6745
|
+
import path6 from "path";
|
|
6746
|
+
function sourceDeclarationsBehind(decl, resolution, visited = /* @__PURE__ */ new Set()) {
|
|
6747
|
+
const file = decl.getSourceFile();
|
|
6748
|
+
if (!file.isDeclarationFile() || file.isInNodeModules()) {
|
|
6749
|
+
return [decl];
|
|
6750
|
+
}
|
|
6751
|
+
const packageDir = namedPackageDirAbove(path6.dirname(file.getFilePath()));
|
|
6752
|
+
if (packageDir === null || visited.has(packageDir)) {
|
|
6753
|
+
return [decl];
|
|
6754
|
+
}
|
|
6755
|
+
visited.add(packageDir);
|
|
6756
|
+
const project = file.getProject();
|
|
6757
|
+
const { entries } = resolvePackageExportsCached(
|
|
6758
|
+
path6.join(packageDir, "package.json")
|
|
6759
|
+
);
|
|
6760
|
+
const found = [];
|
|
6761
|
+
for (const entry of entries) {
|
|
6762
|
+
const published = sourceFileFor(project, entry.publishedFile);
|
|
6763
|
+
const source = sourceFileFor(project, entry.sourceFile);
|
|
6764
|
+
if (published === void 0 || source === void 0) {
|
|
6765
|
+
continue;
|
|
6766
|
+
}
|
|
6767
|
+
for (const [name, nodes] of resolution.exportsOf(published)) {
|
|
6768
|
+
if (!nodes.some((node) => sameDeclaration(node, decl))) {
|
|
6769
|
+
continue;
|
|
6770
|
+
}
|
|
6771
|
+
for (const behind of resolution.exportsOf(source).get(name) ?? []) {
|
|
6772
|
+
for (const candidate of sourceDeclarationsBehind(
|
|
6773
|
+
behind,
|
|
6774
|
+
resolution,
|
|
6775
|
+
visited
|
|
6776
|
+
)) {
|
|
6777
|
+
if (!found.includes(candidate)) {
|
|
6778
|
+
found.push(candidate);
|
|
6779
|
+
}
|
|
6780
|
+
}
|
|
6781
|
+
}
|
|
6782
|
+
}
|
|
6783
|
+
}
|
|
6784
|
+
return found.length > 0 ? found : [decl];
|
|
6785
|
+
}
|
|
6786
|
+
function sameDeclaration(a, b) {
|
|
6787
|
+
return a === b || a.getSourceFile().getFilePath() === b.getSourceFile().getFilePath() && a.getStart() === b.getStart() && a.getEnd() === b.getEnd();
|
|
6788
|
+
}
|
|
6789
|
+
|
|
6720
6790
|
// src/discovery/factorySurface.ts
|
|
6721
6791
|
import { Node as Node28, SyntaxKind as SyntaxKind6 } from "ts-morph";
|
|
6792
|
+
var MAX_BUILDER_HOPS = 2;
|
|
6722
6793
|
function surfaceMethods(decl) {
|
|
6723
6794
|
if (Node28.isClassDeclaration(decl)) {
|
|
6724
6795
|
return surfaceClassMethods(decl);
|
|
@@ -6758,16 +6829,20 @@ function surfaceClassMethods(cls) {
|
|
|
6758
6829
|
function surfaceFactoryReturnMethods(fn) {
|
|
6759
6830
|
const out = [];
|
|
6760
6831
|
const seen = /* @__PURE__ */ new Set();
|
|
6832
|
+
collectFromFunctionReturns(fn, out, seen, 0);
|
|
6833
|
+
return out;
|
|
6834
|
+
}
|
|
6835
|
+
function collectFromFunctionReturns(fn, out, seen, depth) {
|
|
6761
6836
|
if (Node28.isArrowFunction(fn)) {
|
|
6762
6837
|
const body2 = fn.getBody();
|
|
6763
6838
|
if (Node28.isExpression(body2)) {
|
|
6764
|
-
|
|
6765
|
-
return
|
|
6839
|
+
collectFromReturnValue(body2, out, seen, depth);
|
|
6840
|
+
return;
|
|
6766
6841
|
}
|
|
6767
6842
|
}
|
|
6768
6843
|
const body = fn.getBody?.();
|
|
6769
6844
|
if (body === void 0) {
|
|
6770
|
-
return
|
|
6845
|
+
return;
|
|
6771
6846
|
}
|
|
6772
6847
|
const returns = [];
|
|
6773
6848
|
body.forEachDescendant((node, traversal) => {
|
|
@@ -6784,9 +6859,53 @@ function surfaceFactoryReturnMethods(fn) {
|
|
|
6784
6859
|
if (expr === void 0) {
|
|
6785
6860
|
continue;
|
|
6786
6861
|
}
|
|
6862
|
+
collectFromReturnValue(expr, out, seen, depth);
|
|
6863
|
+
}
|
|
6864
|
+
}
|
|
6865
|
+
function collectFromReturnValue(node, out, seen, depth) {
|
|
6866
|
+
const expr = peelParens(node);
|
|
6867
|
+
if (Node28.isObjectLiteralExpression(expr)) {
|
|
6787
6868
|
collectFromObjectLiteral(expr, out, seen);
|
|
6869
|
+
return;
|
|
6788
6870
|
}
|
|
6789
|
-
|
|
6871
|
+
if (depth >= MAX_BUILDER_HOPS || !Node28.isCallExpression(expr)) {
|
|
6872
|
+
return;
|
|
6873
|
+
}
|
|
6874
|
+
const callee = expr.getExpression();
|
|
6875
|
+
if (!Node28.isIdentifier(callee)) {
|
|
6876
|
+
return;
|
|
6877
|
+
}
|
|
6878
|
+
const helper = sameFileFunctionBehind(callee);
|
|
6879
|
+
if (helper !== null) {
|
|
6880
|
+
collectFromFunctionReturns(helper, out, seen, depth + 1);
|
|
6881
|
+
}
|
|
6882
|
+
}
|
|
6883
|
+
function sameFileFunctionBehind(id) {
|
|
6884
|
+
const symbol = id.getSymbol();
|
|
6885
|
+
if (symbol === void 0) {
|
|
6886
|
+
return null;
|
|
6887
|
+
}
|
|
6888
|
+
return functionAmong(
|
|
6889
|
+
symbol.getDeclarations(),
|
|
6890
|
+
id.getSourceFile().getFilePath()
|
|
6891
|
+
);
|
|
6892
|
+
}
|
|
6893
|
+
function functionAmong(declarations, filePath) {
|
|
6894
|
+
for (const decl of declarations) {
|
|
6895
|
+
if (decl.getSourceFile().getFilePath() !== filePath) {
|
|
6896
|
+
continue;
|
|
6897
|
+
}
|
|
6898
|
+
if (Node28.isFunctionDeclaration(decl)) {
|
|
6899
|
+
return decl;
|
|
6900
|
+
}
|
|
6901
|
+
if (Node28.isVariableDeclaration(decl)) {
|
|
6902
|
+
const init = decl.getInitializer();
|
|
6903
|
+
if (init !== void 0 && (Node28.isArrowFunction(init) || Node28.isFunctionExpression(init))) {
|
|
6904
|
+
return init;
|
|
6905
|
+
}
|
|
6906
|
+
}
|
|
6907
|
+
}
|
|
6908
|
+
return null;
|
|
6790
6909
|
}
|
|
6791
6910
|
function collectFromObjectLiteral(node, out, seen) {
|
|
6792
6911
|
const e = peelParens(node);
|
|
@@ -6821,31 +6940,31 @@ function collectFromObjectLiteral(node, out, seen) {
|
|
|
6821
6940
|
out.push({ func: v3, name });
|
|
6822
6941
|
}
|
|
6823
6942
|
}
|
|
6943
|
+
if (Node28.isShorthandPropertyAssignment(prop)) {
|
|
6944
|
+
collectShorthandFunction(prop, out, seen);
|
|
6945
|
+
}
|
|
6824
6946
|
}
|
|
6825
6947
|
}
|
|
6826
|
-
|
|
6827
|
-
|
|
6828
|
-
|
|
6829
|
-
|
|
6830
|
-
function packageJsonStamp(packageJsonPath) {
|
|
6831
|
-
try {
|
|
6832
|
-
const stat = fs4.statSync(packageJsonPath);
|
|
6833
|
-
return `${stat.mtimeMs}:${stat.size}`;
|
|
6834
|
-
} catch {
|
|
6835
|
-
return "unreadable";
|
|
6948
|
+
function collectShorthandFunction(prop, out, seen) {
|
|
6949
|
+
const name = prop.getName();
|
|
6950
|
+
if (seen.has(name)) {
|
|
6951
|
+
return;
|
|
6836
6952
|
}
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
|
|
6840
|
-
|
|
6841
|
-
const
|
|
6842
|
-
|
|
6843
|
-
|
|
6953
|
+
const symbol = prop.getValueSymbol();
|
|
6954
|
+
if (symbol === void 0) {
|
|
6955
|
+
return;
|
|
6956
|
+
}
|
|
6957
|
+
const fn = functionAmong(
|
|
6958
|
+
symbol.getDeclarations(),
|
|
6959
|
+
prop.getSourceFile().getFilePath()
|
|
6960
|
+
);
|
|
6961
|
+
if (fn !== null) {
|
|
6962
|
+
seen.add(name);
|
|
6963
|
+
out.push({ func: fn, name });
|
|
6844
6964
|
}
|
|
6845
|
-
const fresh = resolvePackageExports(packageJsonPath);
|
|
6846
|
-
packageExportsCache.set(key, fresh);
|
|
6847
|
-
return fresh;
|
|
6848
6965
|
}
|
|
6966
|
+
|
|
6967
|
+
// src/discovery/packageExports.ts
|
|
6849
6968
|
function discoverPackageExports(sourceFile, match, kind, resolution) {
|
|
6850
6969
|
if (match.packageJsonPath === void 0) {
|
|
6851
6970
|
return [];
|
|
@@ -6880,7 +6999,10 @@ function discoverPackageExports(sourceFile, match, kind, resolution) {
|
|
|
6880
6999
|
if (seenNames.has(key)) {
|
|
6881
7000
|
continue;
|
|
6882
7001
|
}
|
|
6883
|
-
|
|
7002
|
+
const candidates = decls.flatMap(
|
|
7003
|
+
(decl) => sourceDeclarationsBehind(decl, resolution)
|
|
7004
|
+
);
|
|
7005
|
+
for (const decl of candidates) {
|
|
6884
7006
|
if (Node29.isVariableDeclaration(decl)) {
|
|
6885
7007
|
const init = decl.getInitializer();
|
|
6886
7008
|
if (init !== void 0 && (Node29.isArrowFunction(init) || Node29.isFunctionExpression(init))) {
|
|
@@ -7035,7 +7157,7 @@ function attributedCalls(sourceFile, packages, resolution) {
|
|
|
7035
7157
|
return null;
|
|
7036
7158
|
}
|
|
7037
7159
|
if (!methodComesFromSource(callee)) {
|
|
7038
|
-
return
|
|
7160
|
+
return null;
|
|
7039
7161
|
}
|
|
7040
7162
|
return {
|
|
7041
7163
|
packageName: subject.packageName,
|
|
@@ -7149,12 +7271,12 @@ function originEndOf(flattened) {
|
|
|
7149
7271
|
const slash = flattened.indexOf("/", opener[0].length);
|
|
7150
7272
|
return slash === -1 ? flattened.length : slash;
|
|
7151
7273
|
}
|
|
7152
|
-
function appendPathText(
|
|
7274
|
+
function appendPathText(path14, text) {
|
|
7153
7275
|
const idx = text.search(/[?#]/);
|
|
7154
7276
|
if (idx === -1) {
|
|
7155
|
-
return { path:
|
|
7277
|
+
return { path: path14 + text, stop: false };
|
|
7156
7278
|
}
|
|
7157
|
-
return { path:
|
|
7279
|
+
return { path: path14 + text.slice(0, idx), stop: true };
|
|
7158
7280
|
}
|
|
7159
7281
|
function parseAbsoluteUrl(text) {
|
|
7160
7282
|
try {
|
|
@@ -7178,8 +7300,8 @@ function pathnameOfAbsoluteLiteral(text) {
|
|
|
7178
7300
|
return stripQueryAndFragment(stripOriginManually(text));
|
|
7179
7301
|
}
|
|
7180
7302
|
function pathFromLiteralUrl(text) {
|
|
7181
|
-
const
|
|
7182
|
-
return
|
|
7303
|
+
const path14 = isAbsoluteUrlLiteral(text) ? pathnameOfAbsoluteLiteral(text) : stripQueryAndFragment(text);
|
|
7304
|
+
return path14 === "" ? void 0 : path14;
|
|
7183
7305
|
}
|
|
7184
7306
|
function pathFromTemplateUrl(arg, resolution) {
|
|
7185
7307
|
const headText = arg.getHead().getLiteralText();
|
|
@@ -7187,7 +7309,7 @@ function pathFromTemplateUrl(arg, resolution) {
|
|
|
7187
7309
|
const tails = spans.map((span) => span.getLiteral().getLiteralText());
|
|
7188
7310
|
const originEnd = originEndOf([headText, ...tails].join(SUBSTITUTION));
|
|
7189
7311
|
const head = appendPathText("", headText.slice(originEnd));
|
|
7190
|
-
let
|
|
7312
|
+
let path14 = head.path;
|
|
7191
7313
|
let stop = head.stop;
|
|
7192
7314
|
let at = headText.length;
|
|
7193
7315
|
for (let i = 0; i < spans.length && !stop; i++) {
|
|
@@ -7197,18 +7319,18 @@ function pathFromTemplateUrl(arg, resolution) {
|
|
|
7197
7319
|
continue;
|
|
7198
7320
|
}
|
|
7199
7321
|
if (at >= originEnd) {
|
|
7200
|
-
|
|
7322
|
+
path14 += holeText(span.getExpression(), resolution);
|
|
7201
7323
|
}
|
|
7202
7324
|
at += SUBSTITUTION.length;
|
|
7203
7325
|
const appended = appendPathText(
|
|
7204
|
-
|
|
7326
|
+
path14,
|
|
7205
7327
|
tailText.slice(Math.max(0, originEnd - at))
|
|
7206
7328
|
);
|
|
7207
|
-
|
|
7329
|
+
path14 = appended.path;
|
|
7208
7330
|
stop = appended.stop;
|
|
7209
7331
|
at += tailText.length;
|
|
7210
7332
|
}
|
|
7211
|
-
return
|
|
7333
|
+
return path14 === "" ? void 0 : path14;
|
|
7212
7334
|
}
|
|
7213
7335
|
function pathFromUrlNode(node, resolution) {
|
|
7214
7336
|
if (Node31.isStringLiteral(node)) {
|
|
@@ -7278,12 +7400,12 @@ function discoverRegistrationCalls(sourceFile, match, kind, bindingExtraction, r
|
|
|
7278
7400
|
match.importName,
|
|
7279
7401
|
resolution
|
|
7280
7402
|
);
|
|
7281
|
-
if (registrationSubjects.size === 0 && !storeCanFindSubjects(sourceFile, match, resolution)) {
|
|
7282
|
-
return results;
|
|
7283
|
-
}
|
|
7284
7403
|
const registrationMethods = match.registrationChain.map(
|
|
7285
7404
|
(c) => c.startsWith(".") ? c.slice(1) : c
|
|
7286
7405
|
);
|
|
7406
|
+
if (registrationSubjects.size === 0 && !storeCanFindSubjects(sourceFile, match, resolution, registrationMethods)) {
|
|
7407
|
+
return results;
|
|
7408
|
+
}
|
|
7287
7409
|
sourceFile.forEachDescendant((node) => {
|
|
7288
7410
|
if (!Node32.isCallExpression(node)) {
|
|
7289
7411
|
return;
|
|
@@ -7477,8 +7599,54 @@ function receiverOf(subject, subjects, match, resolution) {
|
|
|
7477
7599
|
);
|
|
7478
7600
|
return candidates > 1 ? { kind: "several", candidates } : NOT_A_ROUTABLE;
|
|
7479
7601
|
}
|
|
7480
|
-
function storeCanFindSubjects(sourceFile, match, resolution) {
|
|
7481
|
-
|
|
7602
|
+
function storeCanFindSubjects(sourceFile, match, resolution, methods = []) {
|
|
7603
|
+
if (resolution === void 0) {
|
|
7604
|
+
return false;
|
|
7605
|
+
}
|
|
7606
|
+
if (importDeclarationsOf(sourceFile, [match.importModule]).length > 0) {
|
|
7607
|
+
return true;
|
|
7608
|
+
}
|
|
7609
|
+
return methods.length > 0 && callsOnCallResult(sourceFile, methods);
|
|
7610
|
+
}
|
|
7611
|
+
function callsOnCallResult(sourceFile, methods) {
|
|
7612
|
+
let called = methodsCalledOnCallResults.get(sourceFile);
|
|
7613
|
+
if (called === void 0) {
|
|
7614
|
+
called = collectMethodsCalledOnCallResults(sourceFile);
|
|
7615
|
+
methodsCalledOnCallResults.set(sourceFile, called);
|
|
7616
|
+
}
|
|
7617
|
+
return methods.some((method) => called.has(method));
|
|
7618
|
+
}
|
|
7619
|
+
var methodsCalledOnCallResults = /* @__PURE__ */ new WeakMap();
|
|
7620
|
+
function collectMethodsCalledOnCallResults(sourceFile) {
|
|
7621
|
+
const setToCalls = /* @__PURE__ */ new Set();
|
|
7622
|
+
const calledOn = /* @__PURE__ */ new Map();
|
|
7623
|
+
sourceFile.forEachDescendant((node) => {
|
|
7624
|
+
if (Node32.isVariableDeclaration(node)) {
|
|
7625
|
+
const init = node.getInitializer();
|
|
7626
|
+
if (init !== void 0 && Node32.isCallExpression(init)) {
|
|
7627
|
+
setToCalls.add(node.getName());
|
|
7628
|
+
}
|
|
7629
|
+
return;
|
|
7630
|
+
}
|
|
7631
|
+
if (!Node32.isCallExpression(node)) {
|
|
7632
|
+
return;
|
|
7633
|
+
}
|
|
7634
|
+
const callee = node.getExpression();
|
|
7635
|
+
if (!Node32.isPropertyAccessExpression(callee) || !Node32.isIdentifier(callee.getExpression())) {
|
|
7636
|
+
return;
|
|
7637
|
+
}
|
|
7638
|
+
const receiver = callee.getExpression().getText();
|
|
7639
|
+
const methods = calledOn.get(receiver) ?? /* @__PURE__ */ new Set();
|
|
7640
|
+
methods.add(callee.getName());
|
|
7641
|
+
calledOn.set(receiver, methods);
|
|
7642
|
+
});
|
|
7643
|
+
const called = /* @__PURE__ */ new Set();
|
|
7644
|
+
for (const name of setToCalls) {
|
|
7645
|
+
for (const method of calledOn.get(name) ?? []) {
|
|
7646
|
+
called.add(method);
|
|
7647
|
+
}
|
|
7648
|
+
}
|
|
7649
|
+
return called;
|
|
7482
7650
|
}
|
|
7483
7651
|
function registrationSubjectsOf(sourceFile, importModule, importName, resolution) {
|
|
7484
7652
|
const importedLocalName = resolveImportedLocalName(
|
|
@@ -7543,9 +7711,33 @@ function registrationSubjectIdsOf(sourceFile, matches, resolution) {
|
|
|
7543
7711
|
).values()) {
|
|
7544
7712
|
ids.add(nodeId(node));
|
|
7545
7713
|
}
|
|
7714
|
+
for (const node of unboundConstructionsOf(
|
|
7715
|
+
sourceFile,
|
|
7716
|
+
match.importModule,
|
|
7717
|
+
match.importName
|
|
7718
|
+
)) {
|
|
7719
|
+
ids.add(nodeId(node));
|
|
7720
|
+
}
|
|
7546
7721
|
}
|
|
7547
7722
|
return ids;
|
|
7548
7723
|
}
|
|
7724
|
+
function unboundConstructionsOf(sourceFile, importModule, importName) {
|
|
7725
|
+
const importedLocalName = resolveImportedLocalName(
|
|
7726
|
+
sourceFile,
|
|
7727
|
+
importModule,
|
|
7728
|
+
importName
|
|
7729
|
+
);
|
|
7730
|
+
if (importedLocalName === null) {
|
|
7731
|
+
return [];
|
|
7732
|
+
}
|
|
7733
|
+
const constructions = [];
|
|
7734
|
+
sourceFile.forEachDescendant((node) => {
|
|
7735
|
+
if ((Node32.isCallExpression(node) || Node32.isNewExpression(node)) && node.getExpression().getText() === importedLocalName && !Node32.isVariableDeclaration(node.getParent())) {
|
|
7736
|
+
constructions.push(node);
|
|
7737
|
+
}
|
|
7738
|
+
});
|
|
7739
|
+
return constructions;
|
|
7740
|
+
}
|
|
7549
7741
|
function discoverMountEdges(sourceFile, match, mount, knownSubjectIds, resolution) {
|
|
7550
7742
|
const subjects = registrationSubjectsOf(
|
|
7551
7743
|
sourceFile,
|
|
@@ -7553,7 +7745,7 @@ function discoverMountEdges(sourceFile, match, mount, knownSubjectIds, resolutio
|
|
|
7553
7745
|
match.importName,
|
|
7554
7746
|
resolution
|
|
7555
7747
|
);
|
|
7556
|
-
if (subjects.size === 0 && !storeCanFindSubjects(sourceFile, match, resolution)) {
|
|
7748
|
+
if (subjects.size === 0 && !storeCanFindSubjects(sourceFile, match, resolution, [mount.method])) {
|
|
7557
7749
|
return [];
|
|
7558
7750
|
}
|
|
7559
7751
|
const edges = [];
|
|
@@ -7634,11 +7826,11 @@ function extractRouteInfoFromBinding(call, methodName, binding, resolution) {
|
|
|
7634
7826
|
return null;
|
|
7635
7827
|
}
|
|
7636
7828
|
const method2 = stringProperty(routeObject, binding.method.property);
|
|
7637
|
-
const
|
|
7638
|
-
if (method2 === null ||
|
|
7829
|
+
const path15 = stringProperty(routeObject, binding.path.property);
|
|
7830
|
+
if (method2 === null || path15 === null) {
|
|
7639
7831
|
return null;
|
|
7640
7832
|
}
|
|
7641
|
-
return { method: method2.toUpperCase(), path:
|
|
7833
|
+
return { method: method2.toUpperCase(), path: path15 };
|
|
7642
7834
|
}
|
|
7643
7835
|
if (binding.method.type !== "fromRegistration" || binding.path.type !== "fromArgument") {
|
|
7644
7836
|
return null;
|
|
@@ -7655,8 +7847,8 @@ function extractRouteInfoFromBinding(call, methodName, binding, resolution) {
|
|
|
7655
7847
|
method = arg.getLiteralValue().toUpperCase();
|
|
7656
7848
|
}
|
|
7657
7849
|
const pathArg = call.getArguments()[binding.path.position];
|
|
7658
|
-
const
|
|
7659
|
-
return
|
|
7850
|
+
const path14 = pathArg === void 0 ? void 0 : pathFromArgument(pathArg, resolution);
|
|
7851
|
+
return path14 === void 0 ? null : { method, path: path14 };
|
|
7660
7852
|
}
|
|
7661
7853
|
|
|
7662
7854
|
// src/discovery/registrationLoop.ts
|
|
@@ -7788,7 +7980,7 @@ function bodyCallsOnRoutable(loop, guard, resolution) {
|
|
|
7788
7980
|
}
|
|
7789
7981
|
function readRouteSpec(element, shape, resolution) {
|
|
7790
7982
|
let method = null;
|
|
7791
|
-
let
|
|
7983
|
+
let path14 = null;
|
|
7792
7984
|
let handler = null;
|
|
7793
7985
|
for (const prop of element.getProperties()) {
|
|
7794
7986
|
if (Node33.isMethodDeclaration(prop) && prop.getName() === shape.handlerKey) {
|
|
@@ -7806,16 +7998,16 @@ function readRouteSpec(element, shape, resolution) {
|
|
|
7806
7998
|
if (name === shape.methodKey) {
|
|
7807
7999
|
method = readStringLiteralValue(init);
|
|
7808
8000
|
} else if (name === shape.pathKey) {
|
|
7809
|
-
|
|
8001
|
+
path14 = readStringLiteralValue(init);
|
|
7810
8002
|
} else if (name === shape.handlerKey) {
|
|
7811
8003
|
const func = functionValueOf(init, resolution);
|
|
7812
8004
|
handler = func === null ? null : { func, name: handlerName(init) };
|
|
7813
8005
|
}
|
|
7814
8006
|
}
|
|
7815
|
-
if (method === null ||
|
|
8007
|
+
if (method === null || path14 === null || handler === null) {
|
|
7816
8008
|
return null;
|
|
7817
8009
|
}
|
|
7818
|
-
return { method, path:
|
|
8010
|
+
return { method, path: path14, handler: handler.func, handlerName: handler.name };
|
|
7819
8011
|
}
|
|
7820
8012
|
function readStringLiteralValue(node) {
|
|
7821
8013
|
if (Node33.isStringLiteral(node) || Node33.isNoSubstitutionTemplateLiteral(node)) {
|
|
@@ -7828,7 +8020,7 @@ function handlerName(value) {
|
|
|
7828
8020
|
}
|
|
7829
8021
|
|
|
7830
8022
|
// src/discovery/registrationTemplate.ts
|
|
7831
|
-
import
|
|
8023
|
+
import path7 from "path";
|
|
7832
8024
|
import { Node as Node35 } from "ts-morph";
|
|
7833
8025
|
import { joinMountedPath as joinMountedPath2 } from "@suss/resolution";
|
|
7834
8026
|
|
|
@@ -7837,6 +8029,10 @@ import {
|
|
|
7837
8029
|
Node as Node34,
|
|
7838
8030
|
SyntaxKind as SyntaxKind7
|
|
7839
8031
|
} from "ts-morph";
|
|
8032
|
+
import {
|
|
8033
|
+
unfollowedCallGap,
|
|
8034
|
+
worthRecording
|
|
8035
|
+
} from "@suss/behavioral-ir";
|
|
7840
8036
|
function isInExternalCode(sourceFile) {
|
|
7841
8037
|
if (sourceFile.isDeclarationFile()) {
|
|
7842
8038
|
return true;
|
|
@@ -7890,6 +8086,19 @@ function declarationsBehind(symbol) {
|
|
|
7890
8086
|
function isParameterOf(declaration, scanning) {
|
|
7891
8087
|
return Node34.isParameterDeclaration(declaration) && declaration.getParent() === scanning;
|
|
7892
8088
|
}
|
|
8089
|
+
function parameterIndexOf(declarations, scanning) {
|
|
8090
|
+
if (scanning === void 0) {
|
|
8091
|
+
return void 0;
|
|
8092
|
+
}
|
|
8093
|
+
const params = scanning.getParameters();
|
|
8094
|
+
for (const declaration of declarations) {
|
|
8095
|
+
const index = params.findIndex((param) => param === declaration);
|
|
8096
|
+
if (index !== -1) {
|
|
8097
|
+
return index;
|
|
8098
|
+
}
|
|
8099
|
+
}
|
|
8100
|
+
return void 0;
|
|
8101
|
+
}
|
|
7893
8102
|
function classifyStop(declarations, scanning) {
|
|
7894
8103
|
if (declarations.length === 0) {
|
|
7895
8104
|
return "noDeclaration";
|
|
@@ -7910,36 +8119,6 @@ function classifyStop(declarations, scanning) {
|
|
|
7910
8119
|
}
|
|
7911
8120
|
return "unsettledValue";
|
|
7912
8121
|
}
|
|
7913
|
-
var RECORDED = {
|
|
7914
|
-
noBody: true,
|
|
7915
|
-
unsettledValue: true,
|
|
7916
|
-
multipleSources: true,
|
|
7917
|
-
outsideRun: false,
|
|
7918
|
-
noDeclaration: false,
|
|
7919
|
-
callerSupplied: false,
|
|
7920
|
-
multipleReceivers: true
|
|
7921
|
-
};
|
|
7922
|
-
function worthRecording(reason) {
|
|
7923
|
-
return RECORDED[reason];
|
|
7924
|
-
}
|
|
7925
|
-
var STOP_SENTENCE = {
|
|
7926
|
-
noBody: ({ callee }) => `The call to ${callee} lands on a declaration with no body, so whatever runs there is missing from this summary`,
|
|
7927
|
-
unsettledValue: ({ callee }) => `The call to ${callee} goes through a value this run could not settle, so whatever runs there is missing from this summary`,
|
|
7928
|
-
multipleSources: ({ callee }) => `The call to ${callee} reaches a value with more than one possible source, so whatever runs there is missing from this summary`,
|
|
7929
|
-
outsideRun: ({ callee }) => `The call to ${callee} lands in a package whose source is not in this run, so whatever runs there is missing from this summary`,
|
|
7930
|
-
noDeclaration: ({ callee }) => `The call to ${callee} has no declaration this run could find, so whatever runs there is missing from this summary`,
|
|
7931
|
-
callerSupplied: ({ callee }) => `The call to ${callee} runs the function this unit's caller passed in, so what happens there is decided at the call site`,
|
|
7932
|
-
multipleReceivers: ({ callee, candidates }) => `The call to ${callee} is made on a receiver this run reads as ${candidates ?? "several"} different values, so nothing says which one it registers on and the registration is left out`
|
|
7933
|
-
};
|
|
7934
|
-
function unfollowedCallGap(stop) {
|
|
7935
|
-
return {
|
|
7936
|
-
type: "unfollowedCall",
|
|
7937
|
-
conditions: [],
|
|
7938
|
-
consequence: "unknown",
|
|
7939
|
-
description: STOP_SENTENCE[stop.reason](stop),
|
|
7940
|
-
callee: stop.callee
|
|
7941
|
-
};
|
|
7942
|
-
}
|
|
7943
8122
|
|
|
7944
8123
|
// src/discovery/registrationTemplate.ts
|
|
7945
8124
|
function discoverRegistrationTemplates(sourceFile, match, kind, resolution, mountPrefixes) {
|
|
@@ -7949,8 +8128,8 @@ function discoverRegistrationTemplates(sourceFile, match, kind, resolution, moun
|
|
|
7949
8128
|
const subject = subjectOfCall(sourceFile, args, match, resolution);
|
|
7950
8129
|
const prefix = subject === void 0 ? "" : mountPrefixes?.effectivePrefixFor(subject) ?? "";
|
|
7951
8130
|
for (const reg of match.registrations) {
|
|
7952
|
-
const
|
|
7953
|
-
if (
|
|
8131
|
+
const path14 = substitutePath(reg.pathTemplate, args);
|
|
8132
|
+
if (path14 === null) {
|
|
7954
8133
|
continue;
|
|
7955
8134
|
}
|
|
7956
8135
|
const handler = resolveHandler(reg.handlerArg, args, resolution);
|
|
@@ -7964,7 +8143,7 @@ function discoverRegistrationTemplates(sourceFile, match, kind, resolution, moun
|
|
|
7964
8143
|
...subject === void 0 ? {} : { registrationSubjectId: nodeId(subject) },
|
|
7965
8144
|
routeInfo: {
|
|
7966
8145
|
method: reg.method.toUpperCase(),
|
|
7967
|
-
path: prefix === "" ?
|
|
8146
|
+
path: prefix === "" ? path14 : joinMountedPath2(prefix, path14)
|
|
7968
8147
|
}
|
|
7969
8148
|
});
|
|
7970
8149
|
}
|
|
@@ -7997,7 +8176,7 @@ function subjectOfCall(sourceFile, args, match, resolution) {
|
|
|
7997
8176
|
}
|
|
7998
8177
|
function helperCallsOf(sourceFile, match, resolution) {
|
|
7999
8178
|
const module = match.importModule;
|
|
8000
|
-
if (module !== void 0 && !
|
|
8179
|
+
if (module !== void 0 && !path7.isAbsolute(module)) {
|
|
8001
8180
|
const store = resolution ?? new ResolutionStore();
|
|
8002
8181
|
return callsResolvingTo(sourceFile, store, {
|
|
8003
8182
|
module,
|
|
@@ -8443,24 +8622,24 @@ function declName(decl) {
|
|
|
8443
8622
|
|
|
8444
8623
|
// src/parameterReads.ts
|
|
8445
8624
|
function pathAbove(reference) {
|
|
8446
|
-
const
|
|
8625
|
+
const path14 = [];
|
|
8447
8626
|
let current2 = reference;
|
|
8448
8627
|
for (; ; ) {
|
|
8449
8628
|
const parent = current2.getParent();
|
|
8450
8629
|
if (parent !== void 0 && Node38.isPropertyAccessExpression(parent) && parent.getExpression() === current2) {
|
|
8451
|
-
|
|
8630
|
+
path14.push(parent.getName());
|
|
8452
8631
|
current2 = parent;
|
|
8453
8632
|
continue;
|
|
8454
8633
|
}
|
|
8455
8634
|
if (parent !== void 0 && Node38.isElementAccessExpression(parent) && parent.getExpression() === current2) {
|
|
8456
8635
|
const argument = parent.getArgumentExpression();
|
|
8457
8636
|
if (argument !== void 0 && Node38.isStringLiteral(argument)) {
|
|
8458
|
-
|
|
8637
|
+
path14.push(argument.getLiteralValue());
|
|
8459
8638
|
current2 = parent;
|
|
8460
8639
|
continue;
|
|
8461
8640
|
}
|
|
8462
8641
|
}
|
|
8463
|
-
return
|
|
8642
|
+
return path14;
|
|
8464
8643
|
}
|
|
8465
8644
|
}
|
|
8466
8645
|
function declaresParameterOf(node, func) {
|
|
@@ -9159,142 +9338,40 @@ function importSpecifierMatches(decl, expectedModule) {
|
|
|
9159
9338
|
return Node41.isImportDeclaration(importDecl) && importDecl.getModuleSpecifierValue() === expectedModule;
|
|
9160
9339
|
}
|
|
9161
9340
|
function extractInvocationEffects(func, barriers = NO_BARRIERS) {
|
|
9162
|
-
const
|
|
9341
|
+
const calls = [];
|
|
9163
9342
|
func.forEachDescendant((node, traversal) => {
|
|
9164
|
-
if (isDescentStop(node, func, barriers)) {
|
|
9343
|
+
if (isDescentStop(node, func, barriers) || Node41.isDecorator(node)) {
|
|
9165
9344
|
traversal.skip();
|
|
9166
9345
|
return;
|
|
9167
9346
|
}
|
|
9168
|
-
if (Node41.isExpressionStatement(node)) {
|
|
9169
|
-
const { call, async } = unwrapCall(node.getExpression());
|
|
9170
|
-
if (call !== null) {
|
|
9171
|
-
const preconditions = collectPreconditions(node, func);
|
|
9172
|
-
results.push({
|
|
9173
|
-
effect: {
|
|
9174
|
-
type: "invocation",
|
|
9175
|
-
callee: call.getExpression().getText(),
|
|
9176
|
-
args: extractArgs(call),
|
|
9177
|
-
async,
|
|
9178
|
-
...preconditions.length > 0 ? { preconditions } : {}
|
|
9179
|
-
},
|
|
9180
|
-
line: startLineOf(node),
|
|
9181
|
-
neverTerminal: false,
|
|
9182
|
-
alwaysRuns: runsOnEveryPath(node, func)
|
|
9183
|
-
});
|
|
9184
|
-
}
|
|
9185
|
-
return;
|
|
9186
|
-
}
|
|
9187
|
-
if (Node41.isSpreadElement(node)) {
|
|
9188
|
-
const parent = node.getParent();
|
|
9189
|
-
if (parent !== void 0 && (Node41.isArrayLiteralExpression(parent) || Node41.isObjectLiteralExpression(parent))) {
|
|
9190
|
-
const { call, async } = unwrapCall(node.getExpression());
|
|
9191
|
-
if (call !== null) {
|
|
9192
|
-
const preconditions = collectPreconditions(node, func);
|
|
9193
|
-
results.push({
|
|
9194
|
-
effect: {
|
|
9195
|
-
type: "invocation",
|
|
9196
|
-
callee: call.getExpression().getText(),
|
|
9197
|
-
args: extractArgs(call),
|
|
9198
|
-
async,
|
|
9199
|
-
...preconditions.length > 0 ? { preconditions } : {}
|
|
9200
|
-
},
|
|
9201
|
-
line: enclosingStatementLine(node),
|
|
9202
|
-
neverTerminal: true,
|
|
9203
|
-
alwaysRuns: runsOnEveryPath(node, func)
|
|
9204
|
-
});
|
|
9205
|
-
}
|
|
9206
|
-
}
|
|
9207
|
-
return;
|
|
9208
|
-
}
|
|
9209
|
-
if (Node41.isVariableDeclaration(node)) {
|
|
9210
|
-
const initializer = node.getInitializer();
|
|
9211
|
-
if (initializer !== void 0) {
|
|
9212
|
-
const { call, async } = unwrapCall(initializer);
|
|
9213
|
-
if (call !== null) {
|
|
9214
|
-
const preconditions = collectPreconditions(node, func);
|
|
9215
|
-
results.push({
|
|
9216
|
-
effect: {
|
|
9217
|
-
type: "invocation",
|
|
9218
|
-
callee: call.getExpression().getText(),
|
|
9219
|
-
args: extractArgs(call),
|
|
9220
|
-
async,
|
|
9221
|
-
...preconditions.length > 0 ? { preconditions } : {}
|
|
9222
|
-
},
|
|
9223
|
-
line: enclosingStatementLine(node),
|
|
9224
|
-
neverTerminal: true,
|
|
9225
|
-
alwaysRuns: runsOnEveryPath(node, func)
|
|
9226
|
-
});
|
|
9227
|
-
}
|
|
9228
|
-
}
|
|
9229
|
-
return;
|
|
9230
|
-
}
|
|
9231
|
-
if (Node41.isReturnStatement(node)) {
|
|
9232
|
-
const returned = node.getExpression();
|
|
9233
|
-
const { call, async } = returned === void 0 ? { call: null, async: false } : unwrapCall(returned);
|
|
9234
|
-
if (call !== null) {
|
|
9235
|
-
const preconditions = collectPreconditions(node, func);
|
|
9236
|
-
results.push({
|
|
9237
|
-
effect: {
|
|
9238
|
-
type: "invocation",
|
|
9239
|
-
callee: call.getExpression().getText(),
|
|
9240
|
-
args: extractArgs(call),
|
|
9241
|
-
async,
|
|
9242
|
-
...preconditions.length > 0 ? { preconditions } : {}
|
|
9243
|
-
},
|
|
9244
|
-
line: startLineOf(node),
|
|
9245
|
-
neverTerminal: false,
|
|
9246
|
-
alwaysRuns: runsOnEveryPath(node, func),
|
|
9247
|
-
node: call
|
|
9248
|
-
});
|
|
9249
|
-
}
|
|
9250
|
-
return;
|
|
9251
|
-
}
|
|
9252
|
-
if (Node41.isArrowFunction(node)) {
|
|
9253
|
-
const body = node.getBody();
|
|
9254
|
-
const { call, async } = Node41.isExpression(body) ? unwrapCall(body) : { call: null, async: false };
|
|
9255
|
-
if (call !== null) {
|
|
9256
|
-
const preconditions = collectPreconditions(node, func);
|
|
9257
|
-
results.push({
|
|
9258
|
-
effect: {
|
|
9259
|
-
type: "invocation",
|
|
9260
|
-
callee: call.getExpression().getText(),
|
|
9261
|
-
args: extractArgs(call),
|
|
9262
|
-
async: async || node.isAsync(),
|
|
9263
|
-
...preconditions.length > 0 ? { preconditions } : {}
|
|
9264
|
-
},
|
|
9265
|
-
line: startLineOf(node),
|
|
9266
|
-
neverTerminal: false,
|
|
9267
|
-
alwaysRuns: runsOnEveryPath(node, func),
|
|
9268
|
-
node: call
|
|
9269
|
-
});
|
|
9270
|
-
}
|
|
9271
|
-
return;
|
|
9272
|
-
}
|
|
9273
9347
|
if (Node41.isCallExpression(node)) {
|
|
9274
|
-
|
|
9275
|
-
if (parent === void 0) {
|
|
9276
|
-
return;
|
|
9277
|
-
}
|
|
9278
|
-
const isArrayElement = Node41.isArrayLiteralExpression(parent);
|
|
9279
|
-
const isPropertyValue = Node41.isPropertyAssignment(parent) && parent.getInitializer() === node;
|
|
9280
|
-
if (isArrayElement || isPropertyValue) {
|
|
9281
|
-
const preconditions = collectPreconditions(node, func);
|
|
9282
|
-
results.push({
|
|
9283
|
-
effect: {
|
|
9284
|
-
type: "invocation",
|
|
9285
|
-
callee: node.getExpression().getText(),
|
|
9286
|
-
args: extractArgs(node),
|
|
9287
|
-
async: false,
|
|
9288
|
-
...preconditions.length > 0 ? { preconditions } : {}
|
|
9289
|
-
},
|
|
9290
|
-
line: enclosingStatementLine(node),
|
|
9291
|
-
neverTerminal: true,
|
|
9292
|
-
alwaysRuns: runsOnEveryPath(node, func)
|
|
9293
|
-
});
|
|
9294
|
-
}
|
|
9348
|
+
calls.push(node);
|
|
9295
9349
|
}
|
|
9296
9350
|
});
|
|
9297
|
-
|
|
9351
|
+
calls.sort((a, b) => a.getEnd() - b.getEnd());
|
|
9352
|
+
return calls.map((call) => invocationAt(call, func));
|
|
9353
|
+
}
|
|
9354
|
+
function invocationAt(call, func) {
|
|
9355
|
+
const preconditions = collectPreconditions(call, func);
|
|
9356
|
+
return {
|
|
9357
|
+
effect: {
|
|
9358
|
+
type: "invocation",
|
|
9359
|
+
callee: call.getExpression().getText(),
|
|
9360
|
+
args: extractArgs(call),
|
|
9361
|
+
async: isAwaited(call),
|
|
9362
|
+
...preconditions.length > 0 ? { preconditions } : {}
|
|
9363
|
+
},
|
|
9364
|
+
node: call,
|
|
9365
|
+
line: enclosingStatementLine(call),
|
|
9366
|
+
alwaysRuns: runsOnEveryPath(call, func)
|
|
9367
|
+
};
|
|
9368
|
+
}
|
|
9369
|
+
function isAwaited(call) {
|
|
9370
|
+
let current2 = call.getParent();
|
|
9371
|
+
while (current2 !== void 0 && Node41.isParenthesizedExpression(current2)) {
|
|
9372
|
+
current2 = current2.getParent();
|
|
9373
|
+
}
|
|
9374
|
+
return current2 !== void 0 && Node41.isAwaitExpression(current2);
|
|
9298
9375
|
}
|
|
9299
9376
|
function runInvocationRecognizers(func, recognizers, barriers = NO_BARRIERS, resolveWrittenValue, originatesFrom, anchorCallsOf) {
|
|
9300
9377
|
if (recognizers.length === 0) {
|
|
@@ -9637,22 +9714,6 @@ function enclosingStatementLine(node) {
|
|
|
9637
9714
|
}
|
|
9638
9715
|
return startLineOf(node);
|
|
9639
9716
|
}
|
|
9640
|
-
function unwrapCall(node) {
|
|
9641
|
-
if (Node41.isAwaitExpression(node)) {
|
|
9642
|
-
const inner = node.getExpression();
|
|
9643
|
-
if (Node41.isCallExpression(inner)) {
|
|
9644
|
-
return { call: inner, async: true };
|
|
9645
|
-
}
|
|
9646
|
-
return { call: null, async: false };
|
|
9647
|
-
}
|
|
9648
|
-
if (Node41.isParenthesizedExpression(node)) {
|
|
9649
|
-
return unwrapCall(node.getExpression());
|
|
9650
|
-
}
|
|
9651
|
-
if (Node41.isCallExpression(node)) {
|
|
9652
|
-
return { call: node, async: false };
|
|
9653
|
-
}
|
|
9654
|
-
return { call: null, async: false };
|
|
9655
|
-
}
|
|
9656
9717
|
|
|
9657
9718
|
// src/terminals/index.ts
|
|
9658
9719
|
import { Node as Node51 } from "ts-morph";
|
|
@@ -11694,6 +11755,22 @@ function firesOn(site, branch) {
|
|
|
11694
11755
|
}
|
|
11695
11756
|
return site.alwaysRuns || runsBefore(site.line, branch.terminal.location.end);
|
|
11696
11757
|
}
|
|
11758
|
+
function writesTerminal(call, terminalNodes) {
|
|
11759
|
+
let current2 = call;
|
|
11760
|
+
for (; ; ) {
|
|
11761
|
+
if (terminalNodes.has(current2)) {
|
|
11762
|
+
return true;
|
|
11763
|
+
}
|
|
11764
|
+
const parent = current2.getParent();
|
|
11765
|
+
if (parent === void 0 || !isReceiverOf(current2, parent)) {
|
|
11766
|
+
return false;
|
|
11767
|
+
}
|
|
11768
|
+
current2 = parent;
|
|
11769
|
+
}
|
|
11770
|
+
}
|
|
11771
|
+
function isReceiverOf(node, parent) {
|
|
11772
|
+
return (Node52.isPropertyAccessExpression(parent) || Node52.isElementAccessExpression(parent) || Node52.isCallExpression(parent)) && parent.getExpression() === node;
|
|
11773
|
+
}
|
|
11697
11774
|
var isDefaultConditionList = (conditions) => conditions.length === 0 || conditions.every(
|
|
11698
11775
|
(c) => c.source === "earlyReturn" || c.source === "earlyThrow"
|
|
11699
11776
|
);
|
|
@@ -11832,11 +11909,8 @@ function extractRawBranches(func, terminalPatterns, invocationRecognizers = [],
|
|
|
11832
11909
|
});
|
|
11833
11910
|
if (invocations.length > 0) {
|
|
11834
11911
|
const terminalNodes = new Set(terminals.map(({ node }) => node));
|
|
11835
|
-
const terminalLines = new Set(
|
|
11836
|
-
distinctBranches.map((b) => b.terminal.location.start)
|
|
11837
|
-
);
|
|
11838
11912
|
const sideEffects = invocations.filter(
|
|
11839
|
-
(i) =>
|
|
11913
|
+
(i) => !writesTerminal(i.node, terminalNodes)
|
|
11840
11914
|
);
|
|
11841
11915
|
for (const branch of distinctBranches) {
|
|
11842
11916
|
branch.effects = sideEffects.filter(
|
|
@@ -11882,9 +11956,9 @@ function createSourceFileLookup(project) {
|
|
|
11882
11956
|
if (sf === null) {
|
|
11883
11957
|
return null;
|
|
11884
11958
|
}
|
|
11885
|
-
const
|
|
11886
|
-
const index = functionsByFile.get(
|
|
11887
|
-
functionsByFile.set(
|
|
11959
|
+
const path14 = sf.getFilePath();
|
|
11960
|
+
const index = functionsByFile.get(path14) ?? indexFunctions(sf);
|
|
11961
|
+
functionsByFile.set(path14, index);
|
|
11888
11962
|
if (location.span !== void 0) {
|
|
11889
11963
|
const bySpan = index.get(spanKey(location.span));
|
|
11890
11964
|
if (bySpan !== void 0) {
|
|
@@ -11929,356 +12003,6 @@ function indexFunctions(sf) {
|
|
|
11929
12003
|
return index;
|
|
11930
12004
|
}
|
|
11931
12005
|
|
|
11932
|
-
// src/cache.ts
|
|
11933
|
-
import { createHash as createHash2 } from "crypto";
|
|
11934
|
-
import fs5 from "fs/promises";
|
|
11935
|
-
import path7 from "path";
|
|
11936
|
-
var SCHEMA_VERSION = "6";
|
|
11937
|
-
var MAX_ENTRIES = 2;
|
|
11938
|
-
var ENTRY_PREFIX = "key-";
|
|
11939
|
-
var ENTRY_DIR_NAME = new RegExp(`^${ENTRY_PREFIX}[0-9a-f]{16}$`);
|
|
11940
|
-
function createCacheLayer(cacheDir) {
|
|
11941
|
-
if (cacheDir === null) {
|
|
11942
|
-
return {
|
|
11943
|
-
tryHit: async () => null,
|
|
11944
|
-
lookup: async () => ({
|
|
11945
|
-
kind: "miss",
|
|
11946
|
-
diagnostic: { kind: "miss", missReason: "no-manifest" }
|
|
11947
|
-
}),
|
|
11948
|
-
plan: async () => null,
|
|
11949
|
-
write: async () => {
|
|
11950
|
-
}
|
|
11951
|
-
};
|
|
11952
|
-
}
|
|
11953
|
-
return {
|
|
11954
|
-
async tryHit(input) {
|
|
11955
|
-
const result = await this.lookup(input);
|
|
11956
|
-
return result.kind === "hit" ? result.summaries : null;
|
|
11957
|
-
},
|
|
11958
|
-
async lookup(input) {
|
|
11959
|
-
const entryDir = entryDirFor(cacheDir, input);
|
|
11960
|
-
const manifest = await readManifest(path7.join(entryDir, "manifest.json"));
|
|
11961
|
-
if (manifest === null) {
|
|
11962
|
-
return missDiag(await describeAbsentEntry(cacheDir));
|
|
11963
|
-
}
|
|
11964
|
-
const currentTsconfigStamp = await stampTsconfig(input.tsconfigPath);
|
|
11965
|
-
if (!fileStampEquals(manifest.tsconfigStamp, currentTsconfigStamp)) {
|
|
11966
|
-
return missDiag("tsconfig-changed");
|
|
11967
|
-
}
|
|
11968
|
-
const currentFiles = await resolveFileStamps(input);
|
|
11969
|
-
if (!fileStampsEqual(manifest.files, currentFiles)) {
|
|
11970
|
-
return missDiag("files-changed");
|
|
11971
|
-
}
|
|
11972
|
-
await markUsed(entryDir);
|
|
11973
|
-
return {
|
|
11974
|
-
kind: "hit",
|
|
11975
|
-
summaries: manifest.summaries,
|
|
11976
|
-
diagnostic: { kind: "hit" }
|
|
11977
|
-
};
|
|
11978
|
-
},
|
|
11979
|
-
async plan(input) {
|
|
11980
|
-
const entryDir = entryDirFor(cacheDir, input);
|
|
11981
|
-
const manifest = await readManifest(path7.join(entryDir, "manifest.json"));
|
|
11982
|
-
if (manifest === null || manifest.roots === void 0 || manifest.rootMeta === void 0 || manifest.owners === void 0) {
|
|
11983
|
-
return null;
|
|
11984
|
-
}
|
|
11985
|
-
const currentTsconfigStamp = await stampTsconfig(input.tsconfigPath);
|
|
11986
|
-
if (!fileStampEquals(manifest.tsconfigStamp, currentTsconfigStamp)) {
|
|
11987
|
-
return null;
|
|
11988
|
-
}
|
|
11989
|
-
await markUsed(entryDir);
|
|
11990
|
-
return buildPlan(manifest, await resolveFileStamps(input));
|
|
11991
|
-
},
|
|
11992
|
-
async write(input, summaries, attribution) {
|
|
11993
|
-
const entryDir = entryDirFor(cacheDir, input);
|
|
11994
|
-
const previous = await readManifest(path7.join(entryDir, "manifest.json"));
|
|
11995
|
-
const tsconfigStamp = await stampTsconfig(input.tsconfigPath);
|
|
11996
|
-
const files = await hashStamps(await resolveFileStamps(input), previous);
|
|
11997
|
-
const manifest = {
|
|
11998
|
-
schemaVersion: SCHEMA_VERSION,
|
|
11999
|
-
adapterPacksDigest: input.adapterPacksDigest,
|
|
12000
|
-
tsconfigStamp,
|
|
12001
|
-
files,
|
|
12002
|
-
summaries,
|
|
12003
|
-
...attribution === void 0 ? {} : encodeAttribution(attribution)
|
|
12004
|
-
};
|
|
12005
|
-
await fs5.mkdir(entryDir, { recursive: true });
|
|
12006
|
-
await fs5.writeFile(
|
|
12007
|
-
path7.join(entryDir, "manifest.json"),
|
|
12008
|
-
JSON.stringify(manifest)
|
|
12009
|
-
);
|
|
12010
|
-
await evictOldEntries(cacheDir, entryDir);
|
|
12011
|
-
}
|
|
12012
|
-
};
|
|
12013
|
-
}
|
|
12014
|
-
async function buildPlan(manifest, currentStamps) {
|
|
12015
|
-
const stored = new Map(manifest.files.map((f) => [f.path, f]));
|
|
12016
|
-
const current2 = new Map(currentStamps.map((f) => [f.path, f]));
|
|
12017
|
-
const changed = /* @__PURE__ */ new Set();
|
|
12018
|
-
const removed = /* @__PURE__ */ new Set();
|
|
12019
|
-
for (const p of stored.keys()) {
|
|
12020
|
-
if (!current2.has(p)) {
|
|
12021
|
-
removed.add(p);
|
|
12022
|
-
}
|
|
12023
|
-
}
|
|
12024
|
-
const toVerify = [];
|
|
12025
|
-
for (const [p, stamp] of current2) {
|
|
12026
|
-
const before = stored.get(p);
|
|
12027
|
-
if (before === void 0) {
|
|
12028
|
-
changed.add(p);
|
|
12029
|
-
} else if (!fileStampEquals(before, stamp)) {
|
|
12030
|
-
if (before.contentHash === void 0) {
|
|
12031
|
-
changed.add(p);
|
|
12032
|
-
} else {
|
|
12033
|
-
toVerify.push(p);
|
|
12034
|
-
}
|
|
12035
|
-
}
|
|
12036
|
-
}
|
|
12037
|
-
await Promise.all(
|
|
12038
|
-
toVerify.map(async (p) => {
|
|
12039
|
-
const hash = await hashFile(p);
|
|
12040
|
-
if (hash === null || hash !== stored.get(p)?.contentHash) {
|
|
12041
|
-
changed.add(p);
|
|
12042
|
-
}
|
|
12043
|
-
})
|
|
12044
|
-
);
|
|
12045
|
-
const roots = /* @__PURE__ */ new Map();
|
|
12046
|
-
const rootNames = manifest.roots ?? [];
|
|
12047
|
-
const depPaths = manifest.depPaths ?? [];
|
|
12048
|
-
let rootsDeclined = 0;
|
|
12049
|
-
rootNames.forEach((rootPath, i) => {
|
|
12050
|
-
const meta = manifest.rootMeta?.[i];
|
|
12051
|
-
if (meta === void 0) {
|
|
12052
|
-
return;
|
|
12053
|
-
}
|
|
12054
|
-
if (!meta.cacheable) {
|
|
12055
|
-
rootsDeclined += 1;
|
|
12056
|
-
}
|
|
12057
|
-
roots.set(rootPath, {
|
|
12058
|
-
path: rootPath,
|
|
12059
|
-
cacheable: meta.cacheable,
|
|
12060
|
-
deps: meta.deps.flatMap((d) => {
|
|
12061
|
-
const p = depPaths[d];
|
|
12062
|
-
return p === void 0 ? [] : [p];
|
|
12063
|
-
}),
|
|
12064
|
-
claims: meta.claims,
|
|
12065
|
-
mountPrefixes: meta.mountPrefixes,
|
|
12066
|
-
packs: meta.packs
|
|
12067
|
-
});
|
|
12068
|
-
});
|
|
12069
|
-
const validRoots = /* @__PURE__ */ new Set();
|
|
12070
|
-
for (const [rootPath, record2] of roots) {
|
|
12071
|
-
if (!record2.cacheable || !current2.has(rootPath)) {
|
|
12072
|
-
continue;
|
|
12073
|
-
}
|
|
12074
|
-
if (changed.has(rootPath)) {
|
|
12075
|
-
continue;
|
|
12076
|
-
}
|
|
12077
|
-
const depMoved = record2.deps.some((d) => changed.has(d) || removed.has(d));
|
|
12078
|
-
if (!depMoved) {
|
|
12079
|
-
validRoots.add(rootPath);
|
|
12080
|
-
}
|
|
12081
|
-
}
|
|
12082
|
-
const owners = manifest.owners ?? [];
|
|
12083
|
-
return {
|
|
12084
|
-
changed,
|
|
12085
|
-
removed,
|
|
12086
|
-
roots,
|
|
12087
|
-
validRoots,
|
|
12088
|
-
rootsDeclined,
|
|
12089
|
-
reuse(valid) {
|
|
12090
|
-
const summaries = [];
|
|
12091
|
-
const reusedOwners = [];
|
|
12092
|
-
manifest.summaries.forEach((summary, i) => {
|
|
12093
|
-
const ownerPaths = (owners[i] ?? []).flatMap((o) => {
|
|
12094
|
-
const p = rootNames[o];
|
|
12095
|
-
return p === void 0 ? [] : [p];
|
|
12096
|
-
});
|
|
12097
|
-
if (ownerPaths.some((p) => valid.has(p))) {
|
|
12098
|
-
summaries.push(summary);
|
|
12099
|
-
reusedOwners.push(ownerPaths.filter((p) => valid.has(p)));
|
|
12100
|
-
}
|
|
12101
|
-
});
|
|
12102
|
-
return { summaries, owners: reusedOwners };
|
|
12103
|
-
},
|
|
12104
|
-
allSummaries() {
|
|
12105
|
-
return manifest.summaries;
|
|
12106
|
-
},
|
|
12107
|
-
attribution() {
|
|
12108
|
-
return {
|
|
12109
|
-
roots: [...roots.values()],
|
|
12110
|
-
owners: owners.map(
|
|
12111
|
-
(ownerIds) => ownerIds.flatMap((o) => {
|
|
12112
|
-
const p = rootNames[o];
|
|
12113
|
-
return p === void 0 ? [] : [p];
|
|
12114
|
-
})
|
|
12115
|
-
)
|
|
12116
|
-
};
|
|
12117
|
-
}
|
|
12118
|
-
};
|
|
12119
|
-
}
|
|
12120
|
-
function encodeAttribution(attribution) {
|
|
12121
|
-
const roots = attribution.roots.map((r) => r.path);
|
|
12122
|
-
const rootIndex = new Map(roots.map((p, i) => [p, i]));
|
|
12123
|
-
const depIndex = /* @__PURE__ */ new Map();
|
|
12124
|
-
const depPaths = [];
|
|
12125
|
-
const depIdOf = (p) => {
|
|
12126
|
-
const existing = depIndex.get(p);
|
|
12127
|
-
if (existing !== void 0) {
|
|
12128
|
-
return existing;
|
|
12129
|
-
}
|
|
12130
|
-
const id = depPaths.length;
|
|
12131
|
-
depPaths.push(p);
|
|
12132
|
-
depIndex.set(p, id);
|
|
12133
|
-
return id;
|
|
12134
|
-
};
|
|
12135
|
-
const rootMeta = attribution.roots.map((r) => ({
|
|
12136
|
-
cacheable: r.cacheable,
|
|
12137
|
-
deps: r.deps.map(depIdOf),
|
|
12138
|
-
claims: r.claims,
|
|
12139
|
-
mountPrefixes: r.mountPrefixes,
|
|
12140
|
-
packs: r.packs
|
|
12141
|
-
}));
|
|
12142
|
-
const owners = attribution.owners.map(
|
|
12143
|
-
(ownerPaths) => ownerPaths.flatMap((p) => {
|
|
12144
|
-
const i = rootIndex.get(p);
|
|
12145
|
-
return i === void 0 ? [] : [i];
|
|
12146
|
-
})
|
|
12147
|
-
);
|
|
12148
|
-
return { roots, rootMeta, depPaths, owners };
|
|
12149
|
-
}
|
|
12150
|
-
async function hashStamps(stamps, previous) {
|
|
12151
|
-
const before = new Map((previous?.files ?? []).map((f) => [f.path, f]));
|
|
12152
|
-
return Promise.all(
|
|
12153
|
-
stamps.map(async (stamp) => {
|
|
12154
|
-
const prior = before.get(stamp.path);
|
|
12155
|
-
if (prior !== void 0 && prior.contentHash !== void 0 && fileStampEquals(prior, stamp)) {
|
|
12156
|
-
return { ...stamp, contentHash: prior.contentHash };
|
|
12157
|
-
}
|
|
12158
|
-
const contentHash = await hashFile(stamp.path);
|
|
12159
|
-
return contentHash === null ? stamp : { ...stamp, contentHash };
|
|
12160
|
-
})
|
|
12161
|
-
);
|
|
12162
|
-
}
|
|
12163
|
-
async function hashFile(filePath) {
|
|
12164
|
-
try {
|
|
12165
|
-
const content = await fs5.readFile(filePath);
|
|
12166
|
-
return createHash2("sha256").update(content).digest("hex").slice(0, 16);
|
|
12167
|
-
} catch {
|
|
12168
|
-
return null;
|
|
12169
|
-
}
|
|
12170
|
-
}
|
|
12171
|
-
async function describeAbsentEntry(cacheDir) {
|
|
12172
|
-
try {
|
|
12173
|
-
const entries = await fs5.readdir(cacheDir, { withFileTypes: true });
|
|
12174
|
-
return entries.some((e) => e.isDirectory() && isEntryDir(e.name)) ? "key-changed" : "no-manifest";
|
|
12175
|
-
} catch {
|
|
12176
|
-
return "no-manifest";
|
|
12177
|
-
}
|
|
12178
|
-
}
|
|
12179
|
-
function entryDirFor(cacheDir, input) {
|
|
12180
|
-
const key = [
|
|
12181
|
-
SCHEMA_VERSION,
|
|
12182
|
-
input.adapterPacksDigest,
|
|
12183
|
-
input.tsconfigPath ?? ""
|
|
12184
|
-
].join(" ");
|
|
12185
|
-
const name = createHash2("sha256").update(key).digest("hex").slice(0, 16);
|
|
12186
|
-
return path7.join(cacheDir, `${ENTRY_PREFIX}${name}`);
|
|
12187
|
-
}
|
|
12188
|
-
function isEntryDir(name) {
|
|
12189
|
-
return ENTRY_DIR_NAME.test(name);
|
|
12190
|
-
}
|
|
12191
|
-
async function markUsed(entryDir) {
|
|
12192
|
-
const now = /* @__PURE__ */ new Date();
|
|
12193
|
-
try {
|
|
12194
|
-
await fs5.utimes(entryDir, now, now);
|
|
12195
|
-
} catch {
|
|
12196
|
-
}
|
|
12197
|
-
}
|
|
12198
|
-
async function evictOldEntries(cacheDir, keepDir) {
|
|
12199
|
-
try {
|
|
12200
|
-
await fs5.rm(path7.join(cacheDir, "manifest.json"), { force: true });
|
|
12201
|
-
const entries = await fs5.readdir(cacheDir, { withFileTypes: true });
|
|
12202
|
-
const dirs = await Promise.all(
|
|
12203
|
-
entries.filter((e) => e.isDirectory() && isEntryDir(e.name)).map(async (e) => {
|
|
12204
|
-
const dir = path7.join(cacheDir, e.name);
|
|
12205
|
-
const stat = await fs5.stat(dir);
|
|
12206
|
-
return { dir, mtimeMs: stat.mtimeMs };
|
|
12207
|
-
})
|
|
12208
|
-
);
|
|
12209
|
-
const doomed = dirs.filter((d) => d.dir !== keepDir).sort((a, b) => b.mtimeMs - a.mtimeMs).slice(MAX_ENTRIES - 1);
|
|
12210
|
-
await Promise.all(
|
|
12211
|
-
doomed.map((d) => fs5.rm(d.dir, { recursive: true, force: true }))
|
|
12212
|
-
);
|
|
12213
|
-
} catch {
|
|
12214
|
-
}
|
|
12215
|
-
}
|
|
12216
|
-
function missDiag(reason) {
|
|
12217
|
-
return {
|
|
12218
|
-
kind: "miss",
|
|
12219
|
-
diagnostic: { kind: "miss", missReason: reason }
|
|
12220
|
-
};
|
|
12221
|
-
}
|
|
12222
|
-
async function readManifest(manifestPath) {
|
|
12223
|
-
try {
|
|
12224
|
-
const raw = await fs5.readFile(manifestPath, "utf-8");
|
|
12225
|
-
return JSON.parse(raw);
|
|
12226
|
-
} catch {
|
|
12227
|
-
return null;
|
|
12228
|
-
}
|
|
12229
|
-
}
|
|
12230
|
-
async function stampTsconfig(tsconfigPath) {
|
|
12231
|
-
if (tsconfigPath === void 0) {
|
|
12232
|
-
return null;
|
|
12233
|
-
}
|
|
12234
|
-
try {
|
|
12235
|
-
const stat = await fs5.stat(tsconfigPath);
|
|
12236
|
-
return { path: tsconfigPath, mtimeMs: stat.mtimeMs, size: stat.size };
|
|
12237
|
-
} catch {
|
|
12238
|
-
return null;
|
|
12239
|
-
}
|
|
12240
|
-
}
|
|
12241
|
-
async function resolveFileStamps(input) {
|
|
12242
|
-
if (input.files !== void 0) {
|
|
12243
|
-
return stampPaths(input.files);
|
|
12244
|
-
}
|
|
12245
|
-
if (input.project !== void 0) {
|
|
12246
|
-
return stampProjectFiles(input.project);
|
|
12247
|
-
}
|
|
12248
|
-
return [];
|
|
12249
|
-
}
|
|
12250
|
-
async function stampProjectFiles(project) {
|
|
12251
|
-
const files = project.getSourceFiles().filter((sf) => !sf.isDeclarationFile()).map((sf) => sf.getFilePath());
|
|
12252
|
-
return stampPaths(files);
|
|
12253
|
-
}
|
|
12254
|
-
async function stampPaths(paths) {
|
|
12255
|
-
const files = paths;
|
|
12256
|
-
const stamped = await Promise.all(
|
|
12257
|
-
files.map(async (p) => {
|
|
12258
|
-
try {
|
|
12259
|
-
const stat = await fs5.stat(p);
|
|
12260
|
-
return { path: p, mtimeMs: stat.mtimeMs, size: stat.size };
|
|
12261
|
-
} catch {
|
|
12262
|
-
return { path: p, mtimeMs: -1, size: -1 };
|
|
12263
|
-
}
|
|
12264
|
-
})
|
|
12265
|
-
);
|
|
12266
|
-
stamped.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
12267
|
-
return stamped;
|
|
12268
|
-
}
|
|
12269
|
-
function fileStampsEqual(a, b) {
|
|
12270
|
-
return a.length === b.length && a.every((s, i) => fileStampEquals(s, b[i]));
|
|
12271
|
-
}
|
|
12272
|
-
function fileStampEquals(a, b) {
|
|
12273
|
-
if (a === null && b === null) {
|
|
12274
|
-
return true;
|
|
12275
|
-
}
|
|
12276
|
-
if (a === null || b === null) {
|
|
12277
|
-
return false;
|
|
12278
|
-
}
|
|
12279
|
-
return a.path === b.path && a.mtimeMs === b.mtimeMs && a.size === b.size;
|
|
12280
|
-
}
|
|
12281
|
-
|
|
12282
12006
|
// src/contract.ts
|
|
12283
12007
|
import { Node as Node54 } from "ts-morph";
|
|
12284
12008
|
import { restBinding } from "@suss/behavioral-ir";
|
|
@@ -12421,7 +12145,7 @@ function extractEndpointContract(endpointNode, pattern, framework) {
|
|
|
12421
12145
|
}
|
|
12422
12146
|
const responses = [];
|
|
12423
12147
|
let method;
|
|
12424
|
-
let
|
|
12148
|
+
let path14;
|
|
12425
12149
|
for (const prop of endpointNode.getProperties()) {
|
|
12426
12150
|
if (!Node54.isPropertyAssignment(prop)) {
|
|
12427
12151
|
continue;
|
|
@@ -12436,7 +12160,7 @@ function extractEndpointContract(endpointNode, pattern, framework) {
|
|
|
12436
12160
|
if (propName === pattern.pathProperty) {
|
|
12437
12161
|
const val = prop.getInitializer();
|
|
12438
12162
|
if (val !== void 0 && Node54.isStringLiteral(val)) {
|
|
12439
|
-
|
|
12163
|
+
path14 = val.getLiteralValue();
|
|
12440
12164
|
}
|
|
12441
12165
|
}
|
|
12442
12166
|
if (propName === pattern.responseExtraction.property) {
|
|
@@ -12460,10 +12184,10 @@ function extractEndpointContract(endpointNode, pattern, framework) {
|
|
|
12460
12184
|
if (responses.length === 0) {
|
|
12461
12185
|
return null;
|
|
12462
12186
|
}
|
|
12463
|
-
const boundaryBinding = method !== void 0 ||
|
|
12187
|
+
const boundaryBinding = method !== void 0 || path14 !== void 0 ? restBinding({
|
|
12464
12188
|
transport: "http",
|
|
12465
12189
|
method: method ?? null,
|
|
12466
|
-
path:
|
|
12190
|
+
path: path14 ?? null,
|
|
12467
12191
|
recognition: framework
|
|
12468
12192
|
}) : null;
|
|
12469
12193
|
return {
|
|
@@ -13102,8 +12826,8 @@ function noteExpanded(expanded, readings, discovery) {
|
|
|
13102
12826
|
const paths = new Set(match.registrations.map((one) => one.pathTemplate));
|
|
13103
12827
|
const methods = expanded.get(reading.declarationId) ?? /* @__PURE__ */ new Set();
|
|
13104
12828
|
for (const sink of reading.helper.sinks) {
|
|
13105
|
-
const
|
|
13106
|
-
if (sink.method !== null &&
|
|
12829
|
+
const path14 = sink.arguments[0];
|
|
12830
|
+
if (sink.method !== null && path14?.as === "text" && paths.has(path14.text)) {
|
|
13107
12831
|
methods.add(sink.method);
|
|
13108
12832
|
}
|
|
13109
12833
|
}
|
|
@@ -13697,7 +13421,7 @@ function scalarOrRef(node) {
|
|
|
13697
13421
|
}
|
|
13698
13422
|
|
|
13699
13423
|
// src/moduleInit.ts
|
|
13700
|
-
import { assembleSummary } from "@suss/extractor";
|
|
13424
|
+
import { assembleSummary, moduleInitStructure } from "@suss/extractor";
|
|
13701
13425
|
function moduleInitName(sourceFile) {
|
|
13702
13426
|
return sourceFile.getBaseName();
|
|
13703
13427
|
}
|
|
@@ -13705,44 +13429,15 @@ function moduleInitSummary(sourceFile, effects, options) {
|
|
|
13705
13429
|
if (effects.length === 0) {
|
|
13706
13430
|
return null;
|
|
13707
13431
|
}
|
|
13708
|
-
|
|
13709
|
-
|
|
13710
|
-
identity: {
|
|
13432
|
+
return assembleSummary(
|
|
13433
|
+
moduleInitStructure({
|
|
13711
13434
|
name: moduleInitName(sourceFile),
|
|
13712
|
-
kind: "module-init",
|
|
13713
13435
|
file: sourceFile.getFilePath(),
|
|
13714
|
-
range: { start: 0, end },
|
|
13715
|
-
|
|
13716
|
-
|
|
13717
|
-
|
|
13718
|
-
|
|
13719
|
-
parameters: [],
|
|
13720
|
-
branches: [
|
|
13721
|
-
{
|
|
13722
|
-
conditions: [],
|
|
13723
|
-
terminal: {
|
|
13724
|
-
kind: "void",
|
|
13725
|
-
statusCode: null,
|
|
13726
|
-
body: null,
|
|
13727
|
-
exceptionType: null,
|
|
13728
|
-
message: null,
|
|
13729
|
-
component: null,
|
|
13730
|
-
renderTree: null,
|
|
13731
|
-
delegateTarget: null,
|
|
13732
|
-
emitEvent: null,
|
|
13733
|
-
location: { start: 0, end }
|
|
13734
|
-
},
|
|
13735
|
-
effects: [],
|
|
13736
|
-
extraEffects: effects,
|
|
13737
|
-
location: { start: 0, end },
|
|
13738
|
-
isDefault: true
|
|
13739
|
-
}
|
|
13740
|
-
],
|
|
13741
|
-
unmatchedReturns: 0,
|
|
13742
|
-
dependencyCalls: [],
|
|
13743
|
-
declaredContract: null
|
|
13744
|
-
};
|
|
13745
|
-
return assembleSummary(raw, options);
|
|
13436
|
+
range: { start: 0, end: sourceFile.getEnd() },
|
|
13437
|
+
effects
|
|
13438
|
+
}),
|
|
13439
|
+
options
|
|
13440
|
+
);
|
|
13746
13441
|
}
|
|
13747
13442
|
|
|
13748
13443
|
// src/referencedFiles.ts
|
|
@@ -13890,7 +13585,7 @@ function deriveBoundaryEffects(summaries, facts) {
|
|
|
13890
13585
|
|
|
13891
13586
|
// src/resolve/reachableClosure.ts
|
|
13892
13587
|
import { Node as Node60 } from "ts-morph";
|
|
13893
|
-
import { functionCallBinding } from "@suss/behavioral-ir";
|
|
13588
|
+
import { functionCallBinding, TargetPlacements } from "@suss/behavioral-ir";
|
|
13894
13589
|
import { Database as Database3, evaluate as evaluate4, lit as lit4, rule as rule4, variable as variable2 } from "@suss/datalog";
|
|
13895
13590
|
import { assembleSummary as assembleSummary2 } from "@suss/extractor";
|
|
13896
13591
|
var reachablePack = {
|
|
@@ -13914,6 +13609,12 @@ var reachablePack = {
|
|
|
13914
13609
|
function nodeKey(func) {
|
|
13915
13610
|
return offsetKeyOf(func);
|
|
13916
13611
|
}
|
|
13612
|
+
function targetOf(node) {
|
|
13613
|
+
return {
|
|
13614
|
+
file: node.getSourceFile().getFilePath(),
|
|
13615
|
+
span: { start: node.getStart(), end: node.getEnd() }
|
|
13616
|
+
};
|
|
13617
|
+
}
|
|
13917
13618
|
function resolveCallee(call, calleeName, scan) {
|
|
13918
13619
|
if (!Node60.isCallExpression(call)) {
|
|
13919
13620
|
return null;
|
|
@@ -13938,19 +13639,42 @@ function resolveCallee(call, calleeName, scan) {
|
|
|
13938
13639
|
if (sources.length > 1) {
|
|
13939
13640
|
return {
|
|
13940
13641
|
kind: "stopped",
|
|
13941
|
-
stop: { callee: calleeName, reason: "multipleSources" }
|
|
13642
|
+
stop: { callee: calleeName, reason: "multipleSources" },
|
|
13643
|
+
declaration: declarationToReport(declarations, calleeName, scan)
|
|
13942
13644
|
};
|
|
13943
13645
|
}
|
|
13944
13646
|
}
|
|
13647
|
+
const reason = classifyStop(declarations, scan.scanning);
|
|
13648
|
+
const parameterIndex = reason === "callerSupplied" ? parameterIndexOf(declarations, scan.scanning) : void 0;
|
|
13945
13649
|
return {
|
|
13946
13650
|
kind: "stopped",
|
|
13947
|
-
stop: {
|
|
13948
|
-
|
|
13949
|
-
|
|
13950
|
-
}
|
|
13651
|
+
stop: { callee: calleeName, reason },
|
|
13652
|
+
declaration: declarationToReport(declarations, calleeName, scan),
|
|
13653
|
+
...parameterIndex === void 0 ? {} : { parameterIndex }
|
|
13951
13654
|
};
|
|
13952
13655
|
}
|
|
13953
|
-
function
|
|
13656
|
+
function declarationToReport(declarations, calleeName, scan) {
|
|
13657
|
+
const first = declarations[0];
|
|
13658
|
+
if (first === void 0) {
|
|
13659
|
+
return null;
|
|
13660
|
+
}
|
|
13661
|
+
const sources = scan.sourceDeclarationsBehind?.(first) ?? [first];
|
|
13662
|
+
const only = sources.length === 1 ? sources[0] : void 0;
|
|
13663
|
+
if (only === void 0 || only === first) {
|
|
13664
|
+
return first;
|
|
13665
|
+
}
|
|
13666
|
+
return resolveDecl(only, calleeName)?.func ?? only;
|
|
13667
|
+
}
|
|
13668
|
+
function declaredAtOf(outcome) {
|
|
13669
|
+
if (outcome.kind === "followed") {
|
|
13670
|
+
return targetOf(outcome.candidate.func);
|
|
13671
|
+
}
|
|
13672
|
+
return outcome.declaration === null ? null : targetOf(outcome.declaration);
|
|
13673
|
+
}
|
|
13674
|
+
function passedPositionKey(target, position) {
|
|
13675
|
+
return `${offsetKeyFor(target.file, target.span)}#${position}`;
|
|
13676
|
+
}
|
|
13677
|
+
function resolveJsxReference(node, scan) {
|
|
13954
13678
|
if (!Node60.isJsxOpeningElement(node) && !Node60.isJsxSelfClosingElement(node)) {
|
|
13955
13679
|
return null;
|
|
13956
13680
|
}
|
|
@@ -13970,7 +13694,8 @@ function resolveJsxReference(node) {
|
|
|
13970
13694
|
tag: name,
|
|
13971
13695
|
outcome: {
|
|
13972
13696
|
kind: "stopped",
|
|
13973
|
-
stop: { callee: name, reason: classifyStop(declarations) }
|
|
13697
|
+
stop: { callee: name, reason: classifyStop(declarations) },
|
|
13698
|
+
declaration: declarationToReport(declarations, name, scan)
|
|
13974
13699
|
}
|
|
13975
13700
|
};
|
|
13976
13701
|
}
|
|
@@ -13978,7 +13703,11 @@ function collectReachable(func, scan) {
|
|
|
13978
13703
|
const inFunc = { ...scan, scanning: func };
|
|
13979
13704
|
const candidates = [];
|
|
13980
13705
|
const stops = [];
|
|
13706
|
+
const placements = new TargetPlacements();
|
|
13707
|
+
const parameterCalls = [];
|
|
13708
|
+
const passedPositions = /* @__PURE__ */ new Set();
|
|
13981
13709
|
const seen = /* @__PURE__ */ new Set();
|
|
13710
|
+
const parameterCallsSeen = /* @__PURE__ */ new Set();
|
|
13982
13711
|
const record2 = (outcome) => {
|
|
13983
13712
|
if (outcome.kind === "stopped") {
|
|
13984
13713
|
const stopKey = `${outcome.stop.reason}:${outcome.stop.callee}`;
|
|
@@ -13995,8 +13724,28 @@ function collectReachable(func, scan) {
|
|
|
13995
13724
|
seen.add(key);
|
|
13996
13725
|
candidates.push(outcome.candidate);
|
|
13997
13726
|
};
|
|
13727
|
+
const recordPassedArgs = (call, calleeText, calleeOutcome) => {
|
|
13728
|
+
if (!Node60.isCallExpression(call)) {
|
|
13729
|
+
return;
|
|
13730
|
+
}
|
|
13731
|
+
const calleeTarget = declaredAtOf(calleeOutcome);
|
|
13732
|
+
call.getArguments().forEach((arg, position) => {
|
|
13733
|
+
if (!Node60.isIdentifier(arg)) {
|
|
13734
|
+
return;
|
|
13735
|
+
}
|
|
13736
|
+
const resolved = functionTargetOf(arg);
|
|
13737
|
+
if (resolved === null) {
|
|
13738
|
+
return;
|
|
13739
|
+
}
|
|
13740
|
+
record2({ kind: "followed", candidate: resolved });
|
|
13741
|
+
placements.placeArg(calleeText, position, targetOf(resolved.func));
|
|
13742
|
+
if (calleeTarget !== null) {
|
|
13743
|
+
passedPositions.add(passedPositionKey(calleeTarget, position));
|
|
13744
|
+
}
|
|
13745
|
+
});
|
|
13746
|
+
};
|
|
13998
13747
|
func.forEachDescendant((node) => {
|
|
13999
|
-
const jsx = resolveJsxReference(node);
|
|
13748
|
+
const jsx = resolveJsxReference(node, inFunc);
|
|
14000
13749
|
if (jsx !== null) {
|
|
14001
13750
|
record2(jsx.outcome);
|
|
14002
13751
|
return;
|
|
@@ -14010,8 +13759,24 @@ function collectReachable(func, scan) {
|
|
|
14010
13759
|
return;
|
|
14011
13760
|
}
|
|
14012
13761
|
record2(outcome);
|
|
13762
|
+
placements.place(calleeText, declaredAtOf(outcome));
|
|
13763
|
+
recordPassedArgs(node, calleeText, outcome);
|
|
13764
|
+
if (outcome.kind === "stopped" && outcome.stop.reason === "callerSupplied" && outcome.parameterIndex !== void 0 && !parameterCallsSeen.has(calleeText)) {
|
|
13765
|
+
parameterCallsSeen.add(calleeText);
|
|
13766
|
+
parameterCalls.push({
|
|
13767
|
+
callee: calleeText,
|
|
13768
|
+
parameterIndex: outcome.parameterIndex
|
|
13769
|
+
});
|
|
13770
|
+
}
|
|
14013
13771
|
});
|
|
14014
|
-
return {
|
|
13772
|
+
return {
|
|
13773
|
+
candidates,
|
|
13774
|
+
stops,
|
|
13775
|
+
targets: placements.targets,
|
|
13776
|
+
argTargets: placements.argTargets,
|
|
13777
|
+
parameterCalls,
|
|
13778
|
+
passedPositions
|
|
13779
|
+
};
|
|
14015
13780
|
}
|
|
14016
13781
|
function normalizeCallee(text) {
|
|
14017
13782
|
return text.replace(/\s+/g, " ").trim();
|
|
@@ -14086,6 +13851,10 @@ function expandReachableClosure(seeds, project, options, projectFileSet, facts,
|
|
|
14086
13851
|
const seedKeys = /* @__PURE__ */ new Set();
|
|
14087
13852
|
const scanned = /* @__PURE__ */ new Set();
|
|
14088
13853
|
const stopsByKey = /* @__PURE__ */ new Map();
|
|
13854
|
+
const targetsByKey = /* @__PURE__ */ new Map();
|
|
13855
|
+
const argTargetsByKey = /* @__PURE__ */ new Map();
|
|
13856
|
+
const parameterCallsByKey = /* @__PURE__ */ new Map();
|
|
13857
|
+
const passedPositions = /* @__PURE__ */ new Set();
|
|
14089
13858
|
const summariesByKey = /* @__PURE__ */ new Map();
|
|
14090
13859
|
const reachedFrom = /* @__PURE__ */ new Map();
|
|
14091
13860
|
for (const seed of seeds) {
|
|
@@ -14130,9 +13899,17 @@ function expandReachableClosure(seeds, project, options, projectFileSet, facts,
|
|
|
14130
13899
|
const cameFrom = reachedFrom.get(key);
|
|
14131
13900
|
const scan = {
|
|
14132
13901
|
...recognizers.resolveCallableSources === void 0 ? {} : { resolveCallableSources: recognizers.resolveCallableSources },
|
|
13902
|
+
...recognizers.sourceDeclarationsBehind === void 0 ? {} : { sourceDeclarationsBehind: recognizers.sourceDeclarationsBehind },
|
|
14133
13903
|
...cameFrom === void 0 ? {} : { reachedFrom: cameFrom }
|
|
14134
13904
|
};
|
|
14135
|
-
const {
|
|
13905
|
+
const {
|
|
13906
|
+
candidates,
|
|
13907
|
+
stops,
|
|
13908
|
+
targets,
|
|
13909
|
+
argTargets,
|
|
13910
|
+
parameterCalls,
|
|
13911
|
+
passedPositions: scanPassedPositions
|
|
13912
|
+
} = scanWithRecording(
|
|
14136
13913
|
key,
|
|
14137
13914
|
facts,
|
|
14138
13915
|
() => collectReachable(source.func, scan)
|
|
@@ -14140,6 +13917,14 @@ function expandReachableClosure(seeds, project, options, projectFileSet, facts,
|
|
|
14140
13917
|
if (stops.length > 0) {
|
|
14141
13918
|
stopsByKey.set(key, stops);
|
|
14142
13919
|
}
|
|
13920
|
+
targetsByKey.set(key, targets);
|
|
13921
|
+
argTargetsByKey.set(key, argTargets);
|
|
13922
|
+
if (parameterCalls.length > 0) {
|
|
13923
|
+
parameterCallsByKey.set(key, parameterCalls);
|
|
13924
|
+
}
|
|
13925
|
+
for (const position of scanPassedPositions) {
|
|
13926
|
+
passedPositions.add(position);
|
|
13927
|
+
}
|
|
14143
13928
|
for (const candidate of candidates) {
|
|
14144
13929
|
const calleeKey = nodeKey(candidate.func);
|
|
14145
13930
|
if (!functionByKey.has(calleeKey)) {
|
|
@@ -14179,6 +13964,15 @@ function expandReachableClosure(seeds, project, options, projectFileSet, facts,
|
|
|
14179
13964
|
reached.push(summary);
|
|
14180
13965
|
}
|
|
14181
13966
|
recordStops(stopsByKey, summariesByKey, options);
|
|
13967
|
+
recordTargets(targetsByKey, summariesByKey);
|
|
13968
|
+
recordArgTargets(argTargetsByKey, summariesByKey);
|
|
13969
|
+
recordCalleeParameters(parameterCallsByKey, summariesByKey);
|
|
13970
|
+
recordParameterGaps(
|
|
13971
|
+
parameterCallsByKey,
|
|
13972
|
+
summariesByKey,
|
|
13973
|
+
passedPositions,
|
|
13974
|
+
options
|
|
13975
|
+
);
|
|
14182
13976
|
return [...seeds, ...reached];
|
|
14183
13977
|
}
|
|
14184
13978
|
function scanWithRecording(key, facts, fn) {
|
|
@@ -14210,6 +14004,90 @@ function recordStops(stopsByKey, summariesByKey, options) {
|
|
|
14210
14004
|
}
|
|
14211
14005
|
}
|
|
14212
14006
|
}
|
|
14007
|
+
function recordTargets(targetsByKey, summariesByKey) {
|
|
14008
|
+
for (const [key, targets] of targetsByKey) {
|
|
14009
|
+
for (const summary of summariesByKey.get(key) ?? []) {
|
|
14010
|
+
for (const transition of summary.transitions) {
|
|
14011
|
+
for (const effect of transition.effects) {
|
|
14012
|
+
if (effect.type !== "invocation") {
|
|
14013
|
+
continue;
|
|
14014
|
+
}
|
|
14015
|
+
const target = targets.get(normalizeCallee(effect.callee));
|
|
14016
|
+
if (target !== void 0) {
|
|
14017
|
+
effect.declaredAt = target;
|
|
14018
|
+
}
|
|
14019
|
+
}
|
|
14020
|
+
}
|
|
14021
|
+
}
|
|
14022
|
+
}
|
|
14023
|
+
}
|
|
14024
|
+
function recordArgTargets(argTargetsByKey, summariesByKey) {
|
|
14025
|
+
for (const [key, argTargets] of argTargetsByKey) {
|
|
14026
|
+
for (const summary of summariesByKey.get(key) ?? []) {
|
|
14027
|
+
for (const transition of summary.transitions) {
|
|
14028
|
+
for (const effect of transition.effects) {
|
|
14029
|
+
if (effect.type !== "invocation") {
|
|
14030
|
+
continue;
|
|
14031
|
+
}
|
|
14032
|
+
const byPosition = argTargets.get(normalizeCallee(effect.callee));
|
|
14033
|
+
if (byPosition === void 0) {
|
|
14034
|
+
continue;
|
|
14035
|
+
}
|
|
14036
|
+
const argsDeclaredAt = {};
|
|
14037
|
+
for (const [position, target] of byPosition) {
|
|
14038
|
+
argsDeclaredAt[position] = target;
|
|
14039
|
+
}
|
|
14040
|
+
if (Object.keys(argsDeclaredAt).length > 0) {
|
|
14041
|
+
effect.argsDeclaredAt = argsDeclaredAt;
|
|
14042
|
+
}
|
|
14043
|
+
}
|
|
14044
|
+
}
|
|
14045
|
+
}
|
|
14046
|
+
}
|
|
14047
|
+
}
|
|
14048
|
+
function recordCalleeParameters(parameterCallsByKey, summariesByKey) {
|
|
14049
|
+
for (const [key, parameterCalls] of parameterCallsByKey) {
|
|
14050
|
+
const byCallee = new Map(
|
|
14051
|
+
parameterCalls.map(({ callee, parameterIndex }) => [
|
|
14052
|
+
callee,
|
|
14053
|
+
parameterIndex
|
|
14054
|
+
])
|
|
14055
|
+
);
|
|
14056
|
+
for (const summary of summariesByKey.get(key) ?? []) {
|
|
14057
|
+
for (const transition of summary.transitions) {
|
|
14058
|
+
for (const effect of transition.effects) {
|
|
14059
|
+
if (effect.type !== "invocation") {
|
|
14060
|
+
continue;
|
|
14061
|
+
}
|
|
14062
|
+
const parameterIndex = byCallee.get(normalizeCallee(effect.callee));
|
|
14063
|
+
if (parameterIndex !== void 0) {
|
|
14064
|
+
effect.calleeParameter = parameterIndex;
|
|
14065
|
+
}
|
|
14066
|
+
}
|
|
14067
|
+
}
|
|
14068
|
+
}
|
|
14069
|
+
}
|
|
14070
|
+
}
|
|
14071
|
+
function recordParameterGaps(parameterCallsByKey, summariesByKey, passedPositions, options) {
|
|
14072
|
+
if (options?.gapHandling === "silent") {
|
|
14073
|
+
return;
|
|
14074
|
+
}
|
|
14075
|
+
for (const [key, parameterCalls] of parameterCallsByKey) {
|
|
14076
|
+
const unbound = parameterCalls.filter(
|
|
14077
|
+
({ parameterIndex }) => !passedPositions.has(`${key}#${parameterIndex}`)
|
|
14078
|
+
);
|
|
14079
|
+
if (unbound.length === 0) {
|
|
14080
|
+
continue;
|
|
14081
|
+
}
|
|
14082
|
+
for (const summary of summariesByKey.get(key) ?? []) {
|
|
14083
|
+
summary.gaps.push(
|
|
14084
|
+
...unbound.map(
|
|
14085
|
+
({ callee }) => unfollowedCallGap({ callee, reason: "unboundParameter" })
|
|
14086
|
+
)
|
|
14087
|
+
);
|
|
14088
|
+
}
|
|
14089
|
+
}
|
|
14090
|
+
}
|
|
14213
14091
|
|
|
14214
14092
|
// src/resolve/rethrowEnrichment.ts
|
|
14215
14093
|
import { Node as Node61 } from "ts-morph";
|
|
@@ -14945,10 +14823,10 @@ function readArrayLiteralText(node) {
|
|
|
14945
14823
|
}
|
|
14946
14824
|
|
|
14947
14825
|
// src/summaryIdentity.ts
|
|
14948
|
-
import fs6 from "fs";
|
|
14949
14826
|
import path8 from "path";
|
|
14950
14827
|
import {
|
|
14951
14828
|
disambiguateSummaryIds,
|
|
14829
|
+
linkCallsToSummaries,
|
|
14952
14830
|
summaryIdFromParts
|
|
14953
14831
|
} from "@suss/behavioral-ir";
|
|
14954
14832
|
function workspaceRootFor(anchor) {
|
|
@@ -14965,32 +14843,6 @@ function workspaceNameFor(root) {
|
|
|
14965
14843
|
const folder = path8.basename(path8.resolve(root));
|
|
14966
14844
|
return folder.length > 0 ? folder : null;
|
|
14967
14845
|
}
|
|
14968
|
-
function namedPackageDirAbove(start) {
|
|
14969
|
-
let at = path8.resolve(start);
|
|
14970
|
-
for (let up = 0; up < 12; up += 1) {
|
|
14971
|
-
if (packageNameAt(at) !== null) {
|
|
14972
|
-
return at;
|
|
14973
|
-
}
|
|
14974
|
-
const parent = path8.dirname(at);
|
|
14975
|
-
if (parent === at) {
|
|
14976
|
-
break;
|
|
14977
|
-
}
|
|
14978
|
-
at = parent;
|
|
14979
|
-
}
|
|
14980
|
-
return null;
|
|
14981
|
-
}
|
|
14982
|
-
function packageNameAt(dir) {
|
|
14983
|
-
try {
|
|
14984
|
-
const manifest = JSON.parse(
|
|
14985
|
-
fs6.readFileSync(path8.join(dir, "package.json"), "utf8")
|
|
14986
|
-
);
|
|
14987
|
-
if (typeof manifest.name === "string" && manifest.name.length > 0) {
|
|
14988
|
-
return manifest.name;
|
|
14989
|
-
}
|
|
14990
|
-
} catch {
|
|
14991
|
-
}
|
|
14992
|
-
return null;
|
|
14993
|
-
}
|
|
14994
14846
|
function nameSummaries(summaries, args) {
|
|
14995
14847
|
for (const summary of summaries) {
|
|
14996
14848
|
const file = relativeFile(summary.location.file, args.projectRoot);
|
|
@@ -15000,7 +14852,7 @@ function nameSummaries(summaries, args) {
|
|
|
15000
14852
|
summary.identity.id = idFor(args.workspace, file, summary);
|
|
15001
14853
|
}
|
|
15002
14854
|
disambiguateSummaryIds(summaries);
|
|
15003
|
-
|
|
14855
|
+
linkCallsToSummaries(summaries);
|
|
15004
14856
|
}
|
|
15005
14857
|
function relativeFile(file, projectRoot) {
|
|
15006
14858
|
if (projectRoot === void 0 || !path8.isAbsolute(file)) {
|
|
@@ -15017,185 +14869,35 @@ function idFor(workspace, file, summary) {
|
|
|
15017
14869
|
exportPath: summary.identity.exportPath
|
|
15018
14870
|
});
|
|
15019
14871
|
}
|
|
15020
|
-
function nameWhatEachCallReaches(summaries) {
|
|
15021
|
-
const byName = /* @__PURE__ */ new Map();
|
|
15022
|
-
const byFileAndName = /* @__PURE__ */ new Map();
|
|
15023
|
-
const remember = (index, key, summary) => {
|
|
15024
|
-
const found = index.get(key);
|
|
15025
|
-
if (found === void 0) {
|
|
15026
|
-
index.set(key, [summary]);
|
|
15027
|
-
return;
|
|
15028
|
-
}
|
|
15029
|
-
found.push(summary);
|
|
15030
|
-
};
|
|
15031
|
-
for (const summary of summaries) {
|
|
15032
|
-
if (summary.identity.nameKind === "label") {
|
|
15033
|
-
continue;
|
|
15034
|
-
}
|
|
15035
|
-
remember(byName, summary.identity.name, summary);
|
|
15036
|
-
remember(
|
|
15037
|
-
byFileAndName,
|
|
15038
|
-
`${summary.location.file}::${summary.identity.name}`,
|
|
15039
|
-
summary
|
|
15040
|
-
);
|
|
15041
|
-
}
|
|
15042
|
-
const onlyAnswer = (index, key) => {
|
|
15043
|
-
const found = index.get(key) ?? [];
|
|
15044
|
-
return found.length === 1 ? found[0] : null;
|
|
15045
|
-
};
|
|
15046
|
-
for (const summary of summaries) {
|
|
15047
|
-
for (const transition of summary.transitions) {
|
|
15048
|
-
for (const effect of transition.effects) {
|
|
15049
|
-
if (effect.type !== "invocation") {
|
|
15050
|
-
continue;
|
|
15051
|
-
}
|
|
15052
|
-
const called = effect.callee.split(".").pop() ?? effect.callee;
|
|
15053
|
-
const reached = onlyAnswer(byFileAndName, `${summary.location.file}::${called}`) ?? onlyAnswer(byName, called);
|
|
15054
|
-
if (reached?.identity.id !== void 0) {
|
|
15055
|
-
effect.summary = reached.identity.id;
|
|
15056
|
-
}
|
|
15057
|
-
}
|
|
15058
|
-
}
|
|
15059
|
-
}
|
|
15060
|
-
}
|
|
15061
14872
|
|
|
15062
14873
|
// src/timing.ts
|
|
15063
|
-
|
|
15064
|
-
const phases = /* @__PURE__ */ new Map();
|
|
15065
|
-
const start = performance.now();
|
|
15066
|
-
function record2(label, deltaMs) {
|
|
15067
|
-
const existing = phases.get(label);
|
|
15068
|
-
if (existing === void 0) {
|
|
15069
|
-
phases.set(label, { durationMs: deltaMs, calls: 1 });
|
|
15070
|
-
} else {
|
|
15071
|
-
existing.durationMs += deltaMs;
|
|
15072
|
-
existing.calls += 1;
|
|
15073
|
-
}
|
|
15074
|
-
}
|
|
15075
|
-
return {
|
|
15076
|
-
time(label, fn) {
|
|
15077
|
-
const t0 = performance.now();
|
|
15078
|
-
try {
|
|
15079
|
-
return fn();
|
|
15080
|
-
} finally {
|
|
15081
|
-
record2(label, performance.now() - t0);
|
|
15082
|
-
}
|
|
15083
|
-
},
|
|
15084
|
-
async timeAsync(label, fn) {
|
|
15085
|
-
const t0 = performance.now();
|
|
15086
|
-
try {
|
|
15087
|
-
return await fn();
|
|
15088
|
-
} finally {
|
|
15089
|
-
record2(label, performance.now() - t0);
|
|
15090
|
-
}
|
|
15091
|
-
},
|
|
15092
|
-
report() {
|
|
15093
|
-
const totalMs = performance.now() - start;
|
|
15094
|
-
const ordered = [...phases.entries()].map(([label, s]) => ({
|
|
15095
|
-
label,
|
|
15096
|
-
durationMs: s.durationMs,
|
|
15097
|
-
calls: s.calls
|
|
15098
|
-
})).sort((a, b) => b.durationMs - a.durationMs);
|
|
15099
|
-
return { totalMs, phases: ordered };
|
|
15100
|
-
}
|
|
15101
|
-
};
|
|
15102
|
-
}
|
|
14874
|
+
import { createTimer, noopTimer } from "@suss/extractor";
|
|
15103
14875
|
|
|
15104
14876
|
// src/version.ts
|
|
15105
|
-
import {
|
|
15106
|
-
import
|
|
15107
|
-
|
|
15108
|
-
|
|
15109
|
-
|
|
14877
|
+
import { createAdapterStamp } from "@suss/extractor";
|
|
14878
|
+
import {
|
|
14879
|
+
computeContentHash,
|
|
14880
|
+
computeDistHashFrom,
|
|
14881
|
+
projectFileStamp
|
|
14882
|
+
} from "@suss/extractor";
|
|
15110
14883
|
var ADAPTER_VERSION = "0.2.1";
|
|
15111
|
-
var
|
|
15112
|
-
|
|
15113
|
-
|
|
15114
|
-
|
|
15115
|
-
"@suss/behavioral-ir"
|
|
15116
|
-
];
|
|
15117
|
-
var SOURCE_STAMP = { kind: "source" };
|
|
15118
|
-
var cachedCodeStamp = null;
|
|
15119
|
-
function adapterCodeStamp() {
|
|
15120
|
-
if (cachedCodeStamp !== null) {
|
|
15121
|
-
return cachedCodeStamp;
|
|
15122
|
-
}
|
|
15123
|
-
cachedCodeStamp = readAdapterCodeStamp();
|
|
15124
|
-
return cachedCodeStamp;
|
|
15125
|
-
}
|
|
15126
|
-
function readAdapterCodeStamp() {
|
|
15127
|
-
try {
|
|
15128
|
-
const selfPath = fileURLToPath(import.meta.url);
|
|
15129
|
-
const hash = computeDistHashFrom(path9.dirname(selfPath));
|
|
15130
|
-
return hash.length > 0 ? { kind: "bundle", hash } : SOURCE_STAMP;
|
|
15131
|
-
} catch {
|
|
15132
|
-
return SOURCE_STAMP;
|
|
15133
|
-
}
|
|
15134
|
-
}
|
|
15135
|
-
function computeDistHashFrom(dir) {
|
|
15136
|
-
const candidates = [path9.join(dir, "index.js"), path9.join(dir, "index.cjs")];
|
|
15137
|
-
for (const candidate of candidates) {
|
|
15138
|
-
if (!fs7.existsSync(candidate)) {
|
|
15139
|
-
continue;
|
|
15140
|
-
}
|
|
15141
|
-
return computeContentHash([candidate, ...analysisBundles()]);
|
|
15142
|
-
}
|
|
15143
|
-
return "";
|
|
15144
|
-
}
|
|
15145
|
-
function computeContentHash(paths) {
|
|
15146
|
-
if (paths.length === 0) {
|
|
15147
|
-
return "";
|
|
15148
|
-
}
|
|
15149
|
-
const hash = createHash3("sha256");
|
|
15150
|
-
for (const file of paths) {
|
|
15151
|
-
try {
|
|
15152
|
-
hash.update(fs7.readFileSync(file));
|
|
15153
|
-
} catch {
|
|
15154
|
-
return "";
|
|
15155
|
-
}
|
|
15156
|
-
}
|
|
15157
|
-
return hash.digest("hex").slice(0, 16);
|
|
15158
|
-
}
|
|
15159
|
-
function projectFileStamp(paths) {
|
|
15160
|
-
if (paths.length === 0) {
|
|
15161
|
-
return "none";
|
|
15162
|
-
}
|
|
15163
|
-
const hash = createHash3("sha256");
|
|
15164
|
-
for (const file of [...paths].sort()) {
|
|
15165
|
-
hash.update(file);
|
|
15166
|
-
hash.update("\0");
|
|
15167
|
-
try {
|
|
15168
|
-
hash.update(fs7.readFileSync(file));
|
|
15169
|
-
} catch {
|
|
15170
|
-
hash.update("absent");
|
|
15171
|
-
}
|
|
15172
|
-
}
|
|
15173
|
-
return hash.digest("hex").slice(0, 16);
|
|
15174
|
-
}
|
|
15175
|
-
function analysisBundles() {
|
|
15176
|
-
const require2 = createRequire(import.meta.url);
|
|
15177
|
-
const found = [];
|
|
15178
|
-
for (const name of ANALYSIS_PACKAGES) {
|
|
15179
|
-
try {
|
|
15180
|
-
found.push(require2.resolve(name));
|
|
15181
|
-
} catch {
|
|
15182
|
-
}
|
|
15183
|
-
}
|
|
15184
|
-
return found;
|
|
15185
|
-
}
|
|
14884
|
+
var stamp = createAdapterStamp({
|
|
14885
|
+
moduleUrl: import.meta.url,
|
|
14886
|
+
version: ADAPTER_VERSION
|
|
14887
|
+
});
|
|
15186
14888
|
function computeAdapterPacksDigest(packVersions) {
|
|
15187
|
-
|
|
15188
|
-
|
|
15189
|
-
|
|
15190
|
-
return
|
|
14889
|
+
return stamp.packsDigest(packVersions);
|
|
14890
|
+
}
|
|
14891
|
+
function declineWhenRunFromSource(cacheDir) {
|
|
14892
|
+
return stamp.declineWhenRunFromSource(cacheDir);
|
|
15191
14893
|
}
|
|
15192
14894
|
|
|
15193
14895
|
// src/workspacePatterns.ts
|
|
15194
|
-
import
|
|
15195
|
-
import
|
|
14896
|
+
import fs4 from "fs";
|
|
14897
|
+
import path9 from "path";
|
|
15196
14898
|
function readJson(filePath) {
|
|
15197
14899
|
try {
|
|
15198
|
-
return JSON.parse(
|
|
14900
|
+
return JSON.parse(fs4.readFileSync(filePath, "utf8"));
|
|
15199
14901
|
} catch {
|
|
15200
14902
|
return void 0;
|
|
15201
14903
|
}
|
|
@@ -15222,7 +14924,7 @@ function pnpmWorkspaceGlobs(yamlText) {
|
|
|
15222
14924
|
return globs;
|
|
15223
14925
|
}
|
|
15224
14926
|
function workspaceGlobsAt(dir) {
|
|
15225
|
-
const pkg = readJson(
|
|
14927
|
+
const pkg = readJson(path9.join(dir, "package.json"));
|
|
15226
14928
|
if (typeof pkg === "object" && pkg !== null && "workspaces" in pkg) {
|
|
15227
14929
|
const ws = pkg.workspaces;
|
|
15228
14930
|
if (Array.isArray(ws)) {
|
|
@@ -15234,10 +14936,10 @@ function workspaceGlobsAt(dir) {
|
|
|
15234
14936
|
);
|
|
15235
14937
|
}
|
|
15236
14938
|
}
|
|
15237
|
-
const pnpmPath =
|
|
15238
|
-
if (
|
|
14939
|
+
const pnpmPath = path9.join(dir, "pnpm-workspace.yaml");
|
|
14940
|
+
if (fs4.existsSync(pnpmPath)) {
|
|
15239
14941
|
try {
|
|
15240
|
-
return pnpmWorkspaceGlobs(
|
|
14942
|
+
return pnpmWorkspaceGlobs(fs4.readFileSync(pnpmPath, "utf8"));
|
|
15241
14943
|
} catch {
|
|
15242
14944
|
return null;
|
|
15243
14945
|
}
|
|
@@ -15246,14 +14948,14 @@ function workspaceGlobsAt(dir) {
|
|
|
15246
14948
|
}
|
|
15247
14949
|
function isDirectory(candidate) {
|
|
15248
14950
|
try {
|
|
15249
|
-
return
|
|
14951
|
+
return fs4.statSync(candidate).isDirectory();
|
|
15250
14952
|
} catch {
|
|
15251
14953
|
return false;
|
|
15252
14954
|
}
|
|
15253
14955
|
}
|
|
15254
14956
|
function subdirectoriesOf(dir) {
|
|
15255
14957
|
try {
|
|
15256
|
-
return
|
|
14958
|
+
return fs4.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).filter((name) => !name.startsWith(".") && name !== "node_modules");
|
|
15257
14959
|
} catch {
|
|
15258
14960
|
return [];
|
|
15259
14961
|
}
|
|
@@ -15271,13 +14973,13 @@ function directoriesMatchingGlob(root, glob) {
|
|
|
15271
14973
|
for (const dir of current2) {
|
|
15272
14974
|
for (const entry of subdirectoriesOf(dir)) {
|
|
15273
14975
|
if (pattern.test(entry)) {
|
|
15274
|
-
next.push(
|
|
14976
|
+
next.push(path9.join(dir, entry));
|
|
15275
14977
|
}
|
|
15276
14978
|
}
|
|
15277
14979
|
}
|
|
15278
14980
|
} else {
|
|
15279
14981
|
for (const dir of current2) {
|
|
15280
|
-
next.push(
|
|
14982
|
+
next.push(path9.join(dir, segment));
|
|
15281
14983
|
}
|
|
15282
14984
|
}
|
|
15283
14985
|
current2 = next.filter(isDirectory);
|
|
@@ -15285,7 +14987,7 @@ function directoriesMatchingGlob(root, glob) {
|
|
|
15285
14987
|
return current2;
|
|
15286
14988
|
}
|
|
15287
14989
|
function packageAt(dir) {
|
|
15288
|
-
const packageJsonPath =
|
|
14990
|
+
const packageJsonPath = path9.join(dir, "package.json");
|
|
15289
14991
|
const pkg = readJson(packageJsonPath);
|
|
15290
14992
|
if (typeof pkg === "object" && pkg !== null && typeof pkg.name === "string") {
|
|
15291
14993
|
return { name: pkg.name, packageJsonPath };
|
|
@@ -15293,7 +14995,7 @@ function packageAt(dir) {
|
|
|
15293
14995
|
return null;
|
|
15294
14996
|
}
|
|
15295
14997
|
function workspacePackagesFrom(anchor) {
|
|
15296
|
-
let dir =
|
|
14998
|
+
let dir = path9.resolve(anchor);
|
|
15297
14999
|
for (; ; ) {
|
|
15298
15000
|
const globs = workspaceGlobsAt(dir);
|
|
15299
15001
|
if (globs !== null) {
|
|
@@ -15313,7 +15015,7 @@ function workspacePackagesFrom(anchor) {
|
|
|
15313
15015
|
(a, b) => a.packageJsonPath.localeCompare(b.packageJsonPath)
|
|
15314
15016
|
);
|
|
15315
15017
|
}
|
|
15316
|
-
const parent =
|
|
15018
|
+
const parent = path9.dirname(dir);
|
|
15317
15019
|
if (parent === dir) {
|
|
15318
15020
|
return [];
|
|
15319
15021
|
}
|
|
@@ -15855,11 +15557,11 @@ function extractConsumerBinding(unit, pattern, pack, resolution) {
|
|
|
15855
15557
|
return null;
|
|
15856
15558
|
}
|
|
15857
15559
|
const method = extractBindingMethod(binding, callSite, pack, resolution);
|
|
15858
|
-
const
|
|
15560
|
+
const path14 = extractBindingPath(binding, callSite, pack, resolution);
|
|
15859
15561
|
return restBinding2({
|
|
15860
15562
|
transport: pack.protocol,
|
|
15861
15563
|
method: method ?? null,
|
|
15862
|
-
path:
|
|
15564
|
+
path: path14 ?? null,
|
|
15863
15565
|
recognition: pack.name
|
|
15864
15566
|
});
|
|
15865
15567
|
}
|
|
@@ -16335,24 +16037,6 @@ function stampWrappers(raw, unit, wrappers) {
|
|
|
16335
16037
|
recordFileDependency(wrapper.file);
|
|
16336
16038
|
}
|
|
16337
16039
|
}
|
|
16338
|
-
function stampModuleImports(summaries, project) {
|
|
16339
|
-
const byFile2 = /* @__PURE__ */ new Map();
|
|
16340
|
-
for (const summary of summaries) {
|
|
16341
|
-
const file = summary.location.file;
|
|
16342
|
-
let imports = byFile2.get(file);
|
|
16343
|
-
if (imports === void 0) {
|
|
16344
|
-
imports = internalImportsOf(project, file);
|
|
16345
|
-
byFile2.set(file, imports);
|
|
16346
|
-
}
|
|
16347
|
-
if (imports.length === 0) {
|
|
16348
|
-
continue;
|
|
16349
|
-
}
|
|
16350
|
-
summary.metadata = {
|
|
16351
|
-
...summary.metadata ?? {},
|
|
16352
|
-
moduleImports: imports
|
|
16353
|
-
};
|
|
16354
|
-
}
|
|
16355
|
-
}
|
|
16356
16040
|
function emitLibraryEnvReadMarkers(summaries, project, frameworks) {
|
|
16357
16041
|
for (const pack of frameworks) {
|
|
16358
16042
|
for (const declared of pack.libraryEnvVars ?? []) {
|
|
@@ -16527,8 +16211,8 @@ function synthesizeCallerSummaries(wrapper, _project, options, resolution) {
|
|
|
16527
16211
|
if (pathArg === void 0) {
|
|
16528
16212
|
continue;
|
|
16529
16213
|
}
|
|
16530
|
-
const
|
|
16531
|
-
if (
|
|
16214
|
+
const path14 = pathFromArgument(pathArg, resolution);
|
|
16215
|
+
if (path14 === void 0) {
|
|
16532
16216
|
continue;
|
|
16533
16217
|
}
|
|
16534
16218
|
const callerFunc = enclosingFunction(callExpr);
|
|
@@ -16540,7 +16224,7 @@ function synthesizeCallerSummaries(wrapper, _project, options, resolution) {
|
|
|
16540
16224
|
continue;
|
|
16541
16225
|
}
|
|
16542
16226
|
seen.add(dedupKey);
|
|
16543
|
-
out.push(buildCallerSummary(wrapper, callerFunc, callExpr,
|
|
16227
|
+
out.push(buildCallerSummary(wrapper, callerFunc, callExpr, path14, options));
|
|
16544
16228
|
}
|
|
16545
16229
|
return out;
|
|
16546
16230
|
}
|
|
@@ -16597,7 +16281,7 @@ function callerName(func) {
|
|
|
16597
16281
|
}
|
|
16598
16282
|
return "anonymous";
|
|
16599
16283
|
}
|
|
16600
|
-
function buildCallerSummary(wrapper, callerFunc, callExpr,
|
|
16284
|
+
function buildCallerSummary(wrapper, callerFunc, callExpr, path14, options) {
|
|
16601
16285
|
const wrapperBinding = wrapper.summary.identity.boundaryBinding;
|
|
16602
16286
|
const wrapperRest = wrapperBinding?.semantics.name === "rest" ? wrapperBinding.semantics : null;
|
|
16603
16287
|
const syntheticPack = {
|
|
@@ -16629,7 +16313,7 @@ function buildCallerSummary(wrapper, callerFunc, callExpr, path15, options) {
|
|
|
16629
16313
|
raw.boundaryBinding = restBinding2({
|
|
16630
16314
|
transport: wrapperBinding?.transport ?? "http",
|
|
16631
16315
|
method: wrapperRest?.method ?? null,
|
|
16632
|
-
path:
|
|
16316
|
+
path: path14,
|
|
16633
16317
|
recognition: wrapperBinding?.recognition ?? "unknown"
|
|
16634
16318
|
});
|
|
16635
16319
|
const summary = assembleSummary3(raw, options);
|
|
@@ -16651,25 +16335,12 @@ function named(summaries, workspace, runRoot) {
|
|
|
16651
16335
|
});
|
|
16652
16336
|
return summaries;
|
|
16653
16337
|
}
|
|
16654
|
-
var saidWhyNoCache = false;
|
|
16655
16338
|
function extractionConfigStamp(config) {
|
|
16656
16339
|
return [
|
|
16657
16340
|
`includeReachable=${config.includeReachable !== false}`,
|
|
16658
16341
|
`gapHandling=${config.extractorOptions?.gapHandling ?? "default"}`
|
|
16659
16342
|
].join(",");
|
|
16660
16343
|
}
|
|
16661
|
-
function declineWhenRunFromSource(cacheDir) {
|
|
16662
|
-
if (cacheDir === null || adapterCodeStamp().kind === "bundle") {
|
|
16663
|
-
return cacheDir;
|
|
16664
|
-
}
|
|
16665
|
-
if (!saidWhyNoCache) {
|
|
16666
|
-
saidWhyNoCache = true;
|
|
16667
|
-
process.stderr.write(
|
|
16668
|
-
"[suss] extraction cache off: this process loaded the adapter from source, where nothing can tell one build of it from another. Run the built adapter to cache.\n"
|
|
16669
|
-
);
|
|
16670
|
-
}
|
|
16671
|
-
return null;
|
|
16672
|
-
}
|
|
16673
16344
|
function loadRunFiles(project, candidatePaths, timer) {
|
|
16674
16345
|
if (candidatePaths !== null) {
|
|
16675
16346
|
const deep2 = timer.time(
|
|
@@ -16700,7 +16371,7 @@ function createTypeScriptAdapter(suppliedConfig) {
|
|
|
16700
16371
|
...suppliedConfig,
|
|
16701
16372
|
frameworks: expandWorkspacePatterns(
|
|
16702
16373
|
suppliedConfig.frameworks,
|
|
16703
|
-
suppliedConfig.projectRoot ?? (suppliedConfig.tsConfigFilePath !== void 0 ?
|
|
16374
|
+
suppliedConfig.projectRoot ?? (suppliedConfig.tsConfigFilePath !== void 0 ? path10.dirname(suppliedConfig.tsConfigFilePath) : void 0)
|
|
16704
16375
|
)
|
|
16705
16376
|
};
|
|
16706
16377
|
const project = config.project ?? new Project(
|
|
@@ -16709,11 +16380,11 @@ function createTypeScriptAdapter(suppliedConfig) {
|
|
|
16709
16380
|
skipAddingFilesFromTsConfig: true
|
|
16710
16381
|
} : { skipAddingFilesFromTsConfig: true }
|
|
16711
16382
|
);
|
|
16712
|
-
const runRoot = config.projectRoot ?? (config.tsConfigFilePath !== void 0 ? workspaceRootFor(
|
|
16383
|
+
const runRoot = config.projectRoot ?? (config.tsConfigFilePath !== void 0 ? workspaceRootFor(path10.dirname(config.tsConfigFilePath)) : void 0);
|
|
16713
16384
|
let lazyBootstrapped = false;
|
|
16714
16385
|
let projectFileSet;
|
|
16715
16386
|
const cacheDir = declineWhenRunFromSource(
|
|
16716
|
-
config.cacheDir === null ? null : config.cacheDir ?? (config.tsConfigFilePath !== void 0 ?
|
|
16387
|
+
config.cacheDir === null ? null : config.cacheDir ?? (config.tsConfigFilePath !== void 0 ? path10.join(path10.dirname(config.tsConfigFilePath), ".suss", "cache") : null)
|
|
16717
16388
|
);
|
|
16718
16389
|
const cache = createCacheLayer(cacheDir);
|
|
16719
16390
|
const packsDigest = `${computeAdapterPacksDigest(
|
|
@@ -16721,12 +16392,6 @@ function createTypeScriptAdapter(suppliedConfig) {
|
|
|
16721
16392
|
(p) => p.version !== void 0 ? { name: p.name, version: p.version } : { name: p.name }
|
|
16722
16393
|
)
|
|
16723
16394
|
)}|${extractionConfigStamp(config)}|ws:${workspaceExpansionStamp(config.frameworks)}`;
|
|
16724
|
-
const digestFor = (files) => {
|
|
16725
|
-
const inputs = config.frameworks.flatMap(
|
|
16726
|
-
(pack) => pack.discoveryInputs?.(files) ?? []
|
|
16727
|
-
);
|
|
16728
|
-
return `${packsDigest}|reads:${projectFileStamp(inputs)}`;
|
|
16729
|
-
};
|
|
16730
16395
|
const packWrappers = config.frameworks.flatMap(
|
|
16731
16396
|
(pack) => pack.transparentWrappers ?? []
|
|
16732
16397
|
);
|
|
@@ -16770,20 +16435,17 @@ function createTypeScriptAdapter(suppliedConfig) {
|
|
|
16770
16435
|
config.tsConfigFilePath ?? raise("lazy bootstrap requires tsConfigFilePath")
|
|
16771
16436
|
)
|
|
16772
16437
|
) : null;
|
|
16773
|
-
|
|
16774
|
-
|
|
16775
|
-
() =>
|
|
16776
|
-
|
|
16777
|
-
|
|
16778
|
-
|
|
16779
|
-
|
|
16780
|
-
|
|
16781
|
-
|
|
16782
|
-
tsconfigPath: config.tsConfigFilePath ?? raise("lazy bootstrap requires tsConfigFilePath")
|
|
16783
|
-
} : {
|
|
16784
|
-
project,
|
|
16438
|
+
let cacheFiles = null;
|
|
16439
|
+
const adapterPacksDigest = cacheDir === null ? packsDigest : timer.time("cache.digest", () => {
|
|
16440
|
+
cacheFiles = tsconfigFileList ?? project.getSourceFiles().map((sf) => sf.getFilePath());
|
|
16441
|
+
return runDigest(packsDigest, config.frameworks, cacheFiles);
|
|
16442
|
+
});
|
|
16443
|
+
const cacheInput = {
|
|
16444
|
+
// Empty when cacheDir is null: a no-op cache layer never reads
|
|
16445
|
+
// the file list, so there is nothing worth resolving early.
|
|
16446
|
+
files: cacheFiles ?? [],
|
|
16785
16447
|
adapterPacksDigest,
|
|
16786
|
-
...config.tsConfigFilePath !== void 0 ? {
|
|
16448
|
+
...config.tsConfigFilePath !== void 0 ? { configPath: config.tsConfigFilePath } : {}
|
|
16787
16449
|
};
|
|
16788
16450
|
const lookup = await timer.timeAsync(
|
|
16789
16451
|
"cache.lookup",
|
|
@@ -16989,7 +16651,8 @@ function createTypeScriptAdapter(suppliedConfig) {
|
|
|
16989
16651
|
],
|
|
16990
16652
|
access: collectAccessRecognizers(config.frameworks, tallies),
|
|
16991
16653
|
resolveWrittenValue: (value) => resolution.resolveWrittenValue(value),
|
|
16992
|
-
resolveCallableSources: (value, alsoFrom) => resolution.resolveCallableSources(value, alsoFrom)
|
|
16654
|
+
resolveCallableSources: (value, alsoFrom) => resolution.resolveCallableSources(value, alsoFrom),
|
|
16655
|
+
sourceDeclarationsBehind: (declaration) => sourceDeclarationsBehind(declaration, resolution)
|
|
16993
16656
|
},
|
|
16994
16657
|
// Reached units the cache already serves emit nothing,
|
|
16995
16658
|
// the way a cold run's seeds do not.
|
|
@@ -17026,7 +16689,10 @@ function createTypeScriptAdapter(suppliedConfig) {
|
|
|
17026
16689
|
}
|
|
17027
16690
|
timer.time(
|
|
17028
16691
|
"stampModuleImports",
|
|
17029
|
-
() => stampModuleImports(enriched,
|
|
16692
|
+
() => stampModuleImports(enriched, (file) => {
|
|
16693
|
+
const imports = internalImportsOf(project, file);
|
|
16694
|
+
return imports.length === 0 ? void 0 : imports;
|
|
16695
|
+
})
|
|
17030
16696
|
);
|
|
17031
16697
|
timer.time(
|
|
17032
16698
|
"emitLibraryEnvReadMarkers",
|
|
@@ -17117,7 +16783,7 @@ function createTypeScriptAdapter(suppliedConfig) {
|
|
|
17117
16783
|
};
|
|
17118
16784
|
}
|
|
17119
16785
|
function mountAssumptionsAgree(record2, index) {
|
|
17120
|
-
return Object.entries(record2.mountPrefixes).every(
|
|
16786
|
+
return Object.entries(record2.meta.mountPrefixes).every(
|
|
17121
16787
|
([childId, prefix]) => (index.prefixForId?.(childId) ?? "") === prefix
|
|
17122
16788
|
);
|
|
17123
16789
|
}
|
|
@@ -17277,7 +16943,7 @@ function buildCacheAttribution(args) {
|
|
|
17277
16943
|
cacheable,
|
|
17278
16944
|
deps: [...deps].sort(),
|
|
17279
16945
|
claims: sink.claims,
|
|
17280
|
-
mountPrefixes: Object.fromEntries(sink.mountPrefixes),
|
|
16946
|
+
meta: { mountPrefixes: Object.fromEntries(sink.mountPrefixes) },
|
|
17281
16947
|
packs: packNamesByPath.get(rootPath) ?? []
|
|
17282
16948
|
});
|
|
17283
16949
|
}
|
|
@@ -17422,8 +17088,8 @@ function buildSubUnitSummary(subUnit, parent, invocationRecognizers, accessRecog
|
|
|
17422
17088
|
}
|
|
17423
17089
|
|
|
17424
17090
|
// src/bootstrap/noTsconfigProject.ts
|
|
17425
|
-
import
|
|
17426
|
-
import
|
|
17091
|
+
import fs5 from "fs";
|
|
17092
|
+
import path11 from "path";
|
|
17427
17093
|
import {
|
|
17428
17094
|
ModuleKind,
|
|
17429
17095
|
ModuleResolutionKind,
|
|
@@ -17459,7 +17125,7 @@ function findSourceFiles(rootDir, depth = 0) {
|
|
|
17459
17125
|
const found = [];
|
|
17460
17126
|
let entries;
|
|
17461
17127
|
try {
|
|
17462
|
-
entries =
|
|
17128
|
+
entries = fs5.readdirSync(rootDir, { withFileTypes: true });
|
|
17463
17129
|
} catch {
|
|
17464
17130
|
return [];
|
|
17465
17131
|
}
|
|
@@ -17467,10 +17133,10 @@ function findSourceFiles(rootDir, depth = 0) {
|
|
|
17467
17133
|
if (entry.name.startsWith(".") || SKIP_DIRECTORIES.has(entry.name)) {
|
|
17468
17134
|
continue;
|
|
17469
17135
|
}
|
|
17470
|
-
const full =
|
|
17136
|
+
const full = path11.join(rootDir, entry.name);
|
|
17471
17137
|
if (entry.isDirectory()) {
|
|
17472
17138
|
found.push(...findSourceFiles(full, depth + 1));
|
|
17473
|
-
} else if (SOURCE_EXTENSIONS.has(
|
|
17139
|
+
} else if (SOURCE_EXTENSIONS.has(path11.extname(entry.name)) && !entry.name.endsWith(".d.ts")) {
|
|
17474
17140
|
found.push(full);
|
|
17475
17141
|
}
|
|
17476
17142
|
}
|
|
@@ -17505,15 +17171,15 @@ function createProjectWithoutTsconfig(rootDir) {
|
|
|
17505
17171
|
return { project, files };
|
|
17506
17172
|
}
|
|
17507
17173
|
function findNearestTsconfig(startDir) {
|
|
17508
|
-
let dir =
|
|
17174
|
+
let dir = path11.resolve(startDir);
|
|
17509
17175
|
while (true) {
|
|
17510
17176
|
for (const name of ["tsconfig.json", "jsconfig.json"]) {
|
|
17511
|
-
const candidate =
|
|
17512
|
-
if (
|
|
17177
|
+
const candidate = path11.join(dir, name);
|
|
17178
|
+
if (fs5.existsSync(candidate)) {
|
|
17513
17179
|
return candidate;
|
|
17514
17180
|
}
|
|
17515
17181
|
}
|
|
17516
|
-
const parent =
|
|
17182
|
+
const parent = path11.dirname(dir);
|
|
17517
17183
|
if (parent === dir) {
|
|
17518
17184
|
return null;
|
|
17519
17185
|
}
|
|
@@ -17522,7 +17188,7 @@ function findNearestTsconfig(startDir) {
|
|
|
17522
17188
|
}
|
|
17523
17189
|
|
|
17524
17190
|
// src/facts/why.ts
|
|
17525
|
-
import
|
|
17191
|
+
import path12 from "path";
|
|
17526
17192
|
import { Node as Node65, Project as Project3, SyntaxKind as SyntaxKind12 } from "ts-morph";
|
|
17527
17193
|
import { explainResolutionProof, renderExplanation } from "@suss/resolution";
|
|
17528
17194
|
var JS_PHRASES = {
|
|
@@ -17530,12 +17196,12 @@ var JS_PHRASES = {
|
|
|
17530
17196
|
reason: `${describe(tuple[0])} is a .bind of ${describe(tuple[1])}, which runs the same function`
|
|
17531
17197
|
})
|
|
17532
17198
|
};
|
|
17533
|
-
var
|
|
17199
|
+
var TypeScriptWhySession = class {
|
|
17534
17200
|
project;
|
|
17535
17201
|
store;
|
|
17536
17202
|
root;
|
|
17537
17203
|
constructor(options) {
|
|
17538
|
-
this.root =
|
|
17204
|
+
this.root = path12.resolve(options.dir);
|
|
17539
17205
|
const tsconfig = findNearestTsconfig(this.root);
|
|
17540
17206
|
this.project = tsconfig === null ? createProjectWithoutTsconfig(this.root).project : new Project3({ tsConfigFilePath: tsconfig });
|
|
17541
17207
|
this.store = new ResolutionStore();
|
|
@@ -17624,7 +17290,7 @@ var WhySession = class {
|
|
|
17624
17290
|
};
|
|
17625
17291
|
}
|
|
17626
17292
|
sourceFileAt(file) {
|
|
17627
|
-
const absolute =
|
|
17293
|
+
const absolute = path12.resolve(this.root, file);
|
|
17628
17294
|
const loaded = this.project.getSourceFile(absolute);
|
|
17629
17295
|
if (loaded !== void 0) {
|
|
17630
17296
|
return loaded;
|
|
@@ -17638,7 +17304,7 @@ var WhySession = class {
|
|
|
17638
17304
|
/** A module key: a file path said relative to the root, or a package name. */
|
|
17639
17305
|
displayPath(key) {
|
|
17640
17306
|
if (key.startsWith(this.root)) {
|
|
17641
|
-
return
|
|
17307
|
+
return path12.relative(this.root, key);
|
|
17642
17308
|
}
|
|
17643
17309
|
return key;
|
|
17644
17310
|
}
|
|
@@ -17666,228 +17332,8 @@ function displayNameOf(node) {
|
|
|
17666
17332
|
return text.length > 40 ? `${text.slice(0, 40)}...` : text;
|
|
17667
17333
|
}
|
|
17668
17334
|
|
|
17669
|
-
// src/packHealth.ts
|
|
17670
|
-
function stagesOf(funnel) {
|
|
17671
|
-
const stages = [];
|
|
17672
|
-
const gateSaysSomething = funnel.gates.length > 0 && funnel.unresolvedGates.length === 0;
|
|
17673
|
-
if (funnel.recognizes && !funnel.discovers && gateSaysSomething) {
|
|
17674
|
-
stages.push({
|
|
17675
|
-
from: { count: funnel.unitsInGatedFiles, name: "unit bodies" },
|
|
17676
|
-
to: { count: funnel.effectsRecognized, name: "effects" }
|
|
17677
|
-
});
|
|
17678
|
-
}
|
|
17679
|
-
if (funnel.discovers && gateSaysSomething) {
|
|
17680
|
-
stages.push({
|
|
17681
|
-
from: { count: funnel.candidateFiles, name: "source files" },
|
|
17682
|
-
to: { count: funnel.unitsDiscovered, name: "units" }
|
|
17683
|
-
});
|
|
17684
|
-
}
|
|
17685
|
-
stages.push(
|
|
17686
|
-
{
|
|
17687
|
-
from: { count: funnel.unitsClaimed, name: "units" },
|
|
17688
|
-
to: { count: funnel.summariesBound, name: "summaries" }
|
|
17689
|
-
},
|
|
17690
|
-
{
|
|
17691
|
-
from: { count: funnel.summariesBound, name: "summaries" },
|
|
17692
|
-
to: { count: funnel.summariesWithBehavior, name: "transitions" }
|
|
17693
|
-
}
|
|
17694
|
-
);
|
|
17695
|
-
return stages;
|
|
17696
|
-
}
|
|
17697
|
-
function funnelDrops(packs) {
|
|
17698
|
-
const violations = [];
|
|
17699
|
-
for (const funnel of packs) {
|
|
17700
|
-
for (const stage of stagesOf(funnel)) {
|
|
17701
|
-
if (stage.from.count === 0 || stage.to.count > 0) {
|
|
17702
|
-
continue;
|
|
17703
|
-
}
|
|
17704
|
-
violations.push({
|
|
17705
|
-
label: funnel.pack,
|
|
17706
|
-
detail: `${stage.from.count} ${stage.from.name} -> 0 ${stage.to.name}`
|
|
17707
|
-
});
|
|
17708
|
-
}
|
|
17709
|
-
}
|
|
17710
|
-
return violations;
|
|
17711
|
-
}
|
|
17712
|
-
function recognizersWithNoUnits(packs) {
|
|
17713
|
-
return packs.filter(
|
|
17714
|
-
(funnel) => funnel.recognizes && !funnel.discovers && funnel.gates.length > 0 && funnel.unresolvedGates.length === 0 && funnel.candidateFiles > 0 && funnel.unitsInGatedFiles === 0 && // The closure walks a recognizer-only pack's gated exports as
|
|
17715
|
-
// roots, so effects recognized there mean the run worked and
|
|
17716
|
-
// the missing framework pack costs attribution, not existence.
|
|
17717
|
-
funnel.effectsRecognized === 0
|
|
17718
|
-
).map((funnel) => ({
|
|
17719
|
-
label: funnel.pack,
|
|
17720
|
-
detail: `${funnel.candidateFiles} gated files, and no pack in this run discovered a unit in them. ${funnel.pack} reads calls inside units another pack finds, so add the pack that finds this project's handlers (-f express, -f fastify, ...), or run suss init to work out which.`
|
|
17721
|
-
}));
|
|
17722
|
-
}
|
|
17723
|
-
function helpersThatMatchedNothing(packs) {
|
|
17724
|
-
return packs.flatMap(
|
|
17725
|
-
(funnel) => funnel.helpersUnmatched.map((helper) => ({
|
|
17726
|
-
label: funnel.pack,
|
|
17727
|
-
detail: `${helper} matched no call in this run, so whatever it registers is missing. suss read that helper out of the project and then failed to match a call to it, which is a bug in suss rather than in your code.`
|
|
17728
|
-
}))
|
|
17729
|
-
);
|
|
17730
|
-
}
|
|
17731
|
-
function unversionedPacks(packs) {
|
|
17732
|
-
return packs.filter((funnel) => funnel.version === null).map((funnel) => ({
|
|
17733
|
-
label: funnel.pack,
|
|
17734
|
-
detail: "no version declared"
|
|
17735
|
-
}));
|
|
17736
|
-
}
|
|
17737
|
-
function selfCollisions(packs) {
|
|
17738
|
-
return packs.filter((funnel) => funnel.selfCollisions > 0).map((funnel) => ({
|
|
17739
|
-
label: funnel.pack,
|
|
17740
|
-
detail: `${funnel.selfCollisions} ${funnel.selfCollisions === 1 ? "unit" : "units"} matched twice, second dropped`
|
|
17741
|
-
}));
|
|
17742
|
-
}
|
|
17743
|
-
function threwWhileReading(packs) {
|
|
17744
|
-
return packs.filter((funnel) => funnel.failures.length > 0).map((funnel) => {
|
|
17745
|
-
const first = funnel.failures[0];
|
|
17746
|
-
const rest = funnel.failures.length - 1;
|
|
17747
|
-
const alsoIn = rest > 0 ? ` (+${rest} more)` : "";
|
|
17748
|
-
return {
|
|
17749
|
-
label: funnel.pack,
|
|
17750
|
-
detail: `${first.hook} on ${first.file}${alsoIn}: ${first.message}`
|
|
17751
|
-
};
|
|
17752
|
-
});
|
|
17753
|
-
}
|
|
17754
|
-
function packGradients(report) {
|
|
17755
|
-
const gradients = [];
|
|
17756
|
-
for (const funnel of report.packs) {
|
|
17757
|
-
if (funnel.declarations === null) {
|
|
17758
|
-
continue;
|
|
17759
|
-
}
|
|
17760
|
-
gradients.push(gradientOf(funnel.pack, funnel.declarations.declarations));
|
|
17761
|
-
}
|
|
17762
|
-
return gradients;
|
|
17763
|
-
}
|
|
17764
|
-
function gradientOf(pack, declarations) {
|
|
17765
|
-
const gradient = {
|
|
17766
|
-
pack,
|
|
17767
|
-
dataLinks: 0,
|
|
17768
|
-
functionLinks: [],
|
|
17769
|
-
astLinks: [],
|
|
17770
|
-
withoutExample: []
|
|
17771
|
-
};
|
|
17772
|
-
for (const declaration of declarations) {
|
|
17773
|
-
gradient.dataLinks += declaration.dataLinks;
|
|
17774
|
-
for (const question of declaration.functionLinks) {
|
|
17775
|
-
gradient.functionLinks.push(`${declaration.name}.${question}`);
|
|
17776
|
-
}
|
|
17777
|
-
for (const question of declaration.astLinks) {
|
|
17778
|
-
gradient.astLinks.push(`${declaration.name}.${question}`);
|
|
17779
|
-
}
|
|
17780
|
-
if (declaration.example === null) {
|
|
17781
|
-
gradient.withoutExample.push(declaration.name);
|
|
17782
|
-
}
|
|
17783
|
-
}
|
|
17784
|
-
return gradient;
|
|
17785
|
-
}
|
|
17786
|
-
function opaqueLinks(gradients) {
|
|
17787
|
-
return gradients.filter((gradient) => gradient.functionLinks.length > 0).map((gradient) => ({
|
|
17788
|
-
label: gradient.pack,
|
|
17789
|
-
detail: `${gradient.functionLinks.join(", ")} (${gradient.dataLinks} data)`
|
|
17790
|
-
}));
|
|
17791
|
-
}
|
|
17792
|
-
function reachesTheSyntaxTree(gradients) {
|
|
17793
|
-
return gradients.filter((gradient) => gradient.astLinks.length > 0).map((gradient) => ({
|
|
17794
|
-
label: gradient.pack,
|
|
17795
|
-
detail: gradient.astLinks.join(", ")
|
|
17796
|
-
}));
|
|
17797
|
-
}
|
|
17798
|
-
function undocumentedDeclarations(gradients) {
|
|
17799
|
-
return gradients.filter((gradient) => gradient.withoutExample.length > 0).map((gradient) => ({
|
|
17800
|
-
label: gradient.pack,
|
|
17801
|
-
detail: gradient.withoutExample.join(", ")
|
|
17802
|
-
}));
|
|
17803
|
-
}
|
|
17804
|
-
function evaluatePackHealth(report) {
|
|
17805
|
-
const gradients = packGradients(report);
|
|
17806
|
-
return [
|
|
17807
|
-
{
|
|
17808
|
-
name: "no pack throws while it reads",
|
|
17809
|
-
code: "threw",
|
|
17810
|
-
audience: "run",
|
|
17811
|
-
violations: threwWhileReading(report.packs)
|
|
17812
|
-
},
|
|
17813
|
-
{
|
|
17814
|
-
name: "no pack finds something and records nothing",
|
|
17815
|
-
code: "no-output",
|
|
17816
|
-
audience: "run",
|
|
17817
|
-
violations: funnelDrops(report.packs)
|
|
17818
|
-
},
|
|
17819
|
-
{
|
|
17820
|
-
name: "no pack collides with itself",
|
|
17821
|
-
code: "double-match",
|
|
17822
|
-
audience: "run",
|
|
17823
|
-
violations: selfCollisions(report.packs)
|
|
17824
|
-
},
|
|
17825
|
-
{
|
|
17826
|
-
name: "every recognizer had units to look inside",
|
|
17827
|
-
code: "no-units",
|
|
17828
|
-
audience: "run",
|
|
17829
|
-
violations: recognizersWithNoUnits(report.packs)
|
|
17830
|
-
},
|
|
17831
|
-
{
|
|
17832
|
-
name: "every registration helper the run read matched a call",
|
|
17833
|
-
code: "no-helper",
|
|
17834
|
-
audience: "run",
|
|
17835
|
-
violations: helpersThatMatchedNothing(report.packs)
|
|
17836
|
-
},
|
|
17837
|
-
{
|
|
17838
|
-
name: "every pack declares a version",
|
|
17839
|
-
code: "no-version",
|
|
17840
|
-
audience: "pack",
|
|
17841
|
-
violations: unversionedPacks(report.packs)
|
|
17842
|
-
},
|
|
17843
|
-
{
|
|
17844
|
-
name: "every link a declared pack states is data",
|
|
17845
|
-
code: "fn-link",
|
|
17846
|
-
audience: "pack",
|
|
17847
|
-
violations: opaqueLinks(gradients)
|
|
17848
|
-
},
|
|
17849
|
-
{
|
|
17850
|
-
name: "no declared pack reads the syntax tree",
|
|
17851
|
-
code: "ast-link",
|
|
17852
|
-
audience: "pack",
|
|
17853
|
-
violations: reachesTheSyntaxTree(gradients)
|
|
17854
|
-
},
|
|
17855
|
-
{
|
|
17856
|
-
name: "every declaration states an example",
|
|
17857
|
-
code: "no-example",
|
|
17858
|
-
audience: "pack",
|
|
17859
|
-
violations: undocumentedDeclarations(gradients)
|
|
17860
|
-
}
|
|
17861
|
-
];
|
|
17862
|
-
}
|
|
17863
|
-
function formatPackHealth(checks, audiences) {
|
|
17864
|
-
const fired = checks.filter(
|
|
17865
|
-
(check) => check.violations.length > 0 && audiences.includes(check.audience)
|
|
17866
|
-
);
|
|
17867
|
-
if (fired.length === 0) {
|
|
17868
|
-
return "";
|
|
17869
|
-
}
|
|
17870
|
-
const rows = fired.flatMap(
|
|
17871
|
-
(check) => check.violations.map((violation) => ({
|
|
17872
|
-
code: check.code,
|
|
17873
|
-
pack: violation.label,
|
|
17874
|
-
detail: violation.detail
|
|
17875
|
-
}))
|
|
17876
|
-
);
|
|
17877
|
-
const codeWidth = Math.max(...rows.map((row) => row.code.length));
|
|
17878
|
-
const packWidth = Math.max(...rows.map((row) => row.pack.length));
|
|
17879
|
-
const lines = ["", `Pack health (${rows.length}):`];
|
|
17880
|
-
for (const row of rows) {
|
|
17881
|
-
lines.push(
|
|
17882
|
-
` ${row.code.padEnd(codeWidth)} ${row.pack.padEnd(packWidth)} ${row.detail}`
|
|
17883
|
-
);
|
|
17884
|
-
}
|
|
17885
|
-
return `${lines.join("\n")}
|
|
17886
|
-
`;
|
|
17887
|
-
}
|
|
17888
|
-
|
|
17889
17335
|
// src/stubEvidence.ts
|
|
17890
|
-
import
|
|
17336
|
+
import path13 from "path";
|
|
17891
17337
|
import { Project as Project4 } from "ts-morph";
|
|
17892
17338
|
function stubEvidenceIn(project, packageName, root) {
|
|
17893
17339
|
const resolution = new ResolutionStore();
|
|
@@ -17903,7 +17349,7 @@ function stubEvidenceIn(project, packageName, root) {
|
|
|
17903
17349
|
calls: []
|
|
17904
17350
|
};
|
|
17905
17351
|
entry.calls.push({
|
|
17906
|
-
file:
|
|
17352
|
+
file: path13.relative(root, sourceFile.getFilePath()).split(path13.sep).join("/"),
|
|
17907
17353
|
line: one.call.getStartLineNumber(),
|
|
17908
17354
|
args: one.call.getArguments().map((arg) => effectArgOf(arg))
|
|
17909
17355
|
});
|
|
@@ -17918,7 +17364,7 @@ function stubEvidence(options) {
|
|
|
17918
17364
|
const project = new Project4(
|
|
17919
17365
|
options.tsConfigFilePath !== void 0 ? { tsConfigFilePath: options.tsConfigFilePath } : { compilerOptions: { allowJs: true } }
|
|
17920
17366
|
);
|
|
17921
|
-
const root = options.tsConfigFilePath !== void 0 ?
|
|
17367
|
+
const root = options.tsConfigFilePath !== void 0 ? path13.dirname(options.tsConfigFilePath) : path13.resolve(options.directory ?? process.cwd());
|
|
17922
17368
|
if (options.tsConfigFilePath === void 0) {
|
|
17923
17369
|
project.addSourceFilesAtPaths([
|
|
17924
17370
|
`${root}/**/*.{ts,tsx,js,jsx}`,
|
|
@@ -17930,7 +17376,7 @@ function stubEvidence(options) {
|
|
|
17930
17376
|
export {
|
|
17931
17377
|
ADAPTER_VERSION,
|
|
17932
17378
|
ResolutionStore,
|
|
17933
|
-
|
|
17379
|
+
TypeScriptWhySession,
|
|
17934
17380
|
accessContextFor,
|
|
17935
17381
|
buildProjectHelperIndex,
|
|
17936
17382
|
callOpsFor,
|
|
@@ -17943,13 +17389,11 @@ export {
|
|
|
17943
17389
|
createTsSubUnitContext,
|
|
17944
17390
|
createTypeScriptAdapter,
|
|
17945
17391
|
discoverUnits,
|
|
17946
|
-
evaluatePackHealth,
|
|
17947
17392
|
exportedDeclarationsOf,
|
|
17948
17393
|
extractCodeStructure,
|
|
17949
17394
|
extractRawBranches,
|
|
17950
17395
|
findNearestTsconfig,
|
|
17951
17396
|
findTerminals,
|
|
17952
|
-
formatPackHealth,
|
|
17953
17397
|
functionTargetOf,
|
|
17954
17398
|
importDeclarationsOf,
|
|
17955
17399
|
importedNamesOf,
|