Skip to content

Release 6.1.0 #185

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# next release

Features:
- `--silent` option. Output only errors to console (default: false)

Fixes:
- Bug with `kebab-case` path params (issue #184, thanks @Mr-sgreen)
- Typings for `--js` option

# 6.0.0

BREAKING_CHANGES:
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Options:
--clean-output clean output folder before generate api. WARNING: May cause data loss (default: false)
--axios generate axios http client (default: false)
--single-http-client Ability to send HttpClient instance to Api constructor (default: false)
--silent Output only errors to console (default: false)
--default-response <type> default type for empty response schema (default: "void")
-h, --help display help for command
```
Expand Down
3 changes: 3 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ program
.option("--disableStrictSSL", "disabled strict SSL", false)
.option("--axios", "generate axios http client", false)
.option("--single-http-client", "Ability to send HttpClient instance to Api constructor", false)
.option("--silent", "Output only errors to console", false)
.option("--default-response <type>", "default type for empty response schema", TS_KEYWORDS.VOID)
.option(
"--clean-output",
Expand Down Expand Up @@ -93,6 +94,7 @@ const {
defaultResponse,
singleHttpClient,
axios,
silent,
} = program;

generateApi({
Expand All @@ -116,4 +118,5 @@ generateApi({
disableStrictSSL: !!disableStrictSSL,
singleHttpClient: !!singleHttpClient,
cleanOutput: !!cleanOutput,
silent: !!silent,
});
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "swagger-typescript-api",
"version": "6.0.0",
"version": "6.1.0",
"description": "Create typescript api module from swagger schema",
"scripts": {
"cli:json": "node index.js -r -d -p ./swagger-test-cli.json -n swagger-test-cli.ts --extract-request-params --enum-names-as-values",
Expand Down Expand Up @@ -30,6 +30,7 @@
"test:--enum-names-as-values": "node tests/spec/enumNamesAsValues/test.js",
"test:--default-response": "node tests/spec/defaultResponse/test.js",
"test:--js": "node tests/spec/js/test.js",
"test:--js--axios": "node tests/spec/jsAxios/test.js",
"test:--axios": "node tests/spec/axios/test.js",
"test:partialBaseTemplate": "node tests/spec/partialBaseTemplate/test.js",
"test:partialDefaultTemplate": "node tests/spec/partialDefaultTemplate/test.js"
Expand Down
2 changes: 2 additions & 0 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ const config = {
},
/** Record<templateName, templateContent> */
templatesToRender: {},
toJS: false,
silent: false,
};

/** needs to use data everywhere in project */
Expand Down
13 changes: 9 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ module.exports = {
url,
spec,
name: fileName,
toJS: translateToJavaScript,
toJS: translateToJavaScript = config.toJS,
modular,
templates,
generateResponses = config.generateResponses,
Expand All @@ -45,6 +45,7 @@ module.exports = {
enumNamesAsValues,
disableStrictSSL = config.disableStrictSSL,
cleanOutput,
silent = config.silent,
}) =>
new Promise((resolve, reject) => {
addToConfig({
Expand All @@ -66,6 +67,8 @@ module.exports = {
defaultResponseType,
singleHttpClient,
constants,
silent,
toJS: translateToJavaScript,
});
(spec ? convertSwaggerObject(spec) : getSwaggerObject(input, url, disableStrictSSL))
.then(({ usageSchema, originalSchema }) => {
Expand All @@ -75,7 +78,7 @@ module.exports = {

const templatesToRender = getTemplates(config);

console.log("☄️ start generating your typescript api");
if (!config.silent) console.log("☄️ start generating your typescript api");

fixSwaggerScheme(usageSchema, originalSchema);

Expand Down Expand Up @@ -148,10 +151,12 @@ module.exports = {
if (translateToJavaScript) {
createFile(output, file.name, file.content);
createFile(output, file.declaration.name, file.declaration.content);
console.log(`✔️ your javascript api file created in "${output}"`);
if (!config.silent)
console.log(`✔️ your javascript api file created in "${output}"`);
} else {
createFile(output, file.name, file.content);
console.log(`✔️ your typescript api file created in "${output}"`);
if (!config.silent)
console.log(`✔️ your typescript api file created in "${output}"`);
}

return file;
Expand Down
3 changes: 2 additions & 1 deletion src/modelNames.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
const _ = require("lodash");
const { config } = require("./config");

const isValidName = (name) => /^([A-Za-z$_]{1,})$/g.test(name);

const formattedModelNamesMap = new Map();

const checkAndRenameModelName = (name) => {
if (typeof name !== "string") {
console.warn("🔨 wrong name of the model name", name);
if (!config.silent) console.warn("🔨 wrong name of the model name", name, config.silent);

return name;
}
Expand Down
13 changes: 7 additions & 6 deletions src/routeNames.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ const getRouteName = (routeInfo) => {
duplicateIdentifier,
routeNameDuplicatesMap.get(duplicateIdentifier) + 1,
);
console.warn(
`🥵 Module "${moduleName}" already have method "${routeName}()"`,
`\n🥵 This method has been renamed to "${
routeName + routeNameDuplicatesMap.get(duplicateIdentifier)
}()" to solve conflict names.`,
);
if (!config.silent)
console.warn(
`🥵 Module "${moduleName}" already have method "${routeName}()"`,
`\n🥵 This method has been renamed to "${
routeName + routeNameDuplicatesMap.get(duplicateIdentifier)
}()" to solve conflict names.`,
);
} else {
routeNameDuplicatesMap.set(duplicateIdentifier, 1);
}
Expand Down
9 changes: 7 additions & 2 deletions src/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,14 @@ const parseRoute = (route) => {
if (!paramName) return pathParams;

if (_.includes(paramName, "-")) {
console.warn("🔨 wrong path param name", paramName);
if (!config.silent) console.warn("🔨 wrong path param name", paramName);
}

return [
...pathParams,
{
$match: match,
name: paramName,
name: _.camelCase(paramName),
required: true,
type: "string",
description: "",
Expand All @@ -162,6 +162,7 @@ const parseRoute = (route) => {
);

return {
originalRoute: route || "",
route: fixedRoute,
pathParams,
};
Expand Down Expand Up @@ -206,6 +207,10 @@ const getRouteParams = (routeInfo, pathParams) => {
};
}

if (routeParam.in === "path" && routeParam.name) {
routeParam.name = _.camelCase(routeParam.name);
}

if (routeParam) {
routeParams[routeParam.in].push(routeParam);
}
Expand Down
6 changes: 3 additions & 3 deletions src/swagger.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const yaml = require("js-yaml");
const axios = require("axios");
const converter = require("swagger2openapi");
const https = require("https");
const { addToConfig } = require("./config");
const { addToConfig, config } = require("./config");
const { pathIsExist, getFileContent } = require("./files");

const parseSwaggerFile = (file) => {
Expand All @@ -19,10 +19,10 @@ const parseSwaggerFile = (file) => {
const getSwaggerFile = (pathToSwagger, urlToSwagger, disableStrictSSL) =>
new Promise((resolve) => {
if (pathIsExist(pathToSwagger)) {
console.log(`✨ try to get swagger by path "${pathToSwagger}"`);
if (!config.silent) console.log(`✨ try to get swagger by path "${pathToSwagger}"`);
resolve(getFileContent(pathToSwagger));
} else {
console.log(`✨ try to get swagger by url "${urlToSwagger}"`);
if (!config.silent) console.log(`✨ try to get swagger by url "${urlToSwagger}"`);
let agent = undefined;
if (disableStrictSSL) {
agent = new https.Agent({
Expand Down
14 changes: 8 additions & 6 deletions src/templates.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const _ = require("lodash");
const Eta = require("eta");
const { getFileContent, pathIsExist } = require("./files");
const { config, addToConfig } = require("./config");
const { config } = require("./config");
const { resolve } = require("path");

/**
Expand Down Expand Up @@ -38,7 +38,8 @@ const getTemplatePaths = ({ templates, modular }) => {
};

const getTemplates = ({ templatePaths }) => {
console.log(`✨ try to read templates from directory "${templatePaths.custom}"`);
if (!config.silent)
console.log(`✨ try to read templates from directory "${templatePaths.custom}"`);

const templatesMap = _.reduce(
TEMPLATE_INFOS,
Expand All @@ -53,10 +54,11 @@ const getTemplates = ({ templatePaths }) => {
if (pathIsExist(baseFullPath)) {
fileContent = getFileContent(baseFullPath);
} else {
console.log(
`❗❗❗ ${_.lowerCase(name)} template not found in ${customFullPath}\n` +
`Code generator will use the default template`,
);
if (!config.silent)
console.log(
`❗❗❗ ${_.lowerCase(name)} template not found in ${customFullPath}\n` +
`Code generator will use the default template`,
);
}

if (pathIsExist(originalFullPath)) {
Expand Down
2 changes: 1 addition & 1 deletion templates/default/api.eta
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const descriptionLines = _.compact([
]);

%>
<% if (config.httpClientType === config.constants.HTTP_CLIENT.AXIOS) { %> import { AxiosRequestConfig } from "axios"; <% } %>
<% if (config.httpClientType === config.constants.HTTP_CLIENT.AXIOS) { %> import { AxiosRequestConfig, AxiosResponse } from "axios"; <% } %>
<% if (descriptionLines.length) { %>
/**
<% descriptionLines.forEach((descriptionLine) => { %>
Expand Down
15 changes: 14 additions & 1 deletion templates/default/procedure-call.eta
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,19 @@ const bodyContentKindTmpl = requestContentKind[requestBodyInfo.contentKind] || n
const responseFormatTmpl = responseContentKind[responseBodyInfo.success && responseBodyInfo.success.schema && responseBodyInfo.success.schema.contentKind] || null;
const securityTmpl = security ? 'true' : null;

const describeReturnType = () => {
if (!config.toJS) return "";

switch(config.httpClientType) {
case config.constants.HTTP_CLIENT.AXIOS: {
return `Promise<AxiosResponse<${type}>>`
}
default: {
return `Promise<HttpResponse<${type}, ${errorType}>`
}
}
}

%>
/**
<%~ routeDocs.description %>
Expand All @@ -69,7 +82,7 @@ const securityTmpl = security ? 'true' : null;
<%~ routeDocs.lines %>

*/
<%~ route.routeName.usage %><%~ route.namespace ? ': ' : ' = ' %>(<%~ wrapperArgs %>) =>
<%~ route.routeName.usage %><%~ route.namespace ? ': ' : ' = ' %>(<%~ wrapperArgs %>)<%~ config.toJS ? `: ${describeReturnType()}` : "" %> =>
<%~ config.singleHttpClient ? 'this.http.request' : 'this.request' %><<%~ type %>, <%~ errorType %>>({
path: `<%~ path %>`,
method: '<%~ _.upperCase(method) %>',
Expand Down
2 changes: 1 addition & 1 deletion templates/modular/api.eta
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const apiClassName = classNameCase(route.moduleName);
const routes = route.routes;
const dataContracts = _.map(modelTypes, "name");
%>
<% if (config.httpClientType === config.constants.HTTP_CLIENT.AXIOS) { %> import { AxiosRequestConfig } from "axios"; <% } %>
<% if (config.httpClientType === config.constants.HTTP_CLIENT.AXIOS) { %> import { AxiosRequestConfig, AxiosResponse } from "axios"; <% } %>
import { HttpClient, RequestParams, ContentType } from "./<%~ config.fileNames.httpClient %>";
<% if (dataContracts.length) { %>
import { <%~ dataContracts.join(", ") %> } from "./<%~ config.fileNames.dataContracts %>"
Expand Down
16 changes: 15 additions & 1 deletion templates/modular/procedure-call.eta
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,20 @@ const queryTmpl = (query != null && queryName) || null;
const bodyContentKindTmpl = requestContentKind[requestBodyInfo.contentKind] || null;
const responseFormatTmpl = responseContentKind[responseBodyInfo.success && responseBodyInfo.success.schema && responseBodyInfo.success.schema.contentKind] || null;
const securityTmpl = security ? 'true' : null;

const describeReturnType = () => {
if (!config.toJS) return "";

switch(config.httpClientType) {
case config.constants.HTTP_CLIENT.AXIOS: {
return `Promise<AxiosResponse<${type}>>`
}
default: {
return `Promise<HttpResponse<${type}, ${errorType}>`
}
}
}

%>
/**
<%~ routeDocs.description %>
Expand All @@ -68,7 +82,7 @@ const securityTmpl = security ? 'true' : null;
<%~ routeDocs.lines %>

*/
<%~ route.routeName.usage %> = (<%~ wrapperArgs %>) =>
<%~ route.routeName.usage %> = (<%~ wrapperArgs %>)<%~ config.toJS ? `: ${describeReturnType()}` : "" %> =>
<%~ config.singleHttpClient ? 'this.http.request' : 'this.request' %><<%~ type %>, <%~ errorType %>>({
path: `<%~ path %>`,
method: '<%~ _.upperCase(method) %>',
Expand Down
21 changes: 9 additions & 12 deletions tests/generate.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
const { resolve } = require("path");
const createSchemasInfos = require("./helpers/createSchemaInfos")
const { generateApi } = require('../src');
const createSchemasInfos = require("./helpers/createSchemaInfos");
const { generateApi } = require("../src");

const schemas = [
...createSchemasInfos({
absolutePathToSchemas: resolve(__dirname, "./schemas/v2.0"),
absoluteOutputPath: resolve(__dirname, "./generated/v2.0")
absoluteOutputPath: resolve(__dirname, "./generated/v2.0"),
}),
...createSchemasInfos({
absolutePathToSchemas: resolve(__dirname, "./schemas/v3.0"),
absoluteOutputPath: resolve(__dirname, "./generated/v3.0")
absoluteOutputPath: resolve(__dirname, "./generated/v3.0"),
}),
]
];

schemas.forEach(({
absolutePath,
apiFileName,
outputPath,
}) => {
schemas.forEach(({ absolutePath, apiFileName, outputPath }) => {
generateApi({
name: apiFileName,
input: absolutePath,
output: outputPath,
generateClient: true,
generateRouteTypes: false
generateRouteTypes: false,
silent: true,
});
})
});
Loading