UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

160 lines 6.55 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.blobTuple = void 0; exports.cranBlobUrl = cranBlobUrl; exports.tupleToBlob = tupleToBlob; exports.signatureParameterNames = signatureParameterNames; exports.transitiveCallees = transitiveCallees; exports.decodeFunction = decodeFunction; exports.decodeDependencies = decodeDependencies; exports.versionFnIndices = versionFnIndices; exports.deriveLibraryExports = deriveLibraryExports; /** * Decoding a {@link PkgBlob} into the reader-facing views: the on-disk tuple form, the decoded function/ * dependency records, and the {@link LibraryExports} export view. Pure -- no I/O, no mutation of inputs. * Split out of `../sigdb` so the reader/writer there does not carry the per-record decoding. */ const schema_1 = require("./schema"); const sigdb_version_1 = require("./sigdb-version"); /** * Reconstruct the CRAN source blob link which is the newest non-archived version lives under `src/contrib`, * every other under `Archive`. */ function cranBlobUrl(cranBase, pkg, version, opts) { if (!opts.cran) { return undefined; } const base = cranBase.endsWith('/') ? cranBase : cranBase + '/'; return version === opts.latest && !opts.archived ? `${base}${pkg}_${version}.tar.gz` : `${base}Archive/${pkg}/${pkg}_${version}.tar.gz`; } /** a {@link PkgBlob} in its compact on-disk tuple form (drops the trailing `dates` when empty) */ const blobTuple = (b) => Object.keys(b.dates).length > 0 ? [b.sigs, b.cgs, b.fns, b.versions, b.noncran ?? [], b.deps, b.depsByVersion, b.dates] : [b.sigs, b.cgs, b.fns, b.versions, b.noncran ?? [], b.deps, b.depsByVersion]; exports.blobTuple = blobTuple; /** the inverse of {@link blobTuple}: rebuild a {@link PkgBlob} from its on-disk tuple */ function tupleToBlob(t) { return { sigs: t[0], cgs: t[1], fns: t[2], versions: t[3], noncran: t[4]?.length ? t[4] : undefined, deps: t[5] ?? [], depsByVersion: t[6] ?? {}, dates: t[7] ?? {} }; } /** * The formal parameter names of a known signature, ready for `RFunctionCall.matchArgumentsToParameters`: the * `...` parameter is excluded so partial (`pmatch`) matches against the remaining names stay unambiguous. */ function signatureParameterNames(signature) { return signature.map(p => p.name).filter(n => n !== '...'); } /** * The transitive callees of `name`. Each local callee that is itself a function of `functions` (one package * version's set) is expanded, names outside the set stay as leaves. Deduplicated and ascending. */ function transitiveCallees(functions, name) { const local = new Map(functions.map(f => [f.name, f.callees])); const reached = new Set(); const queue = [...(local.get(name) ?? [])]; while (queue.length > 0) { const callee = queue.pop(); if (reached.has(callee)) { continue; } reached.add(callee); const inner = local.get(callee); if (inner !== undefined) { queue.push(...inner); } } return [...reached].sort(); } /** decode one of a blob's function records against the global string dictionary */ function decodeFunction(strings, blob, fnIdx) { const [nameIdx, sigIdx, cgIdx, bits, fileIdx, line, topicIdx] = blob.fns[fnIdx]; const signature = (sigIdx >= 0 ? blob.sigs[sigIdx] : []).map(p => { const [n, flags, def] = Array.isArray(p) ? [p[0], p[1], p.length === 3 ? p[2] : -1] : [p, 0, -1]; return { name: strings[n], forced: Boolean(flags & 1 /* ParamFlag.Forced */), optional: !(flags & 2 /* ParamFlag.Missing */), ...(def >= 0 ? { default: strings[def] } : {}) }; }); let callees = []; if (cgIdx >= 0) { let prev = 0; callees = blob.cgs[cgIdx].map(d => strings[prev += d]); } return { name: strings[nameIdx], ...(topicIdx !== undefined && topicIdx >= 0 ? { topic: strings[topicIdx] } : {}), ...(fileIdx >= 0 ? { file: strings[fileIdx] } : {}), line, exported: Boolean(bits & 1 /* FnProp.Exported */), props: Object.entries(schema_1.FnPropNames).filter(([m]) => bits & Number(m)).map(([, n]) => n), signature, callees }; } /** decode the declared dependencies of one blob version (empty when it declares none / the bundle omits them) */ function decodeDependencies(strings, blob, ver) { const idx = blob.depsByVersion[ver]; if (idx === undefined) { return []; } return blob.deps[idx].map(d => ({ name: strings[d[0]], type: d[1], ...(d.length === 3 ? { constraint: strings[d[2]] } : {}) })); } /** the function indices of a blob version (undoing the delta encoding) */ function versionFnIndices(blob, ver) { const list = blob.versions[ver]; if (list === undefined) { return undefined; } const out = []; let prev = 0; for (const d of list) { out.push(prev += d); } return out; } /** derive the {@link LibraryExports} export view of one package version from its blob + metadata */ function deriveLibraryExports(strings, blob, meta, pkg, version, cranBase = schema_1.DefaultCranBase) { const [latest, archived] = meta; const ver = (0, sigdb_version_1.resolveVersion)(blob, latest, version); if (ver === undefined) { return undefined; } const idxs = versionFnIndices(blob, ver) ?? []; const exported = []; const internal = []; const deprecated = []; const s3Classes = []; const s4Classes = []; const locations = new Map(); for (const i of idxs) { const [nameIdx, , , bits, fileIdx, line] = blob.fns[i]; const name = strings[nameIdx]; (bits & 1 /* FnProp.Exported */ ? exported : internal).push(name); if (bits & 32 /* FnProp.Deprecated */) { deprecated.push(name); } if (bits & 1024 /* FnProp.S3Owner */) { s3Classes.push(name); } if (bits & 2048 /* FnProp.S4Owner */) { s4Classes.push(name); } if (fileIdx >= 0) { locations.set(name, { file: strings[fileIdx], line }); } } const cran = !blob.noncran?.includes(ver); return { version: ver, exported, internal, deprecated, s3Classes, s4Classes, cran, cranUrl: cranBlobUrl(cranBase, pkg, ver, { latest, archived: archived === 1, cran }), ...(locations.size > 0 ? { locations } : {}) }; } //# sourceMappingURL=decode.js.map