functions/param-order.js (36 lines of code) (raw):

// Check conformance to Azure parameter order conventions: // - path parameters must be in the same order as the path // NOTE: Missing path parameters will be flagged by the Spectral path-params rule // `given` is the paths object module.exports = (paths) => { if (paths === null || typeof paths !== 'object') { return []; } const inPath = (p) => p.in === 'path'; const paramName = (p) => p.name; const methods = ['get', 'post', 'put', 'patch', 'delete', 'options', 'head']; const errors = []; // eslint-disable-next-line no-restricted-syntax for (const pathKey of Object.keys(paths)) { // find all the path parameters in pathKey const paramsInPath = pathKey.match(/[^{}]+(?=})/g) ?? []; if (paramsInPath.length > 0) { const pathItem = paths[pathKey]; const pathItemPathParams = pathItem.parameters?.filter(inPath).map(paramName) ?? []; // find the first index where in-consistency observed or offset till no in-consistency // observed to validate further const indx = pathItemPathParams.findIndex((v, i) => v !== paramsInPath[i]); // If path params exists and are not in expected order then raise the error if (indx >= 0 && indx < paramsInPath.length) { // NOTE: we do not include `indx` in the path because if the parameter is a ref then // Spectral will show the path of the ref'ed parameter and not the path/operation with // improper ordering errors.push({ message: `Path parameter "${paramsInPath[indx]}" should appear before "${pathItemPathParams[indx]}".`, path: ['paths', pathKey, 'parameters'], // no index in path }); } else { // this will be a case when few path params are defined in respective methods const offset = pathItemPathParams.length; methods.filter((m) => pathItem[m]).forEach((method) => { const opPathParams = pathItem[method].parameters?.filter(inPath).map(paramName) ?? []; const indx2 = opPathParams.findIndex((v, i) => v !== paramsInPath[offset + i]); if (indx2 >= 0 && (offset + indx2) < paramsInPath.length) { errors.push({ message: `Path parameter "${paramsInPath[offset + indx2]}" should appear before "${opPathParams[indx2]}".`, path: ['paths', pathKey, method, 'parameters'], // no index in path }); } }); } } } return errors; };