diff --git a/README.md b/README.md index 0b537579..085fb296 100644 --- a/README.md +++ b/README.md @@ -176,6 +176,72 @@ const customGenerator: Types.CodeGenerator.CustomGenerator = { } ``` +### Define any Data Types Format + +Convert a Data Type with the following `format` to any type definition. + +```yaml +components: + schemas: + Binary: + type: string + format: binary + IntOrString: + type: string + format: int-or-string + AandB: + type: string + format: A-and-B +``` + +The option to convert the Data Type Format to an arbitrary type definition is defined as follows. + +```ts +import { CodeGenerator, Option } from "@himenon/openapi-typescript-code-generator"; +const option: Option = { + convertOption: { + formatConversions: [ + { + selector: { + format: "binary", + }, + output: { + type: ["Blob"], + }, + }, + { + selector: { + format: "int-or-string", + }, + output: { + type: ["number", "string"], + }, + }, + { + selector: { + format: "A-and-B", + }, + output: { + type: ["A", "B"], + multiType: "allOf", + }, + }, + ], + }, +}; +const codeGenerator = new CodeGenerator(inputFilename, option); +``` + +The typedef generated by this will look like this + +```ts +export namespace Schemas { + export type Binary = Blob; + export type IntOrString = number | string; + export type AandB = A & B; +} +``` + ### Define a code template with TypeScript AST You can extend your code using the API of TypeScript AST. diff --git a/docs/ja/README-ja.md b/docs/ja/README-ja.md index e27798b8..9a818961 100644 --- a/docs/ja/README-ja.md +++ b/docs/ja/README-ja.md @@ -174,6 +174,72 @@ const customGenerator: Types.CodeGenerator.CustomGenerator = { } ``` +### 任意の Data Types Format を定義する + +以下のような`format`が指定された Data Type を任意の型定義に変換します。 + +```yaml +components: + schemas: + Binary: + type: string + format: binary + IntOrString: + type: string + format: int-or-string + AandB: + type: string + format: A-and-B +``` + +Data Type Formatを任意の型定義に変換するオプションは次のように定義します。 + +```ts +import { CodeGenerator, Option } from "@himenon/openapi-typescript-code-generator"; +const option: Option = { + convertOption: { + formatConversions: [ + { + selector: { + format: "binary", + }, + output: { + type: ["Blob"], + }, + }, + { + selector: { + format: "int-or-string", + }, + output: { + type: ["number", "string"], + }, + }, + { + selector: { + format: "A-and-B", + }, + output: { + type: ["A", "B"], + multiType: "allOf", + }, + }, + ], + }, +}; +const codeGenerator = new CodeGenerator(inputFilename, option); +``` + +これで生成される型定義は次のようになります。 + +```ts +export namespace Schemas { + export type Binary = Blob; + export type IntOrString = number | string; + export type AandB = A & B; +} +``` + ### TypeScript AST によるコードテンプレートを定義する TypeScript AST の API を利用したコードの拡張が可能です。 diff --git a/scripts/testCodeGen.ts b/scripts/testCodeGen.ts index 181dbeec..1f9a4e91 100644 --- a/scripts/testCodeGen.ts +++ b/scripts/testCodeGen.ts @@ -1,131 +1,42 @@ -import * as fs from "fs"; -import { posix as path } from "path"; - -import { CodeGenerator } from "../lib"; -import * as Templates from "../lib/templates"; -import type * as Types from "../lib/types"; - -const writeText = (filename: string, text: string): void => { - fs.mkdirSync(path.dirname(filename), { recursive: true }); - fs.writeFileSync(filename, text, { encoding: "utf-8" }); - console.log(`Generate Code : ${filename}`); -}; - -const generateTypedefCodeOnly = (inputFilename: string, outputFilename: string, isValidate: boolean) => { - const codeGenerator = new CodeGenerator(inputFilename); - if (isValidate) { - codeGenerator.validateOpenApiSchema({ - logger: { displayLogLines: 1 }, - }); - } - const code = codeGenerator.generateTypeDefinition(); - writeText(outputFilename, code); -}; - -const generateTemplateCodeOnly = ( - inputFilename: string, - outputFilename: string, - isValidate: boolean, - option: Templates.ApiClient.Option, -): void => { - const codeGenerator = new CodeGenerator(inputFilename); - if (isValidate) { - codeGenerator.validateOpenApiSchema({ - logger: { displayLogLines: 1 }, - }); - } - - const apiClientGeneratorTemplate: Types.CodeGenerator.CustomGenerator = { - generator: Templates.ApiClient.generator, - option: option, - }; - - const code = codeGenerator.generateCode([apiClientGeneratorTemplate]); - - writeText(outputFilename, code); -}; - -const generateTypedefWithTemplateCode = ( - inputFilename: string, - outputFilename: string, - isValidate: boolean, - option: Templates.ApiClient.Option, -): void => { - const codeGenerator = new CodeGenerator(inputFilename); - if (isValidate) { - codeGenerator.validateOpenApiSchema({ - logger: { displayLogLines: 1 }, - }); - } - - const code = codeGenerator.generateTypeDefinition([ - codeGenerator.getAdditionalTypeDefinitionCustomCodeGenerator(), - { - generator: Templates.ApiClient.generator, - option: option, - }, - ]); - - writeText(outputFilename, code); -}; - -const generateSplitCode = (inputFilename: string, outputDir: string) => { - const codeGenerator = new CodeGenerator(inputFilename); - - const apiClientGeneratorTemplate: Types.CodeGenerator.CustomGenerator = { - generator: Templates.ApiClient.generator, - option: { sync: false, additionalMethodComment: true }, - }; - - const typeDefCode = codeGenerator.generateTypeDefinition(); - const apiClientCode = codeGenerator.generateCode([ - { - generator: () => { - return [`import { Schemas } from "./types";`]; - }, - }, - 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)); -}; +import * as Writer from "./writer"; 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); + Writer.generateTypedefCodeOnly("test/api.test.domain/index.yml", "test/code/typedef-only/api.test.domain.ts", true); + Writer.generateTypedefCodeOnly("test/infer.domain/index.yml", "test/code/typedef-only/infer.domain.ts", false); - generateTemplateCodeOnly("test/api.test.domain/index.yml", "test/code/template-only/api.test.domain.ts", true, { sync: false }); - generateTemplateCodeOnly("test/api.test.domain/index.yml", "test/code/template-only/sync-api.test.domain.ts", true, { sync: true }); - generateTemplateCodeOnly("test/infer.domain/index.yml", "test/code/template-only/infer.domain.ts", false, { sync: true }); + Writer.generateTemplateCodeOnly("test/api.test.domain/index.yml", "test/code/template-only/api.test.domain.ts", true, { sync: false }); + Writer.generateTemplateCodeOnly("test/api.test.domain/index.yml", "test/code/template-only/sync-api.test.domain.ts", true, { sync: true }); + Writer.generateTemplateCodeOnly("test/infer.domain/index.yml", "test/code/template-only/infer.domain.ts", false, { sync: true }); - generateTypedefWithTemplateCode("test/api.v2.domain/index.yml", "test/code/typedef-with-template/api.v2.domain.ts", false, { sync: false }); - generateTypedefWithTemplateCode("test/api.test.domain/index.yml", "test/code/typedef-with-template/api.test.domain.ts", true, { + Writer.generateTypedefWithTemplateCode("test/api.v2.domain/index.yml", "test/code/typedef-with-template/api.v2.domain.ts", false, { sync: false, }); - generateTypedefWithTemplateCode("test/api.test.domain/index.yml", "test/code/typedef-with-template/sync-api.test.domain.ts", true, { + Writer.generateTypedefWithTemplateCode("test/api.test.domain/index.yml", "test/code/typedef-with-template/api.test.domain.ts", true, { + sync: false, + }); + Writer.generateTypedefWithTemplateCode("test/api.test.domain/index.yml", "test/code/typedef-with-template/sync-api.test.domain.ts", true, { sync: true, }); - generateTypedefWithTemplateCode("test/infer.domain/index.yml", "test/code/typedef-with-template/infer.domain.ts", false, { sync: false }); + Writer.generateTypedefWithTemplateCode("test/infer.domain/index.yml", "test/code/typedef-with-template/infer.domain.ts", false, { + sync: false, + }); - generateTypedefWithTemplateCode("test/ref.access/index.yml", "test/code/typedef-with-template/ref-access.ts", false, { + Writer.generateTypedefWithTemplateCode("test/ref.access/index.yml", "test/code/typedef-with-template/ref-access.ts", false, { sync: false, }); - generateTypedefWithTemplateCode("test/kubernetes/openapi-v1.18.5.json", "test/code/kubernetes/client-v1.18.5.ts", false, { sync: false }); - generateTypedefWithTemplateCode("test/argo-rollout/index.json", "test/code/argo-rollout/client.ts", false, { + Writer.generateTypedefWithTemplateCode("test/kubernetes/openapi-v1.18.5.json", "test/code/kubernetes/client-v1.18.5.ts", false, { sync: false, }); + Writer.generateTypedefWithTemplateCode("test/argo-rollout/index.json", "test/code/argo-rollout/client.ts", false, { + sync: false, + }); + + Writer.generateSplitCode("test/api.test.domain/index.yml", "test/code/split"); - generateSplitCode("test/api.test.domain/index.yml", "test/code/split"); + Writer.generateParameter("test/api.test.domain/index.yml", "test/code/parameter/api.test.domain.json"); + Writer.generateParameter("test/infer.domain/index.yml", "test/code/parameter/infer.domain.json"); - 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"); + Writer.generateFormatTypeCode("test/format.domain/index.yml", "test/code/format.domain/code.ts"); }; main(); diff --git a/scripts/writer/index.ts b/scripts/writer/index.ts new file mode 100644 index 00000000..13a5dd25 --- /dev/null +++ b/scripts/writer/index.ts @@ -0,0 +1,161 @@ +import * as fs from "fs"; +import { posix as path } from "path"; + +import { CodeGenerator, Option as CodeGeneratorOption } from "../../lib"; +import * as Templates from "../../lib/templates"; +import type * as Types from "../../lib/types"; + +const writeText = (filename: string, text: string): void => { + fs.mkdirSync(path.dirname(filename), { recursive: true }); + fs.writeFileSync(filename, text, { encoding: "utf-8" }); + console.log(`Generate Code : ${filename}`); +}; + +export const generateTypedefCodeOnly = (inputFilename: string, outputFilename: string, isValidate: boolean) => { + const codeGenerator = new CodeGenerator(inputFilename); + if (isValidate) { + codeGenerator.validateOpenApiSchema({ + logger: { displayLogLines: 1 }, + }); + } + const code = codeGenerator.generateTypeDefinition(); + writeText(outputFilename, code); +}; + +export const generateTemplateCodeOnly = ( + inputFilename: string, + outputFilename: string, + isValidate: boolean, + option: Templates.ApiClient.Option, +): void => { + const codeGenerator = new CodeGenerator(inputFilename); + if (isValidate) { + codeGenerator.validateOpenApiSchema({ + logger: { displayLogLines: 1 }, + }); + } + + const apiClientGeneratorTemplate: Types.CodeGenerator.CustomGenerator = { + generator: Templates.ApiClient.generator, + option: option, + }; + + const code = codeGenerator.generateCode([apiClientGeneratorTemplate]); + + writeText(outputFilename, code); +}; + +export const generateTypedefWithTemplateCode = ( + inputFilename: string, + outputFilename: string, + isValidate: boolean, + option: Templates.ApiClient.Option, +): void => { + const codeGenerator = new CodeGenerator(inputFilename); + if (isValidate) { + codeGenerator.validateOpenApiSchema({ + logger: { displayLogLines: 1 }, + }); + } + + const code = codeGenerator.generateTypeDefinition([ + codeGenerator.getAdditionalTypeDefinitionCustomCodeGenerator(), + { + generator: Templates.ApiClient.generator, + option: option, + }, + ]); + + writeText(outputFilename, code); +}; + +export const generateSplitCode = (inputFilename: string, outputDir: string) => { + const codeGenerator = new CodeGenerator(inputFilename); + + const apiClientGeneratorTemplate: Types.CodeGenerator.CustomGenerator = { + generator: Templates.ApiClient.generator, + option: { sync: false, additionalMethodComment: true }, + }; + + const typeDefCode = codeGenerator.generateTypeDefinition(); + const apiClientCode = codeGenerator.generateCode([ + { + generator: () => { + return [`import { Schemas } from "./types";`]; + }, + }, + codeGenerator.getAdditionalTypeDefinitionCustomCodeGenerator(), + apiClientGeneratorTemplate, + ]); + + writeText(path.join(outputDir, "types.ts"), typeDefCode); + writeText(path.join(outputDir, "apiClient.ts"), apiClientCode); +}; + +export const generateParameter = (inputFilename: string, outputFilename: string) => { + const codeGenerator = new CodeGenerator(inputFilename); + writeText(outputFilename, JSON.stringify(codeGenerator.getCodeGeneratorParamsArray(), null, 2)); +}; + +export const generateFormatTypeCode = (inputFilename: string, outputFilename: string) => { + const option: CodeGeneratorOption = { + convertOption: { + formatConversions: [ + { + selector: { + format: "binary", + }, + output: { + type: ["Blob"], + }, + }, + { + selector: { + format: "int-or-string", + }, + output: { + type: ["number", "string"], + }, + }, + { + selector: { + format: "custom-type", + }, + output: { + type: ["CustomType"], + }, + }, + { + selector: { + format: "date-time", + }, + output: { + type: ["Date"], + }, + }, + { + selector: { + format: "A-and-B", + }, + output: { + type: ["A", "B"], + multiType: "allOf", + }, + }, + ], + }, + }; + const codeGenerator = new CodeGenerator(inputFilename, option); + + const apiClientGeneratorTemplate: Types.CodeGenerator.CustomGenerator = { + generator: Templates.ApiClient.generator, + option: {}, + }; + + const code = codeGenerator.generateTypeDefinition([ + codeGenerator.getAdditionalTypeDefinitionCustomCodeGenerator(), + apiClientGeneratorTemplate, + ]); + + writeText(outputFilename, code); +}; diff --git a/src/index.ts b/src/index.ts index ca022235..99481ec1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,20 +5,21 @@ import type * as Types from "./types"; export interface Option { allowOperationIds?: string[]; + convertOption: Api.OpenApiTools.ConvertContext.Options; } export class CodeGenerator { private rootSchema: Types.OpenApi.Document; private resolvedReferenceDocument: Types.OpenApi.Document; private parser: Api.OpenApiTools.Parser; - constructor(private readonly entryPoint: string, option?: Option) { + constructor(private readonly entryPoint: string, private option?: Option) { this.rootSchema = Api.FileSystem.loadJsonOrYaml(entryPoint); this.resolvedReferenceDocument = Api.ResolveReference.resolve(entryPoint, entryPoint, JSON.parse(JSON.stringify(this.rootSchema))); this.parser = this.createParser(); } private createParser(): Api.OpenApiTools.Parser { - return new Api.OpenApiTools.Parser(this.entryPoint, this.rootSchema, this.resolvedReferenceDocument); + return new Api.OpenApiTools.Parser(this.entryPoint, this.rootSchema, this.resolvedReferenceDocument, this.option?.convertOption); } /** diff --git a/src/internal/OpenApiTools/ConverterContext.ts b/src/internal/OpenApiTools/ConverterContext.ts index 2dcd8513..f3346e53 100644 --- a/src/internal/OpenApiTools/ConverterContext.ts +++ b/src/internal/OpenApiTools/ConverterContext.ts @@ -1,10 +1,43 @@ +import ts from "typescript"; + import * as Utils from "../../utils"; +import type { Factory } from "../TsGenerator"; + +export interface FormatConversion { + /** + * Search parameters for the Schema to be converted + */ + selector: { + /** + * DataType format + * + * @see https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#data-types + */ + format: string; + }; + /** + * Output format + */ + output: { + /** + * The type after conversion. The input string will be output as a typedef. + */ + type: string[]; + /** + * How to handle typedefs when there is more than one. + * + * Default oneOf + */ + multiType?: "allOf" | "oneOf"; + }; +} + /** * ユーザーが利用できる各種変換オプション */ -// export interface Options { - -// } +export interface Options { + formatConversions?: FormatConversion[]; +} export interface Types { /** @@ -35,12 +68,29 @@ export interface Types { generateParameterName: (operationId: string) => string; generateRequestBodyName: (operationId: string) => string; generateFunctionName: (operationId: string) => string; + convertFormatTypeNode: (schema: { format?: string }) => undefined | ts.TypeNode; } +const createFormatSchemaToTypeNode = (factory: Factory.Type, target: FormatConversion): ts.TypeNode => { + const typeNodes = target.output.type.map(value => { + return factory.TypeReferenceNode.create({ + name: value, + }); + }); + if (target.output.multiType === "allOf") { + return factory.IntersectionTypeNode.create({ + typeNodes: typeNodes, + }); + } + return factory.UnionTypeNode.create({ + typeNodes: typeNodes, + }); +}; + /** * ユーザーが利用できる各種変換オプション */ -export const create = (): Types => { +export const create = (factory: Factory.Type, options?: Options): Types => { const convertReservedWord = (word: string): string => { if (["import", "export"].includes(word)) { return word + "_"; @@ -92,5 +142,22 @@ export const create = (): Types => { generateFunctionName: (operationId: string) => { return convertString(operationId); }, + convertFormatTypeNode: schema => { + const formatConversions = options?.formatConversions; + if (!formatConversions || formatConversions.length === 0) { + return; + } + if (typeof schema === "boolean") { + return; + } + if (!schema.format) { + return; + } + const target = formatConversions.find(formatConvertion => formatConvertion.selector.format === schema.format); + if (!target) { + return; + } + return createFormatSchemaToTypeNode(factory, target); + }, }; }; diff --git a/src/internal/OpenApiTools/Parser.ts b/src/internal/OpenApiTools/Parser.ts index 0e2b92ca..3bbd45dd 100644 --- a/src/internal/OpenApiTools/Parser.ts +++ b/src/internal/OpenApiTools/Parser.ts @@ -13,15 +13,17 @@ import * as Paths from "./paths"; import * as TypeNodeContext from "./TypeNodeContext"; import { Store } from "./Walker"; +export { ConvertContext }; + export class Parser { private currentPoint: string; private convertContext: ConvertContext.Types; private store: Store; private factory: TypeScriptCodeGenerator.Factory.Type; - constructor(private entryPoint: string, private readonly rootSchema: OpenApi.Document, noReferenceOpenApiSchema: OpenApi.Document) { + constructor(private entryPoint: string, private readonly rootSchema: OpenApi.Document, noReferenceOpenApiSchema: OpenApi.Document, convertOption?: ConvertContext.Options) { this.currentPoint = entryPoint; - this.convertContext = ConvertContext.create(); this.factory = TypeScriptCodeGenerator.Factory.create(); + this.convertContext = ConvertContext.create(this.factory, convertOption); this.store = new Store(this.factory, noReferenceOpenApiSchema); this.initialize(); } diff --git a/src/internal/OpenApiTools/components/RequestBody.ts b/src/internal/OpenApiTools/components/RequestBody.ts index 8030174b..d3baf1f6 100644 --- a/src/internal/OpenApiTools/components/RequestBody.ts +++ b/src/internal/OpenApiTools/components/RequestBody.ts @@ -1,4 +1,4 @@ -import * as ts from "typescript"; +import ts from "typescript"; import type { OpenApi } from "../../../types"; import { Factory } from "../../TsGenerator"; diff --git a/src/internal/OpenApiTools/components/Schema.ts b/src/internal/OpenApiTools/components/Schema.ts index 270c9982..4dba8c05 100644 --- a/src/internal/OpenApiTools/components/Schema.ts +++ b/src/internal/OpenApiTools/components/Schema.ts @@ -1,4 +1,4 @@ -import ts from "typescript"; +import ts, { skipPartiallyEmittedExpressions } from "typescript"; import type { OpenApi } from "../../../types"; import { FeatureDevelopmentError } from "../../Exception"; @@ -132,7 +132,13 @@ export const generateTypeAlias = ( convertContext: ConvertContext.Types, ): ts.TypeAliasDeclaration => { let type: ts.TypeNode; - if (schema.enum) { + let formatTypeNode: ts.TypeNode | undefined; + if (schema.format && schema.type !== "any") { + formatTypeNode = convertContext.convertFormatTypeNode(schema); + } + if (formatTypeNode) { + type = formatTypeNode; + } else if (schema.enum) { if (Guard.isNumberArray(schema.enum) && (schema.type === "number" || schema.type === "integer")) { type = factory.TypeNode.create({ type: schema.type, diff --git a/src/internal/OpenApiTools/index.ts b/src/internal/OpenApiTools/index.ts index 8c01bbaf..fd09c9d0 100644 --- a/src/internal/OpenApiTools/index.ts +++ b/src/internal/OpenApiTools/index.ts @@ -1,2 +1,2 @@ export * as Comment from "./Comment"; -export { Parser } from "./Parser"; +export { Parser, ConvertContext } from "./Parser"; diff --git a/src/internal/OpenApiTools/toTypeNode.ts b/src/internal/OpenApiTools/toTypeNode.ts index 6e313f4f..3f3835e8 100644 --- a/src/internal/OpenApiTools/toTypeNode.ts +++ b/src/internal/OpenApiTools/toTypeNode.ts @@ -188,6 +188,10 @@ export const convert: Convert = ( case "number": { const items = schema.enum; let typeNode: ts.TypeNode; + const formatTypeNode = converterContext.convertFormatTypeNode(schema); + if (formatTypeNode) { + return formatTypeNode; + } if (items && Guard.isNumberArray(items)) { typeNode = factory.TypeNode.create({ type: schema.type, @@ -202,6 +206,10 @@ export const convert: Convert = ( } case "string": { const items = schema.enum; + const formatTypeNode = converterContext.convertFormatTypeNode(schema); + if (formatTypeNode) { + return formatTypeNode; + } let typeNode: ts.TypeNode; if (items && Guard.isStringArray(items)) { typeNode = factory.TypeNode.create({ diff --git a/test/__tests__/__snapshots__/format.domain.ts.snap b/test/__tests__/__snapshots__/format.domain.ts.snap new file mode 100644 index 00000000..53f3e9d0 --- /dev/null +++ b/test/__tests__/__snapshots__/format.domain.ts.snap @@ -0,0 +1,54 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Format Types format.domain 1`] = ` +"// +// Generated by @himenon/openapi-typescript-code-generator +// +// OpenApi : 3.1.0 +// +// License : MIT +// + + +export namespace Schemas { + export interface CustomType { + name?: string; + } + export type BinaryFormat_String = Blob; + export type IntOrStringFormat_String = number | string; + export type CustomTypeFormat_String = CustomType; + export type DateTimeFormat_String = Date; + export type BinaryFormat_Int = Blob; + export type IntOrStringFormat_Int = number | string; + export type CustomTypeFormat_Int = CustomType; + export type DateTimeFormat_Int = Date; + export interface ObjectPropertyCustomType { + date?: Date; + } + export type Binary = Blob; + export type IntOrString = number | string; + export type AandB = A & B; +} +export type HttpMethod = \\"GET\\" | \\"PUT\\" | \\"POST\\" | \\"DELETE\\" | \\"OPTIONS\\" | \\"HEAD\\" | \\"PATCH\\" | \\"TRACE\\"; +export interface ObjectLike { + [key: string]: any; +} +export interface QueryParameter { + value: any; + style?: \\"form\\" | \\"spaceDelimited\\" | \\"pipeDelimited\\" | \\"deepObject\\"; + explode: boolean; +} +export interface QueryParameters { + [key: string]: QueryParameter; +} +export type SuccessResponses = void; +export namespace ErrorResponse { } +export interface ApiClient { + request: (httpMethod: HttpMethod, url: string, headers: ObjectLike | any, requestBody: ObjectLike | any, queryParameters: QueryParameters | undefined, options?: RequestOption) => Promise; +} +export class Client { + private baseUrl: string; + constructor(private apiClient: ApiClient, baseUrl: string) { this.baseUrl = baseUrl.replace(/\\\\/$/, \\"\\"); } +} +" +`; diff --git a/test/__tests__/format.domain.ts b/test/__tests__/format.domain.ts new file mode 100644 index 00000000..cab0ccdc --- /dev/null +++ b/test/__tests__/format.domain.ts @@ -0,0 +1,12 @@ +import * as fs from "fs"; +import * as path from "path"; + +import * as Utils from "../utils"; + +describe("Format Types", () => { + test("format.domain", () => { + const generateCode = fs.readFileSync(path.join(__dirname, "../code/format.domain/code.ts"), { encoding: "utf-8" }); + const text = Utils.replaceVersionInfo(generateCode); + expect(text).toMatchSnapshot(); + }); +}); diff --git a/test/format.domain/index.yml b/test/format.domain/index.yml new file mode 100644 index 00000000..f23b4078 --- /dev/null +++ b/test/format.domain/index.yml @@ -0,0 +1,64 @@ +openapi: 3.1.0 +info: + version: 1.0.0 + title: format.domain + description: Type Format + license: + name: MIT + +servers: + - url: "http://dev.api.test.domain/" + description: Development Environment + - url: "https://api.test.domain/" + description: Production Environment + +tags: + - name: test + +components: + schemas: + CustomType: + type: object + properties: + name: + type: string + BinaryFormat_String: + type: string + format: binary + IntOrStringFormat_String: + type: string + format: int-or-string + CustomTypeFormat_String: + type: string + format: custom-type + DateTimeFormat_String: + type: string + format: date-time + BinaryFormat_Int: + type: integer + format: binary + IntOrStringFormat_Int: + type: integer + format: int-or-string + CustomTypeFormat_Int: + type: integer + format: custom-type + DateTimeFormat_Int: + type: integer + format: date-time + ObjectPropertyCustomType: + type: object + properties: + date: + type: string + format: date-time + Binary: + type: string + format: binary + IntOrString: + type: string + format: int-or-string + AandB: + type: string + format: A-and-B +