11cb0ef41Sopenharmony_ci'use strict' 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ci// walk the tree of deps starting from the top level list of bundled deps 41cb0ef41Sopenharmony_ci// Any deps at the top level that are depended on by a bundled dep that 51cb0ef41Sopenharmony_ci// does not have that dep in its own node_modules folder are considered 61cb0ef41Sopenharmony_ci// bundled deps as well. This list of names can be passed to npm-packlist 71cb0ef41Sopenharmony_ci// as the "bundled" argument. Additionally, packageJsonCache is shared so 81cb0ef41Sopenharmony_ci// packlist doesn't have to re-read files already consumed in this pass 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ciconst fs = require('fs') 111cb0ef41Sopenharmony_ciconst path = require('path') 121cb0ef41Sopenharmony_ciconst EE = require('events').EventEmitter 131cb0ef41Sopenharmony_ci// we don't care about the package bins, but we share a pj cache 141cb0ef41Sopenharmony_ci// with other modules that DO care about it, so keep it nice. 151cb0ef41Sopenharmony_ciconst normalizePackageBin = require('npm-normalize-package-bin') 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_ciclass BundleWalker extends EE { 181cb0ef41Sopenharmony_ci constructor (opt) { 191cb0ef41Sopenharmony_ci opt = opt || {} 201cb0ef41Sopenharmony_ci super(opt) 211cb0ef41Sopenharmony_ci this.path = path.resolve(opt.path || process.cwd()) 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_ci this.parent = opt.parent || null 241cb0ef41Sopenharmony_ci if (this.parent) { 251cb0ef41Sopenharmony_ci this.result = this.parent.result 261cb0ef41Sopenharmony_ci // only collect results in node_modules folders at the top level 271cb0ef41Sopenharmony_ci // since the node_modules in a bundled dep is included always 281cb0ef41Sopenharmony_ci if (!this.parent.parent) { 291cb0ef41Sopenharmony_ci const base = path.basename(this.path) 301cb0ef41Sopenharmony_ci const scope = path.basename(path.dirname(this.path)) 311cb0ef41Sopenharmony_ci this.result.add(/^@/.test(scope) ? scope + '/' + base : base) 321cb0ef41Sopenharmony_ci } 331cb0ef41Sopenharmony_ci this.root = this.parent.root 341cb0ef41Sopenharmony_ci this.packageJsonCache = this.parent.packageJsonCache 351cb0ef41Sopenharmony_ci } else { 361cb0ef41Sopenharmony_ci this.result = new Set() 371cb0ef41Sopenharmony_ci this.root = this.path 381cb0ef41Sopenharmony_ci this.packageJsonCache = opt.packageJsonCache || new Map() 391cb0ef41Sopenharmony_ci } 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_ci this.seen = new Set() 421cb0ef41Sopenharmony_ci this.didDone = false 431cb0ef41Sopenharmony_ci this.children = 0 441cb0ef41Sopenharmony_ci this.node_modules = [] 451cb0ef41Sopenharmony_ci this.package = null 461cb0ef41Sopenharmony_ci this.bundle = null 471cb0ef41Sopenharmony_ci } 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ci addListener (ev, fn) { 501cb0ef41Sopenharmony_ci return this.on(ev, fn) 511cb0ef41Sopenharmony_ci } 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ci on (ev, fn) { 541cb0ef41Sopenharmony_ci const ret = super.on(ev, fn) 551cb0ef41Sopenharmony_ci if (ev === 'done' && this.didDone) { 561cb0ef41Sopenharmony_ci this.emit('done', this.result) 571cb0ef41Sopenharmony_ci } 581cb0ef41Sopenharmony_ci return ret 591cb0ef41Sopenharmony_ci } 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ci done () { 621cb0ef41Sopenharmony_ci if (!this.didDone) { 631cb0ef41Sopenharmony_ci this.didDone = true 641cb0ef41Sopenharmony_ci if (!this.parent) { 651cb0ef41Sopenharmony_ci const res = Array.from(this.result) 661cb0ef41Sopenharmony_ci this.result = res 671cb0ef41Sopenharmony_ci this.emit('done', res) 681cb0ef41Sopenharmony_ci } else { 691cb0ef41Sopenharmony_ci this.emit('done') 701cb0ef41Sopenharmony_ci } 711cb0ef41Sopenharmony_ci } 721cb0ef41Sopenharmony_ci } 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_ci start () { 751cb0ef41Sopenharmony_ci const pj = path.resolve(this.path, 'package.json') 761cb0ef41Sopenharmony_ci if (this.packageJsonCache.has(pj)) { 771cb0ef41Sopenharmony_ci this.onPackage(this.packageJsonCache.get(pj)) 781cb0ef41Sopenharmony_ci } else { 791cb0ef41Sopenharmony_ci this.readPackageJson(pj) 801cb0ef41Sopenharmony_ci } 811cb0ef41Sopenharmony_ci return this 821cb0ef41Sopenharmony_ci } 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ci readPackageJson (pj) { 851cb0ef41Sopenharmony_ci fs.readFile(pj, (er, data) => 861cb0ef41Sopenharmony_ci er ? this.done() : this.onPackageJson(pj, data)) 871cb0ef41Sopenharmony_ci } 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_ci onPackageJson (pj, data) { 901cb0ef41Sopenharmony_ci try { 911cb0ef41Sopenharmony_ci this.package = normalizePackageBin(JSON.parse(data + '')) 921cb0ef41Sopenharmony_ci } catch (er) { 931cb0ef41Sopenharmony_ci return this.done() 941cb0ef41Sopenharmony_ci } 951cb0ef41Sopenharmony_ci this.packageJsonCache.set(pj, this.package) 961cb0ef41Sopenharmony_ci this.onPackage(this.package) 971cb0ef41Sopenharmony_ci } 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ci allDepsBundled (pkg) { 1001cb0ef41Sopenharmony_ci return Object.keys(pkg.dependencies || {}).concat( 1011cb0ef41Sopenharmony_ci Object.keys(pkg.optionalDependencies || {})) 1021cb0ef41Sopenharmony_ci } 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_ci onPackage (pkg) { 1051cb0ef41Sopenharmony_ci // all deps are bundled if we got here as a child. 1061cb0ef41Sopenharmony_ci // otherwise, only bundle bundledDeps 1071cb0ef41Sopenharmony_ci // Get a unique-ified array with a short-lived Set 1081cb0ef41Sopenharmony_ci const bdRaw = this.parent ? this.allDepsBundled(pkg) 1091cb0ef41Sopenharmony_ci : pkg.bundleDependencies || pkg.bundledDependencies || [] 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_ci const bd = Array.from(new Set( 1121cb0ef41Sopenharmony_ci Array.isArray(bdRaw) ? bdRaw 1131cb0ef41Sopenharmony_ci : bdRaw === true ? this.allDepsBundled(pkg) 1141cb0ef41Sopenharmony_ci : Object.keys(bdRaw))) 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ci if (!bd.length) { 1171cb0ef41Sopenharmony_ci return this.done() 1181cb0ef41Sopenharmony_ci } 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci this.bundle = bd 1211cb0ef41Sopenharmony_ci this.readModules() 1221cb0ef41Sopenharmony_ci } 1231cb0ef41Sopenharmony_ci 1241cb0ef41Sopenharmony_ci readModules () { 1251cb0ef41Sopenharmony_ci readdirNodeModules(this.path + '/node_modules', (er, nm) => 1261cb0ef41Sopenharmony_ci er ? this.onReaddir([]) : this.onReaddir(nm)) 1271cb0ef41Sopenharmony_ci } 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci onReaddir (nm) { 1301cb0ef41Sopenharmony_ci // keep track of what we have, in case children need it 1311cb0ef41Sopenharmony_ci this.node_modules = nm 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_ci this.bundle.forEach(dep => this.childDep(dep)) 1341cb0ef41Sopenharmony_ci if (this.children === 0) { 1351cb0ef41Sopenharmony_ci this.done() 1361cb0ef41Sopenharmony_ci } 1371cb0ef41Sopenharmony_ci } 1381cb0ef41Sopenharmony_ci 1391cb0ef41Sopenharmony_ci childDep (dep) { 1401cb0ef41Sopenharmony_ci if (this.node_modules.indexOf(dep) !== -1) { 1411cb0ef41Sopenharmony_ci if (!this.seen.has(dep)) { 1421cb0ef41Sopenharmony_ci this.seen.add(dep) 1431cb0ef41Sopenharmony_ci this.child(dep) 1441cb0ef41Sopenharmony_ci } 1451cb0ef41Sopenharmony_ci } else if (this.parent) { 1461cb0ef41Sopenharmony_ci this.parent.childDep(dep) 1471cb0ef41Sopenharmony_ci } 1481cb0ef41Sopenharmony_ci } 1491cb0ef41Sopenharmony_ci 1501cb0ef41Sopenharmony_ci child (dep) { 1511cb0ef41Sopenharmony_ci const p = this.path + '/node_modules/' + dep 1521cb0ef41Sopenharmony_ci this.children += 1 1531cb0ef41Sopenharmony_ci const child = new BundleWalker({ 1541cb0ef41Sopenharmony_ci path: p, 1551cb0ef41Sopenharmony_ci parent: this, 1561cb0ef41Sopenharmony_ci }) 1571cb0ef41Sopenharmony_ci child.on('done', _ => { 1581cb0ef41Sopenharmony_ci if (--this.children === 0) { 1591cb0ef41Sopenharmony_ci this.done() 1601cb0ef41Sopenharmony_ci } 1611cb0ef41Sopenharmony_ci }) 1621cb0ef41Sopenharmony_ci child.start() 1631cb0ef41Sopenharmony_ci } 1641cb0ef41Sopenharmony_ci} 1651cb0ef41Sopenharmony_ci 1661cb0ef41Sopenharmony_ciclass BundleWalkerSync extends BundleWalker { 1671cb0ef41Sopenharmony_ci start () { 1681cb0ef41Sopenharmony_ci super.start() 1691cb0ef41Sopenharmony_ci this.done() 1701cb0ef41Sopenharmony_ci return this 1711cb0ef41Sopenharmony_ci } 1721cb0ef41Sopenharmony_ci 1731cb0ef41Sopenharmony_ci readPackageJson (pj) { 1741cb0ef41Sopenharmony_ci try { 1751cb0ef41Sopenharmony_ci this.onPackageJson(pj, fs.readFileSync(pj)) 1761cb0ef41Sopenharmony_ci } catch { 1771cb0ef41Sopenharmony_ci // empty catch 1781cb0ef41Sopenharmony_ci } 1791cb0ef41Sopenharmony_ci return this 1801cb0ef41Sopenharmony_ci } 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ci readModules () { 1831cb0ef41Sopenharmony_ci try { 1841cb0ef41Sopenharmony_ci this.onReaddir(readdirNodeModulesSync(this.path + '/node_modules')) 1851cb0ef41Sopenharmony_ci } catch { 1861cb0ef41Sopenharmony_ci this.onReaddir([]) 1871cb0ef41Sopenharmony_ci } 1881cb0ef41Sopenharmony_ci } 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci child (dep) { 1911cb0ef41Sopenharmony_ci new BundleWalkerSync({ 1921cb0ef41Sopenharmony_ci path: this.path + '/node_modules/' + dep, 1931cb0ef41Sopenharmony_ci parent: this, 1941cb0ef41Sopenharmony_ci }).start() 1951cb0ef41Sopenharmony_ci } 1961cb0ef41Sopenharmony_ci} 1971cb0ef41Sopenharmony_ci 1981cb0ef41Sopenharmony_ciconst readdirNodeModules = (nm, cb) => { 1991cb0ef41Sopenharmony_ci fs.readdir(nm, (er, set) => { 2001cb0ef41Sopenharmony_ci if (er) { 2011cb0ef41Sopenharmony_ci cb(er) 2021cb0ef41Sopenharmony_ci } else { 2031cb0ef41Sopenharmony_ci const scopes = set.filter(f => /^@/.test(f)) 2041cb0ef41Sopenharmony_ci if (!scopes.length) { 2051cb0ef41Sopenharmony_ci cb(null, set) 2061cb0ef41Sopenharmony_ci } else { 2071cb0ef41Sopenharmony_ci const unscoped = set.filter(f => !/^@/.test(f)) 2081cb0ef41Sopenharmony_ci let count = scopes.length 2091cb0ef41Sopenharmony_ci scopes.forEach(scope => { 2101cb0ef41Sopenharmony_ci fs.readdir(nm + '/' + scope, (readdirEr, pkgs) => { 2111cb0ef41Sopenharmony_ci if (readdirEr || !pkgs.length) { 2121cb0ef41Sopenharmony_ci unscoped.push(scope) 2131cb0ef41Sopenharmony_ci } else { 2141cb0ef41Sopenharmony_ci unscoped.push.apply(unscoped, pkgs.map(p => scope + '/' + p)) 2151cb0ef41Sopenharmony_ci } 2161cb0ef41Sopenharmony_ci if (--count === 0) { 2171cb0ef41Sopenharmony_ci cb(null, unscoped) 2181cb0ef41Sopenharmony_ci } 2191cb0ef41Sopenharmony_ci }) 2201cb0ef41Sopenharmony_ci }) 2211cb0ef41Sopenharmony_ci } 2221cb0ef41Sopenharmony_ci } 2231cb0ef41Sopenharmony_ci }) 2241cb0ef41Sopenharmony_ci} 2251cb0ef41Sopenharmony_ci 2261cb0ef41Sopenharmony_ciconst readdirNodeModulesSync = nm => { 2271cb0ef41Sopenharmony_ci const set = fs.readdirSync(nm) 2281cb0ef41Sopenharmony_ci const unscoped = set.filter(f => !/^@/.test(f)) 2291cb0ef41Sopenharmony_ci const scopes = set.filter(f => /^@/.test(f)).map(scope => { 2301cb0ef41Sopenharmony_ci try { 2311cb0ef41Sopenharmony_ci const pkgs = fs.readdirSync(nm + '/' + scope) 2321cb0ef41Sopenharmony_ci return pkgs.length ? pkgs.map(p => scope + '/' + p) : [scope] 2331cb0ef41Sopenharmony_ci } catch (er) { 2341cb0ef41Sopenharmony_ci return [scope] 2351cb0ef41Sopenharmony_ci } 2361cb0ef41Sopenharmony_ci }).reduce((a, b) => a.concat(b), []) 2371cb0ef41Sopenharmony_ci return unscoped.concat(scopes) 2381cb0ef41Sopenharmony_ci} 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ciconst walk = (options, callback) => { 2411cb0ef41Sopenharmony_ci const p = new Promise((resolve, reject) => { 2421cb0ef41Sopenharmony_ci new BundleWalker(options).on('done', resolve).on('error', reject).start() 2431cb0ef41Sopenharmony_ci }) 2441cb0ef41Sopenharmony_ci return callback ? p.then(res => callback(null, res), callback) : p 2451cb0ef41Sopenharmony_ci} 2461cb0ef41Sopenharmony_ci 2471cb0ef41Sopenharmony_ciconst walkSync = options => { 2481cb0ef41Sopenharmony_ci return new BundleWalkerSync(options).start().result 2491cb0ef41Sopenharmony_ci} 2501cb0ef41Sopenharmony_ci 2511cb0ef41Sopenharmony_cimodule.exports = walk 2521cb0ef41Sopenharmony_ciwalk.sync = walkSync 2531cb0ef41Sopenharmony_ciwalk.BundleWalker = BundleWalker 2541cb0ef41Sopenharmony_ciwalk.BundleWalkerSync = BundleWalkerSync 255