# Copyright 2015 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("//build/util/java_action.gni")

declare_args() {
  # Control whether the JavaScript files shipped with Chrome on iOS are
  # compiled with closure_compiler or not. Useful for debugging.
  compile_javascript = true
}

closure_compiler_path = "//third_party/closure_compiler/compiler/compiler.jar"

# Defines a target that create a JavaScript bundle using the closure compiler.
#
# Variables
#   sources:
#     List of JavaScript files to compile into the bundle.
#
#   closure_entry_point:
#     Name of the entry point closure module.
#
#   deps (optional)
#     List of targets required by this target.
#
#   visibility (optional)
#     Visibility restrictions.
#
# Generates a single JavaScript bundle file that can be put in the application
# bundle.
#
# TODO(crbug.com/487804): once all errors have been fixed, sync with the flags
# from third_party/closure_compiler/closure_args.gni.
template("js_compile_bundle") {
  assert(defined(invoker.sources),
         "Need sources in $target_name listing the js files.")

  assert(defined(invoker.closure_entry_point),
         "Need closure_entry_point in $target_name for generated js file.")

  _target_name = target_name
  compile_js_target_name = target_name + "_compile_js"

  java_action(compile_js_target_name) {
    visibility = [ ":$_target_name" ]
    forward_variables_from(invoker, [ "testonly" ])
    script = closure_compiler_path
    sources = invoker.sources
    outputs = [
      "$target_gen_dir/$_target_name.js",
    ]

    args = [
             "--compilation_level",
             "SIMPLE_OPTIMIZATIONS",
             "--js_output_file",
             rebase_path("$target_gen_dir/$_target_name.js", root_build_dir),
             "--only_closure_dependencies",
             "--closure_entry_point",
             invoker.closure_entry_point,
             "--js",
           ] + rebase_path(sources, root_build_dir)
  }

  bundle_data(target_name) {
    forward_variables_from(invoker,
                           [
                             "data_deps",
                             "deps",
                             "public_deps",
                             "testonly",
                             "visibility",
                           ])

    if (!defined(public_deps)) {
      public_deps = []
    }
    public_deps += [ ":$compile_js_target_name" ]
    sources = get_target_outputs(":$compile_js_target_name")
    outputs = [
      "{{bundle_resources_dir}}/{{source_file_part}}",
    ]
  }
}

# Defines a target that compile JavaScript files with error checking using the
# closure compiler.
#
# Variables
#   sources:
#     List of JavaScript files to compile.
#
#   deps (optional)
#     List of targets required by this target.
#
#   js_modules
#     List of JS files defining modules that are required by the sources.
#     The list must be sorted in dependency order.
#     This is based on
#     https://github.com/google/closure-compiler/wiki/JS-Modules
#     https://stackoverflow.com/questions/10395810/how-do-i-split-my-javascript-into-modules-using-googles-closure-compiler/10401030#10401030
#
#   visibility (optional)
#     Visibility restrictions.
#
# TODO(crbug.com/487804): once all errors have been fixed, sync with the flags
# from third_party/closure_compiler/closure_args.gni.
template("js_compile_checked") {
  assert(defined(invoker.sources),
         "Need sources in $target_name listing the js files.")

  if (compile_javascript) {
    _target_name = target_name
    compile_js_target_name = target_name + "_compile_js"

    java_action_foreach(compile_js_target_name) {
      visibility = [ ":$_target_name" ]
      forward_variables_from(invoker, [ "testonly" ])
      script = closure_compiler_path
      sources = invoker.sources
      _js_modules = [
        "//ios/web/web_state/js/resources/base.js",
        "//ios/web/web_state/js/resources/common.js",
        "//ios/web/web_state/js/resources/frame_messaging.js",
        "//ios/web/web_state/js/resources/message.js",
      ]
      if (defined(invoker.js_modules)) {
        _js_modules += invoker.js_modules
      }
      inputs = _js_modules
      outputs = [
        "$target_gen_dir/{{source_file_part}}",
      ]

      args = [
        "--compilation_level",
        "SIMPLE_OPTIMIZATIONS",
        "--jscomp_error=checkTypes",
        "--jscomp_error=checkVars",
        "--jscomp_error=missingProperties",
        "--jscomp_error=undefinedVars",
        "--jscomp_error=accessControls",
        "--jscomp_error=ambiguousFunctionDecl",
        "--jscomp_error=constantProperty",
        "--jscomp_error=deprecated",
        "--jscomp_error=externsValidation",
        "--jscomp_error=globalThis",
        "--jscomp_error=invalidCasts",
        "--jscomp_error=missingReturn",
        "--jscomp_error=nonStandardJsDocs",
        "--jscomp_error=suspiciousCode",
        "--jscomp_error=undefinedNames",
        "--jscomp_error=unknownDefines",
        "--jscomp_error=uselessCode",
        "--jscomp_error=visibility",
        "--module_output_path_prefix",
        rebase_path(target_gen_dir, root_build_dir) + "/",
      ]
      last_dependency = ""
      foreach(_js_module, _js_modules) {
        _js_module_name = get_path_info(_js_module, "name")
        args += [
          "--js",
          rebase_path(_js_module, root_build_dir),
          "--module",
          "$_js_module_name:1$last_dependency",
        ]
        last_dependency = ":$_js_module_name"
      }
      args += [
        "--js",
        "{{source}}",
        "--module",
        "{{source_name_part}}:1$last_dependency",
      ]
    }

    bundle_data(target_name) {
      forward_variables_from(invoker,
                             [
                               "data_deps",
                               "deps",
                               "public_deps",
                               "testonly",
                               "visibility",
                             ])

      if (!defined(public_deps)) {
        public_deps = []
      }
      public_deps += [ ":$compile_js_target_name" ]
      sources = get_target_outputs(":$compile_js_target_name")
      outputs = [
        "{{bundle_resources_dir}}/{{source_file_part}}",
      ]
    }
  } else {
    bundle_data(target_name) {
      not_needed(invoker, [ "js_modules" ])
      forward_variables_from(invoker,
                             [
                               "data_deps",
                               "deps",
                               "public_deps",
                               "testonly",
                               "visibility",
                             ])

      sources = invoker.sources
      outputs = [
        "{{bundle_resources_dir}}/{{source_file_part}}",
      ]
    }
  }
}

# Defines a target that compile JavaScript files without error checking using
# the closure compiler.
#
# Variables
#   sources:
#     List of JavaScript files to compile.
#
#   deps (optional)
#     List of targets required by this target.
#
#   visibility (optional)
#     Visibility restrictions.
#
# TODO(crbug.com/487804): once all errors have been fixed, remove this template
# and port all code to use js_compile_checked instead.
template("js_compile_unchecked") {
  assert(defined(invoker.sources),
         "Need sources in $target_name listing the js files.")

  if (compile_javascript) {
    _target_name = target_name
    compile_js_target_name = target_name + "_compile_js"

    java_action_foreach(compile_js_target_name) {
      visibility = [ ":$_target_name" ]
      forward_variables_from(invoker, [ "testonly" ])
      script = closure_compiler_path
      sources = invoker.sources
      outputs = [
        "$target_gen_dir/{{source_file_part}}",
      ]

      args = [
        "--compilation_level",
        "SIMPLE_OPTIMIZATIONS",
        "--js",
        "{{source}}",
        "--js_output_file",
        rebase_path("$target_gen_dir/{{source_file_part}}", root_build_dir),
      ]
    }

    bundle_data(target_name) {
      forward_variables_from(invoker,
                             [
                               "data_deps",
                               "deps",
                               "public_deps",
                               "testonly",
                               "visibility",
                             ])

      if (!defined(public_deps)) {
        public_deps = []
      }
      public_deps += [ ":$compile_js_target_name" ]
      sources = get_target_outputs(":$compile_js_target_name")
      outputs = [
        "{{bundle_resources_dir}}/{{source_file_part}}",
      ]
    }
  } else {
    bundle_data(target_name) {
      forward_variables_from(invoker,
                             [
                               "data_deps",
                               "deps",
                               "public_deps",
                               "testonly",
                               "visibility",
                             ])

      sources = invoker.sources
      outputs = [
        "{{bundle_resources_dir}}/{{source_file_part}}",
      ]
    }
  }
}