Add vectortile branch
This commit is contained in:
@@ -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)
|
||||
Reference in New Issue
Block a user