Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove unused feature #166

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/.idea/
/node_modules/
/*.log
/lib-es5/
4 changes: 4 additions & 0 deletions lib/cli.js
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ const cli = meow({
-u, --update Interactive update.
-g, --global Look at global modules.
-s, --skip-unused Skip check for unused packages.
-r, --remove-unused Automatically remove unused dependencies.
-p, --production Skip devDependencies.
-i, --ignore Ignore dependencies based on succeeding glob.
-E, --save-exact Save exact version (x.y.z) instead of caret (^x.y.z) in package.json.
@@ -43,6 +44,7 @@ const cli = meow({
u: 'update',
g: 'global',
s: 'skip-unused',
r: 'remove-unused',
p: 'production',
E: 'save-exact',
i: 'ignore'
@@ -56,6 +58,7 @@ const cli = meow({
'update',
'global',
'skip-unused',
'remove-unused',
'production',
'save-exact',
'color',
@@ -72,6 +75,7 @@ const options = {
update: cli.flags.update,
global: cli.flags.global,
skipUnused: cli.flags.skipUnused,
removeUnused: cli.flags.removeUnused,
ignoreDev: cli.flags.production,
saveExact: cli.flags.saveExact,
emoji: cli.flags.emoji,
3 changes: 2 additions & 1 deletion lib/in/create-package-summary.js
Original file line number Diff line number Diff line change
@@ -104,7 +104,8 @@ function createPackageSummary(moduleName, currentState) {
bump !== 'major',
bump: bump,

unused: unused
unused: unused,
removed: unused && currentState.get('removeUnused')
};
});
}
8 changes: 1 addition & 7 deletions lib/in/get-unused-packages.js
Original file line number Diff line number Diff line change
@@ -2,15 +2,9 @@

const depcheck = require('depcheck');
const ora = require('ora');
const skipUnused = require('./skip-unused-packages');
const _ = require('lodash');

function skipUnused(currentState) {
return currentState.get('skipUnused') || // manual option to ignore this
currentState.get('global') || // global modules
currentState.get('update') || // in the process of doing an update
!currentState.get('cwdPackageJson').name; // there's no package.json
}

function checkUnused(currentState) {
const spinner = ora(`Checking for unused packages. --skip-unused if you don't want this.`);
spinner.enabled = spinner.enabled && currentState.get('spinner');
2 changes: 2 additions & 0 deletions lib/in/index.js
Original file line number Diff line number Diff line change
@@ -3,11 +3,13 @@ const co = require('co');
const merge = require('merge-options');
const ora = require('ora');
const getUnusedPackages = require('./get-unused-packages');
const removeUnusedPackages = require('./remove-unused-packages');
const createPackageSummary = require('./create-package-summary');

module.exports = function (currentState) {
return co(function *() {
yield getUnusedPackages(currentState);
yield removeUnusedPackages(currentState);

const spinner = ora(`Checking npm registries for updated packages.`);
spinner.enabled = spinner.enabled && currentState.get('spinner');
36 changes: 36 additions & 0 deletions lib/in/remove-unused-packages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
'use strict';

const exec = require('child_process').exec;
const ora = require('ora');
const skipUnused = require('./skip-unused-packages');
const _ = require('lodash');

function skipAutoRemove(currentState) {
return skipUnused(currentState) || !currentState.get('removeUnused');
}

function removeUnused(currentState) {
const dependenciesToRemove = currentState.get('unusedDependencies');
if (skipAutoRemove(currentState) || _.isEmpty(dependenciesToRemove)) {
return Promise.resolve(currentState);
}

const spinner = ora(`Remove unused dependencies. --skip-unused if you don't want this.`);
spinner.enabled = spinner.enabled && currentState.get('spinner');
spinner.start();

return new Promise(resolve => {
const removeCommand = 'npm remove --save ' + dependenciesToRemove.join(' ');
exec(removeCommand, {cwd: currentState.get('cwd')}, (error, stdout, stderr) => {
if (error || !_.isEmpty(stderr)) {
currentState.set('removeUnusedError', error || new Error(stderr));
}
resolve(currentState);
});
}).then(result => {
spinner.stop();
return currentState;
});
}

module.exports = removeUnused;
10 changes: 10 additions & 0 deletions lib/in/skip-unused-packages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use strict';

function skipUnused(currentState) {
return currentState.get('skipUnused') || // manual option to ignore this
currentState.get('global') || // global modules
currentState.get('update') || // in the process of doing an update
!currentState.get('cwdPackageJson').name; // there's no package.json
}

module.exports = skipUnused;
18 changes: 15 additions & 3 deletions lib/out/static-output.js
Original file line number Diff line number Diff line change
@@ -17,9 +17,10 @@ function render(pkg, currentState) {
const flags = currentState.get('global') ? '--global' : `--save${pkg.devDependency ? '-dev' : ''}`;
const upgradeCommand = `npm install ${flags} ${packageName}@${pkg.latest}`;
const upgradeMessage = `${chalk.green(upgradeCommand)} to go from ${pkg.installed} to ${pkg.latest}`;

// DYLAN: clean this up
const status = _([
pkg.notInstalled ? chalk.bgRed.white.bold(emoji(' :worried: ') + ' MISSING! ') + ' Not installed.' : '',
pkg.notInstalled && !pkg.removed ? chalk.bgRed.white.bold(emoji(' :worried: ') + ' MISSING! ') + ' Not installed.' : '',
pkg.notInPackageJson ? chalk.bgRed.white.bold(emoji(' :worried: ') + ' PKG ERR! ') + ' Not in the package.json. ' + pkg.notInPackageJson : '',
pkg.pkgError && !pkg.notInstalled ? chalk.bgGreen.white.bold(emoji(' :worried: ') + ' PKG ERR! ') + ' ' + chalk.red(pkg.pkgError.message) : '',
pkg.bump && pkg.easyUpgrade ? [
@@ -30,12 +31,16 @@ function render(pkg, currentState) {
chalk.white.bold.bgGreen((pkg.bump === 'nonSemver' ? emoji(' :sunglasses: ') + ' new ver! '.toUpperCase() : emoji(' :sunglasses: ') + ' ' + pkg.bump.toUpperCase() + ' UP ')) + ' ' + uppercaseFirstLetter(pkg.bump) + ' update available. ' + chalk.blue.underline(pkg.homepage || ''),
indent + upgradeMessage
] : '',
pkg.unused ? [
pkg.unused && !pkg.removed ? [
chalk.black.bold.bgWhite(emoji(' :confused: ') + ' NOTUSED? ') + ` ${chalk.yellow(`Still using ${packageName}?`)}`,
indent + `Depcheck did not find code similar to ${chalk.green(`require('${packageName}')`)} or ${chalk.green(`import from '${packageName}'`)}.`,
indent + `Check your code before removing as depcheck isn't able to foresee all ways dependencies can be used.`,
indent + `Use ${chalk.green('--skip-unused')} to skip this check.`,
indent + `To remove this package: ${chalk.green(`npm uninstall --save${pkg.devDependency ? '-dev' : ''} ${packageName}`)}`
indent + `To remove this package: ${chalk.green(`npm uninstall --save${pkg.devDependency ? '-dev' : ''} ${packageName}`)} or add ${chalk.green(`--remove-unused`)} option for auto removing unused dependencies.`
] : '',
pkg.removed ? [
chalk.bgGreen.white.bold(emoji(' :thumbsup: ') + ' RM UNUSED ') + `The package was removed as unused.`,
indent + `Don't use ${chalk.green('--remove-unused')} or add ${chalk.green('--skip-unused')} option to skip this check.`
] : '',
pkg.mismatch && !pkg.bump ? chalk.bgRed.yellow.bold(emoji(' :interrobang: ') + ' MISMATCH ') + ' Installed version does not match package.json. ' + pkg.installed + ' ≠ ' + pkg.packageJson : '',
pkg.regError ? chalk.bgRed.white.bold(emoji(' :no_entry: ') + ' NPM ERR! ') + ' ' + chalk.red(pkg.regError) : ''
@@ -85,6 +90,13 @@ function outputConsole(currentState) {
console.log('');
console.log(renderedTable);
console.log(`Use ${chalk.green(`npm-check -${currentState.get('global') ? 'g' : ''}u`)} for interactive update.`);

const removeError = currentState.get('removeUnusedError');
if (removeError) {
console.log("Auto removing dependencies have crashed with following error: ",
chalk.red(removeError));
}

process.exitCode = 1;
} else {
console.log(`${emoji(':heart: ')}Your modules look ${chalk.bold('amazing')}. Keep up the great work.${emoji(' :heart:')}`);
2 changes: 2 additions & 0 deletions lib/state/state.js
Original file line number Diff line number Diff line change
@@ -9,6 +9,8 @@ const defaultOptions = {
cwd: process.cwd(),
nodeModulesPath: false,
skipUnused: false,
removeUnused: false,
removeUnusedError: null,

ignoreDev: false,
forceColor: false,
5 changes: 5 additions & 0 deletions templates/readme/api.md
Original file line number Diff line number Diff line change
@@ -25,6 +25,11 @@ npmCheck(options)
* Skip checking for unused packages.
* default is `false`

### `removeUnused`

* Automatically remove all unused packages.
* default is `false`

### `ignoreDev`

* Ignore `devDependencies`.
9 changes: 9 additions & 0 deletions templates/readme/cli.md
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@ Options
-u, --update Interactive update.
-g, --global Look at global modules.
-s, --skip-unused Skip check for unused packages.
-r, --remove-unused Automatically remove unused dependencies.
-p, --production Skip devDependencies.
-i, --ignore Ignore dependencies based on succeeding glob.
-E, --save-exact Save exact version (x.y.z) instead of caret (^x.y.z) in package.json.
@@ -90,6 +91,14 @@ This option will skip that check.

This is enabled by default when using `global` or `update`.

### `-r, --remove-unused`

You can automatically remove all unused dependencies that `npm-check` marked as unused. You must also
be worried about false positive tests, so it's highly recommended to make a backup of your `package.json`
before running `npm-check` with this option.

This option is disabled by default.

### `-p, --production`

By default `npm-check` will look at packages listed as `dependencies` and `devDependencies`.
1 change: 1 addition & 0 deletions templates/readme/features.md
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@
* Tells you what's out of date.
* Provides a link to the package's documentation so you can decide if you want the update.
* Kindly informs you if a dependency is not being used in your code.
* Allows to automatically remove all unused dependencies via `--remove-unused` option.
* Works on your globally installed packages too, via `-g`.
* **Interactive Update** for less typing and fewer typos, via `-u`.
* Supports public and private [@scoped/packages](https://docs.npmjs.com/getting-started/scoped-packages).