Skip to content

Commit 4b0ace2

Browse files
js2meandrefilimono
andauthored
Release 1.10.0 (#62)
* Custom template (#60) * feat: allow to provide custom templates * internal: add manual test script for custom templates option * feat: resolving paths to templates * internal: adjust test for custom templates Co-authored-by: Volkov Sergey <[email protected]> Co-authored-by: Filimonov Andrey <[email protected]> * [Feature] `--union-enums` CLI option (#61) * feat: add --union-enums cli option which generate all enums as union types * docs: update README, CHANGELOG * chore(fix): manual test for union enums option * docs: update CHANGELOG; bump: up version to 1.10.0 Co-authored-by: Filimonov Andrey <[email protected]>
1 parent 8db5766 commit 4b0ace2

21 files changed

+640
-69
lines changed

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
11
# next release
22

3+
4+
# 1.10.0
5+
6+
Features:
7+
- `--templates` CLI option. [[feature request]](https://github.com/acacode/swagger-typescript-api/issues/54)
8+
Provide custom `mustache` templates folder which allows to generate custom code (models, Api class, routes)
9+
- `--union-enums` CLI option. [[feature request]](https://github.com/acacode/swagger-typescript-api/issues/58)
10+
Allows to generate all enums as union types.
11+
For example, schema part:
12+
```
13+
"StringEnum": {
14+
"enum": ["String1", "String2", "String3", "String4"],
15+
"type": "string"
16+
}
17+
```
18+
will be converted into:
19+
```
20+
export type StringEnum = "String1" | "String2" | "String3" | "String4";
21+
```
22+
23+
324
# 1.8.4
425

526
Fixes:

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,13 @@ Options:
3434
-p, --path <path> path/url to swagger scheme
3535
-o, --output <output> output path of typescript api file (default: "./")
3636
-n, --name <name> name of output typescript api file (default: "Api.ts")
37+
-t, --templates <path> path to folder containing templates (default: "./src/templates")
3738
-d, --default-as-success use "default" response status code as success response too.
3839
some swagger schemas use "default" response status code
3940
as success response type by default. (default: false)
4041
-r, --responses generate additional information about request responses
4142
also add typings for bad responses
43+
--union-enums generate all "enum" types as union types (T1 | T2 | TN) (default: false)
4244
--route-types generate type definitions for API routes (default: false)
4345
--no-client do not generate an API class
4446
-h, --help output usage information

index.d.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
21
interface GenerateApiParams {
3-
42
/**
53
* path to swagger schema
64
*/
@@ -20,7 +18,12 @@ interface GenerateApiParams {
2018
* path to folder where will been located the created api module
2119
*/
2220
output?: string;
23-
21+
22+
/**
23+
* path to folder containing templates (default: ./scr/templates)
24+
*/
25+
templates?: string;
26+
2427
/**
2528
* generate type definitions for API routes (default: false)
2629
*/
@@ -32,7 +35,7 @@ interface GenerateApiParams {
3235
generateClient?: boolean;
3336

3437
/**
35-
* use "default" response status code as success response too.
38+
* use "default" response status code as success response too.
3639
* some swagger schemas use "default" response status code as success response type by default.
3740
*/
3841
defaultResponseAsSuccess?: boolean;
@@ -44,5 +47,5 @@ interface GenerateApiParams {
4447
generateResponses?: boolean;
4548
}
4649

47-
export declare function generateApi(params: Omit<GenerateApiParams, "url">): Promise<string>
48-
export declare function generateApi(params: Omit<GenerateApiParams, "input">): Promise<string>
50+
export declare function generateApi(params: Omit<GenerateApiParams, "url">): Promise<string>;
51+
export declare function generateApi(params: Omit<GenerateApiParams, "input">): Promise<string>;

index.js

100644100755
Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,51 +6,47 @@
66
// License text available at https://opensource.org/licenses/MIT
77
// Repository https://github.com/acacode/swagger-typescript-api
88

9-
const program = require('commander');
10-
const { resolve } = require('path');
11-
const { generateApi } = require('./src');
12-
const { version } = require('./package.json');
9+
const program = require("commander");
10+
const { resolve } = require("path");
11+
const { generateApi } = require("./src");
12+
const { version } = require("./package.json");
1313

1414
program
15-
.version(version, '-v, --version', 'output the current version')
15+
.version(version, "-v, --version", "output the current version")
1616
.description("Generate api via swagger scheme.\nSupports OA 3.0, 2.0, JSON, yaml.")
17-
.requiredOption('-p, --path <path>', 'path/url to swagger scheme')
18-
.option('-o, --output <output>', 'output path of typescript api file', './')
19-
.option('-n, --name <name>', 'name of output typescript api file', 'Api.ts')
17+
.requiredOption("-p, --path <path>", "path/url to swagger scheme")
18+
.option("-o, --output <output>", "output path of typescript api file", "./")
19+
.option("-n, --name <name>", "name of output typescript api file", "Api.ts")
20+
.option("-t, --templates <path>", "path to folder containing templates")
2021
.option(
21-
'-d, --default-as-success',
22+
"-d, --default-as-success",
2223
'use "default" response status code as success response too.\n' +
23-
'some swagger schemas use "default" response status code as success response type by default.',
24-
false
24+
'some swagger schemas use "default" response status code as success response type by default.',
25+
false,
2526
)
2627
.option(
27-
'-r, --responses',
28-
'generate additional information about request responses\n' +
29-
'also add typings for bad responses',
28+
"-r, --responses",
29+
"generate additional information about request responses\n" +
30+
"also add typings for bad responses",
3031
false,
3132
)
32-
.option('--route-types', 'generate type definitions for API routes', false)
33-
.option('--no-client', 'do not generate an API class', false);
34-
33+
.option("--union-enums", 'generate all "enum" types as union types (T1 | T2 | TN)', false)
34+
.option("--route-types", "generate type definitions for API routes", false)
35+
.option("--no-client", "do not generate an API class", false);
36+
3537
program.parse(process.argv);
3638

37-
const {
38-
path,
39-
output,
40-
name,
41-
routeTypes,
42-
client,
43-
defaultAsSuccess,
44-
responses,
45-
} = program;
39+
const { path, output, name, templates, unionEnums, routeTypes, client, defaultAsSuccess, responses } = program;
4640

4741
generateApi({
4842
name,
4943
url: path,
5044
generateRouteTypes: routeTypes,
5145
generateClient: client,
5246
defaultResponseAsSuccess: defaultAsSuccess,
47+
generateUnionEnums: unionEnums,
5348
generateResponses: responses,
5449
input: resolve(process.cwd(), path),
55-
output: resolve(process.cwd(), output || '.')
56-
})
50+
output: resolve(process.cwd(), output || "."),
51+
templates: resolve(templates ? process.cwd() : __dirname, templates || "./src/templates"),
52+
});

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
{
22
"name": "swagger-typescript-api",
3-
"version": "1.8.4",
3+
"version": "1.10.0",
44
"description": "Create typescript api module from swagger schema",
55
"scripts": {
66
"cli:json": "node index.js -r -d -p ./swagger-test-cli.json -n swagger-test-cli.ts",
77
"cli:yaml": "node index.js -r -d -p ./swagger-test-cli.yaml -n swagger-test-cli.ts",
8-
"cli:debug:json": "node --nolazy --inspect-brk=9229 index.js -p ./swagger-test-cli.json -n swagger-test-cli.ts",
8+
"cli:debug:json": "node --nolazy --inspect-brk=9229 index.js -p ./swagger-test-cli.json -n swagger-test-cli.ts --union-enums",
99
"cli:debug:yaml": "node --nolazy --inspect-brk=9229 index.js -p ./swagger-test-cli.yaml -n swagger-test-cli.ts",
1010
"cli:help": "node index.js -h",
11-
"test:all": "npm-run-all generate validate test:routeTypes test:noClient test:defaultAsSuccess test:responses --continue-on-error",
11+
"test:all": "npm-run-all generate validate test:routeTypes test:noClient test:defaultAsSuccess test:responses test:templates test:unionEnums --continue-on-error",
1212
"generate": "node tests/generate.js",
1313
"generate:debug": "node --nolazy --inspect-brk=9229 tests/generate.js",
1414
"validate": "node tests/validate.js",
1515
"validate:debug": "node --nolazy --inspect-brk=9229 tests/validate.js",
1616
"test:routeTypes": "node tests/spec/routeTypes/test.js",
1717
"test:noClient": "node tests/spec/noClient/test.js",
1818
"test:defaultAsSuccess": "node tests/spec/defaultAsSuccess/test.js",
19+
"test:templates": "node tests/spec/templates/test.js",
20+
"test:unionEnums": "node tests/spec/unionEnums/test.js",
1921
"test:responses": "node tests/spec/responses/test.js"
2022
},
2123
"author": "acacode",

src/config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
const config = {
2+
/** CLI flag */
3+
templates: "./templates",
24
/** CLI flag */
35
generateResponses: false,
46
/** CLI flag */
@@ -7,6 +9,8 @@ const config = {
79
generateRouteTypes: false,
810
/** CLI flag */
911
generateClient: true,
12+
/** CLI flag */
13+
generateUnionEnums: false,
1014
/** parsed swagger schema from getSwaggerObject() */
1115

1216
/** parsed swagger schema ref */

src/files.js

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,15 @@ const _ = require("lodash");
22
const fs = require("fs");
33
const { resolve } = require("path");
44

5-
const getFileContent = path =>
6-
fs.readFileSync(path, { encoding: 'UTF-8' })
5+
const getFileContent = (path) => fs.readFileSync(path, { encoding: "UTF-8" });
76

8-
const pathIsExist = path =>
9-
path && fs.existsSync(path)
7+
const pathIsExist = (path) => path && fs.existsSync(path);
108

119
const createFile = (pathTo, fileName, content) =>
12-
fs.writeFileSync(resolve(__dirname, pathTo, `./${fileName}`), content, _.noop)
13-
14-
const getTemplate = templateName =>
15-
getFileContent(resolve(__dirname, `./templates/${templateName}.mustache`))
10+
fs.writeFileSync(resolve(__dirname, pathTo, `./${fileName}`), content, _.noop);
1611

1712
module.exports = {
18-
getTemplate,
1913
createFile,
2014
pathIsExist,
2115
getFileContent,
22-
}
16+
};

src/index.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,16 @@
99
const mustache = require("mustache");
1010
const prettier = require("prettier");
1111
const _ = require("lodash");
12+
const { resolve } = require("path");
1213
const { parseSchemas } = require("./schema");
1314
const { parseRoutes, groupRoutes } = require("./routes");
1415
const { createApiConfig } = require("./apiConfig");
1516
const { getModelType } = require("./modelTypes");
1617
const { getSwaggerObject, fixSwaggerScheme } = require("./swagger");
1718
const { createComponentsMap, filterComponentsMap } = require("./components");
18-
const { getTemplate, createFile, pathIsExist } = require("./files");
19+
const { createFile, pathIsExist } = require("./files");
1920
const { addToConfig, config } = require("./config");
21+
const { getTemplates } = require("./templates");
2022

2123
mustache.escape = (value) => value;
2224

@@ -33,20 +35,26 @@ module.exports = {
3335
output,
3436
url,
3537
name,
38+
templates = resolve(__dirname, config.templates),
3639
generateResponses = config.generateResponses,
3740
defaultResponseAsSuccess = config.defaultResponseAsSuccess,
3841
generateRouteTypes = config.generateRouteTypes,
3942
generateClient = config.generateClient,
43+
generateUnionEnums = config.generateUnionEnums,
4044
}) =>
4145
new Promise((resolve, reject) => {
4246
addToConfig({
4347
defaultResponseAsSuccess,
4448
generateRouteTypes,
4549
generateClient,
4650
generateResponses,
51+
templates,
52+
generateUnionEnums,
4753
});
4854
getSwaggerObject(input, url)
4955
.then(({ usageSchema, originalSchema }) => {
56+
const { apiTemplate, clientTemplate, routeTypesTemplate } = getTemplates();
57+
5058
console.log("☄️ start generating your typescript api");
5159

5260
fixSwaggerScheme(usageSchema, originalSchema);
@@ -58,10 +66,6 @@ module.exports = {
5866

5967
const { info, paths, servers, components } = usageSchema;
6068

61-
const apiTemplate = getTemplate("api");
62-
const clientTemplate = getTemplate("client");
63-
const routeTypesTemplate = getTemplate("route-types");
64-
6569
const componentsMap = createComponentsMap(components);
6670
const schemasMap = filterComponentsMap(componentsMap, "schemas");
6771

src/modelTypes.js

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
1-
const _ = require('lodash');
1+
const _ = require("lodash");
22
const { formatters } = require("./typeFormatters");
33
const { checkAndRenameModelName } = require("./modelNames");
4-
const { formatDescription } = require("./common")
5-
const { getTypeData } = require('./components');
4+
const { formatDescription } = require("./common");
5+
const { config } = require("./config");
6+
const { getTypeData } = require("./components");
67

7-
const CONTENT_KEYWORD = '__CONTENT__';
8+
const CONTENT_KEYWORD = "__CONTENT__";
89

910
const contentWrapersByTypeIdentifier = {
10-
'enum': `{\r\n${CONTENT_KEYWORD} \r\n }`,
11-
'interface': `{\r\n${CONTENT_KEYWORD}}`,
12-
'type': `= ${CONTENT_KEYWORD}`,
13-
}
11+
enum: `{\r\n${CONTENT_KEYWORD} \r\n }`,
12+
interface: `{\r\n${CONTENT_KEYWORD}}`,
13+
type: `= ${CONTENT_KEYWORD}`,
14+
};
1415

15-
const getModelType = typeInfo => {
16-
const { typeIdentifier, name: originalName, content, type, description } = getTypeData(typeInfo);
16+
const getModelType = (typeInfo) => {
17+
let { typeIdentifier, name: originalName, content, type, description } = getTypeData(typeInfo);
18+
19+
if (config.generateUnionEnums && typeIdentifier === "enum") {
20+
typeIdentifier = "type";
21+
}
1722

1823
if (!contentWrapersByTypeIdentifier[typeIdentifier]) {
19-
throw new Error(`${typeIdentifier} - type identifier is unknown for this utility`)
24+
throw new Error(`${typeIdentifier} - type identifier is unknown for this utility`);
2025
}
2126

2227
const resultContent = formatters[type] ? formatters[type](content) : content;
@@ -27,11 +32,15 @@ const getModelType = typeInfo => {
2732
name,
2833
rawContent: resultContent,
2934
description: formatDescription(description),
30-
content: _.replace(contentWrapersByTypeIdentifier[typeIdentifier], CONTENT_KEYWORD, resultContent)
31-
}
32-
}
35+
content: _.replace(
36+
contentWrapersByTypeIdentifier[typeIdentifier],
37+
CONTENT_KEYWORD,
38+
resultContent,
39+
),
40+
};
41+
};
3342

3443
module.exports = {
3544
getModelType,
3645
checkAndRenameModelName,
37-
}
46+
};

src/templates.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const { getFileContent } = require("./files");
2+
const { config } = require("./config");
3+
const { resolve } = require("path");
4+
5+
const getTemplates = () => {
6+
console.log(`✨ try to read templates from directory "${config.templates}"`);
7+
8+
return {
9+
apiTemplate: getTemplate("api"),
10+
clientTemplate: config.generateClient ? getTemplate("client") : null,
11+
routeTypesTemplate: config.generateRouteTypes ? getTemplate("route-types") : null,
12+
};
13+
};
14+
15+
const getTemplate = (templateName) =>
16+
getFileContent(resolve(config.templates, `./${templateName}.mustache`));
17+
18+
module.exports = {
19+
getTemplates,
20+
};

src/typeFormatters.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
const _ = require("lodash");
2+
const { config } = require("./config");
23
const { checkAndRenameModelName } = require("./modelNames");
34

45
const formatters = {
5-
enum: (content) => _.map(content, ({ key, value }) => ` ${key} = ${value}`).join(",\n"),
6+
enum: (content) =>
7+
_.map(content, ({ key, value }) =>
8+
config.generateUnionEnums ? value : ` ${key} = ${value}`,
9+
).join(config.generateUnionEnums ? " | " : ",\n"),
610
intEnum: (content) => _.map(content, ({ value }) => value).join(" | "),
711
object: (content) =>
812
_.map(content, (part) => {

0 commit comments

Comments
 (0)