code: function build(
      projectOptions, buildOptions, outDirsAsync, cssRenamingFileAsync) {
    var inputFilesAsync = resolveInputsAsync(projectOptions);
  
    return outDirsAsync.then(function(outDirs) {
      var transitiveClosureDepsAsync =
          closureDepCalculator.calcDeps(projectOptions, buildOptions, outDirs);
      return kew.all([inputFilesAsync, transitiveClosureDepsAsync])
          .then(function(results) {
            var inputFiles = results[0];
            var transitiveClosureDeps = results[1];
  
            var resolvedProjectOptions =
                resolveProjectOptions(projectOptions, inputFiles);
            var jsModules = jsModuleManager.calcInputFiles(
                resolvedProjectOptions, transitiveClosureDeps);
            return compileAndOutputJs(resolvedProjectOptions, buildOptions,
                outDirs, cssRenamingFileAsync, jsModules);
          });
    });
  }
docs: Builds project JS as specified in the given options, using Closure JS
  Compiler if required and assembling final output JS files.
  @param {!Object} projectOptions Specifies the project input files; see
  README.md for option documentation.
  @param {!Object} buildOptions Specifies options specific to this build (like
  debug/release); see README.md for option documentation.
  @param {!Promise.<!OutputDirs>} outDirsAsync
  @param {!Promise.<?string>} cssRenamingFileAsync
  @return {!Promise} Tracks success/failure.