-
Notifications
You must be signed in to change notification settings - Fork 761
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(helpers): reorganize helpers in backward compatible way
Refs #2717
- Loading branch information
Showing
15 changed files
with
259 additions
and
237 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// iterate over each operation, and fire a callback with details | ||
// `find=true` will stop iterating, when the cb returns truthy | ||
export default function eachOperation(spec, cb, find) { | ||
if (!spec || typeof spec !== 'object' || !spec.paths || typeof spec.paths !== 'object') { | ||
return null; | ||
} | ||
|
||
const { paths } = spec; | ||
|
||
// Iterate over the spec, collecting operations | ||
// eslint-disable-next-line no-restricted-syntax, guard-for-in | ||
for (const pathName in paths) { | ||
// eslint-disable-next-line no-restricted-syntax, guard-for-in | ||
for (const method in paths[pathName]) { | ||
if (method.toUpperCase() === 'PARAMETERS') { | ||
continue; // eslint-disable-line no-continue | ||
} | ||
const operation = paths[pathName][method]; | ||
if (!operation || typeof operation !== 'object') { | ||
continue; // eslint-disable-line no-continue | ||
} | ||
|
||
const operationObj = { | ||
spec, | ||
pathName, | ||
method: method.toUpperCase(), | ||
operation, | ||
}; | ||
const cbValue = cb(operationObj); | ||
|
||
if (find && cbValue) { | ||
return operationObj; | ||
} | ||
} | ||
} | ||
|
||
return undefined; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import eachOperation from './each-operation.js'; | ||
|
||
// Will stop iterating over the operations and return the operationObj | ||
// as soon as predicate returns true | ||
export default function findOperation(spec, predicate) { | ||
return eachOperation(spec, predicate, true) || null; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import findOperation from './find-operation.js'; | ||
import opId from './op-id.js'; | ||
import idFromPathMethodLegacy from './id-from-path-method/legacy.js'; | ||
|
||
export default function getOperationRaw(spec, id) { | ||
if (!spec || !spec.paths) { | ||
return null; | ||
} | ||
|
||
return findOperation(spec, ({ pathName, method, operation }) => { | ||
if (!operation || typeof operation !== 'object') { | ||
return false; | ||
} | ||
|
||
const rawOperationId = operation.operationId; // straight from the source | ||
const operationId = opId(operation, pathName, method); | ||
const legacyOperationId = idFromPathMethodLegacy(pathName, method); | ||
|
||
return [operationId, legacyOperationId, rawOperationId].some((val) => val && val === id); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import replaceSpecialCharsWithUnderscore from '../replace-special-chars-with-underscore.js'; | ||
|
||
export default function idFromPathMethod( | ||
pathName, | ||
method, | ||
{ v2OperationIdCompatibilityMode } = {} | ||
) { | ||
if (v2OperationIdCompatibilityMode) { | ||
let res = `${method.toLowerCase()}_${pathName}`.replace( | ||
/[\s!@#$%^&*()_+=[{\]};:<>|./?,\\'""-]/g, | ||
'_' | ||
); | ||
|
||
res = res || `${pathName.substring(1)}_${method}`; | ||
|
||
return res | ||
.replace(/((_){2,})/g, '_') | ||
.replace(/^(_)*/g, '') | ||
.replace(/([_])*$/g, ''); | ||
} | ||
return `${method.toLowerCase()}${replaceSpecialCharsWithUnderscore(pathName)}`; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function idFromPathMethodLegacy(pathName, method) { | ||
return `${method.toLowerCase()}-${pathName}`; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,211 +1,6 @@ | ||
const toLower = (str) => String.prototype.toLowerCase.call(str); | ||
const escapeString = (str) => str.replace(/[^\w]/gi, '_'); | ||
|
||
// Strategy for determining operationId | ||
export function opId(operation, pathName, method = '', { v2OperationIdCompatibilityMode } = {}) { | ||
if (!operation || typeof operation !== 'object') { | ||
return null; | ||
} | ||
const idWithoutWhitespace = (operation.operationId || '').replace(/\s/g, ''); | ||
if (idWithoutWhitespace.length) { | ||
return escapeString(operation.operationId); | ||
} | ||
return idFromPathMethod(pathName, method, { v2OperationIdCompatibilityMode }); | ||
} | ||
|
||
// Create a generated operationId from pathName + method | ||
export function idFromPathMethod(pathName, method, { v2OperationIdCompatibilityMode } = {}) { | ||
if (v2OperationIdCompatibilityMode) { | ||
let res = `${method.toLowerCase()}_${pathName}`.replace( | ||
/[\s!@#$%^&*()_+=[{\]};:<>|./?,\\'""-]/g, | ||
'_' | ||
); | ||
|
||
res = res || `${pathName.substring(1)}_${method}`; | ||
|
||
return res | ||
.replace(/((_){2,})/g, '_') | ||
.replace(/^(_)*/g, '') | ||
.replace(/([_])*$/g, ''); | ||
} | ||
return `${toLower(method)}${escapeString(pathName)}`; | ||
} | ||
|
||
export function legacyIdFromPathMethod(pathName, method) { | ||
return `${toLower(method)}-${pathName}`; | ||
} | ||
|
||
// Get the operation, based on operationId ( just return the object, no inheritence ) | ||
export function getOperationRaw(spec, id) { | ||
if (!spec || !spec.paths) { | ||
return null; | ||
} | ||
|
||
return findOperation(spec, ({ pathName, method, operation }) => { | ||
if (!operation || typeof operation !== 'object') { | ||
return false; | ||
} | ||
|
||
const rawOperationId = operation.operationId; // straight from the source | ||
const operationId = opId(operation, pathName, method); | ||
const legacyOperationId = legacyIdFromPathMethod(pathName, method); | ||
|
||
return [operationId, legacyOperationId, rawOperationId].some((val) => val && val === id); | ||
}); | ||
} | ||
|
||
// Will stop iterating over the operations and return the operationObj | ||
// as soon as predicate returns true | ||
export function findOperation(spec, predicate) { | ||
return eachOperation(spec, predicate, true) || null; | ||
} | ||
|
||
// iterate over each operation, and fire a callback with details | ||
// `find=true` will stop iterating, when the cb returns truthy | ||
export function eachOperation(spec, cb, find) { | ||
if (!spec || typeof spec !== 'object' || !spec.paths || typeof spec.paths !== 'object') { | ||
return null; | ||
} | ||
|
||
const { paths } = spec; | ||
|
||
// Iterate over the spec, collecting operations | ||
// eslint-disable-next-line no-restricted-syntax, guard-for-in | ||
for (const pathName in paths) { | ||
// eslint-disable-next-line no-restricted-syntax, guard-for-in | ||
for (const method in paths[pathName]) { | ||
if (method.toUpperCase() === 'PARAMETERS') { | ||
continue; // eslint-disable-line no-continue | ||
} | ||
const operation = paths[pathName][method]; | ||
if (!operation || typeof operation !== 'object') { | ||
continue; // eslint-disable-line no-continue | ||
} | ||
|
||
const operationObj = { | ||
spec, | ||
pathName, | ||
method: method.toUpperCase(), | ||
operation, | ||
}; | ||
const cbValue = cb(operationObj); | ||
|
||
if (find && cbValue) { | ||
return operationObj; | ||
} | ||
} | ||
} | ||
|
||
return undefined; | ||
} | ||
|
||
// REVIEW: OAS3: identify normalization steps that need changes | ||
// ...maybe create `normalizeOAS3`? | ||
|
||
export function normalizeSwagger(parsedSpec) { | ||
const { spec } = parsedSpec; | ||
const { paths } = spec; | ||
const map = {}; | ||
|
||
if (!paths || spec.$$normalized) { | ||
return parsedSpec; | ||
} | ||
|
||
// eslint-disable-next-line no-restricted-syntax, guard-for-in | ||
for (const pathName in paths) { | ||
const path = paths[pathName]; | ||
|
||
if (path == null || !['object', 'function'].includes(typeof path)) { | ||
continue; // eslint-disable-line no-continue | ||
} | ||
|
||
const pathParameters = path.parameters; | ||
|
||
// eslint-disable-next-line no-restricted-syntax, guard-for-in | ||
for (const method in path) { | ||
const operation = path[method]; | ||
if (operation == null || !['object', 'function'].includes(typeof operation)) { | ||
continue; // eslint-disable-line no-continue | ||
} | ||
|
||
const oid = opId(operation, pathName, method); | ||
|
||
if (oid) { | ||
if (map[oid]) { | ||
map[oid].push(operation); | ||
} else { | ||
map[oid] = [operation]; | ||
} | ||
|
||
const opList = map[oid]; | ||
if (opList.length > 1) { | ||
opList.forEach((o, i) => { | ||
// eslint-disable-next-line no-underscore-dangle | ||
o.__originalOperationId = o.__originalOperationId || o.operationId; | ||
o.operationId = `${oid}${i + 1}`; | ||
}); | ||
} else if (typeof operation.operationId !== 'undefined') { | ||
// Ensure we always add the normalized operation ID if one already exists | ||
// ( potentially different, given that we normalize our IDs) | ||
// ... _back_ to the spec. Otherwise, they might not line up | ||
const obj = opList[0]; | ||
// eslint-disable-next-line no-underscore-dangle | ||
obj.__originalOperationId = obj.__originalOperationId || operation.operationId; | ||
obj.operationId = oid; | ||
} | ||
} | ||
|
||
if (method !== 'parameters') { | ||
// Add inherited consumes, produces, parameters, securities | ||
const inheritsList = []; | ||
const toBeInherit = {}; | ||
|
||
// Global-levels | ||
// eslint-disable-next-line no-restricted-syntax | ||
for (const key in spec) { | ||
if (key === 'produces' || key === 'consumes' || key === 'security') { | ||
toBeInherit[key] = spec[key]; | ||
inheritsList.push(toBeInherit); | ||
} | ||
} | ||
|
||
// Path-levels | ||
if (pathParameters) { | ||
toBeInherit.parameters = pathParameters; | ||
inheritsList.push(toBeInherit); | ||
} | ||
|
||
if (inheritsList.length) { | ||
// eslint-disable-next-line no-restricted-syntax | ||
for (const inherits of inheritsList) { | ||
// eslint-disable-next-line no-restricted-syntax | ||
for (const inheritName in inherits) { | ||
if (!operation[inheritName]) { | ||
operation[inheritName] = inherits[inheritName]; | ||
} else if (inheritName === 'parameters') { | ||
// eslint-disable-next-line no-restricted-syntax | ||
for (const param of inherits[inheritName]) { | ||
const exists = operation[inheritName].some( | ||
(opParam) => | ||
(opParam.name && opParam.name === param.name) || | ||
(opParam.$ref && opParam.$ref === param.$ref) || | ||
(opParam.$$ref && opParam.$$ref === param.$$ref) || | ||
opParam === param | ||
); | ||
|
||
if (!exists) { | ||
operation[inheritName].push(param); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
spec.$$normalized = true; | ||
|
||
return parsedSpec; | ||
} | ||
export { default as eachOperation } from './each-operation.js'; | ||
export { default as findOperation } from './find-operation.js'; | ||
export { default as getOperationRaw } from './get-operation-raw.js'; | ||
export { default as opId } from './op-id.js'; | ||
export { default as idFromPathMethod } from './id-from-path-method/index.js'; | ||
export { default as idFromPathMethodLegacy } from './id-from-path-method/legacy.js'; |
Oops, something went wrong.