UNPKG

myst-cli

Version:
105 lines (104 loc) 3.53 kB
import { RuleId, plural, fileError, toText } from 'myst-common'; import { selectAll } from 'unist-util-select'; import { computeHash, tic } from 'myst-cli-utils'; import { loadFromCache, writeToCache } from '../session/cache.js'; const ROR_MAX_AGE = 30; // in days /** * Build a path to the cache-file for the given ROR * * @param session: CLI session * @param ror: normalized ROR ID */ function rorCacheFilename(ror) { return `ror-${computeHash(ror)}.json`; } /** * Resolve the given ror.org ID into JSON data about the organization * * @param session - CLI session * @param ror - ror.org ID */ export async function resolveRORAsJSON(session, ror) { const url = `https://api.ror.org/organizations/${ror}`; session.log.debug(`Fetching ROR JSON from ${url}`); const response = await session.fetch(url).catch(() => { session.log.debug(`Request to ${url} failed.`); return undefined; }); if (!response || !response.ok) { session.log.debug(`ROR fetch failed for ${url}`); return undefined; } const data = (await response.json()); return data; } /** * Fetch organization data for the given ROR ID in JSON * * @param session - CLI session * @param vfile * @param node * @param ror - ror ID (does not include the https://ror.org) */ export async function resolveROR(session, vfile, node, ror) { if (!ror) return undefined; // Cache ROR resolution as JSON const filename = rorCacheFilename(ror); const cached = loadFromCache(session, filename, { maxAge: ROR_MAX_AGE }); if (cached) return JSON.parse(cached); const toc = tic(); let data; try { data = await resolveRORAsJSON(session, ror); if (data) { session.log.debug(toc(`Fetched ROR JSON for ror:${ror} in %s`)); } else { fileError(vfile, `Could not find ROR "${ror}" from https://ror.org/${ror}`, { node, ruleId: RuleId.rorLinkValid, note: `Please check the ROR is correct and has a page at https://ror.org/${ror}`, }); session.log.debug(`JSON not available from ror.org for ror:${ror}`); } } catch (error) { session.log.debug(`JSON from ror.org was malformed for ror:${ror}`); } if (!data) return undefined; writeToCache(session, filename, JSON.stringify(data)); return data; } /** * Find in-line RORs and add default text */ export async function transformLinkedRORs(session, vfile, mdast, path) { const toc = tic(); const linkedRORs = selectAll('link[protocol=ror]', mdast); if (linkedRORs.length === 0) return; session.log.debug(`Found ${plural('%s ROR(s)', linkedRORs.length)} to auto link.`); let number = 0; await Promise.all([ ...linkedRORs.map(async (node) => { var _a; const ror = (_a = node.data) === null || _a === void 0 ? void 0 : _a.ror; if (!ror) return; number += 1; const rorData = await resolveROR(session, vfile, node, ror); if (rorData && toText(node.children) === ror) { // If the link text is the ROR, update with a organization name node.children = [{ type: 'text', value: rorData.name }]; } return true; }), ]); if (number > 0) { session.log.info(toc(`🪄 Linked ${plural('%s ROR(s)', number)} in %s for ${path}`)); } return; }