@sdk-it/generic 0.38.0 → 0.40.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.js
CHANGED
|
@@ -10,9 +10,36 @@ import {
|
|
|
10
10
|
isHttpMethod,
|
|
11
11
|
toSchema
|
|
12
12
|
} from "@sdk-it/core";
|
|
13
|
-
|
|
13
|
+
function symbolFile(symbol) {
|
|
14
|
+
if (!symbol) {
|
|
15
|
+
return void 0;
|
|
16
|
+
}
|
|
17
|
+
const declarations = symbol.declarations ?? [];
|
|
18
|
+
if (declarations.length === 0) {
|
|
19
|
+
return void 0;
|
|
20
|
+
}
|
|
21
|
+
const sourceFile = declarations[0].getSourceFile();
|
|
22
|
+
return sourceFile?.fileName;
|
|
23
|
+
}
|
|
24
|
+
function isExternalFunction(symbol) {
|
|
25
|
+
const fileName = symbolFile(symbol);
|
|
26
|
+
return fileName ? fileName.includes("node_modules") : false;
|
|
27
|
+
}
|
|
28
|
+
function isLocalFunction(symbol) {
|
|
29
|
+
if (!symbol) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return !isExternalFunction(symbol);
|
|
33
|
+
}
|
|
34
|
+
var returnTokens = (node, typeChecker, options) => {
|
|
14
35
|
const tokens = [];
|
|
15
|
-
const
|
|
36
|
+
const consider3rdParty = options?.consider3rdParty ?? false;
|
|
37
|
+
const maxDepth = options?.maxDepth ?? 5;
|
|
38
|
+
const visitedFunctions = /* @__PURE__ */ new Set();
|
|
39
|
+
const visitor = (node2, depth) => {
|
|
40
|
+
if (depth > maxDepth) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
16
43
|
if (ts.isThrowStatement(node2)) {
|
|
17
44
|
if (ts.isNewExpression(node2.expression)) {
|
|
18
45
|
tokens.push({
|
|
@@ -28,11 +55,45 @@ var returnToken = (node) => {
|
|
|
28
55
|
node: node2.expression
|
|
29
56
|
});
|
|
30
57
|
}
|
|
31
|
-
|
|
58
|
+
if (ts.isNewExpression(node2.expression)) {
|
|
59
|
+
tokens.push({
|
|
60
|
+
token: `new.${node2.expression.expression.getText()}`,
|
|
61
|
+
node: node2.expression
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
ts.forEachChild(node2.expression, (child) => visitor(child, depth));
|
|
65
|
+
return;
|
|
32
66
|
}
|
|
33
|
-
|
|
67
|
+
if (ts.isCallExpression(node2) && typeChecker && depth < maxDepth) {
|
|
68
|
+
const callExpression = node2;
|
|
69
|
+
let symbol;
|
|
70
|
+
if (ts.isIdentifier(callExpression.expression)) {
|
|
71
|
+
symbol = typeChecker.getSymbolAtLocation(callExpression.expression);
|
|
72
|
+
} else if (ts.isPropertyAccessExpression(callExpression.expression)) {
|
|
73
|
+
symbol = typeChecker.getSymbolAtLocation(
|
|
74
|
+
callExpression.expression.name
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
if (symbol && symbol.flags & ts.SymbolFlags.Alias) {
|
|
78
|
+
symbol = typeChecker.getAliasedSymbol(symbol);
|
|
79
|
+
}
|
|
80
|
+
const shouldFollow = consider3rdParty || isLocalFunction(symbol);
|
|
81
|
+
if (shouldFollow && symbol) {
|
|
82
|
+
const declarations = symbol?.declarations ?? [];
|
|
83
|
+
for (const declaration of declarations) {
|
|
84
|
+
if (visitedFunctions.has(declaration)) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (isFunctionWithBody(declaration) && declaration.body) {
|
|
88
|
+
visitedFunctions.add(declaration);
|
|
89
|
+
visitor(declaration.body, depth + 1);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
ts.forEachChild(node2, (child) => visitor(child, depth));
|
|
34
95
|
};
|
|
35
|
-
|
|
96
|
+
visitor(node, 0);
|
|
36
97
|
return tokens;
|
|
37
98
|
};
|
|
38
99
|
var logger = debug("@sdk-it/generic");
|
|
@@ -94,7 +155,7 @@ function parseJSDocComment(node) {
|
|
|
94
155
|
summary
|
|
95
156
|
};
|
|
96
157
|
}
|
|
97
|
-
function visit(node, responseAnalyzer2, paths) {
|
|
158
|
+
function visit(node, responseAnalyzer2, paths, typeChecker) {
|
|
98
159
|
if (!ts.isCallExpression(node) || node.arguments.length < 2) {
|
|
99
160
|
return moveOn();
|
|
100
161
|
}
|
|
@@ -139,13 +200,53 @@ function visit(node, responseAnalyzer2, paths) {
|
|
|
139
200
|
if (!selector || !ts.isParenthesizedExpression(selector.body) || !ts.isObjectLiteralExpression(selector.body.expression)) {
|
|
140
201
|
return moveOn();
|
|
141
202
|
}
|
|
203
|
+
const middlewareDeclarations = [];
|
|
204
|
+
for (const arg of node.arguments.slice(1, -1)) {
|
|
205
|
+
if (ts.isCallExpression(arg)) {
|
|
206
|
+
if (ts.isIdentifier(arg.expression)) {
|
|
207
|
+
let symbol = typeChecker.getSymbolAtLocation(arg.expression);
|
|
208
|
+
if (symbol && symbol.flags & ts.SymbolFlags.Alias) {
|
|
209
|
+
symbol = typeChecker.getAliasedSymbol(symbol);
|
|
210
|
+
}
|
|
211
|
+
const allDeclarations = [
|
|
212
|
+
symbol?.valueDeclaration,
|
|
213
|
+
...symbol?.declarations ?? []
|
|
214
|
+
].filter((it) => !!it);
|
|
215
|
+
let declaration = allDeclarations.find(isFunctionWithBody);
|
|
216
|
+
if (!declaration) {
|
|
217
|
+
for (const decl of allDeclarations) {
|
|
218
|
+
if (ts.isVariableDeclaration(decl) && decl.initializer) {
|
|
219
|
+
if (isFunctionWithBody(decl.initializer)) {
|
|
220
|
+
declaration = decl.initializer;
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (declaration) {
|
|
227
|
+
middlewareDeclarations.push(declaration);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (ts.isIdentifier(arg.expression) && arg.expression.text === "validate") {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
const firstArg = arg.arguments[0];
|
|
234
|
+
if (isFunctionWithBody(firstArg)) {
|
|
235
|
+
middlewareDeclarations.push(firstArg);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
142
239
|
const props = selector.body.expression.properties.filter(
|
|
143
240
|
ts.isPropertyAssignment
|
|
144
241
|
);
|
|
145
242
|
const sourceFile = node.getSourceFile();
|
|
146
|
-
const tokens = returnToken(handler);
|
|
147
243
|
const responses = [];
|
|
148
|
-
for (const
|
|
244
|
+
for (const middlewareDecl of middlewareDeclarations) {
|
|
245
|
+
for (const { token, node: node2 } of returnTokens(middlewareDecl, typeChecker)) {
|
|
246
|
+
responses.push(...responseAnalyzer2(middlewareDecl, token, node2));
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
for (const { token, node: node2 } of returnTokens(handler, typeChecker)) {
|
|
149
250
|
responses.push(...responseAnalyzer2(handler, token, node2));
|
|
150
251
|
}
|
|
151
252
|
paths.addPath(
|
|
@@ -159,7 +260,10 @@ function visit(node, responseAnalyzer2, paths) {
|
|
|
159
260
|
metadata
|
|
160
261
|
);
|
|
161
262
|
function moveOn() {
|
|
162
|
-
ts.forEachChild(
|
|
263
|
+
ts.forEachChild(
|
|
264
|
+
node,
|
|
265
|
+
(node2) => visit(node2, responseAnalyzer2, paths, typeChecker)
|
|
266
|
+
);
|
|
163
267
|
}
|
|
164
268
|
}
|
|
165
269
|
function toSelectors(props) {
|
|
@@ -216,7 +320,8 @@ async function analyze(tsconfigPath, config) {
|
|
|
216
320
|
}
|
|
217
321
|
return responseAnalyzer2(handler, typeDeriver);
|
|
218
322
|
},
|
|
219
|
-
paths
|
|
323
|
+
paths,
|
|
324
|
+
typeChecker
|
|
220
325
|
);
|
|
221
326
|
}
|
|
222
327
|
}
|
|
@@ -232,6 +337,12 @@ async function analyze(tsconfigPath, config) {
|
|
|
232
337
|
components
|
|
233
338
|
};
|
|
234
339
|
}
|
|
340
|
+
function isFunctionWithBody(node) {
|
|
341
|
+
if (!node) {
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
return (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node) || ts.isConstructorDeclaration(node) || ts.isGetAccessor(node) || ts.isSetAccessor(node)) && !!node.body;
|
|
345
|
+
}
|
|
235
346
|
|
|
236
347
|
// packages/generic/src/lib/response-analyzer.ts
|
|
237
348
|
import ts2 from "typescript";
|
|
@@ -322,6 +433,6 @@ export {
|
|
|
322
433
|
analyze,
|
|
323
434
|
defaultResponseAnalyzer,
|
|
324
435
|
responseAnalyzer,
|
|
325
|
-
|
|
436
|
+
returnTokens
|
|
326
437
|
};
|
|
327
438
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/lib/generic.ts", "../src/lib/response-analyzer.ts"],
|
|
4
|
-
"sourcesContent": ["import debug from 'debug';\nimport type { ComponentsObject } from 'openapi3-ts/oas31';\nimport { camelcase } from 'stringcase';\nimport ts from 'typescript';\n\nimport {\n type InjectImport,\n type NaunceResponseAnalyzer,\n type OnOperation,\n Paths,\n type ResponseAnalyzerFn,\n type ResponseItem,\n type Selector,\n type SemanticSource,\n TypeDeriver,\n getProgram,\n isCallExpression,\n isHttpMethod,\n toSchema,\n} from '@sdk-it/core';\n\nexport const returnToken = (node: ts.ArrowFunction) => {\n const tokens: { token: string; node: ts.Expression }[] = [];\n\n const visitor: ts.Visitor = (node) => {\n if (ts.isThrowStatement(node)) {\n if (ts.isNewExpression(node.expression)) {\n tokens.push({\n token: `throw.new.${node.expression.expression.getText()}`,\n node: node.expression,\n });\n }\n }\n\n if (ts.isReturnStatement(node) && node.expression) {\n if (ts.isCallExpression(node.expression)) {\n tokens.push({\n token: node.expression.expression.getText(),\n node: node.expression,\n });\n }\n return undefined;\n }\n\n return ts.forEachChild(node, visitor);\n };\n\n ts.forEachChild(node, visitor);\n return tokens;\n};\n\nconst logger = debug('@sdk-it/generic');\n\nconst jsDocsTags = [\n 'openapi',\n 'tags',\n 'description',\n 'summary',\n 'access',\n 'tool',\n 'toolDescription',\n] as const;\ntype JSDocsTags = (typeof jsDocsTags)[number];\n\nfunction parseJSDocComment(node: ts.Node) {\n let tags: string[] = [];\n let name = '';\n let description = '';\n let summary = '';\n let access = '';\n let tool = '';\n let toolDescription = '';\n\n for (const tag of ts.getAllJSDocTags(node, (tag): tag is ts.JSDocTag =>\n jsDocsTags.includes(tag.tagName.text as JSDocsTags),\n )) {\n if (typeof tag.comment !== 'string') {\n continue;\n }\n switch (tag.tagName.text as JSDocsTags) {\n case 'openapi':\n name = tag.comment;\n break;\n case 'tags':\n tags = tag.comment.split(',').map((tag) => tag.trim());\n break;\n case 'description':\n description = tag.comment;\n break;\n case 'summary':\n summary = tag.comment;\n break;\n case 'access':\n access = tag.comment.trim().toLowerCase();\n break;\n case 'tool':\n tool = tag.comment.trim();\n break;\n case 'toolDescription':\n toolDescription = tag.comment.trim();\n break;\n }\n }\n return {\n name,\n tags,\n description,\n access,\n tool,\n toolDescription,\n summary,\n };\n}\n\nfunction visit(\n node: ts.Node,\n responseAnalyzer: (\n handler: ts.ArrowFunction,\n token: string,\n node: ts.Node,\n ) => ResponseItem[],\n paths: Paths,\n) {\n if (!ts.isCallExpression(node) || node.arguments.length < 2) {\n return moveOn();\n }\n if (\n !ts.isPropertyAccessExpression(node.expression) ||\n !ts.isIdentifier(node.expression.name) ||\n !isHttpMethod(node.expression.name.text)\n ) {\n return moveOn();\n }\n\n const [pathNode] = node.arguments;\n if (!ts.isStringLiteral(pathNode)) {\n return moveOn();\n }\n const method = node.expression.name.text;\n const path = pathNode.text;\n const validate = node.arguments.find((arg) =>\n isCallExpression(arg, 'validate'),\n );\n if (!validate) {\n return moveOn();\n }\n const handler = node.arguments.at(-1);\n if (!handler || !ts.isArrowFunction(handler)) {\n return moveOn();\n }\n\n const metadata = parseJSDocComment(node.parent);\n // Skip endpoints marked as private access\n if (metadata.access === 'private') {\n return moveOn();\n }\n const operationName =\n metadata.name ||\n camelcase(`${method} ${path.replace(/[^a-zA-Z0-9]/g, '')}`);\n if (!validate.arguments.length) {\n return moveOn();\n }\n let selector: ts.Expression | undefined;\n let contentType: ts.Expression | undefined;\n if (validate.arguments.length === 2) {\n contentType = validate.arguments[0];\n selector = validate.arguments[1];\n } else {\n selector = validate.arguments[0];\n }\n if (!ts.isArrowFunction(selector)) {\n return moveOn();\n }\n if (\n !selector ||\n !ts.isParenthesizedExpression(selector.body) ||\n !ts.isObjectLiteralExpression(selector.body.expression)\n ) {\n return moveOn();\n }\n const props = selector.body.expression.properties.filter(\n ts.isPropertyAssignment,\n );\n\n const sourceFile = node.getSourceFile();\n const tokens = returnToken(handler);\n\n const responses: ResponseItem[] = [];\n for (const { token, node } of tokens) {\n responses.push(...responseAnalyzer(handler, token, node));\n }\n\n paths.addPath(\n operationName,\n path,\n method,\n contentType\n ? ts.isStringLiteral(contentType)\n ? contentType.text\n : undefined\n : undefined,\n toSelectors(props),\n responses,\n sourceFile.fileName,\n metadata,\n );\n\n function moveOn() {\n ts.forEachChild(node, (node) => visit(node, responseAnalyzer, paths));\n }\n}\n\nfunction toSelectors(props: ts.PropertyAssignment[]) {\n const selectors: Selector[] = [];\n for (const prop of props) {\n if (!ts.isObjectLiteralExpression(prop.initializer)) {\n continue;\n }\n const name = prop.name.getText();\n const select = prop.initializer.properties\n .filter(ts.isPropertyAssignment)\n .find((prop) => prop.name.getText() === 'select');\n if (!select) {\n console.warn(`No select found in ${name}`);\n continue;\n }\n const against = prop.initializer.properties\n .filter(ts.isPropertyAssignment)\n .find((prop) => prop.name.getText() === 'against');\n if (!against) {\n console.warn(`No against found in ${name}`);\n continue;\n }\n const [, source, selectText] = select.initializer.getText().split('.');\n selectors.push({\n name: selectText,\n against: against.initializer.getText(),\n source: source as SemanticSource,\n });\n }\n return selectors;\n}\n\nexport async function analyze(\n tsconfigPath: string,\n config: {\n /**\n * Additional code to inject before resolving zod schemas\n */\n imports?: InjectImport[];\n typesMap?: Record<string, string>;\n responseAnalyzer: ResponseAnalyzerFn | NaunceResponseAnalyzer;\n onOperation?: OnOperation;\n },\n) {\n logger(`Parsing tsconfig`);\n const program = getProgram(tsconfigPath);\n logger(`Program created`);\n const typeChecker = program.getTypeChecker();\n\n logger(`Type checker created`);\n const typeDeriver = new TypeDeriver(typeChecker, config.typesMap);\n const paths = new Paths({\n imports: config.imports ?? [],\n onOperation: config.onOperation,\n });\n\n for (const sourceFile of program.getSourceFiles()) {\n logger(`Analyzing ${sourceFile.fileName}`);\n if (!sourceFile.isDeclarationFile) {\n logger(`Visiting ${sourceFile.fileName}`);\n visit(\n sourceFile,\n (handler, token, node) => {\n const responseAnalyzer = config.responseAnalyzer;\n if (typeof responseAnalyzer !== 'function') {\n const naunce =\n responseAnalyzer[token] || responseAnalyzer['default'];\n if (!naunce) {\n throw new Error(`No response analyzer for token ${token}`);\n }\n return naunce(handler, typeDeriver, node);\n }\n return responseAnalyzer(handler, typeDeriver);\n },\n paths,\n );\n }\n }\n\n const components: ComponentsObject = {\n schemas: Object.entries(typeDeriver.collector).reduce(\n (acc, [key, value]) => ({ ...acc, [key]: toSchema(value) }),\n {},\n ),\n };\n\n return {\n paths: await paths.getPaths(),\n tags: paths.getTags(),\n components,\n };\n}\n\nexport type Serialized = ReturnType<typeof analyze>;\n", "import ts from 'typescript';\n\nimport type {\n NaunceResponseAnalyzer,\n ResponseItem,\n TypeDeriver,\n} from '@sdk-it/core';\n\nconst handlerVisitor: (\n on: (\n node: ts.Node | undefined,\n statusCode: ts.Node | undefined,\n headers: ts.Node | undefined,\n contentType: string,\n ) => void,\n) => ts.Visitor = (callback) => {\n return (node: ts.Node) => {\n if (ts.isReturnStatement(node) && node.expression) {\n if (\n ts.isCallExpression(node.expression) &&\n ts.isPropertyAccessExpression(node.expression.expression)\n ) {\n const propAccess = node.expression.expression;\n if (\n ts.isIdentifier(propAccess.expression) &&\n propAccess.expression.text === 'output'\n ) {\n let contentType = 'application/json';\n const callerMethod = propAccess.name.text;\n const [body, statusCode, headers] = node.expression.arguments;\n if (callerMethod === 'attachment') {\n contentType = 'application/octet-stream';\n }\n if (!body) {\n contentType = 'empty';\n }\n callback(body, statusCode, headers, contentType);\n }\n }\n }\n return ts.forEachChild(node, handlerVisitor(callback));\n };\n};\n\nfunction toResponses(handler: ts.ArrowFunction, deriver: TypeDeriver) {\n const responsesList: ResponseItem[] = [];\n const visit = handlerVisitor((node, statusCode, headers, contentType) => {\n responsesList.push({\n headers: headers ? Object.keys(deriver.serializeNode(headers)) : [],\n contentType,\n statusCode: statusCode ? resolveStatusCode(statusCode) : '200',\n response: node ? deriver.serializeNode(node) : undefined,\n });\n });\n visit(handler.body);\n return responsesList;\n}\n\nfunction resolveStatusCode(node: ts.Node) {\n if (ts.isNumericLiteral(node)) {\n return node.text;\n }\n throw new Error(`Could not resolve status code`);\n}\n\nexport function defaultResponseAnalyzer(\n handler: ts.ArrowFunction,\n deriver: TypeDeriver,\n) {\n try {\n return toResponses(handler, deriver);\n } catch (error) {\n console.error('Error analyzing response\\n', handler.getText());\n throw error;\n }\n}\n\nexport const responseAnalyzer: NaunceResponseAnalyzer = {\n 'throw.new.ProblemDetailsException': (handler, deriver, node) => {\n if (ts.isNewExpression(node)) {\n const [problem] = node.arguments ?? [];\n if (!ts.isObjectLiteralExpression(problem)) {\n return [];\n }\n const properties = problem.properties.reduce<Record<string, string>>(\n (acc, prop) => {\n if (ts.isPropertyAssignment(prop)) {\n const key = prop.name.getText();\n if (ts.isLiteralExpression(prop.initializer)) {\n acc[key] = prop.initializer.text;\n } else {\n acc[key] = prop.initializer.getText();\n }\n }\n return acc;\n },\n {},\n );\n return [\n {\n contentType: 'application/problem+json',\n headers: [],\n statusCode: properties.status,\n response: problem ? deriver.serializeNode(problem) : undefined,\n },\n ];\n }\n return [];\n },\n default: defaultResponseAnalyzer,\n};\n\nexport default responseAnalyzer;"],
|
|
5
|
-
"mappings": ";AAAA,OAAO,WAAW;AAElB,SAAS,iBAAiB;AAC1B,OAAO,QAAQ;AAEf;AAAA,EAIE;AAAA,EAKA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEA,
|
|
4
|
+
"sourcesContent": ["import debug from 'debug';\nimport type { ComponentsObject } from 'openapi3-ts/oas31';\nimport { camelcase } from 'stringcase';\nimport ts from 'typescript';\n\nimport {\n type InjectImport,\n type NaunceResponseAnalyzer,\n type OnOperation,\n Paths,\n type ResponseAnalyzerFn,\n type ResponseItem,\n type Selector,\n type SemanticSource,\n TypeDeriver,\n getProgram,\n isCallExpression,\n isHttpMethod,\n toSchema,\n} from '@sdk-it/core';\n\n/**\n * Gets the file path from a symbol's first declaration\n */\nfunction symbolFile(symbol: ts.Symbol | undefined): string | undefined {\n if (!symbol) {\n return undefined;\n }\n\n const declarations = symbol.declarations ?? [];\n if (declarations.length === 0) {\n return undefined;\n }\n\n const sourceFile = declarations[0].getSourceFile();\n return sourceFile?.fileName;\n}\n\n/**\n * Determines if a symbol is from an external library (node_modules)\n */\nfunction isExternalFunction(symbol: ts.Symbol | undefined): boolean {\n const fileName = symbolFile(symbol);\n return fileName ? fileName.includes('node_modules') : false;\n}\n\n/**\n * Determines if a symbol refers to a local function (not from node_modules)\n */\nfunction isLocalFunction(symbol: ts.Symbol | undefined): boolean {\n if (!symbol) {\n return false;\n }\n\n return !isExternalFunction(symbol);\n}\n\nexport const returnTokens = (\n node: ts.Node,\n typeChecker?: ts.TypeChecker,\n options?: { consider3rdParty?: boolean; maxDepth?: number },\n) => {\n const tokens: { token: string; node: ts.Expression }[] = [];\n const consider3rdParty = options?.consider3rdParty ?? false;\n const maxDepth = options?.maxDepth ?? 5;\n // Track visited function declarations to prevent infinite recursion\n const visitedFunctions = new Set<ts.Declaration>();\n\n const visitor = (node: ts.Node, depth: number): void => {\n // Skip if we've exceeded max depth\n if (depth > maxDepth) {\n return;\n }\n\n if (ts.isThrowStatement(node)) {\n if (ts.isNewExpression(node.expression)) {\n tokens.push({\n token: `throw.new.${node.expression.expression.getText()}`,\n node: node.expression,\n });\n }\n }\n\n if (ts.isReturnStatement(node) && node.expression) {\n if (ts.isCallExpression(node.expression)) {\n tokens.push({\n token: node.expression.expression.getText(),\n node: node.expression,\n });\n }\n if (ts.isNewExpression(node.expression)) {\n tokens.push({\n token: `new.${node.expression.expression.getText()}`,\n node: node.expression,\n });\n }\n // Continue traversing into the returned expression (e.g., arrow functions)\n // This handles: return async (c, next) => { throw ... }\n ts.forEachChild(node.expression, (child) => visitor(child, depth));\n return;\n }\n\n // If we encounter a call expression and have a type checker, follow it\n if (ts.isCallExpression(node) && typeChecker && depth < maxDepth) {\n const callExpression = node;\n\n // Try to resolve the function being called\n let symbol: ts.Symbol | undefined;\n\n if (ts.isIdentifier(callExpression.expression)) {\n symbol = typeChecker.getSymbolAtLocation(callExpression.expression);\n } else if (ts.isPropertyAccessExpression(callExpression.expression)) {\n symbol = typeChecker.getSymbolAtLocation(\n callExpression.expression.name,\n );\n }\n\n // Resolve aliases\n if (symbol && symbol.flags & ts.SymbolFlags.Alias) {\n symbol = typeChecker.getAliasedSymbol(symbol);\n }\n\n // Check if we should follow this function\n const shouldFollow = consider3rdParty || isLocalFunction(symbol);\n\n if (shouldFollow && symbol) {\n const declarations = symbol?.declarations ?? [];\n\n for (const declaration of declarations) {\n // Skip if we've already visited this function (prevent infinite recursion)\n if (visitedFunctions.has(declaration)) {\n continue;\n }\n\n if (isFunctionWithBody(declaration) && declaration.body) {\n visitedFunctions.add(declaration);\n // Recursively visit the function body with incremented depth\n visitor(declaration.body, depth + 1);\n }\n }\n }\n }\n\n ts.forEachChild(node, (child) => visitor(child, depth));\n };\n\n visitor(node, 0);\n return tokens;\n};\n\nconst logger = debug('@sdk-it/generic');\n\nconst jsDocsTags = [\n 'openapi',\n 'tags',\n 'description',\n 'summary',\n 'access',\n 'tool',\n 'toolDescription',\n] as const;\ntype JSDocsTags = (typeof jsDocsTags)[number];\n\nfunction parseJSDocComment(node: ts.Node) {\n let tags: string[] = [];\n let name = '';\n let description = '';\n let summary = '';\n let access = '';\n let tool = '';\n let toolDescription = '';\n\n for (const tag of ts.getAllJSDocTags(node, (tag): tag is ts.JSDocTag =>\n jsDocsTags.includes(tag.tagName.text as JSDocsTags),\n )) {\n if (typeof tag.comment !== 'string') {\n continue;\n }\n switch (tag.tagName.text as JSDocsTags) {\n case 'openapi':\n name = tag.comment;\n break;\n case 'tags':\n tags = tag.comment.split(',').map((tag) => tag.trim());\n break;\n case 'description':\n description = tag.comment;\n break;\n case 'summary':\n summary = tag.comment;\n break;\n case 'access':\n access = tag.comment.trim().toLowerCase();\n break;\n case 'tool':\n tool = tag.comment.trim();\n break;\n case 'toolDescription':\n toolDescription = tag.comment.trim();\n break;\n }\n }\n return {\n name,\n tags,\n description,\n access,\n tool,\n toolDescription,\n summary,\n };\n}\n\nfunction visit(\n node: ts.Node,\n responseAnalyzer: (\n handler: ts.ArrowFunction | ts.FunctionExpression,\n token: string,\n node: ts.Node,\n ) => ResponseItem[],\n paths: Paths,\n typeChecker: ts.TypeChecker,\n) {\n if (!ts.isCallExpression(node) || node.arguments.length < 2) {\n return moveOn();\n }\n if (\n !ts.isPropertyAccessExpression(node.expression) ||\n !ts.isIdentifier(node.expression.name) ||\n !isHttpMethod(node.expression.name.text)\n ) {\n return moveOn();\n }\n\n const [pathNode] = node.arguments;\n if (!ts.isStringLiteral(pathNode)) {\n return moveOn();\n }\n const method = node.expression.name.text;\n const path = pathNode.text;\n const validate = node.arguments.find((arg) =>\n isCallExpression(arg, 'validate'),\n );\n if (!validate) {\n return moveOn();\n }\n const handler = node.arguments.at(-1);\n if (!handler || !ts.isArrowFunction(handler)) {\n return moveOn();\n }\n const metadata = parseJSDocComment(node.parent);\n // Skip endpoints marked as private access\n if (metadata.access === 'private') {\n return moveOn();\n }\n const operationName =\n metadata.name ||\n camelcase(`${method} ${path.replace(/[^a-zA-Z0-9]/g, '')}`);\n if (!validate.arguments.length) {\n return moveOn();\n }\n\n let selector: ts.Expression | undefined;\n let contentType: ts.Expression | undefined;\n if (validate.arguments.length === 2) {\n contentType = validate.arguments[0];\n selector = validate.arguments[1];\n } else {\n selector = validate.arguments[0];\n }\n if (!ts.isArrowFunction(selector)) {\n return moveOn();\n }\n if (\n !selector ||\n !ts.isParenthesizedExpression(selector.body) ||\n !ts.isObjectLiteralExpression(selector.body.expression)\n ) {\n return moveOn();\n }\n\n // Collect all middleware declarations for analysis\n const middlewareDeclarations: ts.Node[] = [];\n\n // slice(1, -1) to skip first (path) and last (handler) arguments\n // and skip the validate middleware - it's handled separately\n for (const arg of node.arguments.slice(1, -1)) {\n if (ts.isCallExpression(arg)) {\n // Try to resolve the factory function declaration\n if (ts.isIdentifier(arg.expression)) {\n let symbol = typeChecker.getSymbolAtLocation(arg.expression);\n\n // If symbol has alias, resolve to the actual symbol\n if (symbol && symbol.flags & ts.SymbolFlags.Alias) {\n symbol = typeChecker.getAliasedSymbol(symbol);\n }\n\n const allDeclarations = [\n symbol?.valueDeclaration,\n ...(symbol?.declarations ?? []),\n ].filter((it) => !!it);\n\n let declaration = allDeclarations.find(isFunctionWithBody);\n\n // If not found, check for variable declarations with function initializers\n if (!declaration) {\n for (const decl of allDeclarations) {\n if (ts.isVariableDeclaration(decl) && decl.initializer) {\n if (isFunctionWithBody(decl.initializer)) {\n declaration = decl.initializer;\n break;\n }\n }\n }\n }\n\n if (declaration) {\n middlewareDeclarations.push(declaration);\n }\n }\n\n // Also check if the call expression argument itself is an arrow function\n // e.g., middleware((ctx) => {...})\n // But skip if the function name is 'validate'\n if (\n ts.isIdentifier(arg.expression) &&\n arg.expression.text === 'validate'\n ) {\n continue;\n }\n const firstArg = arg.arguments[0];\n if (isFunctionWithBody(firstArg)) {\n middlewareDeclarations.push(firstArg);\n }\n }\n }\n\n const props = selector.body.expression.properties.filter(\n ts.isPropertyAssignment,\n );\n\n const sourceFile = node.getSourceFile();\n\n const responses: ResponseItem[] = [];\n\n // Analyze all middlewares for potential responses\n for (const middlewareDecl of middlewareDeclarations) {\n for (const { token, node } of returnTokens(middlewareDecl, typeChecker)) {\n responses.push(...responseAnalyzer(middlewareDecl as any, token, node));\n }\n }\n\n // Analyze the main handler for responses\n for (const { token, node } of returnTokens(handler, typeChecker)) {\n responses.push(...responseAnalyzer(handler, token, node));\n }\n\n paths.addPath(\n operationName,\n path,\n method,\n contentType\n ? ts.isStringLiteral(contentType)\n ? contentType.text\n : undefined\n : undefined,\n toSelectors(props),\n responses,\n sourceFile.fileName,\n metadata,\n );\n\n function moveOn() {\n ts.forEachChild(node, (node) =>\n visit(node, responseAnalyzer, paths, typeChecker),\n );\n }\n}\n\nfunction toSelectors(props: ts.PropertyAssignment[]) {\n const selectors: Selector[] = [];\n for (const prop of props) {\n if (!ts.isObjectLiteralExpression(prop.initializer)) {\n continue;\n }\n const name = prop.name.getText();\n const select = prop.initializer.properties\n .filter(ts.isPropertyAssignment)\n .find((prop) => prop.name.getText() === 'select');\n if (!select) {\n console.warn(`No select found in ${name}`);\n continue;\n }\n const against = prop.initializer.properties\n .filter(ts.isPropertyAssignment)\n .find((prop) => prop.name.getText() === 'against');\n if (!against) {\n console.warn(`No against found in ${name}`);\n continue;\n }\n const [, source, selectText] = select.initializer.getText().split('.');\n selectors.push({\n name: selectText,\n against: against.initializer.getText(),\n source: source as SemanticSource,\n });\n }\n return selectors;\n}\n\nexport async function analyze(\n tsconfigPath: string,\n config: {\n /**\n * Additional code to inject before resolving zod schemas\n */\n imports?: InjectImport[];\n typesMap?: Record<string, string>;\n responseAnalyzer: ResponseAnalyzerFn | NaunceResponseAnalyzer;\n onOperation?: OnOperation;\n },\n) {\n logger(`Parsing tsconfig`);\n const program = getProgram(tsconfigPath);\n logger(`Program created`);\n const typeChecker = program.getTypeChecker();\n\n logger(`Type checker created`);\n const typeDeriver = new TypeDeriver(typeChecker, config.typesMap);\n const paths = new Paths({\n imports: config.imports ?? [],\n onOperation: config.onOperation,\n });\n\n for (const sourceFile of program.getSourceFiles()) {\n logger(`Analyzing ${sourceFile.fileName}`);\n if (!sourceFile.isDeclarationFile) {\n logger(`Visiting ${sourceFile.fileName}`);\n visit(\n sourceFile,\n (handler, token, node) => {\n const responseAnalyzer = config.responseAnalyzer;\n if (typeof responseAnalyzer !== 'function') {\n const naunce =\n responseAnalyzer[token] || responseAnalyzer['default'];\n if (!naunce) {\n throw new Error(`No response analyzer for token ${token}`);\n }\n return naunce(handler, typeDeriver, node);\n }\n return responseAnalyzer(handler, typeDeriver);\n },\n paths,\n typeChecker,\n );\n }\n }\n\n const components: ComponentsObject = {\n schemas: Object.entries(typeDeriver.collector).reduce(\n (acc, [key, value]) => ({ ...acc, [key]: toSchema(value) }),\n {},\n ),\n };\n\n return {\n paths: await paths.getPaths(),\n tags: paths.getTags(),\n components,\n };\n}\n\nexport type Serialized = ReturnType<typeof analyze>;\n\nfunction isFunctionWithBody(\n node: ts.Node | ts.Declaration | undefined,\n): node is ts.FunctionLikeDeclaration & { body: ts.Block | ts.Expression } {\n if (!node) {\n return false;\n }\n return (\n (ts.isFunctionDeclaration(node) ||\n ts.isFunctionExpression(node) ||\n ts.isArrowFunction(node) ||\n ts.isMethodDeclaration(node) ||\n ts.isConstructorDeclaration(node) ||\n ts.isGetAccessor(node) ||\n ts.isSetAccessor(node)) &&\n !!node.body\n );\n}\n", "import ts from 'typescript';\n\nimport type {\n NaunceResponseAnalyzer,\n ResponseItem,\n TypeDeriver,\n} from '@sdk-it/core';\n\nconst handlerVisitor: (\n on: (\n node: ts.Node | undefined,\n statusCode: ts.Node | undefined,\n headers: ts.Node | undefined,\n contentType: string,\n ) => void,\n) => ts.Visitor = (callback) => {\n return (node: ts.Node) => {\n if (ts.isReturnStatement(node) && node.expression) {\n if (\n ts.isCallExpression(node.expression) &&\n ts.isPropertyAccessExpression(node.expression.expression)\n ) {\n const propAccess = node.expression.expression;\n if (\n ts.isIdentifier(propAccess.expression) &&\n propAccess.expression.text === 'output'\n ) {\n let contentType = 'application/json';\n const callerMethod = propAccess.name.text;\n const [body, statusCode, headers] = node.expression.arguments;\n if (callerMethod === 'attachment') {\n contentType = 'application/octet-stream';\n }\n if (!body) {\n contentType = 'empty';\n }\n callback(body, statusCode, headers, contentType);\n }\n }\n }\n return ts.forEachChild(node, handlerVisitor(callback));\n };\n};\n\nfunction toResponses(\n handler: ts.ArrowFunction | ts.FunctionExpression,\n deriver: TypeDeriver,\n) {\n const responsesList: ResponseItem[] = [];\n const visit = handlerVisitor((node, statusCode, headers, contentType) => {\n responsesList.push({\n headers: headers ? Object.keys(deriver.serializeNode(headers)) : [],\n contentType,\n statusCode: statusCode ? resolveStatusCode(statusCode) : '200',\n response: node ? deriver.serializeNode(node) : undefined,\n });\n });\n visit(handler.body);\n return responsesList;\n}\n\nfunction resolveStatusCode(node: ts.Node) {\n if (ts.isNumericLiteral(node)) {\n return node.text;\n }\n throw new Error(`Could not resolve status code`);\n}\n\nexport function defaultResponseAnalyzer(\n handler: ts.ArrowFunction | ts.FunctionExpression,\n deriver: TypeDeriver,\n) {\n try {\n return toResponses(handler, deriver);\n } catch (error) {\n console.error('Error analyzing response\\n', handler.getText());\n throw error;\n }\n}\n\nexport const responseAnalyzer: NaunceResponseAnalyzer = {\n 'throw.new.ProblemDetailsException': (handler, deriver, node) => {\n if (ts.isNewExpression(node)) {\n const [problem] = node.arguments ?? [];\n if (!ts.isObjectLiteralExpression(problem)) {\n return [];\n }\n const properties = problem.properties.reduce<Record<string, string>>(\n (acc, prop) => {\n if (ts.isPropertyAssignment(prop)) {\n const key = prop.name.getText();\n if (ts.isLiteralExpression(prop.initializer)) {\n acc[key] = prop.initializer.text;\n } else {\n acc[key] = prop.initializer.getText();\n }\n }\n return acc;\n },\n {},\n );\n return [\n {\n contentType: 'application/problem+json',\n headers: [],\n statusCode: properties.status,\n response: problem ? deriver.serializeNode(problem) : undefined,\n },\n ];\n }\n return [];\n },\n default: defaultResponseAnalyzer,\n};\n\nexport default responseAnalyzer;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["node", "tag", "responseAnalyzer", "prop", "ts", "visit"]
|
|
7
7
|
}
|
package/dist/lib/generic.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { ComponentsObject } from 'openapi3-ts/oas31';
|
|
2
2
|
import ts from 'typescript';
|
|
3
3
|
import { type InjectImport, type NaunceResponseAnalyzer, type OnOperation, type ResponseAnalyzerFn } from '@sdk-it/core';
|
|
4
|
-
export declare const
|
|
4
|
+
export declare const returnTokens: (node: ts.Node, typeChecker?: ts.TypeChecker, options?: {
|
|
5
|
+
consider3rdParty?: boolean;
|
|
6
|
+
maxDepth?: number;
|
|
7
|
+
}) => {
|
|
5
8
|
token: string;
|
|
6
9
|
node: ts.Expression;
|
|
7
10
|
}[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generic.d.ts","sourceRoot":"","sources":["../../src/lib/generic.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,sBAAsB,EAC3B,KAAK,WAAW,EAEhB,KAAK,kBAAkB,EASxB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"generic.d.ts","sourceRoot":"","sources":["../../src/lib/generic.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,sBAAsB,EAC3B,KAAK,WAAW,EAEhB,KAAK,kBAAkB,EASxB,MAAM,cAAc,CAAC;AAsCtB,eAAO,MAAM,YAAY,GACvB,MAAM,EAAE,CAAC,IAAI,EACb,cAAc,EAAE,CAAC,WAAW,EAC5B,UAAU;IAAE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE;WAEpC,MAAM;UAAQ,EAAE,CAAC,UAAU;GAsFnD,CAAC;AAsQF,wBAAsB,OAAO,CAC3B,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE;IACN;;OAEG;IACH,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,gBAAgB,EAAE,kBAAkB,GAAG,sBAAsB,CAAC;IAC9D,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;;;;GAkDF;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
2
|
import type { NaunceResponseAnalyzer, ResponseItem, TypeDeriver } from '@sdk-it/core';
|
|
3
|
-
export declare function defaultResponseAnalyzer(handler: ts.ArrowFunction, deriver: TypeDeriver): ResponseItem[];
|
|
3
|
+
export declare function defaultResponseAnalyzer(handler: ts.ArrowFunction | ts.FunctionExpression, deriver: TypeDeriver): ResponseItem[];
|
|
4
4
|
export declare const responseAnalyzer: NaunceResponseAnalyzer;
|
|
5
5
|
export default responseAnalyzer;
|
|
6
6
|
//# sourceMappingURL=response-analyzer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response-analyzer.d.ts","sourceRoot":"","sources":["../../src/lib/response-analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,KAAK,EACV,sBAAsB,EACtB,YAAY,EACZ,WAAW,EACZ,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"response-analyzer.d.ts","sourceRoot":"","sources":["../../src/lib/response-analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,KAAK,EACV,sBAAsB,EACtB,YAAY,EACZ,WAAW,EACZ,MAAM,cAAc,CAAC;AA8DtB,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,EAAE,CAAC,aAAa,GAAG,EAAE,CAAC,kBAAkB,EACjD,OAAO,EAAE,WAAW,kBAQrB;AAED,eAAO,MAAM,gBAAgB,EAAE,sBAiC9B,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sdk-it/generic",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"!**/*.test.*"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@sdk-it/core": "0.
|
|
25
|
+
"@sdk-it/core": "0.40.0",
|
|
26
26
|
"stringcase": "^4.3.1",
|
|
27
27
|
"debug": "^4.4.0",
|
|
28
28
|
"openapi3-ts": "^4.4.0"
|