1#!/usr/bin/env python 2# 3# Copyright 2007 The Closure Linter Authors. All Rights Reserved. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS-IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17"""Core methods for checking JS files for common style guide violations.""" 18 19__author__ = ('robbyw@google.com (Robert Walker)', 20 'ajp@google.com (Andy Perelson)') 21 22import gflags as flags 23 24from closure_linter import checkerbase 25from closure_linter import closurizednamespacesinfo 26from closure_linter import ecmametadatapass 27from closure_linter import javascriptlintrules 28from closure_linter import javascriptstatetracker 29from closure_linter.common import lintrunner 30 31flags.DEFINE_list('limited_doc_files', ['dummy.js', 'externs.js'], 32 'List of files with relaxed documentation checks. Will not ' 33 'report errors for missing documentation, some missing ' 34 'descriptions, or methods whose @return tags don\'t have a ' 35 'matching return statement.') 36flags.DEFINE_list('closurized_namespaces', '', 37 'Namespace prefixes, used for testing of' 38 'goog.provide/require') 39flags.DEFINE_list('ignored_extra_namespaces', '', 40 'Fully qualified namespaces that should be not be reported ' 41 'as extra by the linter.') 42 43 44class JavaScriptStyleChecker(checkerbase.CheckerBase): 45 """Checker that applies JavaScriptLintRules.""" 46 47 def __init__(self, error_handler): 48 """Initialize an JavaScriptStyleChecker object. 49 50 Args: 51 error_handler: Error handler to pass all errors to. 52 """ 53 self._namespaces_info = None 54 if flags.FLAGS.closurized_namespaces: 55 self._namespaces_info = ( 56 closurizednamespacesinfo.ClosurizedNamespacesInfo( 57 flags.FLAGS.closurized_namespaces, 58 flags.FLAGS.ignored_extra_namespaces)) 59 60 checkerbase.CheckerBase.__init__( 61 self, 62 error_handler=error_handler, 63 lint_rules=javascriptlintrules.JavaScriptLintRules( 64 self._namespaces_info), 65 state_tracker=javascriptstatetracker.JavaScriptStateTracker(), 66 metadata_pass=ecmametadatapass.EcmaMetaDataPass(), 67 limited_doc_files=flags.FLAGS.limited_doc_files) 68 69 def _CheckTokens(self, token, parse_error, debug_tokens): 70 """Checks a token stream for lint warnings/errors. 71 72 Adds a separate pass for computing dependency information based on 73 goog.require and goog.provide statements prior to the main linting pass. 74 75 Args: 76 token: The first token in the token stream. 77 parse_error: A ParseError if any errors occurred. 78 debug_tokens: Whether every token should be printed as it is encountered 79 during the pass. 80 81 Returns: 82 A boolean indicating whether the full token stream could be checked or if 83 checking failed prematurely. 84 """ 85 # To maximize the amount of errors that get reported before a parse error 86 # is displayed, don't run the dependency pass if a parse error exists. 87 if self._namespaces_info and not parse_error: 88 self._namespaces_info.Reset() 89 result = (self._ExecutePass(token, self._DependencyPass) and 90 self._ExecutePass(token, self._LintPass, 91 debug_tokens=debug_tokens)) 92 else: 93 result = self._ExecutePass(token, self._LintPass, parse_error, 94 debug_tokens) 95 96 if not result: 97 return False 98 99 self._lint_rules.Finalize(self._state_tracker, self._tokenizer.mode) 100 101 self._error_handler.FinishFile() 102 return True 103 104 def _DependencyPass(self, token): 105 """Processes an invidual token for dependency information. 106 107 Used to encapsulate the logic needed to process an individual token so that 108 it can be passed to _ExecutePass. 109 110 Args: 111 token: The token to process. 112 """ 113 self._namespaces_info.ProcessToken(token, self._state_tracker) 114 115 116class GJsLintRunner(lintrunner.LintRunner): 117 """Wrapper class to run GJsLint.""" 118 119 def Run(self, filenames, error_handler): 120 """Run GJsLint on the given filenames. 121 122 Args: 123 filenames: The filenames to check 124 error_handler: An ErrorHandler object. 125 """ 126 checker = JavaScriptStyleChecker(error_handler) 127 128 # Check the list of files. 129 for filename in filenames: 130 checker.Check(filename) 131