mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
Compare commits
288 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 18091e72cb | |||
| 4c1abc4fc1 | |||
| 0c86d3e1f3 | |||
| bea852fa15 | |||
| 914f540a43 | |||
| fbf0c8226e | |||
| f0ecbe62de | |||
| 118803035f | |||
| bae473d718 | |||
| 83d2a09922 | |||
| 03a14b5034 | |||
| 21106bf3cd | |||
| 08b9452f01 | |||
| beec8969ee | |||
| b386b1aa6f | |||
| fb1fa8b0fc | |||
| ea0bf74e31 | |||
| 70547ebce0 | |||
| b8a450bbed | |||
| 9a9d1bfcdc | |||
| b21f96dc0e | |||
| cb5ea19cde | |||
| fa84477f26 | |||
| 48b48c1eea | |||
| a41ac8329a | |||
| 307ed7dba9 | |||
| 84f45ea3ff | |||
| de0d5c768b | |||
| bafcf2c292 | |||
| 671fdce9c1 | |||
| 6bee546c4d | |||
| ea5d74bb34 | |||
| d69a4e1e15 | |||
| 78cf51b12a | |||
| 600bab4356 | |||
| d7dfd47232 | |||
| 9fdec75c08 | |||
| a20689dc88 | |||
| 46d173d60f | |||
| 26d75b0315 | |||
| 97625d22c0 | |||
| ffbe7635d1 | |||
| c30ae2d069 | |||
| a0ca7d1513 | |||
| b2eccad3d6 | |||
| d3491c7cee | |||
| 5ce10264a4 | |||
| a6d2d2dc10 | |||
| ab701f4a24 | |||
| 9796067515 | |||
| 836ed79c89 | |||
| fe1a771c9a | |||
| 99715104a1 | |||
| 6b057bcfdb | |||
| 52912f064b | |||
| 9a01c42214 | |||
| 818659c6ec | |||
| 8694f919ad | |||
| ab4f81044c | |||
| ec674c6a68 | |||
| a3be5b0f25 | |||
| 28254ca134 | |||
| 4b7f295e8d | |||
| b767b660b6 | |||
| 273ee7a290 | |||
| 7c9f42540b | |||
| 678f333956 | |||
| ac52ce8ae7 | |||
| d87f4830bb | |||
| d4f5c85f60 | |||
| baedea7b3f | |||
| 472dd58537 | |||
| 69c29639fa | |||
| f4e2777994 | |||
| 4970ebab57 | |||
| ca032a2289 | |||
| a983865bff | |||
| e6e7a4e22b | |||
| 502ee0e722 | |||
| 4dfe5b6cef | |||
| e4dc7f1361 | |||
| 154e6052d3 | |||
| bf8ee41877 | |||
| 5838f43774 | |||
| c4357ebcc1 | |||
| 7bd56fd296 | |||
| e7566c3c47 | |||
| b2802e573a | |||
| 02b258a2ed | |||
| f696ecb424 | |||
| c79dd4e722 | |||
| 88c253ff61 | |||
| 2c04430a3e | |||
| 2c05f4ce9c | |||
| 805d8f1ca1 | |||
| 392b9920a0 | |||
| 51df77583c | |||
| 497fe97ada | |||
| 1192c89671 | |||
| 36a5712b67 | |||
| df210a463b | |||
| e6514b9f3d | |||
| e33b19592f | |||
| 806a61b5a6 | |||
| e5d3abb298 | |||
| 80f56954ce | |||
| 2be161d015 | |||
| 91a616fca7 | |||
| c53e3ac300 | |||
| 21ccc2333a | |||
| 5b7e768226 | |||
| ee499473ef | |||
| 02555bf5ef | |||
| e7131231fe | |||
| fa1b021aad | |||
| 5fe57d4fbb | |||
| f503c15ea9 | |||
| 715caea46b | |||
| d892b4aa2b | |||
| 29001ea586 | |||
| 506413cf23 | |||
| acca96c3e1 | |||
| 5ffec9a3af | |||
| f8248b948d | |||
| 45537eb648 | |||
| 23530a47de | |||
| e1e2e3fb67 | |||
| 4abb64580f | |||
| 87dc5003a2 | |||
| e26797b38e | |||
| c570be385c | |||
| b84ed2b628 | |||
| cfecdd50e7 | |||
| 29207d84a3 | |||
| 7082688a14 | |||
| a5e7a02f9b | |||
| 26602fcaae | |||
| 560282aa9b | |||
| 51933ef5a6 | |||
| 71ee81af2c | |||
| d190f82147 | |||
| b59c218b2d | |||
| dc5d2b7c34 | |||
| 829aa5dade | |||
| a32eb1ccbe | |||
| c77b53be11 | |||
| b834d7f5ee | |||
| 549c0ad2bd | |||
| d92001acd4 | |||
| 1996794957 | |||
| 320560b254 | |||
| 9bbb01c85e | |||
| 7cff2b73d2 | |||
| 3df159f54a | |||
| 746ea40c37 | |||
| 64661dd0dd | |||
| b6a998b2fd | |||
| 10540b54f9 | |||
| a524f42635 | |||
| 923cc33c6d | |||
| 9395aae1f7 | |||
| c988b91759 | |||
| e1c7327064 | |||
| c53ad709b1 | |||
| d6749683ba | |||
| c5511dc458 | |||
| 1848d2719f | |||
| f8322bd7cb | |||
| 499b227e11 | |||
| 791ee323dc | |||
| 4bebc9d5e4 | |||
| a314878bb5 | |||
| 7c4e0766be | |||
| fda8f70e29 | |||
| c4a84920b2 | |||
| 671fafac95 | |||
| b62c4534b2 | |||
| 3c0b2441fd | |||
| 3aa02635db | |||
| ab701ad1a6 | |||
| 65a0a1d416 | |||
| 0ec9533a6f | |||
| 203aa0c124 | |||
| 4a0d9eb01e | |||
| 1ead8ba765 | |||
| 10e6a25643 | |||
| 5eb3db8686 | |||
| f994539f6b | |||
| 728bfbbb31 | |||
| 4a0dc3c712 | |||
| d4d76ead80 | |||
| e85ac5c7cb | |||
| 8ae84be3df | |||
| b0711d74c4 | |||
| 5c9e2e41e1 | |||
| 3db099c8e6 | |||
| 85fa27d92a | |||
| 5b5828e856 | |||
| e7ac965b29 | |||
| c36a1c023b | |||
| 90509f88fe | |||
| a32e897c5a | |||
| ba84a02a6b | |||
| 11f86a0a08 | |||
| 996593809c | |||
| e6b05c72ea | |||
| 6e0af6dbbb | |||
| 36f4457b69 | |||
| 61565eafee | |||
| 23b1316822 | |||
| c5e676bb87 | |||
| 86d8f6bda8 | |||
| 3f82c3f0eb | |||
| 5278f194e5 | |||
| efa7baa976 | |||
| f87a773278 | |||
| da1cd6fc59 | |||
| 257d5b9979 | |||
| 8a38b68561 | |||
| 3b130087e9 | |||
| 22cd6869ef | |||
| abd0da7265 | |||
| b25121ee4a | |||
| d7a7c80066 | |||
| f1aab73189 | |||
| 1a919034a1 | |||
| 44a7257303 | |||
| 600ef5eff2 | |||
| 0ca14e2c72 | |||
| 8d00d0fe85 | |||
| ea9bfff739 | |||
| bb6e0aab1b | |||
| b5b0b4af29 | |||
| ea086905c3 | |||
| ee1d06c8fa | |||
| dcd16b43f3 | |||
| 3230d78c54 | |||
| 616b411a6d | |||
| d504452e2f | |||
| ddef41e897 | |||
| 8709359a1f | |||
| dbe612f2cd | |||
| 3e50842593 | |||
| 3d918de05f | |||
| a899623b51 | |||
| 7cb6adcb50 | |||
| fd7716440b | |||
| 98f54cb134 | |||
| 23531f249e | |||
| c6a21cc7f9 | |||
| df14cb6f8e | |||
| f815d7b8c8 | |||
| 90c7ec39a0 | |||
| eafe9040a2 | |||
| 7a65cdd911 | |||
| 1806fcce82 | |||
| 598c397c85 | |||
| 98804fd4be | |||
| ad3fbe6d97 | |||
| 2de5314400 | |||
| c0d606195c | |||
| 1efc4bb9e6 | |||
| 2d3a689660 | |||
| cf7f8c7c03 | |||
| 7dfb127c03 | |||
| 93c3f7a931 | |||
| 395cb34599 | |||
| 00b79f8157 | |||
| 50e99b66e5 | |||
| 0b2f18ff25 | |||
| 77fa588025 | |||
| d7283bf740 | |||
| f34268161b | |||
| 9c4bcb16ca | |||
| 0730d9d748 | |||
| a49c35ec76 | |||
| 917e99db42 | |||
| da9c0c5044 | |||
| d5998daa3d | |||
| 486c5a9d7e | |||
| 28516fd852 | |||
| c79b62ced2 | |||
| c095679f92 | |||
| aadcfda224 | |||
| d9ac59c88f | |||
| 61a732d71e | |||
| a36b54d63e | |||
| f418b49547 |
+7
-7
@@ -8,32 +8,32 @@ dist
|
||||
|
||||
# All integration test node_modules folders
|
||||
integration/animations/node_modules
|
||||
integration/animations-async/node_modules
|
||||
integration/cli-elements-universal/node_modules
|
||||
integration/cli-hello-world/node_modules
|
||||
integration/cli-hello-world-ivy-i18n/node_modules
|
||||
integration/cli-hello-world-lazy/node_modules
|
||||
integration/cli-hello-world-mocha/node_modules
|
||||
integration/cli-signal-inputs/node_modules
|
||||
integration/platform-server-hydration/node_modules
|
||||
integration/defer/node_modules
|
||||
integration/dynamic-compiler/node_modules
|
||||
integration/forms/node_modules
|
||||
integration/injectable-def/node_modules
|
||||
integration/ivy-i18n/node_modules
|
||||
integration/ng-add-localize/node_modules
|
||||
integration/ng_elements/node_modules
|
||||
integration/ng_update/node_modules
|
||||
integration/ng_update_migrations/node_modules
|
||||
integration/ng-add-localize/node_modules
|
||||
integration/nodenext_resolution/node_modules
|
||||
integration/npm_package_archives.bzl/node_modules
|
||||
integration/platform-server/node_modules
|
||||
integration/platform-server-hydration/node_modules
|
||||
integration/service-worker-schema/node_modules
|
||||
integration/side-effects/node_modules
|
||||
integration/standalone-bootstrap/node_modules
|
||||
integration/terser/node_modules
|
||||
integration/trusted-types/node_modules
|
||||
integration/typings_test_rxjs7/node_modules
|
||||
integration/typings_test_ts49/node_modules
|
||||
integration/typings_test_ts50/node_modules
|
||||
integration/typings_test_ts51/node_modules
|
||||
integration/typings_test_ts52/node_modules
|
||||
integration/typings_test_ts55/node_modules
|
||||
integration/typings_test_ts56/node_modules
|
||||
integration/typings_test_ts57/node_modules
|
||||
modules/ssr-benchmarks/node_modules
|
||||
|
||||
@@ -78,12 +78,6 @@ query --output=label_kind
|
||||
# By default, failing tests don't print any output, it goes to the log file
|
||||
test --test_output=errors
|
||||
|
||||
################################
|
||||
# Settings for CircleCI #
|
||||
################################
|
||||
|
||||
# Bazel flags for CircleCI are in /.circleci/bazel.linux.rc and /.circleci/bazel.windows.rc
|
||||
|
||||
##################################
|
||||
# Remote Build Execution support #
|
||||
# Turn on these settings with #
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
# Encryption
|
||||
|
||||
Based on https://github.com/circleci/encrypted-files
|
||||
|
||||
In the CircleCI web UI, we have a secret variable called `KEY`
|
||||
https://circleci.com/gh/angular/angular/edit#env-vars
|
||||
which is only exposed to non-fork builds
|
||||
(see "Pass secrets to builds from forked pull requests" under
|
||||
https://circleci.com/gh/angular/angular/edit#advanced-settings)
|
||||
|
||||
We use this as a symmetric AES encryption key to encrypt tokens like
|
||||
a GitHub token that enables publishing snapshots.
|
||||
|
||||
To create the github_token file, we take this approach:
|
||||
- Find the angular-builds:token in the internal pw database
|
||||
- Go inside the CircleCI default docker image so you use the same version of openssl as we will at runtime: `docker run --rm -it circleci/node:10.12`
|
||||
- echo "https://[token]:@github.com" > credentials
|
||||
- openssl aes-256-cbc -e -in credentials -out .circleci/github_token -k $KEY
|
||||
- If needed, base64-encode the result so you can copy-paste it out of docker: `base64 github_token`
|
||||
@@ -1,16 +0,0 @@
|
||||
# Settings in this file should be OS agnostic. Use the bazel.<OS>.rc files for OS specific settings.
|
||||
|
||||
# Print all the options that apply to the build.
|
||||
# This helps us diagnose which options override others
|
||||
# (e.g. /etc/bazel.bazelrc vs. tools/bazel.rc)
|
||||
build --announce_rc
|
||||
|
||||
# Retry in the event of flakes, eg. https://circleci.com/gh/angular/angular/31309
|
||||
# By default this is set in the project `.bazelrc` to `1`.
|
||||
test --flaky_test_attempts=3
|
||||
|
||||
# More details on failures
|
||||
build --verbose_failures=true
|
||||
|
||||
# CI supports colors but Bazel does not detect it.
|
||||
common --color=yes
|
||||
@@ -1,23 +0,0 @@
|
||||
# These options are enabled when running on CI
|
||||
# We do this by copying this file to /etc/bazel.bazelrc at the start of the build.
|
||||
# See documentation in /docs/BAZEL.md
|
||||
|
||||
# Import config items common to both Linux and Windows setups.
|
||||
# https://docs.bazel.build/versions/master/guide.html#bazelrc-syntax-and-semantics
|
||||
try-import %workspace%/.circleci/bazel.common.rc
|
||||
|
||||
# Save downloaded repositories in a location that can be cached by CircleCI. This helps us
|
||||
# speeding up the analysis time significantly with Bazel managed node dependencies on the CI.
|
||||
build --repository_cache=/home/circleci/bazel_repository_cache
|
||||
|
||||
# Workaround https://github.com/bazelbuild/bazel/issues/3645
|
||||
# Bazel doesn't calculate the memory ceiling correctly when running under Docker.
|
||||
# Limit Bazel to consuming resources that fit in CircleCI "2xlarge+" class
|
||||
# https://circleci.com/docs/2.0/configuration-reference/#resource_class
|
||||
build --local_cpu_resources=20
|
||||
build --local_ram_resources=40960
|
||||
|
||||
# All build executed remotely should be done using our RBE configuration.
|
||||
build:remote --google_default_credentials
|
||||
|
||||
build --config=remote
|
||||
@@ -1,17 +0,0 @@
|
||||
# These options are enabled when running on CI
|
||||
# We do this by copying this file to $env:ProgramData\bazel.bazelrc at the start of the build.
|
||||
# See documentation in /docs/BAZEL.md
|
||||
|
||||
# Import config items common to both Linux and Windows setups.
|
||||
# https://docs.bazel.build/versions/master/guide.html#bazelrc-syntax-and-semantics
|
||||
try-import %workspace%/.circleci/bazel.common.rc
|
||||
|
||||
# Manually set the local resources used in windows CI runs
|
||||
build --local_ram_resources=120000
|
||||
build --local_cpu_resources=32
|
||||
|
||||
# All windows jobs run on master and should use http caching
|
||||
build --remote_http_cache=https://storage.googleapis.com/angular-team-cache
|
||||
build --remote_accept_cached=true
|
||||
build --remote_upload_local_results=true
|
||||
build --google_default_credentials
|
||||
@@ -1,16 +0,0 @@
|
||||
# This config is remaining in place to prevent pull requests failing because of CircleCI config missing.
|
||||
|
||||
version: 2.1
|
||||
|
||||
jobs:
|
||||
pass:
|
||||
docker:
|
||||
- image: cimg/base:2022.05
|
||||
steps:
|
||||
- run: echo "This too shall pass (always)"
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
default_workflow:
|
||||
jobs:
|
||||
- pass
|
||||
@@ -1,76 +0,0 @@
|
||||
####################################################################################################
|
||||
# Helpers for defining environment variables for CircleCI.
|
||||
#
|
||||
# In CircleCI, each step runs in a new shell. The way to share ENV variables across steps is to
|
||||
# export them from `$BASH_ENV`, which is automatically sourced at the beginning of every step (for
|
||||
# the default `bash` shell).
|
||||
#
|
||||
# See also https://circleci.com/docs/2.0/env-vars/#using-bash_env-to-set-environment-variables.
|
||||
####################################################################################################
|
||||
|
||||
# Set and print an environment variable.
|
||||
#
|
||||
# Use this function for setting environment variables that are public, i.e. it is OK for them to be
|
||||
# visible to anyone through the CI logs.
|
||||
#
|
||||
# Usage: `setPublicVar <name> <value>`
|
||||
function setPublicVar() {
|
||||
setSecretVar $1 "$2";
|
||||
echo "$1=$2";
|
||||
}
|
||||
|
||||
# Set (without printing) an environment variable.
|
||||
#
|
||||
# Use this function for setting environment variables that are secret, i.e. should not be visible to
|
||||
# everyone through the CI logs.
|
||||
#
|
||||
# Usage: `setSecretVar <name> <value>`
|
||||
function setSecretVar() {
|
||||
# WARNING: Secrets (e.g. passwords, access tokens) should NOT be printed.
|
||||
# (Keep original shell options to restore at the end.)
|
||||
local -r originalShellOptions=$(set +o);
|
||||
set +x -eu -o pipefail;
|
||||
|
||||
local assignmentStatement="export $1=\"${2:-}\";"
|
||||
|
||||
echo "${assignmentStatement}" >> $BASH_ENV;
|
||||
eval "${assignmentStatement}"
|
||||
|
||||
# Restore original shell options.
|
||||
eval "$originalShellOptions";
|
||||
}
|
||||
|
||||
|
||||
# Create a function to set an environment variable, when called.
|
||||
#
|
||||
# Use this function for creating setter for public environment variables that require expensive or
|
||||
# time-consuming computations and may not be needed. When needed, you can call this function to set
|
||||
# the environment variable (which will be available through `$BASH_ENV` from that point onwards).
|
||||
#
|
||||
# Arguments:
|
||||
# - `<name>`: The name of the environment variable. The generated setter function will be
|
||||
# `setPublicVar_<name>`.
|
||||
# - `<code>`: The code to run to compute the value for the variable. Since this code should be
|
||||
# executed lazily, it must be properly escaped. For example:
|
||||
# ```sh
|
||||
# # DO NOT do this:
|
||||
# createPublicVarSetter MY_VAR "$(whoami)"; # `whoami` will be evaluated eagerly
|
||||
#
|
||||
# # DO this isntead:
|
||||
# createPublicVarSetter MY_VAR "\$(whoami)"; # `whoami` will NOT be evaluated eagerly
|
||||
# ```
|
||||
#
|
||||
# Usage: `createPublicVarSetter <name> <code>`
|
||||
#
|
||||
# Example:
|
||||
# ```sh
|
||||
# createPublicVarSetter MY_VAR 'echo "FOO"';
|
||||
# echo $MY_VAR; # Not defined
|
||||
#
|
||||
# setPublicVar_MY_VAR;
|
||||
# source $BASH_ENV;
|
||||
# echo $MY_VAR; # FOO
|
||||
# ```
|
||||
function createPublicVarSetter() {
|
||||
echo "setPublicVar_$1() { setPublicVar $1 \"$2\"; }" >> $BASH_ENV;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
####################################################################################################
|
||||
# Set bazel configuration for CircleCI runs.
|
||||
####################################################################################################
|
||||
cp "${PROJECT_ROOT}/.circleci/bazel.linux.rc" ".bazelrc.user";
|
||||
@@ -1,88 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Variables
|
||||
readonly projectDir=$(realpath "$(dirname ${BASH_SOURCE[0]})/..")
|
||||
readonly envHelpersPath="$projectDir/.circleci/env-helpers.inc.sh";
|
||||
|
||||
# Load helpers and make them available everywhere (through `$BASH_ENV`).
|
||||
source $envHelpersPath;
|
||||
echo "source $envHelpersPath;" >> $BASH_ENV;
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# Define PUBLIC environment variables for CircleCI.
|
||||
####################################################################################################
|
||||
# See https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables for more info.
|
||||
####################################################################################################
|
||||
setPublicVar CI "$CI"
|
||||
setPublicVar PROJECT_ROOT "$projectDir";
|
||||
# This is the branch being built; e.g. `pull/12345` for PR builds.
|
||||
setPublicVar CI_BRANCH "$CIRCLE_BRANCH";
|
||||
setPublicVar CI_BUILD_URL "$CIRCLE_BUILD_URL";
|
||||
setPublicVar CI_COMMIT "$CIRCLE_SHA1";
|
||||
# `CI_COMMIT_RANGE` is only used on push builds (a.k.a. non-PR, non-scheduled builds and rerun
|
||||
# workflows of such builds).
|
||||
setPublicVar CI_GIT_BASE_REVISION "${CIRCLE_GIT_BASE_REVISION}";
|
||||
setPublicVar CI_GIT_REVISION "${CIRCLE_GIT_REVISION}";
|
||||
setPublicVar CI_COMMIT_RANGE "$CIRCLE_GIT_BASE_REVISION..$CIRCLE_GIT_REVISION";
|
||||
setPublicVar CI_PULL_REQUEST "${CIRCLE_PR_NUMBER:-false}";
|
||||
setPublicVar CI_REPO_NAME "$CIRCLE_PROJECT_REPONAME";
|
||||
setPublicVar CI_REPO_OWNER "$CIRCLE_PROJECT_USERNAME";
|
||||
setPublicVar CI_PR_REPONAME "$CIRCLE_PR_REPONAME";
|
||||
setPublicVar CI_PR_USERNAME "$CIRCLE_PR_USERNAME";
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# Define "lazy" PUBLIC environment variables for CircleCI.
|
||||
# (I.e. functions to set an environment variable when called.)
|
||||
####################################################################################################
|
||||
createPublicVarSetter CI_STABLE_BRANCH "\$(npm info @angular/core dist-tags.latest | sed -r 's/^\\s*([0-9]+\\.[0-9]+)\\.[0-9]+.*$/\\1.x/')";
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# Define SECRET environment variables for CircleCI.
|
||||
####################################################################################################
|
||||
setSecretVar CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN "$AIO_DEPLOY_TOKEN";
|
||||
setSecretVar CI_SECRET_PAYLOAD_FIREBASE_TOKEN "$ANGULAR_PAYLOAD_TOKEN";
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# Define SauceLabs environment variables for CircleCI.
|
||||
####################################################################################################
|
||||
setPublicVar SAUCE_USERNAME "angular-framework";
|
||||
setSecretVar SAUCE_ACCESS_KEY "f4bf7c639c5a-c6bb-d6a4-a4b5-800aa111";
|
||||
# TODO(josephperrott): Remove environment variables once all saucelabs tests are via bazel method.
|
||||
setPublicVar SAUCE_LOG_FILE /tmp/angular/sauce-connect.log
|
||||
setPublicVar SAUCE_READY_FILE /tmp/angular/sauce-connect-ready-file.lock
|
||||
setPublicVar SAUCE_PID_FILE /tmp/angular/sauce-connect-pid-file.lock
|
||||
setPublicVar SAUCE_TUNNEL_IDENTIFIER "angular-framework-${CIRCLE_BUILD_NUM}-${CIRCLE_NODE_INDEX}"
|
||||
# Amount of seconds we wait for sauceconnect to establish a tunnel instance. In order to not
|
||||
# acquire CircleCI instances for too long if sauceconnect failed, we need a connect timeout.
|
||||
setPublicVar SAUCE_READY_FILE_TIMEOUT 120
|
||||
|
||||
####################################################################################################
|
||||
# Create shell script in /tmp for Bazel actions to access CI envs without
|
||||
# busting the cache. Used by payload-size.sh script in integration tests.
|
||||
####################################################################################################
|
||||
readonly bazelVarEnv="/tmp/bazel-ci-env.sh"
|
||||
echo "# Setup by /.circle/env.sh" > $bazelVarEnv
|
||||
echo "export PROJECT_ROOT=\"${PROJECT_ROOT}\";" >> $bazelVarEnv
|
||||
echo "export CI_BRANCH=\"${CI_BRANCH}\";" >> $bazelVarEnv
|
||||
echo "export CI_BUILD_URL=\"${CI_BUILD_URL}\";" >> $bazelVarEnv
|
||||
echo "export CI_COMMIT=\"${CI_COMMIT}\";" >> $bazelVarEnv
|
||||
echo "export CI_PULL_REQUEST=\"${CI_PULL_REQUEST}\";" >> $bazelVarEnv
|
||||
echo "export CI_REPO_NAME=\"${CI_REPO_NAME}\";" >> $bazelVarEnv
|
||||
echo "export CI_REPO_OWNER=\"${CI_REPO_OWNER}\";" >> $bazelVarEnv
|
||||
echo "export CI_SECRET_PAYLOAD_FIREBASE_TOKEN=\"${CI_SECRET_PAYLOAD_FIREBASE_TOKEN}\";" >> $bazelVarEnv
|
||||
|
||||
####################################################################################################
|
||||
# Platform-specific environment setup (which can leverage the base variables from here)
|
||||
####################################################################################################
|
||||
|
||||
# Conditionally, load additional environment settings based on the current VM
|
||||
# operating system running. We detect Windows by checking for `%AppData%`.
|
||||
if [[ -n "${APPDATA}" ]]; then
|
||||
source ${projectDir}/.circleci/env.windows.sh
|
||||
else
|
||||
source ${projectDir}/.circleci/env.linux.sh
|
||||
fi
|
||||
@@ -1,13 +0,0 @@
|
||||
####################################################################################################
|
||||
# Set bazel configuration for CircleCI runs.
|
||||
####################################################################################################
|
||||
cp "${PROJECT_ROOT}/.circleci/bazel.windows.rc" ".bazelrc.user";
|
||||
|
||||
# Override the `PATH` environment variable so that the windows-nvm NodeJS version
|
||||
# always has precedence over potential existing NodeJS versions from the image.
|
||||
setPublicVar PATH "/c/Program Files/nodejs/:$PATH"
|
||||
|
||||
# Expose the Bazelisk version. We need to run Bazelisk globally since Windows has problems launching
|
||||
# Bazel from a node modules directoy that might be modified by the Bazel Yarn install then.
|
||||
setPublicVar BAZELISK_VERSION \
|
||||
"$(cd ${PROJECT_ROOT}; node -p 'require("./package.json").devDependencies["@bazel/bazelisk"]')"
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Install bazel remote cache proxy
|
||||
# This is temporary until the feature is no longer experimental on CircleCI.
|
||||
# See remote cache documentation in /docs/BAZEL.md
|
||||
|
||||
set -u -e
|
||||
|
||||
readonly DOWNLOAD_URL="https://5-116431813-gh.circle-artifacts.com/0/pkg/bazel-remote-proxy-$(uname -s)_$(uname -m)"
|
||||
|
||||
curl --fail -o ~/bazel-remote-proxy "$DOWNLOAD_URL"
|
||||
chmod +x ~/bazel-remote-proxy
|
||||
@@ -1,6 +1,5 @@
|
||||
# Image metadata and config.
|
||||
# Ideally, the Node.js version should match what we use on CI.
|
||||
# See `executors > default-executor` in `.circleci/config.yml`.
|
||||
FROM cimg/node:18.13.0@sha256:45d0ee279f522c4562a464df71108104cc9b2187205333ffd0707d4f05589731
|
||||
|
||||
|
||||
@@ -12,7 +11,7 @@ LABEL name="Angular dev environment" \
|
||||
EXPOSE 4000 4200 4433 5000 8080 9876
|
||||
|
||||
|
||||
# Switch to `root` (CircleCI images use `circleci` as the user).
|
||||
# Switch to `root`.
|
||||
USER root
|
||||
|
||||
|
||||
|
||||
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@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Saucelabs Variables
|
||||
uses: angular/dev-infra/github-actions/saucelabs@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/saucelabs@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- 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@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Build adev to ensure it continues to work
|
||||
run: yarn bazel build //adev:build --full_build_adev --config=release
|
||||
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
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@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
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@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
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@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: angular/dev-infra/github-actions/branch-manager@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
- uses: angular/dev-infra/github-actions/branch-manager@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
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@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
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:
|
||||
|
||||
- uses: ./.github/actions/yarn-install
|
||||
|
||||
- uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
- uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
bazelrc: ./.bazelrc.user
|
||||
|
||||
|
||||
+22
-24
@@ -21,7 +21,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Install node modules
|
||||
@@ -41,13 +41,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Run unit tests
|
||||
@@ -59,13 +59,13 @@ jobs:
|
||||
runs-on: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile --network-timeout 100000
|
||||
- name: Run CI tests for framework
|
||||
@@ -76,32 +76,30 @@ jobs:
|
||||
labels: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Build adev in fast mode to ensure it continues to work
|
||||
run: yarn bazel build //adev:build --config=release
|
||||
# TODO: re-enable tests once the next release is shipped
|
||||
# Tests are broken because of https://github.com/angular/angular/issues/54858
|
||||
# - name: Run tests
|
||||
# run: yarn bazel test //adev/...
|
||||
- name: Run tests
|
||||
run: yarn bazel test //adev/...
|
||||
|
||||
publish-snapshots:
|
||||
runs-on:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- run: echo "https://${{secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN}}:@github.com" > ${HOME}/.git_credentials
|
||||
@@ -113,7 +111,7 @@ jobs:
|
||||
labels: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
@@ -121,9 +119,9 @@ jobs:
|
||||
./packages/zone.js/node_modules
|
||||
./packages/zone.js/test/typings/node_modules
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- run: |
|
||||
@@ -160,7 +158,7 @@ jobs:
|
||||
SAUCE_TUNNEL_IDENTIFIER: angular-framework-${{ github.run_number }}
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Install node modules
|
||||
@@ -173,11 +171,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Install node modules
|
||||
run: yarn 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@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
- uses: angular/dev-infra/github-actions/commit-message-based-labels@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: angular/dev-infra/github-actions/commit-message-based-labels@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
post_approval_changes:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
- uses: angular/dev-infra/github-actions/post-approval-changes@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: angular/dev-infra/github-actions/post-approval-changes@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -13,8 +13,8 @@ jobs:
|
||||
statuses: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
- uses: angular/dev-infra/github-actions/google-internal-tests@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: angular/dev-infra/github-actions/google-internal-tests@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
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@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Saucelabs Variables
|
||||
uses: angular/dev-infra/github-actions/saucelabs@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/saucelabs@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Set up Sauce Tunnel Daemon
|
||||
run: yarn 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@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
- uses: angular/dev-infra/github-actions/unified-status-check@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
name: Performance Tracking
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: 'read'
|
||||
id-token: 'write'
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
list:
|
||||
timeout-minutes: 3
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
workflows: ${{ steps.workflows.outputs.workflows }}
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Install node modules
|
||||
run: yarn -s install --frozen-lockfile
|
||||
- id: workflows
|
||||
run: echo "workflows=$(yarn -s ng-dev perf workflows --list)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
workflow:
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest
|
||||
needs: list
|
||||
strategy:
|
||||
matrix:
|
||||
workflow: ${{ fromJSON(needs.list.outputs.workflows) }}
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Install node modules
|
||||
run: yarn -s install --frozen-lockfile
|
||||
# We utilize the google-github-actions/auth action to allow us to get an active credential using workflow
|
||||
# identity federation. This allows us to request short lived credentials on demand, rather than storing
|
||||
# credentials in secrets long term. More information can be found at:
|
||||
# https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/configuring-openid-connect-in-google-cloud-platform
|
||||
- uses: 'google-github-actions/auth@6fc4af4b145ae7821d527454aa9bd537d1f2dc5f' # v2
|
||||
with:
|
||||
project_id: 'internal-200822'
|
||||
workload_identity_provider: 'projects/823469418460/locations/global/workloadIdentityPools/measurables-tracking/providers/angular'
|
||||
service_account: 'measures-uploader@internal-200822.iam.gserviceaccount.com'
|
||||
- run: yarn ng-dev perf workflows --name ${{ matrix.workflow }} --commit-sha ${{github.sha}}
|
||||
+21
-23
@@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Install node modules
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
- name: Check code format
|
||||
run: yarn ng-dev format changed --check ${{ github.event.pull_request.base.sha }}
|
||||
- name: Check Package Licenses
|
||||
uses: angular/dev-infra/github-actions/linting/licenses@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/linting/licenses@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
allow-dependencies-licenses: 'pkg:npm/google-protobuf@'
|
||||
|
||||
@@ -47,13 +47,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Run unit tests
|
||||
@@ -65,13 +65,13 @@ jobs:
|
||||
runs-on: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile --network-timeout 100000
|
||||
- name: Run CI tests for framework
|
||||
@@ -83,19 +83,19 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile --network-timeout 100000
|
||||
- name: Run CI tests for framework
|
||||
run: yarn tsx ./scripts/build/build-packages-dist.mts
|
||||
- name: Archive build artifacts
|
||||
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
with:
|
||||
name: pr-artifacts-${{ github.event.number }}
|
||||
path: dist/packages-dist/
|
||||
@@ -105,26 +105,24 @@ jobs:
|
||||
labels: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Build adev in fast mode to ensure it continues to work
|
||||
run: yarn bazel build //adev:build --config=release
|
||||
# TODO: re-enable tests once the next release is shipped
|
||||
# Tests are broken because of https://github.com/angular/angular/issues/54858
|
||||
# - name: Run tests
|
||||
# run: yarn bazel test //adev/...
|
||||
- name: Run tests
|
||||
run: yarn bazel test //adev/...
|
||||
|
||||
zone-js:
|
||||
runs-on:
|
||||
labels: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
@@ -132,9 +130,9 @@ jobs:
|
||||
./packages/zone.js/node_modules
|
||||
./packages/zone.js/test/typings/node_modules
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- run: |
|
||||
@@ -171,7 +169,7 @@ jobs:
|
||||
SAUCE_TUNNEL_IDENTIFIER: angular-framework-${{ github.run_number }}
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Install node modules
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 'Checkout code'
|
||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
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@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13
|
||||
uses: github/codeql-action/upload-sarif@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
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
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
env:
|
||||
ANGULAR_CLI_BUILDS_READONLY_GITHUB_TOKEN: ${{ secrets.ANGULAR_CLI_BUILDS_READONLY_GITHUB_TOKEN }}
|
||||
- name: Create a PR (if necessary)
|
||||
uses: angular/dev-infra/github-actions/create-pr-for-changes@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
|
||||
uses: angular/dev-infra/github-actions/create-pr-for-changes@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
branch-prefix: update-cli-help
|
||||
pr-title: 'docs: update Angular CLI help [${{github.ref_name}}]'
|
||||
|
||||
+2
-10
@@ -4,11 +4,8 @@
|
||||
/bazel-out
|
||||
/integration/bazel/bazel-*
|
||||
*.log
|
||||
/node_modules/
|
||||
|
||||
# CircleCI temporary file for cache key computation.
|
||||
# See `save_month_to_file` in `.circleci/config.yml`.
|
||||
month.txt
|
||||
node_modules/
|
||||
modules/ssr-benchmarks/node_modules/
|
||||
|
||||
# Include when developing application packages.
|
||||
pubspec.lock
|
||||
@@ -57,10 +54,5 @@ baseline.json
|
||||
# Husky
|
||||
.husky/_
|
||||
|
||||
|
||||
# Ignore cache created with the Angular CLI.
|
||||
.angular/
|
||||
|
||||
# Ignore AIO files, useful when changing branches
|
||||
aio/node_modules
|
||||
aio/out-tsc
|
||||
@@ -0,0 +1,7 @@
|
||||
workflows:
|
||||
build-adev:
|
||||
name: Build adev
|
||||
prepare:
|
||||
- bazel clean
|
||||
workflow:
|
||||
- bazel build //adev:build
|
||||
@@ -8,6 +8,7 @@ export const format: FormatConfig = {
|
||||
'matchers': [
|
||||
'**/*.{yaml,yml}',
|
||||
'**/*.{js,ts}',
|
||||
'devtools/**/*.{js,ts,html,scss}',
|
||||
|
||||
// Do not format d.ts files as they are generated
|
||||
'!**/*.d.ts',
|
||||
|
||||
@@ -3,15 +3,7 @@
|
||||
"separateFilePatterns": ["packages/core/primitives/**"],
|
||||
"alwaysExternalFilePatterns": [
|
||||
"packages/*",
|
||||
"packages/bazel/*",
|
||||
"packages/bazel/src/*",
|
||||
"packages/bazel/src/api-extractor/**",
|
||||
"packages/bazel/src/builders/**",
|
||||
"packages/bazel/src/ng_module/**",
|
||||
"packages/bazel/src/ng_package/**",
|
||||
"packages/bazel/src/protractor/**",
|
||||
"packages/bazel/src/schematics/**",
|
||||
"packages/bazel/src/types_bundle/**",
|
||||
"packages/bazel/**",
|
||||
"packages/compiler-cli/linker/**",
|
||||
"packages/compiler-cli/src/ngtsc/sourcemaps/**",
|
||||
"packages/compiler-cli/src/ngtsc/testing/**",
|
||||
@@ -27,6 +19,7 @@
|
||||
"packages/localize/**",
|
||||
"packages/private/**",
|
||||
"packages/service-worker/**",
|
||||
"packages/ssr/BUILD.bazel",
|
||||
"packages/common/locales/generate-locales-tool/**",
|
||||
"packages/common/locales/index.bzl",
|
||||
"packages/http/**",
|
||||
|
||||
+2
-1
@@ -6,5 +6,6 @@
|
||||
"singleQuote": true,
|
||||
"semi": true,
|
||||
"quoteProps": "preserve",
|
||||
"bracketSpacing": false
|
||||
"bracketSpacing": false,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
|
||||
+3
-1
@@ -300,6 +300,7 @@ groups:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'packages/platform-server/**/{*,.*}',
|
||||
'packages/ssr/**/{*,.*}',
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
@@ -633,7 +634,6 @@ groups:
|
||||
- >
|
||||
contains_any_globs(files.exclude('.pullapprove.yml'), [
|
||||
'{*,.*}',
|
||||
'.circleci/**/{*,.*}',
|
||||
'.devcontainer/**/{*,.*}',
|
||||
'.github/**/{*,.*}',
|
||||
'.husky/**/{*,.*}',
|
||||
@@ -684,6 +684,8 @@ groups:
|
||||
conditions:
|
||||
- author in ["angular-robot"]
|
||||
reviewers:
|
||||
users:
|
||||
- ~alan-agius4
|
||||
teams:
|
||||
- framework-team
|
||||
|
||||
|
||||
+1430
-910
File diff suppressed because it is too large
Load Diff
@@ -2,4 +2,4 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
yarn-path ".yarn/releases/yarn-1.22.19.cjs"
|
||||
yarn-path ".yarn/releases/yarn-1.22.22.cjs"
|
||||
|
||||
+2
-2
@@ -64,8 +64,8 @@ config_setting(
|
||||
|
||||
nodejs_binary(
|
||||
name = "yarn_vendored",
|
||||
data = [".yarn/releases/yarn-1.22.19.cjs"],
|
||||
entry_point = ".yarn/releases/yarn-1.22.19.cjs",
|
||||
data = [".yarn/releases/yarn-1.22.22.cjs"],
|
||||
entry_point = ".yarn/releases/yarn-1.22.22.cjs",
|
||||
visibility = [
|
||||
"//integration:__subpackages__",
|
||||
"//modules/ssr-benchmarks:__subpackages__",
|
||||
|
||||
+208
-339
@@ -1,76 +1,221 @@
|
||||
<a name="18.2.9"></a>
|
||||
# 18.2.9 (2024-10-23)
|
||||
<a name="19.0.1"></a>
|
||||
# 19.0.1 (2024-11-26)
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [b0ab653965](https://github.com/angular/angular/commit/b0ab653965cf88fcfde23fc6a6cc78ce3121a30f) | fix | report when NgModule imports or exports itself ([#58231](https://github.com/angular/angular/pull/58231)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="19.0.0-next.10"></a>
|
||||
# 19.0.0-next.10 (2024-10-16)
|
||||
## Breaking Changes
|
||||
### core
|
||||
- Angular directives, components and pipes are now standalone by default. Specify `standalone: false` for declarations that are currently declared in `@NgModule`s. `ng update` for v19 will take care of this automatically.
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [0c9d721ac1](https://github.com/angular/angular/commit/0c9d721ac157662b2602cf0278ba4b79325f6882) | feat | add support for the `typeof` keyword in template expressions. ([#58183](https://github.com/angular/angular/pull/58183)) |
|
||||
| [a3cb530d84](https://github.com/angular/angular/commit/a3cb530d846bf4d15802b9f42b6dee5c9a3a08ee) | fix | handle typeof expressions in serializer ([#58217](https://github.com/angular/angular/pull/58217)) |
|
||||
| [ba4340875a](https://github.com/angular/angular/commit/ba4340875ac8e338ff1390fc7897eecc704ef7c5) | fix | ignore placeholder-only i18n messages ([#58154](https://github.com/angular/angular/pull/58154)) |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [231e6ff6ca](https://github.com/angular/angular/commit/231e6ff6ca0dae0289a03615bcaed29455c2d4b8) | feat | generate the HMR replacement module ([#58205](https://github.com/angular/angular/pull/58205)) |
|
||||
| [fb44323c51](https://github.com/angular/angular/commit/fb44323c51da5a86853aafd8a70ce0c25d6c0d7f) | fix | incorrectly generating relative file paths on case-insensitive platforms ([#58150](https://github.com/angular/angular/pull/58150)) |
|
||||
| [fb1fa8b0fc](https://github.com/angular/angular/commit/fb1fa8b0fc04c9cfac6551ca27bee89dcd7c72ac) | fix | more accurate diagnostics for host binding parser errors ([#58870](https://github.com/angular/angular/pull/58870)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [6b8c494d05](https://github.com/angular/angular/commit/6b8c494d05e545830fffb9626153480af6339ddc) | feat | flipping the default value for `standalone` to `true` ([#58169](https://github.com/angular/angular/pull/58169)) |
|
||||
| [3f1e7ab6ae](https://github.com/angular/angular/commit/3f1e7ab6ae984149004c449c04301b434ea64d2a) | feat | promote `outputFromObservable` & `outputToObservable` to stable. ([#58214](https://github.com/angular/angular/pull/58214)) |
|
||||
| [97c44a1d6c](https://github.com/angular/angular/commit/97c44a1d6c41be250d585fba5af2bc2af4d98ae2) | feat | Promote `takeUntilDestroyed` to stable. ([#58200](https://github.com/angular/angular/pull/58200)) |
|
||||
| [819ff034ce](https://github.com/angular/angular/commit/819ff034ce7cf014cedef60510b83af9340efa71) | feat | treat directives, pipes, components as by default ([#58229](https://github.com/angular/angular/pull/58229)) |
|
||||
| [502ee0e722](https://github.com/angular/angular/commit/502ee0e7221a9e7cfa0fa3bd92298d3b650a7713) | fix | correctly clear template HMR internal renderer cache ([#58724](https://github.com/angular/angular/pull/58724)) |
|
||||
| [99715104a1](https://github.com/angular/angular/commit/99715104a1a787c3899dfbfac6b44f28c7d24356) | fix | correctly perform lazy routes migration for components with additional decorators ([#58796](https://github.com/angular/angular/pull/58796)) |
|
||||
| [118803035f](https://github.com/angular/angular/commit/118803035f366acdffc577ec857b888f764bb338) | fix | Ensure _tick is always run within the TracingSnapshot. ([#58881](https://github.com/angular/angular/pull/58881)) |
|
||||
| [08b9452f01](https://github.com/angular/angular/commit/08b9452f012b2ef660f767c2f0a4bf86bb15bb61) | fix | Ensure resource sets an error ([#58855](https://github.com/angular/angular/pull/58855)) |
|
||||
| [84f45ea3ff](https://github.com/angular/angular/commit/84f45ea3ffe02003350c6c19fdafdc6f4d521ccb) | fix | make component id generation more stable between client and server builds ([#58813](https://github.com/angular/angular/pull/58813)) |
|
||||
| [d3491c7cee](https://github.com/angular/angular/commit/d3491c7cee3d110da1adb51f8047b4e1976ece71) | fix | Prevents race condition of cleanup for incremental hydration ([#58722](https://github.com/angular/angular/pull/58722)) |
|
||||
### forms
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [4dfe5b6cef](https://github.com/angular/angular/commit/4dfe5b6cefd7901a466b37b660f8b3a051a06cb3) | fix | work around TypeScript 5.7 issue ([#58731](https://github.com/angular/angular/pull/58731)) |
|
||||
### language-service
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [a983865bff](https://github.com/angular/angular/commit/a983865bffa828a982ef7e56204924d9c2989ead) | fix | add fix for individual unused imports ([#58719](https://github.com/angular/angular/pull/58719)) |
|
||||
| [e6e7a4e22b](https://github.com/angular/angular/commit/e6e7a4e22b0a654808e5eb88a30cd6effa383332) | fix | allow fixes to run without template info ([#58719](https://github.com/angular/angular/pull/58719)) |
|
||||
### migrations
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [5ce10264a4](https://github.com/angular/angular/commit/5ce10264a434ffc8e31cdc68208d2c3c7f8378ed) | fix | fix provide-initializer migration when using useFactory ([#58518](https://github.com/angular/angular/pull/58518)) |
|
||||
| [d4f5c85f60](https://github.com/angular/angular/commit/d4f5c85f60133550303d59b3f9e3e34f14ca63ce) | fix | handle parameters with initializers in inject migration ([#58769](https://github.com/angular/angular/pull/58769)) |
|
||||
| [a6d2d2dc10](https://github.com/angular/angular/commit/a6d2d2dc104608f14c3850b21bc23ba75ca04e4d) | fix | Mark hoisted properties as removed in inject migration ([#58804](https://github.com/angular/angular/pull/58804)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="19.0.0-next.9"></a>
|
||||
# 19.0.0-next.9 (2024-10-10)
|
||||
<a name="19.0.0"></a>
|
||||
# 19.0.0 (2024-11-19)
|
||||
|
||||
Blog post: https://blog.angular.dev/meet-angular-v19-7b29dfd05b84
|
||||
|
||||
## Breaking Changes
|
||||
### compiler
|
||||
- `this.foo` property reads no longer refer to template context variables. If you intended to read the template variable, do not use `this.`.
|
||||
### core
|
||||
- Angular directives, components and pipes are now standalone by default.
|
||||
* Specify `standalone: false` for declarations that are currently declared in modules.
|
||||
* `ng update` for v19 will take care of this automatically.
|
||||
- TypeScript versions less than 5.5 are no longer supported.
|
||||
- Timing changes for `effect` API (in developer preview):
|
||||
|
||||
* effects which are triggered outside of change detection run as part of
|
||||
the change detection process instead of as a microtask. Depending on the
|
||||
specifics of application/test setup, this can result in them executing
|
||||
earlier or later (or requiring additional test steps to trigger; see below
|
||||
examples).
|
||||
|
||||
* effects which are triggered during change detection (e.g. by input
|
||||
signals) run _earlier_, before the component's template.
|
||||
|
||||
- `ExperimentalPendingTasks` has been renamed to `PendingTasks`.
|
||||
- The `autoDetect` feature of `ComponentFixture` will now
|
||||
attach the fixture to the `ApplicationRef`. As a result, errors during
|
||||
automatic change detection of the fixture be reported to the `ErrorHandler`.
|
||||
This change may cause custom error handlers to observe new failures that were previously unreported.
|
||||
- `createComponent` will now render default fallback with empty `projectableNodes`.
|
||||
|
||||
* When passing an empty array to `projectableNodes` in the `createComponent` API, the default fallback content
|
||||
of the `ng-content` will be rendered if present. To prevent rendering the default content, pass `document.createTextNode('')` as a `projectableNode`.
|
||||
|
||||
```ts
|
||||
// The first ng-content will render the default fallback content if present
|
||||
createComponent(MyComponent. { projectableNodes: [[], [secondNode]] });
|
||||
|
||||
// To prevent projecting the default fallback content:
|
||||
createComponent(MyComponent. { projectableNodes: [[document.createTextNode('')], [secondNode]] });
|
||||
|
||||
```
|
||||
- Errors that are thrown during `ApplicationRef.tick`
|
||||
will now be rethrown when using `TestBed`. These errors should be
|
||||
resolved by ensuring the test environment is set up correctly to
|
||||
complete change detection successfully. There are two alternatives to
|
||||
catch the errors:
|
||||
|
||||
* Instead of waiting for automatic change detection to happen, trigger
|
||||
it synchronously and expect the error. For example, a jasmine test
|
||||
could write `expect(() => TestBed.inject(ApplicationRef).tick()).toThrow()`
|
||||
* `TestBed` will reject any outstanding `ComponentFixture.whenStable` promises. A jasmine test,
|
||||
for example, could write `expectAsync(fixture.whenStable()).toBeRejected()`.
|
||||
|
||||
As a last resort, you can configure errors to _not_ be rethrown by
|
||||
setting `rethrowApplicationErrors` to `false` in `TestBed.configureTestingModule`.
|
||||
- The timers that are used for zone coalescing and hybrid
|
||||
mode scheduling (which schedules an application state synchronization
|
||||
when changes happen outside the Angular zone) will now run in the zone
|
||||
above Angular rather than the root zone. This will mostly affect tests
|
||||
which use `fakeAsync`: these timers will now be visible to `fakeAsync`
|
||||
and can be affected by `tick` or `flush`.
|
||||
- The deprecated `factories` property in `KeyValueDiffers` has been removed.
|
||||
### elements
|
||||
- as part of switching away from custom CD behavior to the
|
||||
hybrid scheduler, timing of change detection around custom elements has
|
||||
changed subtly. These changes make elements more efficient, but can cause
|
||||
tests which encoded assumptions about how or when elements would be checked
|
||||
to require updating.
|
||||
### localize
|
||||
- The `name` option in the `ng add @localize` schematic has been removed in favor of the `project` option.
|
||||
- The `name` option in the `ng add `@localize`` schematic has been removed in favor of the `project` option.
|
||||
### platform-browser
|
||||
- The deprecated `BrowserModule.withServerTransition` method has been removed. Please use the `APP_ID` DI token to set the application id instead.
|
||||
### router
|
||||
- The `Router.errorHandler` property has been removed.
|
||||
Adding an error handler should be configured in either
|
||||
`withNavigationErrorHandler` with `provideRouter` or the `errorHandler`
|
||||
property in the extra options of `RouterModule.forRoot`. In addition,
|
||||
the error handler cannot be used to change the return value of the
|
||||
router navigation promise or prevent it from rejecting. Instead, if you
|
||||
want to prevent the promise from rejecting, use `resolveNavigationPromiseOnError`.
|
||||
- The return type of the `Resolve` interface now includes
|
||||
`RedirectCommand`.
|
||||
### common
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [24c6373820](https://github.com/angular/angular/commit/24c6373820231faf9d012a2e4d7ea945d3e8513b) | feat | add optional rounded transform support in cloudinary image loader ([#55364](https://github.com/angular/angular/pull/55364)) |
|
||||
| [50f08e6c4b](https://github.com/angular/angular/commit/50f08e6c4bf1caeeb08d3505ce7fabd466b9c76b) | feat | automatically use sizes auto in NgOptimizedImage ([#57479](https://github.com/angular/angular/pull/57479)) |
|
||||
| [13c13067bc](https://github.com/angular/angular/commit/13c13067bc3ed50cb80b0a86e62655448adb3051) | feat | disable keyvalue sorting using null compareFn ([#57487](https://github.com/angular/angular/pull/57487)) |
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [a2e4ee0cb3](https://github.com/angular/angular/commit/a2e4ee0cb3d40cadc05e28d58b06853973944456) | feat | add diagnostic for unused standalone imports ([#57605](https://github.com/angular/angular/pull/57605)) |
|
||||
| [0c9d721ac1](https://github.com/angular/angular/commit/0c9d721ac157662b2602cf0278ba4b79325f6882) | feat | add support for the `typeof` keyword in template expressions. ([#58183](https://github.com/angular/angular/pull/58183)) |
|
||||
| [09f589f000](https://github.com/angular/angular/commit/09f589f0006f4b428b675b83c12c0dc8ebb7e45f) | fix | `this.a` should always refer to class property `a` ([#55183](https://github.com/angular/angular/pull/55183)) |
|
||||
| [e8d1944999](https://github.com/angular/angular/commit/e8d1944999e1fdfbd67630d475334c0d7f41a0eb) | fix | add multiple :host and nested selectors support ([#57796](https://github.com/angular/angular/pull/57796)) |
|
||||
| [82144b6d63](https://github.com/angular/angular/commit/82144b6d63d072d112d1a7f4dcc018a1d64bb994) | fix | allow combinators inside pseudo selectors ([#57796](https://github.com/angular/angular/pull/57796)) |
|
||||
| [292ea4714f](https://github.com/angular/angular/commit/292ea4714fb7e76cf1748d2f9059991e05c42574) | fix | fix comment typo ([#57796](https://github.com/angular/angular/pull/57796)) |
|
||||
| [69529d8873](https://github.com/angular/angular/commit/69529d8873fbd7888ab68fddc6e7c654c5065764) | fix | fix parsing of the :host-context with pseudo selectors ([#57796](https://github.com/angular/angular/pull/57796)) |
|
||||
| [2374b87b64](https://github.com/angular/angular/commit/2374b87b643e0373f85cf126d4b01b2fff785f64) | fix | preserve attributes attached to :host selector ([#57796](https://github.com/angular/angular/pull/57796)) |
|
||||
| [46a6324c82](https://github.com/angular/angular/commit/46a6324c82a41b69c16a4c8c9f3fc52d1ecf6917) | fix | scope :host-context inside pseudo selectors, do not decrease specificity ([#57796](https://github.com/angular/angular/pull/57796)) |
|
||||
| [bc5f1175e9](https://github.com/angular/angular/commit/bc5f1175e9f39dfa2699c4de19ee9af4ce4b50d1) | fix | transform pseudo selectors correctly for the encapsulated view ([#57796](https://github.com/angular/angular/pull/57796)) |
|
||||
| [98804fd4be](https://github.com/angular/angular/commit/98804fd4beb6292f5a50ce728424fdb33c47f654) | fix | add more specific matcher for hydrate never block ([#58360](https://github.com/angular/angular/pull/58360)) |
|
||||
| [b25121ee4a](https://github.com/angular/angular/commit/b25121ee4aba427954fef074a967b9332654be84) | fix | avoid having to duplicate core environment ([#58444](https://github.com/angular/angular/pull/58444)) |
|
||||
| [560282aa9b](https://github.com/angular/angular/commit/560282aa9b3204ad8311017905beed63072c7303) | fix | control flow nodes with root at the end projected incorrectly ([#58607](https://github.com/angular/angular/pull/58607)) |
|
||||
| [2be161d015](https://github.com/angular/angular/commit/2be161d015ce6bab0142b6e6c34a8ede6341f627) | fix | fix `:host` parsing in pseudo-selectors ([#58681](https://github.com/angular/angular/pull/58681)) |
|
||||
| [806a61b5a6](https://github.com/angular/angular/commit/806a61b5a619d98c0226ba6a566b1562f6e16e5a) | fix | fix multiline selectors ([#58681](https://github.com/angular/angular/pull/58681)) |
|
||||
| [a3cb530d84](https://github.com/angular/angular/commit/a3cb530d846bf4d15802b9f42b6dee5c9a3a08ee) | fix | handle typeof expressions in serializer ([#58217](https://github.com/angular/angular/pull/58217)) |
|
||||
| [ba4340875a](https://github.com/angular/angular/commit/ba4340875ac8e338ff1390fc7897eecc704ef7c5) | fix | ignore placeholder-only i18n messages ([#58154](https://github.com/angular/angular/pull/58154)) |
|
||||
| [e5d3abb298](https://github.com/angular/angular/commit/e5d3abb29842412f82a67562aceff245d493ec53) | fix | resolve `:host:host-context(.foo)` ([#58681](https://github.com/angular/angular/pull/58681)) |
|
||||
| [80f56954ce](https://github.com/angular/angular/commit/80f56954cecf763e36bdcfbbd592a82d693eeef7) | fix | transform chained pseudo-selectors ([#58681](https://github.com/angular/angular/pull/58681)) |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [8d8c03abc4](https://github.com/angular/angular/commit/8d8c03abc40099da268d7301f029954f3e3f1c90) | fix | defer symbols only used in types ([#58104](https://github.com/angular/angular/pull/58104)) |
|
||||
| [d9687f43dd](https://github.com/angular/angular/commit/d9687f43dd2ccfcf7dd3ee4f9066ce727f3224c6) | feat | 'strictStandalone' flag enforces standalone ([#57935](https://github.com/angular/angular/pull/57935)) |
|
||||
| [9e87593055](https://github.com/angular/angular/commit/9e87593055a5314a67090bd15d5552c23b538050) | feat | ensure template style elements are preprocessed as inline styles ([#57429](https://github.com/angular/angular/pull/57429)) |
|
||||
| [231e6ff6ca](https://github.com/angular/angular/commit/231e6ff6ca0dae0289a03615bcaed29455c2d4b8) | feat | generate the HMR replacement module ([#58205](https://github.com/angular/angular/pull/58205)) |
|
||||
| [dbe612f2cd](https://github.com/angular/angular/commit/dbe612f2cd59adecdab3abb270b014c4b26e472c) | fix | disable standalone by default on older versions of Angular ([#58405](https://github.com/angular/angular/pull/58405)) |
|
||||
| [d4d76ead80](https://github.com/angular/angular/commit/d4d76ead802837bc6cc7908bc9ebfefa73eb9969) | fix | do not fail fatal when references to non-existent module are discovered ([#58515](https://github.com/angular/angular/pull/58515)) |
|
||||
| [33fe252c58](https://github.com/angular/angular/commit/33fe252c588ee94d6ef99e8070d35c483ec24fda) | fix | do not report unused declarations coming from an imported array ([#57940](https://github.com/angular/angular/pull/57940)) |
|
||||
| [fb44323c51](https://github.com/angular/angular/commit/fb44323c51da5a86853aafd8a70ce0c25d6c0d7f) | fix | incorrectly generating relative file paths on case-insensitive platforms ([#58150](https://github.com/angular/angular/pull/58150)) |
|
||||
| [22cd6869ef](https://github.com/angular/angular/commit/22cd6869ef453c342b206f84e857ef6c34922fa5) | fix | make the unused imports diagnostic easier to read ([#58468](https://github.com/angular/angular/pull/58468)) |
|
||||
| [9bbb01c85e](https://github.com/angular/angular/commit/9bbb01c85e763b0457456a2393a834db15008671) | fix | report individual diagnostics for unused imports ([#58589](https://github.com/angular/angular/pull/58589)) |
|
||||
| [4716c3b966](https://github.com/angular/angular/commit/4716c3b9660b01f4ef3642fb774270b7f4a13d1a) | perf | reduce duplicate component style resolution ([#57502](https://github.com/angular/angular/pull/57502)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [6ea8e1e9aa](https://github.com/angular/angular/commit/6ea8e1e9aae028572873cf97aa1949c8153f458f) | feat | Add a schematics to migrate to `standalone: false`. ([#57643](https://github.com/angular/angular/pull/57643)) |
|
||||
| [3ebe6b4ad4](https://github.com/angular/angular/commit/3ebe6b4ad401337e18619edc34477ae98226fa3e) | feat | Add async `run` method on `ExperimentalPendingTasks` ([#56546](https://github.com/angular/angular/pull/56546)) |
|
||||
| [69fc5ae922](https://github.com/angular/angular/commit/69fc5ae9229b872a9ad70eb920087af2a378fead) | feat | Add incremental hydration public api ([#58249](https://github.com/angular/angular/pull/58249)) |
|
||||
| [8ebbae88ca](https://github.com/angular/angular/commit/8ebbae88ca48b8aa78cd85deedbed19d44b8227e) | feat | Add rxjs operator prevent app stability until an event ([#56533](https://github.com/angular/angular/pull/56533)) |
|
||||
| [19edf2c057](https://github.com/angular/angular/commit/19edf2c057f7587bc16812685d31a556521ad414) | feat | add syntactic sugar for initializers ([#53152](https://github.com/angular/angular/pull/53152)) |
|
||||
| [c93b510f9b](https://github.com/angular/angular/commit/c93b510f9b2e23aa7a3848a04c05249fde14a9b1) | feat | allow passing `undefined` without needing to include it in the type argument of `input` ([#57621](https://github.com/angular/angular/pull/57621)) |
|
||||
| [ab25a192ba](https://github.com/angular/angular/commit/ab25a192ba664863ad68d224b9b2df78da22769a) | feat | allow running output migration on a subset of paths ([#58299](https://github.com/angular/angular/pull/58299)) |
|
||||
| [fc59e2a7b7](https://github.com/angular/angular/commit/fc59e2a7b7afa491a5ea740284a742574805eb36) | feat | change effect() execution timing & no-op `allowSignalWrites` ([#57874](https://github.com/angular/angular/pull/57874)) |
|
||||
| [8bcc663a53](https://github.com/angular/angular/commit/8bcc663a53888717cdf4ce0c23404caa00abb1b2) | feat | drop support for TypeScript 5.4 ([#57577](https://github.com/angular/angular/pull/57577)) |
|
||||
| [18d8d44b1f](https://github.com/angular/angular/commit/18d8d44b1f3d56a4eda68f2cafded7529e08d0f1) | feat | experimental `resource()` API for async dependencies ([#58255](https://github.com/angular/angular/pull/58255)) |
|
||||
| [9762b24b5e](https://github.com/angular/angular/commit/9762b24b5e8d7ab3ed2321959492a77b01d8ae57) | feat | experimental impl of `rxResource()` ([#58255](https://github.com/angular/angular/pull/58255)) |
|
||||
| [6b8c494d05](https://github.com/angular/angular/commit/6b8c494d05e545830fffb9626153480af6339ddc) | feat | flipping the default value for `standalone` to `true` ([#58169](https://github.com/angular/angular/pull/58169)) |
|
||||
| [e6e5d29e83](https://github.com/angular/angular/commit/e6e5d29e830a0a74d7677d5f2345f29391064853) | feat | initial version of the output migration ([#57604](https://github.com/angular/angular/pull/57604)) |
|
||||
| [be2e49639b](https://github.com/angular/angular/commit/be2e49639bda831831ad62d49253db942a83fd46) | feat | introduce `afterRenderEffect` ([#57549](https://github.com/angular/angular/pull/57549)) |
|
||||
| [ec386e7f12](https://github.com/angular/angular/commit/ec386e7f1216e0047392e75ab686b310b073eb42) | feat | introduce debugName optional arg to framework signal functions ([#57073](https://github.com/angular/angular/pull/57073)) |
|
||||
| [8311f00faa](https://github.com/angular/angular/commit/8311f00faaf282d1a5b1ddca29247a2fba94a692) | feat | introduce the reactive linkedSignal ([#58189](https://github.com/angular/angular/pull/58189)) |
|
||||
| [1b1519224d](https://github.com/angular/angular/commit/1b1519224d10c1cd25d05d7b958772b9adee1e1a) | feat | mark input, output and model APIs as stable ([#57804](https://github.com/angular/angular/pull/57804)) |
|
||||
| [a7eff3ffaa](https://github.com/angular/angular/commit/a7eff3ffaaecbcb3034130d475ff7b4e41a1e1cc) | feat | mark signal-based query APIs as stable ([#57921](https://github.com/angular/angular/pull/57921)) |
|
||||
| [a1f229850a](https://github.com/angular/angular/commit/a1f229850ad36da009f772faa831da173a60268c) | feat | migrate ExperimentalPendingTasks to PendingTasks ([#57533](https://github.com/angular/angular/pull/57533)) |
|
||||
| [3f1e7ab6ae](https://github.com/angular/angular/commit/3f1e7ab6ae984149004c449c04301b434ea64d2a) | feat | promote `outputFromObservable` & `outputToObservable` to stable. ([#58214](https://github.com/angular/angular/pull/58214)) |
|
||||
| [97c44a1d6c](https://github.com/angular/angular/commit/97c44a1d6c41be250d585fba5af2bc2af4d98ae2) | feat | Promote `takeUntilDestroyed` to stable. ([#58200](https://github.com/angular/angular/pull/58200)) |
|
||||
| [e5adf92965](https://github.com/angular/angular/commit/e5adf9296595644e415d5c147df08890be01ba77) | feat | stabilize `@let` syntax ([#57813](https://github.com/angular/angular/pull/57813)) |
|
||||
| [b063468027](https://github.com/angular/angular/commit/b0634680272569501146bb7a9cdfe53033e25971) | feat | support TypeScript 5.6 ([#57424](https://github.com/angular/angular/pull/57424)) |
|
||||
| [819ff034ce](https://github.com/angular/angular/commit/819ff034ce7cf014cedef60510b83af9340efa71) | feat | treat directives, pipes, components as by default ([#58229](https://github.com/angular/angular/pull/58229)) |
|
||||
| [ee426c62f0](https://github.com/angular/angular/commit/ee426c62f07579ec7dc89ce9582972cc1e3471d4) | fix | allow signal write error ([#57973](https://github.com/angular/angular/pull/57973)) |
|
||||
| [67db4305c2](https://github.com/angular/angular/commit/67db4305c2261625fd54d284c29e94e26cb19488) | fix | clean up afterRender after it is executed ([#58119](https://github.com/angular/angular/pull/58119)) |
|
||||
| [c095679f92](https://github.com/angular/angular/commit/c095679f927ad67fec6c18cb140ea550ae02639e) | fix | avoid breaking change with apps using rxjs 6.x ([#58341](https://github.com/angular/angular/pull/58341)) |
|
||||
| [71ee81af2c](https://github.com/angular/angular/commit/71ee81af2c4c5854a54cf94a48d5829da41878a7) | fix | clean up event contract once hydration is done ([#58174](https://github.com/angular/angular/pull/58174)) |
|
||||
| [f03d274e87](https://github.com/angular/angular/commit/f03d274e87c919514a70d02c0699523957de7386) | fix | ComponentFixture autoDetect feature works like production ([#55228](https://github.com/angular/angular/pull/55228)) |
|
||||
| [950a5540f1](https://github.com/angular/angular/commit/950a5540f15118e7360506ad82ec9dab5a11f789) | fix | Ensure the `ViewContext` is retained after closure minification ([#57903](https://github.com/angular/angular/pull/57903)) |
|
||||
| [7b1e5be20b](https://github.com/angular/angular/commit/7b1e5be20b99c88246c6be78a4dcd64eb55cee1a) | fix | fallback to default ng-content with empty projectable nodes. ([#57480](https://github.com/angular/angular/pull/57480)) |
|
||||
| [0300dd2e18](https://github.com/angular/angular/commit/0300dd2e18f064f2f57f7371e0dc5c01218b5019) | fix | Fix fixture.detectChanges with autoDetect disabled and zoneless ([#57416](https://github.com/angular/angular/pull/57416)) |
|
||||
| [5fe57d4fbb](https://github.com/angular/angular/commit/5fe57d4fbb578c35a8e8ef037ae8c19c8a0e901c) | fix | fixes issues with control flow and incremental hydration ([#58644](https://github.com/angular/angular/pull/58644)) |
|
||||
| [51933ef5a6](https://github.com/angular/angular/commit/51933ef5a6ce62df37945fa22e87e3868288e318) | fix | prevent errors on contract cleanup ([#58614](https://github.com/angular/angular/pull/58614)) |
|
||||
| [fd7716440b](https://github.com/angular/angular/commit/fd7716440bec8f7ed042d79bafacf3048d45cd47) | fix | Prevents trying to trigger incremental hydration on CSR ([#58366](https://github.com/angular/angular/pull/58366)) |
|
||||
| [656b5d3e78](https://github.com/angular/angular/commit/656b5d3e78004229a76488e0de1eb1d3508d8f6d) | fix | Re-assign error codes to be within core bounds (<1000) ([#53455](https://github.com/angular/angular/pull/53455)) |
|
||||
| [6e0af6dbbb](https://github.com/angular/angular/commit/6e0af6dbbbe5e9a9e2e5809ada0b7b5a7e456402) | fix | resolve forward-referenced host directives during directive matching ([#58492](https://github.com/angular/angular/pull/58492)) |
|
||||
| [468d3fb9b1](https://github.com/angular/angular/commit/468d3fb9b1c3dd6dff86afcb6d8f89cc4c29b24b) | fix | rethrow errors during ApplicationRef.tick in TestBed ([#57200](https://github.com/angular/angular/pull/57200)) |
|
||||
| [226a67dabb](https://github.com/angular/angular/commit/226a67dabba90a488ad09ce7bb026b8883c90d4a) | fix | Schedulers run in zone above Angular rather than root ([#57553](https://github.com/angular/angular/pull/57553)) |
|
||||
| [97fb86d331](https://github.com/angular/angular/commit/97fb86d3310ae891ba4d894a8d3479eda08bd4c2) | perf | set encapsulation to `None` for empty component styles ([#57130](https://github.com/angular/angular/pull/57130)) |
|
||||
| [c15ec36bd1](https://github.com/angular/angular/commit/c15ec36bd1dcff4c7c387337a5bcfd928994db2f) | refactor | remove deprecated `factories` Property in `KeyValueDiffers` ([#58064](https://github.com/angular/angular/pull/58064)) |
|
||||
### elements
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [fe5c4e086a](https://github.com/angular/angular/commit/fe5c4e086add655bf53315d71b0736ff758c7199) | fix | support `output()`-shaped outputs ([#57535](https://github.com/angular/angular/pull/57535)) |
|
||||
| [0cebfd7462](https://github.com/angular/angular/commit/0cebfd7462c6a7c6c3b0d66720c436a4b0eea19d) | fix | switch to `ComponentRef.setInput` & remove custom scheduler ([#56728](https://github.com/angular/angular/pull/56728)) |
|
||||
### forms
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [3e7d724037](https://github.com/angular/angular/commit/3e7d724037cca4d256b1442eda20d6c6ad91d279) | feat | add ability to clear a FormRecord ([#50750](https://github.com/angular/angular/pull/50750)) |
|
||||
| [18b6f3339f](https://github.com/angular/angular/commit/18b6f3339f46b37ee67fce2fa8a900cc73b2f23c) | fix | fix FormRecord type inference ([#50750](https://github.com/angular/angular/pull/50750)) |
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [4b9accdf16](https://github.com/angular/angular/commit/4b9accdf166f3990b3706de83ada15937fe786e2) | feat | promote `withRequestsMadeViaParent` to stable. ([#58221](https://github.com/angular/angular/pull/58221)) |
|
||||
| [057cf7fb6b](https://github.com/angular/angular/commit/057cf7fb6bd2ac37a7a30d3a143e6737e386247f) | fix | preserve all headers from Headers object ([#57802](https://github.com/angular/angular/pull/57802)) |
|
||||
### language-service
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [8da9fb49b5](https://github.com/angular/angular/commit/8da9fb49b54e50de2d028691f73fb773def62ecd) | feat | add code fix for unused standalone imports ([#57605](https://github.com/angular/angular/pull/57605)) |
|
||||
| [1f067f4507](https://github.com/angular/angular/commit/1f067f4507b6e908fe991d5de0dc4d3a627ab2f9) | feat | add code reactoring action to migrate `@Input` to signal-input ([#57214](https://github.com/angular/angular/pull/57214)) |
|
||||
| [56ee47f2ec](https://github.com/angular/angular/commit/56ee47f2ec6e983e2ffdf59476ab29a92590811e) | feat | allow code refactorings to compute edits asynchronously ([#57214](https://github.com/angular/angular/pull/57214)) |
|
||||
| [bc83fc1e2e](https://github.com/angular/angular/commit/bc83fc1e2ebac1a99b6e8ed63cea48f48dd7c863) | feat | support converting to signal queries in VSCode extension ([#58106](https://github.com/angular/angular/pull/58106)) |
|
||||
| [5c4305f024](https://github.com/angular/angular/commit/5c4305f0248ac3cc1adc76aebd3ef8af041039dc) | feat | support migrating full classes to signal inputs in VSCode ([#57975](https://github.com/angular/angular/pull/57975)) |
|
||||
| [6342befff8](https://github.com/angular/angular/commit/6342befff8ee491f37e8912cccb0099bbbf01042) | feat | support migrating full classes to signal queries ([#58263](https://github.com/angular/angular/pull/58263)) |
|
||||
| [7ecfd89592](https://github.com/angular/angular/commit/7ecfd8959219b6e2ec19e1244a6694711daf1782) | fix | The suppress diagnostics option should work for external templates ([#57873](https://github.com/angular/angular/pull/57873)) |
|
||||
### localize
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
@@ -78,22 +223,47 @@
|
||||
### migrations
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [dff4de0f75](https://github.com/angular/angular/commit/dff4de0f75741bc629462bb8da833b876c754453) | feat | add a combined migration for all signals APIs ([#58259](https://github.com/angular/angular/pull/58259)) |
|
||||
| [b6bc93803c](https://github.com/angular/angular/commit/b6bc93803c246d47aac0d2d8619271d42b249a4a) | feat | add schematic to migrate to signal queries ([#58032](https://github.com/angular/angular/pull/58032)) |
|
||||
| [2bfc64daf1](https://github.com/angular/angular/commit/2bfc64daf1cad9be8099759e8de7a361555ad5d1) | feat | expose output as function migration ([#58299](https://github.com/angular/angular/pull/58299)) |
|
||||
| [59fe9bc772](https://github.com/angular/angular/commit/59fe9bc77236f1374427a851e55b0fa5216d9cf9) | feat | introduce signal input migration as `ng generate` schematic ([#57805](https://github.com/angular/angular/pull/57805)) |
|
||||
| [90c7ec39a0](https://github.com/angular/angular/commit/90c7ec39a06e5c14711e0a42e2d6a478cde2b9cc) | fix | inject migration always inserting generated variables before super call ([#58393](https://github.com/angular/angular/pull/58393)) |
|
||||
| [7a65cdd911](https://github.com/angular/angular/commit/7a65cdd911cbbf22445c916fc754d3a3304bc5fe) | fix | inject migration not inserting generated code after super call in some cases ([#58393](https://github.com/angular/angular/pull/58393)) |
|
||||
| [c1aa411cf1](https://github.com/angular/angular/commit/c1aa411cf13259d991c8f224a2bafc3e9763fe8d) | fix | properly resolve tsconfig paths on windows ([#58137](https://github.com/angular/angular/pull/58137)) |
|
||||
| [e26797b38e](https://github.com/angular/angular/commit/e26797b38efe0ac813601c10581f34b7591954c1) | fix | replace removed NgModules in tests with their exports ([#58627](https://github.com/angular/angular/pull/58627)) |
|
||||
### platform-browser
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [c36a1c023b](https://github.com/angular/angular/commit/c36a1c023b34f9b2056e1bef6364787e8495bfad) | fix | correctly add external stylesheets to ShadowDOM components ([#58482](https://github.com/angular/angular/pull/58482)) |
|
||||
| [5c61f46409](https://github.com/angular/angular/commit/5c61f46409855bb8fe66d71a9c16c00753032987) | refactor | remove deprecated `BrowserModule.withServerTransition` method ([#58062](https://github.com/angular/angular/pull/58062)) |
|
||||
### platform-server
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [9e82559de4](https://github.com/angular/angular/commit/9e82559de4e99a1aedf645a05b01fc08d3f4b1b1) | fix | destroy `PlatformRef` when error happens during the `bootstrap()` phase ([#58112](https://github.com/angular/angular/pull/58112)) |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [f271021e19](https://github.com/angular/angular/commit/f271021e190ede70bfd181d46f0a468a8e7fa144) | feat | Add `routerOutletData` input to `RouterOutlet` directive ([#57051](https://github.com/angular/angular/pull/57051)) |
|
||||
| [b2790813a6](https://github.com/angular/angular/commit/b2790813a62e4dfdd77e27d1bb82201788476d06) | fix | Align RouterModule.forRoot errorHandler with provider error handler ([#57050](https://github.com/angular/angular/pull/57050)) |
|
||||
| [a49c35ec76](https://github.com/angular/angular/commit/a49c35ec769461b9eb490719f0aa3e5aea8e243f) | fix | remove setter for `injector` on `OutletContext` ([#58343](https://github.com/angular/angular/pull/58343)) |
|
||||
| [7436d3180e](https://github.com/angular/angular/commit/7436d3180ea5ad2c0b58d920bd45f8641a14cc8d) | fix | Update Resolve interface to include RedirectCommand like ResolveFn ([#57309](https://github.com/angular/angular/pull/57309)) |
|
||||
### service-worker
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [8ddce80a0b](https://github.com/angular/angular/commit/8ddce80a0bab4ebbd0f7db1c85ee27e4f0249db9) | feat | allow specifying maxAge for entire application ([#49601](https://github.com/angular/angular/pull/49601)) |
|
||||
| [1479af978c](https://github.com/angular/angular/commit/1479af978cd2bbe4ee9f1ca9682684b8e5135fa7) | feat | finish implementation of refreshAhead feature ([#53356](https://github.com/angular/angular/pull/53356)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="18.2.9"></a>
|
||||
# 18.2.9 (2024-10-23)
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [b0ab653965](https://github.com/angular/angular/commit/b0ab653965cf88fcfde23fc6a6cc78ce3121a30f) | fix | report when NgModule imports or exports itself ([#58231](https://github.com/angular/angular/pull/58231)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="18.2.8"></a>
|
||||
# 18.2.8 (2024-10-10)
|
||||
### compiler
|
||||
@@ -121,45 +291,6 @@
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="19.0.0-next.8"></a>
|
||||
# 19.0.0-next.8 (2024-10-02)
|
||||
### common
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [c3115b882e](https://github.com/angular/angular/commit/c3115b882ebbe4f971e1f06bb1ce2cdf43327bb0) | fix | execute checks and remove placeholder when image is already loaded ([#55444](https://github.com/angular/angular/pull/55444)) |
|
||||
| [b7bd429951](https://github.com/angular/angular/commit/b7bd42995130f80ea74ed5b905446f09a98a9480) | fix | prevent warning about oversize image twice ([#58021](https://github.com/angular/angular/pull/58021)) |
|
||||
| [e8b2d5fad8](https://github.com/angular/angular/commit/e8b2d5fad8aece3b2e3f4a7ed1356642f68ee275) | fix | skip checking whether SVGs are oversized ([#57966](https://github.com/angular/angular/pull/57966)) |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [d9687f43dd](https://github.com/angular/angular/commit/d9687f43dd2ccfcf7dd3ee4f9066ce727f3224c6) | feat | 'strictStandalone' flag enforces standalone ([#57935](https://github.com/angular/angular/pull/57935)) |
|
||||
| [39ccaf4cc4](https://github.com/angular/angular/commit/39ccaf4cc457894a3cf0455349e1c016a858751a) | fix | correctly get the type of nested function call expressions ([#57010](https://github.com/angular/angular/pull/57010)) |
|
||||
| [33fe252c58](https://github.com/angular/angular/commit/33fe252c588ee94d6ef99e8070d35c483ec24fda) | fix | do not report unused declarations coming from an imported array ([#57940](https://github.com/angular/angular/pull/57940)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [3240598158](https://github.com/angular/angular/commit/32405981582030d7eb5d307f44b9c00fb384c480) | fix | provide flag to opt into manual cleanup for after render hooks ([#57917](https://github.com/angular/angular/pull/57917)) |
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [22dafa658b](https://github.com/angular/angular/commit/22dafa658bdf5536c3002e7f312efe0dfbc7236d) | fix | cleanup JSONP script listeners once loading completed ([#57877](https://github.com/angular/angular/pull/57877)) |
|
||||
| [057cf7fb6b](https://github.com/angular/angular/commit/057cf7fb6bd2ac37a7a30d3a143e6737e386247f) | fix | preserve all headers from Headers object ([#57802](https://github.com/angular/angular/pull/57802)) |
|
||||
### language-service
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [5c4305f024](https://github.com/angular/angular/commit/5c4305f0248ac3cc1adc76aebd3ef8af041039dc) | feat | support migrating full classes to signal inputs in VSCode ([#57975](https://github.com/angular/angular/pull/57975)) |
|
||||
### migrations
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [b6bc93803c](https://github.com/angular/angular/commit/b6bc93803c246d47aac0d2d8619271d42b249a4a) | feat | add schematic to migrate to signal queries ([#58032](https://github.com/angular/angular/pull/58032)) |
|
||||
| [ef577b2d2b](https://github.com/angular/angular/commit/ef577b2d2b62ba0a48a120b9631296812e9049d3) | fix | delete constructor if it only has super call ([#58013](https://github.com/angular/angular/pull/58013)) |
|
||||
### upgrade
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [5f56a65837](https://github.com/angular/angular/commit/5f56a6583753f5aaff8a43e1e5f9a376433d0c0c) | fix | support input signal bindings ([#57020](https://github.com/angular/angular/pull/57020)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="18.2.7"></a>
|
||||
# 18.2.7 (2024-10-02)
|
||||
### common
|
||||
@@ -191,80 +322,11 @@
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="19.0.0-next.7"></a>
|
||||
# 19.0.0-next.7 (2024-09-25)
|
||||
## Breaking Changes
|
||||
### core
|
||||
- Changes to effect timing which generally has two implications:
|
||||
|
||||
* effects which are triggered outside of change detection run as part of
|
||||
the change detection process instead of as a microtask. Depending on the
|
||||
specifics of application/test setup, this can result in them executing
|
||||
earlier or later (or requiring additional test steps to trigger; see below
|
||||
examples).
|
||||
|
||||
* effects which are triggered during change detection (e.g. by input
|
||||
signals) run _earlier_, before the component's template.
|
||||
|
||||
We've seen a few common failure cases:
|
||||
|
||||
* Tests which used to rely on the `Promise` timing of effects now need to
|
||||
`await whenStable()` or call `.detectChanges()` in order for effects to
|
||||
run.
|
||||
|
||||
* Tests which use faked clocks may need to fast-forward/flush the clock to
|
||||
cause effects to run.
|
||||
|
||||
* `effect()`s triggered during CD could rely on the application being fully
|
||||
rendered (for example, they could easily read computed styles, etc). With
|
||||
the change, they run before the component's updates and can get incorrect
|
||||
answers. The recent `afterRenderEffect()` API is a natural replacement for
|
||||
this style of effect.
|
||||
|
||||
* `effect()`s which synchronize with the forms system are particularly
|
||||
timing-sensitive and might need to adjust their initialization timing.
|
||||
- `ExperimentalPendingTasks` has been renamed to
|
||||
`PendingTasks`.
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [fc59e2a7b7](https://github.com/angular/angular/commit/fc59e2a7b7afa491a5ea740284a742574805eb36) | feat | change effect() execution timing & no-op `allowSignalWrites` ([#57874](https://github.com/angular/angular/pull/57874)) |
|
||||
| [a7eff3ffaa](https://github.com/angular/angular/commit/a7eff3ffaaecbcb3034130d475ff7b4e41a1e1cc) | feat | mark signal-based query APIs as stable ([#57921](https://github.com/angular/angular/pull/57921)) |
|
||||
| [a1f229850a](https://github.com/angular/angular/commit/a1f229850ad36da009f772faa831da173a60268c) | feat | migrate ExperimentalPendingTasks to PendingTasks ([#57533](https://github.com/angular/angular/pull/57533)) |
|
||||
| [950a5540f1](https://github.com/angular/angular/commit/950a5540f15118e7360506ad82ec9dab5a11f789) | fix | Ensure the `ViewContext` is retained after closure minification ([#57903](https://github.com/angular/angular/pull/57903)) |
|
||||
### language-service
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [7ecfd89592](https://github.com/angular/angular/commit/7ecfd8959219b6e2ec19e1244a6694711daf1782) | fix | The suppress diagnostics option should work for external templates ([#57873](https://github.com/angular/angular/pull/57873)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="18.2.6"></a>
|
||||
# 18.2.6 (2024-09-25)
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="19.0.0-next.6"></a>
|
||||
# 19.0.0-next.6 (2024-09-18)
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [f611faadfe](https://github.com/angular/angular/commit/f611faadfedd8dc2c3291da98e2c2c60fe3984bd) | fix | extended diagnostics not validating ICUs ([#57845](https://github.com/angular/angular/pull/57845)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [3ebe6b4ad4](https://github.com/angular/angular/commit/3ebe6b4ad401337e18619edc34477ae98226fa3e) | feat | Add async `run` method on `ExperimentalPendingTasks` ([#56546](https://github.com/angular/angular/pull/56546)) |
|
||||
| [1b1519224d](https://github.com/angular/angular/commit/1b1519224d10c1cd25d05d7b958772b9adee1e1a) | feat | mark input, output and model APIs as stable ([#57804](https://github.com/angular/angular/pull/57804)) |
|
||||
| [e5adf92965](https://github.com/angular/angular/commit/e5adf9296595644e415d5c147df08890be01ba77) | feat | stabilize `@let` syntax ([#57813](https://github.com/angular/angular/pull/57813)) |
|
||||
| [4231e8f28f](https://github.com/angular/angular/commit/4231e8f28ffe8f55dddc2af0647b5b04fa8445d7) | fix | Handle `@let` declaration with array when `preparingForHydration` ([#57816](https://github.com/angular/angular/pull/57816)) |
|
||||
### migrations
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [59fe9bc772](https://github.com/angular/angular/commit/59fe9bc77236f1374427a851e55b0fa5216d9cf9) | feat | introduce signal input migration as `ng generate` schematic ([#57805](https://github.com/angular/angular/pull/57805)) |
|
||||
| [6144612940](https://github.com/angular/angular/commit/614461294041d7a2331bf7528907f37353205115) | fix | account for explicit standalone: false in migration ([#57803](https://github.com/angular/angular/pull/57803)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="18.2.5"></a>
|
||||
# 18.2.5 (2024-09-18)
|
||||
### compiler-cli
|
||||
@@ -282,15 +344,6 @@
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="19.0.0-next.5"></a>
|
||||
# 19.0.0-next.5 (2024-09-11)
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [c93b510f9b](https://github.com/angular/angular/commit/c93b510f9b2e23aa7a3848a04c05249fde14a9b1) | feat | allow passing `undefined` without needing to include it in the type argument of `input` ([#57621](https://github.com/angular/angular/pull/57621)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="18.2.4"></a>
|
||||
# 18.2.4 (2024-09-11)
|
||||
### compiler
|
||||
@@ -304,60 +357,6 @@
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="19.0.0-next.4"></a>
|
||||
# 19.0.0-next.4 (2024-09-09)
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [40ff18f87a](https://github.com/angular/angular/commit/40ff18f87a04fd1c00dea9fee1568bfe52acf25c) | fix | produce less noisy errors when parsing control flow ([#57711](https://github.com/angular/angular/pull/57711)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [6ea8e1e9aa](https://github.com/angular/angular/commit/6ea8e1e9aae028572873cf97aa1949c8153f458f) | feat | Add a schematics to migrate to `standalone: false`. ([#57643](https://github.com/angular/angular/pull/57643)) |
|
||||
### migrations
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [cbec46a51d](https://github.com/angular/angular/commit/cbec46a51d22a1238cc8bf1ebdf343d031b8f0ba) | feat | migrate .pipe calls in outputs used in tests ([#57691](https://github.com/angular/angular/pull/57691)) |
|
||||
| [68e5370a66](https://github.com/angular/angular/commit/68e5370a66633f4b069d6adffa95c2ea94291820) | feat | remove complete calls for migrated outputs ([#57671](https://github.com/angular/angular/pull/57671)) |
|
||||
| [9da21f798d](https://github.com/angular/angular/commit/9da21f798de2033af9d39a8a9b255ef2fe74f948) | feat | replace .next usage on outputs ([#57654](https://github.com/angular/angular/pull/57654)) |
|
||||
| [71f5ef2aa5](https://github.com/angular/angular/commit/71f5ef2aa53a74bab7d0543f98870d81c44c4978) | fix | change imports to be G3 compatible ([#57654](https://github.com/angular/angular/pull/57654)) |
|
||||
| [3a264db866](https://github.com/angular/angular/commit/3a264db86611cba9b69780d7f01ee25787278320) | fix | properly handle comments in output migration ([#57691](https://github.com/angular/angular/pull/57691)) |
|
||||
| [fc95a9adff](https://github.com/angular/angular/commit/fc95a9adff42da53dfeee5df8c42be25e8559708) | fix | replace leftover modules with their exports during pruning ([#57684](https://github.com/angular/angular/pull/57684)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="19.0.0-next.3"></a>
|
||||
# 19.0.0-next.3 (2024-09-04)
|
||||
## Breaking Changes
|
||||
### core
|
||||
- * TypeScript versions less than 5.5 are no longer supported.
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [a2e4ee0cb3](https://github.com/angular/angular/commit/a2e4ee0cb3d40cadc05e28d58b06853973944456) | feat | add diagnostic for unused standalone imports ([#57605](https://github.com/angular/angular/pull/57605)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [8bcc663a53](https://github.com/angular/angular/commit/8bcc663a53888717cdf4ce0c23404caa00abb1b2) | feat | drop support for TypeScript 5.4 ([#57577](https://github.com/angular/angular/pull/57577)) |
|
||||
| [e6e5d29e83](https://github.com/angular/angular/commit/e6e5d29e830a0a74d7677d5f2345f29391064853) | feat | initial version of the output migration ([#57604](https://github.com/angular/angular/pull/57604)) |
|
||||
| [be2e49639b](https://github.com/angular/angular/commit/be2e49639bda831831ad62d49253db942a83fd46) | feat | introduce `afterRenderEffect` ([#57549](https://github.com/angular/angular/pull/57549)) |
|
||||
### elements
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [fe5c4e086a](https://github.com/angular/angular/commit/fe5c4e086add655bf53315d71b0736ff758c7199) | fix | support `output()`-shaped outputs ([#57535](https://github.com/angular/angular/pull/57535)) |
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [c2892fee58](https://github.com/angular/angular/commit/c2892fee58d28ffec0dfeaad6a5d6822c040cf03) | fix | Dynamicaly call the global fetch implementation ([#57531](https://github.com/angular/angular/pull/57531)) |
|
||||
### language-service
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [8da9fb49b5](https://github.com/angular/angular/commit/8da9fb49b54e50de2d028691f73fb773def62ecd) | feat | add code fix for unused standalone imports ([#57605](https://github.com/angular/angular/pull/57605)) |
|
||||
| [1f067f4507](https://github.com/angular/angular/commit/1f067f4507b6e908fe991d5de0dc4d3a627ab2f9) | feat | add code refactoring action to migrate `@Input` to signal-input ([#57214](https://github.com/angular/angular/pull/57214)) |
|
||||
| [56ee47f2ec](https://github.com/angular/angular/commit/56ee47f2ec6e983e2ffdf59476ab29a92590811e) | feat | allow code refactorings to compute edits asynchronously ([#57214](https://github.com/angular/angular/pull/57214)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="18.2.3"></a>
|
||||
# 18.2.3 (2024-09-04)
|
||||
### http
|
||||
@@ -367,67 +366,6 @@
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="19.0.0-next.2"></a>
|
||||
# 19.0.0-next.2 (2024-08-28)
|
||||
## Breaking Changes
|
||||
### core
|
||||
- Render default fallback with empty `projectableNodes`.
|
||||
|
||||
When passing an empty array to `projectableNodes` in the `createComponent` API, the default fallback content of the `ng-content` will be rendered if present. To prevent rendering the default content, pass `document.createTextNode('')` as a `projectableNode`.
|
||||
|
||||
For example:
|
||||
|
||||
```ts
|
||||
// The first ng-content will render the default fallback content if present
|
||||
createComponent(MyComponent. { projectableNodes: [[], [secondNode]] });
|
||||
|
||||
// To prevent projecting the default fallback content:
|
||||
createComponent(MyComponent. { projectableNodes: [[document.createTextNode('')], [secondNode]] });
|
||||
|
||||
```
|
||||
- The timers that are used for zone coalescing and hybrid
|
||||
mode scheduling (which schedules an application state synchronization
|
||||
when changes happen outside the Angular zone) will now run in the zone
|
||||
above Angular rather than the root zone. This will mostly affect tests
|
||||
which use `fakeAsync`: these timers will now be visible to `fakeAsync`
|
||||
and can be affected by `tick` or `flush`.
|
||||
### elements
|
||||
- as part of switching away from custom CD behavior to the
|
||||
hybrid scheduler, timing of change detection around custom elements has
|
||||
changed subtly. These changes make elements more efficient, but can cause
|
||||
tests which encoded assumptions about how or when elements would be checked
|
||||
to require updating.
|
||||
### common
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [50f08e6c4bf](https://github.com/angular/angular/commit/50f08e6c4bf1caeeb08d3505ce7fabd466b9c76b) | feat | automatically use sizes auto in NgOptimizedImage ([#57479](https://github.com/angular/angular/pull/57479)) |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [4716c3b9660](https://github.com/angular/angular/commit/4716c3b9660b01f4ef3642fb774270b7f4a13d1a) | perf | reduce duplicate component style resolution ([#57502](https://github.com/angular/angular/pull/57502)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [a3cdbfe87f5](https://github.com/angular/angular/commit/a3cdbfe87f5a8daef11a154ef3edb5a3a5c12f77) | fix | avoid leaking memory if component throws during creation ([#57546](https://github.com/angular/angular/pull/57546)) |
|
||||
| [7a99815146e](https://github.com/angular/angular/commit/7a99815146eb78074aa3ed6db73c6e87042df692) | fix | Do not bubble capture events. ([#57476](https://github.com/angular/angular/pull/57476)) |
|
||||
| [7b1e5be20b9](https://github.com/angular/angular/commit/7b1e5be20b99c88246c6be78a4dcd64eb55cee1a) | fix | fallback to default ng-content with empty projectable nodes. ([#57480](https://github.com/angular/angular/pull/57480)) |
|
||||
| [0300dd2e18f](https://github.com/angular/angular/commit/0300dd2e18f064f2f57f7371e0dc5c01218b5019) | fix | Fix fixture.detectChanges with autoDetect disabled and zoneless ([#57416](https://github.com/angular/angular/pull/57416)) |
|
||||
| [226a67dabba](https://github.com/angular/angular/commit/226a67dabba90a488ad09ce7bb026b8883c90d4a) | fix | Schedulers run in zone above Angular rather than root ([#57553](https://github.com/angular/angular/pull/57553)) |
|
||||
### elements
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [0cebfd7462c](https://github.com/angular/angular/commit/0cebfd7462c6a7c6c3b0d66720c436a4b0eea19d) | fix | switch to `ComponentRef.setInput` & remove custom scheduler ([#56728](https://github.com/angular/angular/pull/56728)) |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [8f6308457f0](https://github.com/angular/angular/commit/8f6308457f0f03e9bbd09f4bc10d1c61fd41d22c) | fix | Do not unnecessarily run matcher twice on route matching ([#57530](https://github.com/angular/angular/pull/57530)) |
|
||||
### upgrade
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [c9d90786d0a](https://github.com/angular/angular/commit/c9d90786d0a6421bbb21b9d1649d031b34e3fa5d) | fix | Address Trusted Types violations in @angular/upgrade ([#57454](https://github.com/angular/angular/pull/57454)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="18.2.2"></a>
|
||||
# 18.2.2 (2024-08-28)
|
||||
### core
|
||||
@@ -466,75 +404,6 @@
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="19.0.0-next.1"></a>
|
||||
# 19.0.0-next.1 (2024-08-22)
|
||||
## Breaking Changes
|
||||
### core
|
||||
- The `autoDetect` feature of `ComponentFixture` will now
|
||||
attach the fixture to the `ApplicationRef`. As a result, errors during
|
||||
automatic change detection of the fixture be reported to the `ErrorHandler`.
|
||||
This change may cause custom error handlers to observe new failures that were previously unreported.
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [9e87593055](https://github.com/angular/angular/commit/9e87593055a5314a67090bd15d5552c23b538050) | feat | ensure template style elements are preprocessed as inline styles ([#57429](https://github.com/angular/angular/pull/57429)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [b063468027](https://github.com/angular/angular/commit/b0634680272569501146bb7a9cdfe53033e25971) | feat | support TypeScript 5.6 ([#57424](https://github.com/angular/angular/pull/57424)) |
|
||||
| [3b0dca75d6](https://github.com/angular/angular/commit/3b0dca75d6dab6039253edd00c436715775bd0dd) | fix | Allow zoneless scheduler to run inside `fakeAsync` ([#56932](https://github.com/angular/angular/pull/56932)) |
|
||||
| [f03d274e87](https://github.com/angular/angular/commit/f03d274e87c919514a70d02c0699523957de7386) | fix | ComponentFixture autoDetect feature works like production ([#55228](https://github.com/angular/angular/pull/55228)) |
|
||||
| [d4449fce21](https://github.com/angular/angular/commit/d4449fce21bebbb18f9e1341f1675cdbec7e83ac) | fix | handle hydration of components that project content conditionally ([#57383](https://github.com/angular/angular/pull/57383)) |
|
||||
### migrations
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [4ae66f25d0](https://github.com/angular/angular/commit/4ae66f25d01ffd603872b3df3faf5c5c555b6446) | fix | account for members with doc strings and no modifiers ([#57389](https://github.com/angular/angular/pull/57389)) |
|
||||
| [ac93839d69](https://github.com/angular/angular/commit/ac93839d694929fdf16c610994a369d4efb2823a) | fix | avoid migrating route component in tests ([#57317](https://github.com/angular/angular/pull/57317)) |
|
||||
| [58a79b6e43](https://github.com/angular/angular/commit/58a79b6e435f2a46a7ab17ff5538083e05340b6f) | fix | preserve type when using inject decorator ([#57389](https://github.com/angular/angular/pull/57389)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="19.0.0-next.0"></a>
|
||||
# 19.0.0-next.0 (2024-08-14)
|
||||
## Breaking Changes
|
||||
### core
|
||||
- Errors that are thrown during `ApplicationRef.tick`
|
||||
will now be rethrown when using `TestBed`. These errors should be
|
||||
resolved by ensuring the test environment is set up correctly to
|
||||
complete change detection successfully. There are two alternatives to
|
||||
catch the errors:
|
||||
|
||||
* Instead of waiting for automatic change detection to happen, trigger
|
||||
it synchronously and expect the error. For example, a jasmine test
|
||||
could write `expect(() => TestBed.inject(ApplicationRef).tick()).toThrow()`
|
||||
* `TestBed` will reject any outstanding `ComponentFixture.whenStable` promises. A jasmine test,
|
||||
for example, could write `expectAsync(fixture.whenStable()).toBeRejected()`.
|
||||
|
||||
As a last resort, you can configure errors to _not_ be rethrown by
|
||||
setting `rethrowApplicationErrors` to `false` in `TestBed.configureTestingModule`.
|
||||
### router
|
||||
- The `Router.errorHandler` property has been removed.
|
||||
Adding an error handler should be configured in either
|
||||
`withNavigationErrorHandler` with `provideRouter` or the `errorHandler`
|
||||
property in the extra options of `RouterModule.forRoot`. In addition,
|
||||
the error handler cannot be used to change the return value of the
|
||||
router navigation promise or prevent it from rejecting. Instead, if you
|
||||
want to prevent the promise from rejecting, use `resolveNavigationPromiseOnError`.
|
||||
- The return type of the `Resolve` interface now includes
|
||||
`RedirectCommand`.
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [468d3fb9b1](https://github.com/angular/angular/commit/468d3fb9b1c3dd6dff86afcb6d8f89cc4c29b24b) | fix | rethrow errors during ApplicationRef.tick in TestBed ([#57200](https://github.com/angular/angular/pull/57200)) |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [f271021e19](https://github.com/angular/angular/commit/f271021e190ede70bfd181d46f0a468a8e7fa144) | feat | Add `routerOutletData` input to `RouterOutlet` directive ([#57051](https://github.com/angular/angular/pull/57051)) |
|
||||
| [b2790813a6](https://github.com/angular/angular/commit/b2790813a62e4dfdd77e27d1bb82201788476d06) | fix | Align RouterModule.forRoot errorHandler with provider error handler ([#57050](https://github.com/angular/angular/pull/57050)) |
|
||||
| [7436d3180e](https://github.com/angular/angular/commit/7436d3180ea5ad2c0b58d920bd45f8641a14cc8d) | fix | Update Resolve interface to include RedirectCommand like ResolveFn ([#57309](https://github.com/angular/angular/pull/57309)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="18.2.0"></a>
|
||||
# 18.2.0 (2024-08-14)
|
||||
### compiler
|
||||
|
||||
+1
-1
@@ -260,7 +260,7 @@ The `<type>` and `<summary>` fields are mandatory, the `(<scope>)` field is opti
|
||||
Must be one of the following:
|
||||
|
||||
* **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
|
||||
* **ci**: Changes to our CI configuration files and scripts (examples: CircleCi, SauceLabs)
|
||||
* **ci**: Changes to our CI configuration files and scripts (examples: Github Actions, SauceLabs)
|
||||
* **docs**: Documentation only changes
|
||||
* **feat**: A new feature
|
||||
* **fix**: A bug fix
|
||||
|
||||
@@ -24,9 +24,6 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://circleci.com/gh/angular/workflows/angular/tree/main">
|
||||
<img src="https://img.shields.io/circleci/build/github/angular/angular/main.svg?logo=circleci&logoColor=fff&label=CircleCI" alt="CI status" />
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/@angular/core">
|
||||
<img src="https://img.shields.io/npm/v/@angular/core.svg?logo=npm&logoColor=fff&label=NPM+package&color=limegreen" alt="Angular on npm" />
|
||||
</a>
|
||||
@@ -35,12 +32,6 @@
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://app.circleci.com/insights/github/angular/angular/workflows/default_workflow?branch=main">
|
||||
<img src="https://dl.circleci.com/insights-snapshot/gh/angular/angular/main/default_workflow/badge.svg" alt="InsightsSnapshot" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -143,10 +143,10 @@ cldr_xml_data_repository(
|
||||
# sass rules
|
||||
http_archive(
|
||||
name = "io_bazel_rules_sass",
|
||||
sha256 = "b00f13a280fc60ef2a1d142b31c629075bac841c980a0c3462190f338e5d584a",
|
||||
strip_prefix = "rules_sass-6e23fb1351f392f7fe7a07038cd537770fe97742",
|
||||
sha256 = "0c97c6d8f7a8697e53d91832117c91b71a23e6900acf530a22bf3de2e05179fc",
|
||||
strip_prefix = "rules_sass-35b1c3236a2b2a23c9d1eaeb82c5f7d030a892d1",
|
||||
urls = [
|
||||
"https://github.com/bazelbuild/rules_sass/archive/6e23fb1351f392f7fe7a07038cd537770fe97742.zip",
|
||||
"https://github.com/bazelbuild/rules_sass/archive/35b1c3236a2b2a23c9d1eaeb82c5f7d030a892d1.zip",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
<ng-content></ng-content>
|
||||
<ng-content />
|
||||
|
||||
@@ -1,76 +1,78 @@
|
||||
<ng-template #navigationList let-navigationItems>
|
||||
<ul
|
||||
class="docs-navigation-list docs-faceted-list"
|
||||
[class.docs-navigation-list-dropdown]="isDropdownView"
|
||||
[class.docs-navigation-list-dropdown]="isDropdownView()"
|
||||
>
|
||||
@for (item of navigationItems; track $index) {
|
||||
<li
|
||||
class="docs-faceted-list-item"
|
||||
[class.docs-navigation-link-hidden]="displayItemsToLevel && item.level > displayItemsToLevel"
|
||||
>
|
||||
@if (item.path) { @if (item.isExternal) {
|
||||
<a [href]="item.path" target="_blank">
|
||||
<span [class.docs-external-link]="item.isExternal">{{ item.label }}</span>
|
||||
@if (item.children && item.level! > 1 && !item.isExpanded) {
|
||||
<docs-icon>chevron_right</docs-icon>
|
||||
}
|
||||
</a>
|
||||
} @else {
|
||||
<a
|
||||
[routerLink]="'/' + item.path"
|
||||
[routerLinkActiveOptions]="{
|
||||
queryParams: 'ignored',
|
||||
fragment: 'ignored',
|
||||
matrixParams: 'exact',
|
||||
paths: 'exact',
|
||||
exact: false
|
||||
}"
|
||||
routerLinkActive="docs-faceted-list-item-active"
|
||||
(click)="emitClickOnLink()"
|
||||
<li
|
||||
class="docs-faceted-list-item"
|
||||
[class.docs-navigation-link-hidden]="displayItemsToLevel() && item.level > displayItemsToLevel()"
|
||||
>
|
||||
<span>{{ item.label }}</span>
|
||||
@if (item.children && !item.isExpanded) {
|
||||
<docs-icon>chevron_right</docs-icon>
|
||||
}
|
||||
</a>
|
||||
} } @else {
|
||||
<!-- Nav Section Header -->
|
||||
@if (item.level !== collapsableLevel && item.level !== expandableLevel) {
|
||||
<div class="docs-secondary-nav-header">
|
||||
<span>{{ item.label }}</span>
|
||||
</div>
|
||||
}
|
||||
@if (item.path) {
|
||||
@if (item.isExternal) {
|
||||
<a [href]="item.path" target="_blank">
|
||||
<span [class.docs-external-link]="item.isExternal">{{ item.label }}</span>
|
||||
@if (item.children && item.level! > 1 && !item.isExpanded) {
|
||||
<docs-icon>chevron_right</docs-icon>
|
||||
}
|
||||
</a>
|
||||
} @else {
|
||||
<a
|
||||
[routerLink]="'/' + item.path"
|
||||
[routerLinkActiveOptions]="{
|
||||
queryParams: 'ignored',
|
||||
fragment: 'ignored',
|
||||
matrixParams: 'exact',
|
||||
paths: 'exact',
|
||||
exact: false
|
||||
}"
|
||||
routerLinkActive="docs-faceted-list-item-active"
|
||||
(click)="emitClickOnLink()"
|
||||
>
|
||||
<span [innerHtml]="item.label"></span>
|
||||
@if (item.children && !item.isExpanded) {
|
||||
<docs-icon>chevron_right</docs-icon>
|
||||
}
|
||||
</a>
|
||||
}
|
||||
} @else {
|
||||
<!-- Nav Section Header -->
|
||||
@if (item.level !== collapsableLevel() && item.level !== expandableLevel()) {
|
||||
<div class="docs-secondary-nav-header">
|
||||
<span [innerHtml]="item.label"></span>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Nav Button Expand/Collapse -->
|
||||
@if ((item.children && item.level === expandableLevel) || item.level === collapsableLevel) {
|
||||
<button
|
||||
type="button"
|
||||
(click)="toggle(item)"
|
||||
attr.aria-label="{{ item.isExpanded ? 'Collapse' : 'Expand' }} {{ item.label }}"
|
||||
[attr.aria-expanded]="item.isExpanded"
|
||||
class="docs-secondary-nav-button"
|
||||
[class.docs-faceted-list-item-active]="item | isActiveNavigationItem: activeItem()"
|
||||
[class.docs-expanded-button]="item.children && item.level == collapsableLevel"
|
||||
[class.docs-not-expanded-button]="item.children && item.level === expandableLevel"
|
||||
[class.docs-nav-item-has-icon]="
|
||||
item.children && item.level === expandableLevel && !item.isExpanded
|
||||
"
|
||||
>
|
||||
@if (item.children && item.level === collapsableLevel) {
|
||||
<docs-icon>arrow_back</docs-icon>
|
||||
<!-- Nav Button Expand/Collapse -->
|
||||
@if (
|
||||
(item.children && item.level === expandableLevel()) || item.level === collapsableLevel()
|
||||
) {
|
||||
<button
|
||||
type="button"
|
||||
(click)="toggle(item)"
|
||||
attr.aria-label="{{ item.isExpanded ? 'Collapse' : 'Expand' }} {{ item.label }}"
|
||||
[attr.aria-expanded]="item.isExpanded"
|
||||
class="docs-secondary-nav-button"
|
||||
[class.docs-faceted-list-item-active]="item | isActiveNavigationItem: activeItem()"
|
||||
[class.docs-expanded-button]="item.children && item.level == collapsableLevel()"
|
||||
[class.docs-not-expanded-button]="item.children && item.level === expandableLevel()"
|
||||
[class.docs-nav-item-has-icon]="
|
||||
item.children && item.level === expandableLevel() && !item.isExpanded
|
||||
"
|
||||
>
|
||||
@if (item.children && item.level === collapsableLevel()) {
|
||||
<docs-icon>arrow_back</docs-icon>
|
||||
}
|
||||
<span>{{ item.label }}</span>
|
||||
</button>
|
||||
}
|
||||
}
|
||||
<span>{{ item.label }}</span>
|
||||
</button>
|
||||
} } @if (item.children?.length > 0) {
|
||||
<ng-container
|
||||
*ngTemplateOutlet="navigationList; context: {$implicit: item.children}"
|
||||
></ng-container>
|
||||
}
|
||||
</li>
|
||||
@if (item.children?.length > 0) {
|
||||
<ng-container *ngTemplateOutlet="navigationList; context: {$implicit: item.children}" />
|
||||
}
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</ng-template>
|
||||
|
||||
<ng-container
|
||||
*ngTemplateOutlet="navigationList; context: {$implicit: navigationItems}"
|
||||
></ng-container>
|
||||
<ng-container *ngTemplateOutlet="navigationList; context: {$implicit: navigationItems()}" />
|
||||
|
||||
@@ -44,11 +44,13 @@ describe('NavigationList', () => {
|
||||
],
|
||||
}).compileComponents();
|
||||
fixture = TestBed.createComponent(NavigationList);
|
||||
fixture.componentRef.setInput('navigationItems', []);
|
||||
|
||||
component = fixture.componentInstance;
|
||||
});
|
||||
|
||||
it('should display provided navigation structure', () => {
|
||||
component.navigationItems = [...navigationItems];
|
||||
fixture.componentRef.setInput('navigationItems', [...navigationItems]);
|
||||
fixture.detectChanges();
|
||||
|
||||
const links = fixture.debugElement.queryAll(By.css('a'));
|
||||
@@ -59,7 +61,7 @@ describe('NavigationList', () => {
|
||||
});
|
||||
|
||||
it('should append `docs-navigation-list-dropdown` when isDropdownView is true', () => {
|
||||
component.isDropdownView = true;
|
||||
fixture.componentRef.setInput('isDropdownView', true);
|
||||
fixture.detectChanges();
|
||||
|
||||
const ulElement = fixture.debugElement.query(By.css('ul.docs-navigation-list-dropdown'));
|
||||
@@ -68,7 +70,7 @@ describe('NavigationList', () => {
|
||||
});
|
||||
|
||||
it('should not append `docs-navigation-list-dropdown` when isDropdownView is false', () => {
|
||||
component.isDropdownView = false;
|
||||
fixture.componentRef.setInput('isDropdownView', false);
|
||||
fixture.detectChanges();
|
||||
|
||||
const ulElement = fixture.debugElement.query(By.css('ul.docs-navigation-list-dropdown'));
|
||||
@@ -78,7 +80,7 @@ describe('NavigationList', () => {
|
||||
|
||||
it('should emit linkClicked when user clicked on link', () => {
|
||||
const emitClickOnLinkSpy = spyOn(component, 'emitClickOnLink');
|
||||
component.navigationItems = [...navigationItems];
|
||||
fixture.componentRef.setInput('navigationItems', [...navigationItems]);
|
||||
fixture.detectChanges(true);
|
||||
|
||||
const guideLink = fixture.debugElement.query(By.css('a[href="/guide"]'));
|
||||
@@ -102,7 +104,7 @@ describe('NavigationList', () => {
|
||||
const toggleItemSpy = spyOn(navigationState, 'toggleItem');
|
||||
const itemToToggle = navigationItems[1];
|
||||
|
||||
component.expandableLevel = 1;
|
||||
fixture.componentRef.setInput('expandableLevel', 1);
|
||||
component.toggle(itemToToggle);
|
||||
|
||||
expect(toggleItemSpy).toHaveBeenCalledOnceWith(itemToToggle);
|
||||
@@ -113,15 +115,15 @@ describe('NavigationList', () => {
|
||||
const toggleItemSpy = spyOn(navigationState, 'toggleItem');
|
||||
const itemToToggle = navigationItems[1].children![1];
|
||||
|
||||
component.collapsableLevel = 2;
|
||||
fixture.componentRef.setInput('collapsableLevel', 2);
|
||||
component.toggle(itemToToggle);
|
||||
|
||||
expect(toggleItemSpy).toHaveBeenCalledOnceWith(itemToToggle);
|
||||
});
|
||||
|
||||
it('should display items to provided level', () => {
|
||||
component.navigationItems = [...navigationItems];
|
||||
component.displayItemsToLevel = 1;
|
||||
fixture.componentRef.setInput('navigationItems', [...navigationItems]);
|
||||
fixture.componentRef.setInput('displayItemsToLevel', 1);
|
||||
fixture.detectChanges(true);
|
||||
|
||||
const visibleItems = fixture.debugElement.queryAll(
|
||||
|
||||
@@ -6,14 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
Output,
|
||||
inject,
|
||||
} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, inject, input, output} from '@angular/core';
|
||||
import {NavigationItem} from '../../interfaces/index';
|
||||
import {NavigationState} from '../../services/index';
|
||||
import {RouterLink, RouterLinkActive} from '@angular/router';
|
||||
@@ -30,24 +23,23 @@ import {IsActiveNavigationItem} from '../../pipes/is-active-navigation-item.pipe
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class NavigationList {
|
||||
@Input({required: true}) navigationItems: NavigationItem[] = [];
|
||||
@Input() displayItemsToLevel: number = 2;
|
||||
@Input() collapsableLevel: number | undefined = undefined;
|
||||
@Input() expandableLevel: number = 2;
|
||||
@Input() isDropdownView = false;
|
||||
readonly navigationItems = input.required<NavigationItem[]>();
|
||||
readonly displayItemsToLevel = input<number>(2);
|
||||
readonly collapsableLevel = input<number | undefined>();
|
||||
readonly expandableLevel = input<number>(2);
|
||||
readonly isDropdownView = input<boolean>(false);
|
||||
|
||||
@Output() linkClicked = new EventEmitter<void>();
|
||||
readonly linkClicked = output<void>();
|
||||
|
||||
private readonly navigationState = inject(NavigationState);
|
||||
|
||||
expandedItems = this.navigationState.expandedItems;
|
||||
activeItem = this.navigationState.activeNavigationItem;
|
||||
readonly activeItem = this.navigationState.activeNavigationItem;
|
||||
|
||||
toggle(item: NavigationItem): void {
|
||||
if (
|
||||
item.level === 1 &&
|
||||
item.level !== this.expandableLevel &&
|
||||
item.level !== this.collapsableLevel
|
||||
item.level !== this.expandableLevel() &&
|
||||
item.level !== this.collapsableLevel()
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
(ngModelChange)="updateSearchQuery($event)"
|
||||
class="docs-search-input"
|
||||
placeholder="Search docs"
|
||||
></docs-text-field>
|
||||
/>
|
||||
|
||||
@if (searchResults() && searchResults()!.length > 0) {
|
||||
<ul class="docs-search-results docs-mini-scroll-track">
|
||||
@@ -31,7 +31,7 @@
|
||||
<ng-container
|
||||
[ngTemplateOutlet]="highlightSnippet"
|
||||
[ngTemplateOutletContext]="{snippet}"
|
||||
></ng-container>
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
<ng-container
|
||||
[ngTemplateOutlet]="highlightSnippet"
|
||||
[ngTemplateOutletContext]="{snippet}"
|
||||
></ng-container>
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
@@ -70,7 +70,8 @@
|
||||
|
||||
<div class="docs-algolia">
|
||||
<span>Search by</span>
|
||||
<a href="https://www.algolia.com/developers/" target="_blank" rel="noopener">
|
||||
<a target="_blank" rel="noopener"
|
||||
href="https://www.algolia.com/developers/?utm_source=angular.dev&utm_medium=referral&utm_content=powered_by&utm_campaign=docsearch">
|
||||
<docs-algolia-icon />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
<select [attr.id]="id" [attr.name]="name" [ngModel]="selectedOption()" (ngModelChange)="setOption($event)">
|
||||
@for (item of options; track item) {
|
||||
<select
|
||||
[attr.id]="id()"
|
||||
[attr.name]="name()"
|
||||
[ngModel]="selectedOption()"
|
||||
(ngModelChange)="setOption($event)"
|
||||
>
|
||||
@for (item of options(); track item) {
|
||||
<option [value]="item.value">{{ item.label }}</option>
|
||||
}
|
||||
</select>
|
||||
|
||||
@@ -22,6 +22,12 @@ describe('Select', () => {
|
||||
});
|
||||
fixture = TestBed.createComponent(Select);
|
||||
component = fixture.componentInstance;
|
||||
|
||||
// Sets the required inputs
|
||||
fixture.componentRef.setInput('selectId', 'id');
|
||||
fixture.componentRef.setInput('name', 'name');
|
||||
fixture.componentRef.setInput('options', []);
|
||||
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {ControlValueAccessor, NG_VALUE_ACCESSOR, FormsModule} from '@angular/forms';
|
||||
import {ChangeDetectionStrategy, Component, Input, forwardRef, signal} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, model, forwardRef, input, signal} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
|
||||
type SelectOptionValue = string | number | boolean;
|
||||
@@ -36,10 +36,10 @@ export interface SelectOption {
|
||||
},
|
||||
})
|
||||
export class Select implements ControlValueAccessor {
|
||||
@Input({required: true, alias: 'selectId'}) id!: string;
|
||||
@Input({required: true}) name!: string;
|
||||
@Input({required: true}) options!: SelectOption[];
|
||||
@Input() disabled = false;
|
||||
readonly id = input.required<string>({alias: 'selectId'});
|
||||
readonly name = input.required<string>();
|
||||
readonly options = input.required<SelectOption[]>();
|
||||
readonly disabled = model<boolean>(false);
|
||||
|
||||
// Implemented as part of ControlValueAccessor.
|
||||
private onChange: (value: SelectOptionValue) => void = (_: SelectOptionValue) => {};
|
||||
@@ -64,11 +64,11 @@ export class Select implements ControlValueAccessor {
|
||||
|
||||
// Implemented as part of ControlValueAccessor.
|
||||
setDisabledState?(isDisabled: boolean): void {
|
||||
this.disabled = isDisabled;
|
||||
this.disabled.set(isDisabled);
|
||||
}
|
||||
|
||||
setOption($event: SelectOptionValue): void {
|
||||
if (this.disabled) {
|
||||
if (this.disabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<label [attr.for]="buttonId">
|
||||
<span class="docs-label">{{ label }}</span>
|
||||
<label [attr.for]="buttonId()">
|
||||
<span class="docs-label">{{ label() }}</span>
|
||||
<div class="docs-toggle">
|
||||
<input
|
||||
type="checkbox"
|
||||
[id]="buttonId"
|
||||
[id]="buttonId()"
|
||||
role="switch"
|
||||
(click)="toggle()"
|
||||
[class.docs-toggle-active]="checked()"
|
||||
|
||||
@@ -21,6 +21,8 @@ describe('SlideToggle', () => {
|
||||
providers: [provideExperimentalZonelessChangeDetection()],
|
||||
});
|
||||
fixture = TestBed.createComponent(SlideToggle);
|
||||
fixture.componentRef.setInput('buttonId', 'id');
|
||||
fixture.componentRef.setInput('label', 'foo');
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {ChangeDetectionStrategy, Component, Input, forwardRef, signal} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, forwardRef, model, input, signal} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
|
||||
|
||||
@@ -26,9 +26,9 @@ import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
|
||||
],
|
||||
})
|
||||
export class SlideToggle implements ControlValueAccessor {
|
||||
@Input({required: true}) buttonId!: string;
|
||||
@Input({required: true}) label!: string;
|
||||
@Input() disabled = false;
|
||||
readonly buttonId = input.required<string>();
|
||||
readonly label = input.required<string>();
|
||||
readonly disabled = model<boolean>(false);
|
||||
|
||||
// Implemented as part of ControlValueAccessor.
|
||||
private onChange: (value: boolean) => void = (_: boolean) => {};
|
||||
@@ -53,12 +53,12 @@ export class SlideToggle implements ControlValueAccessor {
|
||||
|
||||
// Implemented as part of ControlValueAccessor.
|
||||
setDisabledState(isDisabled: boolean): void {
|
||||
this.disabled = isDisabled;
|
||||
this.disabled.set(isDisabled);
|
||||
}
|
||||
|
||||
// Toggles the checked state of the slide-toggle.
|
||||
toggle(): void {
|
||||
if (this.disabled) {
|
||||
if (this.disabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,8 @@ describe('TableOfContents', () => {
|
||||
spyOn(tableOfContentsLoaderSpy, 'buildTableOfContent').and.returnValue();
|
||||
tableOfContentsLoaderSpy.tableOfContentItems.set(items);
|
||||
fixture = TestBed.createComponent(TableOfContents);
|
||||
fixture.componentRef.setInput('contentSourceElement', document.createElement('div'));
|
||||
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
DestroyRef,
|
||||
Input,
|
||||
input,
|
||||
computed,
|
||||
inject,
|
||||
} from '@angular/core';
|
||||
@@ -30,7 +30,7 @@ import {IconComponent} from '../icon/icon.component';
|
||||
})
|
||||
export class TableOfContents {
|
||||
// Element that contains the content from which the Table of Contents is built
|
||||
@Input({required: true}) contentSourceElement!: HTMLElement;
|
||||
readonly contentSourceElement = input.required<HTMLElement>();
|
||||
|
||||
private readonly scrollSpy = inject(TableOfContentsScrollSpy);
|
||||
private readonly tableOfContentsLoader = inject(TableOfContentsLoader);
|
||||
@@ -43,8 +43,8 @@ export class TableOfContents {
|
||||
TableOfContentsLevel = TableOfContentsLevel;
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.tableOfContentsLoader.buildTableOfContent(this.contentSourceElement);
|
||||
this.scrollSpy.startListeningToScroll(this.contentSourceElement, this.destroyRef);
|
||||
this.tableOfContentsLoader.buildTableOfContent(this.contentSourceElement());
|
||||
this.scrollSpy.startListeningToScroll(this.contentSourceElement(), this.destroyRef);
|
||||
}
|
||||
|
||||
scrollToTop(): void {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
@if (!hideIcon) {
|
||||
<docs-icon class="docs-icon_high-contrast">search</docs-icon>
|
||||
@if (!hideIcon()) {
|
||||
<docs-icon class="docs-icon_high-contrast">search</docs-icon>
|
||||
}
|
||||
<input
|
||||
#inputRef
|
||||
type="text"
|
||||
[attr.placeholder]="placeholder"
|
||||
[attr.name]="name"
|
||||
[attr.placeholder]="placeholder()"
|
||||
[attr.name]="name()"
|
||||
[ngModel]="value()"
|
||||
(ngModelChange)="setValue($event)"
|
||||
class="docs-text-field"
|
||||
|
||||
@@ -10,11 +10,12 @@ import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
ElementRef,
|
||||
Input,
|
||||
ViewChild,
|
||||
input,
|
||||
afterNextRender,
|
||||
forwardRef,
|
||||
signal,
|
||||
model,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR} from '@angular/forms';
|
||||
@@ -39,13 +40,13 @@ import {IconComponent} from '../icon/icon.component';
|
||||
},
|
||||
})
|
||||
export class TextField implements ControlValueAccessor {
|
||||
@ViewChild('inputRef') private input?: ElementRef<HTMLInputElement>;
|
||||
readonly input = viewChild.required<ElementRef<HTMLInputElement>>('inputRef');
|
||||
|
||||
@Input() name: string | null = null;
|
||||
@Input() placeholder: string | null = null;
|
||||
@Input() disabled = false;
|
||||
@Input() hideIcon = false;
|
||||
@Input() autofocus = false;
|
||||
readonly name = input<string | null>(null);
|
||||
readonly placeholder = input<string | null>(null);
|
||||
readonly disabled = model<boolean>(false);
|
||||
readonly hideIcon = input<boolean>(false);
|
||||
readonly autofocus = input<boolean>(false);
|
||||
|
||||
// Implemented as part of ControlValueAccessor.
|
||||
private onChange: (value: string) => void = (_: string) => {};
|
||||
@@ -55,8 +56,8 @@ export class TextField implements ControlValueAccessor {
|
||||
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
if (this.autofocus) {
|
||||
this.input?.nativeElement.focus();
|
||||
if (this.autofocus()) {
|
||||
this.input().nativeElement.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -78,11 +79,11 @@ export class TextField implements ControlValueAccessor {
|
||||
|
||||
// Implemented as part of ControlValueAccessor.
|
||||
setDisabledState?(isDisabled: boolean): void {
|
||||
this.disabled = isDisabled;
|
||||
this.disabled.set(isDisabled);
|
||||
}
|
||||
|
||||
setValue(value: string): void {
|
||||
if (this.disabled) {
|
||||
if (this.disabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
@if (!hasClosed()) {
|
||||
@if (link()) {
|
||||
<a [href]="link()" class="docs-top-level-banner">
|
||||
<h1 tabindex="-1" class="docs-top-level-banner-cta background">{{ text() }}</h1>
|
||||
<h1 tabindex="0" class="docs-top-level-banner-cta shimmer">{{ text() }}</h1>
|
||||
</a>
|
||||
} @else {
|
||||
<div class="docs-top-level-banner">
|
||||
<h1 tabindex="-1" class="docs-top-level-banner-cta background">{{ text() }}</h1>
|
||||
<h1 tabindex="0" class="docs-top-level-banner-cta shimmer">{{ text() }}</h1>
|
||||
</div>
|
||||
}
|
||||
|
||||
<button class="docs-top-level-banner-close" type="button" (click)="close()">
|
||||
<docs-icon class="docs-icon_high-contrast">close</docs-icon>
|
||||
</button>
|
||||
@if (link()) {
|
||||
<a [href]="link()" class="docs-top-level-banner">
|
||||
<h1 tabindex="-1" class="docs-top-level-banner-cta shimmer">{{ text() }}</h1>
|
||||
<h1 tabindex="0" class="docs-top-level-banner-cta background"><span class="docs-top-level-banner-cta__text">{{ text()
|
||||
}}</span></h1>
|
||||
</a>
|
||||
} @else {
|
||||
<div class="docs-top-level-banner">
|
||||
<h1 tabindex="-1" class="docs-top-level-banner-cta shimmer">{{ text() }}</h1>
|
||||
<h1 tabindex="0" class="docs-top-level-banner-cta background"><span class="docs-top-level-banner-cta__text">{{ text()
|
||||
}}</span></h1>
|
||||
</div>
|
||||
}
|
||||
|
||||
<button class="docs-top-level-banner-close" type="button" (click)="close()">
|
||||
<docs-icon class="docs-icon_high-contrast">close</docs-icon>
|
||||
</button>
|
||||
}
|
||||
@@ -1,9 +1,13 @@
|
||||
:host {
|
||||
&:not(:empty) {
|
||||
z-index: 50;
|
||||
z-index: var(--z-index-top-level-banner);
|
||||
position: fixed;
|
||||
height: 2rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: auto;
|
||||
width: 100vw;
|
||||
padding: .5rem;
|
||||
border-bottom: 1px solid var(--septenary-contrast);
|
||||
text-align: center;
|
||||
align-content: center;
|
||||
@@ -12,16 +16,22 @@
|
||||
}
|
||||
|
||||
a.docs-top-level-banner {
|
||||
width: 100%;
|
||||
display: inherit;
|
||||
display: grid;
|
||||
width: auto;
|
||||
margin: 0rem 2.5rem;
|
||||
|
||||
&:hover{
|
||||
h1.docs-top-level-banner-cta.background{
|
||||
span.docs-top-level-banner-cta__text::after{
|
||||
transform: scaleX(1);
|
||||
transform-origin: bottom left;
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
h1.docs-top-level-banner-cta {
|
||||
display: inline;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
grid-row-start: 1;
|
||||
grid-column-start: 1;
|
||||
font-size: 0.875rem;
|
||||
margin: 0;
|
||||
width: fit-content;
|
||||
@@ -29,45 +39,46 @@
|
||||
|
||||
&.background {
|
||||
color: var(--tertiary-contrast);
|
||||
|
||||
& .docs-top-level-banner-cta__text{
|
||||
position:relative;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: calc(100% + 2rem);
|
||||
height: 1px;
|
||||
bottom: -2px;
|
||||
left: -1rem;
|
||||
background: var(--tertiary-contrast);
|
||||
transform: scaleX(0);
|
||||
transform-origin: bottom right;
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&:not(.background) {
|
||||
color: transparent;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
bottom: -2px;
|
||||
left: 0;
|
||||
background: var(--tertiary-contrast);
|
||||
transform: scaleX(0);
|
||||
transform-origin: bottom right;
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&::after {
|
||||
transform: scaleX(1);
|
||||
transform-origin: bottom left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.docs-top-level-banner-close {
|
||||
position: absolute;
|
||||
top: 0.25rem;
|
||||
right: 0.5rem;
|
||||
right: 1.4rem;
|
||||
color: var(--tertiary-contrast);
|
||||
padding-left: 0rem;
|
||||
}
|
||||
}
|
||||
|
||||
.shimmer {
|
||||
background: var(--red-to-pink-to-purple-horizontal-gradient);
|
||||
z-index: 1;
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
background-repeat: no-repeat;
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
h5,
|
||||
h6 {
|
||||
.docs-anchor {
|
||||
margin-block-start: 2.5rem;
|
||||
margin-block-start: 0.75rem;
|
||||
display: inline-block;
|
||||
color: inherit;
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import {By} from '@angular/platform-browser';
|
||||
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {RouterTestingModule} from '@angular/router/testing';
|
||||
import {provideNoopAnimations} from '@angular/platform-browser/animations';
|
||||
import {provideRouter} from '@angular/router';
|
||||
import {ExampleViewerContentLoader} from '../../../interfaces';
|
||||
import {EXAMPLE_VIEWER_CONTENT_LOADER} from '../../../providers';
|
||||
import {CodeExampleViewMode, ExampleViewer} from '../example-viewer/example-viewer.component';
|
||||
@@ -80,8 +80,10 @@ describe('DocViewer', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [DocViewer, NoopAnimationsModule, RouterTestingModule],
|
||||
imports: [DocViewer],
|
||||
providers: [
|
||||
provideNoopAnimations(),
|
||||
provideRouter([]),
|
||||
provideExperimentalZonelessChangeDetection(),
|
||||
{provide: EXAMPLE_VIEWER_CONTENT_LOADER, useValue: exampleContentSpy},
|
||||
{provide: NavigationState, useValue: navigationStateSpy},
|
||||
|
||||
@@ -26,8 +26,7 @@ import {
|
||||
ViewContainerRef,
|
||||
ViewEncapsulation,
|
||||
ɵPendingTasks as PendingTasks,
|
||||
EventEmitter,
|
||||
Output,
|
||||
output,
|
||||
} from '@angular/core';
|
||||
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
|
||||
import {TOC_SKIP_CONTENT_MARKER, NavigationState} from '../../../services/index';
|
||||
@@ -68,7 +67,7 @@ export const GITHUB_CONTENT_URL =
|
||||
export class DocViewer implements OnChanges {
|
||||
@Input() docContent?: string;
|
||||
@Input() hasToc = false;
|
||||
@Output() contentLoaded = new EventEmitter<void>();
|
||||
readonly contentLoaded = output<void>();
|
||||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
private readonly document = inject(DOCUMENT);
|
||||
@@ -134,7 +133,7 @@ export class DocViewer implements OnChanges {
|
||||
// Render ToC
|
||||
this.renderTableOfContents(contentContainer);
|
||||
|
||||
this.contentLoaded.next();
|
||||
this.contentLoaded.emit();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,7 +11,7 @@ import {ExampleViewer} from './example-viewer.component';
|
||||
import {DocsContentLoader, ExampleMetadata, ExampleViewerContentLoader} from '../../../interfaces';
|
||||
import {DOCS_CONTENT_LOADER, EXAMPLE_VIEWER_CONTENT_LOADER} from '../../../providers';
|
||||
import {Component, provideExperimentalZonelessChangeDetection} from '@angular/core';
|
||||
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {provideNoopAnimations} from '@angular/platform-browser/animations';
|
||||
import {HarnessLoader} from '@angular/cdk/testing';
|
||||
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
|
||||
import {Clipboard} from '@angular/cdk/clipboard';
|
||||
@@ -35,8 +35,9 @@ describe('ExampleViewer', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [ExampleViewer, NoopAnimationsModule],
|
||||
imports: [ExampleViewer],
|
||||
providers: [
|
||||
provideNoopAnimations(),
|
||||
provideExperimentalZonelessChangeDetection(),
|
||||
{provide: EXAMPLE_VIEWER_CONTENT_LOADER, useValue: exampleContentSpy},
|
||||
{provide: DOCS_CONTENT_LOADER, useValue: contentServiceSpy},
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {DOCUMENT} from '@angular/common';
|
||||
import {Directive, ElementRef, EventEmitter, Input, Output, inject} from '@angular/core';
|
||||
import {Directive, ElementRef, Input, inject, output} from '@angular/core';
|
||||
|
||||
@Directive({
|
||||
selector: '[docsClickOutside]',
|
||||
@@ -18,7 +18,7 @@ import {Directive, ElementRef, EventEmitter, Input, Output, inject} from '@angul
|
||||
})
|
||||
export class ClickOutside {
|
||||
@Input('docsClickOutsideIgnore') public ignoredElementsIds: string[] = [];
|
||||
@Output('docsClickOutside') public clickOutside = new EventEmitter<void>();
|
||||
public readonly clickOutside = output<void>({alias: 'docsClickOutside'});
|
||||
|
||||
private readonly document = inject(DOCUMENT);
|
||||
private readonly elementRef = inject(ElementRef<HTMLElement>);
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
"name": "@angular/docs",
|
||||
"version": "0.0.0-PLACEHOLDER",
|
||||
"peerDependencies": {
|
||||
"@angular/cdk": "^19.0.0-next",
|
||||
"@angular/common": "^19.0.0-next",
|
||||
"@angular/core": "^19.0.0-next",
|
||||
"@angular/forms": "^19.0.0-next",
|
||||
"@angular/material": "^19.0.0-next",
|
||||
"@angular/platform-browser": "^19.0.0-next",
|
||||
"@angular/router": "^19.0.0-next",
|
||||
"@angular/ssr": "^19.0.0-next",
|
||||
"@angular/cdk": "^19.0.0",
|
||||
"@angular/common": "^19.0.0",
|
||||
"@angular/core": "^19.0.0",
|
||||
"@angular/forms": "^19.0.0",
|
||||
"@angular/material": "^19.0.0",
|
||||
"@angular/platform-browser": "^19.0.0",
|
||||
"@angular/router": "^19.0.0",
|
||||
"@angular/ssr": "^19.0.0",
|
||||
"algoliasearch": "^5.0.0",
|
||||
"rxjs": "^7.8.1"
|
||||
},
|
||||
@@ -21,7 +21,7 @@
|
||||
"fflate": "^0.8.2",
|
||||
"html-entities": "~2.5.2",
|
||||
"jsdom": "~25.0.0",
|
||||
"marked": "~14.1.0",
|
||||
"marked": "~15.0.0",
|
||||
"mermaid": "^11.0.0",
|
||||
"shiki": "^1.10.3"
|
||||
},
|
||||
|
||||
@@ -52,6 +52,8 @@ function main() {
|
||||
rootDir: '.',
|
||||
skipLibCheck: true,
|
||||
target: ts.ScriptTarget.ES2022,
|
||||
// This is necessary because otherwise types that include `| null` are not included in the documentation.
|
||||
strictNullChecks: true,
|
||||
moduleResolution: ts.ModuleResolutionKind.NodeNext,
|
||||
experimentalDecorators: true,
|
||||
};
|
||||
|
||||
@@ -94,7 +94,9 @@ export interface ConstantEntry extends DocEntry {
|
||||
}
|
||||
|
||||
/** Documentation entity for a type alias. */
|
||||
export type TypeAliasEntry = ConstantEntry;
|
||||
export interface TypeAliasEntry extends ConstantEntry {
|
||||
generics: GenericEntry[];
|
||||
}
|
||||
|
||||
/** Documentation entity for a TypeScript class. */
|
||||
export interface ClassEntry extends DocEntry {
|
||||
|
||||
@@ -21,11 +21,7 @@ export async function initHighlighter() {
|
||||
});
|
||||
}
|
||||
|
||||
export function codeToHtml(
|
||||
code: string,
|
||||
language: string | undefined,
|
||||
options?: {removeFunctionKeyword?: boolean},
|
||||
): string {
|
||||
export function codeToHtml(code: string, language: string | undefined): string {
|
||||
const html = highlighter.codeToHtml(code, {
|
||||
lang: language ?? 'text',
|
||||
themes: {
|
||||
@@ -36,9 +32,6 @@ export function codeToHtml(
|
||||
defaultColor: false,
|
||||
});
|
||||
|
||||
if (options?.removeFunctionKeyword) {
|
||||
return replaceKeywordFromShikiHtml('function', html);
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,6 @@ export const signatureCard = (
|
||||
// Always omit types in signature headers, to keep them short.
|
||||
true,
|
||||
)}
|
||||
removeFunctionKeyword={true}
|
||||
/>
|
||||
</code>
|
||||
) : (
|
||||
|
||||
@@ -11,10 +11,8 @@ import {RawHtml} from './raw-html';
|
||||
import {codeToHtml} from '../shiki/shiki';
|
||||
|
||||
/** Component to render a header of the CLI page. */
|
||||
export function HighlightTypeScript(props: {code: string; removeFunctionKeyword?: boolean}) {
|
||||
const result = codeToHtml(props.code, 'typescript', {
|
||||
removeFunctionKeyword: props.removeFunctionKeyword,
|
||||
});
|
||||
export function HighlightTypeScript(props: {code: string; }) {
|
||||
const result = codeToHtml(props.code, 'typescript');
|
||||
|
||||
return <RawHtml value={result} />;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import {makeGenericsText} from '../../transforms/code-transforms';
|
||||
|
||||
describe('makeGenericsText', () => {
|
||||
it('should return an empty string if no generics are provided', () => {
|
||||
expect(makeGenericsText(undefined)).toBe('');
|
||||
expect(makeGenericsText([])).toBe('');
|
||||
});
|
||||
|
||||
it('should return a single generic type without constraints or default', () => {
|
||||
const generics = [{name: 'T', constraint: undefined, default: undefined}];
|
||||
expect(makeGenericsText(generics)).toBe('<T>');
|
||||
});
|
||||
|
||||
it('should handle a single generic type with a constraint', () => {
|
||||
const generics = [{name: 'T', constraint: 'string', default: undefined}];
|
||||
expect(makeGenericsText(generics)).toBe('<T extends string>');
|
||||
});
|
||||
|
||||
it('should handle a single generic type with a default value', () => {
|
||||
const generics = [{name: 'T', default: 'number', constraint: undefined}];
|
||||
expect(makeGenericsText(generics)).toBe('<T = number>');
|
||||
});
|
||||
|
||||
it('should handle a single generic type with both constraint and default value', () => {
|
||||
const generics = [{name: 'T', constraint: 'string', default: 'number'}];
|
||||
expect(makeGenericsText(generics)).toBe('<T extends string = number>');
|
||||
});
|
||||
|
||||
it('should handle multiple generic types without constraints or defaults', () => {
|
||||
const generics = [
|
||||
{name: 'T', constraint: undefined, default: undefined},
|
||||
{name: 'U', constraint: undefined, default: undefined},
|
||||
];
|
||||
expect(makeGenericsText(generics)).toBe('<T, U>');
|
||||
});
|
||||
|
||||
it('should handle multiple generic types with constraints and defaults', () => {
|
||||
const generics = [
|
||||
{name: 'T', constraint: 'string', default: 'number'},
|
||||
{name: 'U', constraint: 'boolean', default: undefined},
|
||||
{name: 'V', default: 'any', constraint: undefined},
|
||||
];
|
||||
expect(makeGenericsText(generics)).toBe(
|
||||
'<T extends string = number, U extends boolean, V = any>',
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle complex generics with mixed constraints and defaults', () => {
|
||||
const generics = [
|
||||
{name: 'A', constraint: 'string', default: undefined},
|
||||
{name: 'B', constraint: undefined, default: undefined},
|
||||
{name: 'C', default: 'number', constraint: undefined},
|
||||
{name: 'D', constraint: 'boolean', default: 'true'},
|
||||
];
|
||||
expect(makeGenericsText(generics)).toBe(
|
||||
'<A extends string, B, C = number, D extends boolean = true>',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -9,6 +9,7 @@
|
||||
import {
|
||||
DocEntry,
|
||||
FunctionSignatureMetadata,
|
||||
GenericEntry,
|
||||
MemberEntry,
|
||||
MemberTags,
|
||||
ParameterEntry,
|
||||
@@ -66,9 +67,7 @@ export function addRenderableCodeToc<T extends DocEntry & HasModuleName>(
|
||||
const metadata = mapDocEntryToCode(entry);
|
||||
appendPrefixAndSuffix(entry, metadata);
|
||||
|
||||
let codeWithSyntaxHighlighting = codeToHtml(metadata.contents, 'typescript', {
|
||||
removeFunctionKeyword: true,
|
||||
});
|
||||
let codeWithSyntaxHighlighting = codeToHtml(metadata.contents, 'typescript');
|
||||
|
||||
if (isDecoratorEntry(entry)) {
|
||||
// Shiki requires a keyword for correct formating of Decorators
|
||||
@@ -242,7 +241,8 @@ export function mapDocEntryToCode(entry: DocEntry): CodeTableOfContentsData {
|
||||
}
|
||||
|
||||
if (isTypeAliasEntry(entry)) {
|
||||
const contents = `type ${entry.name} = ${entry.type}`;
|
||||
const generics = makeGenericsText(entry.generics);
|
||||
const contents = `type ${entry.name}${generics} = ${entry.type}`;
|
||||
|
||||
if (isDeprecated) {
|
||||
const numberOfLinesOfCode = getNumberOfLinesOfCode(contents);
|
||||
@@ -332,8 +332,10 @@ function getMethodCodeLine(
|
||||
displayParamsInNewLines: boolean = false,
|
||||
isFunction: boolean = false,
|
||||
): string {
|
||||
const generics = makeGenericsText(member.generics);
|
||||
|
||||
displayParamsInNewLines &&= member.params.length > 0;
|
||||
return `${isFunction ? 'function' : ''}${memberTags.join(' ')} ${member.name}(${displayParamsInNewLines ? '\n ' : ''}${member.params
|
||||
return `${isFunction ? 'function' : ''}${memberTags.join(' ')} ${member.name}${generics}(${displayParamsInNewLines ? '\n ' : ''}${member.params
|
||||
.map((param) => mapParamEntry(param))
|
||||
.join(`,${displayParamsInNewLines ? '\n ' : ' '}`)}${
|
||||
displayParamsInNewLines ? '\n' : ''
|
||||
@@ -442,13 +444,7 @@ function appendPrefixAndSuffix(entry: DocEntry, codeTocData: CodeTableOfContents
|
||||
};
|
||||
|
||||
if (isClassEntry(entry) || isInterfaceEntry(entry)) {
|
||||
const generics =
|
||||
entry.generics?.length > 0
|
||||
? `<${entry.generics
|
||||
.map((g) => (g.constraint ? `${g.name} extends ${g.constraint}` : g.name))
|
||||
.join(', ')}>`
|
||||
: '';
|
||||
|
||||
const generics = makeGenericsText(entry.generics);
|
||||
const extendsStr = entry.extends ? ` extends ${entry.extends}` : '';
|
||||
// TODO: remove the ? when we distinguish Class & Decorator entries
|
||||
const implementsStr =
|
||||
@@ -501,3 +497,45 @@ export function addApiLinksToHtml(htmlString: string): string {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a TypeScript generics string based on an array of generic type entries.
|
||||
*
|
||||
* This function takes an array of generic type entries and returns a formatted string
|
||||
* representing TypeScript generics syntax, including any constraints and default values
|
||||
* specified in each entry.
|
||||
*
|
||||
* @param generics - An array of `GenericEntry` objects representing the generics to be formatted,
|
||||
* or `undefined` if there are no generics.
|
||||
*
|
||||
* @returns A formatted string representing TypeScript generics syntax, or an empty string if no generics are provided.
|
||||
*/
|
||||
export function makeGenericsText(generics: GenericEntry[] | undefined): string {
|
||||
if (!generics?.length) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const parts: string[] = ['<'];
|
||||
|
||||
for (let index = 0; index < generics.length; index++) {
|
||||
const {constraint, default: defaultVal, name} = generics[index];
|
||||
|
||||
parts.push(name);
|
||||
|
||||
if (constraint) {
|
||||
parts.push(' extends ', constraint);
|
||||
}
|
||||
|
||||
if (defaultVal !== undefined) {
|
||||
parts.push(' = ', defaultVal);
|
||||
}
|
||||
|
||||
if (index < generics.length - 1) {
|
||||
parts.push(', ');
|
||||
}
|
||||
}
|
||||
|
||||
parts.push('>');
|
||||
|
||||
return parts.join('');
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import {getLinkToModule} from './url-transforms';
|
||||
import {addApiLinksToHtml} from './code-transforms';
|
||||
import {getCurrentSymbol, getModuleName, logUnknownSymbol} from '../symbol-context';
|
||||
|
||||
export const JS_DOC_REMARKS_TAG = 'remarks';
|
||||
export const JS_DOC_USAGE_NOTES_TAG = 'usageNotes';
|
||||
export const JS_DOC_SEE_TAG = 'see';
|
||||
export const JS_DOC_DESCRIPTION_TAG = 'description';
|
||||
@@ -96,7 +97,9 @@ export function addHtmlAdditionalLinks<T extends HasJsDocTags & HasModuleName>(
|
||||
}
|
||||
|
||||
export function addHtmlUsageNotes<T extends HasJsDocTags>(entry: T): T & HasHtmlUsageNotes {
|
||||
const usageNotesTag = entry.jsdocTags.find((tag) => tag.name === JS_DOC_USAGE_NOTES_TAG);
|
||||
const usageNotesTag = entry.jsdocTags.find(
|
||||
({name}) => name === JS_DOC_USAGE_NOTES_TAG || name === JS_DOC_REMARKS_TAG,
|
||||
);
|
||||
const htmlUsageNotes = usageNotesTag
|
||||
? (marked.parse(
|
||||
convertJsDocExampleToHtmlExample(wrapExampleHtmlElementsWithCode(usageNotesTag.comment)),
|
||||
|
||||
@@ -10,22 +10,22 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^16.1.1",
|
||||
"@angular/common": "^16.1.1",
|
||||
"@angular/compiler": "^16.1.1",
|
||||
"@angular/core": "^16.1.1",
|
||||
"@angular/forms": "^16.1.1",
|
||||
"@angular/platform-browser": "^16.1.1",
|
||||
"@angular/platform-browser-dynamic": "^16.1.1",
|
||||
"@angular/router": "^16.1.1",
|
||||
"@angular/animations": "^19.0.0",
|
||||
"@angular/common": "^19.0.0",
|
||||
"@angular/compiler": "^19.0.0",
|
||||
"@angular/core": "^19.0.0",
|
||||
"@angular/forms": "^19.0.0",
|
||||
"@angular/platform-browser": "^19.0.0",
|
||||
"@angular/platform-browser-dynamic": "^19.0.0",
|
||||
"@angular/router": "^19.0.0",
|
||||
"rxjs": "~7.4.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^16.1.0",
|
||||
"@angular/cli": "^16.1.0",
|
||||
"@angular/compiler-cli": "^16.1.1",
|
||||
"@angular-devkit/build-angular": "^19.0.0",
|
||||
"@angular/cli": "^19.0.0",
|
||||
"@angular/compiler-cli": "^19.0.0",
|
||||
"@types/jasmine": "~3.10.0",
|
||||
"@types/node": "^12.11.1",
|
||||
"jasmine-core": "~3.10.0",
|
||||
@@ -34,6 +34,6 @@
|
||||
"karma-coverage": "~2.0.3",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.1.0",
|
||||
"typescript": "~5.0.3"
|
||||
"typescript": "~5.6.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,18 +9,18 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/common": "^17.0.0-rc.1",
|
||||
"@angular/compiler": "^17.0.0-rc.1",
|
||||
"@angular/core": "^17.0.0-rc.1",
|
||||
"@angular/platform-browser": "^17.0.0-rc.1",
|
||||
"@angular/common": "^19.0.0",
|
||||
"@angular/compiler": "^19.0.0",
|
||||
"@angular/core": "^19.0.0",
|
||||
"@angular/platform-browser": "^19.0.0",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.14.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^17.0.0-rc.2",
|
||||
"@angular/cli": "^17.0.0-rc.2",
|
||||
"@angular/compiler-cli": "^17.0.0-rc.1",
|
||||
"typescript": "~5.2.0"
|
||||
"@angular-devkit/build-angular": "^19.0.0",
|
||||
"@angular/cli": "^19.0.0",
|
||||
"@angular/compiler-cli": "^19.0.0",
|
||||
"typescript": "~5.6.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
:root {
|
||||
--z-index-mini-menu: 200;
|
||||
--z-index-top-level-banner: 150;
|
||||
--z-index-nav: 100;
|
||||
--z-index-cookie-consent: 60;
|
||||
--z-index-content: 50;
|
||||
|
||||
@@ -276,6 +276,12 @@
|
||||
overflow-x: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
pre > * {
|
||||
min-width: 100%;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// TODO: Continue organizing and refactoring this file
|
||||
@use '@angular/material' as mat;
|
||||
@use '@angular/cdk';
|
||||
|
||||
// Using disable-next-line to avoid stylelint errors - these imports are necessary
|
||||
// TODO: Is there another way to prevent these linting errors?
|
||||
@@ -61,7 +62,7 @@ $theme: mat.m2-define-light-theme(
|
||||
);
|
||||
|
||||
// Include material core styles.
|
||||
@include mat.core();
|
||||
@include cdk.a11y-visually-hidden();
|
||||
@include mat.tabs-theme($theme);
|
||||
@include mat.button-toggle-theme($theme);
|
||||
@include mat.tooltip-theme($theme);
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
FileSystemTree,
|
||||
IFSWatcher,
|
||||
PortListener,
|
||||
PreviewMessageListener,
|
||||
ServerReadyListener,
|
||||
Unsubscribe,
|
||||
WebContainer,
|
||||
@@ -98,6 +99,7 @@ export class FakeWebContainer extends WebContainer {
|
||||
override on(event: 'port', listener: PortListener): Unsubscribe;
|
||||
override on(event: 'server-ready', listener: ServerReadyListener): Unsubscribe;
|
||||
override on(event: 'error', listener: ErrorListener): Unsubscribe;
|
||||
override on(event: 'preview-message', listener: PreviewMessageListener): Unsubscribe;
|
||||
override on(event: unknown, listener: unknown): Unsubscribe {
|
||||
return () => {};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@defer (when isBrowser) {
|
||||
<adev-progress-bar />
|
||||
<docs-top-level-banner expiry="2024-09-27" id="ng-survey-2024" link="https://goo.gle/angular-survey-2024" text="Take the 2024 Angular Developer Survey today!" />
|
||||
<docs-top-level-banner expiry="2024-12-06" id="state-of-js-2024" link="https://survey.devographics.com/en-US/survey/state-of-js/2024?source=angular_homepage" text="Share your experience with Angular in The State of JavaScript 2024 survey" />
|
||||
}
|
||||
<button (click)="focusFirstHeading()" class="adev-skip">Skip to main content</button>
|
||||
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
transform: translateY(0);
|
||||
transition: transform 0.3s ease-out 0.6s;
|
||||
}
|
||||
|
||||
// show it under the navbar.
|
||||
@include mq.for-tablet-landscape-down{
|
||||
z-index: calc(var(--z-index-nav) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Case: If secondary navigation exists, display banner below secondary navigation for tablets.
|
||||
|
||||
@@ -26,7 +26,8 @@ describe('ProgressBarComponent', () => {
|
||||
});
|
||||
|
||||
it('should call progressBar.complete() on route change', async () => {
|
||||
const progressBarCompleteSpy = spyOn(component.progressBar, 'complete');
|
||||
const progressBar = component.progressBar();
|
||||
const progressBarCompleteSpy = spyOn(progressBar, 'complete');
|
||||
|
||||
const harness = await RouterTestingHarness.create();
|
||||
await harness.navigateByUrl('/');
|
||||
|
||||
@@ -12,10 +12,11 @@ import {
|
||||
inject,
|
||||
OnInit,
|
||||
PLATFORM_ID,
|
||||
ViewChild,
|
||||
Signal,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import {isPlatformBrowser} from '@angular/common';
|
||||
import {NgProgressbar} from 'ngx-progressbar';
|
||||
import {NgProgressbar, NgProgressRef} from 'ngx-progressbar';
|
||||
import {
|
||||
NavigationCancel,
|
||||
NavigationEnd,
|
||||
@@ -41,7 +42,7 @@ export const PROGRESS_BAR_DELAY = 30;
|
||||
export class ProgressBarComponent implements OnInit {
|
||||
private readonly router = inject(Router);
|
||||
|
||||
@ViewChild(NgProgressbar, {static: true}) progressBar!: NgProgressbar;
|
||||
progressBar = viewChild.required(NgProgressRef);
|
||||
|
||||
isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
|
||||
|
||||
@@ -62,7 +63,7 @@ export class ProgressBarComponent implements OnInit {
|
||||
map(() => {
|
||||
// Only apply set the property if the navigation is not "immediate"
|
||||
return setTimeout(() => {
|
||||
this.progressBar.start();
|
||||
this.progressBar().start();
|
||||
}, PROGRESS_BAR_DELAY);
|
||||
}),
|
||||
switchMap((timeoutId) => {
|
||||
@@ -83,7 +84,7 @@ export class ProgressBarComponent implements OnInit {
|
||||
.subscribe((timeoutId) => {
|
||||
// When the navigation finishes, prevent the navigating class from being applied in the timeout.
|
||||
clearTimeout(timeoutId);
|
||||
this.progressBar.complete();
|
||||
this.progressBar().complete();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import {ChangeDetectorRef, signal} from '@angular/core';
|
||||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import {MatTabGroupHarness} from '@angular/material/tabs/testing';
|
||||
import {By} from '@angular/platform-browser';
|
||||
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {provideNoopAnimations} from '@angular/platform-browser/animations';
|
||||
import {BehaviorSubject} from 'rxjs';
|
||||
|
||||
import {EmbeddedTutorialManager} from '../embedded-tutorial-manager.service';
|
||||
@@ -21,7 +21,6 @@ import {CodeEditor, REQUIRED_FILES} from './code-editor.component';
|
||||
import {CodeMirrorEditor} from './code-mirror-editor.service';
|
||||
import {FakeChangeDetectorRef} from '@angular/docs';
|
||||
import {TutorialType} from '@angular/docs';
|
||||
import {MatTooltip} from '@angular/material/tooltip';
|
||||
import {MatTooltipHarness} from '@angular/material/tooltip/testing';
|
||||
|
||||
const files = [
|
||||
@@ -53,8 +52,9 @@ describe('CodeEditor', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [CodeEditor, NoopAnimationsModule, MatTooltip],
|
||||
imports: [CodeEditor],
|
||||
providers: [
|
||||
provideNoopAnimations(),
|
||||
{
|
||||
provide: CodeMirrorEditor,
|
||||
useValue: codeMirrorEditorService,
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<as-split class="docs-right-side" direction="vertical" restrictMove="true" gutterSize="5">
|
||||
<!-- Preview Section: for larger screens -->
|
||||
@if (!displayPreviewInMatTabGroup()) {
|
||||
<as-split-area [size]="50" [order]="1">
|
||||
<as-split-area [size]="50">
|
||||
<!-- Preview Section: for larger screens -->
|
||||
<div class="adev-preview-section">
|
||||
<div class="adev-preview-header">
|
||||
@@ -34,7 +34,7 @@
|
||||
</as-split-area>
|
||||
}
|
||||
|
||||
<as-split-area class="docs-editor-tabs-and-refresh" [size]="50" [order]="2">
|
||||
<as-split-area class="docs-editor-tabs-and-refresh" [size]="50">
|
||||
<!-- Container to hide preview, console and footer when only the interactive terminal is used -->
|
||||
<mat-tab-group class="docs-editor-tabs" animationDuration="0ms" mat-stretch-tabs="false">
|
||||
@if (displayPreviewInMatTabGroup()) {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
@if (documentContent()) {
|
||||
@let docContent = this.docContent();
|
||||
@if (docContent) {
|
||||
<docs-viewer
|
||||
class="docs-viewer"
|
||||
[docContent]="documentContent()!.contents"
|
||||
[docContent]="docContent.contents"
|
||||
[hasToc]="true"
|
||||
/>
|
||||
}
|
||||
|
||||
@@ -7,10 +7,7 @@
|
||||
*/
|
||||
|
||||
import {DocContent, DocViewer} from '@angular/docs';
|
||||
import {ChangeDetectionStrategy, Component, inject} from '@angular/core';
|
||||
import {toSignal} from '@angular/core/rxjs-interop';
|
||||
import {ActivatedRoute} from '@angular/router';
|
||||
import {map} from 'rxjs/operators';
|
||||
import {ChangeDetectionStrategy, Component, input} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'docs-docs',
|
||||
@@ -21,14 +18,9 @@ import {map} from 'rxjs/operators';
|
||||
templateUrl: './docs.component.html',
|
||||
})
|
||||
export default class DocsComponent {
|
||||
private readonly activatedRoute = inject(ActivatedRoute);
|
||||
|
||||
// Based on current route, proper static content for doc page is fetched.
|
||||
// In case when exists example-viewer placeholders, then ExampleViewer
|
||||
// components are going to be rendered.
|
||||
private readonly documentContent$ = this.activatedRoute.data.pipe(
|
||||
map((data) => data['docContent'] as DocContent),
|
||||
);
|
||||
|
||||
documentContent = toSignal(this.documentContent$);
|
||||
docContent = input<DocContent>();
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<div class="adev-top">
|
||||
<div class="adev-top-content">
|
||||
<!-- Banner(s) can be edited here! -->
|
||||
<a href="https://goo.gle/angular-v18" class="adev-banner" target="_blank">
|
||||
<h1 tabindex="-1">Angular v18 is now available!</h1>
|
||||
<p class="adev-banner-cta">Read about our newest release</p>
|
||||
<a href="https://blog.angular.dev/meet-angular-v19-7b29dfd05b84" class="adev-banner" target="_blank">
|
||||
<h1 tabindex="-1">Angular v19 is here!</h1>
|
||||
<p class="adev-banner-cta">Read about our newest release.</p>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
@if (apiItemType()) {
|
||||
{{ apiItemType()! | adevApiLabel: labelMode() }}
|
||||
}
|
||||
{{ type() | adevApiLabel: mode() }}
|
||||
|
||||
@@ -21,11 +21,11 @@ describe('ApiItemLabel', () => {
|
||||
});
|
||||
fixture = TestBed.createComponent(ApiItemLabel);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should by default display short label for Class', () => {
|
||||
component.type = ApiItemType.CLASS;
|
||||
fixture.componentRef.setInput('type', ApiItemType.CLASS);
|
||||
fixture.componentRef.setInput('mode', 'short');
|
||||
fixture.detectChanges();
|
||||
|
||||
const label = fixture.nativeElement.innerText;
|
||||
@@ -34,8 +34,8 @@ describe('ApiItemLabel', () => {
|
||||
});
|
||||
|
||||
it('should display full label for Class when labelMode equals full', () => {
|
||||
component.type = ApiItemType.CLASS;
|
||||
component.mode = 'full';
|
||||
fixture.componentRef.setInput('type', ApiItemType.CLASS);
|
||||
fixture.componentRef.setInput('mode', 'full');
|
||||
fixture.detectChanges();
|
||||
|
||||
const label = fixture.nativeElement.innerText;
|
||||
@@ -44,8 +44,8 @@ describe('ApiItemLabel', () => {
|
||||
});
|
||||
|
||||
it('should display short label for Class when labelMode equals short', () => {
|
||||
component.type = ApiItemType.CLASS;
|
||||
component.mode = 'short';
|
||||
fixture.componentRef.setInput('type', ApiItemType.CLASS);
|
||||
fixture.componentRef.setInput('mode', 'short');
|
||||
fixture.detectChanges();
|
||||
|
||||
const label = fixture.nativeElement.innerText;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {ChangeDetectionStrategy, Component, Input, signal} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, input} from '@angular/core';
|
||||
import {ApiItemType} from '../interfaces/api-item-type';
|
||||
import {ApiLabel} from '../pipes/api-label.pipe';
|
||||
|
||||
@@ -16,19 +16,12 @@ import {ApiLabel} from '../pipes/api-label.pipe';
|
||||
templateUrl: './api-item-label.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: {
|
||||
'[attr.data-type]': 'apiItemType()',
|
||||
'[attr.data-mode]': 'labelMode()',
|
||||
'[attr.data-type]': 'type()',
|
||||
'[attr.data-mode]': 'mode()',
|
||||
},
|
||||
imports: [ApiLabel],
|
||||
})
|
||||
export default class ApiItemLabel {
|
||||
@Input({required: true}) set type(value: ApiItemType) {
|
||||
this.apiItemType.set(value);
|
||||
}
|
||||
@Input({required: true}) set mode(value: 'short' | 'full') {
|
||||
this.labelMode.set(value);
|
||||
}
|
||||
|
||||
protected apiItemType = signal<ApiItemType | undefined>(undefined);
|
||||
protected labelMode = signal<'short' | 'full'>('short');
|
||||
readonly type = input.required<ApiItemType>();
|
||||
readonly mode = input.required<'short' | 'full'>();
|
||||
}
|
||||
|
||||
+4
-16
@@ -1,22 +1,19 @@
|
||||
<header class="adev-api-items-section-header">
|
||||
<h3 [attr.id]="group.id">
|
||||
@if (group.isFeatured) {
|
||||
<docs-icon aria-hidden>star</docs-icon>
|
||||
}
|
||||
<h3 [id]="group().id">
|
||||
<!-- we use innerHtml because the title can be an html string-->
|
||||
<a
|
||||
routerLink="/api"
|
||||
[fragment]="group.id"
|
||||
[fragment]="group().id"
|
||||
queryParamsHandling="preserve"
|
||||
class="adev-api-anchor"
|
||||
tabindex="-1"
|
||||
[innerHtml]="group.title"
|
||||
[innerHtml]="group().title"
|
||||
></a>
|
||||
</h3>
|
||||
</header>
|
||||
|
||||
<ul class="adev-api-items-section-grid">
|
||||
@for (apiItem of group.items; track apiItem.url) {
|
||||
@for (apiItem of group().items; track apiItem.url) {
|
||||
<li [class.adev-api-items-section-item-deprecated]="apiItem.isDeprecated">
|
||||
<a
|
||||
[routerLink]="'/' + apiItem.url"
|
||||
@@ -34,15 +31,6 @@
|
||||
@if (apiItem.isDeprecated) {
|
||||
<span class="docs-deprecated"> <!> </span>
|
||||
}
|
||||
@if (apiItem.isFeatured) {
|
||||
<docs-icon
|
||||
class="adev-api-items-section-item-featured"
|
||||
[class.adev-api-item-in-featured-section]="group.isFeatured"
|
||||
[class.adev-api-items-section-item-featured-active]="apiItem.isFeatured"
|
||||
>
|
||||
star
|
||||
</docs-icon>
|
||||
}
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
|
||||
+1
-25
@@ -57,39 +57,16 @@
|
||||
margin-block-start: 3px;
|
||||
}
|
||||
|
||||
// star icon
|
||||
.adev-api-items-section-item-featured {
|
||||
opacity: 0;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
color: var(--quinary-contrast);
|
||||
cursor: pointer;
|
||||
margin-top: -2px;
|
||||
transition: color 0.3s ease;
|
||||
|
||||
&-active {
|
||||
opacity: 1;
|
||||
color: var(--quinary-contrast);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-inline-start: 1px solid var(--quaternary-contrast);
|
||||
background-color: var(--septenary-contrast);
|
||||
a {
|
||||
color: var(--primary-contrast);
|
||||
}
|
||||
.adev-api-items-section-item-featured-active {
|
||||
color: var(--tertiary-contrast);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.adev-api-item-in-featured-section {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.adev-api-items-section-item {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
@@ -106,9 +83,8 @@
|
||||
margin-inline-start: 0.5rem;
|
||||
}
|
||||
|
||||
|
||||
.adev-api-anchor {
|
||||
color: inherit;
|
||||
|
||||
@include anchor.docs-anchor();
|
||||
}
|
||||
}
|
||||
|
||||
+15
-59
@@ -12,7 +12,7 @@ import ApiItemsSection from './api-items-section.component';
|
||||
import {ApiItemsGroup} from '../interfaces/api-items-group';
|
||||
import {ApiReferenceManager} from '../api-reference-list/api-reference-manager.service';
|
||||
import {ApiItemType} from '../interfaces/api-item-type';
|
||||
import {RouterTestingModule} from '@angular/router/testing';
|
||||
import {provideRouter} from '@angular/router';
|
||||
import {By} from '@angular/platform-browser';
|
||||
|
||||
describe('ApiItemsSection', () => {
|
||||
@@ -20,80 +20,47 @@ describe('ApiItemsSection', () => {
|
||||
let fixture: ComponentFixture<ApiItemsSection>;
|
||||
let apiReferenceManagerSpy: jasmine.SpyObj<ApiReferenceManager>;
|
||||
|
||||
const fakeFeaturedGroup: ApiItemsGroup = {
|
||||
title: 'Featured',
|
||||
id: 'featured',
|
||||
isFeatured: true,
|
||||
const fakeGroup: ApiItemsGroup = {
|
||||
title: 'Group',
|
||||
id: 'group',
|
||||
items: [
|
||||
{
|
||||
title: 'Fake Featured Title',
|
||||
itemType: ApiItemType.CLASS,
|
||||
url: 'api/fakeFeaturedTitle',
|
||||
isFeatured: true,
|
||||
},
|
||||
{
|
||||
title: 'Fake Deprecated Title',
|
||||
itemType: ApiItemType.CONST,
|
||||
url: 'api/fakeDeprecatedTitle',
|
||||
isFeatured: false,
|
||||
isDeprecated: true,
|
||||
},
|
||||
{
|
||||
title: 'Fake Standard Title',
|
||||
itemType: ApiItemType.DIRECTIVE,
|
||||
url: 'api/fakeTitle',
|
||||
isFeatured: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const fakeGroup: ApiItemsGroup = {
|
||||
title: 'Example group',
|
||||
id: 'example',
|
||||
isFeatured: false,
|
||||
items: [
|
||||
{title: 'Fake Title', itemType: ApiItemType.CONST, url: 'api/fakeTitle', isFeatured: false},
|
||||
],
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [ApiItemsSection, RouterTestingModule],
|
||||
providers: [{provide: ApiReferenceManager, useValue: apiReferenceManagerSpy}],
|
||||
imports: [ApiItemsSection],
|
||||
providers: [
|
||||
provideRouter([]),
|
||||
{provide: ApiReferenceManager, useValue: apiReferenceManagerSpy},
|
||||
],
|
||||
});
|
||||
fixture = TestBed.createComponent(ApiItemsSection);
|
||||
component = fixture.componentInstance;
|
||||
});
|
||||
|
||||
it('should render star icon for featured group', () => {
|
||||
component.group = fakeFeaturedGroup;
|
||||
fixture.detectChanges();
|
||||
|
||||
const starIcon = fixture.debugElement.query(By.css('.adev-api-items-section-header docs-icon'));
|
||||
|
||||
expect(starIcon).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not render star icon for standard group', () => {
|
||||
component.group = fakeGroup;
|
||||
fixture.detectChanges();
|
||||
|
||||
const starIcon = fixture.debugElement.query(By.css('.adev-api-items-section-header docs-icon'));
|
||||
|
||||
expect(starIcon).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should render list of all APIs of provided group', () => {
|
||||
component.group = fakeFeaturedGroup;
|
||||
fixture.componentRef.setInput('group', fakeGroup);
|
||||
fixture.detectChanges();
|
||||
|
||||
const apis = fixture.debugElement.queryAll(By.css('.adev-api-items-section-grid li'));
|
||||
|
||||
expect(apis.length).toBe(3);
|
||||
expect(apis.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should display deprecated icon for deprecated API', () => {
|
||||
component.group = fakeFeaturedGroup;
|
||||
fixture.componentRef.setInput('group', fakeGroup);
|
||||
fixture.detectChanges();
|
||||
|
||||
const deprecatedApiIcons = fixture.debugElement.queryAll(
|
||||
@@ -101,22 +68,11 @@ describe('ApiItemsSection', () => {
|
||||
);
|
||||
const deprecatedApiTitle = deprecatedApiIcons[0].parent?.query(By.css('.adev-item-title'));
|
||||
|
||||
console.log('DEPRECATED API ICONS', deprecatedApiIcons);
|
||||
console.log('DEPRECATED API TITLE', deprecatedApiTitle);
|
||||
|
||||
expect(deprecatedApiIcons.length).toBe(1);
|
||||
expect(deprecatedApiIcons[0]).toBeTruthy();
|
||||
expect(deprecatedApiTitle?.nativeElement.innerText).toBe('Fake Deprecated Title');
|
||||
});
|
||||
|
||||
it('should display star icon for featured API', () => {
|
||||
component.group = fakeFeaturedGroup;
|
||||
fixture.detectChanges();
|
||||
|
||||
const featuredApiIcons = fixture.debugElement.queryAll(
|
||||
By.css('.adev-api-items-section-grid li .adev-api-items-section-item-featured'),
|
||||
);
|
||||
const featuredApiTitle = featuredApiIcons[0].parent?.query(By.css('.adev-item-title'));
|
||||
|
||||
expect(featuredApiIcons.length).toBe(1);
|
||||
expect(featuredApiIcons[0]).toBeTruthy();
|
||||
expect(featuredApiTitle?.nativeElement.innerText).toBe('Fake Featured Title');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, input} from '@angular/core';
|
||||
import {RouterLink} from '@angular/router';
|
||||
import {ApiItemsGroup} from '../interfaces/api-items-group';
|
||||
import ApiItemLabel from '../api-item-label/api-item-label.component';
|
||||
@@ -21,5 +21,5 @@ import {IconComponent} from '@angular/docs';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export default class ApiItemsSection {
|
||||
@Input({required: true}) group!: ApiItemsGroup;
|
||||
group = input.required<ApiItemsGroup>();
|
||||
}
|
||||
|
||||
+5
-5
@@ -1,8 +1,8 @@
|
||||
<div class="adev-header-and-tabs docs-scroll-track-transparent">
|
||||
<docs-viewer [docContent]="headerInnerHtml()" class="docs-reference-header"></docs-viewer>
|
||||
<docs-viewer [docContent]="parsedDocContent().header" class="docs-reference-header"></docs-viewer>
|
||||
|
||||
<mat-tab-group class="docs-reference-tabs" animationDuration="0ms" mat-stretch-tabs="false" [selectedIndex]="selectedTabIndex()">
|
||||
@for (tab of tabs(); track tab) {
|
||||
<mat-tab-group class="docs-reference-tabs" animationDuration="0ms" mat-stretch-tabs="false" [selectedIndex]="selectedTabIndex()" (selectedIndexChange)="tabChange($event)">
|
||||
@for (tab of tabs(); track tab.url) {
|
||||
<mat-tab [label]="tab.title">
|
||||
<div class="adev-reference-tab-body">
|
||||
<docs-viewer [docContent]="tab.content"></docs-viewer>
|
||||
@@ -12,10 +12,10 @@
|
||||
</mat-tab-group>
|
||||
</div>
|
||||
|
||||
@if (canDisplayCards() && membersMarginTopInPx() > 0) {
|
||||
@if (isApiTabActive() && membersMarginTopInPx() > 0) {
|
||||
<docs-viewer
|
||||
class="docs-reference-members-container"
|
||||
[docContent]="membersInnerHtml()"
|
||||
[docContent]="parsedDocContent().members"
|
||||
[style.marginTop.px]="membersMarginTopInPx()"
|
||||
(contentLoaded)="membersCardsLoaded()">
|
||||
</docs-viewer>
|
||||
|
||||
+1
-1
@@ -272,7 +272,7 @@
|
||||
header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 0.25rem;
|
||||
border-radius: 0.25rem 0.25rem 0 0;
|
||||
background-color: var(--octonary-contrast);
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
|
||||
+18
-14
@@ -10,11 +10,11 @@ import {HarnessLoader} from '@angular/cdk/testing';
|
||||
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {MatTabGroupHarness} from '@angular/material/tabs/testing';
|
||||
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {provideNoopAnimations} from '@angular/platform-browser/animations';
|
||||
import {ReferenceScrollHandler} from '../services/reference-scroll-handler.service';
|
||||
import {signal} from '@angular/core';
|
||||
import {provideRouter} from '@angular/router';
|
||||
import {RouterTestingHarness, RouterTestingModule} from '@angular/router/testing';
|
||||
import {provideRouter, withComponentInputBinding} from '@angular/router';
|
||||
import {RouterTestingHarness} from '@angular/router/testing';
|
||||
|
||||
import ApiReferenceDetailsPage from './api-reference-details-page.component';
|
||||
import {By} from '@angular/platform-browser';
|
||||
@@ -40,20 +40,24 @@ describe('ApiReferenceDetailsPage', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [ApiReferenceDetailsPage, RouterTestingModule, NoopAnimationsModule],
|
||||
imports: [ApiReferenceDetailsPage],
|
||||
providers: [
|
||||
provideRouter([
|
||||
{
|
||||
path: '**',
|
||||
component: ApiReferenceDetailsPage,
|
||||
data: {
|
||||
'docContent': {
|
||||
id: 'id',
|
||||
contents: SAMPLE_CONTENT_WITH_TABS,
|
||||
provideNoopAnimations(),
|
||||
provideRouter(
|
||||
[
|
||||
{
|
||||
path: '**',
|
||||
component: ApiReferenceDetailsPage,
|
||||
data: {
|
||||
'docContent': {
|
||||
id: 'id',
|
||||
contents: SAMPLE_CONTENT_WITH_TABS,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
]),
|
||||
],
|
||||
withComponentInputBinding(),
|
||||
),
|
||||
],
|
||||
});
|
||||
TestBed.overrideProvider(ReferenceScrollHandler, {useValue: fakeApiReferenceScrollHandler});
|
||||
|
||||
+71
-100
@@ -7,21 +7,15 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
AfterViewInit,
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
DestroyRef,
|
||||
Injector,
|
||||
OnInit,
|
||||
ViewChild,
|
||||
afterNextRender,
|
||||
inject,
|
||||
signal,
|
||||
input,
|
||||
computed,
|
||||
} from '@angular/core';
|
||||
import {DOCUMENT} from '@angular/common';
|
||||
import {MatTabGroup, MatTabsModule} from '@angular/material/tabs';
|
||||
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
|
||||
import {distinctUntilChanged, map} from 'rxjs/operators';
|
||||
import {MatTabsModule} from '@angular/material/tabs';
|
||||
import {DocContent, DocViewer} from '@angular/docs';
|
||||
import {ActivatedRoute, Router} from '@angular/router';
|
||||
import {ApiItemType} from './../interfaces/api-item-type';
|
||||
@@ -30,7 +24,6 @@ import {
|
||||
API_REFERENCE_DETAILS_PAGE_HEADER_CLASS_NAME,
|
||||
API_REFERENCE_DETAILS_PAGE_MEMBERS_CLASS_NAME,
|
||||
API_REFERENCE_TAB_ATTRIBUTE,
|
||||
API_REFERENCE_TAB_QUERY_PARAM,
|
||||
API_REFERENCE_TAB_API_LABEL,
|
||||
API_TAB_CLASS_NAME,
|
||||
API_REFERENCE_TAB_BODY_CLASS_NAME,
|
||||
@@ -47,116 +40,94 @@ import {AppScroller} from '../../../app-scroller';
|
||||
providers: [ReferenceScrollHandler],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export default class ApiReferenceDetailsPage implements OnInit, AfterViewInit {
|
||||
@ViewChild(MatTabGroup, {static: true}) matTabGroup!: MatTabGroup;
|
||||
|
||||
export default class ApiReferenceDetailsPage {
|
||||
private readonly activatedRoute = inject(ActivatedRoute);
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
private readonly document = inject(DOCUMENT);
|
||||
private readonly router = inject(Router);
|
||||
private readonly scrollHandler = inject(ReferenceScrollHandler);
|
||||
private readonly appScroller = inject(AppScroller);
|
||||
private readonly injector = inject(Injector);
|
||||
|
||||
docContent = input<DocContent | undefined>();
|
||||
tab = input<string | undefined>();
|
||||
|
||||
// aliases
|
||||
ApiItemType = ApiItemType;
|
||||
|
||||
canDisplayCards = signal<boolean>(false);
|
||||
tabs = signal<{url: string; title: string; content: string}[]>([]);
|
||||
headerInnerHtml = signal<string | undefined>(undefined);
|
||||
membersInnerHtml = signal<string | undefined>(undefined);
|
||||
membersMarginTopInPx = this.scrollHandler.membersMarginTopInPx;
|
||||
selectedTabIndex = signal(0);
|
||||
|
||||
// computed state
|
||||
parsedDocContent = computed(() => {
|
||||
// TODO: pull this logic outside of a computed where it can be tested etc.
|
||||
const docContent = this.docContent();
|
||||
|
||||
if (docContent === undefined) {
|
||||
return {
|
||||
header: undefined,
|
||||
members: undefined,
|
||||
tabs: [],
|
||||
};
|
||||
}
|
||||
|
||||
const element = this.document.createElement('div');
|
||||
element.innerHTML = docContent.contents;
|
||||
|
||||
// Get the innerHTML of the header element from received document.
|
||||
const header = element.querySelector(API_REFERENCE_DETAILS_PAGE_HEADER_CLASS_NAME);
|
||||
// Get the innerHTML of the card elements from received document.
|
||||
const members = element.querySelector(API_REFERENCE_DETAILS_PAGE_MEMBERS_CLASS_NAME);
|
||||
|
||||
// Get the tab elements from received document.
|
||||
// We're expecting that tab element will contain `tab` attribute.
|
||||
const tabs = Array.from(element.querySelectorAll(`[${API_REFERENCE_TAB_ATTRIBUTE}]`)).map(
|
||||
(tab) => ({
|
||||
url: tab.getAttribute(API_REFERENCE_TAB_URL_ATTRIBUTE)!,
|
||||
title: tab.getAttribute(API_REFERENCE_TAB_ATTRIBUTE)!,
|
||||
content: tab.innerHTML,
|
||||
}),
|
||||
);
|
||||
|
||||
element.remove();
|
||||
|
||||
return {
|
||||
header: header?.innerHTML,
|
||||
members: members?.innerHTML,
|
||||
tabs,
|
||||
};
|
||||
});
|
||||
|
||||
tabs = () => this.parsedDocContent().tabs;
|
||||
|
||||
selectedTabIndex = computed(() => {
|
||||
const existingTabIdx = this.tabs().findIndex((tab) => tab.url === this.tab());
|
||||
return Math.max(existingTabIdx, 0);
|
||||
});
|
||||
|
||||
isApiTabActive = computed(() => {
|
||||
const activeTabTitle = this.tabs()[this.selectedTabIndex()]?.title;
|
||||
return activeTabTitle === API_REFERENCE_TAB_API_LABEL || activeTabTitle === 'CLI';
|
||||
});
|
||||
|
||||
constructor() {
|
||||
this.appScroller.disableScrolling = true;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.setPageContent();
|
||||
afterNextRender({
|
||||
write: () => {
|
||||
this.scrollHandler.updateMembersMarginTop(API_REFERENCE_TAB_BODY_CLASS_NAME);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.appScroller.disableScrolling = false;
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.setActiveTab();
|
||||
this.listenToTabChange();
|
||||
}
|
||||
|
||||
membersCardsLoaded(): void {
|
||||
this.scrollHandler.setupListeners(API_TAB_CLASS_NAME);
|
||||
}
|
||||
|
||||
// Fetch the content for API Reference page based on the active route.
|
||||
private setPageContent(): void {
|
||||
this.activatedRoute.data
|
||||
.pipe(
|
||||
map((data) => data['docContent']),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
)
|
||||
.subscribe((doc: DocContent | undefined) => {
|
||||
this.setContentForPageSections(doc);
|
||||
afterNextRender(() => this.setActiveTab(), {injector: this.injector});
|
||||
});
|
||||
}
|
||||
|
||||
private listenToTabChange(): void {
|
||||
this.matTabGroup.selectedIndexChange
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((index) => {
|
||||
this.router.navigate([], {
|
||||
relativeTo: this.activatedRoute,
|
||||
queryParams: {tab: this.tabs()[index].url},
|
||||
queryParamsHandling: 'merge',
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private setContentForPageSections(doc: DocContent | undefined): void {
|
||||
const element = this.document.createElement('div');
|
||||
element.innerHTML = doc?.contents!;
|
||||
|
||||
// Get the innerHTML of the header element from received document.
|
||||
const header = element.querySelector(API_REFERENCE_DETAILS_PAGE_HEADER_CLASS_NAME);
|
||||
if (header) {
|
||||
this.headerInnerHtml.set(header.innerHTML);
|
||||
}
|
||||
|
||||
// Get the innerHTML of the card elements from received document.
|
||||
const members = element.querySelector(API_REFERENCE_DETAILS_PAGE_MEMBERS_CLASS_NAME);
|
||||
if (members) {
|
||||
this.membersInnerHtml.set(members.innerHTML);
|
||||
}
|
||||
|
||||
// Get the tab elements from received document.
|
||||
// We're expecting that tab element will contain `tab` attribute.
|
||||
const tabs = Array.from(element.querySelectorAll(`[${API_REFERENCE_TAB_ATTRIBUTE}]`));
|
||||
this.tabs.set(
|
||||
tabs.map((tab) => ({
|
||||
url: tab.getAttribute(API_REFERENCE_TAB_URL_ATTRIBUTE)!,
|
||||
title: tab.getAttribute(API_REFERENCE_TAB_ATTRIBUTE)!,
|
||||
content: tab.innerHTML,
|
||||
})),
|
||||
);
|
||||
|
||||
element.remove();
|
||||
}
|
||||
|
||||
private setActiveTab(): void {
|
||||
this.activatedRoute.queryParamMap
|
||||
.pipe(distinctUntilChanged(), takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((paramsMap) => {
|
||||
const selectedTabUrl = paramsMap.get(API_REFERENCE_TAB_QUERY_PARAM);
|
||||
const tabIndexToSelect = this.tabs().findIndex((tab) => tab.url === selectedTabUrl);
|
||||
this.selectedTabIndex.set(tabIndexToSelect < 0 ? 0 : tabIndexToSelect);
|
||||
|
||||
this.scrollHandler.updateMembersMarginTop(API_REFERENCE_TAB_BODY_CLASS_NAME);
|
||||
|
||||
const isApiTabActive =
|
||||
this.tabs()[this.selectedTabIndex()]?.title === API_REFERENCE_TAB_API_LABEL ||
|
||||
this.tabs()[this.selectedTabIndex()]?.title === 'CLI';
|
||||
this.canDisplayCards.set(isApiTabActive);
|
||||
});
|
||||
tabChange(tabIndex: number) {
|
||||
this.router.navigate([], {
|
||||
relativeTo: this.activatedRoute,
|
||||
queryParams: {tab: this.tabs()[tabIndex].url},
|
||||
queryParamsHandling: 'merge',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+32
-37
@@ -1,43 +1,38 @@
|
||||
<div class="adev-reference-list-page">
|
||||
<header>
|
||||
<h6>Getting Started</h6>
|
||||
<h1>API Reference</h1>
|
||||
</header>
|
||||
|
||||
@if (featuredGroup().items.length) {
|
||||
<adev-api-items-section [group]="featuredGroup()" class="adev-featured-list" />
|
||||
}
|
||||
<form class="adev-reference-list-form">
|
||||
<ul class="adev-reference-list-legend">
|
||||
@for (itemType of itemTypes; track itemType) {
|
||||
<li
|
||||
class="adev-reference-list-legend-item"
|
||||
[class.adev-reference-list-legend-item-active]="type() === itemType"
|
||||
(click)="filterByItemType(itemType)"
|
||||
>
|
||||
<docs-api-item-label [type]="itemType" mode="short" class="docs-api-item-label" />
|
||||
<span class="docs-api-item-label-full">{{ itemType | adevApiLabel : 'full' }}</span>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
<header>
|
||||
<h1>API Reference</h1>
|
||||
</header>
|
||||
|
||||
<div class="adev-reference-list-filter">
|
||||
<div class="adev-reference-list-query-filter">
|
||||
<docs-text-field name="query" placeholder="Filter" [(ngModel)]="query" />
|
||||
|
||||
<div class="adev-reference-list-form-part-two">
|
||||
<docs-slide-toggle
|
||||
buttonId="includeDeprecated"
|
||||
label="Show @deprecated"
|
||||
name="includeDeprecated"
|
||||
[(ngModel)]="includeDeprecated"
|
||||
/>
|
||||
</div>
|
||||
<docs-slide-toggle
|
||||
buttonId="includeDeprecated"
|
||||
label="Show @deprecated"
|
||||
name="includeDeprecated"
|
||||
[(ngModel)]="includeDeprecated"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@for (group of filteredGroups(); track group.id) {
|
||||
<adev-api-items-section [group]="group" />
|
||||
} @empty {
|
||||
<div class="adev-reference-list-empty">
|
||||
<p>No API items found.</p>
|
||||
</div>
|
||||
<p class="adev-reference-list-type-filter-label">Filter by Identifier type</p>
|
||||
<ul class="adev-reference-list-type-filter">
|
||||
@for (itemType of itemTypes; track itemType) {
|
||||
<li
|
||||
class="adev-reference-list-type-filter-item"
|
||||
[class.adev-reference-list-type-filter-item-active]="type() === itemType"
|
||||
(click)="filterByItemType(itemType)"
|
||||
>
|
||||
<docs-api-item-label [type]="itemType" mode="short" class="docs-api-item-label" />
|
||||
<span class="docs-api-item-label-full">{{ itemType | adevApiLabel : 'full' }}</span>
|
||||
</li>
|
||||
}
|
||||
</form>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@for (group of filteredGroups(); track group.id) {
|
||||
<adev-api-items-section [group]="group" />
|
||||
} @empty {
|
||||
<div class="adev-reference-list-empty">
|
||||
<p>No API items found.</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
+74
-78
@@ -1,6 +1,7 @@
|
||||
.adev-reference-list-page {
|
||||
:host {
|
||||
padding: var(--layout-padding);
|
||||
max-width: var(--page-width);
|
||||
display: block;
|
||||
|
||||
container: api-ref-page / inline-size;
|
||||
|
||||
@@ -20,91 +21,86 @@
|
||||
color: var(--secondary-contrast);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.adev-reference-list-legend {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
margin-block-start: 0;
|
||||
padding-inline: 0;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
.adev-reference-list-filter {
|
||||
border-block-end: 1px solid var(--senary-contrast);
|
||||
padding-block-end: 2rem;
|
||||
margin-block-end: 1rem;
|
||||
|
||||
@container api-ref-page (max-width: 775px) {
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
}
|
||||
@container api-ref-page (max-width: 600px) {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
@container api-ref-page (max-width: 500px) {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
@container api-ref-page (max-width: 350px) {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
padding: 0.3rem;
|
||||
font-size: 0.875rem;
|
||||
color: var(--quaternary-contrast);
|
||||
font-weight: 500;
|
||||
text-transform: capitalize;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 0.25rem;
|
||||
margin-inline-end: 0.5rem;
|
||||
margin-block-end: 0.5rem;
|
||||
transition:
|
||||
color 0.3s ease,
|
||||
background 0.3s ease,
|
||||
border 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
color: var(--primary-contrast);
|
||||
border: 1px solid var(--senary-contrast);
|
||||
.adev-reference-list-type-filter-label {
|
||||
margin-block: 2.5rem 1rem;
|
||||
}
|
||||
|
||||
&.adev-reference-list-legend-item-active {
|
||||
background: var(--septenary-contrast);
|
||||
border: 1px solid var(--quinary-contrast);
|
||||
color: var(--primary-contrast);
|
||||
.adev-reference-list-type-filter {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
margin-block: 0;
|
||||
padding-inline: 0;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
gap: 0.5rem;
|
||||
|
||||
@container api-ref-page (max-width: 775px) {
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
}
|
||||
@container api-ref-page (max-width: 600px) {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
@container api-ref-page (max-width: 500px) {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
@container api-ref-page (max-width: 350px) {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
padding: 0.3rem;
|
||||
font-size: 0.875rem;
|
||||
color: var(--quaternary-contrast);
|
||||
font-weight: 500;
|
||||
text-transform: capitalize;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 0.25rem;
|
||||
transition:
|
||||
color 0.3s ease,
|
||||
background 0.3s ease,
|
||||
border 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
color: var(--primary-contrast);
|
||||
border: 1px solid var(--senary-contrast);
|
||||
}
|
||||
|
||||
&.adev-reference-list-type-filter-item-active {
|
||||
background: var(--septenary-contrast);
|
||||
border: 1px solid var(--quinary-contrast);
|
||||
color: var(--primary-contrast);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.adev-reference-list-query-filter {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.adev-reference-list-form {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 1.5rem;
|
||||
padding-block-start: 1.5rem;
|
||||
padding-block-end: 2rem;
|
||||
border-block: 1px solid var(--senary-contrast);
|
||||
}
|
||||
.adev-reference-list-empty {
|
||||
text-align: center;
|
||||
margin-block-start: 2rem;
|
||||
|
||||
.adev-reference-list-form-part-two {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
p {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.adev-reference-list-empty {
|
||||
text-align: center;
|
||||
p {
|
||||
font-size: 1rem;
|
||||
.docs-api-item-label-full {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.adev-featured-list {
|
||||
display: block;
|
||||
padding-block-end: 1rem;
|
||||
margin-block: 1rem;
|
||||
border-top: 0;
|
||||
margin-top: -1.5rem;
|
||||
}
|
||||
|
||||
.docs-api-item-label-full {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user