private void _configureTaskTranspileJSForJavaPlugin(TranspileJSTask transpileJSTask) {

    transpileJSTask.mustRunAfter(JavaPlugin.PROCESS_RESOURCES_TASK_NAME);

    Project project = transpileJSTask.getProject();

    final SourceSet sourceSet = GradleUtil.getSourceSet(project, SourceSet.MAIN_SOURCE_SET_NAME);

    transpileJSTask.setSourceDir(
        new Callable<File>() {

          @Override
          public File call() throws Exception {
            File resourcesDir = _getSrcDir(sourceSet.getResources());

            return new File(resourcesDir, "META-INF/resources");
          }
        });

    transpileJSTask.setWorkingDir(
        new Callable<File>() {

          @Override
          public File call() throws Exception {
            SourceSetOutput sourceSetOutput = sourceSet.getOutput();

            return new File(sourceSetOutput.getResourcesDir(), "META-INF/resources");
          }
        });

    Task classesTask = GradleUtil.getTask(project, JavaPlugin.CLASSES_TASK_NAME);

    classesTask.dependsOn(transpileJSTask);
  }
  private void _addTasksExpandSoyCompileDependencies(
      TranspileJSTask transpileJSTask, Configuration configuration) {

    Project project = transpileJSTask.getProject();

    RenameDependencyClosure renameDependencyClosure =
        new RenameDependencyClosure(project, configuration.getName());

    for (File file : configuration) {
      Copy copy =
          _addTaskExpandCompileDependency(
              project,
              file,
              project.getBuildDir(),
              "expandSoyCompileDependency",
              renameDependencyClosure);

      transpileJSTask.dependsOn(copy);

      String path = FileUtil.getAbsolutePath(copy.getDestinationDir());

      path += "/META-INF/resources/**/*.soy";

      transpileJSTask.soyDependency(path);
    }
  }
  private void _addTasksExpandJSCompileDependencies(
      TranspileJSTask transpileJSTask, NpmInstallTask npmInstallTask, Configuration configuration) {

    Project project = transpileJSTask.getProject();

    RenameDependencyClosure renameDependencyClosure =
        new RenameDependencyClosure(project, configuration.getName());

    for (File file : configuration) {
      Copy copy =
          _addTaskExpandCompileDependency(
              project,
              file,
              npmInstallTask.getNodeModulesDir(),
              "expandJSCompileDependency",
              renameDependencyClosure);

      transpileJSTask.dependsOn(copy);
    }
  }
  private TranspileJSTask _addTaskTranspileJS(Project project) {
    final TranspileJSTask transpileJSTask =
        GradleUtil.addTask(project, TRANSPILE_JS_TASK_NAME, TranspileJSTask.class);

    transpileJSTask.setDescription("Transpiles JS files.");
    transpileJSTask.setGroup(BasePlugin.BUILD_GROUP);

    PluginContainer pluginContainer = project.getPlugins();

    pluginContainer.withType(
        JavaPlugin.class,
        new Action<JavaPlugin>() {

          @Override
          public void execute(JavaPlugin javaPlugin) {
            _configureTaskTranspileJSForJavaPlugin(transpileJSTask);
          }
        });

    return transpileJSTask;
  }
  private void _configureTaskTranspileJS(
      TranspileJSTask transpileJSTask,
      final DownloadNodeModuleTask downloadMetalCliTask,
      final ExecuteNpmTask npmInstallTask) {

    FileCollection fileCollection = transpileJSTask.getSourceFiles();

    if (!transpileJSTask.isEnabled()
        || (transpileJSTask.isSkipWhenEmpty() && fileCollection.isEmpty())) {

      transpileJSTask.setDependsOn(Collections.emptySet());
      transpileJSTask.setEnabled(false);

      return;
    }

    transpileJSTask.dependsOn(downloadMetalCliTask, npmInstallTask);

    transpileJSTask.setScriptFile(
        new Callable<File>() {

          @Override
          public File call() throws Exception {
            return new File(downloadMetalCliTask.getModuleDir(), "index.js");
          }
        });

    transpileJSTask.soyDependency(
        new Callable<String>() {

          @Override
          public String call() throws Exception {
            return npmInstallTask.getWorkingDir() + "/node_modules/lexicon*/src/**/*.soy";
          }
        },
        new Callable<String>() {

          @Override
          public String call() throws Exception {
            return npmInstallTask.getWorkingDir() + "/node_modules/metal*/src/**/*.soy";
          }
        });
  }