Repository: stoplightio/spectral
Pull request #1774 (2021-08-10 22:43:11)

fix(rulesets): oasSchema not using correct dialect for OAS 3.1
Fixes https://github.com/stoplightio/spectral/issues/1752

**Checklist**

- [x] Tests added / updated
- [x] Docs added / updated

**Does this PR introduce a breaking change?**

- [ ] Yes
- [x] No




Patch:
diff --git a/packages/rulesets/package.json b/packages/rulesets/package.json
index e1df5f57..4ba2f1bc 100644
--- a/packages/rulesets/package.json
+++ b/packages/rulesets/package.json
@@ -20,9 +20,9 @@
   "dependencies": {
     "@stoplight/better-ajv-errors": "0.2.0",
     "@stoplight/json": "3.15.0",
-    "@stoplight/spectral-core": "^1.1.0",
-    "@stoplight/spectral-formats": "^1.0.0",
-    "@stoplight/spectral-functions": "^1.0.0",
+    "@stoplight/spectral-core": "^1.3.0",
+    "@stoplight/spectral-formats": "^1.0.1",
+    "@stoplight/spectral-functions": "^1.1.2",
     "@stoplight/types": "^12.3.0",
     "@types/json-schema": "^7.0.7",
     "ajv": "~8.6.0",
diff --git a/packages/rulesets/src/oas/functions/oasSchema.ts b/packages/rulesets/src/oas/functions/oasSchema.ts
index 0e8464ad..281f065c 100644
--- a/packages/rulesets/src/oas/functions/oasSchema.ts
+++ b/packages/rulesets/src/oas/functions/oasSchema.ts
@@ -1,9 +1,10 @@
 import * as traverse from 'json-schema-traverse';
 import type { SchemaObject } from 'json-schema-traverse';
 import { isObject } from './utils/isObject';
-import { schema as schemaFn } from '@stoplight/spectral-functions';
+import { schema as schemaFn, SchemaOptions } from '@stoplight/spectral-functions';
 import { createRulesetFunction } from '@stoplight/spectral-core';
-import { oas2, oas3 } from '@stoplight/spectral-formats';
+import { oas2, oas3_0, oas3_1, extractDraftVersion } from '@stoplight/spectral-formats';
+import { isPlainObject } from '@stoplight/json';
 
 export type Options = {
   schema: Record<string, unknown>;
@@ -27,21 +28,31 @@ export default createRulesetFunction<unknown, Options>(
 
     let { schema } = opts;
 
+    let dialect: SchemaOptions['dialect'] = 'draft4';
+
     if (formats) {
       try {
         if (formats.has(oas2)) {
           schema = convertXNullable({ ...schema });
           traverse(schema, visitOAS2);
-        } else if (formats.has(oas3)) {
+        } else if (formats.has(oas3_0)) {
           schema = convertNullable({ ...schema });
           traverse(schema, visitOAS3);
+        } else if (formats.has(oas3_1)) {
+          if (isPlainObject(context.document.data) && typeof context.document.data.jsonSchemaDialect === 'string') {
+            dialect =
+              (extractDraftVersion(context.document.data.jsonSchemaDialect) as SchemaOptions['dialect']) ??
+              'draft2020-12';
+          } else {
+            dialect = 'draft2020-12';
+          }
         }
       } catch {
         // just in case
       }
     }
 
-    return schemaFn(targetVal, { ...opts, schema, dialect: 'draft4' }, context);
+    return schemaFn(targetVal, { ...opts, schema, dialect }, context);
   },
 );
 


Test patch:
diff --git a/packages/rulesets/src/oas/functions/__tests__/oasSchema.test.ts b/packages/rulesets/src/oas/functions/__tests__/oasSchema.test.ts
index 08a24ea8..2494d405 100644
--- a/packages/rulesets/src/oas/functions/__tests__/oasSchema.test.ts
+++ b/packages/rulesets/src/oas/functions/__tests__/oasSchema.test.ts
@@ -1,4 +1,4 @@
-import { oas2, oas3 } from '@stoplight/spectral-formats';
+import { oas2, oas3, oas3_0, oas3_1 } from '@stoplight/spectral-formats';
 import { DeepPartial } from '@stoplight/types';
 import oasSchema from '../../functions/oasSchema';
 import { createWithRules } from '../../__tests__/__helpers__/tester';
@@ -56,9 +56,9 @@ describe('oasSchema', () => {
     });
   });
 
-  test('given OAS3, supports nullable', () => {
+  test('given OAS 3.0, supports nullable', () => {
     const document = {
-      formats: new Set([oas3]),
+      formats: new Set([oas3, oas3_0]),
     };
 
     const testSchema = {
@@ -101,6 +101,26 @@ describe('oasSchema', () => {
     });
   });
 
+  test('given OAS 3.1, supports numeric exclusiveMinimum & exclusiveMaximum', () => {
+    const document = {
+      formats: new Set([oas3, oas3_1]),
+    };
+
+    const testSchema = {
+      type: 'number',
+      exclusiveMinimum: 1,
+    };
+
+    expect(runSchema(1, testSchema, { document })).toEqual([
+      {
+        message: 'Number must be > 1',
+        path: [],
+      },
+    ]);
+
+    expect(runSchema(1.5, testSchema, { document })).toEqual([]);
+  });
+
   test('should remove all redundant ajv errors', async () => {
     const spectral = createWithRules(['oas3-schema', 'oas3-valid-schema-example', 'oas3-valid-media-example']);
     const invalidSchema = JSON.stringify(require('../../__tests__/__fixtures__/petstore.invalid-schema.oas3.json'));