]> git.madduck.net Git - etc/vim.git/blob - .vim/bundle/ale/test/script/custom-linting-rules

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Merge commit '76265755a1add77121c8f9dabb3e9bb70fe9a972' as '.vim/bundle/ale'
[etc/vim.git] / .vim / bundle / ale / test / script / custom-linting-rules
1 #!/usr/bin/env bash
2
3 set -e
4 set -u
5
6 # This Bash script implements custom sanity checks for scripts beyond what
7 # Vint covers, which are easy to check with regex.
8
9 # A flag for automatically fixing some errors.
10 FIX_ERRORS=0
11 RETURN_CODE=0
12
13 function print_help() {
14     echo "Usage: test/script/custom-linting-rules [--fix] [DIRECTORY]" 1>&2
15     echo 1>&2
16     echo "  -h, --help    Print this help text" 1>&2
17     echo "      --fix     Automatically fix some errors" 1>&2
18     exit 1
19 }
20
21 while [ $# -ne 0 ]; do
22     case $1 in
23     -h) ;& --help)
24         print_help
25     ;;
26     --fix)
27         FIX_ERRORS=1
28         shift
29     ;;
30     --)
31         shift
32         break
33     ;;
34     -?*)
35         echo "Invalid argument: $1" 1>&2
36         exit 1
37     ;;
38     *)
39         break
40     ;;
41     esac
42 done
43
44 if [ $# -eq 0 ] || [ -z "$1" ]; then
45     print_help
46 fi
47
48 shopt -s globstar
49
50 directories=("$@")
51
52 check_errors() {
53     regex="$1"
54     message="$2"
55     include_arg=''
56     exclude_arg=''
57
58     if [ $# -gt 2 ]; then
59         include_arg="--include $3"
60     fi
61
62     if [ $# -gt 3 ]; then
63         shift
64         shift
65         shift
66
67         while (( "$#" )); do
68           exclude_arg="$exclude_arg --exclude $1"
69           shift
70         done
71     fi
72
73     for directory in "${directories[@]}"; do
74         # shellcheck disable=SC2086
75         while read -r; do
76             line=$(cut -d ":" -f2 <<< "$REPLY")
77
78             if ((line > 1)); then
79                 line=$((line - 1))
80                 file=$(cut -d ":" -f1 <<< "$REPLY")
81
82                 if sed -n "${line},${line}p" $file | grep -q '^ *" *no-custom-checks$'; then
83                     continue
84                 fi
85             fi
86
87             RETURN_CODE=1
88             echo "$REPLY $message"
89         done < <(grep -H -n "$regex" $include_arg $exclude_arg "$directory"/**/*.vim \
90             | grep -v 'no-custom-checks' \
91             | grep -o '^[^:]\+:[0-9]\+' \
92             | sed 's:^\./::')
93     done
94 }
95
96 if (( FIX_ERRORS )); then
97     for directory in "${directories[@]}"; do
98         sed -i "s/^\(function.*)\) *$/\1 abort/" "$directory"/**/*.vim
99         sed -i "s/shellescape(/ale#Escape(/" "$directory"/**/*.vim
100         sed -i 's/==#/is#/g' "$directory"/**/*.vim
101         sed -i 's/==?/is?/g' "$directory"/**/*.vim
102         sed -i 's/!=#/isnot#/g' "$directory"/**/*.vim
103         sed -i 's/!=?/isnot?/g' "$directory"/**/*.vim
104         # Improving type checks.
105         sed -i $'s/\\(==.\\?\\|is\\) type([\'"]\+)/is v:t_string/g' "$directory"/**/*.vim
106         sed -i 's/\(==.\?\|is\) type([0-9]\+)/is v:t_number/g' "$directory"/**/*.vim
107         sed -i 's/\(==.\?\|is\) type(\[\])/is v:t_list/g' "$directory"/**/*.vim
108         sed -i 's/\(==.\?\|is\) type({})/is v:t_dict/g' "$directory"/**/*.vim
109         sed -i 's/\(==.\?\|is\) type(function([^)]\+))/is v:t_func/g' "$directory"/**/*.vim
110         sed -i $'s/\\(!=.\\?\\|isnot\\) type([\'"]\+)/isnot v:t_string/g' "$directory"/**/*.vim
111         sed -i 's/\(!=.\?\|isnot\) type([0-9]\+)/isnot v:t_number/g' "$directory"/**/*.vim
112         sed -i 's/\(!=.\?\|isnot\) type(\[\])/isnot v:t_list/g' "$directory"/**/*.vim
113         sed -i 's/\(!=.\?\|isnot\) type({})/isnot v:t_dict/g' "$directory"/**/*.vim
114         sed -i 's/\(!=.\?\|isnot\) type(function([^)]\+))/isnot v:t_func/g' "$directory"/**/*.vim
115     done
116 fi
117
118 # The arguments are: regex, explanation, [filename_filter], [list, of, exclusions]
119 check_errors \
120     '^function.*) *$' \
121     'Function without abort keyword (See :help except-compat)'
122 check_errors '^function[^!]' 'function without !'
123 check_errors ' \+$' 'Trailing whitespace'
124 check_errors '^ * end\?i\? *$' 'Write endif, not en, end, or endi'
125 check_errors '^  [^ ]' 'Use four spaces, not two spaces'
126 check_errors $'\t' 'Use four spaces, not tabs'
127 # This check should prevent people from using a particular inconsistent name.
128 check_errors 'let g:ale_\w\+_\w\+_args =' 'Name your option g:ale_<filetype>_<lintername>_options instead'
129 check_errors 'shellescape(' 'Use ale#Escape instead of shellescape'
130 check_errors 'simplify(' 'Use ale#path#Simplify instead of simplify'
131 check_errors 'tempname(' 'Use ale#util#Tempname instead of tempname'
132 check_errors 'getcurpos(' "Use getpos('.') instead of getcurpos() if you don't need curswant, to avoid a bug that changes curswant"
133 check_errors "expand(['\"]%" "Use expand('#' . a:buffer . '...') instead. You might get a filename for the wrong buffer."
134 check_errors 'getcwd()' "Do not use getcwd(), as it could run from the wrong buffer. Use expand('#' . a:buffer . ':p:h') instead."
135 check_errors '==#' "Use 'is#' instead of '==#'. 0 ==# 'foobar' is true"
136 check_errors '==?' "Use 'is?' instead of '==?'. 0 ==? 'foobar' is true"
137 check_errors '!=#' "Use 'isnot#' instead of '!=#'. 0 !=# 'foobar' is false"
138 check_errors '!=?' "Use 'isnot?' instead of '!=?'. 0 !=? 'foobar' is false"
139 check_errors '^ *:\?echo' "Stray echo line. Ignore with \" no-custom-checks if needed"
140 check_errors '^ *:\?redir' 'User execute() instead of redir'
141 # Exclusions for grandfathered-in exceptions
142 exclusions="clojure/clj_kondo.vim elixir/elixir_ls.vim go/golangci_lint.vim swift/swiftformat.vim"
143 # shellcheck disable=SC2086
144 check_errors $'name.:.*\'[a-z_]*[^a-z_0-9][a-z_0-9]*\',$' 'Use snake_case names for linters' '*/ale_linters/*' $exclusions
145 # Checks for improving type checks.
146 check_errors $'\\(==.\\?\\|is\\) type([\'"]\+)' "Use 'is v:t_string' instead"
147 check_errors '\(==.\?\|is\) type([0-9]\+)' "Use 'is v:t_number' instead"
148 check_errors '\(==.\?\|is\) type(\[\])' "Use 'is v:t_list' instead"
149 check_errors '\(==.\?\|is\) type({})' "Use 'is v:t_dict' instead"
150 check_errors '\(==.\?\|is\) type(function([^)]\+))' "Use 'is v:t_func' instead"
151 check_errors $'\\(!=.\\?\\|isnot\\) type([\'"]\+)' "Use 'isnot v:t_string' instead"
152 check_errors '\(!=.\?\|isnot\) type([0-9]\+)' "Use 'isnot v:t_number' instead"
153 check_errors '\(!=.\?\|isnot\) type(\[\])' "Use 'isnot v:t_list' instead"
154 check_errors '\(!=.\?\|isnot\) type({})' "Use 'isnot v:t_dict' instead"
155 check_errors '\(!=.\?\|isnot\) type(function([^)]\+))' "Use 'isnot v:t_func' instead"
156
157 # Run a Python script to find lines that require padding around them.  For
158 # users without Python installed, we'll skip these checks. GitHub Actions will
159 # run the script.
160 if command -v python > /dev/null; then
161     if ! test/script/block-padding-checker "$directory"/**/*.vim; then
162         RETURN_CODE=1
163     fi
164 fi
165
166 exit $RETURN_CODE