summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/closure-library/closure/bin/scopify.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xdom/canvas/test/webgl-conf/checkout/closure-library/closure/bin/scopify.py221
1 files changed, 221 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/closure-library/closure/bin/scopify.py b/dom/canvas/test/webgl-conf/checkout/closure-library/closure/bin/scopify.py
new file mode 100755
index 0000000000..d8057efbc9
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/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)