#!/usr/bin/env python # # Copyright 2007 The Closure Linter Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS-IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Core methods for checking JS files for common style guide violations.""" __author__ = ('robbyw@google.com (Robert Walker)', 'ajp@google.com (Andy Perelson)') import gflags as flags from closure_linter import checkerbase from closure_linter import closurizednamespacesinfo from closure_linter import ecmametadatapass from closure_linter import errors from closure_linter import javascriptlintrules from closure_linter import javascriptstatetracker from closure_linter.common import errorprinter from closure_linter.common import lintrunner flags.DEFINE_list('limited_doc_files', ['dummy.js', 'externs.js'], 'List of files with relaxed documentation checks. Will not ' 'report errors for missing documentation, some missing ' 'descriptions, or methods whose @return tags don\'t have a ' 'matching return statement.') flags.DEFINE_list('closurized_namespaces', '', 'Namespace prefixes, used for testing of' 'goog.provide/require') flags.DEFINE_list('ignored_extra_namespaces', '', 'Fully qualified namespaces that should be not be reported ' 'as extra by the linter.') class JavaScriptStyleChecker(checkerbase.CheckerBase): """Checker that applies JavaScriptLintRules.""" def __init__(self, error_handler): """Initialize an JavaScriptStyleChecker object. Args: error_handler: Error handler to pass all errors to """ self._namespaces_info = None if flags.FLAGS.closurized_namespaces: self._namespaces_info = ( closurizednamespacesinfo.ClosurizedNamespacesInfo( flags.FLAGS.closurized_namespaces, flags.FLAGS.ignored_extra_namespaces)) checkerbase.CheckerBase.__init__( self, error_handler=error_handler, lint_rules=javascriptlintrules.JavaScriptLintRules( self._namespaces_info), state_tracker=javascriptstatetracker.JavaScriptStateTracker(), metadata_pass=ecmametadatapass.EcmaMetaDataPass(), limited_doc_files=flags.FLAGS.limited_doc_files) def _CheckTokens(self, token, parse_error, debug_tokens): """Checks a token stream for lint warnings/errors. Adds a separate pass for computing dependency information based on goog.require and goog.provide statements prior to the main linting pass. Args: token: The first token in the token stream. parse_error: A ParseError if any errors occurred. debug_tokens: Whether every token should be printed as it is encountered during the pass. Returns: A boolean indicating whether the full token stream could be checked or if checking failed prematurely. """ # To maximize the amount of errors that get reported before a parse error # is displayed, don't run the dependency pass if a parse error exists. if self._namespaces_info and not parse_error: self._namespaces_info.Reset() result = (self._ExecutePass(token, self._DependencyPass) and self._ExecutePass(token, self._LintPass, debug_tokens=debug_tokens)) else: result = self._ExecutePass(token, self._LintPass, parse_error, debug_tokens) if not result: return False self._lint_rules.Finalize(self._state_tracker, self._tokenizer.mode) self._error_handler.FinishFile() return True def _DependencyPass(self, token): """Processes an invidual token for dependency information. Used to encapsulate the logic needed to process an individual token so that it can be passed to _ExecutePass. Args: token: The token to process. """ self._namespaces_info.ProcessToken(token, self._state_tracker) class GJsLintRunner(lintrunner.LintRunner): """Wrapper class to run GJsLint.""" def Run(self, filenames, error_handler=None): """Run GJsLint on the given filenames. Args: filenames: The filenames to check error_handler: An optional ErrorHandler object, an ErrorPrinter is used if none is specified. Returns: error_count, file_count: The number of errors and the number of files that contain errors. """ if not error_handler: error_handler = errorprinter.ErrorPrinter(errors.NEW_ERRORS) checker = JavaScriptStyleChecker(error_handler) # Check the list of files. for filename in filenames: checker.Check(filename) return error_handler