You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

npmsearch 3.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #!/usr/bin/env bash
  2. declare -a args
  3. declare -a packages
  4. declare savedev=0
  5. declare global=0
  6. declare -A colors
  7. colors[red]=$(tput setaf 1)
  8. colors[green]=$(tput setaf 2)
  9. colors[reset]=$(tput sgr0)
  10. usage() {
  11. LESS=-FEXR less <<-HELP
  12. npmsearch [options] [packages]
  13. searches npm for packages
  14. -r, --remove
  15. list and remove packages from package.json
  16. to increase the amount of packages shown when searching, try:
  17. npm config set searchlimit 40
  18. HELP
  19. }
  20. color() {
  21. local color="$1"; shift
  22. printf '%s' "${colors[$color]}"
  23. printf '%s\n' "$@"
  24. printf '%s' "${colors[reset]}"
  25. }
  26. err() { color red "$@" >&2; return 1; }
  27. die() {
  28. (( $# > 0 )) && err "$@"
  29. exit 1
  30. }
  31. has() {
  32. local v c
  33. if [[ $1 = '-v' ]]; then
  34. v=1
  35. shift
  36. fi
  37. for c; do c="${c%% *}"
  38. if ! command -v "$c" &> /dev/null; then
  39. (( v > 0 )) && err "$c not found"
  40. return 1
  41. fi
  42. done
  43. }
  44. select_from() {
  45. local cmd='command -v'
  46. for a; do
  47. case "$a" in
  48. -c) cmd="$2"; shift 2 ;;
  49. esac
  50. done
  51. for c; do
  52. if $cmd "${c%% *}" &> /dev/null; then
  53. echo "$c"
  54. return 0
  55. fi
  56. done
  57. return 1
  58. }
  59. has -v fzf npm || die
  60. fzf() {
  61. command fzf --inline-info --ansi --reverse +s --no-hscroll "$@"
  62. }
  63. if [[ $1 = '-h' || $1 = '--help' ]]; then
  64. usage
  65. exit
  66. fi
  67. if [[ $1 = '-r' || $1 = '--remove' ]]; then
  68. shift
  69. mapfile -t rm < <(
  70. jq -r '{dependencies, devDependencies} | .[] | keys | .[]' package.json |
  71. fzf -m --cycle -e --reverse --query="$*")
  72. (( ${#rm} > 0 )) && $(select_from 'yarn remove' 'npm uninstall') "${rm[@]}"
  73. die
  74. fi
  75. printf '%ssearching...%s\r' "${colors[green]}" "${colors[reset]}"
  76. search=$(npm search --json "$*") || exit
  77. search=$(jq -r '.[] | "\(.name)|\(.version)|\(.description)"' <<< "$search" | column -t -s'|')
  78. mapfile -t packages < <(fzf --multi \
  79. --bind='ctrl-x:toggle-preview' \
  80. --expect='ctrl-g,ctrl-d,enter,ctrl-v,esc' \
  81. --preview-window='hidden:down' \
  82. --preview="npm -s --json view {1} | jq -C \"del(.users, .time, .versions)\"" \
  83. --header='C-d saves as devDependency, C-g installs globally, C-v for specific version, C-x for more info, ' \
  84. <<< "$search")
  85. key="${packages[0]}"
  86. case "${key,,}" in
  87. esc) die ;;
  88. ctrl-d) savedev=1 ;;
  89. ctrl-g) global=1 ;;
  90. ctrl-v)
  91. package="${packages[1]%% *}"
  92. mapfile -t version < <(
  93. npm -s --json view "$package" |
  94. jq -r '.versions[]' | # label with .dist-tags?
  95. fzf --header="choose version for $package | C-d saves as devDependency" --tac --expect='ctrl-d,esc')
  96. key="${version[0]}"
  97. case "${key,,}" in
  98. esc) die ;;
  99. ctrl-d) savedev=1 ;;
  100. esac
  101. packages=( "${package}@${version[1]}" )
  102. ;;
  103. esac
  104. (( ${#packages[@]} > 0 )) || die 'no packages to install'
  105. if (( ${#packages[@]} > 1 )); then
  106. packages=( "${packages[@]:1}" )
  107. packages=( "${packages[@]%% *}" )
  108. fi
  109. printf '%sinstalling...%s\r' "${colors[green]}" "${colors[reset]}"
  110. if (( global > 0 )); then
  111. npm install -g "${args[@]}" "${packages[@]}"
  112. elif has yarn; then
  113. (( savedev > 0 )) && args+=( -D )
  114. yarn add "${args[@]}" "${packages[@]}"
  115. else
  116. if (( savedev > 0 )); then
  117. args+=( -D )
  118. else
  119. args+=( -S )
  120. fi
  121. npm i "${args[@]}" "${packages[@]}"
  122. fi