OLD | NEW |
1 # Copyright (c) 2014 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2014 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import re | 5 import re |
6 | 6 |
7 import eslint | 7 import eslint |
8 from py_vulcanize import strip_js_comments | 8 from py_vulcanize import strip_js_comments |
9 | 9 |
10 from catapult_build import parse_html | 10 from catapult_build import parse_html |
11 | 11 |
12 | 12 |
13 class JSChecker(object): | 13 class JSChecker(object): |
14 | 14 |
15 def __init__(self, input_api, output_api, file_filter=None): | 15 def __init__(self, input_api, output_api, file_filter=None): |
16 self.input_api = input_api | 16 self.input_api = input_api |
17 self.output_api = output_api | 17 self.output_api = output_api |
18 if file_filter: | 18 if file_filter: |
19 self.file_filter = file_filter | 19 self.file_filter = file_filter |
20 else: | 20 else: |
21 self.file_filter = lambda x: True | 21 self.file_filter = lambda x: True |
22 | 22 |
23 def RegexCheck(self, line_number, line, regex, message): | |
24 """Searches for |regex| in |line| to check for a style violation. | |
25 | |
26 The |regex| must have exactly one capturing group so that the relevant | |
27 part of |line| can be highlighted. If more groups are needed, use | |
28 "(?:...)" to make a non-capturing group. Sample message: | |
29 | |
30 Returns a message like the one below if the regex matches. | |
31 line 6: Use var instead of const. | |
32 const foo = bar(); | |
33 ^^^^^ | |
34 """ | |
35 match = re.search(regex, line) | |
36 if match: | |
37 assert len(match.groups()) == 1 | |
38 start = match.start(1) | |
39 length = match.end(1) - start | |
40 return ' line %d: %s\n%s\n%s' % ( | |
41 line_number, | |
42 message, | |
43 line, | |
44 _ErrorHighlight(start, length)) | |
45 return '' | |
46 | |
47 def ConstCheck(self, i, line): | |
48 """Checks for use of the 'const' keyword.""" | |
49 if re.search(r'\*\s+@const', line): | |
50 # Probably a JsDoc line. | |
51 return '' | |
52 | |
53 return self.RegexCheck( | |
54 i, line, r'(?:^|\s|\()(const)\s', 'Use var instead of const.') | |
55 | |
56 def RunChecks(self): | 23 def RunChecks(self): |
57 """Checks for violations of the Chromium JavaScript style guide. | 24 """Checks for violations of the Chromium JavaScript style guide. |
58 | 25 |
59 See: | 26 See: |
60 http://chromium.org/developers/web-development-style-guide#TOC-JavaScript | 27 http://chromium.org/developers/web-development-style-guide#TOC-JavaScript |
61 """ | 28 """ |
62 results = [] | 29 results = [] |
63 | 30 |
64 affected_files = self.input_api.AffectedFiles( | 31 affected_files = self.input_api.AffectedFiles( |
65 file_filter=self.file_filter, | 32 file_filter=self.file_filter, |
66 include_deletes=False) | 33 include_deletes=False) |
67 | 34 |
68 def ShouldCheck(f): | 35 def ShouldCheck(f): |
69 if f.LocalPath().endswith('.js'): | 36 if f.LocalPath().endswith('.js'): |
70 return True | 37 return True |
71 if f.LocalPath().endswith('.html'): | 38 if f.LocalPath().endswith('.html'): |
72 return True | 39 return True |
73 return False | 40 return False |
74 | 41 |
75 affected_js_files = filter(ShouldCheck, affected_files) | 42 affected_js_files = filter(ShouldCheck, affected_files) |
76 error_lines = [] | 43 error_lines = [] |
77 for f in affected_js_files: | 44 for f in affected_js_files: |
78 contents = list(f.NewContents()) | 45 contents = list(f.NewContents()) |
79 error_lines += CheckStrictMode( | 46 error_lines += CheckStrictMode( |
80 '\n'.join(contents), | 47 '\n'.join(contents), |
81 is_html_file=f.LocalPath().endswith('.html')) | 48 is_html_file=f.LocalPath().endswith('.html')) |
82 | 49 |
83 for i, line in enumerate(contents, start=1): | |
84 error_lines += filter(None, [self.ConstCheck(i, line)]) | |
85 | |
86 if affected_js_files: | 50 if affected_js_files: |
87 success, eslint_output = eslint.RunEslint( | 51 success, eslint_output = eslint.RunEslint( |
88 [f.AbsoluteLocalPath() for f in affected_js_files]) | 52 [f.AbsoluteLocalPath() for f in affected_js_files]) |
89 | 53 |
90 if not success: | 54 if not success: |
91 error_lines.append('\neslint found lint errors:') | 55 error_lines.append('\neslint found lint errors:') |
92 error_lines.append(eslint_output) | 56 error_lines.append(eslint_output) |
93 | 57 |
94 if error_lines: | 58 if error_lines: |
95 error_lines.insert(0, 'Found JavaScript style violations:') | 59 error_lines.insert(0, 'Found JavaScript style violations:') |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
140 | 104 |
141 def RunChecks(input_api, output_api, excluded_paths=None): | 105 def RunChecks(input_api, output_api, excluded_paths=None): |
142 | 106 |
143 def ShouldCheck(affected_file): | 107 def ShouldCheck(affected_file): |
144 if not excluded_paths: | 108 if not excluded_paths: |
145 return True | 109 return True |
146 path = affected_file.LocalPath() | 110 path = affected_file.LocalPath() |
147 return not any(re.match(pattern, path) for pattern in excluded_paths) | 111 return not any(re.match(pattern, path) for pattern in excluded_paths) |
148 | 112 |
149 return JSChecker(input_api, output_api, file_filter=ShouldCheck).RunChecks() | 113 return JSChecker(input_api, output_api, file_filter=ShouldCheck).RunChecks() |
OLD | NEW |