Repository: Redocly/redocly-cli
Pull request #1641 (2024-07-21 01:51:31)

Treat `dependentSchemas` as a map not array.
## What/Why/How?

When validating an OpenAPI 3.1 spec that utilizes `dependentSchemas`, `redocly-cli` emits an error:

```json
    {
      "ruleId": "spec",
      "severity": "error",
      "message": "Expected type `SchemaList` (array) but got `object`",
      "suggest": [],
      "location": [
        {
          "source": {
            "ref": "https://raw.githubusercontent.com/json-api/json-api/a2034598b22daf77322b9123c707165ef3ead3ea/schemas/1.0/schema.json"
          },
          "pointer": "#/dependentSchemas",
          "reportOnKey": false
        }
      ]
    }
```

which led me to discover that `dependentSchemas` was configured to be an array, but is in fact [a map](https://json-schema.org/draft/2020-12/json-schema-core#section-10.2.2.4).

https://github.com/Redocly/redocly-cli/blob/368c34fc5faa8e9e920a1c003b19350cee47224e/packages/core/src/types/oas3_1.ts#L136

The line in question dates to the initial implementation of 3.1 support so I imagine this was either incorrect from the beginning and didn't have test coverage, or changed in the OpenAPI spec since then.

## Reference

https://json-schema.org/draft/2020-12/json-schema-core#section-10.2.2.4

## Testing

Test coverage includes a failing test for a `dependentSchemas` property that is actually an array.

## Check yourself

- [x] 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: 93c65ce842a8386be0ccce36b8214833b2b7e739

**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 | Minor |
| @redocly/cli          | Minor |

</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/bradjones1/redocly-cli/new/dependentSchemas-map?filename=.changeset/nine-socks-film.md&value=---%0A%22%40redocly%2Fopenapi-core%22%3A%20patch%0A---%0A%0ATreat%20%60dependentSchemas%60%20as%20a%20map%20not%20array.%0A)


tatomyr: Thank you @bradjones1! Will merge your changes soon. 

Patch:
diff --git a/.changeset/five-cougars-arrive.md b/.changeset/five-cougars-arrive.md
new file mode 100644
index 00000000..b5967e7e
--- /dev/null
+++ b/.changeset/five-cougars-arrive.md
@@ -0,0 +1,7 @@
+---
+"@redocly/openapi-core": patch
+"@redocly/cli": patch
+---
+
+Fixed an issue in the OpenAPI `spec` rule where `dependentSchemas` was parsed as an array.
+It is now correctly parsed as a map.
diff --git a/packages/core/src/types/oas3_1.ts b/packages/core/src/types/oas3_1.ts
index 4b10e2e7..3eb5000a 100755
--- a/packages/core/src/types/oas3_1.ts
+++ b/packages/core/src/types/oas3_1.ts
@@ -133,7 +133,7 @@ const Schema: NodeType = {
     if: 'Schema',
     then: 'Schema',
     else: 'Schema',
-    dependentSchemas: listOf('Schema'),
+    dependentSchemas: mapOf('Schema'),
     dependentRequired: 'DependentRequired',
     prefixItems: listOf('Schema'),
     contains: 'Schema',


Test patch:
diff --git a/packages/core/src/rules/common/__tests__/spec.test.ts b/packages/core/src/rules/common/__tests__/spec.test.ts
index 4c45e7f0..ee35721d 100644
--- a/packages/core/src/rules/common/__tests__/spec.test.ts
+++ b/packages/core/src/rules/common/__tests__/spec.test.ts
@@ -607,4 +607,51 @@ describe('Oas3.1 spec', () => {
       ]
     `);
   });
+
+  it('should flag invalid dependentSchemas', async () => {
+    const document = parseYamlToDocument(
+      outdent`
+      openapi: 3.1.0
+      info:
+        version: 1.0.0
+        title: Example.com
+        description: info,
+        license:
+          name: Apache 2.0
+          url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
+      components:
+        schemas:
+          withInvalidDependentSchemas:
+            dependentSchemas:
+              - invalid1
+              - invalid2
+      `,
+      'foobar.yaml'
+    );
+
+    const results = await lintDocument({
+      externalRefResolver: new BaseResolver(),
+      document,
+      config: await makeConfig({ spec: 'error' }),
+    });
+
+    expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
+      [
+        {
+          "from": undefined,
+          "location": [
+            {
+              "pointer": "#/components/schemas/withInvalidDependentSchemas/dependentSchemas",
+              "reportOnKey": false,
+              "source": "foobar.yaml",
+            },
+          ],
+          "message": "Expected type \`SchemaMap\` (object) but got \`array\`",
+          "ruleId": "spec",
+          "severity": "error",
+          "suggest": [],
+        },
+      ]
+    `);
+  });
 });