summaryrefslogtreecommitdiff
path: root/autoload/ale/fixers/prettier.vim
blob: 12c018afc5f22982bef5fc52c5e9bea59b8a8da7 (plain)
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
" Author: tunnckoCore (Charlike Mike Reagent) <mameto2011@gmail.com>,
"         w0rp <devw0rp@gmail.com>, morhetz (Pavel Pertsev) <morhetz@gmail.com>
" Description: Integration of Prettier with ALE.

call ale#Set('javascript_prettier_executable', 'prettier')
call ale#Set('javascript_prettier_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('javascript_prettier_options', '')

function! ale#fixers#prettier#GetExecutable(buffer) abort
    return ale#node#FindExecutable(a:buffer, 'javascript_prettier', [
    \   'node_modules/.bin/prettier_d',
    \   'node_modules/prettier-cli/index.js',
    \   'node_modules/.bin/prettier',
    \])
endfunction

function! ale#fixers#prettier#Fix(buffer) abort
    return ale#semver#RunWithVersionCheck(
    \   a:buffer,
    \   ale#fixers#prettier#GetExecutable(a:buffer),
    \   '%e --version',
    \   function('ale#fixers#prettier#ApplyFixForVersion'),
    \)
endfunction

function! ale#fixers#prettier#ProcessPrettierDOutput(buffer, output) abort
    " If the output is an error message, don't use it.
    for l:line in a:output[:10]
        if l:line =~# '^\w*Error:'
            return []
        endif
    endfor

    return a:output
endfunction

function! ale#fixers#prettier#GetProjectRoot(buffer) abort
    let l:config = ale#path#FindNearestFile(a:buffer, '.prettierignore')

    if !empty(l:config)
        return fnamemodify(l:config, ':h')
    endif

    " Fall back to the directory of the buffer
    return fnamemodify(bufname(a:buffer), ':p:h')
endfunction

function! ale#fixers#prettier#CdProjectRoot(buffer) abort
    return ale#path#CdString(ale#fixers#prettier#GetProjectRoot(a:buffer))
endfunction

function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
    let l:executable = ale#fixers#prettier#GetExecutable(a:buffer)
    let l:options = ale#Var(a:buffer, 'javascript_prettier_options')
    let l:parser = ''

    let l:filetypes = split(getbufvar(a:buffer, '&filetype'), '\.')

    if index(l:filetypes, 'handlebars') > -1
        let l:parser = 'glimmer'
    endif

    " Append the --parser flag depending on the current filetype (unless it's
    " already set in g:javascript_prettier_options).
    if empty(expand('#' . a:buffer . ':e')) && l:parser is# ''  && match(l:options, '--parser') == -1
        " Mimic Prettier's defaults. In cases without a file extension or
        " filetype (scratch buffer), Prettier needs `parser` set to know how
        " to process the buffer.
        if ale#semver#GTE(a:version, [1, 16, 0])
            let l:parser = 'babel'
        else
            let l:parser = 'babylon'
        endif

        let l:prettier_parsers = {
        \    'typescript': 'typescript',
        \    'css': 'css',
        \    'less': 'less',
        \    'scss': 'scss',
        \    'json': 'json',
        \    'json5': 'json5',
        \    'graphql': 'graphql',
        \    'markdown': 'markdown',
        \    'vue': 'vue',
        \    'yaml': 'yaml',
        \    'openapi': 'yaml',
        \    'html': 'html',
        \}

        for l:filetype in l:filetypes
            if has_key(l:prettier_parsers, l:filetype)
                let l:parser = l:prettier_parsers[l:filetype]
                break
            endif
        endfor
    endif

    if !empty(l:parser)
        let l:options = (!empty(l:options) ? l:options . ' ' : '') . '--parser ' . l:parser
    endif

    " Special error handling needed for prettier_d
    if l:executable =~# 'prettier_d$'
        return {
        \   'command': ale#path#BufferCdString(a:buffer)
        \       . ale#Escape(l:executable)
        \       . (!empty(l:options) ? ' ' . l:options : '')
        \       . ' --stdin-filepath %s --stdin',
        \   'process_with': 'ale#fixers#prettier#ProcessPrettierDOutput',
        \}
    endif

    " 1.4.0 is the first version with --stdin-filepath
    if ale#semver#GTE(a:version, [1, 4, 0])
        return {
        \   'command': ale#fixers#prettier#CdProjectRoot(a:buffer)
        \       . ale#Escape(l:executable)
        \       . (!empty(l:options) ? ' ' . l:options : '')
        \       . ' --stdin-filepath %s --stdin',
        \}
    endif

    return {
    \   'command': ale#Escape(l:executable)
    \       . ' %t'
    \       . (!empty(l:options) ? ' ' . l:options : '')
    \       . ' --write',
    \   'read_temporary_file': 1,
    \}
endfunction