@suss/adapter-typescript 0.7.2 → 0.8.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 +124 -43
- package/dist/index.d.cts +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +124 -43
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -3985,6 +3985,7 @@ var import_ts_morph19 = require("ts-morph");
|
|
|
3985
3985
|
var import_ts_morph18 = require("ts-morph");
|
|
3986
3986
|
var byFile = createPerFileCache();
|
|
3987
3987
|
var byDeclaration = /* @__PURE__ */ new WeakMap();
|
|
3988
|
+
var byField = /* @__PURE__ */ new WeakMap();
|
|
3988
3989
|
function writesToBinding(declaration) {
|
|
3989
3990
|
const remembered = byDeclaration.get(declaration);
|
|
3990
3991
|
if (remembered !== void 0) {
|
|
@@ -4017,22 +4018,19 @@ function writesToBindingUncached(declaration) {
|
|
|
4017
4018
|
return { values, inOrder: writesRunInOrder(declaration, writes) };
|
|
4018
4019
|
}
|
|
4019
4020
|
function writesToField(declaration) {
|
|
4020
|
-
const remembered =
|
|
4021
|
+
const remembered = byField.get(declaration);
|
|
4021
4022
|
if (remembered !== void 0) {
|
|
4022
4023
|
return remembered;
|
|
4023
4024
|
}
|
|
4024
4025
|
const answer = writesToFieldUncached(declaration);
|
|
4025
|
-
|
|
4026
|
+
byField.set(declaration, answer);
|
|
4026
4027
|
return answer;
|
|
4027
4028
|
}
|
|
4028
4029
|
function writesToFieldUncached(declaration) {
|
|
4029
|
-
const
|
|
4030
|
+
const first = startingValueOf(declaration);
|
|
4030
4031
|
const assignments = assignmentsTo(declaration);
|
|
4031
4032
|
if (assignments.length === 0) {
|
|
4032
|
-
return {
|
|
4033
|
-
values: initializer === void 0 ? [] : [initializer],
|
|
4034
|
-
inOrder: true
|
|
4035
|
-
};
|
|
4033
|
+
return { values: first === void 0 ? [] : [first], inOrder: true };
|
|
4036
4034
|
}
|
|
4037
4035
|
const values = [];
|
|
4038
4036
|
for (const write of assignments) {
|
|
@@ -4041,14 +4039,16 @@ function writesToFieldUncached(declaration) {
|
|
|
4041
4039
|
}
|
|
4042
4040
|
values.push(write.value);
|
|
4043
4041
|
}
|
|
4044
|
-
const withInitializer = initializer === void 0 ? values : [initializer, ...values];
|
|
4045
4042
|
return {
|
|
4046
|
-
values:
|
|
4043
|
+
values: first === void 0 ? values : [first, ...values],
|
|
4047
4044
|
inOrder: assignments.every(
|
|
4048
4045
|
(write) => writeRunsInConstructor(declaration, write)
|
|
4049
4046
|
)
|
|
4050
4047
|
};
|
|
4051
4048
|
}
|
|
4049
|
+
function startingValueOf(declaration) {
|
|
4050
|
+
return import_ts_morph18.Node.isParameterDeclaration(declaration) ? declaration : declaration.getInitializer();
|
|
4051
|
+
}
|
|
4052
4052
|
function writeRunsInConstructor(declaration, write) {
|
|
4053
4053
|
const statement = statementOf(write.node);
|
|
4054
4054
|
if (statement === null) {
|
|
@@ -4059,13 +4059,16 @@ function writeRunsInConstructor(declaration, write) {
|
|
|
4059
4059
|
return false;
|
|
4060
4060
|
}
|
|
4061
4061
|
const owner = body.getParent();
|
|
4062
|
-
return owner !== void 0 && import_ts_morph18.Node.isConstructorDeclaration(owner) && owner.getParent() === declaration
|
|
4062
|
+
return owner !== void 0 && import_ts_morph18.Node.isConstructorDeclaration(owner) && owner.getParent() === classHolding(declaration);
|
|
4063
|
+
}
|
|
4064
|
+
function classHolding(declaration) {
|
|
4065
|
+
return import_ts_morph18.Node.isParameterDeclaration(declaration) ? declaration.getParent().getParent() : declaration.getParent();
|
|
4063
4066
|
}
|
|
4064
4067
|
function isWrittenAgain(declaration) {
|
|
4065
4068
|
return assignmentsTo(declaration).length > 0;
|
|
4066
4069
|
}
|
|
4067
4070
|
function assignmentsTo(declaration) {
|
|
4068
|
-
if (import_ts_morph18.Node.isPropertyDeclaration(declaration)) {
|
|
4071
|
+
if (import_ts_morph18.Node.isPropertyDeclaration(declaration) || import_ts_morph18.Node.isParameterDeclaration(declaration)) {
|
|
4069
4072
|
const sourceFile2 = declaration.getSourceFile();
|
|
4070
4073
|
return sourceFile2.isDeclarationFile() ? [] : assignmentsInFile(sourceFile2).get(declaration) ?? [];
|
|
4071
4074
|
}
|
|
@@ -4132,7 +4135,9 @@ function declarationsOf(name) {
|
|
|
4132
4135
|
}
|
|
4133
4136
|
const declarations = [];
|
|
4134
4137
|
for (const declaration of symbol.getDeclarations()) {
|
|
4135
|
-
if (import_ts_morph18.Node.isVariableDeclaration(declaration) || import_ts_morph18.Node.isPropertyDeclaration(declaration)
|
|
4138
|
+
if (import_ts_morph18.Node.isVariableDeclaration(declaration) || import_ts_morph18.Node.isPropertyDeclaration(declaration) || // A parameter property is the field's only declaration, so
|
|
4139
|
+
// `this.dao = other` in the constructor writes to it.
|
|
4140
|
+
import_ts_morph18.Node.isParameterDeclaration(declaration) && declaration.isParameterProperty()) {
|
|
4136
4141
|
declarations.push(declaration);
|
|
4137
4142
|
}
|
|
4138
4143
|
}
|
|
@@ -5909,7 +5914,8 @@ function createNodeTable() {
|
|
|
5909
5914
|
byId: /* @__PURE__ */ new Map(),
|
|
5910
5915
|
seenFunctions: /* @__PURE__ */ new Set(),
|
|
5911
5916
|
seenBindings: /* @__PURE__ */ new Set(),
|
|
5912
|
-
seenValues: /* @__PURE__ */ new Set()
|
|
5917
|
+
seenValues: /* @__PURE__ */ new Set(),
|
|
5918
|
+
seenClasses: /* @__PURE__ */ new Set()
|
|
5913
5919
|
};
|
|
5914
5920
|
}
|
|
5915
5921
|
function nodeId(node) {
|
|
@@ -6130,7 +6136,7 @@ function emitValue(db, table, value) {
|
|
|
6130
6136
|
}
|
|
6131
6137
|
return id;
|
|
6132
6138
|
}
|
|
6133
|
-
if (import_ts_morph28.Node.isCallExpression(expression)) {
|
|
6139
|
+
if (import_ts_morph28.Node.isCallExpression(expression) || import_ts_morph28.Node.isNewExpression(expression)) {
|
|
6134
6140
|
emitCallFacts(db, table, expression);
|
|
6135
6141
|
fact(db, "writtenValue", id);
|
|
6136
6142
|
return id;
|
|
@@ -6157,11 +6163,24 @@ function emitBindingValues(db, table, declaration) {
|
|
|
6157
6163
|
function emitFieldValues(db, table, declaration) {
|
|
6158
6164
|
const { values, inOrder } = writesToField(declaration);
|
|
6159
6165
|
const last = values[values.length - 1];
|
|
6160
|
-
if (!inOrder || last === void 0) {
|
|
6166
|
+
if (!inOrder || last === void 0 || !import_ts_morph28.Node.isExpression(last)) {
|
|
6161
6167
|
return;
|
|
6162
6168
|
}
|
|
6163
6169
|
fact(db, "binds", nodeId(declaration), emitValue(db, table, last));
|
|
6164
6170
|
}
|
|
6171
|
+
function emitParameterPropertyRead(db, table, referenceId, declaration) {
|
|
6172
|
+
const { values, inOrder } = writesToField(declaration);
|
|
6173
|
+
const last = values[values.length - 1];
|
|
6174
|
+
if (!inOrder || last === void 0) {
|
|
6175
|
+
return;
|
|
6176
|
+
}
|
|
6177
|
+
if (!import_ts_morph28.Node.isExpression(last)) {
|
|
6178
|
+
table.byId.set(nodeId(last), last);
|
|
6179
|
+
fact(db, "binds", referenceId, nodeId(last));
|
|
6180
|
+
return;
|
|
6181
|
+
}
|
|
6182
|
+
fact(db, "binds", referenceId, emitValue(db, table, last));
|
|
6183
|
+
}
|
|
6165
6184
|
function emitBindingElementFacts(db, table, element) {
|
|
6166
6185
|
const id = nodeId(element);
|
|
6167
6186
|
table.byId.set(id, element);
|
|
@@ -6243,7 +6262,16 @@ function emitReferenceFacts(db, table, reference) {
|
|
|
6243
6262
|
continue;
|
|
6244
6263
|
}
|
|
6245
6264
|
if (import_ts_morph28.Node.isParameterDeclaration(declaration)) {
|
|
6265
|
+
if (declaration.isParameterProperty() && import_ts_morph28.Node.isPropertyAccessExpression(reference)) {
|
|
6266
|
+
emitParameterPropertyRead(db, table, referenceId, declaration);
|
|
6267
|
+
} else {
|
|
6268
|
+
fact(db, "binds", referenceId, declarationId);
|
|
6269
|
+
}
|
|
6270
|
+
continue;
|
|
6271
|
+
}
|
|
6272
|
+
if (import_ts_morph28.Node.isClassDeclaration(declaration)) {
|
|
6246
6273
|
fact(db, "binds", referenceId, declarationId);
|
|
6274
|
+
emitClassFacts(db, table, declaration);
|
|
6247
6275
|
continue;
|
|
6248
6276
|
}
|
|
6249
6277
|
if (import_ts_morph28.Node.isBindingElement(declaration)) {
|
|
@@ -6288,9 +6316,14 @@ function emitCallFacts(db, table, call) {
|
|
|
6288
6316
|
}
|
|
6289
6317
|
}
|
|
6290
6318
|
function emitClassFacts(db, table, declaration) {
|
|
6319
|
+
if (table.seenClasses.has(declaration)) {
|
|
6320
|
+
return;
|
|
6321
|
+
}
|
|
6322
|
+
table.seenClasses.add(declaration);
|
|
6291
6323
|
const id = nodeId(declaration);
|
|
6292
6324
|
table.byId.set(id, declaration);
|
|
6293
6325
|
fact(db, "objectValue", id);
|
|
6326
|
+
emitConstructorParameters(db, table, declaration, id);
|
|
6294
6327
|
for (const method of declaration.getMethods()) {
|
|
6295
6328
|
const methodId = nodeId(method);
|
|
6296
6329
|
table.byId.set(methodId, method);
|
|
@@ -6311,6 +6344,25 @@ function emitClassFacts(db, table, declaration) {
|
|
|
6311
6344
|
}
|
|
6312
6345
|
}
|
|
6313
6346
|
}
|
|
6347
|
+
function emitConstructorParameters(db, table, declaration, classId) {
|
|
6348
|
+
const implementation = declaration.getConstructors().find((candidate) => candidate.getBody() !== void 0);
|
|
6349
|
+
if (implementation === void 0) {
|
|
6350
|
+
return;
|
|
6351
|
+
}
|
|
6352
|
+
emitParameters(db, table, classId, implementation.getParameters());
|
|
6353
|
+
}
|
|
6354
|
+
function emitParameters(db, table, ownerId, parameters) {
|
|
6355
|
+
for (let position = 0; position < parameters.length; position++) {
|
|
6356
|
+
const parameter = parameters[position];
|
|
6357
|
+
if (parameter === void 0) {
|
|
6358
|
+
continue;
|
|
6359
|
+
}
|
|
6360
|
+
const parameterId = nodeId(parameter);
|
|
6361
|
+
table.byId.set(parameterId, parameter);
|
|
6362
|
+
fact(db, "paramOf", ownerId, String(position), parameterId);
|
|
6363
|
+
fact(db, "paramNamed", ownerId, parameter.getName(), parameterId);
|
|
6364
|
+
}
|
|
6365
|
+
}
|
|
6314
6366
|
function emitFunctionFacts(db, table, fn) {
|
|
6315
6367
|
if (table.seenFunctions.has(fn)) {
|
|
6316
6368
|
return;
|
|
@@ -6319,17 +6371,7 @@ function emitFunctionFacts(db, table, fn) {
|
|
|
6319
6371
|
const fnId = nodeId(fn);
|
|
6320
6372
|
table.byId.set(fnId, fn);
|
|
6321
6373
|
if (import_ts_morph28.Node.isFunctionDeclaration(fn) || import_ts_morph28.Node.isFunctionExpression(fn) || import_ts_morph28.Node.isArrowFunction(fn) || import_ts_morph28.Node.isMethodDeclaration(fn)) {
|
|
6322
|
-
|
|
6323
|
-
for (let position = 0; position < parameters.length; position++) {
|
|
6324
|
-
const parameter = parameters[position];
|
|
6325
|
-
if (parameter === void 0) {
|
|
6326
|
-
continue;
|
|
6327
|
-
}
|
|
6328
|
-
const parameterId = nodeId(parameter);
|
|
6329
|
-
table.byId.set(parameterId, parameter);
|
|
6330
|
-
fact(db, "paramOf", fnId, String(position), parameterId);
|
|
6331
|
-
fact(db, "paramNamed", fnId, parameter.getName(), parameterId);
|
|
6332
|
-
}
|
|
6374
|
+
emitParameters(db, table, fnId, fn.getParameters());
|
|
6333
6375
|
const body = fn.getBody?.();
|
|
6334
6376
|
if (body !== void 0) {
|
|
6335
6377
|
if (import_ts_morph28.Node.isExpression(body)) {
|
|
@@ -10055,9 +10097,21 @@ var ResolutionStore = class {
|
|
|
10055
10097
|
this.db.add("wrapperModule", [wrapper.callee, wrapper.module]);
|
|
10056
10098
|
}
|
|
10057
10099
|
}
|
|
10058
|
-
|
|
10100
|
+
/**
|
|
10101
|
+
* `alsoFrom` is a second file to walk out from, for a caller that
|
|
10102
|
+
* knows where the value it is asking about was set up. The walk
|
|
10103
|
+
* follows imports outward from the value's own file, so a file that
|
|
10104
|
+
* imports it, and passed something to the constructor, is somewhere
|
|
10105
|
+
* the walk never reaches on its own.
|
|
10106
|
+
*/
|
|
10107
|
+
resolveCallable(value, alsoFrom) {
|
|
10059
10108
|
const target = factKeyOf(value);
|
|
10060
|
-
return this.resolveByWaves(
|
|
10109
|
+
return this.resolveByWaves(
|
|
10110
|
+
target,
|
|
10111
|
+
"wanted",
|
|
10112
|
+
() => this.lookup(target),
|
|
10113
|
+
alsoFrom
|
|
10114
|
+
);
|
|
10061
10115
|
}
|
|
10062
10116
|
resolveObject(value) {
|
|
10063
10117
|
const target = factKeyOf(value);
|
|
@@ -10125,18 +10179,18 @@ var ResolutionStore = class {
|
|
|
10125
10179
|
}
|
|
10126
10180
|
return origins.some((pair) => namesAPackage(pairHalves(pair).module)) ? [] : null;
|
|
10127
10181
|
}
|
|
10128
|
-
resolveByWaves(value, question, ask) {
|
|
10182
|
+
resolveByWaves(value, question, ask, alsoFrom) {
|
|
10129
10183
|
try {
|
|
10130
|
-
return this.walkForAnswer(value, question, ask);
|
|
10184
|
+
return this.walkForAnswer(value, question, ask, alsoFrom);
|
|
10131
10185
|
} finally {
|
|
10132
10186
|
this.forgetQuery();
|
|
10133
10187
|
}
|
|
10134
10188
|
}
|
|
10135
|
-
walkForAnswer(value, question, ask) {
|
|
10189
|
+
walkForAnswer(value, question, ask, alsoFrom) {
|
|
10136
10190
|
this.wantValue(question, value);
|
|
10137
10191
|
this.seedValue(value);
|
|
10138
10192
|
const walked = /* @__PURE__ */ new Set();
|
|
10139
|
-
let frontier = [value.getSourceFile()];
|
|
10193
|
+
let frontier = alsoFrom === void 0 ? [value.getSourceFile()] : [value.getSourceFile(), alsoFrom];
|
|
10140
10194
|
for (let hop = 0; hop <= MAX_MODULE_HOPS; hop++) {
|
|
10141
10195
|
const next = [];
|
|
10142
10196
|
for (const sourceFile of frontier) {
|
|
@@ -10657,24 +10711,41 @@ function declName(decl) {
|
|
|
10657
10711
|
}
|
|
10658
10712
|
return null;
|
|
10659
10713
|
}
|
|
10660
|
-
function resolveCallee(call, calleeName) {
|
|
10714
|
+
function resolveCallee(call, calleeName, scan) {
|
|
10661
10715
|
if (!import_ts_morph51.Node.isCallExpression(call)) {
|
|
10662
10716
|
return null;
|
|
10663
10717
|
}
|
|
10664
10718
|
const callee = call.getExpression();
|
|
10665
|
-
const
|
|
10666
|
-
|
|
10667
|
-
return null;
|
|
10668
|
-
}
|
|
10669
|
-
for (const decl of symbol.getDeclarations()) {
|
|
10719
|
+
const declarations = callee.getSymbol()?.getDeclarations() ?? [];
|
|
10720
|
+
for (const decl of declarations) {
|
|
10670
10721
|
const resolved = resolveDecl(decl, calleeName);
|
|
10671
10722
|
if (resolved !== null) {
|
|
10672
10723
|
return resolved;
|
|
10673
10724
|
}
|
|
10674
10725
|
}
|
|
10675
|
-
|
|
10726
|
+
if (scan.resolveCallable === void 0 || !readsAField(callee)) {
|
|
10727
|
+
return null;
|
|
10728
|
+
}
|
|
10729
|
+
if (!declarations.some(isDeclaredShape)) {
|
|
10730
|
+
return null;
|
|
10731
|
+
}
|
|
10732
|
+
const value = scan.resolveCallable(callee, scan.reachedFrom);
|
|
10733
|
+
return value === null ? null : resolveDecl(value, calleeName);
|
|
10676
10734
|
}
|
|
10677
|
-
function
|
|
10735
|
+
function readsAField(callee) {
|
|
10736
|
+
if (!import_ts_morph51.Node.isPropertyAccessExpression(callee)) {
|
|
10737
|
+
return false;
|
|
10738
|
+
}
|
|
10739
|
+
let receiver = callee.getExpression();
|
|
10740
|
+
while (import_ts_morph51.Node.isPropertyAccessExpression(receiver)) {
|
|
10741
|
+
receiver = receiver.getExpression();
|
|
10742
|
+
}
|
|
10743
|
+
return import_ts_morph51.Node.isThisExpression(receiver);
|
|
10744
|
+
}
|
|
10745
|
+
function isDeclaredShape(declaration) {
|
|
10746
|
+
return (import_ts_morph51.Node.isMethodSignature(declaration) || import_ts_morph51.Node.isPropertySignature(declaration)) && !isInExternalCode(declaration.getSourceFile());
|
|
10747
|
+
}
|
|
10748
|
+
function collectReachable(func, scan) {
|
|
10678
10749
|
const found = [];
|
|
10679
10750
|
const seen = /* @__PURE__ */ new Set();
|
|
10680
10751
|
func.forEachDescendant((node) => {
|
|
@@ -10682,7 +10753,7 @@ function collectReachable(func) {
|
|
|
10682
10753
|
return;
|
|
10683
10754
|
}
|
|
10684
10755
|
const calleeText = node.getExpression().getText();
|
|
10685
|
-
const resolved = resolveCallee(node, calleeText);
|
|
10756
|
+
const resolved = resolveCallee(node, calleeText, scan);
|
|
10686
10757
|
if (resolved === null) {
|
|
10687
10758
|
return;
|
|
10688
10759
|
}
|
|
@@ -10733,6 +10804,7 @@ function expandReachableClosure(seeds, project, options, projectFileSet, facts,
|
|
|
10733
10804
|
const functionByKey = /* @__PURE__ */ new Map();
|
|
10734
10805
|
const seedKeys = /* @__PURE__ */ new Set();
|
|
10735
10806
|
const scanned = /* @__PURE__ */ new Set();
|
|
10807
|
+
const reachedFrom = /* @__PURE__ */ new Map();
|
|
10736
10808
|
for (const seed of seeds) {
|
|
10737
10809
|
const func = lookup.functionAt(seed.location);
|
|
10738
10810
|
if (func !== null) {
|
|
@@ -10755,11 +10827,19 @@ function expandReachableClosure(seeds, project, options, projectFileSet, facts,
|
|
|
10755
10827
|
if (source === void 0) {
|
|
10756
10828
|
continue;
|
|
10757
10829
|
}
|
|
10758
|
-
|
|
10830
|
+
const cameFrom = reachedFrom.get(key);
|
|
10831
|
+
const scan = {
|
|
10832
|
+
...recognizers.resolveCallable === void 0 ? {} : { resolveCallable: recognizers.resolveCallable },
|
|
10833
|
+
...cameFrom === void 0 ? {} : { reachedFrom: cameFrom }
|
|
10834
|
+
};
|
|
10835
|
+
for (const candidate of collectReachable(source.func, scan)) {
|
|
10759
10836
|
const calleeKey = nodeKey2(candidate.func);
|
|
10760
10837
|
if (!functionByKey.has(calleeKey)) {
|
|
10761
10838
|
functionByKey.set(calleeKey, candidate);
|
|
10762
10839
|
}
|
|
10840
|
+
if (!reachedFrom.has(calleeKey)) {
|
|
10841
|
+
reachedFrom.set(calleeKey, source.func.getSourceFile());
|
|
10842
|
+
}
|
|
10763
10843
|
db.add("calls", [key, calleeKey]);
|
|
10764
10844
|
}
|
|
10765
10845
|
}
|
|
@@ -13148,7 +13228,8 @@ function createTypeScriptAdapter(config) {
|
|
|
13148
13228
|
tallies
|
|
13149
13229
|
),
|
|
13150
13230
|
access: collectAccessRecognizers(config.frameworks, tallies),
|
|
13151
|
-
resolveWrittenValue: (value) => resolution.resolveWrittenValue(value)
|
|
13231
|
+
resolveWrittenValue: (value) => resolution.resolveWrittenValue(value),
|
|
13232
|
+
resolveCallable: (value, alsoFrom) => resolution.resolveCallable(value, alsoFrom)
|
|
13152
13233
|
}
|
|
13153
13234
|
)
|
|
13154
13235
|
) : withSubUnits;
|
package/dist/index.d.cts
CHANGED
|
@@ -184,7 +184,14 @@ declare class ResolutionStore {
|
|
|
184
184
|
private readonly graph;
|
|
185
185
|
private stale;
|
|
186
186
|
constructor(wrappers?: TransparentWrapper[]);
|
|
187
|
-
|
|
187
|
+
/**
|
|
188
|
+
* `alsoFrom` is a second file to walk out from, for a caller that
|
|
189
|
+
* knows where the value it is asking about was set up. The walk
|
|
190
|
+
* follows imports outward from the value's own file, so a file that
|
|
191
|
+
* imports it, and passed something to the constructor, is somewhere
|
|
192
|
+
* the walk never reaches on its own.
|
|
193
|
+
*/
|
|
194
|
+
resolveCallable(value: Node, alsoFrom?: SourceFile): Node | null;
|
|
188
195
|
resolveObject(value: Node): Node | null;
|
|
189
196
|
/**
|
|
190
197
|
* For a value that is neither a function nor an object, such as a
|
|
@@ -382,8 +389,8 @@ interface DiscoveredUnit {
|
|
|
382
389
|
* shape for decorator-driven controllers).
|
|
383
390
|
*/
|
|
384
391
|
routeInfo?: {
|
|
385
|
-
method: string;
|
|
386
|
-
path: string;
|
|
392
|
+
method: string | null;
|
|
393
|
+
path: string | null;
|
|
387
394
|
};
|
|
388
395
|
/**
|
|
389
396
|
* Populated by a pack's `discoverUnits` callback for a message-bus
|
package/dist/index.d.ts
CHANGED
|
@@ -184,7 +184,14 @@ declare class ResolutionStore {
|
|
|
184
184
|
private readonly graph;
|
|
185
185
|
private stale;
|
|
186
186
|
constructor(wrappers?: TransparentWrapper[]);
|
|
187
|
-
|
|
187
|
+
/**
|
|
188
|
+
* `alsoFrom` is a second file to walk out from, for a caller that
|
|
189
|
+
* knows where the value it is asking about was set up. The walk
|
|
190
|
+
* follows imports outward from the value's own file, so a file that
|
|
191
|
+
* imports it, and passed something to the constructor, is somewhere
|
|
192
|
+
* the walk never reaches on its own.
|
|
193
|
+
*/
|
|
194
|
+
resolveCallable(value: Node, alsoFrom?: SourceFile): Node | null;
|
|
188
195
|
resolveObject(value: Node): Node | null;
|
|
189
196
|
/**
|
|
190
197
|
* For a value that is neither a function nor an object, such as a
|
|
@@ -382,8 +389,8 @@ interface DiscoveredUnit {
|
|
|
382
389
|
* shape for decorator-driven controllers).
|
|
383
390
|
*/
|
|
384
391
|
routeInfo?: {
|
|
385
|
-
method: string;
|
|
386
|
-
path: string;
|
|
392
|
+
method: string | null;
|
|
393
|
+
path: string | null;
|
|
387
394
|
};
|
|
388
395
|
/**
|
|
389
396
|
* Populated by a pack's `discoverUnits` callback for a message-bus
|
package/dist/index.js
CHANGED
|
@@ -3953,6 +3953,7 @@ import { Node as Node18 } from "ts-morph";
|
|
|
3953
3953
|
import { Node as Node17, SyntaxKind as SyntaxKind5, VariableDeclarationKind } from "ts-morph";
|
|
3954
3954
|
var byFile = createPerFileCache();
|
|
3955
3955
|
var byDeclaration = /* @__PURE__ */ new WeakMap();
|
|
3956
|
+
var byField = /* @__PURE__ */ new WeakMap();
|
|
3956
3957
|
function writesToBinding(declaration) {
|
|
3957
3958
|
const remembered = byDeclaration.get(declaration);
|
|
3958
3959
|
if (remembered !== void 0) {
|
|
@@ -3985,22 +3986,19 @@ function writesToBindingUncached(declaration) {
|
|
|
3985
3986
|
return { values, inOrder: writesRunInOrder(declaration, writes) };
|
|
3986
3987
|
}
|
|
3987
3988
|
function writesToField(declaration) {
|
|
3988
|
-
const remembered =
|
|
3989
|
+
const remembered = byField.get(declaration);
|
|
3989
3990
|
if (remembered !== void 0) {
|
|
3990
3991
|
return remembered;
|
|
3991
3992
|
}
|
|
3992
3993
|
const answer = writesToFieldUncached(declaration);
|
|
3993
|
-
|
|
3994
|
+
byField.set(declaration, answer);
|
|
3994
3995
|
return answer;
|
|
3995
3996
|
}
|
|
3996
3997
|
function writesToFieldUncached(declaration) {
|
|
3997
|
-
const
|
|
3998
|
+
const first = startingValueOf(declaration);
|
|
3998
3999
|
const assignments = assignmentsTo(declaration);
|
|
3999
4000
|
if (assignments.length === 0) {
|
|
4000
|
-
return {
|
|
4001
|
-
values: initializer === void 0 ? [] : [initializer],
|
|
4002
|
-
inOrder: true
|
|
4003
|
-
};
|
|
4001
|
+
return { values: first === void 0 ? [] : [first], inOrder: true };
|
|
4004
4002
|
}
|
|
4005
4003
|
const values = [];
|
|
4006
4004
|
for (const write of assignments) {
|
|
@@ -4009,14 +4007,16 @@ function writesToFieldUncached(declaration) {
|
|
|
4009
4007
|
}
|
|
4010
4008
|
values.push(write.value);
|
|
4011
4009
|
}
|
|
4012
|
-
const withInitializer = initializer === void 0 ? values : [initializer, ...values];
|
|
4013
4010
|
return {
|
|
4014
|
-
values:
|
|
4011
|
+
values: first === void 0 ? values : [first, ...values],
|
|
4015
4012
|
inOrder: assignments.every(
|
|
4016
4013
|
(write) => writeRunsInConstructor(declaration, write)
|
|
4017
4014
|
)
|
|
4018
4015
|
};
|
|
4019
4016
|
}
|
|
4017
|
+
function startingValueOf(declaration) {
|
|
4018
|
+
return Node17.isParameterDeclaration(declaration) ? declaration : declaration.getInitializer();
|
|
4019
|
+
}
|
|
4020
4020
|
function writeRunsInConstructor(declaration, write) {
|
|
4021
4021
|
const statement = statementOf(write.node);
|
|
4022
4022
|
if (statement === null) {
|
|
@@ -4027,13 +4027,16 @@ function writeRunsInConstructor(declaration, write) {
|
|
|
4027
4027
|
return false;
|
|
4028
4028
|
}
|
|
4029
4029
|
const owner = body.getParent();
|
|
4030
|
-
return owner !== void 0 && Node17.isConstructorDeclaration(owner) && owner.getParent() === declaration
|
|
4030
|
+
return owner !== void 0 && Node17.isConstructorDeclaration(owner) && owner.getParent() === classHolding(declaration);
|
|
4031
|
+
}
|
|
4032
|
+
function classHolding(declaration) {
|
|
4033
|
+
return Node17.isParameterDeclaration(declaration) ? declaration.getParent().getParent() : declaration.getParent();
|
|
4031
4034
|
}
|
|
4032
4035
|
function isWrittenAgain(declaration) {
|
|
4033
4036
|
return assignmentsTo(declaration).length > 0;
|
|
4034
4037
|
}
|
|
4035
4038
|
function assignmentsTo(declaration) {
|
|
4036
|
-
if (Node17.isPropertyDeclaration(declaration)) {
|
|
4039
|
+
if (Node17.isPropertyDeclaration(declaration) || Node17.isParameterDeclaration(declaration)) {
|
|
4037
4040
|
const sourceFile2 = declaration.getSourceFile();
|
|
4038
4041
|
return sourceFile2.isDeclarationFile() ? [] : assignmentsInFile(sourceFile2).get(declaration) ?? [];
|
|
4039
4042
|
}
|
|
@@ -4100,7 +4103,9 @@ function declarationsOf(name) {
|
|
|
4100
4103
|
}
|
|
4101
4104
|
const declarations = [];
|
|
4102
4105
|
for (const declaration of symbol.getDeclarations()) {
|
|
4103
|
-
if (Node17.isVariableDeclaration(declaration) || Node17.isPropertyDeclaration(declaration)
|
|
4106
|
+
if (Node17.isVariableDeclaration(declaration) || Node17.isPropertyDeclaration(declaration) || // A parameter property is the field's only declaration, so
|
|
4107
|
+
// `this.dao = other` in the constructor writes to it.
|
|
4108
|
+
Node17.isParameterDeclaration(declaration) && declaration.isParameterProperty()) {
|
|
4104
4109
|
declarations.push(declaration);
|
|
4105
4110
|
}
|
|
4106
4111
|
}
|
|
@@ -5884,7 +5889,8 @@ function createNodeTable() {
|
|
|
5884
5889
|
byId: /* @__PURE__ */ new Map(),
|
|
5885
5890
|
seenFunctions: /* @__PURE__ */ new Set(),
|
|
5886
5891
|
seenBindings: /* @__PURE__ */ new Set(),
|
|
5887
|
-
seenValues: /* @__PURE__ */ new Set()
|
|
5892
|
+
seenValues: /* @__PURE__ */ new Set(),
|
|
5893
|
+
seenClasses: /* @__PURE__ */ new Set()
|
|
5888
5894
|
};
|
|
5889
5895
|
}
|
|
5890
5896
|
function nodeId(node) {
|
|
@@ -6105,7 +6111,7 @@ function emitValue(db, table, value) {
|
|
|
6105
6111
|
}
|
|
6106
6112
|
return id;
|
|
6107
6113
|
}
|
|
6108
|
-
if (Node26.isCallExpression(expression)) {
|
|
6114
|
+
if (Node26.isCallExpression(expression) || Node26.isNewExpression(expression)) {
|
|
6109
6115
|
emitCallFacts(db, table, expression);
|
|
6110
6116
|
fact(db, "writtenValue", id);
|
|
6111
6117
|
return id;
|
|
@@ -6132,11 +6138,24 @@ function emitBindingValues(db, table, declaration) {
|
|
|
6132
6138
|
function emitFieldValues(db, table, declaration) {
|
|
6133
6139
|
const { values, inOrder } = writesToField(declaration);
|
|
6134
6140
|
const last = values[values.length - 1];
|
|
6135
|
-
if (!inOrder || last === void 0) {
|
|
6141
|
+
if (!inOrder || last === void 0 || !Node26.isExpression(last)) {
|
|
6136
6142
|
return;
|
|
6137
6143
|
}
|
|
6138
6144
|
fact(db, "binds", nodeId(declaration), emitValue(db, table, last));
|
|
6139
6145
|
}
|
|
6146
|
+
function emitParameterPropertyRead(db, table, referenceId, declaration) {
|
|
6147
|
+
const { values, inOrder } = writesToField(declaration);
|
|
6148
|
+
const last = values[values.length - 1];
|
|
6149
|
+
if (!inOrder || last === void 0) {
|
|
6150
|
+
return;
|
|
6151
|
+
}
|
|
6152
|
+
if (!Node26.isExpression(last)) {
|
|
6153
|
+
table.byId.set(nodeId(last), last);
|
|
6154
|
+
fact(db, "binds", referenceId, nodeId(last));
|
|
6155
|
+
return;
|
|
6156
|
+
}
|
|
6157
|
+
fact(db, "binds", referenceId, emitValue(db, table, last));
|
|
6158
|
+
}
|
|
6140
6159
|
function emitBindingElementFacts(db, table, element) {
|
|
6141
6160
|
const id = nodeId(element);
|
|
6142
6161
|
table.byId.set(id, element);
|
|
@@ -6218,7 +6237,16 @@ function emitReferenceFacts(db, table, reference) {
|
|
|
6218
6237
|
continue;
|
|
6219
6238
|
}
|
|
6220
6239
|
if (Node26.isParameterDeclaration(declaration)) {
|
|
6240
|
+
if (declaration.isParameterProperty() && Node26.isPropertyAccessExpression(reference)) {
|
|
6241
|
+
emitParameterPropertyRead(db, table, referenceId, declaration);
|
|
6242
|
+
} else {
|
|
6243
|
+
fact(db, "binds", referenceId, declarationId);
|
|
6244
|
+
}
|
|
6245
|
+
continue;
|
|
6246
|
+
}
|
|
6247
|
+
if (Node26.isClassDeclaration(declaration)) {
|
|
6221
6248
|
fact(db, "binds", referenceId, declarationId);
|
|
6249
|
+
emitClassFacts(db, table, declaration);
|
|
6222
6250
|
continue;
|
|
6223
6251
|
}
|
|
6224
6252
|
if (Node26.isBindingElement(declaration)) {
|
|
@@ -6263,9 +6291,14 @@ function emitCallFacts(db, table, call) {
|
|
|
6263
6291
|
}
|
|
6264
6292
|
}
|
|
6265
6293
|
function emitClassFacts(db, table, declaration) {
|
|
6294
|
+
if (table.seenClasses.has(declaration)) {
|
|
6295
|
+
return;
|
|
6296
|
+
}
|
|
6297
|
+
table.seenClasses.add(declaration);
|
|
6266
6298
|
const id = nodeId(declaration);
|
|
6267
6299
|
table.byId.set(id, declaration);
|
|
6268
6300
|
fact(db, "objectValue", id);
|
|
6301
|
+
emitConstructorParameters(db, table, declaration, id);
|
|
6269
6302
|
for (const method of declaration.getMethods()) {
|
|
6270
6303
|
const methodId = nodeId(method);
|
|
6271
6304
|
table.byId.set(methodId, method);
|
|
@@ -6286,6 +6319,25 @@ function emitClassFacts(db, table, declaration) {
|
|
|
6286
6319
|
}
|
|
6287
6320
|
}
|
|
6288
6321
|
}
|
|
6322
|
+
function emitConstructorParameters(db, table, declaration, classId) {
|
|
6323
|
+
const implementation = declaration.getConstructors().find((candidate) => candidate.getBody() !== void 0);
|
|
6324
|
+
if (implementation === void 0) {
|
|
6325
|
+
return;
|
|
6326
|
+
}
|
|
6327
|
+
emitParameters(db, table, classId, implementation.getParameters());
|
|
6328
|
+
}
|
|
6329
|
+
function emitParameters(db, table, ownerId, parameters) {
|
|
6330
|
+
for (let position = 0; position < parameters.length; position++) {
|
|
6331
|
+
const parameter = parameters[position];
|
|
6332
|
+
if (parameter === void 0) {
|
|
6333
|
+
continue;
|
|
6334
|
+
}
|
|
6335
|
+
const parameterId = nodeId(parameter);
|
|
6336
|
+
table.byId.set(parameterId, parameter);
|
|
6337
|
+
fact(db, "paramOf", ownerId, String(position), parameterId);
|
|
6338
|
+
fact(db, "paramNamed", ownerId, parameter.getName(), parameterId);
|
|
6339
|
+
}
|
|
6340
|
+
}
|
|
6289
6341
|
function emitFunctionFacts(db, table, fn) {
|
|
6290
6342
|
if (table.seenFunctions.has(fn)) {
|
|
6291
6343
|
return;
|
|
@@ -6294,17 +6346,7 @@ function emitFunctionFacts(db, table, fn) {
|
|
|
6294
6346
|
const fnId = nodeId(fn);
|
|
6295
6347
|
table.byId.set(fnId, fn);
|
|
6296
6348
|
if (Node26.isFunctionDeclaration(fn) || Node26.isFunctionExpression(fn) || Node26.isArrowFunction(fn) || Node26.isMethodDeclaration(fn)) {
|
|
6297
|
-
|
|
6298
|
-
for (let position = 0; position < parameters.length; position++) {
|
|
6299
|
-
const parameter = parameters[position];
|
|
6300
|
-
if (parameter === void 0) {
|
|
6301
|
-
continue;
|
|
6302
|
-
}
|
|
6303
|
-
const parameterId = nodeId(parameter);
|
|
6304
|
-
table.byId.set(parameterId, parameter);
|
|
6305
|
-
fact(db, "paramOf", fnId, String(position), parameterId);
|
|
6306
|
-
fact(db, "paramNamed", fnId, parameter.getName(), parameterId);
|
|
6307
|
-
}
|
|
6349
|
+
emitParameters(db, table, fnId, fn.getParameters());
|
|
6308
6350
|
const body = fn.getBody?.();
|
|
6309
6351
|
if (body !== void 0) {
|
|
6310
6352
|
if (Node26.isExpression(body)) {
|
|
@@ -10050,9 +10092,21 @@ var ResolutionStore = class {
|
|
|
10050
10092
|
this.db.add("wrapperModule", [wrapper.callee, wrapper.module]);
|
|
10051
10093
|
}
|
|
10052
10094
|
}
|
|
10053
|
-
|
|
10095
|
+
/**
|
|
10096
|
+
* `alsoFrom` is a second file to walk out from, for a caller that
|
|
10097
|
+
* knows where the value it is asking about was set up. The walk
|
|
10098
|
+
* follows imports outward from the value's own file, so a file that
|
|
10099
|
+
* imports it, and passed something to the constructor, is somewhere
|
|
10100
|
+
* the walk never reaches on its own.
|
|
10101
|
+
*/
|
|
10102
|
+
resolveCallable(value, alsoFrom) {
|
|
10054
10103
|
const target = factKeyOf(value);
|
|
10055
|
-
return this.resolveByWaves(
|
|
10104
|
+
return this.resolveByWaves(
|
|
10105
|
+
target,
|
|
10106
|
+
"wanted",
|
|
10107
|
+
() => this.lookup(target),
|
|
10108
|
+
alsoFrom
|
|
10109
|
+
);
|
|
10056
10110
|
}
|
|
10057
10111
|
resolveObject(value) {
|
|
10058
10112
|
const target = factKeyOf(value);
|
|
@@ -10120,18 +10174,18 @@ var ResolutionStore = class {
|
|
|
10120
10174
|
}
|
|
10121
10175
|
return origins.some((pair) => namesAPackage(pairHalves(pair).module)) ? [] : null;
|
|
10122
10176
|
}
|
|
10123
|
-
resolveByWaves(value, question, ask) {
|
|
10177
|
+
resolveByWaves(value, question, ask, alsoFrom) {
|
|
10124
10178
|
try {
|
|
10125
|
-
return this.walkForAnswer(value, question, ask);
|
|
10179
|
+
return this.walkForAnswer(value, question, ask, alsoFrom);
|
|
10126
10180
|
} finally {
|
|
10127
10181
|
this.forgetQuery();
|
|
10128
10182
|
}
|
|
10129
10183
|
}
|
|
10130
|
-
walkForAnswer(value, question, ask) {
|
|
10184
|
+
walkForAnswer(value, question, ask, alsoFrom) {
|
|
10131
10185
|
this.wantValue(question, value);
|
|
10132
10186
|
this.seedValue(value);
|
|
10133
10187
|
const walked = /* @__PURE__ */ new Set();
|
|
10134
|
-
let frontier = [value.getSourceFile()];
|
|
10188
|
+
let frontier = alsoFrom === void 0 ? [value.getSourceFile()] : [value.getSourceFile(), alsoFrom];
|
|
10135
10189
|
for (let hop = 0; hop <= MAX_MODULE_HOPS; hop++) {
|
|
10136
10190
|
const next = [];
|
|
10137
10191
|
for (const sourceFile of frontier) {
|
|
@@ -10655,24 +10709,41 @@ function declName(decl) {
|
|
|
10655
10709
|
}
|
|
10656
10710
|
return null;
|
|
10657
10711
|
}
|
|
10658
|
-
function resolveCallee(call, calleeName) {
|
|
10712
|
+
function resolveCallee(call, calleeName, scan) {
|
|
10659
10713
|
if (!Node49.isCallExpression(call)) {
|
|
10660
10714
|
return null;
|
|
10661
10715
|
}
|
|
10662
10716
|
const callee = call.getExpression();
|
|
10663
|
-
const
|
|
10664
|
-
|
|
10665
|
-
return null;
|
|
10666
|
-
}
|
|
10667
|
-
for (const decl of symbol.getDeclarations()) {
|
|
10717
|
+
const declarations = callee.getSymbol()?.getDeclarations() ?? [];
|
|
10718
|
+
for (const decl of declarations) {
|
|
10668
10719
|
const resolved = resolveDecl(decl, calleeName);
|
|
10669
10720
|
if (resolved !== null) {
|
|
10670
10721
|
return resolved;
|
|
10671
10722
|
}
|
|
10672
10723
|
}
|
|
10673
|
-
|
|
10724
|
+
if (scan.resolveCallable === void 0 || !readsAField(callee)) {
|
|
10725
|
+
return null;
|
|
10726
|
+
}
|
|
10727
|
+
if (!declarations.some(isDeclaredShape)) {
|
|
10728
|
+
return null;
|
|
10729
|
+
}
|
|
10730
|
+
const value = scan.resolveCallable(callee, scan.reachedFrom);
|
|
10731
|
+
return value === null ? null : resolveDecl(value, calleeName);
|
|
10674
10732
|
}
|
|
10675
|
-
function
|
|
10733
|
+
function readsAField(callee) {
|
|
10734
|
+
if (!Node49.isPropertyAccessExpression(callee)) {
|
|
10735
|
+
return false;
|
|
10736
|
+
}
|
|
10737
|
+
let receiver = callee.getExpression();
|
|
10738
|
+
while (Node49.isPropertyAccessExpression(receiver)) {
|
|
10739
|
+
receiver = receiver.getExpression();
|
|
10740
|
+
}
|
|
10741
|
+
return Node49.isThisExpression(receiver);
|
|
10742
|
+
}
|
|
10743
|
+
function isDeclaredShape(declaration) {
|
|
10744
|
+
return (Node49.isMethodSignature(declaration) || Node49.isPropertySignature(declaration)) && !isInExternalCode(declaration.getSourceFile());
|
|
10745
|
+
}
|
|
10746
|
+
function collectReachable(func, scan) {
|
|
10676
10747
|
const found = [];
|
|
10677
10748
|
const seen = /* @__PURE__ */ new Set();
|
|
10678
10749
|
func.forEachDescendant((node) => {
|
|
@@ -10680,7 +10751,7 @@ function collectReachable(func) {
|
|
|
10680
10751
|
return;
|
|
10681
10752
|
}
|
|
10682
10753
|
const calleeText = node.getExpression().getText();
|
|
10683
|
-
const resolved = resolveCallee(node, calleeText);
|
|
10754
|
+
const resolved = resolveCallee(node, calleeText, scan);
|
|
10684
10755
|
if (resolved === null) {
|
|
10685
10756
|
return;
|
|
10686
10757
|
}
|
|
@@ -10731,6 +10802,7 @@ function expandReachableClosure(seeds, project, options, projectFileSet, facts,
|
|
|
10731
10802
|
const functionByKey = /* @__PURE__ */ new Map();
|
|
10732
10803
|
const seedKeys = /* @__PURE__ */ new Set();
|
|
10733
10804
|
const scanned = /* @__PURE__ */ new Set();
|
|
10805
|
+
const reachedFrom = /* @__PURE__ */ new Map();
|
|
10734
10806
|
for (const seed of seeds) {
|
|
10735
10807
|
const func = lookup.functionAt(seed.location);
|
|
10736
10808
|
if (func !== null) {
|
|
@@ -10753,11 +10825,19 @@ function expandReachableClosure(seeds, project, options, projectFileSet, facts,
|
|
|
10753
10825
|
if (source === void 0) {
|
|
10754
10826
|
continue;
|
|
10755
10827
|
}
|
|
10756
|
-
|
|
10828
|
+
const cameFrom = reachedFrom.get(key);
|
|
10829
|
+
const scan = {
|
|
10830
|
+
...recognizers.resolveCallable === void 0 ? {} : { resolveCallable: recognizers.resolveCallable },
|
|
10831
|
+
...cameFrom === void 0 ? {} : { reachedFrom: cameFrom }
|
|
10832
|
+
};
|
|
10833
|
+
for (const candidate of collectReachable(source.func, scan)) {
|
|
10757
10834
|
const calleeKey = nodeKey2(candidate.func);
|
|
10758
10835
|
if (!functionByKey.has(calleeKey)) {
|
|
10759
10836
|
functionByKey.set(calleeKey, candidate);
|
|
10760
10837
|
}
|
|
10838
|
+
if (!reachedFrom.has(calleeKey)) {
|
|
10839
|
+
reachedFrom.set(calleeKey, source.func.getSourceFile());
|
|
10840
|
+
}
|
|
10761
10841
|
db.add("calls", [key, calleeKey]);
|
|
10762
10842
|
}
|
|
10763
10843
|
}
|
|
@@ -13152,7 +13232,8 @@ function createTypeScriptAdapter(config) {
|
|
|
13152
13232
|
tallies
|
|
13153
13233
|
),
|
|
13154
13234
|
access: collectAccessRecognizers(config.frameworks, tallies),
|
|
13155
|
-
resolveWrittenValue: (value) => resolution.resolveWrittenValue(value)
|
|
13235
|
+
resolveWrittenValue: (value) => resolution.resolveWrittenValue(value),
|
|
13236
|
+
resolveCallable: (value, alsoFrom) => resolution.resolveCallable(value, alsoFrom)
|
|
13156
13237
|
}
|
|
13157
13238
|
)
|
|
13158
13239
|
) : withSubUnits;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suss/adapter-typescript",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "TypeScript adapter for suss — walks source files with ts-morph and emits raw extractions for the suss pipeline.",
|
|
6
6
|
"keywords": [
|
|
@@ -46,10 +46,10 @@
|
|
|
46
46
|
"typecheck": "tsc --noEmit"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@suss/behavioral-ir": "0.
|
|
50
|
-
"@suss/datalog": "0.
|
|
51
|
-
"@suss/extractor": "0.
|
|
52
|
-
"@suss/resolution": "0.
|
|
49
|
+
"@suss/behavioral-ir": "0.8.0",
|
|
50
|
+
"@suss/datalog": "0.8.0",
|
|
51
|
+
"@suss/extractor": "0.8.0",
|
|
52
|
+
"@suss/resolution": "0.8.0",
|
|
53
53
|
"graphql": "^16.8.0",
|
|
54
54
|
"picomatch": "^4.0.4",
|
|
55
55
|
"ts-morph": "^23.0.0"
|