sammy-sdk 0.1.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/README.md +75 -0
- package/dist/cli/commands/dev.d.ts +3 -0
- package/dist/cli/commands/dev.d.ts.map +1 -0
- package/dist/cli/commands/dev.js +13 -0
- package/dist/cli/commands/dev.js.map +1 -0
- package/dist/cli/commands/eval.d.ts +3 -0
- package/dist/cli/commands/eval.d.ts.map +1 -0
- package/dist/cli/commands/eval.js +28 -0
- package/dist/cli/commands/eval.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +3 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +10 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli/commands/init.d.ts +3 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +9 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +17 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cloud/sammy-cloud.d.ts +10 -0
- package/dist/cloud/sammy-cloud.d.ts.map +1 -0
- package/dist/cloud/sammy-cloud.js +113 -0
- package/dist/cloud/sammy-cloud.js.map +1 -0
- package/dist/dev/chat-ui.d.ts +6 -0
- package/dist/dev/chat-ui.d.ts.map +1 -0
- package/dist/dev/chat-ui.js +95 -0
- package/dist/dev/chat-ui.js.map +1 -0
- package/dist/dev/server.d.ts +5 -0
- package/dist/dev/server.d.ts.map +1 -0
- package/dist/dev/server.js +87 -0
- package/dist/dev/server.js.map +1 -0
- package/dist/dev/watcher.d.ts +2 -0
- package/dist/dev/watcher.d.ts.map +1 -0
- package/dist/dev/watcher.js +19 -0
- package/dist/dev/watcher.js.map +1 -0
- package/dist/discovery/ast/call-route-finder.d.ts +16 -0
- package/dist/discovery/ast/call-route-finder.d.ts.map +1 -0
- package/dist/discovery/ast/call-route-finder.js +106 -0
- package/dist/discovery/ast/call-route-finder.js.map +1 -0
- package/dist/discovery/ast/handler-detector.d.ts +8 -0
- package/dist/discovery/ast/handler-detector.d.ts.map +1 -0
- package/dist/discovery/ast/handler-detector.js +56 -0
- package/dist/discovery/ast/handler-detector.js.map +1 -0
- package/dist/discovery/ast/named-export-finder.d.ts +7 -0
- package/dist/discovery/ast/named-export-finder.d.ts.map +1 -0
- package/dist/discovery/ast/named-export-finder.js +21 -0
- package/dist/discovery/ast/named-export-finder.js.map +1 -0
- package/dist/discovery/ast/param-extractor.d.ts +7 -0
- package/dist/discovery/ast/param-extractor.d.ts.map +1 -0
- package/dist/discovery/ast/param-extractor.js +236 -0
- package/dist/discovery/ast/param-extractor.js.map +1 -0
- package/dist/discovery/ast/project.d.ts +8 -0
- package/dist/discovery/ast/project.d.ts.map +1 -0
- package/dist/discovery/ast/project.js +66 -0
- package/dist/discovery/ast/project.js.map +1 -0
- package/dist/discovery/ast/resolve.d.ts +5 -0
- package/dist/discovery/ast/resolve.d.ts.map +1 -0
- package/dist/discovery/ast/resolve.js +60 -0
- package/dist/discovery/ast/resolve.js.map +1 -0
- package/dist/discovery/ast/side-effect-tracer.d.ts +4 -0
- package/dist/discovery/ast/side-effect-tracer.d.ts.map +1 -0
- package/dist/discovery/ast/side-effect-tracer.js +100 -0
- package/dist/discovery/ast/side-effect-tracer.js.map +1 -0
- package/dist/discovery/ast/source-files.d.ts +3 -0
- package/dist/discovery/ast/source-files.d.ts.map +1 -0
- package/dist/discovery/ast/source-files.js +37 -0
- package/dist/discovery/ast/source-files.js.map +1 -0
- package/dist/discovery/config-generator.d.ts +5 -0
- package/dist/discovery/config-generator.d.ts.map +1 -0
- package/dist/discovery/config-generator.js +71 -0
- package/dist/discovery/config-generator.js.map +1 -0
- package/dist/discovery/extractors/auth-detector.d.ts +3 -0
- package/dist/discovery/extractors/auth-detector.d.ts.map +1 -0
- package/dist/discovery/extractors/auth-detector.js +97 -0
- package/dist/discovery/extractors/auth-detector.js.map +1 -0
- package/dist/discovery/extractors/http-call-extractor.d.ts +5 -0
- package/dist/discovery/extractors/http-call-extractor.d.ts.map +1 -0
- package/dist/discovery/extractors/http-call-extractor.js +122 -0
- package/dist/discovery/extractors/http-call-extractor.js.map +1 -0
- package/dist/discovery/extractors/model-extractor.d.ts +4 -0
- package/dist/discovery/extractors/model-extractor.d.ts.map +1 -0
- package/dist/discovery/extractors/model-extractor.js +256 -0
- package/dist/discovery/extractors/model-extractor.js.map +1 -0
- package/dist/discovery/extractors/nestjs-extractor.d.ts +4 -0
- package/dist/discovery/extractors/nestjs-extractor.d.ts.map +1 -0
- package/dist/discovery/extractors/nestjs-extractor.js +156 -0
- package/dist/discovery/extractors/nestjs-extractor.js.map +1 -0
- package/dist/discovery/extractors/remix-extractor.d.ts +5 -0
- package/dist/discovery/extractors/remix-extractor.d.ts.map +1 -0
- package/dist/discovery/extractors/remix-extractor.js +118 -0
- package/dist/discovery/extractors/remix-extractor.js.map +1 -0
- package/dist/discovery/extractors/route-extractor.d.ts +4 -0
- package/dist/discovery/extractors/route-extractor.d.ts.map +1 -0
- package/dist/discovery/extractors/route-extractor.js +108 -0
- package/dist/discovery/extractors/route-extractor.js.map +1 -0
- package/dist/discovery/extractors/server-action-extractor.d.ts +4 -0
- package/dist/discovery/extractors/server-action-extractor.d.ts.map +1 -0
- package/dist/discovery/extractors/server-action-extractor.js +129 -0
- package/dist/discovery/extractors/server-action-extractor.js.map +1 -0
- package/dist/discovery/extractors/service-detector.d.ts +3 -0
- package/dist/discovery/extractors/service-detector.d.ts.map +1 -0
- package/dist/discovery/extractors/service-detector.js +114 -0
- package/dist/discovery/extractors/service-detector.js.map +1 -0
- package/dist/discovery/extractors/sveltekit-extractor.d.ts +5 -0
- package/dist/discovery/extractors/sveltekit-extractor.d.ts.map +1 -0
- package/dist/discovery/extractors/sveltekit-extractor.js +129 -0
- package/dist/discovery/extractors/sveltekit-extractor.js.map +1 -0
- package/dist/discovery/extractors/trpc-extractor.d.ts +4 -0
- package/dist/discovery/extractors/trpc-extractor.d.ts.map +1 -0
- package/dist/discovery/extractors/trpc-extractor.js +191 -0
- package/dist/discovery/extractors/trpc-extractor.js.map +1 -0
- package/dist/discovery/framework-detector.d.ts +9 -0
- package/dist/discovery/framework-detector.d.ts.map +1 -0
- package/dist/discovery/framework-detector.js +68 -0
- package/dist/discovery/framework-detector.js.map +1 -0
- package/dist/discovery/init.d.ts +4 -0
- package/dist/discovery/init.d.ts.map +1 -0
- package/dist/discovery/init.js +102 -0
- package/dist/discovery/init.js.map +1 -0
- package/dist/discovery/llm-analyzer.d.ts +32 -0
- package/dist/discovery/llm-analyzer.d.ts.map +1 -0
- package/dist/discovery/llm-analyzer.js +162 -0
- package/dist/discovery/llm-analyzer.js.map +1 -0
- package/dist/discovery/orchestrator.d.ts +4 -0
- package/dist/discovery/orchestrator.d.ts.map +1 -0
- package/dist/discovery/orchestrator.js +47 -0
- package/dist/discovery/orchestrator.js.map +1 -0
- package/dist/discovery/scanners/express-scanner.d.ts +3 -0
- package/dist/discovery/scanners/express-scanner.d.ts.map +1 -0
- package/dist/discovery/scanners/express-scanner.js +10 -0
- package/dist/discovery/scanners/express-scanner.js.map +1 -0
- package/dist/discovery/scanners/fastify-scanner.d.ts +3 -0
- package/dist/discovery/scanners/fastify-scanner.d.ts.map +1 -0
- package/dist/discovery/scanners/fastify-scanner.js +10 -0
- package/dist/discovery/scanners/fastify-scanner.js.map +1 -0
- package/dist/discovery/scanners/hono-scanner.d.ts +3 -0
- package/dist/discovery/scanners/hono-scanner.d.ts.map +1 -0
- package/dist/discovery/scanners/hono-scanner.js +10 -0
- package/dist/discovery/scanners/hono-scanner.js.map +1 -0
- package/dist/discovery/scanners/nestjs-scanner.d.ts +3 -0
- package/dist/discovery/scanners/nestjs-scanner.d.ts.map +1 -0
- package/dist/discovery/scanners/nestjs-scanner.js +10 -0
- package/dist/discovery/scanners/nestjs-scanner.js.map +1 -0
- package/dist/discovery/scanners/nextjs-scanner.d.ts +3 -0
- package/dist/discovery/scanners/nextjs-scanner.d.ts.map +1 -0
- package/dist/discovery/scanners/nextjs-scanner.js +15 -0
- package/dist/discovery/scanners/nextjs-scanner.js.map +1 -0
- package/dist/discovery/scanners/registry.d.ts +3 -0
- package/dist/discovery/scanners/registry.d.ts.map +1 -0
- package/dist/discovery/scanners/registry.js +22 -0
- package/dist/discovery/scanners/registry.js.map +1 -0
- package/dist/discovery/scanners/remix-scanner.d.ts +3 -0
- package/dist/discovery/scanners/remix-scanner.d.ts.map +1 -0
- package/dist/discovery/scanners/remix-scanner.js +13 -0
- package/dist/discovery/scanners/remix-scanner.js.map +1 -0
- package/dist/discovery/scanners/sveltekit-scanner.d.ts +3 -0
- package/dist/discovery/scanners/sveltekit-scanner.d.ts.map +1 -0
- package/dist/discovery/scanners/sveltekit-scanner.js +10 -0
- package/dist/discovery/scanners/sveltekit-scanner.js.map +1 -0
- package/dist/discovery/scanners/trpc-scanner.d.ts +3 -0
- package/dist/discovery/scanners/trpc-scanner.d.ts.map +1 -0
- package/dist/discovery/scanners/trpc-scanner.js +21 -0
- package/dist/discovery/scanners/trpc-scanner.js.map +1 -0
- package/dist/discovery/scanners/types.d.ts +18 -0
- package/dist/discovery/scanners/types.d.ts.map +1 -0
- package/dist/discovery/scanners/types.js +2 -0
- package/dist/discovery/scanners/types.js.map +1 -0
- package/dist/discovery/types.d.ts +60 -0
- package/dist/discovery/types.d.ts.map +1 -0
- package/dist/discovery/types.js +2 -0
- package/dist/discovery/types.js.map +1 -0
- package/dist/eval/diagnoser.d.ts +4 -0
- package/dist/eval/diagnoser.d.ts.map +1 -0
- package/dist/eval/diagnoser.js +97 -0
- package/dist/eval/diagnoser.js.map +1 -0
- package/dist/eval/judge.d.ts +8 -0
- package/dist/eval/judge.d.ts.map +1 -0
- package/dist/eval/judge.js +71 -0
- package/dist/eval/judge.js.map +1 -0
- package/dist/eval/loop-guard.d.ts +12 -0
- package/dist/eval/loop-guard.d.ts.map +1 -0
- package/dist/eval/loop-guard.js +45 -0
- package/dist/eval/loop-guard.js.map +1 -0
- package/dist/eval/refiner.d.ts +5 -0
- package/dist/eval/refiner.d.ts.map +1 -0
- package/dist/eval/refiner.js +149 -0
- package/dist/eval/refiner.js.map +1 -0
- package/dist/eval/runner.d.ts +27 -0
- package/dist/eval/runner.d.ts.map +1 -0
- package/dist/eval/runner.js +198 -0
- package/dist/eval/runner.js.map +1 -0
- package/dist/eval/scenario-generator.d.ts +5 -0
- package/dist/eval/scenario-generator.d.ts.map +1 -0
- package/dist/eval/scenario-generator.js +185 -0
- package/dist/eval/scenario-generator.js.map +1 -0
- package/dist/eval/scorer.d.ts +9 -0
- package/dist/eval/scorer.d.ts.map +1 -0
- package/dist/eval/scorer.js +189 -0
- package/dist/eval/scorer.js.map +1 -0
- package/dist/eval/types.d.ts +135 -0
- package/dist/eval/types.d.ts.map +1 -0
- package/dist/eval/types.js +37 -0
- package/dist/eval/types.js.map +1 -0
- package/dist/generator/agent-generator.d.ts +3 -0
- package/dist/generator/agent-generator.d.ts.map +1 -0
- package/dist/generator/agent-generator.js +29 -0
- package/dist/generator/agent-generator.js.map +1 -0
- package/dist/generator/generate.d.ts +5 -0
- package/dist/generator/generate.d.ts.map +1 -0
- package/dist/generator/generate.js +119 -0
- package/dist/generator/generate.js.map +1 -0
- package/dist/generator/handler-generator.d.ts +3 -0
- package/dist/generator/handler-generator.d.ts.map +1 -0
- package/dist/generator/handler-generator.js +66 -0
- package/dist/generator/handler-generator.js.map +1 -0
- package/dist/generator/index-generator.d.ts +3 -0
- package/dist/generator/index-generator.d.ts.map +1 -0
- package/dist/generator/index-generator.js +28 -0
- package/dist/generator/index-generator.js.map +1 -0
- package/dist/generator/merge-logic.d.ts +15 -0
- package/dist/generator/merge-logic.d.ts.map +1 -0
- package/dist/generator/merge-logic.js +52 -0
- package/dist/generator/merge-logic.js.map +1 -0
- package/dist/generator/router-generator.d.ts +3 -0
- package/dist/generator/router-generator.d.ts.map +1 -0
- package/dist/generator/router-generator.js +55 -0
- package/dist/generator/router-generator.js.map +1 -0
- package/dist/generator/schema-generator.d.ts +3 -0
- package/dist/generator/schema-generator.d.ts.map +1 -0
- package/dist/generator/schema-generator.js +58 -0
- package/dist/generator/schema-generator.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime/agent-orchestrator.d.ts +19 -0
- package/dist/runtime/agent-orchestrator.d.ts.map +1 -0
- package/dist/runtime/agent-orchestrator.js +96 -0
- package/dist/runtime/agent-orchestrator.js.map +1 -0
- package/dist/runtime/agent-runner.d.ts +22 -0
- package/dist/runtime/agent-runner.d.ts.map +1 -0
- package/dist/runtime/agent-runner.js +59 -0
- package/dist/runtime/agent-runner.js.map +1 -0
- package/dist/runtime/config-loader.d.ts +12 -0
- package/dist/runtime/config-loader.d.ts.map +1 -0
- package/dist/runtime/config-loader.js +42 -0
- package/dist/runtime/config-loader.js.map +1 -0
- package/dist/runtime/conversation-manager.d.ts +16 -0
- package/dist/runtime/conversation-manager.d.ts.map +1 -0
- package/dist/runtime/conversation-manager.js +33 -0
- package/dist/runtime/conversation-manager.js.map +1 -0
- package/dist/runtime/sammy.d.ts +17 -0
- package/dist/runtime/sammy.d.ts.map +1 -0
- package/dist/runtime/sammy.js +97 -0
- package/dist/runtime/sammy.js.map +1 -0
- package/dist/runtime/tool-executor.d.ts +14 -0
- package/dist/runtime/tool-executor.d.ts.map +1 -0
- package/dist/runtime/tool-executor.js +58 -0
- package/dist/runtime/tool-executor.js.map +1 -0
- package/dist/runtime/tool-types.d.ts +26 -0
- package/dist/runtime/tool-types.d.ts.map +1 -0
- package/dist/runtime/tool-types.js +2 -0
- package/dist/runtime/tool-types.js.map +1 -0
- package/dist/runtime/types.d.ts +100 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +2 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/runtime/zod-to-json-schema.d.ts +3 -0
- package/dist/runtime/zod-to-json-schema.d.ts.map +1 -0
- package/dist/runtime/zod-to-json-schema.js +82 -0
- package/dist/runtime/zod-to-json-schema.js.map +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { SyntaxKind } from "ts-morph";
|
|
2
|
+
import { functionLikeFromExpression, resolveDefinitions, getFunctionBody } from "./resolve.js";
|
|
3
|
+
const HTTP_VERBS = new Set(["get", "post", "put", "delete", "patch", "options", "head", "all"]);
|
|
4
|
+
// Find `obj.<verb>('/path', ...handlers)` route registrations. Precision guard:
|
|
5
|
+
// a route is only emitted when one of the args after the path resolves to a
|
|
6
|
+
// function body — this filters non-route calls like `map.get('key')`.
|
|
7
|
+
export function findCallRoutes(sourceFile) {
|
|
8
|
+
const out = [];
|
|
9
|
+
for (const call of sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)) {
|
|
10
|
+
const prop = call.getExpression().asKind(SyntaxKind.PropertyAccessExpression);
|
|
11
|
+
if (!prop)
|
|
12
|
+
continue;
|
|
13
|
+
const verb = prop.getName().toLowerCase();
|
|
14
|
+
if (!HTTP_VERBS.has(verb))
|
|
15
|
+
continue;
|
|
16
|
+
const args = call.getArguments();
|
|
17
|
+
if (args.length < 2)
|
|
18
|
+
continue; // need at least a path + a handler
|
|
19
|
+
const path = literalText(args[0]);
|
|
20
|
+
if (path === undefined)
|
|
21
|
+
continue;
|
|
22
|
+
const handlerBody = resolveHandlerBody(args.slice(1));
|
|
23
|
+
if (!handlerBody)
|
|
24
|
+
continue;
|
|
25
|
+
out.push({ method: verb.toUpperCase(), path, handlerBody, args });
|
|
26
|
+
}
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
export function findRouteObjects(sourceFile) {
|
|
30
|
+
const out = [];
|
|
31
|
+
for (const call of sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)) {
|
|
32
|
+
const prop = call.getExpression().asKind(SyntaxKind.PropertyAccessExpression);
|
|
33
|
+
if (!prop || prop.getName() !== "route")
|
|
34
|
+
continue;
|
|
35
|
+
const obj = call.getArguments()[0]?.asKind(SyntaxKind.ObjectLiteralExpression);
|
|
36
|
+
if (!obj)
|
|
37
|
+
continue;
|
|
38
|
+
const methods = readMethods(initializerOf(obj, "method"));
|
|
39
|
+
const path = literalText(initializerOf(obj, "url"));
|
|
40
|
+
if (methods.length === 0 || path === undefined)
|
|
41
|
+
continue;
|
|
42
|
+
const handlerInit = initializerOf(obj, "handler");
|
|
43
|
+
const handlerBody = handlerInit ? toFunctionBody(handlerInit) : undefined;
|
|
44
|
+
const schemaObj = initializerOf(obj, "schema")?.asKind(SyntaxKind.ObjectLiteralExpression);
|
|
45
|
+
const schemaBody = schemaObj ? initializerOf(schemaObj, "body") : undefined;
|
|
46
|
+
out.push({ methods, path, handlerBody, schemaBody });
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
function initializerOf(obj, name) {
|
|
51
|
+
const objLit = obj.asKind(SyntaxKind.ObjectLiteralExpression);
|
|
52
|
+
const prop = objLit?.getProperty(name)?.asKind(SyntaxKind.PropertyAssignment);
|
|
53
|
+
return prop?.getInitializer();
|
|
54
|
+
}
|
|
55
|
+
function readMethods(init) {
|
|
56
|
+
if (!init)
|
|
57
|
+
return [];
|
|
58
|
+
const single = literalText(init);
|
|
59
|
+
if (single !== undefined)
|
|
60
|
+
return [single.toUpperCase()];
|
|
61
|
+
const arr = init.asKind(SyntaxKind.ArrayLiteralExpression);
|
|
62
|
+
if (arr) {
|
|
63
|
+
return arr
|
|
64
|
+
.getElements()
|
|
65
|
+
.map((e) => literalText(e))
|
|
66
|
+
.filter((v) => v !== undefined)
|
|
67
|
+
.map((v) => v.toUpperCase());
|
|
68
|
+
}
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
// First arg (scanning right-to-left) that resolves to a function body — the
|
|
72
|
+
// real handler, skipping any preceding middleware.
|
|
73
|
+
function resolveHandlerBody(args) {
|
|
74
|
+
for (let i = args.length - 1; i >= 0; i--) {
|
|
75
|
+
const body = toFunctionBody(args[i]);
|
|
76
|
+
if (body)
|
|
77
|
+
return body;
|
|
78
|
+
}
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
function toFunctionBody(arg) {
|
|
82
|
+
const direct = functionLikeFromExpression(arg);
|
|
83
|
+
if (direct)
|
|
84
|
+
return direct;
|
|
85
|
+
// Named handler reference: `app.get('/x', getUser)`.
|
|
86
|
+
if (arg.getKind() === SyntaxKind.Identifier) {
|
|
87
|
+
for (const def of resolveDefinitions(arg)) {
|
|
88
|
+
const body = getFunctionBody(def);
|
|
89
|
+
if (body)
|
|
90
|
+
return body;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
function literalText(node) {
|
|
96
|
+
if (!node)
|
|
97
|
+
return undefined;
|
|
98
|
+
const str = node.asKind(SyntaxKind.StringLiteral);
|
|
99
|
+
if (str)
|
|
100
|
+
return str.getLiteralText();
|
|
101
|
+
const tpl = node.asKind(SyntaxKind.NoSubstitutionTemplateLiteral);
|
|
102
|
+
if (tpl)
|
|
103
|
+
return tpl.getLiteralText();
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=call-route-finder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"call-route-finder.js","sourceRoot":"","sources":["../../../src/discovery/ast/call-route-finder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Node, SourceFile } from "ts-morph";
|
|
2
|
+
export interface DetectedHandler {
|
|
3
|
+
method: string;
|
|
4
|
+
fnNode: Node | undefined;
|
|
5
|
+
fnDecl: Node;
|
|
6
|
+
}
|
|
7
|
+
export declare function detectHandlers(sourceFile: SourceFile): DetectedHandler[];
|
|
8
|
+
//# sourceMappingURL=handler-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler-detector.d.ts","sourceRoot":"","sources":["../../../src/discovery/ast/handler-detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAc,MAAM,UAAU,CAAC;AAKxD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,IAAI,GAAG,SAAS,CAAC;IACzB,MAAM,EAAE,IAAI,CAAC;CACd;AAKD,wBAAgB,cAAc,CAAC,UAAU,EAAE,UAAU,GAAG,eAAe,EAAE,CA4BxE"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { SyntaxKind } from "ts-morph";
|
|
2
|
+
import { getFunctionBody, functionLikeFromExpression } from "./resolve.js";
|
|
3
|
+
const HTTP_METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"];
|
|
4
|
+
// Find exported route handlers named after HTTP methods, in all declaration
|
|
5
|
+
// forms: `export async function GET`, `export const GET = async () =>`,
|
|
6
|
+
// HOF-wrapped `export const POST = withAuth(fn)`, and re-exports.
|
|
7
|
+
export function detectHandlers(sourceFile) {
|
|
8
|
+
const handlers = [];
|
|
9
|
+
for (const method of HTTP_METHODS) {
|
|
10
|
+
// export async function GET() {}
|
|
11
|
+
const fn = sourceFile.getFunction(method);
|
|
12
|
+
if (fn && fn.isExported()) {
|
|
13
|
+
handlers.push({ method, fnNode: fn.getBody(), fnDecl: fn });
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
// export const GET = ... (arrow, function expr, or HOF call)
|
|
17
|
+
const varDecl = sourceFile.getVariableDeclaration(method);
|
|
18
|
+
if (varDecl && varDecl.isExported()) {
|
|
19
|
+
const init = varDecl.getInitializer();
|
|
20
|
+
const body = init ? functionLikeFromExpression(init) : undefined;
|
|
21
|
+
handlers.push({ method, fnNode: body, fnDecl: varDecl });
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
// export { GET } from "./handlers" OR export { GET }
|
|
25
|
+
const exported = resolveExportedDeclaration(sourceFile, method);
|
|
26
|
+
if (exported) {
|
|
27
|
+
handlers.push({ method, fnNode: getFunctionBody(exported), fnDecl: exported });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return handlers;
|
|
31
|
+
}
|
|
32
|
+
function resolveExportedDeclaration(sourceFile, name) {
|
|
33
|
+
try {
|
|
34
|
+
for (const exportDecl of sourceFile.getExportDeclarations()) {
|
|
35
|
+
for (const spec of exportDecl.getNamedExports()) {
|
|
36
|
+
if (spec.getName() === name || spec.getAliasNode()?.getText() === name) {
|
|
37
|
+
const nameNode = spec.getNameNode().asKind(SyntaxKind.Identifier);
|
|
38
|
+
if (!nameNode)
|
|
39
|
+
continue;
|
|
40
|
+
const defs = nameNode.getDefinitionNodes();
|
|
41
|
+
const local = defs.find((d) => {
|
|
42
|
+
const fp = d.getSourceFile().getFilePath();
|
|
43
|
+
return !fp.includes("node_modules") && !fp.endsWith(".d.ts");
|
|
44
|
+
});
|
|
45
|
+
if (local)
|
|
46
|
+
return local;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// best-effort
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=handler-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler-detector.js","sourceRoot":"","sources":["../../../src/discovery/ast/handler-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Node, SourceFile } from "ts-morph";
|
|
2
|
+
export interface NamedExport {
|
|
3
|
+
name: string;
|
|
4
|
+
body: Node | undefined;
|
|
5
|
+
}
|
|
6
|
+
export declare function findNamedExports(sourceFile: SourceFile, names: string[]): NamedExport[];
|
|
7
|
+
//# sourceMappingURL=named-export-finder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"named-export-finder.d.ts","sourceRoot":"","sources":["../../../src/discovery/ast/named-export-finder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAG5C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,IAAI,GAAG,SAAS,CAAC;CACxB;AAKD,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,CAkBvF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { functionLikeFromExpression } from "./resolve.js";
|
|
2
|
+
// Find exported declarations by exact name (e.g. Remix `loader`/`action`,
|
|
3
|
+
// SvelteKit `+server.ts` verb handlers / `load`). Handles both the function
|
|
4
|
+
// declaration and `export const name = async () => {}` forms.
|
|
5
|
+
export function findNamedExports(sourceFile, names) {
|
|
6
|
+
const out = [];
|
|
7
|
+
for (const name of names) {
|
|
8
|
+
const fn = sourceFile.getFunction(name);
|
|
9
|
+
if (fn && fn.isExported()) {
|
|
10
|
+
out.push({ name, body: fn.getBody() });
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
const varDecl = sourceFile.getVariableDeclaration(name);
|
|
14
|
+
if (varDecl && varDecl.isExported()) {
|
|
15
|
+
const init = varDecl.getInitializer();
|
|
16
|
+
out.push({ name, body: init ? functionLikeFromExpression(init) : undefined });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=named-export-finder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"named-export-finder.js","sourceRoot":"","sources":["../../../src/discovery/ast/named-export-finder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAO1D,0EAA0E;AAC1E,4EAA4E;AAC5E,8DAA8D;AAC9D,MAAM,UAAU,gBAAgB,CAAC,UAAsB,EAAE,KAAe;IACtE,MAAM,GAAG,GAAkB,EAAE,CAAC;IAE9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,EAAE,GAAG,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,EAAE,IAAI,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC;YAC1B,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACvC,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAG,UAAU,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC;QACxD,IAAI,OAAO,IAAI,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;YACpC,MAAM,IAAI,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;YACtC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,0BAA0B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;QAChF,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Node } from "ts-morph";
|
|
2
|
+
import type { ParameterDef } from "../types.js";
|
|
3
|
+
export declare function extractRouteParams(fnBody: Node | undefined): ParameterDef[];
|
|
4
|
+
export declare function extractParamsFromZodSchemaExpr(expr: Node | undefined): ParameterDef[];
|
|
5
|
+
export declare function enumerateClassProperties(decl: Node): ParameterDef[];
|
|
6
|
+
export declare function extractDeclaredParams(fnDecl: Node): ParameterDef[];
|
|
7
|
+
//# sourceMappingURL=param-extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"param-extractor.d.ts","sourceRoot":"","sources":["../../../src/discovery/ast/param-extractor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAwB,MAAM,UAAU,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAOhD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,IAAI,GAAG,SAAS,GAAG,YAAY,EAAE,CAkB3E;AAKD,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,GAAG,YAAY,EAAE,CAQrF;AAID,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,IAAI,GAAG,YAAY,EAAE,CAiBnE;AAmKD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,IAAI,GAAG,YAAY,EAAE,CA+BlE"}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { SyntaxKind, ts } from "ts-morph";
|
|
2
|
+
import { resolveDefinitions } from "./resolve.js";
|
|
3
|
+
// Extract parameters for a route handler. Strategy A: resolve the Zod schema
|
|
4
|
+
// passed to .parse()/.safeParse() (following imports across files) and walk its
|
|
5
|
+
// z.object({...}). Strategy B: fall back to the TS type of `await req.json()`
|
|
6
|
+
// when it's annotated (`const body: T = ...`) or cast (`... as T`).
|
|
7
|
+
export function extractRouteParams(fnBody) {
|
|
8
|
+
if (!fnBody)
|
|
9
|
+
return [];
|
|
10
|
+
try {
|
|
11
|
+
const zodParams = extractFromZodValidation(fnBody);
|
|
12
|
+
if (zodParams.length > 0)
|
|
13
|
+
return zodParams;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
// fall through
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
const typeParams = extractFromJsonType(fnBody);
|
|
20
|
+
if (typeParams.length > 0)
|
|
21
|
+
return typeParams;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// fall through
|
|
25
|
+
}
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
// Resolve a Zod schema expression directly to ParameterDef[]. Used where the
|
|
29
|
+
// schema is passed as an argument rather than reached via `.parse()` — e.g.
|
|
30
|
+
// tRPC `.input(schema)`, Hono `zValidator("json", schema)`, Fastify schema.body.
|
|
31
|
+
export function extractParamsFromZodSchemaExpr(expr) {
|
|
32
|
+
if (!expr)
|
|
33
|
+
return [];
|
|
34
|
+
try {
|
|
35
|
+
const objectLiteral = resolveZodObject(expr);
|
|
36
|
+
return objectLiteral ? parseZodObject(objectLiteral) : [];
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Enumerate the declared properties of a class or interface (e.g. a NestJS DTO).
|
|
43
|
+
// Syntactic (no type-checker), so it works even on partially-typed projects.
|
|
44
|
+
export function enumerateClassProperties(decl) {
|
|
45
|
+
const cls = decl.asKind(SyntaxKind.ClassDeclaration);
|
|
46
|
+
const iface = decl.asKind(SyntaxKind.InterfaceDeclaration);
|
|
47
|
+
const members = cls ? cls.getProperties() : iface ? iface.getProperties() : [];
|
|
48
|
+
const params = [];
|
|
49
|
+
for (const member of members) {
|
|
50
|
+
const name = member.getName();
|
|
51
|
+
if (!name)
|
|
52
|
+
continue;
|
|
53
|
+
const typeNode = member.getTypeNode();
|
|
54
|
+
params.push({
|
|
55
|
+
name,
|
|
56
|
+
type: typeNode ? typeNode.getText() : "unknown",
|
|
57
|
+
required: !member.hasQuestionToken(),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return params;
|
|
61
|
+
}
|
|
62
|
+
function extractFromZodValidation(fnBody) {
|
|
63
|
+
const calls = fnBody.getDescendantsOfKind(SyntaxKind.CallExpression);
|
|
64
|
+
for (const call of calls) {
|
|
65
|
+
const callee = call.getExpression();
|
|
66
|
+
if (callee.getKind() !== SyntaxKind.PropertyAccessExpression)
|
|
67
|
+
continue;
|
|
68
|
+
const prop = callee.asKind(SyntaxKind.PropertyAccessExpression);
|
|
69
|
+
const methodName = prop.getName();
|
|
70
|
+
if (methodName !== "parse" && methodName !== "safeParse")
|
|
71
|
+
continue;
|
|
72
|
+
// The object before .parse — e.g. InvoiceSchema
|
|
73
|
+
const schemaExpr = prop.getExpression();
|
|
74
|
+
const objectLiteral = resolveZodObject(schemaExpr);
|
|
75
|
+
if (objectLiteral) {
|
|
76
|
+
return parseZodObject(objectLiteral);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
// Resolve an expression to the z.object({...}) ObjectLiteralExpression it
|
|
82
|
+
// ultimately references, following an imported/local schema identifier.
|
|
83
|
+
function resolveZodObject(expr) {
|
|
84
|
+
// Inline: z.object({...}).parse(...)
|
|
85
|
+
const inline = findZodObjectArg(expr);
|
|
86
|
+
if (inline)
|
|
87
|
+
return inline;
|
|
88
|
+
// Identifier referencing a schema declared (possibly in another file)
|
|
89
|
+
if (expr.getKind() === SyntaxKind.Identifier) {
|
|
90
|
+
for (const def of resolveDefinitions(expr)) {
|
|
91
|
+
const varDecl = def.asKind(SyntaxKind.VariableDeclaration);
|
|
92
|
+
const init = varDecl?.getInitializer();
|
|
93
|
+
if (init) {
|
|
94
|
+
const obj = findZodObjectArg(init);
|
|
95
|
+
if (obj)
|
|
96
|
+
return obj;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
// Given an expression like z.object({...}) (possibly chained .strict() etc.),
|
|
103
|
+
// return the first ObjectLiteralExpression argument of a z.object(...) call.
|
|
104
|
+
function findZodObjectArg(expr) {
|
|
105
|
+
const calls = [
|
|
106
|
+
...(expr.getKind() === SyntaxKind.CallExpression ? [expr] : []),
|
|
107
|
+
...expr.getDescendantsOfKind(SyntaxKind.CallExpression),
|
|
108
|
+
];
|
|
109
|
+
for (const node of calls) {
|
|
110
|
+
const call = node.asKind(SyntaxKind.CallExpression);
|
|
111
|
+
if (!call)
|
|
112
|
+
continue;
|
|
113
|
+
const callee = call.getExpression();
|
|
114
|
+
if (callee.getKind() === SyntaxKind.PropertyAccessExpression) {
|
|
115
|
+
const prop = callee.asKind(SyntaxKind.PropertyAccessExpression);
|
|
116
|
+
if (prop.getName() === "object") {
|
|
117
|
+
const arg = call.getArguments()[0];
|
|
118
|
+
const obj = arg?.asKind(SyntaxKind.ObjectLiteralExpression);
|
|
119
|
+
if (obj)
|
|
120
|
+
return obj;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
function parseZodObject(objectLiteral) {
|
|
127
|
+
const obj = objectLiteral.asKind(SyntaxKind.ObjectLiteralExpression);
|
|
128
|
+
if (!obj)
|
|
129
|
+
return [];
|
|
130
|
+
const params = [];
|
|
131
|
+
for (const prop of obj.getProperties()) {
|
|
132
|
+
const assignment = prop.asKind(SyntaxKind.PropertyAssignment);
|
|
133
|
+
if (!assignment)
|
|
134
|
+
continue;
|
|
135
|
+
const name = assignment.getName().replace(/['"]/g, "");
|
|
136
|
+
const valueText = assignment.getInitializer()?.getText() ?? "";
|
|
137
|
+
const type = zodBaseType(valueText);
|
|
138
|
+
const required = !valueText.includes(".optional()") && !valueText.includes(".default(");
|
|
139
|
+
params.push({ name, type, required });
|
|
140
|
+
}
|
|
141
|
+
return params;
|
|
142
|
+
}
|
|
143
|
+
function zodBaseType(text) {
|
|
144
|
+
// z.string() -> string, z.coerce.number() -> number
|
|
145
|
+
const m = text.match(/z\.(?:coerce\.)?(\w+)\(/);
|
|
146
|
+
return m ? m[1] : "unknown";
|
|
147
|
+
}
|
|
148
|
+
// Strategy B: when a route reads `await req.json()` and the result is typed via
|
|
149
|
+
// annotation or `as` cast, enumerate that type's properties through the checker.
|
|
150
|
+
function extractFromJsonType(fnBody) {
|
|
151
|
+
const calls = fnBody.getDescendantsOfKind(SyntaxKind.CallExpression);
|
|
152
|
+
for (const call of calls) {
|
|
153
|
+
const prop = call.getExpression().asKind(SyntaxKind.PropertyAccessExpression);
|
|
154
|
+
if (!prop || prop.getName() !== "json")
|
|
155
|
+
continue;
|
|
156
|
+
const bodyType = resolveJsonBodyType(call);
|
|
157
|
+
if (bodyType) {
|
|
158
|
+
const params = enumerateTypeProperties(bodyType);
|
|
159
|
+
if (params.length > 0)
|
|
160
|
+
return params;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return [];
|
|
164
|
+
}
|
|
165
|
+
// Climb out of `req.json()` through await/parens to the type annotation or cast.
|
|
166
|
+
function resolveJsonBodyType(call) {
|
|
167
|
+
let node = call;
|
|
168
|
+
let parent = node.getParent();
|
|
169
|
+
while (parent &&
|
|
170
|
+
(parent.getKind() === SyntaxKind.AwaitExpression ||
|
|
171
|
+
parent.getKind() === SyntaxKind.ParenthesizedExpression)) {
|
|
172
|
+
node = parent;
|
|
173
|
+
parent = parent.getParent();
|
|
174
|
+
}
|
|
175
|
+
if (!parent)
|
|
176
|
+
return undefined;
|
|
177
|
+
// const body = (await req.json()) as CreateUser
|
|
178
|
+
const asExpr = parent.asKind(SyntaxKind.AsExpression);
|
|
179
|
+
if (asExpr)
|
|
180
|
+
return asExpr.getTypeNode()?.getType();
|
|
181
|
+
// const body: CreateUser = await req.json()
|
|
182
|
+
const varDecl = parent.asKind(SyntaxKind.VariableDeclaration);
|
|
183
|
+
if (varDecl)
|
|
184
|
+
return varDecl.getTypeNode()?.getType();
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
function enumerateTypeProperties(type) {
|
|
188
|
+
const params = [];
|
|
189
|
+
for (const symbol of type.getProperties()) {
|
|
190
|
+
const name = symbol.getName();
|
|
191
|
+
const optional = (symbol.getFlags() & ts.SymbolFlags.Optional) !== 0;
|
|
192
|
+
let typeText = "unknown";
|
|
193
|
+
const decl = symbol.getDeclarations()[0];
|
|
194
|
+
if (decl) {
|
|
195
|
+
try {
|
|
196
|
+
typeText = symbol.getTypeAtLocation(decl).getText().replace(/ \| undefined$/, "");
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
typeText = "unknown";
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
params.push({ name, type: typeText, required: !optional });
|
|
203
|
+
}
|
|
204
|
+
return params;
|
|
205
|
+
}
|
|
206
|
+
// Build ParameterDef[] from a function's declared parameters (server actions).
|
|
207
|
+
export function extractDeclaredParams(fnDecl) {
|
|
208
|
+
const params = [];
|
|
209
|
+
const fn = fnDecl.asKind(SyntaxKind.FunctionDeclaration) ||
|
|
210
|
+
fnDecl.asKind(SyntaxKind.ArrowFunction) ||
|
|
211
|
+
fnDecl.asKind(SyntaxKind.FunctionExpression);
|
|
212
|
+
if (!fn)
|
|
213
|
+
return [];
|
|
214
|
+
for (const param of fn.getParameters()) {
|
|
215
|
+
const nameNode = param.getNameNode();
|
|
216
|
+
let name;
|
|
217
|
+
if (nameNode.getKind() === SyntaxKind.ObjectBindingPattern || nameNode.getKind() === SyntaxKind.ArrayBindingPattern) {
|
|
218
|
+
name = nameNode.getText();
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
name = param.getName();
|
|
222
|
+
}
|
|
223
|
+
let type = "unknown";
|
|
224
|
+
try {
|
|
225
|
+
const typeNode = param.getTypeNode();
|
|
226
|
+
type = typeNode ? typeNode.getText() : param.getType().getText();
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
type = "unknown";
|
|
230
|
+
}
|
|
231
|
+
const required = !param.isOptional() && !param.hasInitializer();
|
|
232
|
+
params.push({ name, type, required });
|
|
233
|
+
}
|
|
234
|
+
return params;
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=param-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"param-extractor.js","sourceRoot":"","sources":["../../../src/discovery/ast/param-extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Project } from "ts-morph";
|
|
2
|
+
export interface AstContext {
|
|
3
|
+
project: Project;
|
|
4
|
+
projectRoot: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function createAstContext(projectRoot: string): AstContext;
|
|
7
|
+
export declare function addFile(ast: AstContext, filePath: string): import("ts-morph").SourceFile | undefined;
|
|
8
|
+
//# sourceMappingURL=project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../../src/discovery/ast/project.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAM,MAAM,UAAU,CAAC;AAEvC,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAQD,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,UAAU,CAqBhE;AAwBD,wBAAgB,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,6CASxD"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { Project, ts } from "ts-morph";
|
|
4
|
+
// Build a ts-morph Project for the target codebase. Loads the target's tsconfig
|
|
5
|
+
// for compiler options + path aliases when present (without loading the whole
|
|
6
|
+
// repo), else falls back to sane in-memory defaults. Dependency resolution is
|
|
7
|
+
// left ON so cross-file symbol resolution (getDefinitionNodes) works when we
|
|
8
|
+
// add an entry file — the graph is bounded because we only add route/action
|
|
9
|
+
// files explicitly, never the whole tsconfig.
|
|
10
|
+
export function createAstContext(projectRoot) {
|
|
11
|
+
const tsconfigPath = [
|
|
12
|
+
path.join(projectRoot, "tsconfig.json"),
|
|
13
|
+
path.join(projectRoot, "src", "tsconfig.json"),
|
|
14
|
+
].find((p) => fs.existsSync(p));
|
|
15
|
+
let project;
|
|
16
|
+
try {
|
|
17
|
+
if (tsconfigPath) {
|
|
18
|
+
project = new Project({
|
|
19
|
+
tsConfigFilePath: tsconfigPath,
|
|
20
|
+
skipAddingFilesFromTsConfig: true,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
project = makeInMemoryProject(projectRoot);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
project = makeInMemoryProject(projectRoot);
|
|
29
|
+
}
|
|
30
|
+
return { project, projectRoot };
|
|
31
|
+
}
|
|
32
|
+
function makeInMemoryProject(projectRoot) {
|
|
33
|
+
return new Project({
|
|
34
|
+
skipAddingFilesFromTsConfig: true,
|
|
35
|
+
compilerOptions: {
|
|
36
|
+
target: ts.ScriptTarget.ES2022,
|
|
37
|
+
module: ts.ModuleKind.NodeNext,
|
|
38
|
+
moduleResolution: ts.ModuleResolutionKind.NodeNext,
|
|
39
|
+
jsx: ts.JsxEmit.Preserve,
|
|
40
|
+
allowJs: true,
|
|
41
|
+
// NestJS and other decorator-based frameworks need these to parse cleanly.
|
|
42
|
+
experimentalDecorators: true,
|
|
43
|
+
emitDecoratorMetadata: true,
|
|
44
|
+
baseUrl: projectRoot,
|
|
45
|
+
// Common Next.js alias default so resolution works even without a tsconfig.
|
|
46
|
+
paths: { "@/*": ["./src/*", "./*"] },
|
|
47
|
+
noEmit: true,
|
|
48
|
+
strict: false,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
// Add a single file to the project on demand. Skips node_modules and .d.ts.
|
|
53
|
+
export function addFile(ast, filePath) {
|
|
54
|
+
if (filePath.includes("node_modules") || filePath.endsWith(".d.ts"))
|
|
55
|
+
return undefined;
|
|
56
|
+
const existing = ast.project.getSourceFile(filePath);
|
|
57
|
+
if (existing)
|
|
58
|
+
return existing;
|
|
59
|
+
try {
|
|
60
|
+
return ast.project.addSourceFileAtPathIfExists(filePath);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../../src/discovery/ast/project.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAOvC,gFAAgF;AAChF,8EAA8E;AAC9E,8EAA8E;AAC9E,6EAA6E;AAC7E,4EAA4E;AAC5E,8CAA8C;AAC9C,MAAM,UAAU,gBAAgB,CAAC,WAAmB;IAClD,MAAM,YAAY,GAAG;QACnB,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,eAAe,CAAC;KAC/C,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAEhC,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACH,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO,GAAG,IAAI,OAAO,CAAC;gBACpB,gBAAgB,EAAE,YAAY;gBAC9B,2BAA2B,EAAE,IAAI;aAClC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,mBAAmB,CAAC,WAAW,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,mBAAmB,CAAC,WAAW,CAAC,CAAC;IAC7C,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;AAClC,CAAC;AAED,SAAS,mBAAmB,CAAC,WAAmB;IAC9C,OAAO,IAAI,OAAO,CAAC;QACjB,2BAA2B,EAAE,IAAI;QACjC,eAAe,EAAE;YACf,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM;YAC9B,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ;YAC9B,gBAAgB,EAAE,EAAE,CAAC,oBAAoB,CAAC,QAAQ;YAClD,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ;YACxB,OAAO,EAAE,IAAI;YACb,2EAA2E;YAC3E,sBAAsB,EAAE,IAAI;YAC5B,qBAAqB,EAAE,IAAI;YAC3B,OAAO,EAAE,WAAW;YACpB,4EAA4E;YAC5E,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE;YACpC,MAAM,EAAE,IAAI;YACZ,MAAM,EAAE,KAAK;SACd;KACF,CAAC,CAAC;AACL,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,OAAO,CAAC,GAAe,EAAE,QAAgB;IACvD,IAAI,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,SAAS,CAAC;IACtF,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IACrD,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,IAAI,CAAC;QACH,OAAO,GAAG,CAAC,OAAO,CAAC,2BAA2B,CAAC,QAAQ,CAAC,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Node } from "ts-morph";
|
|
2
|
+
export declare function resolveDefinitions(node: Node): Node[];
|
|
3
|
+
export declare function getFunctionBody(decl: Node): Node | undefined;
|
|
4
|
+
export declare function functionLikeFromExpression(expr: Node): Node | undefined;
|
|
5
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/discovery/ast/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAc,MAAM,UAAU,CAAC;AAK5C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,CAYrD;AAKD,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,CAkB5D;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,CAiBvE"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { SyntaxKind } from "ts-morph";
|
|
2
|
+
// Resolve an identifier node to its definition declarations, following imports
|
|
3
|
+
// across files. Project-local only (skips node_modules and .d.ts). Best-effort:
|
|
4
|
+
// returns [] on any resolution failure.
|
|
5
|
+
export function resolveDefinitions(node) {
|
|
6
|
+
try {
|
|
7
|
+
const id = node.asKind(SyntaxKind.Identifier);
|
|
8
|
+
if (!id)
|
|
9
|
+
return [];
|
|
10
|
+
const defs = id.getDefinitionNodes();
|
|
11
|
+
return defs.filter((d) => {
|
|
12
|
+
const fp = d.getSourceFile().getFilePath();
|
|
13
|
+
return !fp.includes("node_modules") && !fp.endsWith(".d.ts");
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
// Given a declaration node, return the function-like body node to recurse into,
|
|
21
|
+
// handling: function declarations, arrow/function-expression initializers on
|
|
22
|
+
// variable declarations, and HOF-wrapped function arguments.
|
|
23
|
+
export function getFunctionBody(decl) {
|
|
24
|
+
// function foo() {}
|
|
25
|
+
const fn = decl.asKind(SyntaxKind.FunctionDeclaration);
|
|
26
|
+
if (fn)
|
|
27
|
+
return fn.getBody();
|
|
28
|
+
// class method foo() {} — e.g. a NestJS service method reached via this.svc.foo()
|
|
29
|
+
const method = decl.asKind(SyntaxKind.MethodDeclaration);
|
|
30
|
+
if (method)
|
|
31
|
+
return method.getBody();
|
|
32
|
+
// const foo = () => {} | function () {}
|
|
33
|
+
const varDecl = decl.asKind(SyntaxKind.VariableDeclaration);
|
|
34
|
+
if (varDecl) {
|
|
35
|
+
const init = varDecl.getInitializer();
|
|
36
|
+
if (init)
|
|
37
|
+
return functionLikeFromExpression(init);
|
|
38
|
+
}
|
|
39
|
+
// Already a function-like node
|
|
40
|
+
return functionLikeFromExpression(decl);
|
|
41
|
+
}
|
|
42
|
+
export function functionLikeFromExpression(expr) {
|
|
43
|
+
const arrow = expr.asKind(SyntaxKind.ArrowFunction);
|
|
44
|
+
if (arrow)
|
|
45
|
+
return arrow.getBody();
|
|
46
|
+
const fnExpr = expr.asKind(SyntaxKind.FunctionExpression);
|
|
47
|
+
if (fnExpr)
|
|
48
|
+
return fnExpr.getBody();
|
|
49
|
+
// HOF-wrapped: withAuth(async () => {...}) — unwrap first function-like arg
|
|
50
|
+
const call = expr.asKind(SyntaxKind.CallExpression);
|
|
51
|
+
if (call) {
|
|
52
|
+
for (const arg of call.getArguments()) {
|
|
53
|
+
const body = functionLikeFromExpression(arg);
|
|
54
|
+
if (body)
|
|
55
|
+
return body;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=resolve.js.map
|