diff --git a/.changeset/fifty-glasses-whisper.md b/.changeset/fifty-glasses-whisper.md new file mode 100644 index 000000000..731e367a5 --- /dev/null +++ b/.changeset/fifty-glasses-whisper.md @@ -0,0 +1,5 @@ +--- +"@hey-api/openapi-ts": patch +--- + +fix(enum): append index number on duplicate name diff --git a/.eslintrc.json b/.eslintrc.json index d1c5fcb6b..ff1cbb445 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -9,22 +9,23 @@ "es6": true, "node": true }, - "plugins": ["simple-import-sort"], + "plugins": ["simple-import-sort", "sort-keys-fix"], "rules": { - "@typescript-eslint/ban-ts-comment": 0, - "@typescript-eslint/ban-ts-ignore": 0, - "@typescript-eslint/explicit-function-return-type": 0, - "@typescript-eslint/explicit-module-boundary-types": 0, + "@typescript-eslint/ban-ts-comment": "off", + "@typescript-eslint/ban-ts-ignore": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-inferrable-types": 0, - "@typescript-eslint/no-non-null-assertion": 0, - "@typescript-eslint/no-var-requires": 0, + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/no-var-requires": "off", "arrow-body-style": "error", "import/order": "off", "object-shorthand": "error", "prettier/prettier": ["error"], "simple-import-sort/exports": "error", "simple-import-sort/imports": "error", - "sort-imports": "off" + "sort-imports": "off", + "sort-keys-fix/sort-keys-fix": "warn" } } diff --git a/package-lock.json b/package-lock.json index c03617d04..796f03de9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,6 +48,7 @@ "eslint-config-prettier": "9.1.0", "eslint-plugin-prettier": "5.1.3", "eslint-plugin-simple-import-sort": "12.0.0", + "eslint-plugin-sort-keys-fix": "1.1.2", "express": "4.19.2", "node-fetch": "3.3.2", "npm-run-all2": "6.1.2", @@ -8101,6 +8102,56 @@ "eslint": ">=5.0.0" } }, + "node_modules/eslint-plugin-sort-keys-fix": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-sort-keys-fix/-/eslint-plugin-sort-keys-fix-1.1.2.tgz", + "integrity": "sha512-DNPHFGCA0/hZIsfODbeLZqaGY/+q3vgtshF85r+YWDNCQ2apd9PNs/zL6ttKm0nD1IFwvxyg3YOTI7FHl4unrw==", + "dev": true, + "dependencies": { + "espree": "^6.1.2", + "esutils": "^2.0.2", + "natural-compare": "^1.4.0", + "requireindex": "~1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-sort-keys-fix/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/eslint-plugin-sort-keys-fix/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-sort-keys-fix/node_modules/espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", @@ -13750,6 +13801,15 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, + "node_modules/requireindex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", + "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", + "dev": true, + "engines": { + "node": ">=0.10.5" + } + }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", diff --git a/package.json b/package.json index fac2ace57..7cbe992c8 100644 --- a/package.json +++ b/package.json @@ -97,6 +97,7 @@ "eslint-config-prettier": "9.1.0", "eslint-plugin-prettier": "5.1.3", "eslint-plugin-simple-import-sort": "12.0.0", + "eslint-plugin-sort-keys-fix": "1.1.2", "express": "4.19.2", "node-fetch": "3.3.2", "npm-run-all2": "6.1.2", diff --git a/rollup.config.ts b/rollup.config.ts index 81e3f731a..48d79fc08 100644 --- a/rollup.config.ts +++ b/rollup.config.ts @@ -18,13 +18,6 @@ import { defineConfig } from 'rollup'; */ export function handlebarsPlugin(): Plugin { return { - name: 'handlebars', - resolveId: (file: any, importer: any) => { - if (path.extname(file) === '.hbs') { - return path.resolve(path.dirname(importer), file); - } - return null; - }, load: (file: any) => { if (path.extname(file) === '.hbs') { const template = readFileSync(file, 'utf8').toString().trim(); @@ -41,9 +34,9 @@ export function handlebarsPlugin(): Plugin { escapeDescription: true, escapeNewline: true, exactArray: true, - ifdef: true, ifNotNullNotUndefined: true, ifOperationDataOptional: true, + ifdef: true, intersection: true, modelUnionType: true, nameOperationDataType: true, @@ -60,6 +53,13 @@ export function handlebarsPlugin(): Plugin { } return null; }, + name: 'handlebars', + resolveId: (file: any, importer: any) => { + if (path.extname(file) === '.hbs') { + return path.resolve(path.dirname(importer), file); + } + return null; + }, }; } diff --git a/rollup.dts.config.ts b/rollup.dts.config.ts index 968b38501..216df7063 100644 --- a/rollup.dts.config.ts +++ b/rollup.dts.config.ts @@ -8,6 +8,7 @@ const pkg = JSON.parse(readFileSync(new URL('./package.json', import.meta.url)). const external = [/^node:*/, ...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)]; export default defineConfig({ + external, input: { index: './temp/node/index.d.ts', }, @@ -15,6 +16,5 @@ export default defineConfig({ dir: './dist/node', format: 'esm', }, - external, plugins: [dts({ respectExternal: true })], }); diff --git a/src/openApi/common/parser/__tests__/getPattern.spec.ts b/src/openApi/common/parser/__tests__/getPattern.spec.ts index 8efe94b92..2c091b945 100644 --- a/src/openApi/common/parser/__tests__/getPattern.spec.ts +++ b/src/openApi/common/parser/__tests__/getPattern.spec.ts @@ -4,15 +4,15 @@ import { getPattern } from '../getPattern'; describe('getPattern', () => { it.each([ - { pattern: undefined, expected: undefined }, - { pattern: '', expected: '' }, - { pattern: '^[a-zA-Z]', expected: '^[a-zA-Z]' }, - { pattern: '^\\w+$', expected: '^\\\\w+$' }, - { pattern: '^\\d{3}-\\d{2}-\\d{4}$', expected: '^\\\\d{3}-\\\\d{2}-\\\\d{4}$' }, - { pattern: '\\', expected: '\\\\' }, - { pattern: '\\/', expected: '\\\\/' }, - { pattern: '\\/\\/', expected: '\\\\/\\\\/' }, - { pattern: "'", expected: "\\'" }, + { expected: undefined, pattern: undefined }, + { expected: '', pattern: '' }, + { expected: '^[a-zA-Z]', pattern: '^[a-zA-Z]' }, + { expected: '^\\\\w+$', pattern: '^\\w+$' }, + { expected: '^\\\\d{3}-\\\\d{2}-\\\\d{4}$', pattern: '^\\d{3}-\\d{2}-\\d{4}$' }, + { expected: '\\\\', pattern: '\\' }, + { expected: '\\\\/', pattern: '\\/' }, + { expected: '\\\\/\\\\/', pattern: '\\/\\/' }, + { expected: "\\'", pattern: "'" }, ])('getPattern($pattern) -> $expected', ({ pattern, expected }) => { expect(getPattern(pattern)).toEqual(expected); }); diff --git a/src/openApi/common/parser/__tests__/getRef.spec.ts b/src/openApi/common/parser/__tests__/getRef.spec.ts index c0243c95f..152195df1 100644 --- a/src/openApi/common/parser/__tests__/getRef.spec.ts +++ b/src/openApi/common/parser/__tests__/getRef.spec.ts @@ -7,21 +7,21 @@ describe('getRef (v2)', () => { expect( getRef( { - swagger: '2.0', - info: { - title: 'dummy', - version: '1.0', - }, - host: 'localhost:8080', basePath: '/api', - schemes: ['http', 'https'], - paths: {}, definitions: { Example: { description: 'This is an Example model ', type: 'integer', }, }, + host: 'localhost:8080', + info: { + title: 'dummy', + version: '1.0', + }, + paths: {}, + schemes: ['http', 'https'], + swagger: '2.0', }, { $ref: '#/definitions/Example', @@ -39,25 +39,25 @@ describe('getRef (v3)', () => { expect( getRef( { - openapi: '3.0', + components: { + schemas: { + Example: { + description: 'This is an Example model ', + type: 'integer', + }, + }, + }, info: { title: 'dummy', version: '1.0', }, + openapi: '3.0', paths: {}, servers: [ { url: 'https://localhost:8080/api', }, ], - components: { - schemas: { - Example: { - description: 'This is an Example model ', - type: 'integer', - }, - }, - }, }, { $ref: '#/components/schemas/Example', @@ -73,11 +73,11 @@ describe('getRef (v3)', () => { expect( getRef( { - openapi: '3.0', info: { title: 'dummy', version: '1.0', }, + openapi: '3.0', paths: { '/api/user/{id}': { description: 'This is an Example path', diff --git a/src/openApi/common/parser/__tests__/operation.spec.ts b/src/openApi/common/parser/__tests__/operation.spec.ts index 64c0c7671..e2a50c3e0 100644 --- a/src/openApi/common/parser/__tests__/operation.spec.ts +++ b/src/openApi/common/parser/__tests__/operation.spec.ts @@ -13,147 +13,147 @@ describe('getOperationName', () => { it.each([ { - url: '/api/v{api-version}/users', + expected: 'getAllUsers', method: 'GET', - options: options1, operationId: 'GetAllUsers', - expected: 'getAllUsers', + options: options1, + url: '/api/v{api-version}/users', }, { - url: '/api/v{api-version}/users', + expected: 'getApiUsers', method: 'GET', - options: options1, operationId: undefined, - expected: 'getApiUsers', + options: options1, + url: '/api/v{api-version}/users', }, { - url: '/api/v{api-version}/users', + expected: 'postApiUsers', method: 'POST', - options: options1, operationId: undefined, - expected: 'postApiUsers', + options: options1, + url: '/api/v{api-version}/users', }, - { url: '/api/v1/users', method: 'GET', options: options1, operationId: 'GetAllUsers', expected: 'getAllUsers' }, - { url: '/api/v1/users', method: 'GET', options: options1, operationId: undefined, expected: 'getApiV1Users' }, - { url: '/api/v1/users', method: 'POST', options: options1, operationId: undefined, expected: 'postApiV1Users' }, + { expected: 'getAllUsers', method: 'GET', operationId: 'GetAllUsers', options: options1, url: '/api/v1/users' }, + { expected: 'getApiV1Users', method: 'GET', operationId: undefined, options: options1, url: '/api/v1/users' }, + { expected: 'postApiV1Users', method: 'POST', operationId: undefined, options: options1, url: '/api/v1/users' }, { - url: '/api/v1/users/{id}', + expected: 'getApiV1UsersById', method: 'GET', - options: options1, operationId: undefined, - expected: 'getApiV1UsersById', + options: options1, + url: '/api/v1/users/{id}', }, { - url: '/api/v1/users/{id}', + expected: 'postApiV1UsersById', method: 'POST', - options: options1, operationId: undefined, - expected: 'postApiV1UsersById', + options: options1, + url: '/api/v1/users/{id}', }, { - url: '/api/v{api-version}/users', + expected: 'fooBar', method: 'GET', - options: options1, operationId: 'fooBar', - expected: 'fooBar', + options: options1, + url: '/api/v{api-version}/users', }, { - url: '/api/v{api-version}/users', + expected: 'fooBar', method: 'GET', - options: options1, operationId: 'FooBar', - expected: 'fooBar', + options: options1, + url: '/api/v{api-version}/users', }, { - url: '/api/v{api-version}/users', + expected: 'fooBar', method: 'GET', - options: options1, operationId: 'Foo Bar', - expected: 'fooBar', + options: options1, + url: '/api/v{api-version}/users', }, { - url: '/api/v{api-version}/users', + expected: 'fooBar', method: 'GET', - options: options1, operationId: 'foo bar', - expected: 'fooBar', + options: options1, + url: '/api/v{api-version}/users', }, { - url: '/api/v{api-version}/users', + expected: 'fooBar', method: 'GET', - options: options1, operationId: 'foo-bar', - expected: 'fooBar', + options: options1, + url: '/api/v{api-version}/users', }, { - url: '/api/v{api-version}/users', + expected: 'fooBar', method: 'GET', - options: options1, operationId: 'foo_bar', - expected: 'fooBar', + options: options1, + url: '/api/v{api-version}/users', }, { - url: '/api/v{api-version}/users', + expected: 'fooBar', method: 'GET', - options: options1, operationId: 'foo.bar', - expected: 'fooBar', + options: options1, + url: '/api/v{api-version}/users', }, { - url: '/api/v{api-version}/users', + expected: 'fooBar', method: 'GET', - options: options1, operationId: '@foo.bar', - expected: 'fooBar', + options: options1, + url: '/api/v{api-version}/users', }, { - url: '/api/v{api-version}/users', + expected: 'fooBar', method: 'GET', - options: options1, operationId: '$foo.bar', - expected: 'fooBar', + options: options1, + url: '/api/v{api-version}/users', }, { - url: '/api/v{api-version}/users', + expected: 'fooBar', method: 'GET', - options: options1, operationId: '_foo.bar', - expected: 'fooBar', + options: options1, + url: '/api/v{api-version}/users', }, { - url: '/api/v{api-version}/users', + expected: 'fooBar', method: 'GET', - options: options1, operationId: '-foo.bar', - expected: 'fooBar', + options: options1, + url: '/api/v{api-version}/users', }, { - url: '/api/v{api-version}/users', + expected: 'fooBar', method: 'GET', - options: options1, operationId: '123.foo.bar', - expected: 'fooBar', + options: options1, + url: '/api/v{api-version}/users', }, { - url: '/api/v1/users', + expected: 'getApiV1Users', method: 'GET', - options: options2, operationId: 'GetAllUsers', - expected: 'getApiV1Users', + options: options2, + url: '/api/v1/users', }, { - url: '/api/v{api-version}/users', + expected: 'getApiUsers', method: 'GET', - options: options2, operationId: 'fooBar', - expected: 'getApiUsers', + options: options2, + url: '/api/v{api-version}/users', }, { - url: '/api/v{api-version}/users/{userId}/location/{locationId}', + expected: 'getApiUsersByUserIdLocationByLocationId', method: 'GET', - options: options2, operationId: 'fooBar', - expected: 'getApiUsersByUserIdLocationByLocationId', + options: options2, + url: '/api/v{api-version}/users/{userId}/location/{locationId}', }, ])( 'getOperationName($url, $method, { operationId: $useOperationId }, $operationId) -> $expected', @@ -165,19 +165,19 @@ describe('getOperationName', () => { describe('getOperationParameterName', () => { it.each([ - { input: '', expected: '' }, - { input: 'foobar', expected: 'foobar' }, - { input: 'fooBar', expected: 'fooBar' }, - { input: 'foo_bar', expected: 'fooBar' }, - { input: 'foo-bar', expected: 'fooBar' }, - { input: 'foo.bar', expected: 'fooBar' }, - { input: '@foo.bar', expected: 'fooBar' }, - { input: '$foo.bar', expected: 'fooBar' }, - { input: '123.foo.bar', expected: 'fooBar' }, - { input: 'Foo-Bar', expected: 'fooBar' }, - { input: 'FOO-BAR', expected: 'fooBar' }, - { input: 'foo[bar]', expected: 'fooBar' }, - { input: 'foo.bar[]', expected: 'fooBarArray' }, + { expected: '', input: '' }, + { expected: 'foobar', input: 'foobar' }, + { expected: 'fooBar', input: 'fooBar' }, + { expected: 'fooBar', input: 'foo_bar' }, + { expected: 'fooBar', input: 'foo-bar' }, + { expected: 'fooBar', input: 'foo.bar' }, + { expected: 'fooBar', input: '@foo.bar' }, + { expected: 'fooBar', input: '$foo.bar' }, + { expected: 'fooBar', input: '123.foo.bar' }, + { expected: 'fooBar', input: 'Foo-Bar' }, + { expected: 'fooBar', input: 'FOO-BAR' }, + { expected: 'fooBar', input: 'foo[bar]' }, + { expected: 'fooBarArray', input: 'foo.bar[]' }, ])('getOperationParameterName($input) -> $expected', ({ input, expected }) => { expect(getOperationParameterName(input)).toEqual(expected); }); @@ -185,13 +185,13 @@ describe('getOperationParameterName', () => { describe('getOperationResponseCode', () => { it.each([ - { input: '', expected: null }, - { input: 'default', expected: 200 }, - { input: '200', expected: 200 }, - { input: '300', expected: 300 }, - { input: '400', expected: 400 }, - { input: 'abc', expected: null }, - { input: '-100', expected: 100 }, + { expected: null, input: '' }, + { expected: 200, input: 'default' }, + { expected: 200, input: '200' }, + { expected: 300, input: '300' }, + { expected: 400, input: '400' }, + { expected: null, input: 'abc' }, + { expected: 100, input: '-100' }, ])('getOperationResponseCode($input) -> $expected', ({ input, expected }) => { expect(getOperationResponseCode(input)).toEqual(expected); }); diff --git a/src/openApi/common/parser/__tests__/sanitize.spec.ts b/src/openApi/common/parser/__tests__/sanitize.spec.ts index a653dca9a..2891abe24 100644 --- a/src/openApi/common/parser/__tests__/sanitize.spec.ts +++ b/src/openApi/common/parser/__tests__/sanitize.spec.ts @@ -9,10 +9,10 @@ import { describe('sanitizeOperationName', () => { it.each([ - { input: 'abc', expected: 'abc' }, - { input: 'æbc', expected: 'æbc' }, - { input: 'æb.c', expected: 'æb-c' }, - { input: '1æb.c', expected: 'æb-c' }, + { expected: 'abc', input: 'abc' }, + { expected: 'æbc', input: 'æbc' }, + { expected: 'æb-c', input: 'æb.c' }, + { expected: 'æb-c', input: '1æb.c' }, ])('sanitizeOperationName($input) -> $expected', ({ input, expected }) => { expect(sanitizeOperationName(input)).toEqual(expected); }); @@ -20,11 +20,11 @@ describe('sanitizeOperationName', () => { describe('sanitizeOperationParameterName', () => { it.each([ - { input: 'abc', expected: 'abc' }, - { input: 'æbc', expected: 'æbc' }, - { input: 'æb.c', expected: 'æb-c' }, - { input: '1æb.c', expected: 'æb-c' }, - { input: 'unknown[]', expected: 'unknownArray' }, + { expected: 'abc', input: 'abc' }, + { expected: 'æbc', input: 'æbc' }, + { expected: 'æb-c', input: 'æb.c' }, + { expected: 'æb-c', input: '1æb.c' }, + { expected: 'unknownArray', input: 'unknown[]' }, ])('sanitizeOperationParameterName($input) -> $expected', ({ input, expected }) => { expect(sanitizeOperationParameterName(input)).toEqual(expected); }); @@ -32,10 +32,10 @@ describe('sanitizeOperationParameterName', () => { describe('sanitizeServiceName', () => { it.each([ - { input: 'abc', expected: 'abc' }, - { input: 'æbc', expected: 'æbc' }, - { input: 'æb.c', expected: 'æb-c' }, - { input: '1æb.c', expected: 'æb-c' }, + { expected: 'abc', input: 'abc' }, + { expected: 'æbc', input: 'æbc' }, + { expected: 'æb-c', input: 'æb.c' }, + { expected: 'æb-c', input: '1æb.c' }, ])('sanitizeServiceName($input) -> $expected', ({ input, expected }) => { expect(sanitizeServiceName(input)).toEqual(expected); }); @@ -43,10 +43,10 @@ describe('sanitizeServiceName', () => { describe('sanitizeTypeName', () => { it.each([ - { input: 'abc', expected: 'abc' }, - { input: 'æbc', expected: 'æbc' }, - { input: 'æb.c', expected: 'æb_c' }, - { input: '1æb.c', expected: 'æb_c' }, + { expected: 'abc', input: 'abc' }, + { expected: 'æbc', input: 'æbc' }, + { expected: 'æb_c', input: 'æb.c' }, + { expected: 'æb_c', input: '1æb.c' }, ])('sanitizeTypeName($input) -> $expected', ({ input, expected }) => { expect(sanitizeTypeName(input)).toEqual(expected); }); diff --git a/src/openApi/common/parser/__tests__/service.spec.ts b/src/openApi/common/parser/__tests__/service.spec.ts index 574ca72aa..dd3f0278f 100644 --- a/src/openApi/common/parser/__tests__/service.spec.ts +++ b/src/openApi/common/parser/__tests__/service.spec.ts @@ -4,9 +4,9 @@ import { getServiceName, getServiceVersion } from '../service'; describe('getServiceVersion', () => { it.each([ - { input: '1.0', expected: '1.0' }, - { input: 'v1.2', expected: '1.2' }, - { input: 'V2.4', expected: '2.4' }, + { expected: '1.0', input: '1.0' }, + { expected: '1.2', input: 'v1.2' }, + { expected: '2.4', input: 'V2.4' }, ])('should get $expected when version is $input', ({ input, expected }) => { expect(getServiceVersion(input)).toEqual(expected); }); @@ -14,14 +14,14 @@ describe('getServiceVersion', () => { describe('getServiceName', () => { it.each([ - { input: '', expected: '' }, - { input: 'FooBar', expected: 'FooBar' }, - { input: 'Foo Bar', expected: 'FooBar' }, - { input: 'foo bar', expected: 'FooBar' }, - { input: '@fooBar', expected: 'FooBar' }, - { input: '$fooBar', expected: 'FooBar' }, - { input: '123fooBar', expected: 'FooBar' }, - { input: 'non-ascii-æøåÆØÅöôêÊ字符串', expected: 'NonAsciiÆøåÆøÅöôêÊ字符串' }, + { expected: '', input: '' }, + { expected: 'FooBar', input: 'FooBar' }, + { expected: 'FooBar', input: 'Foo Bar' }, + { expected: 'FooBar', input: 'foo bar' }, + { expected: 'FooBar', input: '@fooBar' }, + { expected: 'FooBar', input: '$fooBar' }, + { expected: 'FooBar', input: '123fooBar' }, + { expected: 'NonAsciiÆøåÆøÅöôêÊ字符串', input: 'non-ascii-æøåÆØÅöôêÊ字符串' }, ])('getServiceName($input) -> $expected', ({ input, expected }) => { expect(getServiceName(input)).toEqual(expected); }); diff --git a/src/openApi/common/parser/__tests__/sort.spec.ts b/src/openApi/common/parser/__tests__/sort.spec.ts index 840da7ef8..b4e36e7d0 100644 --- a/src/openApi/common/parser/__tests__/sort.spec.ts +++ b/src/openApi/common/parser/__tests__/sort.spec.ts @@ -5,27 +5,27 @@ import { toSortedByRequired } from '../sort'; describe('sort', () => { it.each([ { - input: [ - { id: 'test', isRequired: false }, + expected: [ { id: 'test2', isRequired: true }, { id: 'test3', isRequired: true }, + { id: 'test', isRequired: false }, ], - expected: [ + input: [ + { id: 'test', isRequired: false }, { id: 'test2', isRequired: true }, { id: 'test3', isRequired: true }, - { id: 'test', isRequired: false }, ], }, { - input: [ + expected: [ { id: 'test', isRequired: false }, { id: 'test2', isRequired: false }, - { id: 'test3', isRequired: true, default: 'something' }, + { default: 'something', id: 'test3', isRequired: true }, ], - expected: [ + input: [ { id: 'test', isRequired: false }, { id: 'test2', isRequired: false }, - { id: 'test3', isRequired: true, default: 'something' }, + { default: 'something', id: 'test3', isRequired: true }, ], }, ])('should sort $input by required to produce $expected', ({ input, expected }) => { diff --git a/src/openApi/common/parser/__tests__/stripNamespace.spec.ts b/src/openApi/common/parser/__tests__/stripNamespace.spec.ts index 69e5e10a3..c4afb668a 100644 --- a/src/openApi/common/parser/__tests__/stripNamespace.spec.ts +++ b/src/openApi/common/parser/__tests__/stripNamespace.spec.ts @@ -4,19 +4,19 @@ import { stripNamespace } from '../stripNamespace'; describe('stripNamespace', () => { it.each([ - { input: '#/definitions/Item', expected: 'Item' }, - { input: '#/parameters/Item', expected: 'Item' }, - { input: '#/responses/Item', expected: 'Item' }, - { input: '#/securityDefinitions/Item', expected: 'Item' }, - { input: '#/components/schemas/Item', expected: 'Item' }, - { input: '#/components/responses/Item', expected: 'Item' }, - { input: '#/components/parameters/Item', expected: 'Item' }, - { input: '#/components/examples/Item', expected: 'Item' }, - { input: '#/components/requestBodies/Item', expected: 'Item' }, - { input: '#/components/headers/Item', expected: 'Item' }, - { input: '#/components/securitySchemes/Item', expected: 'Item' }, - { input: '#/components/links/Item', expected: 'Item' }, - { input: '#/components/callbacks/Item', expected: 'Item' }, + { expected: 'Item', input: '#/definitions/Item' }, + { expected: 'Item', input: '#/parameters/Item' }, + { expected: 'Item', input: '#/responses/Item' }, + { expected: 'Item', input: '#/securityDefinitions/Item' }, + { expected: 'Item', input: '#/components/schemas/Item' }, + { expected: 'Item', input: '#/components/responses/Item' }, + { expected: 'Item', input: '#/components/parameters/Item' }, + { expected: 'Item', input: '#/components/examples/Item' }, + { expected: 'Item', input: '#/components/requestBodies/Item' }, + { expected: 'Item', input: '#/components/headers/Item' }, + { expected: 'Item', input: '#/components/securitySchemes/Item' }, + { expected: 'Item', input: '#/components/links/Item' }, + { expected: 'Item', input: '#/components/callbacks/Item' }, ])('stripNamespace($input) -> $expected', ({ input, expected }) => { expect(stripNamespace(input)).toEqual(expected); }); diff --git a/src/openApi/common/parser/__tests__/type.spec.ts b/src/openApi/common/parser/__tests__/type.spec.ts index b1d763ad9..b2cfec749 100644 --- a/src/openApi/common/parser/__tests__/type.spec.ts +++ b/src/openApi/common/parser/__tests__/type.spec.ts @@ -4,27 +4,27 @@ import { getMappedType, getType } from '../type'; describe('getMappedType', () => { it.each([ - { type: '', expected: undefined }, - { type: 'any', expected: 'unknown' }, - { type: 'array', expected: 'unknown[]' }, - { type: 'boolean', expected: 'boolean' }, - { type: 'byte', expected: 'number' }, - { type: 'char', expected: 'string' }, - { type: 'date-time', expected: 'string' }, - { type: 'date', expected: 'string' }, - { type: 'double', expected: 'number' }, - { type: 'file', expected: 'binary' }, - { type: 'float', expected: 'number' }, - { type: 'int', expected: 'number' }, - { type: 'integer', expected: 'number' }, - { type: 'long', expected: 'number' }, - { type: 'null', expected: 'null' }, - { type: 'number', expected: 'number' }, - { type: 'object', expected: 'unknown' }, - { type: 'password', expected: 'string' }, - { type: 'short', expected: 'number' }, - { type: 'string', expected: 'string' }, - { type: 'void', expected: 'void' }, + { expected: undefined, type: '' }, + { expected: 'unknown', type: 'any' }, + { expected: 'unknown[]', type: 'array' }, + { expected: 'boolean', type: 'boolean' }, + { expected: 'number', type: 'byte' }, + { expected: 'string', type: 'char' }, + { expected: 'string', type: 'date-time' }, + { expected: 'string', type: 'date' }, + { expected: 'number', type: 'double' }, + { expected: 'binary', type: 'file' }, + { expected: 'number', type: 'float' }, + { expected: 'number', type: 'int' }, + { expected: 'number', type: 'integer' }, + { expected: 'number', type: 'long' }, + { expected: 'null', type: 'null' }, + { expected: 'number', type: 'number' }, + { expected: 'unknown', type: 'object' }, + { expected: 'string', type: 'password' }, + { expected: 'number', type: 'short' }, + { expected: 'string', type: 'string' }, + { expected: 'void', type: 'void' }, ])('should map type $type to $expected', ({ type, expected }) => { expect(getMappedType(type)).toEqual(expected); }); diff --git a/src/openApi/common/parser/getEnums.ts b/src/openApi/common/parser/getEnums.ts index 8786c71cd..ecb2af83a 100644 --- a/src/openApi/common/parser/getEnums.ts +++ b/src/openApi/common/parser/getEnums.ts @@ -14,9 +14,9 @@ export const getEnums = (definition: WithEnumExtension, values?: ReadonlyArray typeof value === 'number' || typeof value === 'string') .map((value, index) => ({ - 'x-enum-description': descriptions[index], - 'x-enum-varname': names[index], description: undefined, value, + 'x-enum-description': descriptions[index], + 'x-enum-varname': names[index], })); }; diff --git a/src/openApi/v2/index.ts b/src/openApi/v2/index.ts index f1ee4a1b3..9cd9753df 100644 --- a/src/openApi/v2/index.ts +++ b/src/openApi/v2/index.ts @@ -18,5 +18,11 @@ export const parse = (openApi: OpenApi, options: Config): Client => { const models = getModels(openApi); const services = getServices(openApi, options); - return { version, server, models, services }; + return { + enumNames: [], + models, + server, + services, + version, + }; }; diff --git a/src/openApi/v2/parser/__tests__/getServer.spec.ts b/src/openApi/v2/parser/__tests__/getServer.spec.ts index 3da9b20e3..07fa4077a 100644 --- a/src/openApi/v2/parser/__tests__/getServer.spec.ts +++ b/src/openApi/v2/parser/__tests__/getServer.spec.ts @@ -6,15 +6,15 @@ describe('getServer', () => { it('should produce correct result', () => { expect( getServer({ - swagger: '2.0', + basePath: '/api', + host: 'localhost:8080', info: { title: 'dummy', version: '1.0', }, - host: 'localhost:8080', - basePath: '/api', - schemes: ['http', 'https'], paths: {}, + schemes: ['http', 'https'], + swagger: '2.0', }) ).toEqual('http://localhost:8080/api'); }); diff --git a/src/openApi/v2/parser/__tests__/getServices.spec.ts b/src/openApi/v2/parser/__tests__/getServices.spec.ts index 9804d7aae..18a386f8e 100644 --- a/src/openApi/v2/parser/__tests__/getServices.spec.ts +++ b/src/openApi/v2/parser/__tests__/getServices.spec.ts @@ -27,7 +27,6 @@ describe('getServices', () => { }; const services = getServices( { - swagger: '2.0', info: { title: 'x', version: '1', @@ -35,7 +34,6 @@ describe('getServices', () => { paths: { '/api/trips': { get: { - tags: [], responses: { 200: { description: 'x', @@ -44,9 +42,11 @@ describe('getServices', () => { description: 'default', }, }, + tags: [], }, }, }, + swagger: '2.0', }, options ); diff --git a/src/openApi/v2/parser/getModel.ts b/src/openApi/v2/parser/getModel.ts index 84bcd6529..59f9276d6 100644 --- a/src/openApi/v2/parser/getModel.ts +++ b/src/openApi/v2/parser/getModel.ts @@ -29,14 +29,14 @@ export const getModel = ( isReadOnly: definition.readOnly === true, isRequired: false, link: null, - maximum: definition.maximum, maxItems: definition.maxItems, maxLength: definition.maxLength, maxProperties: definition.maxProperties, - minimum: definition.minimum, + maximum: definition.maximum, minItems: definition.minItems, minLength: definition.minLength, minProperties: definition.minProperties, + minimum: definition.minimum, multipleOf: definition.multipleOf, name, pattern: getPattern(definition.pattern), diff --git a/src/openApi/v2/parser/getModelProperties.ts b/src/openApi/v2/parser/getModelProperties.ts index 63dace623..a6724d711 100644 --- a/src/openApi/v2/parser/getModelProperties.ts +++ b/src/openApi/v2/parser/getModelProperties.ts @@ -33,14 +33,14 @@ export const getModelProperties = (openApi: OpenApi, definition: OpenApiSchema, isReadOnly: property.readOnly === true, isRequired: propertyRequired, link: null, - maximum: property.maximum, maxItems: property.maxItems, maxLength: property.maxLength, maxProperties: property.maxProperties, - minimum: property.minimum, + maximum: property.maximum, minItems: property.minItems, minLength: property.minLength, minProperties: property.minProperties, + minimum: property.minimum, multipleOf: property.multipleOf, name: escapeName(propertyName), pattern: getPattern(property.pattern), @@ -67,14 +67,14 @@ export const getModelProperties = (openApi: OpenApi, definition: OpenApiSchema, isReadOnly: property.readOnly === true, isRequired: propertyRequired, link: model.link, - maximum: property.maximum, maxItems: property.maxItems, maxLength: property.maxLength, maxProperties: property.maxProperties, - minimum: property.minimum, + maximum: property.maximum, minItems: property.minItems, minLength: property.minLength, minProperties: property.minProperties, + minimum: property.minimum, multipleOf: property.multipleOf, name: escapeName(propertyName), pattern: getPattern(property.pattern), diff --git a/src/openApi/v2/parser/getOperation.ts b/src/openApi/v2/parser/getOperation.ts index c3bb067f2..844dd921d 100644 --- a/src/openApi/v2/parser/getOperation.ts +++ b/src/openApi/v2/parser/getOperation.ts @@ -24,24 +24,24 @@ export const getOperation = ( // Create a new operation object for this method. const operation: Operation = { $refs: [], - service: serviceName, - name, - summary: op.summary || null, - description: op.description || null, deprecated: op.deprecated === true, + description: op.description || null, + errors: [], + imports: [], method: method.toUpperCase() as Operation['method'], - path: url, + name, parameters: [...pathParams.parameters], - parametersPath: [...pathParams.parametersPath], - parametersQuery: [...pathParams.parametersQuery], + parametersBody: pathParams.parametersBody, + parametersCookie: [...pathParams.parametersCookie], parametersForm: [...pathParams.parametersForm], parametersHeader: [...pathParams.parametersHeader], - parametersCookie: [...pathParams.parametersCookie], - parametersBody: pathParams.parametersBody, - imports: [], - errors: [], - results: [], + parametersPath: [...pathParams.parametersPath], + parametersQuery: [...pathParams.parametersQuery], + path: url, responseHeader: null, + results: [], + service: serviceName, + summary: op.summary || null, }; // Parse the operation parameters (path, query, body, etc). diff --git a/src/openApi/v2/parser/getOperationParameter.ts b/src/openApi/v2/parser/getOperationParameter.ts index 5c2c264e6..14369fcf0 100644 --- a/src/openApi/v2/parser/getOperationParameter.ts +++ b/src/openApi/v2/parser/getOperationParameter.ts @@ -28,13 +28,13 @@ export const getOperationParameter = (openApi: OpenApi, parameter: OpenApiParame isReadOnly: false, isRequired: parameter.required === true, link: null, - maximum: parameter.maximum, maxItems: parameter.maxItems, maxLength: parameter.maxLength, + maximum: parameter.maximum, mediaType: null, - minimum: parameter.minimum, minItems: parameter.minItems, minLength: parameter.minLength, + minimum: parameter.minimum, multipleOf: parameter.multipleOf, name: getOperationParameterName(parameter.name), pattern: getPattern(parameter.pattern), diff --git a/src/openApi/v2/parser/getOperationParameters.ts b/src/openApi/v2/parser/getOperationParameters.ts index 9ff35bc6f..9c2b87154 100644 --- a/src/openApi/v2/parser/getOperationParameters.ts +++ b/src/openApi/v2/parser/getOperationParameters.ts @@ -9,12 +9,12 @@ export const getOperationParameters = (openApi: OpenApi, parameters: OpenApiPara $refs: [], imports: [], parameters: [], - parametersPath: [], - parametersQuery: [], - parametersForm: [], + parametersBody: null, parametersCookie: [], + parametersForm: [], parametersHeader: [], - parametersBody: null, + parametersPath: [], + parametersQuery: [], }; // Iterate over the parameters diff --git a/src/openApi/v2/parser/getServices.ts b/src/openApi/v2/parser/getServices.ts index 00609f0ef..1304ad434 100644 --- a/src/openApi/v2/parser/getServices.ts +++ b/src/openApi/v2/parser/getServices.ts @@ -37,9 +37,9 @@ export const getServices = (openApi: OpenApi, options: Config): Service[] => { // append the new method to it. Otherwise we should create a new service object. const service: Service = services.get(operation.service) || { $refs: [], + imports: [], name: operation.service, operations: [], - imports: [], }; // Push the operation in the service diff --git a/src/openApi/v3/index.ts b/src/openApi/v3/index.ts index a7ec3a3c5..9cd9753df 100644 --- a/src/openApi/v3/index.ts +++ b/src/openApi/v3/index.ts @@ -19,6 +19,7 @@ export const parse = (openApi: OpenApi, options: Config): Client => { const services = getServices(openApi, options); return { + enumNames: [], models, server, services, diff --git a/src/openApi/v3/parser/__tests__/getModel.spec.ts b/src/openApi/v3/parser/__tests__/getModel.spec.ts index f57e52089..033dfd7f3 100644 --- a/src/openApi/v3/parser/__tests__/getModel.spec.ts +++ b/src/openApi/v3/parser/__tests__/getModel.spec.ts @@ -5,46 +5,19 @@ import { getType } from '../../../common/parser/type'; import { getModel } from '../getModel'; const openApi = { - openapi: '3.0', - info: { - title: 'dummy', - version: '1.0', - }, - paths: {}, - servers: [ - { - url: 'https://localhost:8080/api', - }, - ], components: { schemas: { - Enum1: { - enum: ['Bird', 'Dog'], - type: 'string', - }, - ConstValue: { - type: 'string', - const: 'ConstValue', - }, - CompositionWithAnyOfAndNull: { + CompositionWithAny: { description: "This is a model with one property with a 'any of' relationship where the options are not $ref", - type: 'object', properties: { propA: { anyOf: [ { - items: { - anyOf: [ - { - $ref: '#/components/schemas/Enum1', - }, - { - $ref: '#/components/schemas/ConstValue', - }, - ], - }, - type: 'array', + $ref: '#/components/schemas/Enum1', + }, + { + $ref: '#/components/schemas/ConstValue', }, { type: 'null', @@ -52,19 +25,26 @@ const openApi = { ], }, }, + type: 'object', }, - CompositionWithAny: { + CompositionWithAnyOfAndNull: { description: "This is a model with one property with a 'any of' relationship where the options are not $ref", - type: 'object', properties: { propA: { anyOf: [ { - $ref: '#/components/schemas/Enum1', - }, - { - $ref: '#/components/schemas/ConstValue', + items: { + anyOf: [ + { + $ref: '#/components/schemas/Enum1', + }, + { + $ref: '#/components/schemas/ConstValue', + }, + ], + }, + type: 'array', }, { type: 'null', @@ -72,9 +52,29 @@ const openApi = { ], }, }, + type: 'object', + }, + ConstValue: { + const: 'ConstValue', + type: 'string', + }, + Enum1: { + enum: ['Bird', 'Dog'], + type: 'string', }, }, }, + info: { + title: 'dummy', + version: '1.0', + }, + openapi: '3.0', + paths: {}, + servers: [ + { + url: 'https://localhost:8080/api', + }, + ], }; describe('getModel', () => { diff --git a/src/openApi/v3/parser/__tests__/getServer.spec.ts b/src/openApi/v3/parser/__tests__/getServer.spec.ts index e26ef7d17..acdce66b2 100644 --- a/src/openApi/v3/parser/__tests__/getServer.spec.ts +++ b/src/openApi/v3/parser/__tests__/getServer.spec.ts @@ -6,11 +6,11 @@ describe('getServer', () => { it('should produce correct result', () => { expect( getServer({ - openapi: '3.0', info: { title: 'dummy', version: '1.0', }, + openapi: '3.0', paths: {}, servers: [ { @@ -24,22 +24,22 @@ describe('getServer', () => { it('should produce correct result with variables', () => { expect( getServer({ - openapi: '3.0', info: { title: 'dummy', version: '1.0', }, + openapi: '3.0', paths: {}, servers: [ { url: '{scheme}://localhost:{port}/api', variables: { - scheme: { - default: 'https', - }, port: { default: '8080', }, + scheme: { + default: 'https', + }, }, }, ], diff --git a/src/openApi/v3/parser/__tests__/getServices.spec.ts b/src/openApi/v3/parser/__tests__/getServices.spec.ts index 79d21cce1..b81330a02 100644 --- a/src/openApi/v3/parser/__tests__/getServices.spec.ts +++ b/src/openApi/v3/parser/__tests__/getServices.spec.ts @@ -27,15 +27,14 @@ describe('getServices', () => { }; const services = getServices( { - openapi: '3.0.0', info: { title: 'x', version: '1', }, + openapi: '3.0.0', paths: { '/api/trips': { get: { - tags: [], responses: { 200: { description: 'x', @@ -44,6 +43,7 @@ describe('getServices', () => { description: 'default', }, }, + tags: [], }, }, }, diff --git a/src/openApi/v3/parser/getModel.ts b/src/openApi/v3/parser/getModel.ts index 71af26743..717d42786 100644 --- a/src/openApi/v3/parser/getModel.ts +++ b/src/openApi/v3/parser/getModel.ts @@ -34,14 +34,14 @@ export const getModel = ( isReadOnly: definition.readOnly === true, isRequired: false, link: null, - maximum: definition.maximum, maxItems: definition.maxItems, maxLength: definition.maxLength, maxProperties: definition.maxProperties, - minimum: definition.minimum, + maximum: definition.maximum, minItems: definition.minItems, minLength: definition.minLength, minProperties: definition.minProperties, + minimum: definition.minimum, multipleOf: definition.multipleOf, name, pattern: getPattern(definition.pattern), diff --git a/src/openApi/v3/parser/getModelProperties.ts b/src/openApi/v3/parser/getModelProperties.ts index 2be023fae..550c28b36 100644 --- a/src/openApi/v3/parser/getModelProperties.ts +++ b/src/openApi/v3/parser/getModelProperties.ts @@ -76,23 +76,23 @@ export const getModelProperties = ( | 'template' | 'type' > = { + default: property.default, deprecated: property.deprecated === true, description: property.description || null, - default: property.default, exclusiveMaximum: property.exclusiveMaximum, exclusiveMinimum: property.exclusiveMinimum, format: property.format, isDefinition: false, isReadOnly: property.readOnly === true, isRequired: propertyRequired, - maximum: property.maximum, maxItems: property.maxItems, maxLength: property.maxLength, maxProperties: property.maxProperties, - minimum: property.minimum, + maximum: property.maximum, minItems: property.minItems, minLength: property.minLength, minProperties: property.minProperties, + minimum: property.minimum, multipleOf: property.multipleOf, name: escapeName(propertyName), pattern: getPattern(property.pattern), @@ -136,10 +136,10 @@ export const getModelProperties = ( ...propertyValues, $refs: model.$refs, base: model.base, + default: model.default, enum: model.enum, enums: model.enums, export: model.export, - default: model.default, imports: model.imports, isNullable: model.isNullable || property.nullable === true, link: model.link, diff --git a/src/openApi/v3/parser/getOperationParameters.ts b/src/openApi/v3/parser/getOperationParameters.ts index e223c85e4..b682e190d 100644 --- a/src/openApi/v3/parser/getOperationParameters.ts +++ b/src/openApi/v3/parser/getOperationParameters.ts @@ -11,12 +11,12 @@ export const getOperationParameters = (openApi: OpenApi, parameters: OpenApiPara $refs: [], imports: [], parameters: [], - parametersPath: [], - parametersQuery: [], - parametersForm: [], + parametersBody: null, parametersCookie: [], + parametersForm: [], parametersHeader: [], - parametersBody: null, // Not used in v3 -> @see requestBody + parametersPath: [], + parametersQuery: [], // Not used in v3 -> @see requestBody }; parameters.forEach(parameterOrReference => { diff --git a/src/templates/partials/exportEnum.hbs b/src/templates/partials/exportEnum.hbs index 32184bb73..a6ce6c71d 100644 --- a/src/templates/partials/exportEnum.hbs +++ b/src/templates/partials/exportEnum.hbs @@ -30,7 +30,7 @@ export type {{{name}}} = {{{enumUnionType enum}}}; {{/if}} {{#equals @root.$config.enums 'javascript'}} -export const {{{enumName name }}} = { +export const {{{enumName name}}} = { {{#each enum}} {{#if x-enum-description}} /** diff --git a/src/types/client.ts b/src/types/client.ts index 26dfa63b2..561741721 100644 --- a/src/types/client.ts +++ b/src/types/client.ts @@ -1,5 +1,7 @@ import { Model, Service } from '../openApi'; + export interface Client { + enumNames: string[]; models: Model[]; server: string; services: Service[]; diff --git a/src/utils/__tests__/escapeName.spec.ts b/src/utils/__tests__/escapeName.spec.ts index 7605cffba..4ef541869 100644 --- a/src/utils/__tests__/escapeName.spec.ts +++ b/src/utils/__tests__/escapeName.spec.ts @@ -3,21 +3,21 @@ import { describe, expect, it } from 'vitest'; import { escapeName, unescapeName } from '../escapeName'; const toCheck: { unescaped: string; escaped: string }[] = [ - { unescaped: '', escaped: "''" }, - { unescaped: 'fooBar', escaped: 'fooBar' }, - { unescaped: 'Foo Bar', escaped: `'Foo Bar'` }, - { unescaped: 'foo bar', escaped: `'foo bar'` }, - { unescaped: 'foo-bar', escaped: `'foo-bar'` }, - { unescaped: 'foo.bar', escaped: `'foo.bar'` }, - { unescaped: 'foo_bar', escaped: 'foo_bar' }, - { unescaped: '123foo.bar', escaped: `'123foo.bar'` }, - { unescaped: '@foo.bar', escaped: `'@foo.bar'` }, - { unescaped: '$foo.bar', escaped: `'$foo.bar'` }, - { unescaped: '_foo.bar', escaped: `'_foo.bar'` }, - { unescaped: '123foobar', escaped: `'123foobar'` }, - { unescaped: '@foobar', escaped: `'@foobar'` }, - { unescaped: '$foobar', escaped: '$foobar' }, - { unescaped: '_foobar', escaped: '_foobar' }, + { escaped: "''", unescaped: '' }, + { escaped: 'fooBar', unescaped: 'fooBar' }, + { escaped: `'Foo Bar'`, unescaped: 'Foo Bar' }, + { escaped: `'foo bar'`, unescaped: 'foo bar' }, + { escaped: `'foo-bar'`, unescaped: 'foo-bar' }, + { escaped: `'foo.bar'`, unescaped: 'foo.bar' }, + { escaped: 'foo_bar', unescaped: 'foo_bar' }, + { escaped: `'123foo.bar'`, unescaped: '123foo.bar' }, + { escaped: `'@foo.bar'`, unescaped: '@foo.bar' }, + { escaped: `'$foo.bar'`, unescaped: '$foo.bar' }, + { escaped: `'_foo.bar'`, unescaped: '_foo.bar' }, + { escaped: `'123foobar'`, unescaped: '123foobar' }, + { escaped: `'@foobar'`, unescaped: '@foobar' }, + { escaped: '$foobar', unescaped: '$foobar' }, + { escaped: '_foobar', unescaped: '_foobar' }, ]; describe('escapeName', () => { diff --git a/src/utils/__tests__/handlebars.spec.ts b/src/utils/__tests__/handlebars.spec.ts index ded814bb2..afe749941 100644 --- a/src/utils/__tests__/handlebars.spec.ts +++ b/src/utils/__tests__/handlebars.spec.ts @@ -28,6 +28,7 @@ describe('registerHandlebarHelpers', () => { write: true, }, { + enumNames: [], models: [], server: '', services: [], @@ -82,6 +83,7 @@ describe('registerHandlebarTemplates', () => { write: true, }, { + enumNames: [], models: [], server: '', services: [], diff --git a/src/utils/__tests__/unique.spec.ts b/src/utils/__tests__/unique.spec.ts index 08cf80e9e..b262501cb 100644 --- a/src/utils/__tests__/unique.spec.ts +++ b/src/utils/__tests__/unique.spec.ts @@ -4,18 +4,18 @@ import { unique } from '../unique'; describe('unique', () => { it.each([ - { value: 'a', index: 0, arr: ['a', 'b', 'c'], result: true }, - { value: 'a', index: 1, arr: ['a', 'b', 'c'], result: false }, - { value: 'a', index: 2, arr: ['a', 'b', 'c'], result: false }, - { value: 'a', index: 1, arr: ['z', 'a', 'b'], result: true }, - { value: 'a', index: 2, arr: ['y', 'z', 'a'], result: true }, + { arr: ['a', 'b', 'c'], index: 0, result: true, value: 'a' }, + { arr: ['a', 'b', 'c'], index: 1, result: false, value: 'a' }, + { arr: ['a', 'b', 'c'], index: 2, result: false, value: 'a' }, + { arr: ['z', 'a', 'b'], index: 1, result: true, value: 'a' }, + { arr: ['y', 'z', 'a'], index: 2, result: true, value: 'a' }, ])('unique($value, $index, $arr) -> $result', ({ value, index, arr, result }) => { expect(unique(value, index, arr)).toEqual(result); }); it.each([ - { input: ['a', 'a', 'b', 'c', 'b', 'b'], expected: ['a', 'b', 'c'] }, - { input: [1, 2, 3, 4, 4, 5, 6, 3], expected: [1, 2, 3, 4, 5, 6] }, + { expected: ['a', 'b', 'c'], input: ['a', 'a', 'b', 'c', 'b', 'b'] }, + { expected: [1, 2, 3, 4, 5, 6], input: [1, 2, 3, 4, 4, 5, 6, 3] }, ])('should filter: $input to the unique array: $expected', ({ input, expected }) => { expect(input.filter(unique)).toEqual(expected); }); diff --git a/src/utils/enum.ts b/src/utils/enum.ts index cf11524ea..1463a95fb 100644 --- a/src/utils/enum.ts +++ b/src/utils/enum.ts @@ -1,4 +1,6 @@ import type { Enum } from '../openApi'; +import type { Client } from '../types/client'; +import type { Config } from '../types/config'; import { unescapeName } from './escapeName'; import { unique } from './unique'; @@ -41,12 +43,22 @@ export const enumKey = (value?: string | number, key?: string) => { * already escaped, so we need to remove quotes around it. * {@link https://github.com/ferdikoomen/openapi-typescript-codegen/issues/1969} */ -export const enumName = (name?: string) => { +export const enumName = (config: Config, client: Client, name?: string) => { if (!name) { return name; } - const escapedName = unescapeName(name).replace(/-([a-z])/gi, ($0, $1: string) => $1.toLocaleUpperCase()); - return `${escapedName.charAt(0).toLocaleUpperCase()}${escapedName.slice(1)}Enum`; + const escapedName = unescapeName(name).replace(/[-_]([a-z])/gi, ($0, $1: string) => $1.toLocaleUpperCase()); + let result = `${escapedName.charAt(0).toLocaleUpperCase() + escapedName.slice(1)}Enum`; + let index = 1; + while (client.enumNames.includes(result)) { + if (result.endsWith(index.toString())) { + result = result.slice(0, result.length - index.toString().length); + } + index += 1; + result = result + index.toString(); + } + client.enumNames = [...client.enumNames, result]; + return result; }; export const enumUnionType = (enums: Enum[]) => diff --git a/src/utils/handlebars.ts b/src/utils/handlebars.ts index f57b030b8..162595b4c 100644 --- a/src/utils/handlebars.ts +++ b/src/utils/handlebars.ts @@ -184,7 +184,6 @@ const operationDataType = (config: Config, service: Service) => { return output.join('\n'); }; -// eslint-disable-next-line @typescript-eslint/no-unused-vars export const registerHandlebarHelpers = (config: Config, client: Client): void => { Handlebars.registerHelper('camelCase', camelCase); @@ -193,7 +192,11 @@ export const registerHandlebarHelpers = (config: Config, client: Client): void = }); Handlebars.registerHelper('enumKey', enumKey); - Handlebars.registerHelper('enumName', enumName); + + Handlebars.registerHelper('enumName', function (name: string | undefined) { + return enumName(config, client, name); + }); + Handlebars.registerHelper('enumUnionType', enumUnionType); Handlebars.registerHelper('enumValue', enumValue); diff --git a/src/utils/postprocess.ts b/src/utils/postprocess.ts index f51f8539c..867a50163 100644 --- a/src/utils/postprocess.ts +++ b/src/utils/postprocess.ts @@ -10,6 +10,7 @@ import { unique } from './unique'; export function postProcessClient(client: Client): Client { return { ...client, + enumNames: [], models: client.models.map(model => postProcessModel(model)), services: client.services.map(service => postProcessService(service)), }; @@ -23,9 +24,9 @@ export function postProcessClient(client: Client): Client { export function postProcessModel(model: Model): Model { return { ...model, - imports: postProcessModelImports(model), - enums: postProcessModelEnums(model), enum: postProcessModelEnum(model), + enums: postProcessModelEnums(model), + imports: postProcessModelImports(model), }; } diff --git a/src/utils/write/__tests__/class.spec.ts b/src/utils/write/__tests__/class.spec.ts index ded911509..b50bf8744 100644 --- a/src/utils/write/__tests__/class.spec.ts +++ b/src/utils/write/__tests__/class.spec.ts @@ -10,10 +10,11 @@ vi.mock('node:fs'); describe('writeClientClass', () => { it('should write to filesystem', async () => { const client: Parameters[0] = { - server: 'http://localhost:8080', - version: 'v1', + enumNames: [], models: [], + server: 'http://localhost:8080', services: [], + version: 'v1', }; await writeClientClass(client, mockTemplates, './dist', { diff --git a/src/utils/write/__tests__/client.spec.ts b/src/utils/write/__tests__/client.spec.ts index 3855450dd..2a7e80618 100644 --- a/src/utils/write/__tests__/client.spec.ts +++ b/src/utils/write/__tests__/client.spec.ts @@ -10,10 +10,11 @@ vi.mock('node:fs'); describe('writeClient', () => { it('should write to filesystem', async () => { const client: Parameters[0] = { - server: 'http://localhost:8080', - version: 'v1', + enumNames: [], models: [], + server: 'http://localhost:8080', services: [], + version: 'v1', }; await writeClient(client, mockTemplates, { diff --git a/src/utils/write/__tests__/core.spec.ts b/src/utils/write/__tests__/core.spec.ts index 5bf4bdc90..b734cdf97 100644 --- a/src/utils/write/__tests__/core.spec.ts +++ b/src/utils/write/__tests__/core.spec.ts @@ -16,6 +16,7 @@ describe('writeClientCore', () => { it('should write to filesystem', async () => { const client: Parameters[0] = { + enumNames: [], models: [], server: 'http://localhost:8080', services: [], @@ -58,6 +59,7 @@ describe('writeClientCore', () => { it('uses client server value for base', async () => { const client: Parameters[0] = { + enumNames: [], models: [], server: 'http://localhost:8080', services: [], @@ -99,6 +101,7 @@ describe('writeClientCore', () => { it('uses custom value for base', async () => { const client: Parameters[0] = { + enumNames: [], models: [], server: 'http://localhost:8080', services: [], diff --git a/src/utils/write/__tests__/index.spec.ts b/src/utils/write/__tests__/index.spec.ts index 73095ddd9..785d131ff 100644 --- a/src/utils/write/__tests__/index.spec.ts +++ b/src/utils/write/__tests__/index.spec.ts @@ -11,10 +11,11 @@ vi.mock('node:fs'); describe('writeClientIndex', () => { it('should write to filesystem', async () => { const client: Parameters[0] = { - server: 'http://localhost:8080', - version: '1.0', + enumNames: [], models: [], + server: 'http://localhost:8080', services: [], + version: '1.0', }; await writeClientIndex(client, mockTemplates, '/', { diff --git a/src/utils/write/__tests__/models.spec.ts b/src/utils/write/__tests__/models.spec.ts index c8178b70f..1a48c0334 100644 --- a/src/utils/write/__tests__/models.spec.ts +++ b/src/utils/write/__tests__/models.spec.ts @@ -11,8 +11,7 @@ vi.mock('node:fs'); describe('writeClientModels', () => { it('should write to filesystem', async () => { const client: Parameters[0] = { - server: 'http://localhost:8080', - version: 'v1', + enumNames: [], models: [ { $refs: [], @@ -33,7 +32,9 @@ describe('writeClientModels', () => { type: 'User', }, ], + server: 'http://localhost:8080', services: [], + version: 'v1', }; await writeClientModels(client, mockTemplates, '/', { diff --git a/src/utils/write/__tests__/schemas.spec.ts b/src/utils/write/__tests__/schemas.spec.ts index 10af99f79..5d226f519 100644 --- a/src/utils/write/__tests__/schemas.spec.ts +++ b/src/utils/write/__tests__/schemas.spec.ts @@ -11,8 +11,7 @@ vi.mock('node:fs'); describe('writeClientSchemas', () => { it('should write to filesystem', async () => { const client: Parameters[0] = { - server: 'http://localhost:8080', - version: 'v1', + enumNames: [], models: [ { $refs: [], @@ -33,7 +32,9 @@ describe('writeClientSchemas', () => { type: 'User', }, ], + server: 'http://localhost:8080', services: [], + version: 'v1', }; await writeClientSchemas(client, mockTemplates, '/', { diff --git a/src/utils/write/__tests__/services.spec.ts b/src/utils/write/__tests__/services.spec.ts index 072b051a5..132623df9 100644 --- a/src/utils/write/__tests__/services.spec.ts +++ b/src/utils/write/__tests__/services.spec.ts @@ -10,9 +10,9 @@ vi.mock('node:fs'); describe('writeClientServices', () => { it('should write to filesystem', async () => { const client: Parameters[0] = { - server: 'http://localhost:8080', - version: 'v1', + enumNames: [], models: [], + server: 'http://localhost:8080', services: [ { $refs: [], @@ -21,6 +21,7 @@ describe('writeClientServices', () => { operations: [], }, ], + version: 'v1', }; await writeClientServices(client, mockTemplates, '/', { diff --git a/test/__snapshots__/v3/models.ts.snap b/test/__snapshots__/v3/models.ts.snap index 5444e2211..0f8135cd3 100644 --- a/test/__snapshots__/v3/models.ts.snap +++ b/test/__snapshots__/v3/models.ts.snap @@ -288,8 +288,19 @@ export type ModelWithNullableString = { * This is a simple string property */ nullableRequiredProp2: string | null; + /** + * This is a simple enum with strings + */ + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; }; +export const FooBarEnumEnum = { + SUCCESS: 'Success', + WARNING: 'Warning', + ERROR: 'Error', + ØÆÅ字符串: 'ØÆÅ字符串', +} as const; + /** * This is a model with one enum */ @@ -297,7 +308,7 @@ export type ModelWithEnum = { /** * This is a simple enum with strings */ - test?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; /** * These are the HTTP error code enums */ @@ -308,7 +319,7 @@ export type ModelWithEnum = { bool?: boolean; }; -export const TestEnum = { +export const FooBarEnumEnum2 = { SUCCESS: 'Success', WARNING: 'Warning', ERROR: 'Error', @@ -353,8 +364,19 @@ export type ModelWithNestedEnums = { dictionaryWithEnumFromDescription?: Record; arrayWithEnum?: Array<'Success' | 'Warning' | 'Error'>; arrayWithDescription?: Array; + /** + * This is a simple enum with strings + */ + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; }; +export const FooBarEnumEnum3 = { + SUCCESS: 'Success', + WARNING: 'Warning', + ERROR: 'Error', + ØÆÅ字符串: 'ØÆÅ字符串', +} as const; + /** * This is a model with one property containing a reference */ diff --git a/test/__snapshots__/v3/schemas.ts.snap b/test/__snapshots__/v3/schemas.ts.snap index d68433294..e402b1ef7 100644 --- a/test/__snapshots__/v3/schemas.ts.snap +++ b/test/__snapshots__/v3/schemas.ts.snap @@ -319,13 +319,17 @@ export const $ModelWithNullableString = { isRequired: true, isNullable: true, }, + 'foo_bar-enum': { + type: 'Enum', + enum: ['Success', 'Warning', 'Error', 'ØÆÅ字符串'], + }, }, } as const; export const $ModelWithEnum = { description: `This is a model with one enum`, properties: { - test: { + 'foo_bar-enum': { type: 'Enum', enum: ['Success', 'Warning', 'Error', 'ØÆÅ字符串'], }, @@ -392,6 +396,10 @@ export const $ModelWithNestedEnums = { description: `Success=1,Warning=2,Error=3`, }, }, + 'foo_bar-enum': { + type: 'Enum', + enum: ['Success', 'Warning', 'Error', 'ØÆÅ字符串'], + }, }, } as const; diff --git a/test/__snapshots__/v3_angular/models.ts.snap b/test/__snapshots__/v3_angular/models.ts.snap index ad411322f..80e21ac3f 100644 --- a/test/__snapshots__/v3_angular/models.ts.snap +++ b/test/__snapshots__/v3_angular/models.ts.snap @@ -238,6 +238,10 @@ export type ModelWithNullableString = { * This is a simple string property */ nullableRequiredProp2: string | null; + /** + * This is a simple enum with strings + */ + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; }; /** @@ -247,7 +251,7 @@ export type ModelWithEnum = { /** * This is a simple enum with strings */ - test?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; /** * These are the HTTP error code enums */ @@ -283,6 +287,10 @@ export type ModelWithNestedEnums = { dictionaryWithEnumFromDescription?: Record; arrayWithEnum?: Array<'Success' | 'Warning' | 'Error'>; arrayWithDescription?: Array; + /** + * This is a simple enum with strings + */ + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; }; /** diff --git a/test/__snapshots__/v3_angular/schemas.ts.snap b/test/__snapshots__/v3_angular/schemas.ts.snap index d68433294..e402b1ef7 100644 --- a/test/__snapshots__/v3_angular/schemas.ts.snap +++ b/test/__snapshots__/v3_angular/schemas.ts.snap @@ -319,13 +319,17 @@ export const $ModelWithNullableString = { isRequired: true, isNullable: true, }, + 'foo_bar-enum': { + type: 'Enum', + enum: ['Success', 'Warning', 'Error', 'ØÆÅ字符串'], + }, }, } as const; export const $ModelWithEnum = { description: `This is a model with one enum`, properties: { - test: { + 'foo_bar-enum': { type: 'Enum', enum: ['Success', 'Warning', 'Error', 'ØÆÅ字符串'], }, @@ -392,6 +396,10 @@ export const $ModelWithNestedEnums = { description: `Success=1,Warning=2,Error=3`, }, }, + 'foo_bar-enum': { + type: 'Enum', + enum: ['Success', 'Warning', 'Error', 'ØÆÅ字符串'], + }, }, } as const; diff --git a/test/__snapshots__/v3_client/models.ts.snap b/test/__snapshots__/v3_client/models.ts.snap index e9246c715..7b8a5cc0f 100644 --- a/test/__snapshots__/v3_client/models.ts.snap +++ b/test/__snapshots__/v3_client/models.ts.snap @@ -288,8 +288,19 @@ export type ModelWithNullableString = { * This is a simple string property */ nullableRequiredProp2: string | null; + /** + * This is a simple enum with strings + */ + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; }; +export const FooBarEnumEnum = { + SUCCESS: 'Success', + WARNING: 'Warning', + ERROR: 'Error', + ØÆÅ字符串: 'ØÆÅ字符串', +} as const; + /** * This is a model with one enum */ @@ -297,7 +308,7 @@ export type ModelWithEnum = { /** * This is a simple enum with strings */ - test?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; /** * These are the HTTP error code enums */ @@ -308,7 +319,7 @@ export type ModelWithEnum = { bool?: boolean; }; -export const TestEnum = { +export const FooBarEnumEnum2 = { SUCCESS: 'Success', WARNING: 'Warning', ERROR: 'Error', @@ -353,8 +364,19 @@ export type ModelWithNestedEnums = { dictionaryWithEnumFromDescription?: Record; arrayWithEnum?: Array<'Success' | 'Warning' | 'Error'>; arrayWithDescription?: Array; + /** + * This is a simple enum with strings + */ + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; }; +export const FooBarEnumEnum3 = { + SUCCESS: 'Success', + WARNING: 'Warning', + ERROR: 'Error', + ØÆÅ字符串: 'ØÆÅ字符串', +} as const; + /** * This is a model with one property containing a reference */ diff --git a/test/__snapshots__/v3_enums_typescript/models.ts.snap b/test/__snapshots__/v3_enums_typescript/models.ts.snap index 8a3a8146a..d0b9ad717 100644 --- a/test/__snapshots__/v3_enums_typescript/models.ts.snap +++ b/test/__snapshots__/v3_enums_typescript/models.ts.snap @@ -274,6 +274,10 @@ export type ModelWithNullableString = { * This is a simple string property */ nullableRequiredProp2: string | null; + /** + * This is a simple enum with strings + */ + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; }; /** @@ -283,7 +287,7 @@ export type ModelWithEnum = { /** * This is a simple enum with strings */ - test?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; /** * These are the HTTP error code enums */ @@ -319,6 +323,10 @@ export type ModelWithNestedEnums = { dictionaryWithEnumFromDescription?: Record; arrayWithEnum?: Array<'Success' | 'Warning' | 'Error'>; arrayWithDescription?: Array; + /** + * This is a simple enum with strings + */ + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; }; /** diff --git a/test/__snapshots__/v3_enums_typescript/schemas.ts.snap b/test/__snapshots__/v3_enums_typescript/schemas.ts.snap index d68433294..e402b1ef7 100644 --- a/test/__snapshots__/v3_enums_typescript/schemas.ts.snap +++ b/test/__snapshots__/v3_enums_typescript/schemas.ts.snap @@ -319,13 +319,17 @@ export const $ModelWithNullableString = { isRequired: true, isNullable: true, }, + 'foo_bar-enum': { + type: 'Enum', + enum: ['Success', 'Warning', 'Error', 'ØÆÅ字符串'], + }, }, } as const; export const $ModelWithEnum = { description: `This is a model with one enum`, properties: { - test: { + 'foo_bar-enum': { type: 'Enum', enum: ['Success', 'Warning', 'Error', 'ØÆÅ字符串'], }, @@ -392,6 +396,10 @@ export const $ModelWithNestedEnums = { description: `Success=1,Warning=2,Error=3`, }, }, + 'foo_bar-enum': { + type: 'Enum', + enum: ['Success', 'Warning', 'Error', 'ØÆÅ字符串'], + }, }, } as const; diff --git a/test/__snapshots__/v3_experimental/models.ts.snap b/test/__snapshots__/v3_experimental/models.ts.snap index ad411322f..80e21ac3f 100644 --- a/test/__snapshots__/v3_experimental/models.ts.snap +++ b/test/__snapshots__/v3_experimental/models.ts.snap @@ -238,6 +238,10 @@ export type ModelWithNullableString = { * This is a simple string property */ nullableRequiredProp2: string | null; + /** + * This is a simple enum with strings + */ + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; }; /** @@ -247,7 +251,7 @@ export type ModelWithEnum = { /** * This is a simple enum with strings */ - test?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; /** * These are the HTTP error code enums */ @@ -283,6 +287,10 @@ export type ModelWithNestedEnums = { dictionaryWithEnumFromDescription?: Record; arrayWithEnum?: Array<'Success' | 'Warning' | 'Error'>; arrayWithDescription?: Array; + /** + * This is a simple enum with strings + */ + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; }; /** diff --git a/test/__snapshots__/v3_experimental/schemas.ts.snap b/test/__snapshots__/v3_experimental/schemas.ts.snap index d68433294..e402b1ef7 100644 --- a/test/__snapshots__/v3_experimental/schemas.ts.snap +++ b/test/__snapshots__/v3_experimental/schemas.ts.snap @@ -319,13 +319,17 @@ export const $ModelWithNullableString = { isRequired: true, isNullable: true, }, + 'foo_bar-enum': { + type: 'Enum', + enum: ['Success', 'Warning', 'Error', 'ØÆÅ字符串'], + }, }, } as const; export const $ModelWithEnum = { description: `This is a model with one enum`, properties: { - test: { + 'foo_bar-enum': { type: 'Enum', enum: ['Success', 'Warning', 'Error', 'ØÆÅ字符串'], }, @@ -392,6 +396,10 @@ export const $ModelWithNestedEnums = { description: `Success=1,Warning=2,Error=3`, }, }, + 'foo_bar-enum': { + type: 'Enum', + enum: ['Success', 'Warning', 'Error', 'ØÆÅ字符串'], + }, }, } as const; diff --git a/test/__snapshots__/v3_models/models.ts.snap b/test/__snapshots__/v3_models/models.ts.snap index ad411322f..80e21ac3f 100644 --- a/test/__snapshots__/v3_models/models.ts.snap +++ b/test/__snapshots__/v3_models/models.ts.snap @@ -238,6 +238,10 @@ export type ModelWithNullableString = { * This is a simple string property */ nullableRequiredProp2: string | null; + /** + * This is a simple enum with strings + */ + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; }; /** @@ -247,7 +251,7 @@ export type ModelWithEnum = { /** * This is a simple enum with strings */ - test?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; /** * These are the HTTP error code enums */ @@ -283,6 +287,10 @@ export type ModelWithNestedEnums = { dictionaryWithEnumFromDescription?: Record; arrayWithEnum?: Array<'Success' | 'Warning' | 'Error'>; arrayWithDescription?: Array; + /** + * This is a simple enum with strings + */ + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; }; /** diff --git a/test/custom/request.ts b/test/custom/request.ts index f468504cc..055594f3e 100644 --- a/test/custom/request.ts +++ b/test/custom/request.ts @@ -10,13 +10,13 @@ export const request = (config: OpenAPIConfig, options: ApiRequestOptions): C // Do your request... const timeout = setTimeout(() => { resolve({ - url, - ok: true, - status: 200, - statusText: 'dummy', body: { ...options, }, + ok: true, + status: 200, + statusText: 'dummy', + url, }); }, 500); diff --git a/test/e2e/assets/main-angular-module.ts b/test/e2e/assets/main-angular-module.ts index 674282fdd..97a7cc0de 100644 --- a/test/e2e/assets/main-angular-module.ts +++ b/test/e2e/assets/main-angular-module.ts @@ -47,7 +47,6 @@ export class AppComponent { ) { // @ts-ignore window.api = { - OpenAPI, ApiModule, CollectionFormatService: this.collectionFormatService, ComplexService: this.complexService, @@ -60,6 +59,7 @@ export class AppComponent { MultipleTags2Service: this.multipleTags2Service, MultipleTags3Service: this.multipleTags3Service, NoContentService: this.noContentService, + OpenAPI, ParametersService: this.parametersService, ResponseService: this.responseService, SimpleService: this.simpleService, @@ -69,8 +69,8 @@ export class AppComponent { } @NgModule({ - imports: [BrowserModule, HttpClientModule, ApiModule], bootstrap: [AppComponent], + imports: [BrowserModule, HttpClientModule, ApiModule], }) export class AppModule {} diff --git a/test/e2e/assets/main-angular.ts b/test/e2e/assets/main-angular.ts index 4697fe44d..b2ee843f1 100644 --- a/test/e2e/assets/main-angular.ts +++ b/test/e2e/assets/main-angular.ts @@ -46,7 +46,6 @@ export class AppComponent { ) { // @ts-ignore window.api = { - OpenAPI, CollectionFormatService: this.collectionFormatService, ComplexService: this.complexService, DefaultService: this.defaultService, @@ -58,6 +57,7 @@ export class AppComponent { MultipleTags2Service: this.multipleTags2Service, MultipleTags3Service: this.multipleTags3Service, NoContentService: this.noContentService, + OpenAPI, ParametersService: this.parametersService, ResponseService: this.responseService, SimpleService: this.simpleService, @@ -67,6 +67,7 @@ export class AppComponent { } @NgModule({ + bootstrap: [AppComponent], imports: [BrowserModule, HttpClientModule], providers: [ CollectionFormatService, @@ -85,7 +86,6 @@ export class AppComponent { SimpleService, TypesService, ], - bootstrap: [AppComponent], }) export class AppModule {} diff --git a/test/e2e/client.angular.spec.ts b/test/e2e/client.angular.spec.ts index b67cc83fe..00b008edb 100644 --- a/test/e2e/client.angular.spec.ts +++ b/test/e2e/client.angular.spec.ts @@ -107,17 +107,22 @@ describe('client.angular', () => { resolve( JSON.stringify({ // @ts-ignore - name: e.name, + body: e.body, + // @ts-ignore message: e.message, + // @ts-ignore - url: e.url, + name: e.name, + // @ts-ignore status: e.status, + // @ts-ignore statusText: e.statusText, + // @ts-ignore - body: e.body, + url: e.url, }) ); }, @@ -126,15 +131,15 @@ describe('client.angular', () => { ); expect(error).toBe( JSON.stringify({ - name: 'ApiError', - message: 'Custom message: Internal Server Error', - url: 'http://localhost:3000/base/api/v1.0/error?status=500', - status: 500, - statusText: 'Internal Server Error', body: { - status: 500, message: 'hello world', + status: 500, }, + message: 'Custom message: Internal Server Error', + name: 'ApiError', + status: 500, + statusText: 'Internal Server Error', + url: 'http://localhost:3000/base/api/v1.0/error?status=500', }) ); }); @@ -150,17 +155,22 @@ describe('client.angular', () => { resolve( JSON.stringify({ // @ts-ignore - name: e.name, + body: e.body, + // @ts-ignore message: e.message, + // @ts-ignore - url: e.url, + name: e.name, + // @ts-ignore status: e.status, + // @ts-ignore statusText: e.statusText, + // @ts-ignore - body: e.body, + url: e.url, }) ); }, @@ -170,16 +180,16 @@ describe('client.angular', () => { expect(error).toBe( JSON.stringify({ - name: 'ApiError', + body: { + message: 'hello world', + status: 599, + }, message: 'Generic Error: status: 599; status text: unknown; body: {\n "status": 599,\n "message": "hello world"\n}', - url: 'http://localhost:3000/base/api/v1.0/error?status=599', + name: 'ApiError', status: 599, statusText: 'unknown', - body: { - status: 599, - message: 'hello world', - }, + url: 'http://localhost:3000/base/api/v1.0/error?status=599', }) ); }); diff --git a/test/e2e/client.axios.spec.ts b/test/e2e/client.axios.spec.ts index e67831c2d..4ec09c028 100644 --- a/test/e2e/client.axios.spec.ts +++ b/test/e2e/client.axios.spec.ts @@ -21,9 +21,9 @@ describe('client.axios', () => { const { ApiClient } = await import('./generated/client/axios/index.js'); const tokenRequest = vi.fn().mockResolvedValue('MY_TOKEN'); const client = new ApiClient({ + PASSWORD: undefined, TOKEN: tokenRequest, USERNAME: undefined, - PASSWORD: undefined, }); const result = await client.simple.getCallWithoutParametersAndResponse(); expect(tokenRequest.mock.calls.length).toBe(1); @@ -34,9 +34,9 @@ describe('client.axios', () => { it('uses credentials', async () => { const { ApiClient } = await import('./generated/client/axios/index.js'); const client = new ApiClient({ + PASSWORD: 'password', TOKEN: undefined, USERNAME: 'username', - PASSWORD: 'password', }); const result = await client.simple.getCallWithoutParametersAndResponse(); // @ts-ignore @@ -98,25 +98,25 @@ describe('client.axios', () => { await client.error.testErrorCode(500); } catch (err) { error = JSON.stringify({ - name: err.name, + body: err.body, message: err.message, - url: err.url, + name: err.name, status: err.status, statusText: err.statusText, - body: err.body, + url: err.url, }); } expect(error).toBe( JSON.stringify({ - name: 'ApiError', - message: 'Custom message: Internal Server Error', - url: 'http://localhost:3000/base/api/v1.0/error?status=500', - status: 500, - statusText: 'Internal Server Error', body: { - status: 500, message: 'hello world', + status: 500, }, + message: 'Custom message: Internal Server Error', + name: 'ApiError', + status: 500, + statusText: 'Internal Server Error', + url: 'http://localhost:3000/base/api/v1.0/error?status=500', }) ); }); @@ -129,26 +129,26 @@ describe('client.axios', () => { await client.error.testErrorCode(599); } catch (err) { error = JSON.stringify({ - name: err.name, + body: err.body, message: err.message, - url: err.url, + name: err.name, status: err.status, statusText: err.statusText, - body: err.body, + url: err.url, }); } expect(error).toBe( JSON.stringify({ - name: 'ApiError', + body: { + message: 'hello world', + status: 599, + }, message: 'Generic Error: status: 599; status text: unknown; body: {\n "status": 599,\n "message": "hello world"\n}', - url: 'http://localhost:3000/base/api/v1.0/error?status=599', + name: 'ApiError', status: 599, statusText: 'unknown', - body: { - status: 599, - message: 'hello world', - }, + url: 'http://localhost:3000/base/api/v1.0/error?status=599', }) ); }); diff --git a/test/e2e/client.fetch.spec.ts b/test/e2e/client.fetch.spec.ts index 4f50490be..537ce01e7 100644 --- a/test/e2e/client.fetch.spec.ts +++ b/test/e2e/client.fetch.spec.ts @@ -29,10 +29,10 @@ describe('client.fetch', () => { // @ts-ignore const { ApiClient } = window.api; const client = new ApiClient({ + PASSWORD: undefined, // @ts-ignore TOKEN: window.tokenRequest, USERNAME: undefined, - PASSWORD: undefined, }); return await client.simple.getCallWithoutParametersAndResponse(); }); @@ -45,9 +45,9 @@ describe('client.fetch', () => { // @ts-ignore const { ApiClient } = window.api; const client = new ApiClient({ + PASSWORD: 'password', TOKEN: undefined, USERNAME: 'username', - PASSWORD: 'password', }); return await client.simple.getCallWithoutParametersAndResponse(); }); @@ -118,12 +118,12 @@ describe('client.fetch', () => { await client.error.testErrorCode(500); } catch (error) { return JSON.stringify({ - name: error.name, + body: error.body, message: error.message, - url: error.url, + name: error.name, status: error.status, statusText: error.statusText, - body: error.body, + url: error.url, }); } return; @@ -131,15 +131,15 @@ describe('client.fetch', () => { expect(error).toBe( JSON.stringify({ - name: 'ApiError', - message: 'Custom message: Internal Server Error', - url: 'http://localhost:3000/base/api/v1.0/error?status=500', - status: 500, - statusText: 'Internal Server Error', body: { - status: 500, message: 'hello world', + status: 500, }, + message: 'Custom message: Internal Server Error', + name: 'ApiError', + status: 500, + statusText: 'Internal Server Error', + url: 'http://localhost:3000/base/api/v1.0/error?status=500', }) ); }); @@ -153,28 +153,28 @@ describe('client.fetch', () => { await client.error.testErrorCode(599); } catch (error) { return JSON.stringify({ - name: error.name, + body: error.body, message: error.message, - url: error.url, + name: error.name, status: error.status, statusText: error.statusText, - body: error.body, + url: error.url, }); } return; }); expect(error).toBe( JSON.stringify({ - name: 'ApiError', + body: { + message: 'hello world', + status: 599, + }, message: 'Generic Error: status: 599; status text: unknown; body: {\n "status": 599,\n "message": "hello world"\n}', - url: 'http://localhost:3000/base/api/v1.0/error?status=599', + name: 'ApiError', status: 599, statusText: 'unknown', - body: { - status: 599, - message: 'hello world', - }, + url: 'http://localhost:3000/base/api/v1.0/error?status=599', }) ); }); diff --git a/test/e2e/client.node.spec.ts b/test/e2e/client.node.spec.ts index 95b7c3203..9b848805b 100644 --- a/test/e2e/client.node.spec.ts +++ b/test/e2e/client.node.spec.ts @@ -21,9 +21,9 @@ describe('client.node', () => { const { ApiClient } = await import('./generated/client/node/index.js'); const tokenRequest = vi.fn().mockResolvedValue('MY_TOKEN'); const client = new ApiClient({ + PASSWORD: undefined, TOKEN: tokenRequest, USERNAME: undefined, - PASSWORD: undefined, }); const result = await client.simple.getCallWithoutParametersAndResponse(); expect(tokenRequest.mock.calls.length).toBe(1); @@ -34,9 +34,9 @@ describe('client.node', () => { it('uses credentials', async () => { const { ApiClient } = await import('./generated/client/node/index.js'); const client = new ApiClient({ + PASSWORD: 'password', TOKEN: undefined, USERNAME: 'username', - PASSWORD: 'password', }); const result = await client.simple.getCallWithoutParametersAndResponse(); // @ts-ignore @@ -98,25 +98,25 @@ describe('client.node', () => { await client.error.testErrorCode(500); } catch (err) { error = JSON.stringify({ - name: err.name, + body: err.body, message: err.message, - url: err.url, + name: err.name, status: err.status, statusText: err.statusText, - body: err.body, + url: err.url, }); } expect(error).toBe( JSON.stringify({ - name: 'ApiError', - message: 'Custom message: Internal Server Error', - url: 'http://localhost:3000/base/api/v1.0/error?status=500', - status: 500, - statusText: 'Internal Server Error', body: { - status: 500, message: 'hello world', + status: 500, }, + message: 'Custom message: Internal Server Error', + name: 'ApiError', + status: 500, + statusText: 'Internal Server Error', + url: 'http://localhost:3000/base/api/v1.0/error?status=500', }) ); }); @@ -129,26 +129,26 @@ describe('client.node', () => { await client.error.testErrorCode(599); } catch (err) { error = JSON.stringify({ - name: err.name, + body: err.body, message: err.message, - url: err.url, + name: err.name, status: err.status, statusText: err.statusText, - body: err.body, + url: err.url, }); } expect(error).toBe( JSON.stringify({ - name: 'ApiError', + body: { + message: 'hello world', + status: 599, + }, message: 'Generic Error: status: 599; status text: unknown; body: {\n "status": 599,\n "message": "hello world"\n}', - url: 'http://localhost:3000/base/api/v1.0/error?status=599', + name: 'ApiError', status: 599, statusText: 'unknown', - body: { - status: 599, - message: 'hello world', - }, + url: 'http://localhost:3000/base/api/v1.0/error?status=599', }) ); }); diff --git a/test/e2e/client.xhr.spec.ts b/test/e2e/client.xhr.spec.ts index cb610c78d..53beee1aa 100644 --- a/test/e2e/client.xhr.spec.ts +++ b/test/e2e/client.xhr.spec.ts @@ -29,10 +29,10 @@ describe('client.xhr', () => { // @ts-ignore const { ApiClient } = window.api; const client = new ApiClient({ + PASSWORD: undefined, // @ts-ignore TOKEN: window.tokenRequest, USERNAME: undefined, - PASSWORD: undefined, }); return await client.simple.getCallWithoutParametersAndResponse(); }); @@ -45,9 +45,9 @@ describe('client.xhr', () => { // @ts-ignore const { ApiClient } = window.api; const client = new ApiClient({ + PASSWORD: 'password', TOKEN: undefined, USERNAME: 'username', - PASSWORD: 'password', }); return await client.simple.getCallWithoutParametersAndResponse(); }); @@ -118,27 +118,27 @@ describe('client.xhr', () => { await client.error.testErrorCode(500); } catch (error) { return JSON.stringify({ - name: error.name, + body: error.body, message: error.message, - url: error.url, + name: error.name, status: error.status, statusText: error.statusText, - body: error.body, + url: error.url, }); } return; }); expect(error).toBe( JSON.stringify({ - name: 'ApiError', - message: 'Custom message: Internal Server Error', - url: 'http://localhost:3000/base/api/v1.0/error?status=500', - status: 500, - statusText: 'Internal Server Error', body: { - status: 500, message: 'hello world', + status: 500, }, + message: 'Custom message: Internal Server Error', + name: 'ApiError', + status: 500, + statusText: 'Internal Server Error', + url: 'http://localhost:3000/base/api/v1.0/error?status=500', }) ); }); @@ -152,28 +152,28 @@ describe('client.xhr', () => { await client.error.testErrorCode(599); } catch (error) { return JSON.stringify({ - name: error.name, + body: error.body, message: error.message, - url: error.url, + name: error.name, status: error.status, statusText: error.statusText, - body: error.body, + url: error.url, }); } return; }); expect(error).toBe( JSON.stringify({ - name: 'ApiError', + body: { + message: 'hello world', + status: 599, + }, message: 'Generic Error: status: 599; status text: unknown; body: {\n "status": 599,\n "message": "hello world"\n}', - url: 'http://localhost:3000/base/api/v1.0/error?status=599', + name: 'ApiError', status: 599, statusText: 'unknown', - body: { - status: 599, - message: 'hello world', - }, + url: 'http://localhost:3000/base/api/v1.0/error?status=599', }) ); }); diff --git a/test/e2e/scripts/browser.ts b/test/e2e/scripts/browser.ts index b5ef4d171..aa82eaa5f 100644 --- a/test/e2e/scripts/browser.ts +++ b/test/e2e/scripts/browser.ts @@ -29,8 +29,8 @@ const evaluate = async (fn: EvaluateFunc) => await _page.evaluate(fn) const exposeFunction = async (name: string, fn: Function) => await _page.exposeFunction(name, fn); export default { - start, - stop, evaluate, exposeFunction, + start, + stop, }; diff --git a/test/e2e/scripts/compileWithTypescript.ts b/test/e2e/scripts/compileWithTypescript.ts index 1e9a741b7..cbfe911ef 100644 --- a/test/e2e/scripts/compileWithTypescript.ts +++ b/test/e2e/scripts/compileWithTypescript.ts @@ -15,20 +15,20 @@ export const compileWithTypescript = (dir: string) => { const cwd = `./test/e2e/generated/${dir}/`; const tsconfig = { compilerOptions: { - target: 'es2020', - module: 'es2020', - moduleResolution: 'node', - lib: ['es2020', 'dom'], + allowSyntheticDefaultImports: true, declaration: false, declarationMap: false, - sourceMap: false, + experimentalDecorators: true, + lib: ['es2020', 'dom'], + module: 'es2020', + moduleResolution: 'node', + noImplicitAny: true, noImplicitReturns: true, noImplicitThis: true, - noImplicitAny: true, - strict: true, skipLibCheck: true, - allowSyntheticDefaultImports: true, - experimentalDecorators: true, + sourceMap: false, + strict: true, + target: 'es2020', }, include: ['**/*.ts'], }; @@ -50,8 +50,8 @@ export const compileWithTypescript = (dir: string) => { const diagnostics = getPreEmitDiagnostics(compiler).concat(result.diagnostics); if (diagnostics.length) { const message = formatDiagnosticsWithColorAndContext(diagnostics, { - getCurrentDirectory: () => sys.getCurrentDirectory(), getCanonicalFileName: f => f, + getCurrentDirectory: () => sys.getCurrentDirectory(), getNewLine: () => EOL, }); console.log(message); diff --git a/test/e2e/scripts/server.ts b/test/e2e/scripts/server.ts index 9f05b3fc5..1115ed500 100644 --- a/test/e2e/scripts/server.ts +++ b/test/e2e/scripts/server.ts @@ -58,8 +58,8 @@ const start = async (dir: string) => _app.all('/base/api/v1.0/error', (req, res) => { const status = parseInt(String(req.query.status)); res.status(status).json({ - status, message: 'hello world', + status, }); }); @@ -69,14 +69,14 @@ const start = async (dir: string) => _app.all('/base/api/v1.0/*', (req, res) => { setTimeout(() => { res.json({ - method: req.method, - protocol: req.protocol, + body: req.body, + headers: req.headers, hostname: req.hostname, + method: req.method, path: req.path, - url: req.url, + protocol: req.protocol, query: req.query, - body: req.body, - headers: req.headers, + url: req.url, }); }, 100); }); diff --git a/test/e2e/v3.angular.spec.ts b/test/e2e/v3.angular.spec.ts index 1f9a12bdd..d0a48b5aa 100644 --- a/test/e2e/v3.angular.spec.ts +++ b/test/e2e/v3.angular.spec.ts @@ -106,27 +106,27 @@ describe('v3.angular', () => { }); } catch (error) { return JSON.stringify({ - name: error.name, + body: error.body, message: error.message, - url: error.url, + name: error.name, status: error.status, statusText: error.statusText, - body: error.body, + url: error.url, }); } return; }); expect(error).toBe( JSON.stringify({ - name: 'ApiError', - message: 'Custom message: Internal Server Error', - url: 'http://localhost:3000/base/api/v1.0/error?status=500', - status: 500, - statusText: 'Internal Server Error', body: { - status: 500, message: 'hello world', + status: 500, }, + message: 'Custom message: Internal Server Error', + name: 'ApiError', + status: 500, + statusText: 'Internal Server Error', + url: 'http://localhost:3000/base/api/v1.0/error?status=500', }) ); }); @@ -142,28 +142,28 @@ describe('v3.angular', () => { }); } catch (error) { return JSON.stringify({ - name: error.name, + body: error.body, message: error.message, - url: error.url, + name: error.name, status: error.status, statusText: error.statusText, - body: error.body, + url: error.url, }); } return; }); expect(error).toBe( JSON.stringify({ - name: 'ApiError', + body: { + message: 'hello world', + status: 599, + }, message: 'Generic Error: status: 599; status text: unknown; body: {\n "status": 599,\n "message": "hello world"\n}', - url: 'http://localhost:3000/base/api/v1.0/error?status=599', + name: 'ApiError', status: 599, statusText: 'unknown', - body: { - status: 599, - message: 'hello world', - }, + url: 'http://localhost:3000/base/api/v1.0/error?status=599', }) ); }); diff --git a/test/e2e/v3.axios.spec.ts b/test/e2e/v3.axios.spec.ts index b8388367c..b1e36cf14 100644 --- a/test/e2e/v3.axios.spec.ts +++ b/test/e2e/v3.axios.spec.ts @@ -92,25 +92,25 @@ describe('v3.axios', () => { await ErrorService.testErrorCode(500); } catch (err) { error = JSON.stringify({ - name: err.name, + body: err.body, message: err.message, - url: err.url, + name: err.name, status: err.status, statusText: err.statusText, - body: err.body, + url: err.url, }); } expect(error).toBe( JSON.stringify({ - name: 'ApiError', - message: 'Custom message: Internal Server Error', - url: 'http://localhost:3000/base/api/v1.0/error?status=500', - status: 500, - statusText: 'Internal Server Error', body: { - status: 500, message: 'hello world', + status: 500, }, + message: 'Custom message: Internal Server Error', + name: 'ApiError', + status: 500, + statusText: 'Internal Server Error', + url: 'http://localhost:3000/base/api/v1.0/error?status=500', }) ); }); @@ -123,26 +123,26 @@ describe('v3.axios', () => { await ErrorService.testErrorCode(599); } catch (err) { error = JSON.stringify({ - name: err.name, + body: err.body, message: err.message, - url: err.url, + name: err.name, status: err.status, statusText: err.statusText, - body: err.body, + url: err.url, }); } expect(error).toBe( JSON.stringify({ - name: 'ApiError', + body: { + message: 'hello world', + status: 599, + }, message: 'Generic Error: status: 599; status text: unknown; body: {\n "status": 599,\n "message": "hello world"\n}', - url: 'http://localhost:3000/base/api/v1.0/error?status=599', + name: 'ApiError', status: 599, statusText: 'unknown', - body: { - status: 599, - message: 'hello world', - }, + url: 'http://localhost:3000/base/api/v1.0/error?status=599', }) ); }); diff --git a/test/e2e/v3.fetch.spec.ts b/test/e2e/v3.fetch.spec.ts index f548c38e5..588e5aa2e 100644 --- a/test/e2e/v3.fetch.spec.ts +++ b/test/e2e/v3.fetch.spec.ts @@ -119,12 +119,12 @@ describe('v3.fetch', () => { await ErrorService.testErrorCode(500); } catch (error) { return JSON.stringify({ - name: error.name, + body: error.body, message: error.message, - url: error.url, + name: error.name, status: error.status, statusText: error.statusText, - body: error.body, + url: error.url, }); } return; @@ -132,15 +132,15 @@ describe('v3.fetch', () => { expect(error).toBe( JSON.stringify({ - name: 'ApiError', - message: 'Custom message: Internal Server Error', - url: 'http://localhost:3000/base/api/v1.0/error?status=500', - status: 500, - statusText: 'Internal Server Error', body: { - status: 500, message: 'hello world', + status: 500, }, + message: 'Custom message: Internal Server Error', + name: 'ApiError', + status: 500, + statusText: 'Internal Server Error', + url: 'http://localhost:3000/base/api/v1.0/error?status=500', }) ); }); @@ -153,28 +153,28 @@ describe('v3.fetch', () => { await ErrorService.testErrorCode(599); } catch (error) { return JSON.stringify({ - name: error.name, + body: error.body, message: error.message, - url: error.url, + name: error.name, status: error.status, statusText: error.statusText, - body: error.body, + url: error.url, }); } return; }); expect(error).toBe( JSON.stringify({ - name: 'ApiError', + body: { + message: 'hello world', + status: 599, + }, message: 'Generic Error: status: 599; status text: unknown; body: {\n "status": 599,\n "message": "hello world"\n}', - url: 'http://localhost:3000/base/api/v1.0/error?status=599', + name: 'ApiError', status: 599, statusText: 'unknown', - body: { - status: 599, - message: 'hello world', - }, + url: 'http://localhost:3000/base/api/v1.0/error?status=599', }) ); }); diff --git a/test/e2e/v3.node.spec.ts b/test/e2e/v3.node.spec.ts index c6a6048a7..80b46afae 100644 --- a/test/e2e/v3.node.spec.ts +++ b/test/e2e/v3.node.spec.ts @@ -98,25 +98,25 @@ describe('v3.node', () => { await ErrorService.testErrorCode(500); } catch (err) { error = JSON.stringify({ - name: err.name, + body: err.body, message: err.message, - url: err.url, + name: err.name, status: err.status, statusText: err.statusText, - body: err.body, + url: err.url, }); } expect(error).toBe( JSON.stringify({ - name: 'ApiError', - message: 'Custom message: Internal Server Error', - url: 'http://localhost:3000/base/api/v1.0/error?status=500', - status: 500, - statusText: 'Internal Server Error', body: { - status: 500, message: 'hello world', + status: 500, }, + message: 'Custom message: Internal Server Error', + name: 'ApiError', + status: 500, + statusText: 'Internal Server Error', + url: 'http://localhost:3000/base/api/v1.0/error?status=500', }) ); }); @@ -129,26 +129,26 @@ describe('v3.node', () => { await ErrorService.testErrorCode(599); } catch (err) { error = JSON.stringify({ - name: err.name, + body: err.body, message: err.message, - url: err.url, + name: err.name, status: err.status, statusText: err.statusText, - body: err.body, + url: err.url, }); } expect(error).toBe( JSON.stringify({ - name: 'ApiError', + body: { + message: 'hello world', + status: 599, + }, message: 'Generic Error: status: 599; status text: unknown; body: {\n "status": 599,\n "message": "hello world"\n}', - url: 'http://localhost:3000/base/api/v1.0/error?status=599', + name: 'ApiError', status: 599, statusText: 'unknown', - body: { - status: 599, - message: 'hello world', - }, + url: 'http://localhost:3000/base/api/v1.0/error?status=599', }) ); }); diff --git a/test/e2e/v3.xhr.spec.ts b/test/e2e/v3.xhr.spec.ts index 929bc85db..660777e06 100644 --- a/test/e2e/v3.xhr.spec.ts +++ b/test/e2e/v3.xhr.spec.ts @@ -110,27 +110,27 @@ describe('v3.xhr', () => { await ErrorService.testErrorCode(500); } catch (error) { return JSON.stringify({ - name: error.name, + body: error.body, message: error.message, - url: error.url, + name: error.name, status: error.status, statusText: error.statusText, - body: error.body, + url: error.url, }); } return; }); expect(error).toBe( JSON.stringify({ - name: 'ApiError', - message: 'Custom message: Internal Server Error', - url: 'http://localhost:3000/base/api/v1.0/error?status=500', - status: 500, - statusText: 'Internal Server Error', body: { - status: 500, message: 'hello world', + status: 500, }, + message: 'Custom message: Internal Server Error', + name: 'ApiError', + status: 500, + statusText: 'Internal Server Error', + url: 'http://localhost:3000/base/api/v1.0/error?status=500', }) ); }); @@ -143,28 +143,28 @@ describe('v3.xhr', () => { await ErrorService.testErrorCode(599); } catch (error) { return JSON.stringify({ - name: error.name, + body: error.body, message: error.message, - url: error.url, + name: error.name, status: error.status, statusText: error.statusText, - body: error.body, + url: error.url, }); } return; }); expect(error).toBe( JSON.stringify({ - name: 'ApiError', + body: { + message: 'hello world', + status: 599, + }, message: 'Generic Error: status: 599; status text: unknown; body: {\n "status": 599,\n "message": "hello world"\n}', - url: 'http://localhost:3000/base/api/v1.0/error?status=599', + name: 'ApiError', status: 599, statusText: 'unknown', - body: { - status: 599, - message: 'hello world', - }, + url: 'http://localhost:3000/base/api/v1.0/error?status=599', }) ); }); diff --git a/test/index.spec.ts b/test/index.spec.ts index 0e4668e59..f69afeda4 100644 --- a/test/index.spec.ts +++ b/test/index.spec.ts @@ -16,8 +16,6 @@ const toSnapshotPath = (file: string) => `./__snapshots__/${file.replace(OUTPUT_ describe('OpenAPI v2', () => { it.each([ { - description: 'generate fetch client', - name: 'v2', config: { client: 'fetch', enums: 'javascript', @@ -27,6 +25,8 @@ describe('OpenAPI v2', () => { exportServices: true, useOptions: true, } as UserConfig, + description: 'generate fetch client', + name: 'v2', }, ])('$description', async ({ name, config }) => { const output = toOutputPath(name); @@ -45,8 +45,6 @@ describe('OpenAPI v2', () => { describe('OpenAPI v3', () => { it.each([ { - description: 'generate fetch client', - name: 'v3', config: { client: 'fetch', enums: 'javascript', @@ -56,10 +54,10 @@ describe('OpenAPI v3', () => { exportServices: true, useOptions: true, } as UserConfig, + description: 'generate fetch client', + name: 'v3', }, { - description: 'generate angular client', - name: 'v3_angular', config: { client: 'angular', enums: false, @@ -69,10 +67,10 @@ describe('OpenAPI v3', () => { exportServices: true, useOptions: true, } as UserConfig, + description: 'generate angular client', + name: 'v3_angular', }, { - description: 'generate node client', - name: 'v3_node', config: { client: 'node', enums: false, @@ -82,10 +80,10 @@ describe('OpenAPI v3', () => { exportServices: false, useOptions: true, } as UserConfig, + description: 'generate node client', + name: 'v3_node', }, { - description: 'generate axios client', - name: 'v3_axios', config: { client: 'axios', enums: false, @@ -95,10 +93,10 @@ describe('OpenAPI v3', () => { exportServices: false, useOptions: true, } as UserConfig, + description: 'generate axios client', + name: 'v3_axios', }, { - description: 'generate xhr client', - name: 'v3_xhr', config: { client: 'xhr', enums: false, @@ -108,10 +106,10 @@ describe('OpenAPI v3', () => { exportServices: false, useOptions: true, } as UserConfig, + description: 'generate xhr client', + name: 'v3_xhr', }, { - description: 'generate Date types', - name: 'v3_date', config: { client: 'fetch', enums: 'javascript', @@ -119,13 +117,13 @@ describe('OpenAPI v3', () => { exportModels: '^ModelWithPattern', exportSchemas: true, exportServices: false, - useOptions: true, useDateType: true, + useOptions: true, } as UserConfig, + description: 'generate Date types', + name: 'v3_date', }, { - description: 'generate optional arguments', - name: 'v3_options', config: { client: 'fetch', enums: 'javascript', @@ -133,13 +131,13 @@ describe('OpenAPI v3', () => { exportModels: '^ModelWithString', exportSchemas: false, exportServices: '^Defaults', - useOptions: true, useDateType: true, + useOptions: true, } as UserConfig, + description: 'generate optional arguments', + name: 'v3_options', }, { - description: 'generate client', - name: 'v3_client', config: { client: 'fetch', enums: 'javascript', @@ -147,14 +145,14 @@ describe('OpenAPI v3', () => { exportModels: true, exportSchemas: false, exportServices: true, - useOptions: true, - useDateType: true, name: 'ApiClient', + useDateType: true, + useOptions: true, } as UserConfig, + description: 'generate client', + name: 'v3_client', }, { - description: 'generate TypeScript enums', - name: 'v3_enums_typescript', config: { client: 'fetch', enums: 'typescript', @@ -164,10 +162,10 @@ describe('OpenAPI v3', () => { exportServices: true, useOptions: true, } as UserConfig, + description: 'generate TypeScript enums', + name: 'v3_enums_typescript', }, { - description: 'generate models', - name: 'v3_models', config: { client: 'fetch', exportCore: false, @@ -175,14 +173,16 @@ describe('OpenAPI v3', () => { exportSchemas: false, exportServices: false, } as UserConfig, + description: 'generate models', + name: 'v3_models', }, { - description: 'generate experimental build', - name: 'v3_experimental', config: { client: 'fetch', experimental: true, } as UserConfig, + description: 'generate experimental build', + name: 'v3_experimental', }, ])('$description', async ({ name, config }) => { const output = toOutputPath(name); diff --git a/test/spec/v3.json b/test/spec/v3.json index a32dc03fb..45fef8a1f 100644 --- a/test/spec/v3.json +++ b/test/spec/v3.json @@ -2055,6 +2055,15 @@ "string", "null" ] + }, + "foo_bar-enum": { + "description": "This is a simple enum with strings", + "enum": [ + "Success", + "Warning", + "Error", + "ØÆÅ字符串" + ] } } }, @@ -2062,7 +2071,7 @@ "description": "This is a model with one enum", "type": "object", "properties": { - "test": { + "foo_bar-enum": { "description": "This is a simple enum with strings", "enum": [ "Success", @@ -2152,6 +2161,15 @@ "type": "integer", "description": "Success=1,Warning=2,Error=3" } + }, + "foo_bar-enum": { + "description": "This is a simple enum with strings", + "enum": [ + "Success", + "Warning", + "Error", + "ØÆÅ字符串" + ] } } }, diff --git a/vitest.config.unit.ts b/vitest.config.unit.ts index 008cc07df..80a21e6de 100644 --- a/vitest.config.unit.ts +++ b/vitest.config.unit.ts @@ -7,12 +7,12 @@ import { handlebarsPlugin } from './rollup.config'; export default defineConfig({ plugins: [handlebarsPlugin()], test: { - exclude: [...configDefaults.exclude, 'test/e2e/**/*.spec.ts'], - root: fileURLToPath(new URL('./', import.meta.url)), coverage: { - provider: 'v8', - include: ['src/**/*.ts'], exclude: ['bin', 'dist', 'src/**/*.d.ts'], + include: ['src/**/*.ts'], + provider: 'v8', }, + exclude: [...configDefaults.exclude, 'test/e2e/**/*.spec.ts'], + root: fileURLToPath(new URL('./', import.meta.url)), }, });