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 aliaspass 25from closure_linter import checkerbase 26from closure_linter import closurizednamespacesinfo 27from closure_linter import javascriptlintrules 28 29 30flags.DEFINE_list('closurized_namespaces', '', 31 'Namespace prefixes, used for testing of' 32 'goog.provide/require') 33flags.DEFINE_list('ignored_extra_namespaces', '', 34 'Fully qualified namespaces that should be not be reported ' 35 'as extra by the linter.') 36 37 38class JavaScriptStyleChecker(checkerbase.CheckerBase): 39 """Checker that applies JavaScriptLintRules.""" 40 41 def __init__(self, state_tracker, error_handler): 42 """Initialize an JavaScriptStyleChecker object. 43 44 Args: 45 state_tracker: State tracker. 46 error_handler: Error handler to pass all errors to. 47 """ 48 self._namespaces_info = None 49 self._alias_pass = None 50 if flags.FLAGS.closurized_namespaces: 51 self._namespaces_info = ( 52 closurizednamespacesinfo.ClosurizedNamespacesInfo( 53 flags.FLAGS.closurized_namespaces, 54 flags.FLAGS.ignored_extra_namespaces)) 55 56 self._alias_pass = aliaspass.AliasPass( 57 flags.FLAGS.closurized_namespaces, error_handler) 58 59 checkerbase.CheckerBase.__init__( 60 self, 61 error_handler=error_handler, 62 lint_rules=javascriptlintrules.JavaScriptLintRules( 63 self._namespaces_info), 64 state_tracker=state_tracker) 65 66 def Check(self, start_token, limited_doc_checks=False, is_html=False, 67 stop_token=None): 68 """Checks a token stream for lint warnings/errors. 69 70 Adds a separate pass for computing dependency information based on 71 goog.require and goog.provide statements prior to the main linting pass. 72 73 Args: 74 start_token: The first token in the token stream. 75 limited_doc_checks: Whether to perform limited checks. 76 is_html: Whether this token stream is HTML. 77 stop_token: If given, checks should stop at this token. 78 """ 79 self._lint_rules.Initialize(self, limited_doc_checks, is_html) 80 81 self._state_tracker.DocFlagPass(start_token, self._error_handler) 82 83 if self._alias_pass: 84 self._alias_pass.Process(start_token) 85 86 # To maximize the amount of errors that get reported before a parse error 87 # is displayed, don't run the dependency pass if a parse error exists. 88 if self._namespaces_info: 89 self._namespaces_info.Reset() 90 self._ExecutePass(start_token, self._DependencyPass, stop_token) 91 92 self._ExecutePass(start_token, self._LintPass, stop_token) 93 94 # If we have a stop_token, we didn't end up reading the whole file and, 95 # thus, don't call Finalize to do end-of-file checks. 96 if not stop_token: 97 self._lint_rules.Finalize(self._state_tracker) 98 99 def _DependencyPass(self, token): 100 """Processes an individual token for dependency information. 101 102 Used to encapsulate the logic needed to process an individual token so that 103 it can be passed to _ExecutePass. 104 105 Args: 106 token: The token to process. 107 """ 108 self._namespaces_info.ProcessToken(token, self._state_tracker) 109