| 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 |