fork of hey-api/openapi-ts because I need some additional things
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #3376 from spikesagal/main

fix: number enum properties to avoid collision

authored by

Lubos and committed by
GitHub
61acecce a2ad2aa4

+427 -18
+5
.changeset/lovely-moons-taste.md
··· 1 + --- 2 + "@hey-api/openapi-ts": patch 3 + --- 4 + 5 + **plugin(@hey-api/typescript)**: fix: deduplicate enum keys to avoid name collision
+55 -2
packages/openapi-ts-tests/main/test/3.0.x.test.ts
··· 21 21 version, 22 22 typeof input === 'string' ? input : ((input?.path as string) ?? ''), 23 23 ); 24 + const output = userConfig.output instanceof Array ? userConfig.output[0] : userConfig.output; 25 + const outputPath = path.join( 26 + outputDir, 27 + typeof output === 'string' ? output : ((output?.path as string) ?? ''), 28 + ); 29 + const nameConflictResolver = 30 + typeof output === 'string' ? undefined : output?.nameConflictResolver; 24 31 return { 25 32 plugins: ['@hey-api/typescript'], 26 33 ...userConfig, ··· 34 41 logs: { 35 42 level: 'silent', 36 43 }, 37 - output: path.join(outputDir, typeof userConfig.output === 'string' ? userConfig.output : ''), 44 + output: { 45 + nameConflictResolver, 46 + path: outputPath, 47 + }, 38 48 } as const satisfies UserConfig; 39 49 }; 40 50 ··· 262 272 ], 263 273 }), 264 274 description: 'exports inline enums (TypeScript)', 275 + }, 276 + { 277 + config: createConfig({ 278 + input: 'enum-inline.json', 279 + output: { 280 + nameConflictResolver: ({ attempt, baseName }) => 281 + attempt === 0 ? baseName : `${baseName}_N${attempt + 1}`, 282 + path: 'enum-inline-name-resolver', 283 + }, 284 + parser: { 285 + transforms: { 286 + enums: 'root', 287 + }, 288 + }, 289 + plugins: [ 290 + { 291 + enums: 'javascript', 292 + name: '@hey-api/typescript', 293 + }, 294 + ], 295 + }), 296 + description: 'exports inline enums with name conflict resolver', 297 + }, 298 + { 299 + config: createConfig({ 300 + input: 'enum-inline.json', 301 + output: { 302 + nameConflictResolver: () => null, 303 + path: 'enum-inline-name-resolver-null', 304 + }, 305 + parser: { 306 + transforms: { 307 + enums: 'root', 308 + }, 309 + }, 310 + plugins: [ 311 + { 312 + enums: 'javascript', 313 + name: '@hey-api/typescript', 314 + }, 315 + ], 316 + }), 317 + description: 'exports inline enums with name conflict resolver returning null', 265 318 }, 266 319 { 267 320 config: createConfig({ ··· 673 726 it.each(scenarios)('$description', async ({ config }) => { 674 727 await createClient(config); 675 728 676 - const filePaths = getFilePaths(config.output); 729 + const filePaths = getFilePaths(config.output.path); 677 730 678 731 await Promise.all( 679 732 filePaths.map(async (filePath) => {
+54 -2
packages/openapi-ts-tests/main/test/3.1.x.test.ts
··· 22 22 typeof input === 'string' ? input : ((input?.path as string) ?? ''), 23 23 ); 24 24 const output = userConfig.output instanceof Array ? userConfig.output[0] : userConfig.output; 25 + const outputPath = path.join( 26 + outputDir, 27 + typeof output === 'string' ? output : ((output?.path as string) ?? ''), 28 + ); 29 + const nameConflictResolver = 30 + typeof output === 'string' ? undefined : output?.nameConflictResolver; 25 31 return { 26 32 plugins: ['@hey-api/typescript'], 27 33 ...userConfig, ··· 35 41 logs: { 36 42 level: 'silent', 37 43 }, 38 - output: path.join(outputDir, typeof output === 'string' ? output : (output?.path ?? '')), 44 + output: { 45 + nameConflictResolver, 46 + path: outputPath, 47 + }, 39 48 } as const satisfies UserConfig; 40 49 }; 41 50 ··· 296 305 ], 297 306 }), 298 307 description: 'exports inline enums (TypeScript)', 308 + }, 309 + { 310 + config: createConfig({ 311 + input: 'enum-inline.yaml', 312 + output: { 313 + nameConflictResolver: ({ attempt, baseName }) => 314 + attempt === 0 ? baseName : `${baseName}_N${attempt + 1}`, 315 + path: 'enum-inline-name-resolver', 316 + }, 317 + parser: { 318 + transforms: { 319 + enums: 'root', 320 + }, 321 + }, 322 + plugins: [ 323 + { 324 + enums: 'javascript', 325 + name: '@hey-api/typescript', 326 + }, 327 + ], 328 + }), 329 + description: 'exports inline enums with name conflict resolver', 330 + }, 331 + { 332 + config: createConfig({ 333 + input: 'enum-inline.yaml', 334 + output: { 335 + nameConflictResolver: () => null, 336 + path: 'enum-inline-name-resolver-null', 337 + }, 338 + parser: { 339 + transforms: { 340 + enums: 'root', 341 + }, 342 + }, 343 + plugins: [ 344 + { 345 + enums: 'javascript', 346 + name: '@hey-api/typescript', 347 + }, 348 + ], 349 + }), 350 + description: 'exports inline enums with name conflict resolver returning null', 299 351 }, 300 352 { 301 353 config: createConfig({ ··· 991 1043 it.each(scenarios)('$description', async ({ config }) => { 992 1044 await createClient(config); 993 1045 994 - const filePaths = getFilePaths(config.output); 1046 + const filePaths = getFilePaths(config.output.path); 995 1047 996 1048 await Promise.all( 997 1049 filePaths.map(async (filePath) => {
+7 -1
packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/enum-inline-javascript/types.gen.ts
··· 8 8 type?: TypeEnum; 9 9 }; 10 10 11 - export const TypeEnum = { FOO: 'foo', BAR: 'bar' } as const; 11 + export const TypeEnum = { 12 + FOO: 'foo', 13 + BAR: 'bar', 14 + FOO_BAR: 'FooBar', 15 + FOO_BAR2: 'fooBar', 16 + FOO_BAR3: 'foo bar' 17 + } as const; 12 18 13 19 export type TypeEnum = typeof TypeEnum[keyof typeof TypeEnum];
+3
packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/enum-inline-name-resolver-null/index.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export { type ClientOptions, type Foo, TypeEnum } from './types.gen';
+19
packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/enum-inline-name-resolver-null/types.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export type ClientOptions = { 4 + baseUrl: `${string}://${string}` | (string & {}); 5 + }; 6 + 7 + export type Foo = { 8 + type?: TypeEnum; 9 + }; 10 + 11 + export const TypeEnum = { 12 + FOO: 'foo', 13 + BAR: 'bar', 14 + FOO_BAR: 'FooBar', 15 + FOO_BAR2: 'fooBar', 16 + FOO_BAR3: 'foo bar' 17 + } as const; 18 + 19 + export type TypeEnum = typeof TypeEnum[keyof typeof TypeEnum];
+3
packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/enum-inline-name-resolver/index.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export { type ClientOptions, type Foo, TypeEnum } from './types.gen';
+19
packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/enum-inline-name-resolver/types.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export type ClientOptions = { 4 + baseUrl: `${string}://${string}` | (string & {}); 5 + }; 6 + 7 + export type Foo = { 8 + type?: TypeEnum; 9 + }; 10 + 11 + export const TypeEnum = { 12 + FOO: 'foo', 13 + BAR: 'bar', 14 + FOO_BAR: 'FooBar', 15 + FOO_BAR_N2: 'fooBar', 16 + FOO_BAR_N3: 'foo bar' 17 + } as const; 18 + 19 + export type TypeEnum = typeof TypeEnum[keyof typeof TypeEnum];
+4 -1
packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/enum-inline-typescript/types.gen.ts
··· 10 10 11 11 export enum TypeEnum { 12 12 FOO = 'foo', 13 - BAR = 'bar' 13 + BAR = 'bar', 14 + FOO_BAR = 'FooBar', 15 + FOO_BAR2 = 'fooBar', 16 + FOO_BAR3 = 'foo bar' 14 17 }
+1 -1
packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/enum-inline/types.gen.ts
··· 8 8 type?: TypeEnum; 9 9 }; 10 10 11 - export type TypeEnum = 'foo' | 'bar'; 11 + export type TypeEnum = 'foo' | 'bar' | 'FooBar' | 'fooBar' | 'foo bar';
+3
packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/index.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export { type ClientOptions, type Foo, TypeEnum } from './types.gen';
+19
packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/types.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export type ClientOptions = { 4 + baseUrl: `${string}://${string}` | (string & {}); 5 + }; 6 + 7 + export type Foo = { 8 + type?: TypeEnum; 9 + }; 10 + 11 + export const TypeEnum = { 12 + FOO: 'foo', 13 + BAR: 'bar', 14 + FOO_BAR: 'FooBar', 15 + FOO_BAR2: 'fooBar', 16 + FOO_BAR3: 'foo bar' 17 + } as const; 18 + 19 + export type TypeEnum = typeof TypeEnum[keyof typeof TypeEnum];
+1 -1
packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/enum-inline-javascript/index.ts
··· 1 1 // This file is auto-generated by @hey-api/openapi-ts 2 2 3 - export { type Bar, Baz, type ClientOptions, type Foo, FooEnum, FooEnum2, type GetFooData, type GetFooResponse, type GetFooResponses, type PostFooData, type PostFooResponse, type PostFooResponses, type PutFooData, type PutFooResponse, type PutFooResponses } from './types.gen'; 3 + export { type Bar, Baz, type ClientOptions, type Foo, FooEnum, FooEnum2, type GetFooData, type GetFooResponse, type GetFooResponses, type PostFooData, type PostFooResponse, type PostFooResponses, type PutFooData, type PutFooResponse, type PutFooResponses, TypeEnum } from './types.gen';
+12 -2
packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/enum-inline-javascript/types.gen.ts
··· 5 5 }; 6 6 7 7 export type Foo = { 8 - type?: FooEnum; 8 + type?: TypeEnum; 9 9 }; 10 10 11 11 export type Bar = { ··· 16 16 17 17 export type Baz = typeof Baz[keyof typeof Baz]; 18 18 19 - export const FooEnum = { FOO: 'foo', BAR: 'bar' } as const; 19 + export const FooEnum = { 20 + FOO: 'foo', 21 + BAR: 'bar', 22 + FOO_BAR: 'FooBar', 23 + FOO_BAR2: 'fooBar', 24 + FOO_BAR3: 'foo bar' 25 + } as const; 20 26 21 27 export type FooEnum = typeof FooEnum[keyof typeof FooEnum]; 22 28 23 29 export const FooEnum2 = { BAZ: 'baz' } as const; 24 30 25 31 export type FooEnum2 = typeof FooEnum2[keyof typeof FooEnum2]; 32 + 33 + export const TypeEnum = { FOO: 'foo', BAR: 'bar' } as const; 34 + 35 + export type TypeEnum = typeof TypeEnum[keyof typeof TypeEnum]; 26 36 27 37 export type GetFooData = { 28 38 body?: never;
+3
packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/enum-inline-name-resolver-null/index.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export { type Bar, Baz, type ClientOptions, type Foo, FooEnum, FooEnum2, type GetFooData, type GetFooResponse, type GetFooResponses, type PostFooData, type PostFooResponse, type PostFooResponses, type PutFooData, type PutFooResponse, type PutFooResponses, TypeEnum } from './types.gen';
+87
packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/enum-inline-name-resolver-null/types.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export type ClientOptions = { 4 + baseUrl: `${string}://${string}` | (string & {}); 5 + }; 6 + 7 + export type Foo = { 8 + type?: TypeEnum; 9 + }; 10 + 11 + export type Bar = { 12 + type?: Baz; 13 + }; 14 + 15 + export const Baz = { QUX: 'qux', QUUX: 'quux' } as const; 16 + 17 + export type Baz = typeof Baz[keyof typeof Baz]; 18 + 19 + export const FooEnum = { 20 + FOO: 'foo', 21 + BAR: 'bar', 22 + FOO_BAR: 'FooBar', 23 + FOO_BAR2: 'fooBar', 24 + FOO_BAR3: 'foo bar' 25 + } as const; 26 + 27 + export type FooEnum = typeof FooEnum[keyof typeof FooEnum]; 28 + 29 + export const FooEnum2 = { BAZ: 'baz' } as const; 30 + 31 + export type FooEnum2 = typeof FooEnum2[keyof typeof FooEnum2]; 32 + 33 + export const TypeEnum = { FOO: 'foo', BAR: 'bar' } as const; 34 + 35 + export type TypeEnum = typeof TypeEnum[keyof typeof TypeEnum]; 36 + 37 + export type GetFooData = { 38 + body?: never; 39 + path?: never; 40 + query?: never; 41 + url: '/foo'; 42 + }; 43 + 44 + export type GetFooResponses = { 45 + /** 46 + * OK 47 + */ 48 + 200: { 49 + foo?: FooEnum; 50 + }; 51 + }; 52 + 53 + export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; 54 + 55 + export type PostFooData = { 56 + body?: never; 57 + path?: never; 58 + query?: never; 59 + url: '/foo'; 60 + }; 61 + 62 + export type PostFooResponses = { 63 + /** 64 + * OK 65 + */ 66 + 200: { 67 + foo?: FooEnum2; 68 + }; 69 + }; 70 + 71 + export type PostFooResponse = PostFooResponses[keyof PostFooResponses]; 72 + 73 + export type PutFooData = { 74 + body?: never; 75 + path?: never; 76 + query?: never; 77 + url: '/foo'; 78 + }; 79 + 80 + export type PutFooResponses = { 81 + /** 82 + * OK 83 + */ 84 + 200: Baz; 85 + }; 86 + 87 + export type PutFooResponse = PutFooResponses[keyof PutFooResponses];
+3
packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/enum-inline-name-resolver/index.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export { type Bar, Baz, type ClientOptions, type Foo, FooEnum, FooEnum2, type GetFooData, type GetFooResponse, type GetFooResponses, type PostFooData, type PostFooResponse, type PostFooResponses, type PutFooData, type PutFooResponse, type PutFooResponses, TypeEnum } from './types.gen';
+87
packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/enum-inline-name-resolver/types.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export type ClientOptions = { 4 + baseUrl: `${string}://${string}` | (string & {}); 5 + }; 6 + 7 + export type Foo = { 8 + type?: TypeEnum; 9 + }; 10 + 11 + export type Bar = { 12 + type?: Baz; 13 + }; 14 + 15 + export const Baz = { QUX: 'qux', QUUX: 'quux' } as const; 16 + 17 + export type Baz = typeof Baz[keyof typeof Baz]; 18 + 19 + export const FooEnum = { 20 + FOO: 'foo', 21 + BAR: 'bar', 22 + FOO_BAR: 'FooBar', 23 + FOO_BAR_N2: 'fooBar', 24 + FOO_BAR_N3: 'foo bar' 25 + } as const; 26 + 27 + export type FooEnum = typeof FooEnum[keyof typeof FooEnum]; 28 + 29 + export const FooEnum2 = { BAZ: 'baz' } as const; 30 + 31 + export type FooEnum2 = typeof FooEnum2[keyof typeof FooEnum2]; 32 + 33 + export const TypeEnum = { FOO: 'foo', BAR: 'bar' } as const; 34 + 35 + export type TypeEnum = typeof TypeEnum[keyof typeof TypeEnum]; 36 + 37 + export type GetFooData = { 38 + body?: never; 39 + path?: never; 40 + query?: never; 41 + url: '/foo'; 42 + }; 43 + 44 + export type GetFooResponses = { 45 + /** 46 + * OK 47 + */ 48 + 200: { 49 + foo?: FooEnum; 50 + }; 51 + }; 52 + 53 + export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; 54 + 55 + export type PostFooData = { 56 + body?: never; 57 + path?: never; 58 + query?: never; 59 + url: '/foo'; 60 + }; 61 + 62 + export type PostFooResponses = { 63 + /** 64 + * OK 65 + */ 66 + 200: { 67 + foo?: FooEnum2; 68 + }; 69 + }; 70 + 71 + export type PostFooResponse = PostFooResponses[keyof PostFooResponses]; 72 + 73 + export type PutFooData = { 74 + body?: never; 75 + path?: never; 76 + query?: never; 77 + url: '/foo'; 78 + }; 79 + 80 + export type PutFooResponses = { 81 + /** 82 + * OK 83 + */ 84 + 200: Baz; 85 + }; 86 + 87 + export type PutFooResponse = PutFooResponses[keyof PutFooResponses];
+1 -1
packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/enum-inline-typescript/index.ts
··· 1 1 // This file is auto-generated by @hey-api/openapi-ts 2 2 3 - export { type Bar, Baz, type ClientOptions, type Foo, FooEnum, FooEnum2, type GetFooData, type GetFooResponse, type GetFooResponses, type PostFooData, type PostFooResponse, type PostFooResponses, type PutFooData, type PutFooResponse, type PutFooResponses } from './types.gen'; 3 + export { type Bar, Baz, type ClientOptions, type Foo, FooEnum, FooEnum2, type GetFooData, type GetFooResponse, type GetFooResponses, type PostFooData, type PostFooResponse, type PostFooResponses, type PutFooData, type PutFooResponse, type PutFooResponses, TypeEnum } from './types.gen';
+10 -2
packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/enum-inline-typescript/types.gen.ts
··· 5 5 }; 6 6 7 7 export type Foo = { 8 - type?: FooEnum; 8 + type?: TypeEnum; 9 9 }; 10 10 11 11 export type Bar = { ··· 19 19 20 20 export enum FooEnum { 21 21 FOO = 'foo', 22 - BAR = 'bar' 22 + BAR = 'bar', 23 + FOO_BAR = 'FooBar', 24 + FOO_BAR2 = 'fooBar', 25 + FOO_BAR3 = 'foo bar' 23 26 } 24 27 25 28 export enum FooEnum2 { 26 29 BAZ = 'baz' 30 + } 31 + 32 + export enum TypeEnum { 33 + FOO = 'foo', 34 + BAR = 'bar' 27 35 } 28 36 29 37 export type GetFooData = {
+1 -1
packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/enum-inline/index.ts
··· 1 1 // This file is auto-generated by @hey-api/openapi-ts 2 2 3 - export type { Bar, Baz, ClientOptions, Foo, FooEnum, FooEnum2, GetFooData, GetFooResponse, GetFooResponses, PostFooData, PostFooResponse, PostFooResponses, PutFooData, PutFooResponse, PutFooResponses } from './types.gen'; 3 + export type { Bar, Baz, ClientOptions, Foo, FooEnum, FooEnum2, GetFooData, GetFooResponse, GetFooResponses, PostFooData, PostFooResponse, PostFooResponses, PutFooData, PutFooResponse, PutFooResponses, TypeEnum } from './types.gen';
+4 -2
packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/enum-inline/types.gen.ts
··· 5 5 }; 6 6 7 7 export type Foo = { 8 - type?: FooEnum; 8 + type?: TypeEnum; 9 9 }; 10 10 11 11 export type Bar = { ··· 14 14 15 15 export type Baz = 'qux' | 'quux'; 16 16 17 - export type FooEnum = 'foo' | 'bar'; 17 + export type FooEnum = 'foo' | 'bar' | 'FooBar' | 'fooBar' | 'foo bar'; 18 18 19 19 export type FooEnum2 = 'baz'; 20 + 21 + export type TypeEnum = 'foo' | 'bar'; 20 22 21 23 export type GetFooData = { 22 24 body?: never;
+22 -1
packages/openapi-ts/src/plugins/@hey-api/typescript/shared/export.ts
··· 16 16 plugin: HeyApiTypeScriptPlugin['Instance']; 17 17 schema: IR.SchemaObject; 18 18 }) => { 19 + const keyCounts: Record<string, number> = {}; 19 20 const typeofItems: Array< 20 21 'bigint' | 'boolean' | 'function' | 'number' | 'object' | 'string' | 'symbol' | 'undefined' 21 22 > = []; ··· 57 58 ) { 58 59 key = `_${key}`; 59 60 } 60 - } 61 61 62 + const keyCount = (keyCounts[key] ?? 0) + 1; 63 + keyCounts[key] = keyCount; 64 + 65 + // avoid collision 66 + if (keyCount > 1) { 67 + const nameConflictResolver = plugin.context.config.output?.nameConflictResolver; 68 + if (nameConflictResolver) { 69 + const resolvedName = nameConflictResolver({ 70 + attempt: keyCount - 1, // 0-based index 71 + baseName: key, 72 + }); 73 + if (resolvedName !== null) { 74 + key = resolvedName; 75 + } else { 76 + key = `${key}${keyCount}`; 77 + } 78 + } else { 79 + key = `${key}${keyCount}`; 80 + } 81 + } 82 + } 62 83 return { 63 84 key, 64 85 schema: item,
+1 -1
specs/3.0.x/enum-inline.json
··· 9 9 "Foo": { 10 10 "properties": { 11 11 "type": { 12 - "enum": ["foo", "bar"], 12 + "enum": ["foo", "bar", "FooBar", "fooBar", "foo bar"], 13 13 "type": "string" 14 14 } 15 15 },
+3
specs/3.1.x/enum-inline.yaml
··· 18 18 enum: 19 19 - foo 20 20 - bar 21 + - FooBar 22 + - fooBar 23 + - foo bar 21 24 post: 22 25 responses: 23 26 '200':