Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adds useSchemaTitleAsRef in the bundler #1490

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/five-snails-divide.md
@@ -0,0 +1,5 @@
---
"@redocly/openapi-core": minor
---

adds useSchemaTitleAsRef in the bundler which uses the schema title as ref instead of the file name
30 changes: 30 additions & 0 deletions packages/core/src/__tests__/__snapshots__/bundle.test.ts.snap
Expand Up @@ -233,6 +233,36 @@ components:

`;

exports[`bundle should bundle external refs and use schema title if useSchemaTitleAsRef is true 1`] = `
openapi: 3.1.0
paths:
/football/match:
get:
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/FootballMatch'
/basketball/match:
get:
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/BasketballMatch'
components:
schemas:
FootballMatch:
title: FootballMatch
type: object
BasketballMatch:
title: BasketballMatch
type: object

`;

exports[`bundle should bundle external refs and warn for conflicting names 1`] = `
openapi: 3.0.0
paths:
Expand Down
10 changes: 10 additions & 0 deletions packages/core/src/__tests__/bundle.test.ts
Expand Up @@ -74,6 +74,16 @@ describe('bundle', () => {
expect(res.parsed).toMatchSnapshot();
});

it('should bundle external refs and use schema title if useSchemaTitleAsRef is true', async () => {
const { bundle: res, problems } = await bundle({
config: new Config({} as ResolvedConfig),
ref: path.join(__dirname, 'fixtures/refs/openapi-with-external-refs-using-title-as-ref.yaml'),
useSchemaTitleAsRef: true,
});
expect(problems).toHaveLength(0);
expect(res.parsed).toMatchSnapshot();
});

it('should dereferenced correctly when used with dereference', async () => {
const { bundle: res, problems } = await bundleDocument({
externalRefResolver: new BaseResolver(),
Expand Down
@@ -0,0 +1,2 @@
title: BasketballMatch
type: object
@@ -0,0 +1,2 @@
title: FootballMatch
type: object
@@ -0,0 +1,18 @@
openapi: 3.1.0
paths:
/football/match:
get:
responses:
200:
content:
application/json:
schema:
$ref: ./football/match.yaml
/basketball/match:
get:
responses:
200:
content:
application/json:
schema:
$ref: ./basketball/match.yaml
32 changes: 22 additions & 10 deletions packages/core/src/bundle.ts
Expand Up @@ -41,6 +41,7 @@ export type BundleOptions = {
skipRedoclyRegistryRefs?: boolean;
removeUnusedComponents?: boolean;
keepUrlRefs?: boolean;
useSchemaTitleAsRef?: boolean;
};

export async function bundleConfig(document: Document, resolvedRefMap: ResolvedRefMap) {
Expand Down Expand Up @@ -149,6 +150,7 @@ export async function bundleDocument(opts: {
skipRedoclyRegistryRefs?: boolean;
removeUnusedComponents?: boolean;
keepUrlRefs?: boolean;
useSchemaTitleAsRef?: boolean;
}): Promise<BundleResult> {
const {
document,
Expand All @@ -159,6 +161,7 @@ export async function bundleDocument(opts: {
skipRedoclyRegistryRefs = false,
removeUnusedComponents = false,
keepUrlRefs = false,
useSchemaTitleAsRef = false,
} = opts;
const specVersion = detectSpec(document.parsed);
const specMajorVersion = getMajorSpecVersion(specVersion);
Expand Down Expand Up @@ -222,7 +225,8 @@ export async function bundleDocument(opts: {
skipRedoclyRegistryRefs,
document,
resolvedRefMap,
keepUrlRefs
keepUrlRefs,
useSchemaTitleAsRef
),
},
...decorators,
Expand Down Expand Up @@ -316,7 +320,8 @@ function makeBundleVisitor(
skipRedoclyRegistryRefs: boolean,
rootDocument: Document,
resolvedRefMap: ResolvedRefMap,
keepUrlRefs: boolean
keepUrlRefs: boolean,
useSchemaTitleAsRef: boolean
) {
let components: Record<string, Record<string, any>>;
let rootLocation: Location;
Expand Down Expand Up @@ -351,10 +356,10 @@ function makeBundleVisitor(
replaceRef(node, resolved, ctx);
} else {
if (dereference) {
saveComponent(componentType, resolved, ctx);
saveComponent(componentType, resolved, ctx, useSchemaTitleAsRef);
replaceRef(node, resolved, ctx);
} else {
node.$ref = saveComponent(componentType, resolved, ctx);
node.$ref = saveComponent(componentType, resolved, ctx, useSchemaTitleAsRef);
resolveBundledComponent(node, resolved, ctx);
}
}
Expand Down Expand Up @@ -385,9 +390,9 @@ function makeBundleVisitor(

const componentType = mapTypeToComponent('Schema', version)!;
if (dereference) {
saveComponent(componentType, resolved, ctx);
saveComponent(componentType, resolved, ctx, useSchemaTitleAsRef);
} else {
mapping[name] = saveComponent(componentType, resolved, ctx);
mapping[name] = saveComponent(componentType, resolved, ctx, useSchemaTitleAsRef);
}
}
},
Expand All @@ -408,10 +413,11 @@ function makeBundleVisitor(
function saveComponent(
componentType: string,
target: { node: any; location: Location },
ctx: UserContext
ctx: UserContext,
useSchemaTitleAsRef: boolean
) {
components[componentType] = components[componentType] || {};
const name = getComponentName(target, componentType, ctx);
const name = getComponentName(target, componentType, ctx, useSchemaTitleAsRef);
components[componentType][name] = target.node;
if (version === SpecMajorVersion.OAS3) {
return `#/components/${componentType}/${name}`;
Expand Down Expand Up @@ -439,7 +445,8 @@ function makeBundleVisitor(
function getComponentName(
target: { node: any; location: Location },
componentType: string,
ctx: UserContext
ctx: UserContext,
useSchemaTitleAsRef: boolean
) {
const [fileRef, pointer] = [target.location.source.absoluteRef, target.location.pointer];
const componentsGroup = components[componentType];
Expand All @@ -458,7 +465,12 @@ function makeBundleVisitor(
}
}

name = refBaseName(fileRef) + (name ? `_${name}` : '');
if (useSchemaTitleAsRef && typeof target.node.title === 'string') {
name = target.node.title;
} else {
name = refBaseName(fileRef) + (name ? `_${name}` : '');
}

if (!componentsGroup[name] || isEqualOrEqualRef(componentsGroup[name], target, ctx)) {
return name;
}
Expand Down