Compare commits

..

1 Commits

Author SHA1 Message Date
Ben Hong d63f71931e docs: fix outdated security guide reference 2024-03-27 11:10:49 -07:00
3935 changed files with 311508 additions and 267404 deletions
-1
View File
@@ -17,7 +17,6 @@ integration/cli-hello-world-ivy-i18n/node_modules
integration/cli-hello-world-lazy/node_modules
integration/cli-hello-world-mocha/node_modules
integration/cli-signal-inputs/node_modules
integration/platform-server-hydration/node_modules
integration/defer/node_modules
integration/dynamic-compiler/node_modules
integration/forms/node_modules
+17 -7
View File
@@ -56,17 +56,15 @@ build --enable_runfiles
build:release --workspace_status_command="yarn -s ng-dev release build-env-stamp --mode=release"
build:release --stamp
# Building AIO against local Angular deps requires stamping
# versions in Angular packages due to CLI version checks.
build:aio_local_deps --stamp
build:aio_local_deps --workspace_status_command="yarn -s --cwd aio local-workspace-status"
# Snapshots should also be stamped with version control information.
build:snapshot-build --workspace_status_command="yarn -s ng-dev release build-env-stamp --mode=snapshot"
build:snapshot-build --stamp
# Angular DevTools for Firefox releases *cannot* be stamped and `--config snapshot-build-firefox` is a no-op.
# This is because Mozilla requires add-on source code to be uploaded and then they manually reproduce the build.
# If we stamp the build based on Git information such as the current commit, then reproducing the build would require
# uploading the entire `.git` directory. We already must upload the entire monorepo, and uploading `.git` as well
# exceeds the max source file size. To address this, we just *don't* stamp Firefox builds of Angular DevTools.
build:snapshot-build-firefox --nostamp
##########################################################
# AIO architect build configuration #
# See aio/angular.json for available configurations. #
@@ -76,6 +74,14 @@ build:snapshot-build-firefox --nostamp
##########################################################
build --flag_alias=aio_build_config=//aio:flag_aio_build_config
####################################
# AIO first party dep substitution #
# Turn on with #
# --config=aio_local_deps #
####################################
build:aio_local_deps --//aio:flag_aio_local_deps
###############################
# Output #
###############################
@@ -112,6 +118,10 @@ common:remote --jobs=200
build:remote --google_default_credentials
# Limit the number of test jobs for on an AIO local deps build. The example tests running
# concurrently pushes the circleci executor RAM usage to its limits.
test:aio_local_deps --jobs=24
# Force remote exeuctions to consider the entire run as linux
build:remote --cpu=k8
build:remote --host_cpu=k8
@@ -8,6 +8,7 @@
"devondcarew.bazel-code",
"gkalpak.aio-docs-utils",
"ms-vscode.vscode-typescript-tslint-plugin",
"xaver.clang-format",
// The following extensions are useful when working on angular.io (i.e. inside the `aio/` directory).
//"angular.ng-template",
//"dbaeumer.vscode-eslint",
+1 -1
View File
@@ -1,4 +1,4 @@
name: 'Docs or angular.dev Bug Report'
name: 'Docs or angular.io Bug Report'
description: Report an issue in Angular's documentation or angular.io application
body:
@@ -1,18 +0,0 @@
load("//tools:defaults.bzl", "esbuild_checked_in")
exports_files([
"tsconfig.json",
])
esbuild_checked_in(
name = "main",
entry_point = "//.github/actions/deploy-docs-site/lib:main.ts",
external = [
"undici",
],
platform = "node",
target = "node14",
deps = [
"//.github/actions/deploy-docs-site/lib",
],
)
@@ -1,16 +0,0 @@
name: 'Deploy angular.dev site'
description: 'Automatically deploy and set up redirects for angular.dev'
author: 'Angular'
inputs:
serviceKey:
description: 'The service key used for firebase deployments.'
required: true
configPath:
description: 'The path to the firebase config file.'
required: true
distDir:
description: 'The path to the firebase dist directory.'
required: true
runs:
using: 'node20'
main: 'main.js'
@@ -1,23 +0,0 @@
load("//tools:defaults.bzl", "ts_library")
package(default_visibility = ["//.github/actions/deploy-docs-site:__subpackages__"])
exports_files([
"main.ts",
])
ts_library(
name = "lib",
srcs = glob(
["*.ts"],
),
#tsconfig = "//.github/actions/deploy-docs-site:tsconfig.json",
deps = [
"@npm//@actions/core",
"@npm//@actions/github",
"@npm//@angular/ng-dev",
"@npm//@types/node",
"@npm//@types/tmp",
"@npm//tmp",
],
)
@@ -1,15 +0,0 @@
import {fileSync} from 'tmp';
import {writeSync} from 'fs';
import {getInput, setSecret} from '@actions/core';
let credentialFilePath: undefined | string;
export function getCredentialFilePath(): string {
if (credentialFilePath === undefined) {
const tmpFile = fileSync({postfix: '.json'});
writeSync(tmpFile.fd, getInput('serviceKey', {required: true}));
setSecret(tmpFile.name);
credentialFilePath = tmpFile.name;
}
return credentialFilePath;
}
@@ -1,116 +0,0 @@
import {cp, mkdtemp, readFile, rm, writeFile} from 'fs/promises';
import {Deployment} from './deployments';
import {join} from 'path';
import {tmpdir} from 'os';
import {spawnSync} from 'child_process';
import {getCredentialFilePath} from './credential';
export async function deployToFirebase(
deployment: Deployment,
configPath: string,
distDirPath: string,
) {
if (deployment.destination == undefined) {
console.log(`No deployment necessary for docs created from: ${deployment.branch}`);
return;
}
console.log('Preparing for deployment to firebase...');
const tmpDeployDir = await mkdtemp(join(tmpdir(), 'deploy-directory'));
const deployConfigPath = join(tmpDeployDir, 'firebase.json');
const config = JSON.parse(await readFile(configPath, {encoding: 'utf-8'})) as {
hosting: {public: string};
};
config['hosting']['public'] = './dist';
await writeFile(deployConfigPath, JSON.stringify(config, null, 2));
await cp(distDirPath, join(tmpDeployDir, 'dist'), {recursive: true});
spawnSync(`chmod 777 -R ${tmpDeployDir}`, {encoding: 'utf-8', shell: true});
firebase(
`target:clear --config ${deployConfigPath} --project angular-dev-site hosting angular-docs`,
tmpDeployDir,
);
firebase(
`target:apply --config ${deployConfigPath} --project angular-dev-site hosting angular-docs ${deployment.destination}`,
tmpDeployDir,
);
firebase(
`deploy --config ${deployConfigPath} --project angular-dev-site --only hosting --non-interactive`,
tmpDeployDir,
);
firebase(
`target:clear --config ${deployConfigPath} --project angular-dev-site hosting angular-docs`,
tmpDeployDir,
);
await rm(tmpDeployDir, {recursive: true});
}
export async function setupRedirect(deployment: Deployment) {
if (deployment.redirect === undefined) {
console.log(`No redirect necessary for docs created from: ${deployment.branch}`);
return;
}
console.log('Preparing to set up redirect on firebase...');
const redirectConfig = JSON.stringify(
{
hosting: {
target: 'angular-docs',
redirects: [
{
type: 302,
regex: '^(.*)$',
destination: `${deployment.redirect.to}:1`,
},
],
},
},
null,
2,
);
const tmpRedirectDir = await mkdtemp(join(tmpdir(), 'redirect-directory'));
const redirectConfigPath = join(tmpRedirectDir, 'firebase.json');
await writeFile(redirectConfigPath, redirectConfig);
spawnSync(`chmod 777 -R ${tmpRedirectDir}`, {encoding: 'utf-8', shell: true});
firebase(
`target:clear --config ${redirectConfigPath} --project angular-dev-site hosting angular-docs`,
tmpRedirectDir,
);
firebase(
`target:apply --config ${redirectConfigPath} --project angular-dev-site hosting angular-docs ${deployment.redirect.from}`,
tmpRedirectDir,
);
firebase(
`deploy --config ${redirectConfigPath} --project angular-dev-site --only hosting --non-interactive`,
tmpRedirectDir,
);
firebase(
`target:clear --config ${redirectConfigPath} --project angular-dev-site hosting angular-docs`,
tmpRedirectDir,
);
await rm(tmpRedirectDir, {recursive: true});
}
function firebase(cmd: string, cwd?: string) {
spawnSync('npx', `-y firebase-tools@latest ${cmd}`.split(' '), {
cwd,
encoding: 'utf-8',
shell: true,
stdio: 'inherit',
env: {
...process.env,
GOOGLE_APPLICATION_CREDENTIALS: getCredentialFilePath(),
},
});
}
@@ -1,67 +0,0 @@
import {fetchLongTermSupportBranchesFromNpm, ActiveReleaseTrains} from '@angular/ng-dev';
import {ReleaseConfig} from '@angular/ng-dev';
import {GitClient} from '@angular/ng-dev';
export interface Deployment {
branch: string;
redirect?: {
from: string;
to: string;
};
destination?: string;
}
export type Deployments = Map<string, Deployment>;
export async function getDeployments(): Promise<Deployments> {
const {github} = await GitClient.get();
const releaseTrains = await ActiveReleaseTrains.fetch({
api: github,
name: 'angular',
owner: 'angular',
nextBranchName: 'main',
});
const ltsBranches = await fetchLongTermSupportBranchesFromNpm({
representativeNpmPackage: '@angular/core',
} as ReleaseConfig);
const docSites = new Map<string, Deployment>();
[...ltsBranches.active, ...ltsBranches.inactive].forEach((branch) => {
docSites.set(branch.name, {
branch: branch.name,
destination: `v${branch.version.major}-angular-dev`,
});
});
docSites.set(releaseTrains.latest.branchName, {
branch: releaseTrains.latest.branchName,
redirect: {
from: `v${releaseTrains.latest.version.major}-angular-dev`,
to: 'https://angular.dev',
},
destination: 'angular-dev-site',
});
if (releaseTrains.releaseCandidate) {
docSites.set(releaseTrains.next.branchName, {
branch: releaseTrains.next.branchName,
});
docSites.set(releaseTrains.releaseCandidate.branchName, {
branch: releaseTrains.releaseCandidate.branchName,
destination: 'next-angular-dev',
redirect: {
from: `v${releaseTrains.releaseCandidate.version.major}-angular-dev`,
to: 'https://next.angular.dev',
},
});
} else {
docSites.set(releaseTrains.next.branchName, {
branch: releaseTrains.next.branchName,
destination: 'next-angular-dev',
});
}
return docSites;
}
@@ -1,71 +0,0 @@
import {getInput, setFailed} from '@actions/core';
import {context} from '@actions/github';
import {deployToFirebase, setupRedirect} from './deploy';
import {getDeployments} from './deployments';
import {GithubConfig, setConfig} from '@angular/ng-dev';
const refMatcher = /refs\/heads\/(.*)/;
async function deployDocs() {
setConfig({
github: <GithubConfig>{
mainBranchName: 'main',
name: 'angular',
owner: 'angular',
},
});
if (context.eventName !== 'push') {
throw Error();
}
const matchedRef = context.ref.match(refMatcher);
if (matchedRef === null) {
throw Error();
}
const currentBranch = matchedRef[1];
const configPath = getInput('configPath');
const distDir = getInput('distDir');
const deployment = (await getDeployments()).get(currentBranch);
if (deployment === undefined) {
console.log(`Current branch (${currentBranch}) does not deploy a documentation site.`);
console.log(`Exiting...`);
process.exit(0);
}
console.log('Doc site deployment information');
console.log('');
console.log('Current Branch:');
console.log(` ${deployment.branch}`);
console.log('');
console.log('Firebase Site:');
if (deployment.destination === undefined) {
console.log(' No deployment of a documenation site is necessary');
} else {
console.log(` Deploying to: ${deployment.destination}`);
}
console.log('');
console.log('Redirect Configuration:');
if (deployment.redirect === undefined) {
console.log(' No redirects are necessary');
} else {
console.log(` From: ${deployment.redirect.from}`);
console.log(` To: ${deployment.redirect.to}`);
}
await deployToFirebase(deployment, configPath, distDir);
await setupRedirect(deployment);
}
// Only run if the action is executed in a repository with is in the Angular org. This is in place
// to prevent the action from actually running in a fork of a repository with this action set up.
if (context.repo.owner === 'angular') {
deployDocs().catch((e: Error) => {
setFailed(e.message);
console.error(e);
});
} else {
console.warn(
'The action was skipped as this action is only meant to run in repos belonging to the Angular organization.',
);
}
File diff suppressed because it is too large Load Diff
@@ -1,3 +0,0 @@
{
"type": "module"
}
@@ -1,19 +0,0 @@
{
"compilerOptions": {
"module": "Node16",
"target": "es2020",
"lib": ["es2021", "dom"],
"experimentalDecorators": true,
"strict": true,
"outDir": "../../../dist/tsc-non-bazel-out",
"skipLibCheck": true,
"noImplicitOverride": true,
// TODO(ESM): Remove this when Bazel also uses the Node resolution.
"esModuleInterop": true,
"noImplicitReturns": true,
"jsx": "react",
"jsxFactory": "h",
"jsxFragmentFactory": "Fragment"
},
"exclude": []
}
+1 -1
View File
@@ -4,7 +4,7 @@ description: 'Installs the dependencies using Yarn'
runs:
using: 'composite'
steps:
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4
- uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4
with:
path: |
./node_modules/
+5 -5
View File
@@ -21,16 +21,16 @@ jobs:
(github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'adev: preview'))
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Build adev to ensure it continues to work
run: yarn bazel build //adev:build --config=release
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
run: yarn bazel build --config=aio_local_deps //adev:build
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@5774b71c01a55c4c998f858ee37d3b77ae704c31
with:
workflow-artifact-name: 'adev-preview'
pull-number: '${{github.event.pull_request.number}}'
+2 -2
View File
@@ -29,7 +29,7 @@ jobs:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
with:
token: '${{secrets.GITHUB_TOKEN}}'
@@ -40,7 +40,7 @@ jobs:
npx -y firebase-tools@latest target:clear --config adev/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting angular-docs
npx -y firebase-tools@latest target:apply --config adev/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting angular-docs ${{env.PREVIEW_SITE}}
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@5774b71c01a55c4c998f858ee37d3b77ae704c31
with:
github-token: '${{secrets.GITHUB_TOKEN}}'
workflow-artifact-name: 'adev-preview'
@@ -13,9 +13,9 @@ jobs:
assistant_to_the_branch_manager:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false
- uses: angular/dev-infra/github-actions/branch-manager@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
- uses: angular/dev-infra/github-actions/branch-manager@5774b71c01a55c4c998f858ee37d3b77ae704c31
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
+2 -2
View File
@@ -28,7 +28,7 @@ jobs:
- uses: alessbell/pull-request-comment-branch@aad01d65d6982b8eacabed5e9a684cd8ceb98da6 # v1.1
id: comment-branch
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
# Specify repository as the PR branch might be from a fork.
repository: ${{steps.comment-branch.outputs.head_owner}}/${{steps.comment-branch.outputs.head_repo}}
@@ -38,7 +38,7 @@ jobs:
- uses: ./.github/actions/yarn-install
- uses: angular/dev-infra/github-actions/bazel/configure-remote@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
- uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
with:
bazelrc: ./.bazelrc.user
+107 -33
View File
@@ -5,6 +5,8 @@ on:
branches:
- main
- '[0-9]+.[0-9]+.x'
pull_request:
types: [opened, synchronize, reopened]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -21,9 +23,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
with:
cache-node-modules: true
node-module-directories: |
./node_modules
./aio/node_modules
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Install node modules in aio
@@ -38,18 +43,28 @@ jobs:
run: yarn -s ng-dev ngbot verify
- name: Confirm code builds with typescript as expected
run: yarn -s check-tooling-setup
- name: Check commit message
# Commit message validation is only done on pull requests as its too late to validate once
# it has been merged.
if: github.event_name == 'pull_request'
run: yarn ng-dev commit-message validate-range ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}
- name: Check code format
# Code formatting checks are only done on pull requests as its too late to validate once
# it has been merged.
if: github.event_name == 'pull_request'
run: yarn ng-dev format changed --check ${{ github.event.pull_request.base.sha }}
devtools:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Run unit tests
@@ -61,13 +76,13 @@ jobs:
runs-on: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Install node modules
run: yarn install --frozen-lockfile --network-timeout 100000
- name: Run CI tests for framework
@@ -78,30 +93,29 @@ jobs:
labels: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Build adev in fast mode to ensure it continues to work
run: yarn bazel build //adev:build --fast_adev --config=release
- name: Run tests
run: yarn bazel test //adev:test
- name: Build adev to ensure it continues to work
run: yarn bazel test --config=aio_local_deps //adev:test
publish-snapshots:
if: github.event_name == 'push'
runs-on:
labels: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Install node modules
run: yarn install --frozen-lockfile
- run: echo "https://${{secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN}}:@github.com" > ${HOME}/.git_credentials
@@ -113,7 +127,7 @@ jobs:
labels: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
with:
cache-node-modules: true
node-module-directories: |
@@ -121,9 +135,9 @@ jobs:
./packages/zone.js/node_modules
./packages/zone.js/test/typings/node_modules
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Install node modules
run: yarn install --frozen-lockfile
- run: |
@@ -155,22 +169,26 @@ jobs:
- run: yarn --cwd packages/zone.js/test/typings test
bazel-saucelabs:
# TODO: Replace legacy job with Bazel saucelabs job.
if: github.event_name == 'push'
runs-on: ubuntu-latest-4core
env:
JOBS: 2
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
with:
cache-node-modules: true
# Checking out the pull request commit is intended here as we need to run the changed code tests.
ref: ${{ github.event.pull_request.head.sha }}
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Setup Saucelabs Variables
uses: angular/dev-infra/github-actions/saucelabs@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/saucelabs@50bb71e51d3372ca2e359adb9069f89beeac4ae7
- name: Set up Sauce Tunnel Daemon
run: yarn bazel run //tools/saucelabs-daemon/background-service -- $JOBS &
env:
@@ -180,24 +198,80 @@ jobs:
TESTS=$(./node_modules/.bin/bazelisk query --output label '(kind(karma_web_test, ...) intersect attr("tags", "saucelabs", ...)) except attr("tags", "fixme-saucelabs", ...)')
yarn bazel test --config=saucelabs --jobs=$JOBS ${TESTS}
saucelabs:
runs-on: ubuntu-latest-4core
env:
SAUCE_TUNNEL_IDENTIFIER: angular-framework-${{ github.run_number }}
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
with:
cache-node-modules: true
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Setup Saucelabs Variables
uses: angular/dev-infra/github-actions/saucelabs@50bb71e51d3372ca2e359adb9069f89beeac4ae7
- name: Starting Saucelabs tunnel service
run: ./tools/saucelabs/sauce-service.sh run &
# Build test fixtures for a test that rely on Bazel-generated fixtures. Note that disabling
# specific tests which are reliant on such generated fixtures is not an option as SystemJS
# in the Saucelabs legacy job always fetches referenced files, even if the imports would be
# guarded by an check to skip in the Saucelabs legacy job. We should be good running such
# test in all supported browsers on Saucelabs anyway until this job can be removed.
- name: Preparing Bazel-generated fixtures required in legacy tests
run: |
yarn bazel build //packages/core/test:downleveled_es5_fixture //packages/common/locales
# Needed for the ES5 downlevel reflector test in `packages/core/test/reflection`.
mkdir -p dist/legacy-test-out/core/test/reflection/
cp dist/bin/packages/core/test/reflection/es5_downleveled_inheritance_fixture.js \
dist/legacy-test-out/core/test/reflection/es5_downleveled_inheritance_fixture.js
# Locale files are needed for i18n tests running within Saucelabs. These are added
# directly as sources so that the TypeScript compilation of `/packages/tsconfig.json`
# can succeed. Note that the base locale and currencies files are checked-in, so
# we do not need to re-generate those through Bazel.
mkdir -p packages/common/locales/extra
cp dist/bin/packages/common/locales/*.ts packages/common/locales
cp dist/bin/packages/common/locales/extra/*.ts packages/common/locales/extra
- name: Build bundle of tests to run on Saucelabs
run: node tools/legacy-saucelabs/build-saucelabs-test-bundle.mjs
- name: Wait and confirm Saucelabs tunnel has connected
run: ./tools/saucelabs/sauce-service.sh ready-wait
timeout-minutes: 3
- name: Running tests on Saucelabs.
run: KARMA_WEB_TEST_MODE=SL_REQUIRED yarn karma start ./karma-js.conf.js --single-run
- name: Stop Saucelabs tunnel service
run: ./tools/saucelabs/sauce-service.sh stop
adev-deploy:
needs: [adev]
if: needs.adev.result == 'success'
if: needs.adev.result == 'success' && github.event_name == 'push' && github.ref_name == 'main'
env:
DEPLOY_PROJECT: angular-dev-site
DEPLOY_SITE: angular-dev-site
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@89624a6442b75b5cda33c5e9b5c8c4f87ca4f13d
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Build adev to ensure it continues to work
run: yarn bazel build //adev:build --config=release
run: yarn bazel build --config=aio_local_deps //adev:build
- name: Move generated project files into deployment directory
run: cp -r dist/bin/adev/build adev/build
- name: Setup firebase context
run: |
npx -y firebase-tools@latest target:clear --config adev/firebase.json --project ${{ env.DEPLOY_PROJECT }} hosting angular-docs
npx -y firebase-tools@latest target:apply --config adev/firebase.json --project ${{ env.DEPLOY_PROJECT }} hosting angular-docs ${{ env.DEPLOY_SITE }}
- name: Deploy to firebase
uses: ./.github/actions/deploy-docs-site
uses: FirebaseExtended/action-hosting-deploy@120e124148ab7016bec2374e5050f15051255ba2 # v0.7.1
with:
serviceKey: ${{ secrets.ANGULAR_DEV_SITE_DEPLOY }}
configPath: 'adev/firebase.json'
distDir: 'dist/bin/adev/build/browser'
entryPoint: './adev'
firebaseServiceAccount: ${{ secrets.ANGULAR_DEV_SITE_DEPLOY }}
projectId: ${{ env.DEPLOY_PROJECT }}
channelId: live
+4 -4
View File
@@ -12,14 +12,14 @@ jobs:
labels:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- uses: angular/dev-infra/github-actions/commit-message-based-labels@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: angular/dev-infra/github-actions/commit-message-based-labels@5774b71c01a55c4c998f858ee37d3b77ae704c31
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
post_approval_changes:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- uses: angular/dev-infra/github-actions/post-approval-changes@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: angular/dev-infra/github-actions/post-approval-changes@5774b71c01a55c4c998f858ee37d3b77ae704c31
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
+2 -2
View File
@@ -13,8 +13,8 @@ jobs:
statuses: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- uses: angular/dev-infra/github-actions/google-internal-tests@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: angular/dev-infra/github-actions/google-internal-tests@5774b71c01a55c4c998f858ee37d3b77ae704c31
with:
run-tests-guide-url: http://go/angular-g3sync-start
github-token: ${{ secrets.GITHUB_TOKEN }}
+1 -1
View File
@@ -9,6 +9,6 @@ jobs:
status:
runs-on: ubuntu-latest
steps:
- uses: angular/dev-infra/github-actions/unified-status-check@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
- uses: angular/dev-infra/github-actions/unified-status-check@5774b71c01a55c4c998f858ee37d3b77ae704c31
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
+4 -4
View File
@@ -22,15 +22,15 @@ jobs:
version: ['https://next.angular.io/', 'https://angular.io/']
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
with:
cache-node-modules: true
node-module-directories: |
./aio/node_modules
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
- name: Install node modules in aio
run: yarn install --frozen-lockfile --cwd aio
- name: Run basic e2e and deployment config tests.
@@ -44,7 +44,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
with:
cache-node-modules: true
node-module-directories: |
-183
View File
@@ -1,183 +0,0 @@
name: Pull Request
on:
pull_request:
types: [opened, synchronize, reopened]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions: {}
defaults:
run:
shell: bash
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
with:
cache-node-modules: true
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Check code lint
run: yarn -s tslint
- name: Check for circular dependencies
run: yarn -s ts-circular-deps:check
- name: Validate pull approve configuration
run: yarn -s ng-dev pullapprove verify
- name: Validate angular robot configuration
run: yarn -s ng-dev ngbot verify
- name: Confirm code builds with typescript as expected
run: yarn -s check-tooling-setup
- name: Check commit message
run: yarn ng-dev commit-message validate-range ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}
- name: Check code format
run: yarn ng-dev format changed --check ${{ github.event.pull_request.base.sha }}
devtools:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Run unit tests
run: yarn devtools:test
- name: Test build
run: yarn devtools:build:chrome
test:
runs-on: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
- name: Install node modules
run: yarn install --frozen-lockfile --network-timeout 100000
- name: Run CI tests for framework
run: yarn test:ci
adev:
runs-on:
labels: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Build adev in fast mode to ensure it continues to work
run: yarn bazel build //adev:build --fast_adev --config=release
- name: Run tests
run: yarn bazel test //adev:test
zone-js:
runs-on:
labels: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
with:
cache-node-modules: true
node-module-directories: |
./node_modules
./packages/zone.js/node_modules
./packages/zone.js/test/typings/node_modules
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
- name: Install node modules
run: yarn install --frozen-lockfile
- run: |
yarn bazel build \
//packages/zone.js/bundles:zone.umd.js \
//packages/zone.js:npm_package \
//packages/zone.js/test/closure:closure_js \
- run: |
rm -Rf packages/zone.js/build
rm -Rf packages/zone.js/test/extra/*.umd.js
mkdir -p packages/zone.js/build/
mkdir -p packages/zone.js/build/test/
cp dist/bin/packages/zone.js/bundles/zone.umd.js packages/zone.js/build/zone.umd.js
cp dist/bin/packages/zone.js/npm_package/bundles/zone-mix.umd.js ./packages/zone.js/test/extra/
cp dist/bin/packages/zone.js/npm_package/bundles/zone-patch-electron.umd.js ./packages/zone.js/test/extra/
cp dist/bin/packages/zone.js/test/closure/zone.closure.mjs ./packages/zone.js/build/test/zone.closure.mjs
# Install
- run: yarn --cwd packages/zone.js install --frozen-lockfile --non-interactive
# Run zone.js tools tests
- run: yarn --cwd packages/zone.js promisefinallytest
- run: yarn --cwd packages/zone.js jest:test
- run: yarn --cwd packages/zone.js jest:nodetest
- run: yarn --cwd packages/zone.js electrontest
- run: yarn --cwd packages/zone.js/test/typings install --frozen-lockfile --non-interactive
- run: yarn --cwd packages/zone.js/test/typings test
saucelabs:
runs-on: ubuntu-latest-4core
env:
SAUCE_TUNNEL_IDENTIFIER: angular-framework-${{ github.run_number }}
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
with:
cache-node-modules: true
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
- name: Setup Saucelabs Variables
uses: angular/dev-infra/github-actions/saucelabs@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
- name: Starting Saucelabs tunnel service
run: ./tools/saucelabs/sauce-service.sh run &
# Build test fixtures for a test that rely on Bazel-generated fixtures. Note that disabling
# specific tests which are reliant on such generated fixtures is not an option as SystemJS
# in the Saucelabs legacy job always fetches referenced files, even if the imports would be
# guarded by an check to skip in the Saucelabs legacy job. We should be good running such
# test in all supported browsers on Saucelabs anyway until this job can be removed.
- name: Preparing Bazel-generated fixtures required in legacy tests
run: |
yarn bazel build //packages/core/test:downleveled_es5_fixture //packages/common/locales
# Needed for the ES5 downlevel reflector test in `packages/core/test/reflection`.
mkdir -p dist/legacy-test-out/core/test/reflection/
cp dist/bin/packages/core/test/reflection/es5_downleveled_inheritance_fixture.js \
dist/legacy-test-out/core/test/reflection/es5_downleveled_inheritance_fixture.js
# Locale files are needed for i18n tests running within Saucelabs. These are added
# directly as sources so that the TypeScript compilation of `/packages/tsconfig.json`
# can succeed. Note that the base locale and currencies files are checked-in, so
# we do not need to re-generate those through Bazel.
mkdir -p packages/common/locales/extra
cp dist/bin/packages/common/locales/*.ts packages/common/locales
cp dist/bin/packages/common/locales/extra/*.ts packages/common/locales/extra
- name: Build bundle of tests to run on Saucelabs
run: node tools/legacy-saucelabs/build-saucelabs-test-bundle.mjs
- name: Wait and confirm Saucelabs tunnel has connected
run: ./tools/saucelabs/sauce-service.sh ready-wait
timeout-minutes: 3
- name: Running tests on Saucelabs.
run: KARMA_WEB_TEST_MODE=SL_REQUIRED yarn karma start ./karma-js.conf.js --single-run
- name: Stop Saucelabs tunnel service
run: ./tools/saucelabs/sauce-service.sh stop
+4 -4
View File
@@ -25,12 +25,12 @@ jobs:
steps:
- name: 'Checkout code'
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false
- name: 'Run analysis'
uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
with:
results_file: results.sarif
results_format: sarif
@@ -39,7 +39,7 @@ jobs:
# Upload the results as artifacts.
- name: 'Upload artifact'
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: SARIF file
path: results.sarif
@@ -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@f079b8493333aace61c81488f8bd40919487bd9f # v3.25.7
uses: github/codeql-action/upload-sarif@05963f47d870e2cb19a537396c1f668a348c7d8f # v3.24.8
with:
sarif_file: results.sarif
+3 -3
View File
@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
# Setting `persist-credentials: false` prevents the github-action account from being the
# account that is attempted to be used for authentication, instead the remote is set to
@@ -28,11 +28,11 @@ jobs:
# This is needed as otherwise the PR creation will fail with `shallow update not allowed` when the forked branch is not in sync.
fetch-depth: 0
- name: Generate CLI help
run: node adev/scripts/update-cli-help/index.mjs
run: node aio/scripts/update-cli-help/index.mjs
env:
ANGULAR_CLI_BUILDS_READONLY_GITHUB_TOKEN: ${{ secrets.ANGULAR_CLI_BUILDS_READONLY_GITHUB_TOKEN }}
- name: Create a PR (if necessary)
uses: angular/dev-infra/github-actions/create-pr-for-changes@1ebf18a3a60b182a3dbad12e9a149fd93af5c29b
uses: angular/dev-infra/github-actions/create-pr-for-changes@1421ff04811ecb45812930c5d1f61d912880e75f
with:
branch-prefix: update-cli-help
pr-title: 'docs: update Angular CLI help [${{github.ref_name}}]'
+55 -7
View File
@@ -7,7 +7,23 @@ export const format: FormatConfig = {
'prettier': {
'matchers': [
'**/*.{yaml,yml}',
'**/*.{js,ts}',
'adev/**/*.{js,ts}',
'devtools/**/*.{js,ts}',
'tools/**/*.{js,ts}',
'modules/**/*.{js,ts}',
'scripts/**/*.{js,ts}',
'packages/animations/**/*.{js,ts}',
'packages/bazel/**/*.{js,ts}',
'packages/benchpress/**/*.{js,ts}',
'packages/common/**/*.{js,ts}',
'packages/docs/**/*.{js,ts}',
'packages/elements/**/*.{js,ts}',
'packages/examples/**/*.{js,ts}',
'packages/misc/**/*.{js,ts}',
'packages/private/**/*.{js,ts}',
'packages/router/**/*.{js,ts}',
'packages/service-worker/**/*.{js,ts}',
'packages/upgrade/**/*.{js,ts}',
// Do not format d.ts files as they are generated
'!**/*.d.ts',
@@ -15,18 +31,50 @@ export const format: FormatConfig = {
// not be modified.
'!third_party/**',
'!.yarn/**',
],
},
'clang-format': {
'matchers': [
'**/*.{js,ts}',
// TODO: burn down format failures and remove aio and integration exceptions.
'!aio/**',
'!integration/**',
// Both third_party and .yarn are directories containing copied code which should
// not be modified.
'!third_party/**',
'!.yarn/**',
// Do not format d.ts files as they are generated
'!**/*.d.ts',
// Do not format generated ng-dev script
'!dev-infra/ng-dev.js',
'!dev-infra/build-worker.js',
// Do not format compliance test-cases since they must match generated code
'!packages/compiler-cli/test/compliance/test_cases/**/*.js',
// Do not format the locale files which are checked-in for Google3, but generated using
// the `generate-locales-tool` from `packages/common/locales`.
'!packages/core/src/i18n/locale_en.ts',
'!packages/common/locales/closure-locale.ts',
'!packages/common/src/i18n/currencies.ts',
// Test cases contain non valid code.
'!packages/compiler-cli/test/compliance/test_cases/**/*.{js,ts}',
// Ignore AIO as its pending removal.
'!aio/**/*.{js,ts}',
// Temporarily disable formatting for adev
'!adev/**',
// Ignore generated javascript file(s)
'!.github/actions/deploy-docs-site/main.js',
// Migrated to prettier
'!devtools/**/*.{js,ts}',
'!tools/**/*.{js,ts}',
'!modules/**/*.{js,ts}',
'!scripts/**/*.{js,ts}',
'!packages/animations/**/*.{js,ts}',
'!packages/bazel/**/*.{js,ts}',
'!packages/benchpress/**/*.{js,ts}',
'!packages/common/**/*.{js,ts}',
'!packages/docs/**/*.{js,ts}',
'!packages/elements/**/*.{js,ts}',
'!packages/examples/**/*.{js,ts}',
'!packages/misc/**/*.{js,ts}',
'!packages/private/**/*.{js,ts}',
'!packages/router/**/*.{js,ts}',
'!packages/service-worker/**/*.{js,ts}',
'!packages/upgrade/**/*.{js,ts}',
],
},
'buildifier': true,
+1 -1
View File
@@ -1 +1 @@
18.20.0
18.18.2
+22 -76
View File
@@ -140,7 +140,7 @@ groups:
- alxhub
- crisbeto
- ~jelbourn
- thePunderWoman
- jessicajaniuk
# =========================================================
# Framework: Compiler
@@ -183,7 +183,7 @@ groups:
- crisbeto
- devversion
- dylhunn
- thePunderWoman
- jessicajaniuk
- AndrewKushnir
# =========================================================
@@ -193,7 +193,7 @@ groups:
<<: *defaults
conditions:
- >
contains_any_globs(files.exclude("packages/core/schematics/*").exclude('packages/core/primitives/*'), [
contains_any_globs(files.exclude("packages/core/schematics/*"), [
'packages/core/**/{*,.*}',
'packages/examples/core/**/{*,.*}',
'packages/platform-browser/**/{*,.*}',
@@ -358,7 +358,7 @@ groups:
- crisbeto
- devversion
- dylhunn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
# =========================================================
@@ -378,7 +378,7 @@ groups:
- AndrewKushnir
- atscott
- dylhunn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
# =========================================================
@@ -415,7 +415,7 @@ groups:
- AndrewKushnir
- atscott
- dylhunn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
# =========================================================
@@ -438,7 +438,7 @@ groups:
- andrewseguin
- atscott
- dylhunn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
# =========================================================
@@ -536,7 +536,7 @@ groups:
- AndrewKushnir
- atscott
- dylhunn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
# =========================================================
@@ -615,7 +615,7 @@ groups:
reviewers:
users:
- alxhub
- thePunderWoman
- jessicajaniuk
# =========================================================
# Framework: Testing
@@ -644,7 +644,7 @@ groups:
- AndrewKushnir
- atscott
- dylhunn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
# =========================================================
@@ -663,7 +663,7 @@ groups:
- AndrewKushnir
- atscott
- dylhunn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
# =========================================================
@@ -682,7 +682,7 @@ groups:
- AndrewKushnir
- atscott
- dylhunn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
# =========================================================
@@ -778,7 +778,7 @@ groups:
- atscott
- crisbeto
- dylhunn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
# =========================================================
@@ -813,7 +813,7 @@ groups:
- AndrewKushnir
- atscott
- dylhunn
- thePunderWoman
- jessicajaniuk
- josephperrott
- pkozlowski-opensource
@@ -867,7 +867,7 @@ groups:
reviewers:
users:
- AndrewKushnir
- thePunderWoman
- jessicajaniuk
# =========================================================
# Docs: Marketing
@@ -946,7 +946,7 @@ groups:
- alxhub
- AndrewKushnir
- atscott
- thePunderWoman
- jessicajaniuk
- jelbourn
# =========================================================
@@ -1078,12 +1078,11 @@ groups:
- josephperrott
- jelbourn
- bencodezen
- thePunderWoman
- jessicajaniuk
- dylhunn
- AndrewKushnir
- alxhub
- crisbeto
- devversion
- atscott
- pkozlowski-opensource
- ~JeanMeche
@@ -1144,7 +1143,7 @@ groups:
reviewers:
users:
- AndrewKushnir
- thePunderWoman
- jessicajaniuk
- josephperrott
# =========================================================
@@ -1243,7 +1242,7 @@ groups:
- atscott
- dylhunn
- ~jelbourn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
reviews:
request: 3 # Request reviews from 3 people
@@ -1269,7 +1268,7 @@ groups:
- atscott
- dylhunn
- ~jelbourn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
reviews:
request: 2 # Request reviews from 2 people
@@ -1295,7 +1294,7 @@ groups:
- atscott
- dylhunn
- ~jelbourn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
####################################################################################
@@ -1319,62 +1318,9 @@ groups:
- andrewseguin
- dgp1130
- ~jelbourn
- thePunderWoman
- jessicajaniuk
- josephperrott
# =========================================================
# Primitives
# =========================================================
# Angular team required reviews
primitives:
<<: *defaults
conditions:
- >
contains_any_globs(files, [
'packages/core/primitives/**/{*,.*}',
])
reviewers:
users:
- pkozlowski-opensource # Pawel Kozlowski
- alxhub # Alex Rickabaugh
- thePunderWoman # Jessica Janiuk
- dylhunn # Dylan Hunn
- AndrewKushnir # Andrew Kushnir
- atscott # Andrew Scott
labels:
pending: 'requires: TGP'
approved: 'requires: TGP'
rejected: 'requires: TGP'
# External team required reviews
primitives-shared:
<<: *defaults
conditions:
- >
contains_any_globs(files, [
'packages/core/primitives/**/{*,.*}',
])
reviewers:
users:
- csmick # Cameron Smick
- lannka # Hongfei Ding
- eduhmc # Eduardo Huerta-Mercado
- ehlemur # Edward Lesmes
- ellenyuan # Ellen Yuan
- jatraman # Jatin Ramanathan
- jesse-good # Jesse Costello-Good
- mturco # Matt Turco
- neonstalwart # Ben Hockey
- nicholasyu-google # Nicholas Yu
- iteriani # Thomas Nguyen
- tbondwilkinson # Tom Wilkinson
- rahatarmanahmed # Rahat Ahmed
labels:
pending: 'requires: TGP'
approved: 'requires: TGP'
rejected: 'requires: TGP'
####################################################################################
# Override managed result groups
#
+1
View File
@@ -6,5 +6,6 @@
"recommendations": [
"BazelBuild.vscode-bazel",
"ms-vscode.vscode-typescript-tslint-plugin",
"xaver.clang-format",
],
}
+6
View File
@@ -1,10 +1,16 @@
{
// Format js and ts files on save with `clang-format.executable`
// If `clang-format.executable` is not being used, these two settings should be removed otherwise it will break existing formatting.
// You can instead run `yarn gulp format` to manually format your code.
"[javascript]": {
"editor.formatOnSave": true,
},
"[typescript]": {
"editor.formatOnSave": true,
},
// Please install https://marketplace.visualstudio.com/items?itemName=xaver.clang-format to take advantage of `clang-format` in VSCode.
// (See https://clang.llvm.org/docs/ClangFormat.html for more info `clang-format`.)
"clang-format.executable": "${workspaceRoot}/node_modules/.bin/clang-format",
// Exclude third party modules and build artifacts from the editor watchers/searches.
"files.watcherExclude": {
"**/.git/objects/**": true,
+77 -341
View File
@@ -1,61 +1,69 @@
<a name="18.0.2"></a>
# 18.0.2 (2024-06-05)
### core
| Commit | Type | Description |
| -- | -- | -- |
| [78cf9bfc0e](https://github.com/angular/angular/commit/78cf9bfc0eb1e78c1f6d3a562e65982579698896) | fix | Do not migrate `HttpClientModule` imports on components. ([#56067](https://github.com/angular/angular/pull/56067)) |
| [616cdef474](https://github.com/angular/angular/commit/616cdef4748d5112460cf58200832585856777d6) | fix | don't coerce all producers to consumers on liveness change ([#56140](https://github.com/angular/angular/pull/56140)) |
| [2a440e1064](https://github.com/angular/angular/commit/2a440e1064bddc839df91dbe77fc27bb8bd15641) | fix | Fix shouldPreventDefaultBeforeDispatching bug ([#56188](https://github.com/angular/angular/pull/56188)) |
| [290a47d842](https://github.com/angular/angular/commit/290a47d8427f4854234cb2b4244871eaf1f82c19) | fix | handle missing `withI18nSupport()` call for components that use i18n blocks ([#56175](https://github.com/angular/angular/pull/56175)) |
### migrations
| Commit | Type | Description |
| -- | -- | -- |
| [b70b80ba55](https://github.com/angular/angular/commit/b70b80ba55ff16a5dd10e07c7120b0d3aecd5d2d) | fix | do not generate aliased variables with the same name ([#56154](https://github.com/angular/angular/pull/56154)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="18.0.1"></a>
# 18.0.1 (2024-05-29)
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [419ffa2026](https://github.com/angular/angular/commit/419ffa20265e4b9b5b1d92045ec40f59f5c4de2e) | fix | optimize track function that only passes $index ([#55872](https://github.com/angular/angular/pull/55872)) |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [4c7efc005a](https://github.com/angular/angular/commit/4c7efc005a8d0d343f437007740254b1d35c718b) | fix | interpolatedSignalNotInvoked diagnostic for class, style, attribute and animation bindings ([#55969](https://github.com/angular/angular/pull/55969)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [4e6ea0e19c](https://github.com/angular/angular/commit/4e6ea0e19c52c9aceb635accb379572c78a457da) | fix | handle elements with local refs in event replay serialization logic ([#56076](https://github.com/angular/angular/pull/56076)) |
| [d73a0175cb](https://github.com/angular/angular/commit/d73a0175cb2d8c74e6bb877dc30eec07fd484fff) | fix | link errors to ADEV ([#55554](https://github.com/angular/angular/pull/55554)) |
| [985a215b10](https://github.com/angular/angular/commit/985a215b102be2a58dd4d13e1c05399f58f3078e) | fix | typo in zoneless warning ([#55974](https://github.com/angular/angular/pull/55974)) |
### migrations
| Commit | Type | Description |
| -- | -- | -- |
| [ba85d08158](https://github.com/angular/angular/commit/ba85d081583277a5b7a04bc349a3a8d528467c52) | fix | handle empty ngSwitchCase ([#56105](https://github.com/angular/angular/pull/56105)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="18.0.0"></a>
# 18.0.0 (2024-05-22)
[Blog post "Angular v18 is now available"](http://goo.gle/angular-v18).
<a name="18.0.0-next.1"></a>
# 18.0.0-next.1 (2024-03-20)
## Breaking Changes
### animations
- Deprecated `matchesElement` method has been removed from `AnimationDriver` as it is unused.
### common
- The deprecated `isPlatformWorkerUi` and `isPlatformWorkerApp` have been removed without replacement, as they serve no purpose since the removal of the WebWorker platform.
### platform-browser-dynamic
- No longer used `RESOURCE_CACHE_PROVIDER` APIs have been removed.
### platform-server
- deprecated `platformDynamicServer` has been removed. Add an `import @angular/compiler` and replace the usage with `platformServer`
- deprecated `ServerTransferStateModule` has been removed. `TransferState` can be use without providing this module.
- deprecated `useAbsoluteUrl` and `baseUrl` been removed from `PlatformConfig`. Provide and absolute `url` instead.
- Legacy handling or Node.js URL parsing has been removed from `ServerPlatformLocation`.
The main differences are;
- `pathname` is always suffixed with a `/`.
- `port` is empty when `http:` protocol and port in url is `80`
- `port` is empty when `https:` protocol and port in url is `443`
### router
- This change allows `Route.redirectTo` to be a function
in addition to the previous string. Code which expects `redirectTo` to
only be a string on `Route` objects will need to be adjusted.
### compiler
- Angular only supports writable expressions inside of two-way bindings.
| Commit | Type | Description |
| -- | -- | -- |
| [879bd80b57](https://github.com/angular/angular/commit/879bd80b571368bdc6e65c5415d98ad0f546267a) | fix | capture data bindings for content projection purposes in blocks ([#54876](https://github.com/angular/angular/pull/54876)) |
### compiler-cli
- * Angular no longer supports TypeScript versions older than 5.4.
| Commit | Type | Description |
| -- | -- | -- |
| [6aff144232](https://github.com/angular/angular/commit/6aff14423238f8995da8104e60c0baca26df2020) | fix | symbol feature detection for the compiler ([#54711](https://github.com/angular/angular/pull/54711)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [314112de99](https://github.com/angular/angular/commit/314112de99bb97475a0d8bdbddf84a3b3ce4a8fb) | fix | Prevent `markForCheck` during change detection from causing infinite loops ([#54900](https://github.com/angular/angular/pull/54900)) |
### platform-browser-dynamic
| Commit | Type | Description |
| -- | -- | -- |
| [eb20c1a8b1](https://github.com/angular/angular/commit/eb20c1a8b18e2e080c856e3e1bf7bcd02f3bfd28) | refactor | unused `RESOURCE_CACHE_PROVIDER` API has been removed ([#54875](https://github.com/angular/angular/pull/54875)) |
### platform-server
| Commit | Type | Description |
| -- | -- | -- |
| [07ac017731](https://github.com/angular/angular/commit/07ac017731f0e08ea3736f1f212093a28648a304) | refactor | remove deprecated `platformDynamicServer` API ([#54874](https://github.com/angular/angular/pull/54874)) |
| [e8b588d8b7](https://github.com/angular/angular/commit/e8b588d8b7fc014aaef99d4b0c1e4567b4aa195d) | refactor | remove deprecated `ServerTransferStateModule` API ([#54874](https://github.com/angular/angular/pull/54874)) |
| [3b1967ca64](https://github.com/angular/angular/commit/3b1967ca64479df9137b3ad7a0d04dbaff6496f4) | refactor | remove deprecated `useAbsoluteUrl` and `baseUrl` from `PlatformConfig` ([#54874](https://github.com/angular/angular/pull/54874)) |
| [2357d3566c](https://github.com/angular/angular/commit/2357d3566c4d18dc40cbda6644ed459ef7703893) | refactor | remove legacy URL handling logic ([#54874](https://github.com/angular/angular/pull/54874)) |
### router
| Commit | Type | Description |
| -- | -- | -- |
| [2b802587f2](https://github.com/angular/angular/commit/2b802587f27186baa493c1dd01f42d568b652f38) | feat | Allow Route.redirectTo to be a function which returns a string or UrlTree ([#52606](https://github.com/angular/angular/pull/52606)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="17.3.1"></a>
# 17.3.1 (2024-03-20)
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [c0788200e2](https://github.com/angular/angular/commit/c0788200e26406bacb90ee0079ea9753eebd1b32) | fix | capture data bindings for content projection purposes in blocks ([#54876](https://github.com/angular/angular/pull/54876)) |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [99e9474aa2](https://github.com/angular/angular/commit/99e9474aa2ccccdf4385fbac6b62b1a4585ed4b4) | fix | symbol feature detection for the compiler ([#54711](https://github.com/angular/angular/pull/54711)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="18.0.0-next.0"></a>
# 18.0.0-next.0 (2024-03-14)
## Breaking Changes
### core
- `OnPush` views at the root of the application need to
be marked dirty for their host bindings to refresh. Previously, the host
bindings were refreshed for all root views without respecting the
`OnPush` change detection strategy.
- `OnPush` views at the root of the application need to
be marked dirty for their host bindings to refresh. Previously, the host
bindings were refreshed for all root views without respecting the
@@ -66,45 +74,12 @@
claim to be `OnPush` but do not correctly call `markForCheck` when they
need to be refreshed. If this change causes test failures, the easiest
fix is to change the component to `ChangeDetectionStrategy.Default`.
- `ComponentFixture.whenStable` now matches the
`ApplicationRef.isStable` observable. Prior to this change, stability
of the fixture did not include everything that was considered in
`ApplicationRef`. `whenStable` of the fixture will now include unfinished
router navigations and unfinished `HttpClient` requests. This will cause
tests that `await` the `whenStable` promise to time out when there are
incomplete requests. To fix this, remove the `whenStable`,
instead wait for another condition, or ensure `HttpTestingController`
mocks responses for all requests. Try adding `HttpTestingController.verify()`
before your `await fixture.whenStable` to identify the open requests.
Also, make sure your tests wait for the stability promise. We found many
examples of tests that did not, meaning the expectations did not execute
within the test body.
In addition, `ComponentFixture.isStable` would synchronously switch to
true in some scenarios but will now always be asynchronous.
- Angular will ensure change detection runs, even when the state update originates from
outside the zone, tests may observe additional rounds of change
detection compared to the previous behavior.
This change will be more likely to impact existing unit tests.
This should usually be seen as more correct and the test should be updated,
but in cases where it is too much effort to debug, the test can revert to the old behavior by adding
`provideZoneChangeDetection({schedulingMode: NgZoneSchedulingMode.NgZoneOnly})`
to the `TestBed` providers.
Similarly, applications which may want to update state outside the zone
and _not_ trigger change detection can add
`provideZoneChangeDetection({schedulingMode: NgZoneSchedulingMode.NgZoneOnly})`
to the providers in `bootstrapApplication` or add
`schedulingMode: NgZoneSchedulingMode.NgZoneOnly` to the
`BootstrapOptions` of `bootstrapModule`.
- When Angular runs change detection, it will continue to
refresh any views attached to `ApplicationRef` that are still marked for
check after one round completes. In rare cases, this can result in infinite
loops when certain patterns continue to mark views for check using
`ChangeDetectorRef.detectChanges`. This will be surfaced as a runtime
error with the `NG0103` code.
- `async` has been removed, use `waitForAsync` instead.
- The `ComponentFixture.autoDetect` feature now executes
change detection for the fixture within `ApplicationRef.tick`. This more
closely matches the behavior of how a component would refresh in
@@ -133,282 +108,28 @@
queued to be updated in a microtask instead of being available in the
current change detection round. The component only read this value during
initialization and did not read it again after the microtask updated it.
- Testability methods `increasePendingRequestCount`,
`decreasePendingRequestCount` and `getPendingRequestCount` have been
removed. This information is tracked with zones.
### http
- By default we now prevent caching of HTTP requests that require authorization . To opt-out from this behaviour use the `includeRequestsWithAuthHeaders` option in `withHttpTransferCache`.
Example:
```ts
withHttpTransferCache({
includeRequestsWithAuthHeaders: true,
})
```
### platform-browser
- Deprecated `StateKey`, `TransferState` and `makeStateKey` have been removed from `@angular/platform-browser`, use the same APIs from `@angular/core`.
### platform-browser-dynamic
- No longer used `RESOURCE_CACHE_PROVIDER` APIs have been removed.
### platform-server
- deprecated `platformDynamicServer` has been removed. Add an `import @angular/compiler` and replace the usage with `platformServer`
- deprecated `ServerTransferStateModule` has been removed. `TransferState` can be use without providing this module.
- deprecated `useAbsoluteUrl` and `baseUrl` been removed from `PlatformConfig`. Provide and absolute `url` instead.
- Legacy handling or Node.js URL parsing has been removed from `ServerPlatformLocation`.
The main differences are;
- `pathname` is always suffixed with a `/`.
- `port` is empty when `http:` protocol and port in url is `80`
- `port` is empty when `https:` protocol and port in url is `443`
### router
- Guards can now return `RedirectCommand` for redirects
in addition to `UrlTree`. Code which expects only `boolean` or `UrlTree`
values in `Route` types will need to be adjusted.
- This change allows `Route.redirectTo` to be a function
in addition to the previous string. Code which expects `redirectTo` to
only be a string on `Route` objects will need to be adjusted.
- When a a guard returns a `UrlTree` as a redirect, the
redirecting navigation will now use `replaceUrl` if the initial
navigation was also using the `replaceUrl` option. If this is not
desirable, the redirect can configure new `NavigationBehaviorOptions` by
returning a `RedirectCommand` with the desired options instead of `UrlTree`.
- Providers available to the routed components always
come from the injector heirarchy of the routes and never inherit from
the `RouterOutlet`. This means that providers available only to the
component that defines the `RouterOutlet` will no longer be available to
route components in any circumstances. This was already the case
whenever routes defined providers, either through lazy loading an
`NgModule` or through explicit `providers` on the route config.
- Providers available to the routed components always
come from the injector heirarchy of the routes and never inherit from
the `RouterOutlet`. This means that providers available only to the
component that defines the `RouterOutlet` will no longer be available to
route components in any circumstances. This was already the case
whenever routes defined providers, either through lazy loading an
`NgModule` or through explicit `providers` on the route config.
## Deprecations
### common
- `getCurrencySymbol`, `getLocaleCurrencyCode`, `getLocaleCurrencyName`, `getLocaleCurrencySymbol`, `getLocaleDateFormat`, `getLocaleDateTimeFormat`, `getLocaleDayNames`, `getLocaleDayPeriods`, `getLocaleDirection`, `getLocaleEraNames`, `getLocaleExtraDayPeriodRules`, `getLocaleExtraDayPeriods`, `getLocaleFirstDayOfWeek`, `getLocaleId`, `getLocaleMonthNames`, `getLocaleNumberFormat`, `getLocaleNumberSymbol`, `getLocalePluralCase`, `getLocaleTimeFormat`, `getLocaleWeekEndRange`, `getNumberOfCurrencyDigits`
### core
- `@Component.interpolation` is deprecated. Use Angular's
delimiters instead.
### http
- `HttpClientModule`, `HttpClientXsrfModule` and `HttpClientJsonpModule`
As mentionned, those modules can be replaced by provider function only.
### animations
| Commit | Type | Description |
| -- | -- | -- |
| [bcce85af72](https://github.com/angular/angular/commit/bcce85af72a82634f60b31d66a5ef42ecd844ce8) | refactor | remove deprecated `matchesElement` from `AnimationDriver` ([#55479](https://github.com/angular/angular/pull/55479)) |
### common
| Commit | Type | Description |
| -- | -- | -- |
| [d34c033902](https://github.com/angular/angular/commit/d34c033902b4e7543796de6c57d0cfd09093eb43) | refactor | Deprecate Local Data API functions ([#54483](https://github.com/angular/angular/pull/54483)) |
| [3b0de30b37](https://github.com/angular/angular/commit/3b0de30b37f558d4815ca9a61db1010aaf3df068) | refactor | remove deprecated `isPlatformWorkerApp` and `isPlatformWorkerUi` API ([#55302](https://github.com/angular/angular/pull/55302)) |
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [91b007e58f](https://github.com/angular/angular/commit/91b007e58ffb91f7c396cbc0333a91d18f02bd27) | fix | add math elements to schema ([#55631](https://github.com/angular/angular/pull/55631)) |
| [33d0102304](https://github.com/angular/angular/commit/33d0102304e2213ee0af0bc86028a4f564c81ed4) | fix | allow comments between connected blocks ([#55966](https://github.com/angular/angular/pull/55966)) |
| [7fc7f3f05f](https://github.com/angular/angular/commit/7fc7f3f05f0139dd773032fd5ad308f8d2a9fcf5) | fix | capture all control flow branches for content projection in if blocks ([#54921](https://github.com/angular/angular/pull/54921)) |
| [a369f43fbd](https://github.com/angular/angular/commit/a369f43fbdf45456bbae1caf71ef7becd15d1e90) | fix | capture switch block cases for content projection ([#54921](https://github.com/angular/angular/pull/54921)) |
| [eb625d3783](https://github.com/angular/angular/commit/eb625d37839c3b9f20a2ffb3af06426f9910c8ac) | fix | declare for loop aliases in addition to new name ([#54942](https://github.com/angular/angular/pull/54942)) |
| [f824911510](https://github.com/angular/angular/commit/f8249115102204dbb957a0d292ed5342ea5108e9) | fix | For `FatalDiagnosticError`, hide the `message` field without affecting the emit ([#55160](https://github.com/angular/angular/pull/55160)) |
| [a040fb720a](https://github.com/angular/angular/commit/a040fb720af7db08b328a9f78511c9881f50482d) | fix | maintain multiline CSS selectors during CSS scoping ([#55509](https://github.com/angular/angular/pull/55509)) |
| [39624c6b12](https://github.com/angular/angular/commit/39624c6b129252af352c22c6d6f12ef153477bfc) | fix | output input flags as a literal ([#55215](https://github.com/angular/angular/pull/55215)) |
| [eba92cfa55](https://github.com/angular/angular/commit/eba92cfa55500f3558c02edd0aa348ae118794e0) | fix | prevent usage of reserved control flow symbol in custom interpolation context. ([#55809](https://github.com/angular/angular/pull/55809)) |
| [7d5bc1c628](https://github.com/angular/angular/commit/7d5bc1c62870d9c68e06eddec229a9b8988e92ee) | fix | remove container index from conditional instruction ([#55190](https://github.com/angular/angular/pull/55190)) |
| [4eb0165750](https://github.com/angular/angular/commit/4eb0165750d8c65812502343a70ef4cc35c725b9) | fix | remove support for unassignable expressions in two-way bindings ([#55342](https://github.com/angular/angular/pull/55342)) |
| [e1650e3b13](https://github.com/angular/angular/commit/e1650e3b13556ab09c919cfdf97913fa0291622c) | fix | throw error if item name and context variables conflict ([#55045](https://github.com/angular/angular/pull/55045)) |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [5bd188a394](https://github.com/angular/angular/commit/5bd188a394d30053099e2c83fe79136d590e5399) | feat | add partial compilation support for deferred blocks ([#54908](https://github.com/angular/angular/pull/54908)) |
| [b02b31a915](https://github.com/angular/angular/commit/b02b31a915333e680cf96de5d0f965a6e2639028) | feat | drop support for TypeScript older than 5.4 ([#54961](https://github.com/angular/angular/pull/54961)) |
| [78188e877a](https://github.com/angular/angular/commit/78188e877a4db8655bdd3dc5012b70b12a7234de) | fix | add diagnostic if initializer API is used outside of an initializer ([#54993](https://github.com/angular/angular/pull/54993)) |
| [69a83993b3](https://github.com/angular/angular/commit/69a83993b3772dd98cc10d3e12b0ca6c66293cf2) | fix | do not throw when retrieving TCB symbol for signal input with restricted access ([#55774](https://github.com/angular/angular/pull/55774)) |
| [4f4f41016e](https://github.com/angular/angular/commit/4f4f41016e897c3fab77ffc23fcfeddadaa782c1) | fix | dom property binding check in signal extended diagnostic ([#54324](https://github.com/angular/angular/pull/54324)) |
| [7a16d7e969](https://github.com/angular/angular/commit/7a16d7e969eaf5a9475ffdd21a4bf637ce523856) | fix | don't type check the bodies of control flow nodes in basic mode ([#55360](https://github.com/angular/angular/pull/55360)) |
| [8d93597a82](https://github.com/angular/angular/commit/8d93597a82860112a5398828745653a7e27dcef0) | fix | fix type narrowing of `@if` with aliases ([#55835](https://github.com/angular/angular/pull/55835)) |
| [9b424d7224](https://github.com/angular/angular/commit/9b424d7224db46edb16c81979c7e231d5e3db5e9) | fix | preserve original reference to non-deferrable dependency ([#54759](https://github.com/angular/angular/pull/54759)) |
| [694ba79cbf](https://github.com/angular/angular/commit/694ba79cbf7aaed1079b1fabf53ea446162fc933) | fix | report cases where initializer APIs are used in a non-directive class ([#54993](https://github.com/angular/angular/pull/54993)) |
| [6219341d26](https://github.com/angular/angular/commit/6219341d267ae7689299835b90f0afa0fe61e213) | fix | report errors when initializer APIs are used on private fields ([#54981](https://github.com/angular/angular/pull/54981)) |
| [c04ffb1fa6](https://github.com/angular/angular/commit/c04ffb1fa61f5164ee5eb7c05b7d76292042ff0b) | fix | use switch statements to narrow Angular switch blocks ([#55168](https://github.com/angular/angular/pull/55168)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [a730f09ae9](https://github.com/angular/angular/commit/a730f09ae9e729da79a3e0951e15e0139ef67713) | feat | Add a public API to establish events to be replayed and an attribute to mark an element with an event handler. ([#55356](https://github.com/angular/angular/pull/55356)) |
| [fdd560ea14](https://github.com/angular/angular/commit/fdd560ea14f2f35608e26102c7fac0471a634b3e) | feat | Add ability to configure zone change detection to use zoneless scheduler ([#55252](https://github.com/angular/angular/pull/55252)) |
| [bce5e2344f](https://github.com/angular/angular/commit/bce5e2344f312dc3a8a30d54e412958bd07180c1) | feat | Add build target for jsaction contract binary. ([#55319](https://github.com/angular/angular/pull/55319)) |
| [666d646575](https://github.com/angular/angular/commit/666d646575800e9326eebd513776f8e92b0357e9) | feat | Add event delegation library to queue up events and replay them when the application is ready ([#55121](https://github.com/angular/angular/pull/55121)) |
| [5f06ca8f55](https://github.com/angular/angular/commit/5f06ca8f5539ed208bae0b110887b5538ac4041f) | feat | add HOST_TAG_NAME token ([#54751](https://github.com/angular/angular/pull/54751)) |
| [a600a39d0c](https://github.com/angular/angular/commit/a600a39d0cf9bb8fc2b6786e6f31acb78b7acc6e) | feat | add support for fallback content in ng-content ([#54854](https://github.com/angular/angular/pull/54854)) |
| [146306a141](https://github.com/angular/angular/commit/146306a1417c378920d80a6d91fd847f22e407ab) | feat | add support for i18n hydration ([#54823](https://github.com/angular/angular/pull/54823)) |
| [f09c5a7bc4](https://github.com/angular/angular/commit/f09c5a7bc455a59aea133264cbf9fd9ef7509a7f) | feat | Add zoneless change detection provider as experimental ([#55329](https://github.com/angular/angular/pull/55329)) |
| [d28614b90e](https://github.com/angular/angular/commit/d28614b90eff835639747e8961fe61e874c44666) | feat | Modify EventType from an enum to an object. ([#55323](https://github.com/angular/angular/pull/55323)) |
| [ac863ded48](https://github.com/angular/angular/commit/ac863ded4818af3426ef5888c706a2bd8c79c0be) | feat | provide ExperimentalPendingTasks API ([#55487](https://github.com/angular/angular/pull/55487)) |
| [1ee9f32621](https://github.com/angular/angular/commit/1ee9f32621f6d72e8038a08f5ad4a0cfe8bd6a13) | feat | Synchronize changes from internal JSAction codebase. ([#55182](https://github.com/angular/angular/pull/55182)) |
| [d888da4606](https://github.com/angular/angular/commit/d888da460696ee74bb4c10a19ac49e3fa1948399) | fix | `ApplicationRef.tick` should respect OnPush for host bindings ([#53718](https://github.com/angular/angular/pull/53718)) |
| [64f870c12b](https://github.com/angular/angular/commit/64f870c12bae1ad66509f0d65f8d3e051aae6eaa) | fix | `ApplicationRef.tick` should respect OnPush for host bindings ([#53718](https://github.com/angular/angular/pull/53718)) ([#53718](https://github.com/angular/angular/pull/53718)) |
| [8cad4e8cbe](https://github.com/angular/angular/commit/8cad4e8cbe2baf20dae7b7ef1f4253a4940cbba0) | fix | `ComponentFixture` `autoDetect` respects `OnPush` flag of host view ([#54824](https://github.com/angular/angular/pull/54824)) |
| [658cf8c384](https://github.com/angular/angular/commit/658cf8c3840b637284a5bb6c9751226d24ccbf9f) | fix | `ComponentFixture` stability should match `ApplicationRef` ([#54949](https://github.com/angular/angular/pull/54949)) |
| [2fc11eae9e](https://github.com/angular/angular/commit/2fc11eae9ea65160866bf7ba46c10520ae9a141f) | fix | account for re-projected ng-content elements with fallback content ([#54854](https://github.com/angular/angular/pull/54854)) |
| [0cbd73c6e9](https://github.com/angular/angular/commit/0cbd73c6e9931dc4938054fc6f7831bdee2606a4) | fix | add warning when using zoneless but zone.js is still loaded ([#55769](https://github.com/angular/angular/pull/55769)) |
| [d5edfde6ee](https://github.com/angular/angular/commit/d5edfde6ee3d65bf7f938ecfeac9f30633f8731b) | fix | afterRender hooks registered outside change detection can mark views dirty ([#55623](https://github.com/angular/angular/pull/55623)) |
| [de7447d15e](https://github.com/angular/angular/commit/de7447d15ed964ae26f0dace4cb3b08f5cccb1c1) | fix | Angular should not ignore changes that happen outside the zone ([#55102](https://github.com/angular/angular/pull/55102)) |
| [ba8e465974](https://github.com/angular/angular/commit/ba8e46597435a827670f10b971b2c58f7033b180) | fix | Change Detection will continue to refresh views while marked for check ([#54734](https://github.com/angular/angular/pull/54734)) |
| [5a10f405d3](https://github.com/angular/angular/commit/5a10f405d315a28b9a000c669e9b1cb3fa24a7f1) | fix | complete the removal of deprecation `async` function ([#55491](https://github.com/angular/angular/pull/55491)) |
| [24bc0ed4f2](https://github.com/angular/angular/commit/24bc0ed4f2de47bd998338d73cba394fb45dd497) | fix | ComponentFixture autodetect should detect changes within ApplicationRef.tick ([#54733](https://github.com/angular/angular/pull/54733)) |
| [1c0ec56c46](https://github.com/angular/angular/commit/1c0ec56c462cf18fb38aae29858165a08b5a2a82) | fix | correctly project single-root content inside control flow ([#54921](https://github.com/angular/angular/pull/54921)) |
| [840c375255](https://github.com/angular/angular/commit/840c375255dc381674bb27746d9ababd14567c33) | fix | do not save point-in-time `setTimeout` and `rAF` references ([#55124](https://github.com/angular/angular/pull/55124)) |
| [10c5cdb49c](https://github.com/angular/angular/commit/10c5cdb49c51c95086febd37f4d88a9b944d7e1c) | fix | ensure change detection runs in a reasonable timeframe with zone coalescing ([#54578](https://github.com/angular/angular/pull/54578)) |
| [ad045efd4b](https://github.com/angular/angular/commit/ad045efd4b1565e01c14399998143538ebfbfd99) | fix | Ensure views marked for check are refreshed during change detection ([#54735](https://github.com/angular/angular/pull/54735)) |
| [69085ea26e](https://github.com/angular/angular/commit/69085ea26e11f372578999337b2d8f099600b630) | fix | error about provideExperimentalCheckNoChangesForDebug uses wrong name ([#55824](https://github.com/angular/angular/pull/55824)) |
| [0147e0b85a](https://github.com/angular/angular/commit/0147e0b85a4f1201b1ae5edaa0d2bc708a13673e) | fix | exhaustive checkNoChanges should only do a single pass ([#55839](https://github.com/angular/angular/pull/55839)) |
| [e02bcf89cf](https://github.com/angular/angular/commit/e02bcf89cf77c3118c649a7db68e66a78f16155c) | fix | Fix clearing of pending task in zoneless cleanup implementation ([#55074](https://github.com/angular/angular/pull/55074)) |
| [0cec9e4f9a](https://github.com/angular/angular/commit/0cec9e4f9a90ec59f0e9838dcbd82705b1709fc0) | fix | Fix null dereference error `addEvent` ([#55353](https://github.com/angular/angular/pull/55353)) |
| [44c0ed83a6](https://github.com/angular/angular/commit/44c0ed83a6499fa96f65a27bc5c926579c06b6d2) | fix | hide implementation details of ExperimentalPendingTasks ([#55516](https://github.com/angular/angular/pull/55516)) |
| [314112de99](https://github.com/angular/angular/commit/314112de99bb97475a0d8bdbddf84a3b3ce4a8fb) | fix | Prevent `markForCheck` during change detection from causing infinite loops ([#54900](https://github.com/angular/angular/pull/54900)) |
| [a5fa279b6e](https://github.com/angular/angular/commit/a5fa279b6e9f5ab4005d6d33107f0e1bb48d05de) | fix | prevent i18n hydration from cleaning projected nodes ([#54823](https://github.com/angular/angular/pull/54823)) |
| [6534c035c0](https://github.com/angular/angular/commit/6534c035c099b30987d6fd1346aea454b79cc79d) | fix | Remove deprecated Testability methods ([#53768](https://github.com/angular/angular/pull/53768)) |
| [a5c57c7484](https://github.com/angular/angular/commit/a5c57c7484f1dc3afab4ece4e969a4a7308cdeca) | fix | resolve error for multiple component instances that use fallback content ([#55478](https://github.com/angular/angular/pull/55478)) |
| [f44a5e4604](https://github.com/angular/angular/commit/f44a5e460491a29e5c0cad5577bade8347d52e11) | fix | support content projection and VCRs in i18n ([#54823](https://github.com/angular/angular/pull/54823)) |
| [0510930a25](https://github.com/angular/angular/commit/0510930a257e610460c875dbbc5566fd06547814) | fix | TestBed should not override NgZone from initTestEnvironment ([#55226](https://github.com/angular/angular/pull/55226)) |
| [e9a0c86766](https://github.com/angular/angular/commit/e9a0c86766ab15c896e026120f0c63c2fb1f9e04) | fix | TestBed should not override NgZone from initTestEnvironment ([#55226](https://github.com/angular/angular/pull/55226)) |
| [700c0520bb](https://github.com/angular/angular/commit/700c0520bb638952ba41a8d8260cf12afb078c0e) | fix | Update ApplicationRef.tick loop to only throw in dev mode ([#54848](https://github.com/angular/angular/pull/54848)) |
| [a99cb7ce5b](https://github.com/angular/angular/commit/a99cb7ce5b77a125ab660da8ebef23ecb158e2e3) | fix | zoneless scheduler should check if Zone is defined before accessing it ([#55118](https://github.com/angular/angular/pull/55118)) |
| [1fd63e9cff](https://github.com/angular/angular/commit/1fd63e9cff9159a8c10c35a0af43bc986e4e8e26) | refactor | deprecate `@Component.interpolation` ([#55778](https://github.com/angular/angular/pull/55778)) |
### forms
| Commit | Type | Description |
| -- | -- | -- |
| [1c736dc3b2](https://github.com/angular/angular/commit/1c736dc3b258a502360cda40b3a00c07102ccbf5) | feat | Unified Control State Change Events ([#54579](https://github.com/angular/angular/pull/54579)) |
| [61007dced0](https://github.com/angular/angular/commit/61007dced0f3396c40efcd2617c130633fb9837a) | fix | Add event for forms submitted & reset ([#55667](https://github.com/angular/angular/pull/55667)) |
| [2e27ca9ddf](https://github.com/angular/angular/commit/2e27ca9ddfc1f3f0387cd720071e85ff46f19db6) | fix | Allow canceled async validators to emit. ([#55134](https://github.com/angular/angular/pull/55134)) |
### http
| Commit | Type | Description |
| -- | -- | -- |
| [6f88d80758](https://github.com/angular/angular/commit/6f88d8075895bd80592b1b7e0fba8202a58a5417) | feat | allow caching requests with different origins between server and client ([#55274](https://github.com/angular/angular/pull/55274)) |
| [8eacb6e4b9](https://github.com/angular/angular/commit/8eacb6e4b982a5aa23cfbf9078dc4e19d9466d73) | feat | exclude caching for authenticated HTTP requests ([#55034](https://github.com/angular/angular/pull/55034)) |
| [d9b339fdbc](https://github.com/angular/angular/commit/d9b339fdbc0f8d1e9bb7b1e4190e7d80e68542f9) | fix | resolve `withRequestsMadeViaParent` behavior with `withFetch` ([#55652](https://github.com/angular/angular/pull/55652)) |
| [ef665a40a5](https://github.com/angular/angular/commit/ef665a40a580ff4df79617084ac83738f28ae924) | refactor | Deprecate `HttpClientModule` & related modules ([#54020](https://github.com/angular/angular/pull/54020)) |
### language-service
| Commit | Type | Description |
| -- | -- | -- |
| [6d1b82df32](https://github.com/angular/angular/commit/6d1b82df32049cfaba2f6a50b9639b6e3b722170) | fix | allow external projects to use provided compiler options ([#55035](https://github.com/angular/angular/pull/55035)) |
| [a48afe0d94](https://github.com/angular/angular/commit/a48afe0d9478aca314e68552f4af77f4123563cd) | fix | avoid generating TS syntactic diagnostics for templates ([#55091](https://github.com/angular/angular/pull/55091)) |
| [bd236cc150](https://github.com/angular/angular/commit/bd236cc150e1b21932612ecf91678be77a503d18) | fix | implement getDefinitionAtPosition for Angular templates ([#55269](https://github.com/angular/angular/pull/55269)) |
| [4166dfc1b6](https://github.com/angular/angular/commit/4166dfc1b62a83b60203bfe45a6d4aa7148a0b23) | fix | prevent underlying TS Service from handling template files ([#55003](https://github.com/angular/angular/pull/55003)) |
| [b7f2fd4739](https://github.com/angular/angular/commit/b7f2fd473988a561bfd032386d8955e90c8d91ed) | fix | use type-only import in plugin factory ([#55996](https://github.com/angular/angular/pull/55996)) |
### migrations
| Commit | Type | Description |
| -- | -- | -- |
| [f914f6a362](https://github.com/angular/angular/commit/f914f6a3628847c06cbdde9c90cd417fb2f4c61f) | feat | Migration schematics for `HttpClientModule` ([#54020](https://github.com/angular/angular/pull/54020)) |
| [8459ee46cb](https://github.com/angular/angular/commit/8459ee46cba7f63966c41a2fb7199ec295a91cbb) | fix | handle more cases in HttpClientModule migration ([#55640](https://github.com/angular/angular/pull/55640)) |
| [c4b2f18709](https://github.com/angular/angular/commit/c4b2f18709076f8c400bd26226be37ae07e5e83d) | fix | migrate HttpClientTestingModule in test modules ([#55803](https://github.com/angular/angular/pull/55803)) |
| [bb4a4016a9](https://github.com/angular/angular/commit/bb4a4016a9a29a9c56342ee01d866b0c8a3fb419) | fix | preserve existing properties in HttpClientModule migration ([#55777](https://github.com/angular/angular/pull/55777)) |
| [f93e5180be](https://github.com/angular/angular/commit/f93e5180be1e20a59ff68f12853653f4f3282846) | fix | resolve multiple structural issues with HttpClient migration ([#55557](https://github.com/angular/angular/pull/55557)) |
### platform-browser
| Commit | Type | Description |
| -- | -- | -- |
| [45ae7a6b60](https://github.com/angular/angular/commit/45ae7a6b60019bd49b8a58122a0d5bcbda7e245b) | feat | add withI18nSupport() in developer preview ([#55130](https://github.com/angular/angular/pull/55130)) |
| [23f914f101](https://github.com/angular/angular/commit/23f914f1012545330f6a5aeed4e862bf0e66117b) | fix | Use the right namespace for mathML. ([#55622](https://github.com/angular/angular/pull/55622)) |
| [cba336d4f1](https://github.com/angular/angular/commit/cba336d4f1badd601b24a58fc51bde995f45682d) | refactor | remove deprecated transfer state APIs ([#55474](https://github.com/angular/angular/pull/55474)) |
### platform-browser-dynamic
| Commit | Type | Description |
| -- | -- | -- |
| [eb20c1a8b1](https://github.com/angular/angular/commit/eb20c1a8b18e2e080c856e3e1bf7bcd02f3bfd28) | refactor | unused `RESOURCE_CACHE_PROVIDER` API has been removed ([#54875](https://github.com/angular/angular/pull/54875)) |
### platform-server
| Commit | Type | Description |
| -- | -- | -- |
| [5674c644ab](https://github.com/angular/angular/commit/5674c644abf51ae8764befd3011742ff1febdf29) | fix | add `nonce` attribute to event record script ([#55495](https://github.com/angular/angular/pull/55495)) |
| [e71e869112](https://github.com/angular/angular/commit/e71e869112af1c0ee7a9dd64a963ad7af14a40e2) | fix | remove event dispatch script from HTML when hydration is disabled ([#55681](https://github.com/angular/angular/pull/55681)) |
| [07ac017731](https://github.com/angular/angular/commit/07ac017731f0e08ea3736f1f212093a28648a304) | refactor | remove deprecated `platformDynamicServer` API ([#54874](https://github.com/angular/angular/pull/54874)) |
| [e8b588d8b7](https://github.com/angular/angular/commit/e8b588d8b7fc014aaef99d4b0c1e4567b4aa195d) | refactor | remove deprecated `ServerTransferStateModule` API ([#54874](https://github.com/angular/angular/pull/54874)) |
| [3b1967ca64](https://github.com/angular/angular/commit/3b1967ca64479df9137b3ad7a0d04dbaff6496f4) | refactor | remove deprecated `useAbsoluteUrl` and `baseUrl` from `PlatformConfig` ([#54874](https://github.com/angular/angular/pull/54874)) |
| [2357d3566c](https://github.com/angular/angular/commit/2357d3566c4d18dc40cbda6644ed459ef7703893) | refactor | remove legacy URL handling logic ([#54874](https://github.com/angular/angular/pull/54874)) |
### router
| Commit | Type | Description |
| -- | -- | -- |
| [4a42961393](https://github.com/angular/angular/commit/4a42961393b3abf40f34374df059d3959dadecc0) | feat | `withNavigationErrorHandler` can convert errors to redirects ([#55370](https://github.com/angular/angular/pull/55370)) |
| [8735af08b9](https://github.com/angular/angular/commit/8735af08b976b30cf236a83f9e8b64b5ff62e9f3) | feat | Add ability to return `UrlTree` with `NavigationBehaviorOptions` from guards ([#45023](https://github.com/angular/angular/pull/45023)) |
| [87f3f27f90](https://github.com/angular/angular/commit/87f3f27f9087d757e18e8e2a0f2fca6f2a2c7edf) | feat | Allow resolvers to return `RedirectCommand` ([#54556](https://github.com/angular/angular/pull/54556)) |
| [2b802587f2](https://github.com/angular/angular/commit/2b802587f27186baa493c1dd01f42d568b652f38) | feat | Allow Route.redirectTo to be a function which returns a string or UrlTree ([#52606](https://github.com/angular/angular/pull/52606)) |
| [60f1d681e0](https://github.com/angular/angular/commit/60f1d681e0ba66d3d94b0819f2c612f095c2d3d3) | fix | preserve replaceUrl when returning a urlTree from CanActivate ([#54042](https://github.com/angular/angular/pull/54042)) |
| [3839cfbb18](https://github.com/angular/angular/commit/3839cfbb18fcc70cae5a6ba4ba7676b1c4acf7a0) | fix | Routed components never inherit `RouterOutlet` `EnvironmentInjector` ([#54265](https://github.com/angular/angular/pull/54265)) |
| [da906fdafc](https://github.com/angular/angular/commit/da906fdafcbb302fa280a162d1c1f04369be2efa) | fix | Routed components never inherit `RouterOutlet` `EnvironmentInjector` ([#54265](https://github.com/angular/angular/pull/54265)) |
### service-worker
| Commit | Type | Description |
| -- | -- | -- |
| [3bc63eaaf3](https://github.com/angular/angular/commit/3bc63eaaf344712ac6de1c9618d4558d9443c848) | fix | avoid running CDs on `controllerchange` ([#54222](https://github.com/angular/angular/pull/54222)) |
| [e598634c10](https://github.com/angular/angular/commit/e598634c10a60936ec4199b221eca4e901220763) | fix | remove `controllerchange` listener when app is destroyed ([#55365](https://github.com/angular/angular/pull/55365)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="17.3.6"></a>
# 17.3.6 (2024-04-25)
### core
| Commit | Type | Description |
| -- | -- | -- |
| [826861b1fa](https://github.com/angular/angular/commit/826861b1fa7693010743f5dd881fb31ec33eee52) | fix | DeferBlockFixture.render should not wait for stability ([#55271](https://github.com/angular/angular/pull/55271)) |
| [5cf14da35c](https://github.com/angular/angular/commit/5cf14da35cce1ea4456bae4365d3dbe6667b1881) | fix | make `ActivatedRoute` inject correct instance inside `@defer` blocks ([#55374](https://github.com/angular/angular/pull/55374)) |
| [8979fba2c5](https://github.com/angular/angular/commit/8979fba2c5813673767a133caeec9ac768d17329) | fix | skip defer timers on the server ([#55480](https://github.com/angular/angular/pull/55480)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="17.3.5"></a>
# 17.3.5 (2024-04-17)
<!-- CHANGELOG SPLIT MARKER -->
<a name="17.3.4"></a>
# 17.3.4 (2024-04-10)
### common
| Commit | Type | Description |
| -- | -- | -- |
| [53427d875d](https://github.com/angular/angular/commit/53427d875d33de16b1dbb04e76a9fe32a2b8a445) | fix | invalid ImageKit quality parameter ([#55193](https://github.com/angular/angular/pull/55193)) |
| [766548c3ec](https://github.com/angular/angular/commit/766548c3ecc06ffd8f06ed9a7d0cbb3db6f1b0f6) | fix | skip transfer cache on client ([#55012](https://github.com/angular/angular/pull/55012)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="17.3.2"></a>
# 17.3.2 (2024-03-28)
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [2b7bad5151](https://github.com/angular/angular/commit/2b7bad515100cbfa40b3e8d844bae13d43fd5602) | fix | invoke method-based tracking function with context ([#54960](https://github.com/angular/angular/pull/54960)) |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [b478dfbfda](https://github.com/angular/angular/commit/b478dfbfda3f32fbe723a1e8725e86490422520d) | fix | report errors when initializer APIs are used on private fields ([#55070](https://github.com/angular/angular/pull/55070)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [708ba8115f](https://github.com/angular/angular/commit/708ba8115f7ad05201db5c529aefe4dd48fc64c5) | fix | establish proper injector resolution order for `@defer` blocks ([#55079](https://github.com/angular/angular/pull/55079)) |
### http
| Commit | Type | Description |
| -- | -- | -- |
| [cb433af0e1](https://github.com/angular/angular/commit/cb433af0e1ba61073eb4a02ccd75cf360e9fd409) | fix | include transferCache when cloning HttpRequest ([#54939](https://github.com/angular/angular/pull/54939)) |
| [64f202cab9](https://github.com/angular/angular/commit/64f202cab9e7a5c873b17bbddd02368006426152) | fix | manage different body types for caching POST requests ([#54980](https://github.com/angular/angular/pull/54980)) |
### migrations
| Commit | Type | Description |
| -- | -- | -- |
| [2f9d94bc4a](https://github.com/angular/angular/commit/2f9d94bc4ab5a94e620a13404aba4e094f8b2344) | fix | account for variables in imports initializer ([#55081](https://github.com/angular/angular/pull/55081)) |
### router
| Commit | Type | Description |
| -- | -- | -- |
| [365fd50407](https://github.com/angular/angular/commit/365fd504077d0e7509efc3077ea4ae8bbafb01f7) | fix | RouterLinkActive will always remove active classes when links are not active ([#54982](https://github.com/angular/angular/pull/54982)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="17.3.1"></a>
# 17.3.1 (2024-03-20)
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [c0788200e2](https://github.com/angular/angular/commit/c0788200e26406bacb90ee0079ea9753eebd1b32) | fix | capture data bindings for content projection purposes in blocks ([#54876](https://github.com/angular/angular/pull/54876)) |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [99e9474aa2](https://github.com/angular/angular/commit/99e9474aa2ccccdf4385fbac6b62b1a4585ed4b4) | fix | symbol feature detection for the compiler ([#54711](https://github.com/angular/angular/pull/54711)) |
<!-- CHANGELOG SPLIT MARKER -->
@@ -992,6 +713,21 @@ Live long and prosper 🖖🏻
Example after:
```typescript
items.update(itemsArray => [itemsArray, …newItem]);
```
- The `mutate` method was removed from the `WritableSignal` interface and completely
dropped from the public API surface. As an alternative please use the update method and
make immutable changes to the object.
Example before:
```typescript
items.mutate(itemsArray => itemsArray.push(newItem));
```
Example after:
```typescript
items.update(itemsArray => [itemsArray, …newItem]);
```
+6 -1
View File
@@ -207,7 +207,7 @@ To ensure consistency throughout the source code, keep these rules in mind as yo
* All public API methods **must be documented**.
* We follow [Google's JavaScript Style Guide][js-style-guide], but wrap all code at **100 characters**.
An automated formatter is available, see [DEVELOPER.md](docs/DEVELOPER.md#formatting-your-source-code).
An automated formatter is available, see [DEVELOPER.md](docs/DEVELOPER.md#clang-format).
## <a name="commit"></a> Commit Message Format
@@ -389,6 +389,7 @@ The following documents can help you sort out issues with GitHub accounts and mu
[angular-group]: https://groups.google.com/forum/#!forum/angular
[coc]: https://github.com/angular/code-of-conduct/blob/main/CODE_OF_CONDUCT.md
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
[corporate-cla]: https://cla.developers.google.com/about/google-corporate
@@ -397,3 +398,7 @@ The following documents can help you sort out issues with GitHub accounts and mu
[discord]: https://discord.gg/angular
[individual-cla]: https://cla.developers.google.com/about/google-individual
[js-style-guide]: https://google.github.io/styleguide/jsguide.html
[jsfiddle]: https://jsfiddle.net/
[plunker]: https://plnkr.co/edit
[runnable]: https://runnable.com/
[stackoverflow]: https://stackoverflow.com/questions/tagged/angular
+19 -4
View File
@@ -1,7 +1,7 @@
<h1 align="center">Angular - The modern web developer's platform</h1>
<p align="center">
<img src="adev/src/assets/images/press-kit/angular_icon_gradient.gif" alt="angular-logo" width="120px" height="120px"/>
<img src="aio/src/assets/images/logos/angular/angular_renaissance.png" alt="angular-logo" width="120px" height="120px"/>
<br>
<em>Angular is a development platform for building mobile and desktop web applications
<br> using TypeScript/JavaScript and other languages.</em>
@@ -63,7 +63,22 @@ Get started with Angular, learn the fundamentals and explore advanced topics on
### Local Development
To contribute to the Angular Docs, check out the [Angular.dev README](adev/README.md)
To contribute to Angular docs, you can setup a local environment with the following commands:
```bash
# Clone Angular repo
git clone https://github.com/angular/angular.git
# Navigate to project directory
cd angular
# Install dependencies
yarn
# Build and run local dev server
# Note: Initial build will take some time
yarn docs
```
## Development Setup
@@ -152,8 +167,8 @@ Join the conversation and help the community.
[angularmaterial]: https://material.angular.io/
[cli]: https://angular.dev/tools/cli
[architecture]: https://angular.dev/essentials
[componentstemplates]: https://angular.dev/tutorials/learn-angular/1-components-in-angular
[forms]: https://angular.dev/tutorials/learn-angular/15-forms
[componentstemplates]: https://angular.dev/tutorials/learn-angular/components-in-angular
[forms]: https://angular.dev/tutorials/learn-angular/forms
[api]: https://angular.dev/api
[angularelements]: https://angular.dev/guide/elements
[ssr]: https://angular.dev/guide/ssr
+51 -12
View File
@@ -2,12 +2,27 @@ workspace(
name = "angular",
managed_directories = {
"@npm": ["node_modules"],
"@aio_npm": ["aio/node_modules"],
},
)
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("//:yarn.bzl", "YARN_LABEL")
# Add a patch fix for rules_webtesting v0.3.5 required for enabling runfiles on Windows.
# TODO: Remove the http_archive for this transitive dependency when a release is cut
# for https://github.com/bazelbuild/rules_webtesting/commit/581b1557e382f93419da6a03b91a45c2ac9a9ec8
# and the version is updated in rules_nodejs.
http_archive(
name = "io_bazel_rules_webtesting",
patch_args = ["-p1"],
patches = [
"//:tools/bazel-repo-patches/rules_webtesting__windows_runfiles_fix.patch",
],
sha256 = "e9abb7658b6a129740c0b3ef6f5a2370864e102a5ba5ffca2cea565829ed825a",
urls = ["https://github.com/bazelbuild/rules_webtesting/releases/download/0.3.5/rules_webtesting.tar.gz"],
)
http_archive(
name = "build_bazel_rules_nodejs",
patches = [
@@ -50,16 +65,16 @@ load("@rules_nodejs//nodejs:repositories.bzl", "nodejs_register_toolchains")
nodejs_register_toolchains(
name = "nodejs",
node_repositories = {
"18.20.0-darwin_arm64": ("node-v18.20.0-darwin-arm64.tar.gz", "node-v18.20.0-darwin-arm64", "10066ad4dd9e03ea5c4c45ef8775420ff37b860de09bbdf87b97e0c07b1ea036"),
"18.20.0-darwin_amd64": ("node-v18.20.0-darwin-x64.tar.gz", "node-v18.20.0-darwin-x64", "062ba71618e88e06321de5caa038843c350aababa2d315f3ca7b8551f8e66c1c"),
"18.20.0-linux_arm64": ("node-v18.20.0-linux-arm64.tar.xz", "node-v18.20.0-linux-arm64", "afe51da9ffb38ac1e3a20d9a06efd403ced4bf8831ab554a02a088dd8392fd79"),
"18.20.0-linux_ppc64le": ("node-v18.20.0-linux-ppc64le.tar.xz", "node-v18.20.0-linux-ppc64le", "9e652bbf53a3e37285b11dfb9d6a9bb8b02010c3b50e5c8229d4cc10e72681da"),
"18.20.0-linux_s390x": ("node-v18.20.0-linux-s390x.tar.xz", "node-v18.20.0-linux-s390x", "a6c2a5796b9d9e9bf21da62ec89ff30b41a8108880b9eaa3c912f1ce795a7743"),
"18.20.0-linux_amd64": ("node-v18.20.0-linux-x64.tar.xz", "node-v18.20.0-linux-x64", "03eea148e56785babb27930b05ed6bf311aaa3bc573c0399dd63cad2fe5713c7"),
"18.20.0-windows_amd64": ("node-v18.20.0-win-x64.zip", "node-v18.20.0-win-x64", "1c0aab05cc6836a8f5148cca345b92ebc948a4a2013f18d117b7ade6ff05aca6"),
"18.18.2-darwin_arm64": ("node-v18.18.2-darwin-arm64.tar.gz", "node-v18.18.2-darwin-arm64", "9f982cc91b28778dd8638e4f94563b0c2a1da7aba62beb72bd427721035ab553"),
"18.18.2-darwin_amd64": ("node-v18.18.2-darwin-x64.tar.gz", "node-v18.18.2-darwin-x64", "5bb8da908ed590e256a69bf2862238c8a67bc4600119f2f7721ca18a7c810c0f"),
"18.18.2-linux_arm64": ("node-v18.18.2-linux-arm64.tar.xz", "node-v18.18.2-linux-arm64", "2e630e18548627f61eaf573233da7949dc0a1df5eef3f486fa9820c5f6c121aa"),
"18.18.2-linux_ppc64le": ("node-v18.18.2-linux-ppc64le.tar.xz", "node-v18.18.2-linux-ppc64le", "b0adff5cf5938266b711d6c724fb134d802e0dee40b3a3f73d162de1b3d11880"),
"18.18.2-linux_s390x": ("node-v18.18.2-linux-s390x.tar.xz", "node-v18.18.2-linux-s390x", "c70ec2074b5e2b42c55bb4b8105418b67bf8a61c500d9376a07430dfcc341fdb"),
"18.18.2-linux_amd64": ("node-v18.18.2-linux-x64.tar.xz", "node-v18.18.2-linux-x64", "75aba25ae76999309fc6c598efe56ce53fbfc221381a44a840864276264ab8ac"),
"18.18.2-windows_amd64": ("node-v18.18.2-win-x64.zip", "node-v18.18.2-win-x64", "3bb0e51e579a41a22b3bf6cb2f3e79c03801aa17acbe0ca00fc555d1282e7acd"),
},
# We need at least Node 18.17 due to some transitive dependencies.
node_version = "18.20.0",
node_version = "18.18.2",
)
# Download npm dependencies.
@@ -75,7 +90,7 @@ yarn_install(
"//:.yarnrc",
"//:tools/npm-patches/@bazel+jasmine+5.8.1.patch",
"//tools:postinstall-patches.js",
"//tools/esm-interop:patches/npm/@angular+build-tooling+0.0.0-239d56b71911f9fa1eeefb6e4505dbe7b0cd81a7.patch",
"//tools/esm-interop:patches/npm/@angular+build-tooling+0.0.0-e0ec7b60641d7f6369be45d8d02663fd50f320be.patch",
"//tools/esm-interop:patches/npm/@bazel+concatjs+5.8.1.patch",
"//tools/esm-interop:patches/npm/@bazel+esbuild+5.7.1.patch",
"//tools/esm-interop:patches/npm/@bazel+protractor+5.7.1.patch",
@@ -94,6 +109,30 @@ yarn_install(
yarn_lock = "//:yarn.lock",
)
yarn_install(
name = "aio_npm",
# Note that we add the postinstall scripts here so that the dependencies are re-installed
# when the postinstall patches are modified.
data = [
YARN_LABEL,
"//:.yarnrc",
"//:tools/npm-patches/@bazel+jasmine+5.8.1.patch",
"//aio:tools/cli-patches/bazel-architect-output.patch",
"//aio:tools/cli-patches/patch.js",
],
# Currently disabled due to:
# 1. Missing Windows support currently.
# 2. Incompatibilites with the `ts_library` rule.
exports_directories_only = False,
manual_build_file_contents = npm_package_archives(),
package_json = "//aio:package.json",
# We prefer to symlink the `node_modules` to only maintain a single install.
# See https://github.com/angular/dev-infra/pull/446#issuecomment-1059820287 for details.
symlink_node_modules = True,
yarn = YARN_LABEL,
yarn_lock = "//aio:yarn.lock",
)
yarn_install(
name = "aio_example_deps",
# Rename the default js_library target from "node_modules" as this obscures the
@@ -167,10 +206,10 @@ cldr_xml_data_repository(
# sass rules
http_archive(
name = "io_bazel_rules_sass",
sha256 = "4f9be14f1132126c4bd7335e7d9eb70ed7273303e3966bbec1744c14d20d10df",
strip_prefix = "rules_sass-61dde525066c4e17cfe8d404748dbc7195c10bde",
sha256 = "5633816e996a79c77f44306f6228b9ef18fc2ecb412d63b4e314a132225facba",
strip_prefix = "rules_sass-79bd239ce77c101ea1aed575678020bd2999f17d",
urls = [
"https://github.com/bazelbuild/rules_sass/archive/61dde525066c4e17cfe8d404748dbc7195c10bde.zip",
"https://github.com/bazelbuild/rules_sass/archive/79bd239ce77c101ea1aed575678020bd2999f17d.zip",
],
)
+18 -32
View File
@@ -1,9 +1,8 @@
load("//:packages.bzl", "link_packages")
load("@npm//@angular/build-tooling/bazel/remote-execution:index.bzl", "ENABLE_NETWORK")
load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin")
load("@npm//@angular-devkit/architect-cli:index.bzl", "architect", "architect_test")
load("@bazel_skylib//lib:collections.bzl", "collections")
load("//adev/tools/local_deps:index.bzl", "ensure_local_package_deps", "link_local_packages")
package(default_visibility = ["//visibility:public"])
@@ -31,18 +30,7 @@ TEST_FILES = APPLICATION_FILES + [
["**/*.spec.ts"],
)
APPLICATION_ASSETS = [
"//adev/src/assets/images",
"//adev/src/assets/textures",
"//adev/src/assets/previews",
"//adev/src/assets:tutorials",
"//adev/src/assets/icons",
"//adev/src/assets:api",
"//adev/src/assets:content",
]
APPLICATION_DEPS = [
"@npm//@angular/build",
APPLICATION_DEPS = link_packages([
"@npm//@angular-devkit/build-angular",
"@npm//@angular/animations",
"@npm//@angular/cdk",
@@ -62,6 +50,13 @@ APPLICATION_DEPS = [
"@npm//ogl",
"@npm//rxjs",
"@npm//typescript",
"//adev/src/assets/images",
"//adev/src/assets/textures",
"//adev/src/assets/previews",
"//adev/src/assets:tutorials",
"//adev/src/assets/icons",
"//adev/src/assets:api",
"//adev/src/assets:content",
"@npm//@typescript/vfs",
"@npm//@codemirror/state",
"@npm//@codemirror/view",
@@ -79,14 +74,13 @@ APPLICATION_DEPS = [
"@npm//@lezer/javascript",
"@npm//@lezer/common",
"@npm//@xterm/xterm",
"@npm//@xterm/addon-fit",
"@npm//algoliasearch",
"@npm//xterm-addon-fit",
"@npm//angular-split",
"@npm//zone.js",
]
])
TEST_DEPS = APPLICATION_DEPS + [
TEST_DEPS = APPLICATION_DEPS + link_packages([
"@npm//@angular/platform-browser-dynamic",
"@npm//@angular/build-tooling/bazel/browsers/chromium",
"@npm//@types/jasmine",
"@npm//@types/node",
"@npm//assert",
@@ -96,13 +90,8 @@ TEST_DEPS = APPLICATION_DEPS + [
"@npm//karma-coverage",
"@npm//karma-jasmine",
"@npm//karma-jasmine-html-reporter",
]
# Create `npm_link` targets for all dependencies that correspond to a
# first-party Angular package that can be built from `HEAD`.
link_local_packages(
all_deps = collections.uniq(APPLICATION_DEPS + TEST_DEPS),
)
"//aio/tools:windows-chromium-path",
])
copy_to_bin(
name = "application_files_bin",
@@ -140,7 +129,7 @@ architect(
"--output-path=build",
] + config_based_architect_flags,
chdir = "$(RULEDIR)",
data = ensure_local_package_deps(APPLICATION_DEPS) + APPLICATION_ASSETS + [
data = APPLICATION_DEPS + [
":application_files_bin",
],
# Network is required to inline fonts.
@@ -160,7 +149,7 @@ architect(
"--watch",
],
chdir = package_name(),
data = ensure_local_package_deps(APPLICATION_DEPS) + APPLICATION_ASSETS + [
data = APPLICATION_DEPS + [
":application_files_bin",
],
tags = [
@@ -175,10 +164,7 @@ architect_test(
"--no-watch",
],
chdir = package_name(),
data = ensure_local_package_deps(TEST_DEPS) + TEST_FILES + APPLICATION_ASSETS + [
"//aio/tools:windows-chromium-path",
"@npm//@angular/build-tooling/bazel/browsers/chromium",
],
data = TEST_DEPS + TEST_FILES,
env = {
"CHROME_BIN": "../$(CHROMIUM)",
},
-37
View File
@@ -1,37 +0,0 @@
# [Angular.dev](https://www.angular.dev)
This site is built with Angular.
The content is written primarly in Markdown format located in `src/content`. For simple edits, you can directly edit the file on GitHub and generate a Pull Request.
## Local Development
For local development, [yarn](https://yarnpkg.com/) is the preferred package manager. You can setup a local environment with the following commands
:
```bash
# Clone Angular repo
git clone https://github.com/angular/angular.git
# Navigate to project directory
cd angular
# Install dependencies
yarn
# Build and run local dev server
# Note: Initial build will take some time
yarn docs
```
## Contributing
Want to report a bug, contribute some code, or improve the documentation? Excellent!
Read through our [contributing guidelines](CONTRIBUTING.md) to learn about our submission process, coding rules, and more.
And if you're new, check out one of our issues labeled as <kbd>[help wanted](https://github.com/angular/angular/labels/help%20wanted)</kbd> or <kbd>[good first issue](https://github.com/angular/angular/labels/good%20first%20issue)</kbd>.
### Code of Conduct
Help us keep Angular open and inclusive. Please read and follow our [Code of Conduct](CODE_OF_CONDUCT.md).
+11 -10
View File
@@ -17,9 +17,11 @@
"prefix": "adev",
"architect": {
"build": {
"builder": "@angular/build:application",
"builder": "@angular-devkit/build-angular:application",
"options": {
"externalDependencies": ["path"],
"externalDependencies": [
"path"
],
"outputPath": "dist/angular-dev",
"index": "src/index.html",
"browser": "src/main.ts",
@@ -27,8 +29,12 @@
"polyfills": ["src/polyfills.ts", "zone.js"],
"tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": ["src/favicon.ico", "src/robots.txt", "src/assets"],
"styles": ["@angular/docs/styles/global-styles.scss", "./src/local-styles.scss"],
"assets": [
"src/favicon.ico",
"src/robots.txt",
"src/assets"
],
"styles": ["@angular/docs/styles/global-styles.scss"],
"scripts": [],
"webWorkerTsConfig": "tsconfig.worker.json",
"optimization": {
@@ -93,11 +99,6 @@
}
},
"cli": {
"analytics": "dca119a9-da31-47f7-a6cb-b60541037021",
"cache": {
// Disable build caching as the cache folder will just be dropped
// when run under Bazel sandboxed execution.
"enabled": false
}
"analytics": "dca119a9-da31-47f7-a6cb-b60541037021"
}
}
-3
View File
@@ -1,3 +0,0 @@
# Generating data for `angular.dev/cli`
This script updates the Angular CLI help JSON files stored in `adev/src/content/cli/help`. This files are used to generate the [angular.dev CLI](https://angular.dev/cli) pages.
-154
View File
@@ -1,154 +0,0 @@
import {execSync} from 'node:child_process';
import {readFile, writeFile, readdir, mkdtemp, realpath, copyFile, unlink} from 'node:fs/promises';
import {tmpdir} from 'node:os';
import {get} from 'node:https';
import {dirname, resolve as resolvePath, posix, join} from 'node:path';
import {fileURLToPath} from 'node:url';
import {existsSync, constants as fsConstants} from 'node:fs';
const GITHUB_API = 'https://api.github.com/repos/';
const CLI_BUILDS_REPO = 'angular/cli-builds';
const GITHUB_API_CLI_BUILDS = posix.join(GITHUB_API, CLI_BUILDS_REPO);
const scriptDir = dirname(fileURLToPath(import.meta.url));
const CLI_HELP_CONTENT_PATH = resolvePath(scriptDir, '../../src/content/cli/help');
const CLI_SHA_PATH = join(CLI_HELP_CONTENT_PATH, 'build-info.json');
async function main() {
if (!existsSync(CLI_SHA_PATH)) {
throw new Error(`${CLI_SHA_PATH} does not exist.`);
}
const branch = process.env.GITHUB_REF;
const {sha: currentSha} = JSON.parse(await readFile(CLI_SHA_PATH, 'utf-8'));
const latestSha = await getShaFromCliBuilds(branch);
console.log(`Comparing ${currentSha}...${latestSha}.`);
const affectedFiles = await getAffectedFiles(currentSha, latestSha);
const changedHelpFiles = affectedFiles.filter((file) => file.startsWith('help/'));
if (changedHelpFiles.length === 0) {
console.log(`No 'help/**' files changed between ${currentSha} and ${latestSha}.`);
return;
}
console.log(
`The below help files changed between ${currentSha} and ${latestSha}:\n` +
changedHelpFiles.map((f) => '* ' + f).join('\n'),
);
const temporaryDir = await realpath(await mkdtemp(join(tmpdir(), 'cli-src-')));
const execOptions = {cwd: temporaryDir, stdio: 'inherit'};
execSync('git init', execOptions);
execSync('git remote add origin https://github.com/angular/cli-builds.git', execOptions);
// fetch a commit
execSync(`git fetch origin ${latestSha}`, execOptions);
// reset this repository's main branch to the commit of interest
execSync('git reset --hard FETCH_HEAD', execOptions);
// get sha when files where changed
const shaWhenFilesChanged = execSync(`git rev-list -1 ${latestSha} "help/"`, {
encoding: 'utf8',
cwd: temporaryDir,
stdio: ['ignore', 'pipe', 'ignore'],
}).trim();
// Delete existing JSON help files.
const helpFilesUnlink = (await readdir(CLI_HELP_CONTENT_PATH))
.filter((f) => f.endsWith('.json'))
.map((f) => unlink(join(CLI_HELP_CONTENT_PATH, f)));
await Promise.allSettled(helpFilesUnlink);
// Copy new help files
const tempHelpDir = join(temporaryDir, 'help');
const helpFilesCopy = (await readdir(tempHelpDir)).map((f) => {
const src = join(tempHelpDir, f);
const dest = join(CLI_HELP_CONTENT_PATH, f);
return copyFile(src, dest, fsConstants.COPYFILE_FICLONE);
});
await Promise.allSettled(helpFilesCopy);
// Write SHA to file.
await writeFile(
CLI_SHA_PATH,
JSON.stringify(
{
branchName: branch,
sha: shaWhenFilesChanged,
},
undefined,
2,
),
);
console.log('\nChanges: ');
execSync(`git status --porcelain`, {stdio: 'inherit'});
console.log(`Successfully updated help files in '${CLI_HELP_CONTENT_PATH}'.\n`);
}
/**
* Get SHA of a branch.
*
* @param {string} branch
* @param {string} headSha
* @returns Promise<string>
*/
async function getShaFromCliBuilds(branch) {
const sha = await httpGet(`${GITHUB_API_CLI_BUILDS}/commits/${branch}`, {
headers: {Accept: 'application/vnd.github.VERSION.sha'},
});
if (!sha) {
throw new Error(`Unable to extract the SHA for '${branch}'.`);
}
return sha;
}
/**
* Get the affected files.
*
* @param {string} baseSha
* @param {string} headSha
* @returns Promise<string[]>
*/
async function getAffectedFiles(baseSha, headSha) {
const {files} = JSON.parse(
await httpGet(`${GITHUB_API_CLI_BUILDS}/compare/${baseSha}...${headSha}`),
);
return files.map((f) => f.filename);
}
function httpGet(url, options = {}) {
options.headers ??= {};
options.headers[
'Authorization'
] = `token ${process.env.ANGULAR_CLI_BUILDS_READONLY_GITHUB_TOKEN}`;
// User agent is required
// https://docs.github.com/en/rest/overview/resources-in-the-rest-api?apiVersion=2022-11-28#user-agent-required
options.headers['User-Agent'] = `AIO_Angular_CLI_Sources_Update`;
return new Promise((resolve, reject) => {
get(url, options, (res) => {
let data = '';
res
.on('data', (chunk) => {
data += chunk;
})
.on('end', () => {
resolve(data);
});
}).on('error', (e) => {
reject(e);
});
});
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
+4 -4
View File
@@ -1,11 +1,11 @@
@defer (when isBrowser) {
<adev-progress-bar />
<adev-progress-bar />
}
<button (click)="focusFirstHeading()" class="adev-skip">Skip to main content</button>
<div class="adev-nav"></div>
@if (displaySecondaryNav()) {
<adev-secondary-navigation />
<adev-secondary-navigation />
}
<div class="docs-app-main-content">
<!--
@@ -22,9 +22,9 @@
}
}
}
<router-outlet />
<router-outlet />
@if (displayFooter()) {
<footer adev-footer></footer>
<footer adev-footer></footer>
}
</div>
+1 -7
View File
@@ -11,12 +11,10 @@ import {AppComponent} from './app.component';
import {provideRouter} from '@angular/router';
import {routes} from './routes';
import {Search, WINDOW} from '@angular/docs';
import {CURRENT_MAJOR_VERSION} from './core/providers/current-version';
describe('AppComponent', () => {
const fakeSearch = {};
const fakeWindow = {location: {hostname: 'angular.dev'}};
const fakeCurrentMajorVersion = 19;
const fakeWindow = {};
it('should create the app', () => {
TestBed.configureTestingModule({
@@ -30,10 +28,6 @@ describe('AppComponent', () => {
provide: Search,
useValue: fakeSearch,
},
{
provide: CURRENT_MAJOR_VERSION,
useValue: fakeCurrentMajorVersion,
},
],
});
const fixture = TestBed.createComponent(AppComponent);
+1 -3
View File
@@ -8,7 +8,6 @@
import {DOCUMENT, isPlatformBrowser} from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
inject,
NgZone,
@@ -33,9 +32,8 @@ import {ProgressBarComponent} from './core/layout/progress-bar/progress-bar.comp
import {ESCAPE, SEARCH_TRIGGER_KEY} from './core/constants/keys';
@Component({
selector: 'adev-root',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
selector: 'adev-root',
imports: [
CookiePopup,
Navigation,
-6
View File
@@ -12,7 +12,6 @@ import {
ApplicationConfig,
ENVIRONMENT_INITIALIZER,
ErrorHandler,
VERSION,
inject,
provideZoneChangeDetection,
} from '@angular/core';
@@ -45,7 +44,6 @@ import {ExampleContentLoader} from './core/services/example-content-loader.servi
import {ReuseTutorialsRouteStrategy} from './features/tutorial/tutorials-route-reuse-strategy';
import {routes} from './routes';
import {ReferenceScrollHandler} from './features/references/services/reference-scroll-handler.service';
import {CURRENT_MAJOR_VERSION} from './core/providers/current-version';
export const appConfig: ApplicationConfig = {
providers: [
@@ -73,10 +71,6 @@ export const appConfig: ApplicationConfig = {
provideClientHydration(),
provideHttpClient(withFetch()),
provideAnimationsAsync(),
{
provide: CURRENT_MAJOR_VERSION,
useValue: Number(VERSION.major),
},
{provide: ENVIRONMENT, useValue: environment},
{
provide: ENVIRONMENT_INITIALIZER,
+2 -3
View File
@@ -8,6 +8,5 @@
export const GITHUB = 'https://github.com/angular/angular';
export const X = 'https://x.com/angular';
export const MEDIUM = 'https://blog.angular.dev';
export const YOUTUBE = 'https://www.youtube.com/angular';
export const DISCORD = 'https://discord.gg/angular';
export const MEDIUM = 'https://blog.angular.io';
export const YOUTUBE = 'https://www.youtube.com/channel/UCbn1OgGei-DV7aSRo_HaAiw';
-73
View File
@@ -1,73 +0,0 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
export const VERSIONS_CONFIG = {
aDevVersionsLinkPattern: 'https://{{prefix}}{{version}}angular.dev',
aioVersions: [
{
version: 'v17',
url: 'https://v17.angular.io/docs',
},
{
version: 'v16',
url: 'https://v16.angular.io/docs',
},
{
version: 'v15',
url: 'https://v15.angular.io/docs',
},
{
version: 'v14',
url: 'https://v14.angular.io/docs',
},
{
version: 'v13',
url: 'https://v13.angular.io/docs',
},
{
version: 'v12',
url: 'https://v12.angular.io/docs',
},
{
version: 'v11',
url: 'https://v11.angular.io/docs',
},
{
version: 'v10',
url: 'https://v10.angular.io/docs',
},
{
version: 'v9',
url: 'https://v9.angular.io/docs',
},
{
version: 'v8',
url: 'https://v8.angular.io/docs',
},
{
version: 'v7',
url: 'https://v7.angular.io/docs',
},
{
version: 'v6',
url: 'https://v6.angular.io/docs',
},
{
version: 'v5',
url: 'https://v5.angular.io/docs',
},
{
version: 'v4',
url: 'https://v4.angular.io/docs',
},
{
version: 'v2',
url: 'https://v2.angular.io/docs',
},
],
};
-2
View File
@@ -17,7 +17,6 @@ export enum PagePrefix {
PLAYGROUND = 'playground',
REFERENCE = 'reference',
TUTORIALS = 'tutorials',
UPDATE = 'update-guide',
}
// The enum with the default pages for each main tab
@@ -26,5 +25,4 @@ export enum DefaultPage {
REFERENCE = 'api',
TUTORIALS = 'tutorials',
PLAYGROUND = 'playground',
UPDATE = 'update-guide',
}
@@ -77,8 +77,6 @@
}
.adev-version-picker {
overflow-y: auto;
max-height: 90vh;
top: 30px;
left: 10px;
position: absolute;
@@ -61,9 +61,6 @@
<nav
class="adev-nav-primary docs-scroll-hide"
[class.adev-nav-primary--open]="isMobileNavigationOpened()"
[class.adev-nav-primary--rc]="currentDocsVersionMode === 'rc'"
[class.adev-nav-primary--next]="currentDocsVersionMode === 'next'"
[class.adev-nav-primary--deprecated]="currentDocsVersionMode === 'deprecated'"
>
<button
type="button"
@@ -82,8 +79,7 @@
>
<a aria-label="Angular homepage" routerLink="/">
<!-- Logo Symbol -->
@if(!isUwu) {
<svg class="angular-logo" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 223 236" width="32">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 223 236" width="32">
<g clip-path="url(#a)">
<path
fill="url(#b)"
@@ -126,14 +122,7 @@
</clipPath>
</defs>
</svg>
} @else {
<img
src="assets/images/uwu.png"
style="width: auto; margin: 0"
class="uwu-logo"
alt="Angular logo"
height="34"/>
}
<div class="adev-beta-version">Beta Docs</div>
</a>
<!-- Version picker for v18+ -->
@@ -380,24 +369,6 @@
</svg>
</a>
</li>
<li>
<a [href]="DISCORD" cdkMenuItem title="Angular Discord" target="_blank" rel="noopener">
<!-- Discord Icon -->
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 127.14 96.36"
width="20"
height="20"
fill="none"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M107.7,8.07A105.15,105.15,0,0,0,81.47,0a72.06,72.06,0,0,0-3.36,6.83A97.68,97.68,0,0,0,49,6.83,72.37,72.37,0,0,0,45.64,0,105.89,105.89,0,0,0,19.39,8.09C2.79,32.65-1.71,56.6.54,80.21h0A105.73,105.73,0,0,0,32.71,96.36,77.7,77.7,0,0,0,39.6,85.25a68.42,68.42,0,0,1-10.85-5.18c.91-.66,1.8-1.34,2.66-2a75.57,75.57,0,0,0,64.32,0c.87.71,1.76,1.39,2.66,2a68.68,68.68,0,0,110.87,5.19,77,77,0,0,0,6.89,11.1A105.25,105.25,0,0,0,126.6,80.22h0C129.24,52.84,122.09,29.11,107.7,8.07ZM42.45,65.69C36.18,65.69,31,60,31,53s5-12.74,11.43-12.74S54,46,53.89,53,48.84,65.69,42.45,65.69Zm42.24,0C78.41,65.69,73.25,60,73.25,53s5-12.74,11.44-12.74S96.23,46,96.12,53,91.08,65.69,84.69,65.69Z"
/>
</svg>
</a>
</li>
</ul>
</ng-template>
</div>
@@ -69,23 +69,6 @@
padding-block-end: 2rem;
box-sizing: border-box;
&.adev-nav-primary--next,
&.adev-nav-primary--rc {
// change nav background to indicate this is the rc docs
background: linear-gradient(
140deg,
color-mix(in srgb, var(--orange-red), transparent 60%) 0%,
color-mix(in srgb, var(--vivid-pink), transparent 40%) 15%,
color-mix(in srgb, var(--electric-violet), transparent 70%) 25%,
color-mix(in srgb, var(--bright-blue), transparent 60%) 90%,
);
}
&.adev-nav-primary--deprecated {
// change nav background to indicate this is an outdated version of the docs
background-color: color-mix(in srgb, var(--symbolic-gray), transparent 30%);
}
// div containing mobile close button and adev-nav_top
> div {
display: flex;
@@ -146,6 +129,13 @@
flex-direction: row;
}
.adev-beta-version {
font-family: 'Material Symbols Outlined';
text-transform: uppercase;
text-align: center;
line-height: normal;
}
// version dropdown button
.adev-version-button {
border: 1px solid var(--senary-contrast);
@@ -247,10 +237,6 @@
}
}
.adev-nav-item--logo a {
height: 34px;
}
.adev-close-nav {
display: none;
@include mq.for-phone-only {
@@ -27,10 +27,10 @@ import {
isApple,
IS_SEARCH_DIALOG_OPEN,
} from '@angular/docs';
import {ActivatedRoute, NavigationEnd, Router, RouterLink} from '@angular/router';
import {NavigationEnd, Router, RouterLink} from '@angular/router';
import {filter, map, startWith} from 'rxjs/operators';
import {DOCS_ROUTES, REFERENCE_ROUTES, TUTORIALS_ROUTES} from '../../../routes';
import {GITHUB, MEDIUM, X, YOUTUBE, DISCORD} from '../../constants/links';
import {GITHUB, MEDIUM, X, YOUTUBE} from '../../constants/links';
import {PagePrefix} from '../../enums/pages';
import {Theme, ThemeManager} from '../../services/theme-manager.service';
import {VersionManager} from '../../services/version-manager.service';
@@ -79,14 +79,10 @@ export class Navigation implements OnInit {
readonly X = X;
readonly MEDIUM = MEDIUM;
readonly YOUTUBE = YOUTUBE;
readonly DISCORD = DISCORD;
readonly PRIMARY_NAV_ID = PRIMARY_NAV_ID;
readonly SECONDARY_NAV_ID = SECONDARY_NAV_ID;
// We can't use the ActivatedRouter queryParams as we're outside the router outlet
readonly isUwu = 'location' in globalThis ? location.search.includes('uwu') : false;
miniMenuPositions = [
new ConnectionPositionPair(
{originX: 'end', originY: 'center'},
@@ -106,8 +102,6 @@ export class Navigation implements OnInit {
openedMenu: MenuType | null = null;
currentDocsVersion = this.versionManager.currentDocsVersion;
currentDocsVersionMode = this.versionManager.currentDocsVersion()?.version;
// Set the values of the search label and title only on the client, because the label is user-agent specific.
searchLabel = this.isBrowser
? isApple
@@ -203,8 +197,7 @@ export class Navigation implements OnInit {
this.activeRouteItem.set(PagePrefix.DOCS);
} else if (
urlAfterRedirects.startsWith(PagePrefix.REFERENCE) ||
urlAfterRedirects.startsWith(PagePrefix.API) ||
urlAfterRedirects.startsWith(PagePrefix.UPDATE)
urlAfterRedirects.startsWith(PagePrefix.API)
) {
this.activeRouteItem.set(PagePrefix.REFERENCE);
} else if (urlAfterRedirects === PagePrefix.PLAYGROUND) {
@@ -1,5 +1,5 @@
<div [attr.id]="SECONDARY_NAV_ID" class="adev-secondary-nav-mask" [class.docs-nav-secondary--open]="isSecondaryNavVisible()" (docsClickOutside)="close()" [docsClickOutsideIgnore]="[PRIMARY_NAV_ID]">
<div class="docs-nav-secondary docs-scroll-track-transparent" [style.transform]="translateX()" [style.transition]="transition()">
<div class="docs-nav-secondary docs-scroll-track-transparent" [style.transform]="translateX()" [style.transition]="transition">
<!-- Secondary Nav -->
@if (navigationItems && navigationItems.length > 0) {
<docs-navigation-list
@@ -14,7 +14,6 @@ import {
PLATFORM_ID,
computed,
inject,
signal,
} from '@angular/core';
import {takeUntilDestroyed, toObservable} from '@angular/core/rxjs-interop';
import {
@@ -65,19 +64,19 @@ export class SecondaryNavigation implements OnInit {
private readonly router = inject(Router);
private readonly window = inject(WINDOW);
readonly isSecondaryNavVisible = this.navigationState.isMobileNavVisible;
readonly primaryActiveRouteItem = this.navigationState.primaryActiveRouteItem;
readonly maxVisibleLevelsOnSecondaryNav = computed(() =>
isSecondaryNavVisible = this.navigationState.isMobileNavVisible;
primaryActiveRouteItem = this.navigationState.primaryActiveRouteItem;
maxVisibleLevelsOnSecondaryNav = computed(() =>
this.primaryActiveRouteItem() === PagePrefix.REFERENCE ? 1 : 2,
);
readonly navigationItemsSlides = this.navigationState.expandedItems;
navigationItemsSlides = this.navigationState.expandedItems;
navigationItems: NavigationItem[] | undefined;
translateX = computed(() => {
const level = this.navigationState.expandedItems()?.length ?? 0;
return `translateX(${-level * 100}%)`;
});
transition = signal('0ms');
transition: string = '0ms';
readonly PRIMARY_NAV_ID = PRIMARY_NAV_ID;
readonly SECONDARY_NAV_ID = SECONDARY_NAV_ID;
@@ -183,7 +182,7 @@ export class SecondaryNavigation implements OnInit {
return;
}
setTimeout(() => {
this.transition.set(`${ANIMATION_DURATION}ms`);
this.transition = `${ANIMATION_DURATION}ms`;
}, ANIMATION_DURATION);
}
@@ -1,3 +0,0 @@
import {InjectionToken} from '@angular/core';
export const CURRENT_MAJOR_VERSION = new InjectionToken<number>('CURRENT_MAJOR_VERSION');
@@ -7,9 +7,8 @@
*/
import {Injector} from '@angular/core';
import {ENVIRONMENT, WINDOW, LOCAL_STORAGE} from '@angular/docs';
import {ENVIRONMENT, WINDOW} from '@angular/docs';
import {AnalyticsService} from './analytics.service';
import {MockLocalStorage} from '@angular/docs/testing';
describe('AnalyticsService', () => {
let service: AnalyticsService;
@@ -19,7 +18,6 @@ describe('AnalyticsService', () => {
let windowOnErrorHandler: (event: ErrorEvent) => void;
let mockWindow: any;
let mockLocalStorage = new MockLocalStorage();
beforeEach(() => {
gtagSpy = jasmine.createSpy('gtag');
@@ -41,7 +39,6 @@ describe('AnalyticsService', () => {
{provide: ENVIRONMENT, useValue: {}},
{provide: AnalyticsService, deps: [WINDOW]},
{provide: WINDOW, useFactory: () => mockWindow, deps: []},
{provide: LOCAL_STORAGE, useValue: mockLocalStorage},
],
});
@@ -8,7 +8,7 @@
import {inject, Injectable} from '@angular/core';
import {WINDOW, ENVIRONMENT, LOCAL_STORAGE, STORAGE_KEY, setCookieConsent} from '@angular/docs';
import {WINDOW, ENVIRONMENT} from '@angular/docs';
import {formatErrorEventForAnalytics} from './analytics-format-error';
@@ -28,7 +28,6 @@ interface WindowWithAnalytics extends Window {
export class AnalyticsService {
private environment = inject(ENVIRONMENT);
private window: WindowWithAnalytics = inject(WINDOW);
private readonly localStorage = inject(LOCAL_STORAGE);
constructor() {
this._installGlobalSiteTag();
@@ -65,21 +64,6 @@ export class AnalyticsService {
window.gtag = function () {
window.dataLayer?.push(arguments);
};
// Cookie banner consent initial state
// This code is modified in the @angular/docs package in the cookie-popup component.
// Docs: https://developers.google.com/tag-platform/security/guides/consent
if (this.localStorage) {
if (this.localStorage.getItem(STORAGE_KEY) === 'true') {
setCookieConsent('granted');
} else {
setCookieConsent('denied');
}
} else {
// In case localStorage is not available, we default to denying cookies.
setCookieConsent('denied');
}
window.gtag('js', new Date());
// Configure properties before loading the script. This is necessary to avoid
@@ -10,7 +10,6 @@ import {HttpClient} from '@angular/common/http';
import {Injectable, inject} from '@angular/core';
import {DocContent, DocsContentLoader} from '@angular/docs';
import {Router} from '@angular/router';
import {firstValueFrom} from 'rxjs';
import {map} from 'rxjs/operators';
@Injectable()
@@ -28,13 +27,12 @@ export class ContentLoader implements DocsContentLoader {
try {
this.cache.set(
path,
firstValueFrom(
this.httpClient
.get(`assets/content/${path}`, {
responseType: 'text',
})
.pipe(map((contents) => ({contents, id: path}))),
),
this.httpClient
.get(`assets/content/${path}`, {
responseType: 'text',
})
.pipe(map((contents) => ({contents, id: path})))
.toPromise(),
);
} catch {
this.router.navigateByUrl('/404');
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.dev/license
*/
import {ChangeDetectionStrategy, Component, Inject} from '@angular/core';
import {Component, Inject} from '@angular/core';
import {MAT_SNACK_BAR_DATA, MatSnackBarAction, MatSnackBarRef} from '@angular/material/snack-bar';
export interface ErrorSnackBarData {
@@ -16,7 +16,6 @@ export interface ErrorSnackBarData {
@Component({
selector: 'error-snack-bar',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
{{ message }}
<button
@@ -29,8 +28,8 @@ export interface ErrorSnackBarData {
{{ actionText }}
</button>
`,
standalone: true,
imports: [MatSnackBarAction],
standalone: true,
styles: `:host { display: flex; align-items: center; button { margin-left: 16px }}`,
})
export class ErrorSnackBar {
@@ -82,7 +82,7 @@ export class ThemeManager {
}
private watchPreferredColorScheme() {
window.matchMedia(PREFERS_COLOR_SCHEME_DARK).addEventListener('change', (event) => {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (event) => {
const preferredScheme = event.matches ? 'dark' : 'light';
this.setThemeBodyClasses(preferredScheme);
});
@@ -90,5 +90,5 @@ export class ThemeManager {
}
function preferredScheme(): 'dark' | 'light' {
return window.matchMedia(PREFERS_COLOR_SCHEME_DARK).matches ? 'dark' : 'light';
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
@@ -8,52 +8,17 @@
import {TestBed} from '@angular/core/testing';
import {INITIAL_ADEV_DOCS_VERSION, VersionManager} from './version-manager.service';
import {WINDOW} from '@angular/docs';
import {CURRENT_MAJOR_VERSION} from '../providers/current-version';
import {VersionManager} from './version-manager.service';
describe('VersionManager', () => {
const fakeWindow = {location: {hostname: 'angular.dev'}};
const fakeCurrentMajorVersion = 19;
let service: VersionManager;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
{
provide: WINDOW,
useValue: fakeWindow,
},
{
provide: CURRENT_MAJOR_VERSION,
useValue: fakeCurrentMajorVersion,
},
],
});
TestBed.configureTestingModule({});
service = TestBed.inject(VersionManager);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
it('should contain correct number of Angular Docs versions', () => {
// Note: From v2 to v17 (inclusive), there were no v3
const expectedAioDocsVersionsCount = 15;
// Last stable version and next
const expectedRecentDocsVersionCount = 2;
const expectedPreviousAdevVersionsCount = fakeCurrentMajorVersion - INITIAL_ADEV_DOCS_VERSION;
expect(service['getAioVersions']().length).toBe(expectedAioDocsVersionsCount);
expect(service['getRecentVersions']().length).toBe(expectedRecentDocsVersionCount);
expect(service['getAdevVersions']().length).toBe(expectedPreviousAdevVersionsCount);
expect(service.versions().length).toBe(
expectedAioDocsVersionsCount +
expectedRecentDocsVersionCount +
expectedPreviousAdevVersionsCount,
);
});
});
@@ -6,10 +6,75 @@
* found in the LICENSE file at https://angular.dev/license
*/
import {Injectable, computed, inject, signal} from '@angular/core';
import {VERSIONS_CONFIG} from '../constants/versions';
import {WINDOW} from '@angular/docs';
import {CURRENT_MAJOR_VERSION} from '../providers/current-version';
import {Injectable, VERSION, computed, signal} from '@angular/core';
// TODO(josephperrott): extract this out of the file into a managed location.
const VERSIONS_CONFIG = {
currentVersion: 'stable',
historicalVersionsLinkPattern: 'https://v{{version}}.angular.dev',
mainVersions: [
{
version: 'stable',
url: 'https://angular.dev',
},
{
version: 'v16',
url: 'https://v16.angular.io/docs',
},
{
version: 'v15',
url: 'https://v15.angular.io/docs',
},
{
version: 'v14',
url: 'https://v14.angular.io/docs',
},
{
version: 'v13',
url: 'https://v13.angular.io/docs',
},
{
version: 'v12',
url: 'https://v12.angular.io/docs',
},
{
version: 'v11',
url: 'https://v11.angular.io/docs',
},
{
version: 'v10',
url: 'https://v10.angular.io/docs',
},
{
version: 'v9',
url: 'https://v9.angular.io/docs',
},
{
version: 'v8',
url: 'https://v8.angular.io/docs',
},
{
version: 'v7',
url: 'https://v7.angular.io/docs',
},
{
version: 'v6',
url: 'https://v6.angular.io/docs',
},
{
version: 'v5',
url: 'https://v5.angular.io/docs',
},
{
version: 'v4',
url: 'https://v4.angular.io/docs',
},
{
version: 'v2',
url: 'https://v2.angular.io/docs',
},
],
};
export interface Version {
displayName: string;
@@ -17,86 +82,41 @@ export interface Version {
url: string;
}
export type VersionMode = 'stable' | 'deprecated' | 'rc' | 'next' | number;
export type VersionMode = 'stable' | 'rc' | 'next' | number;
export const INITIAL_ADEV_DOCS_VERSION = 18;
export const VERSION_PLACEHOLDER = '{{version}}';
export const MODE_PLACEHOLDER = '{{prefix}}';
export const INITIAL_DOCS_VERSION = 17;
export const VERSION_PATTERN_PLACEHOLDER = '{{version}}';
@Injectable({
providedIn: 'root',
})
export class VersionManager {
private readonly currentMajorVersion = inject(CURRENT_MAJOR_VERSION);
private readonly window = inject(WINDOW);
// Note: We can assume that if the URL starts with v{{version}}, it is documentation for previous versions of Angular.
// Based on URL we can indicate as well if it's rc or next Docs version.
private get currentVersionMode(): VersionMode {
const hostname = this.window.location.hostname;
if (hostname.startsWith('v')) return 'deprecated';
if (hostname.startsWith('rc')) return 'rc';
if (hostname.startsWith('next')) return 'next';
return 'stable';
}
versions = signal<Version[]>([
...this.getRecentVersions(),
...this.getAdevVersions(),
...this.getAioVersions(),
...VERSIONS_CONFIG.mainVersions.map((item) =>
this.mapToVersion(item as Pick<Version, 'url' | 'version'>),
),
...this.getHistoricalVersions(),
]);
currentDocsVersion = computed(() => {
return this.versions().find(
(version) => version.version.toString() === this.currentVersionMode,
(version) => version.version.toString() === VERSIONS_CONFIG.currentVersion,
);
});
// List of Angular Docs versions which includes current version, next and rc.
private getRecentVersions(): Version[] {
return [
{
url: this.getAdevDocsUrl('next'),
displayName: `next`,
version: 'next',
},
// Note: 'rc' should not be visible for now
// {
// url: this.getAdevDocsUrl('rc'),
// displayName: `rc`,
// version: 'rc',
// },
{
url: this.getAdevDocsUrl(this.currentMajorVersion),
displayName: this.getVersion(this.currentMajorVersion),
version: this.currentVersionMode,
},
];
}
// List of Angular Docs versions hosted on angular.dev domain.
private getAdevVersions(): Version[] {
const adevVersions: Version[] = [];
for (
let version = this.currentMajorVersion - 1;
version >= INITIAL_ADEV_DOCS_VERSION;
version--
) {
adevVersions.push({
url: this.getAdevDocsUrl(version),
private getHistoricalVersions(): Version[] {
const historicalVersions: Version[] = [];
for (let version = Number(VERSION.major) - 1; version >= INITIAL_DOCS_VERSION; version--) {
historicalVersions.push({
url: VERSIONS_CONFIG.historicalVersionsLinkPattern.replace(
VERSION_PATTERN_PLACEHOLDER,
version.toString(),
),
displayName: this.getVersion(version),
version: 'deprecated',
version,
});
}
return adevVersions;
}
// List of Angular Docs versions hosted on angular.io domain.
private getAioVersions(): Version[] {
return VERSIONS_CONFIG.aioVersions.map((item) =>
this.mapToVersion(item as Pick<Version, 'url' | 'version'>),
);
return historicalVersions;
}
private mapToVersion(value: Pick<Version, 'url' | 'version'>): Version {
@@ -107,23 +127,12 @@ export class VersionManager {
}
private getVersion(versionMode: VersionMode): string {
if (versionMode === 'stable' || versionMode === 'deprecated') {
return `v${this.currentMajorVersion}`;
if (versionMode === 'stable') {
return `v${VERSION.major}`;
}
if (Number.isInteger(versionMode)) {
return `v${versionMode}`;
}
return versionMode.toString();
}
private getAdevDocsUrl(version: VersionMode): string {
const docsUrlPrefix = isNaN(Number(version)) ? `` : 'v';
return VERSIONS_CONFIG.aDevVersionsLinkPattern
.replace(MODE_PLACEHOLDER, docsUrlPrefix)
.replace(
VERSION_PLACEHOLDER,
`${version.toString() === 'stable' ? '' : `${version.toString()}.`}`,
);
}
}
@@ -10,29 +10,7 @@
@for (file of files(); track file) {
<mat-tab #tab>
<ng-template mat-tab-label>
@if (tab.isActive && isRenamingFile()) {
<form
(submit)="renameFile($event, file.filename)"
(docsClickOutside)="closeRenameFile()">
<input
name="rename-file"
class="adev-rename-file-input"
#renameFileInput
(keydown)="$event.stopPropagation()"
/>
</form>
} @else {
{{ file.filename.replace('src/', '') }}
}
@if (tab.isActive && canRenameFile(file.filename)) {
<button
class="docs-rename-file"
aria-label="rename file"
(click)="onRenameButtonClick()"
>
<docs-icon>edit</docs-icon>
</button>
}
@if (tab.isActive && canDeleteFile(file.filename)) {
<button
class="docs-delete-file"
@@ -79,8 +79,7 @@
}
.adev-add-file,
.docs-delete-file,
.docs-rename-file {
.docs-delete-file {
docs-icon {
color: var(--gray-400);
transition: color 0.3s ease;
@@ -93,8 +92,7 @@
}
}
.docs-delete-file,
.docs-rename-file {
.docs-delete-file {
padding-inline-start: 0.1rem;
padding-inline-end: 0;
margin-block-start: 0.2rem;
@@ -103,8 +101,7 @@
}
}
.adev-new-file-input,
.adev-rename-file-input {
.adev-new-file-input {
color: var(--primary-contrast);
border: none;
border-radius: 0;
@@ -107,7 +107,7 @@ describe('CodeEditor', () => {
const tabs = await matTabGroup.getTabs();
const expectedLabels = files.map((file, index) => {
const label = file.filename.replace('src/', '');
if (index === 0) return `${label} editdelete`;
if (index === 0) return `${label} delete`;
return label;
});
@@ -28,13 +28,9 @@ import {EmbeddedTutorialManager} from '../embedded-tutorial-manager.service';
import {CodeMirrorEditor} from './code-mirror-editor.service';
import {DiagnosticWithLocation, DiagnosticsState} from './services/diagnostics-state.service';
import {DownloadManager} from '../download-manager.service';
import {ClickOutside, IconComponent} from '@angular/docs';
import {IconComponent} from '@angular/docs';
export const REQUIRED_FILES = new Set([
'src/main.ts',
'src/index.html',
'src/app/app.component.ts',
]);
export const REQUIRED_FILES = new Set(['src/main.ts', 'src/index.html']);
@Component({
selector: 'docs-tutorial-code-editor',
@@ -42,7 +38,7 @@ export const REQUIRED_FILES = new Set([
templateUrl: './code-editor.component.html',
styleUrls: ['./code-editor.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [NgIf, NgFor, MatTabsModule, IconComponent, ClickOutside],
imports: [NgIf, NgFor, MatTabsModule, IconComponent],
})
export class CodeEditor implements AfterViewInit, OnDestroy {
@ViewChild('codeEditorWrapper') private codeEditorWrapperRef!: ElementRef<HTMLDivElement>;
@@ -58,16 +54,6 @@ export class CodeEditor implements AfterViewInit, OnDestroy {
}
}
private renameFileInputRef?: ElementRef<HTMLInputElement>;
@ViewChild('renameFileInput') protected set setRenameFileInputRef(
element: ElementRef<HTMLInputElement>,
) {
if (element) {
element.nativeElement.focus();
this.renameFileInputRef = element;
}
}
private readonly destroyRef = inject(DestroyRef);
private readonly codeMirrorEditor = inject(CodeMirrorEditor);
@@ -96,7 +82,6 @@ export class CodeEditor implements AfterViewInit, OnDestroy {
readonly errors = signal<DiagnosticWithLocation[]>([]);
readonly files = this.codeMirrorEditor.openFiles;
readonly isCreatingFile = signal<boolean>(false);
readonly isRenamingFile = signal<boolean>(false);
ngAfterViewInit() {
this.codeMirrorEditor.init(this.codeEditorWrapperRef.nativeElement);
@@ -119,12 +104,6 @@ export class CodeEditor implements AfterViewInit, OnDestroy {
this.displayErrorsBox.set(false);
}
closeRenameFile(): void {
this.isRenamingFile.set(false);
}
canRenameFile = (filename: string) => this.canDeleteFile(filename);
canDeleteFile(filename: string) {
return !REQUIRED_FILES.has(filename);
}
@@ -139,37 +118,6 @@ export class CodeEditor implements AfterViewInit, OnDestroy {
this.matTabGroup.selectedIndex = this.files().length;
}
onRenameButtonClick() {
this.isRenamingFile.set(true);
}
async renameFile(event: SubmitEvent, oldPath: string) {
if (!this.renameFileInputRef) return;
event.preventDefault();
const renameFileInputValue = this.renameFileInputRef.nativeElement.value;
if (renameFileInputValue) {
if (renameFileInputValue.includes('..')) {
alert('File name can not contain ".."');
return;
}
// src is hidden from users, here we manually add it to the new filename
const newFile = 'src/' + renameFileInputValue;
if (this.files().find(({filename}) => filename.includes(newFile))) {
alert('File name already exists');
return;
}
await this.codeMirrorEditor.renameFile(oldPath, newFile);
}
this.isRenamingFile.set(false);
}
async createFile(event: SubmitEvent) {
if (!this.createFileInputRef) return;
@@ -340,34 +340,6 @@ export class CodeMirrorEditor {
this.changeCurrentFile(filename);
}
async renameFile(oldPath: string, newPath: string) {
const content = await this.nodeRuntimeSandbox.readFile(oldPath).catch((error) => {
// empty content if file does not exist
if (error.message.includes('ENOENT')) return '';
else throw error;
});
await this.nodeRuntimeSandbox.renameFile(oldPath, newPath).catch((error) => {
throw error;
});
this.embeddedTutorialManager.tutorialFiles.update((files) => {
delete files[oldPath];
files[newPath] = content;
return files;
});
this.embeddedTutorialManager.openFiles.update((files) => [
...files.filter((file) => file !== oldPath),
newPath,
]);
this.setProjectFiles();
this.updateVfsEnv();
this.saveLibrariesTypes();
this.changeCurrentFile(newPath);
}
async deleteFile(deletedFile: string): Promise<void> {
await this.nodeRuntimeSandbox.deleteFile(deletedFile);
@@ -8,7 +8,6 @@ $width-breakpoint: 950px;
container-name: embedded-editor;
height: 100%;
position: relative;
border: 1px solid var(--senary-contrast);
}
// The entire thing - editor, terminal, console
@@ -9,7 +9,6 @@
import {NgIf, isPlatformBrowser} from '@angular/common';
import {
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
DestroyRef,
@@ -45,12 +44,11 @@ export const LARGE_EDITOR_WIDTH_BREAKPOINT = 950;
export const LARGE_EDITOR_HEIGHT_BREAKPOINT = 550;
@Component({
selector: EMBEDDED_EDITOR_SELECTOR,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [AngularSplitModule, CodeEditor, Preview, Terminal, NgIf, MatTabsModule, IconComponent],
selector: EMBEDDED_EDITOR_SELECTOR,
templateUrl: './embedded-editor.component.html',
styleUrls: ['./embedded-editor.component.scss'],
imports: [AngularSplitModule, CodeEditor, Preview, Terminal, NgIf, MatTabsModule, IconComponent],
providers: [EditorUiState],
})
export class EmbeddedEditor implements OnInit, AfterViewInit, OnDestroy {
@@ -177,20 +177,6 @@ describe('NodeRuntimeSandbox', () => {
expect(writeFileSpy).toHaveBeenCalledOnceWith(path, content);
});
it('should call renameFile with proper parameters', async () => {
setValuesToInitializeProject();
const fakeWebContainer = new FakeWebContainer();
service['webContainerPromise'] = Promise.resolve(fakeWebContainer);
const renameFileSpy = spyOn(fakeWebContainer.fs, 'rename');
const oldPath = 'oldPath';
const newPath = 'newPath';
await service.renameFile(oldPath, newPath);
expect(renameFileSpy).toHaveBeenCalledOnceWith(oldPath, newPath);
});
it('should initialize the Angular CLI based on the tutorial config', async () => {
setValuesToInitializeAngularCLI();
@@ -270,16 +270,6 @@ export class NodeRuntimeSandbox {
}
}
async renameFile(oldPath: string, newPath: string): Promise<void> {
const webContainer = await this.webContainerPromise!;
try {
await webContainer.fs.rename(oldPath, newPath);
} catch (err: any) {
throw err;
}
}
async readFile(filePath: string): Promise<string> {
const webContainer = await this.webContainerPromise!;
@@ -8,7 +8,7 @@
import {Injectable} from '@angular/core';
import {Terminal} from '@xterm/xterm';
import {FitAddon} from '@xterm/addon-fit';
import {FitAddon} from 'xterm-addon-fit';
import {InteractiveTerminal} from './interactive-terminal';
export enum TerminalType {
@@ -2,7 +2,7 @@
// SASS imports, here we're importing a CSS asset
//
// stylelint-disable-next-line @angular/no-import
@import '@xterm/xterm/css/xterm.css';
@import 'xterm/css/xterm.css';
.docs-tutorial-terminal {
display: block;
+1 -2
View File
@@ -8,14 +8,13 @@
import {CommonModule} from '@angular/common';
import {DocContent, DocViewer} from '@angular/docs';
import {ChangeDetectionStrategy, Component, inject} from '@angular/core';
import {Component, inject} from '@angular/core';
import {toSignal} from '@angular/core/rxjs-interop';
import {ActivatedRoute} from '@angular/router';
import {map} from 'rxjs/operators';
@Component({
selector: 'docs-docs',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [CommonModule, DocViewer],
styleUrls: ['./docs.component.scss'],
@@ -7,7 +7,6 @@
*/
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
EnvironmentInjector,
@@ -21,7 +20,6 @@ import {EmbeddedEditor, EmbeddedTutorialManager} from '../../../editor';
@Component({
selector: 'adev-code-editor',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [EmbeddedEditor],
template: `
File diff suppressed because one or more lines are too long
@@ -36,7 +36,6 @@
box-sizing: border-box;
transition: background 0.3s ease, border 0.3s ease;
h1,
p {
display: inline;
font-size: 0.875rem;
+2 -4
View File
@@ -21,7 +21,7 @@ import {
inject,
} from '@angular/core';
import {WINDOW, shouldReduceMotion, isIos} from '@angular/docs';
import {ActivatedRoute, RouterLink} from '@angular/router';
import {RouterLink} from '@angular/router';
import {injectAsync} from '../../core/services/inject-async';
@@ -48,10 +48,8 @@ export default class Home implements OnInit, AfterViewInit, OnDestroy {
private readonly ngZone = inject(NgZone);
private readonly platformId = inject(PLATFORM_ID);
private readonly window = inject(WINDOW);
private readonly activatedRoute = inject(ActivatedRoute);
protected readonly tutorialFiles = TUTORIALS_HOMEPAGE_DIRECTORY;
protected readonly isUwu = 'uwu' in this.activatedRoute.snapshot.queryParams;
private element!: HTMLDivElement;
private homeAnimation?: HomeAnimation;
private intersectionObserver: IntersectionObserver | undefined;
@@ -76,7 +74,7 @@ export default class Home implements OnInit, AfterViewInit, OnDestroy {
// at the end of the page, and to load the embedded editor.
this.initIntersectionObserver();
if (this.isWebGLAvailable() && !shouldReduceMotion() && !this.isUwu) {
if (this.isWebGLAvailable() && !shouldReduceMotion()) {
this.ngZone.runOutsideAngular(async () => {
await this.loadHomeAnimation();
});
@@ -2,7 +2,7 @@
display: block;
padding: var(--layout-padding);
padding-block-end: 100px;
height: 100vh;
height: calc(98vh);
width: 100%;
box-sizing: border-box;
@@ -1,10 +1,8 @@
<header class="adev-api-items-section-header">
<h3 [attr.id]="group.id">
@if (group.isFeatured) {
<docs-icon aria-hidden>star</docs-icon>
}
<a routerLink="/api" [fragment]="group.id" class="adev-api-anchor" tabindex="-1">{{ group.title }}</a>
</h3>
@if (group.isFeatured) {
<docs-icon>star</docs-icon>
}
<h3>{{ group.title }}</h3>
</header>
<ul class="adev-api-items-section-grid">
@@ -1,7 +1,7 @@
@use '@angular/docs/styles/anchor' as anchor;
.adev-api-items-section-header {
display: flex;
gap: 0.75em;
align-items: center;
svg {
fill: var(--primary-contrast);
@@ -9,11 +9,6 @@
h3 {
flex: 1;
display: flex;
gap: 0.75em;
align-items: flex-start;
margin-top: 1.43rem;
font-size: 1.25rem;
}
@@ -105,10 +100,3 @@
padding: 0.001rem 0.2rem 0.005rem;
margin-inline-start: 0.5rem;
}
.adev-api-anchor {
color: inherit;
@include anchor.docs-anchor();
}
@@ -22,7 +22,6 @@ describe('ApiItemsSection', () => {
const fakeFeaturedGroup: ApiItemsGroup = {
title: 'Featured',
id: 'featured',
isFeatured: true,
items: [
{
@@ -49,7 +48,6 @@ describe('ApiItemsSection', () => {
const fakeGroup: ApiItemsGroup = {
title: 'Example group',
id: 'example',
isFeatured: false,
items: [
{title: 'Fake Title', itemType: ApiItemType.CONST, url: 'api/fakeTitle', isFeatured: false},
@@ -7,6 +7,7 @@
*/
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
import {NgFor, NgIf} from '@angular/common';
import {RouterLink} from '@angular/router';
import {ApiItemsGroup} from '../interfaces/api-items-group';
import ApiItemLabel from '../api-item-label/api-item-label.component';
@@ -15,7 +16,7 @@ import {IconComponent} from '@angular/docs';
@Component({
selector: 'adev-api-items-section',
standalone: true,
imports: [ApiItemLabel, RouterLink, IconComponent],
imports: [NgIf, NgFor, ApiItemLabel, RouterLink, IconComponent],
templateUrl: './api-items-section.component.html',
styleUrls: ['./api-items-section.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
@@ -108,6 +108,7 @@
& > .docs-code {
box-sizing: border-box;
width: 100%;
max-height: 93vh;
overflow: hidden;
padding: 0;
@@ -118,7 +119,6 @@
button {
transition: background-color 0.3s ease;
font-family: monospace;
&.hljs-ln-line {
font-weight: 400;
@@ -154,10 +154,6 @@
}
}
.docs-reference-cli-toc {
margin-bottom: 1rem;
}
.adev-reference-tab {
min-width: 50ch;
margin-block-start: 2.5rem;
@@ -271,9 +267,7 @@
background-color: var(--octonary-contrast);
position: relative;
z-index: 10;
transition:
background-color 0.3s ease,
border 0.3s ease;
transition: background-color 0.3s ease, border 0.3s ease;
// h3 + code || # of overloads
.docs-reference-header {
@@ -358,10 +352,6 @@
}
}
.docs-deprecation-message {
border-block-end: 1px solid var(--senary-contrast);
}
.docs-param-group {
margin-block-start: 1rem;
}
@@ -414,17 +404,4 @@
margin-block-start: 0;
}
}
.docs-ref-content {
padding: 1rem 0;
&:not(:first-child) {
border-block-start: 1px solid var(--senary-contrast);
}
.docs-param-keyword {
display: block;
margin: 0 0 0.5rem 0;
}
}
}
@@ -16,12 +16,12 @@ import {
inject,
signal,
} from '@angular/core';
import {DOCUMENT, NgFor, NgIf, ViewportScroller} from '@angular/common';
import {DOCUMENT, NgFor, NgIf} from '@angular/common';
import {MatTabGroup, MatTabsModule} from '@angular/material/tabs';
import {takeUntilDestroyed, toSignal} from '@angular/core/rxjs-interop';
import {distinctUntilChanged, filter, map, take} from 'rxjs/operators';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {distinctUntilChanged, map} from 'rxjs/operators';
import {DocContent, DocViewer} from '@angular/docs';
import {ActivatedRoute, Router, RouterLink, Scroll} from '@angular/router';
import {ActivatedRoute, Router, RouterLink} from '@angular/router';
import {ApiItemType} from './../interfaces/api-item-type';
import {ReferenceScrollHandler} from '../services/reference-scroll-handler.service';
import {
@@ -51,15 +51,6 @@ export default class ApiReferenceDetailsPage implements OnInit, AfterViewInit {
private readonly document = inject(DOCUMENT);
private readonly router = inject(Router);
private readonly scrollHandler = inject(ReferenceScrollHandler);
private readonly scroller = inject(ViewportScroller);
private scrollEvent = toSignal(
this.router.events.pipe(
filter((e): e is Scroll => e instanceof Scroll),
take(1),
),
{initialValue: null},
);
private cardsDisplayedOnInit = false;
ApiItemType = ApiItemType;
@@ -76,22 +67,10 @@ export default class ApiReferenceDetailsPage implements OnInit, AfterViewInit {
ngAfterViewInit(): void {
this.setActiveTab();
if (this.canDisplayCards()) {
this.cardsDisplayedOnInit = true;
}
this.listenToTabChange();
}
membersCardsLoaded(): void {
const event = this.scrollEvent();
if (this.cardsDisplayedOnInit && event) {
// Cards loaded after scroll event happened. We have to handle the scroll event manually
if (event.position) {
this.scroller.scrollToPosition(event.position);
} else if (event.anchor) {
this.scroller.scrollToAnchor(event.anchor);
}
}
this.scrollHandler.setupListeners(API_TAB_CLASS_NAME);
}
@@ -3,11 +3,6 @@
<h6>Getting Started</h6>
<h1 tabindex="-1">API Reference</h1>
</header>
@if (featuredGroup().items.length) {
<adev-api-items-section [group]="featuredGroup()" class="adev-featured-list" />
}
<form class="adev-reference-list-form">
<docs-text-field
name="query"
@@ -39,8 +34,12 @@
</ul>
</form>
@for (group of filteredGroups(); track group.id) {
@if (featuredGroup().items.length) {
<adev-api-items-section [group]="featuredGroup()" class="adev-featured-list" />
}
@for (group of filteredGroups(); track group) {
<adev-api-items-section [group]="group" />
}
<span id="deprecated-description" class="docs-deprecated-description">Deprecated</span>
</div>
@@ -77,9 +77,8 @@
justify-content: flex-start;
flex-wrap: wrap-reverse;
gap: 1.5rem;
padding-block-start: 1.5rem;
padding-block-start: 0;
padding-block-end: 2rem;
border-block: 1px solid var(--senary-contrast);
}
.adev-reference-list-form-part-two {
@@ -90,10 +89,15 @@
.adev-featured-list {
display: block;
padding-block-end: 1rem;
padding-block-end: 2rem;
padding-block-start: 1.5rem;
margin-block: 1rem;
border-top: 0;
margin-top: -1.5rem;
border-block: 1px solid var(--senary-contrast);
}
.docs-deprecated-description {
display: none;
}
.docs-api-item-label-full {
@@ -15,7 +15,6 @@ import {ApiItemType} from '../interfaces/api-item-type';
import {ApiReferenceManager} from './api-reference-manager.service';
import ApiItemLabel from '../api-item-label/api-item-label.component';
import {ApiLabel} from '../pipes/api-label.pipe';
import {ApiItemsGroup} from '../interfaces/api-items-group';
export const ALL_STATUSES_KEY = 'All';
@@ -46,12 +45,11 @@ export default class ApiReferenceList {
type = signal(ALL_STATUSES_KEY);
featuredGroup = this.apiReferenceManager.featuredGroup;
filteredGroups = computed((): ApiItemsGroup[] => {
filteredGroups = computed(() => {
return this.allGroups()
.map((group) => ({
title: group.title,
isFeatured: group.isFeatured,
id: group.id,
items: group.items.filter((apiItem) => {
return (
(this.query()
@@ -7,7 +7,6 @@
*/
import {Injectable, signal} from '@angular/core';
// This file is generated at build-time, error is expected here.
import API_MANIFEST_JSON from '../../../../../src/assets/api/manifest.json';
import {ANGULAR_PACKAGE_PREFIX, getApiUrl} from '../helpers/manifest.helper';
import {ApiItem} from '../interfaces/api-item';
@@ -15,7 +14,7 @@ import {ApiItemsGroup} from '../interfaces/api-items-group';
import {ApiManifest} from '../interfaces/api-manifest';
export const FEATURED_API_ITEMS_KEY = 'apiFeaturedItems';
export const FEATURED_GROUP_TITLE = 'Most Common';
export const FEATURED_GROUP_TITLE = 'Featured';
export type FeaturedItemsByGroup = Record<string, ApiItem[]>;
@@ -41,7 +40,6 @@ export class ApiReferenceManager {
// Represents group of the featured items.
featuredGroup = signal<ApiItemsGroup>({
title: FEATURED_GROUP_TITLE,
id: 'featured',
items: [],
isFeatured: true,
});
@@ -60,7 +58,6 @@ export class ApiReferenceManager {
groups.push({
title: packageNameWithoutPrefix,
id: packageNameWithoutPrefix.replaceAll('/', '-'),
items: packageApis
.map((api) => {
const url = getApiUrl(packageNameWithoutPrefix, api.name);
@@ -10,7 +10,6 @@ import {ApiItem} from './api-item';
export interface ApiItemsGroup {
title: string;
id: string;
items: ApiItem[];
isFeatured?: boolean;
}
@@ -160,6 +160,9 @@ export class ReferenceScrollHandler implements OnDestroy, ReferenceScrollHandler
for (const line of Array.from(activeLines)) {
line.classList.remove(API_TAB_ACTIVE_CODE_LINE);
}
this.getAllMemberCards().forEach((card) => {
card.blur();
});
} else {
const lines = this.document.querySelectorAll<HTMLButtonElement>(
`button[${MEMBER_ID_ATTRIBUTE}="${currentActiveMemberId}"]`,
@@ -167,7 +170,7 @@ export class ReferenceScrollHandler implements OnDestroy, ReferenceScrollHandler
for (const line of Array.from(lines)) {
line.classList.add(API_TAB_ACTIVE_CODE_LINE);
}
this.document.getElementById(`${currentActiveMemberId}`)?.focus({preventScroll: true});
this.document.getElementById(`${currentActiveMemberId}`)?.focus();
}
}
@@ -176,9 +179,7 @@ export class ReferenceScrollHandler implements OnDestroy, ReferenceScrollHandler
return;
}
if (card !== <HTMLElement>document.activeElement) {
(<HTMLElement>document.activeElement).blur();
}
card.focus();
this.window.scrollTo({
top: card!.offsetTop - this.membersMarginTopInPx(),
@@ -210,9 +211,8 @@ export class ReferenceScrollHandler implements OnDestroy, ReferenceScrollHandler
this.resizeObserver = new ResizeObserver((_) => {
this.ngZone.run(() => {
const offsetTop = tabBody.getBoundingClientRect().top;
if (offsetTop) {
this.membersMarginTopInPx.set(offsetTop);
if (tabBody.offsetTop) {
this.membersMarginTopInPx.set(tabBody.offsetTop);
}
});
});
@@ -105,7 +105,7 @@ $column-width: calc(50% - #{$resizer-width} - var(--layout-padding));
margin-block-start: var(--layout-padding);
cursor: col-resize;
align-self: stretch;
height: 100vh;
height: var(--fixed-content-height);
&::before {
content: '';
@@ -133,7 +133,7 @@ $column-width: calc(50% - #{$resizer-width} - var(--layout-padding));
width: 100%;
min-width: 300px;
padding-block-start: var(--layout-padding);
height: 100vh;
height: var(--fixed-content-height);
}
.adev-split-tutorial {
File diff suppressed because it is too large Load Diff
@@ -1,191 +0,0 @@
<div class="page docs-viewer">
<h1 tabindex="-1">Update Guide</h1>
<div class="wizard">
<div>
<h2>Select the options that match your update</h2>
<h3>Angular versions</h3>
<div class="adev-version-selector">
<span class="adev-template-select">
From v.
<button [cdkMenuTriggerFor]="templatesMenuFrom">
<span>{{ from.name }}</span>
<docs-icon>expand_more</docs-icon>
</button>
<ng-template #templatesMenuFrom>
<ul class="adev-template-dropdown" cdkMenu>
@for (version of versions; track $index) {
<li>
<button cdkMenuItem type="button" (click)="from=version; showUpdatePath()">
<span>{{ version.name }}</span>
</button>
</li>
}
</ul>
</ng-template>
</span>
<span>
<span class="adev-template-select">
To v.
<button [cdkMenuTriggerFor]="templatesMenuTo">
<span>{{ to.name }}</span>
<docs-icon>expand_more</docs-icon>
</button>
<ng-template #templatesMenuTo>
<ul class="adev-template-dropdown" cdkMenu>
@for (version of versions; track $index) {
<li>
<button cdkMenuItem type="button" (click)="to=version; showUpdatePath()">
<span>{{ version.name }}</span>
</button>
</li>
}
</ul>
</ng-template>
</span>
</span>
</div>
@if (from.number >= futureVersion || to.number >= futureVersion) {
<div class="docs-alert docs-alert-critical">
<p>
<strong>Warning:</strong>
Plans for releases after the current major release are not finalized and may change.
These recommendations are based on scheduled deprecations.
</p>
</div>
}
@if (from.number > to.number) {
<div class="docs-alert docs-alert-critical">
<p>
<strong>Warning:</strong>
We do not support downgrading versions of Angular.
</p>
</div>
}
@if ((to.number - from.number > 150) && from.number > 240) {
<div class="docs-alert docs-alert-critical">
<p>
<strong>Warning:</strong>
Be sure to follow the guide below to migrate your application to the new version. You
can't run
<code>ng update</code>
to update Angular applications more than one major version at a time.
</p>
</div>
}
<h3>Application complexity</h3>
<mat-button-toggle-group
(change)="level = $event.value;"
[value]="level"
style="margin-bottom:16px;"
>
<mat-button-toggle [value]="1">Basic</mat-button-toggle>
<mat-button-toggle [value]="2">Medium</mat-button-toggle>
<mat-button-toggle [value]="3">Advanced</mat-button-toggle>
</mat-button-toggle-group>
@if (level === 1) {
<p>Shows information for all Angular developers.</p>
} @else if (level === 2) {
<p>Shows information that's of interest to more advanced Angular developers.</p>
} @else if (level === 3) {
<p>Shows all the information we have about this update.</p>
}
<h3>Other dependencies</h3>
@for (option of optionList; track $index) {
<p>
<mat-checkbox
(change)="options[option.id] = $event.checked; showUpdatePath()"
[checked]="options[option.id]"
>I use {{option.name}} {{option.description}}</mat-checkbox
>
</p>
}
@if (from.number < 600) {
<h4>Package Manager</h4>
<mat-button-toggle-group
(change)="packageManager = $event.value; showUpdatePath()"
[value]="packageManager"
>
<mat-button-toggle value="npm install">npm</mat-button-toggle>
<mat-button-toggle value="yarn add">yarn</mat-button-toggle>
</mat-button-toggle-group>
}
<button
type="button"
(click)="showUpdatePath()"
class="docs-primary-btn show-button"
[attr.text]="'Show me how to update!'"
>
Show me how to update!
</button>
</div>
</div>
<hr />
<!-- RECOMMENDATIONS SECTION -->
@if (
beforeRecommendations.length > 0 || duringRecommendations.length > 0 || afterRecommendations.length > 0
) {
<div class="recommendations">
<h2>{{title}}</h2>
<h3>Before you update</h3>
@for (r of beforeRecommendations; track $index) {
<div class="adev-recommentation-item">
<mat-checkbox></mat-checkbox>
<div [innerHTML]="r.renderedStep"></div>
</div>
}
@if (beforeRecommendations.length <= 0) {
<div>
<em>You don't need to do anything before moving between these versions.</em>
</div>
}
<h3>Update to the new version</h3>
@if (duringRecommendations.length > 0) {
<div>
<em>Review these changes and perform the actions to update your application.</em>
</div>
}
@for (r of duringRecommendations; track $index) {
<div class="adev-recommentation-item">
<mat-checkbox></mat-checkbox>
<div [innerHTML]="r.renderedStep"></div>
</div>
}
@if (duringRecommendations.length <= 0) {
<div>
<em>There aren't any recommendations for moving between these versions.</em>
</div>
}
<h3>After you update</h3>
@for (r of afterRecommendations; track $index) {
<div class="adev-recommentation-item">
<mat-checkbox></mat-checkbox>
<div [innerHTML]="r.renderedStep"></div>
</div>
}
@if (afterRecommendations.length <= 0) {
<div>
<em>You don't need to do anything after moving between these versions.</em>
</div>
}
</div>
}
</div>
@@ -1,100 +0,0 @@
.page {
padding: var(--layout-padding);
max-width: var(--page-width);
container: update-guide-page / inline-size;
}
h3,
h4 {
margin-block-start: 2em;
}
.wizard {
padding-inline: 1rem;
.show-button {
display: block;
margin-block-start: 2rem;
}
}
.adev-version-selector {
display: flex;
gap: 1rem;
}
.adev-template-dropdown {
border: 1px solid var(--senary-contrast);
border-radius: 0.25rem;
padding: 0;
transform: translateY(-0.7rem);
max-height: 200px;
overflow-y: auto;
li {
list-style: none;
width: 198px;
box-sizing: border-box;
button {
background: var(--page-background);
font-size: 0.875rem;
width: 100%;
text-align: left;
padding-block: 0.5rem;
color: var(--quaternary-contrast);
transition:
color 0.3s ease,
background 0.3s ease;
font-weight: 400;
&:hover {
background: var(--senary-contrast);
color: var(--primary-contrast);
}
}
}
}
.adev-template-select {
margin-block-end: 0.5rem;
// cdk select button
button {
font-size: 0.875rem;
border: 1px solid var(--senary-contrast);
border-radius: 0.25rem;
width: 200px;
display: inline-flex;
justify-content: space-between;
align-items: center;
padding-block: 0.5rem;
font-weight: 400;
transition: border 0.3s ease;
span {
color: var(--primary-contrast);
transition: color 0.3s ease;
margin-inline-start: 0.1rem;
}
docs-icon {
font-size: 1.3rem;
color: var(--quaternary-contrast);
transition: color 0.3s ease;
}
}
}
.adev-recommentation-item {
display: flex;
align-items: center;
> div {
margin-inline-start: 2rem;
}
// Code blocks are generable from the markdown, we need to opt-out of the scoping
::ng-deep code {
cursor: pointer;
}
}
@@ -1,294 +0,0 @@
import {ChangeDetectionStrategy, Component, HostListener, inject} from '@angular/core';
import {Step, RECOMMENDATIONS} from './recommendations';
import {Clipboard} from '@angular/cdk/clipboard';
import {CdkMenuModule} from '@angular/cdk/menu';
import {MatCheckboxModule} from '@angular/material/checkbox';
import {MatInputModule} from '@angular/material/input';
import {MatCardModule} from '@angular/material/card';
import {MatGridListModule} from '@angular/material/grid-list';
import {MatButtonToggleModule} from '@angular/material/button-toggle';
import {IconComponent} from '@angular/docs';
import {ActivatedRoute, Router} from '@angular/router';
import {marked} from 'marked';
interface Option {
id: keyof Step;
name: string;
description: string;
}
@Component({
selector: 'adev-update-guide',
templateUrl: './update.component.html',
styleUrl: './update.component.scss',
imports: [
MatCheckboxModule,
MatInputModule,
MatCardModule,
MatGridListModule,
MatButtonToggleModule,
CdkMenuModule,
IconComponent,
],
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export default class AppComponent {
protected title = '';
protected level = 1;
protected options: Record<string, boolean> = {
ngUpgrade: false,
material: false,
windows: isWindows(),
};
protected readonly optionList: Option[] = [
{id: 'ngUpgrade', name: 'ngUpgrade', description: 'to combine AngularJS & Angular'},
{id: 'material', name: 'Angular Material', description: ''},
{id: 'windows', name: 'Windows', description: ''},
];
protected packageManager: 'npm install' | 'yarn add' = 'npm install';
protected beforeRecommendations: Step[] = [];
protected duringRecommendations: Step[] = [];
protected afterRecommendations: Step[] = [];
protected readonly versions = [
{name: '18.0', number: 1800},
{name: '17.0', number: 1700},
{name: '16.0', number: 1600},
{name: '15.0', number: 1500},
{name: '14.0', number: 1400},
{name: '13.0', number: 1300},
{name: '12.0', number: 1200},
{name: '11.0', number: 1100},
{name: '10.2', number: 1020},
{name: '10.1', number: 1010},
{name: '10.0', number: 1000},
{name: '9.1', number: 910},
{name: '9.0', number: 900},
{name: '8.2', number: 820},
{name: '8.1', number: 810},
{name: '8.0', number: 800},
{name: '7.2', number: 720},
{name: '7.1', number: 710},
{name: '7.0', number: 700},
{name: '6.1', number: 610},
{name: '6.0', number: 600},
{name: '5.2', number: 520},
{name: '5.1', number: 510},
{name: '5.0', number: 500},
{name: '4.4', number: 440},
{name: '4.3', number: 430},
{name: '4.2', number: 420},
{name: '4.1', number: 410},
{name: '4.0', number: 400},
{name: '2.4', number: 204},
{name: '2.3', number: 203},
{name: '2.2', number: 202},
{name: '2.1', number: 201},
{name: '2.0', number: 200},
];
protected from = this.versions.find((version) => version.name === '17.0')!;
protected to = this.versions.find((version) => version.name === '18.0')!;
protected futureVersion = 1900;
protected readonly steps: Step[] = RECOMMENDATIONS;
private readonly clipboard = inject(Clipboard);
private readonly router = inject(Router);
private readonly activatedRoute = inject(ActivatedRoute);
constructor() {
const queryMap = this.activatedRoute.snapshot.queryParamMap;
// Detect settings in URL
this.level = parseInt(queryMap.get('l')!, 10) || this.level;
// Detect versions of from and to
const versions = queryMap.get('v');
if (versions) {
const [from, to] = versions.split('-');
this.from = this.versions.find((version) => version.name === from)!;
this.to = this.versions.find((version) => version.name === to)!;
this.showUpdatePath();
}
}
@HostListener('click', ['$event.target'])
copyCode({tagName, textContent}: Element) {
if (tagName === 'CODE') {
// TODO: add a toast notification
this.clipboard.copy(textContent!);
}
}
async showUpdatePath() {
this.beforeRecommendations = [];
this.duringRecommendations = [];
this.afterRecommendations = [];
// Refuse to generate recommendations for downgrades
if (this.to.number < this.from.number) {
alert('We do not support downgrading versions of Angular.');
return;
}
const labelTitle = 'Guide to update your Angular application';
const labelBasic = 'basic applications';
const labelMedium = 'medium applications';
const labelAdvanced = 'advanced applications';
this.title = `${labelTitle} v${this.from.name} -> v${this.to.name}
for
${this.level < 2 ? labelBasic : this.level < 3 ? labelMedium : labelAdvanced}`;
// Find applicable steps and organize them into before, during, and after upgrade
for (const step of this.steps) {
if (step.level <= this.level && step.necessaryAsOf > this.from.number) {
// Check Options
// Only show steps that don't have a required option
// Or when the user has a matching option selected
let skip = false;
for (const option of this.optionList) {
// Skip steps which require an option not set by the user.
if (step[option.id] && !this.options[option.id]) {
skip = true;
}
// Skip steps which require **not** using an option which **is** set
// by the user.
if (step[option.id] === false && this.options[option.id]) {
skip = true;
}
}
if (skip) {
continue;
}
// Render and replace variables
step.renderedStep = await marked(this.replaceVariables(step.action));
// If you could do it before now, but didn't have to finish it before now
if (step.possibleIn <= this.from.number && step.necessaryAsOf >= this.from.number) {
this.beforeRecommendations.push(step);
// If you couldn't do it before now, and you must do it now
} else if (step.possibleIn > this.from.number && step.necessaryAsOf <= this.to.number) {
this.duringRecommendations.push(step);
} else if (step.possibleIn <= this.to.number) {
this.afterRecommendations.push(step);
}
}
}
// Update the URL so users can link to this transition
this.router.navigate([], {
relativeTo: this.activatedRoute,
queryParams: {v: `${this.from.name}-${this.to.name}`, l: this.level},
queryParamsHandling: 'merge',
});
// Tell everyone how to upgrade for v6 or earlier
this.renderPreV6Instructions();
}
private getAdditionalDependencies(version: number): string {
if (version < 500) {
return `typescript@'>=2.1.0 <2.4.0'`;
} else if (version < 600) {
return `typescript@2.4.2 rxjs@^5.5.2`;
} else {
return `typescript@2.7.x rxjs@^6.0.0`;
}
}
private getAngularVersion(version: number): string {
if (version < 400) {
return `'^2.0.0'`;
} else {
const major = Math.floor(version / 100);
const minor = Math.floor((version - major * 100) / 10);
return `^${major}.${minor}.0`;
}
}
private async renderPreV6Instructions(): Promise<void> {
let upgradeStep: Step;
const isWindows = /win/i.test(navigator.platform);
const additionalDeps = this.getAdditionalDependencies(this.to.number);
const angularVersion = this.getAngularVersion(this.to.number);
const angularPackages = [
'animations',
'common',
'compiler',
'compiler-cli',
'core',
'forms',
'http',
'platform-browser',
'platform-browser-dynamic',
'platform-server',
'router',
];
// Provide npm/yarn instructions for versions before 6
if (this.to.number < 600) {
const actionMessage = `Update all of your dependencies to the latest Angular and the right version of TypeScript.`;
if (isWindows) {
const packages =
angularPackages
.map((packageName) => `@angular/${packageName}@${angularVersion}`)
.join(' ') +
' ' +
additionalDeps;
upgradeStep = {
step: 'General Update',
action: `${actionMessage}
If you are using Windows, you can use:
\`${this.packageManager} ${packages}\``,
} as Step;
} else {
const packages = `@angular/{${angularPackages.join(',')}}@${angularVersion} ${additionalDeps}`;
upgradeStep = {
step: 'General update',
action: `${actionMessage}
If you are using Linux/Mac, you can use:
\`${this.packageManager} ${packages}\``,
} as Step;
}
// Npm installs typescript wrong in v5, let's manually specify
// https://github.com/npm/npm/issues/16813
if (this.packageManager === 'npm install' && this.to.number === 500) {
upgradeStep.action += `
\`npm install typescript@2.4.2 --save-exact\``;
}
upgradeStep.renderedStep = await marked(upgradeStep.action);
this.duringRecommendations.push(upgradeStep);
}
}
private replaceVariables(action: string): string {
let newAction = action;
newAction = newAction.replace(
'${packageManagerGlobalInstall}',
this.packageManager === 'npm install' ? 'npm install -g' : 'yarn global add',
);
newAction = newAction.replace('${packageManagerInstall}', this.packageManager);
return newAction;
}
}
/** Whether or not the user is running on a Windows OS. */
function isWindows(): boolean {
const platform = navigator.platform.toLowerCase();
return platform.includes('windows') || platform.includes('win32');
}
-8
View File
@@ -41,12 +41,6 @@ const referencePageRoutes = mapNavigationItemsToRoutes(
},
);
const updateGuidePageRoute: Route = {
path: referenceNavigationItems.find((r) => r.path === DefaultPage.UPDATE)!.path,
loadComponent: () => import('./features/update/update.component'),
data: commonReferenceRouteData,
};
const cliReferencePageRoutes = mapNavigationItemsToRoutes(
referenceNavigationItems.filter((r) => r.path?.startsWith(`${PagePrefix.CLI}/`)),
{
@@ -67,7 +61,6 @@ const docsReferencePageRoutes = mapNavigationItemsToRoutes(
referenceNavigationItems.filter(
(r) =>
r.path !== DefaultPage.REFERENCE &&
r.path !== DefaultPage.UPDATE &&
!r.path?.startsWith(`${PagePrefix.API}/`) &&
!r.path?.startsWith(`${PagePrefix.CLI}/`),
),
@@ -150,7 +143,6 @@ export const routes: Route[] = [
...SUB_NAVIGATION_ROUTES,
...API_REFERENCE_ROUTES,
...FOOTER_ROUTES,
updateGuidePageRoute,
],
},
// Error page
+14 -175
View File
@@ -8,7 +8,6 @@
import {NavigationItem} from '@angular/docs';
// These 2 imports are expected to be red because they are generated a build time
import FIRST_APP_TUTORIAL_NAV_DATA from '../../src/assets/tutorials/first-app/routes.json';
import LEARN_ANGULAR_TUTORIAL_NAV_DATA from '../../src/assets/tutorials/learn-angular/routes.json';
@@ -118,11 +117,6 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
path: 'guide/components/outputs',
contentPath: 'guide/components/outputs',
},
{
label: 'output() function',
path: 'guide/components/output-fn',
contentPath: 'guide/components/output-function',
},
{
label: 'Content projection with ng-content',
path: 'guide/components/content-projection',
@@ -640,12 +634,6 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
},
],
},
{
label: 'Experimental features',
children: [
{label: 'Zoneless', path: 'guide/experimental/zoneless', contentPath: 'guide/zoneless'},
],
},
],
},
{
@@ -685,9 +673,9 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
contentPath: 'tools/cli/end-to-end',
},
{
label: 'Migrating to new build system',
path: 'tools/cli/build-system-migration',
contentPath: 'tools/cli/build-system-migration',
label: 'ESBuild',
path: 'tools/cli/esbuild',
contentPath: 'tools/cli/esbuild',
},
{
label: 'Build environments',
@@ -938,28 +926,7 @@ const REFERENCE_SUB_NAVIGATION_DATA: NavigationItem[] = [
},
{
label: 'ng analytics',
children: [
{
label: 'Overview',
path: 'cli/analytics',
},
{
label: 'disable',
path: 'cli/analytics/disable',
},
{
label: 'enable',
path: 'cli/analytics/enable',
},
{
label: 'info',
path: 'cli/analytics/info',
},
{
label: 'prompt',
path: 'cli/analytics/prompt',
},
],
path: 'cli/analytics',
},
{
label: 'ng build',
@@ -967,41 +934,11 @@ const REFERENCE_SUB_NAVIGATION_DATA: NavigationItem[] = [
},
{
label: 'ng cache',
children: [
{
label: 'Overview',
path: 'cli/cache',
},
{
label: 'clear',
path: 'cli/cache/clean',
},
{
label: 'disable',
path: 'cli/cache/disable',
},
{
label: 'enable',
path: 'cli/cache/enable',
},
{
label: 'info',
path: 'cli/cache/info',
},
],
path: 'cli/cache',
},
{
label: 'ng completion',
children: [
{
label: 'Overview',
path: 'cli/completion',
},
{
label: 'script',
path: 'cli/completion/script',
},
],
path: 'cli/completion',
},
{
label: 'ng config',
@@ -1011,6 +948,10 @@ const REFERENCE_SUB_NAVIGATION_DATA: NavigationItem[] = [
label: 'ng deploy',
path: 'cli/deploy',
},
{
label: 'ng doc',
path: 'cli/doc',
},
{
label: 'ng e2e',
path: 'cli/e2e',
@@ -1021,80 +962,7 @@ const REFERENCE_SUB_NAVIGATION_DATA: NavigationItem[] = [
},
{
label: 'ng generate',
children: [
{
label: 'Overview',
path: 'cli/generate',
},
{
label: 'app-shell',
path: 'cli/generate/app-shell',
},
{
label: 'application',
path: 'cli/generate/application',
},
{
label: 'class',
path: 'cli/generate/class',
},
{
label: 'component',
path: 'cli/generate/component',
},
{
label: 'config',
path: 'cli/generate/config',
},
{
label: 'enum',
path: 'cli/generate/enum',
},
{
label: 'environments',
path: 'cli/generate/environments',
},
{
label: 'guard',
path: 'cli/generate/guard',
},
{
label: 'interceptor',
path: 'cli/generate/interceptor',
},
{
label: 'interface',
path: 'cli/generate/interface',
},
{
label: 'library',
path: 'cli/generate/library',
},
{
label: 'module',
path: 'cli/generate/module',
},
{
label: 'pipe',
path: 'cli/generate/pipe',
},
{
label: 'resolver',
path: 'cli/generate/resolver',
},
{
label: 'service-worker',
path: 'cli/generate/service-worker',
},
{
label: 'service',
path: 'cli/generate/service',
},
{
label: 'web-worker',
path: 'cli/generate/web-worker',
},
],
path: 'cli/generate',
},
{
label: 'ng lint',
@@ -1239,11 +1107,6 @@ const REFERENCE_SUB_NAVIGATION_DATA: NavigationItem[] = [
path: 'errors/NG0507',
contentPath: 'reference/errors/NG0507',
},
{
label: 'NG0602: HTML content was altered after server-side rendering',
path: 'errors/NG0602',
contentPath: 'reference/errors/NG0602',
},
{
label: 'NG05104: Root element was not found',
path: 'errors/NG05104',
@@ -1259,26 +1122,6 @@ const REFERENCE_SUB_NAVIGATION_DATA: NavigationItem[] = [
path: 'errors/NG0912',
contentPath: 'reference/errors/NG0912',
},
{
label: 'NG0950: Required input is accessed before a value is set.',
path: 'errors/NG0950',
contentPath: 'reference/errors/NG0950',
},
{
label: 'NG0951: Child query result is required but no value is available.',
path: 'errors/NG0951',
contentPath: 'reference/errors/NG0951',
},
{
label: 'NG0955: Track expression resulted in duplicated keys for a given collection',
path: 'errors/NG0955',
contentPath: 'reference/errors/NG0955',
},
{
label: 'NG0956: Tracking expression caused re-creation of the DOM structure',
path: 'errors/NG0956',
contentPath: 'reference/errors/NG0956',
},
{
label: 'NG1001: Argument Not Literal',
path: 'errors/NG1001',
@@ -1300,9 +1143,9 @@ const REFERENCE_SUB_NAVIGATION_DATA: NavigationItem[] = [
contentPath: 'reference/errors/NG3003',
},
{
label: 'NG05000: Hydration with unsupported Zone.js instance.',
path: 'errors/NG05000',
contentPath: 'reference/errors/NG05000',
label: 'NG5000: Hydration with unsupported Zone.js instance.',
path: 'errors/NG5000',
contentPath: 'reference/errors/NG5000',
},
{
label: 'NG6100: NgModule.id Set to module.id anti-pattern',
@@ -1391,10 +1234,6 @@ const REFERENCE_SUB_NAVIGATION_DATA: NavigationItem[] = [
path: 'reference/versions',
contentPath: 'reference/versions',
},
{
label: 'Update guide',
path: 'update-guide',
},
{
label: 'Configurations',
children: [
+2 -2
View File
@@ -8,7 +8,6 @@ copy_to_directory(
"//adev/src/content",
"//adev/src/content/best-practices",
"//adev/src/content/best-practices/runtime-performance",
"//adev/src/content/cli/help:cli_docs",
"//adev/src/content/ecosystem",
"//adev/src/content/ecosystem/service-workers",
"//adev/src/content/guide",
@@ -39,6 +38,7 @@ copy_to_directory(
"//adev/src/content/tutorials",
"//adev/src/content/tutorials/first-app:first-app-guides",
"//adev/src/content/tutorials/learn-angular:learn-angular-guides",
"//aio/content/cli/help:cli_docs",
"//packages/animations:animations_docs",
"//packages/animations/browser:animations_browser_docs",
"//packages/animations/browser/testing:animations_browser_testing_docs",
@@ -74,7 +74,7 @@ copy_to_directory(
"//tools/manual_api_docs/elements:elements_docs",
],
replace_prefixes = {
"adev/src/content/cli/help/cli_docs_html": "cli/",
"aio/content/cli/**/": "cli/",
"adev/src/content": "",
"packages/**/": "api/",
"tools/**/": "api/",
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Some files were not shown because too many files have changed in this diff Show More