2021-09-01 18:52:53 +03:00
|
|
|
// Check conformance to Azure operationId conventions:
|
|
|
|
// - operationIds should have the form "noun_verb" with just one underscore separator [R1001, R2055]
|
|
|
|
// - get operation with pageable response should have "list" in the operationId verb [R1003]
|
|
|
|
// - get operation should have "get" or "list" in the operationId verb [R1005]
|
|
|
|
// - put operation should have "create" in the operationId verb [R1006]
|
|
|
|
// - patch operation should have "update" in the operationId verb [R1007]
|
|
|
|
// - delete operations should have "delete" in the "verb" component of the operationId [R1009]
|
|
|
|
|
2021-09-03 14:49:06 +03:00
|
|
|
module.exports = (operation, _opts, paths) => {
|
2021-09-01 18:52:53 +03:00
|
|
|
// targetVal should be an operation
|
2021-09-03 14:49:06 +03:00
|
|
|
if (operation === null || typeof operation !== 'object') {
|
2021-09-01 18:52:53 +03:00
|
|
|
return [];
|
|
|
|
}
|
2021-09-10 06:18:35 +03:00
|
|
|
const path = paths.path || paths.target || [];
|
2021-09-01 18:52:53 +03:00
|
|
|
|
|
|
|
const errors = [];
|
|
|
|
|
2021-09-03 14:49:06 +03:00
|
|
|
if (!operation.operationId) {
|
2021-09-01 18:52:53 +03:00
|
|
|
// Missing operationId is caught elsewhere, so just return
|
|
|
|
return errors;
|
|
|
|
}
|
|
|
|
|
2021-09-03 14:49:06 +03:00
|
|
|
const m = operation.operationId.match(/[A-Za-z0-9]+_([A-Za-z0-9]+)/);
|
2021-09-01 18:52:53 +03:00
|
|
|
if (!m) {
|
|
|
|
errors.push({
|
|
|
|
message: 'OperationId should be of the form "Noun_Verb"',
|
|
|
|
path: [...path, 'operationId'],
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-09-03 14:49:06 +03:00
|
|
|
const verb = m ? m[1] : operation.operationId;
|
2021-09-01 18:52:53 +03:00
|
|
|
const method = path[path.length - 1];
|
|
|
|
|
2021-09-03 14:49:06 +03:00
|
|
|
const isCreate = ['put', 'patch'].includes(method) && operation.responses?.['201'];
|
|
|
|
const isUpdate = ['put', 'patch'].includes(method) && operation.responses?.['200'];
|
2021-09-01 18:52:53 +03:00
|
|
|
|
2021-09-03 14:49:06 +03:00
|
|
|
if (isCreate && isUpdate) {
|
2021-09-01 18:52:53 +03:00
|
|
|
if (!verb.match(/create/i) || !verb.match(/update/i)) {
|
|
|
|
errors.push({
|
|
|
|
message: `OperationId for ${method} method should contain both "Create" and "Update"`,
|
|
|
|
path: [...path, 'operationId'],
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else {
|
2021-09-03 14:49:06 +03:00
|
|
|
const isList = method === 'get' && operation['x-ms-pageable'];
|
2021-09-01 18:52:53 +03:00
|
|
|
const patterns = {
|
|
|
|
get: isList ? /list/i : /(get|list)/i,
|
2021-09-03 14:49:06 +03:00
|
|
|
put: isCreate ? /create/i : /(create|update)/i,
|
2021-09-01 18:52:53 +03:00
|
|
|
patch: /update/i,
|
|
|
|
delete: /delete/i,
|
|
|
|
};
|
|
|
|
const frags = {
|
|
|
|
get: isList ? '"List"' : '"Get" or "list"',
|
2021-09-03 14:49:06 +03:00
|
|
|
put: isCreate ? '"Create"' : '"Create" or "Update"',
|
2021-09-01 18:52:53 +03:00
|
|
|
patch: '"Update"',
|
|
|
|
delete: '"Delete"',
|
|
|
|
};
|
|
|
|
|
|
|
|
if (patterns[method] && !verb.match(patterns[method])) {
|
|
|
|
// Customize message for list operation
|
|
|
|
if (isList) {
|
|
|
|
errors.push({
|
|
|
|
message: 'OperationId for get method on a collection should contain "List"',
|
|
|
|
path: [...path, 'operationId'],
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
errors.push({
|
|
|
|
message: `OperationId for ${method} method should contain ${frags[method]}`,
|
|
|
|
path: [...path, 'operationId'],
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return errors;
|
|
|
|
};
|