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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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. mapfile -t rm < <(
  69. jq -r '{dependencies, devDependencies} | .[] | keys | .[]' package.json |
  70. fzf -m --cycle -e --reverse)
  71. (( ${#rm} > 0 )) && $(select_from 'yarn remove' 'npm uninstall') "${rm[@]}"
  72. die
  73. fi
  74. printf '%ssearching...%s\r' "${colors[green]}" "${colors[reset]}"
  75. search=$(npm search --json "$*") || exit
  76. search=$(jq -r '.[] | "\(.name)|\(.version)|\(.description)"' <<< "$search" | column -t -s'|')
  77. mapfile -t packages < <(fzf --multi \
  78. --bind='ctrl-x:toggle-preview' \
  79. --expect='ctrl-g,ctrl-d,enter,ctrl-v,esc' \
  80. --preview-window='hidden:down' \
  81. --preview="npm -s --json view {1} | jq -C \"del(.users, .time, .versions)\"" \
  82. --header='C-d saves as devDependency, C-g installs globally, C-v for specific version, C-x for more info, ' \
  83. <<< "$search")
  84. key="${packages[0]}"
  85. case "${key,,}" in
  86. esc) die ;;
  87. ctrl-d) savedev=1 ;;
  88. ctrl-g) global=1 ;;
  89. ctrl-v)
  90. package="${packages[1]%% *}"
  91. mapfile -t version < <(
  92. npm -s --json view "$package" |
  93. jq -r '.versions[]' | # label with .dist-tags?
  94. fzf --header="choose version for $package | C-d saves as devDependency" --tac --expect='ctrl-d,esc')
  95. key="${version[0]}"
  96. case "${key,,}" in
  97. esc) die ;;
  98. ctrl-d) savedev=1 ;;
  99. esac
  100. packages=( "${package}@${version[1]}" )
  101. ;;
  102. esac
  103. (( ${#packages[@]} > 0 )) || die 'no packages to install'
  104. if (( ${#packages[@]} > 1 )); then
  105. packages=( "${packages[@]:1}" )
  106. packages=( "${packages[@]%% *}" )
  107. fi
  108. printf '%sinstalling...%s\r' "${colors[green]}" "${colors[reset]}"
  109. if (( global > 0 )); then
  110. npm install -g "${args[@]}" "${packages[@]}"
  111. elif has yarn; then
  112. (( savedev > 0 )) && args+=( -D )
  113. yarn add "${args[@]}" "${packages[@]}"
  114. else
  115. if (( savedev > 0 )); then
  116. args+=( -D )
  117. else
  118. args+=( -S )
  119. fi
  120. npm i "${args[@]}" "${packages[@]}"
  121. fi