Files
pnpm/lib/api/uninstall.js
Zoltan Kochan b19369407a fix: don't use ! as a delimiter in the store
! can be part of a valid npm package name. Use + as a
delimiter instead.

close #276, PR #320

BREAKING CHANGE:

Stores created with the ! delimiter are not compatible
with the new version that uses +.

Any store created by older versions of pnpm has to be
removed and reinstalled.
2016-08-28 15:33:07 +03:00

97 lines
3.4 KiB
JavaScript

'use strict'
const cbRimraf = require('rimraf')
const join = require('path').join
const initCmd = require('./init_cmd')
const getSaveType = require('../get_save_type')
const removeDeps = require('../remove_deps')
const binify = require('../binify')
function uninstallCmd (pkgsToUninstall, opts) {
opts = Object.assign({}, require('../defaults'), opts)
let cmd
const uninstalledPkgs = []
const saveType = getSaveType(opts)
return initCmd(opts)
.then(_ => { cmd = _ })
.then(_ => {
cmd.pkg.pkg.dependencies = cmd.pkg.pkg.dependencies || {}
const pkgFullNames = pkgsToUninstall.map(dep => cmd.ctx.dependencies[cmd.pkg.path].find(_ => _.indexOf(dep + '@') === 0))
tryUninstall(pkgFullNames.slice())
if (cmd.ctx.dependencies[cmd.pkg.path]) {
pkgFullNames.forEach(dep => {
cmd.ctx.dependencies[cmd.pkg.path].splice(cmd.ctx.dependencies[cmd.pkg.path].indexOf(dep), 1)
})
if (!cmd.ctx.dependencies[cmd.pkg.path].length) {
delete cmd.ctx.dependencies[cmd.pkg.path]
}
}
return Promise.all(uninstalledPkgs.map(removePkgFromStore))
})
.then(_ => cmd.storeJsonCtrl.save({
dependents: cmd.ctx.dependents,
dependencies: cmd.ctx.dependencies
}))
.then(_ => Promise.all(pkgsToUninstall.map(dep => rimraf(join(cmd.ctx.root, 'node_modules', dep)))))
.then(_ => saveType && removeDeps(cmd.pkg, pkgsToUninstall, saveType))
.then(_ => cmd.unlock())
.catch(err => {
if (cmd && cmd.unlock) cmd.unlock()
throw err
})
function canBeUninstalled (pkgFullName) {
return !cmd.ctx.dependents[pkgFullName] || !cmd.ctx.dependents[pkgFullName].length ||
cmd.ctx.dependents[pkgFullName].length === 1 && cmd.ctx.dependents[pkgFullName].indexOf(cmd.pkg.path) !== -1
}
function tryUninstall (pkgFullNames) {
do {
var numberOfUninstalls = 0
for (let i = 0; i < pkgFullNames.length;) {
if (canBeUninstalled(pkgFullNames[i])) {
const uninstalledPkg = pkgFullNames.splice(i, 1)[0]
removeBins(uninstalledPkg)
uninstalledPkgs.push(uninstalledPkg)
const deps = cmd.ctx.dependencies[uninstalledPkg] || []
delete cmd.ctx.dependencies[uninstalledPkg]
delete cmd.ctx.dependents[uninstalledPkg]
deps.forEach(dep => removeDependency(dep, uninstalledPkg))
tryUninstall(deps)
numberOfUninstalls++
continue
}
i++
}
} while (numberOfUninstalls)
}
function removeDependency (dependentPkgName, uninstalledPkg) {
if (!cmd.ctx.dependents[dependentPkgName]) return
cmd.ctx.dependents[dependentPkgName].splice(cmd.ctx.dependents[dependentPkgName].indexOf(uninstalledPkg), 1)
if (!cmd.ctx.dependents[dependentPkgName].length) {
delete cmd.ctx.dependents[dependentPkgName]
}
}
function removeBins (uninstalledPkg) {
const uninstalledPkgJson = require(join(cmd.ctx.store, uninstalledPkg, '_/package.json'))
const bins = binify(uninstalledPkgJson)
Object.keys(bins).forEach(bin => cbRimraf.sync(join(cmd.ctx.root, 'node_modules/.bin', bin)))
}
function removePkgFromStore (pkgFullName) {
return rimraf(join(cmd.ctx.store, pkgFullName))
}
function rimraf (filePath) {
return new Promise((resolve, reject) => {
cbRimraf(filePath, err => err ? reject(err) : resolve())
})
}
}
module.exports = uninstallCmd