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.

163 lines
4.1 KiB

#!/usr/bin/env bash
declare -A aliases
declare -A helptext
err() { printf '%s\n' "$@" >&2; return 1; }
die() {
(( $# > 0 )) && err "$@"
exit 1
}
select_from() {
local cmd='command -v'
for a; do
case "$a" in
-c) cmd="$2"; shift 2 ;;
esac
done
for c; do
if $cmd "${c%% *}" &> /dev/null; then
echo "$c"
return 0
fi
done
return 1
}
has() {
local v c
if [[ $1 = '-v' ]]; then
v=1
shift
fi
for c; do c="${c%% *}"
if ! command -v "$c" &> /dev/null; then
(( v > 0 )) && err "$c not found"
return 1
fi
done
}
export -f has
aliases[s]=search
helptext['search']="search and install packages"
subcmd_search() {
local init
if [[ -n $1 ]]; then init=$(npm --json search "$*" | pretty_npm_search); fi
# SHELL is needed to use exported functions if default shell is not bash
SHELL=$(which bash) fzf \
--inline-info \
--query="$*" \
--phony \
--multi \
--preview-window=hidden \
--header='enter to install, C-d saves as devDependency, C-v to pick versions' \
--bind='?:toggle-preview' \
--bind='change:reload:npm --json search {q} | pretty_npm_search' \
--bind='ctrl-v:execute:subcmd_ls-versions {1} <> /dev/tty' \
--bind="enter:execute:subcmd_install {+1} <> /dev/tty" \
--bind="ctrl-d:execute:subcmd_install -D {+1} <> /dev/tty" \
--preview="npm view {1}" \
<<< "$init"
}
aliases[lsv]='ls-versions'
helptext['ls-versions']='list and install versions'
subcmd_ls-versions() {
local package="$1"
fzf --tac --preview="npm view ${package}@{1}" \
--header="choose version for $package | C-d saves as devDependency" \
--bind="enter:execute:subcmd_install '${package}@{1}' <> /dev/tty" \
--bind="ctrl-d:execute:subcmd_install -D '${package}@{1}' <> /dev/tty" \
< <(npm --json view "$package" | jq -r '.versions[]') # label with .dist-tags?)
}
export -f subcmd_ls-versions
aliases[un]=uninstall
helptext[uninstall]='uninstall packages'
subcmd_uninstall() {
local rm
mapfile -t rm < <(
jq -r '{dependencies, devDependencies}[] | keys[]' package.json |
fzf -m --query="$*")
(( ${#rm} > 0 )) || return
$(select_from 'yarn remove' 'npm uninstall') "${rm[@]}"
}
aliases[i]=install
helptext[install]='install packages'
subcmd_install() {
if [[ -e yarn.lock ]] && has yarn; then
yarn add "$@"
else
npm i -S "$@"
fi
}
export -f subcmd_install
helptext[init]='guided project setup'
subcmd_init() {
# shellcheck disable=2091
$(select_from 'git-flow init -d' 'git init') > /dev/null
npm init -y > /dev/null
[[ -e .gitignore ]] || curl -sL https://raw.githubusercontent.com/toptal/gitignore/master/templates/Node.gitignore > .gitignore
# install typescript? eslint? prettier? husky + lint-staged?
# react? vue? bundlers etc
}
helptext[lint]='setup or use eslint'
subcmd_lint() { # TODO
# should check if typescript, react, babel is installed, use relevant plugins
if [[ $(jq '.devDependencies.eslint' package.json) = null ]]; then
npx eslint --init
fi
npx eslint --ignore-path=.gitignore "$@"
}
aliases[fmt]=format
helptext[format]='setup or use prettier'
subcmd_format() { # TODO
if [[ $(jq '.devDependencies.prettier' package.json) = null ]]; then
subcmd_install -D prettier # eslint-{config,plugin}-prettier
fi
npx prettier --ignore-path .gitignore --write "$@"
}
aliases[-h]=help
helptext[help]='show this help '
subcmd_help() {
LESS=-FEXR less <<-HELP
js [subcmd] [options]
$(for c in "${subcmds_avail[@]}"; do
printf " %s\n %s\n" "$c" "${helptext[$c]}"
done)
HELP
}
pretty_npm_search() { jq -r '.[] | "\(.name) \(.version)\t\(.description[0:80])\t\(.author.name // .publisher.username)\t\((.keywords // []) | join(" "))"' | column -t -s $'\t'; }
export -f pretty_npm_search
has -v fzf jq npm || die
mapfile -t subcmds_avail < <(compgen -A function | awk '/^subcmd_/ { sub(/^subcmd_/, "", $0); print }')
if (( $# < 1 )); then
err 'missing command'
subcmd_help
exit 1
elif has "subcmd_$1"; then
subcmd="subcmd_$1"
shift
"$subcmd" "$@"
elif [[ -v aliases[$1] ]]; then
subcmd=subcmd_${aliases[$1]}
shift
"$subcmd" "$@"
else
err 'unknown command'
subcmd_help
exit 1
fi