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 #2132 from hey-api/fix/enum-namespace-identifier

fix(typescript): better detect enum namespace

authored by

Lubos and committed by
GitHub
0c179014 265e68de

+153 -67
+5
.changeset/soft-parrots-raise.md
··· 1 + --- 2 + '@hey-api/openapi-ts': patch 3 + --- 4 + 5 + fix(typescript): better detect enum namespace
+12 -12
packages/openapi-ts-tests/test/3.1.x.test.ts
··· 265 265 }, 266 266 { 267 267 config: createConfig({ 268 - input: 'enum-names-values.json', 268 + input: 'enum-names-values.yaml', 269 269 output: 'enum-names-values', 270 270 }), 271 271 description: 'handles various enum names and values', 272 272 }, 273 273 { 274 274 config: createConfig({ 275 - input: 'enum-names-values.json', 275 + input: 'enum-names-values.yaml', 276 276 output: 'enum-names-values-javascript-SCREAMING_SNAKE_CASE', 277 277 plugins: [ 278 278 { ··· 287 287 }, 288 288 { 289 289 config: createConfig({ 290 - input: 'enum-names-values.json', 290 + input: 'enum-names-values.yaml', 291 291 output: 'enum-names-values-javascript-PascalCase', 292 292 plugins: [ 293 293 { ··· 302 302 }, 303 303 { 304 304 config: createConfig({ 305 - input: 'enum-names-values.json', 305 + input: 'enum-names-values.yaml', 306 306 output: 'enum-names-values-javascript-camelCase', 307 307 plugins: [ 308 308 { ··· 317 317 }, 318 318 { 319 319 config: createConfig({ 320 - input: 'enum-names-values.json', 320 + input: 'enum-names-values.yaml', 321 321 output: 'enum-names-values-javascript-snake_case', 322 322 plugins: [ 323 323 { ··· 332 332 }, 333 333 { 334 334 config: createConfig({ 335 - input: 'enum-names-values.json', 335 + input: 'enum-names-values.yaml', 336 336 output: 'enum-names-values-javascript-preserve', 337 337 plugins: [ 338 338 { ··· 347 347 }, 348 348 { 349 349 config: createConfig({ 350 - input: 'enum-names-values.json', 350 + input: 'enum-names-values.yaml', 351 351 output: 'enum-names-values-javascript-ignore-null', 352 352 plugins: [ 353 353 { ··· 363 363 }, 364 364 { 365 365 config: createConfig({ 366 - input: 'enum-names-values.json', 366 + input: 'enum-names-values.yaml', 367 367 output: 'enum-names-values-typescript-SCREAMING_SNAKE_CASE', 368 368 plugins: [ 369 369 { ··· 378 378 }, 379 379 { 380 380 config: createConfig({ 381 - input: 'enum-names-values.json', 381 + input: 'enum-names-values.yaml', 382 382 output: 'enum-names-values-typescript-PascalCase', 383 383 plugins: [ 384 384 { ··· 393 393 }, 394 394 { 395 395 config: createConfig({ 396 - input: 'enum-names-values.json', 396 + input: 'enum-names-values.yaml', 397 397 output: 'enum-names-values-typescript-camelCase', 398 398 plugins: [ 399 399 { ··· 408 408 }, 409 409 { 410 410 config: createConfig({ 411 - input: 'enum-names-values.json', 411 + input: 'enum-names-values.yaml', 412 412 output: 'enum-names-values-typescript-snake_case', 413 413 plugins: [ 414 414 { ··· 423 423 }, 424 424 { 425 425 config: createConfig({ 426 - input: 'enum-names-values.json', 426 + input: 'enum-names-values.yaml', 427 427 output: 'enum-names-values-typescript-preserve', 428 428 plugins: [ 429 429 {
+4
packages/openapi-ts-tests/test/__snapshots__/3.1.x/enum-names-values-javascript-PascalCase/types.gen.ts
··· 57 57 2: ['baz'] 58 58 } as const; 59 59 60 + export type MyFooRef = { 61 + foo?: Array<MyFoo2>; 62 + }; 63 + 60 64 export type ClientOptions = { 61 65 baseUrl: `${string}://${string}` | (string & {}); 62 66 };
+4
packages/openapi-ts-tests/test/__snapshots__/3.1.x/enum-names-values-javascript-SCREAMING_SNAKE_CASE/types.gen.ts
··· 57 57 2: ['baz'] 58 58 } as const; 59 59 60 + export type MyFooRef = { 61 + foo?: Array<MyFoo2>; 62 + }; 63 + 60 64 export type ClientOptions = { 61 65 baseUrl: `${string}://${string}` | (string & {}); 62 66 };
+4
packages/openapi-ts-tests/test/__snapshots__/3.1.x/enum-names-values-javascript-camelCase/types.gen.ts
··· 57 57 2: ['baz'] 58 58 } as const; 59 59 60 + export type MyFooRef = { 61 + foo?: Array<MyFoo2>; 62 + }; 63 + 60 64 export type ClientOptions = { 61 65 baseUrl: `${string}://${string}` | (string & {}); 62 66 };
+4
packages/openapi-ts-tests/test/__snapshots__/3.1.x/enum-names-values-javascript-ignore-null/types.gen.ts
··· 56 56 2: ['baz'] 57 57 } as const; 58 58 59 + export type MyFooRef = { 60 + foo?: Array<MyFoo2>; 61 + }; 62 + 59 63 export type ClientOptions = { 60 64 baseUrl: `${string}://${string}` | (string & {}); 61 65 };
+4
packages/openapi-ts-tests/test/__snapshots__/3.1.x/enum-names-values-javascript-preserve/types.gen.ts
··· 57 57 2: ['baz'] 58 58 } as const; 59 59 60 + export type MyFooRef = { 61 + foo?: Array<MyFoo2>; 62 + }; 63 + 60 64 export type ClientOptions = { 61 65 baseUrl: `${string}://${string}` | (string & {}); 62 66 };
+4
packages/openapi-ts-tests/test/__snapshots__/3.1.x/enum-names-values-javascript-snake_case/types.gen.ts
··· 57 57 2: ['baz'] 58 58 } as const; 59 59 60 + export type MyFooRef = { 61 + foo?: Array<MyFoo2>; 62 + }; 63 + 60 64 export type ClientOptions = { 61 65 baseUrl: `${string}://${string}` | (string & {}); 62 66 };
+4
packages/openapi-ts-tests/test/__snapshots__/3.1.x/enum-names-values-typescript-PascalCase/types.gen.ts
··· 34 34 'baz' 35 35 ]; 36 36 37 + export type MyFooRef = { 38 + foo?: Array<MyFoo2>; 39 + }; 40 + 37 41 export type ClientOptions = { 38 42 baseUrl: `${string}://${string}` | (string & {}); 39 43 };
+4
packages/openapi-ts-tests/test/__snapshots__/3.1.x/enum-names-values-typescript-SCREAMING_SNAKE_CASE/types.gen.ts
··· 34 34 'baz' 35 35 ]; 36 36 37 + export type MyFooRef = { 38 + foo?: Array<MyFoo2>; 39 + }; 40 + 37 41 export type ClientOptions = { 38 42 baseUrl: `${string}://${string}` | (string & {}); 39 43 };
+4
packages/openapi-ts-tests/test/__snapshots__/3.1.x/enum-names-values-typescript-camelCase/types.gen.ts
··· 34 34 'baz' 35 35 ]; 36 36 37 + export type MyFooRef = { 38 + foo?: Array<MyFoo2>; 39 + }; 40 + 37 41 export type ClientOptions = { 38 42 baseUrl: `${string}://${string}` | (string & {}); 39 43 };
+4
packages/openapi-ts-tests/test/__snapshots__/3.1.x/enum-names-values-typescript-preserve/types.gen.ts
··· 34 34 'baz' 35 35 ]; 36 36 37 + export type MyFooRef = { 38 + foo?: Array<MyFoo2>; 39 + }; 40 + 37 41 export type ClientOptions = { 38 42 baseUrl: `${string}://${string}` | (string & {}); 39 43 };
+4
packages/openapi-ts-tests/test/__snapshots__/3.1.x/enum-names-values-typescript-snake_case/types.gen.ts
··· 34 34 'baz' 35 35 ]; 36 36 37 + export type MyFooRef = { 38 + foo?: Array<MyFoo2>; 39 + }; 40 + 37 41 export type ClientOptions = { 38 42 baseUrl: `${string}://${string}` | (string & {}); 39 43 };
+4
packages/openapi-ts-tests/test/__snapshots__/3.1.x/enum-names-values/types.gen.ts
··· 18 18 'baz' 19 19 ]; 20 20 21 + export type MyFooRef = { 22 + foo?: Array<MyFoo2>; 23 + }; 24 + 21 25 export type ClientOptions = { 22 26 baseUrl: `${string}://${string}` | (string & {}); 23 27 };
+7 -2
packages/openapi-ts-tests/test/openapi-ts.config.ts
··· 51 51 // 'invalid', 52 52 // 'servers-entry.yaml', 53 53 // ), 54 - path: path.resolve(__dirname, 'spec', '3.1.x', 'full.json'), 54 + path: path.resolve( 55 + __dirname, 56 + 'spec', 57 + '3.1.x', 58 + 'discriminator-one-of.yaml', 59 + ), 55 60 // path: 'http://localhost:4000/', 56 61 // path: 'https://get.heyapi.dev/', 57 62 // path: 'https://get.heyapi.dev/hey-api/backend?branch=main&version=1.0.0', ··· 121 126 // name: '@hey-api/transformers', 122 127 }, 123 128 { 124 - enums: 'typescript', 129 + enums: 'typescript+namespace', 125 130 enumsCase: 'PascalCase', 126 131 // enumsConstantsIgnoreNull: true, 127 132 // exportInlineEnums: true,
-35
packages/openapi-ts-tests/test/spec/3.1.x/enum-names-values.json
··· 1 - { 2 - "openapi": "3.1.1", 3 - "info": { 4 - "title": "OpenAPI 3.1.1 enum names values example", 5 - "version": "1" 6 - }, 7 - "components": { 8 - "schemas": { 9 - "1-10": { 10 - "enum": ["1-10", "11-20"], 11 - "type": "string" 12 - }, 13 - "myFoo": { 14 - "enum": ["myFoo", "myBar"], 15 - "type": "string" 16 - }, 17 - "MyFoo": { 18 - "enum": ["MyFoo", "MyBar"], 19 - "type": "string" 20 - }, 21 - "Foo": { 22 - "enum": ["foo", "bar", null, "", true, false], 23 - "type": ["string", "null"] 24 - }, 25 - "Numbers": { 26 - "enum": [100, 200, 300, -100, -200, -300], 27 - "type": "number" 28 - }, 29 - "Arrays": { 30 - "enum": [["foo"], ["bar"], ["baz"]], 31 - "type": "array" 32 - } 33 - } 34 - } 35 - }
+54
packages/openapi-ts-tests/test/spec/3.1.x/enum-names-values.yaml
··· 1 + openapi: 3.1.1 2 + info: 3 + title: OpenAPI 3.1.1 enum names values example 4 + version: '1' 5 + components: 6 + schemas: 7 + 1-10: 8 + enum: 9 + - 1-10 10 + - 11-20 11 + type: string 12 + myFoo: 13 + enum: 14 + - myFoo 15 + - myBar 16 + type: string 17 + MyFoo: 18 + enum: 19 + - MyFoo 20 + - MyBar 21 + type: string 22 + Foo: 23 + enum: 24 + - foo 25 + - bar 26 + - null 27 + - '' 28 + - true 29 + - false 30 + type: 31 + - string 32 + - 'null' 33 + Numbers: 34 + enum: 35 + - 100 36 + - 200 37 + - 300 38 + - -100 39 + - -200 40 + - -300 41 + type: number 42 + Arrays: 43 + enum: 44 + - - foo 45 + - - bar 46 + - - baz 47 + type: array 48 + MyFooRef: 49 + type: object 50 + properties: 51 + foo: 52 + type: array 53 + items: 54 + $ref: '#/components/schemas/MyFoo'
+1 -1
packages/openapi-ts/src/compiler/types.ts
··· 784 784 }) => { 785 785 let key = name; 786 786 if (typeof key === 'string') { 787 - if (key.startsWith("'") && key.endsWith("'")) { 787 + if (key.includes("'")) { 788 788 key = createStringLiteral({ 789 789 isSingleQuote: false, 790 790 text: key,
+26 -17
packages/openapi-ts/src/plugins/@hey-api/typescript/plugin.ts
··· 265 265 } 266 266 }; 267 267 268 + const shouldCreateTypeScriptEnum = ({ 269 + plugin, 270 + schema, 271 + }: { 272 + plugin: Plugin.Instance<Config>; 273 + schema: SchemaWithType<'enum'>; 274 + }) => { 275 + const enumObject = schemaToEnumObject({ plugin, schema }); 276 + // TypeScript enums support only string and number values 277 + return !enumObject.typeofItems.filter( 278 + (type) => type !== 'number' && type !== 'string', 279 + ).length; 280 + }; 281 + 268 282 const addTypeScriptEnum = ({ 269 283 $ref, 270 284 context, ··· 280 294 }) => { 281 295 const enumObject = schemaToEnumObject({ plugin, schema }); 282 296 283 - // TypeScript enums support only string and number values so we need to fallback to types 284 - if ( 285 - enumObject.typeofItems.filter( 286 - (type) => type !== 'number' && type !== 'string', 287 - ).length 288 - ) { 297 + // fallback to types 298 + if (!shouldCreateTypeScriptEnum({ plugin, schema })) { 289 299 const node = addTypeEnum({ 290 300 $ref, 291 301 context, ··· 302 312 create: true, 303 313 namespace: 'enum', 304 314 }); 305 - 306 - // TODO: parser - this is the old parser behavior where we would NOT 307 - // print nested enum identifiers if they already exist. This is a 308 - // blocker for referencing these identifiers within the file as 309 - // we cannot guarantee just because they have a duplicate identifier, 310 - // they have a duplicate value. 311 - if (!identifier.created && plugin.enums !== 'typescript+namespace') { 312 - return; 313 - } 314 - 315 315 const node = compiler.enumDeclaration({ 316 316 leadingComment: createSchemaComment({ schema }), 317 317 name: identifier.name || '', ··· 1160 1160 const identifier = file.identifier({ 1161 1161 $ref: finalRef, 1162 1162 create: true, 1163 - namespace: 'type', 1163 + namespace: 1164 + refSchema.type === 'enum' && 1165 + (plugin.enums === 'typescript' || 1166 + plugin.enums === 'typescript+namespace') && 1167 + shouldCreateTypeScriptEnum({ 1168 + plugin, 1169 + schema: refSchema as SchemaWithType<'enum'>, 1170 + }) 1171 + ? 'enum' 1172 + : 'type', 1164 1173 }); 1165 1174 type = compiler.typeReferenceNode({ 1166 1175 typeName: identifier.name || '',