summaryrefslogtreecommitdiff
path: root/chromium/third_party/google-closure-library/closure/bin
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/google-closure-library/closure/bin')
-rwxr-xr-xchromium/third_party/google-closure-library/closure/bin/build/closurebuilder.py293
-rw-r--r--chromium/third_party/google-closure-library/closure/bin/build/depstree.py189
-rwxr-xr-xchromium/third_party/google-closure-library/closure/bin/build/depstree_test.py127
-rwxr-xr-xchromium/third_party/google-closure-library/closure/bin/build/depswriter.py212
-rwxr-xr-xchromium/third_party/google-closure-library/closure/bin/build/depswriter_test.py72
-rw-r--r--chromium/third_party/google-closure-library/closure/bin/build/jscompiler.py161
-rwxr-xr-xchromium/third_party/google-closure-library/closure/bin/build/jscompiler_test.py122
-rw-r--r--chromium/third_party/google-closure-library/closure/bin/build/source.py132
-rwxr-xr-xchromium/third_party/google-closure-library/closure/bin/build/source_test.py164
-rwxr-xr-xchromium/third_party/google-closure-library/closure/bin/build/treescan.py78
-rwxr-xr-xchromium/third_party/google-closure-library/closure/bin/calcdeps.py587
-rw-r--r--chromium/third_party/google-closure-library/closure/bin/generate_closure_unit_tests/generate_closure_unit_tests.js273
-rw-r--r--chromium/third_party/google-closure-library/closure/bin/generate_closure_unit_tests/package.json19
-rw-r--r--chromium/third_party/google-closure-library/closure/bin/labs/code/closure.el39
-rw-r--r--chromium/third_party/google-closure-library/closure/bin/labs/code/closure_test.el31
-rwxr-xr-xchromium/third_party/google-closure-library/closure/bin/labs/code/generate_jsdoc.py171
-rwxr-xr-xchromium/third_party/google-closure-library/closure/bin/labs/code/generate_jsdoc_test.py159
-rwxr-xr-xchromium/third_party/google-closure-library/closure/bin/labs/code/run_el_tests.sh31
-rwxr-xr-xchromium/third_party/google-closure-library/closure/bin/labs/code/run_py_tests.sh28
-rw-r--r--chromium/third_party/google-closure-library/closure/bin/logos/logo.svg25
-rw-r--r--chromium/third_party/google-closure-library/closure/bin/logos/logoandlabel.svg25
21 files changed, 2938 insertions, 0 deletions
diff --git a/chromium/third_party/google-closure-library/closure/bin/build/closurebuilder.py b/chromium/third_party/google-closure-library/closure/bin/build/closurebuilder.py
new file mode 100755
index 00000000000..b542bd0d1b6
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/build/closurebuilder.py
@@ -0,0 +1,293 @@
+#!/usr/bin/env python
+#
+# Copyright 2009 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.
+"""Utility for Closure Library dependency calculation.
+
+ClosureBuilder scans source files to build dependency info. From the
+dependencies, the script can produce a manifest in dependency order,
+a concatenated script, or compiled output from the Closure Compiler.
+
+Paths to files can be expressed as individual arguments to the tool (intended
+for use with find and xargs). As a convenience, --root can be used to specify
+all JS files below a directory.
+
+usage: %prog [options] [file1.js file2.js ...]
+"""
+
+__author__ = 'nnaze@google.com (Nathan Naze)'
+
+
+import io
+import logging
+import optparse
+import os
+import sys
+
+import depstree
+import jscompiler
+import source
+import treescan
+
+
+def _GetOptionsParser():
+ """Get the options parser."""
+
+ parser = optparse.OptionParser(__doc__)
+ parser.add_option('-i',
+ '--input',
+ dest='inputs',
+ action='append',
+ default=[],
+ help='One or more input files to calculate dependencies '
+ 'for. The namespaces in this file will be combined with '
+ 'those given with the -n flag to form the set of '
+ 'namespaces to find dependencies for.')
+ parser.add_option('-n',
+ '--namespace',
+ dest='namespaces',
+ action='append',
+ default=[],
+ help='One or more namespaces to calculate dependencies '
+ 'for. These namespaces will be combined with those given '
+ 'with the -i flag to form the set of namespaces to find '
+ 'dependencies for. A Closure namespace is a '
+ 'dot-delimited path expression declared with a call to '
+ 'goog.provide() (e.g. "goog.array" or "foo.bar").')
+ parser.add_option('--root',
+ dest='roots',
+ action='append',
+ default=[],
+ help='The paths that should be traversed to build the '
+ 'dependencies.')
+ parser.add_option('-o',
+ '--output_mode',
+ dest='output_mode',
+ type='choice',
+ action='store',
+ choices=['list', 'script', 'compiled'],
+ default='list',
+ help='The type of output to generate from this script. '
+ 'Options are "list" for a list of filenames, "script" '
+ 'for a single script containing the contents of all the '
+ 'files, or "compiled" to produce compiled output with '
+ 'the Closure Compiler. Default is "list".')
+ parser.add_option('-c',
+ '--compiler_jar',
+ dest='compiler_jar',
+ action='store',
+ help='The location of the Closure compiler .jar file.')
+ parser.add_option('-f',
+ '--compiler_flags',
+ dest='compiler_flags',
+ default=[],
+ action='append',
+ help='Additional flags to pass to the Closure compiler. '
+ 'To pass multiple flags, --compiler_flags has to be '
+ 'specified multiple times.')
+ parser.add_option('-j',
+ '--jvm_flags',
+ dest='jvm_flags',
+ default=[],
+ action='append',
+ help='Additional flags to pass to the JVM compiler. '
+ 'To pass multiple flags, --jvm_flags has to be '
+ 'specified multiple times.')
+ parser.add_option('--output_file',
+ dest='output_file',
+ action='store',
+ help=('If specified, write output to this path instead of '
+ 'writing to standard output.'))
+
+ return parser
+
+
+def _GetInputByPath(path, sources):
+ """Get the source identified by a path.
+
+ Args:
+ path: str, A path to a file that identifies a source.
+ sources: An iterable collection of source objects.
+
+ Returns:
+ The source from sources identified by path, if found. Converts to
+ real paths for comparison.
+ """
+ for js_source in sources:
+ # Convert both to real paths for comparison.
+ if os.path.realpath(path) == os.path.realpath(js_source.GetPath()):
+ return js_source
+
+
+def _GetClosureBaseFile(sources):
+ """Given a set of sources, returns the one base.js file.
+
+ Note that if zero or two or more base.js files are found, an error message
+ will be written and the program will be exited.
+
+ Args:
+ sources: An iterable of _PathSource objects.
+
+ Returns:
+ The _PathSource representing the base Closure file.
+ """
+ base_files = [
+ js_source for js_source in sources if _IsClosureBaseFile(js_source)
+ ]
+
+ if not base_files:
+ logging.error('No Closure base.js file found.')
+ sys.exit(1)
+ if len(base_files) > 1:
+ logging.error('More than one Closure base.js files found at these paths:')
+ for base_file in base_files:
+ logging.error(base_file.GetPath())
+ sys.exit(1)
+ return base_files[0]
+
+
+def _IsClosureBaseFile(js_source):
+ """Returns true if the given _PathSource is the Closure base.js source."""
+ return (os.path.basename(js_source.GetPath()) == 'base.js' and
+ js_source.provides == set(['goog']))
+
+
+class _PathSource(source.Source):
+ """Source file subclass that remembers its file path."""
+
+ def __init__(self, path):
+ """Initialize a source.
+
+ Args:
+ path: str, Path to a JavaScript file. The source string will be read
+ from this file.
+ """
+ super(_PathSource, self).__init__(source.GetFileContents(path))
+
+ self._path = path
+
+ def __str__(self):
+ return 'PathSource %s' % self._path
+
+ def GetPath(self):
+ """Returns the path."""
+ return self._path
+
+
+def _WrapGoogModuleSource(src):
+ return (u'goog.loadModule(function(exports) {{'
+ '"use strict";'
+ '{0}'
+ '\n' # terminate any trailing single line comment.
+ ';return exports'
+ '}});\n').format(src)
+
+
+def main():
+ logging.basicConfig(format=(sys.argv[0] + ': %(message)s'),
+ level=logging.INFO)
+ options, args = _GetOptionsParser().parse_args()
+
+ # Make our output pipe.
+ if options.output_file:
+ out = io.open(options.output_file, 'wb')
+ else:
+ version = sys.version_info[:2]
+ if version >= (3, 0):
+ # Write bytes to stdout
+ out = sys.stdout.buffer
+ else:
+ out = sys.stdout
+
+ sources = set()
+
+ logging.info('Scanning paths...')
+ for path in options.roots:
+ for js_path in treescan.ScanTreeForJsFiles(path):
+ sources.add(_PathSource(js_path))
+
+ # Add scripts specified on the command line.
+ for js_path in args:
+ sources.add(_PathSource(js_path))
+
+ logging.info('%s sources scanned.', len(sources))
+
+ # Though deps output doesn't need to query the tree, we still build it
+ # to validate dependencies.
+ logging.info('Building dependency tree..')
+ tree = depstree.DepsTree(sources)
+
+ input_namespaces = set()
+ inputs = options.inputs or []
+ for input_path in inputs:
+ js_input = _GetInputByPath(input_path, sources)
+ if not js_input:
+ logging.error('No source matched input %s', input_path)
+ sys.exit(1)
+ input_namespaces.update(js_input.provides)
+
+ input_namespaces.update(options.namespaces)
+
+ if not input_namespaces:
+ logging.error('No namespaces found. At least one namespace must be '
+ 'specified with the --namespace or --input flags.')
+ sys.exit(2)
+
+ # The Closure Library base file must go first.
+ base = _GetClosureBaseFile(sources)
+ deps = [base] + tree.GetDependencies(input_namespaces)
+
+ output_mode = options.output_mode
+ if output_mode == 'list':
+ out.writelines([js_source.GetPath() + '\n' for js_source in deps])
+ elif output_mode == 'script':
+ for js_source in deps:
+ src = js_source.GetSource()
+ if js_source.is_goog_module:
+ src = _WrapGoogModuleSource(src)
+ out.write(src.encode('utf-8') + b'\n')
+ elif output_mode == 'compiled':
+ logging.warning("""\
+Closure Compiler now natively understands and orders Closure dependencies and
+is prefererred over using this script for performing JavaScript compilation.
+
+Please migrate your codebase.
+
+See:
+https://github.com/google/closure-compiler/wiki/Managing-Dependencies
+""")
+
+ # Make sure a .jar is specified.
+ if not options.compiler_jar:
+ logging.error('--compiler_jar flag must be specified if --output is '
+ '"compiled"')
+ sys.exit(2)
+
+ # Will throw an error if the compilation fails.
+ compiled_source = jscompiler.Compile(options.compiler_jar,
+ [js_source.GetPath()
+ for js_source in deps],
+ jvm_flags=options.jvm_flags,
+ compiler_flags=options.compiler_flags)
+
+ logging.info('JavaScript compilation succeeded.')
+ out.write(compiled_source.encode('utf-8'))
+
+ else:
+ logging.error('Invalid value for --output flag.')
+ sys.exit(2)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/chromium/third_party/google-closure-library/closure/bin/build/depstree.py b/chromium/third_party/google-closure-library/closure/bin/build/depstree.py
new file mode 100644
index 00000000000..f288dd3aa61
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/build/depstree.py
@@ -0,0 +1,189 @@
+# Copyright 2009 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.
+
+
+"""Class to represent a full Closure Library dependency tree.
+
+Offers a queryable tree of dependencies of a given set of sources. The tree
+will also do logical validation to prevent duplicate provides and circular
+dependencies.
+"""
+
+__author__ = 'nnaze@google.com (Nathan Naze)'
+
+
+class DepsTree(object):
+ """Represents the set of dependencies between source files."""
+
+ def __init__(self, sources):
+ """Initializes the tree with a set of sources.
+
+ Args:
+ sources: A set of JavaScript sources.
+
+ Raises:
+ MultipleProvideError: A namespace is provided by muplitple sources.
+ NamespaceNotFoundError: A namespace is required but never provided.
+ """
+
+ self._sources = sources
+ self._provides_map = dict()
+
+ # Ensure nothing was provided twice.
+ for source in sources:
+ for provide in source.provides:
+ if provide in self._provides_map:
+ raise MultipleProvideError(
+ provide, [self._provides_map[provide], source])
+
+ self._provides_map[provide] = source
+
+ # Check that all required namespaces are provided.
+ for source in sources:
+ for require in source.requires:
+ if require not in self._provides_map:
+ raise NamespaceNotFoundError(require, source)
+
+ def GetDependencies(self, required_namespaces):
+ """Get source dependencies, in order, for the given namespaces.
+
+ Args:
+ required_namespaces: A string (for one) or list (for one or more) of
+ namespaces.
+
+ Returns:
+ A list of source objects that provide those namespaces and all
+ requirements, in dependency order.
+
+ Raises:
+ NamespaceNotFoundError: A namespace is requested but doesn't exist.
+ CircularDependencyError: A cycle is detected in the dependency tree.
+ """
+ if isinstance(required_namespaces, str):
+ required_namespaces = [required_namespaces]
+
+ deps_sources = []
+
+ for namespace in required_namespaces:
+ for source in DepsTree._ResolveDependencies(
+ namespace, [], self._provides_map, []):
+ if source not in deps_sources:
+ deps_sources.append(source)
+
+ return deps_sources
+
+ @staticmethod
+ def _ResolveDependencies(required_namespace, deps_list, provides_map,
+ traversal_path):
+ """Resolve dependencies for Closure source files.
+
+ Follows the dependency tree down and builds a list of sources in dependency
+ order. This function will recursively call itself to fill all dependencies
+ below the requested namespaces, and then append its sources at the end of
+ the list.
+
+ Args:
+ required_namespace: String of required namespace.
+ deps_list: List of sources in dependency order. This function will append
+ the required source once all of its dependencies are satisfied.
+ provides_map: Map from namespace to source that provides it.
+ traversal_path: List of namespaces of our path from the root down the
+ dependency/recursion tree. Used to identify cyclical dependencies.
+ This is a list used as a stack -- when the function is entered, the
+ current namespace is pushed and popped right before returning.
+ Each recursive call will check that the current namespace does not
+ appear in the list, throwing a CircularDependencyError if it does.
+
+ Returns:
+ The given deps_list object filled with sources in dependency order.
+
+ Raises:
+ NamespaceNotFoundError: A namespace is requested but doesn't exist.
+ CircularDependencyError: A cycle is detected in the dependency tree.
+ """
+
+ source = provides_map.get(required_namespace)
+ if not source:
+ raise NamespaceNotFoundError(required_namespace)
+
+ if required_namespace in traversal_path:
+ traversal_path.append(required_namespace) # do this *after* the test
+
+ # This must be a cycle.
+ raise CircularDependencyError(traversal_path)
+
+ # If we don't have the source yet, we'll have to visit this namespace and
+ # add the required dependencies to deps_list.
+ if source not in deps_list:
+ traversal_path.append(required_namespace)
+
+ for require in source.requires:
+
+ # Append all other dependencies before we append our own.
+ DepsTree._ResolveDependencies(require, deps_list, provides_map,
+ traversal_path)
+ deps_list.append(source)
+
+ traversal_path.pop()
+
+ return deps_list
+
+
+class BaseDepsTreeError(Exception):
+ """Base DepsTree error."""
+
+ def __init__(self):
+ Exception.__init__(self)
+
+
+class CircularDependencyError(BaseDepsTreeError):
+ """Raised when a dependency cycle is encountered."""
+
+ def __init__(self, dependency_list):
+ BaseDepsTreeError.__init__(self)
+ self._dependency_list = dependency_list
+
+ def __str__(self):
+ return ('Encountered circular dependency:\n%s\n' %
+ '\n'.join(self._dependency_list))
+
+
+class MultipleProvideError(BaseDepsTreeError):
+ """Raised when a namespace is provided more than once."""
+
+ def __init__(self, namespace, sources):
+ BaseDepsTreeError.__init__(self)
+ self._namespace = namespace
+ self._sources = sources
+
+ def __str__(self):
+ source_strs = map(str, self._sources)
+
+ return ('Namespace "%s" provided more than once in sources:\n%s\n' %
+ (self._namespace, '\n'.join(source_strs)))
+
+
+class NamespaceNotFoundError(BaseDepsTreeError):
+ """Raised when a namespace is requested but not provided."""
+
+ def __init__(self, namespace, source=None):
+ BaseDepsTreeError.__init__(self)
+ self._namespace = namespace
+ self._source = source
+
+ def __str__(self):
+ msg = 'Namespace "%s" never provided.' % self._namespace
+ if self._source:
+ msg += ' Required in %s' % self._source
+ return msg
diff --git a/chromium/third_party/google-closure-library/closure/bin/build/depstree_test.py b/chromium/third_party/google-closure-library/closure/bin/build/depstree_test.py
new file mode 100755
index 00000000000..eb4c99958ec
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/build/depstree_test.py
@@ -0,0 +1,127 @@
+#!/usr/bin/env python
+#
+# Copyright 2009 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.
+
+
+"""Unit test for depstree."""
+
+__author__ = 'nnaze@google.com (Nathan Naze)'
+
+
+import unittest
+
+import depstree
+
+
+def _GetProvides(sources):
+ """Get all namespaces provided by a collection of sources."""
+
+ provides = set()
+ for source in sources:
+ provides.update(source.provides)
+ return provides
+
+
+class MockSource(object):
+ """Mock Source file."""
+
+ def __init__(self, provides, requires):
+ self.provides = set(provides)
+ self.requires = set(requires)
+
+ def __repr__(self):
+ return 'MockSource %s' % self.provides
+
+
+class DepsTreeTestCase(unittest.TestCase):
+ """Unit test for DepsTree. Tests several common situations and errors."""
+
+ def AssertValidDependencies(self, deps_list):
+ """Validates a dependency list.
+
+ Asserts that a dependency list is valid: For every source in the list,
+ ensure that every require is provided by a source earlier in the list.
+
+ Args:
+ deps_list: A list of sources that should be in dependency order.
+ """
+
+ for i in range(len(deps_list)):
+ source = deps_list[i]
+ previous_provides = _GetProvides(deps_list[:i])
+ for require in source.requires:
+ self.assertTrue(
+ require in previous_provides,
+ 'Namespace "%s" not provided before required by %s' % (
+ require, source))
+
+ def testSimpleDepsTree(self):
+ a = MockSource(['A'], ['B', 'C'])
+ b = MockSource(['B'], [])
+ c = MockSource(['C'], ['D'])
+ d = MockSource(['D'], ['E'])
+ e = MockSource(['E'], [])
+
+ tree = depstree.DepsTree([a, b, c, d, e])
+
+ self.AssertValidDependencies(tree.GetDependencies('A'))
+ self.AssertValidDependencies(tree.GetDependencies('B'))
+ self.AssertValidDependencies(tree.GetDependencies('C'))
+ self.AssertValidDependencies(tree.GetDependencies('D'))
+ self.AssertValidDependencies(tree.GetDependencies('E'))
+
+ def testCircularDependency(self):
+ # Circular deps
+ a = MockSource(['A'], ['B'])
+ b = MockSource(['B'], ['C'])
+ c = MockSource(['C'], ['A'])
+
+ tree = depstree.DepsTree([a, b, c])
+
+ self.assertRaises(depstree.CircularDependencyError,
+ tree.GetDependencies, 'A')
+
+ def testRequiresUndefinedNamespace(self):
+ a = MockSource(['A'], ['B'])
+ b = MockSource(['B'], ['C'])
+ c = MockSource(['C'], ['D']) # But there is no D.
+
+ def MakeDepsTree():
+ return depstree.DepsTree([a, b, c])
+
+ self.assertRaises(depstree.NamespaceNotFoundError, MakeDepsTree)
+
+ def testDepsForMissingNamespace(self):
+ a = MockSource(['A'], ['B'])
+ b = MockSource(['B'], [])
+
+ tree = depstree.DepsTree([a, b])
+
+ # There is no C.
+ self.assertRaises(depstree.NamespaceNotFoundError,
+ tree.GetDependencies, 'C')
+
+ def testMultipleRequires(self):
+ a = MockSource(['A'], ['B'])
+ b = MockSource(['B'], ['C'])
+ c = MockSource(['C'], [])
+ d = MockSource(['D'], ['B'])
+
+ tree = depstree.DepsTree([a, b, c, d])
+ self.AssertValidDependencies(tree.GetDependencies(['D', 'A']))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/chromium/third_party/google-closure-library/closure/bin/build/depswriter.py b/chromium/third_party/google-closure-library/closure/bin/build/depswriter.py
new file mode 100755
index 00000000000..dc5a1019060
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/build/depswriter.py
@@ -0,0 +1,212 @@
+#!/usr/bin/env python
+#
+# Copyright 2009 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.
+
+
+"""Generates out a Closure deps.js file given a list of JavaScript sources.
+
+Paths can be specified as arguments or (more commonly) specifying trees
+with the flags (call with --help for descriptions).
+
+Usage: depswriter.py [path/to/js1.js [path/to/js2.js] ...]
+"""
+
+import json
+import logging
+import optparse
+import os
+import posixpath
+import shlex
+import sys
+
+import source
+import treescan
+
+
+__author__ = 'nnaze@google.com (Nathan Naze)'
+
+
+def MakeDepsFile(source_map):
+ """Make a generated deps file.
+
+ Args:
+ source_map: A dict map of the source path to source.Source object.
+
+ Returns:
+ str, A generated deps file source.
+ """
+
+ # Write in path alphabetical order
+ paths = sorted(source_map.keys())
+
+ lines = []
+
+ for path in paths:
+ js_source = source_map[path]
+
+ # We don't need to add entries that don't provide anything.
+ if js_source.provides:
+ lines.append(_GetDepsLine(path, js_source))
+
+ return ''.join(lines)
+
+
+def _GetDepsLine(path, js_source):
+ """Get a deps.js file string for a source."""
+
+ provides = _ToJsSrc(sorted(js_source.provides))
+ requires = _ToJsSrc(sorted(js_source.requires))
+ module = "{'module': 'goog'}" if js_source.is_goog_module else '{}'
+
+ return 'goog.addDependency(\'%s\', %s, %s, %s);\n' % (
+ path, provides, requires, module)
+
+
+def _ToJsSrc(arr):
+ """Convert a python arr to a js source string."""
+
+ return json.dumps(arr).replace('"', '\'')
+
+
+def _GetOptionsParser():
+ """Get the options parser."""
+
+ parser = optparse.OptionParser(__doc__)
+
+ parser.add_option('--output_file',
+ dest='output_file',
+ action='store',
+ help=('If specified, write output to this path instead of '
+ 'writing to standard output.'))
+ parser.add_option('--root',
+ dest='roots',
+ default=[],
+ action='append',
+ help='A root directory to scan for JS source files. '
+ 'Paths of JS files in generated deps file will be '
+ 'relative to this path. This flag may be specified '
+ 'multiple times.')
+ parser.add_option('--root_with_prefix',
+ dest='roots_with_prefix',
+ default=[],
+ action='append',
+ help='A root directory to scan for JS source files, plus '
+ 'a prefix (if either contains a space, surround with '
+ 'quotes). Paths in generated deps file will be relative '
+ 'to the root, but preceded by the prefix. This flag '
+ 'may be specified multiple times.')
+ parser.add_option('--path_with_depspath',
+ dest='paths_with_depspath',
+ default=[],
+ action='append',
+ help='A path to a source file and an alternate path to '
+ 'the file in the generated deps file (if either contains '
+ 'a space, surround with whitespace). This flag may be '
+ 'specified multiple times.')
+ return parser
+
+
+def _NormalizePathSeparators(path):
+ """Replaces OS-specific path separators with POSIX-style slashes.
+
+ Args:
+ path: str, A file path.
+
+ Returns:
+ str, The path with any OS-specific path separators (such as backslash on
+ Windows) replaced with URL-compatible forward slashes. A no-op on systems
+ that use POSIX paths.
+ """
+ return path.replace(os.sep, posixpath.sep)
+
+
+def _GetRelativePathToSourceDict(root, prefix=''):
+ """Scans a top root directory for .js sources.
+
+ Args:
+ root: str, Root directory.
+ prefix: str, Prefix for returned paths.
+
+ Returns:
+ dict, A map of relative paths (with prefix, if given), to source.Source
+ objects.
+ """
+ # Remember and restore the cwd when we're done. We work from the root so
+ # that paths are relative from the root.
+ start_wd = os.getcwd()
+ os.chdir(root)
+
+ path_to_source = {}
+ for path in treescan.ScanTreeForJsFiles('.'):
+ prefixed_path = _NormalizePathSeparators(os.path.join(prefix, path))
+ path_to_source[prefixed_path] = source.Source(source.GetFileContents(path))
+
+ os.chdir(start_wd)
+
+ return path_to_source
+
+
+def _GetPair(s):
+ """Return a string as a shell-parsed tuple. Two values expected."""
+ try:
+ # shlex uses '\' as an escape character, so they must be escaped.
+ s = s.replace('\\', '\\\\')
+ first, second = shlex.split(s)
+ return (first, second)
+ except:
+ raise Exception('Unable to parse input line as a pair: %s' % s)
+
+
+def main():
+ """CLI frontend to MakeDepsFile."""
+ logging.basicConfig(format=(sys.argv[0] + ': %(message)s'),
+ level=logging.INFO)
+ options, args = _GetOptionsParser().parse_args()
+
+ path_to_source = {}
+
+ # Roots without prefixes
+ for root in options.roots:
+ path_to_source.update(_GetRelativePathToSourceDict(root))
+
+ # Roots with prefixes
+ for root_and_prefix in options.roots_with_prefix:
+ root, prefix = _GetPair(root_and_prefix)
+ path_to_source.update(_GetRelativePathToSourceDict(root, prefix=prefix))
+
+ # Source paths
+ for path in args:
+ path_to_source[path] = source.Source(source.GetFileContents(path))
+
+ # Source paths with alternate deps paths
+ for path_with_depspath in options.paths_with_depspath:
+ srcpath, depspath = _GetPair(path_with_depspath)
+ path_to_source[depspath] = source.Source(source.GetFileContents(srcpath))
+
+ # Make our output pipe.
+ if options.output_file:
+ out = open(options.output_file, 'w')
+ else:
+ out = sys.stdout
+
+ out.write(('// This file was autogenerated by %s.\n' %
+ os.path.basename(__file__)))
+ out.write('// Please do not edit.\n')
+
+ out.write(MakeDepsFile(path_to_source))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/chromium/third_party/google-closure-library/closure/bin/build/depswriter_test.py b/chromium/third_party/google-closure-library/closure/bin/build/depswriter_test.py
new file mode 100755
index 00000000000..30b840c7e2d
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/build/depswriter_test.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env 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.
+
+
+"""Unit test for depswriter."""
+
+__author__ = 'johnlenz@google.com (John Lenz)'
+
+
+import unittest
+
+import depswriter
+
+
+class MockSource(object):
+ """Mock Source file."""
+
+ def __init__(self, provides, requires, is_goog_module=False):
+ self.provides = set(provides)
+ self.requires = set(requires)
+ self.is_goog_module = is_goog_module
+
+ def __repr__(self):
+ return 'MockSource %s' % self.provides
+
+
+class DepsWriterTestCase(unittest.TestCase):
+ """Unit test for depswriter."""
+
+ def testMakeDepsFile(self):
+ sources = {}
+ sources['test.js'] = MockSource(['A'], ['B', 'C'])
+ deps = depswriter.MakeDepsFile(sources)
+
+ self.assertEqual(
+ 'goog.addDependency(\'test.js\', [\'A\'], [\'B\', \'C\'], {});\n',
+ deps)
+
+ def testMakeDepsFileUnicode(self):
+ sources = {}
+ sources['test.js'] = MockSource([u'A'], [u'B', u'C'])
+ deps = depswriter.MakeDepsFile(sources)
+
+ self.assertEqual(
+ 'goog.addDependency(\'test.js\', [\'A\'], [\'B\', \'C\'], {});\n',
+ deps)
+
+ def testMakeDepsFileModule(self):
+ sources = {}
+ sources['test.js'] = MockSource(['A'], ['B', 'C'], True)
+ deps = depswriter.MakeDepsFile(sources)
+
+ self.assertEqual(
+ "goog.addDependency('test.js', "
+ "['A'], ['B', 'C'], {'module': 'goog'});\n",
+ deps)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/chromium/third_party/google-closure-library/closure/bin/build/jscompiler.py b/chromium/third_party/google-closure-library/closure/bin/build/jscompiler.py
new file mode 100644
index 00000000000..a2f6d9c380f
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/build/jscompiler.py
@@ -0,0 +1,161 @@
+# 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.
+"""Utility to use the Closure Compiler CLI from Python."""
+
+import logging
+import os
+import re
+import subprocess
+import tempfile
+
+# Pulls just the major and minor version numbers from the first line of
+# 'java -version'. Versions are in the format of [0-9]+(\.[0-9]+)? See:
+# http://openjdk.java.net/jeps/223
+_VERSION_REGEX = re.compile(r'"([0-9]+)(?:\.([0-9]+))?')
+
+
+class JsCompilerError(Exception):
+ """Raised if there's an error in calling the compiler."""
+ pass
+
+
+def _GetJavaVersionString():
+ """Get the version string from the Java VM."""
+ return subprocess.check_output(['java', '-version'], stderr=subprocess.STDOUT)
+
+
+def _ParseJavaVersion(version_string):
+ """Returns a 2-tuple for the current version of Java installed.
+
+ Args:
+ version_string: String of the Java version (e.g. '1.7.2-ea').
+
+ Returns:
+ The major and minor versions, as a 2-tuple (e.g. (1, 7)).
+ """
+ match = _VERSION_REGEX.search(version_string)
+ if match:
+ version = tuple(int(x or 0) for x in match.groups())
+ assert len(version) == 2
+ return version
+
+
+def _JavaSupports32BitMode():
+ """Determines whether the JVM supports 32-bit mode on the platform."""
+ # Suppresses process output to stderr and stdout from showing up in the
+ # console as we're only trying to determine 32-bit JVM support.
+ supported = False
+ try:
+ devnull = open(os.devnull, 'wb')
+ return subprocess.call(
+ ['java', '-d32', '-version'], stdout=devnull, stderr=devnull) == 0
+ except IOError:
+ pass
+ else:
+ devnull.close()
+ return supported
+
+
+def _GetJsCompilerArgs(compiler_jar_path, java_version, jvm_flags):
+ """Assembles arguments for call to JsCompiler."""
+
+ if java_version < (1, 7):
+ raise JsCompilerError('Closure Compiler requires Java 1.7 or higher. '
+ 'Please visit http://www.java.com/getjava')
+
+ args = ['java']
+
+ # Add JVM flags we believe will produce the best performance. See
+ # https://groups.google.com/forum/#!topic/closure-library-discuss/7w_O9-vzlj4
+
+ # Attempt 32-bit mode if available (Java 7 on Mac OS X does not support 32-bit
+ # mode, for example).
+ if _JavaSupports32BitMode():
+ args += ['-d32']
+
+ # Prefer the "client" VM.
+ args += ['-client']
+
+ # Add JVM flags, if any
+ if jvm_flags:
+ args += jvm_flags
+
+ # Add the application JAR.
+ args += ['-jar', compiler_jar_path]
+
+ return args
+
+
+def _GetFlagFile(source_paths, compiler_flags):
+ """Writes given source paths and compiler flags to a --flagfile.
+
+ The given source_paths will be written as '--js' flags and the compiler_flags
+ are written as-is.
+
+ Args:
+ source_paths: List of string js source paths.
+ compiler_flags: List of string compiler flags.
+
+ Returns:
+ The file to which the flags were written.
+ """
+ args = []
+ for path in source_paths:
+ args += ['--js', path]
+
+ # Add compiler flags, if any.
+ if compiler_flags:
+ args += compiler_flags
+
+ flags_file = tempfile.NamedTemporaryFile(mode='w+t', delete=False)
+ flags_file.write(' '.join(args))
+ flags_file.close()
+
+ return flags_file
+
+
+def Compile(compiler_jar_path,
+ source_paths,
+ jvm_flags=None,
+ compiler_flags=None):
+ """Prepares command-line call to Closure Compiler.
+
+ Args:
+ compiler_jar_path: Path to the Closure compiler .jar file.
+ source_paths: Source paths to build, in order.
+ jvm_flags: A list of additional flags to pass on to JVM.
+ compiler_flags: A list of additional flags to pass on to Closure Compiler.
+
+ Returns:
+ The compiled source, as a string, or None if compilation failed.
+ """
+
+ java_version = _ParseJavaVersion(str(_GetJavaVersionString()))
+
+ args = _GetJsCompilerArgs(compiler_jar_path, java_version, jvm_flags)
+
+ # Write source path arguments to flag file for avoiding "The filename or
+ # extension is too long" error in big projects. See
+ # https://github.com/google/closure-library/pull/678
+ flags_file = _GetFlagFile(source_paths, compiler_flags)
+ args += ['--flagfile', flags_file.name]
+
+ logging.info('Compiling with the following command: %s', ' '.join(args))
+
+ try:
+ return subprocess.check_output(args)
+ except subprocess.CalledProcessError:
+ raise JsCompilerError('JavaScript compilation failed.')
+ finally:
+ os.remove(flags_file.name)
diff --git a/chromium/third_party/google-closure-library/closure/bin/build/jscompiler_test.py b/chromium/third_party/google-closure-library/closure/bin/build/jscompiler_test.py
new file mode 100755
index 00000000000..38a98eb43df
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/build/jscompiler_test.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 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.
+"""Unit test for depstree."""
+
+__author__ = 'nnaze@google.com (Nathan Naze)'
+
+import os
+import unittest
+
+import jscompiler
+
+
+class JsCompilerTestCase(unittest.TestCase):
+ """Unit tests for jscompiler module."""
+
+ def testGetFlagFile(self):
+ flags_file = jscompiler._GetFlagFile(['path/to/src1.js', 'path/to/src2.js'],
+ ['--test_compiler_flag'])
+
+ def file_get_contents(filename):
+ with open(filename) as f:
+ content = f.read()
+ f.close()
+ return content
+
+ flags_file_content = file_get_contents(flags_file.name)
+ os.remove(flags_file.name)
+
+ self.assertEqual(
+ '--js path/to/src1.js --js path/to/src2.js --test_compiler_flag',
+ flags_file_content)
+
+ def testGetJsCompilerArgs(self):
+
+ original_check = jscompiler._JavaSupports32BitMode
+ jscompiler._JavaSupports32BitMode = lambda: False
+ args = jscompiler._GetJsCompilerArgs('path/to/jscompiler.jar', (1, 7),
+ ['--test_jvm_flag'])
+
+ self.assertEqual([
+ 'java', '-client', '--test_jvm_flag', '-jar', 'path/to/jscompiler.jar'
+ ], args)
+
+ def CheckJava15RaisesError():
+ jscompiler._GetJsCompilerArgs('path/to/jscompiler.jar', (1, 5),
+ ['--test_jvm_flag'])
+
+ self.assertRaises(jscompiler.JsCompilerError, CheckJava15RaisesError)
+ jscompiler._JavaSupports32BitMode = original_check
+
+ def testGetJsCompilerArgs32BitJava(self):
+
+ original_check = jscompiler._JavaSupports32BitMode
+
+ # Should include the -d32 flag only if 32-bit Java is supported by the
+ # system.
+ jscompiler._JavaSupports32BitMode = lambda: True
+ args = jscompiler._GetJsCompilerArgs('path/to/jscompiler.jar', (1, 7),
+ ['--test_jvm_flag'])
+
+ self.assertEqual([
+ 'java', '-d32', '-client', '--test_jvm_flag', '-jar',
+ 'path/to/jscompiler.jar'
+ ], args)
+
+ # Should exclude the -d32 flag if 32-bit Java is not supported by the
+ # system.
+ jscompiler._JavaSupports32BitMode = lambda: False
+ args = jscompiler._GetJsCompilerArgs('path/to/jscompiler.jar', (1, 7),
+ ['--test_jvm_flag'])
+
+ self.assertEqual([
+ 'java', '-client', '--test_jvm_flag', '-jar', 'path/to/jscompiler.jar'
+ ], args)
+
+ jscompiler._JavaSupports32BitMode = original_check
+
+ def testGetJavaVersion(self):
+
+ def assertVersion(expected, version_string):
+ self.assertEqual(expected, jscompiler._ParseJavaVersion(version_string))
+
+ assertVersion((9, 0), _TEST_JAVA_JEP_223_VERSION_STRING)
+ assertVersion((1, 7), _TEST_JAVA_VERSION_STRING)
+ assertVersion((1, 6), _TEST_JAVA_NESTED_VERSION_STRING)
+ assertVersion((1, 4), 'java version "1.4.0_03-ea"')
+
+
+_TEST_JAVA_VERSION_STRING = """\
+openjdk version "1.7.0-google-v5"
+OpenJDK Runtime Environment (build 1.7.0-google-v5-64327-39803485)
+OpenJDK Server VM (build 22.0-b10, mixed mode)
+"""
+
+_TEST_JAVA_NESTED_VERSION_STRING = """\
+Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
+java version "1.6.0_35"
+Java(TM) SE Runtime Environment (build 1.6.0_35-b10-428-11M3811)
+Java HotSpot(TM) Client VM (build 20.10-b01-428, mixed mode)
+"""
+
+_TEST_JAVA_JEP_223_VERSION_STRING = """\
+openjdk version "9-Ubuntu"
+OpenJDK Runtime Environment (build 9-Ubuntu+0-9b134-2ubuntu1)
+OpenJDK 64-Bit Server VM (build 9-Ubuntu+0-9b134-2ubuntu1, mixed mode)
+"""
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/chromium/third_party/google-closure-library/closure/bin/build/source.py b/chromium/third_party/google-closure-library/closure/bin/build/source.py
new file mode 100644
index 00000000000..447b2f0aa95
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/build/source.py
@@ -0,0 +1,132 @@
+# Copyright 2009 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.
+
+
+"""Scans a source JS file for its provided and required namespaces.
+
+Simple class to scan a JavaScript file and express its dependencies.
+"""
+
+__author__ = 'nnaze@google.com'
+
+
+import codecs
+import re
+
+_BASE_REGEX_STRING = r'^\s*goog\.%s\(\s*[\'"](.+)[\'"]\s*\)'
+_MODULE_REGEX = re.compile(_BASE_REGEX_STRING % 'module')
+_PROVIDE_REGEX = re.compile(_BASE_REGEX_STRING % 'provide')
+
+_REQUIRE_REGEX_STRING = (r'^\s*(?:(?:var|let|const)\s+[a-zA-Z0-9$_,:{}\s]*'
+ r'\s*=\s*)?goog\.require\(\s*[\'"](.+)[\'"]\s*\)')
+_REQUIRES_REGEX = re.compile(_REQUIRE_REGEX_STRING)
+
+class Source(object):
+ """Scans a JavaScript source for its provided and required namespaces."""
+
+ # Matches a "/* ... */" comment.
+ # Note: We can't definitively distinguish a "/*" in a string literal without a
+ # state machine tokenizer. We'll assume that a line starting with whitespace
+ # and "/*" is a comment.
+ _COMMENT_REGEX = re.compile(
+ r"""
+ ^\s* # Start of a new line and whitespace
+ /\* # Opening "/*"
+ .*? # Non greedy match of any characters (including newlines)
+ \*/ # Closing "*/""",
+ re.MULTILINE | re.DOTALL | re.VERBOSE)
+
+ def __init__(self, source):
+ """Initialize a source.
+
+ Args:
+ source: str, The JavaScript source.
+ """
+
+ self.provides = set()
+ self.requires = set()
+ self.is_goog_module = False
+
+ self._source = source
+ self._ScanSource()
+
+ def GetSource(self):
+ """Get the source as a string."""
+ return self._source
+
+ @classmethod
+ def _StripComments(cls, source):
+ return cls._COMMENT_REGEX.sub('', source)
+
+ @classmethod
+ def _HasProvideGoogFlag(cls, source):
+ """Determines whether the @provideGoog flag is in a comment."""
+ for comment_content in cls._COMMENT_REGEX.findall(source):
+ if '@provideGoog' in comment_content:
+ return True
+
+ return False
+
+ def _ScanSource(self):
+ """Fill in provides and requires by scanning the source."""
+
+ stripped_source = self._StripComments(self.GetSource())
+
+ source_lines = stripped_source.splitlines()
+ for line in source_lines:
+ match = _PROVIDE_REGEX.match(line)
+ if match:
+ self.provides.add(match.group(1))
+ match = _MODULE_REGEX.match(line)
+ if match:
+ self.provides.add(match.group(1))
+ self.is_goog_module = True
+ match = _REQUIRES_REGEX.match(line)
+ if match:
+ self.requires.add(match.group(1))
+
+ # Closure's base file implicitly provides 'goog'.
+ # This is indicated with the @provideGoog flag.
+ if self._HasProvideGoogFlag(self.GetSource()):
+
+ if len(self.provides) or len(self.requires):
+ raise Exception(
+ 'Base file should not provide or require namespaces.')
+
+ self.provides.add('goog')
+
+
+def GetFileContents(path):
+ """Get a file's contents as a string.
+
+ Args:
+ path: str, Path to file.
+
+ Returns:
+ str, Contents of file.
+
+ Raises:
+ IOError: An error occurred opening or reading the file.
+
+ """
+ fileobj = None
+ try:
+ fileobj = codecs.open(path, encoding='utf-8-sig')
+ return fileobj.read()
+ except IOError as error:
+ raise IOError('An error occurred opening or reading the file: %s. %s'
+ % (path, error))
+ finally:
+ if fileobj is not None:
+ fileobj.close()
diff --git a/chromium/third_party/google-closure-library/closure/bin/build/source_test.py b/chromium/third_party/google-closure-library/closure/bin/build/source_test.py
new file mode 100755
index 00000000000..063cb3aced1
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/build/source_test.py
@@ -0,0 +1,164 @@
+#!/usr/bin/env 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.
+
+
+"""Unit test for source."""
+
+__author__ = 'nnaze@google.com (Nathan Naze)'
+
+
+import unittest
+
+import source
+
+
+class SourceTestCase(unittest.TestCase):
+ """Unit test for source. Tests the parser on a known source input."""
+
+ def testSourceScan(self):
+ test_source = source.Source(_TEST_SOURCE)
+
+ self.assertEqual(set(['foo', 'foo.test']),
+ test_source.provides)
+ self.assertEqual(set(['goog.dom', 'goog.events.EventType']),
+ test_source.requires)
+ self.assertFalse(test_source.is_goog_module)
+
+ def testSourceScanBase(self):
+ test_source = source.Source(_TEST_BASE_SOURCE)
+
+ self.assertEqual(set(['goog']),
+ test_source.provides)
+ self.assertEqual(test_source.requires, set())
+ self.assertFalse(test_source.is_goog_module)
+
+ def testSourceScanBadBase(self):
+
+ def MakeSource():
+ source.Source(_TEST_BAD_BASE_SOURCE)
+
+ self.assertRaises(Exception, MakeSource)
+
+ def testSourceScanGoogModule(self):
+ test_source = source.Source(_TEST_MODULE_SOURCE)
+
+ self.assertEqual(set(['foo']),
+ test_source.provides)
+ self.assertEqual(set(['bar']),
+ test_source.requires)
+ self.assertTrue(test_source.is_goog_module)
+
+ def testSourceScanModuleAlias(self):
+ test_source = source.Source(_TEST_MODULE_ALIAS_SOURCE)
+
+ self.assertEqual(set(['goog.dom', 'goog.events']), test_source.requires)
+ self.assertTrue(test_source.is_goog_module)
+
+ def testStripComments(self):
+ self.assertEqual(
+ '\nvar foo = function() {}',
+ source.Source._StripComments(('/* This is\n'
+ ' a comment split\n'
+ ' over multiple lines\n'
+ '*/\n'
+ 'var foo = function() {}')))
+
+ def testGoogStatementsInComments(self):
+ test_source = source.Source(_TEST_COMMENT_SOURCE)
+
+ self.assertEqual(set(['foo']),
+ test_source.provides)
+ self.assertEqual(set(['goog.events.EventType']),
+ test_source.requires)
+ self.assertFalse(test_source.is_goog_module)
+
+ def testHasProvideGoog(self):
+ self.assertTrue(source.Source._HasProvideGoogFlag(_TEST_BASE_SOURCE))
+ self.assertTrue(source.Source._HasProvideGoogFlag(_TEST_BAD_BASE_SOURCE))
+ self.assertFalse(source.Source._HasProvideGoogFlag(_TEST_COMMENT_SOURCE))
+
+
+_TEST_MODULE_ALIAS_SOURCE = """
+goog.module('foo');
+const {createDom: domCreator} = goog.require('goog.dom');
+const {listen} = goog.require('goog.events');
+"""
+
+
+_TEST_MODULE_SOURCE = """
+goog.module('foo');
+var b = goog.require('bar');
+"""
+
+
+_TEST_SOURCE = """// Fake copyright notice
+
+/** Very important comment. */
+
+goog.provide('foo');
+goog.provide('foo.test');
+
+goog.require('goog.dom');
+goog.require('goog.events.EventType');
+
+function foo() {
+ // Set bar to seventeen to increase performance.
+ this.bar = 17;
+}
+"""
+
+_TEST_COMMENT_SOURCE = """// Fake copyright notice
+
+goog.provide('foo');
+
+/*
+goog.provide('foo.test');
+ */
+
+/*
+goog.require('goog.dom');
+*/
+
+// goog.require('goog.dom');
+
+goog.require('goog.events.EventType');
+
+function bar() {
+ this.baz = 55;
+}
+"""
+
+_TEST_BASE_SOURCE = """
+/**
+ * @fileoverview The base file.
+ * @provideGoog
+ */
+
+var goog = goog || {};
+"""
+
+_TEST_BAD_BASE_SOURCE = """
+/**
+ * @fileoverview The base file.
+ * @provideGoog
+ */
+
+goog.provide('goog');
+"""
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/chromium/third_party/google-closure-library/closure/bin/build/treescan.py b/chromium/third_party/google-closure-library/closure/bin/build/treescan.py
new file mode 100755
index 00000000000..6694593aab0
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/build/treescan.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env 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.
+
+
+"""Shared utility functions for scanning directory trees."""
+
+import os
+import re
+
+
+__author__ = 'nnaze@google.com (Nathan Naze)'
+
+
+# Matches a .js file path.
+_JS_FILE_REGEX = re.compile(r'^.+\.js$')
+
+
+def ScanTreeForJsFiles(root):
+ """Scans a directory tree for JavaScript files.
+
+ Args:
+ root: str, Path to a root directory.
+
+ Returns:
+ An iterable of paths to JS files, relative to cwd.
+ """
+ return ScanTree(root, path_filter=_JS_FILE_REGEX)
+
+
+def ScanTree(root, path_filter=None, ignore_hidden=True):
+ """Scans a directory tree for files.
+
+ Args:
+ root: str, Path to a root directory.
+ path_filter: A regular expression filter. If set, only paths matching
+ the path_filter are returned.
+ ignore_hidden: If True, do not follow or return hidden directories or files
+ (those starting with a '.' character).
+
+ Yields:
+ A string path to files, relative to cwd.
+ """
+
+ def OnError(os_error):
+ raise os_error
+
+ for dirpath, dirnames, filenames in os.walk(root, onerror=OnError):
+ # os.walk allows us to modify dirnames to prevent decent into particular
+ # directories. Avoid hidden directories.
+ for dirname in dirnames:
+ if ignore_hidden and dirname.startswith('.'):
+ dirnames.remove(dirname)
+
+ for filename in filenames:
+
+ # nothing that starts with '.'
+ if ignore_hidden and filename.startswith('.'):
+ continue
+
+ fullpath = os.path.join(dirpath, filename)
+
+ if path_filter and not path_filter.match(fullpath):
+ continue
+
+ yield os.path.normpath(fullpath)
diff --git a/chromium/third_party/google-closure-library/closure/bin/calcdeps.py b/chromium/third_party/google-closure-library/closure/bin/calcdeps.py
new file mode 100755
index 00000000000..0f80ea7411f
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/calcdeps.py
@@ -0,0 +1,587 @@
+#!/usr/bin/env python
+#
+# Copyright 2006 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.
+
+
+"""Calculates JavaScript dependencies without requiring Google's build system.
+
+This tool is deprecated and is provided for legacy users.
+See build/closurebuilder.py and build/depswriter.py for the current tools.
+
+It iterates over a number of search paths and builds a dependency tree. With
+the inputs provided, it walks the dependency tree and outputs all the files
+required for compilation.
+"""
+
+
+try:
+ import distutils.version
+except ImportError:
+ # distutils is not available in all environments
+ distutils = None
+
+import logging
+import optparse
+import os
+import re
+import subprocess
+import sys
+
+
+_BASE_REGEX_STRING = '^\s*goog\.%s\(\s*[\'"](.+)[\'"]\s*\)'
+req_regex = re.compile(_BASE_REGEX_STRING % 'require')
+prov_regex = re.compile(_BASE_REGEX_STRING % 'provide')
+ns_regex = re.compile('^ns:((\w+\.)*(\w+))$')
+version_regex = re.compile('[\.0-9]+')
+
+
+def IsValidFile(ref):
+ """Returns true if the provided reference is a file and exists."""
+ return os.path.isfile(ref)
+
+
+def IsJsFile(ref):
+ """Returns true if the provided reference is a JavaScript file."""
+ return ref.endswith('.js')
+
+
+def IsNamespace(ref):
+ """Returns true if the provided reference is a namespace."""
+ return re.match(ns_regex, ref) is not None
+
+
+def IsDirectory(ref):
+ """Returns true if the provided reference is a directory."""
+ return os.path.isdir(ref)
+
+
+def ExpandDirectories(refs):
+ """Expands any directory references into inputs.
+
+ Description:
+ Looks for any directories in the provided references. Found directories
+ are recursively searched for .js files, which are then added to the result
+ list.
+
+ Args:
+ refs: a list of references such as files, directories, and namespaces
+
+ Returns:
+ A list of references with directories removed and replaced by any
+ .js files that are found in them. Also, the paths will be normalized.
+ """
+ result = []
+ for ref in refs:
+ if IsDirectory(ref):
+ # Disable 'Unused variable' for subdirs
+ # pylint: disable=unused-variable
+ for (directory, subdirs, filenames) in os.walk(ref):
+ for filename in filenames:
+ if IsJsFile(filename):
+ result.append(os.path.join(directory, filename))
+ else:
+ result.append(ref)
+ return map(os.path.normpath, result)
+
+
+class DependencyInfo(object):
+ """Represents a dependency that is used to build and walk a tree."""
+
+ def __init__(self, filename):
+ self.filename = filename
+ self.provides = []
+ self.requires = []
+
+ def __str__(self):
+ return '%s Provides: %s Requires: %s' % (self.filename,
+ repr(self.provides),
+ repr(self.requires))
+
+
+def BuildDependenciesFromFiles(files):
+ """Build a list of dependencies from a list of files.
+
+ Description:
+ Takes a list of files, extracts their provides and requires, and builds
+ out a list of dependency objects.
+
+ Args:
+ files: a list of files to be parsed for goog.provides and goog.requires.
+
+ Returns:
+ A list of dependency objects, one for each file in the files argument.
+ """
+ result = []
+ filenames = set()
+ for filename in files:
+ if filename in filenames:
+ continue
+
+ # Python 3 requires the file encoding to be specified
+ if (sys.version_info[0] < 3):
+ file_handle = open(filename, 'r')
+ else:
+ file_handle = open(filename, 'r', encoding='utf8')
+
+ try:
+ dep = CreateDependencyInfo(filename, file_handle)
+ result.append(dep)
+ finally:
+ file_handle.close()
+
+ filenames.add(filename)
+
+ return result
+
+
+def CreateDependencyInfo(filename, source):
+ """Create dependency info.
+
+ Args:
+ filename: Filename for source.
+ source: File-like object containing source.
+
+ Returns:
+ A DependencyInfo object with provides and requires filled.
+ """
+ dep = DependencyInfo(filename)
+ for line in source:
+ if re.match(req_regex, line):
+ dep.requires.append(re.search(req_regex, line).group(1))
+ if re.match(prov_regex, line):
+ dep.provides.append(re.search(prov_regex, line).group(1))
+ return dep
+
+
+def BuildDependencyHashFromDependencies(deps):
+ """Builds a hash for searching dependencies by the namespaces they provide.
+
+ Description:
+ Dependency objects can provide multiple namespaces. This method enumerates
+ the provides of each dependency and adds them to a hash that can be used
+ to easily resolve a given dependency by a namespace it provides.
+
+ Args:
+ deps: a list of dependency objects used to build the hash.
+
+ Raises:
+ Exception: If a multiple files try to provide the same namepace.
+
+ Returns:
+ A hash table { namespace: dependency } that can be used to resolve a
+ dependency by a namespace it provides.
+ """
+ dep_hash = {}
+ for dep in deps:
+ for provide in dep.provides:
+ if provide in dep_hash:
+ raise Exception('Duplicate provide (%s) in (%s, %s)' % (
+ provide,
+ dep_hash[provide].filename,
+ dep.filename))
+ dep_hash[provide] = dep
+ return dep_hash
+
+
+def CalculateDependencies(paths, inputs):
+ """Calculates the dependencies for given inputs.
+
+ Description:
+ This method takes a list of paths (files, directories) and builds a
+ searchable data structure based on the namespaces that each .js file
+ provides. It then parses through each input, resolving dependencies
+ against this data structure. The final output is a list of files,
+ including the inputs, that represent all of the code that is needed to
+ compile the given inputs.
+
+ Args:
+ paths: the references (files, directories) that are used to build the
+ dependency hash.
+ inputs: the inputs (files, directories, namespaces) that have dependencies
+ that need to be calculated.
+
+ Raises:
+ Exception: if a provided input is invalid.
+
+ Returns:
+ A list of all files, including inputs, that are needed to compile the given
+ inputs.
+ """
+ deps = BuildDependenciesFromFiles(paths + inputs)
+ search_hash = BuildDependencyHashFromDependencies(deps)
+ result_list = []
+ seen_list = []
+ for input_file in inputs:
+ if IsNamespace(input_file):
+ namespace = re.search(ns_regex, input_file).group(1)
+ if namespace not in search_hash:
+ raise Exception('Invalid namespace (%s)' % namespace)
+ input_file = search_hash[namespace].filename
+ if not IsValidFile(input_file) or not IsJsFile(input_file):
+ raise Exception('Invalid file (%s)' % input_file)
+ seen_list.append(input_file)
+ file_handle = open(input_file, 'r')
+ try:
+ for line in file_handle:
+ if re.match(req_regex, line):
+ require = re.search(req_regex, line).group(1)
+ ResolveDependencies(require, search_hash, result_list, seen_list)
+ finally:
+ file_handle.close()
+ result_list.append(input_file)
+
+ # All files depend on base.js, so put it first.
+ base_js_path = FindClosureBasePath(paths)
+ if base_js_path:
+ result_list.insert(0, base_js_path)
+ else:
+ logging.warning('Closure Library base.js not found.')
+
+ return result_list
+
+
+def FindClosureBasePath(paths):
+ """Given a list of file paths, return Closure base.js path, if any.
+
+ Args:
+ paths: A list of paths.
+
+ Returns:
+ The path to Closure's base.js file including filename, if found.
+ """
+
+ for path in paths:
+ pathname, filename = os.path.split(path)
+
+ if filename == 'base.js':
+ f = open(path)
+
+ is_base = False
+
+ # Sanity check that this is the Closure base file. Check that this
+ # is where goog is defined. This is determined by the @provideGoog
+ # flag.
+ for line in f:
+ if '@provideGoog' in line:
+ is_base = True
+ break
+
+ f.close()
+
+ if is_base:
+ return path
+
+def ResolveDependencies(require, search_hash, result_list, seen_list):
+ """Takes a given requirement and resolves all of the dependencies for it.
+
+ Description:
+ A given requirement may require other dependencies. This method
+ recursively resolves all dependencies for the given requirement.
+
+ Raises:
+ Exception: when require does not exist in the search_hash.
+
+ Args:
+ require: the namespace to resolve dependencies for.
+ search_hash: the data structure used for resolving dependencies.
+ result_list: a list of filenames that have been calculated as dependencies.
+ This variable is the output for this function.
+ seen_list: a list of filenames that have been 'seen'. This is required
+ for the dependency->dependent ordering.
+ """
+ if require not in search_hash:
+ raise Exception('Missing provider for (%s)' % require)
+
+ dep = search_hash[require]
+ if not dep.filename in seen_list:
+ seen_list.append(dep.filename)
+ for sub_require in dep.requires:
+ ResolveDependencies(sub_require, search_hash, result_list, seen_list)
+ result_list.append(dep.filename)
+
+
+def GetDepsLine(dep, base_path):
+ """Returns a JS string for a dependency statement in the deps.js file.
+
+ Args:
+ dep: The dependency that we're printing.
+ base_path: The path to Closure's base.js including filename.
+ """
+ return 'goog.addDependency("%s", %s, %s);' % (
+ GetRelpath(dep.filename, base_path), dep.provides, dep.requires)
+
+
+def GetRelpath(path, start):
+ """Return a relative path to |path| from |start|."""
+ # NOTE: Python 2.6 provides os.path.relpath, which has almost the same
+ # functionality as this function. Since we want to support 2.4, we have
+ # to implement it manually. :(
+ path_list = os.path.abspath(os.path.normpath(path)).split(os.sep)
+ start_list = os.path.abspath(
+ os.path.normpath(os.path.dirname(start))).split(os.sep)
+
+ common_prefix_count = 0
+ for i in range(0, min(len(path_list), len(start_list))):
+ if path_list[i] != start_list[i]:
+ break
+ common_prefix_count += 1
+
+ # Always use forward slashes, because this will get expanded to a url,
+ # not a file path.
+ return '/'.join(['..'] * (len(start_list) - common_prefix_count) +
+ path_list[common_prefix_count:])
+
+
+def PrintLine(msg, out):
+ out.write(msg)
+ out.write('\n')
+
+
+def PrintDeps(source_paths, deps, out):
+ """Print out a deps.js file from a list of source paths.
+
+ Args:
+ source_paths: Paths that we should generate dependency info for.
+ deps: Paths that provide dependency info. Their dependency info should
+ not appear in the deps file.
+ out: The output file.
+
+ Returns:
+ True on success, false if it was unable to find the base path
+ to generate deps relative to.
+ """
+ base_path = FindClosureBasePath(source_paths + deps)
+ if not base_path:
+ return False
+
+ PrintLine('// This file was autogenerated by calcdeps.py', out)
+ excludesSet = set(deps)
+
+ for dep in BuildDependenciesFromFiles(source_paths + deps):
+ if not dep.filename in excludesSet:
+ PrintLine(GetDepsLine(dep, base_path), out)
+
+ return True
+
+
+def PrintScript(source_paths, out):
+ for index, dep in enumerate(source_paths):
+ PrintLine('// Input %d' % index, out)
+ f = open(dep, 'r')
+ PrintLine(f.read(), out)
+ f.close()
+
+
+def GetJavaVersion():
+ """Returns the string for the current version of Java installed."""
+ proc = subprocess.Popen(['java', '-version'], stderr=subprocess.PIPE)
+ proc.wait()
+ version_line = proc.stderr.read().splitlines()[0]
+ return version_regex.search(version_line.decode('utf-8')).group()
+
+
+def FilterByExcludes(options, files):
+ """Filters the given files by the exlusions specified at the command line.
+
+ Args:
+ options: The flags to calcdeps.
+ files: The files to filter.
+ Returns:
+ A list of files.
+ """
+ excludes = []
+ if options.excludes:
+ excludes = ExpandDirectories(options.excludes)
+
+ excludesSet = set(excludes)
+ return [i for i in files if not i in excludesSet]
+
+
+def GetPathsFromOptions(options):
+ """Generates the path files from flag options.
+
+ Args:
+ options: The flags to calcdeps.
+ Returns:
+ A list of files in the specified paths. (strings).
+ """
+
+ search_paths = options.paths
+ if not search_paths:
+ search_paths = ['.'] # Add default folder if no path is specified.
+
+ search_paths = ExpandDirectories(search_paths)
+ return FilterByExcludes(options, search_paths)
+
+
+def GetInputsFromOptions(options):
+ """Generates the inputs from flag options.
+
+ Args:
+ options: The flags to calcdeps.
+ Returns:
+ A list of inputs (strings).
+ """
+ inputs = options.inputs
+ if not inputs: # Parse stdin
+ logging.info('No inputs specified. Reading from stdin...')
+ inputs = filter(None, [line.strip('\n') for line in sys.stdin.readlines()])
+
+ logging.info('Scanning files...')
+ inputs = ExpandDirectories(inputs)
+
+ return FilterByExcludes(options, inputs)
+
+
+def Compile(compiler_jar_path, source_paths, out, flags=None):
+ """Prepares command-line call to Closure compiler.
+
+ Args:
+ compiler_jar_path: Path to the Closure compiler .jar file.
+ source_paths: Source paths to build, in order.
+ flags: A list of additional flags to pass on to Closure compiler.
+ """
+ args = ['java', '-jar', compiler_jar_path]
+ for path in source_paths:
+ args += ['--js', path]
+
+ if flags:
+ args += flags
+
+ logging.info('Compiling with the following command: %s', ' '.join(args))
+ proc = subprocess.Popen(args, stdout=subprocess.PIPE)
+ (stdoutdata, stderrdata) = proc.communicate()
+ if proc.returncode != 0:
+ logging.error('JavaScript compilation failed.')
+ sys.exit(1)
+ else:
+ out.write(stdoutdata.decode('utf-8'))
+
+
+def main():
+ """The entrypoint for this script."""
+
+ logging.basicConfig(format='calcdeps.py: %(message)s', level=logging.INFO)
+
+ usage = 'usage: %prog [options] arg'
+ parser = optparse.OptionParser(usage)
+ parser.add_option('-i',
+ '--input',
+ dest='inputs',
+ action='append',
+ help='The inputs to calculate dependencies for. Valid '
+ 'values can be files, directories, or namespaces '
+ '(ns:goog.net.XhrIo). Only relevant to "list" and '
+ '"script" output.')
+ parser.add_option('-p',
+ '--path',
+ dest='paths',
+ action='append',
+ help='The paths that should be traversed to build the '
+ 'dependencies.')
+ parser.add_option('-d',
+ '--dep',
+ dest='deps',
+ action='append',
+ help='Directories or files that should be traversed to '
+ 'find required dependencies for the deps file. '
+ 'Does not generate dependency information for names '
+ 'provided by these files. Only useful in "deps" mode.')
+ parser.add_option('-e',
+ '--exclude',
+ dest='excludes',
+ action='append',
+ help='Files or directories to exclude from the --path '
+ 'and --input flags')
+ parser.add_option('-o',
+ '--output_mode',
+ dest='output_mode',
+ action='store',
+ default='list',
+ help='The type of output to generate from this script. '
+ 'Options are "list" for a list of filenames, "script" '
+ 'for a single script containing the contents of all the '
+ 'file, "deps" to generate a deps.js file for all '
+ 'paths, or "compiled" to produce compiled output with '
+ 'the Closure compiler.')
+ parser.add_option('-c',
+ '--compiler_jar',
+ dest='compiler_jar',
+ action='store',
+ help='The location of the Closure compiler .jar file.')
+ parser.add_option('-f',
+ '--compiler_flag',
+ '--compiler_flags', # for backwards compatibility
+ dest='compiler_flags',
+ action='append',
+ help='Additional flag to pass to the Closure compiler. '
+ 'May be specified multiple times to pass multiple flags.')
+ parser.add_option('--output_file',
+ dest='output_file',
+ action='store',
+ help=('If specified, write output to this path instead of '
+ 'writing to standard output.'))
+
+ (options, args) = parser.parse_args()
+
+ search_paths = GetPathsFromOptions(options)
+
+ if options.output_file:
+ out = open(options.output_file, 'w')
+ else:
+ out = sys.stdout
+
+ if options.output_mode == 'deps':
+ result = PrintDeps(search_paths, ExpandDirectories(options.deps or []), out)
+ if not result:
+ logging.error('Could not find Closure Library in the specified paths')
+ sys.exit(1)
+
+ return
+
+ inputs = GetInputsFromOptions(options)
+
+ logging.info('Finding Closure dependencies...')
+ deps = CalculateDependencies(search_paths, inputs)
+ output_mode = options.output_mode
+
+ if output_mode == 'script':
+ PrintScript(deps, out)
+ elif output_mode == 'list':
+ # Just print out a dep per line
+ for dep in deps:
+ PrintLine(dep, out)
+ elif output_mode == 'compiled':
+ # Make sure a .jar is specified.
+ if not options.compiler_jar:
+ logging.error('--compiler_jar flag must be specified if --output is '
+ '"compiled"')
+ sys.exit(1)
+
+ # User friendly version check.
+ if distutils and not (distutils.version.LooseVersion(GetJavaVersion()) >
+ distutils.version.LooseVersion('1.6')):
+ logging.error('Closure Compiler requires Java 1.6 or higher.')
+ logging.error('Please visit http://www.java.com/getjava')
+ sys.exit(1)
+
+ Compile(options.compiler_jar, deps, out, options.compiler_flags)
+
+ else:
+ logging.error('Invalid value for --output flag.')
+ sys.exit(1)
+
+if __name__ == '__main__':
+ main()
diff --git a/chromium/third_party/google-closure-library/closure/bin/generate_closure_unit_tests/generate_closure_unit_tests.js b/chromium/third_party/google-closure-library/closure/bin/generate_closure_unit_tests/generate_closure_unit_tests.js
new file mode 100644
index 00000000000..a8de2bf2ef1
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/generate_closure_unit_tests/generate_closure_unit_tests.js
@@ -0,0 +1,273 @@
+// Copyright 2017 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.
+
+const parse5 = require('parse5');
+const fs = require('fs');
+const path = require('path');
+const process = require('process');
+
+const PATH = '';
+
+/**
+ * @typedef {{
+ * basePath: string,
+ * depsFile: string,
+ * output: string,
+ * overwriteExistingFiles: boolean,
+ * paths: !Array<{path: string, directory: boolean}>,
+ * recursive: boolean,
+ * }}
+ */
+let Args;
+
+
+/**
+ * Entry point for this script.
+ */
+function main() {
+ let args;
+
+ try {
+ args = processArgs(process.argv.slice(2));
+ } catch (error) {
+ showHelp(error.message);
+ }
+
+ for (const path of args.paths) {
+ if (path.directory) {
+ generateHtmlForDirectory(path.path, args);
+ } else {
+ maybeGenerateHtmlForFile(path.path, args);
+ }
+ }
+}
+
+
+/**
+ * Shows script help.
+ * @param {string=} errorMessage
+ */
+function showHelp(errorMessage = '') {
+ if (errorMessage) {
+ console.error(errorMessage);
+ }
+
+ console.log(`Auto generates _test.html files for Closure unit tests.
+
+ Usage:
+ generate_test_html [OPTIONS]... PATH...
+
+ Paths:
+ list of paths to directories or _test.js files. For directories a
+ _test.html file will be generated for each _test.js file in the
+ directory.
+
+ Options:
+ --base
+ Path to base.js file.
+ --dep_file:
+ Path to a deps file to use for all tests. If not specified but a
+ *_test_deps.js file exists it will be automatically included.
+ --recursive
+ generate _test.html for each _test.js in each directory recursively.
+ Defaults to false.
+ --output
+ output file path, should be named _test.html. Only valid if a single
+ _test.js file is specified for PATH.
+ --overwrite
+ overwrite any existing _test.html files. Defaults to true.`);
+ process.exit(errorMessage ? 1 : 0);
+}
+
+/**
+ * @param {!Array<string>} args
+ * @return {!Args}
+ */
+function processArgs(args) {
+ const processedArgs = {
+ basePath: '',
+ output: '',
+ overwriteExistingFiles: true,
+ paths: [],
+ recursive: false,
+ };
+ args.forEach((arg) => {
+ const [key, value] = arg.split('=');
+ switch (key) {
+ case '--base':
+ processedArgs.basePath = value;
+ break;
+ case '--dep_file':
+ processedArgs.depsFile = value;
+ break;
+ case '--help':
+ showHelp();
+ break;
+ case '--recursive':
+ processedArgs.recursive = String(value).toLowerCase() !== 'false';
+ break;
+ case '--output':
+ processedArgs.output = value;
+ break;
+ case '--overwrite':
+ processedArgs.overwriteExistingFiles =
+ String(value).toLowerCase() !== 'false';
+ break;
+ default:
+ const stats = fs.statSync(arg);
+ processedArgs.paths.push({path: arg, directory: stats.isDirectory()});
+ }
+ });
+
+ if (!processedArgs.basePath.endsWith('base.js')) {
+ throw new Error(
+ `Path to base must end with base.js: ${processedArgs.basePath}.`);
+ }
+
+ if (processedArgs.output) {
+ if (processedArgs.paths.length > 1) {
+ throw new Error(
+ 'Cannot specify an output file when there is more than one path.');
+ }
+ if (processedArgs.paths.some(path => path.directory)) {
+ throw new Error('Cannot specify an output when path is a directory.');
+ }
+ if (!processedArgs.output.endsWith('_test.html')) {
+ throw new Error('Output file should end with _test.html.');
+ }
+ }
+
+ if (processedArgs.depsFile && !fs.existsSync(processedArgs.depsFile)) {
+ throw new Error(
+ 'Specified deps file does not exist: ' + processedArgs.depsFile);
+ }
+
+ return processedArgs;
+}
+
+
+/**
+ * Generates one _test.html file for each _test.js file in the given directory.
+ *
+ * @param {string} directory Directory to generate files for.
+ * @param {!Args} args
+ */
+function generateHtmlForDirectory(directory, args) {
+ const directoryContents = fs.readdirSync(directory);
+ const subDirectories = [];
+
+ for (const filename of directoryContents) {
+ const fullname = path.join(directory, filename);
+ const stats = fs.statSync(fullname);
+ if (stats.isDirectory() && args.recursive) {
+ subDirectories.push(fullname);
+ } else if (stats.isFile()) {
+ maybeGenerateHtmlForFile(fullname, args);
+ }
+ }
+
+ for (const subDirectory of subDirectories) {
+ generateHtmlForDirectory(subDirectory, args);
+ }
+}
+
+
+/**
+ * Generates a _test.html file for the given file if it is a _test.js file.
+ * @param {string} filename Full path to the file.
+ * @param {!Args} args
+ */
+function maybeGenerateHtmlForFile(filename, args) {
+ if (!filename.endsWith('_test.js')) {
+ return;
+ }
+
+ const htmlFilename =
+ args.output || filename.replace('_test.js', '_test.html');
+ if (!args.overwriteExistingFiles && fs.existsSync(htmlFilename)) {
+ console.warn(`"${htmlFilename}" exists - skipping.`);
+ return;
+ }
+
+ const originalJs = fs.readFileSync(filename, 'utf8');
+ const provide = /goog\.(?:provide|module)\('([^']*?)'\);/g.exec(originalJs);
+
+ if (!provide || !provide[1]) {
+ console.error(
+ `File ${filename} does not provide or module the tests, ` +
+ 'cannot generate html.');
+ return;
+ }
+
+ const newJS = `goog.require('${provide[1]}');`;
+ const title = `Closure Unit Tests - ${provide[1]}`;
+
+ const baseFileName = filename.replace('_test.js', '');
+ const testDomFilename = baseFileName + '_test_dom.html';
+ const testDom = fs.existsSync(testDomFilename) ?
+ fs.readFileSync(testDomFilename, 'utf8') :
+ '';
+
+ const testBootstrapFilename = baseFileName + '_test_bootstrap.js';
+ const pathToBootstrap = fs.existsSync(testBootstrapFilename) ?
+ path.basename(testBootstrapFilename) :
+ '';
+
+ const testDepsFilename = args.depsFile || baseFileName + '_test_deps.js';
+ const pathToDeps =
+ fs.existsSync(testDepsFilename) ? path.basename(testDepsFilename) : '';
+
+ const pathToBase = path.relative(path.dirname(htmlFilename), args.basePath);
+
+ const html = createHtml(
+ title, pathToBootstrap, pathToDeps, newJS, testDom, pathToBase);
+ fs.writeFileSync(htmlFilename, html);
+}
+
+/**
+ * @param {string} title Title of the test.
+ * @param {string} pathToBootstrap Path to a bootstrap javascript file to run
+ * first, if any. Generally this file will contain closure defines.
+ * @param {string} pathToDeps Bath to a custom deps file, if any.
+ * @param {string} js Script content of the test.
+ * @param {string} testDom Any test DOM related to the test or the empty string
+ * if none.
+ * @param {string} pathToBase Path to the base.js file.
+ * @return {string} The text content of the test HTML file.
+ */
+function createHtml(
+ title, pathToBootstrap, pathToDeps, js, testDom, pathToBase) {
+ // Use parse5 to parse and reserialize the test dom. This generates any
+ // optional tags (html, body, head) if missing. Meaning test doms can specify
+ // these tags, if needed.
+ return parse5.serialize(parse5.parse(`<!DOCTYPE html>
+<!-- DO NOT EDIT. This file auto-generated by generate_closure_unit_tests.js -->
+<!--
+Copyright 2017 The Closure Library Authors. All Rights Reserved.
+
+Use of this source code is governed by the Apache License, Version 2.0.
+See the COPYING file for details.
+-->
+<meta charset="UTF-8" />
+${pathToBootstrap ? `<script src=${pathToBootstrap}></script>` : ''}
+<script src="${pathToBase}"></script>
+${pathToDeps ? `<script src=${pathToDeps}></script>` : ''}
+<script>${js}</script>
+<title>${title}</title>` + testDom));
+}
+
+
+if (require.main === module) {
+ main();
+}
diff --git a/chromium/third_party/google-closure-library/closure/bin/generate_closure_unit_tests/package.json b/chromium/third_party/google-closure-library/closure/bin/generate_closure_unit_tests/package.json
new file mode 100644
index 00000000000..6db974f25e5
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/generate_closure_unit_tests/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "generate_closure_unit_tests",
+ "version": "1.0.0",
+ "description": "Generates *_test.html unit test files given *_test.js and *_test_dom.html files.",
+ "main": "generate_closure_unit_tests.js",
+ "bin": {
+ "generate_closure_unit_tests": "./generate_closure_unit_tests.js"
+ },
+ "author": "johnplaisted@google.com",
+ "licenses": [
+ {
+ "type": "Apache-2.0",
+ "url": "https://raw.githubusercontent.com/google/closure-library/master/LICENSE"
+ }
+ ],
+ "dependencies": {
+ "parse5": "^4.0.0"
+ }
+}
diff --git a/chromium/third_party/google-closure-library/closure/bin/labs/code/closure.el b/chromium/third_party/google-closure-library/closure/bin/labs/code/closure.el
new file mode 100644
index 00000000000..394c4837496
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/labs/code/closure.el
@@ -0,0 +1,39 @@
+;; Copyright 2013 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.
+
+;; Closure JS code editing functions for emacs.
+
+;; Author: nnaze@google.com (Nathan Naze)
+
+;; Remember the path of this file, as we will base our paths on it.
+(setq closure-el-path load-file-name)
+
+(defun closure-el-directory ()
+ "Get the directory the closure.el file lives in."
+ (file-name-directory closure-el-path))
+
+(defun closure-generate-jsdoc-path()
+ "The path of the generate_jsdoc.py script."
+ (concat (closure-el-directory) "generate_jsdoc.py"))
+
+(defun closure-insert-jsdoc ()
+ "Insert JSDoc for the next function after the cursor."
+ (interactive)
+ (save-excursion ; Remembers cursor location
+ (call-process-region
+ (point) (point-max)
+ (closure-generate-jsdoc-path)
+ t t)))
+
+(provide 'closure)
diff --git a/chromium/third_party/google-closure-library/closure/bin/labs/code/closure_test.el b/chromium/third_party/google-closure-library/closure/bin/labs/code/closure_test.el
new file mode 100644
index 00000000000..0a44e97dc6b
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/labs/code/closure_test.el
@@ -0,0 +1,31 @@
+;; Copyright 2013 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.
+
+;; Unit tests for closure_test.el
+
+;; Author: nnaze@google.com (Nathan Naze)
+
+(require 'cl)
+
+(setq closure-test-directory (file-name-directory load-file-name))
+
+(load-file (concat closure-test-directory "closure.el"))
+
+(setq closure-el-path "/test/path/closure.el")
+
+(assert (string= "/test/path/" (closure-el-directory)))
+
+(assert (string=
+ "/test/path/generate_jsdoc.py"
+ (closure-generate-jsdoc-path)))
diff --git a/chromium/third_party/google-closure-library/closure/bin/labs/code/generate_jsdoc.py b/chromium/third_party/google-closure-library/closure/bin/labs/code/generate_jsdoc.py
new file mode 100755
index 00000000000..fc5ca45a48f
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/labs/code/generate_jsdoc.py
@@ -0,0 +1,171 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 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.
+
+"""Tool to insert JsDoc before a function.
+
+This script attempts to find the first function passed in to stdin, generate
+JSDoc for it (with argument names and possibly return value), and inject
+it in the string. This is intended to be used as a subprocess by editors
+such as emacs and vi.
+"""
+
+import re
+import sys
+
+
+# Matches a typical Closure-style function definition.
+_FUNCTION_REGEX = re.compile(r"""
+# Start of line
+^
+
+# Indentation
+(?P<indentation>[ ]*)
+
+# Identifier (handling split across line)
+(?P<identifier>\w+(\s*\.\s*\w+)*)
+
+# "= function"
+\s* = \s* function \s*
+
+# opening paren
+\(
+
+# Function arguments
+(?P<arguments>(?:\s|\w+|,)*)
+
+# closing paren
+\)
+
+# opening bracket
+\s* {
+
+""", re.MULTILINE | re.VERBOSE)
+
+
+def _MatchFirstFunction(script):
+ """Match the first function seen in the script."""
+ return _FUNCTION_REGEX.search(script)
+
+
+def _ParseArgString(arg_string):
+ """Parse an argument string (inside parens) into parameter names."""
+ for arg in arg_string.split(','):
+ arg = arg.strip()
+ if arg:
+ yield arg
+
+
+def _ExtractFunctionBody(script, indentation=0):
+ """Attempt to return the function body."""
+
+ # Real extraction would require a token parser and state machines.
+ # We look for first bracket at the same level of indentation.
+ regex_str = r'{(.*?)^[ ]{%d}}' % indentation
+
+ function_regex = re.compile(regex_str, re.MULTILINE | re.DOTALL)
+ match = function_regex.search(script)
+ if match:
+ return match.group(1)
+
+
+def _ContainsReturnValue(function_body):
+ """Attempt to determine if the function body returns a value."""
+ return_regex = re.compile(r'\breturn\b[^;]')
+
+ # If this matches, we assume they're returning something.
+ return bool(return_regex.search(function_body))
+
+
+def _InsertString(original_string, inserted_string, index):
+ """Insert a string into another string at a given index."""
+ return original_string[0:index] + inserted_string + original_string[index:]
+
+
+def _GenerateJsDoc(args, return_val=False):
+ """Generate JSDoc for a function.
+
+ Args:
+ args: A list of names of the argument.
+ return_val: Whether the function has a return value.
+
+ Returns:
+ The JSDoc as a string.
+ """
+
+ lines = []
+ lines.append('/**')
+
+ lines += [' * @param {} %s' % arg for arg in args]
+
+ if return_val:
+ lines.append(' * @return')
+
+ lines.append(' */')
+
+ return '\n'.join(lines) + '\n'
+
+
+def _IndentString(source_string, indentation):
+ """Indent string some number of characters."""
+ lines = [(indentation * ' ') + line
+ for line in source_string.splitlines(True)]
+ return ''.join(lines)
+
+
+def InsertJsDoc(script):
+ """Attempt to insert JSDoc for the first seen function in the script.
+
+ Args:
+ script: The script, as a string.
+
+ Returns:
+ Returns the new string if function was found and JSDoc inserted. Otherwise
+ returns None.
+ """
+
+ match = _MatchFirstFunction(script)
+ if not match:
+ return
+
+ # Add argument flags.
+ args_string = match.group('arguments')
+ args = _ParseArgString(args_string)
+
+ start_index = match.start(0)
+ function_to_end = script[start_index:]
+
+ lvalue_indentation = len(match.group('indentation'))
+
+ return_val = False
+ function_body = _ExtractFunctionBody(function_to_end, lvalue_indentation)
+ if function_body:
+ return_val = _ContainsReturnValue(function_body)
+
+ jsdoc = _GenerateJsDoc(args, return_val)
+ if lvalue_indentation:
+ jsdoc = _IndentString(jsdoc, lvalue_indentation)
+
+ return _InsertString(script, jsdoc, start_index)
+
+
+if __name__ == '__main__':
+ stdin_script = sys.stdin.read()
+ result = InsertJsDoc(stdin_script)
+
+ if result:
+ sys.stdout.write(result)
+ else:
+ sys.stdout.write(stdin_script)
diff --git a/chromium/third_party/google-closure-library/closure/bin/labs/code/generate_jsdoc_test.py b/chromium/third_party/google-closure-library/closure/bin/labs/code/generate_jsdoc_test.py
new file mode 100755
index 00000000000..470bab40867
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/labs/code/generate_jsdoc_test.py
@@ -0,0 +1,159 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 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.
+
+
+"""Unit test for generate_jsdoc."""
+
+__author__ = 'nnaze@google.com (Nathan Naze)'
+
+
+import re
+import unittest
+
+import generate_jsdoc
+
+
+class InsertJsDocTestCase(unittest.TestCase):
+ """Unit test for source. Tests the parser on a known source input."""
+
+ def testMatchFirstFunction(self):
+ match = generate_jsdoc._MatchFirstFunction(_TEST_SOURCE)
+ self.assertNotEqual(None, match)
+ self.assertEqual('aaa, bbb, ccc', match.group('arguments'))
+
+ match = generate_jsdoc._MatchFirstFunction(_INDENTED_SOURCE)
+ self.assertNotEqual(None, match)
+ self.assertEqual('', match.group('arguments'))
+
+ match = generate_jsdoc._MatchFirstFunction(_ODD_NEWLINES_SOURCE)
+ self.assertEqual('goog.\nfoo.\nbar\n.baz.\nqux', match.group('identifier'))
+
+ def testParseArgString(self):
+ self.assertEqual(['foo', 'bar', 'baz'],
+ list(generate_jsdoc._ParseArgString('foo, bar, baz')))
+
+ def testExtractFunctionBody(self):
+ self.assertEqual('\n // Function comments.\n return;\n',
+ generate_jsdoc._ExtractFunctionBody(_TEST_SOURCE))
+
+ self.assertEqual('\n var bar = 3;\n return true;\n',
+ generate_jsdoc._ExtractFunctionBody(_INDENTED_SOURCE, 2))
+
+ def testContainsValueReturn(self):
+ self.assertTrue(generate_jsdoc._ContainsReturnValue(_INDENTED_SOURCE))
+ self.assertFalse(generate_jsdoc._ContainsReturnValue(_TEST_SOURCE))
+
+ def testInsertString(self):
+ self.assertEqual('abc123def',
+ generate_jsdoc._InsertString('abcdef', '123', 3))
+
+ def testInsertJsDoc(self):
+ self.assertEqual(_EXPECTED_INDENTED_SOURCE,
+ generate_jsdoc.InsertJsDoc(_INDENTED_SOURCE))
+
+ self.assertEqual(_EXPECTED_TEST_SOURCE,
+ generate_jsdoc.InsertJsDoc(_TEST_SOURCE))
+
+ self.assertEqual(_EXPECTED_ODD_NEWLINES_SOURCE,
+ generate_jsdoc.InsertJsDoc(_ODD_NEWLINES_SOURCE))
+
+
+_INDENTED_SOURCE = """\
+ boo.foo.woo = function() {
+ var bar = 3;
+ return true;
+ };
+"""
+
+_EXPECTED_INDENTED_SOURCE = """\
+ /**
+ * @return
+ */
+ boo.foo.woo = function() {
+ var bar = 3;
+ return true;
+ };
+"""
+
+
+_TEST_SOURCE = """\
+
+// Random comment.
+
+goog.foo.bar = function (aaa, bbb, ccc) {
+ // Function comments.
+ return;
+};
+"""
+
+_EXPECTED_TEST_SOURCE = """\
+
+// Random comment.
+
+/**
+ * @param {} aaa
+ * @param {} bbb
+ * @param {} ccc
+ */
+goog.foo.bar = function (aaa, bbb, ccc) {
+ // Function comments.
+ return;
+};
+"""
+
+_ODD_NEWLINES_SOURCE = """\
+goog.
+foo.
+bar
+.baz.
+qux
+ =
+
+ function
+
+(aaa,
+
+bbb, ccc) {
+ // Function comments.
+ return;
+};
+"""
+
+_EXPECTED_ODD_NEWLINES_SOURCE = """\
+/**
+ * @param {} aaa
+ * @param {} bbb
+ * @param {} ccc
+ */
+goog.
+foo.
+bar
+.baz.
+qux
+ =
+
+ function
+
+(aaa,
+
+bbb, ccc) {
+ // Function comments.
+ return;
+};
+"""
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/chromium/third_party/google-closure-library/closure/bin/labs/code/run_el_tests.sh b/chromium/third_party/google-closure-library/closure/bin/labs/code/run_el_tests.sh
new file mode 100755
index 00000000000..ded2a74a119
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/labs/code/run_el_tests.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+#
+# Copyright 2013 The Closure Library Authors
+#
+# 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.
+#
+# Wraps the unit tests not using the Google framework so they may be run
+# on the continuous build.
+#
+# Author: nnaze@google.com (Nathan Naze)
+#
+# Wraps the unit tests not using the Google framework so they may be run
+# run on the continuous build.
+
+set -e
+
+source googletest.sh || exit 1
+
+CLOSURE_SRCDIR=$TEST_SRCDIR/google3/javascript/closure/labs/bin/code/
+
+emacs --script $CLOSURE_SRCDIR/closure_test.el
diff --git a/chromium/third_party/google-closure-library/closure/bin/labs/code/run_py_tests.sh b/chromium/third_party/google-closure-library/closure/bin/labs/code/run_py_tests.sh
new file mode 100755
index 00000000000..d075ebba1f8
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/labs/code/run_py_tests.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+#
+# Copyright 2013 The Closure Library Authors
+#
+# 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.
+#
+# Wraps the unit tests not using the Google framework so they may be run
+# on the continuous build.
+
+set -e
+
+source googletest.sh || exit 1
+
+CLOSURE_SRCDIR=$TEST_SRCDIR/google3/javascript/closure/labs/bin/code/
+
+PYTHONPATH=$CLOSURE_SRCDIR
+
+$CLOSURE_SRCDIR/generate_jsdoc_test.py
diff --git a/chromium/third_party/google-closure-library/closure/bin/logos/logo.svg b/chromium/third_party/google-closure-library/closure/bin/logos/logo.svg
new file mode 100644
index 00000000000..2cb6b88a31d
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/logos/logo.svg
@@ -0,0 +1,25 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!--
+Copyright 2013 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.
+-->
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 9 9">
+ <title>Closure Logo</title>
+ <path d="M2,2 h2 a2,2 0 1 0 -2,2 z" fill="#0066CF" />
+ <path d="M7,2 h-2 a2,2 0 1 1 2,2 z" fill="#FD0100" />
+ <path d="M2,7 h2 a2,2 0 1 1 -2,-2 z" fill="#FEC502" />
+ <path d="M7,7 h-2 a2,2 0 1 0 2,-2 z" fill="#009338" />
+</svg>
diff --git a/chromium/third_party/google-closure-library/closure/bin/logos/logoandlabel.svg b/chromium/third_party/google-closure-library/closure/bin/logos/logoandlabel.svg
new file mode 100644
index 00000000000..69c2d6849b4
--- /dev/null
+++ b/chromium/third_party/google-closure-library/closure/bin/logos/logoandlabel.svg
@@ -0,0 +1,25 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!--
+Copyright 2013 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.
+-->
+<svg xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ viewBox="0 0 200 250">
+ <image x="0" y="0" width="200" height="200" xlink:href="logo.svg" />
+ <text text-anchor="middle" x="100" y="245" font-family="Helvetica"
+ font-size="53" font-weight="bold">Closure</text>
+</svg>