mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
Compare commits
290 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| 50761c8be4 | |||
| 8d56b17b95 | |||
| 4ad6d582d2 | |||
| f363ab41f1 | |||
| 0960592d3d | |||
| d04ddd73df | |||
| b682c62873 | |||
| fea25d1a60 | |||
| f916531ee1 | |||
| 8fd896e99a | |||
| 895c576d49 | |||
| 5fd4f0f854 | |||
| 429513bed0 | |||
| f22d9a7098 | |||
| cf7846bd62 | |||
| 9ea8cb6eea | |||
| 3c41e74fdd | |||
| efbba945bc | |||
| 7d54952e85 | |||
| 94b1b530dc | |||
| 0c9c270552 | |||
| 9b48cb2989 | |||
| bba5ed8e64 | |||
| 56c872dacc | |||
| c8902deb00 | |||
| 4b2008d0f2 | |||
| b453c0ce67 | |||
| a9ca90fc11 | |||
| 807cabd9e1 | |||
| 13f050d220 | |||
| d0cf2995a2 | |||
| a35d572b22 | |||
| 80fd08bcc8 | |||
| d8239c7836 | |||
| c1579163b7 | |||
| dbb15ebab2 | |||
| a6c49e0ea9 | |||
| 2c12339ab8 | |||
| a3048f231c | |||
| ae2f2497d3 | |||
| 2c7d3b5704 | |||
| 6bd2121817 | |||
| e8c047bd8d | |||
| a0ca5a50b2 | |||
| 1cdb322600 | |||
| c9585b7159 | |||
| 238b07fe90 | |||
| 3b3ab8b626 | |||
| e731bbdd14 | |||
| c7a18924a6 | |||
| 244e0b0b59 | |||
| 9bfe1a6065 | |||
| b658accf1f | |||
| 9be5e2c211 | |||
| 8818095a82 | |||
| 80c85ec8a5 | |||
| fb7a10fb18 | |||
| 1af0db5742 | |||
| a821e06e33 | |||
| a21be36e15 | |||
| 7aaa8b9b39 | |||
| d0481860bf | |||
| 880a57d4b3 | |||
| 1ba89d1128 | |||
| 831746eff1 | |||
| 9182b62b96 | |||
| 4d2a9394c3 | |||
| ad0156e056 | |||
| aa3220a4b5 | |||
| b4ab6ba2e8 | |||
| 73d6b01b47 | |||
| 3838554503 | |||
| 1148c93834 | |||
| 9f92312cde | |||
| 04b16dee8f | |||
| 57ce2b64ef | |||
| 5393d8ea2c | |||
| 675d4fb489 | |||
| 851ef77318 | |||
| 5800f17e19 | |||
| e19150d2b5 | |||
| 0e496c1d85 | |||
| 737777ef72 | |||
| fa26e7271f | |||
| 076d41c3f6 | |||
| a8f80c1f99 | |||
| bf948be4c2 | |||
| 23ea431c4e | |||
| 2fb767b139 | |||
| b10e305ccc | |||
| f0d19b88b1 | |||
| 67e0ba7e03 | |||
| ca328eab8f | |||
| faeeef678a | |||
| 4d786517d3 | |||
| 26c43d14ba | |||
| 1890c3008b | |||
| cbb2266984 | |||
| ea4847aae5 | |||
| 5fa3052ed1 | |||
| 86718fbbe1 | |||
| de5fbb7deb | |||
| f39896da99 | |||
| 21cab20dae | |||
| 2d28e9b392 | |||
| 5b46a63c08 | |||
| 03fb3cd463 | |||
| 67a73192bf | |||
| e5ed276f27 | |||
| 334ae10168 | |||
| 1f2dc72e8a | |||
| e3b0e5a0b3 | |||
| 10b0dd94e9 | |||
| 6f41efc689 | |||
| bfb8b177ac | |||
| 2feced366a | |||
| 5d755be01c |
@@ -1 +0,0 @@
|
||||
../.gemini/skills
|
||||
+1
-1
@@ -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
|
||||
@@ -0,0 +1,134 @@
|
||||
---
|
||||
name: PR Review
|
||||
description: Guidelines and tools for reviewing pull requests in the Angular repository.
|
||||
---
|
||||
|
||||
# PR Review Guidelines
|
||||
|
||||
When reviewing a pull request for the `angular` repository, follow these essential guidelines to ensure high-quality contributions:
|
||||
|
||||
1. **Context & Ecosystem**:
|
||||
- Keep in mind that this is the core Angular framework. Changes here can impact millions of developers.
|
||||
- Be mindful of backwards compatibility. Breaking changes require strict approval processes and deprecation periods.
|
||||
|
||||
2. **Key Focus Areas**:
|
||||
- **Comprehensive Reviews**: You **MUST always** perform a deep, comprehensive review of the _entire_ pull request. If the user asks you to look into a specific issue, file, or area of concern, you must investigate that specific area _in addition to_ reviewing the rest of the PR's substantive changes. Do not terminate your review after addressing only the user's focal point.
|
||||
- **Package-Specific Guidelines**: Check if there are specific guidelines for the package being modified in the `reference/` directory (e.g., `reference/router.md`). Always prioritize these rules for their respective packages.
|
||||
- **Commit Messages**: Evaluate the quality of commit messages. They should explain the _why_ behind the change, not just the _what_. Someone should be able to look at the commit history years from now and clearly understand the context and reasoning for the change.
|
||||
- **Code Cleanliness**: Ensure the code is readable, maintainable, and follows Angular's project standards.
|
||||
- **Performance**: Look out for code that might negatively impact runtime performance or bundle size, particularly in hot paths like change detection or rendering.
|
||||
- **Testing**: Ensure all new logic has comprehensive tests, including edge cases. **Do NOT run tests locally** as part of your review process. CI handles this automatically, and running tests locally is redundant and inefficient.
|
||||
- **API Design**: Ensure new public APIs are well-designed, consistent with existing APIs, and properly documented.
|
||||
- **Payload Size**: Pay attention to the impact of changes on the final client payload size.
|
||||
|
||||
3. **Execution Workflow**:
|
||||
Determine the appropriate review method. If the user explicitly asks for a `remote` or `local` review in their request, that takes precedence (e.g. "leave comments on the PR" implies `remote`). Otherwise, use the GitHub MCP or available scripts to determine if the review should be `local` or `remote`.
|
||||
|
||||
**Common Review Practices (Applies to both Local and Remote)**
|
||||
- **Preparation & Checklist**:
|
||||
- First, create a task list (e.g., in `task.md`) that you can easily reference containing **all** the review requirements from the "Key Focus Areas" section (Commit Messages, Performance, Testing, etc.), along with any specific review notes or requests from the user.
|
||||
- Before doing an in-depth review, expand this list into more detailed items of what you plan to explore and verify in the PR.
|
||||
- As you conduct the review, check off items in this list, adding your assessment or findings underneath each item.
|
||||
- At the end of your review, refer back to the checklist to ensure every single requirement was completely verified.
|
||||
- **Fetch PR Metadata Safely**: When you need to read the PR description or context, do NOT use `gh pr view <PR_NUMBER>` by itself, as its default GraphQL query may fail due to lack of `read:org` and `read:discussion` token scopes. Instead, use `read_url_content` on the PR URL or use `gh pr view <PR_NUMBER> --json title,body,state,author`.
|
||||
- **Check Existing Comments First**: Before formulating feedback, use the GitHub MCP or available scripts to fetch existing comments on the PR. Review this feedback to avoid duplicate comments, and incorporate its insights into your own review process.
|
||||
- **Constructive Feedback**: Provide clear, actionable, and polite feedback. Explain the _why_ behind your suggestions or edits. Do **NOT** leave inline comments purely to praise, agree with, or acknowledge a correct implementation detail, as this clutters the review. If you want to praise the PR, do so in the single general PR comment.
|
||||
|
||||
**A. Local Code Review (If the PR is owned by the author requesting the review)**
|
||||
- **Checkout**: Check out the PR branch locally (if it doesn't already exist, fetch it). If checking out the branch fails due to a worktree claim (e.g. "fatal: '<branch>' is already used by worktree at '<path>'"), do the review in that directory.
|
||||
- **Review & Edit**: Execute the review directly on the code. Instead of adding inline PR comments for suggestions, format the codebase or apply the edits directly to the files.
|
||||
- **Feedback**: Summarize the review findings and the concrete changes you made in a message to the user, referencing the completed items from your checklist.
|
||||
- **Do NOT Commit or Push**: Leave the changes uncommitted in the working directory so the user can easily review the pending edits locally. Let the user know the changes are ready for their review, but do not ask for approval to push.
|
||||
- **Resolve Comments**: Once the user confirms the changes are good and should be committed/pushed, respond to the existing comments as 'resolved' using the GitHub MCP or available scripts.
|
||||
|
||||
**B. Remote Code Review (For all other PRs)**
|
||||
- **Batching Comments (MCP Server - Preferred)**: If you have the GitHub MCP Server configured, you **MUST** follow this workflow to avoid spamming the author with multiple notifications:
|
||||
1. Create a pending review using `mcp_github-mcp-server_pull_request_review_write` (method `create`).
|
||||
2. Add your inline comments to the pending review using `mcp_github-mcp-server_add_comment_to_pending_review`.
|
||||
3. Submit the review using `mcp_github-mcp-server_pull_request_review_write` (method `submit_pending`).
|
||||
- **Batching Comments (Scripts - Fallback)**: If you do **NOT** have access to the GitHub MCP Server (e.g., specific MCP tools are missing from your context), fallback to using the provided scripts. Use `post_inline_comment.sh` to stage your comments locally. Once all comments are staged, you **MUST** call `submit_pr_review.sh` to publish them as a single batched review (and send a single notification). Try to keep comments minimal or use a general comment if you have many suggestions.
|
||||
- **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
|
||||
|
||||
The following tools are available for remote interactions. We prefer using standard **GitHub MCP Server** tools when available. If you do not have the MCP server set up, you **MUST** fallback to using the custom bash scripts.
|
||||
|
||||
### GitHub MCP Tools (Preferred)
|
||||
|
||||
- `mcp_github-mcp-server_pull_request_review_write`
|
||||
- `mcp_github-mcp-server_add_comment_to_pending_review`
|
||||
|
||||
### Custom Bash Scripts (Fallback)
|
||||
|
||||
The following scripts are provided as fallbacks if the MCP server is not available. Note that they rely on the `gh` CLI being correctly installed and authenticated in the local environment.
|
||||
|
||||
### `determine_review_type.sh`
|
||||
|
||||
Determines whether to use the Local or Remote review workflow by checking if the currently authenticated GitHub user via the `gh` CLI matches the author of the pull request.
|
||||
|
||||
**Usage:**
|
||||
|
||||
```bash
|
||||
.agent/skills/pr_review/scripts/determine_review_type.sh <PR_NUMBER>
|
||||
```
|
||||
|
||||
### `get_pr_comments.sh`
|
||||
|
||||
Fetches all existing inline comments on a PR using the GitHub API. This is crucial for reviewing other contributors' feedback and avoiding duplicate comments. It outputs JSON containing the `id`, `path`, `line`, `body`, and `user` for each comment.
|
||||
|
||||
**Usage:**
|
||||
|
||||
```bash
|
||||
.agent/skills/pr_review/scripts/get_pr_comments.sh <PR_NUMBER>
|
||||
```
|
||||
|
||||
### `reply_pr_comment.sh`
|
||||
|
||||
Replies to an existing PR comment thread. This is useful for marking comments as resolved after addressing them in a local code review. Note that the `COMMENT_ID` must be the ID of the top-level comment in the thread.
|
||||
|
||||
**Usage:**
|
||||
|
||||
```bash
|
||||
.agent/skills/pr_review/scripts/reply_pr_comment.sh <PR_NUMBER> <COMMENT_ID> <REPLY_BODY>
|
||||
```
|
||||
|
||||
### `post_inline_comment.sh`
|
||||
|
||||
The GitHub CLI `gh pr review` command does not natively support adding inline comments to specific lines of code via its standard flags. This script wraps the GitHub API to stage comments locally. They will not be published until you call `submit_pr_review.sh`.
|
||||
|
||||
**Usage:**
|
||||
|
||||
```bash
|
||||
.agent/skills/pr_review/scripts/post_inline_comment.sh <PR_NUMBER> <FILE_PATH> <LINE_NUMBER> <COMMENT_BODY>
|
||||
```
|
||||
|
||||
**Example:**
|
||||
|
||||
```bash
|
||||
.agent/skills/pr_review/scripts/post_inline_comment.sh 12345 "packages/core/src/render3/instructions/element.ts" 42 "AGENT: Consider the performance implications here."
|
||||
```
|
||||
|
||||
### `submit_pr_review.sh`
|
||||
|
||||
Submits all locally staged inline comments as a single batched review via the GitHub Pull Request Reviews API.
|
||||
|
||||
**Usage:**
|
||||
|
||||
```bash
|
||||
.agent/skills/pr_review/scripts/submit_pr_review.sh <PR_NUMBER> <EVENT_TYPE> [BODY]
|
||||
```
|
||||
|
||||
**Options:**
|
||||
|
||||
- `EVENT_TYPE`: Must be `COMMENT`, `APPROVE`, or `REQUEST_CHANGES`. Never use `APPROVE` for external PRs.
|
||||
- `BODY`: (Optional) A general summary comment for the review.
|
||||
|
||||
**Example:**
|
||||
|
||||
```bash
|
||||
.agent/skills/pr_review/scripts/submit_pr_review.sh 12345 COMMENT "AGENT: I have left a few inline suggestions for your consideration."
|
||||
```
|
||||
@@ -0,0 +1,7 @@
|
||||
# Router PR Review Guidelines
|
||||
|
||||
When reviewing pull requests that modify the Angular Router (`packages/router`), pay special attention to the following:
|
||||
|
||||
- **Timing Sensitivity**: The router is extremely sensitive to timing changes. Any changes that alter the asynchronous timing of navigations, resolvers, or guards are almost always breaking changes and must be scrutinized carefully.
|
||||
- **Testing Practices**: Tests should usually use the `RouterTestingHarness`. Many existing tests are older and do not use this harness. Do not blindly follow the shape of existing tests when writing or reviewing new ones; encourage the use of modern testing utilities.
|
||||
- **Feature Justification**: Changes to router core code should be well-justified. Consider whether the change is proven to be a core developer ask, such as resolving a highly upvoted GitHub issue or addressing a critical bug.
|
||||
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# determine_review_type.sh <PR_NUMBER>
|
||||
# Determines if the PR should be reviewed locally or remotely based on author.
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: determine_review_type.sh <PR_NUMBER>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PR_NUMBER=$1
|
||||
|
||||
# Get current authenticated user
|
||||
CURRENT_USER=$(gh api user -q .login 2>/dev/null)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Could not determine current GitHub user. Are you logged in to gh?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get PR author
|
||||
PR_AUTHOR=$(gh pr view "$PR_NUMBER" --json author -q .author.login 2>/dev/null)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Could not retrieve PR information for $PR_NUMBER."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$CURRENT_USER" = "$PR_AUTHOR" ]; then
|
||||
echo "local"
|
||||
else
|
||||
echo "remote"
|
||||
fi
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# get_pr_comments.sh
|
||||
# Fetches existing inline comments on a PR to avoid duplicate reviews.
|
||||
# Usage: ./get_pr_comments.sh <PR_NUMBER>
|
||||
|
||||
if [ "$#" -lt 1 ]; then
|
||||
echo "Usage: $0 <PR_NUMBER>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PR_NUMBER="$1"
|
||||
|
||||
# Ensure gh cli is installed
|
||||
if ! command -v gh &> /dev/null; then
|
||||
echo "Error: gh CLI could not be found. Please install and authenticate."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get the current repository (e.g., angular/angular)
|
||||
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
|
||||
|
||||
# Fetch comments
|
||||
gh api \
|
||||
--paginate \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
"/repos/${REPO}/pulls/${PR_NUMBER}/comments" \
|
||||
--jq '.[] | {id: .id, path: .path, line: .line, body: .body, user: .user.login}'
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# post_inline_comment.sh
|
||||
# Adds an inline comment to a specific line in a PR via the GitHub API.
|
||||
# Usage: ./post_inline_comment.sh <PR_NUMBER> <FILE_PATH> <LINE_NUMBER> <COMMENT_BODY>
|
||||
|
||||
if [ "$#" -lt 4 ]; then
|
||||
echo "Usage: $0 <PR_NUMBER> <FILE_PATH> <LINE_NUMBER> <COMMENT_BODY>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PR_NUMBER="$1"
|
||||
FILE_PATH="$2"
|
||||
LINE="$3"
|
||||
BODY="$4"
|
||||
|
||||
# Ensure gh cli is installed
|
||||
if ! command -v gh &> /dev/null; then
|
||||
echo "Error: gh CLI could not be found. Please install and authenticate."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get the current repository (e.g., angular/angular)
|
||||
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
|
||||
|
||||
echo "Staging inline comment for PR #${PR_NUMBER} on ${FILE_PATH}:${LINE}..."
|
||||
|
||||
COMMENT_FILE="/tmp/angular_pr_${PR_NUMBER}_comments.json"
|
||||
if [ ! -f "$COMMENT_FILE" ]; then
|
||||
echo "[]" > "$COMMENT_FILE"
|
||||
fi
|
||||
|
||||
# Append the new comment to the JSON array
|
||||
jq --arg path "${FILE_PATH}" --argjson line "${LINE}" --arg body "${BODY}" \
|
||||
'. += [{"path": $path, "line": $line, "body": $body}]' "$COMMENT_FILE" > "${COMMENT_FILE}.tmp" && mv "${COMMENT_FILE}.tmp" "$COMMENT_FILE"
|
||||
|
||||
echo "Comment successfully staged locally. Remember to call submit_pr_review.sh when finished to publish all comments as a single review!"
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# reply_pr_comment.sh <PR_NUMBER> <COMMENT_ID> <REPLY_BODY>
|
||||
# Replies to an existing PR comment thread. Note: COMMENT_ID must be the ID of the top-level comment in the thread you are replying to.
|
||||
|
||||
if [ "$#" -lt 3 ]; then
|
||||
echo "Usage: reply_pr_comment.sh <PR_NUMBER> <COMMENT_ID> <REPLY_BODY>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PR_NUMBER="$1"
|
||||
COMMENT_ID="$2"
|
||||
BODY="$3"
|
||||
|
||||
# Ensure gh cli is installed
|
||||
if ! command -v gh &> /dev/null; then
|
||||
echo "Error: gh CLI could not be found. Please install and authenticate."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get the current repository (e.g., angular/angular)
|
||||
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
|
||||
|
||||
# Reply to the thread using the provided comment ID
|
||||
gh api \
|
||||
--silent \
|
||||
--method POST \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
"/repos/${REPO}/pulls/${PR_NUMBER}/comments/${COMMENT_ID}/replies" \
|
||||
-f body="$BODY"
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# submit_pr_review.sh
|
||||
# Submits a batched PR review using comments previously staged by post_inline_comment.sh
|
||||
# Usage: ./submit_pr_review.sh <PR_NUMBER> <EVENT_TYPE> [BODY]
|
||||
# EVENT_TYPE must be COMMENT, APPROVE, or REQUEST_CHANGES
|
||||
|
||||
if [ "$#" -lt 2 ]; then
|
||||
echo "Usage: $0 <PR_NUMBER> <EVENT_TYPE> [BODY]"
|
||||
echo "EVENT_TYPE must be COMMENT, APPROVE, or REQUEST_CHANGES"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PR_NUMBER="$1"
|
||||
EVENT="$2"
|
||||
BODY="${3:-}"
|
||||
COMMENT_FILE="/tmp/angular_pr_${PR_NUMBER}_comments.json"
|
||||
|
||||
if ! command -v gh &> /dev/null; then
|
||||
echo "Error: gh CLI could not be found. Please install and authenticate."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
|
||||
|
||||
# Check if there are staged comments
|
||||
COMMENTS="[]"
|
||||
if [ -f "$COMMENT_FILE" ]; then
|
||||
COMMENTS=$(cat "$COMMENT_FILE")
|
||||
fi
|
||||
|
||||
echo "Submitting review for PR #${PR_NUMBER}..."
|
||||
|
||||
# Create the payload
|
||||
PAYLOAD_FILE="/tmp/angular_pr_${PR_NUMBER}_payload.json"
|
||||
jq -n --arg event "$EVENT" --arg body "$BODY" --argjson comments "$COMMENTS" \
|
||||
'{event: $event, body: $body, comments: $comments}' > "$PAYLOAD_FILE"
|
||||
|
||||
# Post the review using the GitHub Pull Request Reviews API
|
||||
gh api \
|
||||
--method POST \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"/repos/${REPO}/pulls/${PR_NUMBER}/reviews" \
|
||||
--input "$PAYLOAD_FILE"
|
||||
|
||||
echo "Review submitted successfully!"
|
||||
rm -f "$COMMENT_FILE"
|
||||
rm -f "$PAYLOAD_FILE"
|
||||
@@ -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.
|
||||
+2
-1
@@ -7,4 +7,5 @@ code_review:
|
||||
help: false
|
||||
summary: false
|
||||
code_review: false
|
||||
ignore_patterns: []
|
||||
ignore_patterns:
|
||||
- pnpm-lock.yaml
|
||||
|
||||
@@ -10481,7 +10481,7 @@ var JSONStringify = (value, replacer, space) => {
|
||||
const convertedToCustomJSON = originalStringify(
|
||||
value,
|
||||
(key, value2) => {
|
||||
const isNoise = typeof value2 === "string" && Boolean(value2.match(noiseValue));
|
||||
const isNoise = typeof value2 === "string" && noiseValue.test(value2);
|
||||
if (isNoise)
|
||||
return value2.toString() + "n";
|
||||
if (typeof value2 === "bigint")
|
||||
@@ -10501,12 +10501,29 @@ var JSONStringify = (value, replacer, space) => {
|
||||
const denoisedJSON = processedJSON.replace(noiseStringify, "$1$2$3");
|
||||
return denoisedJSON;
|
||||
};
|
||||
var isContextSourceSupported = () => JSON.parse("1", (_, __, context3) => !!context3 && context3.source === "1");
|
||||
var featureCache = /* @__PURE__ */ new Map();
|
||||
var isContextSourceSupported = () => {
|
||||
const parseFingerprint = JSON.parse.toString();
|
||||
if (featureCache.has(parseFingerprint)) {
|
||||
return featureCache.get(parseFingerprint);
|
||||
}
|
||||
try {
|
||||
const result = JSON.parse(
|
||||
"1",
|
||||
(_, __, context3) => !!context3?.source && context3.source === "1"
|
||||
);
|
||||
featureCache.set(parseFingerprint, result);
|
||||
return result;
|
||||
} catch {
|
||||
featureCache.set(parseFingerprint, false);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
var convertMarkedBigIntsReviver = (key, value, context3, userReviver) => {
|
||||
const isCustomFormatBigInt = typeof value === "string" && value.match(customFormat);
|
||||
const isCustomFormatBigInt = typeof value === "string" && customFormat.test(value);
|
||||
if (isCustomFormatBigInt)
|
||||
return BigInt(value.slice(0, -1));
|
||||
const isNoiseValue = typeof value === "string" && value.match(noiseValue);
|
||||
const isNoiseValue = typeof value === "string" && noiseValue.test(value);
|
||||
if (isNoiseValue)
|
||||
return value.slice(0, -1);
|
||||
if (typeof userReviver !== "function")
|
||||
@@ -10538,7 +10555,7 @@ var JSONParse = (text, reviver) => {
|
||||
stringsOrLargeNumbers,
|
||||
(text2, digits, fractional, exponential) => {
|
||||
const isString = text2[0] === '"';
|
||||
const isNoise = isString && Boolean(text2.match(noiseValueWithQuotes));
|
||||
const isNoise = isString && noiseValueWithQuotes.test(text2);
|
||||
if (isNoise)
|
||||
return text2.substring(0, text2.length - 1) + 'n"';
|
||||
const isFractionalOrExponential = fractional || exponential;
|
||||
@@ -19231,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));
|
||||
});
|
||||
}
|
||||
@@ -19239,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 };
|
||||
@@ -19249,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);
|
||||
@@ -19304,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?
|
||||
@@ -22961,6 +22978,7 @@ var require_stringify = __commonJS2({
|
||||
nullStr: "null",
|
||||
simpleKeys: false,
|
||||
singleQuote: null,
|
||||
trailingComma: false,
|
||||
trueStr: "true",
|
||||
verifyAliasOrder: true
|
||||
}, doc.schema.toStringOptions, options);
|
||||
@@ -23466,12 +23484,19 @@ ${indent}${line}` : "\n";
|
||||
if (comment)
|
||||
reqNewline = true;
|
||||
let str = stringify.stringify(item, itemCtx, () => comment = null);
|
||||
if (i < items.length - 1)
|
||||
reqNewline || (reqNewline = lines.length > linesAtValue || str.includes("\n"));
|
||||
if (i < items.length - 1) {
|
||||
str += ",";
|
||||
} else if (ctx.options.trailingComma) {
|
||||
if (ctx.options.lineWidth > 0) {
|
||||
reqNewline || (reqNewline = lines.reduce((sum, line) => sum + line.length + 2, 2) + (str.length + 2) > ctx.options.lineWidth);
|
||||
}
|
||||
if (reqNewline) {
|
||||
str += ",";
|
||||
}
|
||||
}
|
||||
if (comment)
|
||||
str += stringifyComment.lineComment(str, itemIndent, commentString(comment));
|
||||
if (!reqNewline && (lines.length > linesAtValue || str.includes("\n")))
|
||||
reqNewline = true;
|
||||
lines.push(str);
|
||||
linesAtValue = lines.length;
|
||||
}
|
||||
@@ -26401,17 +26426,22 @@ var require_compose_node = __commonJS2({
|
||||
case "block-map":
|
||||
case "block-seq":
|
||||
case "flow-collection":
|
||||
node = composeCollection.composeCollection(CN, ctx, token, props, onError);
|
||||
if (anchor)
|
||||
node.anchor = anchor.source.substring(1);
|
||||
try {
|
||||
node = composeCollection.composeCollection(CN, ctx, token, props, onError);
|
||||
if (anchor)
|
||||
node.anchor = anchor.source.substring(1);
|
||||
} catch (error2) {
|
||||
const message = error2 instanceof Error ? error2.message : String(error2);
|
||||
onError(token, "RESOURCE_EXHAUSTION", message);
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
const message = token.type === "error" ? token.message : `Unsupported token (type: ${token.type})`;
|
||||
onError(token, "UNEXPECTED_TOKEN", message);
|
||||
node = composeEmptyNode(ctx, token.offset, void 0, null, props, onError);
|
||||
isSrcToken = false;
|
||||
}
|
||||
}
|
||||
node ?? (node = composeEmptyNode(ctx, token.offset, void 0, null, props, onError));
|
||||
if (anchor && node.anchor === "")
|
||||
onError(anchor, "BAD_ALIAS", "Anchor cannot be an empty string");
|
||||
if (atKey && ctx.options.stringKeys && (!identity.isScalar(node) || typeof node.value !== "string" || node.tag && node.tag !== "tag:yaml.org,2002:str")) {
|
||||
@@ -29176,7 +29206,7 @@ var JSONStringify2 = (value, replacer, space) => {
|
||||
const convertedToCustomJSON = originalStringify2(
|
||||
value,
|
||||
(key, value2) => {
|
||||
const isNoise = typeof value2 === "string" && Boolean(value2.match(noiseValue2));
|
||||
const isNoise = typeof value2 === "string" && noiseValue2.test(value2);
|
||||
if (isNoise)
|
||||
return value2.toString() + "n";
|
||||
if (typeof value2 === "bigint")
|
||||
@@ -29196,12 +29226,29 @@ var JSONStringify2 = (value, replacer, space) => {
|
||||
const denoisedJSON = processedJSON.replace(noiseStringify2, "$1$2$3");
|
||||
return denoisedJSON;
|
||||
};
|
||||
var isContextSourceSupported2 = () => JSON.parse("1", (_, __, context3) => !!context3 && context3.source === "1");
|
||||
var featureCache2 = /* @__PURE__ */ new Map();
|
||||
var isContextSourceSupported2 = () => {
|
||||
const parseFingerprint = JSON.parse.toString();
|
||||
if (featureCache2.has(parseFingerprint)) {
|
||||
return featureCache2.get(parseFingerprint);
|
||||
}
|
||||
try {
|
||||
const result = JSON.parse(
|
||||
"1",
|
||||
(_, __, context3) => !!context3?.source && context3.source === "1"
|
||||
);
|
||||
featureCache2.set(parseFingerprint, result);
|
||||
return result;
|
||||
} catch {
|
||||
featureCache2.set(parseFingerprint, false);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
var convertMarkedBigIntsReviver2 = (key, value, context3, userReviver) => {
|
||||
const isCustomFormatBigInt = typeof value === "string" && value.match(customFormat2);
|
||||
const isCustomFormatBigInt = typeof value === "string" && customFormat2.test(value);
|
||||
if (isCustomFormatBigInt)
|
||||
return BigInt(value.slice(0, -1));
|
||||
const isNoiseValue = typeof value === "string" && value.match(noiseValue2);
|
||||
const isNoiseValue = typeof value === "string" && noiseValue2.test(value);
|
||||
if (isNoiseValue)
|
||||
return value.slice(0, -1);
|
||||
if (typeof userReviver !== "function")
|
||||
@@ -29233,7 +29280,7 @@ var JSONParse2 = (text, reviver) => {
|
||||
stringsOrLargeNumbers2,
|
||||
(text2, digits, fractional, exponential) => {
|
||||
const isString = text2[0] === '"';
|
||||
const isNoise = isString && Boolean(text2.match(noiseValueWithQuotes2));
|
||||
const isNoise = isString && noiseValueWithQuotes2.test(text2);
|
||||
if (isNoise)
|
||||
return text2.substring(0, text2.length - 1) + 'n"';
|
||||
const isFractionalOrExponential = fractional || exponential;
|
||||
@@ -32535,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;
|
||||
@@ -32547,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 {
|
||||
@@ -32570,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;
|
||||
}
|
||||
@@ -33495,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:
|
||||
@@ -33536,7 +33636,7 @@ tmp/lib/tmp.js:
|
||||
*)
|
||||
*)
|
||||
|
||||
@angular/ng-dev/bundles/chunk-34WCNHIG.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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Saucelabs Variables
|
||||
uses: angular/dev-infra/github-actions/saucelabs@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
- 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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
- 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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
- 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,11 @@ 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}}
|
||||
|
||||
- run: pnpm install --frozen-lockfile
|
||||
|
||||
- uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
- uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
with:
|
||||
bazelrc: ./.bazelrc.user
|
||||
|
||||
@@ -49,7 +49,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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@bc22e01685c56e89e7813fd8e26f33dc47f87e15 # v7.1.5
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
- 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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
- 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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
- 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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
- 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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Saucelabs Variables
|
||||
uses: angular/dev-infra/github-actions/saucelabs@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
- 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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@bc22e01685c56e89e7813fd8e26f33dc47f87e15 # v7.1.5
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ba726e7bca0b08b125ccc6f93c233749e1213c17
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
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@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
|
||||
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
+10
-10
@@ -99,7 +99,7 @@ groups:
|
||||
reviewers:
|
||||
users:
|
||||
- ~alxhub
|
||||
- AndrewKushnir
|
||||
- ~AndrewKushnir
|
||||
- atscott
|
||||
- crisbeto
|
||||
- devversion
|
||||
@@ -145,7 +145,7 @@ groups:
|
||||
reviewers:
|
||||
users:
|
||||
- ~alxhub
|
||||
- AndrewKushnir
|
||||
- ~AndrewKushnir
|
||||
- atscott
|
||||
- crisbeto
|
||||
- devversion
|
||||
@@ -200,7 +200,7 @@ groups:
|
||||
users:
|
||||
- ~JiaLiPassion
|
||||
- ~alxhub
|
||||
- AndrewKushnir
|
||||
- ~AndrewKushnir
|
||||
- atscott
|
||||
- crisbeto
|
||||
- devversion
|
||||
@@ -250,7 +250,7 @@ groups:
|
||||
users:
|
||||
- alan-agius4
|
||||
- ~alxhub
|
||||
- AndrewKushnir
|
||||
- ~AndrewKushnir
|
||||
- atscott
|
||||
- bencodezen
|
||||
- crisbeto
|
||||
@@ -372,7 +372,7 @@ groups:
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- AndrewKushnir
|
||||
- ~AndrewKushnir
|
||||
- ~alxhub
|
||||
- atscott
|
||||
- thePunderWoman
|
||||
@@ -408,7 +408,7 @@ groups:
|
||||
reviewers:
|
||||
users:
|
||||
- ~alxhub
|
||||
- AndrewKushnir
|
||||
- ~AndrewKushnir
|
||||
- atscott
|
||||
- kirjs
|
||||
- thePunderWoman
|
||||
@@ -434,7 +434,7 @@ groups:
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- marktechson
|
||||
- MarkTechson
|
||||
- kirjs
|
||||
- ~JeanMeche
|
||||
- ~dgp1130
|
||||
@@ -456,7 +456,7 @@ groups:
|
||||
reviewers:
|
||||
users:
|
||||
- ~alxhub
|
||||
- AndrewKushnir
|
||||
- ~AndrewKushnir
|
||||
- andrewseguin
|
||||
- dgp1130
|
||||
- thePunderWoman
|
||||
@@ -479,7 +479,7 @@ groups:
|
||||
- ~pkozlowski-opensource # Pawel Kozlowski
|
||||
- ~alxhub # Alex Rickabaugh
|
||||
- thePunderWoman # Jessica Janiuk
|
||||
- AndrewKushnir # Andrew Kushnir
|
||||
- ~AndrewKushnir # Andrew Kushnir
|
||||
- atscott # Andrew Scott
|
||||
|
||||
# External team required reviews
|
||||
@@ -487,7 +487,7 @@ groups:
|
||||
<<: *defaults
|
||||
conditions:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
contains_any_globs(files.exclude('packages/core/primitives/**/*spec.ts'), [
|
||||
'packages/core/primitives/**/{*,.*}',
|
||||
])
|
||||
reviewers:
|
||||
|
||||
+178
@@ -1,3 +1,181 @@
|
||||
<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
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [fea25d1a60](https://github.com/angular/angular/commit/fea25d1a60ecaba1599d9cd9b8df27109ed195c5) | fix | register SVG animation attributes in URL security context ([#67797](https://github.com/angular/angular/pull/67797)) |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [bba5ed8e64](https://github.com/angular/angular/commit/bba5ed8e643b9c3f680e7e539c3d744ad6905e59) | fix | prevent recursive scope checks for invalid NgModule imports |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [d04ddd73df](https://github.com/angular/angular/commit/d04ddd73dfc03f420afbdde964c5119f338af135) | fix | prevent binding unsafe attributes on SVG animation elements ([#67797](https://github.com/angular/angular/pull/67797)) |
|
||||
| [8fd896e99a](https://github.com/angular/angular/commit/8fd896e99a13855c6569f29efe7e578c301e13ee) | fix | resolve component import by exact specifier in route lazy-loading schematic |
|
||||
| [b682c62873](https://github.com/angular/angular/commit/b682c628731b86a4884e50abb2f5fa73ac0ad057) | fix | treat `object[data]` as resource URL context ([#67797](https://github.com/angular/angular/pull/67797)) |
|
||||
### localize
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [3c41e74fdd](https://github.com/angular/angular/commit/3c41e74fdd279f683156b654699a9312a850add0) | fix | validate locale in getOutputPathFn to prevent path traversal |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [0960592d3d](https://github.com/angular/angular/commit/0960592d3d4fad110d5598144fda9f2488520826) | fix | pass outlet context to split to fix empty path named outlets |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.2.6"></a>
|
||||
# 21.2.6 (2026-03-25)
|
||||
### common
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [b4ab6ba2e8](https://github.com/angular/angular/commit/b4ab6ba2e84a18309b0bb5dd68311ff1776b1cb4) | fix | avoid redundant image fetch on destroy with auto sizes |
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [880a57d4b3](https://github.com/angular/angular/commit/880a57d4b34af5aa27cd5bee11fa218ade6444bb) | fix | prevent shimCssText from adding extra blank lines per CSS comment |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [ad0156e056](https://github.com/angular/angular/commit/ad0156e056e60ffebfeb804fda70dce88d9475a8) | fix | fixes a regression with animate.leave and reordering |
|
||||
### migrations
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [73d6b01b47](https://github.com/angular/angular/commit/73d6b01b47bb6762d182f1cd891f8ad4d7f688e1) | fix | inject migration not work in multi-project workspace with option path |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.2.5"></a>
|
||||
# 21.2.5 (2026-03-18)
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [334ae10168](https://github.com/angular/angular/commit/334ae10168fdad15cd1390180e2994b4eb65349b) | fix | ensure generated code compiles |
|
||||
| [23ea431c4e](https://github.com/angular/angular/commit/23ea431c4ec45cbb4a7db9839969e7cb23b07f58) | fix | parse named HTML entities containing digits |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [26c43d14ba](https://github.com/angular/angular/commit/26c43d14baad1a6b3629a77825e702a97a4f8482) | fix | escape template literal in TCB |
|
||||
| [67e0ba7e03](https://github.com/angular/angular/commit/67e0ba7e03bb940639f0eafb3af45015e9727eac) | fix | generic types not filled out correctly in type check block |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [1890c3008b](https://github.com/angular/angular/commit/1890c3008bbb41b7143b7ede09bed1f7704744fb) | fix | clean up dehydrated views during HMR component replacement |
|
||||
| [bf948be4c2](https://github.com/angular/angular/commit/bf948be4c2c88c604e428cba35e3b9e532bfe5b0) | fix | run linked signal equality check without reactive consumer |
|
||||
### migrations
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [076d41c3f6](https://github.com/angular/angular/commit/076d41c3f6496eb6c6f84b54e2d2ca85c1b35e64) | fix | prevent trailing comma syntax errors after removing NgStyle |
|
||||
### service-worker
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [e19150d2b5](https://github.com/angular/angular/commit/e19150d2b596e87c69bee61f478c3e9c7cbc8f67) | fix | preserve redirect policy on reconstructed asset requests |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.2.4"></a>
|
||||
# 21.2.4 (2026-03-12)
|
||||
### 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:
|
||||
|
||||
|
||||
+24
-26
@@ -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.6")
|
||||
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 = "804515937593ca742f5f119a20774f55a08e70ad",
|
||||
commit = "b1d295334e70335dab7ac9984a989fae0a9c9dc2",
|
||||
remote = "https://github.com/angular/rules_angular.git",
|
||||
)
|
||||
|
||||
bazel_dep(name = "devinfra")
|
||||
git_override(
|
||||
module_name = "devinfra",
|
||||
commit = "491fa7fc1803683748875b2b89d85700aca2b1f4",
|
||||
commit = "48c48fa3848de5bb0ec1c3203558f099765165ab",
|
||||
remote = "https://github.com/angular/dev-infra.git",
|
||||
)
|
||||
|
||||
bazel_dep(name = "rules_sass")
|
||||
git_override(
|
||||
module_name = "rules_sass",
|
||||
commit = "781c41bf7a48147bb20103e250f7215475e915a1",
|
||||
commit = "a65d937fabd87672f7245aeaa5eb5a0c5a2abead",
|
||||
remote = "https://github.com/angular/rules_sass.git",
|
||||
)
|
||||
|
||||
bazel_dep(name = "rules_browsers")
|
||||
git_override(
|
||||
module_name = "rules_browsers",
|
||||
commit = "7043f918640169063a6281ab4afb61389a0aad6d",
|
||||
commit = "b03f09ef28a08f8ae07482851cf5ecbf6ac23a2a",
|
||||
remote = "https://github.com/angular/rules_browsers.git",
|
||||
)
|
||||
|
||||
@@ -49,15 +49,15 @@ use_repo(yq, "yq_toolchains")
|
||||
node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node")
|
||||
node.toolchain(
|
||||
node_repositories = {
|
||||
"22.22.1-darwin_arm64": ("node-v22.22.1-darwin-arm64.tar.gz", "node-v22.22.1-darwin-arm64", "679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"),
|
||||
"22.22.1-darwin_amd64": ("node-v22.22.1-darwin-x64.tar.gz", "node-v22.22.1-darwin-x64", "07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"),
|
||||
"22.22.1-linux_arm64": ("node-v22.22.1-linux-arm64.tar.xz", "node-v22.22.1-linux-arm64", "0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"),
|
||||
"22.22.1-linux_ppc64le": ("node-v22.22.1-linux-ppc64le.tar.xz", "node-v22.22.1-linux-ppc64le", "a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"),
|
||||
"22.22.1-linux_s390x": ("node-v22.22.1-linux-s390x.tar.xz", "node-v22.22.1-linux-s390x", "e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"),
|
||||
"22.22.1-linux_amd64": ("node-v22.22.1-linux-x64.tar.xz", "node-v22.22.1-linux-x64", "9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"),
|
||||
"22.22.1-windows_amd64": ("node-v22.22.1-win-x64.zip", "node-v22.22.1-win-x64", "877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"),
|
||||
"22.22.2-darwin_arm64": ("node-v22.22.2-darwin-arm64.tar.gz", "node-v22.22.2-darwin-arm64", "db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"),
|
||||
"22.22.2-darwin_amd64": ("node-v22.22.2-darwin-x64.tar.gz", "node-v22.22.2-darwin-x64", "12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"),
|
||||
"22.22.2-linux_arm64": ("node-v22.22.2-linux-arm64.tar.xz", "node-v22.22.2-linux-arm64", "e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"),
|
||||
"22.22.2-linux_ppc64le": ("node-v22.22.2-linux-ppc64le.tar.xz", "node-v22.22.2-linux-ppc64le", "14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"),
|
||||
"22.22.2-linux_s390x": ("node-v22.22.2-linux-s390x.tar.xz", "node-v22.22.2-linux-s390x", "9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"),
|
||||
"22.22.2-linux_amd64": ("node-v22.22.2-linux-x64.tar.xz", "node-v22.22.2-linux-x64", "88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"),
|
||||
"22.22.2-windows_amd64": ("node-v22.22.2-win-x64.zip", "node-v22.22.2-win-x64", "7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"),
|
||||
},
|
||||
node_version = "22.22.1",
|
||||
node_version = "22.22.2",
|
||||
)
|
||||
use_repo(node, "nodejs_toolchains")
|
||||
use_repo(node, "nodejs_darwin_amd64")
|
||||
@@ -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.32.0",
|
||||
pnpm_version_integrity = "sha512-myY0uz/tVgHDNjPy2SWT9QYnCjljuMUdKy1qgo2mFc5One6++WFMzrvBOsjTwPnJzM61g8achXhDb6R327INcA==",
|
||||
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
+271
-277
@@ -13,29 +13,23 @@
|
||||
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.0.0/MODULE.bazel": "e118477db5c49419a88d78ebc7a2c2cea9d49600fe0f490c1903324a2c16ecd9",
|
||||
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.11.0/MODULE.bazel": "cb1ba9f9999ed0bc08600c221f532c1ddd8d217686b32ba7d45b0713b5131452",
|
||||
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.14.0/MODULE.bazel": "2b31ffcc9bdc8295b2167e07a757dbbc9ac8906e7028e5170a3708cecaac119f",
|
||||
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.19.2/MODULE.bazel": "30dfabbfae0139b1f0036e01c201dd4c0167da3017f0b7ef3820d78e07622989",
|
||||
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.19.3/MODULE.bazel": "253d739ba126f62a5767d832765b12b59e9f8d2bc88cc1572f4a73e46eb298ca",
|
||||
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.22.5/MODULE.bazel": "004ba890363d05372a97248c37205ae64b6fa31047629cd2c0895a9d0c7779e8",
|
||||
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.22.5/source.json": "ac2c3213df8f985785f1d0aeb7f0f73d5324e6e67d593d9b9470fb74a25d4a9b",
|
||||
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.7.7/MODULE.bazel": "491f8681205e31bb57892d67442ce448cda4f472a8e6b3dc062865e29a64f89c",
|
||||
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.8.1/MODULE.bazel": "812d2dd42f65dca362152101fbec418029cc8fd34cbad1a2fde905383d705838",
|
||||
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.9.3/MODULE.bazel": "66baf724dbae7aff4787bf2245cc188d50cb08e07789769730151c0943587c14",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_esbuild/0.25.0/MODULE.bazel": "5fef5ec709c837312823f9bcf0f276661e2cb48ad52f17c4e01176bbf1e9bf58",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_esbuild/0.25.1/MODULE.bazel": "9b931b3e483bd8eedb6966bda6df07d801f70ccb4896231b4e5e711b5130f3aa",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_esbuild/0.25.1/source.json": "a0b72e23ed06113f3878cb635d586b4045ef37750983467af72fe0315c3a2fcd",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_jasmine/2.0.4/MODULE.bazel": "fbb819eb8b7e5d7f67fdd38f7cecb413e287594cd666ce192c72c8828527775a",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_jasmine/2.0.4/source.json": "81ffb708333cd98ec3c0b4cc004f4d5cf92a16914b5196a2892c45141bba7cff",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_js/2.0.0/MODULE.bazel": "b45b507574aa60a92796e3e13c195cd5744b3b8aff516a9c0cb5ae6a048161c5",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_js/2.4.2/MODULE.bazel": "0d01db38b96d25df7ed952a5e96eac4b3802723d146961974bf020f6dd07591d",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_js/3.0.2/MODULE.bazel": "c5d22d2db2a2f0cf41ec2028ded2e2543d7ff1ea9f6faf5d6b2791546ee1d6a9",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_js/3.0.3/MODULE.bazel": "28a30e8fc33bf64a67835d64d124f6e05a7d59648dcb27b110fb3502f761e503",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_js/3.0.3/source.json": "bb8fff9a304452e1042af9522ad1d54d6f1d1fdf71c5127deadb6fd156654193",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_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.6.3/MODULE.bazel": "d09db394970f076176ce7bab5b5fa7f0d560fd4f30b8432ea5e2c2570505b130",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_ts/3.8.5/MODULE.bazel": "bcf8f0b6b9375f0f74451e2f70671efae9bb366acef8fdc04675305eaf137f06",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_ts/3.8.6/MODULE.bazel": "371bacab13c9c36323384b56c7cabfde1982b69674e78729e1ddd1edd54d984e",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_ts/3.8.6/source.json": "b87a583fa2aa5c546221e3c514c883b2344c9284f27347759a5ff700deceb012",
|
||||
"https://bcr.bazel.build/modules/aspect_tools_telemetry/0.2.3/MODULE.bazel": "20f53b145f40957a51077ae90b37b7ce83582a1daf9350349f0f86179e19dd0d",
|
||||
"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",
|
||||
@@ -59,13 +53,13 @@
|
||||
"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",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.4.0/MODULE.bazel": "2ab127ef8d56a739a99bb2ce00ec4c7d1ecc7977d4370c0ca6efd0d8f03d6d99",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.4.2/MODULE.bazel": "3bd40978e7a1fac911d5989e6b09d8f64921865a45822d8b09e815eaa726a651",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.5.0/MODULE.bazel": "32880f5e2945ce6a03d1fbd588e9198c0a959bb42297b2cfaf1685b7bc32e138",
|
||||
@@ -88,7 +82,8 @@
|
||||
"https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f",
|
||||
"https://bcr.bazel.build/modules/jq.bzl/0.1.0/MODULE.bazel": "2ce69b1af49952cd4121a9c3055faa679e748ce774c7f1fda9657f936cae902f",
|
||||
"https://bcr.bazel.build/modules/jq.bzl/0.4.0/MODULE.bazel": "a7b39b37589f2b0dad53fd6c1ccaabbdb290330caa920d7ef3e6aad068cd4ab2",
|
||||
"https://bcr.bazel.build/modules/jq.bzl/0.4.0/source.json": "52ec7530c4618e03f634b30ff719814a68d7d39c235938b7aa2abbfe1eb1c52c",
|
||||
"https://bcr.bazel.build/modules/jq.bzl/0.6.1/MODULE.bazel": "f30c46e0a08a9f7566a8bf60a43d48abea960cd7f57b315b01e2762f1537eb52",
|
||||
"https://bcr.bazel.build/modules/jq.bzl/0.6.1/source.json": "9ca9e2f90baa6a5bb0a49626ed9528554ec83165adf47b39792673ecc7feda22",
|
||||
"https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075",
|
||||
"https://bcr.bazel.build/modules/jsoncpp/1.9.5/source.json": "4108ee5085dd2885a341c7fab149429db457b3169b86eb081fa245eadf69169d",
|
||||
"https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902",
|
||||
@@ -165,10 +160,10 @@
|
||||
"https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": "a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c",
|
||||
"https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": "a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb",
|
||||
"https://bcr.bazel.build/modules/rules_nodejs/6.2.0/MODULE.bazel": "ec27907f55eb34705adb4e8257952162a2d4c3ed0f0b3b4c3c1aad1fac7be35e",
|
||||
"https://bcr.bazel.build/modules/rules_nodejs/6.3.0/MODULE.bazel": "45345e4aba35dd6e4701c1eebf5a4e67af4ed708def9ebcdc6027585b34ee52d",
|
||||
"https://bcr.bazel.build/modules/rules_nodejs/6.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",
|
||||
@@ -200,17 +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.2.0/MODULE.bazel": "6f3a675677db8885be4d607fde14cc51829715e3a879fb016eb9bf336786ce6d",
|
||||
"https://bcr.bazel.build/modules/yq.bzl/0.3.2/MODULE.bazel": "0384efa70e8033d842ea73aa4b7199fa099709e236a7264345c03937166670b6",
|
||||
"https://bcr.bazel.build/modules/yq.bzl/0.3.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",
|
||||
@@ -221,7 +215,7 @@
|
||||
"moduleExtensions": {
|
||||
"@@aspect_rules_esbuild+//esbuild:extensions.bzl%esbuild": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "GnYkDpVOnWnYv+xwyhEi0qjk3Lvp4Wei30PeSIQF5vM=",
|
||||
"bzlTransitiveDigest": "3l5lERuIkp41OnB+ZcMQkXS5ttpwE3LfWmePbmwDofk=",
|
||||
"usagesDigest": "6We6zwGoawD9YXqMI0KPaxEKJTnamXBsuOekhFS2D40=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
@@ -436,8 +430,8 @@
|
||||
},
|
||||
"@@aspect_rules_ts+//ts:extensions.bzl%ext": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "0PprNyRYWkfOXKNvI8gaaD69N+xwJfjp1B9PAbgTdTI=",
|
||||
"usagesDigest": "5Eyb0Kvg0CG7XCiKJ/v4cA5Rl7qXRtsRk7ZmepukdzQ=",
|
||||
"bzlTransitiveDigest": "dhTbv9E6UfT1WJmmu3ORRPO6AKFJvgBjBxu+BO+u1RY=",
|
||||
"usagesDigest": "wfAUu+hWfjbN8K5K5tnyIyhWKZOHe5xnDfeOD7CIZZ8=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
@@ -455,8 +449,8 @@
|
||||
"rules_angular_npm_typescript": {
|
||||
"repoRuleId": "@@aspect_rules_ts+//ts/private:npm_repositories.bzl%http_archive_version",
|
||||
"attributes": {
|
||||
"version": "5.9.2",
|
||||
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
|
||||
"version": "6.0.3",
|
||||
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
|
||||
"urls": [
|
||||
"https://registry.npmjs.org/typescript/-/typescript-{}.tgz"
|
||||
]
|
||||
@@ -465,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"
|
||||
]
|
||||
@@ -475,8 +469,8 @@
|
||||
"npm_rules_browsers_typescript": {
|
||||
"repoRuleId": "@@aspect_rules_ts+//ts/private:npm_repositories.bzl%http_archive_version",
|
||||
"attributes": {
|
||||
"version": "5.8.2",
|
||||
"integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
|
||||
"version": "6.0.3",
|
||||
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
|
||||
"urls": [
|
||||
"https://registry.npmjs.org/typescript/-/typescript-{}.tgz"
|
||||
]
|
||||
@@ -500,7 +494,7 @@
|
||||
"@@aspect_tools_telemetry+//:extension.bzl%telemetry": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "cl5A2O84vDL6Tt+Qga8FCj1DUDGqn+e7ly5rZ+4xvcc=",
|
||||
"usagesDigest": "X9yWxTU9a+3PzHfKcQZZ8MzjmhcZcGinXvd3iA1e0Dw=",
|
||||
"usagesDigest": "XReaXejedAKAFKyp+2mfnFkPWXBJzM/VxiOYB4nyseY=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
@@ -509,7 +503,7 @@
|
||||
"repoRuleId": "@@aspect_tools_telemetry+//:extension.bzl%tel_repository",
|
||||
"attributes": {
|
||||
"deps": {
|
||||
"aspect_rules_ts": "3.8.6",
|
||||
"aspect_rules_ts": "3.8.8",
|
||||
"aspect_rules_js": "3.0.3",
|
||||
"aspect_rules_esbuild": "0.25.1",
|
||||
"aspect_rules_jasmine": "2.0.4",
|
||||
@@ -568,24 +562,24 @@
|
||||
},
|
||||
"@@rules_angular+//setup:extensions.bzl%rules_angular": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "fkaH7HMicL3g7/NDaFzlq39kcLopMyQ3KdbDn+5CRzA=",
|
||||
"usagesDigest": "RWY3uqO/f0lDK8WZtS5QwE7S7IrkU3PrHr2/Vje4M3s=",
|
||||
"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-local"
|
||||
}
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -953,8 +947,8 @@
|
||||
},
|
||||
"@@rules_nodejs+//nodejs:extensions.bzl%node": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "4pUxCNc22K4I+6+4Nxu52Hur12tFRfa1JMsN5mdDv60=",
|
||||
"usagesDigest": "b5S0m/ld5GaUSiR4bWVkvCiiWcK33vg+ynakv0PZl+o=",
|
||||
"bzlTransitiveDigest": "oZFClfRhTTwsYzpxVPkOpOt/r0+OzEfEV37au0jFZ0s=",
|
||||
"usagesDigest": "dp2HPl9Y2BFhrnM0JALIsJHz02rKnRBpISBHQX4qV7E=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
@@ -964,46 +958,46 @@
|
||||
"attributes": {
|
||||
"node_download_auth": {},
|
||||
"node_repositories": {
|
||||
"22.22.1-darwin_arm64": [
|
||||
"node-v22.22.1-darwin-arm64.tar.gz",
|
||||
"node-v22.22.1-darwin-arm64",
|
||||
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
|
||||
"22.22.2-darwin_arm64": [
|
||||
"node-v22.22.2-darwin-arm64.tar.gz",
|
||||
"node-v22.22.2-darwin-arm64",
|
||||
"db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
|
||||
],
|
||||
"22.22.1-darwin_amd64": [
|
||||
"node-v22.22.1-darwin-x64.tar.gz",
|
||||
"node-v22.22.1-darwin-x64",
|
||||
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
|
||||
"22.22.2-darwin_amd64": [
|
||||
"node-v22.22.2-darwin-x64.tar.gz",
|
||||
"node-v22.22.2-darwin-x64",
|
||||
"12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
|
||||
],
|
||||
"22.22.1-linux_arm64": [
|
||||
"node-v22.22.1-linux-arm64.tar.xz",
|
||||
"node-v22.22.1-linux-arm64",
|
||||
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
|
||||
"22.22.2-linux_arm64": [
|
||||
"node-v22.22.2-linux-arm64.tar.xz",
|
||||
"node-v22.22.2-linux-arm64",
|
||||
"e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
|
||||
],
|
||||
"22.22.1-linux_ppc64le": [
|
||||
"node-v22.22.1-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.1-linux-ppc64le",
|
||||
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
|
||||
"22.22.2-linux_ppc64le": [
|
||||
"node-v22.22.2-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.2-linux-ppc64le",
|
||||
"14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
|
||||
],
|
||||
"22.22.1-linux_s390x": [
|
||||
"node-v22.22.1-linux-s390x.tar.xz",
|
||||
"node-v22.22.1-linux-s390x",
|
||||
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
|
||||
"22.22.2-linux_s390x": [
|
||||
"node-v22.22.2-linux-s390x.tar.xz",
|
||||
"node-v22.22.2-linux-s390x",
|
||||
"9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
|
||||
],
|
||||
"22.22.1-linux_amd64": [
|
||||
"node-v22.22.1-linux-x64.tar.xz",
|
||||
"node-v22.22.1-linux-x64",
|
||||
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
|
||||
"22.22.2-linux_amd64": [
|
||||
"node-v22.22.2-linux-x64.tar.xz",
|
||||
"node-v22.22.2-linux-x64",
|
||||
"88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
|
||||
],
|
||||
"22.22.1-windows_amd64": [
|
||||
"node-v22.22.1-win-x64.zip",
|
||||
"node-v22.22.1-win-x64",
|
||||
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
|
||||
"22.22.2-windows_amd64": [
|
||||
"node-v22.22.2-win-x64.zip",
|
||||
"node-v22.22.2-win-x64",
|
||||
"7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
|
||||
]
|
||||
},
|
||||
"node_urls": [
|
||||
"https://nodejs.org/dist/v{version}/{filename}"
|
||||
],
|
||||
"node_version": "22.22.1",
|
||||
"node_version": "22.22.2",
|
||||
"include_headers": false,
|
||||
"platform": "linux_amd64"
|
||||
}
|
||||
@@ -1013,46 +1007,46 @@
|
||||
"attributes": {
|
||||
"node_download_auth": {},
|
||||
"node_repositories": {
|
||||
"22.22.1-darwin_arm64": [
|
||||
"node-v22.22.1-darwin-arm64.tar.gz",
|
||||
"node-v22.22.1-darwin-arm64",
|
||||
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
|
||||
"22.22.2-darwin_arm64": [
|
||||
"node-v22.22.2-darwin-arm64.tar.gz",
|
||||
"node-v22.22.2-darwin-arm64",
|
||||
"db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
|
||||
],
|
||||
"22.22.1-darwin_amd64": [
|
||||
"node-v22.22.1-darwin-x64.tar.gz",
|
||||
"node-v22.22.1-darwin-x64",
|
||||
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
|
||||
"22.22.2-darwin_amd64": [
|
||||
"node-v22.22.2-darwin-x64.tar.gz",
|
||||
"node-v22.22.2-darwin-x64",
|
||||
"12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
|
||||
],
|
||||
"22.22.1-linux_arm64": [
|
||||
"node-v22.22.1-linux-arm64.tar.xz",
|
||||
"node-v22.22.1-linux-arm64",
|
||||
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
|
||||
"22.22.2-linux_arm64": [
|
||||
"node-v22.22.2-linux-arm64.tar.xz",
|
||||
"node-v22.22.2-linux-arm64",
|
||||
"e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
|
||||
],
|
||||
"22.22.1-linux_ppc64le": [
|
||||
"node-v22.22.1-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.1-linux-ppc64le",
|
||||
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
|
||||
"22.22.2-linux_ppc64le": [
|
||||
"node-v22.22.2-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.2-linux-ppc64le",
|
||||
"14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
|
||||
],
|
||||
"22.22.1-linux_s390x": [
|
||||
"node-v22.22.1-linux-s390x.tar.xz",
|
||||
"node-v22.22.1-linux-s390x",
|
||||
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
|
||||
"22.22.2-linux_s390x": [
|
||||
"node-v22.22.2-linux-s390x.tar.xz",
|
||||
"node-v22.22.2-linux-s390x",
|
||||
"9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
|
||||
],
|
||||
"22.22.1-linux_amd64": [
|
||||
"node-v22.22.1-linux-x64.tar.xz",
|
||||
"node-v22.22.1-linux-x64",
|
||||
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
|
||||
"22.22.2-linux_amd64": [
|
||||
"node-v22.22.2-linux-x64.tar.xz",
|
||||
"node-v22.22.2-linux-x64",
|
||||
"88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
|
||||
],
|
||||
"22.22.1-windows_amd64": [
|
||||
"node-v22.22.1-win-x64.zip",
|
||||
"node-v22.22.1-win-x64",
|
||||
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
|
||||
"22.22.2-windows_amd64": [
|
||||
"node-v22.22.2-win-x64.zip",
|
||||
"node-v22.22.2-win-x64",
|
||||
"7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
|
||||
]
|
||||
},
|
||||
"node_urls": [
|
||||
"https://nodejs.org/dist/v{version}/{filename}"
|
||||
],
|
||||
"node_version": "22.22.1",
|
||||
"node_version": "22.22.2",
|
||||
"include_headers": false,
|
||||
"platform": "linux_arm64"
|
||||
}
|
||||
@@ -1062,46 +1056,46 @@
|
||||
"attributes": {
|
||||
"node_download_auth": {},
|
||||
"node_repositories": {
|
||||
"22.22.1-darwin_arm64": [
|
||||
"node-v22.22.1-darwin-arm64.tar.gz",
|
||||
"node-v22.22.1-darwin-arm64",
|
||||
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
|
||||
"22.22.2-darwin_arm64": [
|
||||
"node-v22.22.2-darwin-arm64.tar.gz",
|
||||
"node-v22.22.2-darwin-arm64",
|
||||
"db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
|
||||
],
|
||||
"22.22.1-darwin_amd64": [
|
||||
"node-v22.22.1-darwin-x64.tar.gz",
|
||||
"node-v22.22.1-darwin-x64",
|
||||
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
|
||||
"22.22.2-darwin_amd64": [
|
||||
"node-v22.22.2-darwin-x64.tar.gz",
|
||||
"node-v22.22.2-darwin-x64",
|
||||
"12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
|
||||
],
|
||||
"22.22.1-linux_arm64": [
|
||||
"node-v22.22.1-linux-arm64.tar.xz",
|
||||
"node-v22.22.1-linux-arm64",
|
||||
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
|
||||
"22.22.2-linux_arm64": [
|
||||
"node-v22.22.2-linux-arm64.tar.xz",
|
||||
"node-v22.22.2-linux-arm64",
|
||||
"e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
|
||||
],
|
||||
"22.22.1-linux_ppc64le": [
|
||||
"node-v22.22.1-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.1-linux-ppc64le",
|
||||
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
|
||||
"22.22.2-linux_ppc64le": [
|
||||
"node-v22.22.2-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.2-linux-ppc64le",
|
||||
"14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
|
||||
],
|
||||
"22.22.1-linux_s390x": [
|
||||
"node-v22.22.1-linux-s390x.tar.xz",
|
||||
"node-v22.22.1-linux-s390x",
|
||||
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
|
||||
"22.22.2-linux_s390x": [
|
||||
"node-v22.22.2-linux-s390x.tar.xz",
|
||||
"node-v22.22.2-linux-s390x",
|
||||
"9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
|
||||
],
|
||||
"22.22.1-linux_amd64": [
|
||||
"node-v22.22.1-linux-x64.tar.xz",
|
||||
"node-v22.22.1-linux-x64",
|
||||
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
|
||||
"22.22.2-linux_amd64": [
|
||||
"node-v22.22.2-linux-x64.tar.xz",
|
||||
"node-v22.22.2-linux-x64",
|
||||
"88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
|
||||
],
|
||||
"22.22.1-windows_amd64": [
|
||||
"node-v22.22.1-win-x64.zip",
|
||||
"node-v22.22.1-win-x64",
|
||||
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
|
||||
"22.22.2-windows_amd64": [
|
||||
"node-v22.22.2-win-x64.zip",
|
||||
"node-v22.22.2-win-x64",
|
||||
"7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
|
||||
]
|
||||
},
|
||||
"node_urls": [
|
||||
"https://nodejs.org/dist/v{version}/{filename}"
|
||||
],
|
||||
"node_version": "22.22.1",
|
||||
"node_version": "22.22.2",
|
||||
"include_headers": false,
|
||||
"platform": "linux_s390x"
|
||||
}
|
||||
@@ -1111,46 +1105,46 @@
|
||||
"attributes": {
|
||||
"node_download_auth": {},
|
||||
"node_repositories": {
|
||||
"22.22.1-darwin_arm64": [
|
||||
"node-v22.22.1-darwin-arm64.tar.gz",
|
||||
"node-v22.22.1-darwin-arm64",
|
||||
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
|
||||
"22.22.2-darwin_arm64": [
|
||||
"node-v22.22.2-darwin-arm64.tar.gz",
|
||||
"node-v22.22.2-darwin-arm64",
|
||||
"db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
|
||||
],
|
||||
"22.22.1-darwin_amd64": [
|
||||
"node-v22.22.1-darwin-x64.tar.gz",
|
||||
"node-v22.22.1-darwin-x64",
|
||||
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
|
||||
"22.22.2-darwin_amd64": [
|
||||
"node-v22.22.2-darwin-x64.tar.gz",
|
||||
"node-v22.22.2-darwin-x64",
|
||||
"12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
|
||||
],
|
||||
"22.22.1-linux_arm64": [
|
||||
"node-v22.22.1-linux-arm64.tar.xz",
|
||||
"node-v22.22.1-linux-arm64",
|
||||
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
|
||||
"22.22.2-linux_arm64": [
|
||||
"node-v22.22.2-linux-arm64.tar.xz",
|
||||
"node-v22.22.2-linux-arm64",
|
||||
"e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
|
||||
],
|
||||
"22.22.1-linux_ppc64le": [
|
||||
"node-v22.22.1-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.1-linux-ppc64le",
|
||||
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
|
||||
"22.22.2-linux_ppc64le": [
|
||||
"node-v22.22.2-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.2-linux-ppc64le",
|
||||
"14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
|
||||
],
|
||||
"22.22.1-linux_s390x": [
|
||||
"node-v22.22.1-linux-s390x.tar.xz",
|
||||
"node-v22.22.1-linux-s390x",
|
||||
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
|
||||
"22.22.2-linux_s390x": [
|
||||
"node-v22.22.2-linux-s390x.tar.xz",
|
||||
"node-v22.22.2-linux-s390x",
|
||||
"9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
|
||||
],
|
||||
"22.22.1-linux_amd64": [
|
||||
"node-v22.22.1-linux-x64.tar.xz",
|
||||
"node-v22.22.1-linux-x64",
|
||||
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
|
||||
"22.22.2-linux_amd64": [
|
||||
"node-v22.22.2-linux-x64.tar.xz",
|
||||
"node-v22.22.2-linux-x64",
|
||||
"88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
|
||||
],
|
||||
"22.22.1-windows_amd64": [
|
||||
"node-v22.22.1-win-x64.zip",
|
||||
"node-v22.22.1-win-x64",
|
||||
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
|
||||
"22.22.2-windows_amd64": [
|
||||
"node-v22.22.2-win-x64.zip",
|
||||
"node-v22.22.2-win-x64",
|
||||
"7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
|
||||
]
|
||||
},
|
||||
"node_urls": [
|
||||
"https://nodejs.org/dist/v{version}/{filename}"
|
||||
],
|
||||
"node_version": "22.22.1",
|
||||
"node_version": "22.22.2",
|
||||
"include_headers": false,
|
||||
"platform": "linux_ppc64le"
|
||||
}
|
||||
@@ -1160,46 +1154,46 @@
|
||||
"attributes": {
|
||||
"node_download_auth": {},
|
||||
"node_repositories": {
|
||||
"22.22.1-darwin_arm64": [
|
||||
"node-v22.22.1-darwin-arm64.tar.gz",
|
||||
"node-v22.22.1-darwin-arm64",
|
||||
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
|
||||
"22.22.2-darwin_arm64": [
|
||||
"node-v22.22.2-darwin-arm64.tar.gz",
|
||||
"node-v22.22.2-darwin-arm64",
|
||||
"db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
|
||||
],
|
||||
"22.22.1-darwin_amd64": [
|
||||
"node-v22.22.1-darwin-x64.tar.gz",
|
||||
"node-v22.22.1-darwin-x64",
|
||||
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
|
||||
"22.22.2-darwin_amd64": [
|
||||
"node-v22.22.2-darwin-x64.tar.gz",
|
||||
"node-v22.22.2-darwin-x64",
|
||||
"12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
|
||||
],
|
||||
"22.22.1-linux_arm64": [
|
||||
"node-v22.22.1-linux-arm64.tar.xz",
|
||||
"node-v22.22.1-linux-arm64",
|
||||
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
|
||||
"22.22.2-linux_arm64": [
|
||||
"node-v22.22.2-linux-arm64.tar.xz",
|
||||
"node-v22.22.2-linux-arm64",
|
||||
"e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
|
||||
],
|
||||
"22.22.1-linux_ppc64le": [
|
||||
"node-v22.22.1-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.1-linux-ppc64le",
|
||||
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
|
||||
"22.22.2-linux_ppc64le": [
|
||||
"node-v22.22.2-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.2-linux-ppc64le",
|
||||
"14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
|
||||
],
|
||||
"22.22.1-linux_s390x": [
|
||||
"node-v22.22.1-linux-s390x.tar.xz",
|
||||
"node-v22.22.1-linux-s390x",
|
||||
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
|
||||
"22.22.2-linux_s390x": [
|
||||
"node-v22.22.2-linux-s390x.tar.xz",
|
||||
"node-v22.22.2-linux-s390x",
|
||||
"9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
|
||||
],
|
||||
"22.22.1-linux_amd64": [
|
||||
"node-v22.22.1-linux-x64.tar.xz",
|
||||
"node-v22.22.1-linux-x64",
|
||||
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
|
||||
"22.22.2-linux_amd64": [
|
||||
"node-v22.22.2-linux-x64.tar.xz",
|
||||
"node-v22.22.2-linux-x64",
|
||||
"88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
|
||||
],
|
||||
"22.22.1-windows_amd64": [
|
||||
"node-v22.22.1-win-x64.zip",
|
||||
"node-v22.22.1-win-x64",
|
||||
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
|
||||
"22.22.2-windows_amd64": [
|
||||
"node-v22.22.2-win-x64.zip",
|
||||
"node-v22.22.2-win-x64",
|
||||
"7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
|
||||
]
|
||||
},
|
||||
"node_urls": [
|
||||
"https://nodejs.org/dist/v{version}/{filename}"
|
||||
],
|
||||
"node_version": "22.22.1",
|
||||
"node_version": "22.22.2",
|
||||
"include_headers": false,
|
||||
"platform": "darwin_amd64"
|
||||
}
|
||||
@@ -1209,46 +1203,46 @@
|
||||
"attributes": {
|
||||
"node_download_auth": {},
|
||||
"node_repositories": {
|
||||
"22.22.1-darwin_arm64": [
|
||||
"node-v22.22.1-darwin-arm64.tar.gz",
|
||||
"node-v22.22.1-darwin-arm64",
|
||||
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
|
||||
"22.22.2-darwin_arm64": [
|
||||
"node-v22.22.2-darwin-arm64.tar.gz",
|
||||
"node-v22.22.2-darwin-arm64",
|
||||
"db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
|
||||
],
|
||||
"22.22.1-darwin_amd64": [
|
||||
"node-v22.22.1-darwin-x64.tar.gz",
|
||||
"node-v22.22.1-darwin-x64",
|
||||
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
|
||||
"22.22.2-darwin_amd64": [
|
||||
"node-v22.22.2-darwin-x64.tar.gz",
|
||||
"node-v22.22.2-darwin-x64",
|
||||
"12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
|
||||
],
|
||||
"22.22.1-linux_arm64": [
|
||||
"node-v22.22.1-linux-arm64.tar.xz",
|
||||
"node-v22.22.1-linux-arm64",
|
||||
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
|
||||
"22.22.2-linux_arm64": [
|
||||
"node-v22.22.2-linux-arm64.tar.xz",
|
||||
"node-v22.22.2-linux-arm64",
|
||||
"e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
|
||||
],
|
||||
"22.22.1-linux_ppc64le": [
|
||||
"node-v22.22.1-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.1-linux-ppc64le",
|
||||
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
|
||||
"22.22.2-linux_ppc64le": [
|
||||
"node-v22.22.2-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.2-linux-ppc64le",
|
||||
"14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
|
||||
],
|
||||
"22.22.1-linux_s390x": [
|
||||
"node-v22.22.1-linux-s390x.tar.xz",
|
||||
"node-v22.22.1-linux-s390x",
|
||||
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
|
||||
"22.22.2-linux_s390x": [
|
||||
"node-v22.22.2-linux-s390x.tar.xz",
|
||||
"node-v22.22.2-linux-s390x",
|
||||
"9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
|
||||
],
|
||||
"22.22.1-linux_amd64": [
|
||||
"node-v22.22.1-linux-x64.tar.xz",
|
||||
"node-v22.22.1-linux-x64",
|
||||
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
|
||||
"22.22.2-linux_amd64": [
|
||||
"node-v22.22.2-linux-x64.tar.xz",
|
||||
"node-v22.22.2-linux-x64",
|
||||
"88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
|
||||
],
|
||||
"22.22.1-windows_amd64": [
|
||||
"node-v22.22.1-win-x64.zip",
|
||||
"node-v22.22.1-win-x64",
|
||||
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
|
||||
"22.22.2-windows_amd64": [
|
||||
"node-v22.22.2-win-x64.zip",
|
||||
"node-v22.22.2-win-x64",
|
||||
"7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
|
||||
]
|
||||
},
|
||||
"node_urls": [
|
||||
"https://nodejs.org/dist/v{version}/{filename}"
|
||||
],
|
||||
"node_version": "22.22.1",
|
||||
"node_version": "22.22.2",
|
||||
"include_headers": false,
|
||||
"platform": "darwin_arm64"
|
||||
}
|
||||
@@ -1258,46 +1252,46 @@
|
||||
"attributes": {
|
||||
"node_download_auth": {},
|
||||
"node_repositories": {
|
||||
"22.22.1-darwin_arm64": [
|
||||
"node-v22.22.1-darwin-arm64.tar.gz",
|
||||
"node-v22.22.1-darwin-arm64",
|
||||
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
|
||||
"22.22.2-darwin_arm64": [
|
||||
"node-v22.22.2-darwin-arm64.tar.gz",
|
||||
"node-v22.22.2-darwin-arm64",
|
||||
"db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
|
||||
],
|
||||
"22.22.1-darwin_amd64": [
|
||||
"node-v22.22.1-darwin-x64.tar.gz",
|
||||
"node-v22.22.1-darwin-x64",
|
||||
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
|
||||
"22.22.2-darwin_amd64": [
|
||||
"node-v22.22.2-darwin-x64.tar.gz",
|
||||
"node-v22.22.2-darwin-x64",
|
||||
"12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
|
||||
],
|
||||
"22.22.1-linux_arm64": [
|
||||
"node-v22.22.1-linux-arm64.tar.xz",
|
||||
"node-v22.22.1-linux-arm64",
|
||||
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
|
||||
"22.22.2-linux_arm64": [
|
||||
"node-v22.22.2-linux-arm64.tar.xz",
|
||||
"node-v22.22.2-linux-arm64",
|
||||
"e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
|
||||
],
|
||||
"22.22.1-linux_ppc64le": [
|
||||
"node-v22.22.1-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.1-linux-ppc64le",
|
||||
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
|
||||
"22.22.2-linux_ppc64le": [
|
||||
"node-v22.22.2-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.2-linux-ppc64le",
|
||||
"14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
|
||||
],
|
||||
"22.22.1-linux_s390x": [
|
||||
"node-v22.22.1-linux-s390x.tar.xz",
|
||||
"node-v22.22.1-linux-s390x",
|
||||
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
|
||||
"22.22.2-linux_s390x": [
|
||||
"node-v22.22.2-linux-s390x.tar.xz",
|
||||
"node-v22.22.2-linux-s390x",
|
||||
"9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
|
||||
],
|
||||
"22.22.1-linux_amd64": [
|
||||
"node-v22.22.1-linux-x64.tar.xz",
|
||||
"node-v22.22.1-linux-x64",
|
||||
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
|
||||
"22.22.2-linux_amd64": [
|
||||
"node-v22.22.2-linux-x64.tar.xz",
|
||||
"node-v22.22.2-linux-x64",
|
||||
"88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
|
||||
],
|
||||
"22.22.1-windows_amd64": [
|
||||
"node-v22.22.1-win-x64.zip",
|
||||
"node-v22.22.1-win-x64",
|
||||
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
|
||||
"22.22.2-windows_amd64": [
|
||||
"node-v22.22.2-win-x64.zip",
|
||||
"node-v22.22.2-win-x64",
|
||||
"7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
|
||||
]
|
||||
},
|
||||
"node_urls": [
|
||||
"https://nodejs.org/dist/v{version}/{filename}"
|
||||
],
|
||||
"node_version": "22.22.1",
|
||||
"node_version": "22.22.2",
|
||||
"include_headers": false,
|
||||
"platform": "windows_amd64"
|
||||
}
|
||||
@@ -1307,46 +1301,46 @@
|
||||
"attributes": {
|
||||
"node_download_auth": {},
|
||||
"node_repositories": {
|
||||
"22.22.1-darwin_arm64": [
|
||||
"node-v22.22.1-darwin-arm64.tar.gz",
|
||||
"node-v22.22.1-darwin-arm64",
|
||||
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
|
||||
"22.22.2-darwin_arm64": [
|
||||
"node-v22.22.2-darwin-arm64.tar.gz",
|
||||
"node-v22.22.2-darwin-arm64",
|
||||
"db4b275b83736df67533529a18cc55de2549a8329ace6c7bcc68f8d22d3c9000"
|
||||
],
|
||||
"22.22.1-darwin_amd64": [
|
||||
"node-v22.22.1-darwin-x64.tar.gz",
|
||||
"node-v22.22.1-darwin-x64",
|
||||
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
|
||||
"22.22.2-darwin_amd64": [
|
||||
"node-v22.22.2-darwin-x64.tar.gz",
|
||||
"node-v22.22.2-darwin-x64",
|
||||
"12a6abb9c2902cf48a21120da13f87fde1ed1b71a13330712949e8db818708ba"
|
||||
],
|
||||
"22.22.1-linux_arm64": [
|
||||
"node-v22.22.1-linux-arm64.tar.xz",
|
||||
"node-v22.22.1-linux-arm64",
|
||||
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
|
||||
"22.22.2-linux_arm64": [
|
||||
"node-v22.22.2-linux-arm64.tar.xz",
|
||||
"node-v22.22.2-linux-arm64",
|
||||
"e9e1930fd321a470e29bb68f30318bf58e3ecb4acb4f1533fb19c58328a091fe"
|
||||
],
|
||||
"22.22.1-linux_ppc64le": [
|
||||
"node-v22.22.1-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.1-linux-ppc64le",
|
||||
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
|
||||
"22.22.2-linux_ppc64le": [
|
||||
"node-v22.22.2-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.2-linux-ppc64le",
|
||||
"14045b5a5030d35ca0030fb7e870bd11a651eb9b57323ebc0021e8d78ac6bac9"
|
||||
],
|
||||
"22.22.1-linux_s390x": [
|
||||
"node-v22.22.1-linux-s390x.tar.xz",
|
||||
"node-v22.22.1-linux-s390x",
|
||||
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
|
||||
"22.22.2-linux_s390x": [
|
||||
"node-v22.22.2-linux-s390x.tar.xz",
|
||||
"node-v22.22.2-linux-s390x",
|
||||
"9e4a07c291b8949289c6ea8ee61b1d14666a4810feae776a8d1eb1f57e03a2fb"
|
||||
],
|
||||
"22.22.1-linux_amd64": [
|
||||
"node-v22.22.1-linux-x64.tar.xz",
|
||||
"node-v22.22.1-linux-x64",
|
||||
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
|
||||
"22.22.2-linux_amd64": [
|
||||
"node-v22.22.2-linux-x64.tar.xz",
|
||||
"node-v22.22.2-linux-x64",
|
||||
"88fd1ce767091fd8d4a99fdb2356e98c819f93f3b1f8663853a2dee9b438068a"
|
||||
],
|
||||
"22.22.1-windows_amd64": [
|
||||
"node-v22.22.1-win-x64.zip",
|
||||
"node-v22.22.1-win-x64",
|
||||
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
|
||||
"22.22.2-windows_amd64": [
|
||||
"node-v22.22.2-win-x64.zip",
|
||||
"node-v22.22.2-win-x64",
|
||||
"7c93e9d92bf68c07182b471aa187e35ee6cd08ef0f24ab060dfff605fcc1c57c"
|
||||
]
|
||||
},
|
||||
"node_urls": [
|
||||
"https://nodejs.org/dist/v{version}/{filename}"
|
||||
],
|
||||
"node_version": "22.22.1",
|
||||
"node_version": "22.22.2",
|
||||
"include_headers": false,
|
||||
"platform": "windows_arm64"
|
||||
}
|
||||
@@ -4113,7 +4107,7 @@
|
||||
},
|
||||
"@@rules_sass+//src/toolchain:extensions.bzl%sass": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "RA58Nyrsn03Z5YmQnpmBw3mqlVck++XIrx34amsqU/E=",
|
||||
"bzlTransitiveDigest": "mOfuR8PsNuUWEq7JZ4MpIRbwyAGAqrCvkXXGaRNnlPQ=",
|
||||
"usagesDigest": "R0KshhzIouLWuexMUCrl4HY+FUDwlVVgF9Z7UnwyUWA=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
@@ -4170,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.0",
|
||||
"@angular/build": "21.2.0",
|
||||
"@angular/cdk": "21.2.0",
|
||||
"@angular/cli": "21.2.0",
|
||||
"@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.0",
|
||||
"@angular/material": "21.2.9",
|
||||
"@angular/platform-browser": "workspace:*",
|
||||
"@angular/platform-server": "workspace:*",
|
||||
"@angular/router": "workspace:*",
|
||||
"@angular/ssr": "21.2.0",
|
||||
"@angular/ssr": "21.2.9",
|
||||
"@codemirror/autocomplete": "6.20.0",
|
||||
"@codemirror/commands": "6.10.1",
|
||||
"@codemirror/lang-angular": "0.1.4",
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
matrixParams: 'ignored',
|
||||
fragment: 'ignored',
|
||||
}"
|
||||
(click)="emitClickOnLink()"
|
||||
(click)="emitClickOnLink(item)"
|
||||
[matTooltip]="item.label"
|
||||
[matTooltipDisabled]="itemLabel.length < 27"
|
||||
matTooltipPosition="after"
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ export class NavigationList {
|
||||
readonly linkClicked = output<void>();
|
||||
|
||||
private readonly navigationState = inject(NavigationState);
|
||||
private readonly crossCategoryOrigin = this.navigationState.crossCategoryOrigin;
|
||||
|
||||
readonly activeItem = this.navigationState.activeNavigationItem;
|
||||
|
||||
@@ -51,10 +52,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
|
||||
}
|
||||
|
||||
@@ -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 ? (
|
||||
|
||||
@@ -27,14 +27,14 @@ export function CliCommandReference(entry: CliCommandRenderable) {
|
||||
<div className={'shiki line cli'}>
|
||||
ng {commandName(entry, command)}
|
||||
{entry.argumentsLabel && (
|
||||
<button member-id={'Arguments'} className="shiki-ln-line-argument">
|
||||
<span member-id={'Arguments'} className="shiki-ln-line-argument">
|
||||
{entry.argumentsLabel}
|
||||
</button>
|
||||
</span>
|
||||
)}
|
||||
{entry.optionsLabel && (
|
||||
<button member-id={'Options'} className="shiki-ln-line-option">
|
||||
<span member-id={'Options'} className="shiki-ln-line-option">
|
||||
{entry.optionsLabel}
|
||||
</button>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</code>
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -95,6 +95,7 @@ export async function addRenderableCodeToc<T extends DocEntry & HasModuleName>(
|
||||
{
|
||||
language: 'typescript',
|
||||
apiEntries: getSymbolsAsApiEntries(),
|
||||
removeWhitespace: false,
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -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()!,
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -135,4 +135,29 @@ describe('markdown to html', () => {
|
||||
// We ensure that we still style the heading content
|
||||
expect(markdownDocument.querySelector('strong')).toBeDefined();
|
||||
});
|
||||
|
||||
it('should strip all HTML tags from the aria-label attribute', () => {
|
||||
const markdownDocument = JSDOM.fragment(
|
||||
parseMarkdown(
|
||||
'## **Phase 5: Experimental Signal Forms (⚠️ WARNING: Subject to Change)**',
|
||||
rendererContext,
|
||||
),
|
||||
);
|
||||
const h2Anchor = markdownDocument.querySelector('h2 > a');
|
||||
|
||||
expect(h2Anchor!.innerHTML).toBe(
|
||||
'<strong><span class="docs-emoji">Phase 5: Experimental Signal Forms (⚠️ WARNING: Subject to Change)</span></strong>',
|
||||
);
|
||||
expect(h2Anchor!.getAttribute('aria-label')).toBe(
|
||||
'Link to Phase 5: Experimental Signal Forms (⚠️ WARNING: Subject to Change)',
|
||||
);
|
||||
});
|
||||
|
||||
it('should escape double quotes from the aria-label attribute', () => {
|
||||
const markdownDocument = JSDOM.fragment(parseMarkdown('## "Special" heading', rendererContext));
|
||||
const h2Anchor = markdownDocument.querySelector('h2 > a');
|
||||
|
||||
expect(h2Anchor!.innerHTML).toBe('"Special" heading');
|
||||
expect(h2Anchor!.getAttribute('aria-label')).toBe('Link to "Special" heading');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -31,7 +31,7 @@ export function headingRender(
|
||||
// Replace code backticks and remove custom ID syntax from the displayed label
|
||||
let label = parsedText.replace(/`(.*?)`/g, '<code>$1</code>');
|
||||
label = label.replace(/{#\s*[\w-]+\s*}/g, '').trim();
|
||||
const normalizedLabel = label.replace(/<\/?code>/g, '');
|
||||
const normalizedLabel = label.replace(/<[^>]+>/g, '').replace(/"/g, '"');
|
||||
|
||||
return `
|
||||
<h${depth} id="${link}">
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -426,6 +426,14 @@
|
||||
.docs-ref-content {
|
||||
padding: 1rem 0;
|
||||
|
||||
.docs-ref-option-and-description {
|
||||
.docs-reference-option {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
&: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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,15 @@ $code-font-size: 0.875rem;
|
||||
}
|
||||
}
|
||||
|
||||
.shiki.line.cli {
|
||||
span {
|
||||
color: var(--quaternary-contrast);
|
||||
font-family: var(--inter-font);
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.docs-light-mode .shiki {
|
||||
color: var(--shiki-light);
|
||||
background-color: var(--shiki-light-bg);
|
||||
@@ -46,7 +55,6 @@ $code-font-size: 0.875rem;
|
||||
/* Optional, if you also want font styles */
|
||||
font-style: var(--shiki-light-font-style);
|
||||
font-weight: var(--shiki-light-font-weight);
|
||||
text-decoration: var(--shiki-light-text-decoration);
|
||||
}
|
||||
|
||||
.shiki-ln-line-highlighted,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -41,3 +41,6 @@ export const setCookieConsent = (state: 'denied' | 'granted'): void => {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// This fixes the RollupError: Exported variable "global" is not defined.
|
||||
export {};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
provideZonelessChangeDetection,
|
||||
provideEnvironmentInitializer,
|
||||
} from '@angular/core';
|
||||
import {UrlSerializer} from '@angular/router';
|
||||
import {
|
||||
DOCS_CONTENT_LOADER,
|
||||
ENVIRONMENT,
|
||||
@@ -33,6 +34,7 @@ import {CustomErrorHandler} from './core/services/errors-handling/error-handler'
|
||||
import {ExampleContentLoader} from './core/services/example-content-loader.service';
|
||||
import {routerProviders} from './routing/router_providers';
|
||||
import {TYPESCRIPT_VFS_WORKER_PROVIDER} from './editor/code-editor/workers/factory-provider';
|
||||
import {AdevUrlSerializer} from './core/services/routing/adev-url-serializer';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
@@ -53,5 +55,9 @@ export const appConfig: ApplicationConfig = {
|
||||
deps: [DOCUMENT],
|
||||
},
|
||||
TYPESCRIPT_VFS_WORKER_PROVIDER,
|
||||
{
|
||||
provide: UrlSerializer,
|
||||
useClass: AdevUrlSerializer,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {DefaultUrlSerializer, UrlTree} from '@angular/router';
|
||||
|
||||
/**
|
||||
* Custom URL serializer extending the default behavior
|
||||
* with Adev-specific behavior.
|
||||
*/
|
||||
export class AdevUrlSerializer extends DefaultUrlSerializer {
|
||||
override parse(url: string): UrlTree {
|
||||
// Since the app host/server is decoding encoded forward slashes,
|
||||
// we perform this on the client as well in order to maintain
|
||||
// a consistent behavior between the two environments and
|
||||
// avoid opening a different page on client hydration (presumably, 404).
|
||||
url = url.replaceAll(/%2(F|f)/g, '/');
|
||||
|
||||
return super.parse(url);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {UrlSerializer} from '@angular/router';
|
||||
import {AdevUrlSerializer} from './adev-url-serializer';
|
||||
|
||||
describe('AdevUrlSerializer', () => {
|
||||
let serializer: UrlSerializer;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
{
|
||||
provide: UrlSerializer,
|
||||
useClass: AdevUrlSerializer,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
serializer = TestBed.inject(UrlSerializer);
|
||||
});
|
||||
|
||||
it('should decode encoded forward slash (%2F)', () => {
|
||||
// Uppercase hex
|
||||
expect(serializer.parse('page%2Fabout').toString()).toBe('/page/about');
|
||||
|
||||
// Lowercase hex
|
||||
expect(serializer.parse('page%2fabout').toString()).toBe('/page/about');
|
||||
});
|
||||
});
|
||||
@@ -19,6 +19,8 @@ import {NodeRuntimeSandbox} from '../node-runtime-sandbox.service';
|
||||
import {TypingsLoader} from '../typings-loader.service';
|
||||
|
||||
import {FileAndContentRecord} from '@angular/docs';
|
||||
import {DomSanitizer} from '@angular/platform-browser';
|
||||
import {NodeRuntimeState} from '../node-runtime-state.service';
|
||||
import {CODE_EDITOR_EXTENSIONS} from './constants/code-editor-extensions';
|
||||
import {LANGUAGES} from './constants/code-editor-languages';
|
||||
import {getAutocompleteExtension} from './extensions/autocomplete';
|
||||
@@ -26,10 +28,9 @@ import {getDiagnosticsExtension} from './extensions/diagnostics';
|
||||
import {getTooltipExtension} from './extensions/tooltip';
|
||||
import {DiagnosticsState} from './services/diagnostics-state.service';
|
||||
import {TsVfsWorkerActions} from './workers/enums/actions';
|
||||
import {TYPESCRIPT_VFS_WORKER_FACTORY} from './workers/factory-provider';
|
||||
import {CodeChangeRequest} from './workers/interfaces/code-change-request';
|
||||
import {ActionMessage} from './workers/interfaces/message';
|
||||
import {NodeRuntimeState} from '../node-runtime-state.service';
|
||||
import {TYPESCRIPT_VFS_WORKER_FACTORY} from './workers/factory-provider';
|
||||
|
||||
export interface EditorFile {
|
||||
filename: string;
|
||||
@@ -81,6 +82,7 @@ export class CodeMirrorEditor {
|
||||
private readonly typingsLoader = inject(TypingsLoader);
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
private readonly diagnosticsState = inject(DiagnosticsState);
|
||||
private readonly domSanitizer = inject(DomSanitizer);
|
||||
private readonly tsVfsWorkerFactory = inject(TYPESCRIPT_VFS_WORKER_FACTORY);
|
||||
private tsVfsWorker: Worker | null = null;
|
||||
|
||||
@@ -448,7 +450,12 @@ export class CodeMirrorEditor {
|
||||
this.sendRequestToTsVfs,
|
||||
this.diagnosticsState,
|
||||
),
|
||||
getTooltipExtension(this.eventManager$, this.currentFile, this.sendRequestToTsVfs),
|
||||
getTooltipExtension(
|
||||
this.eventManager$,
|
||||
this.currentFile,
|
||||
this.sendRequestToTsVfs,
|
||||
this.domSanitizer,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {DomSanitizer} from '@angular/platform-browser';
|
||||
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {getMarkedHtmlFromString, getTagsHtml} from './tooltip';
|
||||
|
||||
describe('getMarkedHtmlFromString', () => {
|
||||
it('sanitizes markdown HTML content before assigning to innerHTML', () => {
|
||||
const markdownContent = 'hello <img src=x onerror="alert(1)" />';
|
||||
const domSanitizer = TestBed.inject(DomSanitizer);
|
||||
|
||||
const result = getMarkedHtmlFromString(markdownContent, domSanitizer);
|
||||
|
||||
expect(result.innerHTML.trim()).toBe('<p>hello <img src="x"></p>');
|
||||
expect(result.innerHTML).not.toContain('onerror');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTagsHtml', () => {
|
||||
it('sanitizes JSDoc tag content before assigning to innerHTML', () => {
|
||||
const tags = [
|
||||
{
|
||||
name: 'example',
|
||||
text: [{text: 'hello <img src=x onerror="alert(1)" />'}],
|
||||
},
|
||||
] as any[];
|
||||
const domSanitizer = TestBed.inject(DomSanitizer);
|
||||
|
||||
const result = getTagsHtml(tags, domSanitizer);
|
||||
|
||||
expect(result.innerHTML).toContain('@example');
|
||||
expect(result.innerHTML).not.toContain('onerror');
|
||||
});
|
||||
});
|
||||
@@ -6,7 +6,9 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Signal} from '@angular/core';
|
||||
import {SecurityContext, Signal} from '@angular/core';
|
||||
import {DomSanitizer} from '@angular/platform-browser';
|
||||
|
||||
import {Tooltip, hoverTooltip} from '@codemirror/view';
|
||||
import {marked} from 'marked';
|
||||
import {Subject, filter, take} from 'rxjs';
|
||||
@@ -23,6 +25,7 @@ export const getTooltipExtension = (
|
||||
emitter: Subject<ActionMessage<DisplayTooltipResponse>>,
|
||||
currentFile: Signal<EditorFile>,
|
||||
sendRequestToTsVfs: (request: ActionMessage<DisplayTooltipRequest>) => void,
|
||||
domSanitizer: DomSanitizer,
|
||||
) => {
|
||||
return hoverTooltip(
|
||||
async (_, pos: number): Promise<Tooltip | null> => {
|
||||
@@ -58,9 +61,9 @@ export const getTooltipExtension = (
|
||||
|
||||
// use documentation if available as it's more informative than tags
|
||||
if (documentation?.[0]?.text) {
|
||||
tooltip.appendChild(getMarkedHtmlFromString(documentation[0]?.text));
|
||||
tooltip.appendChild(getMarkedHtmlFromString(documentation[0]?.text, domSanitizer));
|
||||
} else if (tags?.length) {
|
||||
tooltip.appendChild(getTagsHtml(tags));
|
||||
tooltip.appendChild(getTagsHtml(tags, domSanitizer));
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -91,9 +94,13 @@ function forceTooltipScrollTop() {
|
||||
}
|
||||
}
|
||||
|
||||
function getMarkedHtmlFromString(content: string): HTMLDivElement {
|
||||
export function getMarkedHtmlFromString(
|
||||
content: string,
|
||||
domSanitizer: DomSanitizer,
|
||||
): HTMLDivElement {
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.innerHTML = marked(content) as string;
|
||||
const sanitizedHtml = renderAndSanitizeMarkdownToHtml(content, domSanitizer);
|
||||
wrapper.innerHTML = sanitizedHtml;
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
@@ -123,7 +130,7 @@ function getHtmlFromDisplayParts(displayParts: ts.SymbolDisplayPart[]): HTMLDivE
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
function getTagsHtml(tags: ts.JSDocTagInfo[]): HTMLDivElement {
|
||||
export function getTagsHtml(tags: ts.JSDocTagInfo[], domSanitizer: DomSanitizer): HTMLDivElement {
|
||||
const tagsWrapper = document.createElement('div');
|
||||
|
||||
let contentString = '';
|
||||
@@ -138,7 +145,14 @@ function getTagsHtml(tags: ts.JSDocTagInfo[]): HTMLDivElement {
|
||||
}
|
||||
}
|
||||
|
||||
tagsWrapper.innerHTML = marked(contentString) as string;
|
||||
const sanitizedHtml = renderAndSanitizeMarkdownToHtml(contentString, domSanitizer);
|
||||
tagsWrapper.innerHTML = sanitizedHtml;
|
||||
|
||||
return tagsWrapper;
|
||||
}
|
||||
|
||||
function renderAndSanitizeMarkdownToHtml(content: string, domSanitizer: DomSanitizer): string {
|
||||
const markedHtml = marked(content) as string;
|
||||
const sanitizedHtml = domSanitizer.sanitize(SecurityContext.HTML, markedHtml) ?? '';
|
||||
return sanitizedHtml;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+60
-28
@@ -25,12 +25,14 @@
|
||||
border-block-end: 1px solid var(--senary-contrast);
|
||||
padding-block-end: 2rem;
|
||||
margin-block-end: 1rem;
|
||||
-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;
|
||||
@@ -44,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);
|
||||
@@ -87,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;
|
||||
@@ -107,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,
|
||||
@@ -782,8 +788,7 @@ export const RECOMMENDATIONS: Step[] = [
|
||||
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>.',
|
||||
action: 'Make sure you are using [Node 12 or later](https://nodejs.org/dist/latest-v12.x/).',
|
||||
},
|
||||
{
|
||||
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,4 +1,4 @@
|
||||
<div class="page docs-viewer">
|
||||
<main class="page docs-viewer">
|
||||
<h1 class="page-header" tabindex="-1">Update Guide</h1>
|
||||
<div class="wizard">
|
||||
<div>
|
||||
@@ -205,4 +205,4 @@
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -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,27 @@ 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: 'Async operations',
|
||||
path: 'guide/forms/signals/async-operations',
|
||||
@@ -660,6 +681,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 +885,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,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -875,7 +898,6 @@ export const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
|
||||
},
|
||||
{
|
||||
label: 'Build with AI',
|
||||
status: 'new',
|
||||
children: [
|
||||
{
|
||||
label: 'Get Started',
|
||||
@@ -888,9 +910,10 @@ export const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
|
||||
contentPath: 'ai/develop-with-ai',
|
||||
},
|
||||
{
|
||||
label: 'Design Patterns',
|
||||
path: 'ai/design-patterns',
|
||||
contentPath: 'ai/design-patterns',
|
||||
label: 'Agent Skills',
|
||||
path: 'ai/agent-skills',
|
||||
contentPath: 'ai/agent-skills',
|
||||
status: 'new',
|
||||
},
|
||||
{
|
||||
label: 'Angular CLI MCP Server setup',
|
||||
@@ -902,6 +925,11 @@ export const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
|
||||
path: 'ai/ai-tutor',
|
||||
contentPath: 'ai/ai-tutor',
|
||||
},
|
||||
{
|
||||
label: 'Design Patterns',
|
||||
path: 'ai/design-patterns',
|
||||
contentPath: 'ai/design-patterns',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -1037,16 +1065,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',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -128,13 +128,8 @@ export const REDIRECT_ROUTES: Route[] = [
|
||||
redirectTo: '/tools/cli/build-system-migration#hot-module-replacement',
|
||||
},
|
||||
{
|
||||
path: 'guide',
|
||||
children: [
|
||||
{
|
||||
path: 'pipes',
|
||||
redirectTo: '/guide/templates/pipes',
|
||||
},
|
||||
],
|
||||
path: 'guide/pipes',
|
||||
redirectTo: '/guide/templates/pipes',
|
||||
},
|
||||
{
|
||||
path: 'guide/experimental/zoneless',
|
||||
|
||||
@@ -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 |
@@ -0,0 +1,24 @@
|
||||
# Agent Skills
|
||||
|
||||
Agent Skills are specialized, domain-specific instructions and capabilities designed for AI agents like Gemini CLI. These skills provide architectural guidance, generate idiomatic Angular code, and help scaffold new projects using modern best practices.
|
||||
|
||||
By using Agent Skills, you can ensure that the AI agent you are working with has the most up-to-date information about Angular's conventions, reactivity models (like Signals), and project structure.
|
||||
|
||||
## Available Skills
|
||||
|
||||
The Angular team maintains a collection of official skills that are regularly updated to stay in sync with the latest framework improvements.
|
||||
|
||||
| Skill | Description |
|
||||
| :---------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| **`angular-developer`** | Generates Angular code and provides architectural guidance. Useful for creating components, services, or obtaining best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling, testing, or CLI tooling. |
|
||||
| **`angular-new-app`** | Creates a new Angular app using the Angular CLI. Provides important guidelines for effectively setting up and structuring a modern Angular application. |
|
||||
|
||||
## Using Agent Skills
|
||||
|
||||
Agent Skills are designed to be used with agentic coding tools like [Gemini CLI](https://geminicli.com/docs/cli/skills/), [Antigravity](https://antigravity.google/docs/skills) and more. Activating a skill loads the specific instructions and resources needed for that task.
|
||||
|
||||
To use these skills in your own environment you may follow the instructions for your specific tool or use a community tool like [skills.sh](https://skills.sh/).
|
||||
|
||||
```bash
|
||||
npx skills add https://github.com/angular/skills
|
||||
```
|
||||
@@ -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
|
||||
|
||||
@@ -115,4 +115,5 @@ To learn about LLM prompts and AI IDE setup, see the following guides:
|
||||
|
||||
<docs-pill-row>
|
||||
<docs-pill href="ai/develop-with-ai" title="LLM prompts and IDE setup"/>
|
||||
<docs-pill href="ai/agent-skills" title="Agent Skills"/>
|
||||
</docs-pill-row>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"branchName": "refs/heads/21.2.x",
|
||||
"sha": "a076ff7f05b678c4cdc6b85dbfe474a09f56022a"
|
||||
"sha": "faea5e033fd1bc0a5dec7e430434414d1cf6243d"
|
||||
}
|
||||
@@ -44,16 +44,6 @@
|
||||
"description": "A global unique identifier for the panel.",
|
||||
"jsdocTags": []
|
||||
},
|
||||
{
|
||||
"name": "panelId",
|
||||
"type": "InputSignal<string>",
|
||||
"memberType": "property",
|
||||
"memberTags": [
|
||||
"readonly"
|
||||
],
|
||||
"description": "A local unique identifier for the panel, used to match with its trigger's `panelId`.",
|
||||
"jsdocTags": []
|
||||
},
|
||||
{
|
||||
"name": "visible",
|
||||
"type": "Signal<boolean>",
|
||||
@@ -165,7 +155,7 @@
|
||||
}
|
||||
],
|
||||
"generics": [],
|
||||
"description": "The content panel of an accordion item that is conditionally visible.\n\nThis directive is a container for the content that is shown or hidden. It requires\na `panelId` that must match the `panelId` of its corresponding `ngAccordionTrigger`.\nThe content within the panel should be provided using an `ng-template` with the\n`ngAccordionContent` directive so that the content is not rendered on the page until the trigger\nis expanded. It applies `role=\"region\"` for accessibility and uses the `inert` attribute to hide\nits content from assistive technologies when not visible.\n\n```html\n<div ngAccordionPanel panelId=\"unique-id-1\">\n <ng-template ngAccordionContent>\n <p>This content is lazily rendered and will be shown when the panel is expanded.</p>\n </ng-template>\n</div>\n```",
|
||||
"description": "The content panel of an accordion item that is conditionally visible.\n\nThis directive is a container for the content that is shown or hidden. It should\nexpose a template reference that will be used by the corresponding `ngAccordionTrigger`.\nThe content within the panel should be provided using an `ng-template` with the\n`ngAccordionContent` directive so that the content is not rendered on the page until the trigger\nis expanded. It applies `role=\"region\"` for accessibility and uses the `inert` attribute to hide\nits content from assistive technologies when not visible.\n\n```html\n<div ngAccordionPanel #panel=\"ngAccordionPanel\">\n <ng-template ngAccordionContent>\n <p>This content is lazily rendered and will be shown when the panel is expanded.</p>\n </ng-template>\n</div>\n```",
|
||||
"jsdocTags": [
|
||||
{
|
||||
"name": "developerPreview",
|
||||
@@ -176,12 +166,12 @@
|
||||
"comment": "[Accordion](guide/aria/accordion)"
|
||||
}
|
||||
],
|
||||
"rawComment": "/**\n * The content panel of an accordion item that is conditionally visible.\n *\n * This directive is a container for the content that is shown or hidden. It requires\n * a `panelId` that must match the `panelId` of its corresponding `ngAccordionTrigger`.\n * The content within the panel should be provided using an `ng-template` with the\n * `ngAccordionContent` directive so that the content is not rendered on the page until the trigger\n * is expanded. It applies `role=\"region\"` for accessibility and uses the `inert` attribute to hide\n * its content from assistive technologies when not visible.\n *\n * ```html\n * <div ngAccordionPanel panelId=\"unique-id-1\">\n * <ng-template ngAccordionContent>\n * <p>This content is lazily rendered and will be shown when the panel is expanded.</p>\n * </ng-template>\n * </div>\n * ```\n *\n * @developerPreview 21.0\n * @see [Accordion](guide/aria/accordion)\n */",
|
||||
"rawComment": "/**\n * The content panel of an accordion item that is conditionally visible.\n *\n * This directive is a container for the content that is shown or hidden. It should\n * expose a template reference that will be used by the corresponding `ngAccordionTrigger`.\n * The content within the panel should be provided using an `ng-template` with the\n * `ngAccordionContent` directive so that the content is not rendered on the page until the trigger\n * is expanded. It applies `role=\"region\"` for accessibility and uses the `inert` attribute to hide\n * its content from assistive technologies when not visible.\n *\n * ```html\n * <div ngAccordionPanel #panel=\"ngAccordionPanel\">\n * <ng-template ngAccordionContent>\n * <p>This content is lazily rendered and will be shown when the panel is expanded.</p>\n * </ng-template>\n * </div>\n * ```\n *\n * @developerPreview 21.0\n * @see [Accordion](guide/aria/accordion)\n */",
|
||||
"implements": [],
|
||||
"source": {
|
||||
"filePath": "/src/aria/accordion/accordion-panel.ts",
|
||||
"startLine": 42,
|
||||
"endLine": 103
|
||||
"startLine": 34,
|
||||
"endLine": 88
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -199,6 +189,19 @@
|
||||
"description": "A reference to the trigger element.",
|
||||
"jsdocTags": []
|
||||
},
|
||||
{
|
||||
"name": "panel",
|
||||
"type": "InputSignal<AccordionPanel>",
|
||||
"memberType": "property",
|
||||
"memberTags": [
|
||||
"readonly",
|
||||
"input"
|
||||
],
|
||||
"description": "The associated AccordionPanel.",
|
||||
"jsdocTags": [],
|
||||
"inputAlias": "panel",
|
||||
"isRequiredInput": true
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"type": "InputSignal<any>",
|
||||
@@ -207,23 +210,20 @@
|
||||
"readonly",
|
||||
"input"
|
||||
],
|
||||
"description": "A unique identifier for the widget.",
|
||||
"description": "The unique identifier for the trigger.",
|
||||
"jsdocTags": [],
|
||||
"inputAlias": "id",
|
||||
"isRequiredInput": false
|
||||
},
|
||||
{
|
||||
"name": "panelId",
|
||||
"type": "InputSignal<string>",
|
||||
"type": "Signal<any>",
|
||||
"memberType": "property",
|
||||
"memberTags": [
|
||||
"readonly",
|
||||
"input"
|
||||
"readonly"
|
||||
],
|
||||
"description": "A local unique identifier for the trigger, used to match with its panel's `panelId`.",
|
||||
"jsdocTags": [],
|
||||
"inputAlias": "panelId",
|
||||
"isRequiredInput": true
|
||||
"description": "The unique identifier for the correspondingtrigger panel.",
|
||||
"jsdocTags": []
|
||||
},
|
||||
{
|
||||
"name": "disabled",
|
||||
@@ -263,6 +263,39 @@
|
||||
"description": "Whether the trigger is active.",
|
||||
"jsdocTags": []
|
||||
},
|
||||
{
|
||||
"name": "ngOnInit",
|
||||
"signatures": [
|
||||
{
|
||||
"name": "ngOnInit",
|
||||
"entryType": "function",
|
||||
"description": "",
|
||||
"generics": [],
|
||||
"isNewType": false,
|
||||
"jsdocTags": [],
|
||||
"params": [],
|
||||
"rawComment": "",
|
||||
"returnType": "void"
|
||||
}
|
||||
],
|
||||
"implementation": {
|
||||
"params": [],
|
||||
"isNewType": false,
|
||||
"returnType": "void",
|
||||
"generics": [],
|
||||
"name": "ngOnInit",
|
||||
"description": "",
|
||||
"entryType": "function",
|
||||
"jsdocTags": [],
|
||||
"rawComment": ""
|
||||
},
|
||||
"entryType": "function",
|
||||
"description": "",
|
||||
"jsdocTags": [],
|
||||
"rawComment": "",
|
||||
"memberType": "method",
|
||||
"memberTags": []
|
||||
},
|
||||
{
|
||||
"name": "expand",
|
||||
"signatures": [
|
||||
@@ -364,7 +397,7 @@
|
||||
}
|
||||
],
|
||||
"generics": [],
|
||||
"description": "The trigger that toggles the visibility of its associated `ngAccordionPanel`.\n\nThis directive requires a `panelId` that must match the `panelId` of the `ngAccordionPanel` it\ncontrols. When clicked, it will expand or collapse the panel. It also handles keyboard\ninteractions for navigation within the `ngAccordionGroup`. It applies `role=\"button\"` and manages\n`aria-expanded`, `aria-controls`, and `aria-disabled` attributes for accessibility.\nThe `disabled` input can be used to disable the trigger.\n\n```html\n<button ngAccordionTrigger panelId=\"unique-id-1\">\n Accordion Trigger Text\n</button>\n```",
|
||||
"description": "The trigger that toggles the visibility of its associated `ngAccordionPanel`.\n\nThis directive requires the `panel` input be set to the template reference of the `ngAccordionPanel`\nit controls. When clicked, it will expand or collapse the panel. It also handles keyboard\ninteractions for navigation within the `ngAccordionGroup`. It applies `role=\"button\"` and manages\n`aria-expanded`, `aria-controls`, and `aria-disabled` attributes for accessibility.\nThe `disabled` input can be used to disable the trigger.\n\n```html\n<button ngAccordionTrigger [panel]=\"panel\">\n Accordion Trigger Text\n</button>\n```",
|
||||
"jsdocTags": [
|
||||
{
|
||||
"name": "developerPreview",
|
||||
@@ -375,8 +408,10 @@
|
||||
"comment": "[Accordion](guide/aria/accordion)"
|
||||
}
|
||||
],
|
||||
"rawComment": "/**\n * The trigger that toggles the visibility of its associated `ngAccordionPanel`.\n *\n * This directive requires a `panelId` that must match the `panelId` of the `ngAccordionPanel` it\n * controls. When clicked, it will expand or collapse the panel. It also handles keyboard\n * interactions for navigation within the `ngAccordionGroup`. It applies `role=\"button\"` and manages\n * `aria-expanded`, `aria-controls`, and `aria-disabled` attributes for accessibility.\n * The `disabled` input can be used to disable the trigger.\n *\n * ```html\n * <button ngAccordionTrigger panelId=\"unique-id-1\">\n * Accordion Trigger Text\n * </button>\n * ```\n *\n * @developerPreview 21.0\n * @see [Accordion](guide/aria/accordion)\n */",
|
||||
"implements": [],
|
||||
"rawComment": "/**\n * The trigger that toggles the visibility of its associated `ngAccordionPanel`.\n *\n * This directive requires the `panel` input be set to the template reference of the `ngAccordionPanel`\n * it controls. When clicked, it will expand or collapse the panel. It also handles keyboard\n * interactions for navigation within the `ngAccordionGroup`. It applies `role=\"button\"` and manages\n * `aria-expanded`, `aria-controls`, and `aria-disabled` attributes for accessibility.\n * The `disabled` input can be used to disable the trigger.\n *\n * ```html\n * <button ngAccordionTrigger [panel]=\"panel\">\n * Accordion Trigger Text\n * </button>\n * ```\n *\n * @developerPreview 21.0\n * @see [Accordion](guide/aria/accordion)\n */",
|
||||
"implements": [
|
||||
"OnInit"
|
||||
],
|
||||
"isStandalone": true,
|
||||
"selector": "[ngAccordionTrigger]",
|
||||
"exportAs": [
|
||||
@@ -388,7 +423,7 @@
|
||||
"source": {
|
||||
"filePath": "/src/aria/accordion/accordion-trigger.ts",
|
||||
"startLine": 42,
|
||||
"endLine": 107
|
||||
"endLine": 112
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -536,7 +571,7 @@
|
||||
}
|
||||
],
|
||||
"generics": [],
|
||||
"description": "A container for a group of accordion items. It manages the overall state and\ninteractions of the accordion, such as keyboard navigation and expansion mode.\n\nThe `ngAccordionGroup` serves as the root of a group of accordion triggers and panels,\ncoordinating the behavior of the `ngAccordionTrigger` and `ngAccordionPanel` elements within it.\nIt supports both single and multiple expansion modes.\n\n```html\n<div ngAccordionGroup [multiExpandable]=\"true\" [(expandedPanels)]=\"expandedItems\">\n <div class=\"accordion-item\">\n <h3>\n <button ngAccordionTrigger panelId=\"item-1\">Item 1</button>\n </h3>\n <div ngAccordionPanel panelId=\"item-1\">\n <ng-template ngAccordionContent>\n <p>Content for Item 1.</p>\n </ng-template>\n </div>\n </div>\n <div class=\"accordion-item\">\n <h3>\n <button ngAccordionTrigger panelId=\"item-2\">Item 2</button>\n </h3>\n <div ngAccordionPanel panelId=\"item-2\">\n <ng-template ngAccordionContent>\n <p>Content for Item 2.</p>\n </ng-template>\n </div>\n </div>\n</div>\n```",
|
||||
"description": "A container for a group of accordion items. It manages the overall state and\ninteractions of the accordion, such as keyboard navigation and expansion mode.\n\nThe `ngAccordionGroup` serves as the root of a group of accordion triggers and panels,\ncoordinating the behavior of the `ngAccordionTrigger` and `ngAccordionPanel` elements within it.\nIt supports both single and multiple expansion modes.\n\n```html\n<div ngAccordionGroup [multiExpandable]=\"true\">\n <div class=\"accordion-item\">\n <h3>\n <button ngAccordionTrigger [panel]=\"panel1\">Item 1</button>\n </h3>\n <div ngAccordionPanel #panel1=\"ngAccordionPanel\">\n <ng-template ngAccordionContent>\n <p>Content for Item 1.</p>\n </ng-template>\n </div>\n </div>\n <div class=\"accordion-item\">\n <h3>\n <button ngAccordionTrigger [panel]=\"panel2\">Item 2</button>\n </h3>\n <div ngAccordionPanel #panel2=\"ngAccordionPanel\">\n <ng-template ngAccordionContent>\n <p>Content for Item 2.</p>\n </ng-template>\n </div>\n </div>\n</div>\n```",
|
||||
"jsdocTags": [
|
||||
{
|
||||
"name": "developerPreview",
|
||||
@@ -547,7 +582,7 @@
|
||||
"comment": "[Accordion](guide/aria/accordion)"
|
||||
}
|
||||
],
|
||||
"rawComment": "/**\n * A container for a group of accordion items. It manages the overall state and\n * interactions of the accordion, such as keyboard navigation and expansion mode.\n *\n * The `ngAccordionGroup` serves as the root of a group of accordion triggers and panels,\n * coordinating the behavior of the `ngAccordionTrigger` and `ngAccordionPanel` elements within it.\n * It supports both single and multiple expansion modes.\n *\n * ```html\n * <div ngAccordionGroup [multiExpandable]=\"true\" [(expandedPanels)]=\"expandedItems\">\n * <div class=\"accordion-item\">\n * <h3>\n * <button ngAccordionTrigger panelId=\"item-1\">Item 1</button>\n * </h3>\n * <div ngAccordionPanel panelId=\"item-1\">\n * <ng-template ngAccordionContent>\n * <p>Content for Item 1.</p>\n * </ng-template>\n * </div>\n * </div>\n * <div class=\"accordion-item\">\n * <h3>\n * <button ngAccordionTrigger panelId=\"item-2\">Item 2</button>\n * </h3>\n * <div ngAccordionPanel panelId=\"item-2\">\n * <ng-template ngAccordionContent>\n * <p>Content for Item 2.</p>\n * </ng-template>\n * </div>\n * </div>\n * </div>\n * ```\n *\n * @developerPreview 21.0\n * @see [Accordion](guide/aria/accordion)\n */",
|
||||
"rawComment": "/**\n * A container for a group of accordion items. It manages the overall state and\n * interactions of the accordion, such as keyboard navigation and expansion mode.\n *\n * The `ngAccordionGroup` serves as the root of a group of accordion triggers and panels,\n * coordinating the behavior of the `ngAccordionTrigger` and `ngAccordionPanel` elements within it.\n * It supports both single and multiple expansion modes.\n *\n * ```html\n * <div ngAccordionGroup [multiExpandable]=\"true\">\n * <div class=\"accordion-item\">\n * <h3>\n * <button ngAccordionTrigger [panel]=\"panel1\">Item 1</button>\n * </h3>\n * <div ngAccordionPanel #panel1=\"ngAccordionPanel\">\n * <ng-template ngAccordionContent>\n * <p>Content for Item 1.</p>\n * </ng-template>\n * </div>\n * </div>\n * <div class=\"accordion-item\">\n * <h3>\n * <button ngAccordionTrigger [panel]=\"panel2\">Item 2</button>\n * </h3>\n * <div ngAccordionPanel #panel2=\"ngAccordionPanel\">\n * <ng-template ngAccordionContent>\n * <p>Content for Item 2.</p>\n * </ng-template>\n * </div>\n * </div>\n * </div>\n * ```\n *\n * @developerPreview 21.0\n * @see [Accordion](guide/aria/accordion)\n */",
|
||||
"implements": [],
|
||||
"isStandalone": true,
|
||||
"selector": "[ngAccordionGroup]",
|
||||
@@ -559,8 +594,8 @@
|
||||
],
|
||||
"source": {
|
||||
"filePath": "src/aria/accordion/accordion-group.ts",
|
||||
"startLine": 62,
|
||||
"endLine": 158
|
||||
"startLine": 60,
|
||||
"endLine": 120
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -569,28 +604,20 @@
|
||||
"Directive",
|
||||
"@angular/core"
|
||||
],
|
||||
[
|
||||
"input",
|
||||
"@angular/core"
|
||||
],
|
||||
[
|
||||
"inject",
|
||||
"@angular/core"
|
||||
],
|
||||
[
|
||||
"afterRenderEffect",
|
||||
"@angular/core"
|
||||
],
|
||||
[
|
||||
"signal",
|
||||
"@angular/core"
|
||||
],
|
||||
[
|
||||
"computed",
|
||||
"@angular/core"
|
||||
],
|
||||
[
|
||||
"WritableSignal",
|
||||
"inject",
|
||||
"@angular/core"
|
||||
],
|
||||
[
|
||||
"input",
|
||||
"@angular/core"
|
||||
],
|
||||
[
|
||||
@@ -602,17 +629,25 @@
|
||||
"@angular/core"
|
||||
],
|
||||
[
|
||||
"model",
|
||||
"OnInit",
|
||||
"@angular/core"
|
||||
],
|
||||
[
|
||||
"booleanAttribute",
|
||||
"@angular/core"
|
||||
],
|
||||
[
|
||||
"model",
|
||||
"@angular/core"
|
||||
],
|
||||
[
|
||||
"contentChildren",
|
||||
"@angular/core"
|
||||
],
|
||||
[
|
||||
"signal",
|
||||
"@angular/core"
|
||||
],
|
||||
[
|
||||
"Directionality",
|
||||
"@angular/cdk/bidi"
|
||||
@@ -645,10 +680,6 @@
|
||||
"AccordionPanel.id",
|
||||
"@angular/aria/accordion"
|
||||
],
|
||||
[
|
||||
"AccordionPanel.panelId",
|
||||
"@angular/aria/accordion"
|
||||
],
|
||||
[
|
||||
"AccordionPanel.visible",
|
||||
"@angular/aria/accordion"
|
||||
@@ -673,6 +704,10 @@
|
||||
"AccordionTrigger.element",
|
||||
"@angular/aria/accordion"
|
||||
],
|
||||
[
|
||||
"AccordionTrigger.panel",
|
||||
"@angular/aria/accordion"
|
||||
],
|
||||
[
|
||||
"AccordionTrigger.id",
|
||||
"@angular/aria/accordion"
|
||||
@@ -693,6 +728,10 @@
|
||||
"AccordionTrigger.active",
|
||||
"@angular/aria/accordion"
|
||||
],
|
||||
[
|
||||
"AccordionTrigger.ngOnInit",
|
||||
"@angular/aria/accordion"
|
||||
],
|
||||
[
|
||||
"AccordionTrigger.expand",
|
||||
"@angular/aria/accordion"
|
||||
|
||||
@@ -792,7 +792,7 @@
|
||||
"source": {
|
||||
"filePath": "/src/aria/menu/menu.ts",
|
||||
"startLine": 58,
|
||||
"endLine": 194
|
||||
"endLine": 201
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -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": "fc8b94d631a5d105a87abc2a008a6e8f76d7f3f5"
|
||||
"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"
|
||||
|
||||
@@ -1142,8 +1142,8 @@
|
||||
"implements": [],
|
||||
"source": {
|
||||
"filePath": "/src/cdk/testing/selenium-webdriver/selenium-web-driver-harness-environment.ts",
|
||||
"startLine": 35,
|
||||
"endLine": 38
|
||||
"startLine": 34,
|
||||
"endLine": 37
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1194,8 +1194,8 @@
|
||||
"rawComment": "/** Waits for angular to be ready after the page load. */",
|
||||
"source": {
|
||||
"filePath": "/src/cdk/testing/selenium-webdriver/selenium-web-driver-harness-environment.ts",
|
||||
"startLine": 65,
|
||||
"endLine": 68
|
||||
"startLine": 66,
|
||||
"endLine": 69
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1635,8 +1635,8 @@
|
||||
"implements": [],
|
||||
"source": {
|
||||
"filePath": "/src/cdk/testing/selenium-webdriver/selenium-web-driver-harness-environment.ts",
|
||||
"startLine": 71,
|
||||
"endLine": 150
|
||||
"startLine": 72,
|
||||
"endLine": 151
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"branchName": "refs/heads/21.2.x",
|
||||
"sha": "8e9555870edb3275b35d299613ef3cf9d3bfb73a"
|
||||
"sha": "a8aca91bb6d490f66b6bdc873e3e350b9a1addad"
|
||||
}
|
||||
@@ -109,7 +109,7 @@
|
||||
"aliases": [
|
||||
"s"
|
||||
],
|
||||
"description": "Include the styles for the root component directly within the `app.component.ts` file. Only CSS styles can be included inline. By default, a separate stylesheet file (e.g., `app.component.css`) is created."
|
||||
"description": "Include the styles for the root component directly within the `app.ts` file. Only CSS styles can be included inline. By default, a separate stylesheet file (e.g., `app.css`) is created."
|
||||
},
|
||||
{
|
||||
"name": "inline-template",
|
||||
@@ -117,7 +117,7 @@
|
||||
"aliases": [
|
||||
"t"
|
||||
],
|
||||
"description": "Include the HTML template for the root component directly within the `app.component.ts` file. By default, a separate template file (e.g., `app.component.html`) is created."
|
||||
"description": "Include the HTML template for the root component directly within the `app.ts` file. By default, a separate template file (e.g., `app.html`) is created."
|
||||
},
|
||||
{
|
||||
"name": "minimal",
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
"aliases": [
|
||||
"s"
|
||||
],
|
||||
"description": "Include the styles for the initial application's root component directly within the `app.component.ts` file. By default, a separate stylesheet file (e.g., `app.component.css`) is created."
|
||||
"description": "Include the styles for the initial application's root component directly within the `app.ts` file. By default, a separate stylesheet file (e.g., `app.css`) is created."
|
||||
},
|
||||
{
|
||||
"name": "inline-template",
|
||||
@@ -99,7 +99,7 @@
|
||||
"aliases": [
|
||||
"t"
|
||||
],
|
||||
"description": "Include the HTML template for the initial application's root component directly within the `app.component.ts` file. By default, a separate template file (e.g., `app.component.html`) is created."
|
||||
"description": "Include the HTML template for the initial application's root component directly within the `app.ts` file. By default, a separate template file (e.g., `app.html`) is created."
|
||||
},
|
||||
{
|
||||
"name": "interactive",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user