UNPKG

json-machete

Version:
189 lines (188 loc) • 7.83 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.resolvePath = void 0; exports.getAbsolutePath = getAbsolutePath; exports.getCwd = getCwd; exports.dereferenceObject = dereferenceObject; const tslib_1 = require("tslib"); const json_pointer_1 = tslib_1.__importDefault(require("json-pointer")); const url_join_1 = tslib_1.__importDefault(require("url-join")); const healUntitledDefinitions_js_1 = require("./healUntitledDefinitions.js"); const resolvePath = (path, root) => { try { return json_pointer_1.default.get(root, path); } catch (e) { if (e.message?.startsWith('Invalid reference')) { return undefined; } throw e; } }; exports.resolvePath = resolvePath; function isUrl(str) { return /^https?:\/\//.test(str); } function isRefObject(obj) { return typeof obj === 'object' && typeof obj.$ref === 'string'; } const getAbsolute$Ref = (given$ref, baseFilePath) => { const [givenExternalFileRelativePath, givenRefPath] = given$ref.split('#'); if (givenExternalFileRelativePath) { const cwd = getCwd(baseFilePath); const givenExternalFilePath = getAbsolutePath(givenExternalFileRelativePath, cwd); if (givenRefPath) { return `${givenExternalFilePath}#${givenRefPath}`; } return givenExternalFilePath; } return `${baseFilePath}#${givenRefPath}`; }; function normalizeUrl(url) { return new URL(url).toString(); } function getAbsolutePath(path, cwd) { if (isUrl(path)) { return path; } if (isUrl(cwd)) { return normalizeUrl((0, url_join_1.default)(cwd, path)); } if (path.startsWith('/') || path.substring(1).startsWith(':\\')) { return path; } return cwd + '/' + path; } function getCwd(path) { const pathParts = path.split('/'); pathParts.pop(); return pathParts.join('/'); } async function dereferenceObject(obj, { cwd = globalThis?.process.cwd(), fetch, externalFileCache = new Map(), refMap = new Map(), root = obj, debugLogFn, readFileOrUrl, resolvedObjects = new WeakSet(), }) { if (obj != null && typeof obj === 'object') { if (isRefObject(obj)) { const $ref = obj.$ref; if (refMap.has($ref)) { return refMap.get($ref); } else { debugLogFn?.(`Resolving ${$ref}`); const [externalRelativeFilePath, refPath] = $ref.split('#'); if (externalRelativeFilePath) { const externalFilePath = getAbsolutePath(externalRelativeFilePath, cwd); const newCwd = getCwd(externalFilePath); let externalFile = externalFileCache.get(externalFilePath); if (!externalFile) { try { externalFile = await readFileOrUrl(externalFilePath, { cwd, fetch }); } catch (e) { console.error(e); throw new Error(`Unable to load ${externalRelativeFilePath} from ${cwd}`); } externalFileCache.set(externalFilePath, externalFile); // Title should not be overwritten by the title given from the reference // Usually Swagger and OpenAPI Schemas have this (0, healUntitledDefinitions_js_1.handleUntitledDefinitions)(externalFile); } const result = await dereferenceObject(refPath ? { $ref: `#${refPath}`, } : externalFile, { cwd: newCwd, externalFileCache, refMap: new Proxy(refMap, { get: (originalRefMap, key) => { switch (key) { case 'has': return (given$ref) => { const original$Ref = getAbsolute$Ref(given$ref, externalFilePath); return originalRefMap.has(original$Ref); }; case 'get': return (given$ref) => { const original$Ref = getAbsolute$Ref(given$ref, externalFilePath); return originalRefMap.get(original$Ref); }; case 'set': return (given$ref, val) => { const original$Ref = getAbsolute$Ref(given$ref, externalFilePath); return originalRefMap.set(original$Ref, val); }; } throw new Error('Not implemented ' + key.toString()); }, }), debugLogFn, readFileOrUrl, root: externalFile, resolvedObjects, fetch, }); refMap.set($ref, result); resolvedObjects.add(result); if (result && !result.$resolvedRef) { result.$resolvedRef = refPath; } if (obj.title && !result.title) { result.title = obj.title; } return result; } else { const resolvedObj = (0, exports.resolvePath)(refPath, root); if (resolvedObjects.has(resolvedObj)) { refMap.set($ref, resolvedObj); return resolvedObj; } /* if (resolvedObj && !resolvedObj.$resolvedRef) { resolvedObj.$resolvedRef = refPath; } */ const result = await dereferenceObject(resolvedObj, { cwd, fetch, externalFileCache, refMap, root, debugLogFn, readFileOrUrl, resolvedObjects, }); if (!result) { return obj; } resolvedObjects.add(result); refMap.set($ref, result); if (!result.$resolvedRef) { result.$resolvedRef = refPath; } return result; } } } else { if (!resolvedObjects.has(obj)) { resolvedObjects.add(obj); for (const key in obj) { const val = obj[key]; if (typeof val === 'object') { obj[key] = await dereferenceObject(val, { cwd, externalFileCache, refMap, root, debugLogFn, readFileOrUrl, resolvedObjects, fetch, }); } } } } } return obj; }