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 #3601 from pgraug/fix/self-mapped-discriminator

Fix mapped discriminator to self outputting `$type: string` instead of string literal

authored by

Lubos and committed by
GitHub
7a9f6f1d ef3623e4

+296
+6
.changeset/proud-cougars-report.md
··· 1 + --- 2 + "@hey-api/openapi-ts": patch 3 + "@hey-api/shared": patch 4 + --- 5 + 6 + **parser**: fix: self-referencing discriminator
+7
packages/openapi-ts-tests/main/test/3.0.x.test.ts
··· 226 226 }, 227 227 { 228 228 config: createConfig({ 229 + input: 'discriminator-object-self-mapped.json', 230 + output: 'discriminator-object-self-mapped', 231 + }), 232 + description: 'handles object discriminator mappings that include the schema itself', 233 + }, 234 + { 235 + config: createConfig({ 229 236 input: 'discriminator-non-string.yaml', 230 237 output: 'discriminator-non-string', 231 238 }),
+7
packages/openapi-ts-tests/main/test/3.1.x.test.ts
··· 252 252 }, 253 253 { 254 254 config: createConfig({ 255 + input: 'discriminator-object-self-mapped.json', 256 + output: 'discriminator-object-self-mapped', 257 + }), 258 + description: 'handles object discriminator mappings that include the schema itself', 259 + }, 260 + { 261 + config: createConfig({ 255 262 input: 'discriminator-non-string.yaml', 256 263 output: 'discriminator-non-string', 257 264 }),
+3
packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/discriminator-object-self-mapped/index.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export type { BlogPostDto, BlogPostWithImageDto, ClientOptions, GetBlogPostsData, GetBlogPostsResponse, GetBlogPostsResponses } from './types.gen';
+32
packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/discriminator-object-self-mapped/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 BlogPostDto = { 8 + $type: 'BlogPost'; 9 + id: number; 10 + title: string; 11 + }; 12 + 13 + export type BlogPostWithImageDto = Omit<BlogPostDto, '$type'> & { 14 + imageUrl: string; 15 + $type: 'BlogPostWithImage'; 16 + }; 17 + 18 + export type GetBlogPostsData = { 19 + body?: never; 20 + path?: never; 21 + query?: never; 22 + url: '/blog-posts'; 23 + }; 24 + 25 + export type GetBlogPostsResponses = { 26 + /** 27 + * List of blog posts 28 + */ 29 + 200: Array<BlogPostDto | BlogPostWithImageDto>; 30 + }; 31 + 32 + export type GetBlogPostsResponse = GetBlogPostsResponses[keyof GetBlogPostsResponses];
+3
packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/discriminator-object-self-mapped/index.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export type { BlogPostDto, BlogPostWithImageDto, ClientOptions, GetBlogPostsData, GetBlogPostsResponse, GetBlogPostsResponses } from './types.gen';
+32
packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/discriminator-object-self-mapped/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 BlogPostDto = { 8 + $type: 'BlogPost'; 9 + id: number; 10 + title: string; 11 + }; 12 + 13 + export type BlogPostWithImageDto = Omit<BlogPostDto, '$type'> & { 14 + imageUrl: string; 15 + $type: 'BlogPostWithImage'; 16 + }; 17 + 18 + export type GetBlogPostsData = { 19 + body?: never; 20 + path?: never; 21 + query?: never; 22 + url: '/blog-posts'; 23 + }; 24 + 25 + export type GetBlogPostsResponses = { 26 + /** 27 + * List of blog posts 28 + */ 29 + 200: Array<BlogPostDto | BlogPostWithImageDto>; 30 + }; 31 + 32 + export type GetBlogPostsResponse = GetBlogPostsResponses[keyof GetBlogPostsResponses];
+30
packages/shared/src/openApi/3.0.x/parser/schema.ts
··· 377 377 irSchema.required = schema.required; 378 378 } 379 379 380 + if (schema.discriminator && state.$ref) { 381 + const values = getAllDiscriminatorValues({ 382 + discriminator: schema.discriminator, 383 + schemaRef: state.$ref, 384 + }); 385 + 386 + if (values.length) { 387 + const propertyType = findDiscriminatorPropertyType({ 388 + context, 389 + propertyName: schema.discriminator.propertyName, 390 + schemas: [schema], 391 + }); 392 + const valueSchemas: ReadonlyArray<IR.SchemaObject> = values.map((value) => 393 + convertDiscriminatorValue(value, propertyType), 394 + ); 395 + 396 + if (!irSchema.properties) { 397 + irSchema.properties = {}; 398 + } 399 + 400 + irSchema.properties[schema.discriminator.propertyName] = 401 + valueSchemas.length > 1 402 + ? { 403 + items: valueSchemas, 404 + logicalOperator: 'or', 405 + } 406 + : valueSchemas[0]!; 407 + } 408 + } 409 + 380 410 return irSchema; 381 411 }; 382 412
+30
packages/shared/src/openApi/3.1.x/parser/schema.ts
··· 472 472 irSchema.required = schema.required; 473 473 } 474 474 475 + if (schema.discriminator && state.$ref) { 476 + const values = getAllDiscriminatorValues({ 477 + discriminator: schema.discriminator, 478 + schemaRef: state.$ref, 479 + }); 480 + 481 + if (values.length) { 482 + const propertyType = findDiscriminatorPropertyType({ 483 + context, 484 + propertyName: schema.discriminator.propertyName, 485 + schemas: [schema], 486 + }); 487 + const valueSchemas: ReadonlyArray<IR.SchemaObject> = values.map((value) => 488 + convertDiscriminatorValue(value, propertyType), 489 + ); 490 + 491 + if (!irSchema.properties) { 492 + irSchema.properties = {}; 493 + } 494 + 495 + irSchema.properties[schema.discriminator.propertyName] = 496 + valueSchemas.length > 1 497 + ? { 498 + items: valueSchemas, 499 + logicalOperator: 'or', 500 + } 501 + : valueSchemas[0]!; 502 + } 503 + } 504 + 475 505 return irSchema; 476 506 }; 477 507
+73
specs/3.0.x/discriminator-object-self-mapped.json
··· 1 + { 2 + "openapi": "3.0.3", 3 + "info": { 4 + "title": "Discriminator object schema with self mapping", 5 + "version": "1.0.0", 6 + "description": "Ensures a concrete schema with a discriminator mapping to itself gets a literal discriminator value instead of falling back to string." 7 + }, 8 + "paths": { 9 + "/blog-posts": { 10 + "get": { 11 + "summary": "Get blog posts", 12 + "responses": { 13 + "200": { 14 + "description": "List of blog posts", 15 + "content": { 16 + "application/json": { 17 + "schema": { 18 + "type": "array", 19 + "items": { 20 + "oneOf": [ 21 + { "$ref": "#/components/schemas/BlogPostDto" }, 22 + { "$ref": "#/components/schemas/BlogPostWithImageDto" } 23 + ] 24 + } 25 + } 26 + } 27 + } 28 + } 29 + } 30 + } 31 + } 32 + }, 33 + "components": { 34 + "schemas": { 35 + "BlogPostDto": { 36 + "type": "object", 37 + "required": ["$type", "id", "title"], 38 + "properties": { 39 + "$type": { 40 + "type": "string" 41 + }, 42 + "id": { 43 + "type": "integer" 44 + }, 45 + "title": { 46 + "type": "string" 47 + } 48 + }, 49 + "discriminator": { 50 + "propertyName": "$type", 51 + "mapping": { 52 + "BlogPost": "#/components/schemas/BlogPostDto", 53 + "BlogPostWithImage": "#/components/schemas/BlogPostWithImageDto" 54 + } 55 + } 56 + }, 57 + "BlogPostWithImageDto": { 58 + "allOf": [ 59 + { "$ref": "#/components/schemas/BlogPostDto" }, 60 + { 61 + "type": "object", 62 + "required": ["imageUrl"], 63 + "properties": { 64 + "imageUrl": { 65 + "type": "string" 66 + } 67 + } 68 + } 69 + ] 70 + } 71 + } 72 + } 73 + }
+73
specs/3.1.x/discriminator-object-self-mapped.json
··· 1 + { 2 + "openapi": "3.1.0", 3 + "info": { 4 + "title": "Discriminator object schema with self mapping", 5 + "version": "1.0.0", 6 + "description": "Ensures a concrete schema with a discriminator mapping to itself gets a literal discriminator value instead of falling back to string." 7 + }, 8 + "paths": { 9 + "/blog-posts": { 10 + "get": { 11 + "summary": "Get blog posts", 12 + "responses": { 13 + "200": { 14 + "description": "List of blog posts", 15 + "content": { 16 + "application/json": { 17 + "schema": { 18 + "type": "array", 19 + "items": { 20 + "oneOf": [ 21 + { "$ref": "#/components/schemas/BlogPostDto" }, 22 + { "$ref": "#/components/schemas/BlogPostWithImageDto" } 23 + ] 24 + } 25 + } 26 + } 27 + } 28 + } 29 + } 30 + } 31 + } 32 + }, 33 + "components": { 34 + "schemas": { 35 + "BlogPostDto": { 36 + "type": "object", 37 + "required": ["$type", "id", "title"], 38 + "properties": { 39 + "$type": { 40 + "type": "string" 41 + }, 42 + "id": { 43 + "type": "integer" 44 + }, 45 + "title": { 46 + "type": "string" 47 + } 48 + }, 49 + "discriminator": { 50 + "propertyName": "$type", 51 + "mapping": { 52 + "BlogPost": "#/components/schemas/BlogPostDto", 53 + "BlogPostWithImage": "#/components/schemas/BlogPostWithImageDto" 54 + } 55 + } 56 + }, 57 + "BlogPostWithImageDto": { 58 + "allOf": [ 59 + { "$ref": "#/components/schemas/BlogPostDto" }, 60 + { 61 + "type": "object", 62 + "required": ["imageUrl"], 63 + "properties": { 64 + "imageUrl": { 65 + "type": "string" 66 + } 67 + } 68 + } 69 + ] 70 + } 71 + } 72 + } 73 + }