aboutsummaryrefslogtreecommitdiff
path: root/tools/closure_linter-2.3.4/closure_linter/checker.py
blob: 9cca74201c4c06bb32c519d20d42b986525e7aea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#!/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