diff --git a/packages/downgrader/src/shared.test.ts b/packages/downgrader/src/shared.test.ts index 38a6da2..20de578 100644 --- a/packages/downgrader/src/shared.test.ts +++ b/packages/downgrader/src/shared.test.ts @@ -618,6 +618,13 @@ describe('downgrade', () => { }) }) + it('inlines a reference whose target is itself an external reference', () => { + expect(convertDocument({ + items: [{ $ref: '#/removed/a' }], + removed: { a: { $ref: 'other.json#/a' } }, + }).out).toEqual({ items: [{ $ref: 'other.json#/a' }] }) + }) + it('leaves missing, external, anchor, and malformed references as written', () => { const items = [{ $ref: '#/missing' }, { $ref: 'other.json#/a' }, { $ref: '#anchor' }, { $ref: '#/%E0%A4%A' }] expect(convertDocument({ items }).out).toEqual({ items }) @@ -669,9 +676,11 @@ describe('downgrade', () => { }) }) - it('keeps a loop of aliases as written', () => { + it('keeps a loop of aliases as written, even in a removed part', () => { + const items = [{ $ref: '#/named/a' }, { $ref: '#/removed/a' }] const named = { a: { $ref: '#/named/b' }, b: { $ref: '#/named/a' } } - expect(convertDocument({ items: [{ $ref: '#/named/a' }], named }).out).toEqual({ items: [{ $ref: '#/named/a' }], named }) + const removed = { a: { $ref: '#/removed/b' }, b: { $ref: '#/removed/a' } } + expect(convertDocument({ items, named, removed }, ['#/removed/']).out).toEqual({ items, named }) }) it('removes references to removed targets, cascading through aliases', () => { diff --git a/packages/downgrader/src/shared.ts b/packages/downgrader/src/shared.ts index 81767bc..ba72cf2 100644 --- a/packages/downgrader/src/shared.ts +++ b/packages/downgrader/src/shared.ts @@ -417,9 +417,8 @@ export function downgrade(root: unknown, convert: Convert, removed: readonly str return end } const isInlinable = (ref: string): boolean => { - const end = aliasEnd(ref) - const target = end === undefined ? undefined : resolveRef(end) - return isRecord(target) || typeof target === 'boolean' + const target = resolveRef(ref) + return (isRecord(target) || typeof target === 'boolean') && aliasEnd(ref) !== undefined } const dangling = new Set() const isRemovedPart = (ref: string): boolean => removed.some(prefix => ref.startsWith(prefix)) diff --git a/packages/downgrader/src/v3.1-to-v3.0.test.ts b/packages/downgrader/src/v3.1-to-v3.0.test.ts index 0d11cce..37ea2ca 100644 --- a/packages/downgrader/src/v3.1-to-v3.0.test.ts +++ b/packages/downgrader/src/v3.1-to-v3.0.test.ts @@ -202,6 +202,15 @@ describe('downgradeSpecV31ToV30', () => { ).toEqual({ '/a': { ...inlined, description: 'alias', summary: 'Own' } }) }) + it('inlines an entry that references an external file', () => { + expect( + convertWithPathItems( + { '/a': { $ref: '#/components/pathItems/External', summary: 'Own' } }, + { External: { $ref: './paths/a.yaml' } }, + ).paths, + ).toEqual({ '/a': { $ref: './paths/a.yaml', summary: 'Own' } }) + }) + it('inlines references inside callbacks', () => { expect( convertWithPathItems( @@ -2214,6 +2223,13 @@ describe('downgradeSchemaV31ToV30', () => { expect(convertSchema({ $defs: { a: { type: 'string' } }, items: { $ref: '#/$defs/a' }, type: 'array' })).toEqual({ items: { type: 'string' }, type: 'array' }) }) + it('inlines $refs into $defs entries that reference an external file', () => { + expect(convertSchema({ + $defs: { pet: { $ref: './schemas/pet.yaml' } }, + properties: { pet: { $ref: '#/$defs/pet' } }, + })).toEqual({ properties: { pet: { $ref: './schemas/pet.yaml' } } }) + }) + it('inlines a $ref to items removed beside prefixItems instead of the items placeholder', () => { expect(convertSchema({ properties: { diff --git a/packages/downgrader/src/v3.2-to-v3.1.test.ts b/packages/downgrader/src/v3.2-to-v3.1.test.ts index 12cdafc..6f8e7bd 100644 --- a/packages/downgrader/src/v3.2-to-v3.1.test.ts +++ b/packages/downgrader/src/v3.2-to-v3.1.test.ts @@ -1621,8 +1621,9 @@ describe('downgradeSpecV32ToV31', () => { const result = convertSpec({ components: { parameters: { + External: { $ref: '#/paths/~1a/get/parameters/1' }, Kept: { $ref: '#/paths/~1b/get/parameters/0' }, - Shifted: { $ref: '#/paths/~1a/get/parameters/1' }, + Shifted: { $ref: '#/paths/~1a/get/parameters/2' }, }, }, paths: { @@ -1630,6 +1631,7 @@ describe('downgradeSpecV32ToV31', () => { get: { parameters: [ { in: 'querystring', name: 'qs' }, + { $ref: './parameters/limit.yaml' }, { in: 'query', name: 'b' }, ], responses: {}, @@ -1640,11 +1642,13 @@ describe('downgradeSpecV32ToV31', () => { }) expect(result.components).toEqual({ parameters: { + External: { $ref: './parameters/limit.yaml' }, Kept: { $ref: '#/paths/~1b/get/parameters/0' }, Shifted: { in: 'query', name: 'b' }, }, }) expect(dig(result, 'paths', '/a', 'get', 'parameters')).toEqual([ + { $ref: './parameters/limit.yaml' }, { in: 'query', name: 'b' }, ]) })