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 branch 'main' into fix-body-param

authored by

Lubos and committed by
GitHub
fc701bf6 a33fb04e

+683 -14
+5
.changeset/cuddly-jokes-walk.md
··· 1 + --- 2 + "@hey-api/openapi-ts": patch 3 + --- 4 + 5 + **parser**: inline deep path `$ref` references
+6 -5
dev/openapi-ts.config.ts
··· 48 48 path: path.resolve( 49 49 getSpecsPath(), 50 50 // '2.0.x', 51 - // '3.0.x', 52 - '3.1.x', 51 + '3.0.x', 52 + // '3.1.x', 53 53 // 'circular.yaml', 54 54 // 'dutchie.json', 55 55 // 'enum-names-values.yaml', ··· 60 60 // 'openai.yaml', 61 61 // 'opencode.yaml', 62 62 // 'pagination-ref.yaml', 63 + 'ref-deep.yaml', 63 64 // 'schema-const.yaml', 64 65 // 'sdk-instance.yaml', 65 66 // 'sdk-method-class-conflict.yaml', 66 67 // 'sdk-nested-classes.yaml', 67 68 // 'sdk-nested-conflict.yaml', 68 - 'security-api-key.yaml', 69 + // 'security-api-key.yaml', 69 70 // 'string-with-format.yaml', 70 71 // 'transformers.json', 71 72 // 'transformers-recursive.json', ··· 286 287 // name: '你們_errors_{{name}}', 287 288 // }, 288 289 // exportFromIndex: false, 289 - // name: '@hey-api/typescript', 290 + name: '@hey-api/typescript', 290 291 // requests: '我們_data_{{name}}', 291 292 // responses: { 292 293 // name: '我_responses_{{name}}', ··· 331 332 // fields.unwrap('path') 332 333 // }, 333 334 // include... 334 - name: '@hey-api/sdk', 335 + // name: '@hey-api/sdk', 335 336 operations: { 336 337 // container: 'object', 337 338 // containerName: {
+8
packages/openapi-ts-tests/main/test/2.0.x.test.ts
··· 294 294 }, 295 295 { 296 296 config: createConfig({ 297 + input: 'ref-deep.yaml', 298 + output: 'ref-deep', 299 + plugins: ['@hey-api/typescript'], 300 + }), 301 + description: 'handles deep references', 302 + }, 303 + { 304 + config: createConfig({ 297 305 input: 'transforms-read-write.yaml', 298 306 output: 'transforms-read-write', 299 307 plugins: ['@hey-api/client-fetch', '@hey-api/typescript'],
+8
packages/openapi-ts-tests/main/test/3.0.x.test.ts
··· 548 548 }, 549 549 { 550 550 config: createConfig({ 551 + input: 'ref-deep.yaml', 552 + output: 'ref-deep', 553 + plugins: ['@hey-api/typescript'], 554 + }), 555 + description: 'handles deep references', 556 + }, 557 + { 558 + config: createConfig({ 551 559 input: 'transforms-read-write.yaml', 552 560 output: 'transforms-read-write', 553 561 plugins: ['@hey-api/client-fetch', '@hey-api/typescript'],
+8
packages/openapi-ts-tests/main/test/3.1.x.test.ts
··· 648 648 }, 649 649 { 650 650 config: createConfig({ 651 + input: 'ref-deep.yaml', 652 + output: 'ref-deep', 653 + plugins: ['@hey-api/typescript'], 654 + }), 655 + description: 'handles deep references', 656 + }, 657 + { 658 + config: createConfig({ 651 659 input: 'transforms-read-write.yaml', 652 660 output: 'transforms-read-write', 653 661 plugins: ['@hey-api/client-fetch', '@hey-api/typescript'],
+3
packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/ref-deep/index.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export type { Bar, ClientOptions, Foo, GetFooData, GetFooResponses, PostFooData, PostFooResponses } from './types.gen';
+51
packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/ref-deep/types.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export type ClientOptions = { 4 + baseUrl: string; 5 + }; 6 + 7 + export type Foo = { 8 + foo?: Array<{ 9 + baz?: string; 10 + }>; 11 + bar?: Array<{ 12 + baz?: string; 13 + }>; 14 + }; 15 + 16 + export type Bar = { 17 + foo?: Array<{ 18 + baz?: string; 19 + }>; 20 + bar?: Array<{ 21 + baz?: string; 22 + }>; 23 + }; 24 + 25 + export type GetFooData = { 26 + body?: never; 27 + path?: never; 28 + query?: never; 29 + url: '/foo'; 30 + }; 31 + 32 + export type GetFooResponses = { 33 + /** 34 + * OK 35 + */ 36 + 200: unknown; 37 + }; 38 + 39 + export type PostFooData = { 40 + body?: never; 41 + path?: never; 42 + query?: never; 43 + url: '/foo'; 44 + }; 45 + 46 + export type PostFooResponses = { 47 + /** 48 + * OK 49 + */ 50 + 200: unknown; 51 + };
+3
packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/ref-deep/index.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export type { Bar, ClientOptions, Foo, GetFooData, GetFooResponse, GetFooResponses, PostFooData, PostFooResponse, PostFooResponses } from './types.gen';
+64
packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/ref-deep/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 + foo?: Array<{ 9 + baz?: string; 10 + }>; 11 + bar?: Array<{ 12 + baz?: string; 13 + }>; 14 + }; 15 + 16 + export type Bar = { 17 + foo?: Array<{ 18 + baz?: string; 19 + }>; 20 + bar?: Array<{ 21 + baz?: string; 22 + }>; 23 + }; 24 + 25 + export type GetFooData = { 26 + body?: never; 27 + path?: never; 28 + query?: never; 29 + url: '/foo'; 30 + }; 31 + 32 + export type GetFooResponses = { 33 + /** 34 + * OK 35 + */ 36 + 200: Array<{ 37 + foo?: number; 38 + bar?: string; 39 + }>; 40 + }; 41 + 42 + export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; 43 + 44 + export type PostFooData = { 45 + body?: never; 46 + path?: never; 47 + query?: never; 48 + url: '/foo'; 49 + }; 50 + 51 + export type PostFooResponses = { 52 + /** 53 + * OK 54 + */ 55 + 200: { 56 + foo?: { 57 + foo?: number; 58 + bar?: string; 59 + }; 60 + bar?: string; 61 + }; 62 + }; 63 + 64 + export type PostFooResponse = PostFooResponses[keyof PostFooResponses];
+3
packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/ref-deep/index.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export type { Bar, ClientOptions, Foo, GetFooData, GetFooResponse, GetFooResponses, PostFooData, PostFooResponse, PostFooResponses } from './types.gen';
+64
packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/ref-deep/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 + foo?: Array<{ 9 + baz?: string; 10 + }>; 11 + bar?: Array<{ 12 + baz?: string; 13 + }>; 14 + }; 15 + 16 + export type Bar = { 17 + foo?: Array<{ 18 + baz?: string; 19 + }>; 20 + bar?: Array<{ 21 + baz?: string; 22 + }>; 23 + }; 24 + 25 + export type GetFooData = { 26 + body?: never; 27 + path?: never; 28 + query?: never; 29 + url: '/foo'; 30 + }; 31 + 32 + export type GetFooResponses = { 33 + /** 34 + * OK 35 + */ 36 + 200: Array<{ 37 + foo?: number; 38 + bar?: string; 39 + }>; 40 + }; 41 + 42 + export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; 43 + 44 + export type PostFooData = { 45 + body?: never; 46 + path?: never; 47 + query?: never; 48 + url: '/foo'; 49 + }; 50 + 51 + export type PostFooResponses = { 52 + /** 53 + * OK 54 + */ 55 + 200: { 56 + foo?: { 57 + foo?: number; 58 + bar?: string; 59 + }; 60 + bar?: string; 61 + }; 62 + }; 63 + 64 + export type PostFooResponse = PostFooResponses[keyof PostFooResponses];
+137
packages/openapi-ts/src/__tests__/index.test.ts
··· 5 5 type Config = Parameters<typeof createClient>[0]; 6 6 7 7 describe('createClient', () => { 8 + it('handles deep path $ref without errors', async () => { 9 + // This test verifies that deep path refs like 10 + // #/components/schemas/Foo/properties/bar/items are inlined 11 + // instead of being treated as symbol references (which would fail) 12 + const config: Config = { 13 + dryRun: true, 14 + input: { 15 + components: { 16 + schemas: { 17 + Bar: { 18 + properties: { 19 + nested: { 20 + // Deep path ref - should be inlined, not treated as symbol 21 + $ref: '#/components/schemas/Foo/properties/items/items', 22 + }, 23 + }, 24 + type: 'object', 25 + }, 26 + Foo: { 27 + properties: { 28 + items: { 29 + items: { 30 + properties: { 31 + name: { type: 'string' }, 32 + }, 33 + type: 'object', 34 + }, 35 + type: 'array', 36 + }, 37 + }, 38 + type: 'object', 39 + }, 40 + }, 41 + }, 42 + info: { title: 'deep-ref-test', version: '1.0.0' }, 43 + openapi: '3.1.0', 44 + }, 45 + logs: { 46 + level: 'silent', 47 + }, 48 + output: 'output', 49 + plugins: ['@hey-api/typescript'], 50 + }; 51 + 52 + // Should not throw "Symbol finalName has not been resolved yet" error 53 + const results = await createClient(config); 54 + expect(results).toHaveLength(1); 55 + }); 56 + 57 + it('handles deep path $ref in OpenAPI 3.0.x without errors', async () => { 58 + const config: Config = { 59 + dryRun: true, 60 + input: { 61 + components: { 62 + schemas: { 63 + Bar: { 64 + properties: { 65 + nested: { 66 + $ref: '#/components/schemas/Foo/properties/items/items', 67 + }, 68 + }, 69 + type: 'object', 70 + }, 71 + Foo: { 72 + properties: { 73 + items: { 74 + items: { 75 + properties: { 76 + name: { type: 'string' }, 77 + }, 78 + type: 'object', 79 + }, 80 + type: 'array', 81 + }, 82 + }, 83 + type: 'object', 84 + }, 85 + }, 86 + }, 87 + info: { title: 'deep-ref-test', version: '1.0.0' }, 88 + openapi: '3.0.0', 89 + paths: {}, 90 + }, 91 + logs: { 92 + level: 'silent', 93 + }, 94 + output: 'output', 95 + plugins: ['@hey-api/typescript'], 96 + }; 97 + 98 + const results = await createClient(config); 99 + expect(results).toHaveLength(1); 100 + }); 101 + 102 + it('handles deep path $ref in OpenAPI 2.0 (Swagger) without errors', async () => { 103 + const config: Config = { 104 + dryRun: true, 105 + input: { 106 + definitions: { 107 + Bar: { 108 + properties: { 109 + nested: { 110 + $ref: '#/definitions/Foo/properties/items/items', 111 + }, 112 + }, 113 + type: 'object', 114 + }, 115 + Foo: { 116 + properties: { 117 + items: { 118 + items: { 119 + properties: { 120 + name: { type: 'string' }, 121 + }, 122 + type: 'object', 123 + }, 124 + type: 'array', 125 + }, 126 + }, 127 + type: 'object', 128 + }, 129 + }, 130 + info: { title: 'deep-ref-test', version: '1.0.0' }, 131 + paths: {}, 132 + swagger: '2.0', 133 + }, 134 + logs: { 135 + level: 'silent', 136 + }, 137 + output: 'output', 138 + plugins: ['@hey-api/typescript'], 139 + }; 140 + 141 + const results = await createClient(config); 142 + expect(results).toHaveLength(1); 143 + }); 144 + 8 145 it('1 config, 1 input, 1 output', async () => { 9 146 const config: Config = { 10 147 dryRun: true,
+4 -3
packages/openapi-ts/src/openApi/2.0.x/parser/schema.ts
··· 7 7 SchemaWithRequired, 8 8 } from '~/openApi/shared/types/schema'; 9 9 import { discriminatorValues } from '~/openApi/shared/utils/discriminator'; 10 - import { refToName } from '~/utils/ref'; 10 + import { isTopLevelComponentRef, refToName } from '~/utils/ref'; 11 11 12 12 import type { SchemaObject } from '../types/spec'; 13 13 ··· 554 554 state: SchemaState; 555 555 }): IR.SchemaObject => { 556 556 const irSchema: IR.SchemaObject = {}; 557 - // Inline non-component refs (e.g. #/paths/...) to avoid generating orphaned named types 558 - const isComponentsRef = schema.$ref.startsWith('#/definitions/'); 557 + // Inline non-component refs (e.g. #/paths/...) and deep path refs (e.g. #/definitions/Foo/properties/bar) 558 + // to avoid generating orphaned named types or referencing unregistered symbols 559 + const isComponentsRef = isTopLevelComponentRef(schema.$ref); 559 560 if (!isComponentsRef) { 560 561 if (!state.circularReferenceTracker.has(schema.$ref)) { 561 562 const refSchema = context.resolveRef<SchemaObject>(schema.$ref);
+4 -3
packages/openapi-ts/src/openApi/3.0.x/parser/schema.ts
··· 7 7 SchemaWithRequired, 8 8 } from '~/openApi/shared/types/schema'; 9 9 import { discriminatorValues } from '~/openApi/shared/utils/discriminator'; 10 - import { refToName } from '~/utils/ref'; 10 + import { isTopLevelComponentRef, refToName } from '~/utils/ref'; 11 11 12 12 import type { ReferenceObject, SchemaObject } from '../types/spec'; 13 13 ··· 976 976 schema: ReferenceObject; 977 977 state: SchemaState; 978 978 }): IR.SchemaObject => { 979 - // Inline non-component refs (e.g. #/paths/...) to avoid generating orphaned named types 980 - const isComponentsRef = schema.$ref.startsWith('#/components/'); 979 + // Inline non-component refs (e.g. #/paths/...) and deep path refs (e.g. #/components/schemas/Foo/properties/bar) 980 + // to avoid generating orphaned named types or referencing unregistered symbols 981 + const isComponentsRef = isTopLevelComponentRef(schema.$ref); 981 982 if (!isComponentsRef) { 982 983 if (!state.circularReferenceTracker.has(schema.$ref)) { 983 984 const refSchema = context.resolveRef<SchemaObject>(schema.$ref);
+4 -3
packages/openapi-ts/src/openApi/3.1.x/parser/schema.ts
··· 7 7 SchemaWithRequired, 8 8 } from '~/openApi/shared/types/schema'; 9 9 import { discriminatorValues } from '~/openApi/shared/utils/discriminator'; 10 - import { refToName } from '~/utils/ref'; 10 + import { isTopLevelComponentRef, refToName } from '~/utils/ref'; 11 11 12 12 import type { SchemaObject } from '../types/spec'; 13 13 ··· 1037 1037 schema: SchemaWithRequired<SchemaObject, '$ref'>; 1038 1038 state: SchemaState; 1039 1039 }): IR.SchemaObject => { 1040 - // Inline non-component refs (e.g. #/paths/...) to avoid generating orphaned named types 1041 - const isComponentsRef = schema.$ref.startsWith('#/components/'); 1040 + // Inline non-component refs (e.g. #/paths/...) and deep path refs (e.g. #/components/schemas/Foo/properties/bar) 1041 + // to avoid generating orphaned named types or referencing unregistered symbols 1042 + const isComponentsRef = isTopLevelComponentRef(schema.$ref); 1042 1043 if (!isComponentsRef) { 1043 1044 if (!state.circularReferenceTracker.has(schema.$ref)) { 1044 1045 const refSchema = context.resolveRef<SchemaObject>(schema.$ref);
+91
packages/openapi-ts/src/utils/__tests__/ref.test.ts
··· 1 + import { describe, expect, it } from 'vitest'; 2 + 3 + import { 4 + isTopLevelComponentRef, 5 + jsonPointerToPath, 6 + pathToJsonPointer, 7 + } from '../ref'; 8 + 9 + describe('jsonPointerToPath', () => { 10 + it('parses root pointer', () => { 11 + expect(jsonPointerToPath('#')).toEqual([]); 12 + expect(jsonPointerToPath('')).toEqual([]); 13 + }); 14 + 15 + it('parses component ref', () => { 16 + expect(jsonPointerToPath('#/components/schemas/Foo')).toEqual([ 17 + 'components', 18 + 'schemas', 19 + 'Foo', 20 + ]); 21 + }); 22 + 23 + it('parses deep path ref', () => { 24 + expect( 25 + jsonPointerToPath('#/components/schemas/Foo/properties/bar/items'), 26 + ).toEqual(['components', 'schemas', 'Foo', 'properties', 'bar', 'items']); 27 + }); 28 + }); 29 + 30 + describe('pathToJsonPointer', () => { 31 + it('converts empty path to root pointer', () => { 32 + expect(pathToJsonPointer([])).toBe('#'); 33 + }); 34 + 35 + it('converts path to pointer', () => { 36 + expect(pathToJsonPointer(['components', 'schemas', 'Foo'])).toBe( 37 + '#/components/schemas/Foo', 38 + ); 39 + }); 40 + }); 41 + 42 + describe('isTopLevelComponentRef', () => { 43 + describe('OpenAPI 3.x refs', () => { 44 + it('returns true for top-level component refs', () => { 45 + expect(isTopLevelComponentRef('#/components/schemas/Foo')).toBe(true); 46 + expect(isTopLevelComponentRef('#/components/parameters/Bar')).toBe(true); 47 + expect(isTopLevelComponentRef('#/components/responses/Error')).toBe(true); 48 + expect(isTopLevelComponentRef('#/components/requestBodies/Body')).toBe( 49 + true, 50 + ); 51 + }); 52 + 53 + it('returns false for deep path refs', () => { 54 + expect( 55 + isTopLevelComponentRef('#/components/schemas/Foo/properties/bar'), 56 + ).toBe(false); 57 + expect( 58 + isTopLevelComponentRef('#/components/schemas/Foo/properties/bar/items'), 59 + ).toBe(false); 60 + expect(isTopLevelComponentRef('#/components/schemas/Foo/allOf/0')).toBe( 61 + false, 62 + ); 63 + }); 64 + }); 65 + 66 + describe('OpenAPI 2.0 refs', () => { 67 + it('returns true for top-level definitions refs', () => { 68 + expect(isTopLevelComponentRef('#/definitions/Foo')).toBe(true); 69 + expect(isTopLevelComponentRef('#/definitions/Bar')).toBe(true); 70 + }); 71 + 72 + it('returns false for deep path refs', () => { 73 + expect(isTopLevelComponentRef('#/definitions/Foo/properties/bar')).toBe( 74 + false, 75 + ); 76 + expect( 77 + isTopLevelComponentRef('#/definitions/Foo/properties/bar/items'), 78 + ).toBe(false); 79 + }); 80 + }); 81 + 82 + describe('non-component refs', () => { 83 + it('returns false for path refs', () => { 84 + expect(isTopLevelComponentRef('#/paths/~1users/get')).toBe(false); 85 + }); 86 + 87 + it('returns false for other refs', () => { 88 + expect(isTopLevelComponentRef('#/info/title')).toBe(false); 89 + }); 90 + }); 91 + });
+29
packages/openapi-ts/src/utils/ref.ts
··· 94 94 return '#' + (segments ? `/${segments}` : ''); 95 95 }; 96 96 97 + /** 98 + * Checks if a $ref points to a top-level component (not a deep path reference). 99 + * 100 + * Top-level component references: 101 + * - OpenAPI 3.x: #/components/{type}/{name} (3 segments) 102 + * - OpenAPI 2.0: #/definitions/{name} (2 segments) 103 + * 104 + * Deep path references (4+ segments for 3.x, 3+ for 2.0) should be inlined 105 + * because they don't have corresponding registered symbols. 106 + * 107 + * @param $ref - The $ref string to check 108 + * @returns true if the ref points to a top-level component, false otherwise 109 + */ 110 + export const isTopLevelComponentRef = ($ref: string): boolean => { 111 + const path = jsonPointerToPath($ref); 112 + 113 + // OpenAPI 3.x: #/components/{type}/{name} = 3 segments 114 + if (path[0] === 'components') { 115 + return path.length === 3; 116 + } 117 + 118 + // OpenAPI 2.0: #/definitions/{name} = 2 segments 119 + if (path[0] === 'definitions') { 120 + return path.length === 2; 121 + } 122 + 123 + return false; 124 + }; 125 + 97 126 export const resolveRef = <T>({ 98 127 $ref, 99 128 spec,
+63
specs/2.0.x/ref-deep.yaml
··· 1 + swagger: '2.0' 2 + info: 3 + title: OpenAPI 2.0 ref deep example 4 + version: '1' 5 + paths: 6 + /foo: 7 + get: 8 + responses: 9 + '200': 10 + description: OK 11 + content: 12 + application/json: 13 + schema: 14 + type: array 15 + items: 16 + type: object 17 + properties: 18 + foo: 19 + type: integer 20 + bar: 21 + type: string 22 + post: 23 + responses: 24 + '200': 25 + description: OK 26 + content: 27 + application/json: 28 + schema: 29 + type: object 30 + properties: 31 + foo: 32 + $ref: '#/paths/~1foo/get/responses/200/content/application~1json/schema/items' 33 + bar: 34 + type: string 35 + definitions: 36 + Foo: 37 + type: object 38 + properties: 39 + foo: 40 + type: array 41 + items: 42 + type: object 43 + properties: 44 + baz: 45 + type: string 46 + bar: 47 + type: array 48 + items: 49 + type: object 50 + properties: 51 + baz: 52 + type: string 53 + Bar: 54 + type: object 55 + properties: 56 + foo: 57 + type: array 58 + items: 59 + $ref: '#/definitions/Foo/properties/foo/items' 60 + bar: 61 + type: array 62 + items: 63 + $ref: '#/definitions/Foo/properties/bar/items'
+64
specs/3.0.x/ref-deep.yaml
··· 1 + openapi: 3.0.0 2 + info: 3 + title: OpenAPI 3.0.0 ref deep example 4 + version: '1' 5 + paths: 6 + /foo: 7 + get: 8 + responses: 9 + '200': 10 + description: OK 11 + content: 12 + application/json: 13 + schema: 14 + type: array 15 + items: 16 + type: object 17 + properties: 18 + foo: 19 + type: integer 20 + bar: 21 + type: string 22 + post: 23 + responses: 24 + '200': 25 + description: OK 26 + content: 27 + application/json: 28 + schema: 29 + type: object 30 + properties: 31 + foo: 32 + $ref: '#/paths/~1foo/get/responses/200/content/application~1json/schema/items' 33 + bar: 34 + type: string 35 + components: 36 + schemas: 37 + Foo: 38 + type: object 39 + properties: 40 + foo: 41 + type: array 42 + items: 43 + type: object 44 + properties: 45 + baz: 46 + type: string 47 + bar: 48 + type: array 49 + items: 50 + type: object 51 + properties: 52 + baz: 53 + type: string 54 + Bar: 55 + type: object 56 + properties: 57 + foo: 58 + type: array 59 + items: 60 + $ref: '#/components/schemas/Foo/properties/foo/items' 61 + bar: 62 + type: array 63 + items: 64 + $ref: '#/components/schemas/Foo/properties/bar/items'
+64
specs/3.1.x/ref-deep.yaml
··· 1 + openapi: 3.1.1 2 + info: 3 + title: OpenAPI 3.1.1 ref deep example 4 + version: '1' 5 + paths: 6 + /foo: 7 + get: 8 + responses: 9 + '200': 10 + description: OK 11 + content: 12 + application/json: 13 + schema: 14 + type: array 15 + items: 16 + type: object 17 + properties: 18 + foo: 19 + type: integer 20 + bar: 21 + type: string 22 + post: 23 + responses: 24 + '200': 25 + description: OK 26 + content: 27 + application/json: 28 + schema: 29 + type: object 30 + properties: 31 + foo: 32 + $ref: '#/paths/~1foo/get/responses/200/content/application~1json/schema/items' 33 + bar: 34 + type: string 35 + components: 36 + schemas: 37 + Foo: 38 + type: object 39 + properties: 40 + foo: 41 + type: array 42 + items: 43 + type: object 44 + properties: 45 + baz: 46 + type: string 47 + bar: 48 + type: array 49 + items: 50 + type: object 51 + properties: 52 + baz: 53 + type: string 54 + Bar: 55 + type: object 56 + properties: 57 + foo: 58 + type: array 59 + items: 60 + $ref: '#/components/schemas/Foo/properties/foo/items' 61 + bar: 62 + type: array 63 + items: 64 + $ref: '#/components/schemas/Foo/properties/bar/items'