UNPKG

rapini

Version:

Generate React Query hooks, SWR hooks, Axios requests and Typescript types from OpenAPI files

399 lines (398 loc) 19.9 kB
"use strict"; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.replacePattern = exports.chunker = exports.patternToPath = exports.getAxiosRequestGenericTypeResponse = exports.makeRequests = void 0; var typescript_1 = __importDefault(require("typescript")); var util_1 = require("./util"); var methods = [ "get", "delete", "post", "put", "patch", "head", "options", ]; function makeRequests($refs, paths, options) { var requests = Object.entries(paths).flatMap(function (_a) { var _b = __read(_a, 2), pattern = _b[0], item = _b[1]; return makeRequestsPropertyAssignment($refs, pattern, item, options); }); return [ makeRequestsDeclaration(requests), exportRequestsType(), exportResponseType(), ]; } exports.makeRequests = makeRequests; function exportRequestsType() { return typescript_1.default.factory.createTypeAliasDeclaration([typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.ExportKeyword)], typescript_1.default.factory.createIdentifier("Requests"), undefined, typescript_1.default.factory.createTypeReferenceNode(typescript_1.default.factory.createIdentifier("ReturnType"), [ typescript_1.default.factory.createTypeQueryNode(typescript_1.default.factory.createIdentifier("makeRequests"), undefined), ])); } function exportResponseType() { return typescript_1.default.factory.createTypeAliasDeclaration([typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.ExportKeyword)], typescript_1.default.factory.createIdentifier("Response"), [ typescript_1.default.factory.createTypeParameterDeclaration(undefined, typescript_1.default.factory.createIdentifier("T"), typescript_1.default.factory.createTypeOperatorNode(typescript_1.default.SyntaxKind.KeyOfKeyword, typescript_1.default.factory.createTypeReferenceNode(typescript_1.default.factory.createIdentifier("Requests"), undefined)), undefined), ], typescript_1.default.factory.createTypeReferenceNode(typescript_1.default.factory.createIdentifier("Awaited"), [ typescript_1.default.factory.createTypeReferenceNode(typescript_1.default.factory.createIdentifier("ReturnType"), [ typescript_1.default.factory.createIndexedAccessTypeNode(typescript_1.default.factory.createTypeReferenceNode(typescript_1.default.factory.createIdentifier("Requests"), undefined), typescript_1.default.factory.createTypeReferenceNode(typescript_1.default.factory.createIdentifier("T"), undefined)), ]), ])); } function makeRequestsDeclaration(requests) { var bodyStatements = [ typescript_1.default.factory.createReturnStatement( /*expression*/ typescript_1.default.factory.createAsExpression( /*expression*/ typescript_1.default.factory.createObjectLiteralExpression( /*properties*/ requests, /*multiline*/ true), /*type*/ typescript_1.default.factory.createTypeReferenceNode( /*typeName*/ typescript_1.default.factory.createIdentifier("const"), /*typeArgs*/ undefined))), ]; return typescript_1.default.factory.createFunctionDeclaration( /*modifiers*/ undefined, /*asteriskToken*/ undefined, /*name*/ typescript_1.default.factory.createIdentifier("makeRequests"), /*typeParameters*/ undefined, /*parameters*/ [ typescript_1.default.factory.createParameterDeclaration( /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ typescript_1.default.factory.createIdentifier("axios"), /*questionToken*/ undefined, /*type*/ typescript_1.default.factory.createTypeReferenceNode( /*typeName*/ typescript_1.default.factory.createIdentifier("AxiosInstance"), /*typeArguments*/ undefined), /*initializer*/ undefined), typescript_1.default.factory.createParameterDeclaration( /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ typescript_1.default.factory.createIdentifier("config"), /*questionToken*/ typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.QuestionToken), /*type*/ typescript_1.default.factory.createTypeReferenceNode( /*typeName*/ typescript_1.default.factory.createIdentifier("AxiosConfig"), /*typeArguments*/ undefined), /*initializer*/ undefined), ], /*type*/ undefined, /*body*/ typescript_1.default.factory.createBlock(bodyStatements, /*multiline*/ true)); } function makeRequestsPropertyAssignment($refs, pattern, item, options) { var requests = []; var params = item.parameters; methods.forEach(function (method) { var operation = item[method]; if (operation) { requests.push(makeRequest($refs, pattern, method, operation, options, params)); } }); return requests; } function isRequestBodyObject(obj) { return "content" in obj; } function createRequestParams(item, paramObjects, $refs) { var itemParamsDeclarations = paramObjects .sort(function (x, y) { return (x.required === y.required ? 0 : x.required ? -1 : 1); }) // put all optional values at the end .map(function (param) { return ({ name: typescript_1.default.factory.createIdentifier(param.name), arrowFuncParam: typescript_1.default.factory.createParameterDeclaration( /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ typescript_1.default.factory.createIdentifier(param.name), /*questionToken*/ param.required ? undefined : typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.QuestionToken), /*type*/ (0, util_1.schemaObjectOrRefType)($refs, param.schema).node, /*initializer*/ undefined), }); }); if (item.requestBody) { var payload = typescript_1.default.factory.createIdentifier("payload"); itemParamsDeclarations.unshift({ name: payload, arrowFuncParam: typescript_1.default.factory.createParameterDeclaration( /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ payload, /*questionToken*/ undefined, /*type*/ makeRequestsType($refs, item.requestBody), /*initializer*/ undefined), }); } return itemParamsDeclarations; } function statusCodeToType(statusCode) { if (statusCode.startsWith("2")) { return "success"; } if (statusCode.startsWith("4") || statusCode.startsWith("5")) { return "error"; } return "default"; } function mediaType($refs, mediaTypeObj) { if (!mediaTypeObj.schema) { return []; } var typeName = (0, util_1.schemaObjectOrRefType)($refs, mediaTypeObj.schema); return [typeName]; } function makeAxiosRequestGenericType($refs, statusCode, resOrRef) { var obj = (0, util_1.isReferenceObject)(resOrRef) ? $refs.get(resOrRef.$ref) : resOrRef; var schemas = obj.content ? Object.values(obj.content).flatMap(function (mediaTypeObj) { return mediaType($refs, mediaTypeObj); }) : []; if (!schemas.length) { return []; } return [ { statusType: statusCodeToType(statusCode), schemas: schemas, }, ]; } function getAxiosRequestGenericTypeResponse(item, $refs) { var _a; var genericType = Object.entries(item.responses).flatMap(function (_a) { var _b = __read(_a, 2), statusCode = _b[0], resOrRef = _b[1]; return makeAxiosRequestGenericType($refs, statusCode, resOrRef); }); var successTypes = genericType .filter(function (_a) { var statusType = _a.statusType; return statusType === "success"; }) .flatMap(function (_a) { var schemas = _a.schemas; return schemas; }); var uniqSuccessTypes = successTypes.reduce(function (acc, node) { return (acc.find(function (n) { return n.id === node.id; }) ? acc : acc.concat(node)); }, []); if (uniqSuccessTypes.length) { return typescript_1.default.factory.createUnionTypeNode(uniqSuccessTypes.map(function (item) { return item.node; })); } var defaultType = genericType.find(function (_a) { var statusType = _a.statusType; return statusType === "default"; }); if (defaultType && ((_a = defaultType.schemas) === null || _a === void 0 ? void 0 : _a[0])) { return defaultType.schemas[0].node; } return typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.UnknownKeyword); } exports.getAxiosRequestGenericTypeResponse = getAxiosRequestGenericTypeResponse; function makeRequestsType($refs, reqOrRef) { var reqBody = isRequestBodyObject(reqOrRef) ? reqOrRef : $refs.get(reqOrRef.$ref); var schemas = reqBody.content ? Object.values(reqBody.content).flatMap(function (mediaTypeObj) { return mediaType($refs, mediaTypeObj); }) : undefined; if (schemas === null || schemas === void 0 ? void 0 : schemas.length) { var uniqSchema = schemas.reduce(function (acc, node) { return acc.find(function (n) { return n.id === node.id; }) ? acc : acc.concat(node); }, []); return typescript_1.default.factory.createUnionTypeNode(uniqSchema.map(function (item) { return item.node; })); } return typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.UnknownKeyword); } function makeRequest($refs, pattern, method, item, options, pathParams) { var pathTemplateExpression = patternToPath(pattern, options.baseUrl, options.replacer); var paramObjects = (0, util_1.combineUniqueParams)($refs, pathParams, item.parameters); var arrowFuncParams = createRequestParams(item, paramObjects, $refs).map(function (param) { return param.arrowFuncParam; }); var axiosRequestGenericType = getAxiosRequestGenericTypeResponse(item, $refs); var axiosConfigFields = [ typescript_1.default.factory.createPropertyAssignment( /*name*/ typescript_1.default.factory.createIdentifier("method"), /*initializer*/ typescript_1.default.factory.createStringLiteral(method)), typescript_1.default.factory.createPropertyAssignment( /*name*/ typescript_1.default.factory.createIdentifier("url"), /*initializer*/ pathTemplateExpression), ]; var queryParamObjects = paramObjects.filter(function (paramObject) { return paramObject.in === "query"; }); var queryParamProperties = queryParamObjects.map(function (paramObject) { return paramObject.required ? typescript_1.default.factory.createShorthandPropertyAssignment( /*name*/ typescript_1.default.factory.createIdentifier(paramObject.name), /*objectAssignmentInitializer*/ undefined) : shorthandOptionalObjectLiteralSpread(paramObject.name); }); if (queryParamProperties.length) { axiosConfigFields.push(typescript_1.default.factory.createPropertyAssignment( /*name*/ typescript_1.default.factory.createIdentifier("params"), /*initializer*/ typescript_1.default.factory.createObjectLiteralExpression( /*properties*/ queryParamProperties, /*multiline*/ true)), typescript_1.default.factory.createPropertyAssignment( /*name*/ typescript_1.default.factory.createIdentifier("paramsSerializer"), /*initializer*/ typescript_1.default.factory.createPropertyAccessChain( /*expression*/ typescript_1.default.factory.createIdentifier("config"), /*questionDotToken*/ typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.QuestionDotToken), /*name*/ typescript_1.default.factory.createIdentifier("paramsSerializer")))); } // `data` field is only allowed for certain methods if (item.requestBody && ["put", "post", "patch", "delete"].includes(method)) { axiosConfigFields.push(typescript_1.default.factory.createPropertyAssignment( /*name*/ typescript_1.default.factory.createIdentifier("data"), /*initializer*/ typescript_1.default.factory.createIdentifier("payload"))); var reqBody = isRequestBodyObject(item.requestBody) ? item.requestBody : $refs.get(item.requestBody.$ref); var contentTypeConfig = tryCreateContentTypeAssignment(Object.keys(reqBody.content)); axiosConfigFields.push.apply(axiosConfigFields, __spreadArray([], __read(contentTypeConfig), false)); } return typescript_1.default.factory.createPropertyAssignment(typescript_1.default.factory.createIdentifier((0, util_1.normalizeOperationId)(item.operationId)), typescript_1.default.factory.createArrowFunction( /*modifiers*/ undefined, /*typeParams*/ undefined, /*params*/ arrowFuncParams, /*type*/ undefined, /*equalsGreaterThanToken*/ typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.EqualsGreaterThanToken), /*body*/ typescript_1.default.factory.createCallExpression( /*expression*/ typescript_1.default.factory.createPropertyAccessExpression( /*expression*/ typescript_1.default.factory.createCallExpression( /*expression*/ typescript_1.default.factory.createPropertyAccessExpression( /*expression*/ typescript_1.default.factory.createIdentifier("axios"), /*name*/ typescript_1.default.factory.createIdentifier("request")), /*typeArgs*/ [axiosRequestGenericType], /*args*/ [ typescript_1.default.factory.createObjectLiteralExpression(axiosConfigFields, true), ]), /*name*/ typescript_1.default.factory.createIdentifier("then")), /*typeArgs*/ undefined, /*args*/ [ typescript_1.default.factory.createArrowFunction( /*modifiers*/ undefined, /*typeParameters*/ undefined, /*parameters*/ [ typescript_1.default.factory.createParameterDeclaration( /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ typescript_1.default.factory.createIdentifier("res"), /*questionToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined), ], /*type*/ undefined, /*equalsGreaterThanToken*/ typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.EqualsGreaterThanToken), /*body*/ typescript_1.default.factory.createPropertyAccessExpression( /*expression*/ typescript_1.default.factory.createIdentifier("res"), /*name*/ typescript_1.default.factory.createIdentifier("data"))), ]))); } // Optionally spreads a field if not null // Ex: ...(identifier !== undefined ? { identifier } : undefined) function shorthandOptionalObjectLiteralSpread(identifier) { return typescript_1.default.factory.createSpreadAssignment(typescript_1.default.factory.createParenthesizedExpression(typescript_1.default.factory.createConditionalExpression( /*condition*/ typescript_1.default.factory.createBinaryExpression( /*left*/ typescript_1.default.factory.createIdentifier(identifier), /*operator*/ typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.ExclamationEqualsEqualsToken), /*right*/ typescript_1.default.factory.createIdentifier("undefined")), /*questionToken*/ typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.QuestionToken), /*whenTrue*/ typescript_1.default.factory.createObjectLiteralExpression( /*properties*/ [ typescript_1.default.factory.createShorthandPropertyAssignment( /*name*/ typescript_1.default.factory.createIdentifier(identifier), /*objectAssignmentInitializer*/ undefined), ], /*multiLine*/ false), /*colonToken*/ typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.ColonToken), /*whenFalse*/ typescript_1.default.factory.createIdentifier("undefined")))); } // Match everything inside of curly braces // Ex: /api/pet/{petId} -> would match {petId} var patternRegex = /({.+?})/; // Match all braces, like { or } var bracesRegex = /{|}/g; function patternToPath(pattern, baseUrl, replacers) { var replacedPattern = (replacers === null || replacers === void 0 ? void 0 : replacers.length) ? replacePattern(pattern, replacers) : pattern; var splits = replacedPattern.split(patternRegex); var _a = __read(splits), head = _a[0], tail = _a.slice(1); var headWithBase = baseUrl ? baseUrl + head : head; if (tail.length === 0) { return typescript_1.default.factory.createNoSubstitutionTemplateLiteral( /*text*/ headWithBase, /*rawText*/ headWithBase); } var headTemplate = typescript_1.default.factory.createTemplateHead( /*text*/ headWithBase, /*rawText*/ headWithBase); var chunks = chunker(tail, 2); var middleTemplates = chunks.map(function (_a, index) { var _b = __read(_a, 2), name = _b[0], path = _b[1]; return typescript_1.default.factory.createTemplateSpan( /*expression*/ typescript_1.default.factory.createIdentifier(name.replace(bracesRegex, "")), /*literal*/ index === chunks.length - 1 ? typescript_1.default.factory.createTemplateTail(path, path) : typescript_1.default.factory.createTemplateMiddle(path, path)); }); return typescript_1.default.factory.createTemplateExpression(headTemplate, middleTemplates); } exports.patternToPath = patternToPath; function chunker(arr, chunkSize) { var chunks = []; for (var i = 0; i < arr.length; i += chunkSize) { var chunk = arr.slice(i, i + chunkSize); chunks.push(chunk); } return chunks; } exports.chunker = chunker; function replacePattern(pattern, replacers) { var chunks = chunker(replacers, 2); return chunks.reduce(function (acc, _a) { var _b = __read(_a, 2), oldStr = _b[0], newStr = _b[1]; return acc.replace(new RegExp(oldStr, "g"), newStr); }, pattern); } exports.replacePattern = replacePattern; function tryCreateContentTypeAssignment(contentTypeKeys) { if (!contentTypeKeys.length) { return []; } var propertyAssignment = typescript_1.default.factory.createPropertyAssignment( /*name*/ typescript_1.default.factory.createIdentifier("headers"), /*initializer*/ typescript_1.default.factory.createObjectLiteralExpression( /*properties*/ [ typescript_1.default.factory.createPropertyAssignment( /*name*/ typescript_1.default.factory.createStringLiteral("Content-Type"), /*initializer*/ typescript_1.default.factory.createStringLiteral(contentTypeKeys[0])), ], /*multiline*/ true)); return [propertyAssignment]; }