mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
Compare commits
171 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 64ddde21af | |||
| 479a919f42 | |||
| 98468c0d7a | |||
| b549cd28ae | |||
| cef1449ac7 | |||
| 05a9322c75 | |||
| df89611bf2 | |||
| 35dea23580 | |||
| 596b545130 | |||
| 1e3999ec36 | |||
| 114906d2d6 | |||
| 2e05deaffb | |||
| 2fb029de04 | |||
| 690405b253 | |||
| fe533cd244 | |||
| 421edfe04b | |||
| 87bfe164e3 | |||
| a6a46e9839 | |||
| 9de2f078d5 | |||
| 40844876ea | |||
| ca61366218 | |||
| cd748aad47 | |||
| fce5602b53 | |||
| f87fad3fff | |||
| 06c53679ba | |||
| e8d9bc5119 | |||
| 26072bba9c | |||
| 00bfff52c2 | |||
| 0bc7f154c8 | |||
| 705b94bd21 | |||
| ed6a347109 | |||
| 6d6b0278a8 | |||
| 6e0b66d702 | |||
| 47caed9ada | |||
| 23d1ace339 | |||
| e220a615d1 | |||
| d7b6045d61 | |||
| c9b0f45690 | |||
| 15395a576f | |||
| 9a27c5befb | |||
| a26d94d979 | |||
| 328e588bcd | |||
| 454a269254 | |||
| f881082e80 | |||
| c8f07daf8f | |||
| 3f247f1256 | |||
| aabe146c30 | |||
| 650ad1f7fb | |||
| 269f344d45 | |||
| a649d85de1 | |||
| 020e0f0424 | |||
| 10b0927e15 | |||
| 28c28a0aa4 | |||
| eef93f5a7b | |||
| e1481d89dc | |||
| e8aa7d3ce3 | |||
| b02042301a | |||
| 551c99fd5f | |||
| 6c421ed65d | |||
| 9093e0e132 | |||
| 040cba0b09 | |||
| 6213c7d998 | |||
| 49e00b306a | |||
| 1c27fa982c | |||
| a28672fb70 | |||
| 65c5a734e2 | |||
| 9bdb4fe8cc | |||
| 11c638557b | |||
| a6130e076a | |||
| 906bce0877 | |||
| a827f02746 | |||
| eb0183009b | |||
| 9e172e0280 | |||
| 878b99a1c6 | |||
| 9655ea7f5c | |||
| d76a911669 | |||
| 591c7e2ec8 | |||
| 81dc006772 | |||
| c0eb0cb7a5 | |||
| 416878bb7c | |||
| fceb19128d | |||
| f9d73cc687 | |||
| 5ceb1167fb | |||
| 6b475eb86c | |||
| 9eac011bd0 | |||
| 0ba671d4a0 | |||
| 38b9b79c29 | |||
| 1edb83c019 | |||
| be0e8457b7 | |||
| aff482913b | |||
| 9374d57330 | |||
| 52106fb71b | |||
| 58765137ab | |||
| 8164b2298e | |||
| 966d95df20 | |||
| fe27810a24 | |||
| 4dfd38e127 | |||
| a8c5bafd18 | |||
| d8254d95e9 | |||
| 0c61fc6d43 | |||
| 0da66e6d43 | |||
| 7b51728813 | |||
| 5be80d33a3 | |||
| 1e3748b893 | |||
| 87523e90bc | |||
| bdc31675b7 | |||
| 726d6026b1 | |||
| 0eb550e297 | |||
| 67cfe686b1 | |||
| c7440dddef | |||
| c714426963 | |||
| a1fe7091f9 | |||
| af63b800ec | |||
| 9e828d5e54 | |||
| 7a4bc79720 | |||
| 1d5ea07bca | |||
| 2031359069 | |||
| 0838df97bf | |||
| dbd403031a | |||
| 287d6c8fdd | |||
| 732aadf082 | |||
| 2d8ac7d9ef | |||
| 28b8782266 | |||
| d8ac27f94a | |||
| 81751465b4 | |||
| de6b6413e4 | |||
| d4a380d7bd | |||
| 124d44f130 | |||
| 19ed12c81e | |||
| 557e6fe6eb | |||
| b7cefe0370 | |||
| 8b02aa0333 | |||
| c68a099ded | |||
| dc36fa5200 | |||
| e607d4db2b | |||
| e159ab1ee3 | |||
| 24e7238c54 | |||
| f863792923 | |||
| 65cca30361 | |||
| 8747f9ad55 | |||
| 3ecf8c7114 | |||
| a6a2e38e5c | |||
| 2faed63fed | |||
| 1cf4d34c37 | |||
| ced0357bf8 | |||
| d9f0e6b27c | |||
| 767a280562 | |||
| 254b560138 | |||
| b0900ccee5 | |||
| 0065ebb115 | |||
| 0211668d20 | |||
| ada3c37338 | |||
| 4635095c01 | |||
| b13c3fc2eb | |||
| c81e345e72 | |||
| 31df4d2fd1 | |||
| 0e3465dfd9 | |||
| 6fb2b71489 | |||
| 5105477490 | |||
| 856dd50e64 | |||
| 1a16fb7aa2 | |||
| 0e1bd1b404 | |||
| 4ab709460a | |||
| b38c43bacc | |||
| 88d48de46e | |||
| af247cacb6 | |||
| 499fa8fa88 | |||
| 79b91593c9 | |||
| 51801612c3 | |||
| a92dea5b99 | |||
| 1156d7d786 |
@@ -12,6 +12,9 @@ common --@aspect_rules_ts//ts:default_to_tsc_transpiler
|
||||
# Needed as otherwise `env` of TS actions would be ignored.
|
||||
common --incompatible_merge_fixed_and_default_shell_env
|
||||
|
||||
# Frozen lockfile
|
||||
common --lockfile_mode=error
|
||||
|
||||
###############################
|
||||
# Filesystem interactions #
|
||||
###############################
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
6.5.0
|
||||
7.6.1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
load("//tools:defaults2.bzl", "esbuild_checked_in", "ts_config", "ts_project")
|
||||
load("//tools:defaults.bzl", "esbuild_checked_in", "ts_config", "ts_project")
|
||||
|
||||
package(default_visibility = ["//.github/actions/deploy-docs-site:__subpackages__"])
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,9 +5,9 @@ runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Saucelabs Variables
|
||||
uses: angular/dev-infra/github-actions/saucelabs@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/saucelabs@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Starting Saucelabs tunnel service
|
||||
shell: bash
|
||||
run: ./tools/saucelabs/sauce-service.sh run &
|
||||
|
||||
@@ -21,16 +21,16 @@ jobs:
|
||||
(github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'adev: preview'))
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Build adev to ensure it continues to work
|
||||
run: pnpm bazel build //adev:build --full_build_adev --config=release
|
||||
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
with:
|
||||
workflow-artifact-name: 'adev-preview'
|
||||
pull-number: '${{github.event.pull_request.number}}'
|
||||
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||
with:
|
||||
token: '${{secrets.GITHUB_TOKEN}}'
|
||||
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
npx -y firebase-tools@latest target:clear --config adev/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting angular-docs
|
||||
npx -y firebase-tools@latest target:apply --config adev/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting angular-docs ${{env.PREVIEW_SITE}}
|
||||
|
||||
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
with:
|
||||
github-token: '${{secrets.GITHUB_TOKEN}}'
|
||||
workflow-artifact-name: 'adev-preview'
|
||||
|
||||
@@ -13,9 +13,9 @@ jobs:
|
||||
assistant_to_the_branch_manager:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: angular/dev-infra/github-actions/branch-manager@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
- uses: angular/dev-infra/github-actions/branch-manager@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
- uses: alessbell/pull-request-comment-branch@aad01d65d6982b8eacabed5e9a684cd8ceb98da6 # v1.1
|
||||
id: comment-branch
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
# Specify repository as the PR branch might be from a fork.
|
||||
repository: ${{steps.comment-branch.outputs.head_owner}}/${{steps.comment-branch.outputs.head_repo}}
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
|
||||
- run: pnpm install --frozen-lockfile
|
||||
|
||||
- uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
- uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
with:
|
||||
bazelrc: ./.bazelrc.user
|
||||
|
||||
|
||||
+29
-37
@@ -21,9 +21,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
with:
|
||||
cache-node-modules: true
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Check code lint
|
||||
@@ -41,15 +39,20 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
with:
|
||||
cache-node-modules: true
|
||||
disable-package-manager-cache: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
with:
|
||||
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
|
||||
- name: Cache downloaded Cypress binary
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
with:
|
||||
path: '~/.cache/Cypress'
|
||||
key: cypress-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Run unit tests
|
||||
@@ -63,18 +66,17 @@ jobs:
|
||||
start: pnpm bazel run //devtools/src:devserver
|
||||
wait-on: 'http://localhost:4200'
|
||||
wait-on-timeout: 300
|
||||
install: false
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
with:
|
||||
cache-node-modules: true
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
with:
|
||||
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
|
||||
- name: Install node modules
|
||||
@@ -86,13 +88,11 @@ jobs:
|
||||
runs-on: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
with:
|
||||
cache-node-modules: true
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
with:
|
||||
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
|
||||
- name: Install node modules
|
||||
@@ -105,11 +105,11 @@ jobs:
|
||||
labels: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
with:
|
||||
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
|
||||
- name: Install node modules
|
||||
@@ -124,13 +124,13 @@ jobs:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- run: echo "https://${{secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN}}:@github.com" > ${HOME}/.git_credentials
|
||||
@@ -142,17 +142,11 @@ jobs:
|
||||
labels: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
./node_modules
|
||||
./packages/zone.js/node_modules
|
||||
./packages/zone.js/test/typings/node_modules
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
with:
|
||||
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
|
||||
- name: Install node modules
|
||||
@@ -192,8 +186,6 @@ jobs:
|
||||
# steps:
|
||||
# - name: Initialize environment
|
||||
# uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b5a3609f89c06eb4037dce22a93641213a5d1508
|
||||
# with:
|
||||
# cache-node-modules: true
|
||||
# - name: Install node modules
|
||||
# run: pnpm install --frozen-lockfile
|
||||
# - uses: ./.github/actions/saucelabs-legacy
|
||||
@@ -204,11 +196,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Build adev to ensure it continues to work
|
||||
|
||||
@@ -12,14 +12,14 @@ jobs:
|
||||
labels:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: angular/dev-infra/github-actions/pull-request-labeling@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: angular/dev-infra/github-actions/pull-request-labeling@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
post_approval_changes:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: angular/dev-infra/github-actions/post-approval-changes@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: angular/dev-infra/github-actions/post-approval-changes@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -13,8 +13,8 @@ jobs:
|
||||
statuses: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: angular/dev-infra/github-actions/google-internal-tests@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: angular/dev-infra/github-actions/google-internal-tests@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
with:
|
||||
run-tests-guide-url: http://go/angular-g3sync-start
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -13,17 +13,17 @@ jobs:
|
||||
JOBS: 2
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Saucelabs Variables
|
||||
uses: angular/dev-infra/github-actions/saucelabs@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/saucelabs@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Set up Sauce Tunnel Daemon
|
||||
run: pnpm bazel run //tools/saucelabs-daemon/background-service -- $JOBS &
|
||||
env:
|
||||
|
||||
@@ -9,6 +9,6 @@ jobs:
|
||||
status:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: angular/dev-infra/github-actions/unified-status-check@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
- uses: angular/dev-infra/github-actions/unified-status-check@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
workflows: ${{ steps.workflows.outputs.workflows }}
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- id: workflows
|
||||
@@ -36,9 +36,9 @@ jobs:
|
||||
workflow: ${{ fromJSON(needs.list.outputs.workflows) }}
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- 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
|
||||
|
||||
+24
-32
@@ -19,9 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
with:
|
||||
cache-node-modules: true
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Check code lint
|
||||
@@ -39,7 +37,7 @@ jobs:
|
||||
- name: Check code format
|
||||
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@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/linting/licenses@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
with:
|
||||
allow-dependencies-licenses: 'pkg:npm/google-protobuf@'
|
||||
|
||||
@@ -47,13 +45,18 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
with:
|
||||
cache-node-modules: true
|
||||
disable-package-manager-cache: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Cache downloaded Cypress binary
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
with:
|
||||
path: '~/.cache/Cypress'
|
||||
key: cypress-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Run unit tests
|
||||
@@ -67,18 +70,17 @@ jobs:
|
||||
start: pnpm bazel run //devtools/src:devserver
|
||||
wait-on: 'http://localhost:4200'
|
||||
wait-on-timeout: 300
|
||||
install: false
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest-8core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
with:
|
||||
cache-node-modules: true
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Run CI tests for framework
|
||||
@@ -98,13 +100,11 @@ jobs:
|
||||
runs-on: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
with:
|
||||
cache-node-modules: true
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Run integration CI tests for framework
|
||||
@@ -115,11 +115,11 @@ jobs:
|
||||
labels: ubuntu-latest-8core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Run tests
|
||||
@@ -132,17 +132,11 @@ jobs:
|
||||
labels: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
./node_modules
|
||||
./packages/zone.js/node_modules
|
||||
./packages/zone.js/test/typings/node_modules
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4d2f875ec29ee71e0fe1a349a99c5ab2ccb71e30
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae4e34835e566bbcc12bec8f2191b069f307ece2
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- run: |
|
||||
@@ -180,8 +174,6 @@ jobs:
|
||||
# steps:
|
||||
# - name: Initialize environment
|
||||
# uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b5a3609f89c06eb4037dce22a93641213a5d1508
|
||||
# with:
|
||||
# cache-node-modules: true
|
||||
# - name: Install node modules
|
||||
# run: pnpm install --frozen-lockfile
|
||||
# - uses: ./.github/actions/saucelabs-legacy
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 'Checkout code'
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
@@ -47,6 +47,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: 'Upload to code-scanning'
|
||||
uses: github/codeql-action/upload-sarif@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
||||
uses: github/codeql-action/upload-sarif@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.11
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
# Setting `persist-credentials: false` prevents the github-action account from being the
|
||||
# account that is attempted to be used for authentication, instead the remote is set to
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
env:
|
||||
ANGULAR_CDK_BUILDS_READONLY_GITHUB_TOKEN: ${{ secrets.ANGULAR_CDK_BUILDS_READONLY_GITHUB_TOKEN }}
|
||||
- name: Create a PR CDK apis (if necessary)
|
||||
uses: peter-evans/create-pull-request@v7.0.8 # v7.0.8
|
||||
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
|
||||
with:
|
||||
token: ${{ secrets.ANGULAR_ROBOT_ACCESS_TOKEN }}
|
||||
push-to-fork: 'angular-robot/angular'
|
||||
@@ -66,7 +66,7 @@ jobs:
|
||||
env:
|
||||
ANGULAR_CLI_BUILDS_READONLY_GITHUB_TOKEN: ${{ secrets.ANGULAR_CLI_BUILDS_READONLY_GITHUB_TOKEN }}
|
||||
- name: Create a PR CLI help (if necessary)
|
||||
uses: peter-evans/create-pull-request@v7.0.8 # v7.0.8
|
||||
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
|
||||
with:
|
||||
token: ${{ secrets.ANGULAR_ROBOT_ACCESS_TOKEN }}
|
||||
push-to-fork: 'angular-robot/angular'
|
||||
|
||||
@@ -2,7 +2,6 @@ import {ReleaseConfig} from '@angular/ng-dev';
|
||||
|
||||
/** Configuration for the `ng-dev release` command. */
|
||||
export const release: ReleaseConfig = {
|
||||
rulesJsInteropMode: true,
|
||||
publishRegistry: 'https://wombat-dressing-room.appspot.com',
|
||||
representativeNpmPackage: '@angular/core',
|
||||
npmPackages: [
|
||||
|
||||
+4
-3
@@ -56,8 +56,8 @@
|
||||
|
||||
version: 3
|
||||
|
||||
# availability:
|
||||
# users_unavailable: ['atscott']
|
||||
availability:
|
||||
users_unavailable: ['devversion']
|
||||
|
||||
# Meta field that goes unused by PullApprove to allow for defining aliases to be
|
||||
# used throughout the config.
|
||||
@@ -177,6 +177,7 @@ groups:
|
||||
- thePunderWoman
|
||||
- ~pkozlowski-opensource
|
||||
- mmalerba
|
||||
- JeanMeche
|
||||
|
||||
# =========================================================
|
||||
# Framework: Security-sensitive files which require extra review
|
||||
@@ -273,7 +274,7 @@ groups:
|
||||
- bencodezen
|
||||
- crisbeto
|
||||
- kirjs
|
||||
- ~JeanMeche
|
||||
- JeanMeche
|
||||
- jelbourn
|
||||
- thePunderWoman
|
||||
- devversion
|
||||
|
||||
+8
-3
@@ -1,7 +1,8 @@
|
||||
load("@aspect_rules_js//js:defs.bzl", "js_library")
|
||||
load("@npm2//:defs.bzl", "npm_link_all_packages")
|
||||
load("@devinfra//bazel/validation:defs.bzl", "validate_ts_version_matching")
|
||||
load("@npm//:defs.bzl", "npm_link_all_packages")
|
||||
load("//:yarn.bzl", "YARN_PATH")
|
||||
load("//tools:defaults2.bzl", "copy_to_bin", "js_binary")
|
||||
load("//tools:defaults.bzl", "copy_to_bin", "js_binary")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
@@ -11,7 +12,6 @@ exports_files([
|
||||
"browser-providers.conf.js",
|
||||
YARN_PATH,
|
||||
"package.json",
|
||||
"angular.json",
|
||||
])
|
||||
|
||||
npm_link_all_packages(
|
||||
@@ -25,6 +25,11 @@ filegroup(
|
||||
srcs = ["package.json"],
|
||||
)
|
||||
|
||||
validate_ts_version_matching(
|
||||
module_lock_file = "MODULE.bazel.lock",
|
||||
package_json = "package.json",
|
||||
)
|
||||
|
||||
alias(
|
||||
name = "tsconfig.json",
|
||||
actual = "//packages:tsconfig-build.json",
|
||||
|
||||
+93
-155
@@ -1,52 +1,87 @@
|
||||
<a name="20.2.0-next.6"></a>
|
||||
# 20.2.0-next.6 (2025-08-07)
|
||||
### compiler-cli
|
||||
<a name="20.2.3"></a>
|
||||
# 20.2.3 (2025-08-29)
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [812463c563](https://github.com/angular/angular/commit/812463c5636effe5bd5ba5c7c7fc65c3cc08d047) | fix | Ignore diagnostics on ngTemplateContextGuard lines in TCB ([#63054](https://github.com/angular/angular/pull/63054)) |
|
||||
| [45b030b5ce](https://github.com/angular/angular/commit/45b030b5ce1e116a88fe1c2fe133f654fb1f66c5) | fix | prevent dom event assertion in TCB generation on older angular versions ([#63053](https://github.com/angular/angular/pull/63053)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="20.2.0-next.5"></a>
|
||||
# 20.2.0-next.5 (2025-08-06)
|
||||
## Deprecations
|
||||
### router
|
||||
- The Router.getCurrentNavigation method is deprecated. Use the Router.currentNavigation signal instead.
|
||||
### platform-browser
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [d24d5742db](https://github.com/angular/angular/commit/d24d5742db694604b09d57a3503e8c32751c4836) | feat | Add IsolatedShadowDom encapsulation method ([#62723](https://github.com/angular/angular/pull/62723)) |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [687c374826](https://github.com/angular/angular/commit/687c374826c5e9ea91839c20f0df815ce085c583) | feat | add a currentNavigation signal to the Router service. ([#63011](https://github.com/angular/angular/pull/63011)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="20.1.6"></a>
|
||||
# 20.1.6 (2025-08-06)
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="20.2.0-next.4"></a>
|
||||
# 20.2.0-next.4 (2025-08-06)
|
||||
## Deprecations
|
||||
### router
|
||||
- The Router.getCurrentNavigation method is deprecated. Use the Router.currentNavigation signal instead.
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [fb1fc823c4](https://github.com/angular/angular/commit/fb1fc823c47ef34347ba758dd73cc997c7f0c009) | fix | correctly type check host listeners to own outputs ([#62965](https://github.com/angular/angular/pull/62965)) |
|
||||
| [479a919f42](https://github.com/angular/angular/commit/479a919f42517193653384220adab5b89dd74e3d) | fix | fixes regression with event parsing and animate prefix ([#63470](https://github.com/angular/angular/pull/63470)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [f87fad3fff](https://github.com/angular/angular/commit/f87fad3fff62cebf2868e06cba48e0f27b719d24) | fix | avoid injecting internal error handler from a destroyed injector ([#62275](https://github.com/angular/angular/pull/62275)) |
|
||||
| [114906d2d6](https://github.com/angular/angular/commit/114906d2d68d98c98961d858abd3ae714d4809a3) | fix | Fix cancellation of animation enter classes ([#63442](https://github.com/angular/angular/pull/63442)) |
|
||||
| [596b545130](https://github.com/angular/angular/commit/596b5451309b8ce4f08a1cd36e6b3610507d52f9) | fix | Prevent an error on cleanup when an `rxResource` `stream` threw before returning an `Observable` ([#63342](https://github.com/angular/angular/pull/63342)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="20.2.2"></a>
|
||||
# 20.2.2 (2025-08-27)
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [d7b6045d61](https://github.com/angular/angular/commit/d7b6045d61582d20a17802e769dc1441984988f0) | fix | fixes animations on elements with structural directives ([#63390](https://github.com/angular/angular/pull/63390)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [6c421ed65d](https://github.com/angular/angular/commit/6c421ed65d050765a18eafc51fe7257abc5682ce) | fix | Ensures `@for` loop animations never get cancelled ([#63328](https://github.com/angular/angular/pull/63328)) |
|
||||
| [9093e0e132](https://github.com/angular/angular/commit/9093e0e132f99c2b590c31b299871bcd493b7de0) | fix | fix memory leak with leaving nodes tracking ([#63328](https://github.com/angular/angular/pull/63328)) |
|
||||
| [c8f07daf8f](https://github.com/angular/angular/commit/c8f07daf8f2c7e8c6641eb4368379a3f5f1d1f52) | fix | Fixes `animate.leave` binding to a string with spaces ([#63366](https://github.com/angular/angular/pull/63366)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="20.2.1"></a>
|
||||
# 20.2.1 (2025-08-21)
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [a28672fb70](https://github.com/angular/angular/commit/a28672fb7017cc62e42829c5910c3b39373d7913) | fix | Keep paraenthesis in Nullish + Boolean expression. ([#63292](https://github.com/angular/angular/pull/63292)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="20.2.0"></a>
|
||||
# 20.2.0 (2025-08-20)
|
||||
## Deprecations
|
||||
### animations
|
||||
- @angular/animations
|
||||
### core
|
||||
- @angular/animations
|
||||
### router
|
||||
- The Router.getCurrentNavigation method is deprecated. Use the Router.currentNavigation signal instead.
|
||||
- The Router.getCurrentNavigation method is deprecated. Use the Router.currentNavigation signal instead.
|
||||
### animations
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [9766116cea](https://github.com/angular/angular/commit/9766116cea69607d80144251a599f1cc1b12e02c) | refactor | deprecate the animations package ([#62795](https://github.com/angular/angular/pull/62795)) |
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [7767aa640c](https://github.com/angular/angular/commit/7767aa640c542f5058df9322f2bbe974fa8d3c81) | fix | allow more characters in square-bracketed attribute names ([#62742](https://github.com/angular/angular/pull/62742)) |
|
||||
| [7b51728813](https://github.com/angular/angular/commit/7b517288139aec166e5e5b60e84b1e22e3d6b70f) | fix | fixes animation event host bindings not firing ([#63217](https://github.com/angular/angular/pull/63217)) |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [5abfe4a899](https://github.com/angular/angular/commit/5abfe4a8999e42ad44e6f1d4414f241094bb8fdb) | feat | add diagnostic for uninvoked functions in text interpolation ([#59191](https://github.com/angular/angular/pull/59191)) |
|
||||
| [c4917074f1](https://github.com/angular/angular/commit/c4917074f1e278ea24948a8810b3d4f306765174) | fix | display proper function in NG8117 message ([#62842](https://github.com/angular/angular/pull/62842)) |
|
||||
| [812463c563](https://github.com/angular/angular/commit/812463c5636effe5bd5ba5c7c7fc65c3cc08d047) | fix | Ignore diagnostics on ngTemplateContextGuard lines in TCB ([#63054](https://github.com/angular/angular/pull/63054)) |
|
||||
| [45b030b5ce](https://github.com/angular/angular/commit/45b030b5ce1e116a88fe1c2fe133f654fb1f66c5) | fix | prevent dom event assertion in TCB generation on older angular versions ([#63053](https://github.com/angular/angular/pull/63053)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [6b1f4b9e8b](https://github.com/angular/angular/commit/6b1f4b9e8bb981377e271e6af0d9768ff7f765e9) | feat | add enter and leave animation instructions ([#62682](https://github.com/angular/angular/pull/62682)) |
|
||||
| [cec91c0035](https://github.com/angular/angular/commit/cec91c00356ee3974c39c9471b243a2a16149f5b) | feat | add option to infer the tag names of components in tests ([#62283](https://github.com/angular/angular/pull/62283)) |
|
||||
| [141bb75ff2](https://github.com/angular/angular/commit/141bb75ff241425a93ce5b60b56a4247e67d7648) | feat | Promote zoneless to stable ([#62699](https://github.com/angular/angular/pull/62699)) |
|
||||
| [4138aca91f](https://github.com/angular/angular/commit/4138aca91fe828f0cfbd779d0c456cdea7703bdc) | feat | render ARIA property bindings as attributes ([#62630](https://github.com/angular/angular/pull/62630)) |
|
||||
| [a409534d6c](https://github.com/angular/angular/commit/a409534d6c3d7cb4472afffd6b17df8c25e34106) | feat | support `as` aliases on `else if` blocks ([#63047](https://github.com/angular/angular/pull/63047)) |
|
||||
| [745ea44394](https://github.com/angular/angular/commit/745ea4439465494ab5b7002dd1fa320cd32220fb) | feat | support TypeScript 5.9 ([#62541](https://github.com/angular/angular/pull/62541)) |
|
||||
| [593cc8a368](https://github.com/angular/angular/commit/593cc8a3684dfb163bfffa265c5efb3bc7efacd1) | fix | checks if body exists before continuing ([#62768](https://github.com/angular/angular/pull/62768)) |
|
||||
| [bdc31675b7](https://github.com/angular/angular/commit/bdc31675b7e5f37d2b312c766fe4963305620bdf) | fix | ensure animate events do not have duplicate elements ([#63216](https://github.com/angular/angular/pull/63216)) |
|
||||
| [de3a0c5cf3](https://github.com/angular/angular/commit/de3a0c5cf3f87782fa63d30edf6ac05eb6be9fac) | fix | Fix `animate.enter` class removal when composing classes ([#62981](https://github.com/angular/angular/pull/62981)) |
|
||||
| [6597ac0af7](https://github.com/angular/angular/commit/6597ac0af78ac2224ec2f9a37283b53aee11abe1) | fix | fix support for space separated strings in leave animations ([#62979](https://github.com/angular/angular/pull/62979)) |
|
||||
| [ebd622b344](https://github.com/angular/angular/commit/ebd622b3449789b72efc8295244ca924a299e7c1) | fix | fixes empty animations when recalculating styles ([#63007](https://github.com/angular/angular/pull/63007)) |
|
||||
| [455b147488](https://github.com/angular/angular/commit/455b147488dc0a064c0ca13a96a4df3c3ed01152) | fix | fixes timing issues with enter animations ([#62925](https://github.com/angular/angular/pull/62925)) |
|
||||
| [648bbb097e](https://github.com/angular/angular/commit/648bbb097e858fd1276b6ee88c82b674341e6163) | fix | properly recognize failed `fetch` responses when loading external resources in JIT ([#62992](https://github.com/angular/angular/pull/62992)) |
|
||||
| [f9d73cc687](https://github.com/angular/angular/commit/f9d73cc6877d516da4ab4704c21bb19164123fa1) | fix | handle cases where classes added have no animations ([#63242](https://github.com/angular/angular/pull/63242)) |
|
||||
| [6a1184600c](https://github.com/angular/angular/commit/6a1184600ce0fc7a3f338d6766612e9510ef5518) | fix | prevents duplicate nodes when `@if` toggles with leave animations ([#63048](https://github.com/angular/angular/pull/63048)) |
|
||||
| [063b5e166f](https://github.com/angular/angular/commit/063b5e166f66bce1abd06c258242212009e76cca) | fix | switch check to documentElement with chaining ([#62773](https://github.com/angular/angular/pull/62773)) |
|
||||
| [320de4e96d](https://github.com/angular/angular/commit/320de4e96d250cad1ce2c9f8c0fa2022da53b734) | refactor | deprecate animations field on component interface ([#62895](https://github.com/angular/angular/pull/62895)) |
|
||||
### forms
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
@@ -54,11 +89,16 @@
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [e5d6fb5825](https://github.com/angular/angular/commit/e5d6fb5825d5e1b76d73d5c1c64c9986cfb02874) | fix | Reset headers, progress, and statusCode when using `set()` in `HttpResource` ([#62873](https://github.com/angular/angular/pull/62873)) |
|
||||
### migrations
|
||||
| [0984b30388](https://github.com/angular/angular/commit/0984b30388ef51dfad66f1228f665b89b73ef3fb) | feat | Add redirected property to HttpResponse and HttpErrorResponse ([#62675](https://github.com/angular/angular/pull/62675)) |
|
||||
| [be811fee79](https://github.com/angular/angular/commit/be811fee7925fb482567fa7cd9d485ac28acdade) | feat | add referrer & integrity support for fetch requests in httpResource ([#62461](https://github.com/angular/angular/pull/62461)) |
|
||||
| [1cf9d9064c](https://github.com/angular/angular/commit/1cf9d9064c15c00071ece3b78c8019035a6db6ce) | feat | Add support for fetch referrer & integrity options in HttpClient ([#62417](https://github.com/angular/angular/pull/62417)) |
|
||||
| [1408baff45](https://github.com/angular/angular/commit/1408baff453e636da05838fa17c6e4abd86c4b72) | fix | Add missing timeout and transferCache options to `HttpClient` ([#62586](https://github.com/angular/angular/pull/62586)) |
|
||||
### language-service
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [b1514d512e](https://github.com/angular/angular/commit/b1514d512e041674d1ebbac88eb2d9f6a0f2cf5e) | fix | incorrect filtering in inject migration ([#62913](https://github.com/angular/angular/pull/62913)) |
|
||||
| [c81e345e72](https://github.com/angular/angular/commit/c81e345e726b5b281621159c789e6d80a9f328e2) | feat | support auto-import for attribute completions ([#62797](https://github.com/angular/angular/pull/62797)) |
|
||||
| [d64dd27a02](https://github.com/angular/angular/commit/d64dd27a02630b631bc9890d7292d4683493cb65) | feat | support to report the deprecated API in the template ([#62054](https://github.com/angular/angular/pull/62054)) |
|
||||
| [591c7e2ec8](https://github.com/angular/angular/commit/591c7e2ec82c6669ffa6e0011b8a0a4fc12e9c3a) | fix | Support to resolve the re-export component. ([#62585](https://github.com/angular/angular/pull/62585)) |
|
||||
### platform-browser
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
@@ -67,11 +107,22 @@
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [d00b3fed58](https://github.com/angular/angular/commit/d00b3fed58496369d9f3a1ac0d74416a586be78b) | feat | add a `currentNavigation` signal to the `Router` service. ([#62971](https://github.com/angular/angular/pull/62971)) |
|
||||
| [687c374826](https://github.com/angular/angular/commit/687c374826c5e9ea91839c20f0df815ce085c583) | feat | add a currentNavigation signal to the Router service. ([#63011](https://github.com/angular/angular/pull/63011)) |
|
||||
| [9c45c322d1](https://github.com/angular/angular/commit/9c45c322d1ac3b05c916b7c956263066fb9be47f) | fix | ensure preloaded components are properly activated ([#62502](https://github.com/angular/angular/pull/62502)) |
|
||||
### service-worker
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [8255e0cf15](https://github.com/angular/angular/commit/8255e0cf15353e9eee339ae01851e32c0e5e174d) | feat | add messageerror event handling and logging ([#62834](https://github.com/angular/angular/pull/62834)) |
|
||||
| [5220b51e75](https://github.com/angular/angular/commit/5220b51e75e672ff41c90f4798289961973df8e0) | feat | Adds for type in provideServiceWorker ([#62831](https://github.com/angular/angular/pull/62831)) |
|
||||
| [4ac6171b09](https://github.com/angular/angular/commit/4ac6171b09e449c619e0588c366861f8f3bb59be) | feat | Adds support for updateViaCache in provideServiceWorker ([#62721](https://github.com/angular/angular/pull/62721)) |
|
||||
| [b65c3d5e19](https://github.com/angular/angular/commit/b65c3d5e195267dd90b2826d4615ced1328b1709) | feat | Improves storage full detection in data caching ([#62737](https://github.com/angular/angular/pull/62737)) |
|
||||
| [3b214d2040](https://github.com/angular/angular/commit/3b214d20403160ab73e65dca0352545efd577c31) | feat | Logs unhandled promise rejections in service worker ([#63059](https://github.com/angular/angular/pull/63059)) |
|
||||
| [6d011687ec](https://github.com/angular/angular/commit/6d011687ec1fa2b8f0211379bb98adc8e02f4e9a) | feat | notify clients about version failures ([#62718](https://github.com/angular/angular/pull/62718)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="20.1.6"></a>
|
||||
# 20.1.6 (2025-08-06)
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
@@ -96,44 +147,6 @@
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="20.2.0-next.3"></a>
|
||||
# 20.2.0-next.3 (2025-07-31)
|
||||
## Deprecations
|
||||
### animations
|
||||
- @angular/animations
|
||||
### core
|
||||
- @angular/animations
|
||||
### animations
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [9766116cea](https://github.com/angular/angular/commit/9766116cea69607d80144251a599f1cc1b12e02c) | refactor | deprecate the animations package ([#62795](https://github.com/angular/angular/pull/62795)) |
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [5b25d93f27](https://github.com/angular/angular/commit/5b25d93f27b259098ed968a8a355e9c16867b37b) | fix | exclude more safe reads expression from 2way-binding ([#62852](https://github.com/angular/angular/pull/62852)) |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [c4917074f1](https://github.com/angular/angular/commit/c4917074f1e278ea24948a8810b3d4f306765174) | fix | display proper function in NG8117 message ([#62842](https://github.com/angular/angular/pull/62842)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [92c2d2a006](https://github.com/angular/angular/commit/92c2d2a0065a1d5a7e87fb54a4cd454f21bd8ab9) | fix | update symbols for new signals api ([#62284](https://github.com/angular/angular/pull/62284)) |
|
||||
| [320de4e96d](https://github.com/angular/angular/commit/320de4e96d250cad1ce2c9f8c0fa2022da53b734) | refactor | deprecate animations field on component interface ([#62895](https://github.com/angular/angular/pull/62895)) |
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [0984b30388](https://github.com/angular/angular/commit/0984b30388ef51dfad66f1228f665b89b73ef3fb) | feat | Add redirected property to HttpResponse and HttpErrorResponse ([#62675](https://github.com/angular/angular/pull/62675)) |
|
||||
| [245494ad29](https://github.com/angular/angular/commit/245494ad292ea0b61ad7e314c8913afdcd8ca837) | fix | add missing http options allowed in fetch API ([#62881](https://github.com/angular/angular/pull/62881)) |
|
||||
| [1b73c23597](https://github.com/angular/angular/commit/1b73c235977f37ca7fbc5f4be8b194054632352b) | fix | propagate plain errors when parsing fails ([#62765](https://github.com/angular/angular/pull/62765)) |
|
||||
### service-worker
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [b65c3d5e19](https://github.com/angular/angular/commit/b65c3d5e195267dd90b2826d4615ced1328b1709) | feat | Improves storage full detection in data caching ([#62737](https://github.com/angular/angular/pull/62737)) |
|
||||
| [6d011687ec](https://github.com/angular/angular/commit/6d011687ec1fa2b8f0211379bb98adc8e02f4e9a) | feat | notify clients about version failures ([#62718](https://github.com/angular/angular/pull/62718)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="20.1.4"></a>
|
||||
# 20.1.4 (2025-07-31)
|
||||
### compiler
|
||||
@@ -152,37 +165,6 @@
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="20.2.0-next.2"></a>
|
||||
# 20.2.0-next.2 (2025-07-23)
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [7767aa640c](https://github.com/angular/angular/commit/7767aa640c542f5058df9322f2bbe974fa8d3c81) | fix | allow more characters in square-bracketed attribute names ([#62742](https://github.com/angular/angular/pull/62742)) |
|
||||
| [3171d01452](https://github.com/angular/angular/commit/3171d01452444721dbea53d1d1ca758f38d083a5) | fix | fix detection of directive deps in JIT ([#62666](https://github.com/angular/angular/pull/62666)) |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [5abfe4a899](https://github.com/angular/angular/commit/5abfe4a8999e42ad44e6f1d4414f241094bb8fdb) | feat | add diagnostic for uninvoked functions in text interpolation ([#59191](https://github.com/angular/angular/pull/59191)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [6b1f4b9e8b](https://github.com/angular/angular/commit/6b1f4b9e8bb981377e271e6af0d9768ff7f765e9) | feat | add enter and leave animation instructions ([#62682](https://github.com/angular/angular/pull/62682)) |
|
||||
| [cec91c0035](https://github.com/angular/angular/commit/cec91c00356ee3974c39c9471b243a2a16149f5b) | feat | add option to infer the tag names of components in tests ([#62283](https://github.com/angular/angular/pull/62283)) |
|
||||
| [4138aca91f](https://github.com/angular/angular/commit/4138aca91fe828f0cfbd779d0c456cdea7703bdc) | feat | render ARIA property bindings as attributes ([#62630](https://github.com/angular/angular/pull/62630)) |
|
||||
| [593cc8a368](https://github.com/angular/angular/commit/593cc8a3684dfb163bfffa265c5efb3bc7efacd1) | fix | checks if body exists before continuing ([#62768](https://github.com/angular/angular/pull/62768)) |
|
||||
| [b8e415a717](https://github.com/angular/angular/commit/b8e415a717fd3747c7bab3f6ea652874082a19bb) | fix | fix change tracking for Resource#hasValue ([#62595](https://github.com/angular/angular/pull/62595)) |
|
||||
| [063b5e166f](https://github.com/angular/angular/commit/063b5e166f66bce1abd06c258242212009e76cca) | fix | switch check to documentElement with chaining ([#62773](https://github.com/angular/angular/pull/62773)) |
|
||||
### platform-browser
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [74d99ed379](https://github.com/angular/angular/commit/74d99ed3796a3ced462e327c9b5857e5de4b7cb9) | fix | resolve component resources before bootstrapping in JIT mode ([#62758](https://github.com/angular/angular/pull/62758)) |
|
||||
### service-worker
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [4ac6171b09](https://github.com/angular/angular/commit/4ac6171b09e449c619e0588c366861f8f3bb59be) | feat | Adds support for updateViaCache in provideServiceWorker ([#62721](https://github.com/angular/angular/pull/62721)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="20.1.3"></a>
|
||||
# 20.1.3 (2025-07-23)
|
||||
### core
|
||||
@@ -205,41 +187,6 @@
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="20.2.0-next.1"></a>
|
||||
# 20.2.0-next.1 (2025-07-16)
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [a1e3f2bcd1](https://github.com/angular/angular/commit/a1e3f2bcd14f897e685e11a84e011406dd6f7a33) | fix | incorrect spans for left side of binary operation ([#62641](https://github.com/angular/angular/pull/62641)) |
|
||||
| [18a675081f](https://github.com/angular/angular/commit/18a675081f945ed4d7f4c0ee83172ca1528e7b2e) | fix | more permissive parsing of @ characters ([#62644](https://github.com/angular/angular/pull/62644)) |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [527bd778a7](https://github.com/angular/angular/commit/527bd778a7b23c23766bad7fb272d61df9a884b1) | fix | infer type of event target for void elements ([#62648](https://github.com/angular/angular/pull/62648)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [745ea44394](https://github.com/angular/angular/commit/745ea4439465494ab5b7002dd1fa320cd32220fb) | feat | support TypeScript 5.9 ([#62541](https://github.com/angular/angular/pull/62541)) |
|
||||
| [859958dbfe](https://github.com/angular/angular/commit/859958dbfe5b8b505c84ecfed81d43e6c59e6f0c) | fix | Ensure application remains unstable during bootstrap ([#62631](https://github.com/angular/angular/pull/62631)) |
|
||||
| [780774f948](https://github.com/angular/angular/commit/780774f94806b8eb895cb2a77c0d2a154f3d2d22) | fix | InputBinding marks component a dirty. ([#62613](https://github.com/angular/angular/pull/62613)) |
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [be811fee79](https://github.com/angular/angular/commit/be811fee7925fb482567fa7cd9d485ac28acdade) | feat | add referrer & integrity support for fetch requests in httpResource ([#62461](https://github.com/angular/angular/pull/62461)) |
|
||||
| [1408baff45](https://github.com/angular/angular/commit/1408baff453e636da05838fa17c6e4abd86c4b72) | fix | Add missing timeout and transferCache options to `HttpClient` ([#62586](https://github.com/angular/angular/pull/62586)) |
|
||||
| [75a5d08c5e](https://github.com/angular/angular/commit/75a5d08c5e9947f835ef911aacfe6c673e4c9e94) | fix | do not display warnings `Angular detected that a `HttpClient` request with the `keepalive` option was sent using XHR` when option is not true ([#62536](https://github.com/angular/angular/pull/62536)) |
|
||||
### language-service
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [d64dd27a02](https://github.com/angular/angular/commit/d64dd27a02630b631bc9890d7292d4683493cb65) | feat | support to report the deprecated API in the template ([#62054](https://github.com/angular/angular/pull/62054)) |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [9c45c322d1](https://github.com/angular/angular/commit/9c45c322d1ac3b05c916b7c956263066fb9be47f) | fix | ensure preloaded components are properly activated ([#62502](https://github.com/angular/angular/pull/62502)) |
|
||||
| [e9f215624f](https://github.com/angular/angular/commit/e9f215624f73c6aec6ec78117339c803830f4114) | fix | handle errors from view transition readiness ([#62535](https://github.com/angular/angular/pull/62535)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="20.1.1"></a>
|
||||
# 20.1.1 (2025-07-16)
|
||||
### compiler
|
||||
@@ -267,15 +214,6 @@
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="20.2.0-next.0"></a>
|
||||
# 20.2.0-next.0 (2025-07-09)
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [1cf9d9064c](https://github.com/angular/angular/commit/1cf9d9064c15c00071ece3b78c8019035a6db6ce) | feat | Add support for fetch referrer & integrity options in HttpClient ([#62417](https://github.com/angular/angular/pull/62417)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="20.1.0"></a>
|
||||
# 20.1.0 (2025-07-09)
|
||||
### common
|
||||
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
"""Rules/toolchains for angular with Bazel."""
|
||||
|
||||
module(
|
||||
name = "angular",
|
||||
)
|
||||
|
||||
bazel_dep(name = "rules_pkg", version = "1.1.0")
|
||||
bazel_dep(name = "rules_nodejs", version = "6.5.0")
|
||||
bazel_dep(name = "aspect_rules_ts", version = "3.7.0")
|
||||
bazel_dep(name = "aspect_rules_js", version = "2.5.0")
|
||||
bazel_dep(name = "aspect_rules_esbuild", version = "0.22.1")
|
||||
bazel_dep(name = "aspect_rules_jasmine", version = "2.0.0")
|
||||
bazel_dep(name = "aspect_rules_rollup", version = "2.0.1")
|
||||
bazel_dep(name = "bazel_skylib", version = "1.8.1")
|
||||
bazel_dep(name = "aspect_bazel_lib", version = "2.21.1")
|
||||
bazel_dep(name = "tar.bzl", version = "0.5.5")
|
||||
bazel_dep(name = "yq.bzl", version = "0.2.0")
|
||||
bazel_dep(name = "rules_angular")
|
||||
git_override(
|
||||
module_name = "rules_angular",
|
||||
commit = "17eac47ea99057f7473a7d93292e76327c894ed9",
|
||||
remote = "https://github.com/devversion/rules_angular.git",
|
||||
)
|
||||
|
||||
bazel_dep(name = "devinfra")
|
||||
git_override(
|
||||
module_name = "devinfra",
|
||||
commit = "ae4e34835e566bbcc12bec8f2191b069f307ece2",
|
||||
remote = "https://github.com/angular/dev-infra.git",
|
||||
)
|
||||
|
||||
bazel_dep(name = "rules_sass")
|
||||
git_override(
|
||||
module_name = "rules_sass",
|
||||
commit = "76078d5e9776a0080dcee496e90b88d8a6179c19",
|
||||
remote = "https://github.com/devversion/rules_sass.git",
|
||||
)
|
||||
|
||||
bazel_dep(name = "rules_browsers")
|
||||
git_override(
|
||||
module_name = "rules_browsers",
|
||||
commit = "8ee9ae3216ef26516c8ef20537c89857343cdc3a",
|
||||
remote = "https://github.com/devversion/rules_browsers.git",
|
||||
)
|
||||
|
||||
yq = use_extension("@yq.bzl//yq:extensions.bzl", "yq")
|
||||
use_repo(yq, "yq_toolchains")
|
||||
|
||||
node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node")
|
||||
node.toolchain(node_version = "20.19.0")
|
||||
use_repo(node, "nodejs_toolchains")
|
||||
use_repo(node, "nodejs_darwin_amd64")
|
||||
use_repo(node, "nodejs_darwin_arm64")
|
||||
use_repo(node, "nodejs_linux_amd64")
|
||||
use_repo(node, "nodejs_linux_arm64")
|
||||
use_repo(node, "nodejs_linux_ppc64le")
|
||||
use_repo(node, "nodejs_linux_s390x")
|
||||
use_repo(node, "nodejs_windows_amd64")
|
||||
|
||||
pnpm = use_extension("@aspect_rules_js//npm:extensions.bzl", "pnpm")
|
||||
use_repo(pnpm, "pnpm")
|
||||
|
||||
npm = use_extension("@aspect_rules_js//npm:extensions.bzl", "npm")
|
||||
npm.npm_translate_lock(
|
||||
name = "npm",
|
||||
data = [
|
||||
"//:.pnpmfile.cjs",
|
||||
"//:package.json",
|
||||
"//:pnpm-workspace.yaml",
|
||||
"//:tools/pnpm-patches/dagre-d3-es+7.0.11.patch",
|
||||
"//adev:package.json",
|
||||
"//adev/shared-docs:package.json",
|
||||
"//adev/shared-docs/pipeline/api-gen:package.json",
|
||||
"//integration:package.json",
|
||||
"//modules:package.json",
|
||||
"//packages/animations:package.json",
|
||||
"//packages/benchpress:package.json",
|
||||
"//packages/common:package.json",
|
||||
"//packages/compiler:package.json",
|
||||
"//packages/compiler-cli:package.json",
|
||||
"//packages/compiler-cli/linker/babel/test:package.json",
|
||||
"//packages/core:package.json",
|
||||
"//packages/core/test/bundling:package.json",
|
||||
"//packages/elements:package.json",
|
||||
"//packages/forms:package.json",
|
||||
"//packages/language-service:package.json",
|
||||
"//packages/localize:package.json",
|
||||
"//packages/platform-browser:package.json",
|
||||
"//packages/platform-browser-dynamic:package.json",
|
||||
"//packages/platform-server:package.json",
|
||||
"//packages/router:package.json",
|
||||
"//packages/service-worker:package.json",
|
||||
"//packages/upgrade:package.json",
|
||||
"//tools/bazel/rules_angular_store:package.json",
|
||||
],
|
||||
npmrc = "//:.npmrc",
|
||||
pnpm_lock = "//:pnpm-lock.yaml",
|
||||
verify_node_modules_ignored = "//:.bazelignore",
|
||||
)
|
||||
use_repo(npm, "npm")
|
||||
|
||||
rules_ts_ext = use_extension("@aspect_rules_ts//ts:extensions.bzl", "ext")
|
||||
rules_ts_ext.deps(
|
||||
name = "angular_npm_typescript",
|
||||
# Obtained by: curl --silent https://registry.npmjs.org/typescript/5.9.2 | jq -r '.dist.integrity'
|
||||
ts_integrity = "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
|
||||
ts_version = "5.9.2",
|
||||
)
|
||||
use_repo(rules_ts_ext, **{"npm_typescript": "angular_npm_typescript"})
|
||||
|
||||
rules_angular = use_extension("@rules_angular//setup:extensions.bzl", "rules_angular")
|
||||
rules_angular.setup(
|
||||
name = "components_rules_angular_configurable_deps",
|
||||
angular_compiler_cli = "//:node_modules/@angular/compiler-cli",
|
||||
typescript = "//:node_modules/typescript",
|
||||
)
|
||||
use_repo(rules_angular, **{"rules_angular_configurable_deps": "components_rules_angular_configurable_deps"})
|
||||
|
||||
register_toolchains(
|
||||
"@devinfra//bazel/git-toolchain:git_linux_toolchain",
|
||||
"@devinfra//bazel/git-toolchain:git_macos_x86_toolchain",
|
||||
"@devinfra//bazel/git-toolchain:git_macos_arm64_toolchain",
|
||||
"@devinfra//bazel/git-toolchain:git_windows_toolchain",
|
||||
)
|
||||
|
||||
CLDR_VERSION = "41"
|
||||
|
||||
cldr_json_data = use_repo_rule("//packages/common/locales/generate-locales-tool:cldr-data.bzl", "cldr_json_data_repository")
|
||||
|
||||
cldr_json_data(
|
||||
name = "cldr_json_data",
|
||||
urls = {
|
||||
"https://github.com/unicode-org/cldr-json/releases/download/%s.0.0/cldr-%s.0.0-json-full.zip" % (CLDR_VERSION, CLDR_VERSION): "649b76647269e32b1b0a5f7b6eed52e9e63a1581f1afdcf4f6771e49c9713614",
|
||||
},
|
||||
)
|
||||
|
||||
cldr_xml_data = use_repo_rule("//packages/common/locales/generate-locales-tool:cldr-data.bzl", "cldr_xml_data_repository")
|
||||
|
||||
cldr_xml_data(
|
||||
name = "cldr_xml_data",
|
||||
urls = {
|
||||
"https://github.com/unicode-org/cldr/releases/download/release-%s/cldr-common-%s.0.zip" % (CLDR_VERSION, CLDR_VERSION): "823c6170c41e2de2c229574e8a436332d25f1c9723409867fe721e00bc92d853",
|
||||
},
|
||||
)
|
||||
|
||||
http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
# Fetch sauce connect (tool to open Saucelabs tunnel for Saucelabs browser tests)
|
||||
http_archive(
|
||||
name = "sauce_connect_linux_amd64",
|
||||
build_file_content = """exports_files(["bin/sc"], visibility = ["//visibility:public"])""",
|
||||
sha256 = "26b9c3630f441b47854b6032f7eca6f1d88d3f62e50ee44c27015d71a5155c36",
|
||||
strip_prefix = "sc-4.8.2-linux",
|
||||
url = "https://saucelabs.com/downloads/sc-4.8.2-linux.tar.gz",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "sauce_connect_mac",
|
||||
build_file_content = """exports_files(["bin/sc"], visibility = ["//visibility:public"])""",
|
||||
sha256 = "28277ce81ef9ab84f5b87b526258920a8ead44789a5034346e872629bbf38089",
|
||||
strip_prefix = "sc-4.8.2-osx",
|
||||
url = "https://saucelabs.com/downloads/sc-4.8.2-osx.zip",
|
||||
)
|
||||
Generated
+4329
File diff suppressed because it is too large
Load Diff
@@ -1,257 +0,0 @@
|
||||
workspace(
|
||||
name = "angular",
|
||||
)
|
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
# The PKG rules are needed to build tar packages for integration tests. The builtin
|
||||
# rule in `@bazel_tools` is not Windows compatible and outdated.
|
||||
# NOTE: We cannot move past version 0.6.0 as pkg_tar no longer works on directories, which rules_nodejs
|
||||
# relies on for node_modules setup.
|
||||
http_archive(
|
||||
name = "rules_pkg",
|
||||
sha256 = "62eeb544ff1ef41d786e329e1536c1d541bb9bcad27ae984d57f18f314018e66",
|
||||
urls = [
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/rules_pkg/releases/download/0.6.0/rules_pkg-0.6.0.tar.gz",
|
||||
"https://github.com/bazelbuild/rules_pkg/releases/download/0.6.0/rules_pkg-0.6.0.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "aspect_rules_js",
|
||||
sha256 = "304c51726b727d53277dd28fcda1b8e43b7e46818530b8d6265e7be98d5e2b25",
|
||||
strip_prefix = "rules_js-2.3.8",
|
||||
url = "https://github.com/aspect-build/rules_js/releases/download/v2.3.8/rules_js-v2.3.8.tar.gz",
|
||||
)
|
||||
|
||||
load("@aspect_rules_js//js:repositories.bzl", "rules_js_dependencies")
|
||||
|
||||
rules_js_dependencies()
|
||||
|
||||
load("@aspect_rules_js//js:toolchains.bzl", "rules_js_register_toolchains")
|
||||
|
||||
rules_js_register_toolchains(
|
||||
node_repositories = {
|
||||
"20.19.0-darwin_arm64": ("node-v20.19.0-darwin-arm64.tar.gz", "node-v20.19.0-darwin-arm64", "c016cd1975a264a29dc1b07c6fbe60d5df0a0c2beb4113c0450e3d998d1a0d9c"),
|
||||
"20.19.0-darwin_amd64": ("node-v20.19.0-darwin-x64.tar.gz", "node-v20.19.0-darwin-x64", "a8554af97d6491fdbdabe63d3a1cfb9571228d25a3ad9aed2df856facb131b20"),
|
||||
"20.19.0-linux_arm64": ("node-v20.19.0-linux-arm64.tar.xz", "node-v20.19.0-linux-arm64", "dbe339e55eb393955a213e6b872066880bb9feceaa494f4d44c7aac205ec2ab9"),
|
||||
"20.19.0-linux_ppc64le": ("node-v20.19.0-linux-ppc64le.tar.xz", "node-v20.19.0-linux-ppc64le", "84937108f005679e60b486ed8e801cebfe923f02b76d8e710463d32f82181f65"),
|
||||
"20.19.0-linux_s390x": ("node-v20.19.0-linux-s390x.tar.xz", "node-v20.19.0-linux-s390x", "11f8ee99d792a83bba7b29911e0229dd6cd5e88987d7416346067db1cc76d89a"),
|
||||
"20.19.0-linux_amd64": ("node-v20.19.0-linux-x64.tar.xz", "node-v20.19.0-linux-x64", "b4e336584d62abefad31baecff7af167268be9bb7dd11f1297112e6eed3ca0d5"),
|
||||
"20.19.0-windows_amd64": ("node-v20.19.0-win-x64.zip", "node-v20.19.0-win-x64", "be72284c7bc62de07d5a9fd0ae196879842c085f11f7f2b60bf8864c0c9d6a4f"),
|
||||
},
|
||||
node_version = "20.19.0",
|
||||
)
|
||||
|
||||
load("@aspect_rules_js//npm:repositories.bzl", "npm_translate_lock")
|
||||
|
||||
npm_translate_lock(
|
||||
name = "npm2",
|
||||
data = [
|
||||
"//:.pnpmfile.cjs",
|
||||
"//:package.json",
|
||||
"//:pnpm-workspace.yaml",
|
||||
"//:tools/pnpm-patches/dagre-d3-es+7.0.11.patch",
|
||||
"//adev:package.json",
|
||||
"//adev/shared-docs:package.json",
|
||||
"//adev/shared-docs/pipeline/api-gen:package.json",
|
||||
"//integration:package.json",
|
||||
"//modules:package.json",
|
||||
"//packages/animations:package.json",
|
||||
"//packages/benchpress:package.json",
|
||||
"//packages/common:package.json",
|
||||
"//packages/compiler:package.json",
|
||||
"//packages/compiler-cli:package.json",
|
||||
"//packages/compiler-cli/linker/babel/test:package.json",
|
||||
"//packages/core:package.json",
|
||||
"//packages/core/test/bundling:package.json",
|
||||
"//packages/elements:package.json",
|
||||
"//packages/forms:package.json",
|
||||
"//packages/language-service:package.json",
|
||||
"//packages/localize:package.json",
|
||||
"//packages/platform-browser:package.json",
|
||||
"//packages/platform-browser-dynamic:package.json",
|
||||
"//packages/platform-server:package.json",
|
||||
"//packages/router:package.json",
|
||||
"//packages/service-worker:package.json",
|
||||
"//packages/upgrade:package.json",
|
||||
"//tools/bazel/rules_angular_store:package.json",
|
||||
],
|
||||
npmrc = "//:.npmrc",
|
||||
pnpm_lock = "//:pnpm-lock.yaml",
|
||||
pnpm_version = "9.15.9",
|
||||
verify_node_modules_ignored = "//:.bazelignore",
|
||||
)
|
||||
|
||||
load("@npm2//:repositories.bzl", "npm_repositories")
|
||||
|
||||
npm_repositories()
|
||||
|
||||
http_archive(
|
||||
name = "aspect_rules_ts",
|
||||
sha256 = "09af62a0d46918d815b5f48b5ed0f5349b62c15fc42fcc3fef5c246504ff8d99",
|
||||
strip_prefix = "rules_ts-3.6.3",
|
||||
url = "https://github.com/aspect-build/rules_ts/releases/download/v3.6.3/rules_ts-v3.6.3.tar.gz",
|
||||
)
|
||||
|
||||
load("@aspect_rules_ts//ts:repositories.bzl", "rules_ts_dependencies")
|
||||
|
||||
rules_ts_dependencies(
|
||||
# Obtained by: curl --silent https://registry.npmjs.org/typescript/5.9.2 | jq -r '.dist.integrity'
|
||||
ts_integrity = "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
|
||||
ts_version_from = "//:package.json",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "aspect_rules_rollup",
|
||||
sha256 = "0b8ac7d97cd660eb9a275600227e9c4268f5904cba962939d1a6ce9a0a059d2e",
|
||||
strip_prefix = "rules_rollup-2.0.1",
|
||||
url = "https://github.com/aspect-build/rules_rollup/releases/download/v2.0.1/rules_rollup-v2.0.1.tar.gz",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "aspect_rules_jasmine",
|
||||
sha256 = "0d2f9c977842685895020cac721d8cc4f1b37aae15af46128cf619741dc61529",
|
||||
strip_prefix = "rules_jasmine-2.0.0",
|
||||
url = "https://github.com/aspect-build/rules_jasmine/releases/download/v2.0.0/rules_jasmine-v2.0.0.tar.gz",
|
||||
)
|
||||
|
||||
load("@aspect_rules_jasmine//jasmine:dependencies.bzl", "rules_jasmine_dependencies")
|
||||
|
||||
rules_jasmine_dependencies()
|
||||
|
||||
load("@aspect_bazel_lib//lib:repositories.bzl", "aspect_bazel_lib_dependencies")
|
||||
|
||||
aspect_bazel_lib_dependencies()
|
||||
|
||||
load("@rules_pkg//:deps.bzl", "rules_pkg_dependencies")
|
||||
|
||||
rules_pkg_dependencies()
|
||||
|
||||
load("//packages/common/locales/generate-locales-tool:cldr-data.bzl", "cldr_json_data_repository", "cldr_xml_data_repository")
|
||||
|
||||
cldr_major_version = "41"
|
||||
|
||||
cldr_json_data_repository(
|
||||
name = "cldr_json_data",
|
||||
urls = {
|
||||
"https://github.com/unicode-org/cldr-json/releases/download/%s.0.0/cldr-%s.0.0-json-full.zip" % (cldr_major_version, cldr_major_version): "649b76647269e32b1b0a5f7b6eed52e9e63a1581f1afdcf4f6771e49c9713614",
|
||||
},
|
||||
)
|
||||
|
||||
cldr_xml_data_repository(
|
||||
name = "cldr_xml_data",
|
||||
urls = {
|
||||
"https://github.com/unicode-org/cldr/releases/download/release-%s/cldr-common-%s.0.zip" % (cldr_major_version, cldr_major_version): "823c6170c41e2de2c229574e8a436332d25f1c9723409867fe721e00bc92d853",
|
||||
},
|
||||
)
|
||||
|
||||
# Fetch sauce connect (tool to open Saucelabs tunnel for Saucelabs browser tests)
|
||||
http_archive(
|
||||
name = "sauce_connect_linux_amd64",
|
||||
build_file_content = """exports_files(["bin/sc"], visibility = ["//visibility:public"])""",
|
||||
sha256 = "26b9c3630f441b47854b6032f7eca6f1d88d3f62e50ee44c27015d71a5155c36",
|
||||
strip_prefix = "sc-4.8.2-linux",
|
||||
url = "https://saucelabs.com/downloads/sc-4.8.2-linux.tar.gz",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "sauce_connect_mac",
|
||||
build_file_content = """exports_files(["bin/sc"], visibility = ["//visibility:public"])""",
|
||||
sha256 = "28277ce81ef9ab84f5b87b526258920a8ead44789a5034346e872629bbf38089",
|
||||
strip_prefix = "sc-4.8.2-osx",
|
||||
url = "https://saucelabs.com/downloads/sc-4.8.2-osx.zip",
|
||||
)
|
||||
|
||||
git_repository(
|
||||
name = "devinfra",
|
||||
commit = "17282887a46c27e9f297a3292f1fde5b35dfafc1",
|
||||
remote = "https://github.com/angular/dev-infra.git",
|
||||
)
|
||||
|
||||
load("@devinfra//bazel:setup_dependencies_1.bzl", "setup_dependencies_1")
|
||||
|
||||
setup_dependencies_1()
|
||||
|
||||
load("@devinfra//bazel:setup_dependencies_2.bzl", "setup_dependencies_2")
|
||||
|
||||
setup_dependencies_2()
|
||||
|
||||
git_repository(
|
||||
name = "rules_angular",
|
||||
commit = "a1b4985620e2b66b45c590ed5ddda1b346b3f098",
|
||||
remote = "https://github.com/devversion/rules_angular.git",
|
||||
)
|
||||
|
||||
load("@rules_angular//setup:step_1.bzl", "rules_angular_step1")
|
||||
|
||||
rules_angular_step1()
|
||||
|
||||
load("@rules_angular//setup:step_2.bzl", "rules_angular_step2")
|
||||
|
||||
rules_angular_step2()
|
||||
|
||||
load("@rules_angular//setup:step_3.bzl", "rules_angular_step3")
|
||||
|
||||
rules_angular_step3(
|
||||
angular_compiler_cli = "@angular//tools/bazel/rules_angular_store:node_modules/@angular/compiler-cli",
|
||||
typescript = "@angular//:node_modules/typescript",
|
||||
)
|
||||
|
||||
git_repository(
|
||||
name = "rules_browsers",
|
||||
commit = "56ef8007ea07cd1916429bca8bb523433b0e9cdc",
|
||||
remote = "https://github.com/devversion/rules_browsers.git",
|
||||
)
|
||||
|
||||
load("@rules_browsers//setup:step_1.bzl", "rules_browsers_setup_1")
|
||||
|
||||
rules_browsers_setup_1()
|
||||
|
||||
load("@rules_browsers//setup:step_2.bzl", "rules_browsers_setup_2")
|
||||
|
||||
rules_browsers_setup_2()
|
||||
|
||||
http_archive(
|
||||
name = "aspect_rules_esbuild",
|
||||
sha256 = "530adfeae30bbbd097e8af845a44a04b641b680c5703b3bf885cbd384ffec779",
|
||||
strip_prefix = "rules_esbuild-0.22.1",
|
||||
url = "https://github.com/aspect-build/rules_esbuild/releases/download/v0.22.1/rules_esbuild-v0.22.1.tar.gz",
|
||||
)
|
||||
|
||||
load("@aspect_rules_esbuild//esbuild:dependencies.bzl", "rules_esbuild_dependencies")
|
||||
|
||||
rules_esbuild_dependencies()
|
||||
|
||||
load("@aspect_rules_esbuild//esbuild:repositories.bzl", "LATEST_ESBUILD_VERSION", "esbuild_register_toolchains")
|
||||
|
||||
esbuild_register_toolchains(
|
||||
name = "esbuild",
|
||||
esbuild_version = LATEST_ESBUILD_VERSION,
|
||||
)
|
||||
|
||||
# Register git toolchains
|
||||
register_toolchains(
|
||||
"@devinfra//bazel/git-toolchain:git_linux_toolchain",
|
||||
"@devinfra//bazel/git-toolchain:git_macos_x86_toolchain",
|
||||
"@devinfra//bazel/git-toolchain:git_macos_arm64_toolchain",
|
||||
"@devinfra//bazel/git-toolchain:git_windows_toolchain",
|
||||
)
|
||||
|
||||
git_repository(
|
||||
name = "rules_sass",
|
||||
commit = "cc1e845339fc45d3c8390445014d5824b85a0948",
|
||||
remote = "https://github.com/devversion/rules_sass.git",
|
||||
)
|
||||
|
||||
load("@rules_sass//src/toolchain:repositories.bzl", "setup_rules_sass")
|
||||
|
||||
setup_rules_sass()
|
||||
|
||||
http_archive(
|
||||
name = "jq.bzl",
|
||||
sha256 = "7b63435aa19cc6a0cfd1a82fbdf2c7a2f0a94db1a79ff7a4469ffa94286261ab",
|
||||
strip_prefix = "jq.bzl-0.1.0",
|
||||
url = "https://github.com/bazel-contrib/jq.bzl/releases/download/v0.1.0/jq.bzl-v0.1.0.tar.gz",
|
||||
)
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
|
||||
load("@npm2//:defs.bzl", "npm_link_all_packages")
|
||||
load("@npm//:defs.bzl", "npm_link_all_packages")
|
||||
load("@rules_angular//src/architect:ng_application.bzl", "ng_application")
|
||||
load("@rules_angular//src/architect:ng_config.bzl", "ng_config")
|
||||
load("@rules_angular//src/architect:ng_test.bzl", "ng_test")
|
||||
@@ -87,8 +87,8 @@ TEST_DEPS = [
|
||||
for dep in APPLICATION_DEPS
|
||||
if dep != "//adev:node_modules/@types/node"
|
||||
] + [
|
||||
"@rules_browsers//src/browsers/chromium",
|
||||
"@rules_browsers//src/browsers/firefox",
|
||||
"@rules_browsers//browsers/chromium",
|
||||
"@rules_browsers//browsers/firefox",
|
||||
"//adev/tools:windows-chromium-path",
|
||||
]
|
||||
|
||||
@@ -155,7 +155,7 @@ ng_test(
|
||||
node_modules = "//adev:node_modules",
|
||||
project_name = "angular-dev",
|
||||
toolchains = [
|
||||
"@rules_browsers//src/browsers/chromium:toolchain_alias",
|
||||
"@rules_browsers//src/browsers/firefox:toolchain_alias",
|
||||
"@rules_browsers//browsers/chromium:toolchain_alias",
|
||||
"@rules_browsers//browsers/firefox:toolchain_alias",
|
||||
],
|
||||
)
|
||||
|
||||
+15
-15
@@ -1,21 +1,21 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@angular-devkit/build-angular": "20.2.0-next.2",
|
||||
"@angular-devkit/build-angular": "20.2.1",
|
||||
"@angular/animations": "workspace:*",
|
||||
"@angular/build": "20.2.0-next.2",
|
||||
"@angular/cdk": "20.2.0-next.2",
|
||||
"@angular/cli": "20.2.0-next.2",
|
||||
"@angular/build": "20.2.1",
|
||||
"@angular/cdk": "20.2.1",
|
||||
"@angular/cli": "20.2.1",
|
||||
"@angular/common": "workspace:*",
|
||||
"@angular/compiler-cli": "workspace:*",
|
||||
"@angular/compiler": "workspace:*",
|
||||
"@angular/core": "workspace:*",
|
||||
"@angular/docs": "workspace:*",
|
||||
"@angular/forms": "workspace:*",
|
||||
"@angular/material": "20.2.0-next.2",
|
||||
"@angular/material": "20.2.1",
|
||||
"@angular/platform-browser": "workspace:*",
|
||||
"@angular/platform-server": "workspace:*",
|
||||
"@angular/router": "workspace:*",
|
||||
"@angular/ssr": "20.2.0-next.2",
|
||||
"@angular/ssr": "20.2.1",
|
||||
"@codemirror/autocomplete": "6.18.6",
|
||||
"@codemirror/commands": "6.8.1",
|
||||
"@codemirror/lang-angular": "0.1.4",
|
||||
@@ -23,7 +23,7 @@
|
||||
"@codemirror/lang-html": "6.4.9",
|
||||
"@codemirror/lang-javascript": "6.2.4",
|
||||
"@codemirror/lang-sass": "6.0.2",
|
||||
"@codemirror/language": "6.11.2",
|
||||
"@codemirror/language": "6.11.3",
|
||||
"@codemirror/lint": "6.8.5",
|
||||
"@codemirror/search": "6.5.11",
|
||||
"@codemirror/state": "6.5.2",
|
||||
@@ -33,9 +33,9 @@
|
||||
"@lezer/javascript": "1.5.1",
|
||||
"@stackblitz/sdk": "1.11.0",
|
||||
"@types/dom-navigation": "1.0.6",
|
||||
"@types/jasmine": "5.1.8",
|
||||
"@types/jasmine": "5.1.9",
|
||||
"@types/jsdom": "21.1.7",
|
||||
"@types/node": "24.1.0",
|
||||
"@types/node": "24.3.0",
|
||||
"@typescript/vfs": "1.6.1",
|
||||
"@webcontainer/api": "1.6.1",
|
||||
"@xterm/addon-fit": "0.10.0",
|
||||
@@ -52,16 +52,16 @@
|
||||
"karma-coverage": "2.2.1",
|
||||
"karma-jasmine-html-reporter": "2.1.0",
|
||||
"karma-jasmine": "5.1.0",
|
||||
"marked": "16.1.1",
|
||||
"mermaid": "11.9.0",
|
||||
"marked": "16.2.0",
|
||||
"mermaid": "11.10.0",
|
||||
"ngx-progressbar": "14.0.0",
|
||||
"open-in-idx": "0.1.1",
|
||||
"playwright-core": "1.54.1",
|
||||
"preact-render-to-string": "6.5.13",
|
||||
"preact": "10.27.0",
|
||||
"playwright-core": "1.55.0",
|
||||
"preact-render-to-string": "6.6.1",
|
||||
"preact": "10.27.1",
|
||||
"prettier": "3.6.2",
|
||||
"rxjs": "7.8.2",
|
||||
"shiki": "3.9.0",
|
||||
"shiki": "3.11.0",
|
||||
"tinyglobby": "0.2.14",
|
||||
"tslib": "2.8.1",
|
||||
"typescript": "5.9.2",
|
||||
|
||||
@@ -11,7 +11,7 @@ import {LOCAL_STORAGE} from '../../providers/index';
|
||||
import {setCookieConsent} from '../../utils';
|
||||
|
||||
/**
|
||||
* Decelare gtag as part of the window in this file as gtag is expected to already be loaded.
|
||||
* Declare gtag as part of the window in this file as gtag is expected to already be loaded.
|
||||
*/
|
||||
declare const window: Window & typeof globalThis & {gtag?: Function};
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import {NavigationItem} from '../../interfaces/index';
|
||||
import {NavigationState} from '../../services/index';
|
||||
import {RouterLink, RouterLinkActive} from '@angular/router';
|
||||
import {IconComponent} from '../icon/icon.component';
|
||||
import {IsActiveNavigationItem} from '../../pipes/is-active-navigation-item.pipe';
|
||||
import {IsActiveNavigationItem} from '../../pipes';
|
||||
import {NgTemplateOutlet} from '@angular/common';
|
||||
import {MatTooltipModule} from '@angular/material/tooltip';
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ ng_project(
|
||||
"//adev/shared-docs/directives",
|
||||
"//adev/shared-docs/interfaces",
|
||||
"//adev/shared-docs/pipes",
|
||||
"//adev/shared-docs/providers",
|
||||
"//adev/shared-docs/services",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -20,19 +20,18 @@ import {
|
||||
viewChildren,
|
||||
} from '@angular/core';
|
||||
|
||||
import {WINDOW} from '../../providers/index';
|
||||
import {ClickOutside} from '../../directives/index';
|
||||
import {Search, SearchHistory} from '../../services/index';
|
||||
import {WINDOW} from '../../providers';
|
||||
import {ClickOutside, SearchItem} from '../../directives';
|
||||
import {Search, SearchHistory} from '../../services';
|
||||
|
||||
import {TextField} from '../text-field/text-field.component';
|
||||
import {FormControl, ReactiveFormsModule} from '@angular/forms';
|
||||
import {ActiveDescendantKeyManager} from '@angular/cdk/a11y';
|
||||
import {SearchItem} from '../../directives/search-item/search-item.directive';
|
||||
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
|
||||
import {Router, RouterLink} from '@angular/router';
|
||||
import {fromEvent} from 'rxjs';
|
||||
import {AlgoliaIcon} from '../algolia-icon/algolia-icon.component';
|
||||
import {RelativeLink} from '../../pipes/relative-link.pipe';
|
||||
import {RelativeLink} from '../../pipes';
|
||||
import {SearchHistoryComponent} from '../search-history/search-history.component';
|
||||
|
||||
@Component({
|
||||
@@ -52,10 +51,10 @@ import {SearchHistoryComponent} from '../search-history/search-history.component
|
||||
styleUrls: ['./search-dialog.component.scss'],
|
||||
})
|
||||
export class SearchDialog {
|
||||
onClose = output();
|
||||
dialog = viewChild.required<ElementRef<HTMLDialogElement>>('searchDialog');
|
||||
items = viewChildren(SearchItem);
|
||||
textField = viewChild(TextField);
|
||||
readonly onClose = output();
|
||||
readonly dialog = viewChild.required<ElementRef<HTMLDialogElement>>('searchDialog');
|
||||
readonly items = viewChildren(SearchItem);
|
||||
readonly textField = viewChild(TextField);
|
||||
|
||||
readonly history = inject(SearchHistory);
|
||||
private readonly search = inject(Search);
|
||||
@@ -68,9 +67,9 @@ export class SearchDialog {
|
||||
this.injector,
|
||||
).withWrap();
|
||||
|
||||
searchQuery = this.search.searchQuery;
|
||||
resultsResource = this.search.resultsResource;
|
||||
searchResults = this.search.searchResults;
|
||||
readonly searchQuery = this.search.searchQuery;
|
||||
readonly resultsResource = this.search.resultsResource;
|
||||
readonly searchResults = this.search.searchResults;
|
||||
|
||||
// We use a FormControl instead of relying on NgModel+signal to avoid
|
||||
// the issue https://github.com/angular/angular/issues/13568
|
||||
|
||||
@@ -38,6 +38,8 @@ ts_project(
|
||||
":search-history",
|
||||
"//adev:node_modules/@angular/core",
|
||||
"//adev:node_modules/@angular/platform-browser",
|
||||
"//adev:node_modules/@angular/router",
|
||||
"//adev/shared-docs/providers",
|
||||
"//adev/shared-docs/services",
|
||||
"//adev/shared-docs/testing",
|
||||
],
|
||||
|
||||
@@ -21,7 +21,7 @@ import {ActiveDescendantKeyManager} from '@angular/cdk/a11y';
|
||||
|
||||
import {SearchHistory} from '../../services';
|
||||
import {RelativeLink} from '../../pipes';
|
||||
import {SearchItem} from '../../directives/search-item/search-item.directive';
|
||||
import {SearchItem} from '../../directives';
|
||||
|
||||
@Component({
|
||||
selector: 'docs-search-history',
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
} from '@angular/core';
|
||||
import {Location, ViewportScroller} from '@angular/common';
|
||||
import {TableOfContentsLevel} from '../../interfaces/index';
|
||||
import {TableOfContentsLoader} from '../../services/table-of-contents-loader.service';
|
||||
import {TableOfContentsLoader} from '../../services';
|
||||
import {IconComponent} from '../icon/icon.component';
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -29,16 +29,16 @@ export class TopLevelBannerComponent {
|
||||
* separately for different events or instances. Without a unique ID,
|
||||
* closing one banner could inadvertently hide other banners for different events.
|
||||
*/
|
||||
id = input.required<string>();
|
||||
readonly id = input.required<string>();
|
||||
// Optional URL link that the banner should navigate to when clicked.
|
||||
link = input<string>();
|
||||
readonly link = input<string>();
|
||||
// Text content to be displayed in the banner.
|
||||
text = input.required<string>();
|
||||
readonly text = input.required<string>();
|
||||
// Optional expiry date. Setting the default expiry as a future date so we
|
||||
// don't have to deal with undefined signal values.
|
||||
expiry = input(new Date('3000-01-01'), {transform: parseDate});
|
||||
readonly expiry = input(new Date('3000-01-01'), {transform: parseDate});
|
||||
// Whether the user has closed the banner or the survey has expired.
|
||||
hasClosed = linkedSignal(() => {
|
||||
readonly hasClosed = linkedSignal(() => {
|
||||
const expired = Date.now() > this.expiry().getTime();
|
||||
|
||||
// Needs to be in a try/catch, because some browsers will
|
||||
|
||||
@@ -21,13 +21,17 @@ ng_project(
|
||||
"//adev:node_modules/@angular/common",
|
||||
"//adev:node_modules/@angular/core",
|
||||
"//adev:node_modules/@angular/material",
|
||||
"//adev:node_modules/@angular/platform-browser",
|
||||
"//adev:node_modules/@angular/router",
|
||||
"//adev:node_modules/rxjs",
|
||||
"//adev/shared-docs/components/breadcrumb",
|
||||
"//adev/shared-docs/components/copy-source-code-button",
|
||||
"//adev/shared-docs/components/icon",
|
||||
"//adev/shared-docs/components/table-of-contents",
|
||||
"//adev/shared-docs/interfaces",
|
||||
"//adev/shared-docs/providers",
|
||||
"//adev/shared-docs/services",
|
||||
"//adev/shared-docs/utils",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -28,21 +28,22 @@ import {
|
||||
effect,
|
||||
} from '@angular/core';
|
||||
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
|
||||
import {TOC_SKIP_CONTENT_MARKER, NavigationState} from '../../../services/index';
|
||||
import {TOC_SKIP_CONTENT_MARKER, NavigationState} from '../../../services';
|
||||
import {TableOfContents} from '../../table-of-contents/table-of-contents.component';
|
||||
import {IconComponent} from '../../icon/icon.component';
|
||||
import {handleHrefClickEventWithRouter} from '../../../utils/index';
|
||||
import {Snippet} from '../../../interfaces/index';
|
||||
import {handleHrefClickEventWithRouter} from '../../../utils';
|
||||
import {Snippet} from '../../../interfaces';
|
||||
import {Router} from '@angular/router';
|
||||
import {fromEvent} from 'rxjs';
|
||||
|
||||
import {Breadcrumb} from '../../breadcrumb/breadcrumb.component';
|
||||
import {CopySourceCodeButton} from '../../copy-source-code-button/copy-source-code-button.component';
|
||||
import {ExampleViewer} from '../example-viewer/example-viewer.component';
|
||||
import {DomSanitizer} from '@angular/platform-browser';
|
||||
|
||||
const TOC_HOST_ELEMENT_NAME = 'docs-table-of-contents';
|
||||
export const ASSETS_EXAMPLES_PATH = 'assets/content/examples';
|
||||
export const DOCS_VIEWER_SELECTOR = 'docs-viewer';
|
||||
export const DOCS_VIEWER_SELECTOR = 'docs-viewer, main[docsViewer]';
|
||||
export const DOCS_CODE_SELECTOR = '.docs-code';
|
||||
export const DOCS_CODE_MUTLIFILE_SELECTOR = '.docs-code-multifile';
|
||||
// TODO: Update the branch/sha
|
||||
@@ -60,8 +61,8 @@ export const GITHUB_CONTENT_URL = 'https://github.com/angular/angular/blob/main/
|
||||
},
|
||||
})
|
||||
export class DocViewer {
|
||||
docContent = input<string | undefined>();
|
||||
hasToc = input(false);
|
||||
readonly docContent = input<string | undefined>();
|
||||
readonly hasToc = input(false);
|
||||
readonly contentLoaded = output<void>();
|
||||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
@@ -74,6 +75,7 @@ export class DocViewer {
|
||||
private readonly environmentInjector = inject(EnvironmentInjector);
|
||||
private readonly injector = inject(Injector);
|
||||
private readonly appRef = inject(ApplicationRef);
|
||||
private readonly sanitizer = inject(DomSanitizer);
|
||||
|
||||
protected animateContent = false;
|
||||
private readonly pendingTasks = inject(PendingTasks);
|
||||
@@ -200,10 +202,10 @@ export class DocViewer {
|
||||
id: this.countOfExamples,
|
||||
});
|
||||
|
||||
exampleRef.instance.githubUrl = `${GITHUB_CONTENT_URL}/${snippets[0].name}`;
|
||||
exampleRef.setInput('githubUrl', `${GITHUB_CONTENT_URL}/${snippets[0].name}`);
|
||||
|
||||
// TODO: Re-add support for opening examples on StackBlitz
|
||||
exampleRef.instance.stackblitzUrl = null; // `${ASSETS_EXAMPLES_PATH}/${snippets[0].name}.html`;
|
||||
exampleRef.setInput('stackblitzUrl', null); // `${ASSETS_EXAMPLES_PATH}/${snippets[0].name}.html`;
|
||||
|
||||
placeholder.parentElement!.replaceChild(exampleRef.location.nativeElement, placeholder);
|
||||
|
||||
@@ -215,7 +217,7 @@ export class DocViewer {
|
||||
|
||||
return tabs.map((tab) => ({
|
||||
name: tab.getAttribute('path') ?? tab.getAttribute('header') ?? '',
|
||||
content: tab.innerHTML,
|
||||
sanitizedContent: this.sanitizer.bypassSecurityTrustHtml(tab.innerHTML),
|
||||
visibleLinesRange: tab.getAttribute('visibleLines') ?? undefined,
|
||||
}));
|
||||
}
|
||||
@@ -235,7 +237,9 @@ export class DocViewer {
|
||||
return {
|
||||
title,
|
||||
name: path,
|
||||
content: content?.outerHTML,
|
||||
sanitizedContent: content?.outerHTML
|
||||
? this.sanitizer.bypassSecurityTrustHtml(content.outerHTML)
|
||||
: '',
|
||||
visibleLinesRange: visibleLines,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,11 +5,7 @@
|
||||
}
|
||||
|
||||
@if (view() === CodeExampleViewMode.MULTI_FILE) {
|
||||
<mat-tab-group
|
||||
#codeTabs
|
||||
animationDuration="0ms"
|
||||
mat-stretch-tabs="false"
|
||||
>
|
||||
<mat-tab-group #codeTabs animationDuration="0ms" mat-stretch-tabs="false">
|
||||
@for (tab of tabs(); track tab) {
|
||||
<mat-tab [label]="tab.name"></mat-tab>
|
||||
}
|
||||
@@ -22,6 +18,8 @@
|
||||
class="docs-example-copy-link"
|
||||
[attr.aria-label]="'Copy link to ' + exampleMetadata()?.title + ' example to the clipboard'"
|
||||
(click)="copyLink()"
|
||||
matTooltip="Copy link to example"
|
||||
matTooltipPosition="above"
|
||||
>
|
||||
<i aria-hidden="true">
|
||||
<svg
|
||||
@@ -45,8 +43,9 @@
|
||||
<button
|
||||
type="button"
|
||||
(click)="toggleExampleVisibility()"
|
||||
[attr.title]="(expanded() ? 'Collapse' : 'Expand') + ' example'"
|
||||
[attr.aria-label]="(expanded() ? 'Collapse' : 'Expand') + ' code example'"
|
||||
matTooltip="{{ expanded() ? 'Collapse' : 'Expand' }} example"
|
||||
matTooltipPosition="above"
|
||||
>
|
||||
<i aria-hidden="true">
|
||||
@if (!expanded()) {
|
||||
@@ -87,7 +86,9 @@
|
||||
[class.docs-example-viewer-multi-file]="view() === CodeExampleViewMode.MULTI_FILE"
|
||||
>
|
||||
<button docs-copy-source-code></button>
|
||||
<docs-viewer [docContent]="snippetCode()?.content" />
|
||||
@if (snippetCode()?.sanitizedContent; as content) {
|
||||
<div [innerHTML]="content"></div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (exampleComponent) {
|
||||
@@ -98,13 +99,14 @@
|
||||
|
||||
<ng-template #openCodeInExternalProvider>
|
||||
@if (exampleComponent) {
|
||||
@if (githubUrl) {
|
||||
@if (githubUrl()) {
|
||||
<a
|
||||
[href]="githubUrl"
|
||||
[href]="githubUrl()"
|
||||
target="_blank"
|
||||
title="Open example on GitHub"
|
||||
class="docs-example-github-link"
|
||||
aria-label="Open example on GitHub"
|
||||
matTooltip="Open example on GitHub"
|
||||
matTooltipPosition="above"
|
||||
>
|
||||
<i aria-hidden="true">
|
||||
<svg
|
||||
@@ -125,13 +127,14 @@
|
||||
</i>
|
||||
</a>
|
||||
}
|
||||
@if (stackblitzUrl) {
|
||||
@if (stackblitzUrl()) {
|
||||
<a
|
||||
[href]="stackblitzUrl"
|
||||
[href]="stackblitzUrl()"
|
||||
target="_blank"
|
||||
class="docs-example-stackblitz-link"
|
||||
title="Edit this example in StackBlitz"
|
||||
aria-label="Edit this example in StackBlitz"
|
||||
aria-label="Edit example in StackBlitz"
|
||||
matTooltip="Edit example in StackBlitz"
|
||||
matTooltipPosition="above"
|
||||
>
|
||||
<i aria-hidden="true">
|
||||
<svg
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
:host {
|
||||
.docs-example-viewer-preview {
|
||||
.docs-dark-mode & {
|
||||
background: var(--gray-100);
|
||||
color: var(--primary-contrast);
|
||||
background: var(--gray-900);
|
||||
}
|
||||
@media screen and (prefers-color-scheme: dark) {
|
||||
background: var(--gray-100);
|
||||
color: var(--primary-contrast);
|
||||
background: var(--gray-900);
|
||||
}
|
||||
.docs-light-mode & {
|
||||
background: var(--page-background);
|
||||
|
||||
+20
-20
@@ -35,7 +35,6 @@ describe('ExampleViewer', () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [ExampleViewer],
|
||||
providers: [
|
||||
// TODO: Find why tests warn that zone.js is still loaded
|
||||
provideZonelessChangeDetection(),
|
||||
{provide: EXAMPLE_VIEWER_CONTENT_LOADER, useValue: exampleContentSpy},
|
||||
{provide: ActivatedRoute, useValue: {snapshot: {fragment: 'fragment'}}},
|
||||
@@ -53,9 +52,9 @@ describe('ExampleViewer', () => {
|
||||
'metadata',
|
||||
getMetadata({
|
||||
files: [
|
||||
{name: 'file.ts', content: ''},
|
||||
{name: 'file.html', content: ''},
|
||||
{name: 'file.css', content: ''},
|
||||
{name: 'file.ts', sanitizedContent: ''},
|
||||
{name: 'file.html', sanitizedContent: ''},
|
||||
{name: 'file.css', sanitizedContent: ''},
|
||||
],
|
||||
}),
|
||||
);
|
||||
@@ -73,9 +72,9 @@ describe('ExampleViewer', () => {
|
||||
'metadata',
|
||||
getMetadata({
|
||||
files: [
|
||||
{name: 'file.ts', content: 'typescript file'},
|
||||
{name: 'file.html', content: 'html file'},
|
||||
{name: 'file.css', content: 'css file'},
|
||||
{name: 'file.ts', sanitizedContent: 'typescript file'},
|
||||
{name: 'file.html', sanitizedContent: 'html file'},
|
||||
{name: 'file.css', sanitizedContent: 'css file'},
|
||||
],
|
||||
}),
|
||||
);
|
||||
@@ -93,9 +92,9 @@ describe('ExampleViewer', () => {
|
||||
'metadata',
|
||||
getMetadata({
|
||||
files: [
|
||||
{name: 'example.ts', content: 'typescript file'},
|
||||
{name: 'example.html', content: 'html file'},
|
||||
{name: 'another-example.ts', content: 'css file'},
|
||||
{name: 'example.ts', sanitizedContent: 'typescript file'},
|
||||
{name: 'example.html', sanitizedContent: 'html file'},
|
||||
{name: 'another-example.ts', sanitizedContent: 'css file'},
|
||||
],
|
||||
}),
|
||||
);
|
||||
@@ -124,7 +123,7 @@ describe('ExampleViewer', () => {
|
||||
files: [
|
||||
{
|
||||
name: 'example.ts',
|
||||
content: `<pre><code>${expectedCodeSnippetContent}</code></pre>`,
|
||||
sanitizedContent: `<pre><code>${expectedCodeSnippetContent}</code></pre>`,
|
||||
visibleLinesRange: '[1]',
|
||||
},
|
||||
],
|
||||
@@ -148,7 +147,7 @@ describe('ExampleViewer', () => {
|
||||
files: [
|
||||
{
|
||||
name: 'example.ts',
|
||||
content: `<pre><code>${expectedCodeSnippetContent}</code></pre>`,
|
||||
sanitizedContent: `<pre><code>${expectedCodeSnippetContent}</code></pre>`,
|
||||
visibleLinesRange: '[1]',
|
||||
},
|
||||
],
|
||||
@@ -198,7 +197,7 @@ describe('ExampleViewer', () => {
|
||||
By.css('a[aria-label="Open example on GitHub"]'),
|
||||
);
|
||||
expect(githubButton).toBeTruthy();
|
||||
expect(githubButton.nativeElement.href).toBe(component.githubUrl);
|
||||
expect(githubButton.nativeElement.href).toBe(component.githubUrl());
|
||||
});
|
||||
|
||||
it('should display StackBlitz button when stackblitzUrl is provided and there is preview', async () => {
|
||||
@@ -210,15 +209,16 @@ describe('ExampleViewer', () => {
|
||||
preview: true,
|
||||
}),
|
||||
);
|
||||
component.stackblitzUrl = 'https://stackblitz.com/';
|
||||
componentRef.setInput('stackblitzUrl', 'https://stackblitz.com/');
|
||||
|
||||
await component.renderExample();
|
||||
fixture.detectChanges();
|
||||
|
||||
const stackblitzButton = fixture.debugElement.query(
|
||||
By.css('a[aria-label="Edit this example in StackBlitz"]'),
|
||||
By.css('a[aria-label="Edit example in StackBlitz"]'),
|
||||
);
|
||||
expect(stackblitzButton).toBeTruthy();
|
||||
expect(stackblitzButton.nativeElement.href).toBe(component.stackblitzUrl);
|
||||
expect(stackblitzButton.nativeElement.href).toBe(component.stackblitzUrl());
|
||||
});
|
||||
|
||||
it('should set expanded flag in metadata after toggleExampleVisibility', async () => {
|
||||
@@ -242,9 +242,9 @@ describe('ExampleViewer', () => {
|
||||
files: [
|
||||
{
|
||||
name: 'example.ts',
|
||||
content: `<pre><code>${expectedCodeSnippetContent}</code></pre>`,
|
||||
sanitizedContent: `<pre><code>${expectedCodeSnippetContent}</code></pre>`,
|
||||
},
|
||||
{name: 'example.css', content: ''},
|
||||
{name: 'example.css', sanitizedContent: ''},
|
||||
],
|
||||
}),
|
||||
);
|
||||
@@ -278,8 +278,8 @@ const getMetadata = (value: Partial<ExampleMetadata> = {}): ExampleMetadata => {
|
||||
return {
|
||||
id: 1,
|
||||
files: [
|
||||
{name: 'example.ts', content: ''},
|
||||
{name: 'example.css', content: ''},
|
||||
{name: 'example.ts', sanitizedContent: ''},
|
||||
{name: 'example.css', sanitizedContent: ''},
|
||||
],
|
||||
preview: false,
|
||||
...value,
|
||||
|
||||
@@ -14,11 +14,9 @@ import {
|
||||
computed,
|
||||
DestroyRef,
|
||||
ElementRef,
|
||||
forwardRef,
|
||||
inject,
|
||||
Injector,
|
||||
input,
|
||||
Input,
|
||||
signal,
|
||||
Type,
|
||||
viewChild,
|
||||
@@ -30,7 +28,7 @@ import {CopySourceCodeButton} from '../../copy-source-code-button/copy-source-co
|
||||
import {ExampleMetadata, Snippet} from '../../../interfaces/index';
|
||||
import {EXAMPLE_VIEWER_CONTENT_LOADER} from '../../../providers/index';
|
||||
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
|
||||
import {DocViewer} from '../docs-viewer/docs-viewer.component';
|
||||
import {MatTooltipModule} from '@angular/material/tooltip';
|
||||
|
||||
export enum CodeExampleViewMode {
|
||||
SNIPPET = 'snippet',
|
||||
@@ -44,16 +42,15 @@ export const HIDDEN_CLASS_NAME = 'hidden';
|
||||
|
||||
@Component({
|
||||
selector: 'docs-example-viewer',
|
||||
imports: [CommonModule, forwardRef(() => DocViewer), CopySourceCodeButton, MatTabsModule],
|
||||
imports: [CommonModule, CopySourceCodeButton, MatTabsModule, MatTooltipModule],
|
||||
templateUrl: './example-viewer.component.html',
|
||||
styleUrls: ['./example-viewer.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ExampleViewer {
|
||||
exampleMetadata = input<ExampleMetadata | null>(null, {alias: 'metadata'});
|
||||
|
||||
@Input() githubUrl: string | null = null;
|
||||
@Input() stackblitzUrl: string | null = null;
|
||||
readonly exampleMetadata = input<ExampleMetadata | null>(null, {alias: 'metadata'});
|
||||
readonly githubUrl = input<string | null>(null);
|
||||
readonly stackblitzUrl = input<string | null>(null);
|
||||
readonly matTabGroup = viewChild<MatTabGroup>('codeTabs');
|
||||
|
||||
private readonly changeDetector = inject(ChangeDetectorRef);
|
||||
@@ -82,7 +79,7 @@ export class ExampleViewer {
|
||||
this.exampleMetadata()?.files.map((file) => ({
|
||||
name:
|
||||
file.title ?? (this.shouldDisplayFullName() ? file.name : this.getFileExtension(file.name)),
|
||||
code: file.content,
|
||||
code: file.sanitizedContent,
|
||||
})),
|
||||
);
|
||||
view = computed(() =>
|
||||
|
||||
@@ -3,7 +3,7 @@ load("@aspect_bazel_lib//lib:copy_to_directory.bzl", _copy_to_directory = "copy_
|
||||
load("@aspect_rules_esbuild//esbuild:defs.bzl", _esbuild = "esbuild")
|
||||
load("@devinfra//bazel/private:path_relative_to_label.bzl", _path_relative_to_label = "path_relative_to_label")
|
||||
load(
|
||||
"//tools:defaults2.bzl",
|
||||
"//tools:defaults.bzl",
|
||||
_jasmine_test = "jasmine_test",
|
||||
_js_binary = "js_binary",
|
||||
_js_library = "js_library",
|
||||
|
||||
@@ -8,3 +8,4 @@
|
||||
|
||||
export * from './click-outside/click-outside.directive';
|
||||
export * from './external-link/external-link.directive';
|
||||
export * from './search-item/search-item.directive';
|
||||
|
||||
@@ -26,6 +26,7 @@ ts_project(
|
||||
),
|
||||
deps = [
|
||||
"//adev:node_modules/@angular/core",
|
||||
"//adev:node_modules/@angular/platform-browser",
|
||||
"//adev:node_modules/@angular/router",
|
||||
"//adev:node_modules/@types/node",
|
||||
"//adev:node_modules/@webcontainer/api",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
import {Type} from '@angular/core';
|
||||
import {SafeHtml} from '@angular/platform-browser';
|
||||
|
||||
/**
|
||||
* Map of the examples, values are functions which returns the promise of the component type, which will be displayed as preview in the ExampleViewer component
|
||||
@@ -21,7 +22,7 @@ export interface Snippet {
|
||||
/** Name of the file. */
|
||||
name: string;
|
||||
/** Content of code snippet */
|
||||
content: string;
|
||||
sanitizedContent: SafeHtml;
|
||||
/** Text in following format `start-end`. Start and end are numbers, based on them provided range of lines will be displayed in collapsed mode */
|
||||
visibleLinesRange?: string;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"fflate": "^0.8.2",
|
||||
"html-entities": "~2.6.0",
|
||||
"jsdom": "~26.1.0",
|
||||
"marked": "~16.1.0",
|
||||
"marked": "~16.2.0",
|
||||
"mermaid": "^11.0.0",
|
||||
"shiki": "^3.0.0",
|
||||
"tinyglobby": "^0.2.12"
|
||||
|
||||
@@ -47,13 +47,13 @@ js_binary(
|
||||
"//adev:node_modules/jsdom",
|
||||
"//adev:node_modules/mermaid",
|
||||
"//adev:node_modules/playwright-core",
|
||||
"@rules_browsers//src/browsers/chromium",
|
||||
"@rules_browsers//browsers/chromium",
|
||||
],
|
||||
entry_point = "//adev/shared-docs/pipeline/guides:guides.mjs",
|
||||
env = {
|
||||
"CHROME_HEADLESS_BIN": "$(CHROME-HEADLESS-SHELL)",
|
||||
},
|
||||
toolchains = ["@rules_browsers//src/browsers/chromium:toolchain_alias"],
|
||||
toolchains = ["@rules_browsers//browsers/chromium:toolchain_alias"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
|
||||
@@ -16,6 +16,12 @@ def _generate_guides(ctx):
|
||||
# Pass the the output directory path (which is the bazel-bin directory).
|
||||
args.add(ctx.bin_dir.path)
|
||||
|
||||
# Add the api_manifest file if provided
|
||||
if ctx.attr.api_manifest:
|
||||
args.add(ctx.file.api_manifest.path)
|
||||
else:
|
||||
args.add("")
|
||||
|
||||
# Determine the set of html output files. For each input markdown file, produce an html
|
||||
# file with the same name (replacing the markdown extension with `.html`).
|
||||
html_outputs = []
|
||||
@@ -30,9 +36,13 @@ def _generate_guides(ctx):
|
||||
html_outputs += [ctx.actions.declare_file("%s.html" % relative_basepath)]
|
||||
|
||||
# Define an action that runs the executable.
|
||||
inputs = ctx.files.srcs + ctx.files.data
|
||||
if ctx.attr.api_manifest:
|
||||
inputs.append(ctx.file.api_manifest)
|
||||
|
||||
if (ctx.attr.mermaid_blocks):
|
||||
ctx.actions.run(
|
||||
inputs = depset(ctx.files.srcs + ctx.files.data),
|
||||
inputs = depset(inputs),
|
||||
executable = ctx.executable._generate_guides,
|
||||
outputs = html_outputs,
|
||||
arguments = [args],
|
||||
@@ -42,7 +52,7 @@ def _generate_guides(ctx):
|
||||
)
|
||||
else:
|
||||
ctx.actions.run(
|
||||
inputs = depset(ctx.files.srcs + ctx.files.data),
|
||||
inputs = depset(inputs),
|
||||
executable = ctx.executable._generate_guides_no_mermaid,
|
||||
outputs = html_outputs,
|
||||
arguments = [args],
|
||||
@@ -71,6 +81,10 @@ generate_guides = rule(
|
||||
doc = """Source referenced from within the markdown.""",
|
||||
allow_files = True,
|
||||
),
|
||||
"api_manifest": attr.label(
|
||||
doc = """A file containing API entries to be used in the markdown.""",
|
||||
allow_single_file = True,
|
||||
),
|
||||
"mermaid_blocks": attr.bool(
|
||||
doc = """Whether to transform mermaid blocks.""",
|
||||
default = False,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
load("@npm2//:defs.bzl", "npm_link_all_packages")
|
||||
load("@npm//:defs.bzl", "npm_link_all_packages")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ function main() {
|
||||
...getEntriesFromMembers(entry).map((member) => [member, moduleName]),
|
||||
]),
|
||||
],
|
||||
} as EntryCollection);
|
||||
} satisfies EntryCollection);
|
||||
|
||||
writeFileSync(outputFilenameExecRootRelativePath, output, {encoding: 'utf8'});
|
||||
}
|
||||
|
||||
@@ -14,18 +14,21 @@ describe('api manifest generation', () => {
|
||||
it('should generate a manifest from multiple collections', () => {
|
||||
const manifest: Manifest = generateManifest([
|
||||
{
|
||||
repo: 'angular/router',
|
||||
moduleName: '@angular/router',
|
||||
entries: [entry({name: 'Router', entryType: EntryType.UndecoratedClass})],
|
||||
normalizedModuleName: 'angular_router',
|
||||
moduleLabel: 'router',
|
||||
},
|
||||
{
|
||||
repo: 'angular/core',
|
||||
moduleName: '@angular/core',
|
||||
entries: [entry({name: 'PI', entryType: EntryType.Constant})],
|
||||
normalizedModuleName: 'angular_core',
|
||||
moduleLabel: 'core',
|
||||
},
|
||||
{
|
||||
repo: 'angular/core',
|
||||
moduleName: '@angular/core',
|
||||
entries: [entry({name: 'foo', entryType: EntryType.Constant})],
|
||||
normalizedModuleName: 'angular_core',
|
||||
@@ -79,12 +82,14 @@ describe('api manifest generation', () => {
|
||||
it('should generate a manifest when collections share a symbol with the same name', () => {
|
||||
const manifest = generateManifest([
|
||||
{
|
||||
repo: 'angular/core',
|
||||
moduleName: '@angular/core',
|
||||
entries: [entry({name: 'PI', entryType: EntryType.Constant})],
|
||||
normalizedModuleName: 'angular_core',
|
||||
moduleLabel: 'core',
|
||||
},
|
||||
{
|
||||
repo: 'angular/router',
|
||||
moduleName: '@angular/router',
|
||||
entries: [entry({name: 'PI', entryType: EntryType.Constant})],
|
||||
normalizedModuleName: 'angular_router',
|
||||
@@ -129,12 +134,14 @@ describe('api manifest generation', () => {
|
||||
it('should union collections for the same module into one manifest', () => {
|
||||
const manifest = generateManifest([
|
||||
{
|
||||
repo: 'angular/core',
|
||||
moduleName: '@angular/core',
|
||||
entries: [entry({name: 'PI', entryType: EntryType.Constant})],
|
||||
normalizedModuleName: 'angular_core',
|
||||
moduleLabel: 'core',
|
||||
},
|
||||
{
|
||||
repo: 'angular/core',
|
||||
moduleName: '@angular/core',
|
||||
entries: [entry({name: 'TAO', entryType: EntryType.Constant})],
|
||||
normalizedModuleName: 'angular_core',
|
||||
@@ -172,6 +179,7 @@ describe('api manifest generation', () => {
|
||||
it('should mark a manifest entry as deprecated', () => {
|
||||
const manifest = generateManifest([
|
||||
{
|
||||
repo: 'angular/core',
|
||||
moduleName: '@angular/core',
|
||||
entries: [
|
||||
entry({name: 'PI', entryType: EntryType.Constant, jsdocTags: jsdocTags('deprecated')}),
|
||||
@@ -212,6 +220,7 @@ describe('api manifest generation', () => {
|
||||
it('should not mark a function as deprecated if only one overload is deprecated', () => {
|
||||
const manifest = generateManifest([
|
||||
{
|
||||
repo: 'angular/core',
|
||||
moduleName: '@angular/core',
|
||||
entries: [
|
||||
functionEntry({
|
||||
@@ -271,6 +280,7 @@ describe('api manifest generation', () => {
|
||||
it('should mark a function as deprecated if all overloads are deprecated', () => {
|
||||
const manifest = generateManifest([
|
||||
{
|
||||
repo: 'angular/core',
|
||||
moduleName: '@angular/core',
|
||||
entries: [
|
||||
functionEntry({
|
||||
@@ -330,6 +340,7 @@ describe('api manifest generation', () => {
|
||||
it("should mark a fn as deprecated if there's one w/ the same name in another collection", () => {
|
||||
const manifest = generateManifest([
|
||||
{
|
||||
repo: 'angular/core',
|
||||
moduleName: '@angular/core',
|
||||
entries: [
|
||||
entry({name: 'save', entryType: EntryType.Function, jsdocTags: jsdocTags('deprecated')}),
|
||||
@@ -338,6 +349,7 @@ describe('api manifest generation', () => {
|
||||
moduleLabel: 'core',
|
||||
},
|
||||
{
|
||||
repo: 'angular/more',
|
||||
moduleName: '@angular/more',
|
||||
entries: [entry({name: 'save', entryType: EntryType.Function})],
|
||||
normalizedModuleName: 'angular_more',
|
||||
@@ -382,6 +394,7 @@ describe('api manifest generation', () => {
|
||||
it('should mark a manifest entry as developerPreview', () => {
|
||||
const manifest = generateManifest([
|
||||
{
|
||||
repo: 'angular/core',
|
||||
moduleName: '@angular/core',
|
||||
entries: [
|
||||
entry({
|
||||
|
||||
@@ -20,7 +20,6 @@ ts_project(
|
||||
[
|
||||
"**/*.mts",
|
||||
"**/*.tsx",
|
||||
"shiki.d.ts",
|
||||
],
|
||||
exclude = [
|
||||
"entities.mts",
|
||||
@@ -28,13 +27,15 @@ ts_project(
|
||||
),
|
||||
deps = [
|
||||
":entities",
|
||||
"//adev:node_modules/@types/node",
|
||||
"//adev:node_modules/html-entities",
|
||||
"//adev:node_modules/marked",
|
||||
"//adev:node_modules/preact",
|
||||
"//adev:node_modules/preact-render-to-string",
|
||||
"//adev:node_modules/prettier",
|
||||
"//adev:node_modules/shiki",
|
||||
"//adev/shared-docs/pipeline/shared:linking",
|
||||
"//adev/shared-docs/pipeline/shared:shiki",
|
||||
"//adev/shared-docs/pipeline/shared/marked",
|
||||
"//adev/shared-docs/pipeline/shared/regions",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -11,12 +11,12 @@ import path from 'path';
|
||||
import {CliCommand} from './cli-entities.mjs';
|
||||
import {DocEntry} from './entities.mjs';
|
||||
import {isCliEntry, isHiddenEntry} from './entities/categorization.mjs';
|
||||
import {configureMarkedGlobally} from './marked/configuration.mjs';
|
||||
import {getRenderable} from './processing.mjs';
|
||||
import {renderEntry} from './rendering.mjs';
|
||||
import {initHighlighter} from './shiki/shiki.mjs';
|
||||
import {setCurrentSymbol, setSymbols} from './symbol-context.mjs';
|
||||
import {CliCommandRenderable, DocEntryRenderable} from './entities/renderables.mjs';
|
||||
import {initHighlighter} from '../../shared/shiki.mjs';
|
||||
import {setHighlighterInstance} from './shiki/shiki.mjs';
|
||||
|
||||
/** The JSON data file format for extracted API reference info. */
|
||||
interface EntryCollection {
|
||||
@@ -25,7 +25,7 @@ interface EntryCollection {
|
||||
moduleLabel?: string;
|
||||
normalizedModuleName: string;
|
||||
entries: DocEntry[] | CliCommand[];
|
||||
symbols: Map<string, string>;
|
||||
symbols: Record<string, string>;
|
||||
}
|
||||
|
||||
/** Parse all JSON data source files into an array of collections. */
|
||||
@@ -34,10 +34,15 @@ function parseEntryData(srcs: string[]): EntryCollection[] {
|
||||
const fileContent = readFileSync(jsonDataFilePath, {encoding: 'utf8'});
|
||||
const fileContentJson = JSON.parse(fileContent) as unknown;
|
||||
if ((fileContentJson as EntryCollection).entries) {
|
||||
return {
|
||||
...(fileContentJson as EntryCollection),
|
||||
symbols: new Map((fileContentJson as any).symbols ?? []),
|
||||
};
|
||||
const symbols = Object.fromEntries(
|
||||
// TODO: refactor that, it's dirty and we can probably do better than this.
|
||||
// We're removing the leading `@angular/` from module names.
|
||||
(((fileContentJson as any).symbols ?? []) as [string, string][]).map(
|
||||
([symbol, moduleName]) => [symbol, moduleName.slice(9)],
|
||||
),
|
||||
);
|
||||
|
||||
return {...(fileContentJson as EntryCollection), symbols};
|
||||
}
|
||||
|
||||
// CLI subcommands should generate a separate file for each subcommand.
|
||||
@@ -50,7 +55,7 @@ function parseEntryData(srcs: string[]): EntryCollection[] {
|
||||
moduleName: 'unknown',
|
||||
normalizedModuleName: 'unknown',
|
||||
entries: [fileContentJson as DocEntry],
|
||||
symbols: new Map(),
|
||||
symbols: {},
|
||||
},
|
||||
...command.subcommands!.map((subCommand) => {
|
||||
return {
|
||||
@@ -58,7 +63,7 @@ function parseEntryData(srcs: string[]): EntryCollection[] {
|
||||
moduleName: 'unknown',
|
||||
normalizedModuleName: 'unknown',
|
||||
entries: [{...subCommand, parentCommand: command} as any],
|
||||
symbols: new Map(),
|
||||
symbols: {},
|
||||
};
|
||||
}),
|
||||
];
|
||||
@@ -69,7 +74,7 @@ function parseEntryData(srcs: string[]): EntryCollection[] {
|
||||
moduleName: 'unknown',
|
||||
normalizedModuleName: 'unknown',
|
||||
entries: [fileContentJson as DocEntry], // TODO: fix the typing cli entries aren't DocEntry
|
||||
symbols: new Map(),
|
||||
symbols: {},
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -90,23 +95,14 @@ function getNormalizedFilename(normalizedModuleName: string, entry: DocEntry | C
|
||||
}
|
||||
|
||||
async function main() {
|
||||
configureMarkedGlobally();
|
||||
|
||||
// Shiki highlighter needs to be setup in an async context
|
||||
await initHighlighter();
|
||||
setHighlighterInstance(await initHighlighter());
|
||||
|
||||
const [paramFilePath] = process.argv.slice(2);
|
||||
const rawParamLines = readFileSync(paramFilePath, {encoding: 'utf8'}).split('\n');
|
||||
|
||||
const [srcs, outputFilenameExecRootRelativePath] = rawParamLines;
|
||||
|
||||
// TODO: Remove when we are using Bazel v6+
|
||||
// On RBE, the output directory is not created properly due to a bug.
|
||||
// https://github.com/bazelbuild/bazel/commit/4310aeb36c134e5fc61ed5cdfdf683f3e95f19b7.
|
||||
if (!existsSync(outputFilenameExecRootRelativePath)) {
|
||||
mkdirSync(outputFilenameExecRootRelativePath, {recursive: true});
|
||||
}
|
||||
|
||||
// Docs rendering happens in three phases that occur here:
|
||||
// 1) Aggregate all the raw extracted doc info.
|
||||
// 2) Transform the raw data to a renderable state.
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {marked} from 'marked';
|
||||
import {renderer} from './renderer.mjs';
|
||||
|
||||
/** Globally configures marked for rendering JsDoc content to HTML. */
|
||||
export function configureMarkedGlobally() {
|
||||
marked.use({
|
||||
renderer,
|
||||
});
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Renderer, Tokens} from 'marked';
|
||||
import {codeToHtml} from '../shiki/shiki.mjs';
|
||||
import {SECTION_HEADING, SECTION_SUB_HEADING} from '../styling/css-classes.mjs';
|
||||
|
||||
/**
|
||||
* Custom renderer for marked that will be used to transform markdown files to HTML
|
||||
* files that can be used in the Angular docs.
|
||||
*/
|
||||
export const renderer: Partial<Renderer> = {
|
||||
code({lang, text}): string {
|
||||
const highlightResult = codeToHtml(text, lang)
|
||||
// remove spaces/line-breaks between elements to not mess-up `pre` style
|
||||
.replace(/>\s+</g, '><');
|
||||
|
||||
return `
|
||||
<div class="docs-code" role="group">
|
||||
${highlightResult}
|
||||
</div>
|
||||
`;
|
||||
},
|
||||
image({href, title, text}): string {
|
||||
return `
|
||||
<img src="${href}" alt="${text}" title="${title}" class="docs-image">
|
||||
`;
|
||||
},
|
||||
link(this: Renderer, {href, tokens}): string {
|
||||
return `<a href="${href}">${this.parser.parseInline(tokens)}</a>`;
|
||||
},
|
||||
list(this: Renderer, {items, ordered, start}) {
|
||||
if (ordered) {
|
||||
return `
|
||||
<ol class="docs-ordered-list">
|
||||
${items.map((item) => this.listitem(item)).join('')}
|
||||
</ol>
|
||||
`;
|
||||
}
|
||||
return `
|
||||
<ul class="docs-list">
|
||||
${items.map((item) => this.listitem(item)).join('')}
|
||||
</ul>
|
||||
`;
|
||||
},
|
||||
|
||||
table(this: Renderer, {header, rows}: Tokens.Table) {
|
||||
return `
|
||||
<div class="docs-table docs-scroll-track-transparent">
|
||||
<table>
|
||||
<thead>
|
||||
${this.tablerow({text: header.map((cell) => this.tablecell(cell)).join('')})}
|
||||
</thead>
|
||||
<tbody>
|
||||
${rows
|
||||
.map((row) => this.tablerow({text: row.map((cell) => this.tablecell(cell)).join('')}))
|
||||
.join('')}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
||||
},
|
||||
|
||||
heading(this: Renderer, {text, depth, tokens}: Tokens.Heading) {
|
||||
const id = text
|
||||
.toLowerCase()
|
||||
.replaceAll(' ', '-')
|
||||
.replace(/[^a-z0-9-]/g, '');
|
||||
|
||||
// Since we have a code transformer `addApiLinksToHtml` which adds anchors
|
||||
// to code blocks of known symbols, we add an additional `data-skip-anchor`
|
||||
// attribute that prevents the transformation. This is needed since nested
|
||||
// anchor tags are illegal and break the HTML.
|
||||
const textRenderer = new Renderer();
|
||||
textRenderer.codespan = ({text}) => `<code data-skip-anchor>${text}</code>`;
|
||||
const parsedText = this.parser.parseInline(tokens, textRenderer);
|
||||
|
||||
// The template matches templates/section-heading.tsx
|
||||
return `
|
||||
<h${depth} id="${id}" class="${SECTION_HEADING} ${SECTION_SUB_HEADING}">
|
||||
<a href="#${id}" aria-label="Link to ${text} section" tabIndex="-1">
|
||||
${parsedText}
|
||||
</a>
|
||||
</h${depth}>
|
||||
`;
|
||||
},
|
||||
};
|
||||
@@ -1,196 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import * as blockC from './region-matchers/block-c.mjs';
|
||||
import * as html from './region-matchers/html.mjs';
|
||||
import * as inlineC from './region-matchers/inline-c.mjs';
|
||||
import * as inlineCOnly from './region-matchers/inline-c-only.mjs';
|
||||
import * as inlineHash from './region-matchers/inline-hash.mjs';
|
||||
import {FileType, removeEslintComments} from './remove-eslint-comments.mjs';
|
||||
|
||||
const WHOLE_FILE_REGION_NAME = '';
|
||||
const DEFAULT_PLASTER = '. . .';
|
||||
const REGION_MATCHERS = {
|
||||
ts: inlineC,
|
||||
js: inlineC,
|
||||
mjs: inlineCOnly,
|
||||
es6: inlineC,
|
||||
html: html,
|
||||
svg: html,
|
||||
css: blockC,
|
||||
conf: inlineHash,
|
||||
yaml: inlineHash,
|
||||
yml: inlineHash,
|
||||
sh: inlineHash,
|
||||
jade: inlineCOnly,
|
||||
pug: inlineCOnly,
|
||||
json: inlineCOnly,
|
||||
'json.annotated': inlineCOnly,
|
||||
};
|
||||
|
||||
interface Region {
|
||||
lines: string[];
|
||||
open?: boolean;
|
||||
ranges: {from: number; to?: number}[];
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: We assume that the tag defining the beginning and end of the region will be in different lines in each case.
|
||||
* For example, in HTML, we don't expect to have the following code on one line: <!-- docregion name -->content<!--enddocregion name-->
|
||||
*/
|
||||
export const regionParser = (contents: string, filePath: string) => {
|
||||
const fileType: FileType | undefined = filePath?.split('.').pop() as FileType;
|
||||
|
||||
if (!fileType) {
|
||||
throw new Error(`Incorrect file type for region parser: ${filePath}!`);
|
||||
}
|
||||
|
||||
const regionMatcher = REGION_MATCHERS[fileType];
|
||||
const openRegions: string[] = [];
|
||||
const regionMap: Record<string, Region> = {};
|
||||
|
||||
let countOfRegionLines = 0;
|
||||
|
||||
if (regionMatcher) {
|
||||
let plaster = regionMatcher.createPlasterComment(DEFAULT_PLASTER);
|
||||
const lines = removeEslintComments(contents, fileType)
|
||||
.split(/\r?\n/)
|
||||
.filter((line, index) => {
|
||||
const startRegion = line.match(regionMatcher.regionStartMatcher);
|
||||
const endRegion = line.match(regionMatcher.regionEndMatcher);
|
||||
const updatePlaster = line.match(regionMatcher.plasterMatcher);
|
||||
|
||||
// start region processing
|
||||
if (startRegion) {
|
||||
// open up the specified region
|
||||
handleStartRegion(
|
||||
startRegion,
|
||||
regionMap,
|
||||
index,
|
||||
countOfRegionLines,
|
||||
plaster,
|
||||
openRegions,
|
||||
);
|
||||
} else if (endRegion) {
|
||||
// end region processing
|
||||
handleEndRegion(openRegions, endRegion, regionMap, index, countOfRegionLines);
|
||||
} else if (updatePlaster) {
|
||||
// doc plaster processing
|
||||
const plasterString = updatePlaster[1].trim();
|
||||
plaster = plasterString ? regionMatcher.createPlasterComment(plasterString) : '';
|
||||
} else {
|
||||
// simple line of content processing
|
||||
openRegions.forEach((regionName) => regionMap[regionName].lines.push(line));
|
||||
// do not filter out this line from the content
|
||||
return true;
|
||||
}
|
||||
|
||||
// this line contained an annotation so let's filter it out
|
||||
countOfRegionLines++;
|
||||
return false;
|
||||
});
|
||||
|
||||
if (!regionMap[WHOLE_FILE_REGION_NAME]) {
|
||||
regionMap[WHOLE_FILE_REGION_NAME] = {lines, ranges: [{from: 1, to: lines.length + 1}]};
|
||||
}
|
||||
|
||||
return {
|
||||
contents: lines.join('\n'),
|
||||
regionMap,
|
||||
totalLinesCount: lines.length,
|
||||
};
|
||||
} else {
|
||||
return {contents, regionMap, totalLinesCount: 0};
|
||||
}
|
||||
};
|
||||
|
||||
function handleStartRegion(
|
||||
startRegion: RegExpMatchArray,
|
||||
regionMap: Record<string, Region>,
|
||||
index: number,
|
||||
countOfRegionLines: number,
|
||||
plaster: string,
|
||||
openRegions: string[],
|
||||
) {
|
||||
const regionNames = getRegionNames(startRegion[1]);
|
||||
if (regionNames.length === 0) {
|
||||
regionNames.push(WHOLE_FILE_REGION_NAME);
|
||||
}
|
||||
|
||||
for (const regionName of regionNames) {
|
||||
const region = regionMap[regionName];
|
||||
if (region) {
|
||||
if (region.open) {
|
||||
throw new Error(`Tried to open a region, named "${regionName}", that is already open`);
|
||||
}
|
||||
|
||||
// Region is opened, set from range value.
|
||||
region.open = true;
|
||||
region.ranges.push({from: getFromRangeValue(index, countOfRegionLines)});
|
||||
|
||||
if (plaster) {
|
||||
// Use the same indent as the docregion marker
|
||||
const indent = startRegion[0].split(/[^ ]/, 1);
|
||||
region.lines.push(indent + plaster);
|
||||
}
|
||||
} else {
|
||||
regionMap[regionName] = {
|
||||
lines: [],
|
||||
open: true,
|
||||
ranges: [
|
||||
{
|
||||
from: getFromRangeValue(index, countOfRegionLines),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
openRegions.push(regionName);
|
||||
}
|
||||
}
|
||||
|
||||
function handleEndRegion(
|
||||
openRegions: string[],
|
||||
endRegion: RegExpMatchArray,
|
||||
regionMap: Record<string, Region>,
|
||||
index: number,
|
||||
countOfRegionLines: number,
|
||||
) {
|
||||
if (openRegions.length === 0) {
|
||||
throw new Error('Tried to close a region when none are open');
|
||||
}
|
||||
// close down the specified region (or most recent if no name is given)
|
||||
const regionNames = getRegionNames(endRegion[1]);
|
||||
if (regionNames.length === 0) {
|
||||
regionNames.push(openRegions[openRegions.length - 1]);
|
||||
}
|
||||
|
||||
for (const regionName of regionNames) {
|
||||
const region = regionMap[regionName];
|
||||
if (!region || !region.open) {
|
||||
throw new Error(`Tried to close a region, named "${regionName}", that is not open`);
|
||||
}
|
||||
|
||||
// Region is closed, we can define the last line number of the region
|
||||
region.open = false;
|
||||
region.ranges[region.ranges.length - 1].to = index - countOfRegionLines;
|
||||
removeLast(openRegions, regionName);
|
||||
}
|
||||
}
|
||||
|
||||
function getFromRangeValue(index: number, countOfRegionLines: number): number {
|
||||
return index - countOfRegionLines + 1;
|
||||
}
|
||||
|
||||
function getRegionNames(input: string): string[] {
|
||||
return input.trim() === '' ? [] : input.split(',').map((name) => name.trim());
|
||||
}
|
||||
|
||||
function removeLast(array: string[], item: string): void {
|
||||
const index = array.lastIndexOf(item);
|
||||
array.splice(index, 1);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
// This definition file is a temporary workaround until the toolchain is able to read d.mts definition files
|
||||
// TODO: delete this file when the toolchains supports .d.mts files
|
||||
declare module 'shiki' {
|
||||
function createHighlighter(params: {
|
||||
themes: any[];
|
||||
langs: string[];
|
||||
cssVariablePrefix?: string;
|
||||
defaultColor?: boolean;
|
||||
}): unknown;
|
||||
|
||||
type HighlighterGeneric<BundledLangKeys, BundledThemeKeys> = any;
|
||||
}
|
||||
@@ -6,41 +6,24 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
let highlighter: any;
|
||||
import {HighlighterGeneric} from 'shiki';
|
||||
|
||||
export async function initHighlighter() {
|
||||
const {createHighlighter} = await import('shiki');
|
||||
highlighter = await createHighlighter({
|
||||
themes: ['github-light', 'github-dark'],
|
||||
langs: [
|
||||
'javascript',
|
||||
'typescript',
|
||||
'angular-html',
|
||||
'angular-ts',
|
||||
'shell',
|
||||
'html',
|
||||
'http',
|
||||
'json',
|
||||
'jsonc',
|
||||
'nginx',
|
||||
'markdown',
|
||||
'apache',
|
||||
],
|
||||
});
|
||||
/**
|
||||
* Singleton instance of the Shiki highlighter used during API page generation.
|
||||
*
|
||||
* TODO: Consider removing this singleton pattern if we find a better alternative.
|
||||
*/
|
||||
let highlighter: HighlighterGeneric<any, any>;
|
||||
export function setHighlighterInstance(instance: HighlighterGeneric<any, any>) {
|
||||
highlighter = instance;
|
||||
}
|
||||
|
||||
export function codeToHtml(code: string, language: string | undefined): string {
|
||||
const html = highlighter.codeToHtml(code, {
|
||||
lang: language ?? 'text',
|
||||
themes: {
|
||||
light: 'github-light',
|
||||
dark: 'github-dark',
|
||||
},
|
||||
cssVariablePrefix: '--shiki-',
|
||||
defaultColor: false,
|
||||
});
|
||||
|
||||
return html;
|
||||
export function getHighlighterInstance(): HighlighterGeneric<any, any> {
|
||||
if (!highlighter) {
|
||||
throw new Error(
|
||||
'Shiki highlighter has not been initialized. Make sure to call `setHighlighterInstance`.',
|
||||
);
|
||||
}
|
||||
return highlighter;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,30 +6,17 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {getSymbolUrl as sharedGetSymbolUrl} from '../../shared/linking.mjs';
|
||||
|
||||
/**
|
||||
* API pages are generated each package at a time.
|
||||
* This allows to use a global context to store the symbols and their corresponding module names.
|
||||
* This allows us to use a global context to store the symbols and their corresponding module names.
|
||||
*/
|
||||
|
||||
let symbols = new Map<string, string>();
|
||||
let symbols: Record<string, string> = {};
|
||||
|
||||
// This is used to store the currently processed symbol (usually a class or an interface)
|
||||
let currentSymbol: string | undefined;
|
||||
|
||||
export function setSymbols(newSymbols: Map<string, string>): void {
|
||||
symbols = newSymbols;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the module name of a symbol.
|
||||
* eg: 'ApplicationRef' => 'core', 'FormControl' => 'forms'
|
||||
* Also supports class.member, 'NgZone.runOutsideAngular => 'core'
|
||||
*/
|
||||
export function getModuleName(symbol: string): string | undefined {
|
||||
const moduleName = symbols.get(symbol);
|
||||
return moduleName?.replace('@angular/', '');
|
||||
}
|
||||
|
||||
export function setCurrentSymbol(symbol: string): void {
|
||||
currentSymbol = symbol;
|
||||
}
|
||||
@@ -38,6 +25,14 @@ export function getCurrentSymbol(): string | undefined {
|
||||
return currentSymbol;
|
||||
}
|
||||
|
||||
export function setSymbols(newSymbols: Record<string, string>): void {
|
||||
symbols = newSymbols;
|
||||
}
|
||||
|
||||
export function getSymbolUrl(symbol: string): string | undefined {
|
||||
return sharedGetSymbolUrl(symbol, symbols);
|
||||
}
|
||||
|
||||
export function unknownSymbolMessage(link: string, symbol: string): string {
|
||||
return `WARNING: {@link ${link}} is invalid, ${symbol} or ${currentSymbol}.${symbol} is unknown in this context`;
|
||||
}
|
||||
|
||||
@@ -20,9 +20,10 @@ import {SectionDescription} from './section-description';
|
||||
import {SectionUsageNotes} from './section-usage-notes';
|
||||
import {SectionApi} from './section-api';
|
||||
import {SectionHeading} from './section-heading';
|
||||
import {codeToHtml} from '../shiki/shiki.mjs';
|
||||
import {RawHtml} from './raw-html';
|
||||
import {DeprecationWarning} from './deprecation-warning';
|
||||
import {codeToHtml} from '../../../shared/shiki.mjs';
|
||||
import {getHighlighterInstance} from '../shiki/shiki.mjs';
|
||||
|
||||
/** Component to render a class API reference document. */
|
||||
export function ClassReference(entry: ClassEntryRenderable | PipeEntryRenderable) {
|
||||
@@ -33,7 +34,13 @@ export function ClassReference(entry: ClassEntryRenderable | PipeEntryRenderable
|
||||
<>
|
||||
<div className={SECTION_CONTAINER + ' docs-reference-api-section'}>
|
||||
<SectionHeading name="Pipe usage" />
|
||||
<RawHtml value={codeToHtml((entry as PipeEntry).usage, 'angular-html')} />
|
||||
<RawHtml
|
||||
value={codeToHtml(
|
||||
getHighlighterInstance(),
|
||||
(entry as PipeEntry).usage,
|
||||
'angular-html',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
|
||||
@@ -24,31 +24,28 @@ export function CliCard(props: {card: CliCardRenderable}) {
|
||||
{item.aliases?.map((alias) => (
|
||||
<div class="docs-reference-option-aliases">
|
||||
<span>Alias</span>
|
||||
<code>{alias} </code>
|
||||
<code>{alias}</code>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div dangerouslySetInnerHTML={{__html: item.description}}></div>
|
||||
</div>
|
||||
<div class="docs-reference-type-and-default">
|
||||
{/* Display the enum values if there are some, else the type expected for the option */}
|
||||
{/* Display the type expected for the option and the enum values if there are some. */}
|
||||
<span>Value Type</span>
|
||||
<code>{item.type}</code>
|
||||
{item.enum ? (
|
||||
<>
|
||||
<span>Allowed Values</span>
|
||||
<span>
|
||||
{item.enum.map((val, i, items) => (
|
||||
<>
|
||||
<code>{val}</code>
|
||||
{i < items.length - 1 && ', '}
|
||||
</>
|
||||
))}
|
||||
</span>
|
||||
{item.enum.map((val, i, items) => (
|
||||
<>
|
||||
<code>{val}</code>
|
||||
{i < items.length - 1 && ', '}
|
||||
</>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span>Value Type</span>
|
||||
<code>{item.type}</code>
|
||||
</>
|
||||
<></>
|
||||
)}
|
||||
{/* Default Value */}
|
||||
{item.default !== undefined ? <span>Default</span> : <></>}
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
*/
|
||||
|
||||
import {h} from 'preact';
|
||||
import {getModuleName} from '../symbol-context.mjs';
|
||||
import {getLinkToModule} from '../transforms/url-transforms.mjs';
|
||||
import {getSymbolUrl} from '../symbol-context.mjs';
|
||||
|
||||
const symbolRegex = /([a-zA-Z_$][a-zA-Z_$0-9\.]*)/;
|
||||
|
||||
@@ -23,11 +22,8 @@ export function CodeSymbol(props: {code: string}) {
|
||||
// Every even index is a non-match when the regex has 1 capturing group
|
||||
if (index % 2 === 0) return rawSymbol;
|
||||
|
||||
let [symbol, subSymbol] = rawSymbol.split('.'); // Also takes care of methods, enum value etc.
|
||||
const moduleName = getModuleName(symbol);
|
||||
|
||||
if (moduleName) {
|
||||
const url = getLinkToModule(moduleName, symbol, subSymbol);
|
||||
const url = getSymbolUrl(rawSymbol);
|
||||
if (url) {
|
||||
return <a href={url}>{rawSymbol}</a>;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,11 +8,13 @@
|
||||
|
||||
import {h} from 'preact';
|
||||
import {RawHtml} from './raw-html';
|
||||
import {codeToHtml} from '../shiki/shiki.mjs';
|
||||
import {codeToHtml} from '../../../shared/shiki.mjs';
|
||||
import {get} from 'http';
|
||||
import {getHighlighterInstance} from '../shiki/shiki.mjs';
|
||||
|
||||
/** Component to render a header of the CLI page. */
|
||||
export function HighlightTypeScript(props: {code: string}) {
|
||||
const result = codeToHtml(props.code, 'typescript');
|
||||
const result = codeToHtml(getHighlighterInstance(), props.code, 'typescript');
|
||||
const withScrollTrack = result.replace(/^(<pre class="shiki)/, '$1 docs-mini-scroll-track');
|
||||
|
||||
return <RawHtml value={withScrollTrack} className="docs-code" />;
|
||||
|
||||
@@ -21,6 +21,7 @@ ts_project(
|
||||
"//adev:node_modules/@types/jsdom",
|
||||
"//adev:node_modules/jsdom",
|
||||
"//adev/shared-docs/pipeline/api-gen/rendering:render_api_to_html_lib",
|
||||
"//adev/shared-docs/pipeline/shared:shiki",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -9,18 +9,17 @@
|
||||
import {resolve} from 'path';
|
||||
import {readFile} from 'fs/promises';
|
||||
import {JSDOM} from 'jsdom';
|
||||
import {configureMarkedGlobally} from '../marked/configuration.mjs';
|
||||
import {getRenderable} from '../processing.mjs';
|
||||
import {renderEntry} from '../rendering.mjs';
|
||||
import {initHighlighter} from '../shiki/shiki.mjs';
|
||||
import {initHighlighter} from '../../../shared/shiki.mjs';
|
||||
import {setHighlighterInstance} from '../shiki/shiki.mjs';
|
||||
|
||||
describe('CLI docs to html', () => {
|
||||
let fragment: DocumentFragment;
|
||||
let entryJson: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
await initHighlighter();
|
||||
await configureMarkedGlobally();
|
||||
setHighlighterInstance(await initHighlighter());
|
||||
|
||||
const entryContent = await readFile(resolve('./fake-cli-entries.json'), {
|
||||
encoding: 'utf-8',
|
||||
|
||||
@@ -1276,14 +1276,14 @@
|
||||
}
|
||||
],
|
||||
"symbols": [
|
||||
["AfterRenderPhase", "core"],
|
||||
["afterRender", "core"],
|
||||
["EmbeddedViewRef", "core"],
|
||||
["ChangeDetectionStrategy", "core"],
|
||||
["ChangeDetectorRef", "core"],
|
||||
["withNoHttpTransferCache", "platform-browser"],
|
||||
["withHttpTransferCacheOptions", "platform-browser"],
|
||||
["withI18nSupport", "platform-browser"],
|
||||
["withEventReplay", "platform-browser"]
|
||||
["AfterRenderPhase", "@angular/core"],
|
||||
["afterRender", "@angular/core"],
|
||||
["EmbeddedViewRef", "@angular/core"],
|
||||
["ChangeDetectionStrategy", "@angular/core"],
|
||||
["ChangeDetectorRef", "@angular/core"],
|
||||
["withNoHttpTransferCache", "@angular/platform-browser"],
|
||||
["withHttpTransferCacheOptions", "@angular/platform-browser"],
|
||||
["withI18nSupport", "@angular/platform-browser"],
|
||||
["withEventReplay", "@angular/platform-browser"]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
|
||||
import {readFile} from 'fs/promises';
|
||||
import {JSDOM} from 'jsdom';
|
||||
import {configureMarkedGlobally} from '../marked/configuration.mjs';
|
||||
import {getRenderable} from '../processing.mjs';
|
||||
import {renderEntry} from '../rendering.mjs';
|
||||
import {initHighlighter} from '../shiki/shiki.mjs';
|
||||
import {setSymbols} from '../symbol-context.mjs';
|
||||
import {resolve} from 'path';
|
||||
import {initHighlighter} from '../../../shared/shiki.mjs';
|
||||
import {setHighlighterInstance} from '../shiki/shiki.mjs';
|
||||
|
||||
// Note: The tests will probably break if the schema of the api extraction changes.
|
||||
// All entries in the fake-entries are extracted from Angular's api.
|
||||
@@ -24,14 +24,13 @@ describe('markdown to html', () => {
|
||||
const entries2 = new Map<string, string>();
|
||||
|
||||
beforeAll(async () => {
|
||||
await initHighlighter();
|
||||
await configureMarkedGlobally();
|
||||
setHighlighterInstance(await initHighlighter());
|
||||
|
||||
const entryContent = await readFile(resolve('./fake-entries.json'), {
|
||||
encoding: 'utf-8',
|
||||
});
|
||||
const entryJson = JSON.parse(entryContent) as any;
|
||||
const symbols = new Map<string, string>([
|
||||
const symbols = Object.fromEntries([
|
||||
['AfterRenderPhase', 'core'],
|
||||
['afterRender', 'core'],
|
||||
['EmbeddedViewRef', 'core'],
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
|
||||
import {readFile} from 'fs/promises';
|
||||
import {DocEntryRenderable} from '../entities/renderables.mjs';
|
||||
import {configureMarkedGlobally} from '../marked/configuration.mjs';
|
||||
import {getRenderable} from '../processing.mjs';
|
||||
import {initHighlighter} from '../shiki/shiki.mjs';
|
||||
import {setSymbols} from '../symbol-context.mjs';
|
||||
import {resolve} from 'path';
|
||||
import {initHighlighter} from '../../../shared/shiki.mjs';
|
||||
import {setHighlighterInstance} from '../shiki/shiki.mjs';
|
||||
|
||||
// Note: The tests will probably break if the schema of the api extraction changes.
|
||||
// All entries in the fake-entries are extracted from Angular's api.
|
||||
@@ -22,14 +22,13 @@ describe('renderable', () => {
|
||||
const entries = new Map<string, DocEntryRenderable>();
|
||||
|
||||
beforeAll(async () => {
|
||||
await initHighlighter();
|
||||
await configureMarkedGlobally();
|
||||
setHighlighterInstance(await initHighlighter());
|
||||
|
||||
const entryContent = await readFile(resolve('./fake-entries.json'), {
|
||||
encoding: 'utf-8',
|
||||
});
|
||||
const entryJson = JSON.parse(entryContent) as any;
|
||||
const symbols = new Map<string, string>([
|
||||
const symbols = Object.fromEntries([
|
||||
['AfterRenderPhase', 'core'],
|
||||
['afterRender', 'core'],
|
||||
['EmbeddedViewRef', 'core'],
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ describe('jsdoc transforms', () => {
|
||||
it('should transform links', () => {
|
||||
setCurrentSymbol('Router');
|
||||
setSymbols(
|
||||
new Map([
|
||||
Object.fromEntries([
|
||||
['Route', 'test'],
|
||||
['Router', 'test'],
|
||||
['Router.someMethod', 'test'],
|
||||
|
||||
@@ -34,16 +34,16 @@ import {
|
||||
} from '../entities/categorization.mjs';
|
||||
import {CodeLineRenderable} from '../entities/renderables.mjs';
|
||||
import {HasModuleName, HasRenderableToc} from '../entities/traits.mjs';
|
||||
import {getModuleName} from '../symbol-context.mjs';
|
||||
import {getSymbolUrl} from '../symbol-context.mjs';
|
||||
import {
|
||||
codeToHtml,
|
||||
getHighlighterInstance,
|
||||
insertParenthesesForDecoratorInShikiHtml,
|
||||
replaceKeywordFromShikiHtml,
|
||||
} from '../shiki/shiki.mjs';
|
||||
|
||||
import {filterLifecycleMethods, mergeGettersAndSetters} from './member-transforms.mjs';
|
||||
import {getLinkToModule} from './url-transforms.mjs';
|
||||
import {formatJs} from './format-code.mjs';
|
||||
import {codeToHtml} from '../../../shared/shiki.mjs';
|
||||
|
||||
const INDENT = ' ';
|
||||
const SPACE = ' ';
|
||||
@@ -85,7 +85,11 @@ export async function addRenderableCodeToc<T extends DocEntry & HasModuleName>(
|
||||
formattedCode = await formatJs(metadata.contents);
|
||||
}
|
||||
|
||||
let codeWithSyntaxHighlighting = codeToHtml(formattedCode ?? metadata?.contents, 'typescript');
|
||||
let codeWithSyntaxHighlighting = codeToHtml(
|
||||
getHighlighterInstance(),
|
||||
formattedCode ?? metadata?.contents,
|
||||
'typescript',
|
||||
);
|
||||
|
||||
if (isDecoratorEntry(entry)) {
|
||||
// Shiki requires a keyword for correct formating of Decorators
|
||||
@@ -525,14 +529,9 @@ export function addApiLinksToHtml(htmlString: string): string {
|
||||
// The captured content ==> vvvvvvvv
|
||||
/(?<!<a[^>]*>)(<(?:(?:span)|(?:code))(?!\sdata-skip-anchor)[^>]*>\s*)([^<]*?)(\s*<\/(?:span|code)>)/g,
|
||||
(type: string, span1: string, potentialSymbolName: string, span2: string) => {
|
||||
const [symbol, subSymbol] = potentialSymbolName.split(/(?:#|\.)/) as [string, string?];
|
||||
|
||||
// mySymbol() => mySymbol
|
||||
const symbolWithoutInvocation = symbol.replace(/\([^)]*\);?/g, '');
|
||||
const moduleName = getModuleName(symbolWithoutInvocation);
|
||||
|
||||
if (moduleName) {
|
||||
return `${span1}<a href="${getLinkToModule(moduleName, symbol, subSymbol)}">${potentialSymbolName}</a>${span2}`;
|
||||
const url = getSymbolUrl(potentialSymbolName);
|
||||
if (url) {
|
||||
return `${span1}<a href="${url}">${potentialSymbolName}</a>${span2}`;
|
||||
}
|
||||
|
||||
return type;
|
||||
|
||||
@@ -25,9 +25,8 @@ import {
|
||||
HasStableFlag,
|
||||
} from '../entities/traits.mjs';
|
||||
|
||||
import {getLinkToModule} from './url-transforms.mjs';
|
||||
import {addApiLinksToHtml} from './code-transforms.mjs';
|
||||
import {getCurrentSymbol, getModuleName, unknownSymbolMessage} from '../symbol-context.mjs';
|
||||
import {getCurrentSymbol, getSymbolUrl, unknownSymbolMessage} from '../symbol-context.mjs';
|
||||
|
||||
const JS_DOC_USAGE_NOTE_TAGS: Set<string> = new Set(['remarks', 'usageNotes', 'example']);
|
||||
export const JS_DOC_SEE_TAG = 'see';
|
||||
@@ -141,7 +140,11 @@ function getHtmlAdditionalLinks<T extends HasJsDocTags>(entry: T): LinkEntryRend
|
||||
|
||||
if (linkMatch) {
|
||||
const link = linkMatch[1];
|
||||
const {url, label} = parseAtLink(link);
|
||||
const parsed = parseAtLink(link);
|
||||
if (!parsed) {
|
||||
return undefined;
|
||||
}
|
||||
const {url, label} = parsed;
|
||||
return {label, url};
|
||||
}
|
||||
|
||||
@@ -168,13 +171,17 @@ function wrapExampleHtmlElementsWithCode(text: string) {
|
||||
*/
|
||||
function convertLinks(text: string) {
|
||||
return text.replace(jsDoclinkRegexGlobal, (_, link) => {
|
||||
const {label, url} = parseAtLink(link);
|
||||
const parsed = parseAtLink(link);
|
||||
if (!parsed) {
|
||||
return `<code>${link}</code>`; // leave the link as-is if we can't parse it
|
||||
}
|
||||
const {label, url} = parsed;
|
||||
|
||||
return `<a href="${url}"><code>${label}</code></a>`;
|
||||
});
|
||||
}
|
||||
|
||||
function parseAtLink(link: string): {label: string; url: string} {
|
||||
function parseAtLink(link: string): {label: string; url: string} | undefined {
|
||||
// Because of microsoft/TypeScript/issues/59679
|
||||
// getTextOfJSDocComment introduces an extra space between the symbol and a trailing ()
|
||||
link = link.replace(/ \(\)$/, '');
|
||||
@@ -195,24 +202,18 @@ function parseAtLink(link: string): {label: string; url: string} {
|
||||
};
|
||||
}
|
||||
|
||||
let [symbol, subSymbol] = rawSymbol.replace(/\(\)$/, '').split(/(?:#|\.)/);
|
||||
|
||||
let moduleName = getModuleName(symbol);
|
||||
let url = getSymbolUrl(rawSymbol);
|
||||
const label = description ?? rawSymbol;
|
||||
|
||||
const currentSymbol = getCurrentSymbol();
|
||||
if (!url) {
|
||||
const currentSymbol = getCurrentSymbol();
|
||||
// 2nd attempt, try to get the module name in the context of the current symbol
|
||||
url = getSymbolUrl(`${currentSymbol}.${rawSymbol}`);
|
||||
|
||||
if (!moduleName) {
|
||||
// 2nd attemp, try to get the module name in the context of the current symbol
|
||||
moduleName = getModuleName(`${currentSymbol}.${symbol}`);
|
||||
|
||||
if (!moduleName || !currentSymbol) {
|
||||
throw unknownSymbolMessage(link, symbol);
|
||||
if (!url || !currentSymbol) {
|
||||
throw unknownSymbolMessage(link, rawSymbol);
|
||||
}
|
||||
|
||||
subSymbol = symbol;
|
||||
symbol = currentSymbol;
|
||||
}
|
||||
|
||||
return {label, url: getLinkToModule(moduleName, symbol, subSymbol)};
|
||||
return {label, url};
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
export const API_PREFIX = 'api';
|
||||
export const MODULE_NAME_PREFIX = '@angular/';
|
||||
|
||||
export function getLinkToModule(moduleName: string, symbol: string, subSymbol?: string) {
|
||||
return `/${API_PREFIX}/${moduleName}/${symbol}${subSymbol ? `#${subSymbol}` : ''}`;
|
||||
|
||||
@@ -18,7 +18,7 @@ ts_project(
|
||||
"//adev:node_modules/jsdom",
|
||||
"//adev:node_modules/tinyglobby",
|
||||
"//adev/shared-docs/pipeline/examples/shared",
|
||||
"//adev/shared-docs/pipeline/guides:guides_lib",
|
||||
"//adev/shared-docs/pipeline/shared/regions",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@ import {readFile} from 'fs/promises';
|
||||
import {copyFolder, createFolder, removeFolder} from '../shared/file-system.mjs';
|
||||
import jsdom from 'jsdom';
|
||||
import {glob} from 'tinyglobby';
|
||||
import {regionParser} from '../../guides/extensions/docs-code/regions/region-parser.mjs';
|
||||
import {appendCopyrightToFile} from '../shared/copyright.mjs';
|
||||
import {FileType} from '../../guides/extensions/docs-code/sanitizers/eslint.mjs';
|
||||
import {EXCLUDE_FILES_FOR_STACKBLITZ, STACKBLITZ_CONFIG_FILENAME} from './defaults.mjs';
|
||||
import {regionParser} from '../../shared/regions/region-parser.mjs';
|
||||
import {FileType} from '../../shared/regions/remove-eslint-comments.mjs';
|
||||
|
||||
interface StackblitzConfig {
|
||||
title: string;
|
||||
|
||||
@@ -18,7 +18,7 @@ ts_project(
|
||||
"//adev:node_modules/tinyglobby",
|
||||
"//adev/shared-docs/interfaces",
|
||||
"//adev/shared-docs/pipeline/examples/shared",
|
||||
"//adev/shared-docs/pipeline/guides:guides_lib",
|
||||
"//adev/shared-docs/pipeline/shared/regions",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@ import {join} from 'path';
|
||||
import {readFile} from 'fs/promises';
|
||||
import {copyFolder, createFolder} from '../shared/file-system.mjs';
|
||||
import {glob} from 'tinyglobby';
|
||||
import {regionParser} from '../../guides/extensions/docs-code/regions/region-parser.mjs';
|
||||
import {appendCopyrightToFile} from '../shared/copyright.mjs';
|
||||
import {FileType} from '../../guides/extensions/docs-code/sanitizers/eslint.mjs';
|
||||
import {EXCLUDE_FILES, CONFIG_FILENAME} from './defaults.mjs';
|
||||
import {zip, strToU8} from 'fflate';
|
||||
|
||||
import {FileAndContent} from '../../../interfaces';
|
||||
import {FileType} from '../../shared/regions/remove-eslint-comments.mjs';
|
||||
import {regionParser} from '../../shared/regions/region-parser.mjs';
|
||||
|
||||
interface ZipConfig {
|
||||
ignore: string[];
|
||||
|
||||
@@ -53,7 +53,6 @@ ts_project(
|
||||
srcs = glob(
|
||||
[
|
||||
"**/*.mts",
|
||||
"shiki.d.ts",
|
||||
],
|
||||
exclude = ["index.mts"],
|
||||
),
|
||||
@@ -61,16 +60,8 @@ ts_project(
|
||||
"//adev/shared-docs:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//adev:node_modules/@types/jsdom",
|
||||
"//adev:node_modules/@types/node",
|
||||
"//adev:node_modules/diff",
|
||||
"//adev:node_modules/emoji-regex",
|
||||
"//adev:node_modules/html-entities",
|
||||
"//adev:node_modules/jsdom",
|
||||
"//adev:node_modules/marked",
|
||||
"//adev:node_modules/mermaid",
|
||||
"//adev:node_modules/playwright-core",
|
||||
"//adev:node_modules/shiki",
|
||||
"//adev/shared-docs/pipeline/shared:shiki",
|
||||
"//adev/shared-docs/pipeline/shared/marked",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -85,5 +76,7 @@ ts_project(
|
||||
deps = [
|
||||
":guides_lib",
|
||||
"//adev:node_modules/@types/node",
|
||||
"//adev/shared-docs/pipeline/shared:shiki",
|
||||
"//adev/shared-docs/pipeline/shared/marked",
|
||||
],
|
||||
)
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
// These kind of comments are used CSS and other languages that do not support inline comments
|
||||
export const regionStartMatcher = /^\s*\/\*\s*#docregion\s*(.*)\s*\*\/\s*$/;
|
||||
export const regionEndMatcher = /^\s*\/\*\s*#enddocregion\s*(.*)\s*\*\/\s*$/;
|
||||
export const plasterMatcher = /^\s*\/\*\s*#docplaster\s*(.*)\s*\*\/\s*$/;
|
||||
export const createPlasterComment = (plaster: string) => `/* ${plaster} */`;
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
// These kind of comments are used in HTML
|
||||
|
||||
export const regionStartMatcher = /^\s*<!--\s*#docregion\s*(.*?)\s*(?:-->)?\s*$/;
|
||||
export const regionEndMatcher = /^\s*<!--\s*#enddocregion\s*(.*?)\s*-->\s*$/;
|
||||
export const plasterMatcher = /^\s*<!--\s*#docplaster\s*(.*?)\s*-->\s*$/;
|
||||
export const createPlasterComment = (plaster: string) => `<!-- ${plaster} -->`;
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
// These kind of comments are used in languages that do not support block comments, such as Jade
|
||||
export const regionStartMatcher = /^\s*\/\/\s*#docregion\s*(.*)\s*$/;
|
||||
export const regionEndMatcher = /^\s*\/\/\s*#enddocregion\s*(.*)\s*$/;
|
||||
export const plasterMatcher = /^\s*\/\/\s*#docplaster\s*(.*)\s*$/;
|
||||
export const createPlasterComment = (plaster: string) => `// ${plaster}`;
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
// This comment type is used in C like languages such as JS, TS, etc
|
||||
export const regionStartMatcher = /^\s*\/\/\s*#docregion\s*(.*)\s*$/;
|
||||
export const regionEndMatcher = /^\s*\/\/\s*#enddocregion\s*(.*)\s*$/;
|
||||
export const plasterMatcher = /^\s*\/\/\s*#docplaster\s*(.*)\s*$/;
|
||||
export const createPlasterComment = (plaster: string) => `/* ${plaster} */`;
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
// These type of comments are used in hash comment based languages such as bash and Yaml
|
||||
export const regionStartMatcher = /^\s*#\s*#docregion\s*(.*)\s*$/;
|
||||
export const regionEndMatcher = /^\s*#\s*#enddocregion\s*(.*)\s*$/;
|
||||
export const plasterMatcher = /^\s*#\s*#docplaster\s*(.*)\s*$/;
|
||||
export const createPlasterComment = (plaster: string) => `# ${plaster}`;
|
||||
@@ -1,61 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
export type FileType =
|
||||
| 'ts'
|
||||
| 'js'
|
||||
| 'mjs'
|
||||
| 'es6'
|
||||
| 'html'
|
||||
| 'svg'
|
||||
| 'css'
|
||||
| 'conf'
|
||||
| 'yaml'
|
||||
| 'yml'
|
||||
| 'sh'
|
||||
| 'jade'
|
||||
| 'pug'
|
||||
| 'json'
|
||||
| 'json.annotated';
|
||||
|
||||
/**
|
||||
* Remove any ESLint comments from the provided code string. This is particularly useful as we may
|
||||
* want to store code formatted for an example that would not be allowed in our repo. For instance,
|
||||
* we can disable ESLint to allow for a `console` usage, despite not allowing it typically, so that
|
||||
* it can be used in an example in documenation.
|
||||
*/
|
||||
export function removeEslintComments(input: string, fileType: FileType) {
|
||||
if (!input || (fileType !== 'ts' && fileType !== 'js' && fileType !== 'html')) {
|
||||
return input;
|
||||
}
|
||||
return input.replace(regexesForFileTypes[fileType], '');
|
||||
}
|
||||
|
||||
const jsRegexes = [
|
||||
/\/\/ *eslint-disable(?:-next-line)?(?: .*)?(?:\n *|$)/,
|
||||
/\n? *\/\/ *eslint-(?:disable-line|enable)(?: .*)?(?=\n|$)/,
|
||||
/\/\*\s*eslint-disable(?:-next-line)?(?: [\s\S]*?)?\*\/ *(?:\n *)?/,
|
||||
/\n? *\/\*\s*eslint-(?:disable-line|enable)(?: [\s\S]*?)?\*\//,
|
||||
];
|
||||
|
||||
const htmlRegexes = [
|
||||
/<!--\s*eslint-disable(?:-next-line)?(?: [\s\S]*?)?--> *(?:\n *)?/,
|
||||
/\n? *<!--\s*eslint-(?:disable-line|enable)(?: [\s\S]*?)?-->/,
|
||||
];
|
||||
|
||||
const joinRegexes = (regexes: any) =>
|
||||
new RegExp(regexes.map((regex: any) => `(?:${regex.source})`).join('|'), 'g');
|
||||
const htmlRegex = joinRegexes(htmlRegexes);
|
||||
// Note: the js regex needs to also include the html ones to account for inline templates in @Components
|
||||
const jsRegex = joinRegexes([...jsRegexes, ...htmlRegexes]);
|
||||
|
||||
const regexesForFileTypes = {
|
||||
js: jsRegex,
|
||||
ts: jsRegex,
|
||||
html: htmlRegex,
|
||||
};
|
||||
@@ -8,25 +8,45 @@
|
||||
|
||||
import {readFileSync, writeFileSync} from 'fs';
|
||||
import path from 'path';
|
||||
import {parseMarkdown} from './parse.mjs';
|
||||
import {initHighlighter} from './extensions/docs-code/format/highlight.mjs';
|
||||
import {initHighlighter} from '../shared/shiki.mjs';
|
||||
import {parseMarkdownAsync} from '../shared/marked/parse.mjs';
|
||||
|
||||
type ApiManifest = ApiManifestPackage[];
|
||||
interface ApiManifestPackage {
|
||||
moduleName: string;
|
||||
entries: {name: string}[];
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const [paramFilePath] = process.argv.slice(2);
|
||||
const rawParamLines = readFileSync(paramFilePath, {encoding: 'utf8'}).split('\n');
|
||||
const [srcs, outputFilenameExecRootRelativePath] = rawParamLines;
|
||||
const [srcs, outputFilenameExecRootRelativePath, apiManifestPath] = rawParamLines;
|
||||
|
||||
// The highlighter needs to be setup asynchronously
|
||||
// so we're doing it at the start of the pipeline
|
||||
await initHighlighter();
|
||||
const highlighter = await initHighlighter();
|
||||
|
||||
for (const filePath of srcs.split(',')) {
|
||||
if (!filePath.endsWith('.md')) {
|
||||
throw new Error(`Input file "${filePath}" does not end in a ".md" file extension.`);
|
||||
}
|
||||
|
||||
let apiManifest: ApiManifest = [];
|
||||
if (apiManifestPath) {
|
||||
try {
|
||||
const apiManifestStr = readFileSync(apiManifestPath, {encoding: 'utf8'});
|
||||
apiManifest = JSON.parse(apiManifestStr);
|
||||
} catch (error) {
|
||||
console.warn('Failed to load API entries:', error);
|
||||
}
|
||||
}
|
||||
|
||||
const markdownContent = readFileSync(filePath, {encoding: 'utf8'});
|
||||
const htmlOutputContent = await parseMarkdown(markdownContent, {markdownFilePath: filePath});
|
||||
const htmlOutputContent = await parseMarkdownAsync(markdownContent, {
|
||||
markdownFilePath: filePath,
|
||||
apiEntries: mapManifestToEntries(apiManifest),
|
||||
highlighter,
|
||||
});
|
||||
|
||||
// The expected file name structure is the [name of the file].md.html.
|
||||
const htmlFileName = filePath + '.html';
|
||||
@@ -37,3 +57,22 @@ async function main() {
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
function mapManifestToEntries(apiManifest: ApiManifest): Record<string, string> {
|
||||
const duplicateEntries = new Set<string>();
|
||||
|
||||
const entryToModuleMap: Record<string, string> = {};
|
||||
for (const pkg of apiManifest) {
|
||||
for (const entry of pkg.entries) {
|
||||
if (duplicateEntries.has(entry.name)) {
|
||||
continue;
|
||||
} else if (entryToModuleMap[entry.name]) {
|
||||
delete entryToModuleMap[entry.name];
|
||||
duplicateEntries.add(entry.name);
|
||||
} else {
|
||||
entryToModuleMap[entry.name] = pkg.moduleName.replace(/^@angular\//, '');
|
||||
}
|
||||
}
|
||||
}
|
||||
return entryToModuleMap;
|
||||
}
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {marked} from 'marked';
|
||||
import {hooks} from './hooks.mjs';
|
||||
import {Renderer} from './renderer.mjs';
|
||||
import {docsAlertExtension} from './extensions/docs-alert.mjs';
|
||||
import {docsCalloutExtension} from './extensions/docs-callout.mjs';
|
||||
import {docsPillExtension} from './extensions/docs-pill/docs-pill.mjs';
|
||||
import {docsPillRowExtension} from './extensions/docs-pill/docs-pill-row.mjs';
|
||||
import {docsVideoExtension} from './extensions/docs-video.mjs';
|
||||
import {docsWorkflowExtension} from './extensions/docs-workflow/docs-workflow.mjs';
|
||||
import {docsStepExtension} from './extensions/docs-workflow/docs-step.mjs';
|
||||
import {docsCardExtension} from './extensions/docs-card/docs-card.mjs';
|
||||
import {docsCardContainerExtension} from './extensions/docs-card/docs-card-container.mjs';
|
||||
import {docsDecorativeHeaderExtension} from './extensions/docs-decorative-header.mjs';
|
||||
import {docsCodeBlockExtension} from './extensions/docs-code/docs-code-block.mjs';
|
||||
import {docsCodeExtension} from './extensions/docs-code/docs-code.mjs';
|
||||
import {docsCodeMultifileExtension} from './extensions/docs-code/docs-code-multifile.mjs';
|
||||
import {ParserContext, setContext} from './utils.mjs';
|
||||
import {walkTokens} from './walk-tokens.mjs';
|
||||
|
||||
export async function parseMarkdown(
|
||||
markdownContent: string,
|
||||
context: ParserContext,
|
||||
): Promise<string> {
|
||||
setContext(context);
|
||||
|
||||
marked.use({
|
||||
hooks,
|
||||
extensions: [
|
||||
docsAlertExtension,
|
||||
docsCalloutExtension,
|
||||
docsPillExtension,
|
||||
docsPillRowExtension,
|
||||
docsVideoExtension,
|
||||
docsWorkflowExtension,
|
||||
docsStepExtension,
|
||||
docsCardExtension,
|
||||
docsCardContainerExtension,
|
||||
docsDecorativeHeaderExtension,
|
||||
docsCodeBlockExtension,
|
||||
docsCodeExtension,
|
||||
docsCodeMultifileExtension,
|
||||
],
|
||||
walkTokens,
|
||||
// The async option causes marked to await walkTokens functions before parsing the tokens and returning an HTML string.
|
||||
// We leverage this to allow us to use async libraries like mermaid and building stackblitz examples.
|
||||
async: true,
|
||||
});
|
||||
|
||||
return marked.parse(markdownContent, {renderer: new Renderer()});
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Renderer as _Renderer} from 'marked';
|
||||
import {linkRender} from './tranformations/link.mjs';
|
||||
import {tableRender} from './tranformations/table.mjs';
|
||||
import {listRender} from './tranformations/list.mjs';
|
||||
import {imageRender} from './tranformations/image.mjs';
|
||||
import {textRender} from './tranformations/text.mjs';
|
||||
import {headingRender} from './tranformations/heading.mjs';
|
||||
|
||||
/**
|
||||
* Custom renderer for marked that will be used to transform markdown files to HTML
|
||||
* files that can be used in the Angular docs.
|
||||
*/
|
||||
export class Renderer extends _Renderer {
|
||||
override link = linkRender;
|
||||
override table = tableRender;
|
||||
override list = listRender;
|
||||
override image = imageRender;
|
||||
override text = textRender;
|
||||
override heading = headingRender;
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
// This definition file is a temporary workaround until the toolchain is able to read d.mts definition files
|
||||
// TODO: delete this file when the toolchains supports .d.mts files
|
||||
declare module 'shiki' {
|
||||
function createHighlighter(params: {
|
||||
themes: any[];
|
||||
langs: string[];
|
||||
cssVariablePrefix?: string;
|
||||
defaultColor?: boolean;
|
||||
}): unknown;
|
||||
|
||||
type HighlighterGeneric<BundledLangKeys, BundledThemeKeys> = any;
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {existsSync, readFileSync} from 'fs';
|
||||
import {join} from 'path';
|
||||
import {cwd} from 'process';
|
||||
|
||||
// TODO(josephperrott): Set edit content url based on the owner, repo and branch.
|
||||
|
||||
/** The base url for edting the a file in the repository. */
|
||||
const GITHUB_EDIT_CONTENT_URL = 'https://github.com/angular/angular/edit/main';
|
||||
|
||||
/** Get the page title with edit button to modify the page source. */
|
||||
export function getPageTitle(text: string): string {
|
||||
return `
|
||||
<!-- Page title -->
|
||||
<div class="docs-page-title">
|
||||
<h1 tabindex="-1">${text}</h1>
|
||||
<a class="docs-github-links" target="_blank" href="${GITHUB_EDIT_CONTENT_URL}/${context?.markdownFilePath}" title="Edit this page" aria-label="Edit this page">
|
||||
<!-- Pencil -->
|
||||
<docs-icon role="presentation">edit</docs-icon>
|
||||
</a>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
/** Configuration using environment for parser, providing context. */
|
||||
export interface ParserContext {
|
||||
markdownFilePath?: string;
|
||||
}
|
||||
|
||||
let context: ParserContext = {};
|
||||
export function setContext(envContext: Partial<ParserContext>) {
|
||||
context = envContext;
|
||||
}
|
||||
|
||||
/** The base directory of the workspace the script is running in. */
|
||||
const WORKSPACE_DIR = cwd();
|
||||
|
||||
export function loadWorkspaceRelativeFile(filePath: string): string {
|
||||
const fullFilePath = join(WORKSPACE_DIR, filePath);
|
||||
if (!existsSync(fullFilePath)) {
|
||||
throw Error(`Cannot find: ${filePath}`);
|
||||
}
|
||||
return readFileSync(fullFilePath, {encoding: 'utf-8'});
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Token} from 'marked';
|
||||
import {DocsCodeToken} from './extensions/docs-code/docs-code.mjs';
|
||||
|
||||
/**
|
||||
* Describe a HANDLE_MERMAID value which esbuild will use at build time to determine if the mermaid
|
||||
* related code should be included in the bundle.
|
||||
* THIS VALUE IS NOT AVAILABLE AT RUNTIME.
|
||||
*/
|
||||
export declare const HANDLE_MERMAID: boolean;
|
||||
|
||||
/** Type guard for if a provided token is the DocsCodeToken. */
|
||||
function isDocsCodeToken(token: Token): token is DocsCodeToken {
|
||||
return !!(token as DocsCodeToken).language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the provided token based on the token itself replacing its content/data in place
|
||||
* as appropriate.
|
||||
*/
|
||||
let mermaid: typeof import('./mermaid/index.mjs');
|
||||
export async function walkTokens(token: Token): Promise<void> {
|
||||
if (!isDocsCodeToken(token) || token.language !== 'mermaid') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (HANDLE_MERMAID) {
|
||||
mermaid ??= await import('./mermaid/index.mjs');
|
||||
return mermaid.processMermaidCodeBlock(token);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
load("//adev/shared-docs:defaults.bzl", "ts_project")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
ts_project(
|
||||
name = "linking",
|
||||
srcs = ["linking.mts"],
|
||||
visibility = [
|
||||
"//adev/shared-docs/pipeline:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
ts_project(
|
||||
name = "shiki",
|
||||
srcs = ["shiki.mts"],
|
||||
visibility = [
|
||||
"//adev/shared-docs/pipeline:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//adev:node_modules/shiki",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,62 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
// In some case we know that we don't want to link a symbol
|
||||
// Example when there is a conflict between API entries and compiler features.
|
||||
// eg: "animate" is both an Animation API entry and an template instruction "animation.enter"
|
||||
const LINK_EXEMPT = new Set(['animate', 'animate.enter', 'animate.leave']);
|
||||
|
||||
export function shouldLinkSymbol(symbol: string): boolean {
|
||||
return !LINK_EXEMPT.has(symbol);
|
||||
}
|
||||
|
||||
export type ApiEntries = Record<string, string>; // symbolName -> moduleName (without @angular/ prefix)
|
||||
|
||||
/**
|
||||
* Extracts the symbol name and property name from a symbol string.
|
||||
* eg:
|
||||
* foobar() => {symbolName: 'foobar', propName: null}
|
||||
* ApplicationRef.tick = > {symbolName: 'ApplicationRef', propName: 'tick'}
|
||||
* ApplicationRef.tick() = > {symbolName: 'ApplicationRef', propName: 'tick'}
|
||||
* @Component => {symbolName: 'Component', propName: null}
|
||||
*/
|
||||
export function extractFromSymbol(symbol: string): {propName: string | null; symbolName: string} {
|
||||
let propName: string | undefined;
|
||||
let symbolName = symbol;
|
||||
// we want to match functions when they have parentheses
|
||||
if (symbolName.endsWith('()')) {
|
||||
symbolName = symbolName.slice(0, -2);
|
||||
}
|
||||
|
||||
if (symbolName.startsWith('@')) {
|
||||
symbolName = symbolName.slice(1);
|
||||
}
|
||||
if (symbolName.includes('#')) {
|
||||
[symbolName, propName] = symbolName.split('#');
|
||||
} else if (symbolName.includes('.')) {
|
||||
[symbolName, propName] = symbolName.split('.');
|
||||
}
|
||||
|
||||
return {propName: propName ?? null, symbolName: symbolName};
|
||||
}
|
||||
|
||||
export function getSymbolUrl(symbol: string, apiEntries: ApiEntries): string | undefined {
|
||||
if (hasMoreThanOneDot(symbol) || !shouldLinkSymbol(symbol)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const {symbolName, propName} = extractFromSymbol(symbol);
|
||||
// We don't want to match entries like "constructor"
|
||||
const apiEntry = Object.hasOwn(apiEntries, symbolName) && apiEntries[symbolName];
|
||||
|
||||
return apiEntry ? `/api/${apiEntry}/${symbolName}${propName ? `#${propName}` : ''}` : undefined;
|
||||
}
|
||||
|
||||
function hasMoreThanOneDot(str: string) {
|
||||
return str.split('.').length - 1 > 1;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
load("//adev/shared-docs:defaults.bzl", "ts_project")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
ts_project(
|
||||
name = "marked",
|
||||
srcs = glob(["**/*.mts"]),
|
||||
visibility = [
|
||||
"//adev/shared-docs/pipeline:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//adev:node_modules/@types/jsdom",
|
||||
"//adev:node_modules/@types/node",
|
||||
"//adev:node_modules/diff",
|
||||
"//adev:node_modules/emoji-regex",
|
||||
"//adev:node_modules/html-entities",
|
||||
"//adev:node_modules/jsdom",
|
||||
"//adev:node_modules/marked",
|
||||
"//adev:node_modules/mermaid",
|
||||
"//adev:node_modules/playwright-core",
|
||||
"//adev:node_modules/shiki",
|
||||
"//adev/shared-docs/pipeline/shared:linking",
|
||||
"//adev/shared-docs/pipeline/shared:shiki",
|
||||
"//adev/shared-docs/pipeline/shared/regions",
|
||||
],
|
||||
)
|
||||
+12
-3
@@ -7,8 +7,8 @@
|
||||
*/
|
||||
|
||||
import {Tokens, Token, RendererThis, TokenizerThis} from 'marked';
|
||||
import {anchorTarget} from '../../helpers.mjs';
|
||||
import {loadWorkspaceRelativeFile} from '../../utils.mjs';
|
||||
import {loadWorkspaceRelativeFile, anchorTarget} from '../../helpers.mjs';
|
||||
import {setInsideLink} from '../../transformations/link.mjs';
|
||||
|
||||
interface DocsCardToken extends Tokens.Generic {
|
||||
type: 'docs-card';
|
||||
@@ -73,7 +73,7 @@ function getStandardCard(renderer: RendererThis, token: DocsCardToken) {
|
||||
<a href="${token.href}" ${anchorTarget(token.href)} class="docs-card">
|
||||
<div>
|
||||
<h3>${token.title}</h3>
|
||||
${renderer.parser.parse(token.tokens)}
|
||||
${parseWithoutCreatingLinks(renderer, token)}
|
||||
</div>
|
||||
<span>${token.link ? token.link : 'Learn more'}</span>
|
||||
</a>
|
||||
@@ -90,6 +90,15 @@ function getStandardCard(renderer: RendererThis, token: DocsCardToken) {
|
||||
`;
|
||||
}
|
||||
|
||||
function parseWithoutCreatingLinks(renderer: RendererThis, token: DocsCardToken) {
|
||||
setInsideLink(true);
|
||||
try {
|
||||
return renderer.parser.parse(token.tokens);
|
||||
} finally {
|
||||
setInsideLink(false);
|
||||
}
|
||||
}
|
||||
|
||||
function getCardWithSvgIllustration(renderer: RendererThis, token: DocsCardToken) {
|
||||
// We can assume that all illustrations are svg files
|
||||
// We need to read svg content, instead of renering svg with `img`,
|
||||
+2
-1
@@ -8,6 +8,7 @@
|
||||
|
||||
import {TokenizerThis, RendererThis} from 'marked';
|
||||
import {CodeToken, formatCode} from './format/index.mjs';
|
||||
import {AdevDocsRenderer} from '../../renderer.mjs';
|
||||
|
||||
export interface DocsCodeBlock extends CodeToken {
|
||||
type: 'docs-code-block';
|
||||
@@ -48,6 +49,6 @@ export const docsCodeBlockExtension = {
|
||||
if (token.language === 'mermaid') {
|
||||
return token.code;
|
||||
}
|
||||
return formatCode(token);
|
||||
return formatCode(token, (this.parser.renderer as AdevDocsRenderer).context);
|
||||
},
|
||||
};
|
||||
+4
-3
@@ -8,8 +8,9 @@
|
||||
|
||||
import {TokenizerThis, RendererThis} from 'marked';
|
||||
import {CodeToken, formatCode} from './format/index.mjs';
|
||||
import {FileType, removeEslintComments} from './sanitizers/eslint.mjs';
|
||||
import {loadWorkspaceRelativeFile} from '../../utils.mjs';
|
||||
import {loadWorkspaceRelativeFile} from '../../helpers.mjs';
|
||||
import {AdevDocsRenderer} from '../../renderer.mjs';
|
||||
import {FileType, removeEslintComments} from '../../../regions/remove-eslint-comments.mjs';
|
||||
|
||||
/** Marked token for a custom docs element. */
|
||||
export interface DocsCodeToken extends CodeToken {
|
||||
@@ -82,6 +83,6 @@ export const docsCodeExtension = {
|
||||
return undefined;
|
||||
},
|
||||
renderer(this: RendererThis, token: DocsCodeToken) {
|
||||
return formatCode(token);
|
||||
return formatCode(token, (this.parser.renderer as AdevDocsRenderer).context);
|
||||
},
|
||||
};
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
|
||||
import {diffLines, Change as DiffChange} from 'diff';
|
||||
import {CodeToken} from './index.mjs';
|
||||
import {loadWorkspaceRelativeFile} from '../../../utils.mjs';
|
||||
import {loadWorkspaceRelativeFile} from '../../../helpers.mjs';
|
||||
|
||||
export interface DiffMetadata {
|
||||
code: string;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user