Repository: Redocly/redocly-cli
Pull request #1906 (2025-02-13 16:59:24)

fix: make the no-invalid-media-type-examples rule fail gracefully when the example is not resolved from a ref


## What/Why/How?

Fixed an issue where the `no-invalid-media-type-examples` rule crashed instead of reporting an error when it failed to resolve an example from a $ref.

## Reference

Fixes https://github.com/Redocly/redocly-cli/issues/1905

## Testing

## Screenshots (optional)

## Check yourself

- [ ] Code changed? - Tested with redoc/reference-docs/workflows (internal)
- [x] All new/updated code is covered with tests
- [ ] New package installed? - Tested in different environments (browser/node)

## Security

- [x] Security impact of change has been considered
- [x] Code follows company security practices and guidelines


changeset-bot[bot]: ###  🦋  Changeset detected

Latest commit: 03484dbc606d75e720e998a8a6109449d85aed77

**The changes in this PR will be included in the next version bump.**

<details><summary>This PR includes changesets to release 2 packages</summary>

  | Name                  | Type  |
| --------------------- | ----- |
| @redocly/openapi-core | Patch |
| @redocly/cli          | Patch |

</details>

Not sure what this means? [Click here  to learn what changesets are](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add another changeset to this PR](https://github.com/Redocly/redocly-cli/new/fix/no-invalid-media-type-examples-crashing?filename=.changeset/kind-dolls-double.md&value=---%0A%22%40redocly%2Fopenapi-core%22%3A%20patch%0A---%0A%0Afix%3A%20make%20the%20no-invalid-media-type-examples%20rule%20fail%20gracefully%20when%20the%20example%20is%20not%20resolved%20from%20a%20ref%0A)


github-actions[bot]: | Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|:---|---:|---:|---:|---:|
| `redocly lint packages/core/src/benchmark/benches/rebilly.yaml` | 950.7 ± 10.1 | 928.1 | 966.3 | 1.00 |
| `redocly-next lint packages/core/src/benchmark/benches/rebilly.yaml` | 959.6 ± 16.0 | 938.4 | 988.7 | 1.01 ± 0.02 |

<!-- thollander/actions-comment-pull-request "latest-vs-next-comparison" -->
github-actions[bot]: <!-- jest coverage report action for options with hash 3339ae53a38c44382c0fb4491bdb282d -->

## Coverage report 



| <div title="Status of coverage:&#10; 🟢 - ok&#10; 🟡 - slightly more than threshold&#10; 🔴 - under the threshold">St.<sup>:grey_question:</sup></div> | Category   | Percentage | Covered / Total |
| :----------------------------------------------------------------------------------------------------------------------------------------------------: | :--------- | :--------- | :-------------: |
|                                                                           🟡                                                                           | Statements | 78.54%     |    5062/6445    |
|                                                                           🟡                                                                           | Branches   | 67.24%     |    2065/3071    |
|                                                                           🟡                                                                           | Functions  | 73.2%      |     836/1142    |
|                                                                           🟡                                                                           | Lines      | 78.82%     |    4775/6058    |


## Test suite run success
840 tests passing in 121 suites.

<p align="right">Report generated by <a href="https://github.com/ArtiomTr/jest-coverage-report-action">🧪jest coverage report action</a> from 03484dbc606d75e720e998a8a6109449d85aed77</p>


Patch:
diff --git a/.changeset/violet-guests-suffer.md b/.changeset/violet-guests-suffer.md
new file mode 100644
index 00000000..0fed20f3
--- /dev/null
+++ b/.changeset/violet-guests-suffer.md
@@ -0,0 +1,6 @@
+---
+"@redocly/openapi-core": patch
+"@redocly/cli": patch
+---
+
+Fixed an issue where the `no-invalid-media-type-examples` rule crashed instead of reporting an error when it failed to resolve an example from a $ref.
diff --git a/packages/core/src/rules/oas3/no-invalid-media-type-examples.ts b/packages/core/src/rules/oas3/no-invalid-media-type-examples.ts
index 951dde7a..b9dc4f42 100644
--- a/packages/core/src/rules/oas3/no-invalid-media-type-examples.ts
+++ b/packages/core/src/rules/oas3/no-invalid-media-type-examples.ts
@@ -37,7 +37,7 @@ export const ValidContentExamples: Oas3Rule = (opts) => {
             location = isMultiple ? resolved.location.child('value') : resolved.location;
             example = resolved.node;
           }
-          if (isMultiple && typeof example.value === 'undefined') {
+          if (isMultiple && typeof example?.value === 'undefined') {
             return;
           }
           validateExample(


Test patch:
diff --git a/packages/core/src/rules/oas3/__tests__/no-invalid-media-type-examples.test.ts b/packages/core/src/rules/oas3/__tests__/no-invalid-media-type-examples.test.ts
index 1020916b..7f12a942 100644
--- a/packages/core/src/rules/oas3/__tests__/no-invalid-media-type-examples.test.ts
+++ b/packages/core/src/rules/oas3/__tests__/no-invalid-media-type-examples.test.ts
@@ -677,4 +677,54 @@ describe('no-invalid-media-type-examples', () => {
       ]
     `);
   });
+
+  it('should first report on unresolved ref rather than fail on validation', async () => {
+    const document = parseYamlToDocument(
+      outdent`
+        openapi: 3.1.0
+        paths:
+          /groups:
+            get:
+              responses:
+                '200':
+                  content:
+                    application/json:
+                      schema:
+                        type: string
+                      examples:
+                        example1:
+                          $ref: '#/components/examples/NotExisting'
+      `,
+      'foobar.yaml'
+    );
+
+    const results = await lintDocument({
+      externalRefResolver: new BaseResolver(),
+      document,
+      config: await makeConfig({
+        rules: {
+          'no-invalid-media-type-examples': 'warn',
+          'no-unresolved-refs': 'error',
+        },
+      }),
+    });
+
+    expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
+      [
+        {
+          "location": [
+            {
+              "pointer": "#/paths/~1groups/get/responses/200/content/application~1json/examples/example1",
+              "reportOnKey": false,
+              "source": "foobar.yaml",
+            },
+          ],
+          "message": "Can't resolve $ref",
+          "ruleId": "no-unresolved-refs",
+          "severity": "error",
+          "suggest": [],
+        },
+      ]
+    `);
+  });
 });