@suss/adapter-typescript 0.15.0 → 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 +365 -72
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +365 -72
- 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);
|
|
@@ -5818,9 +5818,9 @@ function createSourceFileLookup(project) {
|
|
|
5818
5818
|
if (sf === null) {
|
|
5819
5819
|
return null;
|
|
5820
5820
|
}
|
|
5821
|
-
const
|
|
5822
|
-
const index = functionsByFile.get(
|
|
5823
|
-
functionsByFile.set(
|
|
5821
|
+
const path13 = sf.getFilePath();
|
|
5822
|
+
const index = functionsByFile.get(path13) ?? indexFunctions(sf);
|
|
5823
|
+
functionsByFile.set(path13, index);
|
|
5824
5824
|
return index.get(rangeKey(location.range)) ?? null;
|
|
5825
5825
|
}
|
|
5826
5826
|
};
|
|
@@ -6347,7 +6347,7 @@ function extractEndpointContract(endpointNode, pattern, framework) {
|
|
|
6347
6347
|
}
|
|
6348
6348
|
const responses = [];
|
|
6349
6349
|
let method;
|
|
6350
|
-
let
|
|
6350
|
+
let path13;
|
|
6351
6351
|
for (const prop of endpointNode.getProperties()) {
|
|
6352
6352
|
if (!Node27.isPropertyAssignment(prop)) {
|
|
6353
6353
|
continue;
|
|
@@ -6362,7 +6362,7 @@ function extractEndpointContract(endpointNode, pattern, framework) {
|
|
|
6362
6362
|
if (propName === pattern.pathProperty) {
|
|
6363
6363
|
const val = prop.getInitializer();
|
|
6364
6364
|
if (val !== void 0 && Node27.isStringLiteral(val)) {
|
|
6365
|
-
|
|
6365
|
+
path13 = val.getLiteralValue();
|
|
6366
6366
|
}
|
|
6367
6367
|
}
|
|
6368
6368
|
if (propName === pattern.responseExtraction.property) {
|
|
@@ -6386,10 +6386,10 @@ function extractEndpointContract(endpointNode, pattern, framework) {
|
|
|
6386
6386
|
if (responses.length === 0) {
|
|
6387
6387
|
return null;
|
|
6388
6388
|
}
|
|
6389
|
-
const boundaryBinding = method !== void 0 ||
|
|
6389
|
+
const boundaryBinding = method !== void 0 || path13 !== void 0 ? restBinding({
|
|
6390
6390
|
transport: "http",
|
|
6391
6391
|
method: method ?? null,
|
|
6392
|
-
path:
|
|
6392
|
+
path: path13 ?? null,
|
|
6393
6393
|
recognition: framework
|
|
6394
6394
|
}) : null;
|
|
6395
6395
|
return {
|
|
@@ -8311,7 +8311,34 @@ function joinRoutePath(prefix, suffix) {
|
|
|
8311
8311
|
}
|
|
8312
8312
|
return `/${segments.join("/")}`;
|
|
8313
8313
|
}
|
|
8314
|
-
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) {
|
|
8315
8342
|
const acceptedModules = Array.isArray(match.importModule) ? match.importModule : [match.importModule];
|
|
8316
8343
|
const routeDecoratorNames = Object.keys(match.methodDecoratorRouteMap);
|
|
8317
8344
|
const importedRouteDecorators = /* @__PURE__ */ new Set();
|
|
@@ -8343,6 +8370,22 @@ function discoverDecoratedRoutes(sourceFile, match, kind, resolution) {
|
|
|
8343
8370
|
const pathPrefix = routePathOf(marker.args, resolution);
|
|
8344
8371
|
const className = cls.getName() ?? "<anon-class>";
|
|
8345
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
|
+
}
|
|
8346
8389
|
const httpMethod = match.methodDecoratorRouteMap[handler.standsFor];
|
|
8347
8390
|
const pathSuffix = resolveRoutePathArg(handler.decorator, resolution);
|
|
8348
8391
|
const routePath = joinRoutePath(pathPrefix, pathSuffix);
|
|
@@ -9362,7 +9405,7 @@ function attributeValueOf(node, name) {
|
|
|
9362
9405
|
}
|
|
9363
9406
|
return null;
|
|
9364
9407
|
}
|
|
9365
|
-
function
|
|
9408
|
+
function literalStringOf2(value) {
|
|
9366
9409
|
const unwrapped2 = Node41.isJsxExpression(value) ? value.getExpression() ?? value : value;
|
|
9367
9410
|
if (Node41.isStringLiteral(unwrapped2) || Node41.isNoSubstitutionTemplateLiteral(unwrapped2)) {
|
|
9368
9411
|
return unwrapped2.getLiteralValue();
|
|
@@ -9372,7 +9415,7 @@ function literalStringOf(value) {
|
|
|
9372
9415
|
function ownPathOfJsx(node, match) {
|
|
9373
9416
|
const pathValue = attributeValueOf(node, match.pathAttribute);
|
|
9374
9417
|
if (pathValue !== null) {
|
|
9375
|
-
const literal =
|
|
9418
|
+
const literal = literalStringOf2(pathValue);
|
|
9376
9419
|
return literal !== null ? { kind: "literal", value: literal } : { kind: "unreadable" };
|
|
9377
9420
|
}
|
|
9378
9421
|
if (match.indexAttribute !== void 0 && attributeValueOf(node, match.indexAttribute) !== null) {
|
|
@@ -9463,14 +9506,14 @@ function unitForJsxRoute(node, match, routeNames, kind, resolution) {
|
|
|
9463
9506
|
}
|
|
9464
9507
|
return routeUnit(node, kind, match.method, resolved.path, target, resolution);
|
|
9465
9508
|
}
|
|
9466
|
-
function routeUnit(at, kind, method,
|
|
9467
|
-
const routeInfo = { method, path:
|
|
9509
|
+
function routeUnit(at, kind, method, path13, target, resolution) {
|
|
9510
|
+
const routeInfo = { method, path: path13 };
|
|
9468
9511
|
if (target.kind === "unreadable") {
|
|
9469
9512
|
return {
|
|
9470
9513
|
func: null,
|
|
9471
9514
|
announcedAt: at,
|
|
9472
9515
|
kind,
|
|
9473
|
-
name:
|
|
9516
|
+
name: path13,
|
|
9474
9517
|
nameKind: "label",
|
|
9475
9518
|
routeInfo
|
|
9476
9519
|
};
|
|
@@ -9640,7 +9683,7 @@ function unitsUnderRouteObject(object, match, kind, resolution, prefix, ancestry
|
|
|
9640
9683
|
function ownPathOfObject(object, match) {
|
|
9641
9684
|
const pathValue = routePropertyOf(object, match.pathAttribute);
|
|
9642
9685
|
if (pathValue !== null) {
|
|
9643
|
-
const literal =
|
|
9686
|
+
const literal = literalStringOf2(pathValue);
|
|
9644
9687
|
return literal !== null ? { kind: "literal", value: literal } : { kind: "unreadable" };
|
|
9645
9688
|
}
|
|
9646
9689
|
if (match.indexAttribute !== void 0) {
|
|
@@ -9900,6 +9943,9 @@ function resolvePackageExportsCached(packageJsonPath) {
|
|
|
9900
9943
|
return fresh;
|
|
9901
9944
|
}
|
|
9902
9945
|
function discoverPackageExports(sourceFile, match, kind) {
|
|
9946
|
+
if (match.packageJsonPath === void 0) {
|
|
9947
|
+
return [];
|
|
9948
|
+
}
|
|
9903
9949
|
const { entries } = resolvePackageExportsCached(match.packageJsonPath);
|
|
9904
9950
|
const filePath = sourceFile.getFilePath();
|
|
9905
9951
|
const matching = [];
|
|
@@ -10287,12 +10333,12 @@ function originEndOf(flattened) {
|
|
|
10287
10333
|
const slash = flattened.indexOf("/", opener[0].length);
|
|
10288
10334
|
return slash === -1 ? flattened.length : slash;
|
|
10289
10335
|
}
|
|
10290
|
-
function appendPathText(
|
|
10336
|
+
function appendPathText(path13, text) {
|
|
10291
10337
|
const idx = text.search(/[?#]/);
|
|
10292
10338
|
if (idx === -1) {
|
|
10293
|
-
return { path:
|
|
10339
|
+
return { path: path13 + text, stop: false };
|
|
10294
10340
|
}
|
|
10295
|
-
return { path:
|
|
10341
|
+
return { path: path13 + text.slice(0, idx), stop: true };
|
|
10296
10342
|
}
|
|
10297
10343
|
function parseAbsoluteUrl(text) {
|
|
10298
10344
|
try {
|
|
@@ -10316,8 +10362,8 @@ function pathnameOfAbsoluteLiteral(text) {
|
|
|
10316
10362
|
return stripQueryAndFragment(stripOriginManually(text));
|
|
10317
10363
|
}
|
|
10318
10364
|
function pathFromLiteralUrl(text) {
|
|
10319
|
-
const
|
|
10320
|
-
return
|
|
10365
|
+
const path13 = isAbsoluteUrlLiteral(text) ? pathnameOfAbsoluteLiteral(text) : stripQueryAndFragment(text);
|
|
10366
|
+
return path13 === "" ? void 0 : path13;
|
|
10321
10367
|
}
|
|
10322
10368
|
function pathFromTemplateUrl(arg, resolution) {
|
|
10323
10369
|
const headText = arg.getHead().getLiteralText();
|
|
@@ -10325,7 +10371,7 @@ function pathFromTemplateUrl(arg, resolution) {
|
|
|
10325
10371
|
const tails = spans.map((span) => span.getLiteral().getLiteralText());
|
|
10326
10372
|
const originEnd = originEndOf([headText, ...tails].join(SUBSTITUTION));
|
|
10327
10373
|
const head = appendPathText("", headText.slice(originEnd));
|
|
10328
|
-
let
|
|
10374
|
+
let path13 = head.path;
|
|
10329
10375
|
let stop = head.stop;
|
|
10330
10376
|
let at = headText.length;
|
|
10331
10377
|
for (let i = 0; i < spans.length && !stop; i++) {
|
|
@@ -10335,18 +10381,18 @@ function pathFromTemplateUrl(arg, resolution) {
|
|
|
10335
10381
|
continue;
|
|
10336
10382
|
}
|
|
10337
10383
|
if (at >= originEnd) {
|
|
10338
|
-
|
|
10384
|
+
path13 += holeText(span.getExpression(), resolution);
|
|
10339
10385
|
}
|
|
10340
10386
|
at += SUBSTITUTION.length;
|
|
10341
10387
|
const appended = appendPathText(
|
|
10342
|
-
|
|
10388
|
+
path13,
|
|
10343
10389
|
tailText.slice(Math.max(0, originEnd - at))
|
|
10344
10390
|
);
|
|
10345
|
-
|
|
10391
|
+
path13 = appended.path;
|
|
10346
10392
|
stop = appended.stop;
|
|
10347
10393
|
at += tailText.length;
|
|
10348
10394
|
}
|
|
10349
|
-
return
|
|
10395
|
+
return path13 === "" ? void 0 : path13;
|
|
10350
10396
|
}
|
|
10351
10397
|
function pathFromUrlNode(node, resolution) {
|
|
10352
10398
|
if (Node46.isStringLiteral(node)) {
|
|
@@ -10513,9 +10559,9 @@ function withMountPrefix(routeInfo, subjectNode, mountPrefixes) {
|
|
|
10513
10559
|
const prefix = mountPrefixes.effectivePrefixFor(subjectNode);
|
|
10514
10560
|
return prefix === "" ? routeInfo : { ...routeInfo, path: joinMountedPath(prefix, routeInfo.path) };
|
|
10515
10561
|
}
|
|
10516
|
-
function joinMountedPath(prefix,
|
|
10562
|
+
function joinMountedPath(prefix, path13) {
|
|
10517
10563
|
const trimmed = prefix.endsWith("/") ? prefix.slice(0, -1) : prefix;
|
|
10518
|
-
return trimmed === "" ?
|
|
10564
|
+
return trimmed === "" ? path13 : trimmed + path13;
|
|
10519
10565
|
}
|
|
10520
10566
|
function registrationSubjectsOf(sourceFile, importModule, importName) {
|
|
10521
10567
|
let importedLocalName = null;
|
|
@@ -10679,11 +10725,11 @@ function extractRouteInfoFromBinding(call, methodName, binding, resolution) {
|
|
|
10679
10725
|
return null;
|
|
10680
10726
|
}
|
|
10681
10727
|
const method2 = stringProperty(routeObject, binding.method.property);
|
|
10682
|
-
const
|
|
10683
|
-
if (method2 === null ||
|
|
10728
|
+
const path14 = stringProperty(routeObject, binding.path.property);
|
|
10729
|
+
if (method2 === null || path14 === null) {
|
|
10684
10730
|
return null;
|
|
10685
10731
|
}
|
|
10686
|
-
return { method: method2.toUpperCase(), path:
|
|
10732
|
+
return { method: method2.toUpperCase(), path: path14 };
|
|
10687
10733
|
}
|
|
10688
10734
|
if (binding.method.type !== "fromRegistration" || binding.path.type !== "fromArgument") {
|
|
10689
10735
|
return null;
|
|
@@ -10700,8 +10746,8 @@ function extractRouteInfoFromBinding(call, methodName, binding, resolution) {
|
|
|
10700
10746
|
method = arg.getLiteralValue().toUpperCase();
|
|
10701
10747
|
}
|
|
10702
10748
|
const pathArg = call.getArguments()[binding.path.position];
|
|
10703
|
-
const
|
|
10704
|
-
return
|
|
10749
|
+
const path13 = pathArg === void 0 ? void 0 : pathFromArgument(pathArg, resolution);
|
|
10750
|
+
return path13 === void 0 ? null : { method, path: path13 };
|
|
10705
10751
|
}
|
|
10706
10752
|
|
|
10707
10753
|
// src/discovery/registrationLoop.ts
|
|
@@ -10824,7 +10870,7 @@ function bodyCallsOn(loop, routables) {
|
|
|
10824
10870
|
}
|
|
10825
10871
|
function readRouteSpec(element, shape, resolution) {
|
|
10826
10872
|
let method = null;
|
|
10827
|
-
let
|
|
10873
|
+
let path13 = null;
|
|
10828
10874
|
let handler = null;
|
|
10829
10875
|
for (const prop of element.getProperties()) {
|
|
10830
10876
|
if (Node48.isMethodDeclaration(prop) && prop.getName() === shape.handlerKey) {
|
|
@@ -10842,16 +10888,16 @@ function readRouteSpec(element, shape, resolution) {
|
|
|
10842
10888
|
if (name === shape.methodKey) {
|
|
10843
10889
|
method = readStringLiteralValue(init);
|
|
10844
10890
|
} else if (name === shape.pathKey) {
|
|
10845
|
-
|
|
10891
|
+
path13 = readStringLiteralValue(init);
|
|
10846
10892
|
} else if (name === shape.handlerKey) {
|
|
10847
10893
|
const func = functionValueOf(init, resolution);
|
|
10848
10894
|
handler = func === null ? null : { func, name: handlerName(init) };
|
|
10849
10895
|
}
|
|
10850
10896
|
}
|
|
10851
|
-
if (method === null ||
|
|
10897
|
+
if (method === null || path13 === null || handler === null) {
|
|
10852
10898
|
return null;
|
|
10853
10899
|
}
|
|
10854
|
-
return { method, path:
|
|
10900
|
+
return { method, path: path13, handler: handler.func, handlerName: handler.name };
|
|
10855
10901
|
}
|
|
10856
10902
|
function readStringLiteralValue(node) {
|
|
10857
10903
|
if (Node48.isStringLiteral(node) || Node48.isNoSubstitutionTemplateLiteral(node)) {
|
|
@@ -10880,8 +10926,8 @@ function discoverRegistrationTemplates(sourceFile, match, kind, resolution) {
|
|
|
10880
10926
|
}
|
|
10881
10927
|
const args = node.getArguments();
|
|
10882
10928
|
for (const reg of match.registrations) {
|
|
10883
|
-
const
|
|
10884
|
-
if (
|
|
10929
|
+
const path13 = substitutePath(reg.pathTemplate, args);
|
|
10930
|
+
if (path13 === null) {
|
|
10885
10931
|
continue;
|
|
10886
10932
|
}
|
|
10887
10933
|
const handler = resolveHandler(reg.handlerArg, args, resolution);
|
|
@@ -10894,7 +10940,7 @@ function discoverRegistrationTemplates(sourceFile, match, kind, resolution) {
|
|
|
10894
10940
|
name: handler.name,
|
|
10895
10941
|
routeInfo: {
|
|
10896
10942
|
method: reg.method.toUpperCase(),
|
|
10897
|
-
path:
|
|
10943
|
+
path: path13
|
|
10898
10944
|
}
|
|
10899
10945
|
});
|
|
10900
10946
|
}
|
|
@@ -11220,7 +11266,8 @@ function runPattern(sourceFile, pattern, resolution, mountPrefixes) {
|
|
|
11220
11266
|
sourceFile,
|
|
11221
11267
|
pattern.match,
|
|
11222
11268
|
pattern.kind,
|
|
11223
|
-
resolution
|
|
11269
|
+
resolution,
|
|
11270
|
+
pattern.binding
|
|
11224
11271
|
);
|
|
11225
11272
|
}
|
|
11226
11273
|
if (pattern.match.type === "jsxElementRoute") {
|
|
@@ -12508,7 +12555,38 @@ var REACHABLE_RULES = [
|
|
|
12508
12555
|
)
|
|
12509
12556
|
];
|
|
12510
12557
|
var NO_RECOGNIZERS = { invocation: [], access: [] };
|
|
12511
|
-
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 = []) {
|
|
12512
12590
|
const lookup = createSourceFileLookup(project);
|
|
12513
12591
|
const db = facts?.db ?? new Database3();
|
|
12514
12592
|
const functionByKey = /* @__PURE__ */ new Map();
|
|
@@ -12528,6 +12606,13 @@ function expandReachableClosure(seeds, project, options, projectFileSet, facts,
|
|
|
12528
12606
|
db.add("entry", [key]);
|
|
12529
12607
|
}
|
|
12530
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
|
+
}
|
|
12531
12616
|
const knownKeys = /* @__PURE__ */ new Set();
|
|
12532
12617
|
for (const summary of alreadySummarized) {
|
|
12533
12618
|
const func = lookup.functionAt(summary.location);
|
|
@@ -13595,6 +13680,185 @@ function computeAdapterPacksDigest(packVersions) {
|
|
|
13595
13680
|
return `${adapterStamp}|${sortedPacks.join(",")}`;
|
|
13596
13681
|
}
|
|
13597
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
|
+
|
|
13598
13862
|
// src/adapter.ts
|
|
13599
13863
|
var raise = (msg) => {
|
|
13600
13864
|
throw new Error(msg);
|
|
@@ -14005,11 +14269,11 @@ function extractConsumerBinding(unit, pattern, pack, resolution) {
|
|
|
14005
14269
|
return null;
|
|
14006
14270
|
}
|
|
14007
14271
|
const method = extractBindingMethod(binding, callSite, pack, resolution);
|
|
14008
|
-
const
|
|
14272
|
+
const path13 = extractBindingPath(binding, callSite, pack, resolution);
|
|
14009
14273
|
return restBinding2({
|
|
14010
14274
|
transport: pack.protocol,
|
|
14011
14275
|
method: method ?? null,
|
|
14012
|
-
path:
|
|
14276
|
+
path: path13 ?? null,
|
|
14013
14277
|
recognition: pack.name
|
|
14014
14278
|
});
|
|
14015
14279
|
}
|
|
@@ -14621,8 +14885,8 @@ function synthesizeCallerSummaries(wrapper, _project, options, resolution) {
|
|
|
14621
14885
|
if (pathArg === void 0) {
|
|
14622
14886
|
continue;
|
|
14623
14887
|
}
|
|
14624
|
-
const
|
|
14625
|
-
if (
|
|
14888
|
+
const path13 = pathFromArgument(pathArg, resolution);
|
|
14889
|
+
if (path13 === void 0) {
|
|
14626
14890
|
continue;
|
|
14627
14891
|
}
|
|
14628
14892
|
const callerFunc = enclosingFunction(callExpr);
|
|
@@ -14634,7 +14898,7 @@ function synthesizeCallerSummaries(wrapper, _project, options, resolution) {
|
|
|
14634
14898
|
continue;
|
|
14635
14899
|
}
|
|
14636
14900
|
seen.add(dedupKey);
|
|
14637
|
-
out.push(buildCallerSummary(wrapper, callerFunc, callExpr,
|
|
14901
|
+
out.push(buildCallerSummary(wrapper, callerFunc, callExpr, path13, options));
|
|
14638
14902
|
}
|
|
14639
14903
|
return out;
|
|
14640
14904
|
}
|
|
@@ -14691,7 +14955,7 @@ function callerName(func) {
|
|
|
14691
14955
|
}
|
|
14692
14956
|
return "anonymous";
|
|
14693
14957
|
}
|
|
14694
|
-
function buildCallerSummary(wrapper, callerFunc, callExpr,
|
|
14958
|
+
function buildCallerSummary(wrapper, callerFunc, callExpr, path13, options) {
|
|
14695
14959
|
const wrapperBinding = wrapper.summary.identity.boundaryBinding;
|
|
14696
14960
|
const wrapperRest = wrapperBinding?.semantics.name === "rest" ? wrapperBinding.semantics : null;
|
|
14697
14961
|
const syntheticPack = {
|
|
@@ -14723,7 +14987,7 @@ function buildCallerSummary(wrapper, callerFunc, callExpr, path12, options) {
|
|
|
14723
14987
|
raw.boundaryBinding = restBinding2({
|
|
14724
14988
|
transport: wrapperBinding?.transport ?? "http",
|
|
14725
14989
|
method: wrapperRest?.method ?? null,
|
|
14726
|
-
path:
|
|
14990
|
+
path: path13,
|
|
14727
14991
|
recognition: wrapperBinding?.recognition ?? "unknown"
|
|
14728
14992
|
});
|
|
14729
14993
|
const summary = assembleSummary3(raw, options);
|
|
@@ -14789,25 +15053,32 @@ function loadRunFiles(project, candidatePaths, timer) {
|
|
|
14789
15053
|
);
|
|
14790
15054
|
return { sourceFiles, deep };
|
|
14791
15055
|
}
|
|
14792
|
-
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
|
+
};
|
|
14793
15064
|
const project = config.project ?? new Project(
|
|
14794
15065
|
config.tsConfigFilePath !== void 0 ? {
|
|
14795
15066
|
tsConfigFilePath: config.tsConfigFilePath,
|
|
14796
15067
|
skipAddingFilesFromTsConfig: true
|
|
14797
15068
|
} : { skipAddingFilesFromTsConfig: true }
|
|
14798
15069
|
);
|
|
14799
|
-
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);
|
|
14800
15071
|
let lazyBootstrapped = false;
|
|
14801
15072
|
let projectFileSet;
|
|
14802
15073
|
const cacheDir = declineWhenRunFromSource(
|
|
14803
|
-
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)
|
|
14804
15075
|
);
|
|
14805
15076
|
const cache = createCacheLayer(cacheDir);
|
|
14806
15077
|
const adapterPacksDigest = `${computeAdapterPacksDigest(
|
|
14807
15078
|
config.frameworks.map(
|
|
14808
15079
|
(p) => p.version !== void 0 ? { name: p.name, version: p.version } : { name: p.name }
|
|
14809
15080
|
)
|
|
14810
|
-
)}|${extractionConfigStamp(config)}`;
|
|
15081
|
+
)}|${extractionConfigStamp(config)}|ws:${workspaceExpansionStamp(config.frameworks)}`;
|
|
14811
15082
|
const packWrappers = config.frameworks.flatMap(
|
|
14812
15083
|
(pack) => pack.transparentWrappers ?? []
|
|
14813
15084
|
);
|
|
@@ -15043,7 +15314,12 @@ function createTypeScriptAdapter(config) {
|
|
|
15043
15314
|
},
|
|
15044
15315
|
// Reached units the cache already serves emit nothing,
|
|
15045
15316
|
// the way a cold run's seeds do not.
|
|
15046
|
-
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)
|
|
15047
15323
|
)
|
|
15048
15324
|
) : withSubUnits;
|
|
15049
15325
|
const closureOwnership = caching && config.includeReachable !== false ? timer.time(
|
|
@@ -15440,8 +15716,8 @@ function buildSubUnitSummary(subUnit, parent, invocationRecognizers, accessRecog
|
|
|
15440
15716
|
}
|
|
15441
15717
|
|
|
15442
15718
|
// src/bootstrap/noTsconfigProject.ts
|
|
15443
|
-
import
|
|
15444
|
-
import
|
|
15719
|
+
import fs9 from "fs";
|
|
15720
|
+
import path11 from "path";
|
|
15445
15721
|
import {
|
|
15446
15722
|
ModuleKind,
|
|
15447
15723
|
ModuleResolutionKind,
|
|
@@ -15477,7 +15753,7 @@ function findSourceFiles(rootDir, depth = 0) {
|
|
|
15477
15753
|
const found = [];
|
|
15478
15754
|
let entries;
|
|
15479
15755
|
try {
|
|
15480
|
-
entries =
|
|
15756
|
+
entries = fs9.readdirSync(rootDir, { withFileTypes: true });
|
|
15481
15757
|
} catch {
|
|
15482
15758
|
return [];
|
|
15483
15759
|
}
|
|
@@ -15485,10 +15761,10 @@ function findSourceFiles(rootDir, depth = 0) {
|
|
|
15485
15761
|
if (entry.name.startsWith(".") || SKIP_DIRECTORIES.has(entry.name)) {
|
|
15486
15762
|
continue;
|
|
15487
15763
|
}
|
|
15488
|
-
const full =
|
|
15764
|
+
const full = path11.join(rootDir, entry.name);
|
|
15489
15765
|
if (entry.isDirectory()) {
|
|
15490
15766
|
found.push(...findSourceFiles(full, depth + 1));
|
|
15491
|
-
} else if (SOURCE_EXTENSIONS.has(
|
|
15767
|
+
} else if (SOURCE_EXTENSIONS.has(path11.extname(entry.name)) && !entry.name.endsWith(".d.ts")) {
|
|
15492
15768
|
found.push(full);
|
|
15493
15769
|
}
|
|
15494
15770
|
}
|
|
@@ -15523,15 +15799,15 @@ function createProjectWithoutTsconfig(rootDir) {
|
|
|
15523
15799
|
return { project, files };
|
|
15524
15800
|
}
|
|
15525
15801
|
function findNearestTsconfig(startDir) {
|
|
15526
|
-
let dir =
|
|
15802
|
+
let dir = path11.resolve(startDir);
|
|
15527
15803
|
while (true) {
|
|
15528
15804
|
for (const name of ["tsconfig.json", "jsconfig.json"]) {
|
|
15529
|
-
const candidate =
|
|
15530
|
-
if (
|
|
15805
|
+
const candidate = path11.join(dir, name);
|
|
15806
|
+
if (fs9.existsSync(candidate)) {
|
|
15531
15807
|
return candidate;
|
|
15532
15808
|
}
|
|
15533
15809
|
}
|
|
15534
|
-
const parent =
|
|
15810
|
+
const parent = path11.dirname(dir);
|
|
15535
15811
|
if (parent === dir) {
|
|
15536
15812
|
return null;
|
|
15537
15813
|
}
|
|
@@ -15540,7 +15816,7 @@ function findNearestTsconfig(startDir) {
|
|
|
15540
15816
|
}
|
|
15541
15817
|
|
|
15542
15818
|
// src/facts/why.ts
|
|
15543
|
-
import
|
|
15819
|
+
import path12 from "path";
|
|
15544
15820
|
import { Node as Node59, Project as Project3, SyntaxKind as SyntaxKind13 } from "ts-morph";
|
|
15545
15821
|
import { explainResolutionProof, renderExplanation } from "@suss/resolution";
|
|
15546
15822
|
var JS_PHRASES = {
|
|
@@ -15553,7 +15829,7 @@ var WhySession = class {
|
|
|
15553
15829
|
store;
|
|
15554
15830
|
root;
|
|
15555
15831
|
constructor(options) {
|
|
15556
|
-
this.root =
|
|
15832
|
+
this.root = path12.resolve(options.dir);
|
|
15557
15833
|
const tsconfig = findNearestTsconfig(this.root);
|
|
15558
15834
|
this.project = tsconfig === null ? createProjectWithoutTsconfig(this.root).project : new Project3({ tsConfigFilePath: tsconfig });
|
|
15559
15835
|
this.store = new ResolutionStore();
|
|
@@ -15642,7 +15918,7 @@ var WhySession = class {
|
|
|
15642
15918
|
};
|
|
15643
15919
|
}
|
|
15644
15920
|
sourceFileAt(file) {
|
|
15645
|
-
const absolute =
|
|
15921
|
+
const absolute = path12.resolve(this.root, file);
|
|
15646
15922
|
const loaded = this.project.getSourceFile(absolute);
|
|
15647
15923
|
if (loaded !== void 0) {
|
|
15648
15924
|
return loaded;
|
|
@@ -15656,7 +15932,7 @@ var WhySession = class {
|
|
|
15656
15932
|
/** A module key: a file path said relative to the root, or a package name. */
|
|
15657
15933
|
displayPath(key) {
|
|
15658
15934
|
if (key.startsWith(this.root)) {
|
|
15659
|
-
return
|
|
15935
|
+
return path12.relative(this.root, key);
|
|
15660
15936
|
}
|
|
15661
15937
|
return key;
|
|
15662
15938
|
}
|
|
@@ -15727,6 +16003,17 @@ function funnelDrops(packs) {
|
|
|
15727
16003
|
}
|
|
15728
16004
|
return violations;
|
|
15729
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
|
+
}
|
|
15730
16017
|
function unversionedPacks(packs) {
|
|
15731
16018
|
return packs.filter((funnel) => funnel.version === null).map((funnel) => ({
|
|
15732
16019
|
label: funnel.pack,
|
|
@@ -15821,6 +16108,12 @@ function evaluatePackHealth(report) {
|
|
|
15821
16108
|
audience: "run",
|
|
15822
16109
|
violations: selfCollisions(report.packs)
|
|
15823
16110
|
},
|
|
16111
|
+
{
|
|
16112
|
+
name: "every recognizer had units to look inside",
|
|
16113
|
+
code: "no-units",
|
|
16114
|
+
audience: "run",
|
|
16115
|
+
violations: recognizersWithNoUnits(report.packs)
|
|
16116
|
+
},
|
|
15824
16117
|
{
|
|
15825
16118
|
name: "every pack declares a version",
|
|
15826
16119
|
code: "no-version",
|