--- /dev/null
+var mout = require('mout');
+var Q = require('q');
+var Project = require('../core/Project');
+var defaultConfig = require('../config');
+
+function uninstall(logger, names, options, config) {
+ if (!names.length) {
+ return new Q();
+ }
+
+ var project;
+
+ options = options || {};
+ config = defaultConfig(config);
+ project = new Project(config, logger);
+
+ return project.getTree(options)
+ .spread(function (tree, flattened) {
+ // Uninstall nodes
+ return project.uninstall(names, options)
+ // Clean out non-shared uninstalled dependencies
+ .then(function (uninstalled) {
+ var names = Object.keys(uninstalled);
+ var children = [];
+
+ // Grab the dependencies of packages that were uninstalled
+ mout.object.forOwn(flattened, function (node) {
+ if (names.indexOf(node.endpoint.name) !== -1) {
+ children.push.apply(children, mout.object.keys(node.dependencies));
+ }
+ });
+
+ // Clean them!
+ return clean(project, children, uninstalled);
+ });
+ });
+}
+
+function clean(project, names, removed) {
+ removed = removed || {};
+
+ return project.getTree()
+ .spread(function (tree, flattened) {
+ var nodes = [];
+ var dependantsCounter = {};
+
+ // Grab the nodes of each specified name
+ mout.object.forOwn(flattened, function (node) {
+ if (names.indexOf(node.endpoint.name) !== -1) {
+ nodes.push(node);
+ }
+ });
+
+ // Walk the down the tree, gathering dependants of the packages
+ project.walkTree(tree, function (node, nodeName) {
+ if (names.indexOf(nodeName) !== -1) {
+ dependantsCounter[nodeName] = dependantsCounter[nodeName] || 0;
+ dependantsCounter[nodeName] += node.nrDependants;
+ }
+ }, true);
+
+
+ // Filter out those that have no dependants
+ nodes = nodes.filter(function (node) {
+ return !dependantsCounter[node.endpoint.name];
+ });
+
+ // Are we done?
+ if (!nodes.length) {
+ return Q.resolve(removed);
+ }
+
+ // Grab the nodes after filtering
+ names = nodes.map(function (node) {
+ return node.endpoint.name;
+ });
+
+ // Uninstall them
+ return project.uninstall(names)
+ // Clean out non-shared uninstalled dependencies
+ .then(function (uninstalled) {
+ var children;
+
+ mout.object.mixIn(removed, uninstalled);
+
+ // Grab the dependencies of packages that were uninstalled
+ children = [];
+ nodes.forEach(function (node) {
+ children.push.apply(children, mout.object.keys(node.dependencies));
+ });
+
+ // Recurse!
+ return clean(project, children, removed);
+ });
+ });
+}
+
+// -------------------
+
+uninstall.readOptions = function (argv) {
+ var cli = require('../util/cli');
+
+ var options = cli.readOptions({
+ 'save': { type: Boolean, shorthand: 'S' },
+ 'save-dev': { type: Boolean, shorthand: 'D' }
+ }, argv);
+
+ var names = options.argv.remain.slice(1);
+
+ delete options.argv;
+
+ return [names, options];
+};
+
+module.exports = uninstall;