UNPKG

koas-core

Version:

> [Koa][] + [OpenAPI Specification][] = Koas

82 lines (81 loc) 2.94 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createResolver = exports.unescapeJsonPointer = exports.escapeJsonPointer = void 0; const util_1 = require("util"); /** * Escape a JSON pointer segment. * * See https://tools.ietf.org/html/rfc6901#section-3 * * @param pointer - THe JSON pointer segment to escape. * @returns The escaped JSON pointer segment. */ function escapeJsonPointer(pointer) { return pointer.replace(/~/g, '~0').replace(/\//g, '~1'); } exports.escapeJsonPointer = escapeJsonPointer; /** * Unescape a JSON pointer segment. * * See https://tools.ietf.org/html/rfc6901#section-3 * * @param pointer - The JSON pointer segment to unescape * @returns The unescaped JSON pointer segment. */ function unescapeJsonPointer(pointer) { return pointer.replace(/~1/g, '/').replace(/~0/g, '~'); } exports.unescapeJsonPointer = unescapeJsonPointer; /** * Create a function to resolve a JSON pointer from an OpenAPI document with caching. * * @param document - The OpenAPI document to create a resolver for. * @returns A JSON ref resolver. */ function createResolver(document) { const cache = new Map(); // eslint-disable-next-line @typescript-eslint/no-explicit-any const resolver = (ref, stack) => { // Null, undefined if (!ref) { return ref; } // Primitives if (typeof ref !== 'object') { return ref; } // Non reference objects if (!('$ref' in ref)) { return ref; } const { $ref } = ref; if (typeof $ref !== 'string') { throw new TypeError(`Invalid JSON pointer. Expected a string. Got: ${(0, util_1.inspect)($ref)}`); } if (stack.includes($ref)) { throw new Error(`Circular JSON reference found: ${stack .map((frame) => (0, util_1.inspect)(frame)) .concat($ref) .join(' → ')}`); } if (cache.has($ref)) { return cache.get($ref); } const [hashtag, ...segments] = $ref.split('/').map(unescapeJsonPointer); if (hashtag !== '#') { throw new TypeError(`Invalid JSON pointer. It should start with '#/'. Got: ${(0, util_1.inspect)($ref)}`); } // eslint-disable-next-line @typescript-eslint/no-explicit-any const result = segments.reduce((acc, name) => { if (acc && typeof acc === 'object' && name in acc) { return acc[name]; } throw new Error(`Unresolved JSON pointer: ${(0, util_1.inspect)($ref)}. Property ${(0, util_1.inspect)(name)} could not be resolved.`); }, document); const dereferenced = resolver(result, [...stack, $ref]); cache.set($ref, dereferenced); return dereferenced; }; return (ref) => resolver(ref, []); } exports.createResolver = createResolver;