typera-openapi
Advanced tools
Comparing version 0.11.2 to 0.11.3
@@ -205,3 +205,3 @@ "use strict"; | ||
.flatMap((c) => c.getParameters()) | ||
.flatMap((param) => ctx.checker.getTypeOfSymbolAtLocation(param, routeConstructor)); | ||
.map((param) => ctx.checker.getTypeOfSymbolAtLocation(param, routeConstructor)); | ||
if (routeHandlerParamTypes.length !== 1) { | ||
@@ -248,12 +248,29 @@ ctx.log('warn', 'Route handler should have one parameter'); | ||
const descriptions = getResponseDescriptions(symbol); | ||
const routeType = ctx.checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration); | ||
if (!routeType.aliasSymbol || | ||
!utils_1.isPackageSymbol(routeType.aliasSymbol, 'typera-common', 'Route')) { | ||
const location = symbol.valueDeclaration; | ||
const routeType = ctx.checker.getTypeOfSymbolAtLocation(symbol, location); | ||
// interface Route<Response> { | ||
// ... | ||
// routeHandler: (req: unknown) => Promise<Response> | ||
// } | ||
// | ||
// We want to dig out the type of `Response`. | ||
const routeHandlerSymbol = routeType.getProperty('routeHandler'); | ||
if (!routeHandlerSymbol) { | ||
ctx.log('warn', 'Not a valid route: No routeHandler method'); | ||
return; | ||
} | ||
const args = routeType.aliasTypeArguments; | ||
if (!args || args.length !== 1) { | ||
throw new Error('expected 1 type argument for Route'); | ||
const routeHandlerType = ctx.checker.getTypeOfSymbolAtLocation(routeHandlerSymbol, location); | ||
const returnTypes = routeHandlerType | ||
.getCallSignatures() | ||
.map((c) => c.getReturnType()); | ||
if (returnTypes.length !== 1) { | ||
ctx.log('warn', 'Not a valid route: Invalid routeHandler return type'); | ||
return; | ||
} | ||
const responseType = args[0]; | ||
// returnType is a Promise | ||
const responseType = utils_1.getPromisePayloadType(context_1.withLocation(ctx, location), returnTypes[0]); | ||
if (!responseType) { | ||
ctx.log('warn', 'Not a valid route: routeHandler does not return a promise'); | ||
return; | ||
} | ||
const result = {}; | ||
@@ -260,0 +277,0 @@ if (utils_1.isObjectType(responseType)) { |
@@ -18,3 +18,2 @@ import * as ts from 'typescript'; | ||
export declare const getPropertyType: (checker: ts.TypeChecker, location: ts.Node, type: ts.Type, propertyName: string) => ts.Type | undefined; | ||
export declare const isPackageSymbol: (symbol: ts.Symbol, packageName: string, symbolName: string) => boolean; | ||
export declare const getBrandedType: (ctx: Context, type: ts.Type) => { | ||
@@ -24,1 +23,2 @@ brandName: string; | ||
} | undefined; | ||
export declare const getPromisePayloadType: (ctx: Context, type: ts.Type) => ts.Type | undefined; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getBrandedType = exports.isPackageSymbol = exports.getPropertyType = exports.isBufferType = exports.isDateType = exports.isNullType = exports.isUndefinedType = exports.isStringLiteralType = exports.isNumberLiteralType = exports.isBooleanLiteralType = exports.isBooleanType = exports.isNumberType = exports.isStringType = exports.isObjectType = exports.isArrayType = exports.isOptional = exports.isDefined = void 0; | ||
exports.getPromisePayloadType = exports.getBrandedType = exports.getPropertyType = exports.isBufferType = exports.isDateType = exports.isNullType = exports.isUndefinedType = exports.isStringLiteralType = exports.isNumberLiteralType = exports.isBooleanLiteralType = exports.isBooleanType = exports.isNumberType = exports.isStringType = exports.isObjectType = exports.isArrayType = exports.isOptional = exports.isDefined = void 0; | ||
const ts = require("typescript"); | ||
@@ -58,10 +58,2 @@ const isDefined = (value) => value !== undefined; | ||
exports.getPropertyType = getPropertyType; | ||
const isPackageSymbol = (symbol, packageName, symbolName) => { | ||
var _a; | ||
const parent = ((_a = symbol.valueDeclaration) !== null && _a !== void 0 ? _a : symbol.declarations[0]).parent; | ||
return (symbol.name === symbolName && | ||
ts.isSourceFile(parent) && | ||
parent.fileName.includes(`/${packageName}/`)); | ||
}; | ||
exports.isPackageSymbol = isPackageSymbol; | ||
const getBrandedType = (ctx, type) => { | ||
@@ -79,1 +71,29 @@ if (!type.isIntersection() || type.types.length !== 2) | ||
exports.getBrandedType = getBrandedType; | ||
const getPromisePayloadType = (ctx, type) => { | ||
// Find out the payload type from `then`'s first parameter. | ||
if (type.symbol.escapedName !== 'Promise') | ||
return; | ||
const thenSymbol = type.getProperty('then'); | ||
if (!thenSymbol) | ||
return; | ||
const thenType = ctx.checker.getTypeOfSymbolAtLocation(thenSymbol, ctx.location); | ||
const thenParamType = thenType | ||
.getCallSignatures() | ||
.flatMap((c) => c.getParameters()) | ||
.map((c) => ctx.checker.getTypeOfSymbolAtLocation(c, ctx.location))[0]; | ||
if (!thenParamType) | ||
return; | ||
const onResolvedType = thenParamType.isUnion() | ||
? thenParamType.types.find((t) => !exports.isUndefinedType(t) && !exports.isNullType(t)) | ||
: thenParamType; | ||
if (!onResolvedType) | ||
return; | ||
const onResolvedArgTypes = onResolvedType | ||
.getCallSignatures() | ||
.flatMap((c) => c.getParameters()) | ||
.map((c) => ctx.checker.getTypeOfSymbolAtLocation(c, ctx.location)); | ||
if (onResolvedArgTypes.length === 0) | ||
return; | ||
return onResolvedArgTypes[0]; | ||
}; | ||
exports.getPromisePayloadType = getPromisePayloadType; |
{ | ||
"name": "typera-openapi", | ||
"version": "0.11.2", | ||
"version": "0.11.3", | ||
"description": "Generate OpenAPI spec from typera routes", | ||
@@ -25,3 +25,3 @@ "repository": "https://github.com/akheron/typera-openapi", | ||
"dependencies": { | ||
"openapi-types": "^8.0.0", | ||
"openapi-types": "^9.0.0", | ||
"statuses": "^2.0.1", | ||
@@ -28,0 +28,0 @@ "typescript": "^4.1.3", |
41210
806
+ Addedopenapi-types@9.3.1(transitive)
- Removedopenapi-types@8.0.0(transitive)
Updatedopenapi-types@^9.0.0