@suss/adapter-typescript 0.31.1 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +145 -7
- package/dist/index.d.cts +46 -2
- package/dist/index.d.ts +46 -2
- package/dist/index.js +145 -7
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -1498,13 +1498,14 @@ function isWriteTarget(name) {
|
|
|
1498
1498
|
function fact(db, relation, ...tuple) {
|
|
1499
1499
|
db.add(relation, tuple);
|
|
1500
1500
|
}
|
|
1501
|
-
function createNodeTable() {
|
|
1501
|
+
function createNodeTable(environmentObjects = []) {
|
|
1502
1502
|
return {
|
|
1503
1503
|
byId: /* @__PURE__ */ new Map(),
|
|
1504
1504
|
seenFunctions: /* @__PURE__ */ new Set(),
|
|
1505
1505
|
seenBindings: /* @__PURE__ */ new Set(),
|
|
1506
1506
|
seenValues: /* @__PURE__ */ new Set(),
|
|
1507
|
-
seenClasses: /* @__PURE__ */ new Set()
|
|
1507
|
+
seenClasses: /* @__PURE__ */ new Set(),
|
|
1508
|
+
environmentObjects
|
|
1508
1509
|
};
|
|
1509
1510
|
}
|
|
1510
1511
|
function nodeId(node) {
|
|
@@ -1649,6 +1650,40 @@ function literalIndexOf(index) {
|
|
|
1649
1650
|
}
|
|
1650
1651
|
return null;
|
|
1651
1652
|
}
|
|
1653
|
+
function readsEnvironment(table, access) {
|
|
1654
|
+
if (table.environmentObjects.length === 0) {
|
|
1655
|
+
return false;
|
|
1656
|
+
}
|
|
1657
|
+
const path14 = dottedPathOf(access.getExpression());
|
|
1658
|
+
return path14 !== null && table.environmentObjects.includes(path14);
|
|
1659
|
+
}
|
|
1660
|
+
function isEnvironmentNameRead(table, node) {
|
|
1661
|
+
if (!import_ts_morph6.Node.isElementAccessExpression(node)) {
|
|
1662
|
+
return false;
|
|
1663
|
+
}
|
|
1664
|
+
const argument = node.getArgumentExpression();
|
|
1665
|
+
return argument !== void 0 && literalIndexOf(argument) === null && readsEnvironment(table, node);
|
|
1666
|
+
}
|
|
1667
|
+
function environmentNameReadsIn(table, sourceFile) {
|
|
1668
|
+
if (table.environmentObjects.length === 0) {
|
|
1669
|
+
return [];
|
|
1670
|
+
}
|
|
1671
|
+
const text = sourceFile.getFullText();
|
|
1672
|
+
if (!table.environmentObjects.some((path14) => text.includes(path14))) {
|
|
1673
|
+
return [];
|
|
1674
|
+
}
|
|
1675
|
+
return sourceFile.getDescendantsOfKind(import_ts_morph6.SyntaxKind.ElementAccessExpression).filter((access) => isEnvironmentNameRead(table, access));
|
|
1676
|
+
}
|
|
1677
|
+
function dottedPathOf(expression) {
|
|
1678
|
+
if (import_ts_morph6.Node.isIdentifier(expression)) {
|
|
1679
|
+
return expression.getText();
|
|
1680
|
+
}
|
|
1681
|
+
if (!import_ts_morph6.Node.isPropertyAccessExpression(expression)) {
|
|
1682
|
+
return null;
|
|
1683
|
+
}
|
|
1684
|
+
const object = dottedPathOf(expression.getExpression());
|
|
1685
|
+
return object === null ? null : `${object}.${expression.getName()}`;
|
|
1686
|
+
}
|
|
1652
1687
|
function asFallbackExpression(expression) {
|
|
1653
1688
|
if (!import_ts_morph6.Node.isBinaryExpression(expression)) {
|
|
1654
1689
|
return null;
|
|
@@ -1720,6 +1755,10 @@ function emitValue(db, table, value) {
|
|
|
1720
1755
|
);
|
|
1721
1756
|
return id;
|
|
1722
1757
|
}
|
|
1758
|
+
const argument = expression.getArgumentExpression();
|
|
1759
|
+
if (argument !== void 0 && readsEnvironment(table, expression)) {
|
|
1760
|
+
fact(db, "readsEnvNamed", id, emitValue(db, table, argument));
|
|
1761
|
+
}
|
|
1723
1762
|
fact(db, "writtenValue", id);
|
|
1724
1763
|
return id;
|
|
1725
1764
|
}
|
|
@@ -2184,6 +2223,9 @@ function recordBodyCalls(db, table, fnId, node) {
|
|
|
2184
2223
|
if (!import_ts_morph6.Node.isExpression(node)) {
|
|
2185
2224
|
return false;
|
|
2186
2225
|
}
|
|
2226
|
+
if (isEnvironmentNameRead(table, node)) {
|
|
2227
|
+
emitValue(db, table, node);
|
|
2228
|
+
}
|
|
2187
2229
|
const call = unwrapExpression(node);
|
|
2188
2230
|
if (import_ts_morph6.Node.isCallExpression(call)) {
|
|
2189
2231
|
const callee = unwrapExpression(call.getExpression());
|
|
@@ -2409,9 +2451,10 @@ var QUERY_FACTS = (0, import_resolution2.queryFacts)(RESOLUTION_PROGRAM);
|
|
|
2409
2451
|
var MODULE_DEMANDS = RESOLUTION_PROGRAM.demands.filter(
|
|
2410
2452
|
(one) => (one.relation === "moduleExport" || one.relation === "moduleForwards") && one.bound[0] === true
|
|
2411
2453
|
).map((one) => one.demand);
|
|
2454
|
+
var NO_NAMERS = { sitesNaming: () => [] };
|
|
2412
2455
|
var ResolutionStore = class {
|
|
2413
2456
|
db = new import_datalog2.Database();
|
|
2414
|
-
table
|
|
2457
|
+
table;
|
|
2415
2458
|
fullyExtracted = /* @__PURE__ */ new Set();
|
|
2416
2459
|
seededValues = /* @__PURE__ */ new Set();
|
|
2417
2460
|
importedNames = /* @__PURE__ */ new Map();
|
|
@@ -2429,13 +2472,18 @@ var ResolutionStore = class {
|
|
|
2429
2472
|
constructionSites = /* @__PURE__ */ new Map();
|
|
2430
2473
|
/** Files the most recent query read, for the memo to keep. */
|
|
2431
2474
|
lastQueryWalked = [];
|
|
2475
|
+
/** See `environmentSiteFiles`; null until the first env question. */
|
|
2476
|
+
envSiteFiles = null;
|
|
2477
|
+
envNamersAnswer = NO_NAMERS;
|
|
2478
|
+
envNamersExtractedAt = -1;
|
|
2432
2479
|
declarations = /* @__PURE__ */ new Map();
|
|
2433
2480
|
graph = new ModuleGraph();
|
|
2434
2481
|
/** See `notePossibleCallers`. */
|
|
2435
2482
|
possibleCallers = /* @__PURE__ */ new Set();
|
|
2436
2483
|
callerFilesRead = /* @__PURE__ */ new Set();
|
|
2437
2484
|
stale = true;
|
|
2438
|
-
constructor(wrappers = []) {
|
|
2485
|
+
constructor(wrappers = [], environmentObjects = []) {
|
|
2486
|
+
this.table = createNodeTable(environmentObjects);
|
|
2439
2487
|
(0, import_resolution2.addPackWords)(this.db, { unwrapsByName: wrappers });
|
|
2440
2488
|
}
|
|
2441
2489
|
/**
|
|
@@ -2648,6 +2696,89 @@ var ResolutionStore = class {
|
|
|
2648
2696
|
}
|
|
2649
2697
|
return found;
|
|
2650
2698
|
}
|
|
2699
|
+
/**
|
|
2700
|
+
* Which parameters an environment read takes its variable's name
|
|
2701
|
+
* from, for a reader standing at a call. One question covers the
|
|
2702
|
+
* whole project: a project has a handful of environment reads and
|
|
2703
|
+
* thousands of parameters, and with the read bound the rules run from
|
|
2704
|
+
* each callee to its callers.
|
|
2705
|
+
*
|
|
2706
|
+
* `definedIn` is the callee's own file, read into the store before
|
|
2707
|
+
* the question so a helper nothing had extracted yet is among the
|
|
2708
|
+
* facts the rules run over.
|
|
2709
|
+
*/
|
|
2710
|
+
envNamers(definedIn) {
|
|
2711
|
+
const siteFiles = this.environmentSiteFiles(definedIn.getProject());
|
|
2712
|
+
if (siteFiles.length === 0) {
|
|
2713
|
+
return NO_NAMERS;
|
|
2714
|
+
}
|
|
2715
|
+
this.extractFile(definedIn);
|
|
2716
|
+
if (this.envNamersExtractedAt === this.fullyExtracted.size) {
|
|
2717
|
+
return this.envNamersAnswer;
|
|
2718
|
+
}
|
|
2719
|
+
const answered = this.askEnvNamers([...siteFiles, definedIn]);
|
|
2720
|
+
const siteFilePaths = new Set(siteFiles.map((one) => one.getFilePath()));
|
|
2721
|
+
this.envNamersAnswer = {
|
|
2722
|
+
sitesNaming: (parameter) => this.sitesNamedBy(answered, siteFilePaths, parameter)
|
|
2723
|
+
};
|
|
2724
|
+
this.envNamersExtractedAt = this.fullyExtracted.size;
|
|
2725
|
+
return this.envNamersAnswer;
|
|
2726
|
+
}
|
|
2727
|
+
sitesNamedBy(answered, siteFilePaths, parameter) {
|
|
2728
|
+
const key = nodeId(parameter);
|
|
2729
|
+
const sites = answered.get(key);
|
|
2730
|
+
if (sites !== void 0) {
|
|
2731
|
+
return sites;
|
|
2732
|
+
}
|
|
2733
|
+
if (!siteFilePaths.has(parameter.getSourceFile().getFilePath())) {
|
|
2734
|
+
return [];
|
|
2735
|
+
}
|
|
2736
|
+
return this.db.lookup("paramOf", 2, key).length > 0 ? [] : null;
|
|
2737
|
+
}
|
|
2738
|
+
/**
|
|
2739
|
+
* Seed every read the store knows of, derive, and take the sites back
|
|
2740
|
+
* per parameter. The question is dropped afterwards, so a later ask
|
|
2741
|
+
* over a larger fact set derives it again.
|
|
2742
|
+
*/
|
|
2743
|
+
askEnvNamers(seeds) {
|
|
2744
|
+
const byParameter = /* @__PURE__ */ new Map();
|
|
2745
|
+
try {
|
|
2746
|
+
for (const [site] of this.db.facts("readsEnvNamed")) {
|
|
2747
|
+
this.wantKey("wantedEnvSite", String(site));
|
|
2748
|
+
}
|
|
2749
|
+
this.extractDemanded(seeds);
|
|
2750
|
+
this.derive();
|
|
2751
|
+
for (const [parameter, site] of this.db.facts("wantedParamNamesEnv")) {
|
|
2752
|
+
const node = this.table.byId.get(String(site));
|
|
2753
|
+
if (node === void 0) {
|
|
2754
|
+
continue;
|
|
2755
|
+
}
|
|
2756
|
+
const sites = byParameter.get(String(parameter)) ?? [];
|
|
2757
|
+
sites.push(node);
|
|
2758
|
+
byParameter.set(String(parameter), sites);
|
|
2759
|
+
}
|
|
2760
|
+
} finally {
|
|
2761
|
+
this.forgetQuery();
|
|
2762
|
+
}
|
|
2763
|
+
return byParameter;
|
|
2764
|
+
}
|
|
2765
|
+
/**
|
|
2766
|
+
* The project's files that spell an environment read with a computed
|
|
2767
|
+
* index, read into the store. Which files those are cannot depend on
|
|
2768
|
+
* what a reader happened to ask about first, so the scan is over the
|
|
2769
|
+
* project's own sources and it happens once.
|
|
2770
|
+
*/
|
|
2771
|
+
environmentSiteFiles(project) {
|
|
2772
|
+
if (this.envSiteFiles !== null) {
|
|
2773
|
+
return this.envSiteFiles;
|
|
2774
|
+
}
|
|
2775
|
+
const found = project.getSourceFiles().filter(
|
|
2776
|
+
(one) => !one.isInNodeModules() && environmentNameReadsIn(this.table, one).length > 0
|
|
2777
|
+
);
|
|
2778
|
+
this.envSiteFiles = found;
|
|
2779
|
+
this.extractFiles(found);
|
|
2780
|
+
return found;
|
|
2781
|
+
}
|
|
2651
2782
|
/**
|
|
2652
2783
|
* Whether running this function hands back that call: returned
|
|
2653
2784
|
* outright, written into a name and returned, or a shorthand body.
|
|
@@ -3058,7 +3189,11 @@ var ResolutionStore = class {
|
|
|
3058
3189
|
this.stale = false;
|
|
3059
3190
|
}
|
|
3060
3191
|
wantValue(question, value) {
|
|
3061
|
-
|
|
3192
|
+
this.wantKey(question, nodeId(value));
|
|
3193
|
+
}
|
|
3194
|
+
/** For a question seeded with a fact key the store read out of the database. */
|
|
3195
|
+
wantKey(question, key) {
|
|
3196
|
+
if (this.db.add(question, [key]) === "added") {
|
|
3062
3197
|
this.stale = true;
|
|
3063
3198
|
}
|
|
3064
3199
|
}
|
|
@@ -17623,11 +17758,14 @@ function createTypeScriptAdapter(suppliedConfig) {
|
|
|
17623
17758
|
const packWrappers = config.frameworks.flatMap(
|
|
17624
17759
|
(pack) => pack.transparentWrappers ?? []
|
|
17625
17760
|
);
|
|
17761
|
+
const packEnvironments = config.frameworks.flatMap(
|
|
17762
|
+
(pack) => pack.environmentObjects ?? []
|
|
17763
|
+
);
|
|
17626
17764
|
return {
|
|
17627
17765
|
tsProject: project,
|
|
17628
17766
|
async extractFromFiles(filePaths) {
|
|
17629
17767
|
const summaries = [];
|
|
17630
|
-
const resolution = new ResolutionStore(packWrappers);
|
|
17768
|
+
const resolution = new ResolutionStore(packWrappers, packEnvironments);
|
|
17631
17769
|
const claimedUnits = /* @__PURE__ */ new Map();
|
|
17632
17770
|
for (const fp of filePaths) {
|
|
17633
17771
|
let sourceFile = project.getSourceFile(fp);
|
|
@@ -17730,7 +17868,7 @@ function createTypeScriptAdapter(suppliedConfig) {
|
|
|
17730
17868
|
timer
|
|
17731
17869
|
);
|
|
17732
17870
|
timer.time("warmExportChains", () => warmExportChains(deep.deepRoots));
|
|
17733
|
-
const resolution = new ResolutionStore(packWrappers);
|
|
17871
|
+
const resolution = new ResolutionStore(packWrappers, packEnvironments);
|
|
17734
17872
|
const packsByFile = timer.time(
|
|
17735
17873
|
"preFilter",
|
|
17736
17874
|
() => computePackApplicability(sourceFiles, config.frameworks, resolution)
|
package/dist/index.d.cts
CHANGED
|
@@ -46,6 +46,18 @@ interface PassedArgument {
|
|
|
46
46
|
call: Node;
|
|
47
47
|
argument: Node;
|
|
48
48
|
}
|
|
49
|
+
/** See `ResolutionStore.envNamers`. */
|
|
50
|
+
interface EnvironmentNamers {
|
|
51
|
+
/**
|
|
52
|
+
* The environment reads that take their variable's name from this
|
|
53
|
+
* parameter, however many helpers forward it along the way. Empty for
|
|
54
|
+
* a parameter no read ever takes a name from, and null where the
|
|
55
|
+
* rules had nothing to go on: a file that exports nothing states no
|
|
56
|
+
* facts, so their silence about its parameters means neither yes nor
|
|
57
|
+
* no, and the asker settles what it can by reading the syntax.
|
|
58
|
+
*/
|
|
59
|
+
sitesNaming(parameter: Node): readonly Node[] | null;
|
|
60
|
+
}
|
|
49
61
|
declare class ResolutionStore {
|
|
50
62
|
private readonly db;
|
|
51
63
|
private readonly table;
|
|
@@ -66,13 +78,17 @@ declare class ResolutionStore {
|
|
|
66
78
|
private readonly constructionSites;
|
|
67
79
|
/** Files the most recent query read, for the memo to keep. */
|
|
68
80
|
private lastQueryWalked;
|
|
81
|
+
/** See `environmentSiteFiles`; null until the first env question. */
|
|
82
|
+
private envSiteFiles;
|
|
83
|
+
private envNamersAnswer;
|
|
84
|
+
private envNamersExtractedAt;
|
|
69
85
|
private readonly declarations;
|
|
70
86
|
private readonly graph;
|
|
71
87
|
/** See `notePossibleCallers`. */
|
|
72
88
|
private readonly possibleCallers;
|
|
73
89
|
private readonly callerFilesRead;
|
|
74
90
|
private stale;
|
|
75
|
-
constructor(wrappers?: TransparentWrapper[]);
|
|
91
|
+
constructor(wrappers?: TransparentWrapper[], environmentObjects?: readonly string[]);
|
|
76
92
|
/**
|
|
77
93
|
* `alsoFrom` is a second file to walk out from, for a caller that
|
|
78
94
|
* knows where the value it is asking about was set up. The walk
|
|
@@ -144,6 +160,32 @@ declare class ResolutionStore {
|
|
|
144
160
|
* parameter's own function with no join against `bodyCalls` needed.
|
|
145
161
|
*/
|
|
146
162
|
callsPassing(parameter: Node): PassedArgument[];
|
|
163
|
+
/**
|
|
164
|
+
* Which parameters an environment read takes its variable's name
|
|
165
|
+
* from, for a reader standing at a call. One question covers the
|
|
166
|
+
* whole project: a project has a handful of environment reads and
|
|
167
|
+
* thousands of parameters, and with the read bound the rules run from
|
|
168
|
+
* each callee to its callers.
|
|
169
|
+
*
|
|
170
|
+
* `definedIn` is the callee's own file, read into the store before
|
|
171
|
+
* the question so a helper nothing had extracted yet is among the
|
|
172
|
+
* facts the rules run over.
|
|
173
|
+
*/
|
|
174
|
+
envNamers(definedIn: SourceFile): EnvironmentNamers;
|
|
175
|
+
private sitesNamedBy;
|
|
176
|
+
/**
|
|
177
|
+
* Seed every read the store knows of, derive, and take the sites back
|
|
178
|
+
* per parameter. The question is dropped afterwards, so a later ask
|
|
179
|
+
* over a larger fact set derives it again.
|
|
180
|
+
*/
|
|
181
|
+
private askEnvNamers;
|
|
182
|
+
/**
|
|
183
|
+
* The project's files that spell an environment read with a computed
|
|
184
|
+
* index, read into the store. Which files those are cannot depend on
|
|
185
|
+
* what a reader happened to ask about first, so the scan is over the
|
|
186
|
+
* project's own sources and it happens once.
|
|
187
|
+
*/
|
|
188
|
+
private environmentSiteFiles;
|
|
147
189
|
/**
|
|
148
190
|
* Whether running this function hands back that call: returned
|
|
149
191
|
* outright, written into a name and returned, or a shorthand body.
|
|
@@ -247,6 +289,8 @@ declare class ResolutionStore {
|
|
|
247
289
|
*/
|
|
248
290
|
private forgetQuery;
|
|
249
291
|
private wantValue;
|
|
292
|
+
/** For a question seeded with a fact key the store read out of the database. */
|
|
293
|
+
private wantKey;
|
|
250
294
|
private wantExportsOf;
|
|
251
295
|
/**
|
|
252
296
|
* Discovery walks the table in order, and the rounds derive it in
|
|
@@ -1579,4 +1623,4 @@ declare function climbSyntax(node: Node): Node;
|
|
|
1579
1623
|
*/
|
|
1580
1624
|
declare function peelValue(node: Node): Node;
|
|
1581
1625
|
|
|
1582
|
-
export { ADAPTER_VERSION, type Accessed, type CallAccountingEntry, type CallAccountingOutcome, type ClientCallSite, type ConfiguredCallContext, type ConfiguredCallRead, type ConfiguredCallSpec, type ContractReadResult, type DescentBarriers, type DiscoveredUnit, type ExplainCallableOptions, type ExplainedResolution, type FoundTerminal, type FunctionRoot, GENERIC_TERMINALS, type ImportScanOptions, NO_BARRIERS, type ObservedStubCall, type RawBranchResult, type ReadNameOptions, ResolutionStore, type StubCallEvidence, type StubEvidenceOptions, TSCONFIG_NAMES, type TsDiscoveryContext, type TsInvocationRecognizerContext, type TsJsxAttributeLocation, type TsSubUnitContext, type TypeScriptAdapter, type TypeScriptAdapterConfig, TypeScriptWhySession, type WhySessionOptions, accessContextFor, arrayLiteralOf, buildProjectHelperIndex, callOpsFor, climbSyntax, collectAncestorBranches, collectClientFieldAccesses, computeAdapterPacksDigest, couldNameAValue, createProjectWithoutTsconfig, createTsDiscoveryContext, createTsSubUnitContext, createTypeScriptAdapter, discoverUnits, exportedDeclarationsOf, extractCodeStructure, extractRawBranches, findEnclosingFunction, findNearestTsconfig, findTerminals, functionTargetOf, functionValueOf, hasBody, importDeclarationsOf, importedNamesOf, importedRootsOf, invocationContextFor, isDefaultedAt, isImportedFrom, methodDeclaredIn, namedImportsOf, objectLiteralOf, parseConditionExpression, peelSyntax, peelValue, propertiesOf, propertyFunctionOf, propertyNameOf, propertyOf, propertyValueOf, readConfiguredCall, readContract, readContractForClientCall, readName, resolveAliasedSymbol, resolveSubject, rootIdentifier, startsItsOwnScope, stringPropertyOf, stringValueOf, stubEvidence, stubEvidenceIn, symbolBehind, workspaceRootFor, writtenNodeOf };
|
|
1626
|
+
export { ADAPTER_VERSION, type Accessed, type CallAccountingEntry, type CallAccountingOutcome, type ClientCallSite, type ConfiguredCallContext, type ConfiguredCallRead, type ConfiguredCallSpec, type ContractReadResult, type DescentBarriers, type DiscoveredUnit, type EnvironmentNamers, type ExplainCallableOptions, type ExplainedResolution, type FoundTerminal, type FunctionRoot, GENERIC_TERMINALS, type ImportScanOptions, NO_BARRIERS, type ObservedStubCall, type RawBranchResult, type ReadNameOptions, ResolutionStore, type StubCallEvidence, type StubEvidenceOptions, TSCONFIG_NAMES, type TsDiscoveryContext, type TsInvocationRecognizerContext, type TsJsxAttributeLocation, type TsSubUnitContext, type TypeScriptAdapter, type TypeScriptAdapterConfig, TypeScriptWhySession, type WhySessionOptions, accessContextFor, arrayLiteralOf, buildProjectHelperIndex, callOpsFor, climbSyntax, collectAncestorBranches, collectClientFieldAccesses, computeAdapterPacksDigest, couldNameAValue, createProjectWithoutTsconfig, createTsDiscoveryContext, createTsSubUnitContext, createTypeScriptAdapter, discoverUnits, exportedDeclarationsOf, extractCodeStructure, extractRawBranches, findEnclosingFunction, findNearestTsconfig, findTerminals, functionTargetOf, functionValueOf, hasBody, importDeclarationsOf, importedNamesOf, importedRootsOf, invocationContextFor, isDefaultedAt, isImportedFrom, methodDeclaredIn, namedImportsOf, objectLiteralOf, parseConditionExpression, peelSyntax, peelValue, propertiesOf, propertyFunctionOf, propertyNameOf, propertyOf, propertyValueOf, readConfiguredCall, readContract, readContractForClientCall, readName, resolveAliasedSymbol, resolveSubject, rootIdentifier, startsItsOwnScope, stringPropertyOf, stringValueOf, stubEvidence, stubEvidenceIn, symbolBehind, workspaceRootFor, writtenNodeOf };
|
package/dist/index.d.ts
CHANGED
|
@@ -46,6 +46,18 @@ interface PassedArgument {
|
|
|
46
46
|
call: Node;
|
|
47
47
|
argument: Node;
|
|
48
48
|
}
|
|
49
|
+
/** See `ResolutionStore.envNamers`. */
|
|
50
|
+
interface EnvironmentNamers {
|
|
51
|
+
/**
|
|
52
|
+
* The environment reads that take their variable's name from this
|
|
53
|
+
* parameter, however many helpers forward it along the way. Empty for
|
|
54
|
+
* a parameter no read ever takes a name from, and null where the
|
|
55
|
+
* rules had nothing to go on: a file that exports nothing states no
|
|
56
|
+
* facts, so their silence about its parameters means neither yes nor
|
|
57
|
+
* no, and the asker settles what it can by reading the syntax.
|
|
58
|
+
*/
|
|
59
|
+
sitesNaming(parameter: Node): readonly Node[] | null;
|
|
60
|
+
}
|
|
49
61
|
declare class ResolutionStore {
|
|
50
62
|
private readonly db;
|
|
51
63
|
private readonly table;
|
|
@@ -66,13 +78,17 @@ declare class ResolutionStore {
|
|
|
66
78
|
private readonly constructionSites;
|
|
67
79
|
/** Files the most recent query read, for the memo to keep. */
|
|
68
80
|
private lastQueryWalked;
|
|
81
|
+
/** See `environmentSiteFiles`; null until the first env question. */
|
|
82
|
+
private envSiteFiles;
|
|
83
|
+
private envNamersAnswer;
|
|
84
|
+
private envNamersExtractedAt;
|
|
69
85
|
private readonly declarations;
|
|
70
86
|
private readonly graph;
|
|
71
87
|
/** See `notePossibleCallers`. */
|
|
72
88
|
private readonly possibleCallers;
|
|
73
89
|
private readonly callerFilesRead;
|
|
74
90
|
private stale;
|
|
75
|
-
constructor(wrappers?: TransparentWrapper[]);
|
|
91
|
+
constructor(wrappers?: TransparentWrapper[], environmentObjects?: readonly string[]);
|
|
76
92
|
/**
|
|
77
93
|
* `alsoFrom` is a second file to walk out from, for a caller that
|
|
78
94
|
* knows where the value it is asking about was set up. The walk
|
|
@@ -144,6 +160,32 @@ declare class ResolutionStore {
|
|
|
144
160
|
* parameter's own function with no join against `bodyCalls` needed.
|
|
145
161
|
*/
|
|
146
162
|
callsPassing(parameter: Node): PassedArgument[];
|
|
163
|
+
/**
|
|
164
|
+
* Which parameters an environment read takes its variable's name
|
|
165
|
+
* from, for a reader standing at a call. One question covers the
|
|
166
|
+
* whole project: a project has a handful of environment reads and
|
|
167
|
+
* thousands of parameters, and with the read bound the rules run from
|
|
168
|
+
* each callee to its callers.
|
|
169
|
+
*
|
|
170
|
+
* `definedIn` is the callee's own file, read into the store before
|
|
171
|
+
* the question so a helper nothing had extracted yet is among the
|
|
172
|
+
* facts the rules run over.
|
|
173
|
+
*/
|
|
174
|
+
envNamers(definedIn: SourceFile): EnvironmentNamers;
|
|
175
|
+
private sitesNamedBy;
|
|
176
|
+
/**
|
|
177
|
+
* Seed every read the store knows of, derive, and take the sites back
|
|
178
|
+
* per parameter. The question is dropped afterwards, so a later ask
|
|
179
|
+
* over a larger fact set derives it again.
|
|
180
|
+
*/
|
|
181
|
+
private askEnvNamers;
|
|
182
|
+
/**
|
|
183
|
+
* The project's files that spell an environment read with a computed
|
|
184
|
+
* index, read into the store. Which files those are cannot depend on
|
|
185
|
+
* what a reader happened to ask about first, so the scan is over the
|
|
186
|
+
* project's own sources and it happens once.
|
|
187
|
+
*/
|
|
188
|
+
private environmentSiteFiles;
|
|
147
189
|
/**
|
|
148
190
|
* Whether running this function hands back that call: returned
|
|
149
191
|
* outright, written into a name and returned, or a shorthand body.
|
|
@@ -247,6 +289,8 @@ declare class ResolutionStore {
|
|
|
247
289
|
*/
|
|
248
290
|
private forgetQuery;
|
|
249
291
|
private wantValue;
|
|
292
|
+
/** For a question seeded with a fact key the store read out of the database. */
|
|
293
|
+
private wantKey;
|
|
250
294
|
private wantExportsOf;
|
|
251
295
|
/**
|
|
252
296
|
* Discovery walks the table in order, and the rounds derive it in
|
|
@@ -1579,4 +1623,4 @@ declare function climbSyntax(node: Node): Node;
|
|
|
1579
1623
|
*/
|
|
1580
1624
|
declare function peelValue(node: Node): Node;
|
|
1581
1625
|
|
|
1582
|
-
export { ADAPTER_VERSION, type Accessed, type CallAccountingEntry, type CallAccountingOutcome, type ClientCallSite, type ConfiguredCallContext, type ConfiguredCallRead, type ConfiguredCallSpec, type ContractReadResult, type DescentBarriers, type DiscoveredUnit, type ExplainCallableOptions, type ExplainedResolution, type FoundTerminal, type FunctionRoot, GENERIC_TERMINALS, type ImportScanOptions, NO_BARRIERS, type ObservedStubCall, type RawBranchResult, type ReadNameOptions, ResolutionStore, type StubCallEvidence, type StubEvidenceOptions, TSCONFIG_NAMES, type TsDiscoveryContext, type TsInvocationRecognizerContext, type TsJsxAttributeLocation, type TsSubUnitContext, type TypeScriptAdapter, type TypeScriptAdapterConfig, TypeScriptWhySession, type WhySessionOptions, accessContextFor, arrayLiteralOf, buildProjectHelperIndex, callOpsFor, climbSyntax, collectAncestorBranches, collectClientFieldAccesses, computeAdapterPacksDigest, couldNameAValue, createProjectWithoutTsconfig, createTsDiscoveryContext, createTsSubUnitContext, createTypeScriptAdapter, discoverUnits, exportedDeclarationsOf, extractCodeStructure, extractRawBranches, findEnclosingFunction, findNearestTsconfig, findTerminals, functionTargetOf, functionValueOf, hasBody, importDeclarationsOf, importedNamesOf, importedRootsOf, invocationContextFor, isDefaultedAt, isImportedFrom, methodDeclaredIn, namedImportsOf, objectLiteralOf, parseConditionExpression, peelSyntax, peelValue, propertiesOf, propertyFunctionOf, propertyNameOf, propertyOf, propertyValueOf, readConfiguredCall, readContract, readContractForClientCall, readName, resolveAliasedSymbol, resolveSubject, rootIdentifier, startsItsOwnScope, stringPropertyOf, stringValueOf, stubEvidence, stubEvidenceIn, symbolBehind, workspaceRootFor, writtenNodeOf };
|
|
1626
|
+
export { ADAPTER_VERSION, type Accessed, type CallAccountingEntry, type CallAccountingOutcome, type ClientCallSite, type ConfiguredCallContext, type ConfiguredCallRead, type ConfiguredCallSpec, type ContractReadResult, type DescentBarriers, type DiscoveredUnit, type EnvironmentNamers, type ExplainCallableOptions, type ExplainedResolution, type FoundTerminal, type FunctionRoot, GENERIC_TERMINALS, type ImportScanOptions, NO_BARRIERS, type ObservedStubCall, type RawBranchResult, type ReadNameOptions, ResolutionStore, type StubCallEvidence, type StubEvidenceOptions, TSCONFIG_NAMES, type TsDiscoveryContext, type TsInvocationRecognizerContext, type TsJsxAttributeLocation, type TsSubUnitContext, type TypeScriptAdapter, type TypeScriptAdapterConfig, TypeScriptWhySession, type WhySessionOptions, accessContextFor, arrayLiteralOf, buildProjectHelperIndex, callOpsFor, climbSyntax, collectAncestorBranches, collectClientFieldAccesses, computeAdapterPacksDigest, couldNameAValue, createProjectWithoutTsconfig, createTsDiscoveryContext, createTsSubUnitContext, createTypeScriptAdapter, discoverUnits, exportedDeclarationsOf, extractCodeStructure, extractRawBranches, findEnclosingFunction, findNearestTsconfig, findTerminals, functionTargetOf, functionValueOf, hasBody, importDeclarationsOf, importedNamesOf, importedRootsOf, invocationContextFor, isDefaultedAt, isImportedFrom, methodDeclaredIn, namedImportsOf, objectLiteralOf, parseConditionExpression, peelSyntax, peelValue, propertiesOf, propertyFunctionOf, propertyNameOf, propertyOf, propertyValueOf, readConfiguredCall, readContract, readContractForClientCall, readName, resolveAliasedSymbol, resolveSubject, rootIdentifier, startsItsOwnScope, stringPropertyOf, stringValueOf, stubEvidence, stubEvidenceIn, symbolBehind, workspaceRootFor, writtenNodeOf };
|
package/dist/index.js
CHANGED
|
@@ -1454,13 +1454,14 @@ function isWriteTarget(name) {
|
|
|
1454
1454
|
function fact(db, relation, ...tuple) {
|
|
1455
1455
|
db.add(relation, tuple);
|
|
1456
1456
|
}
|
|
1457
|
-
function createNodeTable() {
|
|
1457
|
+
function createNodeTable(environmentObjects = []) {
|
|
1458
1458
|
return {
|
|
1459
1459
|
byId: /* @__PURE__ */ new Map(),
|
|
1460
1460
|
seenFunctions: /* @__PURE__ */ new Set(),
|
|
1461
1461
|
seenBindings: /* @__PURE__ */ new Set(),
|
|
1462
1462
|
seenValues: /* @__PURE__ */ new Set(),
|
|
1463
|
-
seenClasses: /* @__PURE__ */ new Set()
|
|
1463
|
+
seenClasses: /* @__PURE__ */ new Set(),
|
|
1464
|
+
environmentObjects
|
|
1464
1465
|
};
|
|
1465
1466
|
}
|
|
1466
1467
|
function nodeId(node) {
|
|
@@ -1605,6 +1606,40 @@ function literalIndexOf(index) {
|
|
|
1605
1606
|
}
|
|
1606
1607
|
return null;
|
|
1607
1608
|
}
|
|
1609
|
+
function readsEnvironment(table, access) {
|
|
1610
|
+
if (table.environmentObjects.length === 0) {
|
|
1611
|
+
return false;
|
|
1612
|
+
}
|
|
1613
|
+
const path14 = dottedPathOf(access.getExpression());
|
|
1614
|
+
return path14 !== null && table.environmentObjects.includes(path14);
|
|
1615
|
+
}
|
|
1616
|
+
function isEnvironmentNameRead(table, node) {
|
|
1617
|
+
if (!Node5.isElementAccessExpression(node)) {
|
|
1618
|
+
return false;
|
|
1619
|
+
}
|
|
1620
|
+
const argument = node.getArgumentExpression();
|
|
1621
|
+
return argument !== void 0 && literalIndexOf(argument) === null && readsEnvironment(table, node);
|
|
1622
|
+
}
|
|
1623
|
+
function environmentNameReadsIn(table, sourceFile) {
|
|
1624
|
+
if (table.environmentObjects.length === 0) {
|
|
1625
|
+
return [];
|
|
1626
|
+
}
|
|
1627
|
+
const text = sourceFile.getFullText();
|
|
1628
|
+
if (!table.environmentObjects.some((path14) => text.includes(path14))) {
|
|
1629
|
+
return [];
|
|
1630
|
+
}
|
|
1631
|
+
return sourceFile.getDescendantsOfKind(SyntaxKind2.ElementAccessExpression).filter((access) => isEnvironmentNameRead(table, access));
|
|
1632
|
+
}
|
|
1633
|
+
function dottedPathOf(expression) {
|
|
1634
|
+
if (Node5.isIdentifier(expression)) {
|
|
1635
|
+
return expression.getText();
|
|
1636
|
+
}
|
|
1637
|
+
if (!Node5.isPropertyAccessExpression(expression)) {
|
|
1638
|
+
return null;
|
|
1639
|
+
}
|
|
1640
|
+
const object = dottedPathOf(expression.getExpression());
|
|
1641
|
+
return object === null ? null : `${object}.${expression.getName()}`;
|
|
1642
|
+
}
|
|
1608
1643
|
function asFallbackExpression(expression) {
|
|
1609
1644
|
if (!Node5.isBinaryExpression(expression)) {
|
|
1610
1645
|
return null;
|
|
@@ -1676,6 +1711,10 @@ function emitValue(db, table, value) {
|
|
|
1676
1711
|
);
|
|
1677
1712
|
return id;
|
|
1678
1713
|
}
|
|
1714
|
+
const argument = expression.getArgumentExpression();
|
|
1715
|
+
if (argument !== void 0 && readsEnvironment(table, expression)) {
|
|
1716
|
+
fact(db, "readsEnvNamed", id, emitValue(db, table, argument));
|
|
1717
|
+
}
|
|
1679
1718
|
fact(db, "writtenValue", id);
|
|
1680
1719
|
return id;
|
|
1681
1720
|
}
|
|
@@ -2140,6 +2179,9 @@ function recordBodyCalls(db, table, fnId, node) {
|
|
|
2140
2179
|
if (!Node5.isExpression(node)) {
|
|
2141
2180
|
return false;
|
|
2142
2181
|
}
|
|
2182
|
+
if (isEnvironmentNameRead(table, node)) {
|
|
2183
|
+
emitValue(db, table, node);
|
|
2184
|
+
}
|
|
2143
2185
|
const call = unwrapExpression(node);
|
|
2144
2186
|
if (Node5.isCallExpression(call)) {
|
|
2145
2187
|
const callee = unwrapExpression(call.getExpression());
|
|
@@ -2365,9 +2407,10 @@ var QUERY_FACTS = queryFacts(RESOLUTION_PROGRAM);
|
|
|
2365
2407
|
var MODULE_DEMANDS = RESOLUTION_PROGRAM.demands.filter(
|
|
2366
2408
|
(one) => (one.relation === "moduleExport" || one.relation === "moduleForwards") && one.bound[0] === true
|
|
2367
2409
|
).map((one) => one.demand);
|
|
2410
|
+
var NO_NAMERS = { sitesNaming: () => [] };
|
|
2368
2411
|
var ResolutionStore = class {
|
|
2369
2412
|
db = new Database2();
|
|
2370
|
-
table
|
|
2413
|
+
table;
|
|
2371
2414
|
fullyExtracted = /* @__PURE__ */ new Set();
|
|
2372
2415
|
seededValues = /* @__PURE__ */ new Set();
|
|
2373
2416
|
importedNames = /* @__PURE__ */ new Map();
|
|
@@ -2385,13 +2428,18 @@ var ResolutionStore = class {
|
|
|
2385
2428
|
constructionSites = /* @__PURE__ */ new Map();
|
|
2386
2429
|
/** Files the most recent query read, for the memo to keep. */
|
|
2387
2430
|
lastQueryWalked = [];
|
|
2431
|
+
/** See `environmentSiteFiles`; null until the first env question. */
|
|
2432
|
+
envSiteFiles = null;
|
|
2433
|
+
envNamersAnswer = NO_NAMERS;
|
|
2434
|
+
envNamersExtractedAt = -1;
|
|
2388
2435
|
declarations = /* @__PURE__ */ new Map();
|
|
2389
2436
|
graph = new ModuleGraph();
|
|
2390
2437
|
/** See `notePossibleCallers`. */
|
|
2391
2438
|
possibleCallers = /* @__PURE__ */ new Set();
|
|
2392
2439
|
callerFilesRead = /* @__PURE__ */ new Set();
|
|
2393
2440
|
stale = true;
|
|
2394
|
-
constructor(wrappers = []) {
|
|
2441
|
+
constructor(wrappers = [], environmentObjects = []) {
|
|
2442
|
+
this.table = createNodeTable(environmentObjects);
|
|
2395
2443
|
addPackWords(this.db, { unwrapsByName: wrappers });
|
|
2396
2444
|
}
|
|
2397
2445
|
/**
|
|
@@ -2604,6 +2652,89 @@ var ResolutionStore = class {
|
|
|
2604
2652
|
}
|
|
2605
2653
|
return found;
|
|
2606
2654
|
}
|
|
2655
|
+
/**
|
|
2656
|
+
* Which parameters an environment read takes its variable's name
|
|
2657
|
+
* from, for a reader standing at a call. One question covers the
|
|
2658
|
+
* whole project: a project has a handful of environment reads and
|
|
2659
|
+
* thousands of parameters, and with the read bound the rules run from
|
|
2660
|
+
* each callee to its callers.
|
|
2661
|
+
*
|
|
2662
|
+
* `definedIn` is the callee's own file, read into the store before
|
|
2663
|
+
* the question so a helper nothing had extracted yet is among the
|
|
2664
|
+
* facts the rules run over.
|
|
2665
|
+
*/
|
|
2666
|
+
envNamers(definedIn) {
|
|
2667
|
+
const siteFiles = this.environmentSiteFiles(definedIn.getProject());
|
|
2668
|
+
if (siteFiles.length === 0) {
|
|
2669
|
+
return NO_NAMERS;
|
|
2670
|
+
}
|
|
2671
|
+
this.extractFile(definedIn);
|
|
2672
|
+
if (this.envNamersExtractedAt === this.fullyExtracted.size) {
|
|
2673
|
+
return this.envNamersAnswer;
|
|
2674
|
+
}
|
|
2675
|
+
const answered = this.askEnvNamers([...siteFiles, definedIn]);
|
|
2676
|
+
const siteFilePaths = new Set(siteFiles.map((one) => one.getFilePath()));
|
|
2677
|
+
this.envNamersAnswer = {
|
|
2678
|
+
sitesNaming: (parameter) => this.sitesNamedBy(answered, siteFilePaths, parameter)
|
|
2679
|
+
};
|
|
2680
|
+
this.envNamersExtractedAt = this.fullyExtracted.size;
|
|
2681
|
+
return this.envNamersAnswer;
|
|
2682
|
+
}
|
|
2683
|
+
sitesNamedBy(answered, siteFilePaths, parameter) {
|
|
2684
|
+
const key = nodeId(parameter);
|
|
2685
|
+
const sites = answered.get(key);
|
|
2686
|
+
if (sites !== void 0) {
|
|
2687
|
+
return sites;
|
|
2688
|
+
}
|
|
2689
|
+
if (!siteFilePaths.has(parameter.getSourceFile().getFilePath())) {
|
|
2690
|
+
return [];
|
|
2691
|
+
}
|
|
2692
|
+
return this.db.lookup("paramOf", 2, key).length > 0 ? [] : null;
|
|
2693
|
+
}
|
|
2694
|
+
/**
|
|
2695
|
+
* Seed every read the store knows of, derive, and take the sites back
|
|
2696
|
+
* per parameter. The question is dropped afterwards, so a later ask
|
|
2697
|
+
* over a larger fact set derives it again.
|
|
2698
|
+
*/
|
|
2699
|
+
askEnvNamers(seeds) {
|
|
2700
|
+
const byParameter = /* @__PURE__ */ new Map();
|
|
2701
|
+
try {
|
|
2702
|
+
for (const [site] of this.db.facts("readsEnvNamed")) {
|
|
2703
|
+
this.wantKey("wantedEnvSite", String(site));
|
|
2704
|
+
}
|
|
2705
|
+
this.extractDemanded(seeds);
|
|
2706
|
+
this.derive();
|
|
2707
|
+
for (const [parameter, site] of this.db.facts("wantedParamNamesEnv")) {
|
|
2708
|
+
const node = this.table.byId.get(String(site));
|
|
2709
|
+
if (node === void 0) {
|
|
2710
|
+
continue;
|
|
2711
|
+
}
|
|
2712
|
+
const sites = byParameter.get(String(parameter)) ?? [];
|
|
2713
|
+
sites.push(node);
|
|
2714
|
+
byParameter.set(String(parameter), sites);
|
|
2715
|
+
}
|
|
2716
|
+
} finally {
|
|
2717
|
+
this.forgetQuery();
|
|
2718
|
+
}
|
|
2719
|
+
return byParameter;
|
|
2720
|
+
}
|
|
2721
|
+
/**
|
|
2722
|
+
* The project's files that spell an environment read with a computed
|
|
2723
|
+
* index, read into the store. Which files those are cannot depend on
|
|
2724
|
+
* what a reader happened to ask about first, so the scan is over the
|
|
2725
|
+
* project's own sources and it happens once.
|
|
2726
|
+
*/
|
|
2727
|
+
environmentSiteFiles(project) {
|
|
2728
|
+
if (this.envSiteFiles !== null) {
|
|
2729
|
+
return this.envSiteFiles;
|
|
2730
|
+
}
|
|
2731
|
+
const found = project.getSourceFiles().filter(
|
|
2732
|
+
(one) => !one.isInNodeModules() && environmentNameReadsIn(this.table, one).length > 0
|
|
2733
|
+
);
|
|
2734
|
+
this.envSiteFiles = found;
|
|
2735
|
+
this.extractFiles(found);
|
|
2736
|
+
return found;
|
|
2737
|
+
}
|
|
2607
2738
|
/**
|
|
2608
2739
|
* Whether running this function hands back that call: returned
|
|
2609
2740
|
* outright, written into a name and returned, or a shorthand body.
|
|
@@ -3014,7 +3145,11 @@ var ResolutionStore = class {
|
|
|
3014
3145
|
this.stale = false;
|
|
3015
3146
|
}
|
|
3016
3147
|
wantValue(question, value) {
|
|
3017
|
-
|
|
3148
|
+
this.wantKey(question, nodeId(value));
|
|
3149
|
+
}
|
|
3150
|
+
/** For a question seeded with a fact key the store read out of the database. */
|
|
3151
|
+
wantKey(question, key) {
|
|
3152
|
+
if (this.db.add(question, [key]) === "added") {
|
|
3018
3153
|
this.stale = true;
|
|
3019
3154
|
}
|
|
3020
3155
|
}
|
|
@@ -17654,11 +17789,14 @@ function createTypeScriptAdapter(suppliedConfig) {
|
|
|
17654
17789
|
const packWrappers = config.frameworks.flatMap(
|
|
17655
17790
|
(pack) => pack.transparentWrappers ?? []
|
|
17656
17791
|
);
|
|
17792
|
+
const packEnvironments = config.frameworks.flatMap(
|
|
17793
|
+
(pack) => pack.environmentObjects ?? []
|
|
17794
|
+
);
|
|
17657
17795
|
return {
|
|
17658
17796
|
tsProject: project,
|
|
17659
17797
|
async extractFromFiles(filePaths) {
|
|
17660
17798
|
const summaries = [];
|
|
17661
|
-
const resolution = new ResolutionStore(packWrappers);
|
|
17799
|
+
const resolution = new ResolutionStore(packWrappers, packEnvironments);
|
|
17662
17800
|
const claimedUnits = /* @__PURE__ */ new Map();
|
|
17663
17801
|
for (const fp of filePaths) {
|
|
17664
17802
|
let sourceFile = project.getSourceFile(fp);
|
|
@@ -17761,7 +17899,7 @@ function createTypeScriptAdapter(suppliedConfig) {
|
|
|
17761
17899
|
timer
|
|
17762
17900
|
);
|
|
17763
17901
|
timer.time("warmExportChains", () => warmExportChains(deep.deepRoots));
|
|
17764
|
-
const resolution = new ResolutionStore(packWrappers);
|
|
17902
|
+
const resolution = new ResolutionStore(packWrappers, packEnvironments);
|
|
17765
17903
|
const packsByFile = timer.time(
|
|
17766
17904
|
"preFilter",
|
|
17767
17905
|
() => computePackApplicability(sourceFiles, config.frameworks, resolution)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suss/adapter-typescript",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Read a TypeScript or JavaScript codebase with suss and check what each handler returns against every caller, spec and template it can see.",
|
|
6
6
|
"keywords": [
|
|
@@ -48,11 +48,11 @@
|
|
|
48
48
|
"typecheck": "tsc --noEmit"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@suss/behavioral-ir": "0.
|
|
52
|
-
"@suss/datalog": "0.
|
|
53
|
-
"@suss/extractor": "0.
|
|
54
|
-
"@suss/resolution": "0.
|
|
55
|
-
"@suss/values": "0.
|
|
51
|
+
"@suss/behavioral-ir": "0.32.0",
|
|
52
|
+
"@suss/datalog": "0.32.0",
|
|
53
|
+
"@suss/extractor": "0.32.0",
|
|
54
|
+
"@suss/resolution": "0.32.0",
|
|
55
|
+
"@suss/values": "0.32.0",
|
|
56
56
|
"graphql": "^16.8.0",
|
|
57
57
|
"picomatch": "^4.0.4",
|
|
58
58
|
"ts-morph": "^23.0.0",
|