@sdk-it/generic 0.40.0 → 0.42.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 +10 -10
- package/dist/index.js +33 -15
- package/dist/index.js.map +2 -2
- package/dist/lib/generic.d.ts.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
<p align="center">A TypeScript analysis tool for generating OpenAPI specifications from TypeScript code</p>
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Analyzes TypeScript code to generate OpenAPI specifications. Extracts route information, parameter types, and response schemas from your codebase.
|
|
6
6
|
|
|
7
7
|
## Frameworks specific integrations
|
|
8
8
|
|
|
@@ -82,7 +82,7 @@ You can customize the operations as well as add more through the `onOperation` f
|
|
|
82
82
|
|
|
83
83
|
**Use file name as tag**
|
|
84
84
|
|
|
85
|
-
Assuming your
|
|
85
|
+
Assuming your project is structured like the following, where routes are grouped by representative file names:
|
|
86
86
|
|
|
87
87
|
```
|
|
88
88
|
apps/
|
|
@@ -93,7 +93,7 @@ apps/
|
|
|
93
93
|
authors.ts
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
The file name becomes the default tag for each operation. Specify a tag in JSDoc only to override this default.
|
|
97
97
|
|
|
98
98
|
```typescript
|
|
99
99
|
import { basename } from 'node:path';
|
|
@@ -119,9 +119,9 @@ const { paths, components } = await analyze('apps/backend/tsconfig.app.json', {
|
|
|
119
119
|
|
|
120
120
|
### Customizing Type Mappings
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
Custom type mappings handle non-standard TypeScript types like Prisma's `Decimal`. Use the `typesMap` option in `analyze` to define your mappings.
|
|
123
123
|
|
|
124
|
-
The example below
|
|
124
|
+
The example below maps `Decimal` to `string`.
|
|
125
125
|
|
|
126
126
|
```typescript
|
|
127
127
|
import { writeFile } from 'node:fs/promises';
|
|
@@ -158,11 +158,11 @@ const spec = {
|
|
|
158
158
|
await writeFile('openapi.json', JSON.stringify(spec, null, 2));
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
-
|
|
161
|
+
With this, the generator maps `Decimal` properties to `string` in the OpenAPI specification.
|
|
162
162
|
|
|
163
163
|
### Referencing external schemas
|
|
164
164
|
|
|
165
|
-
By default, the analyzer
|
|
165
|
+
By default, the analyzer only sees schemas defined inline in the validate middleware.
|
|
166
166
|
|
|
167
167
|
For instance the following route handler is perfectly valid and will be analyzed correctly.
|
|
168
168
|
|
|
@@ -229,9 +229,9 @@ app.post(
|
|
|
229
229
|
);
|
|
230
230
|
```
|
|
231
231
|
|
|
232
|
-
|
|
232
|
+
The analyzer must resolve the `authorSchema` reference to generate the correct OpenAPI schema. Otherwise it will fail.
|
|
233
233
|
|
|
234
|
-
|
|
234
|
+
The analyzer's `imports` option lets you include additional files in the analysis.
|
|
235
235
|
|
|
236
236
|
```ts
|
|
237
237
|
import { join } from 'node:path';
|
|
@@ -279,7 +279,7 @@ app.post(
|
|
|
279
279
|
|
|
280
280
|
### Control endpoint/operation visibility
|
|
281
281
|
|
|
282
|
-
|
|
282
|
+
Control endpoint visibility with the `@access` tag in JSDoc comments. For now, only `private` is supported.
|
|
283
283
|
|
|
284
284
|
```typescript
|
|
285
285
|
/**
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import ts from "typescript";
|
|
|
5
5
|
import {
|
|
6
6
|
Paths,
|
|
7
7
|
TypeDeriver,
|
|
8
|
+
nodeLocation,
|
|
8
9
|
getProgram,
|
|
9
10
|
isCallExpression,
|
|
10
11
|
isHttpMethod,
|
|
@@ -155,7 +156,7 @@ function parseJSDocComment(node) {
|
|
|
155
156
|
summary
|
|
156
157
|
};
|
|
157
158
|
}
|
|
158
|
-
function visit(node, responseAnalyzer2, paths, typeChecker) {
|
|
159
|
+
function visit(node, responseAnalyzer2, paths, typeChecker, typeDeriver) {
|
|
159
160
|
if (!ts.isCallExpression(node) || node.arguments.length < 2) {
|
|
160
161
|
return moveOn();
|
|
161
162
|
}
|
|
@@ -204,6 +205,7 @@ function visit(node, responseAnalyzer2, paths, typeChecker) {
|
|
|
204
205
|
for (const arg of node.arguments.slice(1, -1)) {
|
|
205
206
|
if (ts.isCallExpression(arg)) {
|
|
206
207
|
if (ts.isIdentifier(arg.expression)) {
|
|
208
|
+
const middlewareFnName = arg.expression.text;
|
|
207
209
|
let symbol = typeChecker.getSymbolAtLocation(arg.expression);
|
|
208
210
|
if (symbol && symbol.flags & ts.SymbolFlags.Alias) {
|
|
209
211
|
symbol = typeChecker.getAliasedSymbol(symbol);
|
|
@@ -224,7 +226,7 @@ function visit(node, responseAnalyzer2, paths, typeChecker) {
|
|
|
224
226
|
}
|
|
225
227
|
}
|
|
226
228
|
if (declaration) {
|
|
227
|
-
middlewareDeclarations.push(declaration);
|
|
229
|
+
middlewareDeclarations.push({ node: declaration, name: middlewareFnName });
|
|
228
230
|
}
|
|
229
231
|
}
|
|
230
232
|
if (ts.isIdentifier(arg.expression) && arg.expression.text === "validate") {
|
|
@@ -232,7 +234,7 @@ function visit(node, responseAnalyzer2, paths, typeChecker) {
|
|
|
232
234
|
}
|
|
233
235
|
const firstArg = arg.arguments[0];
|
|
234
236
|
if (isFunctionWithBody(firstArg)) {
|
|
235
|
-
middlewareDeclarations.push(firstArg);
|
|
237
|
+
middlewareDeclarations.push({ node: firstArg });
|
|
236
238
|
}
|
|
237
239
|
}
|
|
238
240
|
}
|
|
@@ -240,10 +242,20 @@ function visit(node, responseAnalyzer2, paths, typeChecker) {
|
|
|
240
242
|
ts.isPropertyAssignment
|
|
241
243
|
);
|
|
242
244
|
const sourceFile = node.getSourceFile();
|
|
245
|
+
typeDeriver.setTrace({
|
|
246
|
+
file: sourceFile.fileName,
|
|
247
|
+
operation: `${method.toUpperCase()} ${path}`
|
|
248
|
+
});
|
|
243
249
|
const responses = [];
|
|
244
|
-
for (const
|
|
245
|
-
for (const { token, node: node2 } of returnTokens(
|
|
246
|
-
|
|
250
|
+
for (const middleware of middlewareDeclarations) {
|
|
251
|
+
for (const { token, node: node2 } of returnTokens(middleware.node, typeChecker)) {
|
|
252
|
+
const items = responseAnalyzer2(middleware.node, token, node2);
|
|
253
|
+
if (middleware.name) {
|
|
254
|
+
for (const item of items) {
|
|
255
|
+
item.middlewareName = middleware.name;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
responses.push(...items);
|
|
247
259
|
}
|
|
248
260
|
}
|
|
249
261
|
for (const { token, node: node2 } of returnTokens(handler, typeChecker)) {
|
|
@@ -262,7 +274,7 @@ function visit(node, responseAnalyzer2, paths, typeChecker) {
|
|
|
262
274
|
function moveOn() {
|
|
263
275
|
ts.forEachChild(
|
|
264
276
|
node,
|
|
265
|
-
(node2) => visit(node2, responseAnalyzer2, paths, typeChecker)
|
|
277
|
+
(node2) => visit(node2, responseAnalyzer2, paths, typeChecker, typeDeriver)
|
|
266
278
|
);
|
|
267
279
|
}
|
|
268
280
|
}
|
|
@@ -275,12 +287,14 @@ function toSelectors(props) {
|
|
|
275
287
|
const name = prop.name.getText();
|
|
276
288
|
const select = prop.initializer.properties.filter(ts.isPropertyAssignment).find((prop2) => prop2.name.getText() === "select");
|
|
277
289
|
if (!select) {
|
|
278
|
-
console.warn(
|
|
290
|
+
console.warn(`\u26A0 No select found in ${name}
|
|
291
|
+
at ${nodeLocation(prop) ?? "unknown"}`);
|
|
279
292
|
continue;
|
|
280
293
|
}
|
|
281
294
|
const against = prop.initializer.properties.filter(ts.isPropertyAssignment).find((prop2) => prop2.name.getText() === "against");
|
|
282
295
|
if (!against) {
|
|
283
|
-
console.warn(
|
|
296
|
+
console.warn(`\u26A0 No against found in ${name}
|
|
297
|
+
at ${nodeLocation(prop) ?? "unknown"}`);
|
|
284
298
|
continue;
|
|
285
299
|
}
|
|
286
300
|
const [, source, selectText] = select.initializer.getText().split(".");
|
|
@@ -321,15 +335,19 @@ async function analyze(tsconfigPath, config) {
|
|
|
321
335
|
return responseAnalyzer2(handler, typeDeriver);
|
|
322
336
|
},
|
|
323
337
|
paths,
|
|
324
|
-
typeChecker
|
|
338
|
+
typeChecker,
|
|
339
|
+
typeDeriver
|
|
325
340
|
);
|
|
326
341
|
}
|
|
327
342
|
}
|
|
328
343
|
const components = {
|
|
329
|
-
schemas:
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
344
|
+
schemas: {
|
|
345
|
+
...paths.getSharedSchemas(),
|
|
346
|
+
...Object.entries(typeDeriver.collector).reduce(
|
|
347
|
+
(acc, [key, value]) => ({ ...acc, [key]: toSchema(value) }),
|
|
348
|
+
{}
|
|
349
|
+
)
|
|
350
|
+
}
|
|
333
351
|
};
|
|
334
352
|
return {
|
|
335
353
|
paths: await paths.getPaths(),
|
|
@@ -421,7 +439,7 @@ var responseAnalyzer = {
|
|
|
421
439
|
contentType: "application/problem+json",
|
|
422
440
|
headers: [],
|
|
423
441
|
statusCode: properties.status,
|
|
424
|
-
response:
|
|
442
|
+
response: deriver.serializeNode(problem)
|
|
425
443
|
}
|
|
426
444
|
];
|
|
427
445
|
}
|
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\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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
|
|
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 nodeLocation,\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 typeDeriver: TypeDeriver,\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: { node: ts.Node; name?: string }[] = [];\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 const middlewareFnName = arg.expression.text;\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({ node: declaration, name: middlewareFnName });\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({ node: 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 typeDeriver.setTrace({\n file: sourceFile.fileName,\n operation: `${method.toUpperCase()} ${path}`,\n });\n\n const responses: ResponseItem[] = [];\n\n // Analyze all middlewares for potential responses\n for (const middleware of middlewareDeclarations) {\n for (const { token, node } of returnTokens(middleware.node, typeChecker)) {\n const items = responseAnalyzer(middleware.node as any, token, node);\n if (middleware.name) {\n for (const item of items) {\n item.middlewareName = middleware.name;\n }\n }\n responses.push(...items);\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, typeDeriver),\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(`\\u26a0 No select found in ${name}\\n at ${nodeLocation(prop) ?? 'unknown'}`);\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(`\\u26a0 No against found in ${name}\\n at ${nodeLocation(prop) ?? 'unknown'}`);\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 typeDeriver,\n );\n }\n }\n\n const components: ComponentsObject = {\n schemas: {\n ...paths.getSharedSchemas(),\n ...Object.entries(typeDeriver.collector).reduce(\n (acc, [key, value]) => ({ ...acc, [key]: toSchema(value) }),\n {},\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: deriver.serializeNode(problem),\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
|
}
|
|
@@ -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,
|
|
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,EAUxB,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;AAmRF,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;;;;GAsDF;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sdk-it/generic",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.42.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.42.0",
|
|
26
26
|
"stringcase": "^4.3.1",
|
|
27
27
|
"debug": "^4.4.0",
|
|
28
28
|
"openapi3-ts": "^4.4.0"
|