-
Notifications
You must be signed in to change notification settings - Fork 31
/
Copy pathjs
executable file
·163 lines (145 loc) · 4.13 KB
/
js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#!/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