mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
Compare commits
303 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dca0a77488 | |||
| caf616670f | |||
| fec5977df4 | |||
| e33d69a71c | |||
| 6afe6fa781 | |||
| 07cb840eac | |||
| 7b884f585a | |||
| 948a8d6831 | |||
| e2660c3dee | |||
| f34a93c946 | |||
| 9949dccce1 | |||
| 5d00aa2bd4 | |||
| e86c31bf26 | |||
| 1804f73bec | |||
| 91df739b80 | |||
| 8d22cc953b | |||
| 5a693bafcd | |||
| 6bcce117fb | |||
| 31c25e2e85 | |||
| 88832c84f8 | |||
| 13fb0afe93 | |||
| 86a56dc279 | |||
| bcb1b7ea25 | |||
| b9d29381bb | |||
| a810a319d1 | |||
| 35510746b7 | |||
| a5f82b8315 | |||
| bc55749698 | |||
| d846326b07 | |||
| e245d40c4d | |||
| dc9c99636d | |||
| 1523061137 | |||
| 03188ddc9f | |||
| 736c4ab7e6 | |||
| 3fd6897a67 | |||
| db157e4aff | |||
| 70af5e8abd | |||
| 66821c4ed5 | |||
| b74fb76d1a | |||
| 66d09558b6 | |||
| ae1c8a1f7a | |||
| 9f6fda6815 | |||
| 1e5d76bfd9 | |||
| 22dd53ca97 | |||
| 1cd4f54aef | |||
| 9d8ea2cc9a | |||
| 69c0d48a0d | |||
| 7e38336dc7 | |||
| 34c4e401ba | |||
| f6d8e642b0 | |||
| 8206972189 | |||
| d3170031b6 | |||
| 9b7d0e5034 | |||
| cea6588bb3 | |||
| 6b8202eab6 | |||
| eb1cbbf2eb | |||
| 8538bdce1c | |||
| 582a417bd2 | |||
| 5c6d6df34b | |||
| 29ceeffd40 | |||
| 1a84668f0c | |||
| 551a2a1f46 | |||
| 84c6579a4e | |||
| 2b17b2db88 | |||
| fd3573d99d | |||
| ef38852213 | |||
| 2232a62bb2 | |||
| ad5053b518 | |||
| ca32fc1000 | |||
| b8bd49341d | |||
| 251c8f2740 | |||
| dada86e43d | |||
| 782e01594e | |||
| ff12fe55ac | |||
| 0b07f47bd6 | |||
| cc1378d54b | |||
| daaf32937f | |||
| 37e8aadf87 | |||
| 72696e244e | |||
| 300f61feb3 | |||
| 7f4ac78994 | |||
| e6fe77cc97 | |||
| 525e1605a6 | |||
| 4a41831326 | |||
| 6d8b156b45 | |||
| 82cf38ad95 | |||
| 711f873e31 | |||
| 3fe8562b38 | |||
| 9627e02bde | |||
| a7b9ff5a58 | |||
| 1b6f780e2d | |||
| d56f1a35ad | |||
| 232b21db55 | |||
| 1d6e71dd78 | |||
| 0c7f70e8ea | |||
| 1ef4ea3e39 | |||
| 395919ffeb | |||
| 49113ac0ef | |||
| 027c7c0c95 | |||
| 7f444e1c7f | |||
| 34f89fb6c2 | |||
| 68282dff9f | |||
| 099bf577ee | |||
| fd05135da9 | |||
| c0f52272ed | |||
| d1736efc32 | |||
| 73b0ada729 | |||
| 0fb2724194 | |||
| 6652ec0115 | |||
| 938a7f3edd | |||
| fc434c1d0a | |||
| 8282c09e2d | |||
| 1e079a8994 | |||
| 7ab78d5c89 | |||
| 49a133aeaf | |||
| c08321988d | |||
| c93d158aae | |||
| 327edb9001 | |||
| 3ec0a10ca0 | |||
| 0b7192f441 | |||
| 5000a6d2c0 | |||
| f9a58c1da3 | |||
| 6ed6498854 | |||
| 629905d537 | |||
| baf92da96e | |||
| 1c6553e97d | |||
| c39f7708a6 | |||
| 2a1e6ec1bb | |||
| 73ba918cce | |||
| bca94ee0bb | |||
| 5316753957 | |||
| 9e38ed7d57 | |||
| 335d8c04dc | |||
| 161d98e7f2 | |||
| 03ad53863b | |||
| 929ec53578 | |||
| e6ab5eca57 | |||
| 3430251fef | |||
| ce7a43a5b6 | |||
| af74b420e1 | |||
| c37f6ca42f | |||
| aba59aac59 | |||
| c2b441af6d | |||
| fe13bb669d | |||
| 08363f0f93 | |||
| 05210ce2f1 | |||
| 3db96a5983 | |||
| c2c869bbe5 | |||
| 7a6f4c2b4f | |||
| 30cf85f71c | |||
| 7a05a9a71a | |||
| dc9b40ebb5 | |||
| 1aeebbe304 | |||
| ef9669c1f8 | |||
| 6c6db5b604 | |||
| 185862ef76 | |||
| 631e303dd9 | |||
| 41e4851928 | |||
| a24dcfd1ec | |||
| 1dde3827e9 | |||
| b40b67cdc1 | |||
| 4900e453e1 | |||
| 42d57c3578 | |||
| 10ad3c0692 | |||
| d07f502946 | |||
| 600da64ba4 | |||
| a40e2cebc8 | |||
| 9ed1b6c045 | |||
| 2b9b27e882 | |||
| 85f1c0a268 | |||
| fb7e67ca9d | |||
| 316d49a8ae | |||
| 9bcbf37641 | |||
| a3d14fc11b | |||
| 0612c8c53b | |||
| 4f5d8a2c0b | |||
| be1f80a253 | |||
| 76cf531002 | |||
| 885a1a1d97 | |||
| 7a64aff9b5 | |||
| cbaba8afe6 | |||
| fbe080f829 | |||
| 1be52ad880 | |||
| fa4eff36cb | |||
| 27da56ee9d | |||
| 7b8faccc34 | |||
| 6662724c99 | |||
| 8ce8b9342a | |||
| 131c422da2 | |||
| fa33854d24 | |||
| f3308dc1f7 | |||
| f9b70a0887 | |||
| a8dd801856 | |||
| 2ec753cb77 | |||
| 90cc755a56 | |||
| 4fd1a08699 | |||
| 750af5b123 | |||
| 5533ab4f56 | |||
| 2b9954fd3d | |||
| 4dc7bf5a75 | |||
| 0d5ee9ae1b | |||
| 6a02320575 | |||
| 751e4af80b | |||
| da346bf696 | |||
| 580212c995 | |||
| a9ddc5d40a | |||
| 0d08d9cc82 | |||
| 4c7ec66807 | |||
| 62266eee8b | |||
| 2a50dceef5 | |||
| c9215b3539 | |||
| d88d6ed69e | |||
| e5b93ea4ca | |||
| ce883d95ef | |||
| be7490964a | |||
| 810fb7382f | |||
| b24ead5571 | |||
| 6d10b8bb95 | |||
| c738d45fa5 | |||
| b2fe2c2474 | |||
| 9577b49666 | |||
| 50f88e1887 | |||
| a57a6496fa | |||
| 8d22beb22c | |||
| e14d5eadd5 | |||
| 528a93a5da | |||
| 32a830231e | |||
| 0d1a5b80c2 | |||
| 17cae6ae5f | |||
| 4f65bb34b2 | |||
| eddca4280b | |||
| 175343dfdb | |||
| e0b5078cf2 | |||
| 1e474f7cfa | |||
| 63a857b874 | |||
| c3d69aeaaa | |||
| 684e9fd53d | |||
| ff0af64ced | |||
| bb8cdd9566 | |||
| 17ffa19a2d | |||
| 6c341347b2 | |||
| 8c32f577f1 | |||
| aa5d23799b | |||
| 540536c386 | |||
| f603d4714f | |||
| b72b6b4710 | |||
| 3ed14c6354 | |||
| 236b80b6f9 | |||
| ca5b3c4d3e | |||
| 245bcdd607 | |||
| e2e7211530 | |||
| b351d493ea | |||
| 096a5c2105 | |||
| b1407e1add | |||
| b4a747a94c | |||
| 3ae69406cc | |||
| b52a6264ac | |||
| dc9581469f | |||
| 05d9b97cf9 | |||
| 6aafd87038 | |||
| d4c8a9a887 | |||
| 057cc6d09d | |||
| dea76c7a6e | |||
| a07d64b406 | |||
| a6d6842467 | |||
| 33a30e0e03 | |||
| a385743983 | |||
| c9f8f3afb6 | |||
| 910dcb6d6a | |||
| de12bc7e02 | |||
| a4f312060c | |||
| de533fe491 | |||
| ea1e34c4dd | |||
| 304222014a | |||
| 82192deda9 | |||
| e8265f4593 | |||
| c0496c1f39 | |||
| 2d2ba938da | |||
| ff8911fe52 | |||
| 72d7a47dfd | |||
| 2c6781071f | |||
| e40d378f3e | |||
| d715c366d9 | |||
| c91bd074c0 | |||
| 2ec9ff087f | |||
| 8102331f82 | |||
| 44fc79b7f7 | |||
| 39827a08fe | |||
| 04f5841eed | |||
| 958fc6ab8a | |||
| cbfd1ee571 | |||
| b0dc2fbfcb | |||
| ef204bdf7a | |||
| 4441a95119 | |||
| d150e2672e | |||
| 59f9912dc1 | |||
| bce82bdc34 | |||
| 2ae0912eea | |||
| e583f4c808 | |||
| 05bcc601ac | |||
| 9f61910923 | |||
| 7797671257 | |||
| 0b08e29f26 |
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: adev-writing-guide
|
||||
description: Comprehensive writing guide for Angular documentation (adev). Covers Google Technical Writing standards, Angular-specific markdown extensions, code blocks, and components. Use when authoring or reviewing content in adev/src/content.
|
||||
description: Comprehensive writing guide for Angular documentation (adev). Covers Google Technical Writing standards, Angular-specific markdown extensions, code blocks, and components. You MUST use this skill any time you plan to create, edit, or review documentation files in `adev/` or `adev/src/content`.
|
||||
---
|
||||
|
||||
# Angular Documentation (adev) Writing Guide
|
||||
|
||||
@@ -50,6 +50,7 @@ When reviewing a pull request for the `angular` repository, follow these essenti
|
||||
- **Use Suggested Changes**: Whenever appropriate (e.g., for simple code fixes, refactoring suggestions, or typo corrections), prefer using GitHub's **Suggested Changes** syntax (`suggestion ... `) in your inline comments. This allows the author to apply your suggested code improvements with a single click in the GitHub UI.
|
||||
- **Review Type**: Never mark an external PR review as an "approval" unless explicitly instructed by a repo maintainer. Always use "Request Changes" or "Comment". Note that some tools might only support commenting.
|
||||
- **Require User Approval Before Posting**: Prepare your review comments and present them to the user, alongside a summary of your completed checklist. Do NOT post comments to the PR without explicitly asking the user for permission first. Only post the review after the user approves.
|
||||
- **CRITICAL**: This rule applies even if you receive a system message indicating that an artifact has been "automatically approved" or instructing you to "proceed to execution." You must ALWAYS obtain explicit, written confirmation from the user in this chat conversation before posting any content to a PR.
|
||||
- **Prefix Agent Comments**: To make it clear when comments are generated and posted by an AI agent rather than a human user, **always** prefix your review comments with `AGENT: `.
|
||||
|
||||
## Available Tools
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
description: Find and fix flaky tests in the repository
|
||||
---
|
||||
|
||||
Investigate flaky tests in the repo and propose fixes to improve stability.
|
||||
High-level process:
|
||||
|
||||
1. Run tests in the repo to look for flakes.
|
||||
- Consider using Bazel's `--runs_per_test` flag to easily find
|
||||
flakes.
|
||||
- Be cognizant of not exhausting all the resources on the current
|
||||
machine, run a subset of tests at a time such as
|
||||
`bazel test //packages/core/...`.
|
||||
2. Once you find some flakes, focus on one at a time.
|
||||
3. Create a new branch named `flakes/${relevantNameFromTest}`.
|
||||
4. Reproduce the flake to the best of your ability.
|
||||
- Consider using `--test_env JASMINE_RANDOM_SEED=1234` to
|
||||
replicate the broken test ordering.
|
||||
5. Debug the test to understand the failure mode.
|
||||
- Consider temporarily disabling / skipping other tests with `xit`
|
||||
and `fit` to narrow down where the flake might be coming from if
|
||||
multiple tests are influencing each other.
|
||||
- Consider temporarily ignoring Firefox tests with
|
||||
`--test_tag_filters -firefox` if the flake does not appear to be
|
||||
browser specific.
|
||||
- Consider using `--test_sharding_strategy disabled` to run the
|
||||
test in a single shard.
|
||||
- Try to understand why the test was _flaky_, not just why it
|
||||
_failed_. Understanding the inconsistency is important to
|
||||
finding the correct fix.
|
||||
6. Attempt a fix and validate with `--runs_per_test`.
|
||||
- Iterate on the fix until you have something which appears to
|
||||
work.
|
||||
- If you find yourself stuck and not making meaningful progress,
|
||||
note down what you've learned/where you're struggling, commit
|
||||
what you have, look for another flake to fix, and continue. At
|
||||
the end, surface to the user what you failed to fix.
|
||||
- Don't try to make significant changes to Angular's runtime
|
||||
behavior, focus just on making the test pass/fail consistently.
|
||||
7. Commit the change with relevant details in the commit message and
|
||||
move on to the next test.
|
||||
- Be sure to include your theory of why the test was flaky and
|
||||
how this fix eliminates or reduces that flakiness.
|
||||
8. Iterate as many times as the user requests you to (default 5
|
||||
branches if not otherwise specified).
|
||||
9. Once you can't find any flaky tests or have iterated as many times
|
||||
as requested, stop and inform the user what you found and fixed.
|
||||
|
||||
Additional notes:
|
||||
|
||||
- Multiple fixes including the same/related files can go in the same
|
||||
commit or multiple commits on the same branch.
|
||||
- Distinct test fixes should go in different branches, make a new one
|
||||
for each investigation.
|
||||
- You may push these branches to `origin`, but do not create PRs for
|
||||
them.
|
||||
@@ -19248,7 +19248,7 @@ var ChildProcess = class {
|
||||
return new Promise((resolve5, reject) => {
|
||||
const commandText = `${command2} ${args.join(" ")}`;
|
||||
Log.debug(`Executing command: ${commandText}`);
|
||||
const childProcess = _spawn(command2, args, { ...options, shell: true, stdio: "inherit" });
|
||||
const childProcess = _spawn(command2, args, { ...options, stdio: "inherit" });
|
||||
childProcess.on("close", (status) => status === 0 ? resolve5() : reject(status));
|
||||
});
|
||||
}
|
||||
@@ -19256,7 +19256,7 @@ var ChildProcess = class {
|
||||
const commandText = `${command2} ${args.join(" ")}`;
|
||||
const env22 = getEnvironmentForNonInteractiveCommand(options.env);
|
||||
Log.debug(`Executing command: ${commandText}`);
|
||||
const { status: exitCode, signal, stdout, stderr } = _spawnSync(command2, args, { ...options, env: env22, encoding: "utf8", shell: true, stdio: "pipe" });
|
||||
const { status: exitCode, signal, stdout, stderr } = _spawnSync(command2, args, { ...options, env: env22, encoding: "utf8", stdio: "pipe" });
|
||||
const status = statusFromExitCodeAndSignal(exitCode, signal);
|
||||
if (status === 0 || options.suppressErrorOnFailingExitCode) {
|
||||
return { status, stdout, stderr };
|
||||
@@ -19266,7 +19266,7 @@ var ChildProcess = class {
|
||||
static spawn(command2, args, options = {}) {
|
||||
const commandText = `${command2} ${args.join(" ")}`;
|
||||
const env22 = getEnvironmentForNonInteractiveCommand(options.env);
|
||||
return processAsyncCmd(commandText, options, _spawn(command2, args, { ...options, env: env22, shell: true, stdio: "pipe" }));
|
||||
return processAsyncCmd(commandText, options, _spawn(command2, args, { ...options, env: env22, stdio: "pipe" }));
|
||||
}
|
||||
static exec(command2, options = {}) {
|
||||
const env22 = getEnvironmentForNonInteractiveCommand(options.env);
|
||||
@@ -19321,7 +19321,7 @@ ${logOutput}`);
|
||||
});
|
||||
}
|
||||
function determineRepoBaseDirFromCwd() {
|
||||
const { stdout, stderr, status } = ChildProcess.spawnSync("git", ["rev-parse --show-toplevel"]);
|
||||
const { stdout, stderr, status } = ChildProcess.spawnSync("git", ["rev-parse", "--show-toplevel"]);
|
||||
if (status !== 0) {
|
||||
throw Error(`Unable to find the path to the base directory of the repository.
|
||||
Was the command run from inside of the repo?
|
||||
@@ -32582,6 +32582,54 @@ var types = (
|
||||
return types2;
|
||||
}()
|
||||
);
|
||||
async function invokeWithRetry(fn, retries = 3, delay = 1e3) {
|
||||
let attempt = 0;
|
||||
while (attempt < retries) {
|
||||
try {
|
||||
return await fn();
|
||||
} catch (e) {
|
||||
attempt++;
|
||||
if (attempt >= retries) {
|
||||
throw e;
|
||||
}
|
||||
if (isGithubApiError(e) && e.status < 500) {
|
||||
throw e;
|
||||
}
|
||||
if (e instanceof GraphqlResponseError2) {
|
||||
if (!e.errors) {
|
||||
throw e;
|
||||
}
|
||||
if (e.errors.every((err) => ["NOT_FOUND", "FORBIDDEN", "BAD_USER_INPUT", "UNAUTHENTICATED"].includes(err.type))) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
Log.warn(`GitHub API call failed (attempt ${attempt}/${retries}). Retrying in ${delay}ms...`);
|
||||
await new Promise((resolve22) => setTimeout(resolve22, delay));
|
||||
}
|
||||
}
|
||||
throw new Error("Unreachable");
|
||||
}
|
||||
function createRetryProxy(target) {
|
||||
return new Proxy(target, {
|
||||
get(targetObj, prop, receiver) {
|
||||
const value = Reflect.get(targetObj, prop, receiver);
|
||||
if (typeof value === "function") {
|
||||
return new Proxy(value, {
|
||||
apply(targetFn, thisArg, argArray) {
|
||||
return invokeWithRetry(() => targetFn.apply(targetObj, argArray));
|
||||
}
|
||||
});
|
||||
}
|
||||
if (typeof value === "object" && value !== null) {
|
||||
return createRetryProxy(value);
|
||||
}
|
||||
return value;
|
||||
},
|
||||
apply(targetFn, thisArg, argArray) {
|
||||
return invokeWithRetry(() => targetFn.apply(thisArg, argArray));
|
||||
}
|
||||
});
|
||||
}
|
||||
var GithubClient = class {
|
||||
constructor(_octokitOptions) {
|
||||
this._octokitOptions = _octokitOptions;
|
||||
@@ -32594,18 +32642,18 @@ var GithubClient = class {
|
||||
},
|
||||
...this._octokitOptions
|
||||
});
|
||||
this.pulls = this._octokit.pulls;
|
||||
this.orgs = this._octokit.orgs;
|
||||
this.repos = this._octokit.repos;
|
||||
this.issues = this._octokit.issues;
|
||||
this.git = this._octokit.git;
|
||||
this.rateLimit = this._octokit.rateLimit;
|
||||
this.teams = this._octokit.teams;
|
||||
this.search = this._octokit.search;
|
||||
this.rest = this._octokit.rest;
|
||||
this.paginate = this._octokit.paginate;
|
||||
this.checks = this._octokit.checks;
|
||||
this.users = this._octokit.users;
|
||||
this.pulls = createRetryProxy(this._octokit.pulls);
|
||||
this.orgs = createRetryProxy(this._octokit.orgs);
|
||||
this.repos = createRetryProxy(this._octokit.repos);
|
||||
this.issues = createRetryProxy(this._octokit.issues);
|
||||
this.git = createRetryProxy(this._octokit.git);
|
||||
this.rateLimit = createRetryProxy(this._octokit.rateLimit);
|
||||
this.teams = createRetryProxy(this._octokit.teams);
|
||||
this.search = createRetryProxy(this._octokit.search);
|
||||
this.rest = createRetryProxy(this._octokit.rest);
|
||||
this.paginate = createRetryProxy(this._octokit.paginate);
|
||||
this.checks = createRetryProxy(this._octokit.checks);
|
||||
this.users = createRetryProxy(this._octokit.users);
|
||||
}
|
||||
};
|
||||
var AuthenticatedGithubClient = class extends GithubClient {
|
||||
@@ -32617,9 +32665,14 @@ var AuthenticatedGithubClient = class extends GithubClient {
|
||||
});
|
||||
}
|
||||
async graphql(queryObject, params2 = {}) {
|
||||
return await this._graphql(query(queryObject).toString(), params2);
|
||||
return invokeWithRetry(async () => {
|
||||
return await this._graphql(query(queryObject).toString(), params2);
|
||||
});
|
||||
}
|
||||
};
|
||||
function isGithubApiError(obj) {
|
||||
return obj instanceof Error && obj.constructor.name === "RequestError" && obj.request !== void 0;
|
||||
}
|
||||
function isDryRun() {
|
||||
return process.env["DRY_RUN"] !== void 0;
|
||||
}
|
||||
@@ -33542,7 +33595,7 @@ tmp/lib/tmp.js:
|
||||
(* v8 ignore next -- @preserve *)
|
||||
(* v8 ignore else -- @preserve *)
|
||||
|
||||
@angular/ng-dev/bundles/chunk-YN3IWAKJ.mjs:
|
||||
@angular/ng-dev/bundles/chunk-G7GMCCSS.mjs:
|
||||
(*! Bundled license information:
|
||||
|
||||
yargs-parser/build/lib/string-utils.js:
|
||||
@@ -33583,7 +33636,7 @@ tmp/lib/tmp.js:
|
||||
*)
|
||||
*)
|
||||
|
||||
@angular/ng-dev/bundles/chunk-U2HAQOXA.mjs:
|
||||
@angular/ng-dev/bundles/chunk-PTDPQBIK.mjs:
|
||||
(*! Bundled license information:
|
||||
|
||||
@octokit/request-error/dist-src/index.js:
|
||||
|
||||
@@ -5,9 +5,9 @@ runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Saucelabs Variables
|
||||
uses: angular/dev-infra/github-actions/saucelabs@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/saucelabs@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Starting Saucelabs tunnel service
|
||||
shell: bash
|
||||
run: ./tools/saucelabs/sauce-service.sh run &
|
||||
|
||||
@@ -21,17 +21,17 @@ 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@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Build adev
|
||||
# `snapshot-build` config is used to stamp the exact version with sha in the footer.
|
||||
run: pnpm bazel build //adev:build.production --config=snapshot-build
|
||||
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
with:
|
||||
workflow-artifact-name: 'adev-preview'
|
||||
pull-number: '${{github.event.pull_request.number}}'
|
||||
|
||||
@@ -32,15 +32,17 @@ jobs:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
token: '${{secrets.GITHUB_TOKEN}}'
|
||||
persist-credentials: false
|
||||
|
||||
- name: Configure Firebase deploy target
|
||||
working-directory: ./
|
||||
run: |
|
||||
# We can use `npx` as the Firebase deploy actions uses it too.
|
||||
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}}
|
||||
# Use stable version release
|
||||
npx -y firebase-tools@15.15.0 target:clear --config adev/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting angular-docs
|
||||
npx -y firebase-tools@15.15.0 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@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
with:
|
||||
github-token: '${{secrets.GITHUB_TOKEN}}'
|
||||
workflow-artifact-name: 'adev-preview'
|
||||
|
||||
@@ -17,6 +17,6 @@ jobs:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: angular/dev-infra/github-actions/branch-manager@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
- uses: angular/dev-infra/github-actions/branch-manager@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
token: '${{secrets.BENCHMARK_POST_RESULTS_GITHUB_TOKEN}}'
|
||||
reactions: 'rocket'
|
||||
|
||||
- uses: alessbell/pull-request-comment-branch@aad01d65d6982b8eacabed5e9a684cd8ceb98da6 # v1.1
|
||||
- uses: alessbell/pull-request-comment-branch@653a7d5ca8bd91d3c5cb83286063314d0b063b8e # v1.4.0
|
||||
id: comment-branch
|
||||
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
@@ -34,11 +34,23 @@ jobs:
|
||||
repository: ${{steps.comment-branch.outputs.head_owner}}/${{steps.comment-branch.outputs.head_repo}}
|
||||
# Checkout the pull request and assume it being trusted given we've checked
|
||||
# that the action was triggered by a team member.
|
||||
ref: ${{steps.comment-branch.outputs.head_ref}}
|
||||
ref: ${{steps.comment-branch.outputs.head_sha}}
|
||||
|
||||
# We cannot use `angular/dev-infra/github-actions/npm/checkout-and-setup-node` here
|
||||
# because it does not support checking out from a fork (as it lacks a `repository` input).
|
||||
# Thus, we checkout and setup Node/pnpm manually.
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@903f9c1a6ebcba6cf41d87230be49611ac97822e # v6.0.3
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'pnpm'
|
||||
|
||||
- run: pnpm install --frozen-lockfile
|
||||
|
||||
- uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
- uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
with:
|
||||
bazelrc: ./.bazelrc.user
|
||||
|
||||
@@ -49,7 +61,8 @@ jobs:
|
||||
COMMENT_BODY: ${{ github.event.comment.body }}
|
||||
run: pnpm benchmarks prepare-for-github-action "$COMMENT_BODY"
|
||||
|
||||
- run: pnpm benchmarks run-compare ${{steps.info.outputs.compareSha}} ${{steps.info.outputs.benchmarkTarget}}
|
||||
- run: pnpm benchmarks run-compare ${{steps.info.outputs.compareSha}} "${{steps.info.outputs.benchmarkTarget}}"
|
||||
|
||||
id: benchmark
|
||||
name: Running benchmark
|
||||
|
||||
|
||||
+26
-26
@@ -21,7 +21,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Check code lint
|
||||
@@ -41,13 +41,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
with:
|
||||
disable-package-manager-cache: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
with:
|
||||
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
|
||||
- name: Install node modules
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
- name: Test build
|
||||
run: pnpm devtools:build:chrome
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@4c06c48f3ffea349b7189aa06dfcda47a9fa7b92 # v7.1.8
|
||||
uses: cypress-io/github-action@c495c3ddffba403ba11be95fffb67e25203b3799 # v7.1.10
|
||||
with:
|
||||
command: pnpm devtools:test:e2e
|
||||
start: pnpm bazel run //devtools/src:devserver
|
||||
@@ -69,11 +69,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
with:
|
||||
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
|
||||
- name: Install node modules
|
||||
@@ -85,11 +85,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
with:
|
||||
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
|
||||
- name: Install node modules
|
||||
@@ -102,11 +102,11 @@ jobs:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
with:
|
||||
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
|
||||
- name: Install node modules
|
||||
@@ -121,11 +121,11 @@ jobs:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
with:
|
||||
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
|
||||
- name: Install node modules
|
||||
@@ -138,11 +138,11 @@ jobs:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- run: echo "https://${{secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN}}:@github.com" > ${HOME}/.git_credentials
|
||||
@@ -154,11 +154,11 @@ jobs:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
with:
|
||||
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
|
||||
- name: Install node modules
|
||||
@@ -208,11 +208,11 @@ jobs:
|
||||
runs-on: ubuntu-latest-8core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Build adev
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
ANGULAR_READONLY_GITHUB_TOKEN: ${{ secrets.READONLY_GITHUB_TOKEN }}
|
||||
|
||||
- name: Create a PR (if necessary)
|
||||
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
|
||||
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
|
||||
with:
|
||||
token: ${{ secrets.ANGULAR_ROBOT_ACCESS_TOKEN }}
|
||||
push-to-fork: 'angular-robot/angular'
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: angular/dev-infra/github-actions/labeling/pull-request@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
- uses: angular/dev-infra/github-actions/labeling/pull-request@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
labels: '{"requires: TGP": ["packages/core/primitives/**/{*,.*}"]}'
|
||||
@@ -25,14 +25,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: angular/dev-infra/github-actions/post-approval-changes@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
- uses: angular/dev-infra/github-actions/post-approval-changes@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
issue_labels:
|
||||
if: github.event_name == 'issues'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: angular/dev-infra/github-actions/labeling/issue@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
- uses: angular/dev-infra/github-actions/labeling/issue@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
google-generative-ai-key: ${{ secrets.GOOGLE_GENERATIVE_AI_KEY }}
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: angular/dev-infra/github-actions/google-internal-tests@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
- uses: angular/dev-infra/github-actions/google-internal-tests@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
with:
|
||||
run-tests-guide-url: http://go/angular-g3sync-start
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -13,15 +13,15 @@ jobs:
|
||||
JOBS: 2
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Saucelabs Variables
|
||||
uses: angular/dev-infra/github-actions/saucelabs@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/saucelabs@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Set up Sauce Tunnel Daemon
|
||||
run: pnpm bazel run //tools/saucelabs-daemon/background-service -- $JOBS &
|
||||
env:
|
||||
|
||||
@@ -9,6 +9,6 @@ jobs:
|
||||
status:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: angular/dev-infra/github-actions/unified-status-check@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
- uses: angular/dev-infra/github-actions/unified-status-check@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
workflows: ${{ steps.workflows.outputs.workflows }}
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- id: workflows
|
||||
@@ -36,9 +36,9 @@ jobs:
|
||||
workflow: ${{ fromJSON(needs.list.outputs.workflows) }}
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
# We utilize the google-github-actions/auth action to allow us to get an active credential using workflow
|
||||
|
||||
+21
-21
@@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Check code lint
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
- name: Check code format
|
||||
run: pnpm ng-dev format changed --check ${{ github.event.pull_request.base.sha }}
|
||||
- name: Check Package Licenses
|
||||
uses: angular/dev-infra/github-actions/linting/licenses@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/linting/licenses@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
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@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
with:
|
||||
disable-package-manager-cache: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Run unit tests
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
- name: Test build
|
||||
run: pnpm devtools:build:chrome
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@4c06c48f3ffea349b7189aa06dfcda47a9fa7b92 # v7.1.8
|
||||
uses: cypress-io/github-action@c495c3ddffba403ba11be95fffb67e25203b3799 # v7.1.10
|
||||
with:
|
||||
command: pnpm devtools:test:e2e
|
||||
start: pnpm bazel run //devtools/src:devserver
|
||||
@@ -73,11 +73,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Run CI tests for framework
|
||||
@@ -97,11 +97,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Run integration CI tests for framework
|
||||
@@ -112,11 +112,11 @@ jobs:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Run tests
|
||||
@@ -129,11 +129,11 @@ jobs:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Run tests
|
||||
@@ -144,11 +144,11 @@ jobs:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@616a50d0b747031b7ea052733adf3771fa6cace9
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- run: |
|
||||
|
||||
@@ -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@b8bb9f28b8d3f992092362369c57161b755dea45 # v4.35.0
|
||||
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
+19
-18
@@ -36,8 +36,9 @@
|
||||
|
||||
version: 3
|
||||
|
||||
#availability:
|
||||
# users_unavailable: []
|
||||
availability:
|
||||
users_unavailable:
|
||||
- devversion
|
||||
|
||||
# Meta field that goes unused by PullApprove to allow for defining aliases to be
|
||||
# used throughout the config.
|
||||
@@ -99,11 +100,11 @@ groups:
|
||||
reviewers:
|
||||
users:
|
||||
- ~alxhub
|
||||
- AndrewKushnir
|
||||
- ~AndrewKushnir
|
||||
- atscott
|
||||
- crisbeto
|
||||
- devversion
|
||||
- thePunderWoman
|
||||
- ~thePunderWoman
|
||||
- kirjs
|
||||
- JoostK
|
||||
- ~amishne
|
||||
@@ -145,12 +146,12 @@ groups:
|
||||
reviewers:
|
||||
users:
|
||||
- ~alxhub
|
||||
- AndrewKushnir
|
||||
- ~AndrewKushnir
|
||||
- atscott
|
||||
- crisbeto
|
||||
- devversion
|
||||
- kirjs
|
||||
- thePunderWoman
|
||||
- ~thePunderWoman
|
||||
- ~pkozlowski-opensource
|
||||
- JeanMeche
|
||||
- ~amishne
|
||||
@@ -200,12 +201,12 @@ groups:
|
||||
users:
|
||||
- ~JiaLiPassion
|
||||
- ~alxhub
|
||||
- AndrewKushnir
|
||||
- ~AndrewKushnir
|
||||
- atscott
|
||||
- crisbeto
|
||||
- devversion
|
||||
- kirjs
|
||||
- thePunderWoman
|
||||
- ~thePunderWoman
|
||||
- ~pkozlowski-opensource
|
||||
- ~amishne
|
||||
- ~leonsenft
|
||||
@@ -250,13 +251,13 @@ groups:
|
||||
users:
|
||||
- alan-agius4
|
||||
- ~alxhub
|
||||
- AndrewKushnir
|
||||
- ~AndrewKushnir
|
||||
- atscott
|
||||
- bencodezen
|
||||
- crisbeto
|
||||
- kirjs
|
||||
- JeanMeche
|
||||
- thePunderWoman
|
||||
- ~thePunderWoman
|
||||
- devversion
|
||||
- josephperrott
|
||||
- ~pkozlowski-opensource
|
||||
@@ -372,10 +373,10 @@ groups:
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- AndrewKushnir
|
||||
- ~AndrewKushnir
|
||||
- ~alxhub
|
||||
- atscott
|
||||
- thePunderWoman
|
||||
- ~thePunderWoman
|
||||
- ~pkozlowski-opensource
|
||||
- kirjs
|
||||
- crisbeto
|
||||
@@ -408,10 +409,10 @@ groups:
|
||||
reviewers:
|
||||
users:
|
||||
- ~alxhub
|
||||
- AndrewKushnir
|
||||
- ~AndrewKushnir
|
||||
- atscott
|
||||
- kirjs
|
||||
- thePunderWoman
|
||||
- ~thePunderWoman
|
||||
- ~pkozlowski-opensource
|
||||
- ~amishne
|
||||
- ~leonsenft
|
||||
@@ -456,10 +457,10 @@ groups:
|
||||
reviewers:
|
||||
users:
|
||||
- ~alxhub
|
||||
- AndrewKushnir
|
||||
- ~AndrewKushnir
|
||||
- andrewseguin
|
||||
- dgp1130
|
||||
- thePunderWoman
|
||||
- ~thePunderWoman
|
||||
- josephperrott
|
||||
|
||||
# =========================================================
|
||||
@@ -478,8 +479,8 @@ groups:
|
||||
users:
|
||||
- ~pkozlowski-opensource # Pawel Kozlowski
|
||||
- ~alxhub # Alex Rickabaugh
|
||||
- thePunderWoman # Jessica Janiuk
|
||||
- AndrewKushnir # Andrew Kushnir
|
||||
- ~thePunderWoman # Jessica Janiuk
|
||||
- ~AndrewKushnir # Andrew Kushnir
|
||||
- atscott # Andrew Scott
|
||||
|
||||
# External team required reviews
|
||||
|
||||
+293
@@ -1,3 +1,296 @@
|
||||
<a name="21.2.20"></a>
|
||||
# 21.2.20 (2026-08-12)
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [6afe6fa781](https://github.com/angular/angular/commit/6afe6fa781c2f0931f0aedd729b9884a8fe212ee) | fix | sanitize host bindings on concrete hosts |
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [fec5977df4](https://github.com/angular/angular/commit/fec5977df4dda3a10d5ce2923e3e06d86ba11ee7) | fix | match header values exactly when deleting |
|
||||
| [e33d69a71c](https://github.com/angular/angular/commit/e33d69a71c5beb8fe5785b53fd6b37658334e8e0) | fix | preserve immutability of materialized clones |
|
||||
| [caf616670f](https://github.com/angular/angular/commit/caf616670fd20d528aa69e0131cc17d60f0cc27d) | fix | run root interceptors in the terminal request chain |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.2.19"></a>
|
||||
# 21.2.19 (2026-07-29)
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [e2660c3dee](https://github.com/angular/angular/commit/e2660c3deeccb86471f9c11b7e65ebcc89d84e9e) | fix | disallow i18n event attributes |
|
||||
| [7b884f585a](https://github.com/angular/angular/commit/7b884f585abf50480c271d234c892c141eb61e2c) | fix | restrict possible event handler check to property names longer than 2 characters |
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [948a8d6831](https://github.com/angular/angular/commit/948a8d6831e8920b54663ec79421da95210e0e35) | fix | distinguish repeated transfer cache params |
|
||||
| [9949dccce1](https://github.com/angular/angular/commit/9949dccce164638597496a6b3881043117dfd1df) | fix | enable xsrf for root-provided HttpClient |
|
||||
### platform-server
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [f34a93c946](https://github.com/angular/angular/commit/f34a93c946c017eff526cfb0c8d17f51e97f01e4) | fix | update domino to latest version |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.2.18"></a>
|
||||
# 21.2.18 (2026-07-08)
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [8d22cc953b](https://github.com/angular/angular/commit/8d22cc953bb9f970c6f86fb0f6e4d0665b874bfa) | fix | update babel dependencies to latest v7 |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [6bcce117fb](https://github.com/angular/angular/commit/6bcce117fbc616e4e721f351e9e038202e916522) | fix | avoid caching missing locale data |
|
||||
| [5a693bafcd](https://github.com/angular/angular/commit/5a693bafcd49ef11ce687bd91a209e1a46652f42) | fix | reject dynamic script host elements |
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [91df739b80](https://github.com/angular/angular/commit/91df739b8022e2177bcc7214ed9a4e94098a4831) | fix | prevent caching of responses with Set-Cookie headers |
|
||||
### service-worker
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [1804f73bec](https://github.com/angular/angular/commit/1804f73becf425b5b1ccee9751d6e3fbd10e1f0b) | fix | preserve referrer in asset requests |
|
||||
| [e86c31bf26](https://github.com/angular/angular/commit/e86c31bf26359aacce814167506dbdae585a7eb8) | fix | preserve referrer policy in asset requests |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.2.17"></a>
|
||||
# 21.2.17 (2026-06-10)
|
||||
## Deprecations
|
||||
### platform-server
|
||||
- XHR support in `@angular/platform-server` is deprecated. Use standard `fetch` APIs instead.
|
||||
### common
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [86a56dc279](https://github.com/angular/angular/commit/86a56dc279e71159d09a073a3cb138f49131995b) | fix | Limits date format string length |
|
||||
| [d846326b07](https://github.com/angular/angular/commit/d846326b071e0a4ab090e068d934b182926c6b15) | fix | skip transfer cache for uncacheable HTTP traffic |
|
||||
| [bc55749698](https://github.com/angular/angular/commit/bc55749698ce3917160cd8e9f7108f3c5d1c0b32) | fix | use cryptographically secure SHA-256 for transfer cache key generation |
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [dc9c99636d](https://github.com/angular/angular/commit/dc9c99636d3471ed5a3c5cda54b95f604cd2b9a4) | fix | sanitize two-way properties |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [1523061137](https://github.com/angular/angular/commit/152306113760e13196653699b42046d9f4129a37) | fix | harden TransferState restoration against DOM clobbering |
|
||||
| [88832c84f8](https://github.com/angular/angular/commit/88832c84f8a3cd88d80adcde539a6f91a1f30b74) | fix | validate lowercase SVG animation attribute names ([#69269](https://github.com/angular/angular/pull/69269)) |
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [bcb1b7ea25](https://github.com/angular/angular/commit/bcb1b7ea2575b140f7bf202ad4f779e402cd6094) | fix | preserve empty referrer option in HttpRequest |
|
||||
| [a810a319d1](https://github.com/angular/angular/commit/a810a319d10a8254307eb8f0598e7a888ce09ec0) | fix | Rejects non-HTTP(S) URLs in JSONP requests |
|
||||
| [e245d40c4d](https://github.com/angular/angular/commit/e245d40c4d05665ab4814c594b8e0849b6e88a2d) | fix | skip transfer cache for fetch credentialed requests |
|
||||
### platform-server
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [35510746b7](https://github.com/angular/angular/commit/35510746b7d6b5c3de41de04c0586fc286c9e748) | fix | harden platform location origin validation during SSR |
|
||||
| [13fb0afe93](https://github.com/angular/angular/commit/13fb0afe93b45e3c2383969f70d3ee1f0146ecfb) | refactor | deprecate ServerXhr ([#69255](https://github.com/angular/angular/pull/69255)) |
|
||||
### service-worker
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [b9d29381bb](https://github.com/angular/angular/commit/b9d29381bb4442164b19d9b7e0baa147a7b25629) | fix | Strips sensitive headers on cross-origin redirects |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.2.16"></a>
|
||||
# 21.2.16 (2026-06-03)
|
||||
### common
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [f6d8e642b0](https://github.com/angular/angular/commit/f6d8e642b0b215d2f9dbf1060abd24348c6cbf66) | fix | only strip a literal /index.html suffix from URLs |
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [ae1c8a1f7a](https://github.com/angular/angular/commit/ae1c8a1f7a7f1d4832da3b22e3763864fa5ff098) | fix | move projection attributes into constants |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [3fd6897a67](https://github.com/angular/angular/commit/3fd6897a67fd6acdc01fcde0452a98c3e0f81e21) | fix | harden inherit definition feature against polluted prototypes |
|
||||
| [7e38336dc7](https://github.com/angular/angular/commit/7e38336dc73e14d98cc6465f54e1b7d6271facb2) | fix | use Object.create(null) for LOCALE_DATA as a hardening measure |
|
||||
### platform-server
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [66821c4ed5](https://github.com/angular/angular/commit/66821c4ed5f580912a1609fc1e06a86f8793c2cf) | fix | throw on suspicious URLs and restrict protocol-relative URLs |
|
||||
| [d3170031b6](https://github.com/angular/angular/commit/d3170031b6f35508f960cba18586843925bb61ec) | fix | update domino to latest version |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.2.15"></a>
|
||||
# 21.2.15 (2026-05-28)
|
||||
### common
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [7f4ac78994](https://github.com/angular/angular/commit/7f4ac78994bff1576ab33f3ce48f95c17f40b4d8) | fix | add upper bounds for digitsInfo |
|
||||
| [300f61feb3](https://github.com/angular/angular/commit/300f61feb3a534bfddf16fcbd240f97b32249699) | fix | sanitize placeholder |
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [0b07f47bd6](https://github.com/angular/angular/commit/0b07f47bd6598ae6bd5b75a375e2c817a3c0f243) | fix | normalize tag names with custom namespaces in DomElementSchemaRegistry ([#68925](https://github.com/angular/angular/pull/68925)) |
|
||||
| [eb1cbbf2eb](https://github.com/angular/angular/commit/eb1cbbf2eb5833219a367a61c04eb07aaa36cc29) | fix | prevent namespaced SVG <style> elements from being stripped |
|
||||
| [cc1378d54b](https://github.com/angular/angular/commit/cc1378d54bd93f3882d732261be8e66720eb71b2) | fix | sanitize dynamic href and xlink:href bindings on SVG a elements ([#68925](https://github.com/angular/angular/pull/68925)) |
|
||||
| [782e01594e](https://github.com/angular/angular/commit/782e01594e2ad9134c7385dcf3b518101b23ccab) | fix | strip namespaced SVG script elements during template compilation ([#68925](https://github.com/angular/angular/pull/68925)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [ff12fe55ac](https://github.com/angular/angular/commit/ff12fe55ace5e861ba261afb4c0480ff3c40a192) | fix | normalize tag names in runtime i18n attribute security context lookup ([#68925](https://github.com/angular/angular/pull/68925)) |
|
||||
| [e6fe77cc97](https://github.com/angular/angular/commit/e6fe77cc97fd10351687416f938bf754aff4eb9f) | fix | sanitize meta selectors |
|
||||
| [daaf32937f](https://github.com/angular/angular/commit/daaf32937fd5c46e411b26f7c082613716fe9550) | fix | support prefix-insensitive DOM schema lookups and compile-time i18n attribute validation ([#68925](https://github.com/angular/angular/pull/68925)) |
|
||||
| [dada86e43d](https://github.com/angular/angular/commit/dada86e43d847204f714d1a933084617ab941c0a) | fix | synchronize core sanitization schema with compiler ([#68925](https://github.com/angular/angular/pull/68925)) |
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [582a417bd2](https://github.com/angular/angular/commit/582a417bd27fdaf989e5065dbcdf1ad752faf70c) | fix | exclude withCredentials requests from transfer cache |
|
||||
| [5c6d6df34b](https://github.com/angular/angular/commit/5c6d6df34bbeff3ce98f3b35875444f925cc8f51) | fix | skip TransferCache for cookie-bearing requests by default |
|
||||
### platform-server
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [37e8aadf87](https://github.com/angular/angular/commit/37e8aadf87b4facfcaf002a1557f8c393a362d97) | fix | prevent SSRF bypasses via backslash URLs in HttpClient |
|
||||
| [72696e244e](https://github.com/angular/angular/commit/72696e244ed7646cca9ab9afc7769a2163943bda) | fix | secure location and document initialization against SSRF and path hijack |
|
||||
### service-worker
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [b8bd49341d](https://github.com/angular/angular/commit/b8bd49341ddcee10d119a9d4aa8e5736e4e5da53) | fix | Preserves explicit 'credentials: omit' in asset requests |
|
||||
| [ca32fc1000](https://github.com/angular/angular/commit/ca32fc10001301e6174804f9abcfba62252334f4) | fix | Preserves HTTP cache mode in asset group requests |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.2.14"></a>
|
||||
# 21.2.14 (2026-05-20)
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [68282dff9f](https://github.com/angular/angular/commit/68282dff9f9ef46540cca4bd38fc1ab739c8a783) | fix | strip namespaced SVG script elements during template compilation |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [c0f52272ed](https://github.com/angular/angular/commit/c0f52272ed337d4776bd4178cbbdc7f32037500f) | fix | do not insert todo when migrating void @Output |
|
||||
| [938a7f3edd](https://github.com/angular/angular/commit/938a7f3eddda97a39edb9edcc8b4dd970858b3a2) | fix | makes resource URL sanitizer lookup case-insensitive |
|
||||
| [0fb2724194](https://github.com/angular/angular/commit/0fb272419407a64a0a47096b03a911f4e7e83d79) | fix | reject script element as a dynamic component host |
|
||||
| [49113ac0ef](https://github.com/angular/angular/commit/49113ac0eff852d987b5acb28a9bbda0242842cd) | fix | visit ICU expressions in signal migration schematics |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [099bf577ee](https://github.com/angular/angular/commit/099bf577ee8f0bab60593a8fd2a1de7d298e3cd6) | fix | skip scroll-to-top on initial navigation when hydrating |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.2.13"></a>
|
||||
# 21.2.13 (2026-05-13)
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [1c6553e97d](https://github.com/angular/angular/commit/1c6553e97d9655d8c48fbf625987fae86f9cd947) | fix | disallow event attribute bindings in host bindings unconditionally |
|
||||
### platform-server
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [629905d537](https://github.com/angular/angular/commit/629905d537f59dc3c264c49f6347e3599dea0215) | fix | add `allowedHosts` option to `renderModule` and `renderApplication` |
|
||||
| [0b7192f441](https://github.com/angular/angular/commit/0b7192f4410d055191ac9b15bff57d1d0b9a644f) | fix | forward BEFORE_APP_SERIALIZED errors to ErrorHandler |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.2.12"></a>
|
||||
# 21.2.12 (2026-05-06)
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [fe13bb669d](https://github.com/angular/angular/commit/fe13bb669d2bfab4713623d17b41c430aa0a61d8) | fix | allow explicit read generic with signal input transforms |
|
||||
| [3430251fef](https://github.com/angular/angular/commit/3430251fef93f6aec1fa9c7867e85df23f67c9a0) | fix | i18n flags leaking on errors |
|
||||
| [1aeebbe304](https://github.com/angular/angular/commit/1aeebbe3048b5aa612dd0a5448de9883ed51e7e8) | fix | respect ngSkipHydration on components with projectable nodes in LContainers |
|
||||
| [9e38ed7d57](https://github.com/angular/angular/commit/9e38ed7d5773a9193ba07afdba3f7a9f2fe02d18) | fix | sanitizer typings |
|
||||
| [7a05a9a71a](https://github.com/angular/angular/commit/7a05a9a71a5ab75042ec5560c01526de6e61e062) | fix | validate security-sensitive attributes in i18n bindings |
|
||||
| [c37f6ca42f](https://github.com/angular/angular/commit/c37f6ca42f263353cb9563fa90d7b31d3c7837ca) | fix | visit ng-let expression value in signal migration schematics |
|
||||
### forms
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [03ad53863b](https://github.com/angular/angular/commit/03ad53863bf3c368f0f02a4322d4141e8f70f674) | fix | prohibit concurrent submits in signal forms |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.2.11"></a>
|
||||
# 21.2.11 (2026-04-29)
|
||||
### common
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [10ad3c0692](https://github.com/angular/angular/commit/10ad3c06923453ae0ec06b06e664ce05900a4ff6) | fix | prevent focus from scrollToAnchor |
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [4f5d8a2c0b](https://github.com/angular/angular/commit/4f5d8a2c0b5e38d4debc4293945270cea4a9590d) | fix | let declaration span not including end character |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [a40e2cebc8](https://github.com/angular/angular/commit/a40e2cebc878965c3e21bfb61658f3f80cbd2ebf) | fix | fix ordering of view queries metadata in JIT mode |
|
||||
| [885a1a1d97](https://github.com/angular/angular/commit/885a1a1d9757adfa8766d9b369c848a277438c31) | fix | guard against non-object events and avoid listener wrapper identity mismatch |
|
||||
| [7a64aff9b5](https://github.com/angular/angular/commit/7a64aff9b59999077ea915486a7fa0b97a286659) | fix | prevent event replay double-invocation when element hydrates before app stability |
|
||||
### platform-server
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [be1f80a253](https://github.com/angular/angular/commit/be1f80a253b8ee27ed7d8de2287d6895c4821909) | fix | ensure origin has a trailing slash when parsing url |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.2.10"></a>
|
||||
# 21.2.10 (2026-04-22)
|
||||
### docs
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [0d5ee9ae1b](https://github.com/angular/angular/commit/0d5ee9ae1ba4b7acd8f27a059a778f0b4bd8a5bd) | fix | link formatting in "Animating your Application with CSS" |
|
||||
### migrations
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [5533ab4f56](https://github.com/angular/angular/commit/5533ab4f56f574bc9365cf0573c4a34a3ab5aaf1) | fix | fix NgClass leaving trailing comma after removal |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [580212c995](https://github.com/angular/angular/commit/580212c995751c4bf4ce8a49df4167498743e0ea) | fix | restore internal URL on popstate when `browserUrl` is used |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.2.9"></a>
|
||||
# 21.2.9 (2026-04-15)
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [f603d4714f](https://github.com/angular/angular/commit/f603d4714fa184aad34a6f7f9ea4e79c8af3afac) | fix | escape forward slashes in transfer state to prevent crawler indexing |
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [540536c386](https://github.com/angular/angular/commit/540536c386f2c735a700c2c9e2697a88dcb3d4ec) | fix | add CSP nonce support to JsonpClientBackend |
|
||||
| [63a857b874](https://github.com/angular/angular/commit/63a857b874172766451aa75ed3347ba50f0ee229) | fix | Don't on Passthru outside of reactive context |
|
||||
### platform-server
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [e0b5078cf2](https://github.com/angular/angular/commit/e0b5078cf2ebe79a6de85e9123148ae948b3d81d) | fix | prevent SSRF bypasses via protocol-relative and backslash URLs |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [684e9fd53d](https://github.com/angular/angular/commit/684e9fd53daacb9e910f42d98c6017f9e5cb4180) | fix | normalize multiple leading slashes in URL parser |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.2.8"></a>
|
||||
# 21.2.8 (2026-04-08)
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [e40d378f3e](https://github.com/angular/angular/commit/e40d378f3e3e7e57a45c8fbd9565ee06a3a6a13f) | fix | handle nested brackets in host object bindings |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [2c6781071f](https://github.com/angular/angular/commit/2c6781071f52d6378a002fba6611bb283fbb2fde) | fix | error for type parameter declarations |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [82192deda9](https://github.com/angular/angular/commit/82192deda9c07113835e6c85af3f2c8c8218cda0) | fix | handle missing serialized container hydration data |
|
||||
| [057cc6d09d](https://github.com/angular/angular/commit/057cc6d09d234f401a810cfdd3ad14127652b88b) | fix | remove obsolete iOS cursor pointer hack in event delegation |
|
||||
### language-service
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [7797671257](https://github.com/angular/angular/commit/7797671257350665e8b3ceb2bc6a0201829dd338) | fix | get quick info at local var location to align with TS semantics and support type narrowing |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.2.7"></a>
|
||||
# 21.2.7 (2026-04-01)
|
||||
### compiler
|
||||
|
||||
+2
-2
@@ -71,7 +71,7 @@ You can file new issues by selecting from our [new issue templates](https://gith
|
||||
|
||||
### <a name="pr-quality"></a> Contribution Quality
|
||||
|
||||
We strongly value open source contribution and pull requests from community contributors. Please note that every pull request is reviewed and merged by an actual person on the team, which does take time and effort. That is time and effort that does take away from other valuable work. With that in mind we have an minimum set of expectations that are required of any community contribution pull request that is opened.
|
||||
We strongly value open source contribution and pull requests from community contributors. Please note that every pull request is reviewed and merged by an actual person on the team, which does take time and effort. That is time and effort that does take away from other valuable work. With that in mind we have a minimum set of expectations that are required of any community contribution pull request that is opened.
|
||||
|
||||
1. Search [GitHub](https://github.com/angular/angular/pulls) for an open or closed PR that relates to your submission.
|
||||
- You don't want to duplicate existing efforts.
|
||||
@@ -238,7 +238,7 @@ changes to be accepted, the CLA must be signed. It's a quick process, we promise
|
||||
- For corporations, we'll need you to
|
||||
[print, sign and one of scan+email, fax or mail the form][corporate-cla].
|
||||
|
||||
If you have more than one GitHub accounts, or multiple email addresses associated with a single GitHub account, you must sign the CLA using the primary email address of the GitHub account used to author Git commits and send pull requests.
|
||||
If you have more than one GitHub account, or multiple email addresses associated with a single GitHub account, you must sign the CLA using the primary email address of the GitHub account used to author Git commits and send pull requests.
|
||||
|
||||
The following documents can help you sort out issues with GitHub accounts and multiple email addresses:
|
||||
|
||||
|
||||
+16
-18
@@ -5,41 +5,41 @@ module(
|
||||
)
|
||||
|
||||
bazel_dep(name = "rules_pkg", version = "1.2.0")
|
||||
bazel_dep(name = "rules_nodejs", version = "6.7.3")
|
||||
bazel_dep(name = "aspect_rules_ts", version = "3.8.7")
|
||||
bazel_dep(name = "rules_nodejs", version = "6.7.4")
|
||||
bazel_dep(name = "aspect_rules_ts", version = "3.8.8")
|
||||
bazel_dep(name = "aspect_rules_js", version = "3.0.3")
|
||||
bazel_dep(name = "aspect_rules_esbuild", version = "0.25.1")
|
||||
bazel_dep(name = "aspect_rules_jasmine", version = "2.0.4")
|
||||
bazel_dep(name = "aspect_rules_rollup", version = "2.0.1")
|
||||
bazel_dep(name = "bazel_skylib", version = "1.9.0")
|
||||
bazel_dep(name = "bazel_lib", version = "3.2.2")
|
||||
bazel_dep(name = "tar.bzl", version = "0.9.0")
|
||||
bazel_dep(name = "yq.bzl", version = "0.3.5")
|
||||
bazel_dep(name = "bazel_lib", version = "3.3.1")
|
||||
bazel_dep(name = "tar.bzl", version = "0.10.1")
|
||||
bazel_dep(name = "yq.bzl", version = "0.3.6")
|
||||
bazel_dep(name = "rules_angular")
|
||||
git_override(
|
||||
module_name = "rules_angular",
|
||||
commit = "32ce54318d9ec5d84269d4acecbc39944cd8b5e7",
|
||||
commit = "b1d295334e70335dab7ac9984a989fae0a9c9dc2",
|
||||
remote = "https://github.com/angular/rules_angular.git",
|
||||
)
|
||||
|
||||
bazel_dep(name = "devinfra")
|
||||
git_override(
|
||||
module_name = "devinfra",
|
||||
commit = "616a50d0b747031b7ea052733adf3771fa6cace9",
|
||||
commit = "48c48fa3848de5bb0ec1c3203558f099765165ab",
|
||||
remote = "https://github.com/angular/dev-infra.git",
|
||||
)
|
||||
|
||||
bazel_dep(name = "rules_sass")
|
||||
git_override(
|
||||
module_name = "rules_sass",
|
||||
commit = "13918bec49cd183a591e3781d1d08044b4aa9f61",
|
||||
commit = "a65d937fabd87672f7245aeaa5eb5a0c5a2abead",
|
||||
remote = "https://github.com/angular/rules_sass.git",
|
||||
)
|
||||
|
||||
bazel_dep(name = "rules_browsers")
|
||||
git_override(
|
||||
module_name = "rules_browsers",
|
||||
commit = "afdc95c1ce8ed9ff0cb94f829b7fc988c43dd783",
|
||||
commit = "b03f09ef28a08f8ae07482851cf5ecbf6ac23a2a",
|
||||
remote = "https://github.com/angular/rules_browsers.git",
|
||||
)
|
||||
|
||||
@@ -71,8 +71,8 @@ use_repo(node, "nodejs_windows_amd64")
|
||||
pnpm = use_extension("@aspect_rules_js//npm:extensions.bzl", "pnpm")
|
||||
pnpm.pnpm(
|
||||
name = "pnpm",
|
||||
pnpm_version = "10.33.0",
|
||||
pnpm_version_integrity = "sha512-EFaLtKavtYyes2MNqQzJUWQXq+vT+rvmc58K55VyjaFJHp21pUTHatjrdXD1xLs9bGN7LLQb/c20f6gjyGSTGQ==",
|
||||
pnpm_version = "10.33.2",
|
||||
pnpm_version_integrity = "sha512-qQ+vb+6rca1sblf5Tg/hoS9dzCLNdU20CulZPraj4LaxLjVAIYuzeuCDQEsfLObbKkEh6XmCm0r/lLmfSdoc+A==",
|
||||
)
|
||||
use_repo(pnpm, "pnpm")
|
||||
|
||||
@@ -125,14 +125,12 @@ use_repo(rules_ts_ext, **{"npm_typescript": "angular_npm_typescript"})
|
||||
|
||||
# TODO: Figure out how to make ng_project update whenever the packages/core::pkg target changes.
|
||||
rules_angular = use_extension("@rules_angular//setup:extensions.bzl", "rules_angular")
|
||||
|
||||
use_repo_rule("@rules_angular//setup:repositories.bzl", "configurable_deps_repo")(
|
||||
name = "rules_angular_configurable_deps",
|
||||
angular_compiler_cli = "@angular//:node_modules/@angular/compiler-cli",
|
||||
typescript = "@angular//:node_modules/typescript",
|
||||
rules_angular.setup(
|
||||
name = "angular_rules_angular_configurable_deps",
|
||||
angular_compiler_cli = "//:node_modules/@angular/compiler-cli",
|
||||
typescript = "//:node_modules/typescript",
|
||||
)
|
||||
|
||||
override_repo(rules_angular, "rules_angular_configurable_deps")
|
||||
use_repo(rules_angular, rules_angular_configurable_deps = "angular_rules_angular_configurable_deps")
|
||||
|
||||
register_toolchains(
|
||||
"@devinfra//bazel/git-toolchain:git_linux_toolchain",
|
||||
|
||||
Generated
+35
-33
@@ -28,8 +28,8 @@
|
||||
"https://bcr.bazel.build/modules/aspect_rules_js/3.0.3/source.json": "bb8fff9a304452e1042af9522ad1d54d6f1d1fdf71c5127deadb6fd156654193",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_rollup/2.0.1/MODULE.bazel": "296e3a053658c2af989ba9bd62a205e6d1fa84bdd6dd5249196546e6b84770ec",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_rollup/2.0.1/source.json": "2fe8ac1ccb4de74bf884761e070010280b272d94e3997205b361b91c75409726",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_ts/3.8.7/MODULE.bazel": "830f8a53bb9f1139c24006a90ddc0230481326d69fa847eb00daf8eaae118724",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_ts/3.8.7/source.json": "95549d64e28f3e4e3648cc037cefdac01ec3b0f58fced2409c286784e82ad0f0",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_ts/3.8.8/MODULE.bazel": "b52b929a948438665809d49af610f58d1b14f63d6d21ab748f47b6050be4c1f6",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_ts/3.8.8/source.json": "5414530b761a45ab7ca6c49f0a2a9cf8dc0da772f5037cf05ca18aaa64bb1b19",
|
||||
"https://bcr.bazel.build/modules/aspect_tools_telemetry/0.2.6/MODULE.bazel": "cafb8781ad591bc57cc765dca5fefab08cf9f65af363d162b79d49205c7f8af7",
|
||||
"https://bcr.bazel.build/modules/aspect_tools_telemetry/0.2.8/MODULE.bazel": "aa975a83e72bcaac62ee61ab12b788ea324a1d05c4aab28aadb202f647881679",
|
||||
"https://bcr.bazel.build/modules/aspect_tools_telemetry/0.3.3/MODULE.bazel": "37c764292861c2f70314efa9846bb6dbb44fc0308903b3285da6528305450183",
|
||||
@@ -53,7 +53,8 @@
|
||||
"https://bcr.bazel.build/modules/bazel_lib/3.0.0-rc.0/MODULE.bazel": "d6e00979a98ac14ada5e31c8794708b41434d461e7e7ca39b59b765e6d233b18",
|
||||
"https://bcr.bazel.build/modules/bazel_lib/3.0.0/MODULE.bazel": "22b70b80ac89ad3f3772526cd9feee2fa412c2b01933fea7ed13238a448d370d",
|
||||
"https://bcr.bazel.build/modules/bazel_lib/3.2.2/MODULE.bazel": "e2c890c8a515d6bca9c66d47718aa9e44b458fde64ec7204b8030bf2d349058c",
|
||||
"https://bcr.bazel.build/modules/bazel_lib/3.2.2/source.json": "9e84e115c20e14652c5c21401ae85ff4daa8702e265b5c0b3bf89353f17aa212",
|
||||
"https://bcr.bazel.build/modules/bazel_lib/3.3.1/MODULE.bazel": "732a0d516cf6400d9b3136e4356258aef1bf91de8d5240f87f0112f098920c1d",
|
||||
"https://bcr.bazel.build/modules/bazel_lib/3.3.1/source.json": "8e5175d7b4125a39b8941d01e38039934d058e03804f46a2b8fd7ae6316b1ce2",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.2.0/MODULE.bazel": "44fe84260e454ed94ad326352a698422dbe372b21a1ac9f3eab76eb531223686",
|
||||
@@ -161,7 +162,8 @@
|
||||
"https://bcr.bazel.build/modules/rules_nodejs/6.2.0/MODULE.bazel": "ec27907f55eb34705adb4e8257952162a2d4c3ed0f0b3b4c3c1aad1fac7be35e",
|
||||
"https://bcr.bazel.build/modules/rules_nodejs/6.5.0/MODULE.bazel": "546d0cf79f36f9f6e080816045f97234b071c205f4542e3351bd4424282a8810",
|
||||
"https://bcr.bazel.build/modules/rules_nodejs/6.7.3/MODULE.bazel": "c22a48b2a0dbf05a9dc5f83837bbc24c226c1f6e618de3c3a610044c9f336056",
|
||||
"https://bcr.bazel.build/modules/rules_nodejs/6.7.3/source.json": "a3f966f4415a8a6545e560ee5449eac95cc633f96429d08e87c87775c72f5e09",
|
||||
"https://bcr.bazel.build/modules/rules_nodejs/6.7.4/MODULE.bazel": "e6a241a55c82e999145553d2e00a08fc6ebadf62b63d108fb5e984696ffd0bd2",
|
||||
"https://bcr.bazel.build/modules/rules_nodejs/6.7.4/source.json": "34e7a8a3b4c8d630ac0e0492b3fed9dba41fe008a0edf220b7d88fa38ac53698",
|
||||
"https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc",
|
||||
"https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff",
|
||||
"https://bcr.bazel.build/modules/rules_pkg/1.2.0/MODULE.bazel": "c7db3c2b407e673c7a39e3625dc05dc9f12d6682cbd82a3a5924a13b491eda7e",
|
||||
@@ -193,16 +195,16 @@
|
||||
"https://bcr.bazel.build/modules/stardoc/0.7.1/MODULE.bazel": "3548faea4ee5dda5580f9af150e79d0f6aea934fc60c1cc50f4efdd9420759e7",
|
||||
"https://bcr.bazel.build/modules/stardoc/0.7.2/MODULE.bazel": "fc152419aa2ea0f51c29583fab1e8c99ddefd5b3778421845606ee628629e0e5",
|
||||
"https://bcr.bazel.build/modules/stardoc/0.7.2/source.json": "58b029e5e901d6802967754adf0a9056747e8176f017cfe3607c0851f4d42216",
|
||||
"https://bcr.bazel.build/modules/tar.bzl/0.10.1/MODULE.bazel": "bf5fda5b5ccef8c3c4a5f4886144377386e0baa382972f257acb42dcf40ea908",
|
||||
"https://bcr.bazel.build/modules/tar.bzl/0.10.1/source.json": "3f1beb35acf53c270a9de493cdc775a985551d7069cfcf24e136b42f683bbb10",
|
||||
"https://bcr.bazel.build/modules/tar.bzl/0.2.1/MODULE.bazel": "52d1c00a80a8cc67acbd01649e83d8dd6a9dc426a6c0b754a04fe8c219c76468",
|
||||
"https://bcr.bazel.build/modules/tar.bzl/0.5.1/MODULE.bazel": "7c2eb3dcfc53b0f3d6f9acdfd911ca803eaf92aadf54f8ca6e4c1f3aee288351",
|
||||
"https://bcr.bazel.build/modules/tar.bzl/0.6.0/MODULE.bazel": "a3584b4edcfafcabd9b0ef9819808f05b372957bbdff41601429d5fd0aac2e7c",
|
||||
"https://bcr.bazel.build/modules/tar.bzl/0.9.0/MODULE.bazel": "452a22d7f02b1c9d7a22ab25edf20f46f3e1101f0f67dc4bfbf9a474ddf02445",
|
||||
"https://bcr.bazel.build/modules/tar.bzl/0.9.0/source.json": "c732760a374831a2cf5b08839e4be75017196b4d796a5aa55235272ee17cd839",
|
||||
"https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43",
|
||||
"https://bcr.bazel.build/modules/yq.bzl/0.1.1/MODULE.bazel": "9039681f9bcb8958ee2c87ffc74bdafba9f4369096a2b5634b88abc0eaefa072",
|
||||
"https://bcr.bazel.build/modules/yq.bzl/0.3.2/MODULE.bazel": "0384efa70e8033d842ea73aa4b7199fa099709e236a7264345c03937166670b6",
|
||||
"https://bcr.bazel.build/modules/yq.bzl/0.3.5/MODULE.bazel": "130c603e54be717bdf84100210f06598a0d2b4b4e01888fb01b70f50f41767ec",
|
||||
"https://bcr.bazel.build/modules/yq.bzl/0.3.5/source.json": "1ae7bdc03cb26aaa8bd2bceadf65e90d90f0b2d03008ba9a0564da2e21396c39",
|
||||
"https://bcr.bazel.build/modules/yq.bzl/0.3.6/MODULE.bazel": "985c2a0cb4ad9994bb0e33cc7fae931c91105eeefe3faa355b8f4c258d0607c0",
|
||||
"https://bcr.bazel.build/modules/yq.bzl/0.3.6/source.json": "678aaf6e291164f3cd761bb3e872e8a151248f413dbb63c5524a50b82a5bc890",
|
||||
"https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0",
|
||||
"https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27",
|
||||
"https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca",
|
||||
@@ -213,7 +215,7 @@
|
||||
"moduleExtensions": {
|
||||
"@@aspect_rules_esbuild+//esbuild:extensions.bzl%esbuild": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "GnYkDpVOnWnYv+xwyhEi0qjk3Lvp4Wei30PeSIQF5vM=",
|
||||
"bzlTransitiveDigest": "3l5lERuIkp41OnB+ZcMQkXS5ttpwE3LfWmePbmwDofk=",
|
||||
"usagesDigest": "6We6zwGoawD9YXqMI0KPaxEKJTnamXBsuOekhFS2D40=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
@@ -428,8 +430,8 @@
|
||||
},
|
||||
"@@aspect_rules_ts+//ts:extensions.bzl%ext": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "GbfZLeEI0W26fAQ89dUljyLGSAkzkr3CkF+VDQ0IFlI=",
|
||||
"usagesDigest": "CnGVBnDYq2qAfYkDXgJlDcJckUt2NU51jQQX+igoGt8=",
|
||||
"bzlTransitiveDigest": "dhTbv9E6UfT1WJmmu3ORRPO6AKFJvgBjBxu+BO+u1RY=",
|
||||
"usagesDigest": "wfAUu+hWfjbN8K5K5tnyIyhWKZOHe5xnDfeOD7CIZZ8=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
@@ -447,8 +449,8 @@
|
||||
"rules_angular_npm_typescript": {
|
||||
"repoRuleId": "@@aspect_rules_ts+//ts/private:npm_repositories.bzl%http_archive_version",
|
||||
"attributes": {
|
||||
"version": "5.9.3",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"version": "6.0.3",
|
||||
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
|
||||
"urls": [
|
||||
"https://registry.npmjs.org/typescript/-/typescript-{}.tgz"
|
||||
]
|
||||
@@ -457,8 +459,8 @@
|
||||
"npm_typescript": {
|
||||
"repoRuleId": "@@aspect_rules_ts+//ts/private:npm_repositories.bzl%http_archive_version",
|
||||
"attributes": {
|
||||
"version": "5.9.3",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"version": "6.0.3",
|
||||
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
|
||||
"urls": [
|
||||
"https://registry.npmjs.org/typescript/-/typescript-{}.tgz"
|
||||
]
|
||||
@@ -467,8 +469,8 @@
|
||||
"npm_rules_browsers_typescript": {
|
||||
"repoRuleId": "@@aspect_rules_ts+//ts/private:npm_repositories.bzl%http_archive_version",
|
||||
"attributes": {
|
||||
"version": "5.9.3",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"version": "6.0.3",
|
||||
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
|
||||
"urls": [
|
||||
"https://registry.npmjs.org/typescript/-/typescript-{}.tgz"
|
||||
]
|
||||
@@ -492,7 +494,7 @@
|
||||
"@@aspect_tools_telemetry+//:extension.bzl%telemetry": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "cl5A2O84vDL6Tt+Qga8FCj1DUDGqn+e7ly5rZ+4xvcc=",
|
||||
"usagesDigest": "mS7+2ykIUJH5qIIq/jathl5rcwdqyvYA8HOpHe8d+/Y=",
|
||||
"usagesDigest": "XReaXejedAKAFKyp+2mfnFkPWXBJzM/VxiOYB4nyseY=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
@@ -501,7 +503,7 @@
|
||||
"repoRuleId": "@@aspect_tools_telemetry+//:extension.bzl%tel_repository",
|
||||
"attributes": {
|
||||
"deps": {
|
||||
"aspect_rules_ts": "3.8.7",
|
||||
"aspect_rules_ts": "3.8.8",
|
||||
"aspect_rules_js": "3.0.3",
|
||||
"aspect_rules_esbuild": "0.25.1",
|
||||
"aspect_rules_jasmine": "2.0.4",
|
||||
@@ -560,24 +562,24 @@
|
||||
},
|
||||
"@@rules_angular+//setup:extensions.bzl%rules_angular": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "fkaH7HMicL3g7/NDaFzlq39kcLopMyQ3KdbDn+5CRzA=",
|
||||
"usagesDigest": "Li29KHtfoig0M7RQAoy9uoACa/RcVICtFkFkARsVOAA=",
|
||||
"bzlTransitiveDigest": "aS7Uud1IzoU7PPLzH3s6IfFS4b2fa0SRWDi2/fS4bQU=",
|
||||
"usagesDigest": "PaJB/TvnSzJTbqGUeIfiFAEjGkG4FEW7es6f6MFMtq8=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
"generatedRepoSpecs": {
|
||||
"angular_rules_angular_configurable_deps": {
|
||||
"repoRuleId": "@@rules_angular+//setup:repositories.bzl%configurable_deps_repo",
|
||||
"attributes": {
|
||||
"angular_compiler_cli": "@@//:node_modules/@angular/compiler-cli",
|
||||
"typescript": "@@//:node_modules/typescript"
|
||||
}
|
||||
},
|
||||
"rules_angular_configurable_deps": {
|
||||
"repoRuleId": "@@rules_angular+//setup:repositories.bzl%configurable_deps_repo",
|
||||
"attributes": {
|
||||
"angular_compiler_cli": "@@rules_angular+//:node_modules/@angular/compiler-cli",
|
||||
"typescript": "@@rules_angular+//:node_modules/typescript"
|
||||
}
|
||||
},
|
||||
"dev_infra_rules_angular_configurable_deps": {
|
||||
"repoRuleId": "@@rules_angular+//setup:repositories.bzl%configurable_deps_repo",
|
||||
"attributes": {
|
||||
"angular_compiler_cli": "@@rules_angular+//:node_modules/@angular/compiler-cli",
|
||||
"typescript": "@@rules_angular+//:node_modules/typescript"
|
||||
"angular_compiler_cli": "@@//:node_modules/@angular/compiler-cli",
|
||||
"typescript": "@@//:node_modules/typescript"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -945,8 +947,8 @@
|
||||
},
|
||||
"@@rules_nodejs+//nodejs:extensions.bzl%node": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "4pUxCNc22K4I+6+4Nxu52Hur12tFRfa1JMsN5mdDv60=",
|
||||
"usagesDigest": "o//mYtRPOfTZZh8pDGhbI7WGo7UOnSiSLgWYaJCEB+0=",
|
||||
"bzlTransitiveDigest": "oZFClfRhTTwsYzpxVPkOpOt/r0+OzEfEV37au0jFZ0s=",
|
||||
"usagesDigest": "dp2HPl9Y2BFhrnM0JALIsJHz02rKnRBpISBHQX4qV7E=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
@@ -4162,7 +4164,7 @@
|
||||
"@@yq.bzl+//yq:extensions.bzl%yq": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "UfFMy8CWK4/dVo/tfaSAIYUiDGNAPes5eRllx9O9Q9Q=",
|
||||
"usagesDigest": "263D9xYtKhXWWCVTxT66bpT89HuZpdkB1AqEir45vbY=",
|
||||
"usagesDigest": "5cUmZOEOibp2h65JoFppstHiXcjDFil/AG+HgD3avRk=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
|
||||
@@ -67,7 +67,7 @@ Install the Angular CLI globally:
|
||||
npm install -g @angular/cli
|
||||
```
|
||||
|
||||
Create workspace:
|
||||
Create a workspace:
|
||||
|
||||
```
|
||||
ng new [PROJECT NAME]
|
||||
|
||||
+6
-6
@@ -5,21 +5,21 @@
|
||||
"@algolia/requester-browser-xhr": "5.48.0",
|
||||
"@algolia/requester-node-http": "5.48.0",
|
||||
"@angular/animations": "workspace:*",
|
||||
"@angular/aria": "21.2.4",
|
||||
"@angular/build": "21.2.6",
|
||||
"@angular/cdk": "21.2.4",
|
||||
"@angular/cli": "21.2.6",
|
||||
"@angular/aria": "21.2.9",
|
||||
"@angular/build": "21.2.9",
|
||||
"@angular/cdk": "21.2.9",
|
||||
"@angular/cli": "21.2.9",
|
||||
"@angular/common": "workspace:*",
|
||||
"@angular/compiler": "workspace:*",
|
||||
"@angular/compiler-cli": "workspace:*",
|
||||
"@angular/core": "workspace:*",
|
||||
"@angular/docs": "workspace:*",
|
||||
"@angular/forms": "workspace:*",
|
||||
"@angular/material": "21.2.4",
|
||||
"@angular/material": "21.2.9",
|
||||
"@angular/platform-browser": "workspace:*",
|
||||
"@angular/platform-server": "workspace:*",
|
||||
"@angular/router": "workspace:*",
|
||||
"@angular/ssr": "21.2.6",
|
||||
"@angular/ssr": "21.2.9",
|
||||
"@codemirror/autocomplete": "6.20.0",
|
||||
"@codemirror/commands": "6.10.1",
|
||||
"@codemirror/lang-angular": "0.1.4",
|
||||
|
||||
@@ -10,6 +10,8 @@ import {get} from 'node:https';
|
||||
import {posix} from 'node:path';
|
||||
|
||||
const GITHUB_API = 'https://api.github.com/repos/';
|
||||
const SHA_REGEX = /^[0-9a-f]{40}$/i;
|
||||
const BRANCH_REGEX = /^(?!.*\.\.)[a-zA-Z0-9/_.-]+$/;
|
||||
|
||||
export class GithubClient {
|
||||
#token;
|
||||
@@ -30,6 +32,12 @@ export class GithubClient {
|
||||
* @returns Promise<string[]>
|
||||
*/
|
||||
async getAffectedFiles(baseSha, headSha) {
|
||||
if (!SHA_REGEX.test(baseSha)) {
|
||||
throw new Error(`Invalid base SHA: ${baseSha}`);
|
||||
}
|
||||
if (!SHA_REGEX.test(headSha)) {
|
||||
throw new Error(`Invalid head SHA: ${headSha}`);
|
||||
}
|
||||
const {files} = JSON.parse(await this.#httpGet(`${this.#api}/compare/${baseSha}...${headSha}`));
|
||||
return files.map((f) => f.filename);
|
||||
}
|
||||
@@ -41,6 +49,9 @@ export class GithubClient {
|
||||
* @returns Promise<string>
|
||||
*/
|
||||
async getShaForBranch(branch) {
|
||||
if (!BRANCH_REGEX.test(branch)) {
|
||||
throw new Error(`Invalid branch name: ${branch}`);
|
||||
}
|
||||
const sha = await this.#httpGet(`${this.#api}/commits/${branch}`, {
|
||||
headers: {Accept: 'application/vnd.github.VERSION.sha'},
|
||||
});
|
||||
@@ -49,7 +60,7 @@ export class GithubClient {
|
||||
throw new Error(`Unable to extract the SHA for '${branch}'.`);
|
||||
}
|
||||
|
||||
return sha;
|
||||
return sha.trim();
|
||||
}
|
||||
|
||||
#httpGet(url, options = {}) {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
//tslint:disable:no-console
|
||||
import assert from 'node:assert';
|
||||
import {execSync} from 'node:child_process';
|
||||
import {execFileSync} from 'node:child_process';
|
||||
import {existsSync, constants as fsConstants} from 'node:fs';
|
||||
import {
|
||||
copyFile,
|
||||
@@ -41,6 +41,16 @@ export async function updateAssets({repo, assetsPath, destPath}) {
|
||||
await readFile(buildInfoPath, 'utf-8'),
|
||||
);
|
||||
|
||||
const shaRegex = /^[0-9a-f]{40}$/i;
|
||||
const branchRegex = /^(?!.*\.\.)[a-zA-Z0-9/_.-]+$/;
|
||||
|
||||
if (!shaRegex.test(storedSha)) {
|
||||
throw new Error(`Invalid SHA in build info: ${storedSha}`);
|
||||
}
|
||||
if (!branchRegex.test(storedBranch)) {
|
||||
throw new Error(`Invalid branch name in build info: ${storedBranch}`);
|
||||
}
|
||||
|
||||
assert(process.env.ANGULAR_READONLY_GITHUB_TOKEN);
|
||||
const githubApi = new GithubClient(
|
||||
repo,
|
||||
@@ -63,6 +73,10 @@ export async function updateAssets({repo, assetsPath, destPath}) {
|
||||
downstreamBranch = storedBranch;
|
||||
}
|
||||
|
||||
if (!shaRegex.test(latestSha)) {
|
||||
throw new Error(`Invalid SHA resolved: ${latestSha}`);
|
||||
}
|
||||
|
||||
console.log(`Comparing ${storedSha}...${latestSha}.`);
|
||||
const affectedFiles = await githubApi.getAffectedFiles(storedSha, latestSha);
|
||||
const changedFiles = affectedFiles.filter((file) => file.startsWith(`${assetsPath}/`));
|
||||
@@ -78,14 +92,18 @@ export async function updateAssets({repo, assetsPath, destPath}) {
|
||||
|
||||
try {
|
||||
const execOptions = {cwd: temporaryDir, stdio: 'inherit'};
|
||||
execSync('git init', execOptions);
|
||||
execSync(`git remote add origin https://github.com/${repo}.git`, execOptions);
|
||||
execFileSync('git', ['init'], execOptions);
|
||||
execFileSync(
|
||||
'git',
|
||||
['remote', 'add', 'origin', `https://github.com/${repo}.git`],
|
||||
execOptions,
|
||||
);
|
||||
// fetch a commit
|
||||
execSync(`git fetch origin ${latestSha}`, execOptions);
|
||||
execFileSync('git', ['fetch', 'origin', latestSha], execOptions);
|
||||
// reset this repository's main branch to the commit of interest
|
||||
execSync('git reset --hard FETCH_HEAD', execOptions);
|
||||
execFileSync('git', ['reset', '--hard', 'FETCH_HEAD'], execOptions);
|
||||
// get sha when files where changed
|
||||
shaWhenFilesChanged = execSync(`git rev-list -1 ${latestSha} "${assetsPath}/"`, {
|
||||
shaWhenFilesChanged = execFileSync('git', ['rev-list', '-1', latestSha, `${assetsPath}/`], {
|
||||
encoding: 'utf8',
|
||||
cwd: temporaryDir,
|
||||
stdio: ['ignore', 'pipe', 'ignore'],
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
[href]="item.path"
|
||||
target="_blank"
|
||||
[matTooltip]="item.label"
|
||||
[matTooltipDisabled]="itemLabel.length < 27"
|
||||
[matTooltipDisabled]="itemLabel.length < labelTruncationThreshold"
|
||||
matTooltipPosition="after"
|
||||
[attr.aria-label]="item.label"
|
||||
[matTooltipClass]="'API-tooltip'"
|
||||
@@ -53,9 +53,9 @@
|
||||
matrixParams: 'ignored',
|
||||
fragment: 'ignored',
|
||||
}"
|
||||
(click)="emitClickOnLink()"
|
||||
(click)="emitClickOnLink(item)"
|
||||
[matTooltip]="item.label"
|
||||
[matTooltipDisabled]="itemLabel.length < 27"
|
||||
[matTooltipDisabled]="itemLabel.length < labelTruncationThreshold"
|
||||
matTooltipPosition="after"
|
||||
[attr.aria-label]="item.label"
|
||||
[matTooltipClass]="'API-tooltip'"
|
||||
@@ -76,7 +76,7 @@
|
||||
<div
|
||||
class="docs-secondary-nav-header"
|
||||
[matTooltip]="item.label"
|
||||
[matTooltipDisabled]="itemLabel.length < 27"
|
||||
[matTooltipDisabled]="itemLabel.length < labelTruncationThreshold"
|
||||
matTooltipPosition="after"
|
||||
[attr.aria-label]="item.label"
|
||||
[matTooltipClass]="'API-tooltip'"
|
||||
@@ -106,7 +106,7 @@
|
||||
item.children && item.level === expandableLevel() && !item.isExpanded
|
||||
"
|
||||
[matTooltip]="item.label"
|
||||
[matTooltipDisabled]="itemLabel.length < 27"
|
||||
[matTooltipDisabled]="itemLabel.length < labelTruncationThreshold"
|
||||
matTooltipPosition="after"
|
||||
[attr.aria-label]="item.label"
|
||||
[matTooltipClass]="'API-tooltip'"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
list-style: none;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
height: 100vh;
|
||||
height: 100dvh;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
padding-block: 1.5rem;
|
||||
|
||||
@@ -153,5 +153,6 @@ describe('NavigationList', () => {
|
||||
class FakeNavigationListState {
|
||||
isOpened = signal(true);
|
||||
activeNavigationItem = signal(navigationItems.at(1));
|
||||
crossCategoryOrigin = signal<NavigationItem | undefined>(undefined);
|
||||
toggleItem(item: NavigationItem) {}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,10 @@ export class NavigationList {
|
||||
|
||||
readonly linkClicked = output<void>();
|
||||
|
||||
protected readonly labelTruncationThreshold = 27;
|
||||
|
||||
private readonly navigationState = inject(NavigationState);
|
||||
private readonly crossCategoryOrigin = this.navigationState.crossCategoryOrigin;
|
||||
|
||||
readonly activeItem = this.navigationState.activeNavigationItem;
|
||||
|
||||
@@ -51,10 +54,19 @@ export class NavigationList {
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const prevParentItem = this.crossCategoryOrigin();
|
||||
if (prevParentItem) {
|
||||
this.crossCategoryOrigin.set(undefined);
|
||||
this.navigationState.toggleItem(prevParentItem);
|
||||
return;
|
||||
}
|
||||
this.navigationState.toggleItem(item);
|
||||
}
|
||||
|
||||
emitClickOnLink(): void {
|
||||
emitClickOnLink(item: NavigationItem): void {
|
||||
if (item.isCrossReferenced) {
|
||||
this.crossCategoryOrigin.set(item.parent);
|
||||
}
|
||||
this.linkClicked.emit();
|
||||
}
|
||||
|
||||
|
||||
@@ -27,14 +27,16 @@
|
||||
</i>
|
||||
</span>
|
||||
|
||||
<!-- Page title -->
|
||||
<span [innerHtml]="result.labelHtml"></span>
|
||||
@if (result.package) {
|
||||
<span
|
||||
[innerHTML]="result.package"
|
||||
class="docs-search-result__label__package"
|
||||
></span>
|
||||
}
|
||||
<!-- Page title and package badge -->
|
||||
<span class="docs-search-result__label__text">
|
||||
<span [innerHtml]="result.labelHtml"></span>
|
||||
@if (result.package) {
|
||||
<span
|
||||
[innerHTML]="result.package"
|
||||
class="docs-search-result__label__package"
|
||||
></span>
|
||||
}
|
||||
</span>
|
||||
</p>
|
||||
|
||||
@if (result.subLabelHtml) {
|
||||
|
||||
@@ -46,6 +46,7 @@ dialog {
|
||||
|
||||
.docs-search-result-icon {
|
||||
display: inline-block;
|
||||
flex-shrink: 0;
|
||||
|
||||
i {
|
||||
display: flex;
|
||||
@@ -91,7 +92,20 @@ dialog {
|
||||
|
||||
&__label {
|
||||
font-weight: 600;
|
||||
flex-wrap: wrap;
|
||||
|
||||
&__text {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: baseline;
|
||||
gap: 0.25rem 0.5rem;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow-wrap: break-word;
|
||||
|
||||
> * {
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__package {
|
||||
font-size: 0.75rem;
|
||||
|
||||
@@ -17,5 +17,6 @@ export interface NavigationItem {
|
||||
contentPath?: string;
|
||||
status?: 'new' | 'updated';
|
||||
category?: string;
|
||||
isCrossReferenced?: boolean;
|
||||
preserveOtherCategoryOrder?: boolean; // true by default
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
ParameterEntry,
|
||||
PipeEntry,
|
||||
TypeAliasEntry,
|
||||
EntryType,
|
||||
} from '../entities.mjs';
|
||||
|
||||
import {CliCommand, CliOption} from '../cli-entities.mjs';
|
||||
@@ -105,6 +104,7 @@ export type FunctionEntryRenderable = FunctionEntry &
|
||||
export type FunctionSignatureMetadataRenderable = FunctionSignatureMetadata &
|
||||
DocEntryRenderable & {
|
||||
params: ParameterEntryRenderable[];
|
||||
htmlReturnDescription?: string;
|
||||
};
|
||||
|
||||
/** Documentation entity for a block augmented with transformed content for rendering. */
|
||||
|
||||
@@ -59,10 +59,16 @@ export function ClassMember(props: {member: MemberEntryRenderable}) {
|
||||
const memberName = member.name;
|
||||
const displayName = member.displayName;
|
||||
const returnType = getMemberType(member);
|
||||
const label = displayName ?? memberName;
|
||||
|
||||
return (
|
||||
<div id={memberName} className={REFERENCE_MEMBER_CARD}>
|
||||
<header className={REFERENCE_MEMBER_CARD_HEADER}>
|
||||
<h3>{displayName ?? memberName}</h3>
|
||||
<h3>
|
||||
<a class="docs-anchor" href={'#' + memberName}>
|
||||
{label}
|
||||
</a>
|
||||
</h3>
|
||||
{isClassMethodEntry(member) && member.signatures.length > 1 ? (
|
||||
<span>{member.signatures.length} overloads</span>
|
||||
) : returnType ? (
|
||||
|
||||
@@ -23,6 +23,7 @@ import {RawHtml} from './raw-html';
|
||||
export function ClassMethodInfo(props: {
|
||||
entry: FunctionSignatureMetadataRenderable;
|
||||
hideUsageNotes?: boolean;
|
||||
hideDescription?: boolean;
|
||||
}) {
|
||||
const entry = props.entry;
|
||||
|
||||
@@ -30,7 +31,9 @@ export function ClassMethodInfo(props: {
|
||||
<div
|
||||
className={`${REFERENCE_MEMBER_CARD_ITEM} ${entry.deprecated ? 'docs-reference-card-item-deprecated' : ''}`}
|
||||
>
|
||||
<RawHtml value={entry.htmlDescription} className={'docs-function-definition'} />
|
||||
{!props.hideDescription && (
|
||||
<RawHtml value={entry.htmlDescription} className={'docs-function-definition'} />
|
||||
)}
|
||||
{/* In case when method is overloaded we need to indicate which overload is deprecated */}
|
||||
{entry.deprecated ? (
|
||||
<div>
|
||||
@@ -45,6 +48,9 @@ export function ClassMethodInfo(props: {
|
||||
<div className={'docs-return-type'}>
|
||||
<span className={PARAM_KEYWORD_CLASS_NAME}>@returns</span>
|
||||
<CodeSymbol code={entry.returnType} />
|
||||
{entry.htmlReturnDescription && (
|
||||
<RawHtml value={entry.htmlReturnDescription} className="docs-parameter-description" />
|
||||
)}
|
||||
</div>
|
||||
{entry.htmlUsageNotes && !props.hideUsageNotes ? (
|
||||
<div className={'docs-usage-notes'}>
|
||||
|
||||
@@ -32,31 +32,43 @@ import {SectionUsageNotes} from './section-usage-notes';
|
||||
export const signatureCard = (
|
||||
name: string,
|
||||
signature: FunctionSignatureMetadataRenderable,
|
||||
opts: {id: string; printSignaturesAsHeader: boolean; hideUsageNotes?: boolean},
|
||||
opts: {
|
||||
id: string;
|
||||
printSignaturesAsHeader: boolean;
|
||||
hideUsageNotes?: boolean;
|
||||
hideHeader?: boolean;
|
||||
hideDescription?: boolean;
|
||||
},
|
||||
) => {
|
||||
return (
|
||||
<div id={opts.id} class={REFERENCE_MEMBER_CARD}>
|
||||
<header class={REFERENCE_MEMBER_CARD_HEADER}>
|
||||
{opts.printSignaturesAsHeader ? (
|
||||
<HighlightTypeScript
|
||||
code={printInitializerFunctionSignatureLine(
|
||||
name,
|
||||
signature,
|
||||
// Always omit types in signature headers, to keep them short.
|
||||
true,
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<h3>{name}</h3>
|
||||
<div>
|
||||
<CodeSymbol code={signature.returnType} />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</header>
|
||||
{!opts.hideHeader && (
|
||||
<header class={REFERENCE_MEMBER_CARD_HEADER}>
|
||||
{opts.printSignaturesAsHeader ? (
|
||||
<HighlightTypeScript
|
||||
code={printInitializerFunctionSignatureLine(
|
||||
name,
|
||||
signature,
|
||||
// Always omit types in signature headers, to keep them short.
|
||||
true,
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<h3>{name}</h3>
|
||||
<div>
|
||||
<CodeSymbol code={signature.returnType} />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</header>
|
||||
)}
|
||||
<div class={REFERENCE_MEMBER_CARD_BODY}>
|
||||
<ClassMethodInfo entry={signature} hideUsageNotes={opts.hideUsageNotes} />
|
||||
<ClassMethodInfo
|
||||
entry={signature}
|
||||
hideUsageNotes={opts.hideUsageNotes}
|
||||
hideDescription={opts.hideDescription}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -64,8 +76,8 @@ export const signatureCard = (
|
||||
|
||||
/** Component to render a function API reference document. */
|
||||
export function FunctionReference(entry: FunctionEntryRenderable) {
|
||||
// Use signatures as header if there are multiple signatures.
|
||||
const printSignaturesAsHeader = entry.signatures.length > 1;
|
||||
const hideSignatureCardDescription = !printSignaturesAsHeader;
|
||||
|
||||
return (
|
||||
<div className={API_REFERENCE_CONTAINER}>
|
||||
@@ -73,14 +85,15 @@ export function FunctionReference(entry: FunctionEntryRenderable) {
|
||||
<DeprecationWarning entry={entry} />
|
||||
<SectionApi entry={entry} />
|
||||
<div className={REFERENCE_MEMBERS}>
|
||||
{entry.signatures.length > 1 &&
|
||||
entry.signatures.map((s, i) =>
|
||||
signatureCard(s.name, getFunctionMetadataRenderable(s, entry.moduleName, entry.repo), {
|
||||
id: `${s.name}_${i}`,
|
||||
printSignaturesAsHeader,
|
||||
hideUsageNotes: true,
|
||||
}),
|
||||
)}
|
||||
{entry.signatures.map((s, i) =>
|
||||
signatureCard(s.name, getFunctionMetadataRenderable(s, entry.moduleName, entry.repo), {
|
||||
id: `${s.name}_${i}`,
|
||||
printSignaturesAsHeader,
|
||||
hideHeader: !printSignaturesAsHeader,
|
||||
hideUsageNotes: hideSignatureCardDescription,
|
||||
hideDescription: hideSignatureCardDescription,
|
||||
}),
|
||||
)}
|
||||
</div>
|
||||
|
||||
<SectionDescription entry={entry} />
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
|
||||
import {h} from 'preact';
|
||||
import {ParameterEntryRenderable} from '../entities/renderables.mjs';
|
||||
import {RawHtml} from './raw-html';
|
||||
import {PARAM_GROUP_CLASS_NAME} from '../styling/css-classes.mjs';
|
||||
import {CodeSymbol} from './code-symbols';
|
||||
import {RawHtml} from './raw-html';
|
||||
|
||||
/** Component to render a function or method parameter reference doc fragment. */
|
||||
export function Parameter(props: {param: ParameterEntryRenderable}) {
|
||||
@@ -21,7 +21,9 @@ export function Parameter(props: {param: ParameterEntryRenderable}) {
|
||||
{/*TODO: isOptional, isRestParam*/}
|
||||
<span class="docs-param-keyword">@param</span>
|
||||
<span class="docs-param-name">{param.name}</span>
|
||||
<CodeSymbol code={param.type} />
|
||||
<span class="docs-param-type">
|
||||
<CodeSymbol code={param.type} />
|
||||
</span>
|
||||
<RawHtml value={param.htmlDescription} className="docs-parameter-description" />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -43,4 +43,17 @@ describe('CLI docs to html', () => {
|
||||
expect(cliTocs[0].textContent).toContain('ng component [name] [options]');
|
||||
expect(cliTocs[1].textContent).toContain('ng c [name] [options]');
|
||||
});
|
||||
|
||||
it('should rewrite absolute angular.dev hrefs in option descriptions to root-relative', async () => {
|
||||
const renderableJson = await getRenderable(entryJson, '', 'angular/cli');
|
||||
const localFragment = JSDOM.fragment(renderEntry(renderableJson));
|
||||
const hrefs = Array.from(localFragment.querySelectorAll('a')).map((a) =>
|
||||
a.getAttribute('href'),
|
||||
);
|
||||
// Absolute angular.dev URLs are rewritten to root-relative.
|
||||
expect(hrefs).toContain('/cli-test-rewrite');
|
||||
expect(hrefs).not.toContain('https://angular.dev/cli-test-rewrite');
|
||||
// Subdomains are intentionally left as external.
|
||||
expect(hrefs).toContain('https://next.angular.dev/cli-test-preview');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
"name": "generate",
|
||||
"command": "ng generate <schematic>",
|
||||
"shortDescription": "Generates and/or modifies files based on a schematic.",
|
||||
"aliases": [
|
||||
"g"
|
||||
],
|
||||
"aliases": ["g"],
|
||||
"deprecated": false,
|
||||
"options": [
|
||||
{
|
||||
@@ -16,9 +14,7 @@
|
||||
{
|
||||
"name": "dry-run",
|
||||
"type": "boolean",
|
||||
"aliases": [
|
||||
"d"
|
||||
],
|
||||
"aliases": ["d"],
|
||||
"default": false,
|
||||
"description": "Run through and reports activity without writing out results."
|
||||
},
|
||||
@@ -44,6 +40,12 @@
|
||||
"type": "string",
|
||||
"description": "The [collection:schematic] to run.",
|
||||
"positional": 0
|
||||
},
|
||||
{
|
||||
"name": "test-angular-dev-href-rewrite",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "See [angular.dev test](https://angular.dev/cli-test-rewrite) and [preview test](https://next.angular.dev/cli-test-preview)."
|
||||
}
|
||||
],
|
||||
"subcommands": [
|
||||
@@ -75,17 +77,13 @@
|
||||
{
|
||||
"name": "inline-style",
|
||||
"type": "boolean",
|
||||
"aliases": [
|
||||
"s"
|
||||
],
|
||||
"aliases": ["s"],
|
||||
"description": "Include styles inline in the root component.ts file. Only CSS styles can be included inline. Default is false, meaning that an external styles file is created and referenced in the root component.ts file."
|
||||
},
|
||||
{
|
||||
"name": "inline-template",
|
||||
"type": "boolean",
|
||||
"aliases": [
|
||||
"t"
|
||||
],
|
||||
"aliases": ["t"],
|
||||
"description": "Include template inline in the root component.ts file. Default is false, meaning that an external template file is created and referenced in the root component.ts file. "
|
||||
},
|
||||
{
|
||||
@@ -103,9 +101,7 @@
|
||||
{
|
||||
"name": "prefix",
|
||||
"type": "string",
|
||||
"aliases": [
|
||||
"p"
|
||||
],
|
||||
"aliases": ["p"],
|
||||
"default": "app",
|
||||
"description": "A prefix to apply to generated selectors."
|
||||
},
|
||||
@@ -135,9 +131,7 @@
|
||||
{
|
||||
"name": "skip-tests",
|
||||
"type": "boolean",
|
||||
"aliases": [
|
||||
"S"
|
||||
],
|
||||
"aliases": ["S"],
|
||||
"default": false,
|
||||
"description": "Do not create \"spec.ts\" test files for the application."
|
||||
},
|
||||
@@ -163,29 +157,17 @@
|
||||
"name": "style",
|
||||
"type": "string",
|
||||
"default": "css",
|
||||
"enum": [
|
||||
"css",
|
||||
"scss",
|
||||
"sass",
|
||||
"less"
|
||||
],
|
||||
"enum": ["css", "scss", "sass", "less"],
|
||||
"description": "The file extension or preprocessor to use for style files."
|
||||
},
|
||||
{
|
||||
"name": "view-encapsulation",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Emulated",
|
||||
"None",
|
||||
"ShadowDom",
|
||||
"ExperimentalIsolatedShadowDom"
|
||||
],
|
||||
"enum": ["Emulated", "None", "ShadowDom", "ExperimentalIsolatedShadowDom"],
|
||||
"description": "The view encapsulation strategy to use in the new application."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"app"
|
||||
],
|
||||
"aliases": ["app"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -216,9 +198,7 @@
|
||||
"description": "Adds a developer-defined type to the filename, in the format \"name.type.ts\"."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"cl"
|
||||
],
|
||||
"aliases": ["cl"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -229,22 +209,15 @@
|
||||
{
|
||||
"name": "change-detection",
|
||||
"type": "string",
|
||||
"aliases": [
|
||||
"c"
|
||||
],
|
||||
"aliases": ["c"],
|
||||
"default": "Default",
|
||||
"enum": [
|
||||
"Default",
|
||||
"OnPush"
|
||||
],
|
||||
"enum": ["Default", "OnPush"],
|
||||
"description": "The change detection strategy to use in the new component."
|
||||
},
|
||||
{
|
||||
"name": "display-block",
|
||||
"type": "boolean",
|
||||
"aliases": [
|
||||
"b"
|
||||
],
|
||||
"aliases": ["b"],
|
||||
"default": false,
|
||||
"description": "Specifies if the style will contain `:host { display: block; }`."
|
||||
},
|
||||
@@ -269,27 +242,21 @@
|
||||
{
|
||||
"name": "inline-style",
|
||||
"type": "boolean",
|
||||
"aliases": [
|
||||
"s"
|
||||
],
|
||||
"aliases": ["s"],
|
||||
"default": false,
|
||||
"description": "Include styles inline in the component.ts file. Only CSS styles can be included inline. By default, an external styles file is created and referenced in the component.ts file."
|
||||
},
|
||||
{
|
||||
"name": "inline-template",
|
||||
"type": "boolean",
|
||||
"aliases": [
|
||||
"t"
|
||||
],
|
||||
"aliases": ["t"],
|
||||
"default": false,
|
||||
"description": "Include template inline in the component.ts file. By default, an external template file is created and referenced in the component.ts file."
|
||||
},
|
||||
{
|
||||
"name": "module",
|
||||
"type": "string",
|
||||
"aliases": [
|
||||
"m"
|
||||
],
|
||||
"aliases": ["m"],
|
||||
"description": "The declaring NgModule."
|
||||
},
|
||||
{
|
||||
@@ -301,9 +268,7 @@
|
||||
{
|
||||
"name": "prefix",
|
||||
"type": "string",
|
||||
"aliases": [
|
||||
"p"
|
||||
],
|
||||
"aliases": ["p"],
|
||||
"description": "The prefix to apply to the generated component selector."
|
||||
},
|
||||
{
|
||||
@@ -344,13 +309,7 @@
|
||||
"name": "style",
|
||||
"type": "string",
|
||||
"default": "css",
|
||||
"enum": [
|
||||
"css",
|
||||
"scss",
|
||||
"sass",
|
||||
"less",
|
||||
"none"
|
||||
],
|
||||
"enum": ["css", "scss", "sass", "less", "none"],
|
||||
"description": "The file extension or preprocessor to use for style files, or 'none' to skip generating the style file."
|
||||
},
|
||||
{
|
||||
@@ -362,21 +321,12 @@
|
||||
{
|
||||
"name": "view-encapsulation",
|
||||
"type": "string",
|
||||
"aliases": [
|
||||
"v"
|
||||
],
|
||||
"enum": [
|
||||
"Emulated",
|
||||
"None",
|
||||
"ShadowDom",
|
||||
"ExperimentalIsolatedShadowDom"
|
||||
],
|
||||
"aliases": ["v"],
|
||||
"enum": ["Emulated", "None", "ShadowDom", "ExperimentalIsolatedShadowDom"],
|
||||
"description": "The view encapsulation strategy to use in the new component."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"c"
|
||||
],
|
||||
"aliases": ["c"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -392,10 +342,7 @@
|
||||
{
|
||||
"name": "type",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"karma",
|
||||
"browserslist"
|
||||
],
|
||||
"enum": ["karma", "browserslist"],
|
||||
"description": "Specifies which type of configuration file to create.",
|
||||
"positional": 0
|
||||
}
|
||||
@@ -423,9 +370,7 @@
|
||||
{
|
||||
"name": "module",
|
||||
"type": "string",
|
||||
"aliases": [
|
||||
"m"
|
||||
],
|
||||
"aliases": ["m"],
|
||||
"description": "The declaring NgModule."
|
||||
},
|
||||
{
|
||||
@@ -437,9 +382,7 @@
|
||||
{
|
||||
"name": "prefix",
|
||||
"type": "string",
|
||||
"aliases": [
|
||||
"p"
|
||||
],
|
||||
"aliases": ["p"],
|
||||
"description": "A prefix to apply to generated selectors."
|
||||
},
|
||||
{
|
||||
@@ -471,9 +414,7 @@
|
||||
"description": "Whether the generated directive is standalone."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"d"
|
||||
],
|
||||
"aliases": ["d"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -498,9 +439,7 @@
|
||||
"description": "Adds a developer-defined type to the filename, in the format \"name.type.ts\"."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"e"
|
||||
],
|
||||
"aliases": ["e"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -537,9 +476,7 @@
|
||||
{
|
||||
"name": "implements",
|
||||
"type": "array",
|
||||
"aliases": [
|
||||
"guardType"
|
||||
],
|
||||
"aliases": ["guardType"],
|
||||
"description": "Specifies which type of guard to create."
|
||||
},
|
||||
{
|
||||
@@ -560,9 +497,7 @@
|
||||
"description": "Do not create \"spec.ts\" test files for the new guard."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"g"
|
||||
],
|
||||
"aliases": ["g"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -631,9 +566,7 @@
|
||||
"positional": 1
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"i"
|
||||
],
|
||||
"aliases": ["i"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -656,9 +589,7 @@
|
||||
{
|
||||
"name": "prefix",
|
||||
"type": "string",
|
||||
"aliases": [
|
||||
"p"
|
||||
],
|
||||
"aliases": ["p"],
|
||||
"default": "lib",
|
||||
"description": "A prefix to apply to generated selectors."
|
||||
},
|
||||
@@ -692,9 +623,7 @@
|
||||
"description": "Creates a library based upon the standalone API, without NgModules."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"lib"
|
||||
],
|
||||
"aliases": ["lib"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -711,9 +640,7 @@
|
||||
{
|
||||
"name": "module",
|
||||
"type": "string",
|
||||
"aliases": [
|
||||
"m"
|
||||
],
|
||||
"aliases": ["m"],
|
||||
"description": "The declaring NgModule."
|
||||
},
|
||||
{
|
||||
@@ -742,16 +669,11 @@
|
||||
"name": "routing-scope",
|
||||
"type": "string",
|
||||
"default": "Child",
|
||||
"enum": [
|
||||
"Child",
|
||||
"Root"
|
||||
],
|
||||
"enum": ["Child", "Root"],
|
||||
"description": "The scope for the new routing module."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"m"
|
||||
],
|
||||
"aliases": ["m"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -774,9 +696,7 @@
|
||||
{
|
||||
"name": "module",
|
||||
"type": "string",
|
||||
"aliases": [
|
||||
"m"
|
||||
],
|
||||
"aliases": ["m"],
|
||||
"description": "The declaring NgModule."
|
||||
},
|
||||
{
|
||||
@@ -809,9 +729,7 @@
|
||||
"description": "Whether the generated pipe is standalone."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"p"
|
||||
],
|
||||
"aliases": ["p"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -849,9 +767,7 @@
|
||||
"description": "Do not create \"spec.ts\" test files for the new resolver."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"r"
|
||||
],
|
||||
"aliases": ["r"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
@@ -883,9 +799,7 @@
|
||||
"description": "Do not create \"spec.ts\" test files for the new service."
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"s"
|
||||
],
|
||||
"aliases": ["s"],
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
|
||||
@@ -463,6 +463,7 @@
|
||||
"isRestParam": false
|
||||
}
|
||||
],
|
||||
"returnDescription": "A reference that can be used to unregister callbacks registered by this call.",
|
||||
"rawComment": "/**\n * Register callbacks to be invoked the next time the application finishes rendering, during the\n * specified phases. The available phases are:\n * - `earlyRead`\n * Use this phase to **read** from the DOM before a subsequent `write` callback, for example to\n * perform custom layout that the browser doesn't natively support. Prefer the `read` phase if\n * reading can wait until after the write phase. **Never** write to the DOM in this phase.\n * - `write`\n * Use this phase to **write** to the DOM. **Never** read from the DOM in this phase.\n * - `mixedReadWrite`\n * Use this phase to read from and write to the DOM simultaneously. **Never** use this phase if\n * it is possible to divide the work among the other phases instead.\n * - `read`\n * Use this phase to **read** from the DOM. **Never** write to the DOM in this phase.\n *\n * <div class=\"docs-alert docs-alert-critical\">\n *\n * You should prefer using the `read` and `write` phases over the `earlyRead` and `mixedReadWrite`\n * phases when possible, to avoid performance degradation.\n *\n * </div>\n *\n * Note that:\n * - Callbacks run in the following phase order *once, after the next render*:\n * 1. `earlyRead`\n * 2. `write`\n * 3. `mixedReadWrite`\n * 4. `read`\n * - Callbacks in the same phase run in the order they are registered.\n * - Callbacks run on browser platforms only, they will not run on the server.\n *\n * The first phase callback to run as part of this spec will receive no parameters. Each\n * subsequent phase callback in this spec will receive the return value of the previously run\n * phase callback as a parameter. This can be used to coordinate work across multiple phases.\n *\n * Angular is unable to verify or enforce that phases are used correctly, and instead\n * relies on each developer to follow the guidelines documented for each value and\n * carefully choose the appropriate one, refactoring their code if necessary. By doing\n * so, Angular is better able to minimize the performance degradation associated with\n * manual DOM access, ensuring the best experience for the end users of your application\n * or library.\n *\n * <div class=\"docs-alert docs-alert-important\">\n *\n * Components are not guaranteed to be [hydrated](guide/hydration) before the callback runs.\n * You must use caution when directly reading or writing the DOM and layout.\n *\n * </div>\n *\n * @param spec The callback functions to register\n * @param options Options to control the behavior of the callback\n *\n * @usageNotes\n *\n * Use `afterNextRender` to read or write the DOM once,\n * for example to initialize a non-Angular library.\n *\n * ### Example\n * ```angular-ts\n * @Component({\n * selector: 'my-chart-cmp',\n * template: `<div #chart>{{ ... }}</div>`,\n * })\n * export class MyChartCmp {\n * @ViewChild('chart') chartRef: ElementRef;\n * chart: MyChart|null;\n *\n * constructor() {\n * afterNextRender({\n * write: () => {\n * this.chart = new MyChart(this.chartRef.nativeElement);\n * }\n * });\n * }\n * }\n * ```\n *\n * @developerPreview\n */",
|
||||
"returnType": "AfterRenderRef"
|
||||
},
|
||||
@@ -497,6 +498,7 @@
|
||||
"isRestParam": false
|
||||
}
|
||||
],
|
||||
"returnDescription": "A reference that can be used to unregister the callback registered by this call.",
|
||||
"rawComment": "/**\n * Register a callback to be invoked the next time the application finishes rendering, during the\n * `mixedReadWrite` phase.\n *\n * <div class=\"docs-alert docs-alert-critical\">\n *\n * You should prefer specifying an explicit phase for the callback instead, or you risk significant\n * performance degradation.\n *\n * </div>\n *\n * Note that the callback will run\n * - in the order it was registered\n * - on browser platforms only\n * - during the `mixedReadWrite` phase\n *\n * <div class=\"docs-alert docs-alert-important\">\n *\n * Components are not guaranteed to be [hydrated](guide/hydration) before the callback runs.\n * You must use caution when directly reading or writing the DOM and layout.\n *\n * </div>\n *\n * @param callback A callback function to register\n * @param options Options to control the behavior of the callback\n *\n * @usageNotes\n *\n * Use `afterNextRender` to read or write the DOM once,\n * for example to initialize a non-Angular library.\n *\n * ### Example\n * ```angular-ts\n * @Component({\n * selector: 'my-chart-cmp',\n * template: `<div #chart>{{ ... }}</div>`,\n * })\n * export class MyChartCmp {\n * @ViewChild('chart') chartRef: ElementRef;\n * chart: MyChart|null;\n *\n * constructor() {\n * afterNextRender({\n * write: () => {\n * this.chart = new MyChart(this.chartRef.nativeElement);\n * }\n * });\n * }\n * }\n * ```\n *\n * @publicApi 20.0\n */",
|
||||
"returnType": "AfterRenderRef"
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ import {setSymbols} from '../symbol-context.mjs';
|
||||
import {resolve} from 'path';
|
||||
import {initHighlighter} from '../../../shared/shiki.mjs';
|
||||
import {setHighlighterInstance} from '../shiki/shiki.mjs';
|
||||
import {renderEntry} from '../rendering.mjs';
|
||||
import {JSDOM} from 'jsdom';
|
||||
|
||||
// Note: The tests will probably break if the schema of the api extraction changes.
|
||||
// All entries in the fake-entries are extracted from Angular's api.
|
||||
@@ -60,4 +62,21 @@ describe('renderable', () => {
|
||||
expect(linkedSignal!.experimental).toBe(undefined);
|
||||
expect(linkedSignal!.stable).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should render docs-anchor links in class member card headers', () => {
|
||||
const viewRef = entries.get('ViewRef')!;
|
||||
expect(viewRef).toBeDefined();
|
||||
|
||||
const html = renderEntry(viewRef);
|
||||
const fragment = JSDOM.fragment(html);
|
||||
|
||||
const memberCards = fragment.querySelectorAll('.docs-reference-member-card');
|
||||
expect(memberCards.length).toBeGreaterThan(0);
|
||||
|
||||
for (const card of Array.from(memberCards)) {
|
||||
const id = card.getAttribute('id')!;
|
||||
const anchor = card.querySelector('h3 a.docs-anchor') as HTMLAnchorElement;
|
||||
expect(anchor.getAttribute('href')).toBe(`#${id}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -199,6 +199,23 @@ describe('jsdoc transforms', () => {
|
||||
|
||||
expect(entryFn).toThrowError(/Forbidden relative link: cli\/build ng build/);
|
||||
});
|
||||
|
||||
it('should throw on a miscased absolute @link to a known API symbol', () => {
|
||||
setSymbols({RouterModule: 'router'});
|
||||
|
||||
const entryFn = () =>
|
||||
addHtmlAdditionalLinks({
|
||||
jsdocTags: [
|
||||
{
|
||||
name: 'see',
|
||||
comment: '{@link /api/router/routerModule#forRoot forRoot}',
|
||||
},
|
||||
],
|
||||
moduleName: 'test',
|
||||
});
|
||||
|
||||
expect(entryFn).toThrowError(/Broken @link.*Did you mean \/api\/router\/RouterModule/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addHtmlDescription', () => {
|
||||
|
||||
@@ -53,11 +53,14 @@ export function getCliCardsRenderable(command: CliCommand): CliCardRenderable[]
|
||||
return cards;
|
||||
}
|
||||
|
||||
// Rewrite absolute angular.dev hrefs to root-relative so links stay in-site.
|
||||
const angularDevHrefRegex = /(href=["'])https?:\/\/angular\.dev\//g;
|
||||
|
||||
function getRenderableOptions(items: CliOption[]): CliOptionRenderable[] {
|
||||
return items.map((option) => ({
|
||||
...option,
|
||||
deprecated: option.deprecated ? {version: undefined} : undefined,
|
||||
description: marked.parse(option.description) as string,
|
||||
description: (marked.parse(option.description) as string).replace(angularDevHrefRegex, '$1/'),
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ export async function addRenderableCodeToc<T extends DocEntry & HasModuleName>(
|
||||
{
|
||||
language: 'typescript',
|
||||
apiEntries: getSymbolsAsApiEntries(),
|
||||
removeWhitespace: false,
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
setEntryFlags,
|
||||
} from './jsdoc-transforms.mjs';
|
||||
import {addModuleName} from './module-name.mjs';
|
||||
import {addRenderableFunctionParams} from './params-transforms.mjs';
|
||||
import {addHtmlReturnDescription, addRenderableFunctionParams} from './params-transforms.mjs';
|
||||
import {addRepo} from './repo.mjs';
|
||||
|
||||
/** Given an unprocessed function entry, get the fully renderable function entry. */
|
||||
@@ -50,11 +50,13 @@ export function getFunctionMetadataRenderable(
|
||||
repo: string,
|
||||
): FunctionSignatureMetadataRenderable {
|
||||
return addHtmlAdditionalLinks(
|
||||
addRenderableFunctionParams(
|
||||
addHtmlUsageNotes(
|
||||
setEntryFlags(
|
||||
addHtmlJsDocTagComments(
|
||||
addHtmlDescription(addRepo(addModuleName(entry, moduleName), repo)),
|
||||
addHtmlReturnDescription(
|
||||
addRenderableFunctionParams(
|
||||
addHtmlUsageNotes(
|
||||
setEntryFlags(
|
||||
addHtmlJsDocTagComments(
|
||||
addHtmlDescription(addRepo(addModuleName(entry, moduleName), repo)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -112,7 +112,7 @@ export function addHtmlUsageNotes<T extends HasJsDocTags>(entry: T): T & HasHtml
|
||||
}
|
||||
|
||||
/** Given a markdown JsDoc text, gets the rendered HTML. */
|
||||
function getHtmlForJsDocText(text: string): string {
|
||||
export function getHtmlForJsDocText(text: string): string {
|
||||
const mdToParse = convertLinks(wrapExampleHtmlElementsWithCode(text));
|
||||
const parsed = parseMarkdown(mdToParse, {
|
||||
apiEntries: getSymbolsAsApiEntries(),
|
||||
@@ -223,6 +223,27 @@ function parseAtLink(link: string): {label: string; url: string} | undefined {
|
||||
);
|
||||
}
|
||||
|
||||
// Validate absolute `/api/...` links against the known symbol registry. This catches
|
||||
// miscased symbol names (e.g. `/api/router/routerModule` instead of
|
||||
// `/api/router/RouterModule`) at build time.
|
||||
if (rawSymbol.startsWith('/api/')) {
|
||||
const [pathPart] = rawSymbol.split('#');
|
||||
const segments = pathPart.split('/').filter((s) => s.length > 0);
|
||||
const symbolName = segments[segments.length - 1];
|
||||
// Case-insensitive lookup: find the canonical symbol name in the registry.
|
||||
const knownSymbols = Object.keys(getSymbolsAsApiEntries());
|
||||
const canonicalSymbol = knownSymbols.find(
|
||||
(s) => s.toLowerCase() === symbolName.toLowerCase(),
|
||||
);
|
||||
if (canonicalSymbol && canonicalSymbol !== symbolName) {
|
||||
const expectedUrl = getSymbolUrl(canonicalSymbol);
|
||||
throw Error(
|
||||
`Broken @link: ${link}. Did you mean ${expectedUrl}? ` +
|
||||
`Symbol names in API URLs are case-sensitive.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
url: rawSymbol,
|
||||
label: description ?? rawSymbol.split('/').pop()!,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {HasModuleName, HasParams, HasRenderableParams} from '../entities/traits.mjs';
|
||||
import {addHtmlDescription} from './jsdoc-transforms.mjs';
|
||||
import {addHtmlDescription, getHtmlForJsDocText} from './jsdoc-transforms.mjs';
|
||||
import {addModuleName} from './module-name.mjs';
|
||||
|
||||
export function addRenderableFunctionParams<T extends HasParams & HasModuleName>(
|
||||
@@ -22,3 +22,13 @@ export function addRenderableFunctionParams<T extends HasParams & HasModuleName>
|
||||
params,
|
||||
};
|
||||
}
|
||||
|
||||
/** Converts `returnDescription` to `htmlReturnDescription` for rendering. */
|
||||
export function addHtmlReturnDescription<
|
||||
T extends {returnDescription?: string; moduleName: string},
|
||||
>(entry: T): T & {htmlReturnDescription?: string} {
|
||||
const htmlReturnDescription = entry.returnDescription
|
||||
? getHtmlForJsDocText(entry.returnDescription)
|
||||
: undefined;
|
||||
return {...entry, htmlReturnDescription};
|
||||
}
|
||||
|
||||
@@ -32,6 +32,13 @@ const LINK_EXEMPT = new Set([
|
||||
'type',
|
||||
'Host',
|
||||
'filter',
|
||||
'required',
|
||||
'pattern',
|
||||
'min',
|
||||
'max',
|
||||
'minLength',
|
||||
'maxLength',
|
||||
'query',
|
||||
]);
|
||||
|
||||
export function shouldLinkSymbol(symbol: string): boolean {
|
||||
|
||||
@@ -18,6 +18,7 @@ interface DocsCardToken extends Tokens.Generic {
|
||||
href?: string;
|
||||
imgSrc?: string;
|
||||
iconImgSrc?: string; // Need image since icons are custom
|
||||
titleInline?: boolean;
|
||||
tokens: Token[];
|
||||
}
|
||||
|
||||
@@ -30,6 +31,7 @@ const linkRule = /link="([^"]*)"/;
|
||||
const hrefRule = /href="([^"]*)"/;
|
||||
const imgSrcRule = /imgSrc="([^"]*)"/;
|
||||
const iconImgSrcRule = /iconImgSrc="([^"]*)"/;
|
||||
const titleInlineRule = /(?:^|\s)titleInline(?=\s|$|=)/;
|
||||
|
||||
export const docsCardExtension = {
|
||||
name: 'docs-card',
|
||||
@@ -47,6 +49,7 @@ export const docsCardExtension = {
|
||||
const href = hrefRule.exec(attr);
|
||||
const imgSrc = imgSrcRule.exec(attr);
|
||||
const iconImgSrc = iconImgSrcRule.exec(attr);
|
||||
const titleInline = titleInlineRule.test(attr);
|
||||
|
||||
const body = match[2].trim();
|
||||
|
||||
@@ -59,6 +62,7 @@ export const docsCardExtension = {
|
||||
link: link ? link[1] : undefined,
|
||||
imgSrc: imgSrc ? imgSrc[1] : undefined,
|
||||
iconImgSrc: iconImgSrc ? iconImgSrc[1] : undefined,
|
||||
titleInline,
|
||||
tokens: [],
|
||||
};
|
||||
this.lexer.blockTokens(token.body, token.tokens);
|
||||
@@ -79,12 +83,14 @@ function getStandardCard(renderer: AdevDocsRenderer, token: DocsCardToken) {
|
||||
// We need to read svg content, instead of renering svg with `img`,
|
||||
// cause we would like to use CSS variables to support dark and light mode.
|
||||
const icon = loadWorkspaceRelativeFile(token.iconImgSrc);
|
||||
const header = token.titleInline
|
||||
? `<div class="docs-card-header-inline">${icon}<h3>${token.title}</h3></div>`
|
||||
: `${icon}<h3>${token.title}</h3>`;
|
||||
|
||||
return `
|
||||
<a href="${token.href}" ${anchorTarget(token.href)} class="docs-card">
|
||||
<div>
|
||||
${icon}
|
||||
<h3>${token.title}</h3>
|
||||
${header}
|
||||
${renderer.parser.parse(token.tokens)}
|
||||
</div>
|
||||
<span>${token.link ? token.link : 'Learn more'}</span>
|
||||
|
||||
@@ -42,6 +42,7 @@ export function codeToHtml(
|
||||
apiEntries?: ApiEntries;
|
||||
language?: string;
|
||||
highlight?: Set<number>;
|
||||
removeWhitespace?: boolean;
|
||||
},
|
||||
): string {
|
||||
const html = highlighter.codeToHtml(code, {
|
||||
@@ -53,7 +54,7 @@ export function codeToHtml(
|
||||
cssVariablePrefix: '--shiki-',
|
||||
defaultColor: false,
|
||||
transformers: [
|
||||
removeWhitespaceTransformer(),
|
||||
...(config.removeWhitespace ? [removeWhitespaceTransformer()] : []),
|
||||
highlightTransformer(config.highlight),
|
||||
linkApiEntriesTransformer(config.apiEntries),
|
||||
],
|
||||
|
||||
@@ -21,6 +21,7 @@ export class NavigationState {
|
||||
private readonly _isMobileNavVisible = signal<boolean>(false);
|
||||
private readonly _level = linkedSignal(() => this._expandedItems().length);
|
||||
|
||||
readonly crossCategoryOrigin = signal<NavigationItem | undefined>(undefined);
|
||||
readonly primaryActiveRouteItem = signal<string | null>(null);
|
||||
activeNavigationItem = this._activeNavigationItem.asReadonly();
|
||||
expandedItems = this._expandedItems.asReadonly();
|
||||
|
||||
@@ -24,43 +24,43 @@ $screen-xxl: 1800px;
|
||||
}
|
||||
|
||||
@mixin for-tablet-portrait-up {
|
||||
@media (min-width: calc($screen-xs + 0.01px)) {
|
||||
@media (min-width: ($screen-xs + 1px)) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin for-tablet {
|
||||
@media (min-width: calc($screen-xs + 0.01px)) and (max-width: $screen-md) {
|
||||
@media (min-width: ($screen-xs + 1px)) and (max-width: $screen-md) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin for-tablet-up {
|
||||
@media (min-width: calc($screen-sm + 0.01px)) {
|
||||
@media (min-width: ($screen-sm + 1px)) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin for-tablet-landscape-up {
|
||||
@media (min-width: calc($screen-md + 0.01px)) {
|
||||
@media (min-width: ($screen-md + 1px)) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin for-desktop-up {
|
||||
@media (min-width: calc($screen-lg + 0.01px)) {
|
||||
@media (min-width: ($screen-lg + 1px)) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin for-large-desktop-up {
|
||||
@media (min-width: calc($screen-xl + 0.01px)) {
|
||||
@media (min-width: ($screen-xl + 1px)) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin for-extra-large-desktop-up {
|
||||
@media (min-width: calc($screen-xxl + 0.01px)) {
|
||||
@media (min-width: ($screen-xxl + 1px)) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,7 @@ $screen-xxl: 1800px;
|
||||
}
|
||||
|
||||
@mixin for-large-desktop-down {
|
||||
@media (max-width: calc($screen-xl )) {
|
||||
@media (max-width: $screen-xl) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,6 +340,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
.docs-param-type {
|
||||
display: inline-block;
|
||||
margin-inline-end: 0.5rem;
|
||||
}
|
||||
|
||||
.docs-parameter-description {
|
||||
p:first-child {
|
||||
margin-block-start: 0;
|
||||
@@ -357,7 +362,7 @@
|
||||
padding-block: 1rem;
|
||||
|
||||
// & does not follow a function definition
|
||||
&:not(.docs-function-definition + .docs-return-type) {
|
||||
&:not(.docs-function-definition + .docs-return-type):not(:first-child) {
|
||||
border-block-start: 1px solid var(--senary-contrast);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Card Grid
|
||||
|
||||
@mixin docs-card() {
|
||||
$compact-breakpoint: 550px;
|
||||
|
||||
.docs-card-container-wrapper {
|
||||
border: 1px solid var(--senary-contrast);
|
||||
border-radius: 0.25rem;
|
||||
@@ -15,6 +17,11 @@
|
||||
h2 {
|
||||
padding: 2.5rem 1rem 2.5rem 2.5rem;
|
||||
min-width: 350px;
|
||||
|
||||
@container docs-content (max-width: $compact-breakpoint) {
|
||||
min-width: auto;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.theme-fill-bg {
|
||||
@@ -57,7 +64,11 @@
|
||||
svg {
|
||||
fill-opacity: 1;
|
||||
|
||||
@container header (max-width: 550px) {
|
||||
@container header (max-width: $compact-breakpoint) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@container docs-content (max-width: $compact-breakpoint) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -71,6 +82,11 @@
|
||||
margin: 1rem;
|
||||
padding: 1.5rem;
|
||||
|
||||
@container docs-content (max-width: $compact-breakpoint) {
|
||||
margin: 0.5rem;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.docs-card {
|
||||
margin: 0;
|
||||
|
||||
@@ -143,6 +159,21 @@
|
||||
margin-block: 1.5rem;
|
||||
}
|
||||
|
||||
.docs-card-header-inline {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
svg {
|
||||
margin-block-end: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-block: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.docs-card-with-svg {
|
||||
padding: 0;
|
||||
|
||||
@@ -252,7 +283,7 @@
|
||||
.docs-nav-card-svg {
|
||||
width: 350px;
|
||||
|
||||
@container header (max-width: 550px) {
|
||||
@container header (max-width: $compact-breakpoint) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,26 +80,11 @@ $code-font-size: 0.875rem;
|
||||
&:not(pre *) {
|
||||
position: relative;
|
||||
padding: 0 0.3rem;
|
||||
// Fallback for older browsers
|
||||
background: #e62600;
|
||||
background: var(--red-to-orange-horizontal-gradient);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
color: transparent;
|
||||
background: var(--subtle-purple);
|
||||
color: var(--hot-pink);
|
||||
max-width: max-content;
|
||||
border-radius: 0.25rem;
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--subtle-purple);
|
||||
border-radius: 0.25rem;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
a:not(.docs-anchor) > & {
|
||||
position: relative;
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
vertical-align: top;
|
||||
min-width: 10ch;
|
||||
}
|
||||
td:has(code) {
|
||||
min-width: 8ch;
|
||||
}
|
||||
&:not(:last-child) {
|
||||
border-block-end: 1px solid var(--senary-contrast);
|
||||
}
|
||||
|
||||
@@ -40,6 +40,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Lock the page behind the mobile primary-nav drawer. `clip` preserves the primary nav's sticky context.
|
||||
@include mq.for-phone-only {
|
||||
&:has(.adev-nav-primary--open) {
|
||||
overflow: clip;
|
||||
}
|
||||
}
|
||||
|
||||
&:has(.adev-home) {
|
||||
.adev-nav {
|
||||
width: 0;
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
<li>
|
||||
<a
|
||||
href="https://github.com/angular/angular/issues"
|
||||
title="Post issues and suggestions on github."
|
||||
title="Post issues and suggestions on GitHub."
|
||||
>
|
||||
Report Issues
|
||||
</a>
|
||||
@@ -99,6 +99,9 @@
|
||||
<li>
|
||||
<a href="https://angular.az/" title="Azərbaycanca">Azərbaycanca</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://docs.angular.lat/" title="Español">Español</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://angular-docs.tr/" title="Türkçe">Türkçe</a>
|
||||
</li>
|
||||
|
||||
@@ -392,11 +392,11 @@
|
||||
<a
|
||||
[href]="ngLinks.GITHUB"
|
||||
cdkMenuItem
|
||||
title="Angular Github"
|
||||
title="Angular GitHub"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<!-- Github Icon -->
|
||||
<!-- GitHub Icon -->
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
@@ -436,6 +436,28 @@
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
[href]="ngLinks.STACKOVERFLOW"
|
||||
cdkMenuItem
|
||||
title="Angular Stack Overflow"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<!-- Stack Overflow Icon -->
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 26 31"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="m22.18 16.32.05.02-.02.01za19 19 0 0 0-2.45 4.14l-.03.07q-.94 2.19-1.29 4.6v.03a18 18 0 0 0-.05 4.85H.01v-4.88h15.94l.1-.6L.69 20.48l1.28-4.7 15.55 4.1.22-.46-13.96-7.96 2.47-4.22 14.16 8.07.34-.4L9.15 3.47 12.65 0l11.78 11.64 1.25 1.23q-1.97 1.5-3.5 3.44"
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
width: 100%;
|
||||
padding-inline: calc(var(--layout-padding) - 1.25rem);
|
||||
height: auto;
|
||||
scrollbar-width: none;
|
||||
padding-block: 0;
|
||||
}
|
||||
|
||||
@@ -139,7 +140,7 @@
|
||||
position: absolute;
|
||||
top: 0;
|
||||
background-color: var(--page-background);
|
||||
box-shadow: 10px 4px 3px 0 rgba(0, 0, 0, 0.001);
|
||||
box-shadow: 2px 0 0 0 var(--page-background);
|
||||
|
||||
transform: translateX(-100%);
|
||||
// primary nav: exit delayed
|
||||
@@ -169,6 +170,7 @@
|
||||
|
||||
@include mq.for-tablet {
|
||||
flex-direction: row;
|
||||
padding-block-start: 0;
|
||||
}
|
||||
|
||||
// version dropdown button
|
||||
@@ -233,7 +235,9 @@
|
||||
|
||||
@include mq.for-tablet {
|
||||
flex-direction: row !important;
|
||||
align-items: center;
|
||||
margin-inline-end: 1.25rem;
|
||||
margin-top: 0.25rem;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
@@ -289,6 +293,8 @@
|
||||
|
||||
@include mq.for-phone-only {
|
||||
display: block;
|
||||
position: relative;
|
||||
top: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
@include mq.for-tablet-landscape-down {
|
||||
position: absolute;
|
||||
height: 100dvh;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
|
||||
<section class="explore-section" id="learn-more">
|
||||
<div class="title">
|
||||
<h2>What to learn more about Angular?</h2>
|
||||
<h2>Want to learn more about Angular?</h2>
|
||||
<div class="pattern"></div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -28,8 +28,12 @@
|
||||
left: calc(var(--layout-padding) + var(--primary-nav-width));
|
||||
z-index: 1;
|
||||
|
||||
@include mq.for-tablet-down {
|
||||
justify-content: flex-start;
|
||||
@include mq.for-tablet-landscape-down {
|
||||
justify-content: center;
|
||||
margin-top: 4rem;
|
||||
}
|
||||
|
||||
@include mq.for-phone-only {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
@@ -182,7 +186,7 @@ section {
|
||||
}
|
||||
|
||||
.search-field {
|
||||
@include mq.for-tablet-down() {
|
||||
@include mq.for-tablet-landscape-down() {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -269,6 +273,11 @@ section {
|
||||
width: fit-content;
|
||||
margin: 0 auto 2rem;
|
||||
|
||||
@include mq.for-phone-only {
|
||||
width: auto;
|
||||
margin: 0 0.5rem 1rem;
|
||||
}
|
||||
|
||||
.tab-background {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
border-radius: 0.25rem;
|
||||
padding: 0;
|
||||
transform: translateY(-0.7rem);
|
||||
background: var(--page-background);
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
|
||||
@@ -33,6 +33,7 @@ describe('TutorialPlayground', () => {
|
||||
|
||||
class FakeNodeRuntimeSandbox {
|
||||
init() {}
|
||||
reset() {}
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
@@ -56,4 +57,22 @@ describe('TutorialPlayground', () => {
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not call reset on the sandbox before it is initialized', async () => {
|
||||
const fakeSandbox = {reset: jasmine.createSpy('reset')} as any;
|
||||
component['nodeRuntimeSandbox'] = fakeSandbox;
|
||||
component['isSandboxReady'].set(false);
|
||||
spyOn<any>(component, 'loadTemplate').and.resolveTo();
|
||||
await component.changeTemplate(component.templates[1]);
|
||||
expect(fakeSandbox.reset).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call reset on the sandbox after it is initialized', async () => {
|
||||
const fakeSandbox = {reset: jasmine.createSpy('reset')} as any;
|
||||
component['nodeRuntimeSandbox'] = fakeSandbox;
|
||||
component['isSandboxReady'].set(true);
|
||||
spyOn<any>(component, 'loadTemplate').and.resolveTo();
|
||||
await component.changeTemplate(component.templates[1]);
|
||||
expect(fakeSandbox.reset).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
DestroyRef,
|
||||
EnvironmentInjector,
|
||||
PLATFORM_ID,
|
||||
signal,
|
||||
Type,
|
||||
effect,
|
||||
inject,
|
||||
@@ -55,6 +56,7 @@ export default class PlaygroundComponent {
|
||||
protected nodeRuntimeSandbox?: NodeRuntimeSandbox;
|
||||
protected embeddedEditorComponent?: Type<unknown>;
|
||||
protected selectedTemplate: PlaygroundTemplate = this.defaultTemplate;
|
||||
private readonly isSandboxReady = signal(false);
|
||||
|
||||
constructor() {
|
||||
if (this.isServer) {
|
||||
@@ -84,6 +86,7 @@ export default class PlaygroundComponent {
|
||||
.subscribe(() => {
|
||||
this.changeDetectorRef.markForCheck();
|
||||
this.nodeRuntimeSandbox?.init();
|
||||
this.isSandboxReady.set(true);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -99,7 +102,9 @@ export default class PlaygroundComponent {
|
||||
});
|
||||
this.selectedTemplate = template;
|
||||
await this.loadTemplate(template.path);
|
||||
await this.nodeRuntimeSandbox?.reset();
|
||||
if (this.isSandboxReady()) {
|
||||
await this.nodeRuntimeSandbox?.reset();
|
||||
}
|
||||
}
|
||||
|
||||
private async loadTemplate(tutorialPath: string) {
|
||||
|
||||
@@ -79,12 +79,15 @@
|
||||
|
||||
:host {
|
||||
--item-attr-base-mix: 80%;
|
||||
--item-attr-text: var(--page-background);
|
||||
|
||||
.docs-light-mode & {
|
||||
--item-attr-base-mix: 20%;
|
||||
--item-attr-text: var(--primary-contrast);
|
||||
}
|
||||
@media screen and (prefers-color-scheme: light) {
|
||||
--item-attr-base-mix: 20%;
|
||||
--item-attr-text: var(--primary-contrast);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +113,7 @@
|
||||
var(--symbolic-yellow) var(--item-attr-base-mix),
|
||||
var(--octonary-contrast)
|
||||
);
|
||||
color: var(--page-background);
|
||||
color: var(--item-attr-text);
|
||||
}
|
||||
|
||||
&.adev-experimental {
|
||||
@@ -119,7 +122,7 @@
|
||||
var(--symbolic-green) var(--item-attr-base-mix),
|
||||
var(--octonary-contrast)
|
||||
);
|
||||
color: var(--page-background);
|
||||
color: var(--item-attr-text);
|
||||
}
|
||||
|
||||
&.adev-deprecated {
|
||||
|
||||
+59
-28
@@ -28,10 +28,11 @@
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
|
||||
.adev-reference-list-type-filter-label {
|
||||
margin-block: 2.5rem 1rem;
|
||||
margin-block: 1rem;
|
||||
}
|
||||
|
||||
.adev-reference-list-type-filter {
|
||||
box-sizing: border-box;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
margin-block: 0;
|
||||
@@ -45,6 +46,7 @@
|
||||
}
|
||||
@container api-ref-page (max-width: 600px) {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
max-width: 500px;
|
||||
}
|
||||
@container api-ref-page (max-width: 500px) {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
@@ -88,16 +90,70 @@
|
||||
|
||||
.adev-reference-list-query-filter {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
docs-text-field,
|
||||
docs-select {
|
||||
width: 100%;
|
||||
max-width: 350px;
|
||||
}
|
||||
|
||||
@container api-ref-page (max-width: 600px) {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
|
||||
docs-text-field,
|
||||
docs-select {
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.adev-reference-list-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 1rem;
|
||||
|
||||
::ng-deep .mat-mdc-chip-listbox {
|
||||
@container api-ref-page (max-width: 600px) {
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
|
||||
.mdc-evolution-chip-set__chips {
|
||||
display: grid !important;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 8px;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.mat-mdc-chip-option {
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@container api-ref-page (max-width: 350px) {
|
||||
.mdc-evolution-chip-set__chips {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.adev-reference-list-empty {
|
||||
text-align: center;
|
||||
margin-block-start: 2rem;
|
||||
flex-basis: 100%;
|
||||
|
||||
p {
|
||||
font-size: 1rem;
|
||||
@@ -108,28 +164,3 @@
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.adev-reference-list-empty {
|
||||
flex-basis: 100%;
|
||||
p {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.docs-api-item-label-full {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.map-chip-option {
|
||||
min-width: 190px;
|
||||
}
|
||||
|
||||
.adev-reference-list-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 12px;
|
||||
|
||||
label {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,12 @@ export enum ApplicationComplexity {
|
||||
|
||||
export interface Step {
|
||||
step: string;
|
||||
/**
|
||||
* Action text rendered as Markdown. Use Markdown link syntax `[text](url)`
|
||||
* for any links — raw `<a>` HTML tags bypass the custom link renderer in
|
||||
* `update.component.ts` and will not pick up `target="_blank"` or the
|
||||
* external-link icon.
|
||||
*/
|
||||
action: string;
|
||||
possibleIn: number;
|
||||
necessaryAsOf: number;
|
||||
@@ -155,7 +161,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Advanced,
|
||||
step: 'gendir',
|
||||
action:
|
||||
'Do not rely on `gendir`, instead look at using `skipTemplateCodeGen`. <a href=https://github.com/angular/angular/issues/19339#issuecomment-332607471" target="_blank">Read More</a>',
|
||||
'Do not rely on `gendir`, instead look at using `skipTemplateCodeGen`. [Read More](https://github.com/angular/angular/issues/19339#issuecomment-332607471)',
|
||||
},
|
||||
{
|
||||
possibleIn: 220,
|
||||
@@ -239,7 +245,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Basic,
|
||||
step: 'node 8',
|
||||
action:
|
||||
'Make sure you are using <a href="http://www.hostingadvice.com/how-to/update-node-js-latest-version/" target="_blank">Node 8 or later</a>',
|
||||
'Make sure you are using [Node 8 or later](http://www.hostingadvice.com/how-to/update-node-js-latest-version/)',
|
||||
},
|
||||
{
|
||||
possibleIn: 600,
|
||||
@@ -248,7 +254,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
windows: false,
|
||||
step: 'Update to CLI v6',
|
||||
action:
|
||||
'Update your Angular CLI, and migrate the configuration to the <a href="https://github.com/angular/angular-cli/wiki/angular-workspace" target="_blank">new angular.json format</a> by running the following:<br/><br/>`NG_DISABLE_VERSION_CHECK=1 npx @angular/cli@6 update @angular/cli@6`<br/>',
|
||||
'Update your Angular CLI, and migrate the configuration to the [new angular.json format](https://github.com/angular/angular-cli/wiki/angular-workspace) by running the following:<br/><br/>`NG_DISABLE_VERSION_CHECK=1 npx @angular/cli@6 update @angular/cli@6`<br/>',
|
||||
},
|
||||
{
|
||||
possibleIn: 600,
|
||||
@@ -257,7 +263,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
windows: true,
|
||||
step: 'Update to CLI v6',
|
||||
action:
|
||||
'Update your Angular CLI, and migrate the configuration to the <a href="https://github.com/angular/angular-cli/wiki/angular-workspace" target="_blank">new angular.json format</a> by running the following:<br/><br/>`cmd /C "set "NG_DISABLE_VERSION_CHECK=1" && npx @angular/cli@6 update @angular/cli@6 @angular/core@6"`<br/>',
|
||||
'Update your Angular CLI, and migrate the configuration to the [new angular.json format](https://github.com/angular/angular-cli/wiki/angular-workspace) by running the following:<br/><br/>`cmd /C "set "NG_DISABLE_VERSION_CHECK=1" && npx @angular/cli@6 update @angular/cli@6 @angular/core@6"`<br/>',
|
||||
},
|
||||
{
|
||||
possibleIn: 600,
|
||||
@@ -343,7 +349,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Medium,
|
||||
step: 'strictPropertyInitializer',
|
||||
action:
|
||||
'If you have TypeScript configured to be strict (if you have set `strict` to `true` in your `tsconfig.json` file), update your `tsconfig.json` to disable `strictPropertyInitialization` or move property initialization from `ngOnInit` to your constructor. You can learn more about this flag on the <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#strict-class-initialization">TypeScript 2.7 release notes</a>.',
|
||||
'If you have TypeScript configured to be strict (if you have set `strict` to `true` in your `tsconfig.json` file), update your `tsconfig.json` to disable `strictPropertyInitialization` or move property initialization from `ngOnInit` to your constructor. You can learn more about this flag on the [TypeScript 2.7 release notes](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#strict-class-initialization).',
|
||||
},
|
||||
{
|
||||
possibleIn: 600,
|
||||
@@ -351,7 +357,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Basic,
|
||||
step: 'update to RxJS 6',
|
||||
action:
|
||||
'Remove deprecated RxJS 5 features using <a href="https://github.com/ReactiveX/rxjs-tslint" target="_blank">rxjs-tslint auto update rules</a><br/><br/>For most applications this will mean running the following two commands:<br/><br/>`npx rxjs-tslint`<br/>`rxjs-5-to-6-migrate -p src/tsconfig.app.json`',
|
||||
'Remove deprecated RxJS 5 features using [rxjs-tslint auto update rules](https://github.com/ReactiveX/rxjs-tslint)<br/><br/>For most applications this will mean running the following two commands:<br/><br/>`npx rxjs-tslint`<br/>`rxjs-5-to-6-migrate -p src/tsconfig.app.json`',
|
||||
},
|
||||
{
|
||||
possibleIn: 600,
|
||||
@@ -374,7 +380,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Basic,
|
||||
step: 'TypeScript 3.1',
|
||||
action:
|
||||
'Angular now uses TypeScript 3.1, read more about any potential breaking changes: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-1.html',
|
||||
'Angular now uses TypeScript 3.1, read more about [any potential breaking changes](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-1.html).',
|
||||
},
|
||||
{
|
||||
possibleIn: 700,
|
||||
@@ -382,7 +388,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Basic,
|
||||
step: 'Node 10',
|
||||
action:
|
||||
'Angular has now added support for Node 10: https://nodejs.org/en/blog/release/v10.0.0/',
|
||||
'Angular has now added support for [Node 10](https://nodejs.org/en/blog/release/v10.0.0/).',
|
||||
},
|
||||
{
|
||||
possibleIn: 700,
|
||||
@@ -464,7 +470,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Basic,
|
||||
step: 'use ::ng-deep instead of /deep/',
|
||||
action:
|
||||
'Replace `/deep/` with `::ng-deep` in your styles, [read more about angular component styles and ::ng-deep](https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep). `/deep/` and `::ng-deep` both are deprecated but using `::ng-deep` is preferred until the shadow-piercing descendant combinator is [removed from browsers and tools](https://www.chromestatus.com/features/6750456638341120) completely.',
|
||||
'Replace `/deep/` with `::ng-deep` in your styles, [read more about angular component styles and ::ng-deep](https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep). `/deep/` and `::ng-deep` both are deprecated but using `::ng-deep` is preferred until the shadow-piercing descendant combinator is [removed from browsers and tools](https://chromestatus.com/feature/5045542597951488) completely.',
|
||||
},
|
||||
{
|
||||
possibleIn: 800,
|
||||
@@ -480,7 +486,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Basic,
|
||||
step: 'node 10',
|
||||
action:
|
||||
'Make sure you are using <a href="http://www.hostingadvice.com/how-to/update-node-js-latest-version/" target="_blank">Node 10 or later</a>.',
|
||||
'Make sure you are using [Node 10 or later](http://www.hostingadvice.com/how-to/update-node-js-latest-version/).',
|
||||
},
|
||||
{
|
||||
possibleIn: 800,
|
||||
@@ -573,7 +579,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Basic,
|
||||
step: 'node 10.13',
|
||||
action:
|
||||
'Make sure you are using <a href="http://www.hostingadvice.com/how-to/update-node-js-latest-version/" target="_blank">Node 10.13 or later</a>.',
|
||||
'Make sure you are using [Node 10.13 or later](http://www.hostingadvice.com/how-to/update-node-js-latest-version/).',
|
||||
},
|
||||
{
|
||||
possibleIn: 900,
|
||||
@@ -781,9 +787,8 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
possibleIn: 1000,
|
||||
necessaryAsOf: 1000,
|
||||
level: ApplicationComplexity.Basic,
|
||||
step: 'v10 NodeJS 12',
|
||||
action:
|
||||
'Make sure you are using <a href="https://nodejs.org/dist/latest-v12.x/" target="_blank">Node 12 or later</a>.',
|
||||
step: 'v10 Node.js 12',
|
||||
action: 'Make sure you are using [Node 12 or later](https://nodejs.org/dist/latest-v12.x/).',
|
||||
},
|
||||
{
|
||||
possibleIn: 1000,
|
||||
@@ -847,7 +852,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Advanced,
|
||||
step: 'closure-jsdoc-comments',
|
||||
action:
|
||||
"Angular's NPM packages no longer contain jsdoc comments, which are necessary for use with closure compiler (extremely uncommon). This support was experimental and only worked in some use cases. There will be an alternative recommended path announced shortly.",
|
||||
"Angular's npm packages no longer contain jsdoc comments, which are necessary for use with closure compiler (extremely uncommon). This support was experimental and only worked in some use cases. There will be an alternative recommended path announced shortly.",
|
||||
},
|
||||
{
|
||||
possibleIn: 1000,
|
||||
@@ -871,7 +876,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Medium,
|
||||
step: 'esm5-bundles',
|
||||
action:
|
||||
"The [Angular Package Format](https://g.co/ng/apf) has been updated to remove `esm5` and `fesm5` formats. These are no longer distributed in our npm packages. If you don't use the CLI, you may need to downlevel Angular code to ES5 yourself.",
|
||||
"The [Angular Package Format](https://angular.dev/tools/libraries/angular-package-format) has been updated to remove `esm5` and `fesm5` formats. These are no longer distributed in our npm packages. If you don't use the CLI, you may need to downlevel Angular code to ES5 yourself.",
|
||||
},
|
||||
{
|
||||
possibleIn: 1000,
|
||||
@@ -1335,7 +1340,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Basic,
|
||||
step: 'TypeScript 4.4',
|
||||
action:
|
||||
'Angular now uses TypeScript 4.4, read more about any potential breaking changes: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-4.html',
|
||||
'Angular now uses TypeScript 4.4, read more about [any potential breaking changes](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-4.html).',
|
||||
},
|
||||
{
|
||||
possibleIn: 1300,
|
||||
@@ -1343,7 +1348,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Basic,
|
||||
step: 'v13 node',
|
||||
action:
|
||||
'Make sure you are using <a href="http://www.hostingadvice.com/how-to/update-node-js-latest-version/" target="_blank">Node 12.20.0 or later</a>',
|
||||
'Make sure you are using [Node 12.20.0 or later](http://www.hostingadvice.com/how-to/update-node-js-latest-version/)',
|
||||
},
|
||||
{
|
||||
possibleIn: 1300,
|
||||
@@ -1457,7 +1462,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Basic,
|
||||
step: 'TypeScript 4.6',
|
||||
action:
|
||||
'Angular now uses TypeScript 4.6, read more about any potential breaking changes: https://devblogs.microsoft.com/typescript/announcing-typescript-4-6/',
|
||||
'Angular now uses TypeScript 4.6, read more about [any potential breaking changes](https://devblogs.microsoft.com/typescript/announcing-typescript-4-6/).',
|
||||
},
|
||||
|
||||
{
|
||||
@@ -1466,7 +1471,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Basic,
|
||||
step: 'v14 node',
|
||||
action:
|
||||
'Make sure you are using <a href="http://www.hostingadvice.com/how-to/update-node-js-latest-version/" target="_blank">Node 14.15.0 or later</a>',
|
||||
'Make sure you are using [Node 14.15.0 or later](http://www.hostingadvice.com/how-to/update-node-js-latest-version/)',
|
||||
},
|
||||
{
|
||||
possibleIn: 1400,
|
||||
@@ -1669,7 +1674,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Basic,
|
||||
step: 'v15 node support',
|
||||
action:
|
||||
'Make sure that you are using a supported version of node.js before you upgrade your application. Angular v15 supports node.js versions: 14.20.x, 16.13.x and 18.10.x. <a href="https://v15.angular.io/guide/update-to-version-15#v15-bc-01" alt="Link to more information about this change">Read further</a>',
|
||||
'Make sure that you are using a supported version of node.js before you upgrade your application. Angular v15 supports node.js versions: 14.20.x, 16.13.x and 18.10.x. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-bc-01)',
|
||||
},
|
||||
{
|
||||
possibleIn: 1500,
|
||||
@@ -1677,7 +1682,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Basic,
|
||||
step: 'v15 ts support',
|
||||
action:
|
||||
'Make sure that you are using a supported version of TypeScript before you upgrade your application. Angular v15 supports TypeScript version 4.8 or later. <a href="https://v15.angular.io/guide/update-to-version-15#v15-bc-02" alt="Link to more information about this change">Read further</a>',
|
||||
'Make sure that you are using a supported version of TypeScript before you upgrade your application. Angular v15 supports TypeScript version 4.8 or later. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-bc-02)',
|
||||
},
|
||||
{
|
||||
possibleIn: 1500,
|
||||
@@ -1701,7 +1706,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Medium,
|
||||
step: 'v15 keyframe',
|
||||
action:
|
||||
'In v15, the Angular compiler prefixes `@keyframes` in CSS with the component\'s scope. This means that any TypeScript code that relies on `keyframes` names no longer works in v15. Update any such instances to: define keyframes programmatically, use global stylesheets, or change the component\'s view encapsulation. <a href="https://v15.angular.io/guide/update-to-version-15#v15-bc-03" alt="Link to more information about this change">Read further</a>',
|
||||
"In v15, the Angular compiler prefixes `@keyframes` in CSS with the component's scope. This means that any TypeScript code that relies on `keyframes` names no longer works in v15. Update any such instances to: define keyframes programmatically, use global stylesheets, or change the component's view encapsulation. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-bc-03)",
|
||||
},
|
||||
{
|
||||
possibleIn: 1500,
|
||||
@@ -1717,7 +1722,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Medium,
|
||||
step: 'v15 base-decorators',
|
||||
action:
|
||||
'Make sure to use decorators in base classes with child classes that inherit constructors and use dependency injection. Such base classes should be decorated with either `@Injectable` or `@Directive` or the compiler returns an error. <a href="https://v15.angular.io/guide/update-to-version-15#v15-bc-05" alt="Link to more information about this change">Read further</a>',
|
||||
'Make sure to use decorators in base classes with child classes that inherit constructors and use dependency injection. Such base classes should be decorated with either `@Injectable` or `@Directive` or the compiler returns an error. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-bc-05)',
|
||||
},
|
||||
{
|
||||
possibleIn: 1500,
|
||||
@@ -1725,7 +1730,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Medium,
|
||||
step: 'v15 setDisabledState',
|
||||
action:
|
||||
'In v15, `setDisabledState` is always called when a `ControlValueAccessor` is attached. To opt-out of this behavior, use `FormsModule.withConfig` or `ReactiveFormsModule.withConfig`. <a href="https://v15.angular.io/guide/update-to-version-15#v15-bc-06" alt="Link to more information about this change">Read further</a>',
|
||||
'In v15, `setDisabledState` is always called when a `ControlValueAccessor` is attached. To opt-out of this behavior, use `FormsModule.withConfig` or `ReactiveFormsModule.withConfig`. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-bc-06)',
|
||||
},
|
||||
{
|
||||
possibleIn: 1500,
|
||||
@@ -1733,7 +1738,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Advanced,
|
||||
step: 'v15 canParse',
|
||||
action:
|
||||
'Applications that use `canParse` should use `analyze` from `@angular/localize/tools` instead. In v15, the `canParse` method was removed from all translation parsers in `@angular/localize/tools`. <a href="https://v15.angular.io/guide/update-to-version-15#v15-bc-07" alt="Link to more information about this change">Read further</a>',
|
||||
'Applications that use `canParse` should use `analyze` from `@angular/localize/tools` instead. In v15, the `canParse` method was removed from all translation parsers in `@angular/localize/tools`. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-bc-07)',
|
||||
},
|
||||
{
|
||||
possibleIn: 1500,
|
||||
@@ -1741,7 +1746,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Basic,
|
||||
step: 'v15 ActivatedRoutSnapshot',
|
||||
action:
|
||||
'Make sure that all `ActivatedRouteSnapshot` objects have a `title` property. In v15, the `title` property is a required property of `ActivatedRouteSnapshot`. <a href="https://v15.angular.io/guide/update-to-version-15#v15-bc-08" alt="Link to more information about this change">Read further</a>',
|
||||
'Make sure that all `ActivatedRouteSnapshot` objects have a `title` property. In v15, the `title` property is a required property of `ActivatedRouteSnapshot`. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-bc-08)',
|
||||
},
|
||||
{
|
||||
possibleIn: 1500,
|
||||
@@ -1749,7 +1754,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Advanced,
|
||||
step: 'v15 RouterOutlet',
|
||||
action:
|
||||
'If your tests with `RouterOutlet` break, make sure they don\'t depend on the instantiation order of the corresponding component relative to change detection. In v15, `RouterOutlet` instantiates the component after change detection. <a href="https://v15.angular.io/guide/update-to-version-15#v15-bc-09" alt="Link to more information about this change">Read further</a>',
|
||||
"If your tests with `RouterOutlet` break, make sure they don't depend on the instantiation order of the corresponding component relative to change detection. In v15, `RouterOutlet` instantiates the component after change detection. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-bc-09)",
|
||||
},
|
||||
{
|
||||
possibleIn: 1500,
|
||||
@@ -1757,7 +1762,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Basic,
|
||||
step: 'v15 relativeLinkResolution',
|
||||
action:
|
||||
'In v15, `relativeLinkResolution` is not configurable in the Router. It was used to opt out of an earlier bug fix that is now standard. <a href="https://v15.angular.io/guide/update-to-version-15#v15-bc-10" alt="Link to more information about this change">Read further</a>',
|
||||
'In v15, `relativeLinkResolution` is not configurable in the Router. It was used to opt out of an earlier bug fix that is now standard. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-bc-10)',
|
||||
},
|
||||
{
|
||||
possibleIn: 1500,
|
||||
@@ -1765,7 +1770,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Medium,
|
||||
step: 'v15 DATE_PIPE_DEFAULT_OPTIONS',
|
||||
action:
|
||||
'Change instances of the `DATE_PIPE_DEFAULT_TIMEZONE` token to use `DATE_PIPE_DEFAULT_OPTIONS` to configure time zones. In v15, the `DATE_PIPE_DEFAULT_TIMEZONE` token is deprecated. <a href="https://v15.angular.io/guide/update-to-version-15#v15-dp-01" alt="Link to more information about this change">Read further</a>',
|
||||
'Change instances of the `DATE_PIPE_DEFAULT_TIMEZONE` token to use `DATE_PIPE_DEFAULT_OPTIONS` to configure time zones. In v15, the `DATE_PIPE_DEFAULT_TIMEZONE` token is deprecated. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-dp-01)',
|
||||
},
|
||||
{
|
||||
possibleIn: 1500,
|
||||
@@ -1781,7 +1786,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Medium,
|
||||
step: 'v15 Injector.get',
|
||||
action:
|
||||
'Update instances of `Injector.get()` that use an `InjectFlags` parameter to use an `InjectOptions` parameter. The `InjectFlags` parameter of `Injector.get()` is deprecated in v15. <a href="https://v15.angular.io/guide/update-to-version-15#v15-dp-02" alt="Link to more information about this change">Read further</a>',
|
||||
'Update instances of `Injector.get()` that use an `InjectFlags` parameter to use an `InjectOptions` parameter. The `InjectFlags` parameter of `Injector.get()` is deprecated in v15. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-dp-02)',
|
||||
},
|
||||
{
|
||||
possibleIn: 1500,
|
||||
@@ -1789,7 +1794,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Basic,
|
||||
step: 'v15 TestBed.inject',
|
||||
action:
|
||||
'Update instances of `TestBed.inject()` that use an `InjectFlags` parameter to use an `InjectOptions` parameter. The `InjectFlags` parameter of `TestBed.inject()` is deprecated in v15. <a href="https://v15.angular.io/guide/update-to-version-15#v15-dp-01" alt="Link to more information about this change">Read further</a>',
|
||||
'Update instances of `TestBed.inject()` that use an `InjectFlags` parameter to use an `InjectOptions` parameter. The `InjectFlags` parameter of `TestBed.inject()` is deprecated in v15. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-dp-01)',
|
||||
},
|
||||
{
|
||||
possibleIn: 1500,
|
||||
@@ -1797,7 +1802,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Medium,
|
||||
step: 'v15 ngModule in providedIn',
|
||||
action:
|
||||
'Using `providedIn: ngModule` for an `@Injectable` and `InjectionToken` is deprecated in v15. <a href="https://v15.angular.io/guide/update-to-version-15#v15-dp-04" alt="Link to more information about this change">Read further</a>',
|
||||
'Using `providedIn: ngModule` for an `@Injectable` and `InjectionToken` is deprecated in v15. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-dp-04)',
|
||||
},
|
||||
{
|
||||
possibleIn: 1500,
|
||||
@@ -1805,7 +1810,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Basic,
|
||||
step: 'v15 providedIn any',
|
||||
action:
|
||||
'Using `providedIn: \'any\'` for an `@Injectable` or `InjectionToken` is deprecated in v15. <a href="https://v15.angular.io/guide/update-to-version-15#v15-dp-05" alt="Link to more information about this change">Read further</a>',
|
||||
"Using `providedIn: 'any'` for an `@Injectable` or `InjectionToken` is deprecated in v15. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-dp-05)",
|
||||
},
|
||||
{
|
||||
possibleIn: 1500,
|
||||
@@ -1813,7 +1818,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Medium,
|
||||
step: 'v15 RouterLinkWithHref',
|
||||
action:
|
||||
'Update instances of the `RouterLinkWithHref`directive to use the `RouterLink` directive. The `RouterLinkWithHref` directive is deprecated in v15. <a href="https://v15.angular.io/guide/update-to-version-15#v15-dp-06" alt="Link to more information about this change">Read further</a>',
|
||||
'Update instances of the `RouterLinkWithHref`directive to use the `RouterLink` directive. The `RouterLinkWithHref` directive is deprecated in v15. [Read further](https://v15.angular.io/guide/update-to-version-15#v15-dp-06)',
|
||||
},
|
||||
{
|
||||
possibleIn: 1500,
|
||||
@@ -1822,7 +1827,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
material: true,
|
||||
step: 'v15 mat refactor',
|
||||
action:
|
||||
'In Angular Material v15, many of the components have been refactored to be based on the official Material Design Components for Web (MDC). This change affected the DOM and CSS classes of many components. <a href="https://rc.material.angular.dev/guide/mdc-migration" alt="Link to more information about this change">Read further</a>',
|
||||
'In Angular Material v15, many of the components have been refactored to be based on the official Material Design Components for Web (MDC). This change affected the DOM and CSS classes of many components. [Read further](https://rc.material.angular.dev/guide/mdc-migration)',
|
||||
},
|
||||
{
|
||||
possibleIn: 1500,
|
||||
@@ -2669,7 +2674,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
level: ApplicationComplexity.Basic,
|
||||
step: '20.0.0_update_nodejs_version',
|
||||
action:
|
||||
'Ensure your Node.js version is at least 20.11.1 and not v18 or v22.0-v22.10 before upgrading to Angular v20. Check https://angular.dev/reference/versions for the full list of supported Node.js versions.',
|
||||
'Ensure your Node.js version is at least 20.11.1 and not v18 or v22.0-v22.10 before upgrading to Angular v20. Check the [full list of supported Node.js versions](https://angular.dev/reference/versions).',
|
||||
},
|
||||
{
|
||||
possibleIn: 2000,
|
||||
@@ -2703,6 +2708,14 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
action:
|
||||
"Upgrade your project's TypeScript version to at least 5.8 before upgrading to Angular v20 to ensure compatibility.",
|
||||
},
|
||||
{
|
||||
possibleIn: 2000,
|
||||
necessaryAsOf: 2000,
|
||||
level: ApplicationComplexity.Medium,
|
||||
step: '20.0.0_set_moduleResolution_to_bundler',
|
||||
action:
|
||||
"Set `moduleResolution` to `'bundler'` in your `tsconfig.json`. Angular CLI's `ng update` migration applies this change automatically; if you upgrade manually or override the option in a base tsconfig, set it explicitly so imports of secondary entry-points such as `@angular/core/rxjs-interop` continue to resolve correctly.",
|
||||
},
|
||||
{
|
||||
possibleIn: 2000,
|
||||
necessaryAsOf: 2000,
|
||||
@@ -2912,4 +2925,12 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
action:
|
||||
'The `lastSuccessfulNavigation` property on the Router has been converted to a signal. To get its value, you now need to invoke it as a function: `router.lastSuccessfulNavigation()`.',
|
||||
},
|
||||
{
|
||||
possibleIn: 2100,
|
||||
necessaryAsOf: 2100,
|
||||
level: ApplicationComplexity.Medium,
|
||||
step: '21.0.0-configure-commonengine-allowed-hosts',
|
||||
action:
|
||||
"Starting `@angular/ssr` 21.1.5, if your application uses SSR with `CommonEngine`, set the `allowedHosts` option in your `server.ts` (for example, `new CommonEngine({allowedHosts: ['localhost', '*.yourdomain.com']})`). Without it, SSR silently falls back to client-side rendering. This requirement comes from security advisory [GHSA-x288-3778-4hhx](https://github.com/angular/angular-cli/security/advisories/GHSA-x288-3778-4hhx) (also backported to 20.3.17 and 19.2.21).",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
@use '@angular/docs/styles/media-queries' as mq;
|
||||
@use '@angular/docs/styles/links' as links;
|
||||
|
||||
$ver-dropdown-width: 200px;
|
||||
$ver-dropdown-width: clamp(165px, 20vw, 200px);
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
align-items: center;
|
||||
padding: var(--layout-padding) 0px;
|
||||
padding: var(--layout-padding);
|
||||
container: update-guide-page / inline-size;
|
||||
|
||||
.docs-viewer {
|
||||
@@ -172,7 +173,14 @@ h4 {
|
||||
}
|
||||
|
||||
// Code blocks are generable from the markdown, we need to opt-out of the scoping
|
||||
::ng-deep code {
|
||||
cursor: pointer;
|
||||
::ng-deep {
|
||||
code {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
// External links (rendered with target="_blank") get an "open in new" icon
|
||||
a[target='_blank'] {
|
||||
@include links.external-link-with-icon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import {provideHttpClientTesting} from '@angular/common/http/testing';
|
||||
import {By} from '@angular/platform-browser';
|
||||
|
||||
import UpdateComponent from './update.component';
|
||||
import {ApplicationComplexity} from './recommendations';
|
||||
import {ApplicationComplexity, RECOMMENDATIONS} from './recommendations';
|
||||
|
||||
describe('UpdateComponent', () => {
|
||||
let component: UpdateComponent;
|
||||
@@ -91,4 +91,14 @@ describe('UpdateComponent', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('RECOMMENDATIONS data', () => {
|
||||
it('should use Markdown links instead of raw <a> HTML tags', () => {
|
||||
for (const step of RECOMMENDATIONS) {
|
||||
expect(step.action)
|
||||
.withContext(`step "${step.step}" should use [text](url), not raw <a> HTML`)
|
||||
.not.toMatch(/<a\s/i);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,6 +17,20 @@ import {ActivatedRoute, Router} from '@angular/router';
|
||||
import {marked} from 'marked';
|
||||
import {MatSnackBar} from '@angular/material/snack-bar';
|
||||
|
||||
/**
|
||||
* Configure marked with a custom link renderer so external links in the
|
||||
* update guide open in a new tab, matching the convention applied elsewhere
|
||||
* in adev via the `ExternalLink` directive.
|
||||
*/
|
||||
marked.use({
|
||||
renderer: {
|
||||
link({href, title, text}) {
|
||||
const titleAttr = title ? ` title="${title}"` : '';
|
||||
return `<a href="${href}"${titleAttr} target="_blank" rel="noopener noreferrer">${text}</a>`;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
interface Option {
|
||||
id: keyof Step;
|
||||
name: string;
|
||||
@@ -108,7 +122,7 @@ export default class UpdateComponent {
|
||||
];
|
||||
protected from = this.versions.find((version) => version.name === '20.0')!;
|
||||
protected to = this.versions.find((version) => version.name === '21.0')!;
|
||||
protected futureVersion = 2100;
|
||||
protected futureVersion = 2200;
|
||||
|
||||
protected readonly steps: Step[] = RECOMMENDATIONS;
|
||||
|
||||
|
||||
@@ -496,6 +496,34 @@ export const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
|
||||
category: 'Signal Forms',
|
||||
status: 'new',
|
||||
},
|
||||
{
|
||||
label: 'Cross-field logic',
|
||||
path: 'guide/forms/signals/cross-field-logic',
|
||||
contentPath: 'guide/forms/signals/cross-field-logic',
|
||||
category: 'Signal Forms',
|
||||
status: 'new',
|
||||
},
|
||||
{
|
||||
label: 'Form submission',
|
||||
path: 'guide/forms/signals/form-submission',
|
||||
contentPath: 'guide/forms/signals/form-submission',
|
||||
category: 'Signal Forms',
|
||||
status: 'new',
|
||||
},
|
||||
{
|
||||
label: 'Schemas',
|
||||
path: 'guide/forms/signals/schemas',
|
||||
contentPath: 'guide/forms/signals/schemas',
|
||||
category: 'Signal Forms',
|
||||
status: 'new',
|
||||
},
|
||||
{
|
||||
label: 'Field metadata',
|
||||
path: 'guide/forms/signals/field-metadata',
|
||||
contentPath: 'guide/forms/signals/field-metadata',
|
||||
category: 'Signal Forms',
|
||||
status: 'new',
|
||||
},
|
||||
{
|
||||
label: 'Async operations',
|
||||
path: 'guide/forms/signals/async-operations',
|
||||
@@ -660,6 +688,7 @@ export const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
|
||||
path: 'guide/routing/testing',
|
||||
contentPath: 'guide/routing/testing',
|
||||
status: 'new',
|
||||
isCrossReferenced: true,
|
||||
},
|
||||
{
|
||||
label: 'Debugging tests',
|
||||
@@ -863,6 +892,7 @@ export const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
|
||||
label: 'Route transition animations',
|
||||
path: 'guide/routing/route-transition-animations',
|
||||
contentPath: 'guide/routing/route-transition-animations',
|
||||
isCrossReferenced: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -1042,16 +1072,15 @@ export const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
|
||||
},
|
||||
// TODO: create those guides
|
||||
// The signal debugging docs should also be added to the signal section
|
||||
// {
|
||||
// label: 'Signals',
|
||||
// path: 'tools/devtools/signals',
|
||||
// contentPath: 'tools/devtools/signals',
|
||||
// },
|
||||
// {
|
||||
// label: 'Router',
|
||||
// path: 'tools/devtools/router',
|
||||
// contentPath: 'tools/devtools/router',
|
||||
// }
|
||||
{
|
||||
label: 'Router Tree',
|
||||
path: 'tools/devtools/router',
|
||||
contentPath: 'tools/devtools/router',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="25" viewBox="0 -960 960 960" fill="#F637E3">
|
||||
<path d="M450.001-611.691v-32.386q-39.385-9.923-64.692-41.897-25.308-31.975-25.308-74.025 0-49.922 35.038-84.96 35.039-35.038 84.961-35.038t84.961 35.038q35.038 35.038 35.038 84.96 0 42.05-25.308 74.025-25.307 31.974-64.692 41.897v32.386l273.846 157.538q17.173 9.912 26.663 26.582 9.491 16.671 9.491 36.495v62.152q0 19.824-9.491 36.495-9.49 16.67-26.663 26.582L516.154-111.771q-17.203 9.846-36.217 9.846t-36.091-9.846L176.155-265.847q-17.173-9.912-26.663-26.582-9.491-16.671-9.491-36.495v-62.152q0-19.824 9.491-36.495 9.49-16.67 26.663-26.582l273.846-157.538Zm-6.155 364.537L200-387.461v58.537q0 3.078 1.539 5.962 1.538 2.885 4.615 4.808l267.692 154.692q3.077 1.923 6.154 1.923t6.154-1.923l267.692-154.692q3.077-1.923 4.615-4.808 1.539-2.884 1.539-5.962v-58.537L516.154-247.154q-17.203 9.847-36.217 9.847t-36.091-9.847Zm6.155-162.847V-542.77L250.46-427.691l223.386 128.846q3.077 1.924 6.154 1.924t6.154-1.924l223.001-128.846L509.999-542.77v132.769h-59.998ZM480-699.999q25 0 42.5-17.5t17.5-42.5q0-25-17.5-42.5t-42.5-17.5q-25 0-42.5 17.5t-17.5 42.5q0 25 17.5 42.5t42.5 17.5Zm-2.308 538.61Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
@@ -18,11 +18,11 @@ Here is a set of instructions to help LLMs generate correct code that follows An
|
||||
|
||||
## Rules Files
|
||||
|
||||
Several editors, such as <a href="https://studio.firebase.google.com?utm_source=adev&utm_medium=website&utm_campaign=BUILD_WITH_AI_ANGULAR&utm_term=angular_devrel&utm_content=build_with_ai_angular_firebase_studio">Firebase Studio</a> have rules files useful for providing critical context to LLMs.
|
||||
Several editors, such as <a href="https://studio.firebase.google.com?utm_source=adev&utm_medium=website&utm_campaign=BUILD_WITH_AI_ANGULAR&utm_term=angular_devrel&utm_content=build_with_ai_angular_firebase_studio" target="_blank">Firebase Studio</a> have rules files useful for providing critical context to LLMs.
|
||||
|
||||
| Environment/IDE | Rules File | Installation Instructions |
|
||||
| :------------------- | :--------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Firebase Studio | <a download href="/assets/context/airules.md" target="_blank">airules.md</a> | <a href="https://firebase.google.com/docs/studio/set-up-gemini#custom-instructions">Configure `airules.md`</a> |
|
||||
| Firebase Studio | <a download href="/assets/context/airules.md" target="_blank">airules.md</a> | <a href="https://firebase.google.com/docs/studio/set-up-gemini#custom-instructions" target="_blank">Configure `airules.md`</a> |
|
||||
| Copilot powered IDEs | <a download="copilot-instructions.md" href="/assets/context/guidelines.md" target="_blank">copilot-instructions.md</a> | <a href="https://code.visualstudio.com/docs/copilot/copilot-customization#_custom-instructions" target="_blank">Configure `.github/copilot-instructions.md`</a> |
|
||||
| Cursor | <a download href="/assets/context/angular-20.mdc" target="_blank">cursor.md</a> | <a href="https://docs.cursor.com/context/rules" target="_blank">Configure `cursorrules.md`</a> |
|
||||
| JetBrains IDEs | <a download href="/assets/context/guidelines.md" target="_blank">guidelines.md</a> | <a href="https://www.jetbrains.com/help/junie/customize-guidelines.html" target="_blank">Configure `guidelines.md`</a> |
|
||||
|
||||
@@ -59,7 +59,7 @@ Here are examples of how to build with Genkit and Angular:
|
||||
|
||||
Here is an example of how to build with Firebase AI Logic and Angular:
|
||||
|
||||
- [Firebase AI Logic x Angular Starter Kit](https://github.com/angular/examples/tree/main/vertex-ai-firebase-angular-example) - Use this starter-kit to build an e-commerce application with a chat agent that can perform tasks. Start here if you do not have experience building with Firebase AI Logic and Angular.
|
||||
- [Firebase AI Logic x Angular Starter Kit](https://github.com/angular/examples/tree/main/firebase-ai-logic-angular-example) - Use this starter-kit to build an e-commerce application with a chat agent that can perform tasks. Start here if you do not have experience building with Firebase AI Logic and Angular.
|
||||
|
||||
This example includes an [in-depth video walkthrough explaining the functionality and demonstrates how to add new features](https://youtube.com/live/4vfDz2al_BI).
|
||||
|
||||
@@ -79,7 +79,7 @@ When connecting to model providers, it is important to keep your API secrets saf
|
||||
|
||||
Your application's architecture determines which AI APIs and tools to choose. Specifically, choose based on whether or not your application is client-side or server-side. Tools such as Firebase AI Logic provide a secure connection to the model APIs for client-side code. If you want to use a different API than Firebase AI Logic or prefer to use a different model provider, consider creating a proxy-server or even [Cloud Functions for Firebase](https://firebase.google.com/docs/functions) to serve as a proxy and not expose your API keys.
|
||||
|
||||
For an example of connecting using a client-side app, see the code: [Firebase AI Logic Angular example repository](https://github.com/angular/examples/tree/main/vertex-ai-firebase-angular-example).
|
||||
For an example of connecting using a client-side app, see the code: [Firebase AI Logic Angular example repository](https://github.com/angular/examples/tree/main/firebase-ai-logic-angular-example).
|
||||
|
||||
For server-side connections to model APIs that require API keys, prefer using a secrets manager or environment variable, not `environments.ts`. You should follow standard best practices for securing API keys and credentials. Firebase now provides a new secrets manager with the latest updates from Firebase App Hosting. To learn more, [check out the official documentation](https://firebase.google.com/docs/app-hosting/configure).
|
||||
|
||||
@@ -91,7 +91,7 @@ If you want to build agentic workflows, where agents are able to act and use too
|
||||
|
||||
Tool calling further enhances your web apps by expanding your AI integration further than a question and answer style chat bot. In fact, you can empower your model to request function calls using the function calling API of your model provider. The available tools can be used to perform more complex actions within the context of your application.
|
||||
|
||||
In the [e-commerce example](https://github.com/angular/examples/blob/main/vertex-ai-firebase-angular-example/src/app/ai.service.ts#L88) of the [Angular examples repository](https://github.com/angular/examples), the LLM requests to make calls to functions for inventory in order to gain the necessary context to perform more complex tasks such as calculating how much a group of items in the store will cost. The scope of the available API is up to you as a developer just as is whether or not to call a function requested by the LLM. You remain in control of the flow of execution. You can expose specific functions of a service for example but not all functions of that service.
|
||||
In the [e-commerce example](https://github.com/angular/examples/blob/main/firebase-ai-logic-angular-example/src/app/ai.service.ts#L88) of the [Angular examples repository](https://github.com/angular/examples), the LLM requests to make calls to functions for inventory in order to gain the necessary context to perform more complex tasks such as calculating how much a group of items in the store will cost. The scope of the available API is up to you as a developer just as is whether or not to call a function requested by the LLM. You remain in control of the flow of execution. You can expose specific functions of a service for example but not all functions of that service.
|
||||
|
||||
### Handling non-deterministic responses
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"branchName": "refs/heads/21.2.x",
|
||||
"sha": "0707c69d63e9962bab077dbc45770c25c8d26b7c"
|
||||
"sha": "887bb70d938ed041e4d1d61f6683c995cb91709c"
|
||||
}
|
||||
@@ -255,7 +255,7 @@
|
||||
"readonly",
|
||||
"input"
|
||||
],
|
||||
"description": "The value of the menu item, used as the default aria-label",
|
||||
"description": "The value of the menu item.",
|
||||
"jsdocTags": [],
|
||||
"inputAlias": "value",
|
||||
"isRequiredInput": true
|
||||
@@ -413,7 +413,7 @@
|
||||
"name": "V"
|
||||
}
|
||||
],
|
||||
"description": "An item in a Menu.\n\n`ngMenuItem` directives can be used in `ngMenu` and `ngMenuBar` to represent a choice\nor action a user can take. They can also act as triggers for sub-menus.\n\n```html\n<div ngMenu (itemSelected)=\"doAction()\">\n <div ngMenuItem >Action Item</div>\n <div ngMenuItem [submenu]=\"anotherMenu\">Submenu Trigger</div>\n</div>\n```",
|
||||
"description": "An item in a Menu.\n\n`ngMenuItem` directives can be used in `ngMenu` and `ngMenuBar` to represent a choice\nor action a user can take. They can also act as triggers for sub-menus.\n\n```html\n<div ngMenu (itemSelected)=\"doAction()\">\n <div ngMenuItem>Action Item</div>\n <div ngMenuItem [submenu]=\"anotherMenu\">Submenu Trigger</div>\n</div>\n```",
|
||||
"jsdocTags": [
|
||||
{
|
||||
"name": "developerPreview",
|
||||
@@ -428,7 +428,7 @@
|
||||
"comment": "[MenuBar](guide/aria/menubar)"
|
||||
}
|
||||
],
|
||||
"rawComment": "/**\n * An item in a Menu.\n *\n * `ngMenuItem` directives can be used in `ngMenu` and `ngMenuBar` to represent a choice\n * or action a user can take. They can also act as triggers for sub-menus.\n *\n * ```html\n * <div ngMenu (itemSelected)=\"doAction()\">\n * <div ngMenuItem >Action Item</div>\n * <div ngMenuItem [submenu]=\"anotherMenu\">Submenu Trigger</div>\n * </div>\n * ```\n *\n * @developerPreview 21.0\n *\n * @see [Menu](guide/aria/menu)\n * @see [MenuBar](guide/aria/menubar)\n */",
|
||||
"rawComment": "/**\n * An item in a Menu.\n *\n * `ngMenuItem` directives can be used in `ngMenu` and `ngMenuBar` to represent a choice\n * or action a user can take. They can also act as triggers for sub-menus.\n *\n * ```html\n * <div ngMenu (itemSelected)=\"doAction()\">\n * <div ngMenuItem>Action Item</div>\n * <div ngMenuItem [submenu]=\"anotherMenu\">Submenu Trigger</div>\n * </div>\n * ```\n *\n * @developerPreview 21.0\n *\n * @see [Menu](guide/aria/menu)\n * @see [MenuBar](guide/aria/menubar)\n */",
|
||||
"implements": [],
|
||||
"isStandalone": true,
|
||||
"selector": "[ngMenuItem]",
|
||||
@@ -441,7 +441,7 @@
|
||||
"source": {
|
||||
"filePath": "/src/aria/menu/menu-item.ts",
|
||||
"startLine": 34,
|
||||
"endLine": 109
|
||||
"endLine": 108
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -792,7 +792,7 @@
|
||||
"source": {
|
||||
"filePath": "/src/aria/menu/menu.ts",
|
||||
"startLine": 58,
|
||||
"endLine": 194
|
||||
"endLine": 201
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -63,6 +63,9 @@ For example:
|
||||
|
||||
For full details of these and other tools, see the [Angular CDK accessibility overview](https://material.angular.dev/cdk/a11y/overview).
|
||||
|
||||
For custom-styled components that need reusable WAI-ARIA interaction patterns, [Angular Aria](guide/aria/overview) provides headless directives for patterns such as accordion, combobox, listbox, menu, tabs, and toolbar.
|
||||
These directives handle keyboard interaction, ARIA attributes, focus management, and screen reader support while letting you provide the HTML structure and styling for your application.
|
||||
|
||||
### Augmenting native elements
|
||||
|
||||
Native HTML elements capture several standard interaction patterns that are important to accessibility.
|
||||
|
||||
@@ -6,9 +6,9 @@ Keeping your Angular application up-to-date enables you to take advantage of lea
|
||||
|
||||
This document contains information and resources to help you keep your Angular applications and libraries up-to-date.
|
||||
|
||||
For information about our versioning policy and practices —including support and deprecation practices, as well as the release schedule— see [Angular versioning and releases](reference/releases 'Angular versioning and releases').
|
||||
For information about our versioning policy and practices — including support and deprecation practices, as well as the release schedule — see [Angular versioning and releases](reference/releases 'Angular versioning and releases').
|
||||
|
||||
HELPFUL: If you are currently using AngularJS, see [Upgrading from AngularJS](https://angular.io/guide/upgrade 'Upgrading from Angular JS').
|
||||
HELPFUL: If you are currently using AngularJS, see [Upgrading from AngularJS](https://angular.io/guide/upgrade 'Upgrading from AngularJS').
|
||||
_AngularJS_ is the name for all v1.x versions of Angular.
|
||||
|
||||
## Getting notified of new releases
|
||||
@@ -30,7 +30,7 @@ To check your application's version of Angular use the `ng version` command from
|
||||
The most recent stable released version of Angular appears [on npm](https://www.npmjs.com/package/@angular/core 'Angular on npm') under "Version." For example, `16.2.4`.
|
||||
|
||||
You can also find the most current version of Angular by using the CLI command [`ng update`](cli/update).
|
||||
By default, [`ng update`](cli/update)(without additional arguments) lists the updates that are available to you.
|
||||
By default, [`ng update`](cli/update) (without additional arguments) lists the updates that are available to you.
|
||||
|
||||
## Updating your environment and apps
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"branchName": "refs/heads/21.2.x",
|
||||
"sha": "d0d970927ed7daa3a7072ef211d4b85c46c30eef"
|
||||
"sha": "4e2c69bca091e2218fd456afe797826f033a76f2"
|
||||
}
|
||||
@@ -482,19 +482,6 @@
|
||||
"endLine": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "CDK_DROP_LIST_GROUP",
|
||||
"type": "any",
|
||||
"entryType": "constant",
|
||||
"rawComment": "/**\n * Injection token that can be used to reference instances of `CdkDropListGroup`. It serves as\n * alternative token to the actual `CdkDropListGroup` class which could cause unnecessary\n * retention of the class and its directive metadata.\n */",
|
||||
"description": "Injection token that can be used to reference instances of `CdkDropListGroup`. It serves as\nalternative token to the actual `CdkDropListGroup` class which could cause unnecessary\nretention of the class and its directive metadata.",
|
||||
"jsdocTags": [],
|
||||
"source": {
|
||||
"filePath": "/src/cdk/drag-drop/directives/drop-list-group.ts",
|
||||
"startLine": 16,
|
||||
"endLine": 18
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "CdkDragRelease",
|
||||
"entryType": "interface",
|
||||
@@ -533,6 +520,19 @@
|
||||
"endLine": 26
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "CDK_DROP_LIST_GROUP",
|
||||
"type": "any",
|
||||
"entryType": "constant",
|
||||
"rawComment": "/**\n * Injection token that can be used to reference instances of `CdkDropListGroup`. It serves as\n * alternative token to the actual `CdkDropListGroup` class which could cause unnecessary\n * retention of the class and its directive metadata.\n */",
|
||||
"description": "Injection token that can be used to reference instances of `CdkDropListGroup`. It serves as\nalternative token to the actual `CdkDropListGroup` class which could cause unnecessary\nretention of the class and its directive metadata.",
|
||||
"jsdocTags": [],
|
||||
"source": {
|
||||
"filePath": "/src/cdk/drag-drop/directives/drop-list-group.ts",
|
||||
"startLine": 17,
|
||||
"endLine": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "CDK_DRAG_PLACEHOLDER",
|
||||
"type": "any",
|
||||
@@ -559,70 +559,6 @@
|
||||
"endLine": 25
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "CdkDropListGroup",
|
||||
"isAbstract": false,
|
||||
"entryType": "undecorated_class",
|
||||
"members": [
|
||||
{
|
||||
"name": "disabled",
|
||||
"type": "boolean",
|
||||
"memberType": "property",
|
||||
"memberTags": [],
|
||||
"description": "Whether starting a dragging sequence from inside this group is disabled.",
|
||||
"jsdocTags": []
|
||||
},
|
||||
{
|
||||
"name": "ngOnDestroy",
|
||||
"signatures": [
|
||||
{
|
||||
"name": "ngOnDestroy",
|
||||
"entryType": "function",
|
||||
"description": "",
|
||||
"generics": [],
|
||||
"isNewType": false,
|
||||
"jsdocTags": [],
|
||||
"params": [],
|
||||
"rawComment": "",
|
||||
"returnType": "void"
|
||||
}
|
||||
],
|
||||
"implementation": {
|
||||
"params": [],
|
||||
"isNewType": false,
|
||||
"returnType": "void",
|
||||
"generics": [],
|
||||
"name": "ngOnDestroy",
|
||||
"description": "",
|
||||
"entryType": "function",
|
||||
"jsdocTags": [],
|
||||
"rawComment": ""
|
||||
},
|
||||
"entryType": "function",
|
||||
"description": "",
|
||||
"jsdocTags": [],
|
||||
"rawComment": "",
|
||||
"memberType": "method",
|
||||
"memberTags": []
|
||||
}
|
||||
],
|
||||
"generics": [
|
||||
{
|
||||
"name": "T"
|
||||
}
|
||||
],
|
||||
"description": "Declaratively connects sibling `cdkDropList` instances together. All of the `cdkDropList`\nelements that are placed inside a `cdkDropListGroup` will be connected to each other\nautomatically. Can be used as an alternative to the `cdkDropListConnectedTo` input\nfrom `cdkDropList`.",
|
||||
"jsdocTags": [],
|
||||
"rawComment": "/**\n * Declaratively connects sibling `cdkDropList` instances together. All of the `cdkDropList`\n * elements that are placed inside a `cdkDropListGroup` will be connected to each other\n * automatically. Can be used as an alternative to the `cdkDropListConnectedTo` input\n * from `cdkDropList`.\n */",
|
||||
"implements": [
|
||||
"OnDestroy"
|
||||
],
|
||||
"source": {
|
||||
"filePath": "/src/cdk/drag-drop/directives/drop-list-group.ts",
|
||||
"startLine": 26,
|
||||
"endLine": 42
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "CdkDragPlaceholder",
|
||||
"isAbstract": false,
|
||||
@@ -706,6 +642,70 @@
|
||||
"endLine": 44
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "CdkDropListGroup",
|
||||
"isAbstract": false,
|
||||
"entryType": "undecorated_class",
|
||||
"members": [
|
||||
{
|
||||
"name": "disabled",
|
||||
"type": "boolean",
|
||||
"memberType": "property",
|
||||
"memberTags": [],
|
||||
"description": "Whether starting a dragging sequence from inside this group is disabled.",
|
||||
"jsdocTags": []
|
||||
},
|
||||
{
|
||||
"name": "ngOnDestroy",
|
||||
"signatures": [
|
||||
{
|
||||
"name": "ngOnDestroy",
|
||||
"entryType": "function",
|
||||
"description": "",
|
||||
"generics": [],
|
||||
"isNewType": false,
|
||||
"jsdocTags": [],
|
||||
"params": [],
|
||||
"rawComment": "",
|
||||
"returnType": "void"
|
||||
}
|
||||
],
|
||||
"implementation": {
|
||||
"params": [],
|
||||
"isNewType": false,
|
||||
"returnType": "void",
|
||||
"generics": [],
|
||||
"name": "ngOnDestroy",
|
||||
"description": "",
|
||||
"entryType": "function",
|
||||
"jsdocTags": [],
|
||||
"rawComment": ""
|
||||
},
|
||||
"entryType": "function",
|
||||
"description": "",
|
||||
"jsdocTags": [],
|
||||
"rawComment": "",
|
||||
"memberType": "method",
|
||||
"memberTags": []
|
||||
}
|
||||
],
|
||||
"generics": [
|
||||
{
|
||||
"name": "T"
|
||||
}
|
||||
],
|
||||
"description": "Declaratively connects sibling `cdkDropList` instances together. All of the `cdkDropList`\nelements that are placed inside a `cdkDropListGroup` will be connected to each other\nautomatically. Can be used as an alternative to the `cdkDropListConnectedTo` input\nfrom `cdkDropList`.",
|
||||
"jsdocTags": [],
|
||||
"rawComment": "/**\n * Declaratively connects sibling `cdkDropList` instances together. All of the `cdkDropList`\n * elements that are placed inside a `cdkDropListGroup` will be connected to each other\n * automatically. Can be used as an alternative to the `cdkDropListConnectedTo` input\n * from `cdkDropList`.\n */",
|
||||
"implements": [
|
||||
"OnDestroy"
|
||||
],
|
||||
"source": {
|
||||
"filePath": "/src/cdk/drag-drop/directives/drop-list-group.ts",
|
||||
"startLine": 27,
|
||||
"endLine": 43
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "CdkDragPreview",
|
||||
"isAbstract": false,
|
||||
@@ -6294,11 +6294,11 @@
|
||||
"@angular/core"
|
||||
],
|
||||
[
|
||||
"OnDestroy",
|
||||
"Input",
|
||||
"@angular/core"
|
||||
],
|
||||
[
|
||||
"Input",
|
||||
"OnDestroy",
|
||||
"@angular/core"
|
||||
],
|
||||
[
|
||||
@@ -6422,11 +6422,11 @@
|
||||
"@angular/cdk/drag-drop"
|
||||
],
|
||||
[
|
||||
"CDK_DROP_LIST_GROUP",
|
||||
"CdkDragRelease",
|
||||
"@angular/cdk/drag-drop"
|
||||
],
|
||||
[
|
||||
"CdkDragRelease",
|
||||
"CDK_DROP_LIST_GROUP",
|
||||
"@angular/cdk/drag-drop"
|
||||
],
|
||||
[
|
||||
@@ -6438,11 +6438,11 @@
|
||||
"@angular/cdk/drag-drop"
|
||||
],
|
||||
[
|
||||
"CdkDropListGroup",
|
||||
"CdkDragPlaceholder",
|
||||
"@angular/cdk/drag-drop"
|
||||
],
|
||||
[
|
||||
"CdkDragPlaceholder",
|
||||
"CdkDropListGroup",
|
||||
"@angular/cdk/drag-drop"
|
||||
],
|
||||
[
|
||||
@@ -6593,10 +6593,6 @@
|
||||
"DropListOrientation",
|
||||
"@angular/cdk/drag-drop"
|
||||
],
|
||||
[
|
||||
"CDK_DROP_LIST_GROUP",
|
||||
"@angular/cdk/drag-drop"
|
||||
],
|
||||
[
|
||||
"CdkDragRelease",
|
||||
"@angular/cdk/drag-drop"
|
||||
@@ -6609,6 +6605,10 @@
|
||||
"CdkDragRelease.event",
|
||||
"@angular/cdk/drag-drop"
|
||||
],
|
||||
[
|
||||
"CDK_DROP_LIST_GROUP",
|
||||
"@angular/cdk/drag-drop"
|
||||
],
|
||||
[
|
||||
"CDK_DRAG_PLACEHOLDER",
|
||||
"@angular/cdk/drag-drop"
|
||||
@@ -6617,18 +6617,6 @@
|
||||
"CDK_DRAG_PREVIEW",
|
||||
"@angular/cdk/drag-drop"
|
||||
],
|
||||
[
|
||||
"CdkDropListGroup",
|
||||
"@angular/cdk/drag-drop"
|
||||
],
|
||||
[
|
||||
"CdkDropListGroup.disabled",
|
||||
"@angular/cdk/drag-drop"
|
||||
],
|
||||
[
|
||||
"CdkDropListGroup.ngOnDestroy",
|
||||
"@angular/cdk/drag-drop"
|
||||
],
|
||||
[
|
||||
"CdkDragPlaceholder",
|
||||
"@angular/cdk/drag-drop"
|
||||
@@ -6645,6 +6633,18 @@
|
||||
"CdkDragPlaceholder.ngOnDestroy",
|
||||
"@angular/cdk/drag-drop"
|
||||
],
|
||||
[
|
||||
"CdkDropListGroup",
|
||||
"@angular/cdk/drag-drop"
|
||||
],
|
||||
[
|
||||
"CdkDropListGroup.disabled",
|
||||
"@angular/cdk/drag-drop"
|
||||
],
|
||||
[
|
||||
"CdkDropListGroup.ngOnDestroy",
|
||||
"@angular/cdk/drag-drop"
|
||||
],
|
||||
[
|
||||
"CdkDragPreview",
|
||||
"@angular/cdk/drag-drop"
|
||||
|
||||
@@ -37,7 +37,7 @@ The `outputToObservable` function lets you create an RxJS observable from a comp
|
||||
import {outputToObservable} from '@angular/core/rxjs-interop';
|
||||
|
||||
@Component(/*...*/)
|
||||
class CustomSlider {
|
||||
class CustomSlider {
|
||||
valueChange = output<number>();
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ For example, an asset group that matches `/foo.js` should appear before one that
|
||||
Each asset group specifies both a group of resources and a policy that governs them.
|
||||
This policy determines when the resources are fetched and what happens when changes are detected.
|
||||
|
||||
Asset groups follow the Typescript interface shown here:
|
||||
Asset groups follow the TypeScript interface shown here:
|
||||
|
||||
```ts
|
||||
interface AssetGroup {
|
||||
@@ -179,7 +179,7 @@ The first data group that matches the requested resource handles the request.
|
||||
It is recommended that you put the more specific data groups higher in the list.
|
||||
For example, a data group that matches `/api/foo.json` should appear before one that matches `/api/*.json`.
|
||||
|
||||
Data groups follow this Typescript interface:
|
||||
Data groups follow this TypeScript interface:
|
||||
|
||||
```ts
|
||||
export interface DataGroup {
|
||||
|
||||
@@ -283,7 +283,7 @@ When the service worker's request for `ngsw.json` returns a `404`, then the serv
|
||||
|
||||
<!-- vale Angular.Google_Acronyms = NO -->
|
||||
|
||||
A small script, `safety-worker.js`, is also included in the `@angular/service-worker` NPM package.
|
||||
A small script, `safety-worker.js`, is also included in the `@angular/service-worker` npm package.
|
||||
When loaded, it un-registers itself from the browser and removes the service worker caches.
|
||||
This script can be used as a last resort to get rid of unwanted service workers already installed on client pages.
|
||||
|
||||
|
||||
@@ -22,16 +22,4 @@ Angular v21 is being delivered to you as a brand new release adventure. With mod
|
||||
- Your first look at Signal Forms, our new streamlined, signal-based approach to forms in Angular
|
||||
- Exciting new details about the Angular Aria package
|
||||
|
||||
<div style="display: block; width: 80%; margin: 0 auto; margin-top: 20px;">
|
||||
<iframe
|
||||
credentialless
|
||||
width="560"
|
||||
height="315"
|
||||
src="https://www.youtube.com/embed/DDAHORVzQ5g?si=B9Uv5vXzIKJfcLGr"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
referrerpolicy="strict-origin-when-cross-origin"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
</div>
|
||||
<docs-video src="https://www.youtube.com/embed/DDAHORVzQ5g?si=B9Uv5vXzIKJfcLGr" title="Angular v21 Developer Event"/>
|
||||
|
||||
@@ -10,9 +10,9 @@ This sample comes from the Angular documentation's "[Example Angular Internation
|
||||
|
||||
> See the scripts in `package.json` for an explanation of these commands.
|
||||
|
||||
## Run in Stackblitz
|
||||
## Run in StackBlitz
|
||||
|
||||
Stackblitz compiles and runs the English version by default.
|
||||
StackBlitz compiles and runs the English version by default.
|
||||
|
||||
To see the example translate to French with Angular i18n:
|
||||
|
||||
@@ -24,4 +24,4 @@ To see the example translate to French with Angular i18n:
|
||||
}
|
||||
```
|
||||
|
||||
1. Click the "Fork" button in the stackblitz header. That makes a new copy for you with this change and re-runs the example in French.
|
||||
1. Click the "Fork" button in the StackBlitz header. That makes a new copy for you with this change and re-runs the example in French.
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ export class ProfileEditorComponent {
|
||||
// #enddocregion add-alias
|
||||
// #docregion on-submit
|
||||
onSubmit() {
|
||||
// TODO: Use EventEmitter with form value
|
||||
// TODO: Use output() with form value
|
||||
console.warn(this.profileForm.value);
|
||||
}
|
||||
// #enddocregion on-submit
|
||||
|
||||
@@ -17,12 +17,12 @@ The functions that control complex animation sequences are:
|
||||
|
||||
## The query() function
|
||||
|
||||
Most complex animations rely on the `query()` function to find child elements and apply animations to them, basic examples of such are:
|
||||
Most complex animations rely on the `query()` function to find child elements and apply animations to them. Basic examples include:
|
||||
|
||||
| Examples | Details |
|
||||
| :------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `query()` followed by `animate()` | Used to query simple HTML elements and directly apply animations to them. |
|
||||
| `query()` followed by `animateChild()` | Used to query child elements, which themselves have animations metadata applied to them and trigger such animation \(which would be otherwise be blocked by the current/parent element's animation\). |
|
||||
| Examples | Details |
|
||||
| :------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `query()` followed by `animate()` | Used to query simple HTML elements and directly apply animations to them. |
|
||||
| `query()` followed by `animateChild()` | Used to query child elements, which themselves have animation metadata applied to them and trigger such animations \(which would otherwise be blocked by the current/parent element's animation\). |
|
||||
|
||||
The first argument of `query()` is a [css selector](https://developer.mozilla.org/docs/Web/CSS/CSS_Selectors) string which can also contain the following Angular-specific tokens:
|
||||
|
||||
@@ -43,7 +43,7 @@ You can also see an illustration of this in the animations example \(introduced
|
||||
|
||||
## Animate multiple elements using query() and stagger() functions
|
||||
|
||||
After having queried child elements via `query()`, the `stagger()` function lets you define a timing gap between each queried item that is animated and thus animates elements with a delay between them.
|
||||
After querying child elements via `query()`, the `stagger()` function lets you define a timing gap between each item, animating elements with a delay between them.
|
||||
|
||||
The following example demonstrates how to use the `query()` and `stagger()` functions to animate a list \(of heroes\) adding each in sequence, with a slight delay, from top to bottom.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ CSS offers a robust set of tools for you to create beautiful and engaging animat
|
||||
|
||||
## How to write animations in native CSS
|
||||
|
||||
If you've never written any native CSS animations, there are a number of excellent guides to get you started. Here's a few of them:
|
||||
If you've never written any native CSS animations, there are a number of excellent guides to get you started. Here are a few of them:
|
||||
[MDN's CSS Animations guide](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animations/Using_CSS_animations)
|
||||
[W3Schools CSS3 Animations guide](https://www.w3schools.com/css/css3_animations.asp)
|
||||
[The Complete CSS Animations Tutorial](https://www.lambdatest.com/blog/css-animations-tutorial/)
|
||||
@@ -14,7 +14,7 @@ and a couple of videos:
|
||||
[Learn CSS Animation in 9 Minutes](https://www.youtube.com/watch?v=z2LQYsZhsFw)
|
||||
[Net Ninja CSS Animation Tutorial Playlist](https://www.youtube.com/watch?v=jgw82b5Y2MU&list=PL4cUxeGkcC9iGYgmEd2dm3zAKzyCGDtM5)
|
||||
|
||||
Check some of these various guides and tutorials out, and then come back to this guide.
|
||||
Check out some of these guides and tutorials, then come back to this guide.
|
||||
|
||||
## Creating Reusable Animations
|
||||
|
||||
@@ -28,7 +28,7 @@ Adding the class `animated-class` to an element would trigger the animation on t
|
||||
|
||||
### Animating State and Styles
|
||||
|
||||
You may want to animate between two different states, for example when an element is opened or closed. You can accomplish this by using CSS classes either using a keyframe animation or transition styling.
|
||||
You may want to animate between two different states, for example when an element is opened or closed. You can accomplish this by using CSS classes, either with a keyframe animation or transition styling.
|
||||
|
||||
<docs-code header="animations.css" path="adev/src/content/examples/animations/src/app/animations.css" region="animation-states"/>
|
||||
|
||||
@@ -38,7 +38,7 @@ You can see similar examples in the template guide for [animating styles directl
|
||||
|
||||
### Transitions, Timing, and Easing
|
||||
|
||||
Animating often requires adjusting timing, delays and easeing behaviors. This can be done using several css properties or shorthand properties.
|
||||
Animating often requires adjusting timing, delays, and easing behaviors. This can be done using several css properties or shorthand properties.
|
||||
|
||||
Specify `animation-duration`, `animation-delay`, and `animation-timing-function` for a keyframe animation in CSS, or alternatively use the `animation` shorthand property.
|
||||
|
||||
@@ -62,7 +62,7 @@ Animations can be triggered by toggling CSS styles or classes. Once a class is p
|
||||
|
||||
### Animating Auto Height
|
||||
|
||||
You can use css-grid to animate to auto height.
|
||||
You can use CSS Grid to animate to auto height.
|
||||
|
||||
<docs-code-multifile preview path="adev/src/content/examples/animations/src/app/native-css/auto-height.ts">
|
||||
<docs-code header="auto-height.ts" path="adev/src/content/examples/animations/src/app/native-css/auto-height.ts" />
|
||||
@@ -70,7 +70,7 @@ You can use css-grid to animate to auto height.
|
||||
<docs-code header="auto-height.css" path="adev/src/content/examples/animations/src/app/native-css/auto-height.css" />
|
||||
</docs-code-multifile>
|
||||
|
||||
If you don't have to worry about supporting all browsers, you can also check out `calc-size()`, which is the true solution to animating auto height. See [MDN's docs](https://developer.mozilla.org/en-US/docs/Web/CSS/calc-size) and (this tutorial)[https://frontendmasters.com/blog/one-of-the-boss-battles-of-css-is-almost-won-transitioning-to-auto/] for more information.
|
||||
If you don't have to worry about supporting all browsers, you can also check out `calc-size()`, which is the true solution to animating auto height. See [MDN's docs](https://developer.mozilla.org/en-US/docs/Web/CSS/calc-size) and [this tutorial](https://frontendmasters.com/blog/one-of-the-boss-battles-of-css-is-almost-won-transitioning-to-auto/) for more information.
|
||||
|
||||
### Animate entering and leaving a view
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# Animating your applications with `animate.enter` and `animate.leave`
|
||||
|
||||
Well-designed animations can make your application more fun and straightforward to use, but they aren't just cosmetic.
|
||||
Animations can improve your application and user experience in a number of ways:
|
||||
Well-designed animations can make your application more intuitive and engaging, but they aren't just cosmetic.
|
||||
Animations can improve your application and the user experience in a number of ways:
|
||||
|
||||
- Without animations, web page transitions can seem abrupt and jarring
|
||||
- Motion greatly enhances the user experience, so animations give users a chance to detect the application's response to their actions
|
||||
- Good animations can smoothly direct the user's attention throughout a workflow
|
||||
|
||||
Angular provides `animate.enter` and `animate.leave` to animate your application's elements. These two features apply enter and leave CSS classes at the appropriate times or call functions to apply animations from third party libraries. `animate.enter` and `animate.leave` are not directives. They are special API supported directly by the Angular compiler. They can be used on elements directly and can also be used as a host binding.
|
||||
Angular provides `animate.enter` and `animate.leave` to animate your application's elements. These two features apply enter and leave CSS classes at the appropriate times or call functions to apply animations from third party libraries. `animate.enter` and `animate.leave` are not directives. They are special API supported directly by the Angular compiler. They can be used directly on elements and also as a host binding.
|
||||
|
||||
## `animate.enter`
|
||||
|
||||
@@ -19,7 +19,7 @@ You can use `animate.enter` to animate elements as they _enter_ the DOM. You can
|
||||
<docs-code header="enter.css" path="adev/src/content/examples/animations/src/app/enter-and-leave/enter.css"/>
|
||||
</docs-code-multifile>
|
||||
|
||||
When the animation completes, Angular removes the class or classes that you specified in `animate.enter` from the DOM. Animation classes are only be present while the animation is active.
|
||||
When the animation completes, Angular removes the class or classes that you specified in `animate.enter` from the DOM. Animation classes are only present while the animation is active.
|
||||
|
||||
NOTE: When using multiple keyframe animations or transition properties on an element, Angular removes all classes only _after_ the longest animation has completed.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ The `@angular/animations` package is deprecated as of v20.2, which also introduc
|
||||
|
||||
## How to write animations in native CSS
|
||||
|
||||
If you've never written any native CSS animations, there are a number of excellent guides to get you started. Here's a few of them:
|
||||
If you've never written any native CSS animations, there are a number of excellent guides to get you started. Here are a few of them:
|
||||
[MDN's CSS Animations guide](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animations/Using_CSS_animations)
|
||||
[W3Schools CSS3 Animations guide](https://www.w3schools.com/css/css3_animations.asp)
|
||||
[The Complete CSS Animations Tutorial](https://www.lambdatest.com/blog/css-animations-tutorial/)
|
||||
@@ -14,7 +14,7 @@ and a couple of videos:
|
||||
[Learn CSS Animation in 9 Minutes](https://www.youtube.com/watch?v=z2LQYsZhsFw)
|
||||
[Net Ninja CSS Animation Tutorial Playlist](https://www.youtube.com/watch?v=jgw82b5Y2MU&list=PL4cUxeGkcC9iGYgmEd2dm3zAKzyCGDtM5)
|
||||
|
||||
Check some of these various guides and tutorials out, and then come back to this guide.
|
||||
Check out some of these guides and tutorials, then come back to this guide.
|
||||
|
||||
## Creating Reusable Animations
|
||||
|
||||
@@ -40,7 +40,7 @@ The animations package allowed you to define various states using the [`state()`
|
||||
|
||||
<docs-code header="open-close.ts" path="adev/src/content/examples/animations/src/app/open-close.ts" region="state1"/>
|
||||
|
||||
This same behavior can be accomplished natively by using CSS classes either using a keyframe animation or transition styling.
|
||||
This same behavior can be accomplished natively by using CSS classes, either with a keyframe animation or transition styling.
|
||||
|
||||
#### With Native CSS
|
||||
|
||||
@@ -102,7 +102,7 @@ The animations package offers the ability to animate things that have been histo
|
||||
<docs-code header="auto-height.css" path="adev/src/content/examples/animations/src/app/animations-package/auto-height.css" />
|
||||
</docs-code-multifile>
|
||||
|
||||
You can use css-grid to animate to auto height.
|
||||
You can use CSS Grid to animate to auto height.
|
||||
|
||||
#### With Native CSS
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
IMPORTANT: The `@angular/animations` package is now deprecated. The Angular team recommends using native CSS with `animate.enter` and `animate.leave` for animations for all new code. Learn more at the new enter and leave [animation guide](guide/animations). Also see [Migrating away from Angular's Animations package](guide/animations/migration) to learn how you can start migrating to pure CSS animations in your apps.
|
||||
|
||||
Animation provides the illusion of motion: HTML elements change styling over time.
|
||||
Well-designed animations can make your application more fun and straightforward to use, but they aren't just cosmetic.
|
||||
Animations can improve your application and user experience in a number of ways:
|
||||
Animation provides the illusion of motion: HTML elements change styles over time.
|
||||
Well-designed animations can make your application more intuitive and engaging, but they aren't just cosmetic.
|
||||
Animations can improve your application and the user experience in a number of ways:
|
||||
|
||||
- Without animations, web page transitions can seem abrupt and jarring
|
||||
- Motion greatly enhances the user experience, so animations give users a chance to detect the application's response to their actions
|
||||
@@ -70,7 +70,7 @@ You put the trigger that defines an animation within the `animations` metadata p
|
||||
Let's animate a transition that changes a single HTML element from one state to another.
|
||||
For example, you can specify that a button displays either **Open** or **Closed** based on the user's last action.
|
||||
When the button is in the `open` state, it's visible and yellow.
|
||||
When it's the `closed` state, it's translucent and blue.
|
||||
When it's in the `closed` state, it's translucent and blue.
|
||||
|
||||
In HTML, these attributes are set using ordinary CSS styles such as color and opacity.
|
||||
In Angular, use the `style()` function to specify a set of CSS styles for use with animations.
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
IMPORTANT: The `@angular/animations` package is now deprecated. The Angular team recommends using native CSS with `animate.enter` and `animate.leave` for animations for all new code. Learn more at the new enter and leave [animation guide](guide/animations). Also see [Migrating away from Angular's Animations package](guide/animations/migration) to learn how you can start migrating to pure CSS animations in your apps.
|
||||
|
||||
This topic provides some examples of how to create reusable animations.
|
||||
This topic provides examples of how to create reusable animations.
|
||||
|
||||
## Create reusable animations
|
||||
|
||||
To create a reusable animation, use the [`animation()`](api/animations/animation) function to define an animation in a separate `.ts` file and declare this animation definition as a `const` export variable.
|
||||
You can then import and reuse this animation in any of your application components using the [`useAnimation()`](api/animations/useAnimation) function.
|
||||
You can then import and reuse this animation in your application components using the [`useAnimation()`](api/animations/useAnimation) function.
|
||||
|
||||
<docs-code header="animations.ts" path="adev/src/content/examples/animations/src/app/animations.1.ts" region="animation-const"/>
|
||||
|
||||
@@ -20,7 +20,7 @@ For example, the following snippet exports the animation `trigger`.
|
||||
|
||||
<docs-code header="animations.1.ts" path="adev/src/content/examples/animations/src/app/animations.1.ts" region="trigger-const"/>
|
||||
|
||||
From this point, you can import reusable animation variables in your component class.
|
||||
From this point, you can import reusable animation variables into your component class.
|
||||
For example, the following code snippet imports the `transitionAnimation` variable and uses it via the `useAnimation()` function.
|
||||
|
||||
<docs-code header="open-close.ts" path="adev/src/content/examples/animations/src/app/open-close.3.ts" region="reusable"/>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
IMPORTANT: The `@angular/animations` package is now deprecated. The Angular team recommends using native CSS with `animate.enter` and `animate.leave` for animations for all new code. Learn more at the new enter and leave [animation guide](guide/animations). Also see [Migrating away from Angular's Animations package](guide/animations/migration) to learn how you can start migrating to pure CSS animations in your apps.
|
||||
|
||||
This guide goes into depth on special transition states such as the `*` wildcard and `void`. It shows how these special states are used for elements entering and leaving a view.
|
||||
This guide goes into depth on special transition states such as the `*` wildcard and `void`. It also shows how these states are used for elements entering and leaving a view.
|
||||
This section also explores multiple animation triggers, animation callbacks, and sequence-based animation using keyframes.
|
||||
|
||||
## Predefined states and wildcard matching
|
||||
@@ -99,7 +99,7 @@ Use the aliases `:enter` and `:leave` to target HTML elements that are inserted
|
||||
|
||||
The `:enter` transition runs when any `*ngIf` or `*ngFor` views are placed on the page, and `:leave` runs when those views are removed from the page.
|
||||
|
||||
IMPORTANT: Entering/leaving behaviors can sometime be confusing.
|
||||
IMPORTANT: Entering/leaving behaviors can sometimes be confusing.
|
||||
As a rule of thumb consider that any element being added to the DOM by Angular passes via the `:enter` transition. Only elements being directly removed from the DOM by Angular pass via the `:leave` transition. For example, an element's view is removed from the DOM because its parent is being removed from the DOM.
|
||||
|
||||
This example has a special trigger for the enter and leave animation called `myInsertRemoveTrigger`.
|
||||
@@ -239,7 +239,7 @@ You can combine keyframes with `duration`, `delay`, and `easing` within a single
|
||||
|
||||
### Keyframes with a pulsation
|
||||
|
||||
Use keyframes to create a pulse effect in your animations by defining styles at specific offset throughout the animation.
|
||||
Use keyframes to create a pulse effect in your animations by defining styles at specific offsets throughout the animation.
|
||||
|
||||
Here's an example of using keyframes to create a pulse effect:
|
||||
|
||||
@@ -254,7 +254,7 @@ The code snippet for this animation might look like this.
|
||||
|
||||
### Animatable properties and units
|
||||
|
||||
Angular animations support builds on top of web animations, so you can animate any property that the browser considers animatable.
|
||||
Angular animations are built on top of web animations, so you can animate any property that the browser considers animatable.
|
||||
This includes positions, sizes, transforms, colors, borders, and more.
|
||||
The W3C maintains a list of animatable properties on its [CSS Transitions](https://www.w3.org/TR/css-transitions-1) page.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
## Overview
|
||||
|
||||
The manubar is a horizontal navigation bar that provides persistent access to application menus. Menubars organize commands into logical categories like File, Edit, and View, helping users discover and execute application features through keyboard or mouse interaction.
|
||||
The menubar is a horizontal navigation bar that provides persistent access to application menus. Menubars organize commands into logical categories like File, Edit, and View, helping users discover and execute application features through keyboard or mouse interaction.
|
||||
|
||||
<docs-tab-group>
|
||||
<docs-tab label="Basic">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user