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
Expand Up @@ -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.
Expand All @@ -43,6 +44,7 @@ const cli = meow({
u: 'update',
g: 'global',
s: 'skip-unused',
r: 'remove-unused',
p: 'production',
E: 'save-exact',
i: 'ignore'
Expand All @@ -56,6 +58,7 @@ const cli = meow({
'update',
'global',
'skip-unused',
'remove-unused',
'production',
'save-exact',
'color',
Expand All @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion lib/in/create-package-summary.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ function createPackageSummary(moduleName, currentState) {
bump !== 'major',
bump: bump,

unused: unused
unused: unused,
removed: unused && currentState.get('removeUnused')
};
});
}
Expand Down
8 changes: 1 addition & 7 deletions lib/in/get-unused-packages.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
2 changes: 2 additions & 0 deletions lib/in/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
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
Expand Up @@ -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 ? [
Expand All @@ -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) : ''
Expand Down Expand Up @@ -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:')}`);
Expand Down
2 changes: 2 additions & 0 deletions lib/state/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const defaultOptions = {
cwd: process.cwd(),
nodeModulesPath: false,
skipUnused: false,
removeUnused: false,
removeUnusedError: null,

ignoreDev: false,
forceColor: false,
Expand Down
5 changes: 5 additions & 0 deletions templates/readme/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
9 changes: 9 additions & 0 deletions templates/readme/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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`.
Expand Down
1 change: 1 addition & 0 deletions templates/readme/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down