requireprovidesorter.py revision 5821806d5e7f356e8fa4b058a389a808ea183019
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright 2011 The Closure Linter Authors. All Rights Reserved.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Licensed under the Apache License, Version 2.0 (the "License");
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# you may not use this file except in compliance with the License.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# You may obtain a copy of the License at
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#      http://www.apache.org/licenses/LICENSE-2.0
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Unless required by applicable law or agreed to in writing, software
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# distributed under the License is distributed on an "AS-IS" BASIS,
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# See the License for the specific language governing permissions and
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# limitations under the License.
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""Contains logic for sorting goog.provide and goog.require statements.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Closurized JavaScript files use goog.provide and goog.require statements at the
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)top of the file to manage dependencies. These statements should be sorted
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)alphabetically, however, it is common for them to be accompanied by inline
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)comments or suppression annotations. In order to sort these statements without
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)disrupting their comments and annotations, the association between statements
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)and comments/annotations must be maintained while sorting.
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RequireProvideSorter: Handles checking/fixing of provide/require statements.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from closure_linter import javascripttokens
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from closure_linter import tokenutil
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Shorthand
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Type = javascripttokens.JavaScriptTokenType
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class RequireProvideSorter(object):
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Checks for and fixes alphabetization of provide and require statements.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  When alphabetizing, comments on the same line or comments directly above a
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  goog.provide or goog.require statement are associated with that statement and
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stay with the statement as it gets sorted.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CheckProvides(self, token):
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Checks alphabetization of goog.provide statements.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Iterates over tokens in given token stream, identifies goog.provide tokens,
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    and checks that they occur in alphabetical order by the object being
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    provided.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      token: A token in the token stream before any goog.provide tokens.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A tuple containing the first provide token in the token stream and a list
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      of provided objects sorted alphabetically. For example:
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (JavaScriptToken, ['object.a', 'object.b', ...])
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      None is returned if all goog.provide statements are already sorted.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    provide_tokens = self._GetRequireOrProvideTokens(token, 'goog.provide')
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    provide_strings = self._GetRequireOrProvideTokenStrings(provide_tokens)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sorted_provide_strings = sorted(provide_strings)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if provide_strings != sorted_provide_strings:
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return [provide_tokens[0], sorted_provide_strings]
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return None
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CheckRequires(self, token):
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Checks alphabetization of goog.require statements.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Iterates over tokens in given token stream, identifies goog.require tokens,
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    and checks that they occur in alphabetical order by the dependency being
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    required.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      token: A token in the token stream before any goog.require tokens.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A tuple containing the first require token in the token stream and a list
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      of required dependencies sorted alphabetically. For example:
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (JavaScriptToken, ['object.a', 'object.b', ...])
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      None is returned if all goog.require statements are already sorted.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    require_tokens = self._GetRequireOrProvideTokens(token, 'goog.require')
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    require_strings = self._GetRequireOrProvideTokenStrings(require_tokens)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sorted_require_strings = sorted(require_strings)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if require_strings != sorted_require_strings:
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return (require_tokens[0], sorted_require_strings)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return None
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def FixProvides(self, token):
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Sorts goog.provide statements in the given token stream alphabetically.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      token: The first token in the token stream.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._FixProvidesOrRequires(
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._GetRequireOrProvideTokens(token, 'goog.provide'))
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def FixRequires(self, token):
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Sorts goog.require statements in the given token stream alphabetically.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      token: The first token in the token stream.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._FixProvidesOrRequires(
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._GetRequireOrProvideTokens(token, 'goog.require'))
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _FixProvidesOrRequires(self, tokens):
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Sorts goog.provide or goog.require statements.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tokens: A list of goog.provide or goog.require tokens in the order they
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              appear in the token stream. i.e. the first token in this list must
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              be the first goog.provide or goog.require token.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    strings = self._GetRequireOrProvideTokenStrings(tokens)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sorted_strings = sorted(strings)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Make a separate pass to remove any blank lines between goog.require/
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # goog.provide tokens.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    first_token = tokens[0]
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_token = tokens[-1]
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    i = last_token
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while i != first_token:
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if i.type is Type.BLANK_LINE:
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tokenutil.DeleteToken(i)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      i = i.previous
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # A map from required/provided object name to tokens that make up the line
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # it was on, including any comments immediately before it or after it on the
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # same line.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tokens_map = self._GetTokensMap(tokens)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Iterate over the map removing all tokens.
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for name in tokens_map:
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tokens_to_delete = tokens_map[name]
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for i in tokens_to_delete:
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tokenutil.DeleteToken(i)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Re-add all tokens in the map in alphabetical order.
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    insert_after = tokens[0].previous
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for string in sorted_strings:
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for i in tokens_map[string]:
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tokenutil.InsertTokenAfter(i, insert_after)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        insert_after = i
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GetRequireOrProvideTokens(self, token, token_string):
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets all goog.provide or goog.require tokens in the given token stream.
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      token: The first token in the token stream.
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      token_string: One of 'goog.provide' or 'goog.require' to indicate which
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    tokens to find.
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A list of goog.provide or goog.require tokens in the order they appear in
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      the token stream.
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tokens = []
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while token:
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if token.type == Type.IDENTIFIER:
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if token.string == token_string:
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          tokens.append(token)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        elif token.string not in ['goog.require', 'goog.provide']:
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          # The goog.provide and goog.require identifiers are at the top of the
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          # file. So if any other identifier is encountered, return.
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      token = token.next
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return tokens
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GetRequireOrProvideTokenStrings(self, tokens):
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets a list of strings corresponding to the given list of tokens.
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The string will be the next string in the token stream after each token in
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tokens. This is used to find the object being provided/required by a given
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    goog.provide or goog.require token.
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tokens: A list of goog.provide or goog.require tokens.
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A list of object names that are being provided or required by the given
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      list of tokens. For example:
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ['object.a', 'object.c', 'object.b']
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token_strings = []
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for token in tokens:
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      name = tokenutil.Search(token, Type.STRING_TEXT).string
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      token_strings.append(name)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return token_strings
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GetTokensMap(self, tokens):
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets a map from object name to tokens associated with that object.
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Starting from the goog.provide/goog.require token, searches backwards in the
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token stream for any lines that start with a comment. These lines are
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    associated with the goog.provide/goog.require token. Also associates any
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tokens on the same line as the goog.provide/goog.require token with that
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token.
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tokens: A list of goog.provide or goog.require tokens.
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary that maps object names to the tokens associated with the
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      goog.provide or goog.require of that object name. For example:
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'object.a': [JavaScriptToken, JavaScriptToken, ...],
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'object.b': [...]
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The list of tokens includes any comment lines above the goog.provide or
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      goog.require statement and everything after the statement on the same
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      line. For example, all of the following would be associated with
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'object.a':
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /** @suppress {extraRequire} */
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      goog.require('object.a'); // Some comment.
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tokens_map = {}
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for token in tokens:
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      object_name = tokenutil.Search(token, Type.STRING_TEXT).string
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # If the previous line starts with a comment, presume that the comment
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # relates to the goog.require or goog.provide and keep them together when
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # sorting.
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_token = token
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      previous_first_token = tokenutil.GetFirstTokenInPreviousLine(first_token)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while previous_first_token.IsAnyType(Type.COMMENT_TYPES):
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        first_token = previous_first_token
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        previous_first_token = tokenutil.GetFirstTokenInPreviousLine(
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            first_token)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Find the last token on the line.
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_token = tokenutil.GetLastTokenInSameLine(token)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      all_tokens = self._GetTokenList(first_token, last_token)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tokens_map[object_name] = all_tokens
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return tokens_map
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GetTokenList(self, first_token, last_token):
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets a list of all tokens from first_token to last_token, inclusive.
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_token: The first token to get.
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_token: The last token to get.
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A list of all tokens between first_token and last_token, including both
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_token and last_token.
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Exception: If the token stream ends before last_token is reached.
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token_list = []
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token = first_token
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while token != last_token:
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not token:
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        raise Exception('ran out of tokens')
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      token_list.append(token)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      token = token.next
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token_list.append(last_token)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return token_list
273