| Index: third_party/closure_compiler/compile_modules.py
|
| diff --git a/third_party/closure_compiler/compile_modules.py b/third_party/closure_compiler/compile_modules.py
|
| new file mode 100755
|
| index 0000000000000000000000000000000000000000..d0b408285ebf05d34a776298ccf3a8758d5e7010
|
| --- /dev/null
|
| +++ b/third_party/closure_compiler/compile_modules.py
|
| @@ -0,0 +1,130 @@
|
| +#!/usr/bin/env python
|
| +# Copyright 2014 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
| +
|
| +import argparse
|
| +from checker import Checker as Checker
|
| +import os
|
| +try:
|
| + import json
|
| +except:
|
| + import simplejson as json
|
| +
|
| +
|
| +
|
| +class Module(object):
|
| + def __init__(self, name, sources, depends=[], externs=[]):
|
| + self._name = name
|
| + self._sources = sources
|
| + self._depends = depends
|
| + self._externs = externs
|
| +
|
| + def name(self):
|
| + return self._name
|
| +
|
| + def sources(self):
|
| + return self._sources
|
| +
|
| + # TODO(dbeam): support depending on other modules/dependency flattening.
|
| + def depends(self):
|
| + return self._depends
|
| +
|
| + def externs(self):
|
| + return self._externs
|
| +
|
| + @staticmethod
|
| + def from_dict(d):
|
| + keys = d.keys()
|
| +
|
| + required = ["name", "sources"]
|
| + assert all(r in keys for r in required), "Module missing name or sources"
|
| +
|
| + allowed = required + ["depends", "externs"]
|
| + assert all(k in allowed for k in keys), "Module has unknown key"
|
| +
|
| + depends = d["depends"] if "depends" in d else []
|
| + externs = d["externs"] if "externs" in d else []
|
| + return Module(d["name"], d["sources"], depends=depends, externs=externs)
|
| +
|
| +
|
| +# TODO(dbeam): should ModuleParser be internal to ModuleCompiler or should we
|
| +# pass Modules into ModuleCompiler.compile()? Maybe this is fine?
|
| +class ModuleParser(object):
|
| + _cache = {}
|
| +
|
| + def __init__(self, verbose=False):
|
| + self._verbose = verbose
|
| +
|
| + def parse(self, file_path):
|
| + if file_path in self._cache:
|
| + print "(INFO) Found module file %s in the cache" % file_path
|
| + return self._cache[file_path]
|
| +
|
| + file = open(file_path, "r")
|
| + data = json.load(file)
|
| + file.close()
|
| +
|
| + if self._verbose:
|
| + pretty_json = json.dumps(data, indent=2, separators=(',', ': ')).strip()
|
| + print "(INFO) Layout: " + os.linesep + pretty_json + os.linesep
|
| +
|
| + self._cache[file_path] = [Module.from_dict(m) for m in data]
|
| + return self._cache[file_path]
|
| +
|
| +
|
| +class ModuleCompiler(object):
|
| + _checker = None
|
| + _parser = None
|
| +
|
| + def __init__(self, verbose=False):
|
| + self._verbose = verbose
|
| +
|
| + def _debug(self, msg, prefix="(INFO) ", suffix=""):
|
| + if self._verbose:
|
| + print prefix + msg.strip() + suffix
|
| +
|
| + def compile(self, module_file):
|
| + self._debug("MODULE FILE: " + module_file, prefix="")
|
| +
|
| + # NOTE: It's possible by unlikely that |_checker| or |_parser|'s verbosity
|
| + # isn't the same as |self._verbose| due to this class being called with
|
| + # verbose=False then verbose=True in the same program.
|
| + self._parser = self._parser or ModuleParser(verbose=self._verbose)
|
| + self._checker = self._checker or Checker(verbose=self._verbose)
|
| +
|
| + module_dir = os.path.dirname(module_file)
|
| + modules = self._parser.parse(module_file)
|
| +
|
| + for m in modules:
|
| + self._debug("MODULE: " + m.name(), prefix="", suffix=os.linesep)
|
| +
|
| + for s in m.sources():
|
| + f = os.path.join(module_dir, s)
|
| + depends = [os.path.join(module_dir, d) for d in m.depends()]
|
| + externs = [os.path.join(module_dir, e) for e in m.externs()]
|
| + self._checker.check(f, depends=depends, externs=externs)
|
| +
|
| + if s != m.sources()[-1]:
|
| + self._debug(os.linesep, prefix="")
|
| +
|
| + if m != modules[-1]:
|
| + self._debug(os.linesep, prefix="")
|
| +
|
| +
|
| +def main(opts):
|
| + module_compiler = ModuleCompiler(verbose=opts.verbose)
|
| + for module_file in opts.module_file:
|
| + module_compiler.compile(module_file)
|
| + if module_file != opts.module_file[-1]:
|
| + print
|
| +
|
| +
|
| +if __name__ == "__main__":
|
| + parser = argparse.ArgumentParser(
|
| + description="Typecheck JavaScript using Closure compiler")
|
| + parser.add_argument("-v", "--verbose", action="store_true",
|
| + help="Show more information as this script runs")
|
| + parser.add_argument("module_file", nargs=argparse.ONE_OR_MORE,
|
| + help="Path to a modules file to check")
|
| + main(parser.parse_args())
|
|
|