# Copyright Google LLC. All Rights Reserved.
#
# Use of this source code is governed by an MIT-style license that can be
# found in the LICENSE file at https://angular.dev/license

load("@devinfra//bazel/api-golden:index.bzl", "api_golden_test_npm_package")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//tools:defaults.bzl", "copy_to_bin", "jasmine_test", "npm_package", "ts_project")
load("//tools:ts_json_schema.bzl", "ts_json_schema")

licenses(["notice"])

package(default_visibility = ["//visibility:public"])

npm_link_all_packages()

ts_json_schema(
    name = "app_shell_schema",
    src = "src/builders/app-shell/schema.json",
)

ts_json_schema(
    name = "browser_schema",
    src = "src/builders/browser/schema.json",
)

ts_json_schema(
    name = "browser_esbuild_schema",
    src = "src/builders/browser-esbuild/schema.json",
)

ts_json_schema(
    name = "dev_server_schema",
    src = "src/builders/dev-server/schema.json",
)

ts_json_schema(
    name = "extract_i18n_schema",
    src = "src/builders/extract-i18n/schema.json",
)

ts_json_schema(
    name = "jest_schema",
    src = "src/builders/jest/schema.json",
)

ts_json_schema(
    name = "karma_schema",
    src = "src/builders/karma/schema.json",
)

ts_json_schema(
    name = "protractor_schema",
    src = "src/builders/protractor/schema.json",
)

ts_json_schema(
    name = "server_schema",
    src = "src/builders/server/schema.json",
)

ts_json_schema(
    name = "ng_packagr_schema",
    src = "src/builders/ng-packagr/schema.json",
)

ts_json_schema(
    name = "ssr_dev_server_schema",
    src = "src/builders/ssr-dev-server/schema.json",
)

ts_json_schema(
    name = "prerender_schema",
    src = "src/builders/prerender/schema.json",
)

ts_json_schema(
    name = "web_test_runner_schema",
    src = "src/builders/web-test-runner/schema.json",
)

copy_to_bin(
    name = "schemas",
    srcs = glob(["**/schema.json"]),
)

RUNTIME_ASSETS = glob(
    include = [
        "src/**/schema.json",
        "src/**/*.js",
        "src/**/*.mjs",
        "src/**/*.html",
    ],
) + [
    "builders.json",
    "package.json",
]

ts_project(
    name = "build_angular",
    srcs = glob(
        include = [
            "src/**/*.ts",
            "plugins/**/*.ts",
        ],
        exclude = [
            "src/test-utils.ts",
            "src/**/*_spec.ts",
            "src/**/tests/**/*.ts",
            "plugins/**/*_spec.ts",
            "src/testing/**/*.ts",
        ],
    ) + [
        "index.ts",
        "//packages/angular_devkit/build_angular:src/builders/app-shell/schema.ts",
        "//packages/angular_devkit/build_angular:src/builders/browser-esbuild/schema.ts",
        "//packages/angular_devkit/build_angular:src/builders/browser/schema.ts",
        "//packages/angular_devkit/build_angular:src/builders/dev-server/schema.ts",
        "//packages/angular_devkit/build_angular:src/builders/extract-i18n/schema.ts",
        "//packages/angular_devkit/build_angular:src/builders/jest/schema.ts",
        "//packages/angular_devkit/build_angular:src/builders/karma/schema.ts",
        "//packages/angular_devkit/build_angular:src/builders/ng-packagr/schema.ts",
        "//packages/angular_devkit/build_angular:src/builders/prerender/schema.ts",
        "//packages/angular_devkit/build_angular:src/builders/protractor/schema.ts",
        "//packages/angular_devkit/build_angular:src/builders/server/schema.ts",
        "//packages/angular_devkit/build_angular:src/builders/ssr-dev-server/schema.ts",
        "//packages/angular_devkit/build_angular:src/builders/web-test-runner/schema.ts",
    ],
    data = RUNTIME_ASSETS,
    deps = [
        ":node_modules/@ampproject/remapping",
        ":node_modules/@angular-devkit/architect",
        ":node_modules/@angular-devkit/build-webpack",
        ":node_modules/@angular-devkit/core",
        ":node_modules/@angular/build",
        ":node_modules/@angular/ssr",
        ":node_modules/@babel/core",
        ":node_modules/@babel/generator",
        ":node_modules/@babel/helper-annotate-as-pure",
        ":node_modules/@babel/helper-split-export-declaration",
        ":node_modules/@babel/plugin-transform-async-generator-functions",
        ":node_modules/@babel/plugin-transform-async-to-generator",
        ":node_modules/@babel/plugin-transform-runtime",
        ":node_modules/@babel/preset-env",
        ":node_modules/@babel/runtime",
        ":node_modules/@discoveryjs/json-ext",
        ":node_modules/@ngtools/webpack",
        ":node_modules/@web/test-runner",
        ":node_modules/ansi-colors",
        ":node_modules/autoprefixer",
        ":node_modules/babel-loader",
        ":node_modules/browser-sync",
        ":node_modules/browserslist",
        ":node_modules/copy-webpack-plugin",
        ":node_modules/css-loader",
        ":node_modules/http-proxy-middleware",
        ":node_modules/istanbul-lib-instrument",
        ":node_modules/jsonc-parser",
        ":node_modules/less",
        ":node_modules/less-loader",
        ":node_modules/license-webpack-plugin",
        ":node_modules/loader-utils",
        ":node_modules/mini-css-extract-plugin",
        ":node_modules/ng-packagr",
        ":node_modules/open",
        ":node_modules/ora",
        ":node_modules/piscina",
        ":node_modules/postcss",
        ":node_modules/postcss-loader",
        ":node_modules/resolve-url-loader",
        ":node_modules/rxjs",
        ":node_modules/sass",
        ":node_modules/sass-loader",
        ":node_modules/source-map-loader",
        ":node_modules/source-map-support",
        ":node_modules/terser",
        ":node_modules/tinyglobby",
        ":node_modules/tree-kill",
        ":node_modules/webpack",
        ":node_modules/webpack-dev-middleware",
        ":node_modules/webpack-dev-server",
        ":node_modules/webpack-merge",
        ":node_modules/webpack-subresource-integrity",
        "//:node_modules/@angular/common",
        "//:node_modules/@angular/compiler-cli",
        "//:node_modules/@angular/core",
        "//:node_modules/@angular/localize",
        "//:node_modules/@angular/platform-browser",
        "//:node_modules/@angular/platform-server",
        "//:node_modules/@angular/service-worker",
        "//:node_modules/@types/babel__core",
        "//:node_modules/@types/babel__generator",
        "//:node_modules/@types/browser-sync",
        "//:node_modules/@types/karma",
        "//:node_modules/@types/less",
        "//:node_modules/@types/loader-utils",
        "//:node_modules/@types/node",
        "//:node_modules/@types/picomatch",
        "//:node_modules/@types/semver",
        "//:node_modules/@types/watchpack",
        "//:node_modules/esbuild",
        "//:node_modules/esbuild-wasm",
        "//:node_modules/karma",
        "//:node_modules/karma-source-map-support",
        "//:node_modules/semver",
        "//:node_modules/tslib",
        "//:node_modules/typescript",
    ],
)

ts_project(
    name = "build_angular_test_lib",
    testonly = True,
    srcs = glob(
        include = [
            "src/**/*_spec.ts",
        ],
        exclude = [
            "src/builders/**/*_spec.ts",
        ],
    ),
    deps = [
        ":build_angular",
        ":build_angular_test_utils",
        ":node_modules/tinyglobby",
        "//:node_modules/@types/node",
        "//:node_modules/prettier",
        "//:node_modules/typescript",
        "//packages/angular_devkit/architect/testing",
        "//packages/angular_devkit/core",
    ],
)

jasmine_test(
    name = "test",
    data = [":build_angular_test_lib"],
)

genrule(
    name = "license",
    srcs = ["//:LICENSE"],
    outs = ["LICENSE"],
    cmd = "cp $(execpath //:LICENSE) $@",
)

npm_package(
    name = "pkg",
    pkg_deps = [
        "//packages/angular/build:package.json",
        "//packages/angular_devkit/architect:package.json",
        "//packages/angular_devkit/build_webpack:package.json",
        "//packages/angular_devkit/core:package.json",
        "//packages/ngtools/webpack:package.json",
    ],
    stamp_files = [
        "src/utils/normalize-cache.js",
    ],
    tags = ["release-package"],
    deps = RUNTIME_ASSETS + [
        ":README.md",
        ":build_angular",
        ":license",
    ],
)

api_golden_test_npm_package(
    name = "build_angular_api",
    data = [
        ":npm_package",
        "//goldens:public-api",
    ],
    golden_dir = "goldens/public-api/angular_devkit/build_angular",
    npm_package = "packages/angular_devkit/build_angular/npm_package",
)

# Large build_angular specs

ts_project(
    name = "build_angular_test_utils",
    testonly = True,
    srcs = glob(
        include = [
            "src/testing/**/*.ts",
            "src/**/tests/*.ts",
        ],
        exclude = [
            "src/**/*_spec.ts",
        ],
    ),
    deps = [
        ":build_angular",
        ":node_modules/@angular-devkit/architect",
        ":node_modules/@angular-devkit/core",
        ":node_modules/@angular/build",
        ":node_modules/rxjs",
        "//:node_modules/@types/jasmine",
        "//:node_modules/@types/node",
        "//modules/testing/builder",
    ],
)

LARGE_SPECS = {
    "app-shell": {},
    "dev-server": {
        "shards": 10,
        "size": "large",
        "flaky": True,
        "extra_deps": [
            "//:node_modules/@types/http-proxy",
            "//:node_modules/@types/node",
            "//:node_modules/http-proxy",
            "//:node_modules/puppeteer",
            "//:node_modules/undici",
        ],
    },
    "extract-i18n": {},
    "karma": {
        "shards": 6,
        "size": "large",
        "flaky": True,
        "extra_deps": [
            "//:node_modules/@types/node",
            "//:node_modules/karma",
            "//:node_modules/karma-chrome-launcher",
            "//:node_modules/karma-coverage",
            "//:node_modules/karma-jasmine",
            "//:node_modules/karma-jasmine-html-reporter",
            "//:node_modules/puppeteer",
            ":node_modules/webpack",
        ],
    },
    "protractor": {
        "extra_deps": [
            "//:node_modules/jasmine-spec-reporter",
            "//:node_modules/protractor",
            "//:node_modules/puppeteer",
            "//:node_modules/ts-node",
        ],
        # NB: does not run on rbe because webdriver manager uses an absolute path to chromedriver
        "tags": ["no-remote-exec"],
        # NB: multiple shards will compete for port 4200 so limiting to 1
        "shards": 1,
    },
    "server": {
        "size": "large",
        "extra_deps": [
            "//:node_modules/@angular/animations",
        ],
    },
    "ng-packagr": {
    },
    "browser": {
        "shards": 10,
        "size": "large",
        "flaky": True,
        "extra_deps": [
            "//:node_modules/@types/node",
            "//:node_modules/@angular/animations",
            "//:node_modules/@angular/material",
            "//:node_modules/ajv",
        ],
    },
    "prerender": {},
    "browser-esbuild": {},
    "ssr-dev-server": {
        "extra_deps": [
            ":node_modules/@angular/ssr",
            "//:node_modules/@types/browser-sync",
            "//:node_modules/@types/node",
            ":node_modules/browser-sync",
            "//:node_modules/express",
            "//:node_modules/undici",
        ],
    },
}

[
    ts_project(
        name = "build_angular_" + spec + "_test_lib",
        testonly = True,
        srcs = glob(["src/builders/" + spec + "/**/*_spec.ts"]),
        deps = [
            # Dependencies needed to compile and run the specs themselves.
            ":build_angular",
            ":build_angular_test_utils",
            ":node_modules/@angular/build",
            ":node_modules/@angular-devkit/architect",
            ":node_modules/@angular-devkit/core",

            # Base dependencies for the application in hello-world-app.
            # Some tests also require extra dependencies.
            "//:node_modules/@angular/common",
            "//:node_modules/@angular/compiler",
            "//:node_modules/@angular/compiler-cli",
            "//:node_modules/@angular/core",
            "//:node_modules/@angular/platform-browser",
            "//:node_modules/@angular/router",
            ":node_modules/rxjs",
            "//:node_modules/tslib",
            "//:node_modules/typescript",
            "//:node_modules/zone.js",
            "//:node_modules/@types/jasmine",
        ] + LARGE_SPECS[spec].get("extra_deps", []),
    )
    for spec in LARGE_SPECS
]

[
    jasmine_test(
        name = "build_angular_" + spec + "_test",
        size = LARGE_SPECS[spec].get("size", "medium"),
        data = [
            ":build_angular_" + spec + "_test_lib",
            # Helpers for `testing/builder` rely on the npm artifact, so we'll make
            # sure it's available during this test. Notably that the package needs to
            # available as a parent of `modules/testing/builder` for resolution to work!
            "//modules/testing/builder:node_modules/@angular-devkit/build-angular",
        ],
        env = {
            # Force IPv4 to resolve RBE resolution issues
            "NODE_OPTIONS": "--dns-result-order=ipv4first",

            # TODO: Replace Puppeteer downloaded browsers with Bazel-managed browsers,
            # or standardize to avoid complex configuration like this!
            "PUPPETEER_DOWNLOAD_PATH": "../../../node_modules/puppeteer/downloads",
        },
        flaky = LARGE_SPECS[spec].get("flaky", False),
        shard_count = LARGE_SPECS[spec].get("shards", 2),
        # These tests are resource intensive and should not be over-parallized as they will
        # compete for the resources of other parallel tests slowing everything down.
        # Ask Bazel to allocate multiple CPUs for these tests with "cpu:n" tag.
        tags = [
            "cpu:2",
        ] + LARGE_SPECS[spec].get("tags", []),
    )
    for spec in LARGE_SPECS
]
