From 59577402bbcd5b139ae12c81c5520a7a4a2e2f69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Augustin=20=C5=A0ulc?= Date: Wed, 7 Dec 2022 17:43:42 +0100 Subject: [PATCH] OpenAPI generator now supports references to external files --- packages/generator/src/index.ts | 3 +++ packages/generator/src/openapi/fileGenerator.ts | 1 + packages/generator/src/openapi/models/entity.ts | 3 ++- .../src/openapi/models/externalEntity.ts | 7 +++++++ .../src/openapi/parsers/openApi2Parser.ts | 16 ++++++++++++++-- .../src/openapi/parsers/openApi3Parser.ts | 16 ++++++++++++++-- 6 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 packages/generator/src/openapi/models/externalEntity.ts diff --git a/packages/generator/src/index.ts b/packages/generator/src/index.ts index 828f143d..02a9895a 100644 --- a/packages/generator/src/index.ts +++ b/packages/generator/src/index.ts @@ -24,6 +24,7 @@ program config: options.config, debug: options.debug, }; + console.log("Processing ", params.config); if (options.decorators) { params.decorators = { output: options.decoratorsOutput }; @@ -52,6 +53,7 @@ program output: options.output, debug: options.debug, }; + console.log("Processing ", params.config); const GeneratorType = await import("./views"); const generator = new GeneratorType.default(params); @@ -72,6 +74,7 @@ program config: options.config, debug: options.debug, }; + console.log("Processing ", params.config); const GeneratorType = await import("./openapi"); const generator = new GeneratorType.default(params); diff --git a/packages/generator/src/openapi/fileGenerator.ts b/packages/generator/src/openapi/fileGenerator.ts index 2ac361d4..3fad4cc4 100644 --- a/packages/generator/src/openapi/fileGenerator.ts +++ b/packages/generator/src/openapi/fileGenerator.ts @@ -79,6 +79,7 @@ export default class FileGenerator { unionWriter.write(type); } // we can ignore AliasEntity because it is inlined + // we can ignore ExternalEntity because it is external progress.increment(); } diff --git a/packages/generator/src/openapi/models/entity.ts b/packages/generator/src/openapi/models/entity.ts index 33f4de36..aa514d34 100644 --- a/packages/generator/src/openapi/models/entity.ts +++ b/packages/generator/src/openapi/models/entity.ts @@ -1,8 +1,9 @@ import type AliasEntity from "./aliasEntity"; +import type ExternalEntity from "./externalEntity"; import type InheritedEntity from "./inheritedEntity"; import type ObjectEntity from "./objectEntity"; import type UnionEntity from "./unionEntity"; -type Entity = AliasEntity | ObjectEntity | InheritedEntity | UnionEntity; +type Entity = AliasEntity | ObjectEntity | InheritedEntity | UnionEntity | ExternalEntity; export default Entity; diff --git a/packages/generator/src/openapi/models/externalEntity.ts b/packages/generator/src/openapi/models/externalEntity.ts new file mode 100644 index 00000000..6c4d860a --- /dev/null +++ b/packages/generator/src/openapi/models/externalEntity.ts @@ -0,0 +1,7 @@ +import NamedObject from "./namedObject"; + +export default class ExternalEntity extends NamedObject { + constructor(name: string, public fullName: string) { + super(name); + } +} diff --git a/packages/generator/src/openapi/parsers/openApi2Parser.ts b/packages/generator/src/openapi/parsers/openApi2Parser.ts index 633ce0bb..2074faaf 100644 --- a/packages/generator/src/openapi/parsers/openApi2Parser.ts +++ b/packages/generator/src/openapi/parsers/openApi2Parser.ts @@ -6,6 +6,7 @@ import type ApiModel from "../models/apiModel"; import type Endpoint from "../models/endpoint"; import EntityProperty from "../models/entityProperty"; import Enum from "../models/enum"; +import ExternalEntity from "../models/externalEntity"; import InheritedEntity from "../models/inheritedEntity"; import ObjectEntity from "../models/objectEntity"; import Restriction from "../models/restriction"; @@ -86,7 +87,11 @@ export default class OpenApi2Parser implements ApiModel { private parseReferenceObject(definition: OpenAPIV2.ReferenceObject) { const name = getReferencedEntityName(definition.$ref); - return this.setTypeReference(name, undefined); + const type = isLocalReference(definition.$ref) + ? undefined // it will be set later when the referenced entity is parsed + : new ExternalEntity(name, definition.$ref); // just link the entity by name + + return this.setTypeReference(name, type); } private parseEnum(name: string, definition: IJsonSchema) { @@ -204,6 +209,13 @@ export default class OpenApi2Parser implements ApiModel { } } +const REFERENCE_START = "#/definitions/"; + function getReferencedEntityName(ref: string) { - return ref.replace("#/definitions/", ""); + const index = ref.indexOf(REFERENCE_START, 0); + return index >= 0 ? ref.substring(index + REFERENCE_START.length) : ref; +} + +function isLocalReference(ref: string) { + return ref.startsWith(REFERENCE_START); } diff --git a/packages/generator/src/openapi/parsers/openApi3Parser.ts b/packages/generator/src/openapi/parsers/openApi3Parser.ts index 2fa76a74..87738158 100644 --- a/packages/generator/src/openapi/parsers/openApi3Parser.ts +++ b/packages/generator/src/openapi/parsers/openApi3Parser.ts @@ -7,6 +7,7 @@ import type ApiModel from "../models/apiModel"; import Endpoint from "../models/endpoint"; import EntityProperty from "../models/entityProperty"; import Enum from "../models/enum"; +import ExternalEntity from "../models/externalEntity"; import InheritedEntity from "../models/inheritedEntity"; import ObjectEntity from "../models/objectEntity"; import Restriction from "../models/restriction"; @@ -83,7 +84,11 @@ export default class OpenApi3Parser implements ApiModel { private parseReferenceObject(definition: OpenAPIV3.ReferenceObject) { const name = getReferencedEntityName(definition.$ref); - return this.setTypeReference(name, undefined); + const type = isLocalReference(definition.$ref) + ? undefined // it will be set later when the referenced entity is parsed + : new ExternalEntity(name, definition.$ref); // just link the entity by name + + return this.setTypeReference(name, type); } private parseEnum(name: string, definition: OpenAPIV3.SchemaObject) { @@ -311,8 +316,15 @@ export default class OpenApi3Parser implements ApiModel { } } +const REFERENCE_START = "#/components/schemas/"; + function getReferencedEntityName(ref: string) { - return ref.replace("#/components/schemas/", ""); + const index = ref.indexOf(REFERENCE_START, 0); + return index >= 0 ? ref.substring(index + REFERENCE_START.length) : ref; +} + +function isLocalReference(ref: string) { + return ref.startsWith(REFERENCE_START); } function isHttpMethod(method: string) {