Files
seasonedShows/.stoplight/custom-functions/oasOpParams.js
2022-08-18 20:08:26 +02:00

82 lines
1.9 KiB
JavaScript

function isObject(value) {
return value !== null && typeof value === 'object';
}
function computeFingerprint(param) {
return `${String(param.in)}-${String(param.name)}`;
}
export const oasOpParams = (params, _opts, { path }) => {
/**
* This function verifies:
*
* 1. Operations must have unique `name` + `in` parameters.
* 2. Operation cannot have both `in:body` and `in:formData` parameters
* 3. Operation must have only one `in:body` parameter.
*/
if (!Array.isArray(params)) return;
if (params.length < 2) return;
const results = [];
const count = {
body: [],
formData: [],
};
const list = [];
const duplicates = [];
let index = -1;
for (const param of params) {
index++;
if (!isObject(param)) continue;
// skip params that are refs
if ('$ref' in param) continue;
// Operations must have unique `name` + `in` parameters.
const fingerprint = computeFingerprint(param);
if (list.includes(fingerprint)) {
duplicates.push(index);
} else {
list.push(fingerprint);
}
if (typeof param.in === 'string' && param.in in count) {
count[param.in].push(index);
}
}
if (duplicates.length > 0) {
for (const i of duplicates) {
results.push({
message: 'A parameter in this operation already exposes the same combination of "name" and "in" values.',
path: [...path, i],
});
}
}
if (count.body.length > 0 && count.formData.length > 0) {
results.push({
message: 'Operation must not have both "in:body" and "in:formData" parameters.',
});
}
if (count.body.length > 1) {
for (let i = 1; i < count.body.length; i++) {
results.push({
message: 'Operation must not have more than a single instance of the "in:body" parameter.',
path: [...path, count.body[i]],
});
}
}
return results;
};
export default oasOpParams;