zelda
Version:
Automatically `npm link` all your packages together!
127 lines (101 loc) • 3.18 kB
JavaScript
module.exports = zelda
var cp = require('child_process')
var findRoot = require('find-root')
var fs = require('fs')
var path = require('path')
var rimraf = require('rimraf')
var NPM_EXEC = process.platform === 'win32'
? 'npm.cmd'
: 'npm'
function zelda (rootPath, opts) {
if (!opts) opts = {}
// Use folder with nearest package.json as root
rootPath = findRoot(rootPath)
var rootName = require(path.join(rootPath, 'package.json')).name
var codePath = path.resolve(rootPath, '..')
if (!rootName) throw new Error('root package must have a name ')
// add node_modules symlink in code folder - magic!
try {
console.log('[zelda] cd ' + codePath + ' && ln -s . node_modules')
if (!opts['dry-run']) fs.symlinkSync('.', path.join(codePath, 'node_modules'), 'dir')
} catch (err) {
// ignore err (symlink already exists)
}
// get packages in code folder
var codePkgs = getCodePkgs(codePath)
if (opts.install) npmInstall(rootPath)
var pkgsToPurge = {}
pkgsToPurge[rootName] = true
traverseNodeModules(rootPath, function (pkgName, pkgPath) {
if (codePkgs[pkgName]) {
pkgsToPurge[pkgName] = true
if (opts.install) npmInstall(path.join(codePath, pkgName))
}
})
traverseNodeModules(rootPath, function (pkgName, pkgPath) {
if (pkgsToPurge[pkgName]) {
rmDir(pkgPath)
}
})
Object.keys(pkgsToPurge).forEach(function (pkgToPurge) {
if (pkgToPurge === rootName) return
var pkgPath = path.join(codePath, pkgToPurge)
traverseNodeModules(pkgPath, function (pkgName, pkgPath) {
if (pkgsToPurge[pkgName]) rmDir(pkgPath)
})
})
function rmDir (dirPath) {
console.log('[zelda] rm -rf ' + dirPath)
if (!opts['dry-run']) rimraf.sync(dirPath)
}
function npmInstall (pkgPath) {
console.log('[zelda] cd ' + pkgPath + ' && rm node_modules/ && npm install')
var args = ['install']
if (opts.production) args.push('--production')
if (!opts['dry-run']) {
rimraf.sync(path.join(pkgPath, 'node_modules'))
cp.spawnSync(NPM_EXEC, args, {
cwd: pkgPath,
stdio: 'inherit'
})
}
}
}
function getCodePkgs (codePath) {
var entries
try {
entries = fs.readdirSync(codePath)
} catch (err) {
throw new Error('Could not find ' + codePath + '. ' + err.message)
}
var pkgs = {}
entries.forEach(function (entry) {
var pkgPath = path.join(codePath, entry)
var pkg
try {
pkg = require(path.join(pkgPath, 'package.json'))
} catch (err) {
return // ignore folders without package.json
}
pkgs[pkg.name] = pkgPath
})
return pkgs
}
function traverseNodeModules (pkgPath, fn) {
var modulesPath = path.join(pkgPath, 'node_modules')
var entries
try {
entries = fs.readdirSync(modulesPath)
} catch (err) {
return // nothing to traverse (no node_modules)
}
entries = entries.filter(function (entry) {
var stat = fs.lstatSync(path.join(modulesPath, entry))
return !stat.isSymbolicLink()
})
entries.forEach(function (entry) {
var entryPath = path.join(modulesPath, entry)
traverseNodeModules(entryPath, fn)
fn(entry, entryPath)
})
}