Skip to content
This repository was archived by the owner on Feb 10, 2023. It is now read-only.

Commit 881625c

Browse files
authored
feat: Add Code template feature (Himenon#30)
* feat: changed the interface of the code generator * fix: test types * feat: add code template
1 parent 5774177 commit 881625c

File tree

17 files changed

+207
-138
lines changed

17 files changed

+207
-138
lines changed

scripts/testCodeGen.ts

+33-15
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,57 @@ import * as fs from "fs";
33
import * as CodeGenerator from "../lib";
44

55
const gen = (name: string, enableValidate = true): void => {
6-
const params: CodeGenerator.Params = {
6+
const params: CodeGenerator.OpenApiTsCodeGen.Configuration = {
77
entryPoint: `test/${name}/index.yml`,
8-
enableValidate,
9-
log: {
10-
validator: {
8+
codeGenerator: {
9+
templates: {
10+
Default: CodeGenerator.DefaultCodeTemplate.makeApiClient,
11+
},
12+
},
13+
typeDefinitionGenerator: {
14+
additional: {
15+
template: "Default",
16+
},
17+
},
18+
validator: {
19+
openapiSchema: enableValidate,
20+
logger: {
1121
displayLogLines: 1,
1222
},
1323
},
1424
};
1525
fs.mkdirSync("test/code", { recursive: true });
16-
const code = CodeGenerator.generateTypeScriptCode(params);
17-
fs.writeFileSync(`test/code/${name}.ts`, code, { encoding: "utf-8" });
26+
const output = CodeGenerator.make(params);
27+
fs.writeFileSync(`test/code/${name}.ts`, output.typeDefinition.value, { encoding: "utf-8" });
1828
console.log(`Generate Code : test/code/${name}.ts`);
1929
};
2030

2131
const genSyncMode = (name: string, enableValidate = true): void => {
22-
const params: CodeGenerator.Params = {
32+
const params: CodeGenerator.OpenApiTsCodeGen.Configuration = {
2333
entryPoint: `test/${name}/index.yml`,
24-
enableValidate,
25-
option: {
26-
codeGenerator: {
27-
sync: true,
34+
codeGenerator: {
35+
templates: {
36+
Default: CodeGenerator.DefaultCodeTemplate.makeApiClient,
37+
},
38+
},
39+
typeDefinitionGenerator: {
40+
additional: {
41+
template: "Default",
42+
option: {
43+
sync: true,
44+
},
2845
},
2946
},
30-
log: {
31-
validator: {
47+
validator: {
48+
openapiSchema: enableValidate,
49+
logger: {
3250
displayLogLines: 1,
3351
},
3452
},
3553
};
3654
fs.mkdirSync("test/code", { recursive: true });
37-
const code = CodeGenerator.generateTypeScriptCode(params);
38-
fs.writeFileSync(`test/code/sync-${name}.ts`, code, { encoding: "utf-8" });
55+
const code = CodeGenerator.make(params);
56+
fs.writeFileSync(`test/code/sync-${name}.ts`, code.typeDefinition.value, { encoding: "utf-8" });
3957
console.log(`Generate Code : test/code/sync-${name}.ts`);
4058
};
4159

src/CodeGenerator/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { DevelopmentError } from "../Exception";
44
import * as Factory from "./factory";
55
import { CreateFunction, traverse } from "./traverse";
66

7+
export * as Utils from "./utils";
8+
79
export { CreateFunction, Factory };
810

911
export type TransformerFactory<T extends ts.Node> = ts.TransformerFactory<T>;

src/CodeGenerator/utils.ts

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import ts from "typescript";
2+
3+
import type { CodeGenerator } from "../types";
4+
5+
export const stringToStatements = (code: string): ts.Statement[] => {
6+
const source = ts.createSourceFile("", code, ts.ScriptTarget.ESNext, false, ts.ScriptKind.TS);
7+
return Array.from(source.statements);
8+
};
9+
10+
export const convertIntermediateCodes = (intermediateCodes: CodeGenerator.IntermediateCode[]): ts.Statement[] => {
11+
return intermediateCodes.reduce<ts.Statement[]>((result, intermediateCode) => {
12+
if (typeof intermediateCode === "string") {
13+
return [...result, ...stringToStatements(intermediateCode)];
14+
}
15+
return result.concat(intermediateCode);
16+
}, []);
17+
};

src/Converter/CodeGenerator.ts

+3-24
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import ts from "typescript";
22

33
import * as ConverterContext from "./ConverterContext";
44
import { Store } from "./store";
5-
import { CodeGeneratorParams, OpenApi, PickedParameter } from "./types";
5+
import type { CodeGeneratorParams, OpenApi, PickedParameter } from "./types";
6+
import type { CodeGenerator } from "../types";
67

78
const extractPickedParameter = (parameter: OpenApi.Parameter): PickedParameter => {
89
return {
@@ -57,7 +58,7 @@ const hasQueryParameters = (parameters?: OpenApi.Parameter[]): boolean => {
5758
return parameters.filter(parameter => parameter.in === "query").length > 0;
5859
};
5960

60-
const generateCodeGeneratorParamsList = (
61+
export const generateCodeGeneratorParamsList = (
6162
store: Store.Type,
6263
converterContext: ConverterContext.Types,
6364
allowOperationIds: string[] | undefined,
@@ -120,25 +121,3 @@ const generateCodeGeneratorParamsList = (
120121

121122
return params;
122123
};
123-
124-
export interface Option {
125-
sync: boolean;
126-
}
127-
128-
export type RewriteCodeAfterTypeDeclaration = (
129-
context: ts.TransformationContext,
130-
codeGeneratorParamsList: CodeGeneratorParams[],
131-
codeGenerateOption: Option,
132-
) => ts.Statement[];
133-
134-
export const generateApiClientCode = (
135-
store: Store.Type,
136-
context: ts.TransformationContext,
137-
converterContext: ConverterContext.Types,
138-
rewriteCodeAfterTypeDeclaration: RewriteCodeAfterTypeDeclaration,
139-
allowOperationIds: string[] | undefined,
140-
option: Option,
141-
): void => {
142-
const codeGeneratorParamsList = generateCodeGeneratorParamsList(store, converterContext, allowOperationIds);
143-
store.addAdditionalStatement(rewriteCodeAfterTypeDeclaration(context, codeGeneratorParamsList, option));
144-
};

src/Converter/InferredType.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import * as Types from "./types";
1+
import type { OpenApi } from "./types";
22

3-
export const getInferredType = (schema: Types.OpenApi.Schema): Types.OpenApi.Schema | undefined => {
3+
export const getInferredType = (schema: OpenApi.Schema): OpenApi.Schema | undefined => {
44
if (schema.type || schema.oneOf || schema.allOf || schema.anyOf) {
55
return schema;
66
}

src/Converter/index.ts

+12-18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import ts from "typescript";
22

33
import * as TypeScriptCodeGenerator from "../CodeGenerator";
4+
import { CodeGenerator as CodeGenerator2 } from "../types";
45
import * as CodeGenerator from "./CodeGenerator";
56
import * as Comment from "./Comment";
67
import * as Headers from "./components/Headers";
@@ -21,22 +22,18 @@ export { OpenApi, CodeGenerator, CodeGeneratorParams, PickedParameter, Name };
2122
export interface Type {
2223
generateLeadingComment: () => string;
2324
createFunction: TypeScriptCodeGenerator.CreateFunction;
24-
codeGeneratorOption: CodeGenerator.Option;
25+
codeGeneratorOption: CodeGenerator2.Option;
2526
}
2627

2728
export interface Option {
28-
/**
29-
* It is possible to rewrite the implementation after the type declaration.
30-
*/
31-
rewriteCodeAfterTypeDeclaration: CodeGenerator.RewriteCodeAfterTypeDeclaration;
32-
/**
33-
*
34-
*/
35-
codeGeneratorOption: CodeGenerator.Option;
3629
/**
3730
* List of operationId to be used
3831
*/
3932
allowOperationIds?: string[];
33+
34+
generateCodeAfterGeneratedTypeDefinition?: CodeGenerator2.GenerateFunction;
35+
36+
codeGeneratorOption: CodeGenerator2.Option;
4037
}
4138

4239
export const create = (entryPoint: string, rootSchema: OpenApi.Document, noReferenceOpenApiSchema: OpenApi.Document, option: Option): Type => {
@@ -47,6 +44,7 @@ export const create = (entryPoint: string, rootSchema: OpenApi.Document, noRefer
4744
const factory = TypeScriptCodeGenerator.Factory.create(context);
4845
const store = Store.create(factory, noReferenceOpenApiSchema);
4946
const toTypeNodeContext = TypeNodeContext.create(entryPoint, store, factory, converterContext);
47+
let extraStatements: ts.Statement[] = [];
5048

5149
if (rootSchema.components) {
5250
if (rootSchema.components.schemas) {
@@ -106,16 +104,12 @@ export const create = (entryPoint: string, rootSchema: OpenApi.Document, noRefer
106104
}
107105
if (rootSchema.paths) {
108106
Paths.generateStatements(entryPoint, currentPoint, store, factory, rootSchema.paths, toTypeNodeContext, converterContext);
109-
CodeGenerator.generateApiClientCode(
110-
store,
111-
context,
112-
converterContext,
113-
option.rewriteCodeAfterTypeDeclaration,
114-
option.allowOperationIds,
115-
option.codeGeneratorOption,
116-
);
107+
108+
const codeGeneratorParamsList = CodeGenerator.generateCodeGeneratorParamsList(store, converterContext, option.allowOperationIds);
109+
const extraStatements2 = option.generateCodeAfterGeneratedTypeDefinition?.(context, codeGeneratorParamsList, option.codeGeneratorOption) || [];
110+
extraStatements = extraStatements.concat(TypeScriptCodeGenerator.Utils.convertIntermediateCodes(extraStatements2));
117111
}
118-
return store.getRootStatements();
112+
return store.getRootStatements().concat(extraStatements);
119113
};
120114

121115
return {

src/Converter/types/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { CodeGeneratorParams, PickedParameter } from "./CodeGeneratorParams";
2-
import * as OpenApi from "./OpenApiSchemaV3";
1+
import { CodeGeneratorParams, PickedParameter } from "../../types/extractSchema";
2+
import * as OpenApi from "../../types/OpenApi";
33

44
export { OpenApi, CodeGeneratorParams, PickedParameter };
55

src/DefaultCodeTemplate/ApiClientClass/ApiClientInterface.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import ts from "typescript";
22

33
import { Factory } from "../../CodeGenerator";
4-
import type { CodeGenerator, CodeGeneratorParams } from "../../Converter";
4+
import type { CodeGenerator } from "../../types";
5+
import type { CodeGeneratorParams } from "../../types/extractSchema";
56

67
const httpMethodList: string[] = ["GET", "PUT", "POST", "DELETE", "OPTIONS", "HEAD", "PATCH", "TRACE"];
78

src/DefaultCodeTemplate/ApiClientClass/Method.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import ts from "typescript";
22

33
import { Factory } from "../../CodeGenerator";
4-
import type { CodeGenerator, CodeGeneratorParams } from "../../Converter";
4+
import type { CodeGenerator } from "../../types";
5+
import type { CodeGeneratorParams } from "../../types/extractSchema";
56
import * as MethodBody from "./MethodBody";
67

78
export { MethodBody };

src/DefaultCodeTemplate/ApiClientClass/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import ts from "typescript";
22

33
import { Factory } from "../../CodeGenerator";
4-
import type { CodeGenerator, CodeGeneratorParams } from "../../Converter";
4+
import type { CodeGenerator } from "../../types";
5+
import type { CodeGeneratorParams } from "../../types/extractSchema";
56
import * as ApiClientInterface from "./ApiClientInterface";
67
import * as Class from "./Class";
78
import * as Constructor from "./Constructor";

src/DefaultCodeTemplate/index.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import ts from "typescript";
22

33
import * as TypeScriptCodeGenerator from "../CodeGenerator";
4-
import type * as Converter from "../Converter";
4+
import type { CodeGenerator } from "../types";
5+
import type { CodeGeneratorParams } from "../types/extractSchema";
56
import * as ApiClientArgument from "./ApiClientArgument";
67
import * as ApiClientClass from "./ApiClientClass";
78

8-
export const rewriteCodeAfterTypeDeclaration: Converter.CodeGenerator.RewriteCodeAfterTypeDeclaration = (
9+
export const makeApiClient: CodeGenerator.GenerateFunction = (
910
context: ts.TransformationContext,
10-
codeGeneratorParamsList: Converter.CodeGeneratorParams[],
11-
option: Converter.CodeGenerator.Option,
11+
codeGeneratorParamsList: CodeGeneratorParams[],
12+
option: CodeGenerator.Option,
1213
): ts.Statement[] => {
1314
const statements: ts.Statement[] = [];
1415
const factory = TypeScriptCodeGenerator.Factory.create(context);

src/Validator/index.ts

+6-13
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,11 @@ import * as Ajv from "ajv";
66

77
import type { OpenApi } from "../Converter/types";
88
import openapiSchema from "./openapi.json";
9+
import type { Validator } from "../types";
910

10-
export interface LogOption {
11-
/**
12-
* default: undefined (all logs)
13-
* Number of lines displayed in the latest log
14-
*/
15-
displayLogLines?: number;
16-
}
17-
18-
const showLogs = (logs: any[], option?: LogOption) => {
19-
if (option && option.displayLogLines && option.displayLogLines > 0) {
20-
const latestLogs = logs.slice(0, option.displayLogLines);
11+
const showLogs = (logs: any[], logger?: Validator.Logger) => {
12+
if (logger && logger.displayLogLines && logger.displayLogLines > 0) {
13+
const latestLogs = logs.slice(0, logger.displayLogLines);
2114
const moreLogNum = logs.length - latestLogs.length;
2215
console.error("Correct the validation error before generating the code.");
2316
console.error(`There are a total of ${logs.length} errors below.`);
@@ -37,12 +30,12 @@ const showLogs = (logs: any[], option?: LogOption) => {
3730
}
3831
};
3932

40-
export const validate = (openapiDoc: OpenApi.Document, option?: LogOption): void => {
33+
export const validate = (openapiDoc: OpenApi.Document, logger?: Validator.Logger): void => {
4134
const ajv = new Ajv.default({ allErrors: true });
4235
const validate = ajv.compile(openapiSchema);
4336
validate(openapiDoc);
4437
if (validate.errors) {
45-
showLogs(validate.errors, option);
38+
showLogs(validate.errors, logger);
4639
throw new Error("Validation Error");
4740
}
4841
};

0 commit comments

Comments
 (0)