typera-openapi
Advanced tools
Comparing version 2.0.1 to 2.0.2
@@ -113,6 +113,6 @@ "use strict"; | ||
const parameters = [ | ||
...typeToParameters(ctx, 'path', routeParams), | ||
...typeToParameters(ctx, 'query', query), | ||
...typeToParameters(ctx, 'header', headers), | ||
...typeToParameters(ctx, 'cookie', cookies), | ||
...typeToRequestParameters(ctx, 'path', routeParams), | ||
...typeToRequestParameters(ctx, 'query', query), | ||
...typeToRequestParameters(ctx, 'header', headers), | ||
...typeToRequestParameters(ctx, 'cookie', cookies), | ||
]; | ||
@@ -378,3 +378,3 @@ const pathTemplate = path.replace(/:([^-.()/]+)(\(.*?\))?/g, '{$1}'); | ||
const headers = !(0, utils_1.isUndefinedType)(headersType) | ||
? typeToHeaders(ctx, headersType) | ||
? typeToResponseHeaders(ctx, headersType) | ||
: undefined; | ||
@@ -393,16 +393,43 @@ let description = responseDescriptions[status]; | ||
? { | ||
content: (0, utils_1.isStringType)(bodyType) || (0, utils_1.isNumberType)(bodyType) | ||
? { 'text/plain': { schema: bodySchema } } | ||
: (0, utils_1.isBufferType)(bodyType) | ||
? { 'application/octet-stream': { schema: bodySchema } } | ||
: { 'application/json': { schema: bodySchema } }, | ||
content: { | ||
[getResponseContentType(ctx, headersType, bodyType)]: { | ||
schema: bodySchema, | ||
}, | ||
}, | ||
} | ||
: undefined)), (headers | ||
? { | ||
headers, | ||
} | ||
: undefined)), | ||
: undefined)), (headers ? { headers } : undefined)), | ||
}; | ||
}; | ||
const typeToParameters = (ctx, in_, type) => { | ||
const getResponseContentType = (ctx, headersType, bodyType) => { | ||
const contentTypeHeader = getContentTypeHeader(ctx, headersType); | ||
if (contentTypeHeader !== undefined) | ||
return contentTypeHeader; | ||
if ((0, utils_1.isStringType)(bodyType) || | ||
(0, utils_1.isNumberType)(bodyType) || | ||
(0, utils_1.isBooleanType)(bodyType)) { | ||
return 'text/plain'; | ||
} | ||
if ((0, utils_1.isBufferType)(bodyType) || (0, utils_1.isStreamingBodyType)(bodyType)) { | ||
return 'application/octet-stream'; | ||
} | ||
return 'application/json'; | ||
}; | ||
const getContentTypeHeader = (ctx, headersType) => { | ||
if ((0, utils_1.isUndefinedType)(headersType) || !headersType.symbol.members) | ||
return; | ||
const members = headersType.symbol.members; | ||
for (const [name, symbol] of members) { | ||
if (name.toLowerCase() !== 'content-type') | ||
continue; | ||
if (symbol.valueDeclaration) { | ||
const t = ctx.checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration); | ||
if ((0, utils_1.isStringLiteralType)(t)) { | ||
return t.value; | ||
} | ||
} | ||
// Content-Type found but it was not suitable, no point in searching further | ||
break; | ||
} | ||
}; | ||
const typeToRequestParameters = (ctx, in_, type) => { | ||
if (!type) | ||
@@ -413,6 +440,6 @@ return []; | ||
const description = getDescriptionFromComment(ctx, prop); | ||
return Object.assign({ name: prop.name, in: in_, required: in_ === 'path' ? true : !(0, utils_1.isOptional)(prop) }, (description ? { description } : undefined)); | ||
return Object.assign({ name: prop.name, in: in_, required: in_ === 'path' ? true : !(0, utils_1.isOptional)(prop), schema: { type: 'string' } }, (description ? { description } : undefined)); | ||
}); | ||
}; | ||
const typeToHeaders = (ctx, type) => { | ||
const typeToResponseHeaders = (ctx, type) => { | ||
const result = {}; | ||
@@ -422,2 +449,3 @@ const props = ctx.checker.getPropertiesOfType(type); | ||
result[prop.name] = { | ||
schema: { type: 'string' }, | ||
required: !(0, utils_1.isOptional)(prop), | ||
@@ -489,3 +517,3 @@ }; | ||
} | ||
if ((0, utils_1.isBufferType)(type)) { | ||
if ((0, utils_1.isBufferType)(type) || (0, utils_1.isStreamingBodyType)(type)) { | ||
return Object.assign({ type: 'string', format: 'binary' }, base); | ||
@@ -492,0 +520,0 @@ } |
@@ -19,2 +19,3 @@ import * as ts from 'typescript'; | ||
export declare const isBufferType: (type: ts.Type) => boolean; | ||
export declare const isStreamingBodyType: (type: ts.Type) => boolean; | ||
export declare const getPropertyType: (checker: ts.TypeChecker, location: ts.Node, type: ts.Type, propertyName: string) => ts.Type | undefined; | ||
@@ -21,0 +22,0 @@ export declare const getBrandedType: (ctx: Context, type: ts.Type) => { |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getPromisePayloadType = exports.getBrandedType = exports.getPropertyType = exports.isBufferType = exports.isDateType = exports.isTypeAlias = exports.isInterface = 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.isStreamingBodyType = exports.isBufferType = exports.isDateType = exports.isTypeAlias = exports.isInterface = 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"); | ||
@@ -35,7 +35,7 @@ const isDefined = (value) => value !== undefined; | ||
const duckTypeChecker = (name, properties) => (type) => { | ||
const symbol = type.symbol; | ||
return ((0, exports.isObjectType)(type) && | ||
symbol.escapedName === name && | ||
var _a, _b; | ||
return (0, exports.isObjectType)(type) && | ||
// If it walks like a duck and it quacks like a duck, then it must be a duck | ||
properties.every((name) => { var _a; return (_a = symbol.members) === null || _a === void 0 ? void 0 : _a.has(name); })); | ||
(((_a = type.aliasSymbol) === null || _a === void 0 ? void 0 : _a.name) === name || ((_b = type.getSymbol()) === null || _b === void 0 ? void 0 : _b.name) === name) && | ||
properties.every((name) => { var _a; return (_a = type.symbol.members) === null || _a === void 0 ? void 0 : _a.has(name); }); | ||
}; | ||
@@ -56,2 +56,6 @@ exports.isDateType = duckTypeChecker('Date', [ | ||
]); | ||
exports.isStreamingBodyType = duckTypeChecker('StreamingBody', [ | ||
'_kind', | ||
'callback', | ||
]); | ||
const getPropertyType = (checker, location, type, propertyName) => { | ||
@@ -58,0 +62,0 @@ const prop = type.getProperty(propertyName); |
{ | ||
"name": "typera-openapi", | ||
"version": "2.0.1", | ||
"version": "2.0.2", | ||
"description": "Generate OpenAPI spec from typera routes", | ||
@@ -32,9 +32,10 @@ "repository": "https://github.com/akheron/typera-openapi", | ||
"devDependencies": { | ||
"@apidevtools/swagger-parser": "^10.0.3", | ||
"@types/jest": "^27.0.1", | ||
"@types/node": "*", | ||
"@types/statuses": "^2.0.0", | ||
"@typescript-eslint/eslint-plugin": "^4.12.0", | ||
"@typescript-eslint/parser": "^4.12.0", | ||
"@typescript-eslint/eslint-plugin": "^5.16.0", | ||
"@typescript-eslint/parser": "^5.16.0", | ||
"doctoc": "^2.0.0", | ||
"eslint": "^7.17.0", | ||
"eslint": "^8.12.0", | ||
"eslint-config-prettier": "^8.1.0", | ||
@@ -41,0 +42,0 @@ "eslint-plugin-prettier": "^4.0.0", |
55711
1012
16