From 7ce43eaf1253bc5daa073b525aca0704bb5e03e5 Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Thu, 26 Aug 2021 15:43:11 -0700 Subject: [PATCH] fix: stop dereferencing when running spec validation --- __tests__/index.test.js | 4 ++++ index.js | 43 +++++++++++++++++++++++------------------ package-lock.json | 38 +++++++++--------------------------- package.json | 3 +-- 4 files changed, 38 insertions(+), 50 deletions(-) diff --git a/__tests__/index.test.js b/__tests__/index.test.js index 2e9eec8..5d87056 100644 --- a/__tests__/index.test.js +++ b/__tests__/index.test.js @@ -130,6 +130,7 @@ describe('#validate', () => { expect(definition.openapi).toBe('3.0.0'); expect(Object.keys(definition.paths)).toHaveLength(14); expect(definition.paths['/pet'].post.operationId).toBe('addPet'); + expect(definition.paths['/pet'].post.requestBody).toStrictEqual({ $ref: '#/components/requestBodies/Pet' }); expect(Object.keys(definition.components.requestBodies)).toHaveLength(2); expect(Object.keys(definition.components.securitySchemes)).toHaveLength(2); expect(Object.keys(definition.components.schemas)).toHaveLength(6); @@ -145,6 +146,7 @@ describe('#validate', () => { expect(definition.openapi).toBe('3.0.0'); expect(Object.keys(definition.paths)).toHaveLength(14); expect(definition.paths['/pet'].post.operationId).toBe('addPet'); + expect(definition.paths['/pet'].post.requestBody).toStrictEqual({ $ref: '#/components/requestBodies/Pet' }); expect(Object.keys(definition.components.requestBodies)).toHaveLength(2); expect(Object.keys(definition.components.securitySchemes)).toHaveLength(2); expect(Object.keys(definition.components.schemas)).toHaveLength(6); @@ -202,6 +204,7 @@ describe('#validate', () => { expect(definition.openapi).toBe('3.0.0'); expect(definition.paths['/pet'].post.operationId).toBe('addPet'); + expect(definition.paths['/pet'].post.requestBody).toStrictEqual({ $ref: '#/components/requestBodies/Pet' }); expect(Object.keys(definition.paths)).toHaveLength(14); expect(Object.keys(definition.components.schemas)).toHaveLength(6); @@ -214,6 +217,7 @@ describe('#validate', () => { expect(definition.openapi).toBe('3.0.0'); expect(definition.paths['/pet'].post.operationId).toBe('addPet'); + expect(definition.paths['/pet'].post.requestBody).toStrictEqual({ $ref: '#/components/requestBodies/Pet' }); expect(Object.keys(definition.paths)).toHaveLength(14); expect(Object.keys(definition.components.schemas)).toHaveLength(6); }); diff --git a/index.js b/index.js index b137fe9..9f21cbf 100644 --- a/index.js +++ b/index.js @@ -1,8 +1,7 @@ const fetch = require('node-fetch'); const fs = require('fs'); -const $RefParser = require('@apidevtools/json-schema-ref-parser'); const converter = require('swagger2openapi'); -const SwaggerParser = require('swagger-parser'); +const swaggerParser = require('@apidevtools/swagger-parser'); const utils = require('./lib/utils'); class oasNormalize { @@ -52,7 +51,7 @@ class oasNormalize { if (this.cache.bundle) return Promise.resolve(this.cache.bundle); return this.load() - .then(schema => $RefParser.bundle(schema)) + .then(schema => swaggerParser.bundle(schema)) .then(bundle => { this.cache.bundle = bundle; return bundle; @@ -63,7 +62,7 @@ class oasNormalize { if (this.cache.deref) return Promise.resolve(this.cache.deref); return this.load() - .then(schema => $RefParser.dereference(schema)) + .then(schema => swaggerParser.dereference(schema)) .then(dereferenced => { this.cache.deref = dereferenced; return dereferenced; @@ -71,24 +70,31 @@ class oasNormalize { } async validate(convertToLatest) { - return this.deref().then(async schema => { + return this.load().then(async schema => { const baseVersion = parseInt(utils.version(schema), 10); - const resolve = out => { - if (!convertToLatest) { - return out; - } - - return converter.convertObj(out, { anchors: true }).then(options => { - return options.openapi; - }); - }; - if (baseVersion === 1) { return Promise.reject(new Error('Swagger v1.2 is unsupported.')); } else if (baseVersion === 2 || baseVersion === 3) { - return resolve( - await SwaggerParser.validate(schema).catch(err => { + // `swaggerParser.validate()` dereferences schemas at the same time as validation and does + // not give us an option to disable this. Since all we already have a dereferencing method + // on this library and our `validate()` method here just needs to tell us if the definition + // is valid or not we need to clone it before passing it over to `swagger-parser` so as to + // not run into pass-by-reference problems. + const clonedSchema = JSON.parse(JSON.stringify(schema)); + + return swaggerParser + .validate(clonedSchema) + .then(() => { + if (!convertToLatest) { + return schema; + } + + return converter.convertObj(schema, { anchors: true }).then(options => { + return options.openapi; + }); + }) + .catch(err => { const error = new Error(err.message.replace(/\[object Object\]/g, 'Schema')); error.full = err; @@ -108,8 +114,7 @@ class oasNormalize { } return Promise.reject(error); - }) - ); + }); } return Promise.reject(new Error('The supplied API definition is unsupported.')); diff --git a/package-lock.json b/package-lock.json index 281d0a8..172d4f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,16 @@ { "name": "oas-normalize", - "version": "3.0.4", + "version": "3.0.5", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "3.0.4", + "version": "3.0.5", "license": "MIT", "dependencies": { - "@apidevtools/json-schema-ref-parser": "^9.0.7", + "@apidevtools/swagger-parser": "^10.0.3", "js-yaml": "^4.1.0", "node-fetch": "^2.6.1", - "swagger-parser": "^10.0.1", "swagger2openapi": "^7.0.8" }, "devDependencies": { @@ -11391,9 +11390,9 @@ } }, "node_modules/openapi-types": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-9.1.0.tgz", - "integrity": "sha512-mhXh8QN8sbErlxfxBeZ/pzgvmDn443p8CXlxwGSi2bWANZAFvjLPI0PoGjqHW+JdBbXg6uvmvM81WXaweh/SVA==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-9.2.0.tgz", + "integrity": "sha512-3x0gg8DxhpZ5MVki7AK6jmMdVIZASmVGo9CoUtD+nksLdkqz7EzWKdfS9Oxxq1J7idnZV0b3LjqcvizfKFySpQ==", "peer": true }, "node_modules/optionator": { @@ -12534,17 +12533,6 @@ "node": ">=8" } }, - "node_modules/swagger-parser": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz", - "integrity": "sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==", - "dependencies": { - "@apidevtools/swagger-parser": "10.0.3" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/swagger2openapi": { "version": "7.0.8", "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-7.0.8.tgz", @@ -22074,9 +22062,9 @@ } }, "openapi-types": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-9.1.0.tgz", - "integrity": "sha512-mhXh8QN8sbErlxfxBeZ/pzgvmDn443p8CXlxwGSi2bWANZAFvjLPI0PoGjqHW+JdBbXg6uvmvM81WXaweh/SVA==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-9.2.0.tgz", + "integrity": "sha512-3x0gg8DxhpZ5MVki7AK6jmMdVIZASmVGo9CoUtD+nksLdkqz7EzWKdfS9Oxxq1J7idnZV0b3LjqcvizfKFySpQ==", "peer": true }, "optionator": { @@ -22951,14 +22939,6 @@ } } }, - "swagger-parser": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz", - "integrity": "sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==", - "requires": { - "@apidevtools/swagger-parser": "10.0.3" - } - }, "swagger2openapi": { "version": "7.0.8", "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-7.0.8.tgz", diff --git a/package.json b/package.json index 044b52f..c9cf6df 100644 --- a/package.json +++ b/package.json @@ -37,10 +37,9 @@ }, "license": "MIT", "dependencies": { - "@apidevtools/json-schema-ref-parser": "^9.0.7", + "@apidevtools/swagger-parser": "^10.0.3", "js-yaml": "^4.1.0", "node-fetch": "^2.6.1", - "swagger-parser": "^10.0.1", "swagger2openapi": "^7.0.8" }, "devDependencies": {