From 778d5f3e6e016a7833af24e8dd17944cdbb3c996 Mon Sep 17 00:00:00 2001 From: nvbn Date: Sat, 6 Feb 2016 15:18:44 +0300 Subject: [PATCH] #N/A: Add `npm_wrong_command` rule --- README.md | 1 + tests/rules/test_npm_wrong_command.py | 58 +++++++++++++++++++++++++++ thefuck/rules/npm_wrong_command.py | 39 ++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 tests/rules/test_npm_wrong_command.py create mode 100644 thefuck/rules/npm_wrong_command.py diff --git a/README.md b/README.md index 474ff0a4..8a1cae57 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,7 @@ using the matched rule and runs it. Rules enabled by default are as follows: * `mkdir_p` – adds `-p` when you trying to create directory without parent; * `mvn_no_command` – adds `clean package` to `mvn`; * `mvn_unknown_lifecycle_phase` – fixes misspelled lifecycle phases with `mvn`; +* `npm_wrong_command` – fixes wrong npm commands like `npm urgrade`; * `no_command` – fixes wrong console commands, for example `vom/vim`; * `no_such_file` – creates missing directories with `mv` and `cp` commands; * `open` – prepends `http` to address passed to `open`; diff --git a/tests/rules/test_npm_wrong_command.py b/tests/rules/test_npm_wrong_command.py new file mode 100644 index 00000000..e9511af5 --- /dev/null +++ b/tests/rules/test_npm_wrong_command.py @@ -0,0 +1,58 @@ +import pytest +from thefuck.rules.npm_wrong_command import match, get_new_command +from tests.utils import Command + +stdout = ''' +Usage: npm + +where is one of: + access, add-user, adduser, apihelp, author, bin, bugs, c, + cache, completion, config, ddp, dedupe, deprecate, dist-tag, + dist-tags, docs, edit, explore, faq, find, find-dupes, get, + help, help-search, home, i, info, init, install, issues, la, + link, list, ll, ln, login, logout, ls, outdated, owner, + pack, ping, prefix, prune, publish, r, rb, rebuild, remove, + repo, restart, rm, root, run-script, s, se, search, set, + show, shrinkwrap, star, stars, start, stop, t, tag, team, + test, tst, un, uninstall, unlink, unpublish, unstar, up, + update, upgrade, v, verison, version, view, whoami + +npm -h quick help on +npm -l display full usage info +npm faq commonly asked questions +npm help search for help on +npm help npm involved overview + +Specify configs in the ini-formatted file: + /home/nvbn/.npmrc +or on the command line via: npm --key value +Config info can be viewed via: npm help config + +npm@2.14.7 /opt/node/lib/node_modules/npm +''' + + +@pytest.mark.parametrize('script', [ + 'npm urgrdae', + 'npm urgrade -g', + 'npm -f urgrade -g', + 'npm urg']) +def test_match(script): + assert match(Command(script, stdout)) + + +@pytest.mark.parametrize('script, stdout', [ + ('npm urgrade', ''), + ('npm', stdout), + ('test urgrade', stdout), + ('npm -e', stdout)]) +def test_not_match(script, stdout): + assert not match(Command(script, stdout)) + + +@pytest.mark.parametrize('script, result', [ + ('npm urgrade', 'npm upgrade'), + ('npm -g isntall gulp', 'npm -g install gulp'), + ('npm isntall -g gulp', 'npm install -g gulp')]) +def test_get_new_command(script, result): + assert get_new_command(Command(script, stdout)) == result diff --git a/thefuck/rules/npm_wrong_command.py b/thefuck/rules/npm_wrong_command.py new file mode 100644 index 00000000..e5927a78 --- /dev/null +++ b/thefuck/rules/npm_wrong_command.py @@ -0,0 +1,39 @@ +from thefuck.utils import replace_argument, for_app, eager, get_closest +from thefuck.specific.sudo import sudo_support + + +def _get_wrong_command(script_parts): + commands = [part for part in script_parts[1:] if not part.startswith('-')] + if commands: + return commands[0] + + +@sudo_support +@for_app('npm') +def match(command): + return (command.script_parts[0] == 'npm' and + 'where is one of:' in command.stdout and + _get_wrong_command(command.script_parts)) + + +@eager +def _get_available_commands(stdout): + commands_listing = False + for line in stdout.split('\n'): + if line.startswith('where is one of:'): + commands_listing = True + elif commands_listing: + if not line: + break + + for command in line.split(', '): + stripped = command.strip() + if stripped: + yield stripped + + +def get_new_command(command): + npm_commands = _get_available_commands(command.stdout) + wrong_command = _get_wrong_command(command.script_parts) + fixed = get_closest(wrong_command, npm_commands) + return replace_argument(command.script, wrong_command, fixed)