@frostup/swr-request-generator
Version:
A tool for generating TypeScript code and interface from swagger by using SWR and axios as client.
673 lines (551 loc) • 24 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var tslib = require('tslib');
var lodash = require('lodash');
var prettier = require('prettier');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var prettier__default = /*#__PURE__*/_interopDefaultLegacy(prettier);
var isArray = function (data) {
return Object.prototype.toString.call(data) === "[object Array]";
};
var isObject = function (data) {
return Object.prototype.toString.call(data) === "[object Object]";
};
var isNumber = function (n) {
return !isNaN( /*#__PURE__*/parseFloat(n)) && isFinite(n);
};
var isSchema = function (schema) {
return !lodash.has(schema, "$ref");
};
var isRequestBody = function (requestBody) {
return !lodash.has(requestBody, "$ref");
};
var ERROR_MESSAGES = {
INVALID_JSON_FILE_ERROR: "Your json file is invalid, please check it!",
FETCH_CLIENT_FAILED_ERROR: "Fetch client failed! Please check your network or ts-codegen.config.ts file."
};
var HTTP_METHODS = ["get", "post", "put", "delete", "patch", "options", "head"];
var SLASH = "/";
var ENUM_SUFFIX = "#EnumTypeSuffix";
var toCapitalCase = function (str) {
if (!str) {
return "";
}
var camelStr = /*#__PURE__*/lodash.camelCase(str);
return "" + camelStr.charAt(0).toUpperCase() + camelStr.slice(1);
};
var addPrefix = function (prefix) {
return function (str) {
if (str === void 0) {
str = "";
}
return "" + prefix + str;
};
};
var addPrefixForInterface = /*#__PURE__*/addPrefix("I");
var arrayToObject = function (arr) {
if (arr === void 0) {
arr = [];
}
var obj = {};
lodash.forEach(arr, function (item) {
obj[item] = item;
});
return obj;
};
var prettifyCode = function (code) {
return prettier__default['default'].format(code, {
printWidth: 120,
trailingComma: "all",
arrowParens: "always",
parser: "typescript"
});
};
var toTypes = function (definitions) {
if (lodash.isEmpty(definitions)) {
return;
}
var fieldDefinitionList = /*#__PURE__*/lodash.map(definitions, function (value, key) {
if (isObject(value) && Object.keys(value).length === 1 && !lodash.isEmpty( /*#__PURE__*/lodash.pickBy(value, function (type) {
return type === "FormData";
}))) {
return convertKeyToCamelCaseAndAddQuote(key) + ": FormData";
}
return isObject(value) ? convertKeyToCamelCaseAndAddQuote(key) + ": " + JSON.stringify(value).replace(/"/g, "") + ";" : convertKeyToCamelCaseAndAddQuote(key) + ": " + lodash.replace(value, ENUM_SUFFIX, "") + ";";
});
return definitions && "{\n " + fieldDefinitionList.sort().join("\n") + "\n }";
};
var convertKeyToCamelCaseAndAddQuote = function (key) {
var isOptional = lodash.indexOf(key, "?") > -1;
key = /*#__PURE__*/lodash.trimEnd(key, "?");
var isValidVariableName = /*#__PURE__*/ /^([a-zA-Z_$][a-zA-Z\d_$]*)$/gm.test(key);
return "'" + (isValidVariableName ? key : lodash.camelCase( /*#__PURE__*/toCapitalCase(key))) + "'" + (isOptional ? "?" : "");
};
var convertJsonToString = function (str, errorMsg, output) {
if (errorMsg === void 0) {
errorMsg = ERROR_MESSAGES.INVALID_JSON_FILE_ERROR;
}
if (output === void 0) {
output = console.error;
}
if (typeof str !== "string") {
return;
}
try {
return JSON.parse(str);
} catch (e) {
output(errorMsg);
return;
}
};
var SchemaResolver =
/** @class */
function () {
function SchemaResolver(inputs) {
var _this = this;
this.inputs = inputs;
this.schemaType = {};
this.getSchemaType = function () {
return _this.schemaType;
};
this.resolve = function (type) {
var _a = _this.inputs,
_b = _a.schema,
schema = _b === void 0 ? {} : _b,
results = _a.results,
parentKey = _a.parentKey,
key = _a.key;
var advancedType = /*#__PURE__*/_this.resolveRef(schema.$ref, type || schema.type);
if (schema.$ref) {
_this.schemaType = advancedType;
return _this;
}
if (schema.allOf || schema.oneOf || schema.anyOf) {
var schemas = schema.oneOf || schema.allOf || schema.anyOf;
_this.schemaType = /*#__PURE__*/_this.resolveRef((schemas !== null && schemas !== void 0 ? schemas : [])[0].$ref, type || schema.type);
return _this;
}
if (schema.items) {
_this.schemaType = /*#__PURE__*/_this.resolveItems(schema.items, schema.type, key, parentKey);
return _this;
}
if (schema.enum) {
var enumKey = /*#__PURE__*/_this.getEnumName(key, parentKey); // Implicit operation!: Assign enum array definition to results
results[enumKey] = schema.enum;
_this.schemaType = enumKey;
return _this;
}
if (schema.type === "object") {
if (schema.properties) {
_this.schemaType = /*#__PURE__*/_this.resolveProperties(schema.properties, schema.required, parentKey);
return _this;
}
if (schema.title) {
_this.schemaType = schema.type;
return _this;
}
_this.schemaType = "{[key:string]:any}";
return _this;
}
if (schema.type === "string" && schema.format === "binary") {
_this.schemaType = "FormData";
return _this;
}
_this.schemaType = /*#__PURE__*/_this.getBasicType(schema.type, advancedType);
return _this;
};
this.resolveNullable = function () {
var _a;
if ((_a = _this.inputs.schema) === null || _a === void 0 ? void 0 : _a.nullable) {
_this.schemaType = isObject(_this.schemaType) ? JSON.stringify(_this.schemaType) + " | null" : _this.schemaType + " | null";
}
return _this;
};
this.getEnumName = function (propertyName, parentKey) {
if (parentKey === void 0) {
parentKey = "";
}
return "" + toCapitalCase(parentKey) + toCapitalCase(propertyName) + ENUM_SUFFIX;
};
this.resolveRef = function ($ref, type) {
if (!$ref) {
return "";
}
var refType = /*#__PURE__*/addPrefixForInterface( /*#__PURE__*/toCapitalCase( /*#__PURE__*/_this.pickTypeByRef($ref)));
return type === "array" ? refType + "[]" : refType;
};
this.getBasicType = function (basicType, advancedType) {
if (basicType === void 0) {
basicType = "";
}
switch (basicType) {
case "integer":
return "number";
case "array":
return _this.getTypeForArray(advancedType);
case "":
return advancedType || "";
default:
return basicType;
}
};
this.getTypeForArray = function (advancedType) {
return advancedType ? advancedType + "[]" : "Array<any>";
};
this.pickTypeByRef = function (str) {
if (!str) {
return;
}
var list = /*#__PURE__*/str.split("/");
return list[list.length - 1];
};
this.resolveItems = function (items, type, key, parentKey) {
if (!items) {
return {};
}
var child = /*#__PURE__*/lodash.get(items, "items");
if (type === "array") {
if (child) {
return _this.resolveItems(child, items.type, key, parentKey) + "[]";
}
if (!lodash.get(items, "$ref")) {
return lodash.get(items, "type") + "[]";
}
}
if (isArray(items)) {
return lodash.map(items, function (item) {
return SchemaResolver.of({
results: _this.inputs.results,
schema: item,
key: key,
parentKey: parentKey
}).resolve().resolveNullable().getSchemaType();
});
}
return SchemaResolver.of({
results: _this.inputs.results,
schema: items,
key: key,
parentKey: parentKey
}).resolve(type).resolveNullable().getSchemaType();
};
this.resolveProperties = function (properties, required, parentKey) {
if (properties === void 0) {
properties = {};
}
if (required === void 0) {
required = [];
}
return lodash.reduce(properties, function (o, v, k) {
var _a;
return tslib.__assign( /*#__PURE__*/tslib.__assign({}, o), (_a = {}, _a["" + k + (lodash.indexOf(required, k) > -1 ? "" : "?")] = /*#__PURE__*/SchemaResolver.of({
results: _this.inputs.results,
schema: v,
key: k,
parentKey: parentKey
}).resolve().resolveNullable().getSchemaType(), _a));
}, {});
};
}
SchemaResolver.of = function (inputs) {
return new SchemaResolver(inputs);
};
return SchemaResolver;
}();
var generateEnums = function (definitions, key) {
if (lodash.isEmpty(definitions)) {
return "";
}
var enums = definitions[key];
var hasNumber = /*#__PURE__*/lodash.some(enums, function (enumValue) {
return isNumber(enumValue);
});
var enumName = /*#__PURE__*/lodash.replace(key, ENUM_SUFFIX, "");
return hasNumber ? "export type " + enumName + " = " + enums.map(function (item) {
return JSON.stringify(item);
}).join("|") : "export enum " + enumName + " " + JSON.stringify( /*#__PURE__*/arrayToObject(enums)).replace(/:/gi, "=");
};
var generateFunctionName = function (method, operationId) {
return method === "get" ? "use" + toCapitalCase( /*#__PURE__*/lodash.camelCase(operationId)) + "Request" : lodash.camelCase(operationId) + "Request";
};
var generateClientName = function (method, responseType) {
return method === "get" ? "useRequest<" + (responseType || undefined) + ", IResponseError>" : "client.request<" + (responseType || undefined) + ", AxiosResponse<" + (responseType || undefined) + ">>";
}; // TODO: 1.refactor THeader logic to align with resolvedPath.xxxParams
// TODO: 2.add response type for download file
var generateRequestArguments = function (resolvedPath) {
var argumentTypes = !lodash.isEmpty( /*#__PURE__*/tslib.__assign( /*#__PURE__*/tslib.__assign({}, resolvedPath.TReq), resolvedPath.THeader)) ? toTypes( /*#__PURE__*/tslib.__assign( /*#__PURE__*/tslib.__assign({}, resolvedPath.TReq), resolvedPath.THeader)) : undefined;
var requestParamList = /*#__PURE__*/lodash.compact( /*#__PURE__*/tslib.__spreadArrays(resolvedPath.pathParams, resolvedPath.queryParams, resolvedPath.bodyParams, resolvedPath.formDataParams, /*#__PURE__*/Object.keys(resolvedPath.THeader), [resolvedPath.requestBody])).map(function (param) {
return lodash.camelCase(param);
});
var requestParams = requestParamList.length === 0 ? "" : "{" + requestParamList.join(",") + "}:" + argumentTypes;
return resolvedPath.method === "get" ? (requestParams ? requestParams + ", " : "") + "SWRConfig?: ISWRConfig<" + (resolvedPath.TResp || undefined) + ", IResponseError>, axiosConfig?: AxiosRequestConfig" : (requestParams ? requestParams + ", " : "") + "axiosConfig?: AxiosRequestConfig";
};
var generateHeader = function (hasBody, contentTypes, operationId, header) {
var result = lodash.reduce(header, function (result, _, key) {
return result + ("\"" + key + "\": ") + lodash.camelCase(key) + ", ";
}, "");
var contentType = hasBody ? "\"Content-Type\": \"" + lodash.get(contentTypes, operationId !== null && operationId !== void 0 ? operationId : "", "application/json") + "\"" : "";
return "headers: { " + result + contentType + "},";
};
var generateResponseType = function (axiosHeaderConfig) {
return axiosHeaderConfig.includes('"Accept":') ? 'responseType: "blob",' : "";
};
var PathResolver =
/** @class */
function () {
function PathResolver(paths) {
var _this = this;
this.paths = paths;
this.resolvedPaths = [];
this.extraDefinitions = {};
this.contentType = {};
this.resolve = function () {
_this.resolvedPaths = /*#__PURE__*/lodash.reduce(_this.paths, function (results, path, pathName) {
return tslib.__spreadArrays(results, /*#__PURE__*/_this.resolvePath(path, pathName));
}, []);
return _this;
};
this.toRequest = function () {
var data = /*#__PURE__*/lodash.sortBy(_this.resolvedPaths, function (o) {
return o.operationId;
});
var requests = /*#__PURE__*/data.map(function (resolvedPath) {
var bodyData = /*#__PURE__*/lodash.get(resolvedPath.bodyParams, "[0]");
var headerType = /*#__PURE__*/lodash.get(resolvedPath, "THeader");
var cookie = /*#__PURE__*/lodash.get(resolvedPath.formDataParams, "[0]");
var requestBody = /*#__PURE__*/lodash.get(resolvedPath, "requestBody");
var body = /*#__PURE__*/lodash.camelCase( /*#__PURE__*/toCapitalCase(requestBody || bodyData || cookie));
var params = /*#__PURE__*/_this.toRequestParams( /*#__PURE__*/lodash.get(resolvedPath, "queryParams"));
var axiosHeaderConfig = /*#__PURE__*/generateHeader(!lodash.isEmpty(body), _this.contentType, resolvedPath.operationId, headerType);
return "export const " + generateFunctionName(resolvedPath.method, resolvedPath.operationId) + " = (" + generateRequestArguments(resolvedPath) + ") => \n " + generateClientName(resolvedPath.method, resolvedPath.TResp) + "({\n url: `" + resolvedPath.url + "`,\n method: \"" + resolvedPath.method + "\"," + axiosHeaderConfig + generateResponseType(axiosHeaderConfig) + "\n " + (body ? "data: " + body + "," : "") + (params ? "params: " + params + "," : "") + "...axiosConfig}" + (resolvedPath.method === "get" ? ", SWRConfig" : "") + ");";
});
var enums = /*#__PURE__*/Object.keys(_this.extraDefinitions).map(function (k) {
return generateEnums(_this.extraDefinitions, k);
});
return tslib.__spreadArrays(requests, enums);
};
this.toRequestParams = function (data) {
if (data === void 0) {
data = [];
}
return !lodash.isEmpty(data) ? "{\n " + data.join(",\n") + "\n }" : undefined;
};
this.getRequestURL = function (pathName) {
return lodash.chain(pathName).split(SLASH).map(function (p) {
return _this.isPathParam(p) ? "$" + p : p;
}).join(SLASH).value();
};
this.isPathParam = function (str) {
return str.startsWith("{");
}; // TODO: handle the case when v.parameters = Reference
this.resolveOperation = function (operation) {
var pickParamsByType = /*#__PURE__*/_this.pickParams(operation.parameters);
var headerParams = /*#__PURE__*/pickParamsByType("header");
var params = {
pathParams: pickParamsByType("path"),
queryParams: pickParamsByType("query"),
bodyParams: pickParamsByType("body"),
formDataParams: pickParamsByType("cookie")
};
return tslib.__assign( /*#__PURE__*/tslib.__assign({
operationId: operation.operationId,
TResp: _this.getResponseTypes(operation.responses),
TReq: _this.getRequestTypes(params, operation.operationId, /*#__PURE__*/lodash.get(operation, "requestBody")),
THeader: _this.getPathParamsTypes(headerParams)
}, /*#__PURE__*/_this.getParamsNames(params)), /*#__PURE__*/_this.getRequestBodyName( /*#__PURE__*/lodash.get(operation, "requestBody"), operation.operationId));
};
this.getParamsNames = function (params) {
var getNames = function (list) {
return lodash.isEmpty(list) ? [] : lodash.map(list, function (item) {
return item.name;
});
};
return {
pathParams: getNames(params.pathParams),
queryParams: getNames(params.queryParams),
bodyParams: getNames(params.bodyParams),
formDataParams: getNames(params.formDataParams)
};
};
this.getRequestTypes = function (params, operationId, requestBody) {
return tslib.__assign( /*#__PURE__*/tslib.__assign( /*#__PURE__*/tslib.__assign( /*#__PURE__*/tslib.__assign( /*#__PURE__*/tslib.__assign({}, /*#__PURE__*/_this.getPathParamsTypes(params.pathParams)), /*#__PURE__*/_this.getBodyAndQueryParamsTypes(params.bodyParams)), /*#__PURE__*/_this.getBodyAndQueryParamsTypes(params.queryParams)), /*#__PURE__*/_this.getFormDataParamsTypes(params.formDataParams)), /*#__PURE__*/_this.getRequestBodyTypes(operationId, requestBody));
};
this.getPathParamsTypes = function (pathParams) {
return pathParams.reduce(function (results, param) {
var _a;
var schema = /*#__PURE__*/lodash.get(param, "schema");
if (isSchema(schema)) {
return tslib.__assign( /*#__PURE__*/tslib.__assign({}, results), (_a = {}, _a["" + param.name + (param.required ? "" : "?")] = schema.type === "integer" ? "number" : schema.type, _a));
}
return tslib.__assign({}, results);
}, {});
};
this.getBodyAndQueryParamsTypes = function (bodyParams) {
return bodyParams.reduce(function (results, param) {
var _a;
return tslib.__assign( /*#__PURE__*/tslib.__assign({}, results), (_a = {}, _a["" + param.name + (param.required ? "" : "?")] = /*#__PURE__*/SchemaResolver.of({
results: _this.extraDefinitions,
schema: param.schema,
key: param.name,
parentKey: param.name
}).resolve().getSchemaType(), _a));
}, {});
}; // TODO: handle other params here?
this.getFormDataParamsTypes = function (formDataParams) {
return formDataParams.reduce(function (results, param) {
var _a, _b;
if (param.schema) {
return tslib.__assign( /*#__PURE__*/tslib.__assign({}, results), (_a = {}, _a["" + param.name + (param.required ? "" : "?")] = /*#__PURE__*/SchemaResolver.of({
results: _this.extraDefinitions,
schema: param.schema,
key: param.name,
parentKey: param.name
}).resolve().getSchemaType(), _a));
}
return tslib.__assign( /*#__PURE__*/tslib.__assign({}, results), (_b = {}, _b["" + param.name + (param.required ? "" : "?")] = param.type === "file" ? "File" : param.type, _b));
}, {});
}; // TODO: handle Response or Reference
this.getResponseTypes = function (responses) {
return SchemaResolver.of({
results: _this.extraDefinitions,
// TODO: handle other content type here
schema: lodash.get(responses, "200.content.application/json.schema") || lodash.get(responses, "200.content.*/*.schema") || lodash.get(responses, "201.content.application/json.schema") || lodash.get(responses, "201.content.*/*.schema")
}).resolve().getSchemaType();
}; // TODO: when parameters has enum
this.pickParams = function (parameters) {
return function (type) {
return lodash.filter(parameters, function (param) {
return param.in === type;
});
};
};
}
PathResolver.of = function (paths) {
return new PathResolver(paths);
};
PathResolver.prototype.resolvePath = function (path, pathName) {
var _this = this;
var operations = /*#__PURE__*/lodash.pick(path, HTTP_METHODS);
return Object.keys(operations).map(function (httpMethod) {
return tslib.__assign({
url: _this.getRequestURL(pathName),
method: httpMethod
}, /*#__PURE__*/_this.resolveOperation(operations[httpMethod]));
});
};
PathResolver.prototype.getContentType = function (operationId, key) {
var _a; // in openAPI spec, the key of content in requestBody field is content type
lodash.assign(this.contentType, (_a = {}, _a[operationId] = key, _a));
};
PathResolver.prototype.getRequestBodyTypes = function (operationId, requestBody) {
var _a;
var _this = this;
if (isRequestBody(requestBody)) {
return lodash.reduce( /*#__PURE__*/lodash.get(requestBody, "content"), function (results, content, key) {
var _a;
_this.getContentType(operationId, key);
return tslib.__assign( /*#__PURE__*/tslib.__assign({}, results), (_a = {}, _a[operationId + "Request"] = /*#__PURE__*/SchemaResolver.of({
results: _this.extraDefinitions,
schema: content.schema,
key: operationId + "Request",
parentKey: operationId + "Request"
}).resolve().getSchemaType(), _a));
}, {});
}
return _a = {}, _a[operationId + "Request"] = /*#__PURE__*/SchemaResolver.of({
results: this.extraDefinitions,
schema: requestBody,
key: operationId + "Request",
parentKey: operationId + "Request"
}).resolve().getSchemaType(), _a;
};
PathResolver.prototype.getRequestBodyName = function (requestBody, operationId) {
if (requestBody) {
return {
requestBody: operationId + "Request"
};
}
};
return PathResolver;
}();
// TODO: handle `in: fromData`
// TODO: handle `in schema`
// TODO: 确认不同 endpoint 是否都会生成 openAPI
var DefinitionsResolver =
/** @class */
function () {
function DefinitionsResolver(components) {
var _this = this;
this.components = components;
this.scanDefinitions = function () {
var results = {};
var requestBodies = /*#__PURE__*/lodash.get(_this.components, "requestBodies");
var schemas = /*#__PURE__*/lodash.get(_this.components, "schemas");
lodash.forEach(requestBodies, function (requestBody, requestBodyName) {
if (isRequestBody(requestBody)) {
return results[requestBodyName] = /*#__PURE__*/SchemaResolver.of({
results: results,
schema: lodash.get(requestBody, "content.application/json.schema"),
key: requestBodyName,
parentKey: requestBodyName
}).resolve().getSchemaType();
}
return results[requestBodyName] = /*#__PURE__*/SchemaResolver.of({
results: results,
schema: requestBody,
key: requestBodyName,
parentKey: requestBodyName
}).resolve().getSchemaType();
});
lodash.forEach(schemas, function (schema, schemaName) {
return results[schemaName] = /*#__PURE__*/SchemaResolver.of({
results: results,
schema: schema,
key: schemaName,
parentKey: schemaName
}).resolve().getSchemaType();
});
_this.resolvedDefinitions = results;
return _this;
};
this.toDeclarations = function () {
var arr = /*#__PURE__*/Object.keys(_this.resolvedDefinitions).sort().map(function (key) {
if (lodash.includes(key, ENUM_SUFFIX)) {
return generateEnums(_this.resolvedDefinitions, key);
}
if (_this.resolvedDefinitions[key] === "object" || lodash.isEmpty(_this.resolvedDefinitions[key])) {
return "export interface " + addPrefixForInterface( /*#__PURE__*/toCapitalCase(key)) + " {[key:string]:any}";
}
var val = /*#__PURE__*/toTypes(_this.resolvedDefinitions[key]);
if (val) {
return "export interface " + addPrefixForInterface( /*#__PURE__*/toCapitalCase(key)) + " " + val;
}
});
return lodash.compact(arr);
};
}
DefinitionsResolver.of = function (components) {
return new DefinitionsResolver(components);
};
return DefinitionsResolver;
}();
exports.DefinitionsResolver = DefinitionsResolver;
exports.PathResolver = PathResolver;
exports.SchemaResolver = SchemaResolver;
exports.addPrefixForInterface = addPrefixForInterface;
exports.arrayToObject = arrayToObject;
exports.convertJsonToString = convertJsonToString;
exports.generateClientName = generateClientName;
exports.generateEnums = generateEnums;
exports.generateFunctionName = generateFunctionName;
exports.generateHeader = generateHeader;
exports.generateRequestArguments = generateRequestArguments;
exports.generateResponseType = generateResponseType;
exports.isArray = isArray;
exports.isNumber = isNumber;
exports.isObject = isObject;
exports.isRequestBody = isRequestBody;
exports.isSchema = isSchema;
exports.prettifyCode = prettifyCode;
exports.toCapitalCase = toCapitalCase;
exports.toTypes = toTypes;