Chromium Code Reviews| Index: third_party/closure_compiler/checker.py |
| diff --git a/third_party/closure_compiler/checker.py b/third_party/closure_compiler/checker.py |
| index 4f9cbd5c9bcb2ea0a6a03f25894f0da574221cdc..09e3b651518346bd30d3704c22ce51104bc63053 100755 |
| --- a/third_party/closure_compiler/checker.py |
| +++ b/third_party/closure_compiler/checker.py |
| @@ -42,13 +42,24 @@ class Checker(object): |
| "--jscomp_error=unknownDefines", |
| "--jscomp_error=uselessCode", |
| "--jscomp_error=visibility", |
| + "--language_in=ECMASCRIPT5_STRICT", |
| + "--summary_detail_level=3", |
| + ] |
| + |
| + # These are the extra flags used when compiling in 'strict' mode. |
| + # Flags that are normally disabled are turned on for strict mode. |
| + _STRICT_CLOSURE_ARGS = [ |
| + "--jscomp_error=reportUnknownTypes", |
| + "--jscomp_error=duplicate", |
| + "--jscomp_error=misplacedTypeAnnotation", |
| + ] |
| + |
| + _DISABLED_CLOSURE_ARGS = [ |
| # TODO(dbeam): happens when the same file is <include>d multiple times. |
| "--jscomp_off=duplicate", |
| # TODO(fukino): happens when cr.defineProperty() has a type annotation. |
| # Avoiding parse-time warnings needs 2 pass compiling. crbug.com/421562. |
| "--jscomp_off=misplacedTypeAnnotation", |
| - "--language_in=ECMASCRIPT5_STRICT", |
| - "--summary_detail_level=3", |
| ] |
| _JAR_COMMAND = [ |
| @@ -61,12 +72,12 @@ class Checker(object): |
| _found_java = False |
| - def __init__(self, verbose=False): |
| + def __init__(self, verbose=False, strict=False): |
| current_dir = os.path.join(os.path.dirname(__file__)) |
| - self._compiler_jar = os.path.join(current_dir, "lib", "compiler.jar") |
|
garykac
2015/01/12 20:22:37
This is never used.
|
| self._runner_jar = os.path.join(current_dir, "runner", "runner.jar") |
| self._temp_files = [] |
| self._verbose = verbose |
| + self._strict = strict |
| self._error_filter = error_filter.PromiseErrorFilter() |
| def _clean_up(self): |
| @@ -86,6 +97,12 @@ class Checker(object): |
| print >> sys.stderr, "(ERROR) %s" % msg |
| self._clean_up() |
| + def _common_args(self): |
| + """Returns an array of the common closure compiler args.""" |
| + if self._strict: |
| + return self._COMMON_CLOSURE_ARGS + self._STRICT_CLOSURE_ARGS |
| + return self._COMMON_CLOSURE_ARGS + self._DISABLED_CLOSURE_ARGS |
| + |
| def _run_command(self, cmd): |
| """Runs a shell command. |
| @@ -170,8 +187,8 @@ class Checker(object): |
| externs: @extern files that inform the compiler about custom globals. |
| Returns: |
| - (exitcode, output) The exit code of the Closure compiler (as a number) |
| - and its output (as a string). |
| + (has_errors, output) A boolean indicating if there were errors and the |
| + Closure compiler output (as a string). |
| """ |
| depends = depends or [] |
| externs = externs or set() |
| @@ -201,7 +218,7 @@ class Checker(object): |
| args = ["--js=%s" % self._expanded_file] |
| args += ["--externs=%s" % e for e in externs] |
| - args_file_content = " %s" % " ".join(self._COMMON_CLOSURE_ARGS + args) |
| + args_file_content = " %s" % " ".join(self._common_args() + args) |
| self._debug("Args: %s" % args_file_content.strip()) |
| args_file = self._create_temp_file(args_file_content) |
| @@ -230,32 +247,87 @@ class Checker(object): |
| return bool(errors), output |
| + def check_multiple(self, sources): |
| + """Closure compile a set of files and check for errors. |
| + |
| + Args: |
| + sources: An array of files to check. |
| + |
| + Returns: |
| + (has_errors, output) A boolean indicating if there were errors and the |
| + Closure compiler output (as a string). |
| + """ |
| + |
| + if not self._check_java_path(): |
| + return 1, "" |
| + |
| + args = ["--js=%s" % s for s in sources] |
| + args_file_content = " %s" % " ".join(self._common_args() + args) |
| + self._debug("Args: %s" % args_file_content.strip()) |
| + |
| + args_file = self._create_temp_file(args_file_content) |
| + self._debug("Args file: %s" % args_file) |
| + |
| + runner_args = ["--compiler-args-file=%s" % args_file] |
| + runner_cmd = self._run_jar(self._runner_jar, args=runner_args) |
| + (_, stderr) = runner_cmd.communicate() |
| + |
| + errors = stderr.strip().split("\n\n") |
| + self._debug("Summary: %s" % errors.pop()) |
| + |
| + return bool(errors), stderr |
| if __name__ == "__main__": |
| parser = argparse.ArgumentParser( |
| description="Typecheck JavaScript using Closure compiler") |
| parser.add_argument("sources", nargs=argparse.ONE_OR_MORE, |
| help="Path to a source file to typecheck") |
| + single_file_group = parser.add_mutually_exclusive_group() |
| + single_file_group.add_argument("--single-file", dest="single_file", |
| + action="store_true", |
| + help="Process each source file individually") |
| + single_file_group.add_argument("--no-single-file", dest="single_file", |
| + action="store_false", |
| + help="Process all source files as a group") |
| parser.add_argument("-d", "--depends", nargs=argparse.ZERO_OR_MORE) |
| parser.add_argument("-e", "--externs", nargs=argparse.ZERO_OR_MORE) |
| parser.add_argument("-o", "--out_file", help="A place to output results") |
| parser.add_argument("-v", "--verbose", action="store_true", |
| help="Show more information as this script runs") |
| + parser.add_argument("--strict", action="store_true", |
| + help="Enable strict type checking") |
| + parser.add_argument("--success-stamp", |
| + help="Timestamp file to update upon success") |
| + |
| + parser.set_defaults(single_file=True, strict=False) |
| opts = parser.parse_args() |
| - checker = Checker(verbose=opts.verbose) |
| - for source in opts.sources: |
| - depends, externs = build.inputs.resolve_recursive_dependencies( |
| - source, |
| - opts.depends, |
| - opts.externs) |
| - exit, _ = checker.check(source, depends=depends, externs=externs) |
| - if exit != 0: |
| + depends = opts.depends or [] |
| + externs = opts.externs or set() |
| + |
| + checker = Checker(verbose=opts.verbose, strict=opts.strict) |
| + if opts.single_file: |
| + for source in opts.sources: |
| + depends, externs = build.inputs.resolve_recursive_dependencies( |
| + source, |
| + depends, |
| + externs) |
| + has_errors, _ = checker.check(source, depends=depends, externs=externs) |
| + if has_errors: |
| + sys.exit(exit) |
| + |
| + if opts.out_file: |
| + out_dir = os.path.dirname(opts.out_file) |
| + if not os.path.exists(out_dir): |
| + os.makedirs(out_dir) |
| + # TODO(dbeam): write compiled file to |opts.out_file|. |
| + open(opts.out_file, "w").write("") |
| + else: |
| + has_errors, _ = checker.check_multiple(opts.sources) |
| + if has_errors: |
| + print _ |
| sys.exit(exit) |
| - if opts.out_file: |
| - out_dir = os.path.dirname(opts.out_file) |
| - if not os.path.exists(out_dir): |
| - os.makedirs(out_dir) |
| - # TODO(dbeam): write compiled file to |opts.out_file|. |
| - open(opts.out_file, "w").write("") |
| + if opts.success_stamp: |
| + with open(opts.success_stamp, 'w'): |
| + os.utime(opts.success_stamp, None) |