rapini
Version:
Generate React Query hooks, SWR hooks, Axios requests and Typescript types from OpenAPI files
399 lines (398 loc) • 19.9 kB
JavaScript
;
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];
}