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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/.idea/
/node_modules/
/*.log
/*.log
lib-es5
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add leading and trailing slash to this line

4 changes: 4 additions & 0 deletions lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,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.
-E, --save-exact Save exact version (x.y.z) instead of caret (^x.y.z) in package.json.
--no-color Force or disable color output.
Expand All @@ -41,6 +42,7 @@ const cli = meow({
u: 'update',
g: 'global',
s: 'skip-unused',
r: 'remove-unused',
p: 'production',
E: 'save-exact'
},
Expand All @@ -53,6 +55,7 @@ const cli = meow({
'update',
'global',
'skip-unused',
'remove-unused',
'production',
'save-exact',
'color',
Expand All @@ -66,6 +69,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 @@ -94,7 +94,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 new Promise(resolve => resolve(currentState));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return Promise.resolve(currentState)

} else {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need else because of the return above

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);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be set to undefined if there is no error but stderr is non-empty

}
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;
19 changes: 16 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,17 @@ 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 '),
indent + `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 +91,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.
-E, --save-exact Save exact version (x.y.z) instead of caret (^x.y.z) in package.json.
--no-color Force or disable color output.
Expand Down Expand Up @@ -89,6 +90,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