| OLD | NEW |
| (Empty) |
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 # Use of this source code is governed by a BSD-style license that can be | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 """ | |
| 6 Presubmit for Chromium HTML resources. See chrome/browser/PRESUBMIT.py. | |
| 7 """ | |
| 8 | |
| 9 import regex_check | |
| 10 | |
| 11 | |
| 12 class HtmlChecker(object): | |
| 13 def __init__(self, input_api, output_api, file_filter=None): | |
| 14 self.input_api = input_api | |
| 15 self.output_api = output_api | |
| 16 self.file_filter = file_filter | |
| 17 | |
| 18 def ClassesUseDashFormCheck(self, line_number, line): | |
| 19 regex = self.input_api.re.compile(""" | |
| 20 (?:^|\s) # start of line or whitespace | |
| 21 (class="[^"]*[A-Z_][^"]*") # class contains caps or '_' | |
| 22 """, | |
| 23 self.input_api.re.VERBOSE) | |
| 24 return regex_check.RegexCheck(self.input_api.re, line_number, line, regex, | |
| 25 "Classes should use dash-form.") | |
| 26 | |
| 27 def DoNotCloseSingleTagsCheck(self, line_number, line): | |
| 28 regex = r"(/>)" | |
| 29 return regex_check.RegexCheck(self.input_api.re, line_number, line, regex, | |
| 30 "Do not close single tags.") | |
| 31 | |
| 32 def DoNotUseBrElementCheck(self, line_number, line): | |
| 33 regex = r"(<br)" | |
| 34 return regex_check.RegexCheck(self.input_api.re, line_number, line, regex, | |
| 35 "Do not use <br>; place blocking elements (<div>) as appropriate.") | |
| 36 | |
| 37 def DoNotUseInputTypeButtonCheck(self, line_number, line): | |
| 38 regex = self.input_api.re.compile(""" | |
| 39 (<input [^>]* # "<input " followed by anything but ">" | |
| 40 type="button" # type="button" | |
| 41 [^>]*>) # anything but ">" then ">" | |
| 42 """, | |
| 43 self.input_api.re.VERBOSE) | |
| 44 return regex_check.RegexCheck(self.input_api.re, line_number, line, regex, | |
| 45 'Use the button element instead of <input type="button">') | |
| 46 | |
| 47 def DoNotUseSingleQuotesCheck(self, line_number, line): | |
| 48 regex = self.input_api.re.compile(""" | |
| 49 <\S+ # The tag name. | |
| 50 (?:\s+\S+\$?="[^"]*"|\s+\S+)* # Correctly quoted or non-value props. | |
| 51 \s+(\S+\$?='[^']*') # Find incorrectly quoted (foo='bar'). | |
| 52 [^>]*> # To the end of the tag. | |
| 53 """, | |
| 54 self.input_api.re.MULTILINE | self.input_api.re.VERBOSE) | |
| 55 return regex_check.RegexCheck(self.input_api.re, line_number, line, regex, | |
| 56 'Use double quotes rather than single quotes in HTML properties') | |
| 57 | |
| 58 def I18nContentJavaScriptCaseCheck(self, line_number, line): | |
| 59 regex = self.input_api.re.compile(""" | |
| 60 (?:^|\s) # start of line or whitespace | |
| 61 i18n-content=" # i18n-content=" | |
| 62 ([A-Z][^"]*|[^"]*[-_][^"]*)" # starts with caps or contains '-' or '_' | |
| 63 """, | |
| 64 self.input_api.re.VERBOSE) | |
| 65 return regex_check.RegexCheck(self.input_api.re, line_number, line, regex, | |
| 66 "For i18n-content use javaScriptCase.") | |
| 67 | |
| 68 def LabelCheck(self, line_number, line): | |
| 69 regex = self.input_api.re.compile(""" | |
| 70 (?:^|\s) # start of line or whitespace | |
| 71 <label[^>]+? # <label tag | |
| 72 (for=) # for= | |
| 73 """, | |
| 74 self.input_api.re.VERBOSE) | |
| 75 return regex_check.RegexCheck(self.input_api.re, line_number, line, regex, | |
| 76 "Avoid 'for' attribute on <label>. Place the input within the <label>, " | |
| 77 "or use aria-labelledby for <select>.") | |
| 78 | |
| 79 def QuotePolymerBindings(self, line_number, line): | |
| 80 regex = self.input_api.re.compile(r"=(\[\[|\{\{)") | |
| 81 return regex_check.RegexCheck(self.input_api.re, line_number, line, regex, | |
| 82 'Please use quotes around Polymer bindings (i.e. attr="[[prop]]")') | |
| 83 | |
| 84 def RunChecks(self): | |
| 85 """Check for violations of the Chromium web development style guide. See | |
| 86 https://chromium.googlesource.com/chromium/src/+/master/styleguide/web/we
b.md | |
| 87 """ | |
| 88 results = [] | |
| 89 | |
| 90 affected_files = self.input_api.change.AffectedFiles( | |
| 91 file_filter=self.file_filter, include_deletes=False) | |
| 92 | |
| 93 for f in affected_files: | |
| 94 if not f.LocalPath().endswith('.html'): | |
| 95 continue | |
| 96 | |
| 97 errors = [] | |
| 98 | |
| 99 for line_number, line in f.ChangedContents(): | |
| 100 errors.extend(filter(None, [ | |
| 101 self.ClassesUseDashFormCheck(line_number, line), | |
| 102 self.DoNotCloseSingleTagsCheck(line_number, line), | |
| 103 self.DoNotUseBrElementCheck(line_number, line), | |
| 104 self.DoNotUseInputTypeButtonCheck(line_number, line), | |
| 105 self.I18nContentJavaScriptCaseCheck(line_number, line), | |
| 106 self.LabelCheck(line_number, line), | |
| 107 self.QuotePolymerBindings(line_number, line), | |
| 108 ])) | |
| 109 | |
| 110 if errors: | |
| 111 abs_local_path = f.AbsoluteLocalPath() | |
| 112 file_indicator = 'Found HTML style issues in %s' % abs_local_path | |
| 113 prompt_msg = file_indicator + '\n\n' + '\n'.join(errors) + '\n' | |
| 114 results.append(self.output_api.PresubmitPromptWarning(prompt_msg)) | |
| 115 | |
| 116 return results | |
| OLD | NEW |