diff --git a/dev/openapi-ts.config.ts b/dev/openapi-ts.config.ts index f7f75e19b..307e8b841 100644 --- a/dev/openapi-ts.config.ts +++ b/dev/openapi-ts.config.ts @@ -49,8 +49,8 @@ export default defineConfig(() => { path: path.resolve( getSpecsPath(), // '2.0.x', - // '3.0.x', - '3.1.x', + '3.0.x', + // '3.1.x', // 'circular.yaml', // 'dutchie.json', // 'enum-names-values.yaml', @@ -66,8 +66,9 @@ export default defineConfig(() => { // 'sdk-method-class-conflict.yaml', // 'sdk-nested-classes.yaml', // 'sdk-nested-conflict.yaml', - 'security-api-key.yaml', + // 'security-api-key.yaml', // 'string-with-format.yaml', + 'broken.yaml', // 'transformers.json', // 'transformers-recursive.json', // 'type-format.yaml', @@ -288,7 +289,7 @@ export default defineConfig(() => { // name: '你們_errors_{{name}}', // }, // exportFromIndex: false, - // name: '@hey-api/typescript', + name: '@hey-api/typescript', // requests: '我們_data_{{name}}', // responses: { // name: '我_responses_{{name}}', @@ -333,7 +334,7 @@ export default defineConfig(() => { // fields.unwrap('path') // }, // include... - name: '@hey-api/sdk', + // name: '@hey-api/sdk', operations: { // container: 'object', // containerName: { diff --git a/specs/3.0.x/broken.yaml b/specs/3.0.x/broken.yaml new file mode 100644 index 000000000..ddaba06af --- /dev/null +++ b/specs/3.0.x/broken.yaml @@ -0,0 +1,35 @@ +openapi: 3.0.1 +info: + title: foo + description: foo + version: '1' +components: + schemas: + Foo: + type: object + properties: + foo: + type: array + items: + type: object + properties: + baz: + type: string + bar: + type: array + items: + type: object + properties: + baz: + type: string + Bar: + type: object + properties: + foo: + type: array + items: + $ref: '#/components/schemas/Foo/properties/foo/items' + bar: + type: array + items: + $ref: '#/components/schemas/Foo/properties/bar/items' -- 2.51.2 From 497d6535cdeb960572a15abd99d665637055973c Mon Sep 17 00:00:00 2001 From: chrg1001 <40189653+chrg1001@users.noreply.github.com> Date: Thu, 22 Jan 2026 10:35:13 +0900 Subject: [PATCH 2/6] fix: inline deep path $ref references instead of treating as symbols Deep path references like `#/components/schemas/Foo/properties/bar/items` were causing "Symbol finalName has not been resolved yet" errors because they don't have corresponding registered symbols (only top-level refs do). Add `isTopLevelComponentRef()` to detect and inline these deep path refs. --- .../src/openApi/2.0.x/parser/schema.ts | 7 +- .../src/openApi/3.0.x/parser/schema.ts | 7 +- .../src/openApi/3.1.x/parser/schema.ts | 7 +- .../src/utils/__tests__/ref.test.ts | 91 +++++++++++++++++++ packages/openapi-ts/src/utils/ref.ts | 29 ++++++ 5 files changed, 132 insertions(+), 9 deletions(-) create mode 100644 packages/openapi-ts/src/utils/__tests__/ref.test.ts diff --git a/packages/openapi-ts/src/openApi/2.0.x/parser/schema.ts b/packages/openapi-ts/src/openApi/2.0.x/parser/schema.ts index f8301b6a4..e39081462 100644 --- a/packages/openapi-ts/src/openApi/2.0.x/parser/schema.ts +++ b/packages/openapi-ts/src/openApi/2.0.x/parser/schema.ts @@ -7,7 +7,7 @@ import type { SchemaWithRequired, } from '~/openApi/shared/types/schema'; import { discriminatorValues } from '~/openApi/shared/utils/discriminator'; -import { refToName } from '~/utils/ref'; +import { isTopLevelComponentRef, refToName } from '~/utils/ref'; import type { SchemaObject } from '../types/spec'; @@ -554,8 +554,9 @@ const parseRef = ({ state: SchemaState; }): IR.SchemaObject => { const irSchema: IR.SchemaObject = {}; - // Inline non-component refs (e.g. #/paths/...) to avoid generating orphaned named types - const isComponentsRef = schema.$ref.startsWith('#/definitions/'); + // Inline non-component refs (e.g. #/paths/...) and deep path refs (e.g. #/definitions/Foo/properties/bar) + // to avoid generating orphaned named types or referencing unregistered symbols + const isComponentsRef = isTopLevelComponentRef(schema.$ref); if (!isComponentsRef) { if (!state.circularReferenceTracker.has(schema.$ref)) { const refSchema = context.resolveRef(schema.$ref); diff --git a/packages/openapi-ts/src/openApi/3.0.x/parser/schema.ts b/packages/openapi-ts/src/openApi/3.0.x/parser/schema.ts index b6dfd33a1..8391f3c0f 100644 --- a/packages/openapi-ts/src/openApi/3.0.x/parser/schema.ts +++ b/packages/openapi-ts/src/openApi/3.0.x/parser/schema.ts @@ -7,7 +7,7 @@ import type { SchemaWithRequired, } from '~/openApi/shared/types/schema'; import { discriminatorValues } from '~/openApi/shared/utils/discriminator'; -import { refToName } from '~/utils/ref'; +import { isTopLevelComponentRef, refToName } from '~/utils/ref'; import type { ReferenceObject, SchemaObject } from '../types/spec'; @@ -976,8 +976,9 @@ const parseRef = ({ schema: ReferenceObject; state: SchemaState; }): IR.SchemaObject => { - // Inline non-component refs (e.g. #/paths/...) to avoid generating orphaned named types - const isComponentsRef = schema.$ref.startsWith('#/components/'); + // Inline non-component refs (e.g. #/paths/...) and deep path refs (e.g. #/components/schemas/Foo/properties/bar) + // to avoid generating orphaned named types or referencing unregistered symbols + const isComponentsRef = isTopLevelComponentRef(schema.$ref); if (!isComponentsRef) { if (!state.circularReferenceTracker.has(schema.$ref)) { const refSchema = context.resolveRef(schema.$ref); diff --git a/packages/openapi-ts/src/openApi/3.1.x/parser/schema.ts b/packages/openapi-ts/src/openApi/3.1.x/parser/schema.ts index 0ba9706da..43a06fc2e 100644 --- a/packages/openapi-ts/src/openApi/3.1.x/parser/schema.ts +++ b/packages/openapi-ts/src/openApi/3.1.x/parser/schema.ts @@ -7,7 +7,7 @@ import type { SchemaWithRequired, } from '~/openApi/shared/types/schema'; import { discriminatorValues } from '~/openApi/shared/utils/discriminator'; -import { refToName } from '~/utils/ref'; +import { isTopLevelComponentRef, refToName } from '~/utils/ref'; import type { SchemaObject } from '../types/spec'; @@ -1037,8 +1037,9 @@ const parseRef = ({ schema: SchemaWithRequired; state: SchemaState; }): IR.SchemaObject => { - // Inline non-component refs (e.g. #/paths/...) to avoid generating orphaned named types - const isComponentsRef = schema.$ref.startsWith('#/components/'); + // Inline non-component refs (e.g. #/paths/...) and deep path refs (e.g. #/components/schemas/Foo/properties/bar) + // to avoid generating orphaned named types or referencing unregistered symbols + const isComponentsRef = isTopLevelComponentRef(schema.$ref); if (!isComponentsRef) { if (!state.circularReferenceTracker.has(schema.$ref)) { const refSchema = context.resolveRef(schema.$ref); diff --git a/packages/openapi-ts/src/utils/__tests__/ref.test.ts b/packages/openapi-ts/src/utils/__tests__/ref.test.ts new file mode 100644 index 000000000..251af2929 --- /dev/null +++ b/packages/openapi-ts/src/utils/__tests__/ref.test.ts @@ -0,0 +1,91 @@ +import { describe, expect, it } from 'vitest'; + +import { + isTopLevelComponentRef, + jsonPointerToPath, + pathToJsonPointer, +} from '../ref'; + +describe('jsonPointerToPath', () => { + it('parses root pointer', () => { + expect(jsonPointerToPath('#')).toEqual([]); + expect(jsonPointerToPath('')).toEqual([]); + }); + + it('parses component ref', () => { + expect(jsonPointerToPath('#/components/schemas/Foo')).toEqual([ + 'components', + 'schemas', + 'Foo', + ]); + }); + + it('parses deep path ref', () => { + expect( + jsonPointerToPath('#/components/schemas/Foo/properties/bar/items'), + ).toEqual(['components', 'schemas', 'Foo', 'properties', 'bar', 'items']); + }); +}); + +describe('pathToJsonPointer', () => { + it('converts empty path to root pointer', () => { + expect(pathToJsonPointer([])).toBe('#'); + }); + + it('converts path to pointer', () => { + expect(pathToJsonPointer(['components', 'schemas', 'Foo'])).toBe( + '#/components/schemas/Foo', + ); + }); +}); + +describe('isTopLevelComponentRef', () => { + describe('OpenAPI 3.x refs', () => { + it('returns true for top-level component refs', () => { + expect(isTopLevelComponentRef('#/components/schemas/Foo')).toBe(true); + expect(isTopLevelComponentRef('#/components/parameters/Bar')).toBe(true); + expect(isTopLevelComponentRef('#/components/responses/Error')).toBe(true); + expect(isTopLevelComponentRef('#/components/requestBodies/Body')).toBe( + true, + ); + }); + + it('returns false for deep path refs', () => { + expect( + isTopLevelComponentRef('#/components/schemas/Foo/properties/bar'), + ).toBe(false); + expect( + isTopLevelComponentRef('#/components/schemas/Foo/properties/bar/items'), + ).toBe(false); + expect(isTopLevelComponentRef('#/components/schemas/Foo/allOf/0')).toBe( + false, + ); + }); + }); + + describe('OpenAPI 2.0 refs', () => { + it('returns true for top-level definitions refs', () => { + expect(isTopLevelComponentRef('#/definitions/Foo')).toBe(true); + expect(isTopLevelComponentRef('#/definitions/Bar')).toBe(true); + }); + + it('returns false for deep path refs', () => { + expect(isTopLevelComponentRef('#/definitions/Foo/properties/bar')).toBe( + false, + ); + expect( + isTopLevelComponentRef('#/definitions/Foo/properties/bar/items'), + ).toBe(false); + }); + }); + + describe('non-component refs', () => { + it('returns false for path refs', () => { + expect(isTopLevelComponentRef('#/paths/~1users/get')).toBe(false); + }); + + it('returns false for other refs', () => { + expect(isTopLevelComponentRef('#/info/title')).toBe(false); + }); + }); +}); diff --git a/packages/openapi-ts/src/utils/ref.ts b/packages/openapi-ts/src/utils/ref.ts index 236770bce..289b404ab 100644 --- a/packages/openapi-ts/src/utils/ref.ts +++ b/packages/openapi-ts/src/utils/ref.ts @@ -94,6 +94,35 @@ export const pathToJsonPointer = ( return '#' + (segments ? `/${segments}` : ''); }; +/** + * Checks if a $ref points to a top-level component (not a deep path reference). + * + * Top-level component references: + * - OpenAPI 3.x: #/components/{type}/{name} (3 segments) + * - OpenAPI 2.0: #/definitions/{name} (2 segments) + * + * Deep path references (4+ segments for 3.x, 3+ for 2.0) should be inlined + * because they don't have corresponding registered symbols. + * + * @param $ref - The $ref string to check + * @returns true if the ref points to a top-level component, false otherwise + */ +export const isTopLevelComponentRef = ($ref: string): boolean => { + const path = jsonPointerToPath($ref); + + // OpenAPI 3.x: #/components/{type}/{name} = 3 segments + if (path[0] === 'components') { + return path.length === 3; + } + + // OpenAPI 2.0: #/definitions/{name} = 2 segments + if (path[0] === 'definitions') { + return path.length === 2; + } + + return false; +}; + export const resolveRef = ({ $ref, spec, -- 2.51.2 From 5ae0baaf6b7b9c4db0bb0b600d4204ba78846d3b Mon Sep 17 00:00:00 2001 From: chrg1001 <40189653+chrg1001@users.noreply.github.com> Date: Thu, 22 Jan 2026 10:46:07 +0900 Subject: [PATCH 3/6] test: add E2E tests for deep path $ref handling Cover the isTopLevelComponentRef calls in parser/schema.ts for all OpenAPI versions (2.0, 3.0.x, 3.1.x) to improve patch coverage. --- .../openapi-ts/src/__tests__/index.test.ts | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/packages/openapi-ts/src/__tests__/index.test.ts b/packages/openapi-ts/src/__tests__/index.test.ts index c3374ee5c..cbde1145a 100644 --- a/packages/openapi-ts/src/__tests__/index.test.ts +++ b/packages/openapi-ts/src/__tests__/index.test.ts @@ -5,6 +5,143 @@ import { createClient } from '~/index'; type Config = Parameters[0]; describe('createClient', () => { + it('handles deep path $ref without errors', async () => { + // This test verifies that deep path refs like + // #/components/schemas/Foo/properties/bar/items are inlined + // instead of being treated as symbol references (which would fail) + const config: Config = { + dryRun: true, + input: { + components: { + schemas: { + Bar: { + properties: { + nested: { + // Deep path ref - should be inlined, not treated as symbol + $ref: '#/components/schemas/Foo/properties/items/items', + }, + }, + type: 'object', + }, + Foo: { + properties: { + items: { + items: { + properties: { + name: { type: 'string' }, + }, + type: 'object', + }, + type: 'array', + }, + }, + type: 'object', + }, + }, + }, + info: { title: 'deep-ref-test', version: '1.0.0' }, + openapi: '3.1.0', + }, + logs: { + level: 'silent', + }, + output: 'output', + plugins: ['@hey-api/typescript'], + }; + + // Should not throw "Symbol finalName has not been resolved yet" error + const results = await createClient(config); + expect(results).toHaveLength(1); + }); + + it('handles deep path $ref in OpenAPI 3.0.x without errors', async () => { + const config: Config = { + dryRun: true, + input: { + components: { + schemas: { + Bar: { + properties: { + nested: { + $ref: '#/components/schemas/Foo/properties/items/items', + }, + }, + type: 'object', + }, + Foo: { + properties: { + items: { + items: { + properties: { + name: { type: 'string' }, + }, + type: 'object', + }, + type: 'array', + }, + }, + type: 'object', + }, + }, + }, + info: { title: 'deep-ref-test', version: '1.0.0' }, + openapi: '3.0.0', + paths: {}, + }, + logs: { + level: 'silent', + }, + output: 'output', + plugins: ['@hey-api/typescript'], + }; + + const results = await createClient(config); + expect(results).toHaveLength(1); + }); + + it('handles deep path $ref in OpenAPI 2.0 (Swagger) without errors', async () => { + const config: Config = { + dryRun: true, + input: { + definitions: { + Bar: { + properties: { + nested: { + $ref: '#/definitions/Foo/properties/items/items', + }, + }, + type: 'object', + }, + Foo: { + properties: { + items: { + items: { + properties: { + name: { type: 'string' }, + }, + type: 'object', + }, + type: 'array', + }, + }, + type: 'object', + }, + }, + info: { title: 'deep-ref-test', version: '1.0.0' }, + paths: {}, + swagger: '2.0', + }, + logs: { + level: 'silent', + }, + output: 'output', + plugins: ['@hey-api/typescript'], + }; + + const results = await createClient(config); + expect(results).toHaveLength(1); + }); + it('1 config, 1 input, 1 output', async () => { const config: Config = { dryRun: true, -- 2.51.2 From d94368bcd9205ceb7e5641644032e26c17b2a1af Mon Sep 17 00:00:00 2001 From: chrg1001 <40189653+chrg1001@users.noreply.github.com> Date: Fri, 23 Jan 2026 09:28:09 +0900 Subject: [PATCH 4/6] test: add test case for deep #/paths/... references --- specs/3.0.x/deep-path-ref.yaml | 39 ++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 specs/3.0.x/deep-path-ref.yaml diff --git a/specs/3.0.x/deep-path-ref.yaml b/specs/3.0.x/deep-path-ref.yaml new file mode 100644 index 000000000..7c05dc11a --- /dev/null +++ b/specs/3.0.x/deep-path-ref.yaml @@ -0,0 +1,39 @@ +openapi: 3.0.1 +info: + title: Deep Path Ref Test + description: Test case for deep path references in #/paths/... + version: '1' +paths: + /users: + get: + operationId: getUsers + responses: + '200': + description: Success + content: + application/json: + schema: + type: array + items: + type: object + properties: + id: + type: integer + name: + type: string + /posts: + get: + operationId: getPosts + responses: + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + author: + # Deep path reference to /users response schema item + $ref: '#/paths/~1users/get/responses/200/content/application~1json/schema/items' + title: + type: string -- 2.51.2 From 00cfaed32a3b1d2a7bbd5c4c2a946a9f7be262b2 Mon Sep 17 00:00:00 2001 From: Lubos Date: Sat, 24 Jan 2026 08:06:26 +0800 Subject: [PATCH 5/6] Update fix message to use parser prefix --- .changeset/cuddly-jokes-walk.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/cuddly-jokes-walk.md diff --git a/.changeset/cuddly-jokes-walk.md b/.changeset/cuddly-jokes-walk.md new file mode 100644 index 000000000..def2de8a0 --- /dev/null +++ b/.changeset/cuddly-jokes-walk.md @@ -0,0 +1,5 @@ +--- +"@hey-api/openapi-ts": patch +--- + +**parser**: inline deep path `$ref` references -- 2.51.2 From 1e5fafcdac9ead7a81235ff85a0342d5cef1a06d Mon Sep 17 00:00:00 2001 From: Lubos Date: Sun, 25 Jan 2026 02:35:31 +0800 Subject: [PATCH 6/6] fix: inline deep references --- dev/openapi-ts.config.ts | 2 +- .../openapi-ts-tests/main/test/2.0.x.test.ts | 8 +++ .../openapi-ts-tests/main/test/3.0.x.test.ts | 8 +++ .../openapi-ts-tests/main/test/3.1.x.test.ts | 8 +++ .../__snapshots__/2.0.x/ref-deep/index.ts | 3 + .../__snapshots__/2.0.x/ref-deep/types.gen.ts | 51 +++++++++++++++ .../__snapshots__/3.0.x/ref-deep/index.ts | 3 + .../__snapshots__/3.0.x/ref-deep/types.gen.ts | 64 +++++++++++++++++++ .../__snapshots__/3.1.x/ref-deep/index.ts | 3 + .../__snapshots__/3.1.x/ref-deep/types.gen.ts | 64 +++++++++++++++++++ specs/2.0.x/ref-deep.yaml | 63 ++++++++++++++++++ specs/3.0.x/broken.yaml | 35 ---------- specs/3.0.x/deep-path-ref.yaml | 39 ----------- specs/3.0.x/ref-deep.yaml | 64 +++++++++++++++++++ specs/3.1.x/ref-deep.yaml | 64 +++++++++++++++++++ 15 files changed, 404 insertions(+), 75 deletions(-) create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/ref-deep/index.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/ref-deep/types.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/ref-deep/index.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/ref-deep/types.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/ref-deep/index.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/ref-deep/types.gen.ts create mode 100644 specs/2.0.x/ref-deep.yaml delete mode 100644 specs/3.0.x/broken.yaml delete mode 100644 specs/3.0.x/deep-path-ref.yaml create mode 100644 specs/3.0.x/ref-deep.yaml create mode 100644 specs/3.1.x/ref-deep.yaml diff --git a/dev/openapi-ts.config.ts b/dev/openapi-ts.config.ts index d26d05029..1bde0b6f1 100644 --- a/dev/openapi-ts.config.ts +++ b/dev/openapi-ts.config.ts @@ -60,6 +60,7 @@ export default defineConfig(() => { // 'openai.yaml', // 'opencode.yaml', // 'pagination-ref.yaml', + 'ref-deep.yaml', // 'schema-const.yaml', // 'sdk-instance.yaml', // 'sdk-method-class-conflict.yaml', @@ -67,7 +68,6 @@ export default defineConfig(() => { // 'sdk-nested-conflict.yaml', // 'security-api-key.yaml', // 'string-with-format.yaml', - 'broken.yaml', // 'transformers.json', // 'transformers-recursive.json', // 'type-format.yaml', diff --git a/packages/openapi-ts-tests/main/test/2.0.x.test.ts b/packages/openapi-ts-tests/main/test/2.0.x.test.ts index 14a1ecd8f..32254b361 100644 --- a/packages/openapi-ts-tests/main/test/2.0.x.test.ts +++ b/packages/openapi-ts-tests/main/test/2.0.x.test.ts @@ -292,6 +292,14 @@ describe(`OpenAPI ${version}`, () => { }), description: 'handles form data', }, + { + config: createConfig({ + input: 'ref-deep.yaml', + output: 'ref-deep', + plugins: ['@hey-api/typescript'], + }), + description: 'handles deep references', + }, { config: createConfig({ input: 'transforms-read-write.yaml', diff --git a/packages/openapi-ts-tests/main/test/3.0.x.test.ts b/packages/openapi-ts-tests/main/test/3.0.x.test.ts index f0ffed2bb..a487f73a8 100644 --- a/packages/openapi-ts-tests/main/test/3.0.x.test.ts +++ b/packages/openapi-ts-tests/main/test/3.0.x.test.ts @@ -546,6 +546,14 @@ describe(`OpenAPI ${version}`, () => { }), description: 'handles non-exploded array query parameters (Axios)', }, + { + config: createConfig({ + input: 'ref-deep.yaml', + output: 'ref-deep', + plugins: ['@hey-api/typescript'], + }), + description: 'handles deep references', + }, { config: createConfig({ input: 'transforms-read-write.yaml', diff --git a/packages/openapi-ts-tests/main/test/3.1.x.test.ts b/packages/openapi-ts-tests/main/test/3.1.x.test.ts index 8ed72f2e6..84246f364 100644 --- a/packages/openapi-ts-tests/main/test/3.1.x.test.ts +++ b/packages/openapi-ts-tests/main/test/3.1.x.test.ts @@ -646,6 +646,14 @@ describe(`OpenAPI ${version}`, () => { }), description: 'handles tuple query parameters', }, + { + config: createConfig({ + input: 'ref-deep.yaml', + output: 'ref-deep', + plugins: ['@hey-api/typescript'], + }), + description: 'handles deep references', + }, { config: createConfig({ input: 'transforms-read-write.yaml', diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/ref-deep/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/ref-deep/index.ts new file mode 100644 index 000000000..028a5386a --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/ref-deep/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type { Bar, ClientOptions, Foo, GetFooData, GetFooResponses, PostFooData, PostFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/ref-deep/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/ref-deep/types.gen.ts new file mode 100644 index 000000000..597cf7562 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/ref-deep/types.gen.ts @@ -0,0 +1,51 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseUrl: string; +}; + +export type Foo = { + foo?: Array<{ + baz?: string; + }>; + bar?: Array<{ + baz?: string; + }>; +}; + +export type Bar = { + foo?: Array<{ + baz?: string; + }>; + bar?: Array<{ + baz?: string; + }>; +}; + +export type GetFooData = { + body?: never; + path?: never; + query?: never; + url: '/foo'; +}; + +export type GetFooResponses = { + /** + * OK + */ + 200: unknown; +}; + +export type PostFooData = { + body?: never; + path?: never; + query?: never; + url: '/foo'; +}; + +export type PostFooResponses = { + /** + * OK + */ + 200: unknown; +}; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/ref-deep/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/ref-deep/index.ts new file mode 100644 index 000000000..48dd9d2e2 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/ref-deep/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type { Bar, ClientOptions, Foo, GetFooData, GetFooResponse, GetFooResponses, PostFooData, PostFooResponse, PostFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/ref-deep/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/ref-deep/types.gen.ts new file mode 100644 index 000000000..3a358d59f --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/ref-deep/types.gen.ts @@ -0,0 +1,64 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseUrl: `${string}://${string}` | (string & {}); +}; + +export type Foo = { + foo?: Array<{ + baz?: string; + }>; + bar?: Array<{ + baz?: string; + }>; +}; + +export type Bar = { + foo?: Array<{ + baz?: string; + }>; + bar?: Array<{ + baz?: string; + }>; +}; + +export type GetFooData = { + body?: never; + path?: never; + query?: never; + url: '/foo'; +}; + +export type GetFooResponses = { + /** + * OK + */ + 200: Array<{ + foo?: number; + bar?: string; + }>; +}; + +export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; + +export type PostFooData = { + body?: never; + path?: never; + query?: never; + url: '/foo'; +}; + +export type PostFooResponses = { + /** + * OK + */ + 200: { + foo?: { + foo?: number; + bar?: string; + }; + bar?: string; + }; +}; + +export type PostFooResponse = PostFooResponses[keyof PostFooResponses]; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/ref-deep/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/ref-deep/index.ts new file mode 100644 index 000000000..48dd9d2e2 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/ref-deep/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type { Bar, ClientOptions, Foo, GetFooData, GetFooResponse, GetFooResponses, PostFooData, PostFooResponse, PostFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/ref-deep/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/ref-deep/types.gen.ts new file mode 100644 index 000000000..3a358d59f --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/ref-deep/types.gen.ts @@ -0,0 +1,64 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseUrl: `${string}://${string}` | (string & {}); +}; + +export type Foo = { + foo?: Array<{ + baz?: string; + }>; + bar?: Array<{ + baz?: string; + }>; +}; + +export type Bar = { + foo?: Array<{ + baz?: string; + }>; + bar?: Array<{ + baz?: string; + }>; +}; + +export type GetFooData = { + body?: never; + path?: never; + query?: never; + url: '/foo'; +}; + +export type GetFooResponses = { + /** + * OK + */ + 200: Array<{ + foo?: number; + bar?: string; + }>; +}; + +export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; + +export type PostFooData = { + body?: never; + path?: never; + query?: never; + url: '/foo'; +}; + +export type PostFooResponses = { + /** + * OK + */ + 200: { + foo?: { + foo?: number; + bar?: string; + }; + bar?: string; + }; +}; + +export type PostFooResponse = PostFooResponses[keyof PostFooResponses]; diff --git a/specs/2.0.x/ref-deep.yaml b/specs/2.0.x/ref-deep.yaml new file mode 100644 index 000000000..aa307fcaf --- /dev/null +++ b/specs/2.0.x/ref-deep.yaml @@ -0,0 +1,63 @@ +swagger: '2.0' +info: + title: OpenAPI 2.0 ref deep example + version: '1' +paths: + /foo: + get: + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + type: object + properties: + foo: + type: integer + bar: + type: string + post: + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + foo: + $ref: '#/paths/~1foo/get/responses/200/content/application~1json/schema/items' + bar: + type: string +definitions: + Foo: + type: object + properties: + foo: + type: array + items: + type: object + properties: + baz: + type: string + bar: + type: array + items: + type: object + properties: + baz: + type: string + Bar: + type: object + properties: + foo: + type: array + items: + $ref: '#/definitions/Foo/properties/foo/items' + bar: + type: array + items: + $ref: '#/definitions/Foo/properties/bar/items' diff --git a/specs/3.0.x/broken.yaml b/specs/3.0.x/broken.yaml deleted file mode 100644 index ddaba06af..000000000 --- a/specs/3.0.x/broken.yaml +++ /dev/null @@ -1,35 +0,0 @@ -openapi: 3.0.1 -info: - title: foo - description: foo - version: '1' -components: - schemas: - Foo: - type: object - properties: - foo: - type: array - items: - type: object - properties: - baz: - type: string - bar: - type: array - items: - type: object - properties: - baz: - type: string - Bar: - type: object - properties: - foo: - type: array - items: - $ref: '#/components/schemas/Foo/properties/foo/items' - bar: - type: array - items: - $ref: '#/components/schemas/Foo/properties/bar/items' diff --git a/specs/3.0.x/deep-path-ref.yaml b/specs/3.0.x/deep-path-ref.yaml deleted file mode 100644 index 7c05dc11a..000000000 --- a/specs/3.0.x/deep-path-ref.yaml +++ /dev/null @@ -1,39 +0,0 @@ -openapi: 3.0.1 -info: - title: Deep Path Ref Test - description: Test case for deep path references in #/paths/... - version: '1' -paths: - /users: - get: - operationId: getUsers - responses: - '200': - description: Success - content: - application/json: - schema: - type: array - items: - type: object - properties: - id: - type: integer - name: - type: string - /posts: - get: - operationId: getPosts - responses: - '200': - description: Success - content: - application/json: - schema: - type: object - properties: - author: - # Deep path reference to /users response schema item - $ref: '#/paths/~1users/get/responses/200/content/application~1json/schema/items' - title: - type: string diff --git a/specs/3.0.x/ref-deep.yaml b/specs/3.0.x/ref-deep.yaml new file mode 100644 index 000000000..ba01b913e --- /dev/null +++ b/specs/3.0.x/ref-deep.yaml @@ -0,0 +1,64 @@ +openapi: 3.0.0 +info: + title: OpenAPI 3.0.0 ref deep example + version: '1' +paths: + /foo: + get: + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + type: object + properties: + foo: + type: integer + bar: + type: string + post: + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + foo: + $ref: '#/paths/~1foo/get/responses/200/content/application~1json/schema/items' + bar: + type: string +components: + schemas: + Foo: + type: object + properties: + foo: + type: array + items: + type: object + properties: + baz: + type: string + bar: + type: array + items: + type: object + properties: + baz: + type: string + Bar: + type: object + properties: + foo: + type: array + items: + $ref: '#/components/schemas/Foo/properties/foo/items' + bar: + type: array + items: + $ref: '#/components/schemas/Foo/properties/bar/items' diff --git a/specs/3.1.x/ref-deep.yaml b/specs/3.1.x/ref-deep.yaml new file mode 100644 index 000000000..8429ec715 --- /dev/null +++ b/specs/3.1.x/ref-deep.yaml @@ -0,0 +1,64 @@ +openapi: 3.1.1 +info: + title: OpenAPI 3.1.1 ref deep example + version: '1' +paths: + /foo: + get: + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + type: object + properties: + foo: + type: integer + bar: + type: string + post: + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + foo: + $ref: '#/paths/~1foo/get/responses/200/content/application~1json/schema/items' + bar: + type: string +components: + schemas: + Foo: + type: object + properties: + foo: + type: array + items: + type: object + properties: + baz: + type: string + bar: + type: array + items: + type: object + properties: + baz: + type: string + Bar: + type: object + properties: + foo: + type: array + items: + $ref: '#/components/schemas/Foo/properties/foo/items' + bar: + type: array + items: + $ref: '#/components/schemas/Foo/properties/bar/items'