Repository: stoplightio/spectral (ts)

Issue:
`example-value-or-externalValue` should only target OAS3
#882 puts under the light a minor issue: `value` or `externalValue` only make sense in the context of OAS3, but the rule `example-value-or-externalValue` apply to both OAS2 and OAS3.

#882 could be merged without incurring any breaking change. However, maybe should we rename the rule to `examples-value-or-externalValue` (and update the doco accordingly) to make it clear what it actually targets.

Pull request description:
fix: make `example-value-or-externalValue` only target oas3 document
Fixes #883.

**Checklist**

- [x] Tests added / updated
- [x] Docs added / updated

**Does this PR introduce a breaking change?**

- [ ] Yes
- [x] No (From the API standpoint)

This results in a change in the OAS3 ruleset content (one rule removed and one rule added).

⚠️ This will impact users who tweaked the rule severity or silenced it

As a side addition, the `xor` function documentation has (tentatively) been updated to make it more clear with regards to `allowed` vs `required`.

Patch:
diff --git a/docs/reference/functions.md b/docs/reference/functions.md
index d1774548..1c36240b 100644
--- a/docs/reference/functions.md
+++ b/docs/reference/functions.md
@@ -257,7 +257,7 @@ unused-definition:
 
 ## xor
 
-Communicate that only one of these properties is allowed, and no more than one of them.
+Communicate that one of these properties is required, and no more than one is allowed to be defined.
 
 <!-- title: functionOptions -->
 
@@ -268,10 +268,10 @@ properties | the properties to check | yes
 <!-- title: example -->
 
 ```yaml
-example-value-or-externalValue:
+components-example-value-or-externalValue:
   description: Example should have either a `value` or `externalValue` field.
   type: style
-  given: "$..example"
+  given: "$.components.examples.*"
   then:
     function: xor
     functionOptions:
diff --git a/docs/reference/openapi-rules.md b/docs/reference/openapi-rules.md
index 388e0e00..41ebef53 100644
--- a/docs/reference/openapi-rules.md
+++ b/docs/reference/openapi-rules.md
@@ -110,30 +110,6 @@ info:
     url: goarmy.com/apis/support
 ```
 
-### example-value-or-externalValue
-
-Examples for `requestBody` or response examples can have an `externalValue` or a `value`, but they cannot have both.
-
-**Recommended:** Yes
-
-**Bad Example**
-
-```yaml
-paths:
-  /pet:
-    put:
-      operationId: "relace-pet"
-      requestBody:
-        content:
-          'application/json':
-            examples: 
-              foo:
-                summary: A foo example
-                value: {"foo": "bar"}
-                externalValue: 'http://example.org/foo.json' 
-                # marp! no, can only have one or the other
-```
-
 ### info-contact
 
 Info object should contain `contact` object. 
@@ -523,6 +499,30 @@ servers:
 
 If this is going out to the world, maybe have production and a general sandbox people can play with.
 
+### oas3-example-value-or-externalValue
+
+Examples for `requestBody` or response examples can have an `externalValue` or a `value`, but they cannot have both.
+
+**Recommended:** Yes
+
+**Bad Example**
+
+```yaml
+paths:
+  /pet:
+    put:
+      operationId: "replace-pet"
+      requestBody:
+        content:
+          'application/json':
+            examples: 
+              foo:
+                summary: A foo example
+                value: {"foo": "bar"}
+                externalValue: 'http://example.org/foo.json' 
+                # marp! no, can only have one or the other
+```
+
 ### oas3-operation-security-defined
 
 Operation `security` values must match a scheme defined in the `components.securitySchemes` object.
diff --git a/src/rulesets/oas/index.json b/src/rulesets/oas/index.json
index 8f8caa75..9bd16ce8 100644
--- a/src/rulesets/oas/index.json
+++ b/src/rulesets/oas/index.json
@@ -112,29 +112,6 @@
         "api"
       ]
     },
-    "example-value-or-externalValue": {
-      "description": "Example should have either a `value` or `externalValue` field.",
-      "recommended": true,
-      "type": "style",
-      "given": [
-        "$.components.examples.*",
-        "$.paths..content.*.examples.*",
-        "$.components..content.*.examples.*",
-        "$.paths..parameters.*.examples.*",
-        "$.components..parameters.*.examples.*",
-        "$.paths..headers.*.examples.*",
-        "$.components..headers.*.examples.*"
-      ],
-      "then": {
-        "function": "xor",
-        "functionOptions": {
-          "properties": [
-            "externalValue",
-            "value"
-          ]
-        }
-      }
-    },
     "info-contact": {
       "description": "Info object should contain `contact` object.",
       "recommended": true,
@@ -657,6 +634,30 @@
         "api"
       ]
     },
+    "oas3-example-value-or-externalValue": {
+      "description": "Example should have either a `value` or `externalValue` field.",
+      "recommended": true,
+      "formats": ["oas3"],
+      "type": "style",
+      "given": [
+        "$.components.examples.*",
+        "$.paths..content.*.examples.*",
+        "$.components..content.*.examples.*",
+        "$.paths..parameters.*.examples.*",
+        "$.components..parameters.*.examples.*",
+        "$.paths..headers.*.examples.*",
+        "$.components..headers.*.examples.*"
+      ],
+      "then": {
+        "function": "xor",
+        "functionOptions": {
+          "properties": [
+            "externalValue",
+            "value"
+          ]
+        }
+      }
+    },
     "oas3-operation-security-defined": {
       "description": "Operation `security` values must match a scheme defined in the `components.securitySchemes` object.",
       "recommended": true,


Test patch:
diff --git a/src/rulesets/oas/__tests__/example-value-or-externalValue.ts b/src/rulesets/oas/__tests__/oas3-example-value-or-externalValue.ts
similarity index 92%
rename from src/rulesets/oas/__tests__/example-value-or-externalValue.ts
rename to src/rulesets/oas/__tests__/oas3-example-value-or-externalValue.ts
index 8b24abc9..e6a3ac13 100644
--- a/src/rulesets/oas/__tests__/example-value-or-externalValue.ts
+++ b/src/rulesets/oas/__tests__/oas3-example-value-or-externalValue.ts
@@ -2,12 +2,13 @@ import { DiagnosticSeverity } from '@stoplight/types';
 import { RuleType, Spectral } from '../../../spectral';
 import * as ruleset from '../index.json';
 
-describe('example-value-or-externalValue', () => {
+describe('oas3-example-value-or-externalValue', () => {
   const s = new Spectral();
+  s.registerFormat('oas3', () => true);
   s.setRules({
-    'example-value-or-externalValue': Object.assign(ruleset.rules['example-value-or-externalValue'], {
+    'oas3-example-value-or-externalValue': Object.assign(ruleset.rules['oas3-example-value-or-externalValue'], {
       recommended: true,
-      type: RuleType[ruleset.rules['example-value-or-externalValue'].type],
+      type: RuleType[ruleset.rules['oas3-example-value-or-externalValue'].type],
     }),
   });
 
@@ -77,7 +78,7 @@ describe('example-value-or-externalValue', () => {
     const results = await s.run({ components: { examples: { first: {} } } });
     expect(results).toEqual([
       {
-        code: 'example-value-or-externalValue',
+        code: 'oas3-example-value-or-externalValue',
         message: 'Example should have either a `value` or `externalValue` field.',
         path: ['components', 'examples', 'first'],
         range: {
@@ -101,7 +102,7 @@ describe('example-value-or-externalValue', () => {
     });
     expect(results).toEqual([
       {
-        code: 'example-value-or-externalValue',
+        code: 'oas3-example-value-or-externalValue',
         message: 'Example should have either a `value` or `externalValue` field.',
         path: ['components', 'examples', 'third'],
         range: {
@@ -125,7 +126,7 @@ describe('example-value-or-externalValue', () => {
     });
     expect(results).toEqual([
       {
-        code: 'example-value-or-externalValue',
+        code: 'oas3-example-value-or-externalValue',
         message: 'Example should have either a `value` or `externalValue` field.',
         path: ['components', 'examples', 'first'],
         range: {
@@ -155,7 +156,7 @@ describe('example-value-or-externalValue', () => {
     });
     expect(results).toEqual([
       {
-        code: 'example-value-or-externalValue',
+        code: 'oas3-example-value-or-externalValue',
         message: 'Example should have either a `value` or `externalValue` field.',
         path: ['components', 'examples', 'second'],
         range: {
@@ -189,7 +190,7 @@ describe('example-value-or-externalValue', () => {
     });
     expect(results).toEqual([
       {
-        code: 'example-value-or-externalValue',
+        code: 'oas3-example-value-or-externalValue',
         message: 'Example should have either a `value` or `externalValue` field.',
         path: ['components', 'headers', 'headerName', 'examples', 'second'],
         range: {
@@ -223,7 +224,7 @@ describe('example-value-or-externalValue', () => {
     });
     expect(results).toEqual([
       {
-        code: 'example-value-or-externalValue',
+        code: 'oas3-example-value-or-externalValue',
         message: 'Example should have either a `value` or `externalValue` field.',
         path: ['components', 'parameters', 'parameterName', 'examples', 'second'],
         range: {
@@ -265,7 +266,7 @@ describe('example-value-or-externalValue', () => {
     });
     expect(results).toEqual([
       {
-        code: 'example-value-or-externalValue',
+        code: 'oas3-example-value-or-externalValue',
         message: 'Example should have either a `value` or `externalValue` field.',
         path: ['paths', '/path', 'get', 'responses', '200', 'content', 'application/json', 'examples', 'second'],
         range: {