@wairon/cli 5.1.1-dev.69 → 5.1.1-dev.70
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/cli/index.js +243 -20
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +209 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11593,7 +11593,7 @@ function defaultTargetConfig(type) {
|
|
|
11593
11593
|
enabled: true
|
|
11594
11594
|
};
|
|
11595
11595
|
}
|
|
11596
|
-
var WAIRON_VERSION = "5.1.1-dev.
|
|
11596
|
+
var WAIRON_VERSION = "5.1.1-dev.70";
|
|
11597
11597
|
var GITHUB_REPO = "SYW-Apps/Waffle-AIron";
|
|
11598
11598
|
var ARCHITECT_AGENT_ID = "agent-architect";
|
|
11599
11599
|
var ARCHITECT_TEMPLATE_ID = "architect";
|
|
@@ -17163,6 +17163,128 @@ var paramConformanceRule = {
|
|
|
17163
17163
|
}
|
|
17164
17164
|
};
|
|
17165
17165
|
|
|
17166
|
+
// src/core/rules/conformance/route-coverage.ts
|
|
17167
|
+
function liesUnder2(path28, prefix) {
|
|
17168
|
+
return path28 === prefix || path28.startsWith(prefix + "/");
|
|
17169
|
+
}
|
|
17170
|
+
function normalizeSegment(segment) {
|
|
17171
|
+
return /^\{.+\}$/.test(segment) || segment.startsWith(":") ? "*" : segment;
|
|
17172
|
+
}
|
|
17173
|
+
function completed(route, heads) {
|
|
17174
|
+
const variants = route.segments[0] === "*" && heads.length > 0 ? heads.map((head) => [head, ...route.segments.slice(1)]) : [route.segments];
|
|
17175
|
+
return variants.map((segments) => ({
|
|
17176
|
+
verb: route.verb.toUpperCase(),
|
|
17177
|
+
segments: segments.map(normalizeSegment),
|
|
17178
|
+
exactLength: route.exactLength,
|
|
17179
|
+
key: `${route.verb.toUpperCase()} /${segments.join("/")}${route.exactLength ? "" : "/\u2026"}`
|
|
17180
|
+
}));
|
|
17181
|
+
}
|
|
17182
|
+
function answers(route, endpoint) {
|
|
17183
|
+
if (route.verb !== endpoint.verb) return false;
|
|
17184
|
+
if (route.exactLength ? endpoint.segments.length !== route.segments.length : endpoint.segments.length < route.segments.length) return false;
|
|
17185
|
+
return route.segments.every((segment, index) => segment === endpoint.segments[index]);
|
|
17186
|
+
}
|
|
17187
|
+
var routeCoverageRule = {
|
|
17188
|
+
name: "route-coverage",
|
|
17189
|
+
description: "Code-to-contract for the ROUTES: does every route a router actually answers have a contract endpoint, and does every contract endpoint have a route that answers it? A portal's endpoints are what its contract promises; the router is what the code serves; nothing compared the two, so a route with no contract \u2014 including a write \u2014 could run for months without a single rule noticing. The listener's mount names the router function (its `via`), and the routes are read out of that function's guards; the path segment the router never checks is the one the mount's prefix guarantees. One idiom is read \u2014 a method comparison with comparisons on the path's split segments \u2014 and a mounted router that yields no route in it is reported as unread, never passed: a check that cannot see a router must say so rather than stay quiet.",
|
|
17190
|
+
codes: [
|
|
17191
|
+
{
|
|
17192
|
+
code: "UNDECLARED_ROUTE",
|
|
17193
|
+
defaultSeverity: "warning",
|
|
17194
|
+
summary: "A router answers a route that no contract endpoint of the portal it serves declares \u2014 a surface the code serves and the design never promised",
|
|
17195
|
+
// Measured code↔contract drift, route by route, at the mount's router
|
|
17196
|
+
// entry — which is why every one of them hands over `parts`.
|
|
17197
|
+
carryable: true
|
|
17198
|
+
},
|
|
17199
|
+
{
|
|
17200
|
+
code: "UNROUTED_ENDPOINT",
|
|
17201
|
+
defaultSeverity: "warning",
|
|
17202
|
+
summary: "A contract endpoint no route of the portal's router answers \u2014 the contract promises a route that no request can reach",
|
|
17203
|
+
carryable: true
|
|
17204
|
+
},
|
|
17205
|
+
{
|
|
17206
|
+
code: "UNREADABLE_ROUTER",
|
|
17207
|
+
defaultSeverity: "warning",
|
|
17208
|
+
summary: "A mounted portal's router yields no route this analysis can read, so its routes were not checked against the contract at all",
|
|
17209
|
+
carryable: true
|
|
17210
|
+
}
|
|
17211
|
+
],
|
|
17212
|
+
check(ctx) {
|
|
17213
|
+
const code = ctx.codeIndex();
|
|
17214
|
+
const realization = ctx.realizationIndex();
|
|
17215
|
+
for (const listener of ctx.components) {
|
|
17216
|
+
if (listener.componentType !== "Portal") continue;
|
|
17217
|
+
for (const mount of listener.mounts ?? []) {
|
|
17218
|
+
const via = mount.via;
|
|
17219
|
+
if (!via) continue;
|
|
17220
|
+
const portal = ctx.componentMap.get(mount.portal);
|
|
17221
|
+
if (!portal || portal.componentType !== "Portal") continue;
|
|
17222
|
+
const [anchor] = realization.implementationsOf(portal.id).map((impl) => impl.id).sort();
|
|
17223
|
+
if (!anchor) continue;
|
|
17224
|
+
const holders = realization.filesOf(portal.id).map(pathKey).filter((file) => {
|
|
17225
|
+
const facts = code.factsAt(file);
|
|
17226
|
+
return !!facts && facts.status === "analyzed" && facts.analysisGrade === "exact" && !!facts.functionParams && Object.prototype.hasOwnProperty.call(facts.functionParams, via);
|
|
17227
|
+
});
|
|
17228
|
+
if (holders.length === 0) continue;
|
|
17229
|
+
const read = holders.flatMap((file) => {
|
|
17230
|
+
const routes = code.factsAt(file).functionRoutes;
|
|
17231
|
+
return routes && Object.prototype.hasOwnProperty.call(routes, via) ? routes[via] : [];
|
|
17232
|
+
});
|
|
17233
|
+
const draftContext = ctx.isComponentDraft(listener.id) || ctx.isComponentDraft(portal.id);
|
|
17234
|
+
const where = holders.map((file) => `"${file}"`).join(", ");
|
|
17235
|
+
if (read.length === 0) {
|
|
17236
|
+
ctx.addIssue(
|
|
17237
|
+
"warning",
|
|
17238
|
+
"UNREADABLE_ROUTER",
|
|
17239
|
+
`Listener "${listener.id}" mounts portal "${portal.id}" through "${via}" in ${where}, but no branch of "${via}" reads as a route \u2014 so none of its routes were checked against the contract at all. Only one idiom is read: an \`if\` whose conditions, together with those of every enclosing \`if\`, compare \`<request>.method\` with a string and \`parts[i]\` / \`parts.length\` with literals. Silence here would read as a clean router; it is only one this analysis cannot see. Write the router in that idiom, or carry this finding with the reason it cannot be.`,
|
|
17240
|
+
anchor,
|
|
17241
|
+
draftContext,
|
|
17242
|
+
void 0,
|
|
17243
|
+
{ at: via }
|
|
17244
|
+
);
|
|
17245
|
+
continue;
|
|
17246
|
+
}
|
|
17247
|
+
const heads = [...new Set(mount.prefixes.map((prefix) => prefix.split("/").filter(Boolean)[0]).filter((head) => !!head))];
|
|
17248
|
+
const served = read.map((route) => completed(route, heads));
|
|
17249
|
+
const endpoints = ctx.interfaceMethodsOf(portal.id).flatMap((method) => {
|
|
17250
|
+
const endpoint = method.endpoint;
|
|
17251
|
+
if (endpoint?.transport !== "HTTP") return [];
|
|
17252
|
+
if (!mount.prefixes.some((prefix) => liesUnder2(endpoint.path, prefix))) return [];
|
|
17253
|
+
return [{
|
|
17254
|
+
verb: endpoint.method.toUpperCase(),
|
|
17255
|
+
segments: endpoint.path.split("/").filter(Boolean).map(normalizeSegment),
|
|
17256
|
+
key: `${endpoint.method.toUpperCase()} ${endpoint.path}`
|
|
17257
|
+
}];
|
|
17258
|
+
});
|
|
17259
|
+
const undeclared = [...new Set(served.filter((variants) => !variants.some((route) => endpoints.some((endpoint) => answers(route, endpoint)))).flatMap((variants) => variants.map((route) => route.key)))].sort();
|
|
17260
|
+
if (undeclared.length > 0) {
|
|
17261
|
+
ctx.addIssue(
|
|
17262
|
+
"warning",
|
|
17263
|
+
"UNDECLARED_ROUTE",
|
|
17264
|
+
`Portal "${portal.id}"'s router "${via}" (${where}), mounted by listener "${listener.id}", answers ${undeclared.length} route(s) no contract endpoint of "${portal.id}" declares \u2014 ${undeclared.map((key) => `"${key}"`).join(", ")}. A surface the code serves and the design never promised is how a write runs with no contract: no brief, no auth review, no rule reading it. Declare each as a contract method with its endpoint, or take the route out of the router.`,
|
|
17265
|
+
anchor,
|
|
17266
|
+
draftContext,
|
|
17267
|
+
void 0,
|
|
17268
|
+
{ at: via, covers: undeclared }
|
|
17269
|
+
);
|
|
17270
|
+
}
|
|
17271
|
+
const unrouted = [...new Set(endpoints.filter((endpoint) => !served.some((variants) => variants.some((route) => answers(route, endpoint)))).map((endpoint) => endpoint.key))].sort();
|
|
17272
|
+
if (unrouted.length > 0) {
|
|
17273
|
+
ctx.addIssue(
|
|
17274
|
+
"warning",
|
|
17275
|
+
"UNROUTED_ENDPOINT",
|
|
17276
|
+
`Portal "${portal.id}" binds ${unrouted.length} HTTP endpoint(s) under listener "${listener.id}"'s mount that no route of its router "${via}" (${where}) answers \u2014 ${unrouted.map((key) => `"${key}"`).join(", ")}. The contract promises a route no request can reach. Route it in the router, or drop the endpoint from the contract.`,
|
|
17277
|
+
anchor,
|
|
17278
|
+
draftContext,
|
|
17279
|
+
void 0,
|
|
17280
|
+
{ at: via, covers: unrouted }
|
|
17281
|
+
);
|
|
17282
|
+
}
|
|
17283
|
+
}
|
|
17284
|
+
}
|
|
17285
|
+
}
|
|
17286
|
+
};
|
|
17287
|
+
|
|
17166
17288
|
// src/core/rules/conformance/unclaimed-source.ts
|
|
17167
17289
|
var unclaimedSourceRule = {
|
|
17168
17290
|
name: "unclaimed-source",
|
|
@@ -17464,14 +17586,21 @@ function isPureForwarder(methods) {
|
|
|
17464
17586
|
const narrated = methods.filter((m) => (m.narrative ?? []).length > 0);
|
|
17465
17587
|
return narrated.length > 0 && narrated.every((m) => isForwardingMethod(m.narrative ?? []));
|
|
17466
17588
|
}
|
|
17467
|
-
function
|
|
17589
|
+
function reachesCollaborator(narrative) {
|
|
17590
|
+
return narrative.some((step) => step.type === "call" || step.type === "dispatch" || step.type === "register");
|
|
17591
|
+
}
|
|
17592
|
+
function isRoutingTable(methods) {
|
|
17593
|
+
const reaching = methods.map((m) => m.narrative ?? []).filter(reachesCollaborator);
|
|
17594
|
+
return reaching.length > 0 && reaching.every(isForwardingMethod);
|
|
17595
|
+
}
|
|
17596
|
+
function routingTableComponents(ctx) {
|
|
17468
17597
|
const realized = /* @__PURE__ */ new Map();
|
|
17469
17598
|
for (const impl of ctx.implementations) {
|
|
17470
17599
|
const intf = ctx.interfaceMap.get(impl.contract);
|
|
17471
17600
|
if (!intf) continue;
|
|
17472
17601
|
realized.set(intf.component, [...realized.get(intf.component) ?? [], ...impl.methods]);
|
|
17473
17602
|
}
|
|
17474
|
-
return new Set([...realized].filter(([, methods]) =>
|
|
17603
|
+
return new Set([...realized].filter(([, methods]) => isRoutingTable(methods)).map(([id]) => id));
|
|
17475
17604
|
}
|
|
17476
17605
|
var methodCohesionRule = {
|
|
17477
17606
|
name: "method-cohesion",
|
|
@@ -17524,7 +17653,7 @@ var couplingRule = {
|
|
|
17524
17653
|
{ code: "MUTUAL_SUBSYSTEM_DEPENDENCY", defaultSeverity: "warning", summary: "Subsystems depend on each other without a declared trusted link" },
|
|
17525
17654
|
{ code: "INVALID_TRUSTED_LINK", defaultSeverity: "error", summary: "trustedLinks references a non-existent subsystem" },
|
|
17526
17655
|
{ code: "UNUSED_TRUSTED_LINK", defaultSeverity: "warning", summary: "trustedLinks declares a peer no dependency actually reaches" },
|
|
17527
|
-
{ code: "GOD_COMPONENT", defaultSeverity: "warning", summary: "Component with excessive dependency fan-out; not reported on a
|
|
17656
|
+
{ code: "GOD_COMPONENT", defaultSeverity: "warning", summary: "Component with excessive dependency fan-out; not reported on a routing table, which reaches every collaborator it has only through single hand-offs" }
|
|
17528
17657
|
],
|
|
17529
17658
|
check(ctx) {
|
|
17530
17659
|
const subsystemDeps = /* @__PURE__ */ new Map();
|
|
@@ -17596,10 +17725,10 @@ var couplingRule = {
|
|
|
17596
17725
|
);
|
|
17597
17726
|
}
|
|
17598
17727
|
}
|
|
17599
|
-
const
|
|
17728
|
+
const routingTables = routingTableComponents(ctx);
|
|
17600
17729
|
for (const comp of ctx.components) {
|
|
17601
17730
|
const threshold = ctx.complexityConfigFor(comp.subsystem)?.maxComponentDependencies ?? DEFAULT_GOD_COMPONENT_THRESHOLD;
|
|
17602
|
-
if (comp.dependsOn.length > threshold && !
|
|
17731
|
+
if (comp.dependsOn.length > threshold && !routingTables.has(comp.id)) {
|
|
17603
17732
|
ctx.addIssue(
|
|
17604
17733
|
"warning",
|
|
17605
17734
|
"GOD_COMPONENT",
|
|
@@ -18191,7 +18320,7 @@ var complexityRule = {
|
|
|
18191
18320
|
{ code: "DESCRIPTION_TOO_SHORT", defaultSeverity: "warning", summary: "Description is shorter than the configured minimum length" },
|
|
18192
18321
|
{ code: "EXCESSIVE_METHODS", defaultSeverity: "warning", summary: "Interface declares more methods than the configured limit" },
|
|
18193
18322
|
{ code: "EXCESSIVE_METHOD_PARAMS", defaultSeverity: "warning", summary: "Interface method declares more parameters than the configured limit" },
|
|
18194
|
-
{ code: "EXCESSIVE_DEPENDENCIES", defaultSeverity: "warning", summary: "Component has more dependencies than the configured limit; not reported on a
|
|
18323
|
+
{ code: "EXCESSIVE_DEPENDENCIES", defaultSeverity: "warning", summary: "Component has more dependencies than the configured limit; not reported on a routing table, which reaches every collaborator it has only through single hand-offs" },
|
|
18195
18324
|
{ code: "EXCESSIVE_SUBSYSTEM_COMPONENTS", defaultSeverity: "warning", summary: "Subsystem has more direct components than the configured limit" }
|
|
18196
18325
|
],
|
|
18197
18326
|
check(ctx) {
|
|
@@ -18211,7 +18340,7 @@ var complexityRule = {
|
|
|
18211
18340
|
);
|
|
18212
18341
|
}
|
|
18213
18342
|
}
|
|
18214
|
-
const
|
|
18343
|
+
const routingTables = routingTableComponents(ctx);
|
|
18215
18344
|
for (const comp of ctx.components) {
|
|
18216
18345
|
const docConfig = ctx.documentationConfigFor(comp.subsystem);
|
|
18217
18346
|
const complexityConfig = ctx.complexityConfigFor(comp.subsystem);
|
|
@@ -18225,7 +18354,7 @@ var complexityRule = {
|
|
|
18225
18354
|
"Component",
|
|
18226
18355
|
isDraft
|
|
18227
18356
|
);
|
|
18228
|
-
if (complexityConfig?.maxComponentDependencies !== void 0 && comp.dependsOn.length > complexityConfig.maxComponentDependencies && !
|
|
18357
|
+
if (complexityConfig?.maxComponentDependencies !== void 0 && comp.dependsOn.length > complexityConfig.maxComponentDependencies && !routingTables.has(comp.id)) {
|
|
18229
18358
|
ctx.addIssue(
|
|
18230
18359
|
"warning",
|
|
18231
18360
|
"EXCESSIVE_DEPENDENCIES",
|
|
@@ -18675,6 +18804,7 @@ var SDD_RULES = [
|
|
|
18675
18804
|
typeRealizationRule,
|
|
18676
18805
|
typeShapeRule,
|
|
18677
18806
|
paramConformanceRule,
|
|
18807
|
+
routeCoverageRule,
|
|
18678
18808
|
unclaimedSourceRule,
|
|
18679
18809
|
exportConformanceRule,
|
|
18680
18810
|
couplingRule,
|
|
@@ -18993,6 +19123,7 @@ function walkExact(ts, sourceText, fileName) {
|
|
|
18993
19123
|
const localTypes = /* @__PURE__ */ new Map();
|
|
18994
19124
|
const typeShapes = /* @__PURE__ */ new Map();
|
|
18995
19125
|
const functionParams = /* @__PURE__ */ new Map();
|
|
19126
|
+
const functionRoutes = /* @__PURE__ */ new Map();
|
|
18996
19127
|
const mutableBindings = /* @__PURE__ */ new Set();
|
|
18997
19128
|
const schemaConstants = /* @__PURE__ */ new Map();
|
|
18998
19129
|
const derivedAliases = [];
|
|
@@ -19164,6 +19295,67 @@ function walkExact(ts, sourceText, fileName) {
|
|
|
19164
19295
|
if (fn.body) count(fn.body);
|
|
19165
19296
|
return { score, callees };
|
|
19166
19297
|
};
|
|
19298
|
+
const conjunctsOf = (expression, out = []) => {
|
|
19299
|
+
if (ts.isParenthesizedExpression(expression)) return conjunctsOf(expression.expression, out);
|
|
19300
|
+
if (ts.isBinaryExpression(expression) && expression.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) {
|
|
19301
|
+
conjunctsOf(expression.left, out);
|
|
19302
|
+
conjunctsOf(expression.right, out);
|
|
19303
|
+
return out;
|
|
19304
|
+
}
|
|
19305
|
+
out.push(expression);
|
|
19306
|
+
return out;
|
|
19307
|
+
};
|
|
19308
|
+
const isPartsRef = (expression) => ts.isIdentifier(expression) && expression.text === "parts" || ts.isPropertyAccessExpression(expression) && expression.name.text === "parts";
|
|
19309
|
+
const constraintOf = (conjunct) => {
|
|
19310
|
+
if (!ts.isBinaryExpression(conjunct) || conjunct.operatorToken.kind !== ts.SyntaxKind.EqualsEqualsEqualsToken) {
|
|
19311
|
+
return void 0;
|
|
19312
|
+
}
|
|
19313
|
+
const { left, right } = conjunct;
|
|
19314
|
+
if (ts.isPropertyAccessExpression(left) && left.name.text === "method" && ts.isStringLiteral(right)) {
|
|
19315
|
+
return { verb: right.text };
|
|
19316
|
+
}
|
|
19317
|
+
if (ts.isPropertyAccessExpression(left) && left.name.text === "length" && isPartsRef(left.expression) && ts.isNumericLiteral(right)) {
|
|
19318
|
+
return { length: Number(right.text) };
|
|
19319
|
+
}
|
|
19320
|
+
if (ts.isElementAccessExpression(left) && isPartsRef(left.expression) && ts.isNumericLiteral(left.argumentExpression) && ts.isStringLiteral(right)) {
|
|
19321
|
+
return { index: Number(left.argumentExpression.text), literal: right.text };
|
|
19322
|
+
}
|
|
19323
|
+
return void 0;
|
|
19324
|
+
};
|
|
19325
|
+
const routeOf = (conjuncts) => {
|
|
19326
|
+
let verb;
|
|
19327
|
+
let length;
|
|
19328
|
+
const fixed = /* @__PURE__ */ new Map();
|
|
19329
|
+
for (const conjunct of conjuncts) {
|
|
19330
|
+
const constraint = constraintOf(conjunct);
|
|
19331
|
+
if (!constraint) continue;
|
|
19332
|
+
if ("verb" in constraint) verb = constraint.verb;
|
|
19333
|
+
else if ("length" in constraint) length = constraint.length;
|
|
19334
|
+
else fixed.set(constraint.index, constraint.literal);
|
|
19335
|
+
}
|
|
19336
|
+
if (verb === void 0) return void 0;
|
|
19337
|
+
const count = length ?? (fixed.size > 0 ? Math.max(...fixed.keys()) + 1 : 0);
|
|
19338
|
+
const segments = [];
|
|
19339
|
+
for (let index = 0; index < count; index++) segments.push(fixed.get(index) ?? "*");
|
|
19340
|
+
return { verb, segments, exactLength: length !== void 0 };
|
|
19341
|
+
};
|
|
19342
|
+
const collectRoutes = (fn) => {
|
|
19343
|
+
const routes = /* @__PURE__ */ new Map();
|
|
19344
|
+
const walk2 = (node, enclosing) => {
|
|
19345
|
+
if (namedFunctionName(node) !== void 0) return;
|
|
19346
|
+
if (ts.isIfStatement(node)) {
|
|
19347
|
+
const guarded = [...enclosing, ...conjunctsOf(node.expression)];
|
|
19348
|
+
const route = routeOf(guarded);
|
|
19349
|
+
if (route) routes.set(`${route.verb} /${route.segments.join("/")}${route.exactLength ? "" : "/\u2026"}`, route);
|
|
19350
|
+
walk2(node.thenStatement, guarded);
|
|
19351
|
+
if (node.elseStatement) walk2(node.elseStatement, enclosing);
|
|
19352
|
+
return;
|
|
19353
|
+
}
|
|
19354
|
+
ts.forEachChild(node, (child) => walk2(child, enclosing));
|
|
19355
|
+
};
|
|
19356
|
+
if (fn.body) walk2(fn.body, []);
|
|
19357
|
+
return routes;
|
|
19358
|
+
};
|
|
19167
19359
|
const visit = (node) => {
|
|
19168
19360
|
const fnName = namedFunctionName(node);
|
|
19169
19361
|
if (fnName && node.body) {
|
|
@@ -19175,6 +19367,12 @@ function walkExact(ts, sourceText, fileName) {
|
|
|
19175
19367
|
const signatures = functionParams.get(fnName) ?? [];
|
|
19176
19368
|
signatures.push(declaredParameters(node));
|
|
19177
19369
|
functionParams.set(fnName, signatures);
|
|
19370
|
+
const routes = collectRoutes(node);
|
|
19371
|
+
if (routes.size > 0) {
|
|
19372
|
+
const known = functionRoutes.get(fnName) ?? /* @__PURE__ */ new Map();
|
|
19373
|
+
for (const [key, route] of routes) known.set(key, route);
|
|
19374
|
+
functionRoutes.set(fnName, known);
|
|
19375
|
+
}
|
|
19178
19376
|
}
|
|
19179
19377
|
if (ts.isPropertyDeclaration(node)) recordFieldType(node.name, node.type);
|
|
19180
19378
|
else if (ts.isParameter(node) && node.parent && ts.isConstructorDeclaration(node.parent) && isParameterProperty(node)) {
|
|
@@ -19282,7 +19480,7 @@ function walkExact(ts, sourceText, fileName) {
|
|
|
19282
19480
|
typeShapes.set(alias.name, { origin: "derived", fields: schemaMembers(literal), methods: [] });
|
|
19283
19481
|
}
|
|
19284
19482
|
const reexportOnly = sf.statements.length > 0 && sf.statements.every((st) => ts.isExportDeclaration(st) && !!st.moduleSpecifier);
|
|
19285
|
-
return { declared, anchors, exported, imports, reexports, starExports, namedReexports, complexity, calls, importBindings, typeOnlyBindings, fieldTypes, localTypes, typeShapes, functionParams, mutableBindings, reexportOnly };
|
|
19483
|
+
return { declared, anchors, exported, imports, reexports, starExports, namedReexports, complexity, calls, importBindings, typeOnlyBindings, fieldTypes, localTypes, typeShapes, functionParams, functionRoutes, mutableBindings, reexportOnly };
|
|
19286
19484
|
}
|
|
19287
19485
|
function resolveRelativeModule(fromFile, specifier) {
|
|
19288
19486
|
if (!specifier.startsWith(".")) return null;
|
|
@@ -19466,6 +19664,7 @@ function buildCodeModel(implementations, types, projectRoot, sourceRoots = [], e
|
|
|
19466
19664
|
localTypes: Object.fromEntries([...facts.localTypes].map(([k, v]) => [k, [...v]])),
|
|
19467
19665
|
typeShapes: Object.fromEntries(facts.typeShapes),
|
|
19468
19666
|
functionParams: Object.fromEntries(facts.functionParams),
|
|
19667
|
+
functionRoutes: Object.fromEntries([...facts.functionRoutes].map(([k, v]) => [k, [...v.values()]])),
|
|
19469
19668
|
topLevelMutableBindings: [...facts.mutableBindings],
|
|
19470
19669
|
reexportOnly: facts.reexportOnly
|
|
19471
19670
|
};
|