UNPKG

openapi-path-templating

Version:

OpenAPI Path Templating parser, validator, resolver and matcher.

53 lines (50 loc) 2 kB
import parse from "../parse/index.mjs"; /** * Implementation of https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.3 */ const significantTypes = ['slash', 'path-literal', 'template-expression']; const pathSegmentNormalizer = pathTemplate => { const parseResult = parse(pathTemplate); if (!parseResult.result.success) return pathTemplate; const parts = []; const stack = []; parseResult.ast.translate(parts); for (let i = 0; i < parts.length; i += 1) { let [type, value] = parts[i]; // remove `template-expression-param-name` and treat `template-expression` as `path-literal` if (type === 'template-expression-param-name') { continue; // skip this segment } if (type === 'path-literal' || type === 'template-expression') { if (value === '.') continue; // ignore '.' segments if (value === '..') { // handle '..' segments if (stack.length > 1) { let last = stack.pop(); // remove preceding segment if (last[0] === 'slash' && stack.length > 0) { stack.pop(); // remove preceding slash if present } } continue; // move to the next segment } stack.push([type, value]); // push valid path-literals } else if (type === 'slash') { var _stack; // only add slash if the last item on the stack is not a slash if (((_stack = stack[stack.length - 1]) === null || _stack === void 0 ? void 0 : _stack[0]) !== 'slash') { stack.push([type, value]); } } else { stack.push([type, value]); // preserve all other types } } const normalizedPathTemplate = stack.reduce((pathTemplateNormalized, [type, value]) => { if (significantTypes.includes(type)) { return `${pathTemplateNormalized}${value}`; } return pathTemplateNormalized; }, ''); // makes sure the root path is represented as '/' return normalizedPathTemplate === '' ? '/' : normalizedPathTemplate; }; export default pathSegmentNormalizer;