def main(argv=None): """Main function. Args: argv: Sequence of command line arguments. """ if argv is None: argv = flags.FLAGS(sys.argv) suffixes = ['.js'] if FLAGS.additional_extensions: suffixes += ['.%s' % ext for ext in FLAGS.additional_extensions] files = fileflags.GetFileList(argv, 'JavaScript', suffixes) output_buffer = None if FLAGS.dry_run: output_buffer = StringIO.StringIO() fixer = error_fixer.ErrorFixer(output_buffer) # Check the list of files. for filename in files: runner.Run(filename, fixer) if FLAGS.dry_run: print output_buffer.getvalue()
def _AssertInError(self, original, expected): """Asserts that the error fixer corrects original to expected.""" # Trap gjslint's output parse it to get messages added. error_accumulator = erroraccumulator.ErrorAccumulator() runner.Run('testing.js', error_accumulator, source=original) error_nums = [e.code for e in error_accumulator.GetErrors()] self.assertIn(expected, error_nums)
def _AssertFixes(self, original, expected, include_header=True): """Asserts that the error fixer corrects original to expected.""" if include_header: original = self._GetHeader() + original expected = self._GetHeader() + expected actual = StringIO.StringIO() runner.Run('testing.js', error_fixer.ErrorFixer(actual), original) actual.seek(0) expected = [x + '\n' for x in expected] self.assertListEqual(actual.readlines(), expected)
def _AssertErrors(self, original, expected_errors, include_header=True): """Asserts that the error fixer corrects original to expected.""" if include_header: original = self._GetHeader() + original # Trap gjslint's output parse it to get messages added. error_accumulator = erroraccumulator.ErrorAccumulator() runner.Run('testing.js', error_accumulator, source=original) error_nums = [e.code for e in error_accumulator.GetErrors()] error_nums.sort() expected_errors.sort() self.assertListEqual(error_nums, expected_errors)
def _CheckPath(path): """Check a path and return any errors. Args: path: paths to check. Returns: A list of errorrecord.ErrorRecords for any found errors. """ error_handler = erroraccumulator.ErrorAccumulator() runner.Run(path, error_handler) make_error_record = lambda err: errorrecord.MakeErrorRecord(path, err) return map(make_error_record, error_handler.GetErrors())
def testFixJsStyle(self): test_cases = [['fixjsstyle.in.js', 'fixjsstyle.out.js'], ['indentation.js', 'fixjsstyle.indentation.out.js'], ['fixjsstyle.html.in.html', 'fixjsstyle.html.out.html'], [ 'fixjsstyle.oplineend.in.js', 'fixjsstyle.oplineend.out.js' ]] for [running_input_file, running_output_file] in test_cases: print 'Checking %s vs %s' % (running_input_file, running_output_file) input_filename = None golden_filename = None current_filename = None try: input_filename = '%s/%s' % (_RESOURCE_PREFIX, running_input_file) current_filename = input_filename golden_filename = '%s/%s' % (_RESOURCE_PREFIX, running_output_file) current_filename = golden_filename except IOError as ex: raise IOError('Could not find testdata resource for %s: %s' % (current_filename, ex)) if running_input_file == 'fixjsstyle.in.js': with open(input_filename) as f: for line in f: # Go to last line. pass self.assertTrue( line == line.rstrip(), '%s file should not end ' 'with a new line.' % (input_filename)) # Autofix the file, sending output to a fake file. actual = StringIO.StringIO() runner.Run(input_filename, error_fixer.ErrorFixer(actual)) # Now compare the files. actual.seek(0) expected = open(golden_filename, 'r') # Uncomment to generate new golden files and run # open('/'.join(golden_filename.split('/')[4:]), 'w').write(actual.read()) # actual.seek(0) self.assertEqual(actual.readlines(), expected.readlines())
def testRunOnMissingFile(self): mock_error_handler = self.mox.CreateMock(errorhandler.ErrorHandler) def ValidateError(err): return (isinstance(err, error.Error) and err.code is errors.FILE_NOT_FOUND and err.token is None) mock_error_handler.HandleFile('does_not_exist.js', None) mock_error_handler.HandleError(mox.Func(ValidateError)) mock_error_handler.FinishFile() self.mox.ReplayAll() runner.Run('does_not_exist.js', mock_error_handler) self.mox.VerifyAll()
def testBadTokenization(self): mock_error_handler = self.mox.CreateMock(errorhandler.ErrorHandler) def ValidateError(err): return (isinstance(err, error.Error) and err.code is errors.FILE_IN_BLOCK and err.token.string == '}') mock_error_handler.HandleFile('foo.js', mox.IsA(tokens.Token)) mock_error_handler.HandleError(mox.Func(ValidateError)) mock_error_handler.HandleError(mox.IsA(error.Error)) mock_error_handler.FinishFile() self.mox.ReplayAll() source = StringIO.StringIO(_BAD_TOKENIZATION_SCRIPT) runner.Run('foo.js', mock_error_handler, source) self.mox.VerifyAll()
def ClosureLint(self, file_to_lint, source=None): """Lints |file_to_lint| and returns the errors.""" import sys import warnings old_path = sys.path old_filters = warnings.filters try: closure_linter_path = self.input_api.os_path.join( self.input_api.change.RepositoryRoot(), "third_party", "closure_linter") gflags_path = self.input_api.os_path.join( self.input_api.change.RepositoryRoot(), "third_party", "python_gflags") sys.path.insert(0, closure_linter_path) sys.path.insert(0, gflags_path) warnings.filterwarnings('ignore', category=DeprecationWarning) from closure_linter import errors, runner from closure_linter.common import errorhandler import gflags finally: sys.path = old_path warnings.filters = old_filters class ErrorHandlerImpl(errorhandler.ErrorHandler): """Filters out errors that don't apply to Chromium JavaScript code.""" def __init__(self, re): self._errors = [] self.re = re def HandleFile(self, filename, first_token): self._filename = filename def HandleError(self, error): if (self._valid(error)): error.filename = self._filename self._errors.append(error) def GetErrors(self): return self._errors def HasErrors(self): return bool(self._errors) def _valid(self, error): """Check whether an error is valid. Most errors are valid, with a few exceptions which are listed here. """ is_grit_statement = bool( self.re.search("</?(include|if)", error.token.line)) # Ignore missing spaces before "(" until Promise#catch issue is solved. # http://crbug.com/338301 if (error.code == errors.MISSING_SPACE and error.token.string == '(' and 'catch(' in error.token.line): return False # Ignore "}.bind(" errors. http://crbug.com/397697 if (error.code == errors.MISSING_SEMICOLON_AFTER_FUNCTION and '}.bind(' in error.token.line): return False return not is_grit_statement and error.code not in [ errors.COMMA_AT_END_OF_LITERAL, errors.JSDOC_ILLEGAL_QUESTION_WITH_PIPE, errors.LINE_TOO_LONG, errors.MISSING_JSDOC_TAG_THIS, ] # Whitelist Polymer-specific JsDoc tags. gflags.FLAGS.custom_jsdoc_tags = ('group', 'element', 'attribute', 'default') error_handler = ErrorHandlerImpl(self.input_api.re) runner.Run(file_to_lint, error_handler, source=source) return error_handler.GetErrors()
def RunChecks(self): """Checks for violations of the Chromium JavaScript style guide. See: http://chromium.org/developers/web-development-style-guide#TOC-JavaScript """ old_path = sys.path old_filters = warnings.filters try: base_path = os.path.abspath( os.path.join(os.path.dirname(__file__), '..')) closure_linter_path = os.path.join(base_path, 'third_party', 'closure_linter') gflags_path = os.path.join(base_path, 'third_party', 'python_gflags') sys.path.insert(0, closure_linter_path) sys.path.insert(0, gflags_path) warnings.filterwarnings('ignore', category=DeprecationWarning) from closure_linter import runner, errors from closure_linter.common import errorhandler finally: sys.path = old_path warnings.filters = old_filters class ErrorHandlerImpl(errorhandler.ErrorHandler): """Filters out errors that don't apply to Chromium JavaScript code.""" def __init__(self): super(ErrorHandlerImpl, self).__init__() self._errors = [] self._filename = None def HandleFile(self, filename, _): self._filename = filename def HandleError(self, error): if self._Valid(error): error.filename = self._filename self._errors.append(error) def GetErrors(self): return self._errors def HasErrors(self): return bool(self._errors) def _Valid(self, error): """Checks whether an error is valid. Most errors are valid, with a few exceptions which are listed here. """ if re.search('</?(include|if)', error.token.line): return False # GRIT statement. if (error.code == errors.MISSING_SEMICOLON and error.token.string == 'of'): return False # ES6 for...of statement. if (error.code == errors.LINE_STARTS_WITH_OPERATOR and error.token.string == '*'): return False # *[...] syntax if (error.code == errors.MISSING_SPACE and error.token.string == '['): return False # *[...] syntax return error.code not in [ errors.JSDOC_ILLEGAL_QUESTION_WITH_PIPE, errors.MISSING_JSDOC_TAG_THIS, errors.MISSING_MEMBER_DOCUMENTATION, ] results = [] affected_files = self.input_api.AffectedFiles( file_filter=self.file_filter, include_deletes=False) def ShouldCheck(f): if f.LocalPath().endswith('.js'): return True if f.LocalPath().endswith('.html'): return True return False affected_js_files = filter(ShouldCheck, affected_files) for f in affected_js_files: error_lines = [] contents = list(f.NewContents()) error_lines += CheckStrictMode( '\n'.join(contents), is_html_file=f.LocalPath().endswith('.html')) for i, line in enumerate(contents, start=1): error_lines += filter(None, [self.ConstCheck(i, line)]) # Use closure_linter to check for several different errors. import gflags as flags flags.FLAGS.strict = True error_handler = ErrorHandlerImpl() runner.Run(f.AbsoluteLocalPath(), error_handler) for error in error_handler.GetErrors(): highlight = _ErrorHighlight(error.token.start_index, error.token.length) error_msg = ' line %d: E%04d: %s\n%s\n%s' % ( error.token.line_number, error.code, error.message, error.token.line.rstrip(), highlight) error_lines.append(error_msg) if error_lines: error_lines = [ 'Found JavaScript style violations in %s:' % f.LocalPath() ] + error_lines results.append( _MakeErrorOrWarning(self.output_api, '\n'.join(error_lines))) return results