UNPKG

static-analysis

Version:

Performs RegEx Static Analysis On JavaScript Programs To Find Out All Dependencies That Stem From The Given Files.

360 lines (352 loc) 11 kB
#!/usr/bin/env node const path = require('path'); const fs = require('fs'); const os = require('os'); const _module = require('module'); const stream = require('stream'); const t = (a, b = 0, d = !1) => { if (0 === b && !d) { return a; } a = a.split("\n", d ? b + 1 : void 0); return d ? a[a.length - 1] : a.slice(b).join("\n"); }, u = (a, b = !1) => t(a, 2 + (b ? 1 : 0)), v = a => { ({callee:{caller:a}} = a); return a; }; const x = os.homedir; const y = /\s+at.*(?:\(|\s)(.*)\)?/, z = /^(?:(?:(?:node|(?:internal\/[\w/]*|.*node_modules\/(?:IGNORED_MODULES)\/.*)?\w+)\.js:\d+:\d+)|native)/, B = x(), C = a => { const {pretty:b = !1, ignoredModules:d = ["pirates"]} = {}, l = d.join("|"), k = new RegExp(z.source.replace("IGNORED_MODULES", l)); return a.replace(/\\/g, "/").split("\n").filter(e => { e = e.match(y); if (null === e || !e[1]) { return !0; } e = e[1]; return e.includes(".app/Contents/Resources/electron.asar") || e.includes(".app/Contents/Resources/default_app.asar") ? !1 : !k.test(e); }).filter(e => e.trim()).map(e => b ? e.replace(y, (m, f) => m.replace(f, f.replace(B, "~"))) : e).join("\n"); }; function D(a, b, d = !1) { return function(l) { var k = v(arguments), {stack:e} = Error(); const m = t(e, 2, !0), f = (e = l instanceof Error) ? l.message : l; k = [`Error: ${f}`, ...null !== k && a === k || d ? [b] : [m, b]].join("\n"); k = C(k); return Object.assign(e ? l : Error(), {message:f, stack:k}); }; } ;function F(a) { var {stack:b} = Error(); const d = v(arguments); b = u(b, a); return D(d, b, a); } ;async function G(a, b, d) { const l = F(!0); if ("function" != typeof a) { throw Error("Function must be passed."); } if (!a.length) { throw Error(`Function${a.name ? ` ${a.name}` : ""} does not accept any arguments.`); } return await new Promise((k, e) => { const m = (h, c) => h ? (h = l(h), e(h)) : k(d || c); let f = [m]; Array.isArray(b) ? f = [...b, m] : 1 < Array.from(arguments).length && (f = [b, m]); a(...f); }); } ;const H = fs.createReadStream, I = fs.lstat; const J = async a => { try { return await G(I, a); } catch (b) { return null; } }; const K = path.dirname, L = path.join, M = path.parse, N = path.relative, O = path.resolve; const Q = async(a, b) => { b && (b = K(b), a = L(b, a)); var d = await J(a); b = a; let l = !1; if (!d) { if (b = await P(a), !b) { throw Error(`${a}.js or ${a}.jsx is not found.`); } } else { if (d.isDirectory()) { d = !1; let k; a.endsWith("/") || (k = b = await P(a), d = !0); if (!k) { b = await P(L(a, "index")); if (!b) { throw Error(`${d ? `${a}.jsx? does not exist, and ` : ""}index.jsx? file is not found in ${a}`); } l = !0; } } } return {path:a.startsWith(".") ? N("", b) : b, h:l}; }, P = async a => { a = `${a}.js`; let b = await J(a); b || (a = `${a}x`); if (b = await J(a)) { return a; } }; const R = _module.builtinModules; const S = stream.Writable; const aa = (a, b) => { b.once("error", d => { a.emit("error", d); }); return b; }; class ba extends S { constructor(a) { const {binary:b = !1, rs:d = null, ...l} = a || {}, {f:k = F(!0), proxyError:e} = a || {}, m = (f, h) => k(h); super(l); this.a = []; this.b = new Promise((f, h) => { this.on("finish", () => { let c; b ? c = Buffer.concat(this.a) : c = this.a.join(""); f(c); this.a = []; }); this.once("error", c => { if (-1 == c.stack.indexOf("\n")) { m`${c}`; } else { const n = C(c.stack); c.stack = n; e && m`${c}`; } h(c); }); d && aa(this, d).pipe(this); }); } _write(a, b, d) { this.a.push(a); d(); } get c() { return this.b; } } const ca = async a => { ({c:a} = new ba({rs:a, f:F(!0)})); return await a; }; async function T(a) { a = H(a); return await ca(a); } ;function U(a, b) { var d = ["q", "from"]; const l = []; b.replace(a, (k, ...e) => { k = e.slice(0, e.length - 2).reduce((m, f, h) => { h = d[h]; if (!h || void 0 === f) { return m; } m[h] = f; return m; }, {}); l.push(k); }); return l; } ;const da = /^ *import(?:\s+(?:[^\s,]+)\s*,?)?(?:\s*{(?:[^}]+)})?\s+from\s+(['"])(.+?)\1/gm, ea = /^ *import\s+(?:.+?\s*,\s*)?\*\s+as\s+.+?\s+from\s+(['"])(.+?)\1/gm, fa = /^ *import\s+(['"])(.+?)\1/gm, ha = /^ *export\s+(?:{[^}]+?}|\*)\s+from\s+(['"])(.+?)\1/gm, ia = a => [da, ea, fa, ha].reduce((b, d) => { d = U(d, a).map(l => l.from); return [...b, ...d]; }, []); let V; const W = async(a, b, d = {}) => { V || ({root:V} = M(process.cwd())); const {fields:l, soft:k = !1} = d; var e = L(a, "node_modules", b); e = L(e, "package.json"); const m = await J(e); if (m) { a = await ja(e, l); if (void 0 === a) { throw Error(`The package ${N("", e)} does export the module.`); } if (!a.entryExists && !k) { throw Error(`The exported module ${a.main} in package ${b} does not exist.`); } const {entry:f, version:h, packageName:c, main:n, entryExists:p, ...g} = a; return {entry:N("", f), packageJson:N("", e), ...h ? {version:h} : {}, packageName:c, ...n ? {hasMain:!0} : {}, ...p ? {} : {entryExists:!1}, ...g}; } if (a == V && !m) { throw Error(`Package.json for module ${b} not found.`); } return W(L(O(a), ".."), b, d); }, ja = async(a, b = []) => { const d = await T(a); let l, k, e, m, f; try { ({module:l, version:k, name:e, main:m, ...f} = JSON.parse(d)), f = b.reduce((c, n) => { c[n] = f[n]; return c; }, {}); } catch (c) { throw Error(`Could not parse ${a}.`); } a = K(a); b = l || m; if (!b) { if (!await J(L(a, "index.js"))) { return; } b = m = "index.js"; } a = L(a, b); let h; try { ({path:h} = await Q(a)), a = h; } catch (c) { } return {entry:a, version:k, packageName:e, main:!l && m, entryExists:!!h, ...f}; }; const X = a => /^[./]/.test(a), Y = async(a, b, d, l, k = null) => { const e = F(), m = K(a); b = b.map(async f => { if (R.includes(f)) { return {internal:f}; } if (/^[./]/.test(f)) { try { var {path:h} = await Q(f, a); return {entry:h, package:k}; } catch (c) { } } else { { let [p, g, ...q] = f.split("/"); !p.startsWith("@") && g ? (q = [g, ...q], g = p) : g = p.startsWith("@") ? `${p}/${g}` : p; h = {name:g, paths:q.join("/")}; } const {name:c, paths:n} = h; if (n) { const {packageJson:p, packageName:g} = await W(m, c); f = K(p); ({path:f} = await Q(L(f, n))); return {entry:f, package:g}; } } try { const {entry:c, packageJson:n, version:p, packageName:g, hasMain:q, ...r} = await W(m, f, {fields:l}); return g == k ? (console.warn("[static-analysis] Skipping package %s that imports itself in %s", g, a), null) : {entry:c, packageJson:n, version:p, name:g, ...q ? {hasMain:q} : {}, ...r}; } catch (c) { if (d) { return null; } throw e(c); } }); return (await Promise.all(b)).filter(Boolean); }, Z = async(a, b = {}, {nodeModules:d = !0, shallow:l = !1, soft:k = !1, fields:e = [], g:m = {}, mergeSameNodeModules:f = !0, package:h} = {}) => { if (a in b) { return []; } b[a] = 1; var c = await T(a), n = ia(c); c = ka(c); n = d ? n : n.filter(X); c = d ? c : c.filter(X); try { const g = await Y(a, n, k, e, h), q = await Y(a, c, k, e, h); q.forEach(r => { r.required = !0; }); var p = [...g, ...q]; } catch (g) { throw g.message = `${a}\n [!] ${g.message}`, g; } h = f ? p.map(g => { var q = g.name, r = g.version; const w = g.required; if (q && r) { q = `${q}:${r}${w ? "-required" : ""}`; if (r = m[q]) { return r; } m[q] = g; } return g; }) : p; p = h.map(g => ({...g, from:a})); return await h.filter(({entry:g}) => g && !(g in b)).reduce(async(g, {entry:q, hasMain:r, packageJson:w, name:E, package:la}) => { if (w && l) { return g; } g = await g; E = (await Z(q, b, {nodeModules:d, shallow:l, soft:k, fields:e, package:E || la, g:m, mergeSameNodeModules:f})).map(A => ({...A, from:A.from ? A.from : q, ...!A.packageJson && r ? {hasMain:r} : {}})); return [...g, ...E]; }, p); }, ka = a => U(/(?:^|[^\w\d_])require\(\s*(['"])(.+?)\1\s*\)/gm, a).map(b => b.from); /* static-analysis: Performs RegEx Static Analysis On JavaScript Programs To Find Out All Dependencies That Stem From The Given Files. Copyright (C) 2019 Art Deco This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ module.exports = {_staticAnalysis:async(a, b = {}) => { const d = F(); a = Array.isArray(a) ? a : [a]; a = await Promise.all(a.map(async c => { ({path:c} = await Q(c)); return c; })); const {nodeModules:l = !0, shallow:k = !1, soft:e = !1, fields:m = [], mergeSameNodeModules:f = !0} = b; let h; try { const c = {}; h = await a.reduce(async(n, p) => { n = await n; p = await Z(p, c, {nodeModules:l, shallow:k, soft:e, fields:m, mergeSameNodeModules:f}); n.push(...p); return n; }, []); } catch (c) { throw d(c); } return h.filter(({internal:c, entry:n}, p) => c ? h.findIndex(({internal:g}) => g == c) == p : h.findIndex(({entry:g}) => n == g) == p).map(c => { const n = c.entry, p = c.internal, g = h.filter(({internal:q, entry:r}) => { if (p) { return p == q; } if (n) { return n == r; } }).map(({from:q}) => q).filter((q, r, w) => w.indexOf(q) == r); return {...c, from:g}; }).map(({package:c, ...n}) => c ? {package:c, ...n} : n); }, _sort:a => { const b = [], d = [], l = [], k = [], e = [], m = []; a.forEach(({packageJson:f, hasMain:h, name:c, entry:n, internal:p}) => { if (p) { return e.push(p); } f && h ? d.push(f) : f && b.push(f); n && h ? l.push(n) : n && k.push(n); c && m.push(c); }); return {commonJsPackageJsons:d, packageJsons:b, commonJs:l, js:k, internals:e, deps:m}; }}; //# sourceMappingURL=depack.js.map