forked from SublimeLinter/SublimeLinter-jshint
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlinter.py
137 lines (112 loc) · 4.72 KB
/
linter.py
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
#
# linter.py
# Linter for SublimeLinter3, a code checking framework for Sublime Text 3
#
# Written by Aparajita Fishman
# Copyright (c) 2013 Aparajita Fishman
#
# License: MIT
#
"""This module exports the JSHint plugin linter class."""
import re
from SublimeLinter.lint import Linter
class JSHint(Linter):
"""Provides an interface to the jshint executable."""
syntax = ('javascript', 'html', 'javascriptnext')
executable = 'jshint'
version_args = '--version'
version_re = r'\bv(?P<version>\d+\.\d+\.\d+)'
version_requirement = '>= 2.5.0'
regex = (
r'^(?:(?P<fail>ERROR: .+)|'
r'.+?: line (?P<line>\d+), col (?P<col>\d+), '
r'(?P<message>'
# undefined warnings
r'\'(?P<undef>.+)\'.+(?=.+W098)'
# duplicate key
r'|.+\'(?P<duplicate>.+)\'.+(?=.+W075)'
# camel case
r'|.+\'(?P<no_camel>.+)\'.+(?=.+W106)'
# using later defined
r'|(.+)?\'(?P<late_def>.+)\'.+(?=.+W003)'
# double declaration
r'|(.+)?\'(?P<double_declare>.+)\'.+(?=.+W004)'
# unexpected use, typically use of non strict operators
r'|.+\'(?P<actual>.+)\'\.(?=.+W116)'
# unexpected use of ++ etc
r'|.+\'(?P<unexpected>.+)\'\.(?=.+W016)'
# match all messages
r'|.+)'
# capture error, warning and code
r' \((?:(?P<error>E)|(?P<warning>W))(?P<code>\d+)\))'
)
config_file = ('--config', '.jshintrc', '~')
def cmd(self):
"""Return the command line to execute."""
command = [self.executable_path, '--verbose', '--filename', '@']
if self.syntax == 'html':
command.append('--extract=always')
return command + ['*', '-']
def split_match(self, match):
"""
Return the components of the match.
We override this to catch linter error messages and return more presise
info used for highlighting.
"""
# restore word regex to default each iteration
self.word_re = None
if match:
fail = match.group('fail')
if fail:
# match, line, col, error, warning, message, near
return match, 0, 0, True, False, fail, None
# now safe to proceed, no error occured with jshint
error = match.group('error')
warning = match.group('warning')
message = match.group('message')
code = match.group('code')
# force line numbers to be at least 0
# if not they appear at end of file
line = max(int(match.group('line')) - 1, 0)
col = int(match.group('col')) - 1
near = None
if warning:
# highlight variables used before defined
if code == '003':
near = match.group('late_def')
col -= len(match.group('late_def'))
# highlight double declared variables
elif code == '004':
near = match.group('double_declare')
col -= len(match.group('double_declare'))
# now jshint place the column in front,
# and as such we need to change our word matching regex,
# and keep the column info
elif code == '016':
self.word_re = re.compile(r'\+\+|--')
# mark the duplicate key
elif code == '075' and match.group('duplicate'):
near = match.group('duplicate')
col = None
# mark the undefined word
elif code == '098' and match.group('undef'):
near = match.group('undef')
col = None
# mark the no camel case key, cannot use safer method of
# subtracting the length of the match, as the original col info
# from jshint is always column 0, using near instead
elif code == '106':
near = match.group('no_camel')
col = None
# if we have a operator == or != manually change the column,
# this also handles the warning when curly brackets are required
# near won't work here as we might have multiple ==/!= on a line
elif code == '116':
actual = match.group('actual')
# match the actual result
near = match.group('actual')
# if a comparison then also change the column
if actual == '!=' or actual == '==':
col -= len(actual)
return match, line, col, error, warning, message, near
return match, None, None, None, None, '', None