Repository: Redocly/redocly-cli (ts)

Issue:
dependentRequired is valid json schema but does not pass linting and prevents component from being available in UI.
**Describe the bug**

Property `dependentRequired` is not expected here is reported when running the linter. I would expect for an OpenAPI 3.1.0 spec for this to lint and be reflected in the UI generated as it seems to be part of the supported JSON Schema dialect.T

**To Reproduce**
Steps to reproduce the behavior:

1. Given this `redocly.yaml` file
```
# See https://redocly.com/docs/cli/configuration/ for more information.
extends:
  - recommended 
rules:
  no-unused-components: error
  no-server-example.com: off
  no-empty-servers: off
  security-defined: off
  info-license: off
  operation-4xx-response: off # https://phab.easypo.net/T72078 turn this back on when 4xx are added.
theme:
  openapi:
    htmlTemplate: ./docs/index.html
    theme:
      colors:
        primary:
          main: "#32329f"
    generateCodeSamples:
      languages:  # Array of language config objects; indicates in which languages to generate code samples.
        - lang: curl
```


2. And this OpenAPI file(s) which is using schema example from https://json-schema.org/understanding-json-schema/reference/conditionals#dependentRequired

```
openapi: 3.1.0
info:
  version: 1.0.0
  title: This is only a test.
  description: testing
paths:
  '/test':
    post:
      summary: test use of dependentRequired 
      operationId: test
      responses:
        "200":
          description: "OK"
          content:
            application/json:
              schema:
                type: object
                properties:
                  name:
                    type: string
                  credit_card:
                    type: number
                  billing_address:
                    type: string
                required:
                - name
                dependentRequired:
                  credit_card:
                  - billing_address

```

3. Run this command with these arguments... `redocly ...`
`redocly lint openapi.yaml

6. See error
```
❯ redocly lint openapi.yaml
(node:45032) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
validating openapi.yaml...
[1] openapi.yaml:27:17 at #/paths/~1test/post/responses/200/content/application~1json/schema/dependentRequired

Property `dependentRequired` is not expected here.

25 | required:
26 | - name
27 | dependentRequired:
28 |   credit_card:
29 |   - billing_address

Error was generated by the spec rule.


openapi.yaml: validated in 7ms

❌ Validation failed with 1 error.
run `redocly lint --generate-ignore-file` to add all problems to the ignore file.
```

**Expected behavior**

The lint should pass.

**Logs**

n/a

**OpenAPI description**

Included above.

**Redocly Version(s)**

1.12.2

**`Node.js` Version(s)**

21.6.2

**Additional context**

I have tried to double check that it's not just a formatting error but this looks to be correct according the the json schema doc and is not a linting error when running spectral


Pull request:
fix: add JSON Schema 2019-09+ validation keyword - dependentRequired
fixes #1558

## What/Why/How?
JSON Schema 2019-09 introduced a new validation keyword which applies to OpenAPI 3.1.x support of JSON Schema 2020-12. 

    [6.5.4. ](https://json-schema.org/draft/2020-12/json-schema-validation#section-6.5.4)[dependentRequired](https://json-schema.org/draft/2020-12/json-schema-validation#name-dependentrequired)
    The value of this keyword MUST be an object. Properties in this object, if any, MUST be arrays. Elements in each array, if any, MUST be strings, and MUST be unique.
    
    This keyword specifies properties that are required if a specific other property is present. Their requirement is dependent on the presence of the other property.
    
    Validation succeeds if, for each name that appears in both the instance and as a name within this keyword's value, every item in the corresponding array is also the name of a property in the instance.
    
    Omitting this keyword has the same behavior as an empty object.

## Reference

## Testing

## Screenshots (optional)

## Check yourself

- [ ] Code changed? - Tested with redoc/reference-docs/workflows (internal)
- [ ] 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

Patch:
diff --git a/.changeset/hungry-bears-do.md b/.changeset/hungry-bears-do.md
new file mode 100644
index 00000000..65328c1c
--- /dev/null
+++ b/.changeset/hungry-bears-do.md
@@ -0,0 +1,6 @@
+---
+"@redocly/openapi-core": patch
+"@redocly/cli": patch
+---
+
+Added JSON Schema draft 2019-09+ validation keyword - `dependentRequired`.
diff --git a/packages/core/src/types/oas3_1.ts b/packages/core/src/types/oas3_1.ts
index 920c98c3..9dbdc9f4 100755
--- a/packages/core/src/types/oas3_1.ts
+++ b/packages/core/src/types/oas3_1.ts
@@ -134,6 +134,7 @@ const Schema: NodeType = {
     then: 'Schema',
     else: 'Schema',
     dependentSchemas: listOf('Schema'),
+    dependentRequired: 'DependentRequired',
     prefixItems: listOf('Schema'),
     contains: 'Schema',
     minContains: { type: 'integer', minimum: 0 },
@@ -266,6 +267,11 @@ const SecurityScheme: NodeType = {
   extensionsPrefix: 'x-',
 };
 
+const DependentRequired: NodeType = {
+  properties: {},
+  additionalProperties: { type: 'array', items: { type: 'string' } },
+};
+
 export const Oas3_1Types: Record<Oas3_1NodeType, NodeType> = {
   ...Oas3Types,
   Info,
@@ -277,4 +283,5 @@ export const Oas3_1Types: Record<Oas3_1NodeType, NodeType> = {
   NamedPathItems: mapOf('PathItem'),
   SecurityScheme,
   Operation,
+  DependentRequired,
 };
diff --git a/packages/core/src/types/redocly-yaml.ts b/packages/core/src/types/redocly-yaml.ts
index 4f4cd995..260c9af5 100644
--- a/packages/core/src/types/redocly-yaml.ts
+++ b/packages/core/src/types/redocly-yaml.ts
@@ -220,6 +220,7 @@ const oas3_1NodeTypesList = [
   'NamedPathItems',
   'SecurityScheme',
   'Operation',
+  'DependentRequired',
 ] as const;
 
 export type Oas3_1NodeType = typeof oas3_1NodeTypesList[number];


Test patch:
diff --git a/__tests__/check-config/wrong-config-type-extensions-in-assertions/snapshot.js b/__tests__/check-config/wrong-config-type-extensions-in-assertions/snapshot.js
index 9791b003..0316180f 100644
--- a/__tests__/check-config/wrong-config-type-extensions-in-assertions/snapshot.js
+++ b/__tests__/check-config/wrong-config-type-extensions-in-assertions/snapshot.js
@@ -4,7 +4,7 @@ exports[`E2E check-config wrong config type extension in assertions 1`] = `
 
 [1] redocly.yaml:10:13 at #/rules/rule~1metadata-lifecycle/subject/type
 
-\`type\` can be one of the following only: "any", "Root", "Tag", "TagList", "TagGroups", "TagGroup", "ExternalDocs", "Example", "ExamplesMap", "EnumDescriptions", "SecurityRequirement", "SecurityRequirementList", "Info", "Contact", "License", "Logo", "Paths", "PathItem", "Parameter", "ParameterItems", "ParameterList", "Operation", "Examples", "Header", "Responses", "Response", "Schema", "Xml", "SchemaProperties", "NamedSchemas", "NamedResponses", "NamedParameters", "NamedSecuritySchemes", "SecurityScheme", "XCodeSample", "XCodeSampleList", "XServerList", "XServer", "Server", "ServerList", "ServerVariable", "ServerVariablesMap", "Callback", "CallbacksMap", "RequestBody", "MediaTypesMap", "MediaType", "Encoding", "EncodingMap", "HeadersMap", "Link", "DiscriminatorMapping", "Discriminator", "Components", "LinksMap", "NamedExamples", "NamedRequestBodies", "NamedHeaders", "NamedLinks", "NamedCallbacks", "ImplicitFlow", "PasswordFlow", "ClientCredentials", "AuthorizationCode", "OAuth2Flows", "XUsePkce", "WebhooksMap", "XMetaData", "NamedPathItems", "ServerMap", "HttpServerBinding", "HttpChannelBinding", "HttpMessageBinding", "HttpOperationBinding", "WsServerBinding", "WsChannelBinding", "WsMessageBinding", "WsOperationBinding", "KafkaServerBinding", "KafkaTopicConfiguration", "KafkaChannelBinding", "KafkaMessageBinding", "KafkaOperationBinding", "AnypointmqServerBinding", "AnypointmqChannelBinding", "AnypointmqMessageBinding", "AnypointmqOperationBinding", "AmqpServerBinding", "AmqpChannelBinding", "AmqpMessageBinding", "AmqpOperationBinding", "Amqp1ServerBinding", "Amqp1ChannelBinding", "Amqp1MessageBinding", "Amqp1OperationBinding", "MqttServerBindingLastWill", "MqttServerBinding", "MqttChannelBinding", "MqttMessageBinding", "MqttOperationBinding", "Mqtt5ServerBinding", "Mqtt5ChannelBinding", "Mqtt5MessageBinding", "Mqtt5OperationBinding", "NatsServerBinding", "NatsChannelBinding", "NatsMessageBinding", "NatsOperationBinding", "JmsServerBinding", "JmsChannelBinding", "JmsMessageBinding", "JmsOperationBinding", "SolaceServerBinding", "SolaceChannelBinding", "SolaceMessageBinding", "SolaceDestination", "SolaceOperationBinding", "StompServerBinding", "StompChannelBinding", "StompMessageBinding", "StompOperationBinding", "RedisServerBinding", "RedisChannelBinding", "RedisMessageBinding", "RedisOperationBinding", "MercureServerBinding", "MercureChannelBinding", "MercureMessageBinding", "MercureOperationBinding", "ServerBindings", "ChannelBindings", "ChannelMap", "Channel", "ParametersMap", "MessageExample", "NamedMessages", "NamedMessageTraits", "NamedOperationTraits", "NamedCorrelationIds", "NamedStreamHeaders", "SecuritySchemeFlows", "Message", "MessageBindings", "OperationBindings", "OperationTrait", "OperationTraitList", "MessageTrait", "MessageTraitList", "CorrelationId", "SpecExtension".
+\`type\` can be one of the following only: "any", "Root", "Tag", "TagList", "TagGroups", "TagGroup", "ExternalDocs", "Example", "ExamplesMap", "EnumDescriptions", "SecurityRequirement", "SecurityRequirementList", "Info", "Contact", "License", "Logo", "Paths", "PathItem", "Parameter", "ParameterItems", "ParameterList", "Operation", "Examples", "Header", "Responses", "Response", "Schema", "Xml", "SchemaProperties", "NamedSchemas", "NamedResponses", "NamedParameters", "NamedSecuritySchemes", "SecurityScheme", "XCodeSample", "XCodeSampleList", "XServerList", "XServer", "Server", "ServerList", "ServerVariable", "ServerVariablesMap", "Callback", "CallbacksMap", "RequestBody", "MediaTypesMap", "MediaType", "Encoding", "EncodingMap", "HeadersMap", "Link", "DiscriminatorMapping", "Discriminator", "Components", "LinksMap", "NamedExamples", "NamedRequestBodies", "NamedHeaders", "NamedLinks", "NamedCallbacks", "ImplicitFlow", "PasswordFlow", "ClientCredentials", "AuthorizationCode", "OAuth2Flows", "XUsePkce", "WebhooksMap", "XMetaData", "NamedPathItems", "DependentRequired", "ServerMap", "HttpServerBinding", "HttpChannelBinding", "HttpMessageBinding", "HttpOperationBinding", "WsServerBinding", "WsChannelBinding", "WsMessageBinding", "WsOperationBinding", "KafkaServerBinding", "KafkaTopicConfiguration", "KafkaChannelBinding", "KafkaMessageBinding", "KafkaOperationBinding", "AnypointmqServerBinding", "AnypointmqChannelBinding", "AnypointmqMessageBinding", "AnypointmqOperationBinding", "AmqpServerBinding", "AmqpChannelBinding", "AmqpMessageBinding", "AmqpOperationBinding", "Amqp1ServerBinding", "Amqp1ChannelBinding", "Amqp1MessageBinding", "Amqp1OperationBinding", "MqttServerBindingLastWill", "MqttServerBinding", "MqttChannelBinding", "MqttMessageBinding", "MqttOperationBinding", "Mqtt5ServerBinding", "Mqtt5ChannelBinding", "Mqtt5MessageBinding", "Mqtt5OperationBinding", "NatsServerBinding", "NatsChannelBinding", "NatsMessageBinding", "NatsOperationBinding", "JmsServerBinding", "JmsChannelBinding", "JmsMessageBinding", "JmsOperationBinding", "SolaceServerBinding", "SolaceChannelBinding", "SolaceMessageBinding", "SolaceDestination", "SolaceOperationBinding", "StompServerBinding", "StompChannelBinding", "StompMessageBinding", "StompOperationBinding", "RedisServerBinding", "RedisChannelBinding", "RedisMessageBinding", "RedisOperationBinding", "MercureServerBinding", "MercureChannelBinding", "MercureMessageBinding", "MercureOperationBinding", "ServerBindings", "ChannelBindings", "ChannelMap", "Channel", "ParametersMap", "MessageExample", "NamedMessages", "NamedMessageTraits", "NamedOperationTraits", "NamedCorrelationIds", "NamedStreamHeaders", "SecuritySchemeFlows", "Message", "MessageBindings", "OperationBindings", "OperationTrait", "OperationTraitList", "MessageTrait", "MessageTraitList", "CorrelationId", "SpecExtension".
 
  8 | rule/metadata-lifecycle:
  9 |   subject:
diff --git a/__tests__/lint-config/invalid-config-assertation-config-type/snapshot.js b/__tests__/lint-config/invalid-config-assertation-config-type/snapshot.js
index fbcfb50c..857e0346 100644
--- a/__tests__/lint-config/invalid-config-assertation-config-type/snapshot.js
+++ b/__tests__/lint-config/invalid-config-assertation-config-type/snapshot.js
@@ -6,7 +6,7 @@ exports[`E2E lint-config test with option: { dirName: 'invalid-config-assertatio
 The 'assert/' syntax in assert/path-item-mutually-required is deprecated. Update your configuration to use 'rule/' instead. Examples and more information: https://redocly.com/docs/cli/rules/configurable-rules/
 [1] .redocly.yaml:9:17 at #/rules/assert~1path-item-mutually-required/where/0/subject/type
 
-\`type\` can be one of the following only: "any", "Root", "Tag", "TagList", "TagGroups", "TagGroup", "ExternalDocs", "Example", "ExamplesMap", "EnumDescriptions", "SecurityRequirement", "SecurityRequirementList", "Info", "Contact", "License", "Logo", "Paths", "PathItem", "Parameter", "ParameterItems", "ParameterList", "Operation", "Examples", "Header", "Responses", "Response", "Schema", "Xml", "SchemaProperties", "NamedSchemas", "NamedResponses", "NamedParameters", "NamedSecuritySchemes", "SecurityScheme", "XCodeSample", "XCodeSampleList", "XServerList", "XServer", "Server", "ServerList", "ServerVariable", "ServerVariablesMap", "Callback", "CallbacksMap", "RequestBody", "MediaTypesMap", "MediaType", "Encoding", "EncodingMap", "HeadersMap", "Link", "DiscriminatorMapping", "Discriminator", "Components", "LinksMap", "NamedExamples", "NamedRequestBodies", "NamedHeaders", "NamedLinks", "NamedCallbacks", "ImplicitFlow", "PasswordFlow", "ClientCredentials", "AuthorizationCode", "OAuth2Flows", "XUsePkce", "WebhooksMap", "NamedPathItems", "ServerMap", "HttpServerBinding", "HttpChannelBinding", "HttpMessageBinding", "HttpOperationBinding", "WsServerBinding", "WsChannelBinding", "WsMessageBinding", "WsOperationBinding", "KafkaServerBinding", "KafkaTopicConfiguration", "KafkaChannelBinding", "KafkaMessageBinding", "KafkaOperationBinding", "AnypointmqServerBinding", "AnypointmqChannelBinding", "AnypointmqMessageBinding", "AnypointmqOperationBinding", "AmqpServerBinding", "AmqpChannelBinding", "AmqpMessageBinding", "AmqpOperationBinding", "Amqp1ServerBinding", "Amqp1ChannelBinding", "Amqp1MessageBinding", "Amqp1OperationBinding", "MqttServerBindingLastWill", "MqttServerBinding", "MqttChannelBinding", "MqttMessageBinding", "MqttOperationBinding", "Mqtt5ServerBinding", "Mqtt5ChannelBinding", "Mqtt5MessageBinding", "Mqtt5OperationBinding", "NatsServerBinding", "NatsChannelBinding", "NatsMessageBinding", "NatsOperationBinding", "JmsServerBinding", "JmsChannelBinding", "JmsMessageBinding", "JmsOperationBinding", "SolaceServerBinding", "SolaceChannelBinding", "SolaceMessageBinding", "SolaceDestination", "SolaceOperationBinding", "StompServerBinding", "StompChannelBinding", "StompMessageBinding", "StompOperationBinding", "RedisServerBinding", "RedisChannelBinding", "RedisMessageBinding", "RedisOperationBinding", "MercureServerBinding", "MercureChannelBinding", "MercureMessageBinding", "MercureOperationBinding", "ServerBindings", "ChannelBindings", "ChannelMap", "Channel", "ParametersMap", "MessageExample", "NamedMessages", "NamedMessageTraits", "NamedOperationTraits", "NamedCorrelationIds", "NamedStreamHeaders", "SecuritySchemeFlows", "Message", "MessageBindings", "OperationBindings", "OperationTrait", "OperationTraitList", "MessageTrait", "MessageTraitList", "CorrelationId", "SpecExtension".
+\`type\` can be one of the following only: "any", "Root", "Tag", "TagList", "TagGroups", "TagGroup", "ExternalDocs", "Example", "ExamplesMap", "EnumDescriptions", "SecurityRequirement", "SecurityRequirementList", "Info", "Contact", "License", "Logo", "Paths", "PathItem", "Parameter", "ParameterItems", "ParameterList", "Operation", "Examples", "Header", "Responses", "Response", "Schema", "Xml", "SchemaProperties", "NamedSchemas", "NamedResponses", "NamedParameters", "NamedSecuritySchemes", "SecurityScheme", "XCodeSample", "XCodeSampleList", "XServerList", "XServer", "Server", "ServerList", "ServerVariable", "ServerVariablesMap", "Callback", "CallbacksMap", "RequestBody", "MediaTypesMap", "MediaType", "Encoding", "EncodingMap", "HeadersMap", "Link", "DiscriminatorMapping", "Discriminator", "Components", "LinksMap", "NamedExamples", "NamedRequestBodies", "NamedHeaders", "NamedLinks", "NamedCallbacks", "ImplicitFlow", "PasswordFlow", "ClientCredentials", "AuthorizationCode", "OAuth2Flows", "XUsePkce", "WebhooksMap", "NamedPathItems", "DependentRequired", "ServerMap", "HttpServerBinding", "HttpChannelBinding", "HttpMessageBinding", "HttpOperationBinding", "WsServerBinding", "WsChannelBinding", "WsMessageBinding", "WsOperationBinding", "KafkaServerBinding", "KafkaTopicConfiguration", "KafkaChannelBinding", "KafkaMessageBinding", "KafkaOperationBinding", "AnypointmqServerBinding", "AnypointmqChannelBinding", "AnypointmqMessageBinding", "AnypointmqOperationBinding", "AmqpServerBinding", "AmqpChannelBinding", "AmqpMessageBinding", "AmqpOperationBinding", "Amqp1ServerBinding", "Amqp1ChannelBinding", "Amqp1MessageBinding", "Amqp1OperationBinding", "MqttServerBindingLastWill", "MqttServerBinding", "MqttChannelBinding", "MqttMessageBinding", "MqttOperationBinding", "Mqtt5ServerBinding", "Mqtt5ChannelBinding", "Mqtt5MessageBinding", "Mqtt5OperationBinding", "NatsServerBinding", "NatsChannelBinding", "NatsMessageBinding", "NatsOperationBinding", "JmsServerBinding", "JmsChannelBinding", "JmsMessageBinding", "JmsOperationBinding", "SolaceServerBinding", "SolaceChannelBinding", "SolaceMessageBinding", "SolaceDestination", "SolaceOperationBinding", "StompServerBinding", "StompChannelBinding", "StompMessageBinding", "StompOperationBinding", "RedisServerBinding", "RedisChannelBinding", "RedisMessageBinding", "RedisOperationBinding", "MercureServerBinding", "MercureChannelBinding", "MercureMessageBinding", "MercureOperationBinding", "ServerBindings", "ChannelBindings", "ChannelMap", "Channel", "ParametersMap", "MessageExample", "NamedMessages", "NamedMessageTraits", "NamedOperationTraits", "NamedCorrelationIds", "NamedStreamHeaders", "SecuritySchemeFlows", "Message", "MessageBindings", "OperationBindings", "OperationTrait", "OperationTraitList", "MessageTrait", "MessageTraitList", "CorrelationId", "SpecExtension".
 
  7 | where:
  8 |   - subject:
diff --git a/__tests__/lint/spec-json-schema-validation-dependentRequired/openapi.yaml b/__tests__/lint/spec-json-schema-validation-dependentRequired/openapi.yaml
new file mode 100644
index 00000000..4510370f
--- /dev/null
+++ b/__tests__/lint/spec-json-schema-validation-dependentRequired/openapi.yaml
@@ -0,0 +1,34 @@
+openapi: 3.1.0
+info:
+  title: test json schema validation keyword - dependentRequired
+  version: 1.0.0
+paths:
+  '/thing':
+    get:
+      summary: a sample api
+      responses:
+        '200':
+          description: OK
+          content:
+            'application/json':
+              schema:
+                $ref: '#/components/schemas/test_schema'
+              examples:
+                dependentRequired_passing:
+                  summary: an example schema
+                  value: { 'name': 'bobby', 'age': 25 }
+                dependentRequired_failing:
+                  summary: an example schema
+                  value: { 'name': 'jennie' }
+components:
+  schemas:
+    test_schema:
+      type: object
+      properties:
+        name:
+          type: string
+        age:
+          type: number
+      dependentRequired:
+        name:
+          - age
diff --git a/__tests__/lint/spec-json-schema-validation-dependentRequired/redocly.yaml b/__tests__/lint/spec-json-schema-validation-dependentRequired/redocly.yaml
new file mode 100644
index 00000000..9867f7c4
--- /dev/null
+++ b/__tests__/lint/spec-json-schema-validation-dependentRequired/redocly.yaml
@@ -0,0 +1,7 @@
+apis:
+  main:
+    root: ./openapi.yaml
+
+rules:
+  spec: error
+  no-invalid-media-type-examples: error
diff --git a/__tests__/lint/spec-json-schema-validation-dependentRequired/snapshot.js b/__tests__/lint/spec-json-schema-validation-dependentRequired/snapshot.js
new file mode 100644
index 00000000..508c6ce9
--- /dev/null
+++ b/__tests__/lint/spec-json-schema-validation-dependentRequired/snapshot.js
@@ -0,0 +1,28 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`E2E lint spec-json-schema-validation-dependentRequired 1`] = `
+
+validating /openapi.yaml...
+[1] openapi.yaml:22:26 at #/paths/~1thing/get/responses/200/content/application~1json/examples/dependentRequired_failing/value
+
+Example value must conform to the schema: must have property age when property name is present.
+
+20 |                 dependentRequired_failing:
+21 |                   summary: an example schema
+22 |                   value: { 'name': 'jennie' }
+   |                          ^^^^^^^^^^^^^^^^^^^^
+23 | components:
+24 |   schemas:
+
+referenced from openapi.yaml:14:15 at #/paths/~1thing/get/responses/200/content/application~1json 
+
+Error was generated by the no-invalid-media-type-examples rule.
+
+
+/openapi.yaml: validated in <test>ms
+
+❌ Validation failed with 1 error.
+run \`redocly lint --generate-ignore-file\` to add all problems to the ignore file.
+
+
+`;
diff --git a/packages/core/src/__tests__/lint.test.ts b/packages/core/src/__tests__/lint.test.ts
index 89c54a51..2e6952a3 100644
--- a/packages/core/src/__tests__/lint.test.ts
+++ b/packages/core/src/__tests__/lint.test.ts
@@ -1593,4 +1593,128 @@ describe('lint', () => {
     expect(result[0]).toHaveProperty('ignored', true);
     expect(result[0]).toHaveProperty('ruleId', 'operation-operationId');
   });
+
+  it('should throw an error for dependentRequired not expected here - OAS 3.0.x', async () => {
+    const document = parseYamlToDocument(
+      outdent`
+        openapi: 3.0.3
+        info:
+          title: test json schema validation keyword - dependentRequired
+          version: 1.0.0
+        paths:
+          '/thing':
+            get:
+              summary: a sample api
+              responses:
+                '200':
+                  description: OK
+                  content:
+                    'application/json':
+                      schema:
+                        $ref: '#/components/schemas/test_schema'
+                      examples:
+                        dependentRequired_passing:
+                          summary: an example schema
+                          value: { "name": "bobby", "age": 25}
+                        dependentRequired_failing:
+                          summary: an example schema
+                          value: { "name": "jennie"}
+        components:
+          schemas:
+            test_schema:
+              type: object
+              properties:
+                name:
+                  type: string
+                age:
+                  type: number
+              dependentRequired:
+                name:
+                - age
+      `,
+      ''
+    );
+
+    const configFilePath = path.join(__dirname, '..', '..', '..', 'redocly.yaml');
+
+    const results = await lintDocument({
+      externalRefResolver: new BaseResolver(),
+      document,
+      config: await makeConfig({ spec: 'error' }, undefined, configFilePath),
+    });
+
+    expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
+      [
+        {
+          "from": {
+            "pointer": "#/paths/~1thing/get/responses/200/content/application~1json/schema",
+            "source": "",
+          },
+          "location": [
+            {
+              "pointer": "#/components/schemas/test_schema/dependentRequired",
+              "reportOnKey": true,
+              "source": "",
+            },
+          ],
+          "message": "Property \`dependentRequired\` is not expected here.",
+          "ruleId": "spec",
+          "severity": "error",
+          "suggest": [],
+        },
+      ]
+    `);
+  });
+
+  it('should not throw an error for dependentRequired not expected here - OAS 3.1.x', async () => {
+    const document = parseYamlToDocument(
+      outdent`
+        openapi: 3.1.0
+        info:
+          title: test json schema validation keyword - dependentRequired
+          version: 1.0.0
+        paths:
+          '/thing':
+            get:
+              summary: a sample api
+              responses:
+                '200':
+                  description: OK
+                  content:
+                    'application/json':
+                      schema:
+                        $ref: '#/components/schemas/test_schema'
+                      examples:
+                        dependentRequired_passing:
+                          summary: an example schema
+                          value: { "name": "bobby", "age": 25}
+                        dependentRequired_failing:
+                          summary: an example schema
+                          value: { "name": "jennie"}
+        components:
+          schemas:
+            test_schema:
+              type: object
+              properties:
+                name:
+                  type: string
+                age:
+                  type: number
+              dependentRequired:
+                name:
+                - age
+      `,
+      ''
+    );
+
+    const configFilePath = path.join(__dirname, '..', '..', '..', 'redocly.yaml');
+
+    const results = await lintDocument({
+      externalRefResolver: new BaseResolver(),
+      document,
+      config: await makeConfig({ spec: 'error' }, undefined, configFilePath),
+    });
+
+    expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
+  });
 });