tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

source.py (3697B)


      1 # Copyright 2009 The Closure Library Authors. All Rights Reserved.
      2 #
      3 # Licensed under the Apache License, Version 2.0 (the "License");
      4 # you may not use this file except in compliance with the License.
      5 # You may obtain a copy of the License at
      6 #
      7 #      http://www.apache.org/licenses/LICENSE-2.0
      8 #
      9 # Unless required by applicable law or agreed to in writing, software
     10 # distributed under the License is distributed on an "AS-IS" BASIS,
     11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 # See the License for the specific language governing permissions and
     13 # limitations under the License.
     14 
     15 
     16 """Scans a source JS file for its provided and required namespaces.
     17 
     18 Simple class to scan a JavaScript file and express its dependencies.
     19 """
     20 
     21 __author__ = 'nnaze@google.com'
     22 
     23 
     24 import re
     25 
     26 _BASE_REGEX_STRING = r'^\s*goog\.%s\(\s*[\'"](.+)[\'"]\s*\)'
     27 _MODULE_REGEX = re.compile(_BASE_REGEX_STRING % 'module')
     28 _PROVIDE_REGEX = re.compile(_BASE_REGEX_STRING % 'provide')
     29 
     30 _REQUIRE_REGEX_STRING = (r'^\s*(?:(?:var|let|const)\s+[a-zA-Z_$][a-zA-Z0-9$_]*'
     31                         r'\s*=\s*)?goog\.require\(\s*[\'"](.+)[\'"]\s*\)')
     32 _REQUIRES_REGEX = re.compile(_REQUIRE_REGEX_STRING)
     33 
     34 
     35 class Source(object):
     36  """Scans a JavaScript source for its provided and required namespaces."""
     37 
     38  # Matches a "/* ... */" comment.
     39  # Note: We can't definitively distinguish a "/*" in a string literal without a
     40  # state machine tokenizer. We'll assume that a line starting with whitespace
     41  # and "/*" is a comment.
     42  _COMMENT_REGEX = re.compile(
     43      r"""
     44      ^\s*   # Start of a new line and whitespace
     45      /\*    # Opening "/*"
     46      .*?    # Non greedy match of any characters (including newlines)
     47      \*/    # Closing "*/""",
     48      re.MULTILINE | re.DOTALL | re.VERBOSE)
     49 
     50  def __init__(self, source):
     51    """Initialize a source.
     52 
     53    Args:
     54      source: str, The JavaScript source.
     55    """
     56 
     57    self.provides = set()
     58    self.requires = set()
     59    self.is_goog_module = False
     60 
     61    self._source = source
     62    self._ScanSource()
     63 
     64  def GetSource(self):
     65    """Get the source as a string."""
     66    return self._source
     67 
     68  @classmethod
     69  def _StripComments(cls, source):
     70    return cls._COMMENT_REGEX.sub('', source)
     71 
     72  @classmethod
     73  def _HasProvideGoogFlag(cls, source):
     74    """Determines whether the @provideGoog flag is in a comment."""
     75    for comment_content in cls._COMMENT_REGEX.findall(source):
     76      if '@provideGoog' in comment_content:
     77        return True
     78 
     79    return False
     80 
     81  def _ScanSource(self):
     82    """Fill in provides and requires by scanning the source."""
     83 
     84    stripped_source = self._StripComments(self.GetSource())
     85 
     86    source_lines = stripped_source.splitlines()
     87    for line in source_lines:
     88      match = _PROVIDE_REGEX.match(line)
     89      if match:
     90        self.provides.add(match.group(1))
     91      match = _MODULE_REGEX.match(line)
     92      if match:
     93        self.provides.add(match.group(1))
     94        self.is_goog_module = True
     95      match = _REQUIRES_REGEX.match(line)
     96      if match:
     97        self.requires.add(match.group(1))
     98 
     99    # Closure's base file implicitly provides 'goog'.
    100    # This is indicated with the @provideGoog flag.
    101    if self._HasProvideGoogFlag(self.GetSource()):
    102 
    103      if len(self.provides) or len(self.requires):
    104        raise Exception(
    105            'Base file should not provide or require namespaces.')
    106 
    107      self.provides.add('goog')
    108 
    109 
    110 def GetFileContents(path):
    111  """Get a file's contents as a string.
    112 
    113  Args:
    114    path: str, Path to file.
    115 
    116  Returns:
    117    str, Contents of file.
    118 
    119  Raises:
    120    IOError: An error occurred opening or reading the file.
    121 
    122  """
    123  fileobj = open(path)
    124  try:
    125    return fileobj.read()
    126  finally:
    127    fileobj.close()