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

77 lines
1.6 KiB
JavaScript

import { isPlainObject } from '@stoplight/json';
function isObject(value) {
return value !== null && typeof value === 'object';
}
const validOperationKeys = ['get', 'head', 'post', 'put', 'patch', 'delete', 'options', 'trace'];
function* getAllOperations(paths) {
if (!isPlainObject(paths)) {
return;
}
const item = {
path: '',
operation: '',
value: null,
};
for (const path of Object.keys(paths)) {
const operations = paths[path];
if (!isPlainObject(operations)) {
continue;
}
item.path = path;
for (const operation of Object.keys(operations)) {
if (!isPlainObject(operations[operation]) || !validOperationKeys.includes(operation)) {
continue;
}
item.operation = operation;
item.value = operations[operation];
yield item;
}
}
}
export const oasOpIdUnique = targetVal => {
if (!isObject(targetVal) || !isObject(targetVal.paths)) return;
const results = [];
const { paths } = targetVal;
const seenIds = [];
for (const { path, operation } of getAllOperations(paths)) {
const pathValue = paths[path];
if (!isObject(pathValue)) continue;
const operationValue = pathValue[operation];
if (!isObject(operationValue) || !('operationId' in operationValue)) {
continue;
}
const { operationId } = operationValue;
if (seenIds.includes(operationId)) {
results.push({
message: 'operationId must be unique.',
path: ['paths', path, operation, 'operationId'],
});
} else {
seenIds.push(operationId);
}
}
return results;
};
export default oasOpIdUnique;