| Index: third_party/google_input_tools/third_party/closure_library/closure/bin/scopify.py
|
| diff --git a/third_party/google_input_tools/third_party/closure_library/closure/bin/scopify.py b/third_party/google_input_tools/third_party/closure_library/closure/bin/scopify.py
|
| new file mode 100755
|
| index 0000000000000000000000000000000000000000..d8057efbc9fa2aa01c6f0e9941f67ffc46d66f77
|
| --- /dev/null
|
| +++ b/third_party/google_input_tools/third_party/closure_library/closure/bin/scopify.py
|
| @@ -0,0 +1,221 @@
|
| +#!/usr/bin/python
|
| +#
|
| +# Copyright 2010 The Closure Library 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.
|
| +
|
| +
|
| +"""Automatically converts codebases over to goog.scope.
|
| +
|
| +Usage:
|
| +cd path/to/my/dir;
|
| +../../../../javascript/closure/bin/scopify.py
|
| +
|
| +Scans every file in this directory, recursively. Looks for existing
|
| +goog.scope calls, and goog.require'd symbols. If it makes sense to
|
| +generate a goog.scope call for the file, then we will do so, and
|
| +try to auto-generate some aliases based on the goog.require'd symbols.
|
| +
|
| +Known Issues:
|
| +
|
| + When a file is goog.scope'd, the file contents will be indented +2.
|
| + This may put some lines over 80 chars. These will need to be fixed manually.
|
| +
|
| + We will only try to create aliases for capitalized names. We do not check
|
| + to see if those names will conflict with any existing locals.
|
| +
|
| + This creates merge conflicts for every line of every outstanding change.
|
| + If you intend to run this on your codebase, make sure your team members
|
| + know. Better yet, send them this script so that they can scopify their
|
| + outstanding changes and "accept theirs".
|
| +
|
| + When an alias is "captured", it can no longer be stubbed out for testing.
|
| + Run your tests.
|
| +
|
| +"""
|
| +
|
| +__author__ = 'nicksantos@google.com (Nick Santos)'
|
| +
|
| +import os.path
|
| +import re
|
| +import sys
|
| +
|
| +REQUIRES_RE = re.compile(r"goog.require\('([^']*)'\)")
|
| +
|
| +# Edit this manually if you want something to "always" be aliased.
|
| +# TODO(nicksantos): Add a flag for this.
|
| +DEFAULT_ALIASES = {}
|
| +
|
| +def Transform(lines):
|
| + """Converts the contents of a file into javascript that uses goog.scope.
|
| +
|
| + Arguments:
|
| + lines: A list of strings, corresponding to each line of the file.
|
| + Returns:
|
| + A new list of strings, or None if the file was not modified.
|
| + """
|
| + requires = []
|
| +
|
| + # Do an initial scan to be sure that this file can be processed.
|
| + for line in lines:
|
| + # Skip this file if it has already been scopified.
|
| + if line.find('goog.scope') != -1:
|
| + return None
|
| +
|
| + # If there are any global vars or functions, then we also have
|
| + # to skip the whole file. We might be able to deal with this
|
| + # more elegantly.
|
| + if line.find('var ') == 0 or line.find('function ') == 0:
|
| + return None
|
| +
|
| + for match in REQUIRES_RE.finditer(line):
|
| + requires.append(match.group(1))
|
| +
|
| + if len(requires) == 0:
|
| + return None
|
| +
|
| + # Backwards-sort the requires, so that when one is a substring of another,
|
| + # we match the longer one first.
|
| + for val in DEFAULT_ALIASES.values():
|
| + if requires.count(val) == 0:
|
| + requires.append(val)
|
| +
|
| + requires.sort()
|
| + requires.reverse()
|
| +
|
| + # Generate a map of requires to their aliases
|
| + aliases_to_globals = DEFAULT_ALIASES.copy()
|
| + for req in requires:
|
| + index = req.rfind('.')
|
| + if index == -1:
|
| + alias = req
|
| + else:
|
| + alias = req[(index + 1):]
|
| +
|
| + # Don't scopify lowercase namespaces, because they may conflict with
|
| + # local variables.
|
| + if alias[0].isupper():
|
| + aliases_to_globals[alias] = req
|
| +
|
| + aliases_to_matchers = {}
|
| + globals_to_aliases = {}
|
| + for alias, symbol in aliases_to_globals.items():
|
| + globals_to_aliases[symbol] = alias
|
| + aliases_to_matchers[alias] = re.compile('\\b%s\\b' % symbol)
|
| +
|
| + # Insert a goog.scope that aliases all required symbols.
|
| + result = []
|
| +
|
| + START = 0
|
| + SEEN_REQUIRES = 1
|
| + IN_SCOPE = 2
|
| +
|
| + mode = START
|
| + aliases_used = set()
|
| + insertion_index = None
|
| + num_blank_lines = 0
|
| + for line in lines:
|
| + if mode == START:
|
| + result.append(line)
|
| +
|
| + if re.search(REQUIRES_RE, line):
|
| + mode = SEEN_REQUIRES
|
| +
|
| + elif mode == SEEN_REQUIRES:
|
| + if (line and
|
| + not re.search(REQUIRES_RE, line) and
|
| + not line.isspace()):
|
| + # There should be two blank lines before goog.scope
|
| + result += ['\n'] * 2
|
| + result.append('goog.scope(function() {\n')
|
| + insertion_index = len(result)
|
| + result += ['\n'] * num_blank_lines
|
| + mode = IN_SCOPE
|
| + elif line.isspace():
|
| + # Keep track of the number of blank lines before each block of code so
|
| + # that we can move them after the goog.scope line if necessary.
|
| + num_blank_lines += 1
|
| + else:
|
| + # Print the blank lines we saw before this code block
|
| + result += ['\n'] * num_blank_lines
|
| + num_blank_lines = 0
|
| + result.append(line)
|
| +
|
| + if mode == IN_SCOPE:
|
| + for symbol in requires:
|
| + if not symbol in globals_to_aliases:
|
| + continue
|
| +
|
| + alias = globals_to_aliases[symbol]
|
| + matcher = aliases_to_matchers[alias]
|
| + for match in matcher.finditer(line):
|
| + # Check to make sure we're not in a string.
|
| + # We do this by being as conservative as possible:
|
| + # if there are any quote or double quote characters
|
| + # before the symbol on this line, then bail out.
|
| + before_symbol = line[:match.start(0)]
|
| + if before_symbol.count('"') > 0 or before_symbol.count("'") > 0:
|
| + continue
|
| +
|
| + line = line.replace(match.group(0), alias)
|
| + aliases_used.add(alias)
|
| +
|
| + if line.isspace():
|
| + # Truncate all-whitespace lines
|
| + result.append('\n')
|
| + else:
|
| + result.append(line)
|
| +
|
| + if len(aliases_used):
|
| + aliases_used = [alias for alias in aliases_used]
|
| + aliases_used.sort()
|
| + aliases_used.reverse()
|
| + for alias in aliases_used:
|
| + symbol = aliases_to_globals[alias]
|
| + result.insert(insertion_index,
|
| + 'var %s = %s;\n' % (alias, symbol))
|
| + result.append('}); // goog.scope\n')
|
| + return result
|
| + else:
|
| + return None
|
| +
|
| +def TransformFileAt(path):
|
| + """Converts a file into javascript that uses goog.scope.
|
| +
|
| + Arguments:
|
| + path: A path to a file.
|
| + """
|
| + f = open(path)
|
| + lines = Transform(f.readlines())
|
| + if lines:
|
| + f = open(path, 'w')
|
| + for l in lines:
|
| + f.write(l)
|
| + f.close()
|
| +
|
| +if __name__ == '__main__':
|
| + args = sys.argv[1:]
|
| + if not len(args):
|
| + args = '.'
|
| +
|
| + for file_name in args:
|
| + if os.path.isdir(file_name):
|
| + for root, dirs, files in os.walk(file_name):
|
| + for name in files:
|
| + if name.endswith('.js') and \
|
| + not os.path.islink(os.path.join(root, name)):
|
| + TransformFileAt(os.path.join(root, name))
|
| + else:
|
| + if file_name.endswith('.js') and \
|
| + not os.path.islink(file_name):
|
| + TransformFileAt(file_name)
|
|
|