diff --git a/.bazelversion b/.bazelversion
index f9c71a52e2fd..acd405b1d62e 100644
--- a/.bazelversion
+++ b/.bazelversion
@@ -1 +1 @@
-8.5.1
+8.6.0
diff --git a/.gemini/config.yaml b/.gemini/config.yaml
new file mode 100644
index 000000000000..9f4eb5f02da3
--- /dev/null
+++ b/.gemini/config.yaml
@@ -0,0 +1,11 @@
+have_fun: false
+code_review:
+ disable: false
+ comment_severity_threshold: MEDIUM
+ max_review_comments: -1
+ pull_request_opened:
+ help: false
+ summary: false
+ code_review: true
+ include_drafts: false
+ignore_patterns: []
diff --git a/.github/workflows/assistant-to-the-branch-manager.yml b/.github/workflows/assistant-to-the-branch-manager.yml
index 6e0a4cb8c7d7..efde5bc5d875 100644
--- a/.github/workflows/assistant-to-the-branch-manager.yml
+++ b/.github/workflows/assistant-to-the-branch-manager.yml
@@ -17,6 +17,6 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- - uses: angular/dev-infra/github-actions/branch-manager@469708f109a90884ca403d150d33079a3a5a8769
+ - uses: angular/dev-infra/github-actions/branch-manager@616a50d0b747031b7ea052733adf3771fa6cace9
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5f62362d4410..4a89f2d7f9ad 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -21,9 +21,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Generate JSON schema types
@@ -44,11 +44,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
@@ -61,11 +61,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
@@ -84,13 +84,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Run CLI E2E tests
@@ -100,11 +100,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Install node modules
@@ -137,7 +137,7 @@ jobs:
runs-on: windows-2025
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Download built Windows E2E tests
@@ -164,13 +164,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Run CLI E2E tests
@@ -188,13 +188,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Run CLI E2E tests
@@ -208,13 +208,13 @@ jobs:
SAUCE_TUNNEL_IDENTIFIER: angular-cli-${{ github.workflow }}-${{ github.run_number }}
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
with:
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
- name: Run E2E Browser tests
@@ -244,11 +244,11 @@ jobs:
CIRCLE_BRANCH: ${{ github.ref_name }}
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
- run: pnpm admin snapshots --verbose
env:
SNAPSHOT_BUILDS_GITHUB_TOKEN: ${{ secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN }}
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 0b070c5aae16..9c9cda1ad80d 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -23,12 +23,12 @@ jobs:
with:
persist-credentials: false
- name: Initialize CodeQL
- uses: github/codeql-action/init@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4.32.2
+ uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
with:
languages: javascript-typescript
build-mode: none
config-file: .github/codeql/config.yml
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4.32.2
+ uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
with:
category: '/language:javascript-typescript'
diff --git a/.github/workflows/dev-infra.yml b/.github/workflows/dev-infra.yml
index d8d2f0b7bb6c..bf29d1e38ae4 100644
--- a/.github/workflows/dev-infra.yml
+++ b/.github/workflows/dev-infra.yml
@@ -3,6 +3,8 @@ name: DevInfra
on:
pull_request_target:
types: [opened, synchronize, reopened]
+ issues:
+ types: [opened, reopened]
# Declare default permissions as read only.
permissions:
@@ -10,16 +12,24 @@ permissions:
jobs:
labels:
+ if: github.event_name == 'pull_request_target'
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- - uses: angular/dev-infra/github-actions/pull-request-labeling@469708f109a90884ca403d150d33079a3a5a8769
+ - uses: angular/dev-infra/github-actions/labeling/pull-request@616a50d0b747031b7ea052733adf3771fa6cace9
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
post_approval_changes:
+ if: github.event_name == 'pull_request_target'
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- - uses: angular/dev-infra/github-actions/post-approval-changes@469708f109a90884ca403d150d33079a3a5a8769
+ - uses: angular/dev-infra/github-actions/post-approval-changes@616a50d0b747031b7ea052733adf3771fa6cace9
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
+ issue_labels:
+ if: github.event_name == 'issues'
+ runs-on: ubuntu-latest
+ steps:
+ - uses: angular/dev-infra/github-actions/labeling/issue@616a50d0b747031b7ea052733adf3771fa6cace9
+ with:
+ angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
+ google-generative-ai-key: ${{ secrets.GOOGLE_GENERATIVE_AI_KEY }}
diff --git a/.github/workflows/feature-requests.yml b/.github/workflows/feature-requests.yml
index 4e22f1a5eda8..b77551c5d2a8 100644
--- a/.github/workflows/feature-requests.yml
+++ b/.github/workflows/feature-requests.yml
@@ -16,6 +16,6 @@ jobs:
if: github.repository == 'angular/angular-cli'
runs-on: ubuntu-latest
steps:
- - uses: angular/dev-infra/github-actions/feature-request@469708f109a90884ca403d150d33079a3a5a8769
+ - uses: angular/dev-infra/github-actions/feature-request@616a50d0b747031b7ea052733adf3771fa6cace9
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
diff --git a/.github/workflows/perf.yml b/.github/workflows/perf.yml
index 9dbf67608b8c..675676394863 100644
--- a/.github/workflows/perf.yml
+++ b/.github/workflows/perf.yml
@@ -23,7 +23,7 @@ jobs:
workflows: ${{ steps.workflows.outputs.workflows }}
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Install node modules
run: pnpm install --frozen-lockfile
- id: workflows
@@ -38,9 +38,9 @@ jobs:
workflow: ${{ fromJSON(needs.list.outputs.workflows) }}
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Install node modules
run: pnpm install --frozen-lockfile
# We utilize the google-github-actions/auth action to allow us to get an active credential using workflow
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index 12195b663fda..9235d910ea5c 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -23,7 +23,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
+ - uses: dorny/paths-filter@d1c1ffe0248fe513906c8e24db8ea791d46f8590 # v3.0.3
id: filter
with:
filters: |
@@ -34,11 +34,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup ESLint Caching
- uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
+ uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
with:
path: .eslintcache
key: ${{ runner.os }}-${{ hashFiles('.eslintrc.json') }}
@@ -66,17 +66,17 @@ jobs:
# it has been merged.
run: pnpm ng-dev format changed --check ${{ github.event.pull_request.base.sha }}
- name: Check Package Licenses
- uses: angular/dev-infra/github-actions/linting/licenses@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/linting/licenses@616a50d0b747031b7ea052733adf3771fa6cace9
build:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Build release targets
@@ -93,11 +93,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Run module and package tests
@@ -114,13 +114,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Run CLI E2E tests
run: pnpm bazel test --test_env=E2E_SHARD_TOTAL=6 --test_env=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests:e2e.${{ matrix.subset }}_node${{ matrix.node }}
@@ -128,11 +128,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Build E2E tests for Windows on Linux
@@ -156,7 +156,7 @@ jobs:
runs-on: windows-2025
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Download built Windows E2E tests
@@ -183,13 +183,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Run CLI E2E tests
run: pnpm bazel test --test_env=E2E_SHARD_TOTAL=3 --test_env=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests:e2e.${{ matrix.subset }}_node${{ matrix.node }}
@@ -205,12 +205,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Install node modules
run: pnpm install --frozen-lockfile
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@469708f109a90884ca403d150d33079a3a5a8769
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
- name: Run CLI E2E tests
run: pnpm bazel test --test_env=E2E_SHARD_TOTAL=6 --test_env=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests:e2e.snapshots.${{ matrix.subset }}_node${{ matrix.node }}
diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml
index 4c9465d0cf9b..f31e15c10d1f 100644
--- a/.github/workflows/scorecard.yml
+++ b/.github/workflows/scorecard.yml
@@ -46,6 +46,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: 'Upload to code-scanning'
- uses: github/codeql-action/upload-sarif@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4.32.2
+ uses: github/codeql-action/upload-sarif@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
with:
sarif_file: results.sarif
diff --git a/.monorepo.json b/.monorepo.json
index 4d5face644df..96877fada26e 100644
--- a/.monorepo.json
+++ b/.monorepo.json
@@ -62,7 +62,11 @@
"@angular-devkit/architect-cli": {
"name": "Architect CLI",
"section": "Tooling",
- "snapshotRepo": "angular/angular-devkit-architect-cli-builds"
+ "snapshotRepo": "angular/angular-devkit-architect-cli-builds",
+ "deprecated": {
+ "version": ">=0.2102.0",
+ "message": "The Architect CLI is now available directly via '@angular-devkit/architect'."
+ }
},
"@angular-devkit/build-angular": {
"name": "Build Angular",
diff --git a/.ng-dev/release.mjs b/.ng-dev/release.mjs
index 2aadf9db122c..7790637ed329 100644
--- a/.ng-dev/release.mjs
+++ b/.ng-dev/release.mjs
@@ -8,7 +8,11 @@ import { releasePackages } from '../scripts/packages.mts';
*/
export const release = {
representativeNpmPackage: '@angular/cli',
- npmPackages: releasePackages.map(({ name, experimental }) => ({ name, experimental })),
+ npmPackages: releasePackages.map(({ name, experimental, deprecated }) => ({
+ name,
+ experimental,
+ deprecated,
+ })),
buildPackages: async () => {
// The `performNpmReleaseBuild` function is loaded at runtime to avoid loading additional
// files and dependencies unless a build is required.
diff --git a/.nvmrc b/.nvmrc
index 85e502778f62..db49bb14d78e 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-22.22.0
+22.22.2
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b11c764b3618..a6e5f434a182 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,131 +1,259 @@
-
+
-# 19.2.20 (2026-02-13)
+# 21.2.6 (2026-04-01)
-### @angular-devkit/build-angular
+### @angular/cli
-| Commit | Type | Description |
-| --------------------------------------------------------------------------------------------------- | ---- | ------------------------- |
-| [0e5421ba7](https://github.com/angular/angular-cli/commit/0e5421ba78814cf11e4d4510e930eaacc6458662) | fix | update webpack to 5.105.0 |
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------- |
+| [ea14f28cc](https://github.com/angular/angular-cli/commit/ea14f28ccfc6e5534eaef516bf1bfbe21582da04) | fix | fix sourceRoot resolution for MCP projects tool |
+
+### @angular/build
+
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------------------- |
+| [9136eb376](https://github.com/angular/angular-cli/commit/9136eb37630d6315891b3c881cd0ba4037c3254c) | fix | ensure transitive SCSS partial errors are tracked in watch mode |
+| [8186faa11](https://github.com/angular/angular-cli/commit/8186faa117803ffb6ac8e2c4cd6ab7873502308d) | fix | ensure Vitest mock patching is executed only once |
+| [107d1a9e2](https://github.com/angular/angular-cli/commit/107d1a9e26fc59c7878254e563758818866f0f6e) | fix | preserve error stack traces during prerendering |
+| [b7f457253](https://github.com/angular/angular-cli/commit/b7f4572533675729e87532bdc23509feb2f3a28d) | fix | scope CHROME_BIN executable path to individual playwright instances |
-
+
+
+# 21.2.5 (2026-03-27)
+
+### @angular/cli
-# 21.2.0-next.2 (2026-02-11)
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------- |
+| [cadf9b201](https://github.com/angular/angular-cli/commit/cadf9b201bd1055a6e3cc016eb01e0196b028080) | feat | support custom port in MCP devserver start tool |
+
+### @angular/ssr
+
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ---------------------------------------------------- |
+| [bbc255419](https://github.com/angular/angular-cli/commit/bbc255419b346e5152391b47f310922f86e9e383) | fix | allow underscores in host validation |
+| [b1fe66a7f](https://github.com/angular/angular-cli/commit/b1fe66a7f8650ce021b4070394bc31848fc64ca5) | fix | patch Headers.forEach in cloneRequestAndPatchHeaders |
+
+
+
+
+
+# 21.2.4 (2026-03-26)
+
+### @angular/cli
+
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ---------------------------------------------- |
+| [a7787d092](https://github.com/angular/angular-cli/commit/a7787d0925559fe7731034856a872708bcfb78be) | fix | restore console methods after logger completes |
### @angular/build
-| Commit | Type | Description |
-| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------------- |
-| [cad7a7c0f](https://github.com/angular/angular-cli/commit/cad7a7c0ff3778f04820a99ad0aa9d74f1067fd5) | feat | run vitest browser with playwright with OS theme |
-| [8ae7f59e6](https://github.com/angular/angular-cli/commit/8ae7f59e6f988489fda8c1346e3d2c3768d7a5f0) | fix | correctly resolve absolute setup file paths in Vitest |
-| [fd5cb28c8](https://github.com/angular/angular-cli/commit/fd5cb28c8082417288a896b89bde659bb0dc92e2) | fix | explicitly fail when using Vitest runtime mocking |
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------------------------- |
+| [7170599ab](https://github.com/angular/angular-cli/commit/7170599ab237691d9208c410363ef7e4ee50db2c) | fix | deduplicate and merge coverage excludes with vitest |
+| [c73f13797](https://github.com/angular/angular-cli/commit/c73f13797afe57fcc98faf6361085e1dd5afae9b) | fix | prevent reporter duplicates by explicitly overriding Vitest configuration |
+| [956ccaa71](https://github.com/angular/angular-cli/commit/956ccaa71ea8a3626e4139cf7e2f26ee637feeed) | fix | remove default for unit-test coverage option |
+| [36978db7e](https://github.com/angular/angular-cli/commit/36978db7e494e4e5612aa2a8384199eeca7c4c2d) | fix | warn about performance of test.exclude in vitest configuration |
+| [6ec36f5be](https://github.com/angular/angular-cli/commit/6ec36f5bee05d97c10ca8d91d5746621ffb1fdb9) | fix | warn when vitest watch config conflicts with builder |
+
+### @angular/ssr
+
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------------------- |
+| [9bdf782c8](https://github.com/angular/angular-cli/commit/9bdf782c838ab5820ec905d689a62ffc3b3cabe3) | fix | apply forwarded prefix and vary header in accept-language redirects |
+| [628c58672](https://github.com/angular/angular-cli/commit/628c586728748e1c367fa7e363299eb79b1566ca) | fix | support '\*' in allowedHosts and warn about security risks |
-
+
-# 21.1.4 (2026-02-11)
+# 21.2.3 (2026-03-18)
+
+### @angular/cli
+
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------ |
+| [1505164bb](https://github.com/angular/angular-cli/commit/1505164bb2703254a2b25a76c7b3a1ff2fd76a85) | fix | use parsed package name for migrate-only updates |
### @angular/build
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------------------------ |
+| [75fa94cad](https://github.com/angular/angular-cli/commit/75fa94cad26b0947e687ef94d50653cb7651d18c) | fix | alias createRequire banner import to avoid duplicate binding |
+| [d009aa1ec](https://github.com/angular/angular-cli/commit/d009aa1ec7411b67b61b81003eb6181cde6f306f) | fix | only use external packages for polyfills when no local files are present |
+
+### @angular/ssr
+
| Commit | Type | Description |
| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------------- |
-| [7a9dd6b47](https://github.com/angular/angular-cli/commit/7a9dd6b47e2191862c64355b10abaeead189759f) | fix | correctly resolve absolute setup file paths in Vitest |
+| [f3e0e82c2](https://github.com/angular/angular-cli/commit/f3e0e82c2cecc3d9ebb5b8acc6e64d2d88c4efbd) | fix | disallow x-forwarded-prefix starting with a backslash |
+| [b8bcd59b4](https://github.com/angular/angular-cli/commit/b8bcd59b40496369a57de0b0b39d85f323af30c7) | fix | ensure unique values in redirect response Vary header |
+| [84385411d](https://github.com/angular/angular-cli/commit/84385411d4542d60d635aea9063c1fd751deb607) | fix | support custom headers in redirect responses |
-
+
-# 20.3.16 (2026-02-09)
+# 21.2.2 (2026-03-11)
### @angular/cli
-| Commit | Type | Description |
-| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------ |
-| [656888a25](https://github.com/angular/angular-cli/commit/656888a250af060c110ae87024b0e475b079c23d) | fix | update dependency @modelcontextprotocol/sdk to v1.26.0 |
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------------------------------------- |
+| [8447d9132](https://github.com/angular/angular-cli/commit/8447d913280a8fa09a842d11193ce77527d0f7a6) | fix | conditionally quote package names when adding dependencies based on host requirements |
+| [d2f209823](https://github.com/angular/angular-cli/commit/d2f209823a524a6effde4910017547675c7a6166) | fix | preserve exact version in ng add when requested |
+| [28f4d684a](https://github.com/angular/angular-cli/commit/28f4d684ae12f0e0860bf0ace8851fdddad1c068) | perf | avoid redundant package version resolution in ng add |
+
+### @angular/build
+
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------- |
+| [06010294f](https://github.com/angular/angular-cli/commit/06010294f8fe7a4843f802aafba51703ce810f61) | fix | allow any `CHROME_BIN` for vitest playwright provider |
+| [8dec0c62b](https://github.com/angular/angular-cli/commit/8dec0c62ba40af339f4fd0fa34f20cbed545cd71) | fix | normalize line endings for CSP hash generation |
+| [58688ebd7](https://github.com/angular/angular-cli/commit/58688ebd727fe295adcb538a33b525867caf82bd) | fix | pass process environment variables to prerender workers |
+| [4ca61647f](https://github.com/angular/angular-cli/commit/4ca61647f208ec0ab9bc06f64583696b0619c259) | fix | resolve assets correctly during i18n prerendering |
-
+
-# 21.2.0-next.1 (2026-02-05)
+# 21.2.1 (2026-03-05)
### @angular/cli
-| Commit | Type | Description |
-| --------------------------------------------------------------------------------------------------- | ---- | ---------------------------------------------------------- |
-| [91b9d281f](https://github.com/angular/angular-cli/commit/91b9d281fc88a242aa6e5dd5495e275990d926ef) | feat | integrate file formatting into update migrations |
-| [6f29a8c35](https://github.com/angular/angular-cli/commit/6f29a8c35abb8928d4e7ea01958192dd2a83491d) | fix | renamed files by their new path in the schematic workflow |
-| [bc363af8b](https://github.com/angular/angular-cli/commit/bc363af8bc40f117a4e35ec9eb7eedf69f5b5b37) | perf | optimize package manager discovery with stat-based probing |
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------ |
+| [ae4c28d00](https://github.com/angular/angular-cli/commit/ae4c28d0083d948489f4ba38c571b7f955400226) | fix | correct dev dependency detection logic in `ng add` |
+| [465073bc1](https://github.com/angular/angular-cli/commit/465073bc1b2b0e9fa594698651a9e0afe747a74a) | fix | disable npm update notifier in package manager host |
+| [36270634f](https://github.com/angular/angular-cli/commit/36270634f6ff5ab15896a8c2b345659511a8a276) | fix | ensure group members are updated to targeted version |
+| [d87dba6af](https://github.com/angular/angular-cli/commit/d87dba6af1116de0838d8683cd69fd31ed9811fd) | fix | ignore unknown files when formatting schematic changes |
### @schematics/angular
-| Commit | Type | Description |
-| --------------------------------------------------------------------------------------------------- | ---- | ---------------------------------------------------------------- |
-| [5d1df50d8](https://github.com/angular/angular-cli/commit/5d1df50d8b84b453570ae5fd9ab6f949bbc11649) | fix | add actionable feedback to vitest-browser schematic |
-| [51fc77828](https://github.com/angular/angular-cli/commit/51fc77828a33fdf35051b7e18d79ad43f90cba1d) | fix | warn when production configuration is missing for service worker |
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | --------------------------------------------------------------- |
+| [72d466aa0](https://github.com/angular/angular-cli/commit/72d466aa04d4d0cc4d654410bcb6dd44f0de3357) | fix | prevent adding test dependencies when minimal option is enabled |
+
+### @angular-devkit/build-angular
+
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------- |
+| [0019d1c8e](https://github.com/angular/angular-cli/commit/0019d1c8e1494295a754063dbf936e1cd40d05bd) | fix | update copy-webpack-plugin to v14.0.0 |
### @angular/build
-| Commit | Type | Description |
-| --------------------------------------------------------------------------------------------------- | ---- | -------------------------------------------------- |
-| [ece30f235](https://github.com/angular/angular-cli/commit/ece30f2359c2dc794b0c9272447f623a121e88b0) | feat | add headless option to unit-test builder |
-| [1f114a9e8](https://github.com/angular/angular-cli/commit/1f114a9e8b9bddd53e01016a2d7cb211a04eee48) | fix | bundle setup files in unit-test builder for Vitest |
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------------------------------ |
+| [6ad860863](https://github.com/angular/angular-cli/commit/6ad8608636ad48ae140cc7299a32e0358c761fcc) | fix | bundle polyfills to preserve execution order in dev server |
+| [d17397375](https://github.com/angular/angular-cli/commit/d1739737564fbcc3e4c5a6c3369046cccf0f6120) | fix | conditionally allow `vi.mock` for non-relative imports |
+| [0d49f86ed](https://github.com/angular/angular-cli/commit/0d49f86edf5592f0266c6d6689ab4d55b27b2d8d) | fix | resolve style include paths relative to `ng-package.json` in unit-test builder |
+| [584f6a2d9](https://github.com/angular/angular-cli/commit/584f6a2d95ac4bdd9f20d918c6700ea79227cc92) | fix | treat empty browsers array as undefined in unit-test builder |
+| [6699cdc9b](https://github.com/angular/angular-cli/commit/6699cdc9bfbabc3de2ff0cf03acfd6989dc5596c) | perf | fix memory leak in `ng serve` with i18n |
+
+### @angular/ssr
+
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ---------------------------------------------------- |
+| [43a9dfa66](https://github.com/angular/angular-cli/commit/43a9dfa663c386217c9a654f0e80af74823fcf6a) | fix | improve header validation logic |
+| [dee3717b3](https://github.com/angular/angular-cli/commit/dee3717b3faae9ea75d0a5e53c925f915949b8d0) | fix | introduce DI token to signal route discovery process |
-
+
-# 21.1.3 (2026-02-05)
+# 21.2.0 (2026-02-25)
+
+### @angular/cli
+
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------------------------------------------------------------- |
+| [0dd04f289](https://github.com/angular/angular-cli/commit/0dd04f289e555a4a8af7bdadabe300da74701e3b) | feat | add markdown files to Prettier's formatting list |
+| [fbae1b6ab](https://github.com/angular/angular-cli/commit/fbae1b6ab384186ae69e804c54815cea80e6a600) | feat | automatic formatting files modified by schematics |
+| [91b9d281f](https://github.com/angular/angular-cli/commit/91b9d281fc88a242aa6e5dd5495e275990d926ef) | feat | integrate file formatting into update migrations |
+| [98a24d040](https://github.com/angular/angular-cli/commit/98a24d0401f36f484dc9c4d8b0f5284ffa524f19) | feat | standardize MCP tools around workspace/project options |
+| [d9cd609c5](https://github.com/angular/angular-cli/commit/d9cd609c5d13fe492b1f31973d9be518f8529387) | fix | correctly parse scoped packages in yarn classic list output |
+| [5b05f2500](https://github.com/angular/angular-cli/commit/5b05f25005621828565585692b1d7a67c5f0fec8) | fix | enable shell option for Prettier execution on Windows platforms |
+| [25b8a157d](https://github.com/angular/angular-cli/commit/25b8a157df70fb0d2c4e6c5438a50ec12e3abc0c) | fix | quote complex range specifiers in package manager |
+| [6f29a8c35](https://github.com/angular/angular-cli/commit/6f29a8c35abb8928d4e7ea01958192dd2a83491d) | fix | renamed files by their new path in the schematic workflow |
+| [201a036f2](https://github.com/angular/angular-cli/commit/201a036f204a6940f70a36a507a4a53d144b5768) | fix | simplify Angular version compatibility checks and add special handling for local builds of new major versions |
+| [cdd26bb66](https://github.com/angular/angular-cli/commit/cdd26bb66d8ab334f76323c2b5cae1aa8ce815f6) | fix | validate package manager version using `semver.valid` and throw an error if invalid |
+| [bc363af8b](https://github.com/angular/angular-cli/commit/bc363af8bc40f117a4e35ec9eb7eedf69f5b5b37) | perf | optimize package manager discovery with stat-based probing |
### @schematics/angular
-| Commit | Type | Description |
-| --------------------------------------------------------------------------------------------------- | ---- | ---------------------------------------------------------------- |
-| [a18196a10](https://github.com/angular/angular-cli/commit/a18196a1096e5eb69cf64102943781d34c4389bf) | fix | warn when production configuration is missing for service worker |
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------------------------------------------- |
+| [aa7381efd](https://github.com/angular/angular-cli/commit/aa7381efd213eff70a8004731a7e2b06a60cb8c2) | feat | add a '.prettierrc' file to generated workspaces and add Prettier as dev dependency |
+| [f80db6fb7](https://github.com/angular/angular-cli/commit/f80db6fb714aa326f6ed03a8a51090ca59ad0955) | feat | add ng-add support for Vitest browser providers |
+| [5d1df50d8](https://github.com/angular/angular-cli/commit/5d1df50d8b84b453570ae5fd9ab6f949bbc11649) | fix | add actionable feedback to vitest-browser schematic |
+
+### @angular/build
+
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | -------------------------------------------------------- |
+| [ece30f235](https://github.com/angular/angular-cli/commit/ece30f2359c2dc794b0c9272447f623a121e88b0) | feat | add headless option to unit-test builder |
+| [cad7a7c0f](https://github.com/angular/angular-cli/commit/cad7a7c0ff3778f04820a99ad0aa9d74f1067fd5) | feat | run vitest browser with playwright with OS theme |
+| [0b4982720](https://github.com/angular/angular-cli/commit/0b4982720e111bf5029bcf97f7e0ce2658c42d43) | fix | adjust sourcemap sources when Vitest wrapper is bypassed |
+| [1f114a9e8](https://github.com/angular/angular-cli/commit/1f114a9e8b9bddd53e01016a2d7cb211a04eee48) | fix | bundle setup files in unit-test builder for Vitest |
+| [fd5cb28c8](https://github.com/angular/angular-cli/commit/fd5cb28c8082417288a896b89bde659bb0dc92e2) | fix | explicitly fail when using Vitest runtime mocking |
+| [dc899e8a5](https://github.com/angular/angular-cli/commit/dc899e8a530979de8e9579f2281b681e6f737a62) | fix | normalize `allowedHosts` in dev-server |
+| [26bbea12f](https://github.com/angular/angular-cli/commit/26bbea12f872c18e59de05d3c51cc11dd0a09cda) | fix | serve extensionless assets without transformation |
+
+
+
+
+
+# 19.2.20 (2026-02-13)
### @angular-devkit/build-angular
-| Commit | Type | Description |
-| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------- |
-| [6d05d27ca](https://github.com/angular/angular-cli/commit/6d05d27ca097b16efb139bcee1c45b1b51dfe746) | fix | address Node.js deprecation DEP0190 |
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ------------------------- |
+| [0e5421ba7](https://github.com/angular/angular-cli/commit/0e5421ba78814cf11e4d4510e930eaacc6458662) | fix | update webpack to 5.105.0 |
-
+
-# 21.2.0-next.0 (2026-01-28)
+# 21.1.4 (2026-02-11)
+
+### @angular/build
+
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------------- |
+| [7a9dd6b47](https://github.com/angular/angular-cli/commit/7a9dd6b47e2191862c64355b10abaeead189759f) | fix | correctly resolve absolute setup file paths in Vitest |
+
+
+
+
+
+# 20.3.16 (2026-02-09)
### @angular/cli
-| Commit | Type | Description |
-| --------------------------------------------------------------------------------------------------- | ---- | --------------------------------------------------------------- |
-| [0dd04f289](https://github.com/angular/angular-cli/commit/0dd04f289e555a4a8af7bdadabe300da74701e3b) | feat | add markdown files to Prettier's formatting list |
-| [fbae1b6ab](https://github.com/angular/angular-cli/commit/fbae1b6ab384186ae69e804c54815cea80e6a600) | feat | automatic formatting files modified by schematics |
-| [98a24d040](https://github.com/angular/angular-cli/commit/98a24d0401f36f484dc9c4d8b0f5284ffa524f19) | feat | standardize MCP tools around workspace/project options |
-| [d9cd609c5](https://github.com/angular/angular-cli/commit/d9cd609c5d13fe492b1f31973d9be518f8529387) | fix | correctly parse scoped packages in yarn classic list output |
-| [5b05f2500](https://github.com/angular/angular-cli/commit/5b05f25005621828565585692b1d7a67c5f0fec8) | fix | enable shell option for Prettier execution on Windows platforms |
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------ |
+| [656888a25](https://github.com/angular/angular-cli/commit/656888a250af060c110ae87024b0e475b079c23d) | fix | update dependency @modelcontextprotocol/sdk to v1.26.0 |
+
+
+
+
+
+# 21.1.3 (2026-02-05)
### @schematics/angular
-| Commit | Type | Description |
-| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------------------------------------------- |
-| [aa7381efd](https://github.com/angular/angular-cli/commit/aa7381efd213eff70a8004731a7e2b06a60cb8c2) | feat | add a '.prettierrc' file to generated workspaces and add Prettier as dev dependency |
-| [f80db6fb7](https://github.com/angular/angular-cli/commit/f80db6fb714aa326f6ed03a8a51090ca59ad0955) | feat | add ng-add support for Vitest browser providers |
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ---------------------------------------------------------------- |
+| [a18196a10](https://github.com/angular/angular-cli/commit/a18196a1096e5eb69cf64102943781d34c4389bf) | fix | warn when production configuration is missing for service worker |
### @angular-devkit/build-angular
| Commit | Type | Description |
| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------- |
-| [b4a8d198c](https://github.com/angular/angular-cli/commit/b4a8d198c78aaf0cac7671f26162ce5818a5704c) | fix | address Node.js deprecation DEP0190 |
-
-### @angular/build
-
-| Commit | Type | Description |
-| --------------------------------------------------------------------------------------------------- | ---- | -------------------------------------------------------- |
-| [0b4982720](https://github.com/angular/angular-cli/commit/0b4982720e111bf5029bcf97f7e0ce2658c42d43) | fix | adjust sourcemap sources when Vitest wrapper is bypassed |
+| [6d05d27ca](https://github.com/angular/angular-cli/commit/6d05d27ca097b16efb139bcee1c45b1b51dfe746) | fix | address Node.js deprecation DEP0190 |
@@ -2401,7 +2529,6 @@
- Protractor is no longer supported.
Protractor was marked end-of-life in August 2023 (see https://protractortest.org/). Projects still relying on Protractor should consider migrating to another E2E testing framework, several support solid migration paths from Protractor.
-
- https://angular.dev/tools/cli/end-to-end
- https://blog.angular.dev/the-state-of-end-to-end-testing-with-angular-d175f751cb9c
@@ -6036,7 +6163,6 @@ Alan Agius, Charles Lyding and Doug Parker
### @angular/cli
- Several changes to the `ng analytics` command syntax.
-
- `ng analytics project ` has been replaced with `ng analytics `
- `ng analytics ` has been replaced with `ng analytics --global`
@@ -6066,7 +6192,6 @@ Alan Agius, Charles Lyding and Doug Parker
- `browser` and `karma` builders `script` and `styles` options input files extensions are now validated.
Valid extensions for `scripts` are:
-
- `.js`
- `.cjs`
- `.mjs`
@@ -6075,7 +6200,6 @@ Alan Agius, Charles Lyding and Doug Parker
- `.mjsx`
Valid extensions for `styles` are:
-
- `.css`
- `.less`
- `.sass`
diff --git a/MODULE.bazel b/MODULE.bazel
index e218349c3d69..c2d2294e87a4 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -5,56 +5,57 @@ module(
)
bazel_dep(name = "platforms", version = "1.0.0")
-bazel_dep(name = "yq.bzl", version = "0.3.4")
+bazel_dep(name = "yq.bzl", version = "0.3.5")
bazel_dep(name = "rules_nodejs", version = "6.7.3")
-bazel_dep(name = "aspect_rules_js", version = "2.9.2")
-bazel_dep(name = "aspect_rules_ts", version = "3.8.4")
+bazel_dep(name = "aspect_rules_js", version = "3.0.3")
+bazel_dep(name = "aspect_rules_ts", version = "3.8.7")
bazel_dep(name = "rules_pkg", version = "1.2.0")
-bazel_dep(name = "rules_cc", version = "0.2.16")
-bazel_dep(name = "aspect_bazel_lib", version = "2.22.5")
+bazel_dep(name = "rules_cc", version = "0.2.17")
+bazel_dep(name = "jq.bzl", version = "0.6.1")
+bazel_dep(name = "bazel_lib", version = "3.2.2")
bazel_dep(name = "bazel_skylib", version = "1.9.0")
-bazel_dep(name = "aspect_rules_esbuild", version = "0.25.0")
-bazel_dep(name = "aspect_rules_jasmine", version = "2.0.2")
+bazel_dep(name = "aspect_rules_esbuild", version = "0.25.1")
+bazel_dep(name = "aspect_rules_jasmine", version = "2.0.4")
bazel_dep(name = "rules_angular")
git_override(
module_name = "rules_angular",
- commit = "d746c4f75e42cffe389d1ab077f4639be2bc78d1",
- remote = "https://github.com/devversion/rules_angular.git",
+ commit = "32ce54318d9ec5d84269d4acecbc39944cd8b5e7",
+ remote = "https://github.com/angular/rules_angular.git",
)
bazel_dep(name = "devinfra")
git_override(
module_name = "devinfra",
- commit = "469708f109a90884ca403d150d33079a3a5a8769",
+ commit = "616a50d0b747031b7ea052733adf3771fa6cace9",
remote = "https://github.com/angular/dev-infra.git",
)
bazel_dep(name = "rules_sass")
git_override(
module_name = "rules_sass",
- commit = "1184a80751a21af8348f308abc5b38a41f26850e",
- remote = "https://github.com/devversion/rules_sass.git",
+ commit = "13918bec49cd183a591e3781d1d08044b4aa9f61",
+ remote = "https://github.com/angular/rules_sass.git",
)
bazel_dep(name = "rules_browsers")
git_override(
module_name = "rules_browsers",
- commit = "e08ae33c679d07b3b2fcc136658b787a81995bc5",
- remote = "https://github.com/devversion/rules_browsers.git",
+ commit = "afdc95c1ce8ed9ff0cb94f829b7fc988c43dd783",
+ remote = "https://github.com/angular/rules_browsers.git",
)
node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node")
node.toolchain(
node_repositories = {
- "22.22.0-darwin_arm64": ("node-v22.22.0-darwin-arm64.tar.gz", "node-v22.22.0-darwin-arm64", "5ed4db0fcf1eaf84d91ad12462631d73bf4576c1377e192d222e48026a902640"),
- "22.22.0-darwin_amd64": ("node-v22.22.0-darwin-x64.tar.gz", "node-v22.22.0-darwin-x64", "5ea50c9d6dea3dfa3abb66b2656f7a4e1c8cef23432b558d45fb538c7b5dedce"),
- "22.22.0-linux_arm64": ("node-v22.22.0-linux-arm64.tar.xz", "node-v22.22.0-linux-arm64", "1bf1eb9ee63ffc4e5d324c0b9b62cf4a289f44332dfef9607cea1a0d9596ba6f"),
- "22.22.0-linux_ppc64le": ("node-v22.22.0-linux-ppc64le.tar.xz", "node-v22.22.0-linux-ppc64le", "d83b9957431cc18e1fc143a4b99f89cde7b8a18f53ef392231b4336afd058865"),
- "22.22.0-linux_s390x": ("node-v22.22.0-linux-s390x.tar.xz", "node-v22.22.0-linux-s390x", "5aa0e520689448c4233e8d73f284e8e0634fdcd32b479735698494be5641f3e4"),
- "22.22.0-linux_amd64": ("node-v22.22.0-linux-x64.tar.xz", "node-v22.22.0-linux-x64", "9aa8e9d2298ab68c600bd6fb86a6c13bce11a4eca1ba9b39d79fa021755d7c37"),
- "22.22.0-windows_amd64": ("node-v22.22.0-win-x64.zip", "node-v22.22.0-win-x64", "c97fa376d2becdc8863fcd3ca2dd9a83a9f3468ee7ccf7a6d076ec66a645c77a"),
+ "22.22.2-darwin_arm64": ("node-v22.22.2-darwin-arm64.tar.gz", "node-v22.22.2-darwin-arm64", "db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"),
+ "22.22.2-darwin_amd64": ("node-v22.22.2-darwin-x64.tar.gz", "node-v22.22.2-darwin-x64", "12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"),
+ "22.22.2-linux_arm64": ("node-v22.22.2-linux-arm64.tar.xz", "node-v22.22.2-linux-arm64", "e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"),
+ "22.22.2-linux_ppc64le": ("node-v22.22.2-linux-ppc64le.tar.xz", "node-v22.22.2-linux-ppc64le", "14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"),
+ "22.22.2-linux_s390x": ("node-v22.22.2-linux-s390x.tar.xz", "node-v22.22.2-linux-s390x", "9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"),
+ "22.22.2-linux_amd64": ("node-v22.22.2-linux-x64.tar.xz", "node-v22.22.2-linux-x64", "88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"),
+ "22.22.2-windows_amd64": ("node-v22.22.2-win-x64.zip", "node-v22.22.2-win-x64", "7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"),
},
- node_version = "22.22.0",
+ node_version = "22.22.2",
)
use_repo(
node,
@@ -110,8 +111,8 @@ use_repo(
pnpm = use_extension("@aspect_rules_js//npm:extensions.bzl", "pnpm")
pnpm.pnpm(
name = "pnpm",
- pnpm_version = "10.29.3",
- pnpm_version_integrity = "sha512-SY4ftMylqgbB3PJhHm+vxQly/+cYmZjECekN50VmREKY/+Q+bNKs3Hdboap8xeCSqLcFTIEbqMV3D4RpPTPS3A==",
+ pnpm_version = "10.33.0",
+ pnpm_version_integrity = "sha512-EFaLtKavtYyes2MNqQzJUWQXq+vT+rvmc58K55VyjaFJHp21pUTHatjrdXD1xLs9bGN7LLQb/c20f6gjyGSTGQ==",
)
use_repo(pnpm, "pnpm")
@@ -155,6 +156,14 @@ npm.npm_translate_lock(
npmrc = "//:.npmrc",
pnpm_lock = "//:pnpm-lock.yaml",
)
+
+# This is needed as by default `.md` files are excluded from the npm package.
+# But @angular/core includes best-practices.md file.
+# See: https://github.com/aspect-build/rules_js/blob/786a74a158dd36ed073188b0e506c423cd05501a/npm/private/exclude_package_contents_presets.bzl#L29
+npm.npm_exclude_package_contents(
+ package = "@angular/core",
+ presets = [],
+)
use_repo(npm, "npm")
rules_ts_ext = use_extension("@aspect_rules_ts//ts:extensions.bzl", "ext")
@@ -180,5 +189,4 @@ register_toolchains(
"@devinfra//bazel/git-toolchain:git_macos_arm64_toolchain",
"@devinfra//bazel/git-toolchain:git_windows_toolchain",
"//tools/toolchains:dummy_cc_windows_no_exec_toolchain",
- "//tools/toolchains:node24_windows_no_exec_toolchain",
)
diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock
index 8af79006afc6..ae7e8f3a44c6 100644
--- a/MODULE.bazel.lock
+++ b/MODULE.bazel.lock
@@ -18,22 +18,15 @@
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.22.5/source.json": "ac2c3213df8f985785f1d0aeb7f0f73d5324e6e67d593d9b9470fb74a25d4a9b",
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.7.7/MODULE.bazel": "491f8681205e31bb57892d67442ce448cda4f472a8e6b3dc062865e29a64f89c",
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.8.1/MODULE.bazel": "812d2dd42f65dca362152101fbec418029cc8fd34cbad1a2fde905383d705838",
- "https://bcr.bazel.build/modules/aspect_bazel_lib/2.9.3/MODULE.bazel": "66baf724dbae7aff4787bf2245cc188d50cb08e07789769730151c0943587c14",
- "https://bcr.bazel.build/modules/aspect_rules_esbuild/0.25.0/MODULE.bazel": "5fef5ec709c837312823f9bcf0f276661e2cb48ad52f17c4e01176bbf1e9bf58",
- "https://bcr.bazel.build/modules/aspect_rules_esbuild/0.25.0/source.json": "5e42968c6d23ab8bd95c02634b16864d866334347827cb6a8425b86c11cc4363",
- "https://bcr.bazel.build/modules/aspect_rules_jasmine/2.0.2/MODULE.bazel": "45f054400ff242c4433f6d7f20f6123a9a72739cb7a1f44247d738db1644f46c",
- "https://bcr.bazel.build/modules/aspect_rules_jasmine/2.0.2/source.json": "3ed399a5654259a822448f9cdbf21f6c738f16ccd7f89249c7507e374cbdd1e3",
+ "https://bcr.bazel.build/modules/aspect_rules_esbuild/0.25.1/MODULE.bazel": "9b931b3e483bd8eedb6966bda6df07d801f70ccb4896231b4e5e711b5130f3aa",
+ "https://bcr.bazel.build/modules/aspect_rules_esbuild/0.25.1/source.json": "a0b72e23ed06113f3878cb635d586b4045ef37750983467af72fe0315c3a2fcd",
+ "https://bcr.bazel.build/modules/aspect_rules_jasmine/2.0.4/MODULE.bazel": "fbb819eb8b7e5d7f67fdd38f7cecb413e287594cd666ce192c72c8828527775a",
+ "https://bcr.bazel.build/modules/aspect_rules_jasmine/2.0.4/source.json": "81ffb708333cd98ec3c0b4cc004f4d5cf92a16914b5196a2892c45141bba7cff",
"https://bcr.bazel.build/modules/aspect_rules_js/2.0.0/MODULE.bazel": "b45b507574aa60a92796e3e13c195cd5744b3b8aff516a9c0cb5ae6a048161c5",
- "https://bcr.bazel.build/modules/aspect_rules_js/2.4.2/MODULE.bazel": "0d01db38b96d25df7ed952a5e96eac4b3802723d146961974bf020f6dd07591d",
- "https://bcr.bazel.build/modules/aspect_rules_js/2.6.2/MODULE.bazel": "ed2a871f4ab8fbde0cab67c425745069d84ea64b64313fa1a2954017326511f5",
- "https://bcr.bazel.build/modules/aspect_rules_js/2.9.2/MODULE.bazel": "93fd5b85e6e912fb0712cbab453c43271d4ea33a093f84fd587638fbc9f8c145",
- "https://bcr.bazel.build/modules/aspect_rules_js/2.9.2/source.json": "4bff7c03ab387b60deb15649ba575688e62f2a71a7544cbc7a660b19ec473808",
- "https://bcr.bazel.build/modules/aspect_rules_ts/3.6.3/MODULE.bazel": "d09db394970f076176ce7bab5b5fa7f0d560fd4f30b8432ea5e2c2570505b130",
- "https://bcr.bazel.build/modules/aspect_rules_ts/3.7.0/MODULE.bazel": "5aace216caf88638950ef061245d23c36f57c8359e56e97f02a36f70bb09c50f",
- "https://bcr.bazel.build/modules/aspect_rules_ts/3.8.3/MODULE.bazel": "a26c28ebcd0c0d50ab0708ac21fa48bd2dced3a4dad4c31a2fa48588b42ad762",
- "https://bcr.bazel.build/modules/aspect_rules_ts/3.8.4/MODULE.bazel": "a50254ac3add6232d0f9f93103836f9afaf614315589a13abf74183982c4101d",
- "https://bcr.bazel.build/modules/aspect_rules_ts/3.8.4/source.json": "f786e0763f3ea5de7ea6d4c4e38fccb48bf4d9c5eafaf95091c0e1590502510e",
- "https://bcr.bazel.build/modules/aspect_tools_telemetry/0.2.3/MODULE.bazel": "20f53b145f40957a51077ae90b37b7ce83582a1daf9350349f0f86179e19dd0d",
+ "https://bcr.bazel.build/modules/aspect_rules_js/3.0.3/MODULE.bazel": "28a30e8fc33bf64a67835d64d124f6e05a7d59648dcb27b110fb3502f761e503",
+ "https://bcr.bazel.build/modules/aspect_rules_js/3.0.3/source.json": "bb8fff9a304452e1042af9522ad1d54d6f1d1fdf71c5127deadb6fd156654193",
+ "https://bcr.bazel.build/modules/aspect_rules_ts/3.8.7/MODULE.bazel": "830f8a53bb9f1139c24006a90ddc0230481326d69fa847eb00daf8eaae118724",
+ "https://bcr.bazel.build/modules/aspect_rules_ts/3.8.7/source.json": "95549d64e28f3e4e3648cc037cefdac01ec3b0f58fced2409c286784e82ad0f0",
"https://bcr.bazel.build/modules/aspect_tools_telemetry/0.2.6/MODULE.bazel": "cafb8781ad591bc57cc765dca5fefab08cf9f65af363d162b79d49205c7f8af7",
"https://bcr.bazel.build/modules/aspect_tools_telemetry/0.2.8/MODULE.bazel": "aa975a83e72bcaac62ee61ab12b788ea324a1d05c4aab28aadb202f647881679",
"https://bcr.bazel.build/modules/aspect_tools_telemetry/0.3.3/MODULE.bazel": "37c764292861c2f70314efa9846bb6dbb44fc0308903b3285da6528305450183",
@@ -49,19 +42,20 @@
"https://bcr.bazel.build/modules/bazel_features/1.30.0/MODULE.bazel": "a14b62d05969a293b80257e72e597c2da7f717e1e69fa8b339703ed6731bec87",
"https://bcr.bazel.build/modules/bazel_features/1.34.0/MODULE.bazel": "e8475ad7c8965542e0c7aac8af68eb48c4af904be3d614b6aa6274c092c2ea1e",
"https://bcr.bazel.build/modules/bazel_features/1.39.0/MODULE.bazel": "28739425c1fc283c91931619749c832b555e60bcd1010b40d8441ce0a5cf726d",
- "https://bcr.bazel.build/modules/bazel_features/1.39.0/source.json": "f63cbeb4c602098484d57001e5a07d31cb02bbccde9b5e2c9bf0b29d05283e93",
"https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7",
+ "https://bcr.bazel.build/modules/bazel_features/1.41.0/MODULE.bazel": "6e0f87fafed801273c371d41e22a15a6f8abf83fdd7f87d5e44ad317b94433d0",
+ "https://bcr.bazel.build/modules/bazel_features/1.41.0/source.json": "8fd525b31b0883c47e0593443cdd10219b94a7556b3195fc02d75c86c66cfe30",
"https://bcr.bazel.build/modules/bazel_features/1.9.0/MODULE.bazel": "885151d58d90d8d9c811eb75e3288c11f850e1d6b481a8c9f766adee4712358b",
"https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a",
- "https://bcr.bazel.build/modules/bazel_lib/3.0.0-beta.1/MODULE.bazel": "407729e232f611c3270005b016b437005daa7b1505826798ea584169a476e878",
+ "https://bcr.bazel.build/modules/bazel_lib/3.0.0-rc.0/MODULE.bazel": "d6e00979a98ac14ada5e31c8794708b41434d461e7e7ca39b59b765e6d233b18",
"https://bcr.bazel.build/modules/bazel_lib/3.0.0/MODULE.bazel": "22b70b80ac89ad3f3772526cd9feee2fa412c2b01933fea7ed13238a448d370d",
- "https://bcr.bazel.build/modules/bazel_lib/3.0.0/source.json": "895f21909c6fba01d7c17914bb6c8e135982275a1b18cdaa4e62272217ef1751",
+ "https://bcr.bazel.build/modules/bazel_lib/3.2.2/MODULE.bazel": "e2c890c8a515d6bca9c66d47718aa9e44b458fde64ec7204b8030bf2d349058c",
+ "https://bcr.bazel.build/modules/bazel_lib/3.2.2/source.json": "9e84e115c20e14652c5c21401ae85ff4daa8702e265b5c0b3bf89353f17aa212",
"https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8",
"https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e",
"https://bcr.bazel.build/modules/bazel_skylib/1.2.0/MODULE.bazel": "44fe84260e454ed94ad326352a698422dbe372b21a1ac9f3eab76eb531223686",
"https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a",
"https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5",
- "https://bcr.bazel.build/modules/bazel_skylib/1.4.0/MODULE.bazel": "2ab127ef8d56a739a99bb2ce00ec4c7d1ecc7977d4370c0ca6efd0d8f03d6d99",
"https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d",
"https://bcr.bazel.build/modules/bazel_skylib/1.4.2/MODULE.bazel": "3bd40978e7a1fac911d5989e6b09d8f64921865a45822d8b09e815eaa726a651",
"https://bcr.bazel.build/modules/bazel_skylib/1.5.0/MODULE.bazel": "32880f5e2945ce6a03d1fbd588e9198c0a959bb42297b2cfaf1685b7bc32e138",
@@ -75,14 +69,17 @@
"https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84",
"https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8",
"https://bcr.bazel.build/modules/gawk/5.3.2.bcr.1/MODULE.bazel": "cdf8cbe5ee750db04b78878c9633cc76e80dcf4416cbe982ac3a9222f80713c8",
- "https://bcr.bazel.build/modules/gawk/5.3.2.bcr.1/source.json": "fa7b512dfcb5eafd90ce3959cf42a2a6fe96144ebbb4b3b3928054895f2afac2",
+ "https://bcr.bazel.build/modules/gawk/5.3.2.bcr.3/MODULE.bazel": "f1b7bb2dd53e8f2ef984b39485ec8a44e9076dda5c4b8efd2fb4c6a6e856a31d",
+ "https://bcr.bazel.build/modules/gawk/5.3.2.bcr.3/source.json": "ebe931bfe362e4b41e59ee00a528db6074157ff2ced92eb9e970acab2e1089c9",
"https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb",
"https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4",
"https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6",
"https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/source.json": "41e9e129f80d8c8bf103a7acc337b76e54fad1214ac0a7084bf24f4cd924b8b4",
"https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f",
"https://bcr.bazel.build/modules/jq.bzl/0.1.0/MODULE.bazel": "2ce69b1af49952cd4121a9c3055faa679e748ce774c7f1fda9657f936cae902f",
- "https://bcr.bazel.build/modules/jq.bzl/0.1.0/source.json": "746bf13cac0860f091df5e4911d0c593971cd8796b5ad4e809b2f8e133eee3d5",
+ "https://bcr.bazel.build/modules/jq.bzl/0.4.0/MODULE.bazel": "a7b39b37589f2b0dad53fd6c1ccaabbdb290330caa920d7ef3e6aad068cd4ab2",
+ "https://bcr.bazel.build/modules/jq.bzl/0.6.1/MODULE.bazel": "f30c46e0a08a9f7566a8bf60a43d48abea960cd7f57b315b01e2762f1537eb52",
+ "https://bcr.bazel.build/modules/jq.bzl/0.6.1/source.json": "9ca9e2f90baa6a5bb0a49626ed9528554ec83165adf47b39792673ecc7feda22",
"https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075",
"https://bcr.bazel.build/modules/jsoncpp/1.9.5/source.json": "4108ee5085dd2885a341c7fab149429db457b3169b86eb081fa245eadf69169d",
"https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902",
@@ -105,6 +102,7 @@
"https://bcr.bazel.build/modules/protobuf/29.0/MODULE.bazel": "319dc8bf4c679ff87e71b1ccfb5a6e90a6dbc4693501d471f48662ac46d04e4e",
"https://bcr.bazel.build/modules/protobuf/29.0/source.json": "b857f93c796750eef95f0d61ee378f3420d00ee1dd38627b27193aa482f4f981",
"https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0",
+ "https://bcr.bazel.build/modules/protobuf/3.19.6/MODULE.bazel": "9233edc5e1f2ee276a60de3eaa47ac4132302ef9643238f23128fea53ea12858",
"https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e",
"https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/source.json": "be4789e951dd5301282729fe3d4938995dc4c1a81c2ff150afc9f1b0504c6022",
"https://bcr.bazel.build/modules/re2/2023-09-01/MODULE.bazel": "cb3d511531b16cfc78a225a9e2136007a48cf8a677e4264baeab57fe78a80206",
@@ -123,7 +121,9 @@
"https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5",
"https://bcr.bazel.build/modules/rules_cc/0.1.1/MODULE.bazel": "2f0222a6f229f0bf44cd711dc13c858dad98c62d52bd51d8fc3a764a83125513",
"https://bcr.bazel.build/modules/rules_cc/0.2.16/MODULE.bazel": "9242fa89f950c6ef7702801ab53922e99c69b02310c39fb6e62b2bd30df2a1d4",
- "https://bcr.bazel.build/modules/rules_cc/0.2.16/source.json": "d03d5cde49376d87e14ec14b666c56075e5e3926930327fd5d0484a1ff2ac1cc",
+ "https://bcr.bazel.build/modules/rules_cc/0.2.17/MODULE.bazel": "1849602c86cb60da8613d2de887f9566a6d354a6df6d7009f9d04a14402f9a84",
+ "https://bcr.bazel.build/modules/rules_cc/0.2.17/source.json": "3832f45d145354049137c0090df04629d9c2b5493dc5c2bf46f1834040133a07",
+ "https://bcr.bazel.build/modules/rules_cc/0.2.4/MODULE.bazel": "1ff1223dfd24f3ecf8f028446d4a27608aa43c3f41e346d22838a4223980b8cc",
"https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6",
"https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8",
"https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/source.json": "c8b1e2c717646f1702290959a3302a178fb639d987ab61d548105019f11e527e",
@@ -157,10 +157,7 @@
"https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": "a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c",
"https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": "a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb",
"https://bcr.bazel.build/modules/rules_nodejs/6.2.0/MODULE.bazel": "ec27907f55eb34705adb4e8257952162a2d4c3ed0f0b3b4c3c1aad1fac7be35e",
- "https://bcr.bazel.build/modules/rules_nodejs/6.3.0/MODULE.bazel": "45345e4aba35dd6e4701c1eebf5a4e67af4ed708def9ebcdc6027585b34ee52d",
- "https://bcr.bazel.build/modules/rules_nodejs/6.3.3/MODULE.bazel": "b66eadebd10f1f1b25f52f95ab5213a57e82c37c3f656fcd9a57ad04d2264ce7",
"https://bcr.bazel.build/modules/rules_nodejs/6.5.0/MODULE.bazel": "546d0cf79f36f9f6e080816045f97234b071c205f4542e3351bd4424282a8810",
- "https://bcr.bazel.build/modules/rules_nodejs/6.5.2/MODULE.bazel": "7f9ea68a0ce6d82905ce9f74e76ab8a8b4531ed4c747018c9d76424ad0b3370d",
"https://bcr.bazel.build/modules/rules_nodejs/6.7.3/MODULE.bazel": "c22a48b2a0dbf05a9dc5f83837bbc24c226c1f6e618de3c3a610044c9f336056",
"https://bcr.bazel.build/modules/rules_nodejs/6.7.3/source.json": "a3f966f4415a8a6545e560ee5449eac95cc633f96429d08e87c87775c72f5e09",
"https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc",
@@ -196,15 +193,16 @@
"https://bcr.bazel.build/modules/stardoc/0.7.2/source.json": "58b029e5e901d6802967754adf0a9056747e8176f017cfe3607c0851f4d42216",
"https://bcr.bazel.build/modules/tar.bzl/0.2.1/MODULE.bazel": "52d1c00a80a8cc67acbd01649e83d8dd6a9dc426a6c0b754a04fe8c219c76468",
"https://bcr.bazel.build/modules/tar.bzl/0.5.1/MODULE.bazel": "7c2eb3dcfc53b0f3d6f9acdfd911ca803eaf92aadf54f8ca6e4c1f3aee288351",
- "https://bcr.bazel.build/modules/tar.bzl/0.8.1/MODULE.bazel": "6ffe8907ed4c555bc94bd35a5a01411cc4470c6dace84f9cf487815409e077d1",
- "https://bcr.bazel.build/modules/tar.bzl/0.8.1/source.json": "835f83b482facf6205ad8708cf2b2f6524d1d7b1075a90fe9bb540da761d6d2e",
+ "https://bcr.bazel.build/modules/tar.bzl/0.6.0/MODULE.bazel": "a3584b4edcfafcabd9b0ef9819808f05b372957bbdff41601429d5fd0aac2e7c",
+ "https://bcr.bazel.build/modules/tar.bzl/0.9.0/MODULE.bazel": "452a22d7f02b1c9d7a22ab25edf20f46f3e1101f0f67dc4bfbf9a474ddf02445",
+ "https://bcr.bazel.build/modules/tar.bzl/0.9.0/source.json": "c732760a374831a2cf5b08839e4be75017196b4d796a5aa55235272ee17cd839",
"https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43",
"https://bcr.bazel.build/modules/yq.bzl/0.1.1/MODULE.bazel": "9039681f9bcb8958ee2c87ffc74bdafba9f4369096a2b5634b88abc0eaefa072",
- "https://bcr.bazel.build/modules/yq.bzl/0.2.0/MODULE.bazel": "6f3a675677db8885be4d607fde14cc51829715e3a879fb016eb9bf336786ce6d",
"https://bcr.bazel.build/modules/yq.bzl/0.3.2/MODULE.bazel": "0384efa70e8033d842ea73aa4b7199fa099709e236a7264345c03937166670b6",
- "https://bcr.bazel.build/modules/yq.bzl/0.3.4/MODULE.bazel": "d3a270662f5d766cd7229732d65a5a5bc485240c3007343dd279edfb60c9ae27",
- "https://bcr.bazel.build/modules/yq.bzl/0.3.4/source.json": "786dafdc2843722da3416e4343ee1a05237227f068590779a6e8496a2064c0f9",
+ "https://bcr.bazel.build/modules/yq.bzl/0.3.5/MODULE.bazel": "130c603e54be717bdf84100210f06598a0d2b4b4e01888fb01b70f50f41767ec",
+ "https://bcr.bazel.build/modules/yq.bzl/0.3.5/source.json": "1ae7bdc03cb26aaa8bd2bceadf65e90d90f0b2d03008ba9a0564da2e21396c39",
"https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0",
+ "https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27",
"https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca",
"https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/source.json": "22bc55c47af97246cfc093d0acf683a7869377de362b5d1c552c2c2e16b7a806",
"https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198"
@@ -213,8 +211,8 @@
"moduleExtensions": {
"@@aspect_rules_esbuild+//esbuild:extensions.bzl%esbuild": {
"general": {
- "bzlTransitiveDigest": "c4i5gawrp4Au9UMb55EzQCePYwkrFqD9tFBN7GdHG5g=",
- "usagesDigest": "ToTaCONCN/E05krnHXLM1kpV1zrHNxHrGpUip973II4=",
+ "bzlTransitiveDigest": "GnYkDpVOnWnYv+xwyhEi0qjk3Lvp4Wei30PeSIQF5vM=",
+ "usagesDigest": "6We6zwGoawD9YXqMI0KPaxEKJTnamXBsuOekhFS2D40=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
"envVariables": {},
@@ -269,11 +267,11 @@
"npm__esbuild_0.19.9": {
"repoRuleId": "@@aspect_rules_js+//npm/private:npm_import.bzl%npm_import_rule",
"attributes": {
+ "key": "npm__esbuild_0.19.9",
"package": "esbuild",
"version": "0.19.9",
"root_package": "",
"link_workspace": "",
- "link_packages": {},
"integrity": "sha512-U9CHtKSy+EpPsEBa+/A2gMs/h3ylBC0H0KSqIg7tpztHerLi6nrrcoUJAkNCEPumx8yJ+Byic4BVwHgRbN0TBg==",
"url": "",
"commit": "",
@@ -288,20 +286,23 @@
"npm_auth_password": "",
"lifecycle_hooks": [],
"extra_build_content": "",
+ "generate_package_json_bzl": false,
"generate_bzl_library_targets": false,
"extract_full_archive": false,
- "exclude_package_contents": []
+ "exclude_package_contents": [],
+ "exclude_package_contents_presets": []
}
},
"npm__esbuild_0.19.9__links": {
- "repoRuleId": "@@aspect_rules_js+//npm/private:npm_import.bzl%npm_import_links",
+ "repoRuleId": "@@aspect_rules_js+//npm/private:npm_import.bzl%npm_import_links_rule",
"attributes": {
+ "key": "npm__esbuild_0.19.9",
"package": "esbuild",
"version": "0.19.9",
- "dev": false,
"root_package": "",
- "link_packages": {},
"deps": {},
+ "deps_oss": {},
+ "deps_cpus": {},
"transitive_closure": {},
"lifecycle_build_target": false,
"lifecycle_hooks_env": [],
@@ -314,31 +315,12 @@
"//visibility:public"
],
"replace_package": "",
- "exclude_package_contents": []
+ "exclude_package_contents": [],
+ "exclude_package_contents_presets": []
}
}
},
"recordedRepoMappingEntries": [
- [
- "aspect_bazel_lib+",
- "bazel_lib",
- "bazel_lib+"
- ],
- [
- "aspect_bazel_lib+",
- "bazel_skylib",
- "bazel_skylib+"
- ],
- [
- "aspect_bazel_lib+",
- "bazel_tools",
- "bazel_tools"
- ],
- [
- "aspect_bazel_lib+",
- "tar.bzl",
- "tar.bzl+"
- ],
[
"aspect_rules_esbuild+",
"aspect_rules_js",
@@ -354,11 +336,6 @@
"bazel_skylib",
"bazel_skylib+"
],
- [
- "aspect_rules_js+",
- "aspect_bazel_lib",
- "aspect_bazel_lib+"
- ],
[
"aspect_rules_js+",
"aspect_rules_js",
@@ -371,162 +348,33 @@
],
[
"aspect_rules_js+",
- "bazel_lib",
- "bazel_lib+"
- ],
- [
- "aspect_rules_js+",
- "bazel_skylib",
- "bazel_skylib+"
+ "bazel_features",
+ "bazel_features+"
],
[
"aspect_rules_js+",
- "bazel_tools",
- "bazel_tools"
- ],
- [
- "bazel_lib+",
- "bazel_skylib",
- "bazel_skylib+"
- ],
- [
- "bazel_lib+",
- "bazel_tools",
- "bazel_tools"
- ],
- [
- "tar.bzl+",
"bazel_lib",
"bazel_lib+"
],
[
- "tar.bzl+",
- "bazel_skylib",
- "bazel_skylib+"
- ],
- [
- "tar.bzl+",
- "tar.bzl",
- "tar.bzl+"
- ]
- ]
- }
- },
- "@@aspect_rules_js+//npm:extensions.bzl%pnpm": {
- "general": {
- "bzlTransitiveDigest": "HC+l+mTivq1p/KbcVQ+iV5QwYR+oKESJh827FY68SH8=",
- "usagesDigest": "PvqSdyUvIknVzZ66q+9FjDqiPWbKoaSj5J3EB+Z3ZAs=",
- "recordedFileInputs": {},
- "recordedDirentsInputs": {},
- "envVariables": {},
- "generatedRepoSpecs": {
- "pnpm": {
- "repoRuleId": "@@aspect_rules_js+//npm/private:npm_import.bzl%npm_import_rule",
- "attributes": {
- "package": "pnpm",
- "version": "10.29.3",
- "root_package": "",
- "link_workspace": "",
- "link_packages": {},
- "integrity": "sha512-SY4ftMylqgbB3PJhHm+vxQly/+cYmZjECekN50VmREKY/+Q+bNKs3Hdboap8xeCSqLcFTIEbqMV3D4RpPTPS3A==",
- "url": "",
- "commit": "",
- "patch_args": [
- "-p0"
- ],
- "patches": [],
- "custom_postinstall": "",
- "npm_auth": "",
- "npm_auth_basic": "",
- "npm_auth_username": "",
- "npm_auth_password": "",
- "lifecycle_hooks": [],
- "extra_build_content": "load(\"@aspect_rules_js//js:defs.bzl\", \"js_binary\")\njs_binary(name = \"pnpm\", data = glob([\"package/**\"]), entry_point = \"package/dist/pnpm.cjs\", visibility = [\"//visibility:public\"])",
- "generate_bzl_library_targets": false,
- "extract_full_archive": true,
- "exclude_package_contents": []
- }
- },
- "pnpm__links": {
- "repoRuleId": "@@aspect_rules_js+//npm/private:npm_import.bzl%npm_import_links",
- "attributes": {
- "package": "pnpm",
- "version": "10.29.3",
- "dev": false,
- "root_package": "",
- "link_packages": {},
- "deps": {},
- "transitive_closure": {},
- "lifecycle_build_target": false,
- "lifecycle_hooks_env": [],
- "lifecycle_hooks_execution_requirements": [
- "no-sandbox"
- ],
- "lifecycle_hooks_use_default_shell_env": false,
- "bins": {},
- "package_visibility": [
- "//visibility:public"
- ],
- "replace_package": "",
- "exclude_package_contents": []
- }
- }
- },
- "recordedRepoMappingEntries": [
- [
- "aspect_bazel_lib+",
- "bazel_lib",
- "bazel_lib+"
- ],
- [
- "aspect_bazel_lib+",
+ "aspect_rules_js+",
"bazel_skylib",
"bazel_skylib+"
],
[
- "aspect_bazel_lib+",
+ "aspect_rules_js+",
"bazel_tools",
"bazel_tools"
],
- [
- "aspect_bazel_lib+",
- "tar.bzl",
- "tar.bzl+"
- ],
[
"aspect_rules_js+",
- "aspect_bazel_lib",
- "aspect_bazel_lib+"
+ "protobuf",
+ "protobuf+"
],
[
"aspect_rules_js+",
- "aspect_rules_js",
- "aspect_rules_js+"
- ],
- [
- "aspect_rules_js+",
- "aspect_tools_telemetry_report",
- "aspect_tools_telemetry++telemetry+aspect_tools_telemetry_report"
- ],
- [
- "aspect_rules_js+",
- "bazel_features",
- "bazel_features+"
- ],
- [
- "aspect_rules_js+",
- "bazel_lib",
- "bazel_lib+"
- ],
- [
- "aspect_rules_js+",
- "bazel_skylib",
- "bazel_skylib+"
- ],
- [
- "aspect_rules_js+",
- "bazel_tools",
- "bazel_tools"
+ "tar.bzl",
+ "tar.bzl+"
],
[
"bazel_features+",
@@ -538,6 +386,11 @@
"bazel_features_version",
"bazel_features++version_extension+bazel_features_version"
],
+ [
+ "bazel_lib+",
+ "bazel_lib",
+ "bazel_lib+"
+ ],
[
"bazel_lib+",
"bazel_skylib",
@@ -548,6 +401,11 @@
"bazel_tools",
"bazel_tools"
],
+ [
+ "protobuf+",
+ "proto_bazel_features",
+ "bazel_features+"
+ ],
[
"tar.bzl+",
"bazel_lib",
@@ -568,11 +426,9 @@
},
"@@aspect_rules_ts+//ts:extensions.bzl%ext": {
"general": {
- "bzlTransitiveDigest": "QDTi1Wl/eEY4IgbXjRhegUQfHj+bB8ZEVyiSGLZc6qo=",
- "usagesDigest": "aaqqxEFKCRGFkeAf0pKmXvZZTLGYIk3pQsDFG28ZbNg=",
- "recordedFileInputs": {
- "@@rules_browsers+//package.json": "84dc1ba9b1c667a25894e97218bd8f247d54f24bb694efb397a881be3c06a4c5"
- },
+ "bzlTransitiveDigest": "GbfZLeEI0W26fAQ89dUljyLGSAkzkr3CkF+VDQ0IFlI=",
+ "usagesDigest": "6j6Q6JXHp4faBWfj1+kQVqEjMSZnJZwfbQoEdHVj1ks=",
+ "recordedFileInputs": {},
"recordedDirentsInputs": {},
"envVariables": {},
"generatedRepoSpecs": {
@@ -589,8 +445,8 @@
"rules_angular_npm_typescript": {
"repoRuleId": "@@aspect_rules_ts+//ts/private:npm_repositories.bzl%http_archive_version",
"attributes": {
- "version": "5.9.2",
- "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
+ "version": "5.9.3",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"urls": [
"https://registry.npmjs.org/typescript/-/typescript-{}.tgz"
]
@@ -609,9 +465,8 @@
"npm_rules_browsers_typescript": {
"repoRuleId": "@@aspect_rules_ts+//ts/private:npm_repositories.bzl%http_archive_version",
"attributes": {
- "version": "",
- "version_from": "@@rules_browsers+//:package.json",
- "integrity": "",
+ "version": "5.9.3",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"urls": [
"https://registry.npmjs.org/typescript/-/typescript-{}.tgz"
]
@@ -635,7 +490,7 @@
"@@aspect_tools_telemetry+//:extension.bzl%telemetry": {
"general": {
"bzlTransitiveDigest": "cl5A2O84vDL6Tt+Qga8FCj1DUDGqn+e7ly5rZ+4xvcc=",
- "usagesDigest": "PRLGsERE1Dznyx/OIAl7BPo8mzMvOklnNnZ8zdCpPTE=",
+ "usagesDigest": "Htk4MyL4d05V7Kpv8OWMQ8y+7IkUx9BOmnhlLXYMO80=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
"envVariables": {},
@@ -644,10 +499,10 @@
"repoRuleId": "@@aspect_tools_telemetry+//:extension.bzl%tel_repository",
"attributes": {
"deps": {
- "aspect_rules_js": "2.9.2",
- "aspect_rules_ts": "3.8.4",
- "aspect_rules_esbuild": "0.25.0",
- "aspect_rules_jasmine": "2.0.2",
+ "aspect_rules_js": "3.0.3",
+ "aspect_rules_ts": "3.8.7",
+ "aspect_rules_esbuild": "0.25.1",
+ "aspect_rules_jasmine": "2.0.4",
"aspect_tools_telemetry": "0.3.3"
}
}
@@ -669,7 +524,7 @@
},
"@@pybind11_bazel+//:python_configure.bzl%extension": {
"general": {
- "bzlTransitiveDigest": "c9ZWWeXeu6bctL4/SsY2otFWyeFN0JJ20+ymGyJZtWk=",
+ "bzlTransitiveDigest": "D2/qWHU6yQFwRG7Bb+caqrYMha5avsASao2vERrxK24=",
"usagesDigest": "fycyB39YnXIJkfWCIXLUKJMZzANcuLy9ZE73hRucjFk=",
"recordedFileInputs": {
"@@pybind11_bazel+//MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e"
@@ -704,7 +559,7 @@
"@@rules_angular+//setup:extensions.bzl%rules_angular": {
"general": {
"bzlTransitiveDigest": "fkaH7HMicL3g7/NDaFzlq39kcLopMyQ3KdbDn+5CRzA=",
- "usagesDigest": "ZinuLP7QHxaW5achD0Vz19qElMu4r2LvGvh96Z5zYlA=",
+ "usagesDigest": "it5nR/3UaQWj2eaaMj+EnoZuL2z/AeTuz7uOnqd+nxo=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
"envVariables": {},
@@ -720,7 +575,7 @@
"repoRuleId": "@@rules_angular+//setup:repositories.bzl%configurable_deps_repo",
"attributes": {
"angular_compiler_cli": "@@rules_angular+//:node_modules/@angular/compiler-cli",
- "typescript": "@@rules_angular+//:node_modules/typescript-local"
+ "typescript": "@@rules_angular+//:node_modules/typescript"
}
},
"dev_infra_rules_angular_configurable_deps": {
@@ -736,8 +591,8 @@
},
"@@rules_browsers+//browsers:extensions.bzl%browsers": {
"general": {
- "bzlTransitiveDigest": "agkaLQ8wE1r/5IX6pkERzFxI/z0M42Em+ICNO6TXsVo=",
- "usagesDigest": "FS7q5WaIwg3KirS3njhuPFkTIBYvDaTInVGrlzu0XL8=",
+ "bzlTransitiveDigest": "Bm6fiKpWy96aLohOlLCP36ARVxRLZm/R+smhsb2HzmI=",
+ "usagesDigest": "FmXYJVoVJlnfUU8x8gObSvu4qWcco/9Faw61aC/wBF0=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
"envVariables": {},
@@ -745,9 +600,9 @@
"rules_browsers_chrome_linux": {
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
"attributes": {
- "sha256": "0a2ff0fc9eb5958b7b420f20e3968f424be7423fef89739e71565a48aa073a57",
+ "sha256": "1ac33f89306327af43be159c03ca4a26486de0858f42fe52394acdef50364143",
"urls": [
- "https://storage.googleapis.com/chrome-for-testing-public/145.0.7586.0/linux64/chrome-headless-shell-linux64.zip"
+ "https://storage.googleapis.com/chrome-for-testing-public/147.0.7687.0/linux64/chrome-headless-shell-linux64.zip"
],
"named_files": {
"CHROME-HEADLESS-SHELL": "chrome-headless-shell-linux64/chrome-headless-shell"
@@ -763,9 +618,9 @@
"rules_browsers_chrome_mac": {
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
"attributes": {
- "sha256": "e6076b1201d86f74c5eab982a239d5af83e66b1aa4d780bcb792698790e01d87",
+ "sha256": "169ff49c465cfda52931395e61861e146dfc5013e92c01ca792db5acea858d0b",
"urls": [
- "https://storage.googleapis.com/chrome-for-testing-public/145.0.7586.0/mac-x64/chrome-headless-shell-mac-x64.zip"
+ "https://storage.googleapis.com/chrome-for-testing-public/147.0.7687.0/mac-x64/chrome-headless-shell-mac-x64.zip"
],
"named_files": {
"CHROME-HEADLESS-SHELL": "chrome-headless-shell-mac-x64/chrome-headless-shell"
@@ -781,9 +636,9 @@
"rules_browsers_chrome_mac_arm": {
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
"attributes": {
- "sha256": "b74dbcf5543d916b02d0a133e2e7c6a4de251f06733f72c2c15ea8c42213f63b",
+ "sha256": "aeaaaaa4d68193a21bed04c44ddeb1230232707b4ea1d845a92925787509cd8e",
"urls": [
- "https://storage.googleapis.com/chrome-for-testing-public/145.0.7586.0/mac-arm64/chrome-headless-shell-mac-arm64.zip"
+ "https://storage.googleapis.com/chrome-for-testing-public/147.0.7687.0/mac-arm64/chrome-headless-shell-mac-arm64.zip"
],
"named_files": {
"CHROME-HEADLESS-SHELL": "chrome-headless-shell-mac-arm64/chrome-headless-shell"
@@ -799,9 +654,9 @@
"rules_browsers_chrome_win64": {
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
"attributes": {
- "sha256": "df1e612dc3b1615e182a1f11821052995913c39df37caa52699de21a68d030d2",
+ "sha256": "4d6d79bcbcb22084df6e3a3d3a2caff67d6c0fa488d63f0c7ec1526f9553db8c",
"urls": [
- "https://storage.googleapis.com/chrome-for-testing-public/145.0.7586.0/win64/chrome-headless-shell-win64.zip"
+ "https://storage.googleapis.com/chrome-for-testing-public/147.0.7687.0/win64/chrome-headless-shell-win64.zip"
],
"named_files": {
"CHROME-HEADLESS-SHELL": "chrome-headless-shell-win64/chrome-headless-shell.exe"
@@ -817,9 +672,9 @@
"rules_browsers_chromedriver_linux": {
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
"attributes": {
- "sha256": "69c504306399d979a2766fea603c3fb9d3d87d46c75bddc9f2a049b4f636d57c",
+ "sha256": "0607ccf6810a07ae08cac6443beac8b23f88dd53c7f1e0299e22d65f7cd2d020",
"urls": [
- "https://storage.googleapis.com/chrome-for-testing-public/145.0.7586.0/linux64/chromedriver-linux64.zip"
+ "https://storage.googleapis.com/chrome-for-testing-public/147.0.7687.0/linux64/chromedriver-linux64.zip"
],
"named_files": {
"CHROMEDRIVER": "chromedriver-linux64/chromedriver"
@@ -833,9 +688,9 @@
"rules_browsers_chromedriver_mac": {
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
"attributes": {
- "sha256": "5fc9d6f594fc5f2568a15145f25116dd8e9c9a60baa8da4bb21a17650fb00e7e",
+ "sha256": "0f512a9dd683ed4c41e609d8d02c07807497dbad3ab2f95f0d583486be7b8cff",
"urls": [
- "https://storage.googleapis.com/chrome-for-testing-public/145.0.7586.0/mac-x64/chromedriver-mac-x64.zip"
+ "https://storage.googleapis.com/chrome-for-testing-public/147.0.7687.0/mac-x64/chromedriver-mac-x64.zip"
],
"named_files": {
"CHROMEDRIVER": "chromedriver-mac-x64/chromedriver"
@@ -849,9 +704,9 @@
"rules_browsers_chromedriver_mac_arm": {
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
"attributes": {
- "sha256": "14e92294c2c3639ca4e7d27e850588b619d698e2f8905cee368f07db2e1bf1e9",
+ "sha256": "7d6fc6d17de1733eb6739d1ea16d085c8df1568bcf9fa0d130c2784b27f38268",
"urls": [
- "https://storage.googleapis.com/chrome-for-testing-public/145.0.7586.0/mac-arm64/chromedriver-mac-arm64.zip"
+ "https://storage.googleapis.com/chrome-for-testing-public/147.0.7687.0/mac-arm64/chromedriver-mac-arm64.zip"
],
"named_files": {
"CHROMEDRIVER": "chromedriver-mac-arm64/chromedriver"
@@ -865,9 +720,9 @@
"rules_browsers_chromedriver_win64": {
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
"attributes": {
- "sha256": "cf641d2e176db95bcc158cd90eafd347ad4928fa0458a5f3bfd56c6d983e70db",
+ "sha256": "f4e9fb7bbf692fde7979b24e8d737b3cef4baafbc7a370e5d0abc4a8450fd830",
"urls": [
- "https://storage.googleapis.com/chrome-for-testing-public/145.0.7586.0/win64/chromedriver-win64.zip"
+ "https://storage.googleapis.com/chrome-for-testing-public/147.0.7687.0/win64/chromedriver-win64.zip"
],
"named_files": {
"CHROMEDRIVER": "chromedriver-win64/chromedriver.exe"
@@ -881,9 +736,9 @@
"rules_browsers_firefox_linux": {
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
"attributes": {
- "sha256": "8d56f479cc398a537a60a3fa20dca92d8a41925113d3a67f534881a4e4d7e344",
+ "sha256": "f055b9c0d7346a10d22edc7f10e08679af2ea495367381ab2be9cab3ec6add97",
"urls": [
- "https://archive.mozilla.org/pub/firefox/releases/146.0/linux-x86_64/en-US/firefox-146.0.tar.xz"
+ "https://archive.mozilla.org/pub/firefox/releases/147.0/linux-x86_64/en-US/firefox-147.0.tar.xz"
],
"named_files": {
"FIREFOX": "firefox/firefox"
@@ -897,9 +752,9 @@
"rules_browsers_firefox_mac": {
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
"attributes": {
- "sha256": "4b1645313887972d466cd82166ea571485c2c40a167f84624e3f3ca739993cc9",
+ "sha256": "48485e2068bc726e2f30cf5855fc2da1fc75c1272bc243a5394f428ffae3ba35",
"urls": [
- "https://archive.mozilla.org/pub/firefox/releases/146.0/mac/en-US/Firefox%20146.0.dmg"
+ "https://archive.mozilla.org/pub/firefox/releases/147.0/mac/en-US/Firefox%20147.0.dmg"
],
"named_files": {
"FIREFOX": "Firefox.app/Contents/MacOS/firefox"
@@ -913,9 +768,9 @@
"rules_browsers_firefox_mac_arm": {
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
"attributes": {
- "sha256": "4b1645313887972d466cd82166ea571485c2c40a167f84624e3f3ca739993cc9",
+ "sha256": "48485e2068bc726e2f30cf5855fc2da1fc75c1272bc243a5394f428ffae3ba35",
"urls": [
- "https://archive.mozilla.org/pub/firefox/releases/146.0/mac/en-US/Firefox%20146.0.dmg"
+ "https://archive.mozilla.org/pub/firefox/releases/147.0/mac/en-US/Firefox%20147.0.dmg"
],
"named_files": {
"FIREFOX": "Firefox.app/Contents/MacOS/firefox"
@@ -929,9 +784,9 @@
"rules_browsers_firefox_win64": {
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
"attributes": {
- "sha256": "216870c89648f32450cfefb5cec417fcd66d480d5dc83f894bf99f5fd7f38dbb",
+ "sha256": "36ff9e150875aa48a0af9eec3eb67f66dddd8efac5c743265371a72ae3e796c4",
"urls": [
- "https://archive.mozilla.org/pub/firefox/releases/146.0/win64/en-US/Firefox%20Setup%20146.0.exe"
+ "https://archive.mozilla.org/pub/firefox/releases/147.0/win64/en-US/Firefox%20Setup%20147.0.exe"
],
"named_files": {
"FIREFOX": "core/firefox.exe"
@@ -948,7 +803,7 @@
},
"@@rules_fuzzing+//fuzzing/private:extensions.bzl%non_module_dependencies": {
"general": {
- "bzlTransitiveDigest": "WHRlQQnxW7e7XMRBhq7SARkDarLDOAbg6iLaJpk5QYM=",
+ "bzlTransitiveDigest": "4LouzhF/yT117s7peGnNs9ROomiJXC6Zl5R0oI21jho=",
"usagesDigest": "wy6ISK6UOcBEjj/mvJ/S3WeXoO67X+1llb9yPyFtPgc=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
@@ -1031,7 +886,7 @@
},
"@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": {
"general": {
- "bzlTransitiveDigest": "rL/34P1aFDq2GqVC2zCFgQ8nTuOC6ziogocpvG50Qz8=",
+ "bzlTransitiveDigest": "nvW/NrBXlAmiQw99EMGKkLaD2KbNp2mQDlxdfpr+0Ls=",
"usagesDigest": "QI2z8ZUR+mqtbwsf2fLqYdJAkPOHdOV+tF2yVAUgRzw=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
@@ -1096,7 +951,7 @@
"@@rules_nodejs+//nodejs:extensions.bzl%node": {
"general": {
"bzlTransitiveDigest": "4pUxCNc22K4I+6+4Nxu52Hur12tFRfa1JMsN5mdDv60=",
- "usagesDigest": "6UAmdIABVpqhlkQ3A3NGscf00ds9dFEt+lei3DibyqM=",
+ "usagesDigest": "sQiW0V9N31hjPrg9r9iPXH5IdB4YKwYtLhn7G+osx1o=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
"envVariables": {},
@@ -1106,46 +961,46 @@
"attributes": {
"node_download_auth": {},
"node_repositories": {
- "22.22.0-darwin_arm64": [
- "node-v22.22.0-darwin-arm64.tar.gz",
- "node-v22.22.0-darwin-arm64",
- "5ed4db0fcf1eaf84d91ad12462631d73bf4576c1377e192d222e48026a902640"
+ "22.22.2-darwin_arm64": [
+ "node-v22.22.2-darwin-arm64.tar.gz",
+ "node-v22.22.2-darwin-arm64",
+ "db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
],
- "22.22.0-darwin_amd64": [
- "node-v22.22.0-darwin-x64.tar.gz",
- "node-v22.22.0-darwin-x64",
- "5ea50c9d6dea3dfa3abb66b2656f7a4e1c8cef23432b558d45fb538c7b5dedce"
+ "22.22.2-darwin_amd64": [
+ "node-v22.22.2-darwin-x64.tar.gz",
+ "node-v22.22.2-darwin-x64",
+ "12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
],
- "22.22.0-linux_arm64": [
- "node-v22.22.0-linux-arm64.tar.xz",
- "node-v22.22.0-linux-arm64",
- "1bf1eb9ee63ffc4e5d324c0b9b62cf4a289f44332dfef9607cea1a0d9596ba6f"
+ "22.22.2-linux_arm64": [
+ "node-v22.22.2-linux-arm64.tar.xz",
+ "node-v22.22.2-linux-arm64",
+ "e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
],
- "22.22.0-linux_ppc64le": [
- "node-v22.22.0-linux-ppc64le.tar.xz",
- "node-v22.22.0-linux-ppc64le",
- "d83b9957431cc18e1fc143a4b99f89cde7b8a18f53ef392231b4336afd058865"
+ "22.22.2-linux_ppc64le": [
+ "node-v22.22.2-linux-ppc64le.tar.xz",
+ "node-v22.22.2-linux-ppc64le",
+ "14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
],
- "22.22.0-linux_s390x": [
- "node-v22.22.0-linux-s390x.tar.xz",
- "node-v22.22.0-linux-s390x",
- "5aa0e520689448c4233e8d73f284e8e0634fdcd32b479735698494be5641f3e4"
+ "22.22.2-linux_s390x": [
+ "node-v22.22.2-linux-s390x.tar.xz",
+ "node-v22.22.2-linux-s390x",
+ "9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
],
- "22.22.0-linux_amd64": [
- "node-v22.22.0-linux-x64.tar.xz",
- "node-v22.22.0-linux-x64",
- "9aa8e9d2298ab68c600bd6fb86a6c13bce11a4eca1ba9b39d79fa021755d7c37"
+ "22.22.2-linux_amd64": [
+ "node-v22.22.2-linux-x64.tar.xz",
+ "node-v22.22.2-linux-x64",
+ "88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
],
- "22.22.0-windows_amd64": [
- "node-v22.22.0-win-x64.zip",
- "node-v22.22.0-win-x64",
- "c97fa376d2becdc8863fcd3ca2dd9a83a9f3468ee7ccf7a6d076ec66a645c77a"
+ "22.22.2-windows_amd64": [
+ "node-v22.22.2-win-x64.zip",
+ "node-v22.22.2-win-x64",
+ "7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
]
},
"node_urls": [
"https://nodejs.org/dist/v{version}/{filename}"
],
- "node_version": "22.22.0",
+ "node_version": "22.22.2",
"include_headers": false,
"platform": "linux_amd64"
}
@@ -1155,46 +1010,46 @@
"attributes": {
"node_download_auth": {},
"node_repositories": {
- "22.22.0-darwin_arm64": [
- "node-v22.22.0-darwin-arm64.tar.gz",
- "node-v22.22.0-darwin-arm64",
- "5ed4db0fcf1eaf84d91ad12462631d73bf4576c1377e192d222e48026a902640"
+ "22.22.2-darwin_arm64": [
+ "node-v22.22.2-darwin-arm64.tar.gz",
+ "node-v22.22.2-darwin-arm64",
+ "db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
],
- "22.22.0-darwin_amd64": [
- "node-v22.22.0-darwin-x64.tar.gz",
- "node-v22.22.0-darwin-x64",
- "5ea50c9d6dea3dfa3abb66b2656f7a4e1c8cef23432b558d45fb538c7b5dedce"
+ "22.22.2-darwin_amd64": [
+ "node-v22.22.2-darwin-x64.tar.gz",
+ "node-v22.22.2-darwin-x64",
+ "12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
],
- "22.22.0-linux_arm64": [
- "node-v22.22.0-linux-arm64.tar.xz",
- "node-v22.22.0-linux-arm64",
- "1bf1eb9ee63ffc4e5d324c0b9b62cf4a289f44332dfef9607cea1a0d9596ba6f"
+ "22.22.2-linux_arm64": [
+ "node-v22.22.2-linux-arm64.tar.xz",
+ "node-v22.22.2-linux-arm64",
+ "e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
],
- "22.22.0-linux_ppc64le": [
- "node-v22.22.0-linux-ppc64le.tar.xz",
- "node-v22.22.0-linux-ppc64le",
- "d83b9957431cc18e1fc143a4b99f89cde7b8a18f53ef392231b4336afd058865"
+ "22.22.2-linux_ppc64le": [
+ "node-v22.22.2-linux-ppc64le.tar.xz",
+ "node-v22.22.2-linux-ppc64le",
+ "14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
],
- "22.22.0-linux_s390x": [
- "node-v22.22.0-linux-s390x.tar.xz",
- "node-v22.22.0-linux-s390x",
- "5aa0e520689448c4233e8d73f284e8e0634fdcd32b479735698494be5641f3e4"
+ "22.22.2-linux_s390x": [
+ "node-v22.22.2-linux-s390x.tar.xz",
+ "node-v22.22.2-linux-s390x",
+ "9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
],
- "22.22.0-linux_amd64": [
- "node-v22.22.0-linux-x64.tar.xz",
- "node-v22.22.0-linux-x64",
- "9aa8e9d2298ab68c600bd6fb86a6c13bce11a4eca1ba9b39d79fa021755d7c37"
+ "22.22.2-linux_amd64": [
+ "node-v22.22.2-linux-x64.tar.xz",
+ "node-v22.22.2-linux-x64",
+ "88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
],
- "22.22.0-windows_amd64": [
- "node-v22.22.0-win-x64.zip",
- "node-v22.22.0-win-x64",
- "c97fa376d2becdc8863fcd3ca2dd9a83a9f3468ee7ccf7a6d076ec66a645c77a"
+ "22.22.2-windows_amd64": [
+ "node-v22.22.2-win-x64.zip",
+ "node-v22.22.2-win-x64",
+ "7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
]
},
"node_urls": [
"https://nodejs.org/dist/v{version}/{filename}"
],
- "node_version": "22.22.0",
+ "node_version": "22.22.2",
"include_headers": false,
"platform": "linux_arm64"
}
@@ -1204,46 +1059,46 @@
"attributes": {
"node_download_auth": {},
"node_repositories": {
- "22.22.0-darwin_arm64": [
- "node-v22.22.0-darwin-arm64.tar.gz",
- "node-v22.22.0-darwin-arm64",
- "5ed4db0fcf1eaf84d91ad12462631d73bf4576c1377e192d222e48026a902640"
+ "22.22.2-darwin_arm64": [
+ "node-v22.22.2-darwin-arm64.tar.gz",
+ "node-v22.22.2-darwin-arm64",
+ "db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
],
- "22.22.0-darwin_amd64": [
- "node-v22.22.0-darwin-x64.tar.gz",
- "node-v22.22.0-darwin-x64",
- "5ea50c9d6dea3dfa3abb66b2656f7a4e1c8cef23432b558d45fb538c7b5dedce"
+ "22.22.2-darwin_amd64": [
+ "node-v22.22.2-darwin-x64.tar.gz",
+ "node-v22.22.2-darwin-x64",
+ "12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
],
- "22.22.0-linux_arm64": [
- "node-v22.22.0-linux-arm64.tar.xz",
- "node-v22.22.0-linux-arm64",
- "1bf1eb9ee63ffc4e5d324c0b9b62cf4a289f44332dfef9607cea1a0d9596ba6f"
+ "22.22.2-linux_arm64": [
+ "node-v22.22.2-linux-arm64.tar.xz",
+ "node-v22.22.2-linux-arm64",
+ "e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
],
- "22.22.0-linux_ppc64le": [
- "node-v22.22.0-linux-ppc64le.tar.xz",
- "node-v22.22.0-linux-ppc64le",
- "d83b9957431cc18e1fc143a4b99f89cde7b8a18f53ef392231b4336afd058865"
+ "22.22.2-linux_ppc64le": [
+ "node-v22.22.2-linux-ppc64le.tar.xz",
+ "node-v22.22.2-linux-ppc64le",
+ "14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
],
- "22.22.0-linux_s390x": [
- "node-v22.22.0-linux-s390x.tar.xz",
- "node-v22.22.0-linux-s390x",
- "5aa0e520689448c4233e8d73f284e8e0634fdcd32b479735698494be5641f3e4"
+ "22.22.2-linux_s390x": [
+ "node-v22.22.2-linux-s390x.tar.xz",
+ "node-v22.22.2-linux-s390x",
+ "9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
],
- "22.22.0-linux_amd64": [
- "node-v22.22.0-linux-x64.tar.xz",
- "node-v22.22.0-linux-x64",
- "9aa8e9d2298ab68c600bd6fb86a6c13bce11a4eca1ba9b39d79fa021755d7c37"
+ "22.22.2-linux_amd64": [
+ "node-v22.22.2-linux-x64.tar.xz",
+ "node-v22.22.2-linux-x64",
+ "88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
],
- "22.22.0-windows_amd64": [
- "node-v22.22.0-win-x64.zip",
- "node-v22.22.0-win-x64",
- "c97fa376d2becdc8863fcd3ca2dd9a83a9f3468ee7ccf7a6d076ec66a645c77a"
+ "22.22.2-windows_amd64": [
+ "node-v22.22.2-win-x64.zip",
+ "node-v22.22.2-win-x64",
+ "7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
]
},
"node_urls": [
"https://nodejs.org/dist/v{version}/{filename}"
],
- "node_version": "22.22.0",
+ "node_version": "22.22.2",
"include_headers": false,
"platform": "linux_s390x"
}
@@ -1253,46 +1108,46 @@
"attributes": {
"node_download_auth": {},
"node_repositories": {
- "22.22.0-darwin_arm64": [
- "node-v22.22.0-darwin-arm64.tar.gz",
- "node-v22.22.0-darwin-arm64",
- "5ed4db0fcf1eaf84d91ad12462631d73bf4576c1377e192d222e48026a902640"
+ "22.22.2-darwin_arm64": [
+ "node-v22.22.2-darwin-arm64.tar.gz",
+ "node-v22.22.2-darwin-arm64",
+ "db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
],
- "22.22.0-darwin_amd64": [
- "node-v22.22.0-darwin-x64.tar.gz",
- "node-v22.22.0-darwin-x64",
- "5ea50c9d6dea3dfa3abb66b2656f7a4e1c8cef23432b558d45fb538c7b5dedce"
+ "22.22.2-darwin_amd64": [
+ "node-v22.22.2-darwin-x64.tar.gz",
+ "node-v22.22.2-darwin-x64",
+ "12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
],
- "22.22.0-linux_arm64": [
- "node-v22.22.0-linux-arm64.tar.xz",
- "node-v22.22.0-linux-arm64",
- "1bf1eb9ee63ffc4e5d324c0b9b62cf4a289f44332dfef9607cea1a0d9596ba6f"
+ "22.22.2-linux_arm64": [
+ "node-v22.22.2-linux-arm64.tar.xz",
+ "node-v22.22.2-linux-arm64",
+ "e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
],
- "22.22.0-linux_ppc64le": [
- "node-v22.22.0-linux-ppc64le.tar.xz",
- "node-v22.22.0-linux-ppc64le",
- "d83b9957431cc18e1fc143a4b99f89cde7b8a18f53ef392231b4336afd058865"
+ "22.22.2-linux_ppc64le": [
+ "node-v22.22.2-linux-ppc64le.tar.xz",
+ "node-v22.22.2-linux-ppc64le",
+ "14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
],
- "22.22.0-linux_s390x": [
- "node-v22.22.0-linux-s390x.tar.xz",
- "node-v22.22.0-linux-s390x",
- "5aa0e520689448c4233e8d73f284e8e0634fdcd32b479735698494be5641f3e4"
+ "22.22.2-linux_s390x": [
+ "node-v22.22.2-linux-s390x.tar.xz",
+ "node-v22.22.2-linux-s390x",
+ "9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
],
- "22.22.0-linux_amd64": [
- "node-v22.22.0-linux-x64.tar.xz",
- "node-v22.22.0-linux-x64",
- "9aa8e9d2298ab68c600bd6fb86a6c13bce11a4eca1ba9b39d79fa021755d7c37"
+ "22.22.2-linux_amd64": [
+ "node-v22.22.2-linux-x64.tar.xz",
+ "node-v22.22.2-linux-x64",
+ "88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
],
- "22.22.0-windows_amd64": [
- "node-v22.22.0-win-x64.zip",
- "node-v22.22.0-win-x64",
- "c97fa376d2becdc8863fcd3ca2dd9a83a9f3468ee7ccf7a6d076ec66a645c77a"
+ "22.22.2-windows_amd64": [
+ "node-v22.22.2-win-x64.zip",
+ "node-v22.22.2-win-x64",
+ "7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
]
},
"node_urls": [
"https://nodejs.org/dist/v{version}/{filename}"
],
- "node_version": "22.22.0",
+ "node_version": "22.22.2",
"include_headers": false,
"platform": "linux_ppc64le"
}
@@ -1302,46 +1157,46 @@
"attributes": {
"node_download_auth": {},
"node_repositories": {
- "22.22.0-darwin_arm64": [
- "node-v22.22.0-darwin-arm64.tar.gz",
- "node-v22.22.0-darwin-arm64",
- "5ed4db0fcf1eaf84d91ad12462631d73bf4576c1377e192d222e48026a902640"
+ "22.22.2-darwin_arm64": [
+ "node-v22.22.2-darwin-arm64.tar.gz",
+ "node-v22.22.2-darwin-arm64",
+ "db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
],
- "22.22.0-darwin_amd64": [
- "node-v22.22.0-darwin-x64.tar.gz",
- "node-v22.22.0-darwin-x64",
- "5ea50c9d6dea3dfa3abb66b2656f7a4e1c8cef23432b558d45fb538c7b5dedce"
+ "22.22.2-darwin_amd64": [
+ "node-v22.22.2-darwin-x64.tar.gz",
+ "node-v22.22.2-darwin-x64",
+ "12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
],
- "22.22.0-linux_arm64": [
- "node-v22.22.0-linux-arm64.tar.xz",
- "node-v22.22.0-linux-arm64",
- "1bf1eb9ee63ffc4e5d324c0b9b62cf4a289f44332dfef9607cea1a0d9596ba6f"
+ "22.22.2-linux_arm64": [
+ "node-v22.22.2-linux-arm64.tar.xz",
+ "node-v22.22.2-linux-arm64",
+ "e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
],
- "22.22.0-linux_ppc64le": [
- "node-v22.22.0-linux-ppc64le.tar.xz",
- "node-v22.22.0-linux-ppc64le",
- "d83b9957431cc18e1fc143a4b99f89cde7b8a18f53ef392231b4336afd058865"
+ "22.22.2-linux_ppc64le": [
+ "node-v22.22.2-linux-ppc64le.tar.xz",
+ "node-v22.22.2-linux-ppc64le",
+ "14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
],
- "22.22.0-linux_s390x": [
- "node-v22.22.0-linux-s390x.tar.xz",
- "node-v22.22.0-linux-s390x",
- "5aa0e520689448c4233e8d73f284e8e0634fdcd32b479735698494be5641f3e4"
+ "22.22.2-linux_s390x": [
+ "node-v22.22.2-linux-s390x.tar.xz",
+ "node-v22.22.2-linux-s390x",
+ "9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
],
- "22.22.0-linux_amd64": [
- "node-v22.22.0-linux-x64.tar.xz",
- "node-v22.22.0-linux-x64",
- "9aa8e9d2298ab68c600bd6fb86a6c13bce11a4eca1ba9b39d79fa021755d7c37"
+ "22.22.2-linux_amd64": [
+ "node-v22.22.2-linux-x64.tar.xz",
+ "node-v22.22.2-linux-x64",
+ "88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
],
- "22.22.0-windows_amd64": [
- "node-v22.22.0-win-x64.zip",
- "node-v22.22.0-win-x64",
- "c97fa376d2becdc8863fcd3ca2dd9a83a9f3468ee7ccf7a6d076ec66a645c77a"
+ "22.22.2-windows_amd64": [
+ "node-v22.22.2-win-x64.zip",
+ "node-v22.22.2-win-x64",
+ "7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
]
},
"node_urls": [
"https://nodejs.org/dist/v{version}/{filename}"
],
- "node_version": "22.22.0",
+ "node_version": "22.22.2",
"include_headers": false,
"platform": "darwin_amd64"
}
@@ -1351,46 +1206,46 @@
"attributes": {
"node_download_auth": {},
"node_repositories": {
- "22.22.0-darwin_arm64": [
- "node-v22.22.0-darwin-arm64.tar.gz",
- "node-v22.22.0-darwin-arm64",
- "5ed4db0fcf1eaf84d91ad12462631d73bf4576c1377e192d222e48026a902640"
+ "22.22.2-darwin_arm64": [
+ "node-v22.22.2-darwin-arm64.tar.gz",
+ "node-v22.22.2-darwin-arm64",
+ "db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
],
- "22.22.0-darwin_amd64": [
- "node-v22.22.0-darwin-x64.tar.gz",
- "node-v22.22.0-darwin-x64",
- "5ea50c9d6dea3dfa3abb66b2656f7a4e1c8cef23432b558d45fb538c7b5dedce"
+ "22.22.2-darwin_amd64": [
+ "node-v22.22.2-darwin-x64.tar.gz",
+ "node-v22.22.2-darwin-x64",
+ "12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
],
- "22.22.0-linux_arm64": [
- "node-v22.22.0-linux-arm64.tar.xz",
- "node-v22.22.0-linux-arm64",
- "1bf1eb9ee63ffc4e5d324c0b9b62cf4a289f44332dfef9607cea1a0d9596ba6f"
+ "22.22.2-linux_arm64": [
+ "node-v22.22.2-linux-arm64.tar.xz",
+ "node-v22.22.2-linux-arm64",
+ "e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
],
- "22.22.0-linux_ppc64le": [
- "node-v22.22.0-linux-ppc64le.tar.xz",
- "node-v22.22.0-linux-ppc64le",
- "d83b9957431cc18e1fc143a4b99f89cde7b8a18f53ef392231b4336afd058865"
+ "22.22.2-linux_ppc64le": [
+ "node-v22.22.2-linux-ppc64le.tar.xz",
+ "node-v22.22.2-linux-ppc64le",
+ "14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
],
- "22.22.0-linux_s390x": [
- "node-v22.22.0-linux-s390x.tar.xz",
- "node-v22.22.0-linux-s390x",
- "5aa0e520689448c4233e8d73f284e8e0634fdcd32b479735698494be5641f3e4"
+ "22.22.2-linux_s390x": [
+ "node-v22.22.2-linux-s390x.tar.xz",
+ "node-v22.22.2-linux-s390x",
+ "9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
],
- "22.22.0-linux_amd64": [
- "node-v22.22.0-linux-x64.tar.xz",
- "node-v22.22.0-linux-x64",
- "9aa8e9d2298ab68c600bd6fb86a6c13bce11a4eca1ba9b39d79fa021755d7c37"
+ "22.22.2-linux_amd64": [
+ "node-v22.22.2-linux-x64.tar.xz",
+ "node-v22.22.2-linux-x64",
+ "88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
],
- "22.22.0-windows_amd64": [
- "node-v22.22.0-win-x64.zip",
- "node-v22.22.0-win-x64",
- "c97fa376d2becdc8863fcd3ca2dd9a83a9f3468ee7ccf7a6d076ec66a645c77a"
+ "22.22.2-windows_amd64": [
+ "node-v22.22.2-win-x64.zip",
+ "node-v22.22.2-win-x64",
+ "7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
]
},
"node_urls": [
"https://nodejs.org/dist/v{version}/{filename}"
],
- "node_version": "22.22.0",
+ "node_version": "22.22.2",
"include_headers": false,
"platform": "darwin_arm64"
}
@@ -1400,46 +1255,46 @@
"attributes": {
"node_download_auth": {},
"node_repositories": {
- "22.22.0-darwin_arm64": [
- "node-v22.22.0-darwin-arm64.tar.gz",
- "node-v22.22.0-darwin-arm64",
- "5ed4db0fcf1eaf84d91ad12462631d73bf4576c1377e192d222e48026a902640"
+ "22.22.2-darwin_arm64": [
+ "node-v22.22.2-darwin-arm64.tar.gz",
+ "node-v22.22.2-darwin-arm64",
+ "db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
],
- "22.22.0-darwin_amd64": [
- "node-v22.22.0-darwin-x64.tar.gz",
- "node-v22.22.0-darwin-x64",
- "5ea50c9d6dea3dfa3abb66b2656f7a4e1c8cef23432b558d45fb538c7b5dedce"
+ "22.22.2-darwin_amd64": [
+ "node-v22.22.2-darwin-x64.tar.gz",
+ "node-v22.22.2-darwin-x64",
+ "12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
],
- "22.22.0-linux_arm64": [
- "node-v22.22.0-linux-arm64.tar.xz",
- "node-v22.22.0-linux-arm64",
- "1bf1eb9ee63ffc4e5d324c0b9b62cf4a289f44332dfef9607cea1a0d9596ba6f"
+ "22.22.2-linux_arm64": [
+ "node-v22.22.2-linux-arm64.tar.xz",
+ "node-v22.22.2-linux-arm64",
+ "e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
],
- "22.22.0-linux_ppc64le": [
- "node-v22.22.0-linux-ppc64le.tar.xz",
- "node-v22.22.0-linux-ppc64le",
- "d83b9957431cc18e1fc143a4b99f89cde7b8a18f53ef392231b4336afd058865"
+ "22.22.2-linux_ppc64le": [
+ "node-v22.22.2-linux-ppc64le.tar.xz",
+ "node-v22.22.2-linux-ppc64le",
+ "14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
],
- "22.22.0-linux_s390x": [
- "node-v22.22.0-linux-s390x.tar.xz",
- "node-v22.22.0-linux-s390x",
- "5aa0e520689448c4233e8d73f284e8e0634fdcd32b479735698494be5641f3e4"
+ "22.22.2-linux_s390x": [
+ "node-v22.22.2-linux-s390x.tar.xz",
+ "node-v22.22.2-linux-s390x",
+ "9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
],
- "22.22.0-linux_amd64": [
- "node-v22.22.0-linux-x64.tar.xz",
- "node-v22.22.0-linux-x64",
- "9aa8e9d2298ab68c600bd6fb86a6c13bce11a4eca1ba9b39d79fa021755d7c37"
+ "22.22.2-linux_amd64": [
+ "node-v22.22.2-linux-x64.tar.xz",
+ "node-v22.22.2-linux-x64",
+ "88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
],
- "22.22.0-windows_amd64": [
- "node-v22.22.0-win-x64.zip",
- "node-v22.22.0-win-x64",
- "c97fa376d2becdc8863fcd3ca2dd9a83a9f3468ee7ccf7a6d076ec66a645c77a"
+ "22.22.2-windows_amd64": [
+ "node-v22.22.2-win-x64.zip",
+ "node-v22.22.2-win-x64",
+ "7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
]
},
"node_urls": [
"https://nodejs.org/dist/v{version}/{filename}"
],
- "node_version": "22.22.0",
+ "node_version": "22.22.2",
"include_headers": false,
"platform": "windows_amd64"
}
@@ -1449,46 +1304,46 @@
"attributes": {
"node_download_auth": {},
"node_repositories": {
- "22.22.0-darwin_arm64": [
- "node-v22.22.0-darwin-arm64.tar.gz",
- "node-v22.22.0-darwin-arm64",
- "5ed4db0fcf1eaf84d91ad12462631d73bf4576c1377e192d222e48026a902640"
+ "22.22.2-darwin_arm64": [
+ "node-v22.22.2-darwin-arm64.tar.gz",
+ "node-v22.22.2-darwin-arm64",
+ "db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
],
- "22.22.0-darwin_amd64": [
- "node-v22.22.0-darwin-x64.tar.gz",
- "node-v22.22.0-darwin-x64",
- "5ea50c9d6dea3dfa3abb66b2656f7a4e1c8cef23432b558d45fb538c7b5dedce"
+ "22.22.2-darwin_amd64": [
+ "node-v22.22.2-darwin-x64.tar.gz",
+ "node-v22.22.2-darwin-x64",
+ "12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
],
- "22.22.0-linux_arm64": [
- "node-v22.22.0-linux-arm64.tar.xz",
- "node-v22.22.0-linux-arm64",
- "1bf1eb9ee63ffc4e5d324c0b9b62cf4a289f44332dfef9607cea1a0d9596ba6f"
+ "22.22.2-linux_arm64": [
+ "node-v22.22.2-linux-arm64.tar.xz",
+ "node-v22.22.2-linux-arm64",
+ "e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
],
- "22.22.0-linux_ppc64le": [
- "node-v22.22.0-linux-ppc64le.tar.xz",
- "node-v22.22.0-linux-ppc64le",
- "d83b9957431cc18e1fc143a4b99f89cde7b8a18f53ef392231b4336afd058865"
+ "22.22.2-linux_ppc64le": [
+ "node-v22.22.2-linux-ppc64le.tar.xz",
+ "node-v22.22.2-linux-ppc64le",
+ "14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
],
- "22.22.0-linux_s390x": [
- "node-v22.22.0-linux-s390x.tar.xz",
- "node-v22.22.0-linux-s390x",
- "5aa0e520689448c4233e8d73f284e8e0634fdcd32b479735698494be5641f3e4"
+ "22.22.2-linux_s390x": [
+ "node-v22.22.2-linux-s390x.tar.xz",
+ "node-v22.22.2-linux-s390x",
+ "9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
],
- "22.22.0-linux_amd64": [
- "node-v22.22.0-linux-x64.tar.xz",
- "node-v22.22.0-linux-x64",
- "9aa8e9d2298ab68c600bd6fb86a6c13bce11a4eca1ba9b39d79fa021755d7c37"
+ "22.22.2-linux_amd64": [
+ "node-v22.22.2-linux-x64.tar.xz",
+ "node-v22.22.2-linux-x64",
+ "88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
],
- "22.22.0-windows_amd64": [
- "node-v22.22.0-win-x64.zip",
- "node-v22.22.0-win-x64",
- "c97fa376d2becdc8863fcd3ca2dd9a83a9f3468ee7ccf7a6d076ec66a645c77a"
+ "22.22.2-windows_amd64": [
+ "node-v22.22.2-win-x64.zip",
+ "node-v22.22.2-win-x64",
+ "7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
]
},
"node_urls": [
"https://nodejs.org/dist/v{version}/{filename}"
],
- "node_version": "22.22.0",
+ "node_version": "22.22.2",
"include_headers": false,
"platform": "windows_arm64"
}
@@ -1883,7 +1738,7 @@
},
"@@rules_python+//python/extensions:pip.bzl%pip": {
"general": {
- "bzlTransitiveDigest": "d3ENjFH8qMwmOrkcb3c9JYqQ5hJ6owjfbSr24KY0Ugg=",
+ "bzlTransitiveDigest": "WViZ5k1A9F8R5wfEe2ArLMFS1g9UmgfbS8Q/7q1/z7o=",
"usagesDigest": "AK1R124YPWwAs8z1CQYyjYuci8RO5Ofot+EP5ZCNQDc=",
"recordedFileInputs": {
"@@protobuf+//python/requirements.txt": "983be60d3cec4b319dcab6d48aeb3f5b2f7c3350f26b3a9e97486c37967c73c5",
@@ -4621,7 +4476,7 @@
},
"@@rules_sass+//src/toolchain:extensions.bzl%sass": {
"general": {
- "bzlTransitiveDigest": "RA58Nyrsn03Z5YmQnpmBw3mqlVck++XIrx34amsqU/E=",
+ "bzlTransitiveDigest": "mOfuR8PsNuUWEq7JZ4MpIRbwyAGAqrCvkXXGaRNnlPQ=",
"usagesDigest": "R0KshhzIouLWuexMUCrl4HY+FUDwlVVgF9Z7UnwyUWA=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
@@ -4677,8 +4532,8 @@
},
"@@yq.bzl+//yq:extensions.bzl%yq": {
"general": {
- "bzlTransitiveDigest": "tDqk+ntWTdxNAWPDjRY1uITgHbti2jcXR5ZdinltBs0=",
- "usagesDigest": "OQwtwmKiZAvI0n0B86XlM4tmQHq4zcjFjAEiRGPhXVI=",
+ "bzlTransitiveDigest": "UfFMy8CWK4/dVo/tfaSAIYUiDGNAPes5eRllx9O9Q9Q=",
+ "usagesDigest": "da9wP1gnmr42ci1bT30rSLLWu7O0jJPIkd01GNAM7NE=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
"envVariables": {},
diff --git a/constants.bzl b/constants.bzl
index d4be4fc34b84..d9a42e40631f 100644
--- a/constants.bzl
+++ b/constants.bzl
@@ -3,10 +3,10 @@ RELEASE_ENGINES_NODE = "^20.19.0 || ^22.12.0 || >=24.0.0"
RELEASE_ENGINES_NPM = "^6.11.0 || ^7.5.6 || >=8.0.0"
RELEASE_ENGINES_YARN = ">= 1.13.0"
-NG_PACKAGR_VERSION = "^21.2.0-next.0"
-ANGULAR_FW_VERSION = "^21.2.0-next.0"
-ANGULAR_FW_PEER_DEP = "^21.0.0 || ^21.2.0-next.0"
-NG_PACKAGR_PEER_DEP = "^21.0.0 || ^21.2.0-next.0"
+NG_PACKAGR_VERSION = "^21.2.0"
+ANGULAR_FW_VERSION = "^21.2.0"
+ANGULAR_FW_PEER_DEP = "^21.0.0"
+NG_PACKAGR_PEER_DEP = "^21.0.0"
# Baseline widely-available date in `YYYY-MM-DD` format which defines Angular's
# browser support. This date serves as the source of truth for the Angular CLI's
diff --git a/docs/DEVELOPER.md b/docs/DEVELOPER.md
index 8204bd7dcbce..075ddbcf9ca3 100644
--- a/docs/DEVELOPER.md
+++ b/docs/DEVELOPER.md
@@ -56,7 +56,7 @@ project](#building-and-installing-the-cli), then run the desired `ng` command
as:
```shell
-node --inspect-brk node_modules/.bin/ng ...
+node --inspect-brk node_modules/.bin/ng
```
This will trigger a breakpoint as the CLI starts up. You can connect to this
diff --git a/goldens/BUILD.bazel b/goldens/BUILD.bazel
index 6dbbdd28f25b..711154f524b1 100644
--- a/goldens/BUILD.bazel
+++ b/goldens/BUILD.bazel
@@ -1,4 +1,4 @@
-load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin")
+load("@bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin")
package(default_visibility = ["//visibility:public"])
diff --git a/goldens/public-api/angular/ssr/index.api.md b/goldens/public-api/angular/ssr/index.api.md
index 81764fcc1f62..e5d85138b72f 100644
--- a/goldens/public-api/angular/ssr/index.api.md
+++ b/goldens/public-api/angular/ssr/index.api.md
@@ -6,19 +6,30 @@
import { DefaultExport } from '@angular/router';
import { EnvironmentProviders } from '@angular/core';
+import { InjectionToken } from '@angular/core';
import { Provider } from '@angular/core';
import { Type } from '@angular/core';
// @public
export class AngularAppEngine {
+ constructor(options?: AngularAppEngineOptions);
handle(request: Request, requestContext?: unknown): Promise;
static ɵallowStaticRouteRender: boolean;
+ static ɵdisableAllowedHostsCheck: boolean;
static ɵhooks: Hooks;
}
+// @public
+export interface AngularAppEngineOptions {
+ allowedHosts?: readonly string[];
+}
+
// @public
export function createRequestHandler(handler: RequestHandlerFunction): RequestHandlerFunction;
+// @public
+export const IS_DISCOVERING_ROUTES: InjectionToken;
+
// @public
export enum PrerenderFallback {
Client = 1,
diff --git a/goldens/public-api/angular/ssr/node/index.api.md b/goldens/public-api/angular/ssr/node/index.api.md
index eccb6396938e..2c52c06b47c1 100644
--- a/goldens/public-api/angular/ssr/node/index.api.md
+++ b/goldens/public-api/angular/ssr/node/index.api.md
@@ -15,8 +15,12 @@ import { Type } from '@angular/core';
// @public
export class AngularNodeAppEngine {
- constructor();
- handle(request: IncomingMessage | Http2ServerRequest, requestContext?: unknown): Promise;
+ constructor(options?: AngularNodeAppEngineOptions);
+ handle(request: IncomingMessage | Http2ServerRequest | Request, requestContext?: unknown): Promise;
+}
+
+// @public
+export interface AngularNodeAppEngineOptions extends AngularAppEngineOptions {
}
// @public
@@ -27,6 +31,7 @@ export class CommonEngine {
// @public (undocumented)
export interface CommonEngineOptions {
+ allowedHosts?: readonly string[];
bootstrap?: Type<{}> | ((context: BootstrapContext) => Promise);
enablePerformanceProfiler?: boolean;
providers?: StaticProvider[];
diff --git a/goldens/public-api/angular_devkit/architect/index.api.md b/goldens/public-api/angular_devkit/architect/index.api.md
index 0ae8751719b5..747b7010f580 100644
--- a/goldens/public-api/angular_devkit/architect/index.api.md
+++ b/goldens/public-api/angular_devkit/architect/index.api.md
@@ -530,7 +530,7 @@ export type Target = json.JsonObject & Target_2;
export function targetFromTargetString(specifier: string, abbreviatedProjectName?: string, abbreviatedTargetName?: string): Target;
// @public
-export function targetStringFromTarget({ project, target, configuration }: Target): string;
+export function targetStringFromTarget(input: Target): string;
// @public
export type TypedBuilderProgress = {
diff --git a/modules/testing/builder/BUILD.bazel b/modules/testing/builder/BUILD.bazel
index 7f542efb0138..4fa8b7ee723b 100644
--- a/modules/testing/builder/BUILD.bazel
+++ b/modules/testing/builder/BUILD.bazel
@@ -22,6 +22,7 @@ ts_project(
":node_modules/@angular/ssr",
":node_modules/browser-sync",
":node_modules/jsdom",
+ ":node_modules/ng-packagr",
":node_modules/vitest",
":node_modules/@vitest/coverage-v8",
] + glob(["projects/**/*"]),
diff --git a/modules/testing/builder/package.json b/modules/testing/builder/package.json
index 47ff33d0cd7d..998158229973 100644
--- a/modules/testing/builder/package.json
+++ b/modules/testing/builder/package.json
@@ -1,12 +1,13 @@
{
"devDependencies": {
- "@angular-devkit/core": "workspace:*",
"@angular-devkit/architect": "workspace:*",
- "@angular/ssr": "workspace:*",
"@angular-devkit/build-angular": "workspace:*",
- "browser-sync": "3.0.4",
+ "@angular-devkit/core": "workspace:*",
+ "@angular/ssr": "workspace:*",
"@vitest/coverage-v8": "4.0.18",
+ "browser-sync": "3.0.4",
"jsdom": "28.1.0",
+ "ng-packagr": "22.0.0-next.1",
"rxjs": "7.8.2",
"vitest": "4.0.18"
}
diff --git a/packages/angular_devkit/build_angular/test/hello-world-lib/.gitignore b/modules/testing/builder/projects/hello-world-lib/.gitignore
similarity index 100%
rename from packages/angular_devkit/build_angular/test/hello-world-lib/.gitignore
rename to modules/testing/builder/projects/hello-world-lib/.gitignore
diff --git a/packages/angular_devkit/build_angular/test/hello-world-lib/angular.json b/modules/testing/builder/projects/hello-world-lib/angular.json
similarity index 100%
rename from packages/angular_devkit/build_angular/test/hello-world-lib/angular.json
rename to modules/testing/builder/projects/hello-world-lib/angular.json
diff --git a/packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/karma.conf.js b/modules/testing/builder/projects/hello-world-lib/projects/lib/karma.conf.js
similarity index 100%
rename from packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/karma.conf.js
rename to modules/testing/builder/projects/hello-world-lib/projects/lib/karma.conf.js
diff --git a/packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/ng-package.json b/modules/testing/builder/projects/hello-world-lib/projects/lib/ng-package.json
similarity index 100%
rename from packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/ng-package.json
rename to modules/testing/builder/projects/hello-world-lib/projects/lib/ng-package.json
diff --git a/packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/package.json b/modules/testing/builder/projects/hello-world-lib/projects/lib/package.json
similarity index 100%
rename from packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/package.json
rename to modules/testing/builder/projects/hello-world-lib/projects/lib/package.json
diff --git a/packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/src/lib/lib.component.spec.ts b/modules/testing/builder/projects/hello-world-lib/projects/lib/src/lib/lib.component.spec.ts
similarity index 100%
rename from packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/src/lib/lib.component.spec.ts
rename to modules/testing/builder/projects/hello-world-lib/projects/lib/src/lib/lib.component.spec.ts
diff --git a/packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/src/lib/lib.component.ts b/modules/testing/builder/projects/hello-world-lib/projects/lib/src/lib/lib.component.ts
similarity index 100%
rename from packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/src/lib/lib.component.ts
rename to modules/testing/builder/projects/hello-world-lib/projects/lib/src/lib/lib.component.ts
diff --git a/packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/src/lib/lib.service.spec.ts b/modules/testing/builder/projects/hello-world-lib/projects/lib/src/lib/lib.service.spec.ts
similarity index 100%
rename from packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/src/lib/lib.service.spec.ts
rename to modules/testing/builder/projects/hello-world-lib/projects/lib/src/lib/lib.service.spec.ts
diff --git a/packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/src/lib/lib.service.ts b/modules/testing/builder/projects/hello-world-lib/projects/lib/src/lib/lib.service.ts
similarity index 100%
rename from packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/src/lib/lib.service.ts
rename to modules/testing/builder/projects/hello-world-lib/projects/lib/src/lib/lib.service.ts
diff --git a/packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/src/public-api.ts b/modules/testing/builder/projects/hello-world-lib/projects/lib/src/public-api.ts
similarity index 100%
rename from packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/src/public-api.ts
rename to modules/testing/builder/projects/hello-world-lib/projects/lib/src/public-api.ts
diff --git a/packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/tsconfig.lib.json b/modules/testing/builder/projects/hello-world-lib/projects/lib/tsconfig.lib.json
similarity index 100%
rename from packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/tsconfig.lib.json
rename to modules/testing/builder/projects/hello-world-lib/projects/lib/tsconfig.lib.json
diff --git a/packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/tsconfig.lib.prod.json b/modules/testing/builder/projects/hello-world-lib/projects/lib/tsconfig.lib.prod.json
similarity index 100%
rename from packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/tsconfig.lib.prod.json
rename to modules/testing/builder/projects/hello-world-lib/projects/lib/tsconfig.lib.prod.json
diff --git a/packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/tsconfig.spec.json b/modules/testing/builder/projects/hello-world-lib/projects/lib/tsconfig.spec.json
similarity index 100%
rename from packages/angular_devkit/build_angular/test/hello-world-lib/projects/lib/tsconfig.spec.json
rename to modules/testing/builder/projects/hello-world-lib/projects/lib/tsconfig.spec.json
diff --git a/packages/angular_devkit/build_angular/test/hello-world-lib/tsconfig.json b/modules/testing/builder/projects/hello-world-lib/tsconfig.json
similarity index 100%
rename from packages/angular_devkit/build_angular/test/hello-world-lib/tsconfig.json
rename to modules/testing/builder/projects/hello-world-lib/tsconfig.json
diff --git a/package.json b/package.json
index 39fba551b317..0ea57d7238b8 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@angular/devkit-repo",
- "version": "21.2.0-next.2",
+ "version": "21.2.6",
"private": true,
"description": "Software Development Kit for Angular",
"keywords": [
@@ -26,14 +26,14 @@
},
"repository": {
"type": "git",
- "url": "https://github.com/angular/angular-cli.git"
+ "url": "git+https://github.com/angular/angular-cli.git"
},
- "packageManager": "pnpm@10.29.3",
+ "packageManager": "pnpm@10.33.0",
"engines": {
"node": "^20.19.0 || ^22.12.0 || >=24.0.0",
"npm": "Please use pnpm instead of NPM to install dependencies",
"yarn": "Please use pnpm instead of Yarn to install dependencies",
- "pnpm": "10.29.3"
+ "pnpm": "10.33.0"
},
"author": "Angular Authors",
"license": "MIT",
@@ -42,20 +42,20 @@
},
"homepage": "https://github.com/angular/angular-cli",
"devDependencies": {
- "@angular/animations": "21.2.0-next.3",
- "@angular/cdk": "21.2.0-next.4",
- "@angular/common": "21.2.0-next.3",
- "@angular/compiler": "21.2.0-next.3",
- "@angular/compiler-cli": "21.2.0-next.3",
- "@angular/core": "21.2.0-next.3",
- "@angular/forms": "21.2.0-next.3",
- "@angular/localize": "21.2.0-next.3",
- "@angular/material": "21.2.0-next.4",
- "@angular/ng-dev": "https://github.com/angular/dev-infra-private-ng-dev-builds.git#2a5e8e5b5398ae13a8d9a963ac980707313a6c9e",
- "@angular/platform-browser": "21.2.0-next.3",
- "@angular/platform-server": "21.2.0-next.3",
- "@angular/router": "21.2.0-next.3",
- "@angular/service-worker": "21.2.0-next.3",
+ "@angular/animations": "21.2.6",
+ "@angular/cdk": "21.2.4",
+ "@angular/common": "21.2.6",
+ "@angular/compiler": "21.2.6",
+ "@angular/compiler-cli": "21.2.6",
+ "@angular/core": "21.2.6",
+ "@angular/forms": "21.2.6",
+ "@angular/localize": "21.2.6",
+ "@angular/material": "21.2.4",
+ "@angular/ng-dev": "https://github.com/angular/dev-infra-private-ng-dev-builds.git#cdbe118e59f59b1ee00ff77a5ccf8c5328248d03",
+ "@angular/platform-browser": "21.2.6",
+ "@angular/platform-server": "21.2.6",
+ "@angular/router": "21.2.6",
+ "@angular/service-worker": "21.2.6",
"@babel/core": "7.29.0",
"@bazel/bazelisk": "1.28.1",
"@bazel/buildifier": "8.2.1",
@@ -66,6 +66,7 @@
"@rollup/plugin-commonjs": "^29.0.0",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "16.0.3",
+ "@rollup/wasm-node": "4.59.0",
"@stylistic/eslint-plugin": "^5.0.0",
"@types/babel__core": "7.20.5",
"@types/babel__generator": "^7.6.8",
@@ -130,9 +131,9 @@
"ts-node": "^10.9.1",
"tslib": "2.8.1",
"typescript": "5.9.3",
- "undici": "7.22.0",
+ "undici": "7.24.4",
"unenv": "^1.10.0",
- "verdaccio": "6.2.5",
+ "verdaccio": "6.2.9",
"verdaccio-auth-memory": "^10.0.0",
"zone.js": "^0.16.0"
},
diff --git a/packages/angular/build/package.json b/packages/angular/build/package.json
index c4d847ae5a8e..e04ef0c7b3a3 100644
--- a/packages/angular/build/package.json
+++ b/packages/angular/build/package.json
@@ -35,14 +35,14 @@
"magic-string": "0.30.21",
"mrmime": "2.0.1",
"parse5-html-rewriting-stream": "8.0.0",
- "picomatch": "4.0.3",
+ "picomatch": "4.0.4",
"piscina": "5.1.4",
"rolldown": "1.0.0-rc.4",
"sass": "1.97.3",
"semver": "7.7.4",
"source-map-support": "0.5.21",
"tinyglobby": "0.2.15",
- "undici": "7.22.0",
+ "undici": "7.24.4",
"vite": "7.3.1",
"watchpack": "2.5.1"
},
@@ -54,7 +54,7 @@
"@angular/ssr": "workspace:*",
"jsdom": "28.1.0",
"less": "4.4.2",
- "ng-packagr": "21.2.0-next.0",
+ "ng-packagr": "21.2.2",
"postcss": "8.5.6",
"rxjs": "7.8.2",
"vitest": "4.0.18"
diff --git a/packages/angular/build/src/builders/application/execute-build.ts b/packages/angular/build/src/builders/application/execute-build.ts
index 0654cd965558..aaddc5b6ef7e 100644
--- a/packages/angular/build/src/builders/application/execute-build.ts
+++ b/packages/angular/build/src/builders/application/execute-build.ts
@@ -56,6 +56,7 @@ export async function executeBuild(
verbose,
colors,
jsonLogs,
+ security,
} = options;
// TODO: Consider integrating into watch mode. Would require full rebuild on target changes.
@@ -263,7 +264,7 @@ export async function executeBuild(
if (serverEntryPoint) {
executionResult.addOutputFile(
SERVER_APP_ENGINE_MANIFEST_FILENAME,
- generateAngularServerAppEngineManifest(i18nOptions, baseHref),
+ generateAngularServerAppEngineManifest(i18nOptions, security.allowedHosts, baseHref),
BuildOutputFileType.ServerRoot,
);
}
diff --git a/packages/angular/build/src/builders/application/i18n.ts b/packages/angular/build/src/builders/application/i18n.ts
index ae37efa674e4..081be50e7a9f 100644
--- a/packages/angular/build/src/builders/application/i18n.ts
+++ b/packages/angular/build/src/builders/application/i18n.ts
@@ -123,48 +123,48 @@ export async function inlineI18n(
inlineResult.prerenderedRoutes = { ...inlineResult.prerenderedRoutes, ...generatedRoutes };
updatedOutputFiles.push(...localeOutputFiles);
}
- } finally {
- await inliner.close();
- }
- // Update the result with all localized files.
- executionResult.outputFiles = [
- // Root and SSR entry files are not modified.
- ...unModifiedOutputFiles,
- // Updated files for each locale.
- ...updatedOutputFiles,
- ];
-
- // Assets are only changed if not using the flat output option
- if (!i18nOptions.flatOutput) {
- executionResult.assetFiles = updatedAssetFiles;
- }
-
- // Inline any template updates if present
- if (executionResult.templateUpdates?.size) {
- // The development server only allows a single locale but issue a warning if used programmatically (experimental)
- // with multiple locales and template HMR.
- if (i18nOptions.inlineLocales.size > 1) {
- inlineResult.warnings.push(
- `Component HMR updates can only be inlined with a single locale. The first locale will be used.`,
- );
+ // Update the result with all localized files.
+ executionResult.outputFiles = [
+ // Root and SSR entry files are not modified.
+ ...unModifiedOutputFiles,
+ // Updated files for each locale.
+ ...updatedOutputFiles,
+ ];
+
+ // Assets are only changed if not using the flat output option
+ if (!i18nOptions.flatOutput) {
+ executionResult.assetFiles = updatedAssetFiles;
}
- const firstLocale = [...i18nOptions.inlineLocales][0];
-
- for (const [id, content] of executionResult.templateUpdates) {
- const templateUpdateResult = await inliner.inlineTemplateUpdate(
- firstLocale,
- i18nOptions.locales[firstLocale].translation,
- content,
- id,
- );
- executionResult.templateUpdates.set(id, templateUpdateResult.code);
- inlineResult.errors.push(...templateUpdateResult.errors);
- inlineResult.warnings.push(...templateUpdateResult.warnings);
+
+ // Inline any template updates if present
+ if (executionResult.templateUpdates?.size) {
+ // The development server only allows a single locale but issue a warning if used programmatically (experimental)
+ // with multiple locales and template HMR.
+ if (i18nOptions.inlineLocales.size > 1) {
+ inlineResult.warnings.push(
+ `Component HMR updates can only be inlined with a single locale. The first locale will be used.`,
+ );
+ }
+ const firstLocale = [...i18nOptions.inlineLocales][0];
+
+ for (const [id, content] of executionResult.templateUpdates) {
+ const templateUpdateResult = await inliner.inlineTemplateUpdate(
+ firstLocale,
+ i18nOptions.locales[firstLocale].translation,
+ content,
+ id,
+ );
+ executionResult.templateUpdates.set(id, templateUpdateResult.code);
+ inlineResult.errors.push(...templateUpdateResult.errors);
+ inlineResult.warnings.push(...templateUpdateResult.warnings);
+ }
}
- }
- return inlineResult;
+ return inlineResult;
+ } finally {
+ await inliner.close();
+ }
}
/**
diff --git a/packages/angular/build/src/builders/application/options.ts b/packages/angular/build/src/builders/application/options.ts
index 83b7ea428f35..4f0d1295a7e3 100644
--- a/packages/angular/build/src/builders/application/options.ts
+++ b/packages/angular/build/src/builders/application/options.ts
@@ -400,8 +400,9 @@ export async function normalizeOptions(
}
}
- const autoCsp = options.security?.autoCsp;
+ const { autoCsp, allowedHosts = [] } = options.security ?? {};
const security = {
+ allowedHosts,
autoCsp: autoCsp
? {
unsafeEval: autoCsp === true ? false : !!autoCsp.unsafeEval,
diff --git a/packages/angular/build/src/builders/application/schema.json b/packages/angular/build/src/builders/application/schema.json
index 8db4e6145b3f..5498a21fe004 100644
--- a/packages/angular/build/src/builders/application/schema.json
+++ b/packages/angular/build/src/builders/application/schema.json
@@ -52,6 +52,14 @@
"type": "object",
"additionalProperties": false,
"properties": {
+ "allowedHosts": {
+ "description": "A list of hostnames that are allowed to access the server-side application. For more information, see https://angular.dev/best-practices/security#preventing-server-side-request-forgery-ssrf.",
+ "type": "array",
+ "uniqueItems": true,
+ "items": {
+ "type": "string"
+ }
+ },
"autoCsp": {
"description": "Enables automatic generation of a hash-based Strict Content Security Policy (https://web.dev/articles/strict-csp#choose-hash) based on scripts in index.html. Will default to true once we are out of experimental/preview phases.",
"default": false,
diff --git a/packages/angular/build/src/builders/application/tests/behavior/rebuild-component_styles_spec.ts b/packages/angular/build/src/builders/application/tests/behavior/rebuild-component_styles_spec.ts
index 26ae35a8221f..08b683439684 100644
--- a/packages/angular/build/src/builders/application/tests/behavior/rebuild-component_styles_spec.ts
+++ b/packages/angular/build/src/builders/application/tests/behavior/rebuild-component_styles_spec.ts
@@ -58,5 +58,85 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => {
]);
});
}
+
+ it('rebuilds component after error on rebuild from transitive import', async () => {
+ harness.useTarget('build', {
+ ...BASE_OPTIONS,
+ watch: true,
+ });
+
+ await harness.modifyFile('src/app/app.component.ts', (content) =>
+ content.replace('app.component.css', 'app.component.scss'),
+ );
+ await harness.writeFile('src/app/app.component.scss', "@import './a';");
+ await harness.writeFile('src/app/a.scss', '$primary: aqua;\\nh1 { color: $primary; }');
+
+ await harness.executeWithCases([
+ async ({ result }) => {
+ expect(result?.success).toBe(true);
+
+ harness.expectFile('dist/browser/main.js').content.toContain('color: aqua');
+
+ // Introduce a syntax error
+ await harness.writeFile(
+ 'src/app/a.scss',
+ 'invalid-invalid-invalid\\nh1 { color: $primary; }',
+ );
+ },
+ async ({ result }) => {
+ expect(result?.success).toBe(false);
+
+ // Fix the syntax error
+ await harness.writeFile('src/app/a.scss', '$primary: blue;\\nh1 { color: $primary; }');
+ },
+ ({ result }) => {
+ expect(result?.success).toBe(true);
+
+ harness.expectFile('dist/browser/main.js').content.toContain('color: blue');
+ },
+ ]);
+ });
+
+ it('rebuilds component after error on rebuild from deep transitive import with partials', async () => {
+ harness.useTarget('build', {
+ ...BASE_OPTIONS,
+ watch: true,
+ });
+
+ await harness.modifyFile('src/app/app.component.ts', (content) =>
+ content.replace('app.component.css', 'app.component.scss'),
+ );
+ await harness.writeFile('src/app/app.component.scss', "@import './intermediary';");
+ await harness.writeFile('src/app/_intermediary.scss', "@import './partial';");
+ await harness.writeFile('src/app/_partial.scss', '$primary: aqua;\\nh1 { color: $primary; }');
+
+ await harness.executeWithCases([
+ async ({ result }) => {
+ expect(result?.success).toBe(true);
+
+ harness.expectFile('dist/browser/main.js').content.toContain('color: aqua');
+
+ // Introduce a syntax error deeply
+ await harness.writeFile(
+ 'src/app/_partial.scss',
+ 'invalid-invalid-invalid\\nh1 { color: $primary; }',
+ );
+ },
+ async ({ result }) => {
+ expect(result?.success).toBe(false);
+
+ // Fix the syntax error deeply
+ await harness.writeFile(
+ 'src/app/_partial.scss',
+ '$primary: blue;\\nh1 { color: $primary; }',
+ );
+ },
+ ({ result }) => {
+ expect(result?.success).toBe(true);
+
+ harness.expectFile('dist/browser/main.js').content.toContain('color: blue');
+ },
+ ]);
+ });
});
});
diff --git a/packages/angular/build/src/builders/dev-server/tests/behavior/build-assets_spec.ts b/packages/angular/build/src/builders/dev-server/tests/behavior/build-assets_spec.ts
index f7c7a0acb33a..7d3e1ffc414b 100644
--- a/packages/angular/build/src/builders/dev-server/tests/behavior/build-assets_spec.ts
+++ b/packages/angular/build/src/builders/dev-server/tests/behavior/build-assets_spec.ts
@@ -21,6 +21,26 @@ describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupT
"import {foo} from 'unresolved'; /* a comment */const foo = `bar`;\n\n\n";
describe('Behavior: "browser builder assets"', () => {
+ it('serves a project extensionless asset unmodified', async () => {
+ await harness.writeFile('src/extensionless', javascriptFileContent);
+
+ setupTarget(harness, {
+ assets: ['src/extensionless'],
+ optimization: {
+ scripts: true,
+ },
+ });
+
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
+ });
+
+ const { result, response } = await executeOnceAndFetch(harness, 'extensionless');
+
+ expect(result?.success).toBeTrue();
+ expect(await response?.text()).toContain(javascriptFileContent);
+ });
+
it('serves a project JavaScript asset unmodified', async () => {
await harness.writeFile('src/extra.js', javascriptFileContent);
diff --git a/packages/angular/build/src/builders/dev-server/tests/behavior/build-budgets_spec.ts b/packages/angular/build/src/builders/dev-server/tests/behavior/build-budgets_spec.ts
index aee551e78b48..97a68506fcf5 100644
--- a/packages/angular/build/src/builders/dev-server/tests/behavior/build-budgets_spec.ts
+++ b/packages/angular/build/src/builders/dev-server/tests/behavior/build-budgets_spec.ts
@@ -11,29 +11,25 @@ import { executeDevServer } from '../../index';
import { describeServeBuilder } from '../jasmine-helpers';
import { BASE_OPTIONS, DEV_SERVER_BUILDER_INFO } from '../setup';
-describeServeBuilder(
- executeDevServer,
- DEV_SERVER_BUILDER_INFO,
- (harness, setupTarget, isViteRun) => {
- // TODO(fix-vite): currently this is broken in vite.
- (isViteRun ? xdescribe : describe)('Behavior: "browser builder budgets"', () => {
- beforeEach(() => {
- setupTarget(harness, {
- // Add a budget error for any file over 100 bytes
- budgets: [{ type: BudgetType.All, maximumError: '100b' }],
- optimization: true,
- });
+describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupTarget) => {
+ // TODO(fix-vite): currently this is broken in vite.
+ xdescribe('Behavior: "browser builder budgets"', () => {
+ beforeEach(() => {
+ setupTarget(harness, {
+ // Add a budget error for any file over 100 bytes
+ budgets: [{ type: BudgetType.All, maximumError: '100b' }],
+ optimization: true,
});
+ });
- it('should ignore budgets defined in the "buildTarget" options', async () => {
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- });
+ it('should ignore budgets defined in the "buildTarget" options', async () => {
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
+ });
- const { result } = await harness.executeOnce();
+ const { result } = await harness.executeOnce();
- expect(result?.success).toBe(true);
- });
+ expect(result?.success).toBe(true);
});
- },
-);
+ });
+});
diff --git a/packages/angular/build/src/builders/dev-server/tests/behavior/build-conditions_spec.ts b/packages/angular/build/src/builders/dev-server/tests/behavior/build-conditions_spec.ts
index 2a7d59d8d574..aef1973d4a48 100644
--- a/packages/angular/build/src/builders/dev-server/tests/behavior/build-conditions_spec.ts
+++ b/packages/angular/build/src/builders/dev-server/tests/behavior/build-conditions_spec.ts
@@ -15,86 +15,74 @@ import { executeOnceAndFetch } from '../execute-fetch';
import { describeServeBuilder } from '../jasmine-helpers';
import { BASE_OPTIONS, DEV_SERVER_BUILDER_INFO } from '../setup';
-describeServeBuilder(
- executeDevServer,
- DEV_SERVER_BUILDER_INFO,
- (harness, setupTarget, isApplicationBuilder) => {
- describe('Behavior: "conditional imports"', () => {
- if (!isApplicationBuilder) {
- it('requires esbuild', () => {
- expect(true).toBeTrue();
- });
-
- return;
- }
-
- beforeEach(async () => {
- setupTarget(harness);
+describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupTarget) => {
+ describe('Behavior: "conditional imports"', () => {
+ beforeEach(async () => {
+ setupTarget(harness);
- await setupConditionImport(harness);
- });
+ await setupConditionImport(harness);
+ });
- interface ImportsTestCase {
- name: string;
- mapping: unknown;
- output?: string;
- }
+ interface ImportsTestCase {
+ name: string;
+ mapping: unknown;
+ output?: string;
+ }
- const GOOD_TARGET = './src/good.js';
- const BAD_TARGET = './src/bad.js';
+ const GOOD_TARGET = './src/good.js';
+ const BAD_TARGET = './src/bad.js';
- const testCases: ImportsTestCase[] = [
- { name: 'simple string', mapping: GOOD_TARGET },
- {
- name: 'default fallback without matching condition',
- mapping: {
- 'never': BAD_TARGET,
- 'default': GOOD_TARGET,
- },
+ const testCases: ImportsTestCase[] = [
+ { name: 'simple string', mapping: GOOD_TARGET },
+ {
+ name: 'default fallback without matching condition',
+ mapping: {
+ 'never': BAD_TARGET,
+ 'default': GOOD_TARGET,
},
- {
- name: 'development condition',
- mapping: {
- 'development': GOOD_TARGET,
- 'default': BAD_TARGET,
- },
+ },
+ {
+ name: 'development condition',
+ mapping: {
+ 'development': GOOD_TARGET,
+ 'default': BAD_TARGET,
},
- {
- name: 'production condition',
- mapping: {
- 'production': BAD_TARGET,
- 'default': GOOD_TARGET,
- },
+ },
+ {
+ name: 'production condition',
+ mapping: {
+ 'production': BAD_TARGET,
+ 'default': GOOD_TARGET,
},
- {
- name: 'browser condition (in browser)',
- mapping: {
- 'browser': GOOD_TARGET,
- 'default': BAD_TARGET,
- },
+ },
+ {
+ name: 'browser condition (in browser)',
+ mapping: {
+ 'browser': GOOD_TARGET,
+ 'default': BAD_TARGET,
},
- ];
+ },
+ ];
- for (const testCase of testCases) {
- describe(testCase.name, () => {
- beforeEach(async () => {
- await setTargetMapping(harness, testCase.mapping);
- });
+ for (const testCase of testCases) {
+ describe(testCase.name, () => {
+ beforeEach(async () => {
+ await setTargetMapping(harness, testCase.mapping);
+ });
- it('resolves to expected target', async () => {
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- });
+ it('resolves to expected target', async () => {
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
+ });
- const { result, response } = await executeOnceAndFetch(harness, '/main.js');
+ const { result, response } = await executeOnceAndFetch(harness, '/main.js');
- expect(result?.success).toBeTrue();
- const output = await response?.text();
- expect(output).toContain('good-value');
- expect(output).not.toContain('bad-value');
- });
+ expect(result?.success).toBeTrue();
+ const output = await response?.text();
+ expect(output).toContain('good-value');
+ expect(output).not.toContain('bad-value');
});
- }
- });
- },
-);
+ });
+ }
+ });
+});
diff --git a/packages/angular/build/src/builders/dev-server/tests/behavior/build_translation_watch_spec.ts b/packages/angular/build/src/builders/dev-server/tests/behavior/build_translation_watch_spec.ts
index b7d65e52e966..24dca8a6a5dc 100644
--- a/packages/angular/build/src/builders/dev-server/tests/behavior/build_translation_watch_spec.ts
+++ b/packages/angular/build/src/builders/dev-server/tests/behavior/build_translation_watch_spec.ts
@@ -12,70 +12,66 @@ import { executeDevServer } from '../../index';
import { describeServeBuilder } from '../jasmine-helpers';
import { BASE_OPTIONS, DEV_SERVER_BUILDER_INFO } from '../setup';
-describeServeBuilder(
- executeDevServer,
- DEV_SERVER_BUILDER_INFO,
- (harness, setupTarget, isViteRun) => {
- // TODO(fix-vite): currently this is broken in vite.
- (isViteRun ? xdescribe : describe)('Behavior: "i18n translation file watching"', () => {
- beforeEach(() => {
- harness.useProject('test', {
- root: '.',
- sourceRoot: 'src',
- cli: {
- cache: {
- enabled: false,
- },
+describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupTarget) => {
+ // TODO(fix-vite): currently this is broken in vite.
+ xdescribe('Behavior: "i18n translation file watching"', () => {
+ beforeEach(() => {
+ harness.useProject('test', {
+ root: '.',
+ sourceRoot: 'src',
+ cli: {
+ cache: {
+ enabled: false,
},
- i18n: {
- locales: {
- fr: 'src/locales/messages.fr.xlf',
- },
+ },
+ i18n: {
+ locales: {
+ fr: 'src/locales/messages.fr.xlf',
},
- });
-
- setupTarget(harness, { localize: ['fr'] });
+ },
});
- it('watches i18n translation files by default', async () => {
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- watch: true,
- });
+ setupTarget(harness, { localize: ['fr'] });
+ });
+
+ it('watches i18n translation files by default', async () => {
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
+ watch: true,
+ });
- await harness.writeFile(
- 'src/app/app.component.html',
- `
+ await harness.writeFile(
+ 'src/app/app.component.html',
+ `
Hello {{ title }}!
`,
- );
+ );
- await harness.writeFile('src/locales/messages.fr.xlf', TRANSLATION_FILE_CONTENT);
+ await harness.writeFile('src/locales/messages.fr.xlf', TRANSLATION_FILE_CONTENT);
- await harness.executeWithCases([
- async ({ result }) => {
- expect(result?.success).toBe(true);
+ await harness.executeWithCases([
+ async ({ result }) => {
+ expect(result?.success).toBe(true);
- const mainUrl = new URL('main.js', `${result?.baseUrl}`);
- const response = await fetch(mainUrl);
- expect(await response?.text()).toContain('Bonjour');
+ const mainUrl = new URL('main.js', `${result?.baseUrl}`);
+ const response = await fetch(mainUrl);
+ expect(await response?.text()).toContain('Bonjour');
- await harness.modifyFile('src/locales/messages.fr.xlf', (content) =>
- content.replace('Bonjour', 'Salut'),
- );
- },
- async ({ result }) => {
- expect(result?.success).toBe(true);
+ await harness.modifyFile('src/locales/messages.fr.xlf', (content) =>
+ content.replace('Bonjour', 'Salut'),
+ );
+ },
+ async ({ result }) => {
+ expect(result?.success).toBe(true);
- const mainUrl = new URL('main.js', `${result?.baseUrl}`);
- const response = await fetch(mainUrl);
- expect(await response?.text()).toContain('Salut');
- },
- ]);
- });
+ const mainUrl = new URL('main.js', `${result?.baseUrl}`);
+ const response = await fetch(mainUrl);
+ expect(await response?.text()).toContain('Salut');
+ },
+ ]);
});
- },
-);
+ });
+});
const TRANSLATION_FILE_CONTENT = `
diff --git a/packages/angular/build/src/builders/dev-server/tests/behavior/serve-live-reload-proxies_spec.ts b/packages/angular/build/src/builders/dev-server/tests/behavior/serve-live-reload-proxies_spec.ts
index efdd749de258..6c41769d5aea 100644
--- a/packages/angular/build/src/builders/dev-server/tests/behavior/serve-live-reload-proxies_spec.ts
+++ b/packages/angular/build/src/builders/dev-server/tests/behavior/serve-live-reload-proxies_spec.ts
@@ -133,145 +133,138 @@ async function goToPageAndWaitForWS(page: Page, url: string): Promise {
await client.detach();
}
-describeServeBuilder(
- executeDevServer,
- DEV_SERVER_BUILDER_INFO,
- (harness, setupTarget, isViteRun) => {
- // TODO(fix-vite): currently this is broken in vite.
- (isViteRun ? xdescribe : describe)(
- 'Behavior: "Dev-server builder live-reload with proxies"',
- () => {
- let browser: Browser;
- let page: Page;
+describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupTarget) => {
+ // TODO(fix-vite): currently this is broken in vite.
+ xdescribe('Behavior: "Dev-server builder live-reload with proxies"', () => {
+ let browser: Browser;
+ let page: Page;
- const SERVE_OPTIONS = Object.freeze({
- ...BASE_OPTIONS,
- hmr: false,
- watch: true,
- liveReload: true,
- });
+ const SERVE_OPTIONS = Object.freeze({
+ ...BASE_OPTIONS,
+ hmr: false,
+ watch: true,
+ liveReload: true,
+ });
- beforeAll(async () => {
- browser = await puppeteer.launch({
- // MacOSX users need to set the local binary manually because Chrome has lib files with
- // spaces in them which Bazel does not support in runfiles
- // See: https://github.com/angular/angular-cli/pull/17624
- // eslint-disable-next-line max-len
- // executablePath: '/Users//git/angular-cli/node_modules/puppeteer/.local-chromium/mac-818858/chrome-mac/Chromium.app/Contents/MacOS/Chromium',
- ignoreHTTPSErrors: true,
- args: ['--no-sandbox', '--disable-gpu'],
- });
- });
+ beforeAll(async () => {
+ browser = await puppeteer.launch({
+ // MacOSX users need to set the local binary manually because Chrome has lib files with
+ // spaces in them which Bazel does not support in runfiles
+ // See: https://github.com/angular/angular-cli/pull/17624
+ // eslint-disable-next-line max-len
+ // executablePath: '/Users//git/angular-cli/node_modules/puppeteer/.local-chromium/mac-818858/chrome-mac/Chromium.app/Contents/MacOS/Chromium',
+ ignoreHTTPSErrors: true,
+ args: ['--no-sandbox', '--disable-gpu'],
+ });
+ });
- afterAll(async () => {
- await browser.close();
- });
+ afterAll(async () => {
+ await browser.close();
+ });
- beforeEach(async () => {
- setupTarget(harness, {
- polyfills: ['src/polyfills.ts'],
- });
+ beforeEach(async () => {
+ setupTarget(harness, {
+ polyfills: ['src/polyfills.ts'],
+ });
- page = await browser.newPage();
- });
+ page = await browser.newPage();
+ });
- afterEach(async () => {
- await page.close();
- });
+ afterEach(async () => {
+ await page.close();
+ });
- it('works without proxy', async () => {
- harness.useTarget('serve', {
- ...SERVE_OPTIONS,
- });
+ it('works without proxy', async () => {
+ harness.useTarget('serve', {
+ ...SERVE_OPTIONS,
+ });
- await harness.writeFile('src/app/app.component.html', '{{ title }}
');
+ await harness.writeFile('src/app/app.component.html', '{{ title }}
');
- await harness.executeWithCases([
- async ({ result }) => {
- expect(result?.success).toBeTrue();
- if (typeof result?.baseUrl !== 'string') {
- throw new Error('Expected "baseUrl" to be a string.');
- }
+ await harness.executeWithCases([
+ async ({ result }) => {
+ expect(result?.success).toBeTrue();
+ if (typeof result?.baseUrl !== 'string') {
+ throw new Error('Expected "baseUrl" to be a string.');
+ }
- await goToPageAndWaitForWS(page, result.baseUrl);
- await harness.modifyFile('src/app/app.component.ts', (content) =>
- content.replace(`'app'`, `'app-live-reload'`),
- );
- },
- async ({ result }) => {
- expect(result?.success).toBeTrue();
- const innerText = await page.evaluate(() => document.querySelector('p').innerText);
- expect(innerText).toBe('app-live-reload');
- },
- ]);
- });
+ await goToPageAndWaitForWS(page, result.baseUrl);
+ await harness.modifyFile('src/app/app.component.ts', (content) =>
+ content.replace(`'app'`, `'app-live-reload'`),
+ );
+ },
+ async ({ result }) => {
+ expect(result?.success).toBeTrue();
+ const innerText = await page.evaluate(() => document.querySelector('p').innerText);
+ expect(innerText).toBe('app-live-reload');
+ },
+ ]);
+ });
- it('works without http -> http proxy', async () => {
- harness.useTarget('serve', {
- ...SERVE_OPTIONS,
- });
+ it('works without http -> http proxy', async () => {
+ harness.useTarget('serve', {
+ ...SERVE_OPTIONS,
+ });
- await harness.writeFile('src/app/app.component.html', '{{ title }}
');
+ await harness.writeFile('src/app/app.component.html', '{{ title }}
');
- let proxy: ProxyInstance | undefined;
- try {
- await harness.executeWithCases([
- async ({ result }) => {
- expect(result?.success).toBeTrue();
- if (typeof result?.baseUrl !== 'string') {
- throw new Error('Expected "baseUrl" to be a string.');
- }
+ let proxy: ProxyInstance | undefined;
+ try {
+ await harness.executeWithCases([
+ async ({ result }) => {
+ expect(result?.success).toBeTrue();
+ if (typeof result?.baseUrl !== 'string') {
+ throw new Error('Expected "baseUrl" to be a string.');
+ }
- proxy = await createProxy(result.baseUrl, false);
- await goToPageAndWaitForWS(page, proxy.url);
- await harness.modifyFile('src/app/app.component.ts', (content) =>
- content.replace(`'app'`, `'app-live-reload'`),
- );
- },
- async ({ result }) => {
- expect(result?.success).toBeTrue();
- const innerText = await page.evaluate(() => document.querySelector('p').innerText);
- expect(innerText).toBe('app-live-reload');
- },
- ]);
- } finally {
- proxy?.server.close();
- }
- });
+ proxy = await createProxy(result.baseUrl, false);
+ await goToPageAndWaitForWS(page, proxy.url);
+ await harness.modifyFile('src/app/app.component.ts', (content) =>
+ content.replace(`'app'`, `'app-live-reload'`),
+ );
+ },
+ async ({ result }) => {
+ expect(result?.success).toBeTrue();
+ const innerText = await page.evaluate(() => document.querySelector('p').innerText);
+ expect(innerText).toBe('app-live-reload');
+ },
+ ]);
+ } finally {
+ proxy?.server.close();
+ }
+ });
- it('works without https -> http proxy', async () => {
- harness.useTarget('serve', {
- ...SERVE_OPTIONS,
- });
+ it('works without https -> http proxy', async () => {
+ harness.useTarget('serve', {
+ ...SERVE_OPTIONS,
+ });
- await harness.writeFile('src/app/app.component.html', '{{ title }}
');
+ await harness.writeFile('src/app/app.component.html', '{{ title }}
');
- let proxy: ProxyInstance | undefined;
- try {
- await harness.executeWithCases([
- async ({ result }) => {
- expect(result?.success).toBeTrue();
- if (typeof result?.baseUrl !== 'string') {
- throw new Error('Expected "baseUrl" to be a string.');
- }
+ let proxy: ProxyInstance | undefined;
+ try {
+ await harness.executeWithCases([
+ async ({ result }) => {
+ expect(result?.success).toBeTrue();
+ if (typeof result?.baseUrl !== 'string') {
+ throw new Error('Expected "baseUrl" to be a string.');
+ }
- proxy = await createProxy(result.baseUrl, true);
- await goToPageAndWaitForWS(page, proxy.url);
- await harness.modifyFile('src/app/app.component.ts', (content) =>
- content.replace(`'app'`, `'app-live-reload'`),
- );
- },
- async ({ result }) => {
- expect(result?.success).toBeTrue();
- const innerText = await page.evaluate(() => document.querySelector('p').innerText);
- expect(innerText).toBe('app-live-reload');
- },
- ]);
- } finally {
- proxy?.server.close();
- }
- });
- },
- );
- },
-);
+ proxy = await createProxy(result.baseUrl, true);
+ await goToPageAndWaitForWS(page, proxy.url);
+ await harness.modifyFile('src/app/app.component.ts', (content) =>
+ content.replace(`'app'`, `'app-live-reload'`),
+ );
+ },
+ async ({ result }) => {
+ expect(result?.success).toBeTrue();
+ const innerText = await page.evaluate(() => document.querySelector('p').innerText);
+ expect(innerText).toBe('app-live-reload');
+ },
+ ]);
+ } finally {
+ proxy?.server.close();
+ }
+ });
+ });
+});
diff --git a/packages/angular/build/src/builders/dev-server/tests/behavior/serve_service-worker_spec.ts b/packages/angular/build/src/builders/dev-server/tests/behavior/serve_service-worker_spec.ts
index b3b63c3a3093..10e2cee70465 100644
--- a/packages/angular/build/src/builders/dev-server/tests/behavior/serve_service-worker_spec.ts
+++ b/packages/angular/build/src/builders/dev-server/tests/behavior/serve_service-worker_spec.ts
@@ -36,180 +36,174 @@ const manifest = {
],
};
-describeServeBuilder(
- executeDevServer,
- DEV_SERVER_BUILDER_INFO,
- (harness, setupTarget, isViteRun) => {
- describe('Behavior: "dev-server builder serves service worker"', () => {
- beforeEach(async () => {
- // Application code is not needed for these tests
- await harness.writeFile('src/main.ts', '');
- await harness.writeFile('src/polyfills.ts', '');
-
- harness.useProject('test', {
- root: '.',
- sourceRoot: 'src',
- cli: {
- cache: {
- enabled: false,
- },
+describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupTarget) => {
+ describe('Behavior: "dev-server builder serves service worker"', () => {
+ beforeEach(async () => {
+ // Application code is not needed for these tests
+ await harness.writeFile('src/main.ts', '');
+ await harness.writeFile('src/polyfills.ts', '');
+
+ harness.useProject('test', {
+ root: '.',
+ sourceRoot: 'src',
+ cli: {
+ cache: {
+ enabled: false,
},
- i18n: {
- sourceLocale: {
- code: 'fr',
- },
+ },
+ i18n: {
+ sourceLocale: {
+ code: 'fr',
},
- });
+ },
+ });
+ });
+
+ it('works with service worker', async () => {
+ setupTarget(harness, {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ serviceWorker: 'ngsw-config.json',
+ assets: ['src/favicon.ico', 'src/assets'],
+ styles: ['src/styles.css'],
});
- it('works with service worker', async () => {
- setupTarget(harness, {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- serviceWorker: (isViteRun ? 'ngsw-config.json' : true) as any,
- assets: ['src/favicon.ico', 'src/assets'],
- styles: ['src/styles.css'],
- });
-
- await harness.writeFiles({
- 'ngsw-config.json': JSON.stringify(manifest),
- 'src/assets/folder-asset.txt': 'folder-asset.txt',
- 'src/styles.css': `body { background: url(./spectrum.png); }`,
- });
-
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- });
-
- const { result, response } = await executeOnceAndFetch(harness, '/ngsw.json');
-
- expect(result?.success).toBeTrue();
-
- expect(await response?.json()).toEqual(
- jasmine.objectContaining({
- configVersion: 1,
- index: '/index.html',
- navigationUrls: [
- { positive: true, regex: '^\\/.*$' },
- { positive: false, regex: '^\\/(?:.+\\/)?[^/]*\\.[^/]*$' },
- { positive: false, regex: '^\\/(?:.+\\/)?[^/]*__[^/]*$' },
- { positive: false, regex: '^\\/(?:.+\\/)?[^/]*__[^/]*\\/.*$' },
- ],
- assetGroups: [
- {
- name: 'app',
- installMode: 'prefetch',
- updateMode: 'prefetch',
- urls: ['/favicon.ico', '/index.html'],
- cacheQueryOptions: {
- ignoreVary: true,
- },
- patterns: [],
+ await harness.writeFiles({
+ 'ngsw-config.json': JSON.stringify(manifest),
+ 'src/assets/folder-asset.txt': 'folder-asset.txt',
+ 'src/styles.css': `body { background: url(./spectrum.png); }`,
+ });
+
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
+ });
+
+ const { result, response } = await executeOnceAndFetch(harness, '/ngsw.json');
+
+ expect(result?.success).toBeTrue();
+
+ expect(await response?.json()).toEqual(
+ jasmine.objectContaining({
+ configVersion: 1,
+ index: '/index.html',
+ navigationUrls: [
+ { positive: true, regex: '^\\/.*$' },
+ { positive: false, regex: '^\\/(?:.+\\/)?[^/]*\\.[^/]*$' },
+ { positive: false, regex: '^\\/(?:.+\\/)?[^/]*__[^/]*$' },
+ { positive: false, regex: '^\\/(?:.+\\/)?[^/]*__[^/]*\\/.*$' },
+ ],
+ assetGroups: [
+ {
+ name: 'app',
+ installMode: 'prefetch',
+ updateMode: 'prefetch',
+ urls: ['/favicon.ico', '/index.html'],
+ cacheQueryOptions: {
+ ignoreVary: true,
},
- {
- name: 'assets',
- installMode: 'lazy',
- updateMode: 'prefetch',
- urls: ['/assets/folder-asset.txt', '/media/spectrum.png'],
- cacheQueryOptions: {
- ignoreVary: true,
- },
- patterns: [],
+ patterns: [],
+ },
+ {
+ name: 'assets',
+ installMode: 'lazy',
+ updateMode: 'prefetch',
+ urls: ['/assets/folder-asset.txt', '/media/spectrum.png'],
+ cacheQueryOptions: {
+ ignoreVary: true,
},
- ],
- dataGroups: [],
- hashTable: {
- '/favicon.ico': '84161b857f5c547e3699ddfbffc6d8d737542e01',
- '/assets/folder-asset.txt': '617f202968a6a81050aa617c2e28e1dca11ce8d4',
- '/index.html': isViteRun
- ? 'e5b73e6798d2782bf59dd5272d254d5bde364695'
- : '9d232e3e13b4605d197037224a2a6303dd337480',
- '/media/spectrum.png': '8d048ece46c0f3af4b598a95fd8e4709b631c3c0',
+ patterns: [],
},
- }),
- );
+ ],
+ dataGroups: [],
+ hashTable: {
+ '/favicon.ico': '84161b857f5c547e3699ddfbffc6d8d737542e01',
+ '/assets/folder-asset.txt': '617f202968a6a81050aa617c2e28e1dca11ce8d4',
+ '/index.html': 'e5b73e6798d2782bf59dd5272d254d5bde364695',
+ '/media/spectrum.png': '8d048ece46c0f3af4b598a95fd8e4709b631c3c0',
+ },
+ }),
+ );
+ });
+
+ it('works with localize', async () => {
+ setupTarget(harness, {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ serviceWorker: 'ngsw-config.json' as any,
+ assets: ['src/favicon.ico', 'src/assets'],
+ styles: ['src/styles.css'],
+ localize: ['fr'],
});
- it('works with localize', async () => {
- setupTarget(harness, {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- serviceWorker: (isViteRun ? 'ngsw-config.json' : true) as any,
- assets: ['src/favicon.ico', 'src/assets'],
- styles: ['src/styles.css'],
- localize: ['fr'],
- });
+ await harness.writeFiles({
+ 'ngsw-config.json': JSON.stringify(manifest),
+ 'src/assets/folder-asset.txt': 'folder-asset.txt',
+ 'src/styles.css': `body { background: url(./spectrum.png); }`,
+ });
+
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
+ });
- await harness.writeFiles({
- 'ngsw-config.json': JSON.stringify(manifest),
- 'src/assets/folder-asset.txt': 'folder-asset.txt',
- 'src/styles.css': `body { background: url(./spectrum.png); }`,
- });
+ const { result, response } = await executeOnceAndFetch(harness, '/ngsw.json');
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- });
+ expect(result?.success).toBeTrue();
- const { result, response } = await executeOnceAndFetch(harness, '/ngsw.json');
+ expect(await response?.json()).toBeDefined();
+ });
- expect(result?.success).toBeTrue();
+ // TODO(fix-vite): currently this is broken in vite due to watcher never terminates.
+ xit('works in watch mode', async () => {
+ setupTarget(harness, {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ serviceWorker: 'ngsw-config.json' as any,
+ assets: ['src/favicon.ico', 'src/assets'],
+ styles: ['src/styles.css'],
+ });
- expect(await response?.json()).toBeDefined();
+ await harness.writeFiles({
+ 'ngsw-config.json': JSON.stringify(manifest),
+ 'src/assets/folder-asset.txt': 'folder-asset.txt',
+ 'src/styles.css': `body { background: url(./spectrum.png); }`,
});
- // TODO(fix-vite): currently this is broken in vite due to watcher never terminates.
- (isViteRun ? xit : it)('works in watch mode', async () => {
- setupTarget(harness, {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- serviceWorker: (isViteRun ? 'ngsw-config.json' : true) as any,
- assets: ['src/favicon.ico', 'src/assets'],
- styles: ['src/styles.css'],
- });
-
- await harness.writeFiles({
- 'ngsw-config.json': JSON.stringify(manifest),
- 'src/assets/folder-asset.txt': 'folder-asset.txt',
- 'src/styles.css': `body { background: url(./spectrum.png); }`,
- });
-
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- watch: true,
- });
-
- await harness.executeWithCases([
- async ({ result }) => {
- expect(result?.success).toBeTrue();
- const response = await fetch(new URL('ngsw.json', `${result?.baseUrl}`));
- const { hashTable } = (await response.json()) as { hashTable: object };
- const hashTableEntries = Object.keys(hashTable);
-
- expect(hashTableEntries).toEqual([
- '/assets/folder-asset.txt',
- '/favicon.ico',
- '/index.html',
- '/media/spectrum.png',
- ]);
-
- await harness.writeFile(
- 'src/assets/folder-new-asset.txt',
- harness.readFile('src/assets/folder-asset.txt'),
- );
- },
- async ({ result }) => {
- expect(result?.success).toBeTrue();
- const response = await fetch(new URL('ngsw.json', `${result?.baseUrl}`));
- const { hashTable } = (await response.json()) as { hashTable: object };
- const hashTableEntries = Object.keys(hashTable);
-
- expect(hashTableEntries).toEqual([
- '/assets/folder-asset.txt',
- '/assets/folder-new-asset.txt',
- '/favicon.ico',
- '/index.html',
- '/media/spectrum.png',
- ]);
- },
- ]);
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
+ watch: true,
});
+
+ await harness.executeWithCases([
+ async ({ result }) => {
+ expect(result?.success).toBeTrue();
+ const response = await fetch(new URL('ngsw.json', `${result?.baseUrl}`));
+ const { hashTable } = (await response.json()) as { hashTable: object };
+ const hashTableEntries = Object.keys(hashTable);
+
+ expect(hashTableEntries).toEqual([
+ '/assets/folder-asset.txt',
+ '/favicon.ico',
+ '/index.html',
+ '/media/spectrum.png',
+ ]);
+
+ await harness.writeFile(
+ 'src/assets/folder-new-asset.txt',
+ harness.readFile('src/assets/folder-asset.txt'),
+ );
+ },
+ async ({ result }) => {
+ expect(result?.success).toBeTrue();
+ const response = await fetch(new URL('ngsw.json', `${result?.baseUrl}`));
+ const { hashTable } = (await response.json()) as { hashTable: object };
+ const hashTableEntries = Object.keys(hashTable);
+
+ expect(hashTableEntries).toEqual([
+ '/assets/folder-asset.txt',
+ '/assets/folder-new-asset.txt',
+ '/favicon.ico',
+ '/index.html',
+ '/media/spectrum.png',
+ ]);
+ },
+ ]);
});
- },
-);
+ });
+});
diff --git a/packages/angular/build/src/builders/dev-server/tests/jasmine-helpers.ts b/packages/angular/build/src/builders/dev-server/tests/jasmine-helpers.ts
index c5a73446cf5a..e680fe0f62ab 100644
--- a/packages/angular/build/src/builders/dev-server/tests/jasmine-helpers.ts
+++ b/packages/angular/build/src/builders/dev-server/tests/jasmine-helpers.ts
@@ -19,7 +19,6 @@ export function describeServeBuilder(
specDefinitions: (
harness: JasmineBuilderHarness,
setupTarget: typeof setupApplicationTarget,
- isViteRun: true,
) => void,
): void {
let optionSchema = optionSchemaCache.get(options.schemaPath);
@@ -36,6 +35,6 @@ export function describeServeBuilder(
beforeEach(() => host.initialize().toPromise());
afterEach(() => host.restore().toPromise());
- specDefinitions(harness, setupApplicationTarget, true);
+ specDefinitions(harness, setupApplicationTarget);
});
}
diff --git a/packages/angular/build/src/builders/dev-server/tests/options/port_spec.ts b/packages/angular/build/src/builders/dev-server/tests/options/port_spec.ts
index 83f3a4d1486b..8869dd20dcbb 100644
--- a/packages/angular/build/src/builders/dev-server/tests/options/port_spec.ts
+++ b/packages/angular/build/src/builders/dev-server/tests/options/port_spec.ts
@@ -26,87 +26,58 @@ function getResultPort(result: Record | undefined): string | un
}
}
-describeServeBuilder(
- executeDevServer,
- DEV_SERVER_BUILDER_INFO,
- (harness, setupTarget, isViteRun) => {
- describe('option: "port"', () => {
- beforeEach(async () => {
- setupTarget(harness);
-
- // Application code is not needed for these tests
- await harness.writeFile('src/main.ts', '');
- });
+describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupTarget) => {
+ describe('option: "port"', () => {
+ beforeEach(async () => {
+ setupTarget(harness);
+
+ // Application code is not needed for these tests
+ await harness.writeFile('src/main.ts', '');
+ });
- it('uses default port (4200) when not present', async () => {
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- // Base options set port to zero
- port: undefined,
- });
-
- const { result, response, logs } = await executeOnceAndFetch(harness, '/');
-
- expect(result?.success).toBeTrue();
- expect(getResultPort(result)).toBe('4200');
- expect(await response?.text()).toContain('');
-
- if (!isViteRun) {
- expect(logs).toContain(
- jasmine.objectContaining({
- message: jasmine.stringMatching(/:4200/),
- }),
- );
- }
+ it('uses default port (4200) when not present', async () => {
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
+ // Base options set port to zero
+ port: undefined,
});
- it('uses a random free port when set to 0 (zero)', async () => {
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- port: 0,
- });
-
- const { result, response, logs } = await executeOnceAndFetch(harness, '/');
-
- expect(result?.success).toBeTrue();
- const port = getResultPort(result);
- expect(port).not.toBe('4200');
- if (isViteRun) {
- // Should not be default Vite port either
- expect(port).not.toBe('5173');
- }
-
- expect(port).toMatch(/\d{4,6}/);
- expect(await response?.text()).toContain('');
-
- if (!isViteRun) {
- expect(logs).toContain(
- jasmine.objectContaining({
- message: jasmine.stringMatching(':' + port),
- }),
- );
- }
+ const { result, response, logs } = await executeOnceAndFetch(harness, '/');
+
+ expect(result?.success).toBeTrue();
+ expect(getResultPort(result)).toBe('4200');
+ expect(await response?.text()).toContain('');
+ });
+
+ it('uses a random free port when set to 0 (zero)', async () => {
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
+ port: 0,
});
- it('uses specific port when a non-zero number is specified', async () => {
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- port: 8000,
- });
-
- const { result, response, logs } = await executeOnceAndFetch(harness, '/');
-
- expect(result?.success).toBeTrue();
- expect(getResultPort(result)).toBe('8000');
- expect(await response?.text()).toContain('');
- if (!isViteRun) {
- expect(logs).toContain(
- jasmine.objectContaining({
- message: jasmine.stringMatching(':8000'),
- }),
- );
- }
+ const { result, response, logs } = await executeOnceAndFetch(harness, '/');
+
+ expect(result?.success).toBeTrue();
+ const port = getResultPort(result);
+ expect(port).not.toBe('4200');
+ // Should not be default Vite port either
+ expect(port).not.toBe('5173');
+
+ expect(port).toMatch(/\d{4,6}/);
+ expect(await response?.text()).toContain('');
+ });
+
+ it('uses specific port when a non-zero number is specified', async () => {
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
+ port: 8000,
});
+
+ const { result, response, logs } = await executeOnceAndFetch(harness, '/');
+
+ expect(result?.success).toBeTrue();
+ expect(getResultPort(result)).toBe('8000');
+ expect(await response?.text()).toContain('');
});
- },
-);
+ });
+});
diff --git a/packages/angular/build/src/builders/dev-server/tests/options/prebundle_spec.ts b/packages/angular/build/src/builders/dev-server/tests/options/prebundle_spec.ts
index 1e7c5fcd7322..80bab96d3bb8 100644
--- a/packages/angular/build/src/builders/dev-server/tests/options/prebundle_spec.ts
+++ b/packages/angular/build/src/builders/dev-server/tests/options/prebundle_spec.ts
@@ -12,88 +12,84 @@ import { describeServeBuilder } from '../jasmine-helpers';
import { BASE_OPTIONS, DEV_SERVER_BUILDER_INFO } from '../setup';
// TODO: Temporarily disabled pending investigation into test-only Vite not stopping when caching is enabled
-describeServeBuilder(
- executeDevServer,
- DEV_SERVER_BUILDER_INFO,
- (harness, setupTarget, isViteRun) => {
- // prebundling is not available in webpack
- (isViteRun ? xdescribe : xdescribe)('option: "prebundle"', () => {
- beforeEach(async () => {
- setupTarget(harness);
-
- harness.useProject('test', {
- cli: {
- cache: {
- enabled: true,
- },
+describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupTarget) => {
+ // prebundling is not available in webpack
+ xdescribe('option: "prebundle"', () => {
+ beforeEach(async () => {
+ setupTarget(harness);
+
+ harness.useProject('test', {
+ cli: {
+ cache: {
+ enabled: true,
},
- });
+ },
+ });
- // Application code is not needed for these tests
- await harness.writeFile(
- 'src/main.ts',
- `
+ // Application code is not needed for these tests
+ await harness.writeFile(
+ 'src/main.ts',
+ `
import { VERSION as coreVersion } from '@angular/core';
import { VERSION as platformVersion } from '@angular/platform-browser';
console.log(coreVersion);
console.log(platformVersion);
`,
- );
+ );
+ });
+
+ it('should prebundle dependencies when option is not present', async () => {
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
});
- it('should prebundle dependencies when option is not present', async () => {
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- });
+ const { result, content } = await executeOnceAndFetch(harness, '/main.js');
- const { result, content } = await executeOnceAndFetch(harness, '/main.js');
+ expect(result?.success).toBeTrue();
+ expect(content).toContain('vite/deps/@angular_core.js');
+ expect(content).not.toContain('node_modules/@angular/core/');
+ });
- expect(result?.success).toBeTrue();
- expect(content).toContain('vite/deps/@angular_core.js');
- expect(content).not.toContain('node_modules/@angular/core/');
+ it('should prebundle dependencies when option is set to true', async () => {
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
+ prebundle: true,
});
- it('should prebundle dependencies when option is set to true', async () => {
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- prebundle: true,
- });
+ const { result, content } = await executeOnceAndFetch(harness, '/main.js');
- const { result, content } = await executeOnceAndFetch(harness, '/main.js');
+ expect(result?.success).toBeTrue();
+ expect(content).toContain('vite/deps/@angular_core.js');
+ expect(content).not.toContain('node_modules/@angular/core/');
+ });
- expect(result?.success).toBeTrue();
- expect(content).toContain('vite/deps/@angular_core.js');
- expect(content).not.toContain('node_modules/@angular/core/');
+ it('should not prebundle dependencies when option is set to false', async () => {
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
+ prebundle: false,
});
- it('should not prebundle dependencies when option is set to false', async () => {
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- prebundle: false,
- });
+ const { result, content } = await executeOnceAndFetch(harness, '/main.js');
- const { result, content } = await executeOnceAndFetch(harness, '/main.js');
+ expect(result?.success).toBeTrue();
+ expect(content).not.toContain('vite/deps/@angular_core.js');
+ expect(content).toContain('node_modules/@angular/core/');
+ });
- expect(result?.success).toBeTrue();
- expect(content).not.toContain('vite/deps/@angular_core.js');
- expect(content).toContain('node_modules/@angular/core/');
+ it('should not prebundle specified dependency if added to exclude list', async () => {
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
+ prebundle: { exclude: ['@angular/platform-browser'] },
});
- it('should not prebundle specified dependency if added to exclude list', async () => {
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- prebundle: { exclude: ['@angular/platform-browser'] },
- });
+ const { result, content } = await executeOnceAndFetch(harness, '/main.js');
- const { result, content } = await executeOnceAndFetch(harness, '/main.js');
-
- expect(result?.success).toBeTrue();
- expect(content).toContain('vite/deps/@angular_core.js');
- expect(content).not.toContain('node_modules/@angular/core/');
- expect(content).not.toContain('vite/deps/@angular_platform-browser.js');
- expect(content).toContain('node_modules/@angular/platform-browser/');
- });
+ expect(result?.success).toBeTrue();
+ expect(content).toContain('vite/deps/@angular_core.js');
+ expect(content).not.toContain('node_modules/@angular/core/');
+ expect(content).not.toContain('vite/deps/@angular_platform-browser.js');
+ expect(content).toContain('node_modules/@angular/platform-browser/');
});
- },
-);
+ });
+});
diff --git a/packages/angular/build/src/builders/dev-server/tests/options/proxy-config_spec.ts b/packages/angular/build/src/builders/dev-server/tests/options/proxy-config_spec.ts
index 78f3323b97cc..1c6dfb60ca9d 100644
--- a/packages/angular/build/src/builders/dev-server/tests/options/proxy-config_spec.ts
+++ b/packages/angular/build/src/builders/dev-server/tests/options/proxy-config_spec.ts
@@ -12,7 +12,7 @@ import { executeOnceAndFetch } from '../execute-fetch';
import { describeServeBuilder } from '../jasmine-helpers';
import { BASE_OPTIONS, DEV_SERVER_BUILDER_INFO, BuilderHarness } from '../setup';
-describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupTarget, isVite) => {
+describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupTarget) => {
describe('option: "proxyConfig"', () => {
beforeEach(async () => {
setupTarget(harness);
@@ -236,14 +236,51 @@ describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupT
}
});
- /**
- * ****************************************************************************************************
- * ********************************** Below only Vite specific tests **********************************
- * ****************************************************************************************************
- */
- if (isVite) {
- viteOnlyTests(harness);
- }
+ it('proxies support regexp as context', async () => {
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
+ proxyConfig: 'proxy.config.json',
+ });
+
+ const proxyServer = await createProxyServer();
+ try {
+ await harness.writeFiles({
+ 'proxy.config.json': `
+ { "^/api/.*": { "target": "http://127.0.0.1:${proxyServer.address.port}" } }
+ `,
+ });
+
+ const { result, response } = await executeOnceAndFetch(harness, '/api/test');
+
+ expect(result?.success).toBeTrue();
+ expect(await response?.text()).toContain('TEST_API_RETURN');
+ } finally {
+ await proxyServer.close();
+ }
+ });
+
+ it('proxies support negated regexp as context', async () => {
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
+ proxyConfig: 'proxy.config.json',
+ });
+
+ const proxyServer = await createProxyServer();
+ try {
+ await harness.writeFiles({
+ 'proxy.config.json': `
+ { "^\\/(?!something).*": { "target": "http://127.0.0.1:${proxyServer.address.port}" } }
+ `,
+ });
+
+ const { result, response } = await executeOnceAndFetch(harness, '/api/test');
+
+ expect(result?.success).toBeTrue();
+ expect(await response?.text()).toContain('TEST_API_RETURN');
+ } finally {
+ await proxyServer.close();
+ }
+ });
});
});
@@ -270,54 +307,3 @@ async function createProxyServer() {
close: () => new Promise((resolve) => proxyServer.close(() => resolve())),
};
}
-
-/**
- * Vite specific tests
- */
-function viteOnlyTests(harness: BuilderHarness): void {
- it('proxies support regexp as context', async () => {
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- proxyConfig: 'proxy.config.json',
- });
-
- const proxyServer = await createProxyServer();
- try {
- await harness.writeFiles({
- 'proxy.config.json': `
- { "^/api/.*": { "target": "http://127.0.0.1:${proxyServer.address.port}" } }
- `,
- });
-
- const { result, response } = await executeOnceAndFetch(harness, '/api/test');
-
- expect(result?.success).toBeTrue();
- expect(await response?.text()).toContain('TEST_API_RETURN');
- } finally {
- await proxyServer.close();
- }
- });
-
- it('proxies support negated regexp as context', async () => {
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- proxyConfig: 'proxy.config.json',
- });
-
- const proxyServer = await createProxyServer();
- try {
- await harness.writeFiles({
- 'proxy.config.json': `
- { "^\\/(?!something).*": { "target": "http://127.0.0.1:${proxyServer.address.port}" } }
- `,
- });
-
- const { result, response } = await executeOnceAndFetch(harness, '/api/test');
-
- expect(result?.success).toBeTrue();
- expect(await response?.text()).toContain('TEST_API_RETURN');
- } finally {
- await proxyServer.close();
- }
- });
-}
diff --git a/packages/angular/build/src/builders/dev-server/tests/options/serve-path_spec.ts b/packages/angular/build/src/builders/dev-server/tests/options/serve-path_spec.ts
index 7570175c65d2..5917dcc8eeb4 100644
--- a/packages/angular/build/src/builders/dev-server/tests/options/serve-path_spec.ts
+++ b/packages/angular/build/src/builders/dev-server/tests/options/serve-path_spec.ts
@@ -12,109 +12,105 @@ import { executeOnceAndFetch } from '../execute-fetch';
import { describeServeBuilder } from '../jasmine-helpers';
import { BASE_OPTIONS, DEV_SERVER_BUILDER_INFO } from '../setup';
-describeServeBuilder(
- executeDevServer,
- DEV_SERVER_BUILDER_INFO,
- (harness, setupTarget, isViteRun) => {
- describe('option: "servePath"', () => {
- beforeEach(async () => {
- setupTarget(harness, {
- assets: ['src/assets'],
- });
-
- // Application code is not needed for these tests
- await harness.writeFile('src/main.ts', 'console.log("foo");');
+describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupTarget) => {
+ describe('option: "servePath"', () => {
+ beforeEach(async () => {
+ setupTarget(harness, {
+ assets: ['src/assets'],
});
- it('serves application at the root when option is not present', async () => {
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- });
-
- const { result, response } = await executeOnceAndFetch(harness, '/main.js');
+ // Application code is not needed for these tests
+ await harness.writeFile('src/main.ts', 'console.log("foo");');
+ });
- expect(result?.success).toBeTrue();
- const baseUrl = new URL(`${result?.baseUrl}`);
- expect(baseUrl.pathname).toBe('/');
- expect(await response?.text()).toContain('console.log');
+ it('serves application at the root when option is not present', async () => {
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
});
- it('serves application at specified path when option is used', async () => {
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- servePath: 'test',
- });
+ const { result, response } = await executeOnceAndFetch(harness, '/main.js');
- const { result, response } = await executeOnceAndFetch(harness, '/test/main.js');
+ expect(result?.success).toBeTrue();
+ const baseUrl = new URL(`${result?.baseUrl}`);
+ expect(baseUrl.pathname).toBe('/');
+ expect(await response?.text()).toContain('console.log');
+ });
- expect(result?.success).toBeTrue();
- const baseUrl = new URL(`${result?.baseUrl}/`);
- expect(baseUrl.pathname).toBe('/test/');
- expect(await response?.text()).toContain('console.log');
+ it('serves application at specified path when option is used', async () => {
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
+ servePath: 'test',
});
- // TODO(fix-vite): currently this is broken in vite.
- (isViteRun ? xit : it)('does not rewrite from root when option is used', async () => {
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- servePath: 'test',
- });
+ const { result, response } = await executeOnceAndFetch(harness, '/test/main.js');
- const { result, response } = await executeOnceAndFetch(harness, '/', {
- // fallback processing requires an accept header
- request: { headers: { accept: 'text/html' } },
- });
+ expect(result?.success).toBeTrue();
+ const baseUrl = new URL(`${result?.baseUrl}/`);
+ expect(baseUrl.pathname).toBe('/test/');
+ expect(await response?.text()).toContain('console.log');
+ });
- expect(result?.success).toBeTrue();
- expect(response?.status).toBe(404);
+ // TODO(fix-vite): currently this is broken in vite.
+ xit('does not rewrite from root when option is used', async () => {
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
+ servePath: 'test',
});
- it('does not rewrite from path outside serve path when option is used', async () => {
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- servePath: 'test',
- });
+ const { result, response } = await executeOnceAndFetch(harness, '/', {
+ // fallback processing requires an accept header
+ request: { headers: { accept: 'text/html' } },
+ });
- const { result, response } = await executeOnceAndFetch(harness, '/api/', {
- // fallback processing requires an accept header
- request: { headers: { accept: 'text/html' } },
- });
+ expect(result?.success).toBeTrue();
+ expect(response?.status).toBe(404);
+ });
- expect(result?.success).toBeTrue();
- expect(response?.status).toBe(404);
+ it('does not rewrite from path outside serve path when option is used', async () => {
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
+ servePath: 'test',
});
- it('rewrites from path inside serve path when option is used', async () => {
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- servePath: 'test',
- });
+ const { result, response } = await executeOnceAndFetch(harness, '/api/', {
+ // fallback processing requires an accept header
+ request: { headers: { accept: 'text/html' } },
+ });
- const { result, response } = await executeOnceAndFetch(harness, '/test/inside', {
- // fallback processing requires an accept header
- request: { headers: { accept: 'text/html' } },
- });
+ expect(result?.success).toBeTrue();
+ expect(response?.status).toBe(404);
+ });
+
+ it('rewrites from path inside serve path when option is used', async () => {
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
+ servePath: 'test',
+ });
- expect(result?.success).toBeTrue();
- expect(await response?.text()).toContain('');
+ const { result, response } = await executeOnceAndFetch(harness, '/test/inside', {
+ // fallback processing requires an accept header
+ request: { headers: { accept: 'text/html' } },
});
- it('serves assets at specified path when option is used', async () => {
- await harness.writeFile('src/assets/test.txt', 'hello world!');
+ expect(result?.success).toBeTrue();
+ expect(await response?.text()).toContain('');
+ });
- harness.useTarget('serve', {
- ...BASE_OPTIONS,
- servePath: 'test',
- });
+ it('serves assets at specified path when option is used', async () => {
+ await harness.writeFile('src/assets/test.txt', 'hello world!');
- const { result, response } = await executeOnceAndFetch(harness, '/test/assets/test.txt', {
- // fallback processing requires an accept header
- request: { headers: { accept: 'text/html' } },
- });
+ harness.useTarget('serve', {
+ ...BASE_OPTIONS,
+ servePath: 'test',
+ });
- expect(result?.success).toBeTrue();
- expect(await response?.text()).toContain('hello world');
+ const { result, response } = await executeOnceAndFetch(harness, '/test/assets/test.txt', {
+ // fallback processing requires an accept header
+ request: { headers: { accept: 'text/html' } },
});
+
+ expect(result?.success).toBeTrue();
+ expect(await response?.text()).toContain('hello world');
});
- },
-);
+ });
+});
diff --git a/packages/angular/build/src/builders/dev-server/vite/index.ts b/packages/angular/build/src/builders/dev-server/vite/index.ts
index 8129daac1ba1..557b2d34b52a 100644
--- a/packages/angular/build/src/builders/dev-server/vite/index.ts
+++ b/packages/angular/build/src/builders/dev-server/vite/index.ts
@@ -9,7 +9,6 @@
import type { BuilderContext } from '@angular-devkit/architect';
import type { Plugin } from 'esbuild';
import assert from 'node:assert';
-import { builtinModules, isBuiltin } from 'node:module';
import { join } from 'node:path';
import type { Connect, ViteDevServer } from 'vite';
import type { ComponentStyleRecord } from '../../../tools/vite/middlewares';
@@ -21,7 +20,6 @@ import { Result, ResultKind } from '../../application/results';
import { OutputHashing } from '../../application/schema';
import {
type ApplicationBuilderInternalOptions,
- type ExternalResultMetadata,
JavaScriptTransformer,
getSupportedBrowsers,
isZonelessApp,
@@ -99,8 +97,20 @@ export async function* serveWithVite(
browserOptions.ssr ||= true;
}
- // Disable auto CSP.
+ // Vite allowedHost syntax doesn't allow `*.` but `.` acts as `*.`
+ // Angular SSR supports `*.`.
+ const allowedHosts = Array.isArray(serverOptions.allowedHosts)
+ ? serverOptions.allowedHosts.map((host) => (host[0] === '.' ? '*' + host : host))
+ : serverOptions.allowedHosts === true
+ ? ['*']
+ : [];
+
+ // Always allow the dev server host
+ allowedHosts.push(serverOptions.host);
+
browserOptions.security = {
+ allowedHosts,
+ // Disable auto CSP.
autoCsp: false,
};
diff --git a/packages/angular/build/src/builders/unit-test/builder.ts b/packages/angular/build/src/builders/unit-test/builder.ts
index 6f2edd0281d7..690baf74ca3a 100644
--- a/packages/angular/build/src/builders/unit-test/builder.ts
+++ b/packages/angular/build/src/builders/unit-test/builder.ts
@@ -373,16 +373,15 @@ async function transformNgPackagrOptions(
throw new Error(`Could not read ng-package.json at ${ngPackagePath}: ${e.message}`);
}
- const lib = ngPackageJson['lib'] || {};
- const styleIncludePaths = lib['styleIncludePaths'] || [];
- const assets = ngPackageJson['assets'] || [];
- const inlineStyleLanguage = ngPackageJson['inlineStyleLanguage'];
+ const { lib: { styleIncludePaths = [] } = {}, assets = [], inlineStyleLanguage } = ngPackageJson;
+
+ const includePaths = styleIncludePaths.map((includePath: string) =>
+ path.resolve(path.dirname(ngPackagePath), includePath),
+ );
return {
- stylePreprocessorOptions: styleIncludePaths.length
- ? { includePaths: styleIncludePaths }
- : undefined,
+ stylePreprocessorOptions: includePaths.length ? { includePaths } : undefined,
assets: assets.length ? assets : undefined,
- inlineStyleLanguage: typeof inlineStyleLanguage === 'string' ? inlineStyleLanguage : undefined,
+ inlineStyleLanguage,
} as ApplicationBuilderInternalOptions;
}
diff --git a/packages/angular/build/src/builders/unit-test/options.ts b/packages/angular/build/src/builders/unit-test/options.ts
index 72b5f3eb3e8d..0a71f2d642f1 100644
--- a/packages/angular/build/src/builders/unit-test/options.ts
+++ b/packages/angular/build/src/builders/unit-test/options.ts
@@ -116,7 +116,7 @@ export async function normalizeOptions(
buildProgress: progress,
reporters: normalizeReporterOption(options.reporters),
outputFile: options.outputFile,
- browsers,
+ browsers: browsers?.length ? browsers : undefined,
browserViewport: width && height ? { width, height } : undefined,
watch,
debug: options.debug ?? false,
diff --git a/packages/angular/build/src/builders/unit-test/runners/vitest/browser-provider.ts b/packages/angular/build/src/builders/unit-test/runners/vitest/browser-provider.ts
index f89848abfbf6..0ca80f4fa60f 100644
--- a/packages/angular/build/src/builders/unit-test/runners/vitest/browser-provider.ts
+++ b/packages/angular/build/src/builders/unit-test/runners/vitest/browser-provider.ts
@@ -7,7 +7,11 @@
*/
import { createRequire } from 'node:module';
-import type { BrowserBuiltinProvider, BrowserConfigOptions } from 'vitest/node';
+import type {
+ BrowserBuiltinProvider,
+ BrowserConfigOptions,
+ BrowserProviderOption,
+} from 'vitest/node';
import { assertIsError } from '../../../../utils/error';
export interface BrowserConfiguration {
@@ -37,7 +41,13 @@ function findBrowserProvider(
return undefined;
}
-function normalizeBrowserName(browserName: string): { browser: string; headless: boolean } {
+export interface BrowserInstanceConfiguration {
+ browser: string;
+ headless: boolean;
+ provider?: BrowserProviderOption;
+}
+
+function normalizeBrowserName(browserName: string): BrowserInstanceConfiguration {
// Normalize browser names to match Vitest's expectations for headless but also supports karma's names
// e.g., 'ChromeHeadless' -> 'chrome', 'FirefoxHeadless' -> 'firefox'
// and 'Chrome' -> 'chrome', 'Firefox' -> 'firefox'.
@@ -50,6 +60,67 @@ function normalizeBrowserName(browserName: string): { browser: string; headless:
};
}
+/**
+ * Mutates the provided browser instances to apply standard headless execution
+ * constraints based on the chosen provider, user options, and CI environment presence.
+ *
+ * @param instances The normalized browser instances to mutate.
+ * @param providerName The identifier for the chosen Vitest browser provider.
+ * @param headless The user-provided headless configuration option.
+ * @param isCI Whether the current environment is running in CI.
+ * @returns An array of informational messages generated during evaluation.
+ */
+export function applyHeadlessConfiguration(
+ instances: BrowserInstanceConfiguration[],
+ providerName: BrowserBuiltinProvider | undefined,
+ headless: boolean | undefined,
+ isCI: boolean,
+): string[] {
+ const messages: string[] = [];
+
+ if (providerName === 'preview') {
+ instances.forEach((instance) => {
+ // Preview mode only supports headed execution
+ instance.headless = false;
+ });
+
+ if (headless) {
+ messages.push('The "headless" option is ignored when using the "preview" provider.');
+ }
+ } else if (headless !== undefined) {
+ if (headless) {
+ const allHeadlessByDefault = isCI || instances.every((i) => i.headless);
+ if (allHeadlessByDefault) {
+ messages.push(
+ 'The "headless" option is unnecessary as all browsers are already configured to run in headless mode.',
+ );
+ }
+ }
+
+ instances.forEach((instance) => {
+ instance.headless = headless;
+ });
+ } else if (isCI) {
+ instances.forEach((instance) => {
+ instance.headless = true;
+ });
+ }
+
+ return messages;
+}
+
+/**
+ * Resolves and configures the Vitest browser provider for the unit test builder.
+ * Dynamically discovers and imports the necessary provider (Playwright, WebdriverIO, or Preview),
+ * maps the requested browser instances, and applies environment-specific execution logic.
+ *
+ * @param browsers An array of requested browser names (e.g., 'chrome', 'firefox').
+ * @param headless User-provided configuration for headless execution.
+ * @param debug Whether the builder is running in watch or debug mode.
+ * @param projectSourceRoot The root directory of the project being tested for resolving installed packages.
+ * @param viewport Optional viewport dimensions to apply to the launched browser instances.
+ * @returns A fully resolved Vitest browser configuration object alongside any generated warning or error messages.
+ */
export async function setupBrowserConfiguration(
browsers: string[] | undefined,
headless: boolean | undefined,
@@ -79,6 +150,8 @@ export async function setupBrowserConfiguration(
);
}
+ const instances = browsers.map(normalizeBrowserName);
+
let provider: import('vitest/node').BrowserProviderOption | undefined;
if (providerName) {
const providerPackage = `@vitest/browser-${providerName}`;
@@ -88,29 +161,27 @@ export async function setupBrowserConfiguration(
// Validate that the imported module has the expected structure
const providerFactory = providerModule[providerName];
if (typeof providerFactory === 'function') {
- if (
- providerName === 'playwright' &&
- process.env['CHROME_BIN']?.includes('rules_browsers')
- ) {
- // Use the Chrome binary from the 'rules_browsers' toolchain (via CHROME_BIN)
- // for Playwright when available to ensure hermetic testing, preventing reliance
- // on locally installed or NPM-managed browser versions.
- provider = providerFactory({
- launchOptions: {
- executablePath: process.env.CHROME_BIN,
- },
+ if (providerName === 'playwright') {
+ const executablePath = process.env['CHROME_BIN'];
+ const baseOptions = {
contextOptions: {
// Enables `prefer-color-scheme` for Vitest browser instead of `light`
colorScheme: null,
},
- });
- } else if (providerName === 'playwright') {
- provider = providerFactory({
- contextOptions: {
- // Enables `prefer-color-scheme` for Vitest browser instead of `light`
- colorScheme: null,
- },
- });
+ };
+
+ provider = providerFactory(baseOptions);
+
+ if (executablePath) {
+ for (const instance of instances) {
+ if (instance.browser === 'chrome' || instance.browser === 'chromium') {
+ instance.provider = providerFactory({
+ ...baseOptions,
+ launchOptions: { executablePath },
+ });
+ }
+ }
+ }
} else {
provider = providerFactory();
}
@@ -143,36 +214,7 @@ export async function setupBrowserConfiguration(
}
const isCI = !!process.env['CI'];
- const instances = browsers.map(normalizeBrowserName);
- const messages: string[] = [];
-
- if (providerName === 'preview') {
- instances.forEach((instance) => {
- // Preview mode only supports headed execution
- instance.headless = false;
- });
-
- if (headless) {
- messages.push('The "headless" option is ignored when using the "preview" provider.');
- }
- } else if (headless !== undefined) {
- if (headless) {
- const allHeadlessByDefault = isCI || instances.every((i) => i.headless);
- if (allHeadlessByDefault) {
- messages.push(
- 'The "headless" option is unnecessary as all browsers are already configured to run in headless mode.',
- );
- }
- }
-
- instances.forEach((instance) => {
- instance.headless = headless;
- });
- } else if (isCI) {
- instances.forEach((instance) => {
- instance.headless = true;
- });
- }
+ const messages = applyHeadlessConfiguration(instances, providerName, headless, isCI);
const browser = {
enabled: true,
diff --git a/packages/angular/build/src/builders/unit-test/runners/vitest/browser-provider_spec.ts b/packages/angular/build/src/builders/unit-test/runners/vitest/browser-provider_spec.ts
index 66f7254593b0..0dd0778420bd 100644
--- a/packages/angular/build/src/builders/unit-test/runners/vitest/browser-provider_spec.ts
+++ b/packages/angular/build/src/builders/unit-test/runners/vitest/browser-provider_spec.ts
@@ -9,7 +9,7 @@
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
-import { setupBrowserConfiguration } from './browser-provider';
+import { applyHeadlessConfiguration, setupBrowserConfiguration } from './browser-provider';
describe('setupBrowserConfiguration', () => {
let workspaceRoot: string;
@@ -47,8 +47,8 @@ describe('setupBrowserConfiguration', () => {
expect(browser?.enabled).toBeTrue();
expect(browser?.instances).toEqual([
- { browser: 'chrome', headless: true },
- { browser: 'firefox', headless: false },
+ jasmine.objectContaining({ browser: 'chrome', headless: true }),
+ jasmine.objectContaining({ browser: 'firefox', headless: false }),
]);
});
@@ -66,8 +66,8 @@ describe('setupBrowserConfiguration', () => {
);
expect(browser?.instances).toEqual([
- { browser: 'chrome', headless: true },
- { browser: 'firefox', headless: true },
+ jasmine.objectContaining({ browser: 'chrome', headless: true }),
+ jasmine.objectContaining({ browser: 'firefox', headless: true }),
]);
} finally {
if (originalCI === undefined) {
@@ -196,8 +196,8 @@ describe('setupBrowserConfiguration', () => {
);
expect(browser?.instances).toEqual([
- { browser: 'chrome', headless: true },
- { browser: 'firefox', headless: true },
+ jasmine.objectContaining({ browser: 'chrome', headless: true }),
+ jasmine.objectContaining({ browser: 'firefox', headless: true }),
]);
expect(messages).toEqual([]);
});
@@ -215,4 +215,106 @@ describe('setupBrowserConfiguration', () => {
'The "headless" option is unnecessary as all browsers are already configured to run in headless mode.',
]);
});
+
+ describe('CHROME_BIN usage', () => {
+ let originalChromeBin: string | undefined;
+
+ beforeEach(() => {
+ originalChromeBin = process.env['CHROME_BIN'];
+ process.env['CHROME_BIN'] = '/custom/path/to/chrome';
+ });
+
+ afterEach(() => {
+ if (originalChromeBin === undefined) {
+ delete process.env['CHROME_BIN'];
+ } else {
+ process.env['CHROME_BIN'] = originalChromeBin;
+ }
+ });
+
+ it('should set executablePath on the individual chrome instance', async () => {
+ const { browser } = await setupBrowserConfiguration(
+ ['ChromeHeadless', 'Chromium'],
+ undefined,
+ false,
+ workspaceRoot,
+ undefined,
+ );
+
+ // Verify the global provider does NOT have executablePath
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ expect((browser?.provider as any)?.options?.launchOptions?.executablePath).toBeUndefined();
+
+ // Verify the individual instances have executablePath
+ expect(
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (browser?.instances?.[0]?.provider as any)?.options?.launchOptions?.executablePath,
+ ).toBe('/custom/path/to/chrome');
+ expect(
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (browser?.instances?.[1]?.provider as any)?.options?.launchOptions?.executablePath,
+ ).toBe('/custom/path/to/chrome');
+ });
+
+ it('should set executablePath for chrome instances but not for others when mixed browsers are requested', async () => {
+ const { browser } = await setupBrowserConfiguration(
+ ['ChromeHeadless', 'Firefox'],
+ undefined,
+ false,
+ workspaceRoot,
+ undefined,
+ );
+
+ // Verify the global provider does NOT have executablePath
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ expect((browser?.provider as any)?.options?.launchOptions?.executablePath).toBeUndefined();
+
+ // Verify chrome gets it
+ expect(
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (browser?.instances?.[0]?.provider as any)?.options?.launchOptions?.executablePath,
+ ).toBe('/custom/path/to/chrome');
+
+ // Verify firefox does not
+ expect(browser?.instances?.[1]?.provider).toBeUndefined();
+ });
+ });
+
+ describe('applyHeadlessConfiguration', () => {
+ it('should set headless false and issue warning when using preview provider with headless true', () => {
+ const instances = [{ browser: 'chrome', headless: true }];
+ const messages = applyHeadlessConfiguration(instances, 'preview', true, false);
+
+ expect(instances[0].headless).toBeFalse();
+ expect(messages).toEqual([
+ 'The "headless" option is ignored when using the "preview" provider.',
+ ]);
+ });
+
+ it('should force headless mode when headless option is true', () => {
+ const instances = [{ browser: 'chrome', headless: false }];
+ const messages = applyHeadlessConfiguration(instances, 'playwright', true, false);
+
+ expect(instances[0].headless).toBeTrue();
+ expect(messages).toEqual([]);
+ });
+
+ it('should return information message when headless option is redundant', () => {
+ const instances = [{ browser: 'chrome', headless: true }];
+ const messages = applyHeadlessConfiguration(instances, 'playwright', true, false);
+
+ expect(instances[0].headless).toBeTrue();
+ expect(messages).toEqual([
+ 'The "headless" option is unnecessary as all browsers are already configured to run in headless mode.',
+ ]);
+ });
+
+ it('should force headless mode in CI environment when headless is undefined', () => {
+ const instances = [{ browser: 'chrome', headless: false }];
+ const messages = applyHeadlessConfiguration(instances, 'playwright', undefined, true);
+
+ expect(instances[0].headless).toBeTrue();
+ expect(messages).toEqual([]);
+ });
+ });
});
diff --git a/packages/angular/build/src/builders/unit-test/runners/vitest/build-options.ts b/packages/angular/build/src/builders/unit-test/runners/vitest/build-options.ts
index 3aa7e2c8947e..27519844312a 100644
--- a/packages/angular/build/src/builders/unit-test/runners/vitest/build-options.ts
+++ b/packages/angular/build/src/builders/unit-test/runners/vitest/build-options.ts
@@ -156,13 +156,37 @@ export async function getVitestBuildOptions(
const mockPatchContents = `
import { vi } from 'vitest';
- const error = new Error(
- 'The "vi.mock" and related methods are not supported with the Angular unit-test system. Please use Angular TestBed for mocking.');
- vi.mock = () => { throw error; };
- vi.doMock = () => { throw error; };
- vi.importMock = () => { throw error; };
- vi.unmock = () => { throw error; };
- vi.doUnmock = () => { throw error; };
+
+ const ANGULAR_VITEST_MOCK_PATCH = Symbol.for('@angular/cli/vitest-mock-patch');
+ if (!globalThis[ANGULAR_VITEST_MOCK_PATCH]) {
+ globalThis[ANGULAR_VITEST_MOCK_PATCH] = true;
+
+ const error = new Error(
+ 'The "vi.mock" and related methods are not supported for relative imports with the Angular unit-test system. ' +
+ 'Please use Angular TestBed for mocking dependencies.'
+ );
+
+ // Store original implementations
+ const { mock, doMock, importMock, unmock, doUnmock } = vi;
+
+ function patch(original) {
+ return (path, ...args) => {
+ // Check if the path is a string and starts with a character that indicates a relative path.
+ if (typeof path === 'string' && /^[./]/.test(path)) {
+ throw error;
+ }
+
+ // Call the original function for non-relative paths.
+ return original(path, ...args);
+ };
+ }
+
+ vi.mock = patch(mock);
+ vi.doMock = patch(doMock);
+ vi.importMock = patch(importMock);
+ vi.unmock = patch(unmock);
+ vi.doUnmock = patch(doUnmock);
+ }
`;
return {
diff --git a/packages/angular/build/src/builders/unit-test/runners/vitest/executor.ts b/packages/angular/build/src/builders/unit-test/runners/vitest/executor.ts
index 503aa5da9071..cbf9a577c4e4 100644
--- a/packages/angular/build/src/builders/unit-test/runners/vitest/executor.ts
+++ b/packages/angular/build/src/builders/unit-test/runners/vitest/executor.ts
@@ -27,6 +27,11 @@ import { setupBrowserConfiguration } from './browser-provider';
import { findVitestBaseConfig } from './configuration';
import { createVitestConfigPlugin, createVitestPlugins } from './plugins';
+enum DebugLogLevel {
+ Info = 1,
+ Verbose = 2,
+}
+
export class VitestExecutor implements TestExecutor {
private vitest: Vitest | undefined;
private normalizePath: ((id: string) => string) | undefined;
@@ -40,6 +45,7 @@ export class VitestExecutor implements TestExecutor {
explicitBrowser: [],
explicitServer: [],
};
+ private readonly debugLevel: number;
// This is a reverse map of the entry points created in `build-options.ts`.
// It is used by the in-memory provider plugin to map the requested test file
@@ -54,19 +60,42 @@ export class VitestExecutor implements TestExecutor {
testEntryPointMappings: Map | undefined,
logger: BuilderContext['logger'],
) {
+ const level = parseInt(process.env['NG_TEST_LOG'] ?? '0', 10);
+ this.debugLevel = isNaN(level) ? 0 : level;
+
this.projectName = projectName;
this.options = options;
this.logger = logger;
+ this.debugLog(DebugLogLevel.Info, 'VitestExecutor instantiated.');
+ this.debugLog(DebugLogLevel.Verbose, 'NormalizedUnitTestBuilderOptions:', options);
+
if (testEntryPointMappings) {
for (const [entryPoint, testFile] of testEntryPointMappings) {
this.testFileToEntryPoint.set(testFile, entryPoint);
this.entryPointToTestFile.set(entryPoint + '.js', testFile);
}
+ this.debugLog(
+ DebugLogLevel.Verbose,
+ 'Test entry point mappings:',
+ Object.fromEntries(testEntryPointMappings),
+ );
}
}
+ private debugLog(level: DebugLogLevel, message: string, data?: object) {
+ if (this.debugLevel < level) {
+ return;
+ }
+
+ const formattedMessage = `[VitestExecutor:${DebugLogLevel[level]}] ${message}`;
+ // Custom formatting for data object to ensure it's readable
+ const logData = data ? JSON.stringify(data, null, 2) : '';
+ this.logger.info(`${formattedMessage}${logData ? `\n${logData}` : ''}`);
+ }
+
async *execute(buildResult: FullResult | IncrementalResult): AsyncIterable {
+ this.debugLog(DebugLogLevel.Info, `Executing test run (kind: ${buildResult.kind}).`);
this.normalizePath ??= (await import('vite')).normalizePath;
if (buildResult.kind === ResultKind.Full) {
@@ -74,7 +103,20 @@ export class VitestExecutor implements TestExecutor {
for (const [path, file] of Object.entries(buildResult.files)) {
this.buildResultFiles.set(this.normalizePath(path), file);
}
+ this.debugLog(
+ DebugLogLevel.Info,
+ `Full build results received. Total files: ${this.buildResultFiles.size}.`,
+ );
} else {
+ this.debugLog(
+ DebugLogLevel.Info,
+ `Incremental build results received.` +
+ `Added: ${buildResult.added.length}, Modified: ${buildResult.modified.length}, Removed: ${buildResult.removed.length}.`,
+ );
+ this.debugLog(DebugLogLevel.Verbose, 'Added files:', buildResult.added);
+ this.debugLog(DebugLogLevel.Verbose, 'Modified files:', buildResult.modified);
+ this.debugLog(DebugLogLevel.Verbose, 'Removed files:', buildResult.removed);
+
for (const file of buildResult.removed) {
this.buildResultFiles.delete(this.normalizePath(file.path));
}
@@ -84,6 +126,7 @@ export class VitestExecutor implements TestExecutor {
}
updateExternalMetadata(buildResult, this.externalMetadata, undefined, true);
+ this.debugLog(DebugLogLevel.Verbose, 'Updated external metadata:', this.externalMetadata);
// Reset the exit code to allow for a clean state.
// This is necessary because Vitest may set the exit code on failure, which can
@@ -103,7 +146,16 @@ export class VitestExecutor implements TestExecutor {
// We need to find the original source file path to pass to Vitest.
const source = this.entryPointToTestFile.get(modifiedFile);
if (source) {
+ this.debugLog(
+ DebugLogLevel.Verbose,
+ `Mapped output file '${modifiedFile}' to source file '${source}' for re-run.`,
+ );
modifiedSourceFiles.add(source);
+ } else {
+ this.debugLog(
+ DebugLogLevel.Verbose,
+ `Could not map output file '${modifiedFile}' to a source file. It may not be a test file.`,
+ );
}
vitest.invalidateFile(
this.normalizePath(path.join(this.options.workspaceRoot, modifiedFile)),
@@ -120,7 +172,11 @@ export class VitestExecutor implements TestExecutor {
}
if (specsToRerun.length > 0) {
+ this.debugLog(DebugLogLevel.Info, `Re-running ${specsToRerun.length} test specifications.`);
+ this.debugLog(DebugLogLevel.Verbose, 'Specs to rerun:', specsToRerun);
testResults = await vitest.rerunTestSpecifications(specsToRerun);
+ } else {
+ this.debugLog(DebugLogLevel.Info, 'No test specifications to rerun.');
}
}
@@ -128,20 +184,29 @@ export class VitestExecutor implements TestExecutor {
const testModules = testResults?.testModules ?? this.vitest.state.getTestModules();
let success = testModules.every((testModule) => testModule.ok());
+ let finalResultReason = 'All tests passed.';
+
// Vitest does not return a failure result when coverage thresholds are not met.
// Instead, it sets the process exit code to 1.
// We check this exit code to determine if the test run should be considered a failure.
if (success && process.exitCode === 1) {
success = false;
+ finalResultReason = 'Test run failed due to unmet coverage thresholds.';
// Reset the exit code to prevent it from carrying over to subsequent runs/builds
process.exitCode = 0;
}
+ this.debugLog(
+ DebugLogLevel.Info,
+ `Test run finished with success: ${success}. Reason: ${finalResultReason}`,
+ );
yield { success };
}
async [Symbol.asyncDispose](): Promise {
+ this.debugLog(DebugLogLevel.Info, 'Disposing VitestExecutor: Closing Vitest instance.');
await this.vitest?.close();
+ this.debugLog(DebugLogLevel.Info, 'Vitest instance closed.');
}
private prepareSetupFiles(): string[] {
@@ -154,10 +219,13 @@ export class VitestExecutor implements TestExecutor {
testSetupFiles.unshift('polyfills.js');
}
+ this.debugLog(DebugLogLevel.Info, 'Prepared setup files:', testSetupFiles);
+
return testSetupFiles;
}
private async initializeVitest(): Promise {
+ this.debugLog(DebugLogLevel.Info, 'Initializing Vitest.');
const {
coverage,
reporters,
@@ -180,6 +248,10 @@ export class VitestExecutor implements TestExecutor {
vitestNodeModule = await import('vitest/node');
} catch (error: unknown) {
assertIsError(error);
+ this.debugLog(
+ DebugLogLevel.Info,
+ `Failed to import 'vitest/node'. Error code: ${error.code}`,
+ );
if (error.code !== 'ERR_MODULE_NOT_FOUND') {
throw error;
}
@@ -198,6 +270,9 @@ export class VitestExecutor implements TestExecutor {
browserViewport,
);
if (browserOptions.errors?.length) {
+ this.debugLog(DebugLogLevel.Info, 'Browser configuration errors found.', {
+ errors: browserOptions.errors,
+ });
throw new Error(browserOptions.errors.join('\n'));
}
@@ -206,7 +281,14 @@ export class VitestExecutor implements TestExecutor {
this.logger.info(message);
}
}
+ this.debugLog(DebugLogLevel.Info, 'Browser configuration complete.', {
+ config: browserOptions.browser,
+ });
+ this.debugLog(
+ DebugLogLevel.Info,
+ `Verifying build results. File count: ${this.buildResultFiles.size}.`,
+ );
assert(
this.buildResultFiles.size > 0,
'buildResult must be available before initializing vitest',
@@ -234,6 +316,10 @@ export class VitestExecutor implements TestExecutor {
? await findVitestBaseConfig([projectRoot, workspaceRoot])
: runnerConfig;
+ this.debugLog(DebugLogLevel.Info, 'External Vitest configuration path:', {
+ externalConfigPath,
+ });
+
let project = projectName;
if (debug && browserOptions.browser?.instances) {
if (browserOptions.browser.instances.length > 1) {
@@ -245,6 +331,9 @@ export class VitestExecutor implements TestExecutor {
// When running browser tests, Vitest appends the browser name to the project identifier.
// The project name must match this augmented name to ensure the correct project is targeted.
project = `${projectName} (${browserOptions.browser.instances[0].browser})`;
+ this.debugLog(DebugLogLevel.Info, 'Adjusted project name for debugging with browser:', {
+ project,
+ });
}
// Filter internal entries and setup files from the include list
@@ -255,43 +344,47 @@ export class VitestExecutor implements TestExecutor {
!internalEntries.some((internal) => entry.startsWith(internal)) && !setupFileSet.has(entry)
);
});
+ this.debugLog(DebugLogLevel.Verbose, 'Included test files (after filtering):', include);
- return startVitest(
- 'test',
- undefined,
- {
- config: externalConfigPath,
- root: workspaceRoot,
- project,
- outputFile,
- cache: cacheOptions.enabled ? undefined : false,
- testNamePattern: this.options.filter,
- watch,
- ...(typeof ui === 'boolean' ? { ui } : {}),
- ...debugOptions,
- },
- {
- // Note `.vitest` is auto appended to the path.
- cacheDir: cacheOptions.path,
- server: {
- // Disable the actual file watcher. The boolean watch option above should still
- // be enabled as it controls other internal behavior related to rerunning tests.
- watch: null,
- },
- plugins: [
- await createVitestConfigPlugin({
- browser: browserOptions.browser,
- coverage,
- projectName,
- projectSourceRoot,
- optimizeDepsInclude: this.externalMetadata.implicitBrowser,
- reporters,
- setupFiles: testSetupFiles,
- projectPlugins,
- include,
- }),
- ],
+ const vitestConfig = {
+ config: externalConfigPath,
+ root: workspaceRoot,
+ project,
+ outputFile,
+ cache: cacheOptions.enabled ? undefined : (false as const),
+ testNamePattern: this.options.filter,
+ watch,
+ ...(typeof ui === 'boolean' ? { ui } : {}),
+ ...debugOptions,
+ };
+ const vitestServerConfig = {
+ // Note `.vitest` is auto appended to the path.
+ cacheDir: cacheOptions.path,
+ server: {
+ // Disable the actual file watcher. The boolean watch option above should still
+ // be enabled as it controls other internal behavior related to rerunning tests.
+ watch: null,
},
- );
+ plugins: [
+ await createVitestConfigPlugin({
+ browser: browserOptions.browser,
+ coverage,
+ projectName,
+ projectSourceRoot,
+ optimizeDepsInclude: this.externalMetadata.implicitBrowser,
+ reporters,
+ setupFiles: testSetupFiles,
+ projectPlugins,
+ include,
+ watch,
+ }),
+ ],
+ };
+
+ this.debugLog(DebugLogLevel.Info, 'Calling startVitest with final configuration.');
+ this.debugLog(DebugLogLevel.Verbose, 'Vitest config:', vitestConfig);
+ this.debugLog(DebugLogLevel.Verbose, 'Vitest server config:', vitestServerConfig);
+
+ return startVitest('test', undefined, vitestConfig, vitestServerConfig);
}
}
diff --git a/packages/angular/build/src/builders/unit-test/runners/vitest/plugins.ts b/packages/angular/build/src/builders/unit-test/runners/vitest/plugins.ts
index 9abe0d7be404..d36f8a05ffa6 100644
--- a/packages/angular/build/src/builders/unit-test/runners/vitest/plugins.ts
+++ b/packages/angular/build/src/builders/unit-test/runners/vitest/plugins.ts
@@ -46,6 +46,7 @@ interface VitestConfigPluginOptions {
projectPlugins: Exclude;
include: string[];
optimizeDepsInclude: string[];
+ watch: boolean;
}
async function findTestEnvironment(
@@ -81,6 +82,18 @@ export async function createVitestConfigPlugin(
async config(config) {
const testConfig = config.test;
+ if (reporters !== undefined) {
+ delete testConfig?.reporters;
+ }
+
+ if (
+ options.coverage.reporters !== undefined &&
+ testConfig?.coverage &&
+ 'reporter' in testConfig.coverage
+ ) {
+ delete testConfig.coverage.reporter;
+ }
+
if (testConfig?.projects?.length) {
this.warn(
'The "test.projects" option in the Vitest configuration file is not supported. ' +
@@ -97,6 +110,22 @@ export async function createVitestConfigPlugin(
delete testConfig.include;
}
+ if (testConfig?.watch !== undefined && testConfig.watch !== options.watch) {
+ this.warn(
+ `The "test.watch" option in the Vitest configuration file is overridden by the builder's ` +
+ `watch option. Please use the Angular CLI "--watch" option to enable or disable watch mode.`,
+ );
+ delete testConfig.watch;
+ }
+
+ if (testConfig?.exclude) {
+ this.warn(
+ 'The "test.exclude" option in the Vitest configuration file is evaluated after ' +
+ 'tests are compiled. For better build performance, please use the Angular CLI ' +
+ '"exclude" option instead.',
+ );
+ }
+
// Merge user-defined plugins from the Vitest config with the CLI's internal plugins.
if (config.plugins) {
const userPlugins = config.plugins.filter(
@@ -389,6 +418,9 @@ async function generateCoverageOption(
projectName: string,
): Promise {
let defaultExcludes: string[] = [];
+ // When a coverage exclude option is provided, Vitest's default coverage excludes
+ // will be overridden. To retain them, we manually fetch the defaults to append to the
+ // user's provided exclusions.
if (optionsCoverage.exclude) {
try {
const vitestConfig = await import('vitest/config');
@@ -420,12 +452,15 @@ async function generateCoverageOption(
// Special handling for `exclude`/`reporters` due to an undefined value causing upstream failures
...(optionsCoverage.exclude
? {
- exclude: [
- // Augment the default exclude https://vitest.dev/config/#coverage-exclude
- // with the user defined exclusions
- ...optionsCoverage.exclude,
- ...defaultExcludes,
- ],
+ exclude: Array.from(
+ new Set([
+ // Augment the default exclude https://vitest.dev/config/#coverage-exclude
+ // with the user defined exclusions
+ ...(configCoverage?.exclude || []),
+ ...optionsCoverage.exclude,
+ ...defaultExcludes,
+ ]),
+ ),
}
: {}),
...(optionsCoverage.reporters
diff --git a/packages/angular/build/src/builders/unit-test/schema.json b/packages/angular/build/src/builders/unit-test/schema.json
index 951fd5a29e73..46b9b5fb6276 100644
--- a/packages/angular/build/src/builders/unit-test/schema.json
+++ b/packages/angular/build/src/builders/unit-test/schema.json
@@ -75,8 +75,7 @@
},
"coverage": {
"type": "boolean",
- "description": "Enables coverage reporting for tests.",
- "default": false
+ "description": "Enables coverage reporting for tests. If not specified, the coverage configuration from a runner configuration file will be used if present. Otherwise, coverage is disabled by default."
},
"coverageInclude": {
"type": "array",
diff --git a/packages/angular/build/src/builders/unit-test/tests/behavior/runner-config-vitest_spec.ts b/packages/angular/build/src/builders/unit-test/tests/behavior/runner-config-vitest_spec.ts
index 603c69f533ea..609d736e00f7 100644
--- a/packages/angular/build/src/builders/unit-test/tests/behavior/runner-config-vitest_spec.ts
+++ b/packages/angular/build/src/builders/unit-test/tests/behavior/runner-config-vitest_spec.ts
@@ -42,6 +42,21 @@ describeBuilder(execute, UNIT_TEST_BUILDER_INFO, (harness) => {
harness.expectFile('vitest-results.xml').toExist();
});
+ it('should override reporters defined in runnerConfig file when CLI option is present', async () => {
+ harness.useTarget('test', {
+ ...BASE_OPTIONS,
+ runnerConfig: 'vitest.config.ts',
+ reporters: ['default'],
+ });
+
+ harness.writeFile('vitest.config.ts', VITEST_CONFIG_CONTENT);
+
+ const { result } = await harness.executeOnce();
+ expect(result?.success).toBeTrue();
+ // The CLI option 'default' should override the 'junit' reporter in VITEST_CONFIG_CONTENT
+ harness.expectFile('vitest-results.xml').toNotExist();
+ });
+
it('should use custom reportsDirectory defined in runnerConfig file', async () => {
harness.useTarget('test', {
...BASE_OPTIONS,
@@ -92,6 +107,31 @@ describeBuilder(execute, UNIT_TEST_BUILDER_INFO, (harness) => {
harness.expectFile('coverage/test/coverage-final.json').toExist();
});
+ it('should enable coverage when set in runnerConfig file without builder option', async () => {
+ harness.useTarget('test', {
+ ...BASE_OPTIONS,
+ runnerConfig: 'vitest.config.ts',
+ });
+
+ harness.writeFile(
+ 'vitest.config.ts',
+ `
+ import { defineConfig } from 'vitest/config';
+ export default defineConfig({
+ test: {
+ coverage: {
+ enabled: true,
+ },
+ },
+ });
+ `,
+ );
+
+ const { result } = await harness.executeOnce();
+ expect(result?.success).toBeTrue();
+ harness.expectFile('coverage/test/coverage-final.json').toExist();
+ });
+
it('should exclude test files based on runnerConfig file', async () => {
harness.useTarget('test', {
...BASE_OPTIONS,
@@ -139,6 +179,59 @@ describeBuilder(execute, UNIT_TEST_BUILDER_INFO, (harness) => {
expect(results.numPassedTests).toBe(1);
});
+ it('should correctly merge coverage.exclude arrays from builder and runner options', async () => {
+ harness.useTarget('test', {
+ ...BASE_OPTIONS,
+ coverage: true,
+ runnerConfig: 'vitest.config.ts',
+ coverageExclude: ['src/app/cli-excluded.ts'],
+ });
+
+ harness.writeFile(
+ 'vitest.config.ts',
+ `
+ import { defineConfig } from 'vitest/config';
+ export default defineConfig({
+ test: {
+ coverage: {
+ exclude: ['src/app/config-excluded.ts'],
+ },
+ },
+ });
+ `,
+ );
+
+ // Create two files that would normally be covered
+ harness.writeFile('src/app/cli-excluded.ts', 'export const cliExcluded = true;');
+ harness.writeFile('src/app/config-excluded.ts', 'export const configExcluded = true;');
+
+ // Update the test file to import them so they're picked up by coverage
+ harness.writeFile(
+ 'src/app/app.component.spec.ts',
+ `
+ import { test, expect } from 'vitest';
+ import './cli-excluded';
+ import './config-excluded';
+ test('should pass', () => {
+ expect(true).toBe(true);
+ });
+ `,
+ );
+
+ const { result } = await harness.executeOnce();
+ expect(result?.success).toBeTrue();
+ harness.expectFile('coverage/test/coverage-final.json').toExist();
+
+ const coverageMap = JSON.parse(harness.readFile('coverage/test/coverage-final.json'));
+ const coveredFiles = Object.keys(coverageMap);
+
+ const hasCliExcluded = coveredFiles.some((f) => f.includes('cli-excluded.ts'));
+ const hasConfigExcluded = coveredFiles.some((f) => f.includes('config-excluded.ts'));
+
+ expect(hasCliExcluded).withContext('CLI target should be excluded').toBeFalse();
+ expect(hasConfigExcluded).withContext('Config file target should be excluded').toBeFalse();
+ });
+
it('should allow overriding globals to false via runnerConfig file', async () => {
harness.useTarget('test', {
...BASE_OPTIONS,
@@ -290,6 +383,71 @@ describeBuilder(execute, UNIT_TEST_BUILDER_INFO, (harness) => {
// );
});
+ it('should warn and ignore "test.watch" option from runnerConfig file', async () => {
+ harness.useTarget('test', {
+ ...BASE_OPTIONS,
+ watch: false,
+ runnerConfig: 'vitest.config.ts',
+ });
+
+ harness.writeFile(
+ 'vitest.config.ts',
+ `
+ import { defineConfig } from 'vitest/config';
+ export default defineConfig({
+ test: {
+ watch: true,
+ },
+ });
+ `,
+ );
+
+ const { result, logs } = await harness.executeOnce();
+ expect(result?.success).toBeTrue();
+
+ // TODO: Re-enable once Vite logs are remapped through build system
+ // expect(logs).toContain(
+ // jasmine.objectContaining({
+ // level: 'warn',
+ // message: jasmine.stringMatching(
+ // 'The "test.watch" option in the Vitest configuration file is overridden by the builder\\'s watch option.',
+ // ),
+ // }),
+ // );
+ });
+
+ it('should warn about performance when "test.exclude" option is in runnerConfig file', async () => {
+ harness.useTarget('test', {
+ ...BASE_OPTIONS,
+ runnerConfig: 'vitest.config.ts',
+ });
+
+ harness.writeFile(
+ 'vitest.config.ts',
+ `
+ import { defineConfig } from 'vitest/config';
+ export default defineConfig({
+ test: {
+ exclude: ['src/app/non-existent.spec.ts'],
+ },
+ });
+ `,
+ );
+
+ const { result, logs } = await harness.executeOnce();
+ expect(result?.success).toBeTrue();
+
+ // TODO: Re-enable once Vite logs are remapped through build system
+ // expect(logs).toContain(
+ // jasmine.objectContaining({
+ // level: 'warn',
+ // message: jasmine.stringMatching(
+ // 'The "test.exclude" option in the Vitest configuration file is evaluated after',
+ // ),
+ // }),
+ // );
+ });
+
it(`should append "test.setupFiles" (string) from runnerConfig to the CLI's setup`, async () => {
harness.useTarget('test', {
...BASE_OPTIONS,
diff --git a/packages/angular/build/src/builders/unit-test/tests/behavior/vitest-mock-unsupported_spec.ts b/packages/angular/build/src/builders/unit-test/tests/behavior/vitest-mock-unsupported_spec.ts
index 30565429f2ca..547d6528d86d 100644
--- a/packages/angular/build/src/builders/unit-test/tests/behavior/vitest-mock-unsupported_spec.ts
+++ b/packages/angular/build/src/builders/unit-test/tests/behavior/vitest-mock-unsupported_spec.ts
@@ -34,8 +34,35 @@ describeBuilder(execute, UNIT_TEST_BUILDER_INFO, (harness) => {
`,
);
- const { result, logs } = await harness.executeOnce();
+ const { result } = await harness.executeOnce();
expect(result?.success).toBeFalse();
});
+
+ it('should not fail when vi.mock is used with a non-relative path', async () => {
+ harness.useTarget('test', {
+ ...BASE_OPTIONS,
+ });
+
+ harness.writeFile(
+ 'src/app/mock-non-relative.spec.ts',
+ `
+ import { vi } from 'vitest';
+ vi.mock('@angular/cdk', () => ({}));
+ describe('Ignored', () => { it('pass', () => expect(true).toBe(true)); });
+ `,
+ );
+
+ // Overwrite default to avoid noise
+ harness.writeFile(
+ 'src/app/app.component.spec.ts',
+ `
+ import { describe, it, expect } from 'vitest';
+ describe('Ignored', () => { it('pass', () => expect(true).toBe(true)); });
+ `,
+ );
+
+ const { result } = await harness.executeOnce();
+ expect(result?.success).toBeTrue();
+ });
});
});
diff --git a/packages/angular/build/src/private.ts b/packages/angular/build/src/private.ts
index 4791a94a42d3..50d57d0e5a01 100644
--- a/packages/angular/build/src/private.ts
+++ b/packages/angular/build/src/private.ts
@@ -26,6 +26,10 @@ export { buildApplicationInternal } from './builders/application';
export type { ApplicationBuilderInternalOptions } from './builders/application/options';
export { type Result, type ResultFile, ResultKind } from './builders/application/results';
export { serveWithVite } from './builders/dev-server/vite';
+export {
+ normalizeOptions as normalizeDevServerOptions,
+ type NormalizedDevServerOptions,
+} from './builders/dev-server/options';
// Tools
export * from './tools/babel/plugins';
diff --git a/packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts b/packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts
index af4dcaea01fb..1bcb8c40500a 100644
--- a/packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts
+++ b/packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts
@@ -220,10 +220,19 @@ export function createCompilerPlugin(
if (stylesheetResult.errors) {
(result.errors ??= []).push(...stylesheetResult.errors);
+ const { referencedFiles } = stylesheetResult;
+ if (referencedFiles) {
+ referencedFileTracker.add(containingFile, referencedFiles);
+ if (stylesheetFile) {
+ referencedFileTracker.add(stylesheetFile, referencedFiles);
+ }
+ }
+
return '';
}
const { contents, outputFiles, metafile, referencedFiles } = stylesheetResult;
+
additionalResults.set(resultSource, {
outputFiles,
metafile,
diff --git a/packages/angular/build/src/tools/esbuild/application-code-bundle.ts b/packages/angular/build/src/tools/esbuild/application-code-bundle.ts
index 635faca8c82e..815afa1a1ba8 100644
--- a/packages/angular/build/src/tools/esbuild/application-code-bundle.ts
+++ b/packages/angular/build/src/tools/esbuild/application-code-bundle.ts
@@ -196,9 +196,14 @@ export function createServerPolyfillBundleOptions(
if (isNodePlatform) {
// Note: Needed as esbuild does not provide require shims / proxy from ESModules.
// See: https://github.com/evanw/esbuild/issues/1921.
+ // Use an alias to avoid colliding with any `createRequire` import that may
+ // already exist in the bundled user code. ESBuild processes banner content
+ // as raw text outside of its module graph, so it cannot deduplicate or
+ // rename banner imports the way it does for user imports. Without the alias,
+ // a duplicate `import { createRequire }` binding would cause a runtime error.
jsBanner.push(
- `import { createRequire } from 'node:module';`,
- `globalThis['require'] ??= createRequire(import.meta.url);`,
+ `import { createRequire as __ngCreateRequire } from 'node:module';`,
+ `globalThis['require'] ??= __ngCreateRequire(import.meta.url);`,
);
}
@@ -397,9 +402,14 @@ export function createSsrEntryCodeBundleOptions(
if (isNodePlatform) {
// Note: Needed as esbuild does not provide require shims / proxy from ESModules.
// See: https://github.com/evanw/esbuild/issues/1921.
+ // Use an alias to avoid colliding with any `createRequire` import that may
+ // already exist in the bundled user code. ESBuild processes banner content
+ // as raw text outside of its module graph, so it cannot deduplicate or
+ // rename banner imports the way it does for user imports. Without the alias,
+ // a duplicate `import { createRequire }` binding would cause a runtime error.
jsBanner.push(
- `import { createRequire } from 'node:module';`,
- `globalThis['require'] ??= createRequire(import.meta.url);`,
+ `import { createRequire as __ngCreateRequire } from 'node:module';`,
+ `globalThis['require'] ??= __ngCreateRequire(import.meta.url);`,
);
}
@@ -656,12 +666,17 @@ function getEsBuildCommonPolyfillsOptions(
): BuildOptions | undefined {
const { jit, workspaceRoot, i18nOptions, externalPackages } = options;
- const buildOptions = getEsBuildCommonOptions(options);
+ let polyfills = options.polyfills ? [...options.polyfills] : [];
+
+ const buildOptions = getEsBuildCommonOptions({
+ ...options,
+ // If any polyfills are local files, disable external packages for the polyfills build.
+ // This ensures that local files are properly bundled.
+ externalPackages: polyfills.some(isLocalFile) ? false : externalPackages,
+ });
buildOptions.splitting = false;
buildOptions.plugins ??= [];
- let polyfills = options.polyfills ? [...options.polyfills] : [];
-
// Angular JIT mode requires the runtime compiler
if (jit) {
polyfills.unshift('@angular/compiler');
@@ -671,10 +686,8 @@ function getEsBuildCommonPolyfillsOptions(
// Locale data should go first so that project provided polyfill code can augment if needed.
let needLocaleDataPlugin = false;
if (i18nOptions.shouldInline) {
- if (!externalPackages) {
- // Remove localize polyfill when i18n inline transformation have been applied to all the packages.
- polyfills = polyfills.filter((path) => !path.startsWith('@angular/localize'));
- }
+ // Remove localize polyfill when i18n inline transformation have been applied to all the packages.
+ polyfills = polyfills.filter((path) => !path.startsWith('@angular/localize'));
// Add locale data for all active locales
// TODO: Inject each individually within the inlining process itself
@@ -749,3 +762,18 @@ function getEsBuildCommonPolyfillsOptions(
function entryFileToWorkspaceRelative(workspaceRoot: string, entryFile: string): string {
return './' + toPosixPath(relative(workspaceRoot, entryFile).replace(/.[mc]?ts$/, ''));
}
+
+/**
+ * Determines if a polyfill path is a local file.
+ * A local file is defined as a path starting with a `.` or having a TypeScript/JavaScript extension.
+ * `zone.js` and its subpaths are specifically excluded and treated as packages.
+ * @param path The polyfill path to check.
+ * @returns true if the path is a local file; false otherwise.
+ */
+function isLocalFile(path: string): boolean {
+ if (path.startsWith('zone.js')) {
+ return false;
+ }
+
+ return path[0] === '.' || /\.[mc]?[jt]sx?$/.test(path);
+}
diff --git a/packages/angular/build/src/tools/vite/middlewares/assets-middleware.ts b/packages/angular/build/src/tools/vite/middlewares/assets-middleware.ts
index f0a137f578f8..e0074625afe0 100644
--- a/packages/angular/build/src/tools/vite/middlewares/assets-middleware.ts
+++ b/packages/angular/build/src/tools/vite/middlewares/assets-middleware.ts
@@ -45,8 +45,8 @@ export function createAngularAssetsMiddleware(
// Rewrite all build assets to a vite raw fs URL
const asset = assets.get(pathname);
if (asset) {
- // This is a workaround to serve CSS, JS and TS files without Vite transformations.
- if (JS_TS_REGEXP.test(extension) || CSS_PREPROCESSOR_REGEXP.test(extension)) {
+ // This is a workaround to serve extensionless, CSS, JS and TS files without Vite transformations.
+ if (!extension || JS_TS_REGEXP.test(extension) || CSS_PREPROCESSOR_REGEXP.test(extension)) {
const contents = readFileSync(asset.source);
const etag = `W/${createHash('sha256').update(contents).digest('hex')}`;
if (checkAndHandleEtag(req, res, etag)) {
diff --git a/packages/angular/build/src/tools/vite/middlewares/ssr-middleware.ts b/packages/angular/build/src/tools/vite/middlewares/ssr-middleware.ts
index 4b0a8d8390f1..a26fa8e5e257 100644
--- a/packages/angular/build/src/tools/vite/middlewares/ssr-middleware.ts
+++ b/packages/angular/build/src/tools/vite/middlewares/ssr-middleware.ts
@@ -90,6 +90,10 @@ export async function createAngularSsrExternalMiddleware(
'@angular/ssr/node' as string
)) as typeof import('@angular/ssr/node', { with: { 'resolution-mode': 'import' } });
+ // Disable host check if allowed hosts is true meaning allow all hosts.
+ const { allowedHosts } = server.config.server;
+ const disableAllowedHostsCheck = allowedHosts === true;
+
return function angularSsrExternalMiddleware(
req: Connect.IncomingMessage,
res: ServerResponse,
@@ -123,6 +127,7 @@ export async function createAngularSsrExternalMiddleware(
}
if (cachedAngularAppEngine !== AngularAppEngine) {
+ AngularAppEngine.ɵdisableAllowedHostsCheck = disableAllowedHostsCheck;
AngularAppEngine.ɵallowStaticRouteRender = true;
AngularAppEngine.ɵhooks.on('html:transform:pre', async ({ html, url }) => {
const processedHtml = await server.transformIndexHtml(url.pathname, html);
diff --git a/packages/angular/build/src/utils/index-file/auto-csp.ts b/packages/angular/build/src/utils/index-file/auto-csp.ts
index c50e0bfce3f2..0e1dfe3ed916 100644
--- a/packages/angular/build/src/utils/index-file/auto-csp.ts
+++ b/packages/angular/build/src/utils/index-file/auto-csp.ts
@@ -52,12 +52,7 @@ function isJavascriptMimeType(mimeType: string): boolean {
* @returns whether to add the script tag to the dynamically loaded script tag
*/
function shouldDynamicallyLoadScriptTagBasedOnType(scriptType: string | undefined): boolean {
- return (
- scriptType === undefined ||
- scriptType === '' ||
- scriptType === 'module' ||
- isJavascriptMimeType(scriptType)
- );
+ return !scriptType || scriptType === 'module' || isJavascriptMimeType(scriptType);
}
/**
@@ -67,7 +62,11 @@ function shouldDynamicallyLoadScriptTagBasedOnType(scriptType: string | undefine
* @returns The hash of the text formatted appropriately for CSP.
*/
export function hashTextContent(scriptText: string): string {
- const hash = crypto.createHash(HASH_FUNCTION).update(scriptText, 'utf-8').digest('base64');
+ // Normalize CRLF to LF to ensure consistent since the rewriter might normalize the line endings.
+ const hash = crypto
+ .createHash(HASH_FUNCTION)
+ .update(scriptText.replace(/\r\n?/g, '\n'), 'utf-8')
+ .digest('base64');
return `'${HASH_FUNCTION}-${hash}'`;
}
diff --git a/packages/angular/build/src/utils/index-file/auto-csp_spec.ts b/packages/angular/build/src/utils/index-file/auto-csp_spec.ts
index 1ec5f2ab06aa..efbd338233ad 100644
--- a/packages/angular/build/src/utils/index-file/auto-csp_spec.ts
+++ b/packages/angular/build/src/utils/index-file/auto-csp_spec.ts
@@ -15,13 +15,13 @@ const getCsps = (html: string) => {
).map((m) => m[1]); // Only capture group.
};
-const ONE_HASH_CSP =
+const CSP_SINGLE_HASH_REGEX =
/script-src 'strict-dynamic' 'sha256-[^']+' https: 'unsafe-inline';object-src 'none';base-uri 'self';/;
-const TWO_HASH_CSP =
+const CSP_TWO_HASHES_REGEX =
/script-src 'strict-dynamic' (?:'sha256-[^']+' ){2}https: 'unsafe-inline';object-src 'none';base-uri 'self';/;
-const FOUR_HASH_CSP =
+const CSP_FOUR_HASHES_REGEX =
/script-src 'strict-dynamic' (?:'sha256-[^']+' ){4}https: 'unsafe-inline';object-src 'none';base-uri 'self';/;
describe('auto-csp', () => {
@@ -38,8 +38,8 @@ describe('auto-csp', () => {
`);
const csps = getCsps(result);
- expect(csps.length).toBe(1);
- expect(csps[0]).toMatch(ONE_HASH_CSP);
+ expect(csps).toHaveSize(1);
+ expect(csps[0]).toMatch(CSP_SINGLE_HASH_REGEX);
expect(csps[0]).toContain(hashTextContent("console.log('foo');"));
});
@@ -56,8 +56,8 @@ describe('auto-csp', () => {
`);
const csps = getCsps(result);
- expect(csps.length).toBe(1);
- expect(csps[0]).toMatch(ONE_HASH_CSP);
+ expect(csps).toHaveSize(1);
+ expect(csps[0]).toMatch(CSP_SINGLE_HASH_REGEX);
expect(result).toContain(`var scripts = [['./main.js', '', false, false]];`);
});
@@ -74,8 +74,8 @@ describe('auto-csp', () => {
`);
const csps = getCsps(result);
- expect(csps.length).toBe(1);
- expect(csps[0]).toMatch(ONE_HASH_CSP);
+ expect(csps).toHaveSize(1);
+ expect(csps[0]).toMatch(CSP_SINGLE_HASH_REGEX);
// Our loader script appears after the HTML text content.
expect(result).toMatch(
/Some text<\/div>\s*`);
// Only two loader scripts are created.
- expect(Array.from(result.matchAll(/`);
// Only one loader script is created.
- expect(Array.from(result.matchAll(/
+ Some text
+