Skip to content

Commit

Permalink
fix: bundle externalValue with relative reference in examples object (#…
Browse files Browse the repository at this point in the history
…1747)


---------
Co-authored-by: Jacek Łękawa <[email protected]>
  • Loading branch information
AlexVarchuk authored Oct 3, 2024
1 parent 1f0ca52 commit 67ea331
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 1 deletion.
6 changes: 6 additions & 0 deletions .changeset/little-pears-sniff.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@redocly/openapi-core": patch
"@redocly/cli": patch
---

Fixed an issue where the bundle command did not resolve links in `externalValue`.
4 changes: 4 additions & 0 deletions __tests__/bundle/bundle-external-value/external-value.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"foo": "bar",
"key": "value"
}
8 changes: 8 additions & 0 deletions __tests__/bundle/bundle-external-value/redocly.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apis:
first:
root: ./test-success.yaml
second:
root: ./test-wrong-examples.yaml

extends:
- recommended
59 changes: 59 additions & 0 deletions __tests__/bundle/bundle-external-value/snapshot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`E2E bundle bundle-external-value 1`] = `
openapi: 3.1.0
info:
version: 1.0.0
title: Example.com
termsOfService: https://example.com/terms/
contact:
email: [email protected]
url: http://example.com/contact
license:
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
description: OpenAPI description with external example
security: []
paths:
/:
post:
summary: Test request externalValue with relative reference in examples
requestBody:
content:
application/xml:
schema:
type: object
examples:
test-resolved:
summary: Example should resolved to value
value:
foo: bar
key: value
test-no-resolved:
summary: Example shouldn't be resolved to value
value:
type: object
externalValue: ./external-value.json
components: {}
bundling ./test-success.yaml...
📦 Created a bundle for ./test-success.yaml at stdout <test>ms.
bundling ./test-wrong-examples.yaml...
[1] test-wrong-examples.yaml:27:17 at #/paths/~1/post/requestBody/content/application~1xml/examples/test-wrong-ref
Can't resolve $ref: ENOENT: no such file or directory './__tests__/bundle/bundle-external-value/external-value-bad-path.json'
25 | examples:
26 | test-wrong-ref:
27 | summary: Example shouldn't resolved to value
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
28 | externalValue: './external-value-bad-path.json'
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29 |
Error was generated by the bundler rule.
❌ Errors encountered while bundling ./test-wrong-examples.yaml: bundle not created (use --force to ignore errors).
`;
33 changes: 33 additions & 0 deletions __tests__/bundle/bundle-external-value/test-success.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
openapi: 3.1.0
security: []
info:
version: 1.0.0
title: Example.com
termsOfService: https://example.com/terms/
contact:
email: [email protected]
url: http://example.com/contact
license:
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
description: OpenAPI description with external example
components: {}

paths:
/:
post:
summary: Test request externalValue with relative reference in examples
requestBody:
content:
application/xml:
schema:
type: object
examples:
test-resolved:
summary: Example should resolved to value
externalValue: './external-value.json'
test-no-resolved:
summary: Example shouldn't be resolved to value
value:
type: object
externalValue: './external-value.json'
28 changes: 28 additions & 0 deletions __tests__/bundle/bundle-external-value/test-wrong-examples.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
openapi: 3.1.0
security: []
info:
version: 1.0.0
title: Example.com
termsOfService: https://example.com/terms/
contact:
email: [email protected]
url: http://example.com/contact
license:
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
description: OpenAPI description with external example
components: {}

paths:
/:
post:
summary: Test request externalValue with relative reference in examples
requestBody:
content:
application/xml:
schema:
type: object
examples:
test-wrong-ref:
summary: Example shouldn't resolved to value
externalValue: './external-value-bad-path.json'
19 changes: 19 additions & 0 deletions packages/core/src/bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,25 @@ function makeBundleVisitor(
}
},
},
Example: {
leave(node: any, ctx: UserContext) {
if (node.externalValue && node.value === undefined) {
const resolved = ctx.resolve({ $ref: node.externalValue });

if (!resolved.location || resolved.node === undefined) {
reportUnresolvedRef(resolved, ctx.report, ctx.location);
return;
}

if (keepUrlRefs && isAbsoluteUrl(node.externalValue)) {
return;
}

node.value = ctx.resolve({ $ref: node.externalValue }).node;
delete node.externalValue;
}
},
},
Root: {
enter(root: any, ctx: any) {
rootLocation = ctx.location;
Expand Down
22 changes: 22 additions & 0 deletions packages/core/src/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,28 @@ export async function resolveDocument(opts: {
});
resolvePromises.push(promise);
}

// handle example.externalValue as reference
if (node.externalValue) {
const promise = followRef(
rootNodeDocument,
{ $ref: node.externalValue },
{
prev: null,
node,
}
).then((resolvedRef) => {
if (resolvedRef.resolved) {
resolveRefsInParallel(
resolvedRef.node,
resolvedRef.document,
resolvedRef.nodePointer!,
type
);
}
});
resolvePromises.push(promise);
}
}

async function followRef(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
a: foo
b: 100
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,7 @@ describe('no-invalid-media-type-examples', () => {
type: number
examples:
first:
externalValue: "https://example.com/example.json"
externalValue: ./fixtures/external-value.yaml
`,
'foobar.yaml'
);
Expand Down

1 comment on commit 67ea331

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage report

St.
Category Percentage Covered / Total
🟡 Statements 78.56% 4993/6356
🟡 Branches 67.19% 2062/3069
🟡 Functions 72.98% 824/1129
🟡 Lines 78.85% 4711/5975

Test suite run success

809 tests passing in 121 suites.

Report generated by 🧪jest coverage report action from 67ea331

Please sign in to comment.