@suss/adapter-typescript 0.14.1 → 0.16.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 +507 -117
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +507 -117
- 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 Node58,
|
|
5
5
|
Project,
|
|
@@ -1827,8 +1827,8 @@ function loadImportGraphsDepthFirstFromPaths(project, rootPaths) {
|
|
|
1827
1827
|
stack.pop();
|
|
1828
1828
|
loadOrder.push(top.path);
|
|
1829
1829
|
let deepest = 0;
|
|
1830
|
-
for (const
|
|
1831
|
-
deepest = Math.max(deepest, chainDepth.get(
|
|
1830
|
+
for (const path13 of top.deps) {
|
|
1831
|
+
deepest = Math.max(deepest, chainDepth.get(path13) ?? 0);
|
|
1832
1832
|
}
|
|
1833
1833
|
chainDepth.set(top.path, deepest + 1);
|
|
1834
1834
|
}
|
|
@@ -2173,11 +2173,11 @@ function walkAndWarm(root, reach) {
|
|
|
2173
2173
|
if (warmedFiles.get(target) !== void 0) {
|
|
2174
2174
|
continue;
|
|
2175
2175
|
}
|
|
2176
|
-
const
|
|
2177
|
-
if (visited.has(
|
|
2176
|
+
const path13 = target.getFilePath();
|
|
2177
|
+
if (visited.has(path13)) {
|
|
2178
2178
|
continue;
|
|
2179
2179
|
}
|
|
2180
|
-
visited.add(
|
|
2180
|
+
visited.add(path13);
|
|
2181
2181
|
stack.push(frameOf(target, reach));
|
|
2182
2182
|
continue;
|
|
2183
2183
|
}
|
|
@@ -2194,7 +2194,7 @@ function sitsOnWarmChains(file) {
|
|
|
2194
2194
|
return false;
|
|
2195
2195
|
}
|
|
2196
2196
|
const imported = importedFilePathsOf(project, file.getFilePath());
|
|
2197
|
-
return imported.length > 0 && imported.every((
|
|
2197
|
+
return imported.length > 0 && imported.every((path13) => warmed.has(path13));
|
|
2198
2198
|
}
|
|
2199
2199
|
function markWarmed(file) {
|
|
2200
2200
|
warmedFiles.set(file, true);
|
|
@@ -2651,7 +2651,7 @@ var ORIGIN = {
|
|
|
2651
2651
|
declaredBy: (origin, receiver) => receiver.callee !== null && origin.importedFrom.some(
|
|
2652
2652
|
(module) => methodDeclaredIn(receiver.callee, module, receiver.resolve)
|
|
2653
2653
|
),
|
|
2654
|
-
constructed: (origin, receiver) => madeFromNamed(origin,
|
|
2654
|
+
constructed: (origin, receiver) => madeFromNamed(origin, madeExpression(receiver)) && origin.importedFrom.some(
|
|
2655
2655
|
(module) => isImportedFrom(madeBy(receiver), module)
|
|
2656
2656
|
)
|
|
2657
2657
|
};
|
|
@@ -2659,14 +2659,15 @@ function madeFromNamed(origin, made) {
|
|
|
2659
2659
|
if (origin.origin !== "constructed" || origin.named === void 0) {
|
|
2660
2660
|
return true;
|
|
2661
2661
|
}
|
|
2662
|
-
return origin.named.includes(made
|
|
2662
|
+
return origin.named.includes(constructorName(made));
|
|
2663
|
+
}
|
|
2664
|
+
function constructorName(made) {
|
|
2665
|
+
const expression = Node13.isNewExpression(made) || Node13.isCallExpression(made) ? made.getExpression() : made;
|
|
2666
|
+
return Node13.isPropertyAccessExpression(expression) ? expression.getName() : expression.getText();
|
|
2663
2667
|
}
|
|
2664
2668
|
var CALL_ORIGIN = {
|
|
2665
2669
|
declaredBy: ORIGIN.declaredBy,
|
|
2666
|
-
constructed: (origin, receiver) => madeFromNamed(
|
|
2667
|
-
origin,
|
|
2668
|
-
rootIdentifier(receiver.expression) ?? receiver.expression
|
|
2669
|
-
) && origin.importedFrom.some(
|
|
2670
|
+
constructed: (origin, receiver) => madeFromNamed(origin, receiver.expression) && origin.importedFrom.some(
|
|
2670
2671
|
(module) => isImportedFrom(
|
|
2671
2672
|
rootIdentifier(receiver.expression) ?? receiver.expression,
|
|
2672
2673
|
module
|
|
@@ -2674,14 +2675,19 @@ var CALL_ORIGIN = {
|
|
|
2674
2675
|
)
|
|
2675
2676
|
};
|
|
2676
2677
|
function madeBy(receiver) {
|
|
2678
|
+
const made = madeExpression(receiver);
|
|
2679
|
+
const expression = Node13.isNewExpression(made) || Node13.isCallExpression(made) ? made.getExpression() : made;
|
|
2680
|
+
return rootIdentifier(expression) ?? expression;
|
|
2681
|
+
}
|
|
2682
|
+
function madeExpression(receiver) {
|
|
2677
2683
|
if (receiver.callee === null) {
|
|
2678
|
-
return
|
|
2684
|
+
return receiver.expression;
|
|
2679
2685
|
}
|
|
2680
2686
|
const written = receiver.resolve(receiver.callee.getExpression());
|
|
2681
2687
|
if (written === null || !Node13.isNewExpression(written) && !Node13.isCallExpression(written)) {
|
|
2682
2688
|
return receiver.callee;
|
|
2683
2689
|
}
|
|
2684
|
-
return
|
|
2690
|
+
return written;
|
|
2685
2691
|
}
|
|
2686
2692
|
function callOpsFor(call, resolveWrittenValue) {
|
|
2687
2693
|
const resolve2 = resolveWrittenValue ?? (() => null);
|
|
@@ -2722,6 +2728,7 @@ function valueOpsFor(value, resolve2) {
|
|
|
2722
2728
|
flag: () => literalFlag(written()),
|
|
2723
2729
|
entries: (unsettled) => entriesOf(written(), unsettled, resolve2),
|
|
2724
2730
|
items: () => itemsOf(written(), resolve2),
|
|
2731
|
+
asArg: () => effectArgOf(written()),
|
|
2725
2732
|
property: (name) => {
|
|
2726
2733
|
const object = written();
|
|
2727
2734
|
const inside = Node13.isObjectLiteralExpression(object) ? initializerOf(object, name) : null;
|
|
@@ -3209,6 +3216,9 @@ var MAX_ARG_DEPTH = 8;
|
|
|
3209
3216
|
function extractArgs(call) {
|
|
3210
3217
|
return call.getArguments().map((arg) => extractArg(arg, MAX_ARG_DEPTH));
|
|
3211
3218
|
}
|
|
3219
|
+
function effectArgOf(node) {
|
|
3220
|
+
return extractArg(node, MAX_ARG_DEPTH);
|
|
3221
|
+
}
|
|
3212
3222
|
function extractArg(node, depth) {
|
|
3213
3223
|
if (Node14.isAsExpression(node) || Node14.isTypeAssertion(node) || Node14.isSatisfiesExpression(node) || Node14.isNonNullExpression(node)) {
|
|
3214
3224
|
return extractArg(node.getExpression(), depth);
|
|
@@ -5808,9 +5818,9 @@ function createSourceFileLookup(project) {
|
|
|
5808
5818
|
if (sf === null) {
|
|
5809
5819
|
return null;
|
|
5810
5820
|
}
|
|
5811
|
-
const
|
|
5812
|
-
const index = functionsByFile.get(
|
|
5813
|
-
functionsByFile.set(
|
|
5821
|
+
const path13 = sf.getFilePath();
|
|
5822
|
+
const index = functionsByFile.get(path13) ?? indexFunctions(sf);
|
|
5823
|
+
functionsByFile.set(path13, index);
|
|
5814
5824
|
return index.get(rangeKey(location.range)) ?? null;
|
|
5815
5825
|
}
|
|
5816
5826
|
};
|
|
@@ -6337,7 +6347,7 @@ function extractEndpointContract(endpointNode, pattern, framework) {
|
|
|
6337
6347
|
}
|
|
6338
6348
|
const responses = [];
|
|
6339
6349
|
let method;
|
|
6340
|
-
let
|
|
6350
|
+
let path13;
|
|
6341
6351
|
for (const prop of endpointNode.getProperties()) {
|
|
6342
6352
|
if (!Node27.isPropertyAssignment(prop)) {
|
|
6343
6353
|
continue;
|
|
@@ -6352,7 +6362,7 @@ function extractEndpointContract(endpointNode, pattern, framework) {
|
|
|
6352
6362
|
if (propName === pattern.pathProperty) {
|
|
6353
6363
|
const val = prop.getInitializer();
|
|
6354
6364
|
if (val !== void 0 && Node27.isStringLiteral(val)) {
|
|
6355
|
-
|
|
6365
|
+
path13 = val.getLiteralValue();
|
|
6356
6366
|
}
|
|
6357
6367
|
}
|
|
6358
6368
|
if (propName === pattern.responseExtraction.property) {
|
|
@@ -6376,10 +6386,10 @@ function extractEndpointContract(endpointNode, pattern, framework) {
|
|
|
6376
6386
|
if (responses.length === 0) {
|
|
6377
6387
|
return null;
|
|
6378
6388
|
}
|
|
6379
|
-
const boundaryBinding = method !== void 0 ||
|
|
6389
|
+
const boundaryBinding = method !== void 0 || path13 !== void 0 ? restBinding({
|
|
6380
6390
|
transport: "http",
|
|
6381
6391
|
method: method ?? null,
|
|
6382
|
-
path:
|
|
6392
|
+
path: path13 ?? null,
|
|
6383
6393
|
recognition: framework
|
|
6384
6394
|
}) : null;
|
|
6385
6395
|
return {
|
|
@@ -7848,6 +7858,31 @@ function constructionRef(node, localNames, resolution) {
|
|
|
7848
7858
|
// src/discovery/clientCall.ts
|
|
7849
7859
|
import path4 from "path";
|
|
7850
7860
|
import { Node as Node32 } from "ts-morph";
|
|
7861
|
+
|
|
7862
|
+
// src/discovery/resolveImport.ts
|
|
7863
|
+
function resolveImportedLocalName(sourceFile, importModule, importName) {
|
|
7864
|
+
for (const importDecl of sourceFile.getImportDeclarations()) {
|
|
7865
|
+
if (importDecl.getModuleSpecifierValue() !== importModule) {
|
|
7866
|
+
continue;
|
|
7867
|
+
}
|
|
7868
|
+
for (const named2 of importDecl.getNamedImports()) {
|
|
7869
|
+
if (named2.getName() === importName || named2.getAliasNode()?.getText() === importName) {
|
|
7870
|
+
return named2.getAliasNode()?.getText() ?? named2.getName();
|
|
7871
|
+
}
|
|
7872
|
+
}
|
|
7873
|
+
const defaultImport = importDecl.getDefaultImport();
|
|
7874
|
+
if (defaultImport !== void 0 && defaultImport.getText() === importName) {
|
|
7875
|
+
return defaultImport.getText();
|
|
7876
|
+
}
|
|
7877
|
+
const namespaceImport = importDecl.getNamespaceImport();
|
|
7878
|
+
if (namespaceImport !== void 0 && namespaceImport.getText() === importName) {
|
|
7879
|
+
return namespaceImport.getText();
|
|
7880
|
+
}
|
|
7881
|
+
}
|
|
7882
|
+
return null;
|
|
7883
|
+
}
|
|
7884
|
+
|
|
7885
|
+
// src/discovery/clientCall.ts
|
|
7851
7886
|
function discoverClientCalls(sourceFile, match, kind, resolution) {
|
|
7852
7887
|
const results = [];
|
|
7853
7888
|
const isGlobal = match.importModule === "global";
|
|
@@ -7866,7 +7901,7 @@ function discoverClientCalls(sourceFile, match, kind, resolution) {
|
|
|
7866
7901
|
if (!isGlobal && importedLocalName !== null) {
|
|
7867
7902
|
for (const varDecl of sourceFile.getVariableDeclarations()) {
|
|
7868
7903
|
const init = varDecl.getInitializer();
|
|
7869
|
-
if (init !== void 0 && Node32.isCallExpression(init) && isInstanceCreationCall(init, importedLocalName, match.factoryMethods)) {
|
|
7904
|
+
if (init !== void 0 && (Node32.isCallExpression(init) || Node32.isNewExpression(init)) && isInstanceCreationCall(init, importedLocalName, match.factoryMethods)) {
|
|
7870
7905
|
clientVarNames.add(varDecl.getName());
|
|
7871
7906
|
}
|
|
7872
7907
|
}
|
|
@@ -7911,12 +7946,50 @@ function discoverClientCalls(sourceFile, match, kind, resolution) {
|
|
|
7911
7946
|
});
|
|
7912
7947
|
return results;
|
|
7913
7948
|
}
|
|
7949
|
+
function clientReceiverCheckFor(sourceFile, match, resolution) {
|
|
7950
|
+
const localName = resolveImportedLocalName(
|
|
7951
|
+
sourceFile,
|
|
7952
|
+
match.importModule,
|
|
7953
|
+
match.importName
|
|
7954
|
+
);
|
|
7955
|
+
const constructedHere = /* @__PURE__ */ new Set();
|
|
7956
|
+
if (localName !== null) {
|
|
7957
|
+
sourceFile.forEachDescendant((node) => {
|
|
7958
|
+
if (Node32.isVariableDeclaration(node)) {
|
|
7959
|
+
const init = node.getInitializer();
|
|
7960
|
+
if (init !== void 0 && (Node32.isCallExpression(init) || Node32.isNewExpression(init)) && isInstanceCreationCall(init, localName, match.factoryMethods) || typedAsClient(node.getTypeNode(), localName)) {
|
|
7961
|
+
constructedHere.add(node.getName());
|
|
7962
|
+
}
|
|
7963
|
+
return;
|
|
7964
|
+
}
|
|
7965
|
+
if (Node32.isParameterDeclaration(node) && typedAsClient(node.getTypeNode(), localName)) {
|
|
7966
|
+
const written = node.getNameNode();
|
|
7967
|
+
if (Node32.isIdentifier(written)) {
|
|
7968
|
+
constructedHere.add(written.getText());
|
|
7969
|
+
}
|
|
7970
|
+
}
|
|
7971
|
+
});
|
|
7972
|
+
}
|
|
7973
|
+
const full = {
|
|
7974
|
+
type: "clientCall",
|
|
7975
|
+
importModule: match.importModule,
|
|
7976
|
+
importName: match.importName,
|
|
7977
|
+
...match.factoryMethods === void 0 ? {} : { factoryMethods: match.factoryMethods }
|
|
7978
|
+
};
|
|
7979
|
+
return (subject) => localName !== null && Node32.isIdentifier(subject) && subject.getText() === localName || Node32.isIdentifier(subject) && constructedHere.has(subject.getText()) || resolvesToKnownInstance(subject, full, resolution);
|
|
7980
|
+
}
|
|
7981
|
+
function typedAsClient(typeNode, localName) {
|
|
7982
|
+
if (typeNode === void 0 || !Node32.isTypeReference(typeNode)) {
|
|
7983
|
+
return false;
|
|
7984
|
+
}
|
|
7985
|
+
return typeNode.getTypeName().getText() === localName;
|
|
7986
|
+
}
|
|
7914
7987
|
function resolvesToKnownInstance(subject, match, resolution) {
|
|
7915
7988
|
if (resolution === void 0 || match.importModule === "global") {
|
|
7916
7989
|
return false;
|
|
7917
7990
|
}
|
|
7918
7991
|
const written = writtenNodeOf(subject, resolution);
|
|
7919
|
-
if (written === null || !Node32.isCallExpression(written)) {
|
|
7992
|
+
if (written === null || !Node32.isCallExpression(written) && !Node32.isNewExpression(written)) {
|
|
7920
7993
|
return false;
|
|
7921
7994
|
}
|
|
7922
7995
|
const writtenLocalName = resolvedImportLocalName(
|
|
@@ -8238,7 +8311,34 @@ function joinRoutePath(prefix, suffix) {
|
|
|
8238
8311
|
}
|
|
8239
8312
|
return `/${segments.join("/")}`;
|
|
8240
8313
|
}
|
|
8241
|
-
function
|
|
8314
|
+
function declaredChannelOf(source, decorator, resolution) {
|
|
8315
|
+
if (source.from === "literal") {
|
|
8316
|
+
return source.value;
|
|
8317
|
+
}
|
|
8318
|
+
if (source.from === "unstated") {
|
|
8319
|
+
return null;
|
|
8320
|
+
}
|
|
8321
|
+
if (!Node36.isDecorator(decorator)) {
|
|
8322
|
+
return null;
|
|
8323
|
+
}
|
|
8324
|
+
const arg = decorator.getArguments()[source.position];
|
|
8325
|
+
if (arg === void 0) {
|
|
8326
|
+
return null;
|
|
8327
|
+
}
|
|
8328
|
+
const text = literalStringOf(arg, resolution);
|
|
8329
|
+
return text === null || text === "" ? null : text;
|
|
8330
|
+
}
|
|
8331
|
+
function literalStringOf(node, resolution) {
|
|
8332
|
+
if (Node36.isStringLiteral(node) || Node36.isNoSubstitutionTemplateLiteral(node)) {
|
|
8333
|
+
return node.getLiteralValue();
|
|
8334
|
+
}
|
|
8335
|
+
const written = resolution?.resolveWrittenValue(node) ?? null;
|
|
8336
|
+
if (written === null || written === node) {
|
|
8337
|
+
return null;
|
|
8338
|
+
}
|
|
8339
|
+
return literalStringOf(written, resolution);
|
|
8340
|
+
}
|
|
8341
|
+
function discoverDecoratedRoutes(sourceFile, match, kind, resolution, binding) {
|
|
8242
8342
|
const acceptedModules = Array.isArray(match.importModule) ? match.importModule : [match.importModule];
|
|
8243
8343
|
const routeDecoratorNames = Object.keys(match.methodDecoratorRouteMap);
|
|
8244
8344
|
const importedRouteDecorators = /* @__PURE__ */ new Set();
|
|
@@ -8270,6 +8370,22 @@ function discoverDecoratedRoutes(sourceFile, match, kind, resolution) {
|
|
|
8270
8370
|
const pathPrefix = routePathOf(marker.args, resolution);
|
|
8271
8371
|
const className = cls.getName() ?? "<anon-class>";
|
|
8272
8372
|
for (const handler of decoratedCallablesOf(cls, routeDecoratorNames)) {
|
|
8373
|
+
if (binding !== void 0) {
|
|
8374
|
+
results.push({
|
|
8375
|
+
func: handler.func,
|
|
8376
|
+
kind,
|
|
8377
|
+
name: `${className}.${handler.name}`,
|
|
8378
|
+
channelInfo: {
|
|
8379
|
+
messageBus: binding.messageBus,
|
|
8380
|
+
channel: declaredChannelOf(
|
|
8381
|
+
binding.channel,
|
|
8382
|
+
handler.decorator,
|
|
8383
|
+
resolution
|
|
8384
|
+
)
|
|
8385
|
+
}
|
|
8386
|
+
});
|
|
8387
|
+
continue;
|
|
8388
|
+
}
|
|
8273
8389
|
const httpMethod = match.methodDecoratorRouteMap[handler.standsFor];
|
|
8274
8390
|
const pathSuffix = resolveRoutePathArg(handler.decorator, resolution);
|
|
8275
8391
|
const routePath = joinRoutePath(pathPrefix, pathSuffix);
|
|
@@ -9117,40 +9233,8 @@ function discoverGraphqlHookCalls(sourceFile, match, kind, resolution) {
|
|
|
9117
9233
|
|
|
9118
9234
|
// src/discovery/graphqlImperativeCall.ts
|
|
9119
9235
|
import { Node as Node40 } from "ts-morph";
|
|
9120
|
-
|
|
9121
|
-
// src/discovery/resolveImport.ts
|
|
9122
|
-
function resolveImportedLocalName(sourceFile, importModule, importName) {
|
|
9123
|
-
for (const importDecl of sourceFile.getImportDeclarations()) {
|
|
9124
|
-
if (importDecl.getModuleSpecifierValue() !== importModule) {
|
|
9125
|
-
continue;
|
|
9126
|
-
}
|
|
9127
|
-
for (const named2 of importDecl.getNamedImports()) {
|
|
9128
|
-
if (named2.getName() === importName || named2.getAliasNode()?.getText() === importName) {
|
|
9129
|
-
return named2.getAliasNode()?.getText() ?? named2.getName();
|
|
9130
|
-
}
|
|
9131
|
-
}
|
|
9132
|
-
const defaultImport = importDecl.getDefaultImport();
|
|
9133
|
-
if (defaultImport !== void 0 && defaultImport.getText() === importName) {
|
|
9134
|
-
return defaultImport.getText();
|
|
9135
|
-
}
|
|
9136
|
-
const namespaceImport = importDecl.getNamespaceImport();
|
|
9137
|
-
if (namespaceImport !== void 0 && namespaceImport.getText() === importName) {
|
|
9138
|
-
return namespaceImport.getText();
|
|
9139
|
-
}
|
|
9140
|
-
}
|
|
9141
|
-
return null;
|
|
9142
|
-
}
|
|
9143
|
-
|
|
9144
|
-
// src/discovery/graphqlImperativeCall.ts
|
|
9145
9236
|
function discoverGraphqlImperativeCalls(sourceFile, match, kind, resolution) {
|
|
9146
|
-
const
|
|
9147
|
-
sourceFile,
|
|
9148
|
-
match.importModule,
|
|
9149
|
-
match.importName
|
|
9150
|
-
);
|
|
9151
|
-
if (localName === null) {
|
|
9152
|
-
return [];
|
|
9153
|
-
}
|
|
9237
|
+
const isTheClient = clientReceiverCheckFor(sourceFile, match, resolution);
|
|
9154
9238
|
const methodSpec = /* @__PURE__ */ new Map();
|
|
9155
9239
|
for (const method of match.methods) {
|
|
9156
9240
|
methodSpec.set(method.methodName, {
|
|
@@ -9172,6 +9256,9 @@ function discoverGraphqlImperativeCalls(sourceFile, match, kind, resolution) {
|
|
|
9172
9256
|
if (spec === void 0) {
|
|
9173
9257
|
return;
|
|
9174
9258
|
}
|
|
9259
|
+
if (!isTheClient(callee.getExpression())) {
|
|
9260
|
+
return;
|
|
9261
|
+
}
|
|
9175
9262
|
const args = node.getArguments();
|
|
9176
9263
|
if (args.length === 0 || !Node40.isObjectLiteralExpression(args[0])) {
|
|
9177
9264
|
return;
|
|
@@ -9318,7 +9405,7 @@ function attributeValueOf(node, name) {
|
|
|
9318
9405
|
}
|
|
9319
9406
|
return null;
|
|
9320
9407
|
}
|
|
9321
|
-
function
|
|
9408
|
+
function literalStringOf2(value) {
|
|
9322
9409
|
const unwrapped2 = Node41.isJsxExpression(value) ? value.getExpression() ?? value : value;
|
|
9323
9410
|
if (Node41.isStringLiteral(unwrapped2) || Node41.isNoSubstitutionTemplateLiteral(unwrapped2)) {
|
|
9324
9411
|
return unwrapped2.getLiteralValue();
|
|
@@ -9328,7 +9415,7 @@ function literalStringOf(value) {
|
|
|
9328
9415
|
function ownPathOfJsx(node, match) {
|
|
9329
9416
|
const pathValue = attributeValueOf(node, match.pathAttribute);
|
|
9330
9417
|
if (pathValue !== null) {
|
|
9331
|
-
const literal =
|
|
9418
|
+
const literal = literalStringOf2(pathValue);
|
|
9332
9419
|
return literal !== null ? { kind: "literal", value: literal } : { kind: "unreadable" };
|
|
9333
9420
|
}
|
|
9334
9421
|
if (match.indexAttribute !== void 0 && attributeValueOf(node, match.indexAttribute) !== null) {
|
|
@@ -9419,14 +9506,14 @@ function unitForJsxRoute(node, match, routeNames, kind, resolution) {
|
|
|
9419
9506
|
}
|
|
9420
9507
|
return routeUnit(node, kind, match.method, resolved.path, target, resolution);
|
|
9421
9508
|
}
|
|
9422
|
-
function routeUnit(at, kind, method,
|
|
9423
|
-
const routeInfo = { method, path:
|
|
9509
|
+
function routeUnit(at, kind, method, path13, target, resolution) {
|
|
9510
|
+
const routeInfo = { method, path: path13 };
|
|
9424
9511
|
if (target.kind === "unreadable") {
|
|
9425
9512
|
return {
|
|
9426
9513
|
func: null,
|
|
9427
9514
|
announcedAt: at,
|
|
9428
9515
|
kind,
|
|
9429
|
-
name:
|
|
9516
|
+
name: path13,
|
|
9430
9517
|
nameKind: "label",
|
|
9431
9518
|
routeInfo
|
|
9432
9519
|
};
|
|
@@ -9596,7 +9683,7 @@ function unitsUnderRouteObject(object, match, kind, resolution, prefix, ancestry
|
|
|
9596
9683
|
function ownPathOfObject(object, match) {
|
|
9597
9684
|
const pathValue = routePropertyOf(object, match.pathAttribute);
|
|
9598
9685
|
if (pathValue !== null) {
|
|
9599
|
-
const literal =
|
|
9686
|
+
const literal = literalStringOf2(pathValue);
|
|
9600
9687
|
return literal !== null ? { kind: "literal", value: literal } : { kind: "unreadable" };
|
|
9601
9688
|
}
|
|
9602
9689
|
if (match.indexAttribute !== void 0) {
|
|
@@ -9856,6 +9943,9 @@ function resolvePackageExportsCached(packageJsonPath) {
|
|
|
9856
9943
|
return fresh;
|
|
9857
9944
|
}
|
|
9858
9945
|
function discoverPackageExports(sourceFile, match, kind) {
|
|
9946
|
+
if (match.packageJsonPath === void 0) {
|
|
9947
|
+
return [];
|
|
9948
|
+
}
|
|
9859
9949
|
const { entries } = resolvePackageExportsCached(match.packageJsonPath);
|
|
9860
9950
|
const filePath = sourceFile.getFilePath();
|
|
9861
9951
|
const matching = [];
|
|
@@ -10243,12 +10333,12 @@ function originEndOf(flattened) {
|
|
|
10243
10333
|
const slash = flattened.indexOf("/", opener[0].length);
|
|
10244
10334
|
return slash === -1 ? flattened.length : slash;
|
|
10245
10335
|
}
|
|
10246
|
-
function appendPathText(
|
|
10336
|
+
function appendPathText(path13, text) {
|
|
10247
10337
|
const idx = text.search(/[?#]/);
|
|
10248
10338
|
if (idx === -1) {
|
|
10249
|
-
return { path:
|
|
10339
|
+
return { path: path13 + text, stop: false };
|
|
10250
10340
|
}
|
|
10251
|
-
return { path:
|
|
10341
|
+
return { path: path13 + text.slice(0, idx), stop: true };
|
|
10252
10342
|
}
|
|
10253
10343
|
function parseAbsoluteUrl(text) {
|
|
10254
10344
|
try {
|
|
@@ -10272,8 +10362,8 @@ function pathnameOfAbsoluteLiteral(text) {
|
|
|
10272
10362
|
return stripQueryAndFragment(stripOriginManually(text));
|
|
10273
10363
|
}
|
|
10274
10364
|
function pathFromLiteralUrl(text) {
|
|
10275
|
-
const
|
|
10276
|
-
return
|
|
10365
|
+
const path13 = isAbsoluteUrlLiteral(text) ? pathnameOfAbsoluteLiteral(text) : stripQueryAndFragment(text);
|
|
10366
|
+
return path13 === "" ? void 0 : path13;
|
|
10277
10367
|
}
|
|
10278
10368
|
function pathFromTemplateUrl(arg, resolution) {
|
|
10279
10369
|
const headText = arg.getHead().getLiteralText();
|
|
@@ -10281,7 +10371,7 @@ function pathFromTemplateUrl(arg, resolution) {
|
|
|
10281
10371
|
const tails = spans.map((span) => span.getLiteral().getLiteralText());
|
|
10282
10372
|
const originEnd = originEndOf([headText, ...tails].join(SUBSTITUTION));
|
|
10283
10373
|
const head = appendPathText("", headText.slice(originEnd));
|
|
10284
|
-
let
|
|
10374
|
+
let path13 = head.path;
|
|
10285
10375
|
let stop = head.stop;
|
|
10286
10376
|
let at = headText.length;
|
|
10287
10377
|
for (let i = 0; i < spans.length && !stop; i++) {
|
|
@@ -10291,18 +10381,18 @@ function pathFromTemplateUrl(arg, resolution) {
|
|
|
10291
10381
|
continue;
|
|
10292
10382
|
}
|
|
10293
10383
|
if (at >= originEnd) {
|
|
10294
|
-
|
|
10384
|
+
path13 += holeText(span.getExpression(), resolution);
|
|
10295
10385
|
}
|
|
10296
10386
|
at += SUBSTITUTION.length;
|
|
10297
10387
|
const appended = appendPathText(
|
|
10298
|
-
|
|
10388
|
+
path13,
|
|
10299
10389
|
tailText.slice(Math.max(0, originEnd - at))
|
|
10300
10390
|
);
|
|
10301
|
-
|
|
10391
|
+
path13 = appended.path;
|
|
10302
10392
|
stop = appended.stop;
|
|
10303
10393
|
at += tailText.length;
|
|
10304
10394
|
}
|
|
10305
|
-
return
|
|
10395
|
+
return path13 === "" ? void 0 : path13;
|
|
10306
10396
|
}
|
|
10307
10397
|
function pathFromUrlNode(node, resolution) {
|
|
10308
10398
|
if (Node46.isStringLiteral(node)) {
|
|
@@ -10314,8 +10404,24 @@ function pathFromUrlNode(node, resolution) {
|
|
|
10314
10404
|
if (Node46.isTemplateExpression(node)) {
|
|
10315
10405
|
return pathFromTemplateUrl(node, resolution);
|
|
10316
10406
|
}
|
|
10407
|
+
if (Node46.isBinaryExpression(node)) {
|
|
10408
|
+
const joined = joinedStringOf(node, resolution);
|
|
10409
|
+
return joined === void 0 ? void 0 : pathFromLiteralUrl(joined);
|
|
10410
|
+
}
|
|
10317
10411
|
return void 0;
|
|
10318
10412
|
}
|
|
10413
|
+
function joinedStringOf(node, resolution) {
|
|
10414
|
+
if (Node46.isStringLiteral(node) || Node46.isNoSubstitutionTemplateLiteral(node)) {
|
|
10415
|
+
return node.getLiteralValue();
|
|
10416
|
+
}
|
|
10417
|
+
if (Node46.isBinaryExpression(node) && node.getOperatorToken().getText() === "+") {
|
|
10418
|
+
const left = joinedStringOf(node.getLeft(), resolution);
|
|
10419
|
+
const right = joinedStringOf(node.getRight(), resolution);
|
|
10420
|
+
return left === void 0 || right === void 0 ? void 0 : left + right;
|
|
10421
|
+
}
|
|
10422
|
+
const written = resolution?.resolveWrittenValue(node) ?? null;
|
|
10423
|
+
return written === null || written === node ? void 0 : joinedStringOf(written, resolution);
|
|
10424
|
+
}
|
|
10319
10425
|
function placeholderName(expr) {
|
|
10320
10426
|
if (Node46.isIdentifier(expr)) {
|
|
10321
10427
|
return expr.getText();
|
|
@@ -10453,9 +10559,9 @@ function withMountPrefix(routeInfo, subjectNode, mountPrefixes) {
|
|
|
10453
10559
|
const prefix = mountPrefixes.effectivePrefixFor(subjectNode);
|
|
10454
10560
|
return prefix === "" ? routeInfo : { ...routeInfo, path: joinMountedPath(prefix, routeInfo.path) };
|
|
10455
10561
|
}
|
|
10456
|
-
function joinMountedPath(prefix,
|
|
10562
|
+
function joinMountedPath(prefix, path13) {
|
|
10457
10563
|
const trimmed = prefix.endsWith("/") ? prefix.slice(0, -1) : prefix;
|
|
10458
|
-
return trimmed === "" ?
|
|
10564
|
+
return trimmed === "" ? path13 : trimmed + path13;
|
|
10459
10565
|
}
|
|
10460
10566
|
function registrationSubjectsOf(sourceFile, importModule, importName) {
|
|
10461
10567
|
let importedLocalName = null;
|
|
@@ -10619,11 +10725,11 @@ function extractRouteInfoFromBinding(call, methodName, binding, resolution) {
|
|
|
10619
10725
|
return null;
|
|
10620
10726
|
}
|
|
10621
10727
|
const method2 = stringProperty(routeObject, binding.method.property);
|
|
10622
|
-
const
|
|
10623
|
-
if (method2 === null ||
|
|
10728
|
+
const path14 = stringProperty(routeObject, binding.path.property);
|
|
10729
|
+
if (method2 === null || path14 === null) {
|
|
10624
10730
|
return null;
|
|
10625
10731
|
}
|
|
10626
|
-
return { method: method2.toUpperCase(), path:
|
|
10732
|
+
return { method: method2.toUpperCase(), path: path14 };
|
|
10627
10733
|
}
|
|
10628
10734
|
if (binding.method.type !== "fromRegistration" || binding.path.type !== "fromArgument") {
|
|
10629
10735
|
return null;
|
|
@@ -10640,26 +10746,46 @@ function extractRouteInfoFromBinding(call, methodName, binding, resolution) {
|
|
|
10640
10746
|
method = arg.getLiteralValue().toUpperCase();
|
|
10641
10747
|
}
|
|
10642
10748
|
const pathArg = call.getArguments()[binding.path.position];
|
|
10643
|
-
const
|
|
10644
|
-
return
|
|
10749
|
+
const path13 = pathArg === void 0 ? void 0 : pathFromArgument(pathArg, resolution);
|
|
10750
|
+
return path13 === void 0 ? null : { method, path: path13 };
|
|
10645
10751
|
}
|
|
10646
10752
|
|
|
10647
10753
|
// src/discovery/registrationLoop.ts
|
|
10648
10754
|
import { Node as Node48 } from "ts-morph";
|
|
10649
10755
|
function discoverRegistrationLoops(sourceFile, match, kind, resolution) {
|
|
10650
10756
|
const results = [];
|
|
10757
|
+
const routables = routableNames(sourceFile, match);
|
|
10758
|
+
if (routables !== null && routables.size === 0) {
|
|
10759
|
+
return results;
|
|
10760
|
+
}
|
|
10651
10761
|
sourceFile.forEachDescendant((node) => {
|
|
10652
10762
|
if (!Node48.isForOfStatement(node)) {
|
|
10653
10763
|
return;
|
|
10654
10764
|
}
|
|
10655
|
-
const expanded = tryExpandLoop(node, match, kind, resolution);
|
|
10765
|
+
const expanded = tryExpandLoop(node, match, kind, resolution, routables);
|
|
10656
10766
|
if (expanded !== null) {
|
|
10657
10767
|
results.push(...expanded);
|
|
10658
10768
|
}
|
|
10659
10769
|
});
|
|
10660
10770
|
return results;
|
|
10661
10771
|
}
|
|
10662
|
-
function
|
|
10772
|
+
function routableNames(sourceFile, match) {
|
|
10773
|
+
if (match.receiver === void 0) {
|
|
10774
|
+
return null;
|
|
10775
|
+
}
|
|
10776
|
+
const names = /* @__PURE__ */ new Set();
|
|
10777
|
+
for (const importName of match.receiver.importNames) {
|
|
10778
|
+
for (const name of registrationSubjectsOf(
|
|
10779
|
+
sourceFile,
|
|
10780
|
+
match.receiver.importModule,
|
|
10781
|
+
importName
|
|
10782
|
+
).keys()) {
|
|
10783
|
+
names.add(name);
|
|
10784
|
+
}
|
|
10785
|
+
}
|
|
10786
|
+
return names;
|
|
10787
|
+
}
|
|
10788
|
+
function tryExpandLoop(loop, match, kind, resolution, routables) {
|
|
10663
10789
|
const loopVar = loopVariableName(loop);
|
|
10664
10790
|
if (loopVar === null) {
|
|
10665
10791
|
return null;
|
|
@@ -10667,6 +10793,9 @@ function tryExpandLoop(loop, match, kind, resolution) {
|
|
|
10667
10793
|
if (!bodyReferencesLoopVar(loop, loopVar)) {
|
|
10668
10794
|
return null;
|
|
10669
10795
|
}
|
|
10796
|
+
if (routables !== null && !bodyCallsOn(loop, routables)) {
|
|
10797
|
+
return null;
|
|
10798
|
+
}
|
|
10670
10799
|
const arrayLit = arrayLiteralOf(loop.getExpression(), resolution);
|
|
10671
10800
|
if (arrayLit === null) {
|
|
10672
10801
|
return null;
|
|
@@ -10725,9 +10854,23 @@ function bodyReferencesLoopVar(loop, name) {
|
|
|
10725
10854
|
});
|
|
10726
10855
|
return referenced;
|
|
10727
10856
|
}
|
|
10857
|
+
function bodyCallsOn(loop, routables) {
|
|
10858
|
+
let found = false;
|
|
10859
|
+
loop.getStatement().forEachDescendant((node) => {
|
|
10860
|
+
if (found || !Node48.isCallExpression(node)) {
|
|
10861
|
+
return;
|
|
10862
|
+
}
|
|
10863
|
+
const callee = node.getExpression();
|
|
10864
|
+
const subject = Node48.isPropertyAccessExpression(callee) || Node48.isElementAccessExpression(callee) ? callee.getExpression() : null;
|
|
10865
|
+
if (subject !== null && Node48.isIdentifier(subject) && routables.has(subject.getText())) {
|
|
10866
|
+
found = true;
|
|
10867
|
+
}
|
|
10868
|
+
});
|
|
10869
|
+
return found;
|
|
10870
|
+
}
|
|
10728
10871
|
function readRouteSpec(element, shape, resolution) {
|
|
10729
10872
|
let method = null;
|
|
10730
|
-
let
|
|
10873
|
+
let path13 = null;
|
|
10731
10874
|
let handler = null;
|
|
10732
10875
|
for (const prop of element.getProperties()) {
|
|
10733
10876
|
if (Node48.isMethodDeclaration(prop) && prop.getName() === shape.handlerKey) {
|
|
@@ -10745,16 +10888,16 @@ function readRouteSpec(element, shape, resolution) {
|
|
|
10745
10888
|
if (name === shape.methodKey) {
|
|
10746
10889
|
method = readStringLiteralValue(init);
|
|
10747
10890
|
} else if (name === shape.pathKey) {
|
|
10748
|
-
|
|
10891
|
+
path13 = readStringLiteralValue(init);
|
|
10749
10892
|
} else if (name === shape.handlerKey) {
|
|
10750
10893
|
const func = functionValueOf(init, resolution);
|
|
10751
10894
|
handler = func === null ? null : { func, name: handlerName(init) };
|
|
10752
10895
|
}
|
|
10753
10896
|
}
|
|
10754
|
-
if (method === null ||
|
|
10897
|
+
if (method === null || path13 === null || handler === null) {
|
|
10755
10898
|
return null;
|
|
10756
10899
|
}
|
|
10757
|
-
return { method, path:
|
|
10900
|
+
return { method, path: path13, handler: handler.func, handlerName: handler.name };
|
|
10758
10901
|
}
|
|
10759
10902
|
function readStringLiteralValue(node) {
|
|
10760
10903
|
if (Node48.isStringLiteral(node) || Node48.isNoSubstitutionTemplateLiteral(node)) {
|
|
@@ -10783,8 +10926,8 @@ function discoverRegistrationTemplates(sourceFile, match, kind, resolution) {
|
|
|
10783
10926
|
}
|
|
10784
10927
|
const args = node.getArguments();
|
|
10785
10928
|
for (const reg of match.registrations) {
|
|
10786
|
-
const
|
|
10787
|
-
if (
|
|
10929
|
+
const path13 = substitutePath(reg.pathTemplate, args);
|
|
10930
|
+
if (path13 === null) {
|
|
10788
10931
|
continue;
|
|
10789
10932
|
}
|
|
10790
10933
|
const handler = resolveHandler(reg.handlerArg, args, resolution);
|
|
@@ -10797,7 +10940,7 @@ function discoverRegistrationTemplates(sourceFile, match, kind, resolution) {
|
|
|
10797
10940
|
name: handler.name,
|
|
10798
10941
|
routeInfo: {
|
|
10799
10942
|
method: reg.method.toUpperCase(),
|
|
10800
|
-
path:
|
|
10943
|
+
path: path13
|
|
10801
10944
|
}
|
|
10802
10945
|
});
|
|
10803
10946
|
}
|
|
@@ -11123,7 +11266,8 @@ function runPattern(sourceFile, pattern, resolution, mountPrefixes) {
|
|
|
11123
11266
|
sourceFile,
|
|
11124
11267
|
pattern.match,
|
|
11125
11268
|
pattern.kind,
|
|
11126
|
-
resolution
|
|
11269
|
+
resolution,
|
|
11270
|
+
pattern.binding
|
|
11127
11271
|
);
|
|
11128
11272
|
}
|
|
11129
11273
|
if (pattern.match.type === "jsxElementRoute") {
|
|
@@ -12411,7 +12555,38 @@ var REACHABLE_RULES = [
|
|
|
12411
12555
|
)
|
|
12412
12556
|
];
|
|
12413
12557
|
var NO_RECOGNIZERS = { invocation: [], access: [] };
|
|
12414
|
-
function
|
|
12558
|
+
function recognizerOnlyRoots(packsByFile) {
|
|
12559
|
+
const roots = [];
|
|
12560
|
+
for (const [sourceFile, packs] of packsByFile) {
|
|
12561
|
+
const recognizerOnly = packs.some(
|
|
12562
|
+
(pack) => pack.discovery.length === 0 && pack.discoverUnits === void 0 && ((pack.invocationRecognizers?.length ?? 0) > 0 || (pack.accessRecognizers?.length ?? 0) > 0)
|
|
12563
|
+
);
|
|
12564
|
+
if (!recognizerOnly) {
|
|
12565
|
+
continue;
|
|
12566
|
+
}
|
|
12567
|
+
for (const declaration of sourceFile.getFunctions()) {
|
|
12568
|
+
if (declaration.isExported() && hasBody(declaration)) {
|
|
12569
|
+
roots.push({
|
|
12570
|
+
func: declaration,
|
|
12571
|
+
name: declaration.getName() ?? "<anon>"
|
|
12572
|
+
});
|
|
12573
|
+
}
|
|
12574
|
+
}
|
|
12575
|
+
for (const variableStatement of sourceFile.getVariableStatements()) {
|
|
12576
|
+
if (!variableStatement.isExported()) {
|
|
12577
|
+
continue;
|
|
12578
|
+
}
|
|
12579
|
+
for (const declaration of variableStatement.getDeclarations()) {
|
|
12580
|
+
const init = declaration.getInitializer();
|
|
12581
|
+
if (init !== void 0 && (Node54.isArrowFunction(init) || Node54.isFunctionExpression(init)) && hasBody(init)) {
|
|
12582
|
+
roots.push({ func: init, name: declaration.getName() });
|
|
12583
|
+
}
|
|
12584
|
+
}
|
|
12585
|
+
}
|
|
12586
|
+
}
|
|
12587
|
+
return roots;
|
|
12588
|
+
}
|
|
12589
|
+
function expandReachableClosure(seeds, project, options, projectFileSet, facts, recognizers = NO_RECOGNIZERS, alreadySummarized = [], extraRoots = []) {
|
|
12415
12590
|
const lookup = createSourceFileLookup(project);
|
|
12416
12591
|
const db = facts?.db ?? new Database3();
|
|
12417
12592
|
const functionByKey = /* @__PURE__ */ new Map();
|
|
@@ -12431,6 +12606,13 @@ function expandReachableClosure(seeds, project, options, projectFileSet, facts,
|
|
|
12431
12606
|
db.add("entry", [key]);
|
|
12432
12607
|
}
|
|
12433
12608
|
}
|
|
12609
|
+
for (const root of extraRoots) {
|
|
12610
|
+
const key = nodeKey2(root.func);
|
|
12611
|
+
if (!functionByKey.has(key)) {
|
|
12612
|
+
functionByKey.set(key, root);
|
|
12613
|
+
}
|
|
12614
|
+
db.add("entry", [key]);
|
|
12615
|
+
}
|
|
12434
12616
|
const knownKeys = /* @__PURE__ */ new Set();
|
|
12435
12617
|
for (const summary of alreadySummarized) {
|
|
12436
12618
|
const func = lookup.functionAt(summary.location);
|
|
@@ -13498,6 +13680,185 @@ function computeAdapterPacksDigest(packVersions) {
|
|
|
13498
13680
|
return `${adapterStamp}|${sortedPacks.join(",")}`;
|
|
13499
13681
|
}
|
|
13500
13682
|
|
|
13683
|
+
// src/workspacePatterns.ts
|
|
13684
|
+
import { createHash as createHash4 } from "crypto";
|
|
13685
|
+
import fs8 from "fs";
|
|
13686
|
+
import path9 from "path";
|
|
13687
|
+
function readJson(filePath) {
|
|
13688
|
+
try {
|
|
13689
|
+
return JSON.parse(fs8.readFileSync(filePath, "utf8"));
|
|
13690
|
+
} catch {
|
|
13691
|
+
return void 0;
|
|
13692
|
+
}
|
|
13693
|
+
}
|
|
13694
|
+
function pnpmWorkspaceGlobs(yamlText) {
|
|
13695
|
+
const globs = [];
|
|
13696
|
+
let inPackages = false;
|
|
13697
|
+
for (const line of yamlText.split("\n")) {
|
|
13698
|
+
if (/^packages\s*:/.test(line)) {
|
|
13699
|
+
inPackages = true;
|
|
13700
|
+
continue;
|
|
13701
|
+
}
|
|
13702
|
+
if (inPackages) {
|
|
13703
|
+
const item = line.match(/^\s+-\s+["']?([^"'#\s]+)["']?/);
|
|
13704
|
+
if (item !== null) {
|
|
13705
|
+
globs.push(item[1]);
|
|
13706
|
+
continue;
|
|
13707
|
+
}
|
|
13708
|
+
if (/^\S/.test(line)) {
|
|
13709
|
+
inPackages = false;
|
|
13710
|
+
}
|
|
13711
|
+
}
|
|
13712
|
+
}
|
|
13713
|
+
return globs;
|
|
13714
|
+
}
|
|
13715
|
+
function workspaceGlobsAt(dir) {
|
|
13716
|
+
const pkg = readJson(path9.join(dir, "package.json"));
|
|
13717
|
+
if (typeof pkg === "object" && pkg !== null && "workspaces" in pkg) {
|
|
13718
|
+
const ws = pkg.workspaces;
|
|
13719
|
+
if (Array.isArray(ws)) {
|
|
13720
|
+
return ws.filter((g) => typeof g === "string");
|
|
13721
|
+
}
|
|
13722
|
+
if (typeof ws === "object" && ws !== null && Array.isArray(ws.packages)) {
|
|
13723
|
+
return ws.packages.filter(
|
|
13724
|
+
(g) => typeof g === "string"
|
|
13725
|
+
);
|
|
13726
|
+
}
|
|
13727
|
+
}
|
|
13728
|
+
const pnpmPath = path9.join(dir, "pnpm-workspace.yaml");
|
|
13729
|
+
if (fs8.existsSync(pnpmPath)) {
|
|
13730
|
+
try {
|
|
13731
|
+
return pnpmWorkspaceGlobs(fs8.readFileSync(pnpmPath, "utf8"));
|
|
13732
|
+
} catch {
|
|
13733
|
+
return null;
|
|
13734
|
+
}
|
|
13735
|
+
}
|
|
13736
|
+
return null;
|
|
13737
|
+
}
|
|
13738
|
+
function isDirectory(candidate) {
|
|
13739
|
+
try {
|
|
13740
|
+
return fs8.statSync(candidate).isDirectory();
|
|
13741
|
+
} catch {
|
|
13742
|
+
return false;
|
|
13743
|
+
}
|
|
13744
|
+
}
|
|
13745
|
+
function subdirectoriesOf(dir) {
|
|
13746
|
+
try {
|
|
13747
|
+
return fs8.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).filter((name) => !name.startsWith(".") && name !== "node_modules");
|
|
13748
|
+
} catch {
|
|
13749
|
+
return [];
|
|
13750
|
+
}
|
|
13751
|
+
}
|
|
13752
|
+
function segmentToRegExp(segment) {
|
|
13753
|
+
const escaped = segment.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
13754
|
+
return new RegExp(`^${escaped.replace(/\*/g, "[^/]*")}$`);
|
|
13755
|
+
}
|
|
13756
|
+
function directoriesMatchingGlob(root, glob) {
|
|
13757
|
+
let current2 = [root];
|
|
13758
|
+
for (const segment of glob.split("/").filter((s) => s.length > 0)) {
|
|
13759
|
+
const next = [];
|
|
13760
|
+
if (segment.includes("*")) {
|
|
13761
|
+
const pattern = segmentToRegExp(segment);
|
|
13762
|
+
for (const dir of current2) {
|
|
13763
|
+
for (const entry of subdirectoriesOf(dir)) {
|
|
13764
|
+
if (pattern.test(entry)) {
|
|
13765
|
+
next.push(path9.join(dir, entry));
|
|
13766
|
+
}
|
|
13767
|
+
}
|
|
13768
|
+
}
|
|
13769
|
+
} else {
|
|
13770
|
+
for (const dir of current2) {
|
|
13771
|
+
next.push(path9.join(dir, segment));
|
|
13772
|
+
}
|
|
13773
|
+
}
|
|
13774
|
+
current2 = next.filter(isDirectory);
|
|
13775
|
+
}
|
|
13776
|
+
return current2;
|
|
13777
|
+
}
|
|
13778
|
+
function packageAt(dir) {
|
|
13779
|
+
const packageJsonPath = path9.join(dir, "package.json");
|
|
13780
|
+
const pkg = readJson(packageJsonPath);
|
|
13781
|
+
if (typeof pkg === "object" && pkg !== null && typeof pkg.name === "string") {
|
|
13782
|
+
return { name: pkg.name, packageJsonPath };
|
|
13783
|
+
}
|
|
13784
|
+
return null;
|
|
13785
|
+
}
|
|
13786
|
+
function workspacePackagesFrom(anchor) {
|
|
13787
|
+
let dir = path9.resolve(anchor);
|
|
13788
|
+
for (; ; ) {
|
|
13789
|
+
const globs = workspaceGlobsAt(dir);
|
|
13790
|
+
if (globs !== null) {
|
|
13791
|
+
const found = /* @__PURE__ */ new Map();
|
|
13792
|
+
for (const glob of globs) {
|
|
13793
|
+
if (glob.startsWith("!")) {
|
|
13794
|
+
continue;
|
|
13795
|
+
}
|
|
13796
|
+
for (const match of directoriesMatchingGlob(dir, glob)) {
|
|
13797
|
+
const pkg = packageAt(match);
|
|
13798
|
+
if (pkg !== null) {
|
|
13799
|
+
found.set(pkg.packageJsonPath, pkg);
|
|
13800
|
+
}
|
|
13801
|
+
}
|
|
13802
|
+
}
|
|
13803
|
+
return [...found.values()].sort(
|
|
13804
|
+
(a, b) => a.packageJsonPath.localeCompare(b.packageJsonPath)
|
|
13805
|
+
);
|
|
13806
|
+
}
|
|
13807
|
+
const parent = path9.dirname(dir);
|
|
13808
|
+
if (parent === dir) {
|
|
13809
|
+
return [];
|
|
13810
|
+
}
|
|
13811
|
+
dir = parent;
|
|
13812
|
+
}
|
|
13813
|
+
}
|
|
13814
|
+
function isWorkspaceMarked(pattern) {
|
|
13815
|
+
const match = pattern.match;
|
|
13816
|
+
return (match.type === "packageExports" || match.type === "packageImport") && match.workspaces === true;
|
|
13817
|
+
}
|
|
13818
|
+
function expandPattern(pattern, packages) {
|
|
13819
|
+
const match = pattern.match;
|
|
13820
|
+
if (match.type === "packageExports" && match.workspaces === true) {
|
|
13821
|
+
const { workspaces: _workspaces, ...rest } = match;
|
|
13822
|
+
return packages.map((pkg) => ({
|
|
13823
|
+
...pattern,
|
|
13824
|
+
match: { ...rest, packageJsonPath: pkg.packageJsonPath }
|
|
13825
|
+
}));
|
|
13826
|
+
}
|
|
13827
|
+
if (match.type === "packageImport" && match.workspaces === true) {
|
|
13828
|
+
const listed = match.packages ?? [];
|
|
13829
|
+
const names = [.../* @__PURE__ */ new Set([...listed, ...packages.map((p) => p.name)])];
|
|
13830
|
+
if (names.length === 0) {
|
|
13831
|
+
return [];
|
|
13832
|
+
}
|
|
13833
|
+
return [{ ...pattern, match: { type: "packageImport", packages: names } }];
|
|
13834
|
+
}
|
|
13835
|
+
return [pattern];
|
|
13836
|
+
}
|
|
13837
|
+
function workspaceExpansionStamp(frameworks) {
|
|
13838
|
+
const paths = frameworks.flatMap((pack) => pack.discovery).flatMap(
|
|
13839
|
+
(pattern) => pattern.match.type === "packageExports" && pattern.match.packageJsonPath !== void 0 ? [pattern.match.packageJsonPath] : []
|
|
13840
|
+
).sort();
|
|
13841
|
+
if (paths.length === 0) {
|
|
13842
|
+
return "none";
|
|
13843
|
+
}
|
|
13844
|
+
return createHash4("sha256").update(paths.join("\n")).digest("hex").slice(0, 12);
|
|
13845
|
+
}
|
|
13846
|
+
function expandWorkspacePatterns(frameworks, anchor) {
|
|
13847
|
+
const marked = frameworks.some(
|
|
13848
|
+
(pack) => pack.discovery.some(isWorkspaceMarked)
|
|
13849
|
+
);
|
|
13850
|
+
if (!marked) {
|
|
13851
|
+
return frameworks;
|
|
13852
|
+
}
|
|
13853
|
+
const packages = anchor !== void 0 ? workspacePackagesFrom(anchor) : [];
|
|
13854
|
+
return frameworks.map((pack) => ({
|
|
13855
|
+
...pack,
|
|
13856
|
+
discovery: pack.discovery.flatMap(
|
|
13857
|
+
(pattern) => expandPattern(pattern, packages)
|
|
13858
|
+
)
|
|
13859
|
+
}));
|
|
13860
|
+
}
|
|
13861
|
+
|
|
13501
13862
|
// src/adapter.ts
|
|
13502
13863
|
var raise = (msg) => {
|
|
13503
13864
|
throw new Error(msg);
|
|
@@ -13908,11 +14269,11 @@ function extractConsumerBinding(unit, pattern, pack, resolution) {
|
|
|
13908
14269
|
return null;
|
|
13909
14270
|
}
|
|
13910
14271
|
const method = extractBindingMethod(binding, callSite, pack, resolution);
|
|
13911
|
-
const
|
|
14272
|
+
const path13 = extractBindingPath(binding, callSite, pack, resolution);
|
|
13912
14273
|
return restBinding2({
|
|
13913
14274
|
transport: pack.protocol,
|
|
13914
14275
|
method: method ?? null,
|
|
13915
|
-
path:
|
|
14276
|
+
path: path13 ?? null,
|
|
13916
14277
|
recognition: pack.name
|
|
13917
14278
|
});
|
|
13918
14279
|
}
|
|
@@ -14524,8 +14885,8 @@ function synthesizeCallerSummaries(wrapper, _project, options, resolution) {
|
|
|
14524
14885
|
if (pathArg === void 0) {
|
|
14525
14886
|
continue;
|
|
14526
14887
|
}
|
|
14527
|
-
const
|
|
14528
|
-
if (
|
|
14888
|
+
const path13 = pathFromArgument(pathArg, resolution);
|
|
14889
|
+
if (path13 === void 0) {
|
|
14529
14890
|
continue;
|
|
14530
14891
|
}
|
|
14531
14892
|
const callerFunc = enclosingFunction(callExpr);
|
|
@@ -14537,7 +14898,7 @@ function synthesizeCallerSummaries(wrapper, _project, options, resolution) {
|
|
|
14537
14898
|
continue;
|
|
14538
14899
|
}
|
|
14539
14900
|
seen.add(dedupKey);
|
|
14540
|
-
out.push(buildCallerSummary(wrapper, callerFunc, callExpr,
|
|
14901
|
+
out.push(buildCallerSummary(wrapper, callerFunc, callExpr, path13, options));
|
|
14541
14902
|
}
|
|
14542
14903
|
return out;
|
|
14543
14904
|
}
|
|
@@ -14594,7 +14955,7 @@ function callerName(func) {
|
|
|
14594
14955
|
}
|
|
14595
14956
|
return "anonymous";
|
|
14596
14957
|
}
|
|
14597
|
-
function buildCallerSummary(wrapper, callerFunc, callExpr,
|
|
14958
|
+
function buildCallerSummary(wrapper, callerFunc, callExpr, path13, options) {
|
|
14598
14959
|
const wrapperBinding = wrapper.summary.identity.boundaryBinding;
|
|
14599
14960
|
const wrapperRest = wrapperBinding?.semantics.name === "rest" ? wrapperBinding.semantics : null;
|
|
14600
14961
|
const syntheticPack = {
|
|
@@ -14626,7 +14987,7 @@ function buildCallerSummary(wrapper, callerFunc, callExpr, path12, options) {
|
|
|
14626
14987
|
raw.boundaryBinding = restBinding2({
|
|
14627
14988
|
transport: wrapperBinding?.transport ?? "http",
|
|
14628
14989
|
method: wrapperRest?.method ?? null,
|
|
14629
|
-
path:
|
|
14990
|
+
path: path13,
|
|
14630
14991
|
recognition: wrapperBinding?.recognition ?? "unknown"
|
|
14631
14992
|
});
|
|
14632
14993
|
const summary = assembleSummary3(raw, options);
|
|
@@ -14692,25 +15053,32 @@ function loadRunFiles(project, candidatePaths, timer) {
|
|
|
14692
15053
|
);
|
|
14693
15054
|
return { sourceFiles, deep };
|
|
14694
15055
|
}
|
|
14695
|
-
function createTypeScriptAdapter(
|
|
15056
|
+
function createTypeScriptAdapter(suppliedConfig) {
|
|
15057
|
+
const config = {
|
|
15058
|
+
...suppliedConfig,
|
|
15059
|
+
frameworks: expandWorkspacePatterns(
|
|
15060
|
+
suppliedConfig.frameworks,
|
|
15061
|
+
suppliedConfig.projectRoot ?? (suppliedConfig.tsConfigFilePath !== void 0 ? path10.dirname(suppliedConfig.tsConfigFilePath) : void 0)
|
|
15062
|
+
)
|
|
15063
|
+
};
|
|
14696
15064
|
const project = config.project ?? new Project(
|
|
14697
15065
|
config.tsConfigFilePath !== void 0 ? {
|
|
14698
15066
|
tsConfigFilePath: config.tsConfigFilePath,
|
|
14699
15067
|
skipAddingFilesFromTsConfig: true
|
|
14700
15068
|
} : { skipAddingFilesFromTsConfig: true }
|
|
14701
15069
|
);
|
|
14702
|
-
const runRoot = config.projectRoot ?? (config.tsConfigFilePath !== void 0 ? workspaceRootFor(
|
|
15070
|
+
const runRoot = config.projectRoot ?? (config.tsConfigFilePath !== void 0 ? workspaceRootFor(path10.dirname(config.tsConfigFilePath)) : void 0);
|
|
14703
15071
|
let lazyBootstrapped = false;
|
|
14704
15072
|
let projectFileSet;
|
|
14705
15073
|
const cacheDir = declineWhenRunFromSource(
|
|
14706
|
-
config.cacheDir === null ? null : config.cacheDir ?? (config.tsConfigFilePath !== void 0 ?
|
|
15074
|
+
config.cacheDir === null ? null : config.cacheDir ?? (config.tsConfigFilePath !== void 0 ? path10.join(path10.dirname(config.tsConfigFilePath), ".suss", "cache") : null)
|
|
14707
15075
|
);
|
|
14708
15076
|
const cache = createCacheLayer(cacheDir);
|
|
14709
15077
|
const adapterPacksDigest = `${computeAdapterPacksDigest(
|
|
14710
15078
|
config.frameworks.map(
|
|
14711
15079
|
(p) => p.version !== void 0 ? { name: p.name, version: p.version } : { name: p.name }
|
|
14712
15080
|
)
|
|
14713
|
-
)}|${extractionConfigStamp(config)}`;
|
|
15081
|
+
)}|${extractionConfigStamp(config)}|ws:${workspaceExpansionStamp(config.frameworks)}`;
|
|
14714
15082
|
const packWrappers = config.frameworks.flatMap(
|
|
14715
15083
|
(pack) => pack.transparentWrappers ?? []
|
|
14716
15084
|
);
|
|
@@ -14946,7 +15314,12 @@ function createTypeScriptAdapter(config) {
|
|
|
14946
15314
|
},
|
|
14947
15315
|
// Reached units the cache already serves emit nothing,
|
|
14948
15316
|
// the way a cold run's seeds do not.
|
|
14949
|
-
reused?.summaries ?? []
|
|
15317
|
+
reused?.summaries ?? [],
|
|
15318
|
+
// A recognizer-only pack's effects need a function to
|
|
15319
|
+
// live on even when nothing discovers units in its
|
|
15320
|
+
// files, so those files' exports join the walk as
|
|
15321
|
+
// roots.
|
|
15322
|
+
recognizerOnlyRoots(packsByFile)
|
|
14950
15323
|
)
|
|
14951
15324
|
) : withSubUnits;
|
|
14952
15325
|
const closureOwnership = caching && config.includeReachable !== false ? timer.time(
|
|
@@ -15343,8 +15716,8 @@ function buildSubUnitSummary(subUnit, parent, invocationRecognizers, accessRecog
|
|
|
15343
15716
|
}
|
|
15344
15717
|
|
|
15345
15718
|
// src/bootstrap/noTsconfigProject.ts
|
|
15346
|
-
import
|
|
15347
|
-
import
|
|
15719
|
+
import fs9 from "fs";
|
|
15720
|
+
import path11 from "path";
|
|
15348
15721
|
import {
|
|
15349
15722
|
ModuleKind,
|
|
15350
15723
|
ModuleResolutionKind,
|
|
@@ -15380,7 +15753,7 @@ function findSourceFiles(rootDir, depth = 0) {
|
|
|
15380
15753
|
const found = [];
|
|
15381
15754
|
let entries;
|
|
15382
15755
|
try {
|
|
15383
|
-
entries =
|
|
15756
|
+
entries = fs9.readdirSync(rootDir, { withFileTypes: true });
|
|
15384
15757
|
} catch {
|
|
15385
15758
|
return [];
|
|
15386
15759
|
}
|
|
@@ -15388,10 +15761,10 @@ function findSourceFiles(rootDir, depth = 0) {
|
|
|
15388
15761
|
if (entry.name.startsWith(".") || SKIP_DIRECTORIES.has(entry.name)) {
|
|
15389
15762
|
continue;
|
|
15390
15763
|
}
|
|
15391
|
-
const full =
|
|
15764
|
+
const full = path11.join(rootDir, entry.name);
|
|
15392
15765
|
if (entry.isDirectory()) {
|
|
15393
15766
|
found.push(...findSourceFiles(full, depth + 1));
|
|
15394
|
-
} else if (SOURCE_EXTENSIONS.has(
|
|
15767
|
+
} else if (SOURCE_EXTENSIONS.has(path11.extname(entry.name)) && !entry.name.endsWith(".d.ts")) {
|
|
15395
15768
|
found.push(full);
|
|
15396
15769
|
}
|
|
15397
15770
|
}
|
|
@@ -15426,15 +15799,15 @@ function createProjectWithoutTsconfig(rootDir) {
|
|
|
15426
15799
|
return { project, files };
|
|
15427
15800
|
}
|
|
15428
15801
|
function findNearestTsconfig(startDir) {
|
|
15429
|
-
let dir =
|
|
15802
|
+
let dir = path11.resolve(startDir);
|
|
15430
15803
|
while (true) {
|
|
15431
15804
|
for (const name of ["tsconfig.json", "jsconfig.json"]) {
|
|
15432
|
-
const candidate =
|
|
15433
|
-
if (
|
|
15805
|
+
const candidate = path11.join(dir, name);
|
|
15806
|
+
if (fs9.existsSync(candidate)) {
|
|
15434
15807
|
return candidate;
|
|
15435
15808
|
}
|
|
15436
15809
|
}
|
|
15437
|
-
const parent =
|
|
15810
|
+
const parent = path11.dirname(dir);
|
|
15438
15811
|
if (parent === dir) {
|
|
15439
15812
|
return null;
|
|
15440
15813
|
}
|
|
@@ -15443,7 +15816,7 @@ function findNearestTsconfig(startDir) {
|
|
|
15443
15816
|
}
|
|
15444
15817
|
|
|
15445
15818
|
// src/facts/why.ts
|
|
15446
|
-
import
|
|
15819
|
+
import path12 from "path";
|
|
15447
15820
|
import { Node as Node59, Project as Project3, SyntaxKind as SyntaxKind13 } from "ts-morph";
|
|
15448
15821
|
import { explainResolutionProof, renderExplanation } from "@suss/resolution";
|
|
15449
15822
|
var JS_PHRASES = {
|
|
@@ -15456,7 +15829,7 @@ var WhySession = class {
|
|
|
15456
15829
|
store;
|
|
15457
15830
|
root;
|
|
15458
15831
|
constructor(options) {
|
|
15459
|
-
this.root =
|
|
15832
|
+
this.root = path12.resolve(options.dir);
|
|
15460
15833
|
const tsconfig = findNearestTsconfig(this.root);
|
|
15461
15834
|
this.project = tsconfig === null ? createProjectWithoutTsconfig(this.root).project : new Project3({ tsConfigFilePath: tsconfig });
|
|
15462
15835
|
this.store = new ResolutionStore();
|
|
@@ -15545,7 +15918,7 @@ var WhySession = class {
|
|
|
15545
15918
|
};
|
|
15546
15919
|
}
|
|
15547
15920
|
sourceFileAt(file) {
|
|
15548
|
-
const absolute =
|
|
15921
|
+
const absolute = path12.resolve(this.root, file);
|
|
15549
15922
|
const loaded = this.project.getSourceFile(absolute);
|
|
15550
15923
|
if (loaded !== void 0) {
|
|
15551
15924
|
return loaded;
|
|
@@ -15559,7 +15932,7 @@ var WhySession = class {
|
|
|
15559
15932
|
/** A module key: a file path said relative to the root, or a package name. */
|
|
15560
15933
|
displayPath(key) {
|
|
15561
15934
|
if (key.startsWith(this.root)) {
|
|
15562
|
-
return
|
|
15935
|
+
return path12.relative(this.root, key);
|
|
15563
15936
|
}
|
|
15564
15937
|
return key;
|
|
15565
15938
|
}
|
|
@@ -15630,6 +16003,17 @@ function funnelDrops(packs) {
|
|
|
15630
16003
|
}
|
|
15631
16004
|
return violations;
|
|
15632
16005
|
}
|
|
16006
|
+
function recognizersWithNoUnits(packs) {
|
|
16007
|
+
return packs.filter(
|
|
16008
|
+
(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
|
|
16009
|
+
// roots, so effects recognized there mean the run worked and
|
|
16010
|
+
// the missing framework pack costs attribution, not existence.
|
|
16011
|
+
funnel.effectsRecognized === 0
|
|
16012
|
+
).map((funnel) => ({
|
|
16013
|
+
label: funnel.pack,
|
|
16014
|
+
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.`
|
|
16015
|
+
}));
|
|
16016
|
+
}
|
|
15633
16017
|
function unversionedPacks(packs) {
|
|
15634
16018
|
return packs.filter((funnel) => funnel.version === null).map((funnel) => ({
|
|
15635
16019
|
label: funnel.pack,
|
|
@@ -15724,6 +16108,12 @@ function evaluatePackHealth(report) {
|
|
|
15724
16108
|
audience: "run",
|
|
15725
16109
|
violations: selfCollisions(report.packs)
|
|
15726
16110
|
},
|
|
16111
|
+
{
|
|
16112
|
+
name: "every recognizer had units to look inside",
|
|
16113
|
+
code: "no-units",
|
|
16114
|
+
audience: "run",
|
|
16115
|
+
violations: recognizersWithNoUnits(report.packs)
|
|
16116
|
+
},
|
|
15727
16117
|
{
|
|
15728
16118
|
name: "every pack declares a version",
|
|
15729
16119
|
code: "no-version",
|