From 6208674c11ce51b496ae5aaed7b5afbe7674ecab Mon Sep 17 00:00:00 2001 From: Tiago Cerqueira Date: Tue, 28 May 2024 11:30:01 +0200 Subject: [PATCH] feat:add --prefer-types-over-interfaces options Co-Authored-By: Kamel Azizi --- README.md | 4 +- index.d.ts | 6 ++ index.js | 6 ++ package.json | 1 + src/configuration.js | 2 + templates/base/data-contracts.ejs | 4 ++ .../spec/preferTypesOverInterface/expected.ts | 18 ++++++ .../spec/preferTypesOverInterface/schema.json | 64 +++++++++++++++++++ tests/spec/preferTypesOverInterface/schema.ts | 18 ++++++ tests/spec/preferTypesOverInterface/test.js | 28 ++++++++ 10 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 tests/spec/preferTypesOverInterface/expected.ts create mode 100644 tests/spec/preferTypesOverInterface/schema.json create mode 100644 tests/spec/preferTypesOverInterface/schema.ts create mode 100644 tests/spec/preferTypesOverInterface/test.js diff --git a/README.md b/README.md index d2f7361a..3b0d11e3 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ Options: -r, --responses generate additional information about request responses also add typings for bad responses (default: false) --union-enums generate all "enum" types as union types (T1 | T2 | TN) (default: false) + --prefer-types-over-interface generate types instead of interfaces for DTOs (default: false) --add-readonly generate readonly properties (default: false) --route-types generate type definitions for API routes (default: false) --no-client do not generate an API class @@ -136,7 +137,8 @@ generateApi({ singleHttpClient: true, cleanOutput: false, enumNamesAsValues: false, - moduleNameFirstTag: false, + moduleNameFirstTag: false, + preferTypesOverInterface: false, generateUnionEnums: false, typePrefix: "", typeSuffix: "", diff --git a/index.d.ts b/index.d.ts index fccb5403..010735c1 100644 --- a/index.d.ts +++ b/index.d.ts @@ -31,6 +31,11 @@ interface GenerateApiParamsBase { */ generateUnionEnums?: boolean; + /** + * generate with types instead of interface + */ + preferTypesOverInterface?: boolean; + /** * generate type definitions for API routes (default: false) */ @@ -613,6 +618,7 @@ export interface GenerateApiConfiguration { generateRouteTypes: boolean; generateClient: boolean; generateUnionEnums: boolean; + preferTypesOverInterface: boolean; swaggerSchema: object; originalSchema: object; componentsMap: Record; diff --git a/index.js b/index.js index 90a27324..a7fa0356 100755 --- a/index.js +++ b/index.js @@ -67,6 +67,12 @@ const program = cli({ default: codeGenBaseConfig.generateUnionEnums, internal: { name: "generateUnionEnums" }, }, + { + flags: "--prefer-types-over-interface", + description: "prefer types over interfaces", + default: codeGenBaseConfig.preferTypesOverInterface, + internal: { name: "preferTypesOverInterface" }, + }, { flags: "--add-readonly", description: "generate readonly properties", diff --git a/package.json b/package.json index 0451a390..f10a145b 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "test:--templates": "node tests/spec/templates/test.js", "test:--type-suffix--type-prefix": "node tests/spec/typeSuffixPrefix/test.js", "test:--union-enums": "node tests/spec/unionEnums/test.js", + "test:--prefer-types-over-interface": "node tests/spec/preferTypesOverInterface/test.js", "test:additionalProperties2.0": "node tests/spec/additional-properties-2.0/test.js", "test:another-query-params": "node tests/spec/another-query-params/test.js", "test:const-keyword": "node tests/spec/const-keyword/test.js", diff --git a/src/configuration.js b/src/configuration.js index f78b4094..a24e2c8e 100644 --- a/src/configuration.js +++ b/src/configuration.js @@ -49,6 +49,8 @@ class CodeGenConfig { /** CLI flag */ generateUnionEnums = false; /** CLI flag */ + preferTypesOverInterface = false; + /** CLI flag */ addReadonly = false; enumNamesAsValues = false; /** parsed swagger schema from getSwaggerObject() */ diff --git a/templates/base/data-contracts.ejs b/templates/base/data-contracts.ejs index 166908da..f7caa7da 100644 --- a/templates/base/data-contracts.ejs +++ b/templates/base/data-contracts.ejs @@ -20,6 +20,10 @@ const dataContractTemplates = { return `enum ${contract.name} {\r\n${contract.content} \r\n }`; }, interface: (contract) => { + if (config.preferTypesOverInterface) { + return `type ${contract.name}${buildGenerics(contract)} = {\r\n${contract.content}}`; + } + return `interface ${contract.name}${buildGenerics(contract)} {\r\n${contract.content}}`; }, type: (contract) => { diff --git a/tests/spec/preferTypesOverInterface/expected.ts b/tests/spec/preferTypesOverInterface/expected.ts new file mode 100644 index 00000000..a5899d48 --- /dev/null +++ b/tests/spec/preferTypesOverInterface/expected.ts @@ -0,0 +1,18 @@ +/* eslint-disable */ +/* tslint:disable */ +/* + * --------------------------------------------------------------- + * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## + * ## ## + * ## AUTHOR: acacode ## + * ## SOURCE: https://github.com/acacode/swagger-typescript-api ## + * --------------------------------------------------------------- + */ + +export type Pet = { + /** @format int64 */ + readonly id: number; + readonly name: string; + readonly tag?: string; + readonly multiple?: string | number; +}; diff --git a/tests/spec/preferTypesOverInterface/schema.json b/tests/spec/preferTypesOverInterface/schema.json new file mode 100644 index 00000000..25ea5647 --- /dev/null +++ b/tests/spec/preferTypesOverInterface/schema.json @@ -0,0 +1,64 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "Swagger Petstore", + "description": "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification", + "termsOfService": "http://swagger.io/terms/", + "contact": { + "name": "Swagger API Team" + }, + "license": { + "name": "MIT" + } + }, + "host": "petstore.swagger.io", + "basePath": "/api", + "schemes": ["http"], + "consumes": ["application/json"], + "produces": ["application/json"], + "paths": { + "/pets": { + "get": { + "description": "Returns all pets from the system that the user has access to", + "produces": ["application/json"], + "responses": { + "200": { + "description": "A list of pets.", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Pet" + } + } + } + } + } + } + }, + "definitions": { + "Pet": { + "type": "object", + "required": ["id", "name"], + "properties": { + "id": { + "type": "integer", + "readOnly": true, + "format": "int64" + }, + "name": { + "type": "string", + "readOnly": true + }, + "tag": { + "type": "string", + "readOnly": true + }, + "multiple": { + "type": ["string", "number"], + "readOnly": true + } + } + } + } +} diff --git a/tests/spec/preferTypesOverInterface/schema.ts b/tests/spec/preferTypesOverInterface/schema.ts new file mode 100644 index 00000000..a5899d48 --- /dev/null +++ b/tests/spec/preferTypesOverInterface/schema.ts @@ -0,0 +1,18 @@ +/* eslint-disable */ +/* tslint:disable */ +/* + * --------------------------------------------------------------- + * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## + * ## ## + * ## AUTHOR: acacode ## + * ## SOURCE: https://github.com/acacode/swagger-typescript-api ## + * --------------------------------------------------------------- + */ + +export type Pet = { + /** @format int64 */ + readonly id: number; + readonly name: string; + readonly tag?: string; + readonly multiple?: string | number; +}; diff --git a/tests/spec/preferTypesOverInterface/test.js b/tests/spec/preferTypesOverInterface/test.js new file mode 100644 index 00000000..a3fd597b --- /dev/null +++ b/tests/spec/preferTypesOverInterface/test.js @@ -0,0 +1,28 @@ +const { generateApiForTest } = require("../../helpers/generateApiForTest"); +const { resolve } = require("node:path"); +const validateGeneratedModule = require("../../helpers/validateGeneratedModule"); +const createSchemaInfos = require("../../helpers/createSchemaInfos"); +const assertGeneratedModule = require("../../helpers/assertGeneratedModule"); + +const schemas = createSchemaInfos({ + absolutePathToSchemas: resolve(__dirname, "./"), +}); + +schemas.forEach(({ absolutePath, apiFileName }) => { + generateApiForTest({ + testName: "prefer types over interface test", + silent: true, + name: apiFileName, + input: absolutePath, + output: resolve(__dirname, "./"), + addReadonly: true, + generateClient: false, + preferTypesOverInterface: true, + }).then(() => { + validateGeneratedModule(resolve(__dirname, `./${apiFileName}`)); + assertGeneratedModule( + resolve(__dirname, `./${apiFileName}`), + resolve(__dirname, "./expected.ts"), + ); + }); +});