openapi-enforcer
Advanced tools
Comparing version 1.14.2 to 1.14.3
@@ -7,3 +7,18 @@ # Change Log | ||
## 1.14.3 | ||
### Fixed | ||
- **Reporting for Equivalent Paths** | ||
A bug was identified that could incorrectly report the wrong paths when equivalent paths were identified. | ||
## 1.14.2 | ||
### Fixed | ||
- **Example Validation with One Of Schema** | ||
There were several problems with validating examples against schemas with `oneOf`. This has been fixed. | ||
## 1.14.1 | ||
@@ -10,0 +25,0 @@ |
{ | ||
"name": "openapi-enforcer", | ||
"version": "1.14.2", | ||
"version": "1.14.3", | ||
"description": "Library for validating, parsing, and formatting data against open api schemas.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -19,4 +19,5 @@ /** | ||
const EnforcerRef = require('../enforcer-ref'); | ||
const util = require('../util') | ||
const methods = ['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace']; | ||
const methods = util.methods() | ||
@@ -23,0 +24,0 @@ module.exports = { |
@@ -22,2 +22,3 @@ /** | ||
const rxPathParam = /{([^}]+)}/; | ||
const methods = util.methods() | ||
@@ -28,4 +29,4 @@ module.exports = { | ||
const pathParsers = {}; | ||
const pathEquivalencies = {}; | ||
const paramlessMap = {}; | ||
// const pathEquivalencies = {}; | ||
// const paramlessMap = {}; | ||
@@ -99,17 +100,17 @@ if (!data.options.disablePathNormalization) { | ||
path.methods.forEach(method => { | ||
equivalencyKey += method + equivalencyKey; | ||
// path.methods.forEach(method => { | ||
// equivalencyKey += method + equivalencyKey; | ||
// | ||
// if (!paramlessMap[equivalencyKey]) paramlessMap[equivalencyKey] = []; | ||
// const paramless = paramlessMap[equivalencyKey]; | ||
// | ||
// if (!pathEquivalencies[equivalencyKey]) pathEquivalencies[equivalencyKey] = []; | ||
// if (pathEquivalencies[equivalencyKey].length === 0) pathEquivalencies[equivalencyKey].push(pathKey); | ||
// if (!paramless.includes(paramlessStr)) { | ||
// paramless.push(paramlessStr); | ||
// } else { | ||
// pathEquivalencies[equivalencyKey].push(pathKey); | ||
// } | ||
// }); | ||
if (!paramlessMap[equivalencyKey]) paramlessMap[equivalencyKey] = []; | ||
const paramless = paramlessMap[equivalencyKey]; | ||
if (!pathEquivalencies[equivalencyKey]) pathEquivalencies[equivalencyKey] = []; | ||
if (pathEquivalencies[equivalencyKey].length === 0) pathEquivalencies[equivalencyKey].push(pathKey); | ||
if (!paramless.includes(paramlessStr)) { | ||
paramless.push(paramlessStr); | ||
} else { | ||
pathEquivalencies[equivalencyKey].push(pathKey); | ||
} | ||
}); | ||
const rx = new RegExp('^' + rxStr + '$'); | ||
@@ -141,11 +142,69 @@ | ||
const equivalencyException = exception.nest('Equivalent paths are not allowed'); | ||
Object.keys(pathEquivalencies).forEach(key => { | ||
const array = pathEquivalencies[key]; | ||
if (array.length > 1) { | ||
const conflicts = equivalencyException.nest('Equivalent paths:'); | ||
array.forEach(err => conflicts.push(err)); | ||
// convert paths into signatures | ||
const pathParamSymbol = Symbol('path parameter') | ||
const pathKeySignatures = [] | ||
Object.keys(result).forEach((pathKey, index) => { | ||
const rxPathParameter = /{([^}]+)}/g; | ||
const pathSignature = [] | ||
let match | ||
let offset = 0 | ||
// pathKey = util.edgeSlashes(pathKey, false, false); | ||
while ((match = rxPathParameter.exec(pathKey))) { | ||
const str = pathKey.substring(offset, match.index) | ||
pathSignature.push(str) | ||
pathSignature.push(pathParamSymbol) | ||
offset = match.index + match[0].length | ||
} | ||
}); | ||
const str = pathKey.substring(offset) | ||
pathSignature.push(str) | ||
methods | ||
.filter(method => result[pathKey].hasOwnProperty(method)) | ||
.forEach(method => { | ||
pathKeySignatures.push({ | ||
key: pathKey, | ||
method, | ||
signature: [method].concat(pathSignature) | ||
}) | ||
}) | ||
}) | ||
// find equivalent paths based on signatures | ||
const pathEquivalencies = [] | ||
const alreadyMatchedPathEquivalencies = [] | ||
pathKeySignatures.forEach((top) => { | ||
const duplicates = pathKeySignatures.filter((bottom) => { | ||
const length = bottom.signature.length | ||
if (top === bottom || top.signature.length !== length || alreadyMatchedPathEquivalencies.includes(bottom.key)) return false | ||
for (let k = 0; k < length; k++) { | ||
if (bottom.signature[k] !== top.signature[k]) return false | ||
} | ||
return true | ||
}) | ||
if (duplicates.length > 0) { | ||
duplicates.unshift(top) | ||
duplicates.forEach(item => alreadyMatchedPathEquivalencies.push(item.key)) | ||
pathEquivalencies.push(duplicates) | ||
} | ||
}) | ||
// report path equivalencies | ||
const equivalencyException = exception.nest('Equivalent paths are not allowed'); | ||
pathEquivalencies.forEach(matches => { | ||
const conflicts = equivalencyException.nest('Equivalent paths:'); | ||
matches.forEach(item => conflicts.push(item.method.toUpperCase() + ' ' + item.key)); | ||
}) | ||
// report equivalent paths | ||
// const equivalencyException = exception.nest('Equivalent paths are not allowed'); | ||
// Object.keys(pathEquivalencies).forEach(key => { | ||
// const array = pathEquivalencies[key]; | ||
// if (array.length > 1) { | ||
// const conflicts = equivalencyException.nest('Equivalent paths:'); | ||
// array.forEach(err => conflicts.push(err)); | ||
// } | ||
// }); | ||
Object.keys(pathParsers).forEach(key => { | ||
@@ -152,0 +211,0 @@ pathParsers[key].sort((a, b) => a.weight < b.weight ? -1 : 1); |
@@ -50,2 +50,3 @@ /** | ||
merge, | ||
methods, | ||
mostOf, | ||
@@ -389,2 +390,6 @@ parseCookieString, | ||
function methods () { | ||
return ['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace']; | ||
} | ||
function mostOf (numberArray) { | ||
@@ -391,0 +396,0 @@ const length = numberArray.length; |
@@ -222,2 +222,13 @@ const expect = require('chai').expect; | ||
describe('issue-118 - incorrectly identifies duplicate paths', () => { | ||
it('will correctly identify duplicate paths', async () => { | ||
const [ , err ] = await Enforcer(path.resolve(resourcesPath, 'issue-118/openapi.yml'), { fullResult: true }); | ||
expect(err).to.match(/Equivalent paths are not allowed/) | ||
expect(err).to.match(/GET \/user\/{userId}/) | ||
expect(err).to.match(/GET \/user\/{username}/) | ||
}) | ||
}) | ||
}); |
1561227
182
20725