diff --git a/scripts/testCodeGen.ts b/scripts/testCodeGen.ts index 1f9a4e91..e4259717 100644 --- a/scripts/testCodeGen.ts +++ b/scripts/testCodeGen.ts @@ -30,6 +30,9 @@ const main = () => { Writer.generateTypedefWithTemplateCode("test/argo-rollout/index.json", "test/code/argo-rollout/client.ts", false, { sync: false, }); + Writer.generateTypedefWithTemplateCode("test/unknown.schema.domain/index.yml", "test/code/unknown.schema.domain/client.ts", false, { + sync: false, + }); Writer.generateSplitCode("test/api.test.domain/index.yml", "test/code/split"); diff --git a/src/internal/OpenApiTools/ConverterContext.ts b/src/internal/OpenApiTools/ConverterContext.ts index f3346e53..536b3ad2 100644 --- a/src/internal/OpenApiTools/ConverterContext.ts +++ b/src/internal/OpenApiTools/ConverterContext.ts @@ -103,9 +103,12 @@ export const create = (factory: Factory.Type, options?: Options): Types => { } return text.replace(/-/g, "$").replace(/\//g, "$"); }; + const convertOperationId = (text: string): string => { + return convertString(text).replace(/\./g, "$"); + } return { escapeOperationIdText: (operationId: string): string => { - return convertString(operationId); + return convertOperationId(operationId); }, escapeDeclarationText: (text: string) => { // console.log(`escapeDeclarationText: ${text}` + `-> ${convertReservedWord(convertString(text).replace(/\./g, "$"))}`.padStart(100, " ")); @@ -122,25 +125,25 @@ export const create = (factory: Factory.Type, options?: Options): Types => { return convertString(text); }, generateResponseName: (operationId: string, statusCode: string): string => { - return Utils.responseName(convertString(operationId), statusCode); + return Utils.responseName(convertOperationId(operationId), statusCode); }, generateArgumentParamsTypeDeclaration: (operationId: string) => { - return Utils.argumentParamsTypeDeclaration(convertString(operationId)); + return Utils.argumentParamsTypeDeclaration(convertOperationId(operationId)); }, generateRequestContentTypeName: (operationId: string) => { - return Utils.requestContentType(convertString(operationId)); + return Utils.requestContentType(convertOperationId(operationId)); }, generateResponseContentTypeName: (operationId: string) => { - return Utils.responseContentType(convertString(operationId)); + return Utils.responseContentType(convertOperationId(operationId)); }, generateParameterName: (operationId: string) => { - return Utils.parameterName(convertString(operationId)); + return Utils.parameterName(convertOperationId(operationId)); }, generateRequestBodyName: (operationId: string) => { - return Utils.requestBodyName(convertString(operationId)); + return Utils.requestBodyName(convertOperationId(operationId)); }, generateFunctionName: (operationId: string) => { - return convertString(operationId); + return convertOperationId(operationId); }, convertFormatTypeNode: schema => { const formatConversions = options?.formatConversions; diff --git a/src/internal/OpenApiTools/toTypeNode.ts b/src/internal/OpenApiTools/toTypeNode.ts index 3f3835e8..e0f419ab 100644 --- a/src/internal/OpenApiTools/toTypeNode.ts +++ b/src/internal/OpenApiTools/toTypeNode.ts @@ -169,8 +169,12 @@ export const convert: Convert = ( Logger.info("Parent Schema:"); Logger.info(JSON.stringify(option.parent)); } - Logger.showFilePosition(entryPoint, currentPoint); - throw new UnsetTypeError("Please set 'type' or '$ref' property \n" + JSON.stringify(schema)); + const typeNode = factory.TypeNode.create({ + type: "any", + }); + return typeNode; + // Logger.showFilePosition(entryPoint, currentPoint); + // throw new UnsetTypeError("Please set 'type' or '$ref' property \n" + JSON.stringify(schema)); } switch (schema.type) { case "boolean": { diff --git a/src/utils.ts b/src/utils.ts index afafdc6a..ac5a74fa 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -9,8 +9,12 @@ export const isAvailableVariableName = (text: string): boolean => { return /^[A-Za-z_0-9\s]+$/.test(text); }; +export const isFirstCharacterIsValidText = (text: string): boolean => { + return /^[A-Za-z]+/.test(text); +} + export const escapeText = (text: string): string => { - if (isAvailableVariableName(text)) { + if (isAvailableVariableName(text) && isFirstCharacterIsValidText(text)) { return text; } return `"${text}"`; diff --git a/test/__tests__/__snapshots__/parameter-test.ts.snap b/test/__tests__/__snapshots__/parameter-test.ts.snap index 63a54130..dbbeb98e 100644 --- a/test/__tests__/__snapshots__/parameter-test.ts.snap +++ b/test/__tests__/__snapshots__/parameter-test.ts.snap @@ -229,6 +229,92 @@ exports[`Parameter api.test.domain 1`] = ` } } }, + { + \\"operationId\\": \\"i.have.dot\\", + \\"convertedParams\\": { + \\"escapedOperationId\\": \\"i$have$dot\\", + \\"argumentParamsTypeDeclaration\\": \\"Params$i$have$dot\\", + \\"functionName\\": \\"i$have$dot\\", + \\"requestContentTypeName\\": \\"RequestContentType$i$have$dot\\", + \\"responseContentTypeName\\": \\"ResponseContentType$i$have$dot\\", + \\"parameterName\\": \\"Parameter$i$have$dot\\", + \\"requestBodyName\\": \\"RequestBody$i$have$dot\\", + \\"hasRequestBody\\": false, + \\"hasParameter\\": false, + \\"pickedParameters\\": [], + \\"requestContentTypes\\": [], + \\"responseSuccessNames\\": [ + \\"Response$i$have$dot$Status$200\\" + ], + \\"responseFirstSuccessName\\": \\"Response$i$have$dot$Status$200\\", + \\"has2OrMoreSuccessNames\\": false, + \\"responseErrorNames\\": [], + \\"has2OrMoreRequestContentTypes\\": false, + \\"successResponseContentTypes\\": [ + \\"application/json\\" + ], + \\"successResponseFirstContentType\\": \\"application/json\\", + \\"has2OrMoreSuccessResponseContentTypes\\": false, + \\"hasAdditionalHeaders\\": false, + \\"hasQueryParameters\\": false + }, + \\"operationParams\\": { + \\"httpMethod\\": \\"get\\", + \\"requestUri\\": \\"/i/have/dot\\", + \\"comment\\": \\"\\", + \\"deprecated\\": false, + \\"parameters\\": [], + \\"responses\\": { + \\"200\\": { + \\"description\\": \\"Get Books\\", + \\"content\\": { + \\"application/json\\": { + \\"schema\\": { + \\"type\\": \\"object\\", + \\"properties\\": { + \\"books\\": { + \\"type\\": \\"array\\", + \\"items\\": { + \\"type\\": \\"object\\", + \\"description\\": \\"Item Model\\", + \\"required\\": [ + \\"name\\", + \\"children\\" + ], + \\"properties\\": { + \\"name\\": { + \\"type\\": \\"string\\" + }, + \\"children\\": { + \\"type\\": \\"array\\", + \\"items\\": { + \\"type\\": \\"object\\", + \\"required\\": [ + \\"id\\", + \\"name\\" + ], + \\"properties\\": { + \\"id\\": { + \\"type\\": \\"string\\" + }, + \\"name\\": { + \\"type\\": \\"string\\", + \\"description\\": \\"child name\\" + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, { \\"operationId\\": \\"getReferenceItems\\", \\"convertedParams\\": { diff --git a/test/__tests__/__snapshots__/spit-code-test.ts.snap b/test/__tests__/__snapshots__/spit-code-test.ts.snap index 70bad30f..ad1df96e 100644 --- a/test/__tests__/__snapshots__/spit-code-test.ts.snap +++ b/test/__tests__/__snapshots__/spit-code-test.ts.snap @@ -37,6 +37,11 @@ export interface Response$getFullRemoteReference$Status$200 { name?: \\"responseA\\"; }; } +export interface Response$i$have$dot$Status$200 { + \\"application/json\\": { + books?: Schemas.Item[]; + }; +} export interface Response$getReferenceItems$Status$200 { \\"application/json\\": { books?: Schemas.Item[]; @@ -81,6 +86,7 @@ export type ResponseContentType$getFullRemoteReference = keyof Response$getFullR export interface Params$getFullRemoteReference { parameter: Parameter$getFullRemoteReference; } +export type ResponseContentType$i$have$dot = keyof Response$i$have$dot$Status$200; export type ResponseContentType$getReferenceItems = keyof Response$getReferenceItems$Status$200; export type ResponseContentType$searchBook = keyof Response$searchBook$Status$200; export interface Params$searchBook { @@ -106,11 +112,12 @@ export interface QueryParameter { export interface QueryParameters { [key: string]: QueryParameter; } -export type SuccessResponses = Response$getIncludeLocalReference$Status$200 | Response$getFullRemoteReference$Status$200 | Response$getReferenceItems$Status$200 | Response$searchBook$Status$200 | Response$getBookById$Status$200 | Response$deleteBook$Status$200; +export type SuccessResponses = Response$getIncludeLocalReference$Status$200 | Response$getFullRemoteReference$Status$200 | Response$i$have$dot$Status$200 | Response$getReferenceItems$Status$200 | Response$searchBook$Status$200 | Response$getBookById$Status$200 | Response$deleteBook$Status$200; export namespace ErrorResponse { export type getIncludeLocalReference = void; export type getIncludeRemoteReference = void; export type getFullRemoteReference = void; + export type i$have$dot = void; export type getReferenceItems = void; export type searchBook = void; export type getBookById = void; @@ -164,6 +171,17 @@ export class Client { }; return this.apiClient.request(\\"GET\\", url, headers, undefined, queryParameters, option); } + /** + * operationId: i.have.dot + * Request URI: /i/have/dot + */ + public async i$have$dot(option?: RequestOption): Promise { + const url = this.baseUrl + \`/i/have/dot\`; + const headers = { + Accept: \\"application/json\\" + }; + return this.apiClient.request(\\"GET\\", url, headers, undefined, undefined, option); + } /** * operationId: getReferenceItems * Request URI: /get/reference/items diff --git a/test/__tests__/__snapshots__/template-only-test.ts.snap b/test/__tests__/__snapshots__/template-only-test.ts.snap index 3818c961..81cfc2ab 100644 --- a/test/__tests__/__snapshots__/template-only-test.ts.snap +++ b/test/__tests__/__snapshots__/template-only-test.ts.snap @@ -23,6 +23,7 @@ export type ResponseContentType$getFullRemoteReference = keyof Response$getFullR export interface Params$getFullRemoteReference { parameter: Parameter$getFullRemoteReference; } +export type ResponseContentType$i$have$dot = keyof Response$i$have$dot$Status$200; export type ResponseContentType$getReferenceItems = keyof Response$getReferenceItems$Status$200; export type ResponseContentType$searchBook = keyof Response$searchBook$Status$200; export interface Params$searchBook { @@ -48,11 +49,12 @@ export interface QueryParameter { export interface QueryParameters { [key: string]: QueryParameter; } -export type SuccessResponses = Response$getIncludeLocalReference$Status$200 | Response$getFullRemoteReference$Status$200 | Response$getReferenceItems$Status$200 | Response$searchBook$Status$200 | Response$getBookById$Status$200 | Response$deleteBook$Status$200; +export type SuccessResponses = Response$getIncludeLocalReference$Status$200 | Response$getFullRemoteReference$Status$200 | Response$i$have$dot$Status$200 | Response$getReferenceItems$Status$200 | Response$searchBook$Status$200 | Response$getBookById$Status$200 | Response$deleteBook$Status$200; export namespace ErrorResponse { export type getIncludeLocalReference = void; export type getIncludeRemoteReference = void; export type getFullRemoteReference = void; + export type i$have$dot = void; export type getReferenceItems = void; export type searchBook = void; export type getBookById = void; @@ -94,6 +96,13 @@ export class Client { }; return this.apiClient.request(\\"GET\\", url, headers, undefined, queryParameters, option); } + public async i$have$dot(option?: RequestOption): Promise { + const url = this.baseUrl + \`/i/have/dot\`; + const headers = { + Accept: \\"application/json\\" + }; + return this.apiClient.request(\\"GET\\", url, headers, undefined, undefined, option); + } public async getReferenceItems(option?: RequestOption): Promise { const url = this.baseUrl + \`/get/reference/items\`; const headers = { @@ -152,6 +161,7 @@ export type ResponseContentType$getFullRemoteReference = keyof Response$getFullR export interface Params$getFullRemoteReference { parameter: Parameter$getFullRemoteReference; } +export type ResponseContentType$i$have$dot = keyof Response$i$have$dot$Status$200; export type ResponseContentType$getReferenceItems = keyof Response$getReferenceItems$Status$200; export type ResponseContentType$searchBook = keyof Response$searchBook$Status$200; export interface Params$searchBook { @@ -177,11 +187,12 @@ export interface QueryParameter { export interface QueryParameters { [key: string]: QueryParameter; } -export type SuccessResponses = Response$getIncludeLocalReference$Status$200 | Response$getFullRemoteReference$Status$200 | Response$getReferenceItems$Status$200 | Response$searchBook$Status$200 | Response$getBookById$Status$200 | Response$deleteBook$Status$200; +export type SuccessResponses = Response$getIncludeLocalReference$Status$200 | Response$getFullRemoteReference$Status$200 | Response$i$have$dot$Status$200 | Response$getReferenceItems$Status$200 | Response$searchBook$Status$200 | Response$getBookById$Status$200 | Response$deleteBook$Status$200; export namespace ErrorResponse { export type getIncludeLocalReference = void; export type getIncludeRemoteReference = void; export type getFullRemoteReference = void; + export type i$have$dot = void; export type getReferenceItems = void; export type searchBook = void; export type getBookById = void; @@ -223,6 +234,13 @@ export class Client { }; return this.apiClient.request(\\"GET\\", url, headers, undefined, queryParameters, option); } + public i$have$dot(option?: RequestOption): Response$i$have$dot$Status$200[\\"application/json\\"] { + const url = this.baseUrl + \`/i/have/dot\`; + const headers = { + Accept: \\"application/json\\" + }; + return this.apiClient.request(\\"GET\\", url, headers, undefined, undefined, option); + } public getReferenceItems(option?: RequestOption): Response$getReferenceItems$Status$200[\\"application/json\\"] { const url = this.baseUrl + \`/get/reference/items\`; const headers = { diff --git a/test/__tests__/__snapshots__/typedef-with-template-test.ts.snap b/test/__tests__/__snapshots__/typedef-with-template-test.ts.snap index bc296b60..3d20d7b0 100644 --- a/test/__tests__/__snapshots__/typedef-with-template-test.ts.snap +++ b/test/__tests__/__snapshots__/typedef-with-template-test.ts.snap @@ -313,6 +313,11 @@ export interface Response$getFullRemoteReference$Status$200 { name?: \\"responseA\\"; }; } +export interface Response$i$have$dot$Status$200 { + \\"application/json\\": { + books?: Schemas.Item[]; + }; +} export interface Response$getReferenceItems$Status$200 { \\"application/json\\": { books?: Schemas.Item[]; @@ -357,6 +362,7 @@ export type ResponseContentType$getFullRemoteReference = keyof Response$getFullR export interface Params$getFullRemoteReference { parameter: Parameter$getFullRemoteReference; } +export type ResponseContentType$i$have$dot = keyof Response$i$have$dot$Status$200; export type ResponseContentType$getReferenceItems = keyof Response$getReferenceItems$Status$200; export type ResponseContentType$searchBook = keyof Response$searchBook$Status$200; export interface Params$searchBook { @@ -382,11 +388,12 @@ export interface QueryParameter { export interface QueryParameters { [key: string]: QueryParameter; } -export type SuccessResponses = Response$getIncludeLocalReference$Status$200 | Response$getFullRemoteReference$Status$200 | Response$getReferenceItems$Status$200 | Response$searchBook$Status$200 | Response$getBookById$Status$200 | Response$deleteBook$Status$200; +export type SuccessResponses = Response$getIncludeLocalReference$Status$200 | Response$getFullRemoteReference$Status$200 | Response$i$have$dot$Status$200 | Response$getReferenceItems$Status$200 | Response$searchBook$Status$200 | Response$getBookById$Status$200 | Response$deleteBook$Status$200; export namespace ErrorResponse { export type getIncludeLocalReference = void; export type getIncludeRemoteReference = void; export type getFullRemoteReference = void; + export type i$have$dot = void; export type getReferenceItems = void; export type searchBook = void; export type getBookById = void; @@ -428,6 +435,13 @@ export class Client { }; return this.apiClient.request(\\"GET\\", url, headers, undefined, queryParameters, option); } + public async i$have$dot(option?: RequestOption): Promise { + const url = this.baseUrl + \`/i/have/dot\`; + const headers = { + Accept: \\"application/json\\" + }; + return this.apiClient.request(\\"GET\\", url, headers, undefined, undefined, option); + } public async getReferenceItems(option?: RequestOption): Promise { const url = this.baseUrl + \`/get/reference/items\`; const headers = { @@ -839,6 +853,11 @@ export interface Response$getFullRemoteReference$Status$200 { name?: \\"responseA\\"; }; } +export interface Response$i$have$dot$Status$200 { + \\"application/json\\": { + books?: Schemas.Item[]; + }; +} export interface Response$getReferenceItems$Status$200 { \\"application/json\\": { books?: Schemas.Item[]; @@ -883,6 +902,7 @@ export type ResponseContentType$getFullRemoteReference = keyof Response$getFullR export interface Params$getFullRemoteReference { parameter: Parameter$getFullRemoteReference; } +export type ResponseContentType$i$have$dot = keyof Response$i$have$dot$Status$200; export type ResponseContentType$getReferenceItems = keyof Response$getReferenceItems$Status$200; export type ResponseContentType$searchBook = keyof Response$searchBook$Status$200; export interface Params$searchBook { @@ -908,11 +928,12 @@ export interface QueryParameter { export interface QueryParameters { [key: string]: QueryParameter; } -export type SuccessResponses = Response$getIncludeLocalReference$Status$200 | Response$getFullRemoteReference$Status$200 | Response$getReferenceItems$Status$200 | Response$searchBook$Status$200 | Response$getBookById$Status$200 | Response$deleteBook$Status$200; +export type SuccessResponses = Response$getIncludeLocalReference$Status$200 | Response$getFullRemoteReference$Status$200 | Response$i$have$dot$Status$200 | Response$getReferenceItems$Status$200 | Response$searchBook$Status$200 | Response$getBookById$Status$200 | Response$deleteBook$Status$200; export namespace ErrorResponse { export type getIncludeLocalReference = void; export type getIncludeRemoteReference = void; export type getFullRemoteReference = void; + export type i$have$dot = void; export type getReferenceItems = void; export type searchBook = void; export type getBookById = void; @@ -954,6 +975,13 @@ export class Client { }; return this.apiClient.request(\\"GET\\", url, headers, undefined, queryParameters, option); } + public i$have$dot(option?: RequestOption): Response$i$have$dot$Status$200[\\"application/json\\"] { + const url = this.baseUrl + \`/i/have/dot\`; + const headers = { + Accept: \\"application/json\\" + }; + return this.apiClient.request(\\"GET\\", url, headers, undefined, undefined, option); + } public getReferenceItems(option?: RequestOption): Response$getReferenceItems$Status$200[\\"application/json\\"] { const url = this.baseUrl + \`/get/reference/items\`; const headers = { diff --git a/test/__tests__/__snapshots__/unknown-schema-domain-test.ts.snap b/test/__tests__/__snapshots__/unknown-schema-domain-test.ts.snap new file mode 100644 index 00000000..79af3182 --- /dev/null +++ b/test/__tests__/__snapshots__/unknown-schema-domain-test.ts.snap @@ -0,0 +1,59 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Unknown client.ts 1`] = ` +"// +// Generated by @himenon/openapi-typescript-code-generator +// +// OpenApi : 3.1.0 +// +// License : MIT +// + + +export namespace Schemas { + /** What is this? */ + export type Unknown = any; +} +export interface Parameter$getUnknown { + /** Number Book ID */ + id: number; +} +export interface Response$getUnknown$Status$200 { + \\"application/json\\": Schemas.Unknown; +} +export type ResponseContentType$getUnknown = keyof Response$getUnknown$Status$200; +export interface Params$getUnknown { + parameter: Parameter$getUnknown; +} +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 = Response$getUnknown$Status$200; +export namespace ErrorResponse { + export type getUnknown = void; +} +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(/\\\\/$/, \\"\\"); } + public async getUnknown(params: Params$getUnknown, option?: RequestOption): Promise { + const url = this.baseUrl + \`/get/unknown\`; + const headers = { + Accept: \\"application/json\\" + }; + return this.apiClient.request(\\"GET\\", url, headers, undefined, undefined, option); + } +} +" +`; diff --git a/test/__tests__/unknown-schema-domain-test.ts b/test/__tests__/unknown-schema-domain-test.ts new file mode 100644 index 00000000..c847cd24 --- /dev/null +++ b/test/__tests__/unknown-schema-domain-test.ts @@ -0,0 +1,12 @@ +import * as fs from "fs"; +import * as path from "path"; + +import * as Utils from "../utils"; + +describe("Unknown", () => { + test("client.ts", () => { + const generateCode = fs.readFileSync(path.join(__dirname, "../code/unknown.schema.domain/client.ts"), { encoding: "utf-8" }); + const text = Utils.replaceVersionInfo(generateCode); + expect(text).toMatchSnapshot(); + }); +}); diff --git a/test/api.test.domain/index.yml b/test/api.test.domain/index.yml index 194762d7..df504206 100644 --- a/test/api.test.domain/index.yml +++ b/test/api.test.domain/index.yml @@ -365,6 +365,21 @@ paths: $ref: "#/components/pathItems/IncludeRemoteReference" /FullRemoteReference: $ref: "./components/pathItems/FullRemoteReference.yml" + /i/have/dot: + get: + operationId: i.have.dot + responses: + 200: + description: Get Books + content: + application/json: + schema: + type: object + properties: + books: + type: array + items: + $ref: "./components/schemas/Item.yml" /get/reference/items: get: operationId: getReferenceItems diff --git a/test/unknown.schema.domain/index.yml b/test/unknown.schema.domain/index.yml new file mode 100644 index 00000000..0e99d325 --- /dev/null +++ b/test/unknown.schema.domain/index.yml @@ -0,0 +1,41 @@ +openapi: 3.1.0 +info: + version: 1.0.0 + title: api.test.domain + description: Library test schema + license: + name: MIT + +servers: + - url: "http://dev.unknown.schema.domain/" + description: Development Environment + - url: "https://unknown.schema.domain/" + description: Production Environment + +tags: + - name: test + +components: + schemas: + Unknown: + description: "What is this?" + +paths: + /get/unknown: + get: + operationId: getUnknown + parameters: + - name: id + in: path + required: true + description: Number Book ID + schema: + type: number + format: uuid + responses: + 200: + description: "get books" + content: + application/json: + schema: + $ref: "#/components/schemas/Unknown" \ No newline at end of file