Skip to content

Commit

Permalink
feat: provide a convenient experimental API for code extension (#35)
Browse files Browse the repository at this point in the history
* refactor: change interface name

* feat: add additional comment option

* test: udpate option

* feat: providing experimental APIs

* test: add generator params test
  • Loading branch information
Himenon authored Apr 6, 2021
1 parent 1c8dc40 commit 5ce24d3
Show file tree
Hide file tree
Showing 30 changed files with 466 additions and 64 deletions.
2 changes: 1 addition & 1 deletion scripts/build.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import "./clean";

import { cherryPick } from "./tools/cherry-pick";
import { copyPackageSet } from "./tools/copyPackageSet";
import { generateExportsField } from "./tools/dualPackageSupport";
import { shell } from "./tools/shell";
import { cherryPick } from "./tools/cherry-pick";

const main = async () => {
await Promise.all([
Expand Down
28 changes: 14 additions & 14 deletions scripts/testCodeGen.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as fs from "fs";
import { posix as path } from "path";

import { CodeGenerator, GeneratorTemplate } from "../lib";
import { CodeGenerator, CustomCodeGenerator } from "../lib";
import * as Templates from "../lib/templates";

const writeText = (filename: string, text: string): void => {
Expand Down Expand Up @@ -34,7 +34,7 @@ const generateTemplateCodeOnly = (
});
}

const apiClientGeneratorTemplate: GeneratorTemplate<Templates.ApiClient.Option> = {
const apiClientGeneratorTemplate: CustomCodeGenerator<Templates.ApiClient.Option> = {
generator: Templates.ApiClient.generator,
option: option,
};
Expand All @@ -58,11 +58,7 @@ const generateTypedefWithTemplateCode = (
}

const code = codeGenerator.generateTypeDefinition([
{
generator: () => {
return codeGenerator.getAdditionalTypeStatements();
},
},
codeGenerator.getAdditionalTypeDefinitionCustomCodeGenerator(),
{
generator: Templates.ApiClient.generator,
option: option,
Expand All @@ -75,9 +71,9 @@ const generateTypedefWithTemplateCode = (
const generateSplitCode = (inputFilename: string, outputDir: string) => {
const codeGenerator = new CodeGenerator(inputFilename);

const apiClientGeneratorTemplate: GeneratorTemplate<Templates.ApiClient.Option> = {
const apiClientGeneratorTemplate: CustomCodeGenerator<Templates.ApiClient.Option> = {
generator: Templates.ApiClient.generator,
option: { sync: false },
option: { sync: false, additionalMethodComment: true },
};

const typeDefCode = codeGenerator.generateTypeDefinition();
Expand All @@ -87,18 +83,19 @@ const generateSplitCode = (inputFilename: string, outputDir: string) => {
return [`import { Schemas } from "./types";`];
},
},
{
generator: () => {
return codeGenerator.getAdditionalTypeStatements();
},
},
codeGenerator.getAdditionalTypeDefinitionCustomCodeGenerator(),
apiClientGeneratorTemplate,
]);

writeText(path.join(outputDir, "types.ts"), typeDefCode);
writeText(path.join(outputDir, "apiClient.ts"), apiClientCode);
};

const generateParameter = (inputFilename: string, outputFilename: string) => {
const codeGenerator = new CodeGenerator(inputFilename);
writeText(outputFilename, JSON.stringify(codeGenerator.getCodeGeneratorParamsArray(), null, 2));
};

const main = () => {
generateTypedefCodeOnly("test/api.test.domain/index.yml", "test/code/typedef-only/api.test.domain.ts", true);
generateTypedefCodeOnly("test/infer.domain/index.yml", "test/code/typedef-only/infer.domain.ts", false);
Expand All @@ -116,6 +113,9 @@ const main = () => {
generateTypedefWithTemplateCode("test/infer.domain/index.yml", "test/code/typedef-with-template/infer.domain.ts", false, { sync: false });

generateSplitCode("test/api.test.domain/index.yml", "test/code/split");

generateParameter("test/api.test.domain/index.yml", "test/code/parameter/api.test.domain.json");
generateParameter("test/infer.domain/index.yml", "test/code/parameter/infer.domain.json");
};

main();
1 change: 0 additions & 1 deletion src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@ export * as OpenApiTools from "./internal/OpenApiTools";
export { FileSystem } from "./internal/FileSystem";
export * as ResolveReference from "./internal/ResolveReference";
export * as Validator from "./internal/Validator";

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import ts from "typescript";

import type { TsGenerator } from "../../../api";
import type { CodeGenerator } from "../../../types";
import type { Option } from "../types";

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

Expand Down Expand Up @@ -104,7 +105,7 @@ const createObjectLikeInterface = (factory: TsGenerator.Factory.Type) => {
});
};

export const create = (factory: TsGenerator.Factory.Type, list: CodeGenerator.Params[], option: { sync?: boolean }): ts.Statement[] => {
export const create = (factory: TsGenerator.Factory.Type, list: CodeGenerator.Params[], option: Option): ts.Statement[] => {
const objectLikeOrAnyType = factory.UnionTypeNode.create({
typeNodes: [
factory.TypeReferenceNode.create({
Expand Down
11 changes: 8 additions & 3 deletions src/code-templates/api-client/ApiClientClass/Method.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { EOL } from "os";

import ts from "typescript";

import type { TsGenerator } from "../../../api";
import type { CodeGenerator } from "../../../types";
import type { Option } from "../types";
import * as MethodBody from "./MethodBody";

export { MethodBody };
Expand Down Expand Up @@ -36,7 +39,7 @@ const generateResponseReturnType = (
factory: TsGenerator.Factory.Type,
successResponseNameList: string[],
successResponseContentTypeList: string[],
option: { sync?: boolean },
option: Option,
) => {
let objectType: ts.TypeNode = factory.TypeNode.create({
type: "void",
Expand Down Expand Up @@ -121,7 +124,7 @@ const methodTypeParameters = (factory: TsGenerator.Factory.Type, params: CodeGen
*
* }
*/
export const create = (factory: TsGenerator.Factory.Type, params: CodeGenerator.Params, option: { sync?: boolean }): ts.MethodDeclaration => {
export const create = (factory: TsGenerator.Factory.Type, params: CodeGenerator.Params, option: Option): ts.MethodDeclaration => {
const typeParameters: ts.TypeParameterDeclaration[] = methodTypeParameters(factory, params);
const methodArguments: ts.ParameterDeclaration[] = [];
const hasParamsArguments =
Expand All @@ -148,7 +151,9 @@ export const create = (factory: TsGenerator.Factory.Type, params: CodeGenerator.
name: params.functionName,
async: !option.sync,
parameters: methodArguments,
comment: params.comment,
comment: option.additionalMethodComment
? [params.comment, `operationId: ${params.operationId}`, `Request URI: ${params.rawRequestUri}`].filter(t => !!t).join(EOL)
: params.comment,
deprecated: params.deprecated,
type: returnType,
typeParameters: typeParameters,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ export const isPathParameter = (params: any): params is CodeGenerator.PickedPara
/**
* const url = this.baseUrl + `[head]${params.parameter.[parameterName]}`;
*/
const generateUrlVariableStatement = (factory: TsGenerator.Factory.Type, urlTemplate: Utils.Params$TemplateExpression): ts.VariableStatement => {
const generateUrlVariableStatement = (
factory: TsGenerator.Factory.Type,
urlTemplate: Utils.Params$TemplateExpression,
): ts.VariableStatement => {
return factory.VariableStatement.create({
declarationList: factory.VariableDeclarationList.create({
declarations: [
Expand Down Expand Up @@ -93,7 +96,11 @@ export const generateUrlTemplateExpression = (
return urlTemplate;
};

export const create = (factory: TsGenerator.Factory.Type, requestUri: string, pathParameters: CodeGenerator.PickedParameter[]): ts.VariableStatement => {
export const create = (
factory: TsGenerator.Factory.Type,
requestUri: string,
pathParameters: CodeGenerator.PickedParameter[],
): ts.VariableStatement => {
if (pathParameters.length > 0) {
const urlTemplate = generateUrlTemplateExpression(factory, requestUri, pathParameters);
return generateUrlVariableStatement(factory, urlTemplate);
Expand Down
3 changes: 2 additions & 1 deletion src/code-templates/api-client/ApiClientClass/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import ts from "typescript";

import type { TsGenerator } from "../../../api";
import type { CodeGenerator } from "../../../types";
import type { Option } from "../types";
import * as ApiClientInterface from "./ApiClientInterface";
import * as Class from "./Class";
import * as Constructor from "./Constructor";
import * as Method from "./Method";

export { Method };

export const create = (factory: TsGenerator.Factory.Type, list: CodeGenerator.Params[], option: { sync?: boolean }): ts.Statement[] => {
export const create = (factory: TsGenerator.Factory.Type, list: CodeGenerator.Params[], option: Option): ts.Statement[] => {
const methodList = list.map(params => {
return Method.create(factory, params, option);
});
Expand Down
5 changes: 2 additions & 3 deletions src/code-templates/api-client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import { TsGenerator } from "../../api";
import type { CodeGenerator } from "../../types";
import * as ApiClientArgument from "./ApiClientArgument";
import * as ApiClientClass from "./ApiClientClass";
import type { Option } from "./types";

export interface Option {
sync?: boolean;
}
export { Option };

export const generator: CodeGenerator.GenerateFunction<Option> = (
codeGeneratorParamsList: CodeGenerator.Params[],
Expand Down
6 changes: 6 additions & 0 deletions src/code-templates/api-client/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface Option {
/** default false */
sync?: boolean;
/** default false */
additionalMethodComment?: boolean;
}
19 changes: 12 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { EOL } from "os";

import ts from "typescript";

import * as Api from "./api";
import type * as Types from "./types";

export interface GeneratorTemplate<T> {
export interface CustomCodeGenerator<T> {
generator: Types.CodeGenerator.GenerateFunction<T>;
option?: T;
}
Expand Down Expand Up @@ -43,7 +41,7 @@ export class CodeGenerator {
* @param generatorTemplate Template for when you want to change the code following a type definition
* @returns String of generated code
*/
public generateTypeDefinition(generatorTemplates?: GeneratorTemplate<any>[]): string {
public generateTypeDefinition(generatorTemplates?: CustomCodeGenerator<any>[]): string {
const create = () => {
const statements = this.parser.getOpenApiTypeDefinitionStatements();
generatorTemplates?.forEach(generatorTemplate => {
Expand All @@ -62,7 +60,7 @@ export class CodeGenerator {
* @param generatorTemplate
* @returns String of generated code
*/
public generateCode(generatorTemplates: GeneratorTemplate<any>[]): string {
public generateCode(generatorTemplates: CustomCodeGenerator<any>[]): string {
const payload = this.parser.getCodeGeneratorParamsArray();
const create = () => {
return generatorTemplates
Expand All @@ -81,7 +79,14 @@ export class CodeGenerator {
return this.parser.getCodeGeneratorParamsArray();
}

public getAdditionalTypeStatements(): ts.Statement[] {
return this.parser.getAdditionalTypeStatements();
/**
* Provides types for parameters for Templates.ApiClient.
*
* This API will be moved to Templates in the future.
*/
public getAdditionalTypeDefinitionCustomCodeGenerator(): CustomCodeGenerator<undefined> {
return {
generator: () => this.parser.getAdditionalTypeStatements(),
};
}
}
6 changes: 3 additions & 3 deletions src/internal/FileSystem/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface Type {

export class FileSystem {
private static FRAGMENT = "#/";
private static internalLoadJsonOrYaml (filename: string): any {
private static internalLoadJsonOrYaml(filename: string): any {
const ext = path.extname(filename);
const data = fs.readFileSync(filename, { encoding: "utf-8" });
switch (ext) {
Expand All @@ -25,7 +25,7 @@ export class FileSystem {
default:
throw new UnSupportError(`Not support file: ${filename}`);
}
};
}

public static existSync(entryPoint: string): boolean {
return !!(fs.existsSync(entryPoint) && fs.statSync(entryPoint).isFile());
Expand All @@ -39,5 +39,5 @@ export class FileSystem {
return Dot.get(data, fragment.replace(/\//g, "."));
}
return this.internalLoadJsonOrYaml(entryPoint);
};
}
}
5 changes: 3 additions & 2 deletions src/internal/OpenApiTools/Extractor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { CodeGenerator, OpenApi } from "../../types";
import type { CodeGenerator, OpenApi, Experimental } from "../../types";
import * as ConverterContext from "./ConverterContext";
import { Store } from "./store";

Expand Down Expand Up @@ -111,7 +111,8 @@ export const generateCodeGeneratorParamsArray = (
//
hasAdditionalHeaders: hasOver2RequestContentTypes || hasOver2SuccessNames,
hasQueryParameters: hasQueryParameters(item.parameters),
// Response Success Name

experimentalOpenApiOperation: item,
};
params.push(formatParams);
});
Expand Down
2 changes: 1 addition & 1 deletion src/internal/OpenApiTools/TypeNodeContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import * as Path from "path";

import ts from "typescript";

import * as TypeScriptCodeGenerator from "../TsGenerator";
import { DevelopmentError } from "../Exception";
import * as TypeScriptCodeGenerator from "../TsGenerator";
import * as ConverterContext from "./ConverterContext";
import { Store } from "./store";
import * as ToTypeNode from "./toTypeNode";
Expand Down
2 changes: 1 addition & 1 deletion src/internal/OpenApiTools/components/Headers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { OpenApi } from "../../../types";
import { Factory } from "../../TsGenerator";
import { UndefinedComponent } from "../../Exception";
import { Factory } from "../../TsGenerator";
import * as ConverterContext from "../ConverterContext";
import * as Guard from "../Guard";
import * as Name from "../Name";
Expand Down
2 changes: 1 addition & 1 deletion src/internal/OpenApiTools/components/Parameters.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { OpenApi } from "../../../types";
import { Factory } from "../../TsGenerator";
import { UnSupportError } from "../../Exception";
import { Factory } from "../../TsGenerator";
import * as ConverterContext from "../ConverterContext";
import * as Guard from "../Guard";
import * as Name from "../Name";
Expand Down
2 changes: 1 addition & 1 deletion src/internal/OpenApiTools/components/PathItems.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { OpenApi } from "../../../types";
import { Factory } from "../../TsGenerator";
import { FeatureDevelopmentError, UnSupportError } from "../../Exception";
import { Factory } from "../../TsGenerator";
import * as ConverterContext from "../ConverterContext";
import * as Guard from "../Guard";
import * as Name from "../Name";
Expand Down
2 changes: 1 addition & 1 deletion src/internal/OpenApiTools/components/Responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import * as path from "path";
import ts from "typescript";

import type { OpenApi } from "../../../types";
import { Factory } from "../../TsGenerator";
import { UndefinedComponent } from "../../Exception";
import { Factory } from "../../TsGenerator";
import * as ConverterContext from "../ConverterContext";
import * as Guard from "../Guard";
import * as Name from "../Name";
Expand Down
2 changes: 1 addition & 1 deletion src/internal/OpenApiTools/components/Schema.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import ts from "typescript";

import type { OpenApi } from "../../../types";
import { Factory } from "../../TsGenerator";
import { FeatureDevelopmentError } from "../../Exception";
import { Factory } from "../../TsGenerator";
import * as ConvertContext from "../ConverterContext";
import * as Guard from "../Guard";
import { Store } from "../store";
Expand Down
2 changes: 1 addition & 1 deletion src/internal/OpenApiTools/components/Schemas.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { OpenApi } from "../../../types";
import { Factory } from "../../TsGenerator";
import { UnSupportError } from "../../Exception";
import { Factory } from "../../TsGenerator";
import * as ConverterContext from "../ConverterContext";
import * as Guard from "../Guard";
import * as InferredType from "../InferredType";
Expand Down
2 changes: 1 addition & 1 deletion src/internal/OpenApiTools/components/SecuritySchemas.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { OpenApi } from "../../../types";
import { Factory } from "../../TsGenerator";
import { UndefinedComponent } from "../../Exception";
import { Factory } from "../../TsGenerator";
import * as Guard from "../Guard";
import * as Name from "../Name";
import { Store } from "../store";
Expand Down
Loading

0 comments on commit 5ce24d3

Please sign in to comment.