Compare commits

..

1 Commits

Author SHA1 Message Date
Ben Hong 95efcdd019 docs: add documentation and script for local docs dev environment 2024-01-25 09:05:49 -08:00
11094 changed files with 740306 additions and 598210 deletions
+3 -1
View File
@@ -5,6 +5,9 @@
.git
node_modules
dist
aio/node_modules
aio/tools/examples/shared/node_modules
aio/tools/examples/shared/example-scaffold
# All integration test node_modules folders
integration/animations/node_modules
@@ -14,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
+26 -9
View File
@@ -1,5 +1,5 @@
# Enable debugging tests with --config=debug
test:debug --test_arg=--node_options=--inspect-brk --test_output=streamed --test_strategy=exclusive --test_timeout=9999 --nocache_test_results --spawn_strategy=local
test:debug --test_arg=--node_options=--inspect-brk --test_output=streamed --test_strategy=exclusive --test_timeout=9999 --nocache_test_results
# Do not attempt to de-flake locally.
# On CI we might set this to `3` to run with deflaking.
@@ -56,16 +56,31 @@ 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. #
# To build with a partiular configuration: #
# bazel build //aio:build --aio_build_config=<config> #
# Default config is `stable``. #
##########################################################
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 #
@@ -103,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
@@ -158,8 +177,6 @@ test:saucelabs --flaky_test_attempts=1
# --ng_perf will ask the Ivy compiler to produce performance results for each build.
build --flag_alias=ng_perf=//packages/compiler-cli:ng_perf
# --prerender_adev will run adev build/serve in a full mode, performing prerendering
build --flag_alias=prerender_adev=//adev:prerender_adev
####################################################
# User bazel configuration
+1 -1
View File
@@ -44,7 +44,7 @@ function setSecretVar() {
# Create a function to set an environment variable, when called.
#
# Use this function for creating setter for public environment variables that require expensive or
# time-consuming computations and may not be needed. When needed, you can call this function to set
# time-consuming computaions and may not be needed. When needed, you can call this function to set
# the environment variable (which will be available through `$BASH_ENV` from that point onwards).
#
# Arguments:
+1
View File
@@ -16,6 +16,7 @@ echo "source $envHelpersPath;" >> $BASH_ENV;
####################################################################################################
setPublicVar CI "$CI"
setPublicVar PROJECT_ROOT "$projectDir";
setPublicVar CI_AIO_MIN_PWA_SCORE "95";
# This is the branch being built; e.g. `pull/12345` for PR builds.
setPublicVar CI_BRANCH "$CIRCLE_BRANCH";
setPublicVar CI_BUILD_URL "$CIRCLE_BUILD_URL";
+6 -1
View File
@@ -6,6 +6,11 @@
"postCreateCommand": "yarn install",
"extensions": [
"devondcarew.bazel-code",
"ms-vscode.vscode-typescript-tslint-plugin"
"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",
],
}
+2 -2
View File
@@ -1,5 +1,5 @@
name: 'Docs or angular.dev Bug Report'
description: Report an issue in Angular's documentation or angular.dev application
name: 'Docs or angular.io Bug Report'
description: Report an issue in Angular's documentation or angular.io application
body:
- type: textarea
+1 -1
View File
@@ -1,7 +1,7 @@
blank_issues_enabled: false
contact_links:
- name: Security issue disclosure
url: https://angular.dev/best-practices/security#report-issues
url: https://angular.io/guide/security#report-issues
about: Report a security issue in Angular Framework, CDK, Material, or CLI
- name: Angular CLI
url: https://github.com/angular/angular-cli/issues/new/choose
+1 -1
View File
@@ -18,7 +18,7 @@ What kind of change does this PR introduce?
- [ ] Build related changes
- [ ] CI related changes
- [ ] Documentation content changes
- [ ] angular.dev application / infrastructure changes
- [ ] angular.io application / infrastructure changes
- [ ] Other... Please describe:
@@ -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,19 +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
githubReleaseTrainReadToken:
description: 'GitHub access token for reading release trains without rate limits.'
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,20 +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;
}
/** Github access token. Used for querying the active release trains. */
export const githubReleaseTrainReadToken: string = getInput('githubReleaseTrainReadToken', {
required: true,
});
@@ -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@13.15.1 ${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 {AuthenticatedGitClient} 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 AuthenticatedGitClient.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,75 +0,0 @@
import {getInput, setFailed} from '@actions/core';
import {context} from '@actions/github';
import {deployToFirebase, setupRedirect} from './deploy';
import {getDeployments} from './deployments';
import {AuthenticatedGitClient, GithubConfig, setConfig} from '@angular/ng-dev';
import {githubReleaseTrainReadToken} from './credential';
const refMatcher = /refs\/heads\/(.*)/;
async function deployDocs() {
setConfig({
github: <GithubConfig>{
mainBranchName: 'main',
name: 'angular',
owner: 'angular',
},
});
AuthenticatedGitClient.configure(githubReleaseTrainReadToken);
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,45 +0,0 @@
name: 'Saucelabs legacy test job'
description: 'Runs tests against Saucelabs (outside of Bazel)'
runs:
using: 'composite'
steps:
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- name: Setup Saucelabs Variables
uses: angular/dev-infra/github-actions/saucelabs@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- name: Starting Saucelabs tunnel service
shell: bash
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
shell: bash
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
shell: bash
run: node tools/legacy-saucelabs/build-saucelabs-test-bundle.mjs
- name: Wait and confirm Saucelabs tunnel has connected
shell: bash
run: ./tools/saucelabs/sauce-service.sh ready-wait
- name: Running tests on Saucelabs.
shell: bash
run: KARMA_WEB_TEST_MODE=SL_REQUIRED yarn karma start ./karma-js.conf.js --single-run
- name: Stop Saucelabs tunnel service
shell: bash
run: ./tools/saucelabs/sauce-service.sh stop
+1 -1
View File
@@ -4,7 +4,7 @@ description: 'Installs the dependencies using Yarn'
runs:
using: 'composite'
steps:
- uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3
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@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Build adev to ensure it continues to work
run: yarn bazel build //adev:build --prerender_adev --config=release
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
run: yarn bazel build --config=aio_local_deps //adev:build
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
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@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
with:
token: '${{secrets.GITHUB_TOKEN}}'
@@ -40,7 +40,7 @@ jobs:
npx -y firebase-tools@latest target:clear --config adev/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting angular-docs
npx -y firebase-tools@latest target:apply --config adev/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting angular-docs ${{env.PREVIEW_SITE}}
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
github-token: '${{secrets.GITHUB_TOKEN}}'
workflow-artifact-name: 'adev-preview'
+42
View File
@@ -0,0 +1,42 @@
# This workflow builds the AIO previews for pull requests when a certain label is applied.
# The actual deployment happens as part of a dedicated second workflow to avoid security
# issues where the building would otherwise occur in an authorized context where secrets
# could be leaked. More details can be found here:
# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/.
name: Build AIO app for preview deployment
on:
pull_request:
types: [synchronize, labeled]
permissions: read-all
jobs:
aio-build:
runs-on: ubuntu-latest
# We only want to build and deploy the AIO app if the `aio: preview` label has been
# added, or if the label is already applied and new changes have been made in the PR.
if: |
(github.event.action == 'labeled' && github.event.label.name == 'aio: preview') ||
(github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'aio: preview'))
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: ./.github/actions/yarn-install
- uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
bazelrc: ./.bazelrc.user
# Build the web package. Note: We run Bazel from a low-resource Github action container,
# so we manually need to instruct Bazel to run more actions concurrently as by default
# the number of concurrent actions is determined based on the host resources.
- run: bazel build //aio:build --jobs=32 --announce_rc --verbose_failures
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
workflow-artifact-name: 'aio'
pull-number: '${{github.event.pull_request.number}}'
artifact-build-revision: '${{github.event.pull_request.head.sha}}'
deploy-directory: './dist/bin/aio/build'
+44
View File
@@ -0,0 +1,44 @@
# This workflow runs whenever the AIO build workflow has completed. Deployment happens
# as part of a dedicated second workflow to avoid security issues where the building would
# otherwise occur in an authorized context where secrets could be leaked.
#
# More details can be found here:
# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/.
name: Deploying AIO preview to Firebase
on:
workflow_run:
workflows: ['Build AIO app for preview deployment']
types: [completed]
permissions:
# Needed in order to be able to comment on the pull request.
pull-requests: write
env:
PREVIEW_PROJECT: ng-dev-previews
PREVIEW_SITE: ng-dev-previews-fw
jobs:
aio-deploy:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
- name: Configure Firebase deploy target
working-directory: aio/
run: |
# We can use `npx` as the Firebase deploy actions uses it too.
npx -y firebase-tools@latest target:clear --project ${{env.PREVIEW_PROJECT}} hosting aio
npx -y firebase-tools@latest target:apply --project ${{env.PREVIEW_PROJECT}} hosting aio ${{env.PREVIEW_SITE}}
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
github-token: '${{secrets.GITHUB_TOKEN}}'
workflow-artifact-name: 'aio'
firebase-config-dir: './aio/'
firebase-public-dir: './aio/dist'
firebase-project-id: '${{env.PREVIEW_PROJECT}}'
firebase-service-key: '${{secrets.FIREBASE_PREVIEW_SERVICE_TOKEN}}'
@@ -13,9 +13,9 @@ jobs:
assistant_to_the_branch_manager:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false
- uses: angular/dev-infra/github-actions/branch-manager@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- uses: angular/dev-infra/github-actions/branch-manager@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
+4 -4
View File
@@ -19,7 +19,7 @@ jobs:
exit: true
# Indicate that the benchmark command was received.
- uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4
- uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3
with:
comment-id: ${{github.event.comment.id}}
token: '${{secrets.BENCHMARK_POST_RESULTS_GITHUB_TOKEN}}'
@@ -28,7 +28,7 @@ jobs:
- uses: alessbell/pull-request-comment-branch@aad01d65d6982b8eacabed5e9a684cd8ceb98da6 # v1.1
id: comment-branch
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- 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@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
bazelrc: ./.bazelrc.user
@@ -53,7 +53,7 @@ jobs:
id: benchmark
name: Running benchmark
- uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4
- uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3
with:
issue-number: ${{github.event.issue.number}}
token: '${{secrets.BENCHMARK_POST_RESULTS_GITHUB_TOKEN}}'
+64
View File
@@ -0,0 +1,64 @@
name: CI
on:
pull_request_target:
types: [opened, synchronize, reopened]
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref }}
cancel-in-progress: true
permissions: {}
defaults:
run:
shell: bash
jobs:
saucelabs:
runs-on: ubuntu-latest-4core
env:
SAUCE_TUNNEL_IDENTIFIER: angular-framework-${{ github.run_number }}
SAUCE_USERNAME: ${{ vars.SAUCE_USERNAME }}
SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
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@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- 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
+147 -53
View File
@@ -1,10 +1,12 @@
name: CI (push)
name: CI
on:
push:
branches:
- main
- '[0-9]+.[0-9]+.x'
pull_request:
types: [opened, synchronize, reopened]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -21,13 +23,20 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
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
run: yarn install --frozen-lockfile --cwd aio
- name: Check code lint
run: yarn -s tslint
- name: Check code lint in aio
run: yarn -s --cwd aio lint
- name: Check for circular dependencies
run: yarn -s ts-circular-deps:check
- name: Validate pull approve configuration
@@ -36,18 +45,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@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Run unit tests
@@ -59,49 +78,132 @@ jobs:
runs-on: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Install node modules
run: yarn install --frozen-lockfile --network-timeout 100000
- name: Run CI tests for framework
run: yarn test:ci
aio:
runs-on: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
cache-node-modules: true
node-module-directories: |
./aio/node_modules
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Install node modules for aio
run: yarn install --cwd aio --frozen-lockfile
- name: Run AIO tests with upstream packages
run: yarn --cwd aio test:ci
- name: Check generated bundle sizes
run: yarn --cwd aio payload-size
adev:
runs-on:
labels: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Build adev in fast mode to ensure it continues to work
run: yarn bazel build //adev:build --config=release
# TODO: re-enable tests once the next release is shipped
# Tests are broken because of https://github.com/angular/angular/issues/54858
# - name: Run tests
# run: yarn bazel test //adev/...
- name: Build adev to ensure it continues to work
run: yarn bazel test --config=aio_local_deps //adev:test
publish-snapshots:
aio-local:
runs-on:
labels: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
cache-node-modules: true
node-module-directories: |
./aio/node_modules
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Install node modules
run: yarn install --cwd aio --frozen-lockfile
- name: Run AIO tests with local packages
run: yarn --cwd aio test-local:ci
- name: Check generated bundle sizes
run: yarn --cwd aio payload-size aio-local
aio-deploy:
needs: [aio]
if: needs.aio.result == 'success' && github.event_name == 'push'
runs-on:
labels: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
cache-node-modules: true
node-module-directories: |
./aio/node_modules
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Install node modules for aio
run: yarn install --cwd aio --frozen-lockfile
- name: Set the stable branch environment variable
id: latest_version
run: |
echo "CI_STABLE_BRANCH=$(npm info @angular/core dist-tags.latest | sed -r 's/^\s*([0-9]+\.[0-9]+)\.[0-9]+.*$/\1.x/')" >> $GITHUB_OUTPUT
echo "CI_BRANCH=$(echo ${{ github.event.ref }} | cut -d '/' -f 3)" >> $GITHUB_OUTPUT
- name: Deploy aio to production
env:
CI_AIO_MIN_PWA_SCORE: '95'
CI_COMMIT: ${{ github.event.after }}
CI_REPO_NAME: 'angular'
CI_PULL_REQUEST: 'false'
CI_REPO_OWNER: 'angular'
CI_BUILD_URL: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
CI_STABLE_BRANCH: ${{ steps.latest_version.outputs.CI_STABLE_BRANCH }}
CI_BRANCH: ${{ steps.latest_version.outputs.CI_BRANCH }}
CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN: ${{ secrets.AIO_DEPLOY_TOKEN }}
CI_SECRET_PAYLOAD_FIREBASE_TOKEN: ${{ secrets.AIO_PAYLOAD_TOKEN }}
run: yarn --cwd aio deploy-production
- name: Notify about failed deployment
if: ${{ failure() }}
uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v=v1.24.0
with:
channel-id: 'C07DT5M6V,CKV1F72BG'
slack-message: 'Deploy to aio job failed for ${{ github.base_ref }} branch failed on build ${{ github.event.after }}: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
env:
SLACK_BOT_TOKEN: ${{ secrets.ANGULAR_ROBOT_SLACK_TOKEN }}
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@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Install node modules
run: yarn install --frozen-lockfile
- run: echo "https://${{secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN}}:@github.com" > ${HOME}/.git_credentials
@@ -113,7 +215,7 @@ jobs:
labels: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
cache-node-modules: true
node-module-directories: |
@@ -121,9 +223,9 @@ jobs:
./packages/zone.js/node_modules
./packages/zone.js/test/typings/node_modules
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Install node modules
run: yarn install --frozen-lockfile
- run: |
@@ -133,11 +235,9 @@ jobs:
//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/
mkdir -p packages/zone.js/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/
@@ -154,38 +254,32 @@ jobs:
- run: yarn --cwd packages/zone.js/test/typings install --frozen-lockfile --non-interactive
- run: yarn --cwd packages/zone.js/test/typings test
saucelabs:
bazel-saucelabs:
# TODO: Replace legacy job with Bazel saucelabs job.
if: github.event_name == 'push'
runs-on: ubuntu-latest-4core
env:
SAUCE_TUNNEL_IDENTIFIER: angular-framework-${{ github.run_number }}
JOBS: 2
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
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
- uses: ./.github/actions/saucelabs-legacy
adev-deploy:
needs: [adev]
if: needs.adev.result == 'success'
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Build adev to ensure it continues to work
run: yarn bazel build //adev:build --prerender_adev --config=release
- name: Deploy to firebase
uses: ./.github/actions/deploy-docs-site
with:
serviceKey: ${{ secrets.ANGULAR_DEV_SITE_DEPLOY }}
githubReleaseTrainReadToken: ${{ secrets.DOCS_DEPLOY_GITHUB_RELEASE_TRAIN_TOKEN }}
configPath: 'adev/firebase.json'
distDir: 'dist/bin/adev/build/browser'
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Set up Sauce Tunnel Daemon
run: yarn bazel run //tools/saucelabs-daemon/background-service -- $JOBS &
env:
SAUCE_TUNNEL_IDENTIFIER: angular-framework-${{ github.run_number }}
SAUCE_USERNAME: ${{ vars.SAUCE_USERNAME }}
SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
- name: Run all saucelabs bazel tests
run: |
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}
+4 -4
View File
@@ -12,14 +12,14 @@ jobs:
labels:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: angular/dev-infra/github-actions/commit-message-based-labels@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: angular/dev-infra/github-actions/commit-message-based-labels@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
post_approval_changes:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: angular/dev-infra/github-actions/post-approval-changes@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: angular/dev-infra/github-actions/post-approval-changes@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
+19
View File
@@ -0,0 +1,19 @@
name: Feature request triage bot
on:
schedule:
# Run at 14:00 every day
- cron: '0 14 * * *'
# Declare default permissions as read only.
permissions:
contents: read
jobs:
feature_triage:
if: github.repository == 'angular/angular'
runs-on: ubuntu-latest
steps:
- uses: angular/dev-infra/github-actions/feature-request@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
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@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: angular/dev-infra/github-actions/google-internal-tests@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: angular/dev-infra/github-actions/google-internal-tests@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
run-tests-guide-url: http://go/angular-g3sync-start
github-token: ${{ secrets.GITHUB_TOKEN }}
-34
View File
@@ -1,34 +0,0 @@
name: Manual jobs
on:
workflow_dispatch:
inputs: {}
jobs:
# Bazel saucelabs job resides in `manual.yml` because it's currently unstable, but
# kept as "runnable" for debugging/stabilization effort purposes.
bazel-saucelabs:
runs-on: ubuntu-latest-4core
env:
JOBS: 2
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
with:
cache-node-modules: true
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- name: Setup Saucelabs Variables
uses: angular/dev-infra/github-actions/saucelabs@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- name: Set up Sauce Tunnel Daemon
run: yarn bazel run //tools/saucelabs-daemon/background-service -- $JOBS &
env:
SAUCE_TUNNEL_IDENTIFIER: angular-framework-${{ github.run_number }}
- name: Run all saucelabs bazel tests
run: |
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}
+1 -1
View File
@@ -9,6 +9,6 @@ jobs:
status:
runs-on: ubuntu-latest
steps:
- uses: angular/dev-infra/github-actions/unified-status-check@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- uses: angular/dev-infra/github-actions/unified-status-check@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
+55
View File
@@ -0,0 +1,55 @@
name: Monitoring
on:
schedule:
# Run at 10:00AM every day.
- cron: '0 10 * * *'
permissions: {}
defaults:
run:
shell: bash
jobs:
check_aio:
runs-on: ubuntu-latest
env:
MINIMUM_PWA_SCORE: 95
strategy:
fail-fast: false
matrix:
version: ['https://next.angular.io/', 'https://angular.io/']
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
cache-node-modules: true
node-module-directories: |
./aio/node_modules
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
- name: Install node modules in aio
run: yarn install --frozen-lockfile --cwd aio
- name: Run basic e2e and deployment config tests.
run: yarn --cwd aio test-production-url --test_env=TARGET_URL="${{ matrix.version }}"
- name: Run PWA-score tests.
run: yarn --cwd aio test-pwa-score "${{ matrix.version }}" "${{ env.MINIMUM_PWA_SCORE }}"
- name: Run a11y tests.
run: yarn --cwd aio test-a11y-score "${{ matrix.version }}"
check_contributor_links:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
cache-node-modules: true
node-module-directories: |
./aio/node_modules
- name: Install node modules in aio
run: yarn install --frozen-lockfile --cwd aio
- name: Check website provided in contributors.json file
run: node aio/scripts/test-external-urls.js
-179
View File
@@ -1,179 +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@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
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 }}
- name: Check Package Licenses
uses: angular/dev-infra/github-actions/linting/licenses@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
with:
allow-dependencies-licenses: 'pkg:npm/google-protobuf@'
devtools:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- 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@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- name: Install node modules
run: yarn install --frozen-lockfile --network-timeout 100000
- name: Run CI tests for framework
run: yarn test:ci
artifacts:
needs: [test]
if: needs.test.result == 'success'
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- name: Install node modules
run: yarn install --frozen-lockfile --network-timeout 100000
- name: Run CI tests for framework
run: yarn tsx ./scripts/build/build-packages-dist.mts
- name: Archive build artifacts
uses: actions/upload-artifact@89ef406dd8d7e03cfd12d9e0a4a378f454709029 # v4.3.5
with:
name: pr-artifacts-${{ github.event.number }}
path: dist/packages-dist/
adev:
runs-on:
labels: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Build adev in fast mode to ensure it continues to work
run: yarn bazel build //adev:build --config=release
# TODO: re-enable tests once the next release is shipped
# Tests are broken because of https://github.com/angular/angular/issues/54858
# - name: Run tests
# run: yarn bazel test //adev/...
zone-js:
runs-on:
labels: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
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@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
- 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@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
with:
cache-node-modules: true
- name: Install node modules
run: yarn install --frozen-lockfile
- uses: ./.github/actions/saucelabs-legacy
+4 -4
View File
@@ -25,12 +25,12 @@ jobs:
steps:
- name: 'Checkout code'
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false
- name: 'Run analysis'
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
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@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0
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@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0
uses: github/codeql-action/upload-sarif@b374143c1149a9115d881581d29b8390bbcbb59c # v3.22.11
with:
sarif_file: results.sarif
+4 -4
View File
@@ -1,4 +1,4 @@
name: Update ADEV Angular CLI help
name: Update AIO Angular CLI help
on:
workflow_dispatch:
@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
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@8d3cb7b9e1b3edd1dc168376689d27407d2dfa7a
uses: angular/dev-infra/github-actions/create-pr-for-changes@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
branch-prefix: update-cli-help
pr-title: 'docs: update Angular CLI help [${{github.ref_name}}]'
+48
View File
@@ -0,0 +1,48 @@
# Update the `events.json` file that powers the [AIO events page](https://angular.io/events) (if
# necessary) and create a pull request.
#
# For more details on the overall process, see
# [aio/scripts/generate-events/README.md](../../aio/scripts/generate-events/README.md).
name: Update AIO events
on:
workflow_dispatch:
inputs: {}
schedule:
# Run every day at 15:00.
- cron: '0 15 * * *'
# Declare default permissions as read only.
permissions:
contents: read
jobs:
update_events:
name: Update `events.json` (if necessary)
if: github.repository == 'angular/angular'
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
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
# an authenticated URL.
persist-credentials: false
# 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 `events.json`
run: node aio/scripts/generate-events/index.mjs --ignore-invalid-dates
- name: Create a PR (if necessary)
uses: angular/dev-infra/github-actions/create-pr-for-changes@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
with:
branch-prefix: docs-update-events
pr-title: 'docs: update events'
pr-description: |
Generated `events.json` with the latest events retrieved from the Firebase DB.
pr-labels: |
action: review
area: docs
target: patch
angular-robot-token: ${{ secrets.ANGULAR_ROBOT_ACCESS_TOKEN }}
+2 -5
View File
@@ -56,11 +56,8 @@ baseline.json
# Husky
.husky/_
aio/content/examples/.DS_Store
# Ignore cache created with the Angular CLI.
.angular/
# Ignore AIO files, useful when changing branches
aio/node_modules
aio/out-tsc
.angular/
+3
View File
@@ -1,3 +1,6 @@
#!/bin/sh
. "$(dirname $0)/_/husky.sh"
set +e
yarn -s ng-dev commit-message pre-commit-validate --file $1 2>/dev/null
+4 -1
View File
@@ -1,8 +1,11 @@
set +e
#!/bin/sh
. "$(dirname $0)/_/husky.sh"
set +e
yarn -s ng-dev format staged 2>/dev/null
if [ $? -ne 0 ]; then
echo "WARNING: failed to run file formatting (ng-dev format staged)"
fi
exit 0;
+3
View File
@@ -1,3 +1,6 @@
#!/bin/sh
. "$(dirname $0)/_/husky.sh"
set +e
yarn -s ng-dev commit-message restore-commit-message-draft $1 $2 2>/dev/null
+35 -7
View File
@@ -7,24 +7,52 @@ export const format: FormatConfig = {
'prettier': {
'matchers': [
'**/*.{yaml,yml}',
'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/elements/**/*.{js,ts}',
'packages/misc/**/*.{js,ts}',
],
},
'clang-format': {
'matchers': [
'**/*.{js,ts}',
// Do not format d.ts files as they are generated
'!**/*.d.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}',
// 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/elements/**/*.{js,ts}',
'!packages/misc/**/*.{js,ts}',
],
},
'buildifier': true,
+2 -8
View File
@@ -1,12 +1,5 @@
{
"syncedFilePatterns": [
"LICENSE",
"modules/benchmarks/**",
"packages/**"
],
"separateFilePatterns": [
"packages/core/primitives/**"
],
"syncedFilePatterns": ["LICENSE", "modules/benchmarks/**", "packages/**"],
"alwaysExternalFilePatterns": [
"packages/*",
"packages/bazel/*",
@@ -29,6 +22,7 @@
"packages/docs/**",
"packages/elements/schematics/**",
"packages/examples/**",
"packages/language-service/**",
"packages/localize/**",
"packages/private/**",
"packages/service-worker/**",
-5
View File
@@ -17,9 +17,4 @@ export const pullRequest: PullRequestConfig = {
// the `bazel` package is not considered part of the public API so that features
// can land in patch branches.
targetLabelExemptScopes: ['dev-infra', 'docs-infra', 'bazel'],
// enables specific validations during the pull request merge process
validators: {
assertEnforceTested: true,
assertIsolatedSeparateFiles: true,
},
};
+1 -1
View File
@@ -28,7 +28,7 @@ export const release: ReleaseConfig = {
return performNpmReleaseBuild();
},
releaseNotes: {
hiddenScopes: ['bazel', 'dev-infra', 'docs-infra', 'zone.js', 'devtools'],
hiddenScopes: ['aio', 'bazel', 'dev-infra', 'docs-infra', 'zone.js', 'devtools'],
},
releasePrLabels: ['area: build & ci', 'action: merge', 'PullApprove: disable'],
};
+1 -1
View File
@@ -1 +1 @@
18.20.0
18.13.0
+2 -3
View File
@@ -1,10 +1,9 @@
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"embeddedLanguageFormatting": "off",
"tabs": false,
"singleQuote": true,
"semi": true,
"semicolon": true,
"quoteProps": "preserve",
"bracketSpacing": false
}
+588 -99
View File
@@ -57,7 +57,7 @@
version: 3
availability:
users_unavailable: ['atscott']
users_unavailable: []
# Meta field that goes unused by PullApprove to allow for defining aliases to be
# used throughout the config.
@@ -121,13 +121,26 @@ groups:
contains_any_globs(files, [
'packages/animations/**/{*,.*}',
'packages/platform-browser/animations/**/{*,.*}',
'aio/content/guide/animations.md',
'aio/content/guide/add-an-animation.md',
'aio/content/guide/animate-state-style.md',
'aio/content/guide/animation-api-summary.md',
'aio/content/guide/understanding-angular-animation.md',
'aio/content/examples/animations/**/{*,.*}',
'aio/content/images/guide/animations/**/{*,.*}',
'aio/content/guide/complex-animation-sequences.md',
'aio/content/guide/reusable-animations.md',
'aio/content/guide/route-animations.md',
'aio/content/guide/transition-and-triggers.md',
'aio/content/guide/animations-attach-to-html-template.md',
'aio/content/guide/animation-transition-timing.md'
])
reviewers:
users:
- alxhub
- crisbeto
- ~jelbourn
- thePunderWoman
- jessicajaniuk
# =========================================================
# Framework: Compiler
@@ -139,7 +152,13 @@ groups:
contains_any_globs(files, [
'packages/compiler/**/{*,.*}',
'packages/examples/compiler/**/{*,.*}',
'aio/content/examples/angular-compiler-options/**/{*,.*}',
'packages/compiler-cli/**/{*,.*}',
'aio/content/guide/angular-compiler-options.md',
'aio/content/guide/aot-compiler.md',
'aio/content/guide/aot-metadata-errors.md',
'aio/content/guide/template-typecheck.md',
'aio/content/extended-diagnostics/*.md'
])
reviewers:
users:
@@ -147,9 +166,8 @@ groups:
- AndrewKushnir
- atscott
- crisbeto
- devversion
- dylhunn
- JoostK
- dylhunn
# =========================================================
# Framework: Migrations
@@ -164,7 +182,7 @@ groups:
- crisbeto
- devversion
- dylhunn
- thePunderWoman
- jessicajaniuk
- AndrewKushnir
# =========================================================
@@ -174,13 +192,159 @@ 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/**/{*,.*}',
'packages/examples/platform-browser/**/{*,.*}',
'packages/platform-browser-dynamic/**/{*,.*}',
'packages/docs/**/{*,.*}',
'aio/content/guide/accessibility.md',
'aio/content/examples/accessibility/**/{*,.*}',
'aio/content/guide/architecture-components.md',
'aio/content/guide/architecture-modules.md',
'aio/content/guide/architecture-next-steps.md',
'aio/content/guide/architecture-services.md',
'aio/content/guide/architecture.md',
'aio/content/examples/architecture/**/{*,.*}',
'aio/content/guide/rxjs-interop.md',
'aio/content/images/guide/architecture/**/{*,.*}',
'aio/content/guide/attribute-directives.md',
'aio/content/examples/attribute-directives/**/{*,.*}',
'aio/content/images/guide/attribute-directives/**/{*,.*}',
'aio/content/guide/bootstrapping.md',
'aio/content/examples/bootstrapping/**/{*,.*}',
'aio/content/guide/change-detection.md',
'aio/content/guide/change-detection-zone-pollution.md',
'aio/content/guide/change-detection-slow-computations.md',
'aio/content/guide/change-detection-skipping-subtrees.md',
'aio/content/images/guide/change-detection/**/{*,.*}',
'aio/content/guide/class-binding.md',
'aio/content/guide/cheatsheet.md',
'aio/content/guide/component-interaction.md',
'aio/content/examples/component-interaction/**/{*,.*}',
'aio/content/images/guide/component-interaction/**/{*,.*}',
'aio/content/guide/component-overview.md',
'aio/content/errors/*.md',
'aio/content/examples/errors/**/{*,.*}',
'aio/content/examples/component-overview/**/{*,.*}',
'aio/content/guide/component-styles.md',
'aio/content/guide/developer-guide-overview.md',
'aio/content/guide/view-encapsulation.md',
'aio/content/examples/component-styles/**/{*,.*}',
'aio/content/examples/content-projection/**/{*,.*}',
'aio/content/guide/content-projection.md',
'aio/content/guide/creating-injectable-service.md',
'aio/content/guide/dependency-injection-overview.md',
'aio/content/guide/dependency-injection.md',
'aio/content/examples/dependency-injection/**/{*,.*}',
'aio/content/images/guide/dependency-injection/**/{*,.*}',
'aio/content/guide/dependency-injection-in-action.md',
'aio/content/examples/dependency-injection-in-action/**/{*,.*}',
'aio/content/images/guide/dependency-injection-in-action/**/{*,.*}',
'aio/content/guide/dependency-injection-navtree.md',
'aio/content/guide/dependency-injection-providers.md',
'aio/content/guide/dependency-injection-context.md',
'aio/content/guide/lightweight-injection-tokens.md',
'aio/content/guide/displaying-data.md',
'aio/content/examples/displaying-data/**/{*,.*}',
'aio/content/images/guide/displaying-data/**/{*,.*}',
'aio/content/guide/dynamic-component-loader.md',
'aio/content/examples/dynamic-component-loader/**/{*,.*}',
'aio/content/images/guide/dynamic-component-loader/**/{*,.*}',
'aio/content/guide/example-apps-list.md',
'aio/content/guide/feature-modules.md',
'aio/content/examples/feature-modules/**/{*,.*}',
'aio/content/images/guide/feature-modules/**/{*,.*}',
'aio/content/guide/frequent-ngmodules.md',
'aio/content/images/guide/frequent-ngmodules/**/{*,.*}',
'aio/content/guide/hierarchical-dependency-injection.md',
'aio/content/examples/hierarchical-dependency-injection/**/{*,.*}',
'aio/content/guide/image-directive.md',
'aio/content/guide/image-directive-setup.md',
'aio/content/examples/providers-viewproviders/**/{*,.*}',
'aio/content/examples/resolution-modifiers/**/{*,.*}',
'aio/content/guide/lazy-loading-ngmodules.md',
'aio/content/examples/lazy-loading-ngmodules/**/{*,.*}',
'aio/content/images/guide/lazy-loading-ngmodules/**/{*,.*}',
'aio/content/guide/lifecycle-hooks.md',
'aio/content/examples/lifecycle-hooks/**/{*,.*}',
'aio/content/images/guide/lifecycle-hooks/**/{*,.*}',
'aio/content/examples/ngcontainer/**/{*,.*}',
'aio/content/guide/ngmodules.md',
'aio/content/examples/ngmodules/**/{*,.*}',
'aio/content/guide/ngmodule-api.md',
'aio/content/guide/ngmodule-faq.md',
'aio/content/guide/ngmodule-vs-jsmodule.md',
'aio/content/guide/module-types.md',
'aio/content/guide/template-overview.md',
'aio/content/guide/template-syntax.md',
'aio/content/guide/built-in-template-functions.md',
'aio/content/examples/built-in-template-functions/**/{*,.*}',
'aio/content/guide/event-binding.md',
'aio/content/guide/event-binding-concepts.md',
'aio/content/examples/event-binding/**/{*,.*}',
'aio/content/guide/interpolation.md',
'aio/content/examples/interpolation/**/{*,.*}',
'aio/content/examples/template-syntax/**/{*,.*}',
'aio/content/images/guide/template-syntax/**/{*,.*}',
'aio/content/guide/binding-overview.md',
'aio/content/guide/binding-syntax.md',
'aio/content/examples/binding-syntax/**/{*,.*}',
'aio/content/guide/property-binding.md',
'aio/content/examples/property-binding/**/{*,.*}',
'aio/content/guide/property-binding-best-practices.md',
'aio/content/guide/attribute-binding.md',
'aio/content/examples/attribute-binding/**/{*,.*}',
'aio/content/guide/two-way-binding.md',
'aio/content/examples/two-way-binding/**/{*,.*}',
'aio/content/guide/built-in-directives.md',
'aio/content/guide/directive-composition-api.md',
'aio/content/examples/built-in-directives/**/{*,.*}',
'aio/content/images/guide/built-in-directives/**/{*,.*}',
'aio/content/guide/template-reference-variables.md',
'aio/content/examples/template-reference-variables/**/{*,.*}',
'aio/content/guide/inputs-outputs.md',
'aio/content/examples/inputs-outputs/**/{*,.*}',
'aio/content/images/guide/inputs-outputs/**/{*,.*}',
'aio/content/guide/understanding-template-expr-overview.md',
'aio/content/guide/template-expression-operators.md',
'aio/content/examples/template-expression-operators/**/{*,.*}',
'aio/content/guide/pipes.md',
'aio/content/guide/pipes-custom-data-trans.md',
'aio/content/guide/pipes-overview.md',
'aio/content/guide/pipe-precedence.md',
'aio/content/guide/pipes-transform-data.md',
'aio/content/guide/pipe-template.md',
'aio/content/examples/pipes/**/{*,.*}',
'aio/content/images/guide/pipes/**/{*,.*}',
'aio/content/guide/providers.md',
'aio/content/examples/providers/**/{*,.*}',
'aio/content/images/guide/providers/**/{*,.*}',
'aio/content/guide/singleton-services.md',
'aio/content/guide/sharing-ngmodules.md',
'aio/content/guide/standalone-components.md',
'aio/content/guide/standalone-migration.md',
'aio/content/guide/structural-directives.md',
'aio/content/examples/structural-directives/**/{*,.*}',
'aio/content/guide/svg-in-templates.md',
'aio/content/guide/style-precedence.md',
'aio/content/images/guide/structural-directives/**/{*,.*}',
'aio/content/guide/template-statements.md',
'aio/content/guide/understanding-angular-overview.md',
'aio/content/guide/user-input.md',
'aio/content/examples/user-input/**/{*,.*}',
'aio/content/images/guide/user-input/**/{*,.*}',
'aio/content/guide/view-encapsulation.md',
'aio/content/examples/view-encapsulation/**/{*,.*}',
'aio/content/images/guide/view-encapsulation/**/{*,.*}',
'aio/content/special-elements/**/{*,.*}',
'aio/content/blocks/**/{*,.*}',
'aio/content/guide/hydration.md',
'aio/content/guide/defer.md',
'aio/content/guide/signals.md',
'aio/content/guide/control_flow.md',
'aio/content/examples/injection-token/**/{*,.*}',
])
reviewers:
users:
@@ -188,9 +352,8 @@ groups:
- AndrewKushnir
- atscott
- crisbeto
- devversion
- dylhunn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
# =========================================================
@@ -210,7 +373,7 @@ groups:
- AndrewKushnir
- atscott
- dylhunn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
# =========================================================
@@ -223,6 +386,23 @@ groups:
contains_any_globs(files, [
'packages/common/http/**/{*,.*}',
'packages/examples/http/**/{*,.*}',
'aio/content/guide/understanding-communicating-with-http.md',
'aio/content/guide/http-configure-http-url-parameters.md',
'aio/content/guide/http-handle-request-errors.md',
'aio/content/guide/http-intercept-requests-and-responses.md',
'aio/content/guide/http-interceptor-use-cases.md',
'aio/content/guide/http-make-jsonp-request.md',
'aio/content/guide/http-optimize-server-interaction.md',
'aio/content/guide/http-pass-metadata-to-interceptors.md',
'aio/content/guide/http-request-data-from-server.md',
'aio/content/guide/http-security-xsrf-protection.md',
'aio/content/guide/http-send-data-to-server.md',
'aio/content/guide/http-server-communication.md',
'aio/content/guide/http-setup-server-communication.md',
'aio/content/guide/http-test-requests.md',
'aio/content/guide/http-track-show-request-progress.md',
'aio/content/examples/http/**/{*,.*}',
'aio/content/images/guide/http/**/{*,.*}'
])
reviewers:
users:
@@ -230,7 +410,7 @@ groups:
- AndrewKushnir
- atscott
- dylhunn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
# =========================================================
@@ -242,6 +422,9 @@ groups:
- >
contains_any_globs(files, [
'packages/elements/**/{*,.*}',
'aio/content/examples/elements/**/{*,.*}',
'aio/content/images/guide/elements/**/{*,.*}',
'aio/content/guide/elements.md'
])
reviewers:
users:
@@ -250,7 +433,7 @@ groups:
- andrewseguin
- atscott
- dylhunn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
# =========================================================
@@ -263,6 +446,22 @@ groups:
contains_any_globs(files, [
'packages/forms/**/{*,.*}',
'packages/examples/forms/**/{*,.*}',
'aio/content/guide/forms.md',
'aio/content/examples/forms/**/{*,.*}',
'aio/content/images/guide/forms/**/{*,.*}',
'aio/content/guide/forms-overview.md',
'aio/content/examples/forms-overview/**/{*,.*}',
'aio/content/images/guide/forms-overview/**/{*,.*}',
'aio/content/guide/form-validation.md',
'aio/content/guide/typed-forms.md',
'aio/content/examples/form-validation/**/{*,.*}',
'aio/content/images/guide/form-validation/**/{*,.*}',
'aio/content/guide/dynamic-form.md',
'aio/content/examples/dynamic-form/**/{*,.*}',
'aio/content/images/guide/dynamic-form/**/{*,.*}',
'aio/content/guide/reactive-forms.md',
'aio/content/examples/reactive-forms/**/{*,.*}',
'aio/content/images/guide/reactive-forms/**/{*,.*}'
])
reviewers:
users:
@@ -291,6 +490,21 @@ groups:
'packages/compiler/src/render3/view/i18n/**/{*,.*}',
'packages/compiler-cli/src/extract_i18n.ts',
'packages/localize/**/{*,.*}',
'aio/content/guide/i18n-overview.md',
'aio/content/guide/i18n-common-overview.md',
'aio/content/guide/i18n-common-add-package.md',
'aio/content/guide/i18n-common-locale-id.md',
'aio/content/guide/i18n-common-format-data-locale.md',
'aio/content/guide/i18n-common-prepare.md',
'aio/content/guide/i18n-common-translation-files.md',
'aio/content/guide/i18n-common-merge.md',
'aio/content/guide/i18n-common-deploy.md',
'aio/content/guide/i18n-example.md',
'aio/content/guide/i18n-optional-overview.md',
'aio/content/guide/i18n-optional-manual-runtime-locale.md',
'aio/content/guide/i18n-optional-import-global-variants.md',
'aio/content/guide/i18n-optional-manage-marked-text.md',
'aio/content/examples/i18n/**/{*,.*}'
])
reviewers:
users:
@@ -306,6 +520,9 @@ groups:
- >
contains_any_globs(files, [
'packages/platform-server/**/{*,.*}',
'aio/content/guide/prerendering.md',
'aio/content/guide/ssr.md',
'aio/content/examples/ssr/**/{*,.*}',
])
reviewers:
users:
@@ -314,7 +531,7 @@ groups:
- AndrewKushnir
- atscott
- dylhunn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
# =========================================================
@@ -327,6 +544,16 @@ groups:
contains_any_globs(files, [
'packages/router/**/{*,.*}',
'packages/examples/router/**/{*,.*}',
'aio/content/guide/router.md',
'aio/content/guide/router-tutorial.md',
'aio/content/guide/router-tutorial-toh.md',
'aio/content/guide/routing-overview.md',
'aio/content/guide/router-reference.md',
'aio/content/examples/router-tutorial/**/{*,.*}',
'aio/content/examples/router/**/{*,.*}',
'aio/content/images/guide/router/**/{*,.*}',
'aio/content/guide/routing-with-urlmatcher.md',
'aio/content/examples/routing-with-urlmatcher/**/{*,.*}'
])
reviewers:
users:
@@ -343,6 +570,15 @@ groups:
contains_any_globs(files, [
'packages/service-worker/**/{*,.*}',
'packages/examples/service-worker/**/{*,.*}',
'aio/content/guide/service-worker-getting-started.md',
'aio/content/examples/service-worker-getting-started/**/{*,.*}',
'aio/content/guide/app-shell.md',
'aio/content/guide/service-worker-communications.md',
'aio/content/guide/service-worker-config.md',
'aio/content/guide/service-worker-devops.md',
'aio/content/guide/service-worker-intro.md',
'aio/content/guide/service-worker-notifications.md',
'aio/content/images/guide/service-worker/**/{*,.*}'
])
reviewers:
users:
@@ -359,11 +595,22 @@ groups:
'packages/upgrade/**/{*,.*}',
'packages/common/upgrade/**/{*,.*}',
'packages/examples/upgrade/**/{*,.*}',
'aio/content/guide/upgrade.md',
'aio/content/examples/upgrade-lazy-load-ajs/**/{*,.*}',
'aio/content/examples/upgrade-module/**/{*,.*}',
'aio/content/images/guide/upgrade/**/{*,.*}',
'aio/content/examples/upgrade-phonecat-1-typescript/**/{*,.*}',
'aio/content/examples/upgrade-phonecat-2-hybrid/**/{*,.*}',
'aio/content/examples/upgrade-phonecat-3-final/**/{*,.*}',
'aio/content/guide/upgrade-performance.md',
'aio/content/guide/upgrade-setup.md',
'aio/content/guide/ajs-quick-reference.md',
'aio/content/examples/ajs-quick-reference/**/{*,.*}'
])
reviewers:
users:
- alxhub
- thePunderWoman
- jessicajaniuk
# =========================================================
# Framework: Testing
@@ -372,8 +619,19 @@ groups:
<<: *defaults
conditions:
- >
contains_any_globs(files.exclude('packages/compiler-cli/*').exclude('packages/language-service/*').exclude('packages/service-worker/*').exclude('packages/core/schematics/*'), [
contains_any_globs(files.exclude('packages/compiler-cli/*').exclude('packages/language-service/*').exclude('packages/service-worker/*'), [
'packages/**/testing/**/{*,.*}',
'aio/content/guide/testing.md',
'aio/content/guide/test-debugging.md',
'aio/content/guide/testing-attribute-directives.md',
'aio/content/guide/testing-code-coverage.md',
'aio/content/guide/testing-components-basics.md',
'aio/content/guide/testing-components-scenarios.md',
'aio/content/guide/testing-pipes.md',
'aio/content/guide/testing-services.md',
'aio/content/guide/testing-utility-apis.md',
'aio/content/examples/testing/**/{*,.*}',
'aio/content/images/guide/testing/**/{*,.*}'
])
reviewers:
users:
@@ -381,7 +639,7 @@ groups:
- AndrewKushnir
- atscott
- dylhunn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
# =========================================================
@@ -400,7 +658,7 @@ groups:
- AndrewKushnir
- atscott
- dylhunn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
# =========================================================
@@ -419,7 +677,7 @@ groups:
- AndrewKushnir
- atscott
- dylhunn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
# =========================================================
@@ -437,6 +695,9 @@ groups:
'packages/tsconfig-tsec-base.json',
'packages/tsec-exemption.json',
'tools/tsec.bzl',
'aio/content/guide/security.md',
'aio/content/examples/security/**/{*,.*}',
'aio/content/images/guide/security/**/{*,.*}',
])
reviewers:
users:
@@ -473,12 +734,13 @@ groups:
- >
contains_any_globs(files, [
'packages/language-service/**/{*,.*}',
'aio/content/guide/language-service.md',
'aio/content/images/guide/language-service/**/{*,.*}'
])
reviewers:
users:
- alxhub
- atscott
- dylhunn
# =========================================================
# zone.js
@@ -489,6 +751,7 @@ groups:
- >
contains_any_globs(files, [
'packages/zone.js/**/{*,.*}',
'aio/content/guide/zone.md'
])
reviewers:
users:
@@ -510,7 +773,7 @@ groups:
- atscott
- crisbeto
- dylhunn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
# =========================================================
@@ -545,8 +808,108 @@ groups:
- AndrewKushnir
- atscott
- dylhunn
- thePunderWoman
- jessicajaniuk
- josephperrott
- pkozlowski-opensource
# =========================================================
# Docs: Contributors
# =========================================================
docs-contributors:
<<: *defaults
conditions:
- >
contains_any_globs(files, [
'aio/content/marketing/contributors.json',
'aio/content/images/bios/**/{*,.*}',
])
reviewers:
users:
- MarkTechson
- mgechev
- twerske
# =========================================================
# Docs: Gettings Started & Tutorial
# =========================================================
docs-getting-started-and-tutorial:
<<: *defaults
conditions:
- >
contains_any_globs(files, [
'aio/content/guide/setup-local.md',
'aio/content/images/guide/setup-local/**/{*,.*}',
'aio/content/tutorial/**/{*,.*}',
'aio/content/images/guide/toh/**/{*,.*}',
'aio/content/demos/first-app/**/{*,.*}',
'aio/content/examples/first-app-*/**/{*,.*}',
'aio/content/images/guide/faa/**/{*,.*}',
'aio/content/examples/toh-pt0/**/{*,.*}',
'aio/content/examples/toh-pt1/**/{*,.*}',
'aio/content/examples/toh-pt2/**/{*,.*}',
'aio/content/examples/toh-pt3/**/{*,.*}',
'aio/content/examples/toh-pt4/**/{*,.*}',
'aio/content/examples/toh-pt5/**/{*,.*}',
'aio/content/examples/toh-pt6/**/{*,.*}',
'aio/content/examples/getting-started-v0/**/{*,.*}',
'aio/content/examples/getting-started/**/{*,.*}',
'aio/content/start/**/{*,.*}',
'aio/content/guide/quick-start.md',
'aio/content/images/guide/start/**/{*,.*}',
'aio/content/examples/what-is-angular/**/{*,.*}',
'aio/content/guide/what-is-angular.md'
])
reviewers:
users:
- AndrewKushnir
- jessicajaniuk
# =========================================================
# Docs: Marketing
# =========================================================
docs-marketing:
<<: *defaults
conditions:
- >
contains_any_globs(files.exclude("aio/content/marketing/contributors.json"), [
'aio/content/examples/marketing-first-app/**/{*,.*}',
'aio/content/guide/roadmap.md',
'aio/content/marketing/**/{*,.*}',
'aio/content/images/marketing/**/{*,.*}',
'aio/content/file-not-found.md',
'aio/content/license.md',
'aio/content/navigation.json'
])
reviewers:
users:
- MarkTechson
- mgechev
- twerske
# =========================================================
# Docs: Observables
# =========================================================
docs-observables:
<<: *defaults
conditions:
- >
contains_any_globs(files, [
'aio/content/guide/observables.md',
'aio/content/examples/observables/**/{*,.*}',
'aio/content/guide/comparing-observables.md',
'aio/content/examples/comparing-observables/**/{*,.*}',
'aio/content/guide/observables-in-angular.md',
'aio/content/examples/observables-in-angular/**/{*,.*}',
'aio/content/guide/practical-observable-usage.md',
'aio/content/examples/practical-observable-usage/**/{*,.*}',
'aio/content/guide/rx-library.md',
'aio/content/examples/rx-library/**/{*,.*}'
])
reviewers:
users:
- alxhub
- atscott
- dylhunn
# =========================================================
# Docs: Packaging, Tooling, Releasing
@@ -556,16 +919,47 @@ groups:
conditions:
- >
contains_any_globs(files, [
'contributing-docs/public-api-surface.md',
'docs/PUBLIC_API.md',
'docs/RELEASE_SCHEDULE.md',
'aio/content/guide/npm-packages.md',
'aio/content/guide/browser-support.md',
'aio/content/guide/releases.md',
'aio/content/guide/updating.md',
'aio/content/guide/deprecations.md',
'aio/content/examples/deprecation-guide/**/{*,.*}',
'aio/content/guide/migration-module-with-providers.md',
'aio/content/guide/static-query-migration.md',
'aio/content/guide/update-to-latest-version.md',
'aio/content/guide/versions.md',
'aio/content/guide/update-to-version-14.md',
'aio/content/guide/update-to-version-15.md',
'aio/content/guide/update-to-version-16.md',
])
reviewers:
users:
- alxhub
- AndrewKushnir
- atscott
- thePunderWoman
- jessicajaniuk
- jelbourn
# =========================================================
# Docs: Angular DevTools
# =========================================================
docs-devtools:
<<: *defaults
conditions:
- >
contains_any_globs(files, [
'aio/content/guide/devtools.md',
'aio/content/images/guide/devtools/**/{*,.*}'
])
reviewers:
users:
- MarkTechson
- mgechev
- twerske
# =========================================================
# Tooling: Compiler API shared with Angular CLI
#
@@ -589,6 +983,80 @@ groups:
required: 2 # require at least 2 approvals
reviewed_for: required
# =========================================================
# Docs: CLI
# =========================================================
docs-cli:
<<: *defaults
conditions:
- >
contains_any_globs(files, [
'aio/content/cli/**/{*,.*}',
'aio/content/guide/typescript-configuration.md',
'aio/content/examples/setup/**/{*,.*}',
'aio/content/guide/build.md',
'aio/content/images/guide/build/**/{*,.*}',
'aio/content/images/guide/cli/**/{*,.*}',
'aio/content/guide/cli-builder.md',
'aio/content/examples/cli-builder/**/{*,.*}',
'aio/content/guide/deployment.md',
'aio/content/images/guide/deployment/**/{*,.*}',
'aio/content/guide/file-structure.md',
'aio/content/guide/ivy.md',
'aio/content/guide/strict-mode.md',
'aio/content/guide/web-worker.md',
'aio/content/guide/workspace-config.md',
'aio/content/guide/migration-solution-style-tsconfig.md',
'aio/content/guide/migration-update-libraries-tslib.md',
'aio/content/guide/esbuild.md',
])
reviewers:
users:
- alan-agius4
- clydin
- dgp1130
- mgechev
# =========================================================
# Docs: CLI Libraries
# =========================================================
docs-libraries:
<<: *defaults
conditions:
- >
contains_any_globs(files, [
'aio/content/examples/angular-linker-plugin/webpack.config.mjs',
'aio/content/guide/creating-libraries.md',
'aio/content/guide/libraries.md',
'aio/content/guide/using-libraries.md',
'aio/content/guide/angular-package-format.md'
])
reviewers:
users:
- alan-agius4
- alxhub
- mgechev
# =========================================================
# Docs: Schematics
# =========================================================
docs-schematics:
<<: *defaults
conditions:
- >
contains_any_globs(files, [
'aio/content/guide/schematics.md',
'aio/content/guide/schematics-authoring.md',
'aio/content/guide/schematics-for-libraries.md',
'aio/content/images/guide/schematics/**/{*,.*}',
'aio/content/examples/schematics-for-libraries/**/{*,.*}'
])
reviewers:
users:
- alan-agius4
- dylhunn
- mgechev
# =========================================================
# Docs: Angular Dev Site
# =========================================================
@@ -597,24 +1065,72 @@ groups:
conditions:
- >
contains_any_globs(files, [
'adev/**/{.*,*}',
'aio/**/{.*,*}'
'adev/**/{.*,*}'
])
reviewers:
users:
- twerske
- josephperrott
- jelbourn
- bencodezen
- thePunderWoman
- dylhunn
# =========================================================
# Docs-infra
# =========================================================
docs-infra:
<<: *defaults
conditions:
- >
contains_any_globs(files, [
'aio/{*,.*}',
'aio/aio-builds-setup/**/{*,.*}',
'aio/content/cli-src/**/{*,.*}',
'aio/content/examples/{*,.*}',
'aio/scripts/**/{*,.*}',
'aio/src/**/{*,.*}',
'aio/tests/**/{*,.*}',
'aio/tools/**/{*,.*}',
'aio/tools/examples/shared/boilerplate/cli/.vscode/**/{*,.*}',
'aio/content/BUILD.bazel',
'aio/content/images/guide/contributors-guide/**/{*,.*}',
'aio/content/guide/contributors-guide-overview.md',
'aio/content/guide/docs-style-guide.md',
'aio/content/examples/docs-style-guide/**/{*,.*}',
'aio/content/images/guide/docs-style-guide/**/{*,.*}',
'aio/content/guide/docs-lint-errors.md',
'aio/content/images/guide/docs-lint-errors/**/{*,.*}',
'aio/content/guide/localized-documentation.md',
'aio/content/guide/localizing-angular.md',
'aio/content/guide/reviewing-content.md',
'aio/content/guide/updating-content-github-ui.md',
'aio/content/guide/updating-search-keywords.md',
'aio/content/guide/doc-build-test.md',
'aio/content/guide/doc-edit-finish.md',
'aio/content/guide/doc-editing.md',
'aio/content/guide/doc-github-tasks.md',
'aio/content/guide/doc-pr-open.md',
'aio/content/guide/doc-pr-prep.md',
'aio/content/guide/doc-pr-update.md',
'aio/content/guide/doc-prepare-to-edit.md',
'aio/content/guide/doc-select-issue.md',
'aio/content/guide/doc-tasks.md',
'aio/content/guide/doc-update-overview.md',
'aio/content/guide/doc-update-start.md',
'aio/content/guide/docs-lint-errors.md',
'aio/content/images/guide/preparing-to-edit-docs/**/{*,.*}',
'aio/content/images/guide/github-for-docs/**/{*,.*}',
'aio/content/images/guide/doc-update-start/**/{*,.*}',
'aio/content/images/guide/doc-update-overview/**/{*,.*}',
'aio/content/images/guide/doc-pr-update/**/{*,.*}',
'aio/content/images/guide/doc-pr-prep/**/{*,.*}',
'aio/content/images/guide/doc-pr-open/**/{*,.*}',
'aio/content/images/guide/doc-github-tasks/**/{*,.*}',
'aio/content/images/guide/doc-prepare-to-edit/**/{*,.*}',
])
reviewers:
users:
- AndrewKushnir
- alxhub
- crisbeto
- devversion
- atscott
- pkozlowski-opensource
- MarkTechson
- ~JeanMeche
- jessicajaniuk
- josephperrott
# =========================================================
# Angular DevTools
@@ -633,8 +1149,8 @@ groups:
- dgp1130
- josephperrott
- mgechev
- MarkTechson
- ~JeanMeche
- twerske
- ~jeanmeche
# =========================================================
# Dev-infra
@@ -652,8 +1168,8 @@ groups:
'.ng-dev/**/{*,.*}',
'.vscode/**/{*,.*}',
'.yarn/**/{*,.*}',
'contributing-docs/*.md',
'contributing-docs/images/**/{*,.*}',
'docs/*.md',
'docs/images/**/{*,.*}',
'goldens/{*,.*}',
'goldens/public-api/manage.js',
'modules/{*,.*}',
@@ -698,6 +1214,12 @@ groups:
- >
contains_any_globs(files.exclude("goldens/public-api/manage.js"), [
'goldens/public-api/**/{*,.*}',
'docs/NAMING.md',
'aio/content/guide/angular-package-format.md',
'aio/content/guide/glossary.md',
'aio/content/guide/styleguide.md',
'aio/content/examples/styleguide/**/{*,.*}',
'aio/content/images/guide/styleguide/{*,.*}'
])
reviewers:
users:
@@ -706,11 +1228,8 @@ groups:
- atscott
- dylhunn
- ~jelbourn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
- ~iteriani
- ~tbondwilkinson
- ~rahatarmanahmed
reviews:
request: 3 # Request reviews from 3 people
required: 2 # Require that 2 people approve
@@ -735,7 +1254,7 @@ groups:
- atscott
- dylhunn
- ~jelbourn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
reviews:
request: 2 # Request reviews from 2 people
@@ -761,7 +1280,7 @@ groups:
- atscott
- dylhunn
- ~jelbourn
- thePunderWoman
- jessicajaniuk
- pkozlowski-opensource
####################################################################################
@@ -785,60 +1304,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
- jesse-good # Jesse Costello-Good
- mturco # Matt Turco
- neonstalwart # Ben Hockey
- iteriani # Thomas Nguyen
- tbondwilkinson # Tom Wilkinson
- rahatarmanahmed # Rahat Ahmed
labels:
pending: 'requires: TGP'
approved: 'requires: TGP'
rejected: 'requires: TGP'
####################################################################################
# Override managed result groups
#
@@ -915,6 +1383,27 @@ groups:
author_value: 0 # The author of the PR cannot provide an approval for themself
reviewed_for: ignored # All reviews apply to this group whether noted via Reviewed-for or not
reviewers:
teams:
# Any member of the team can provide a review to perform the minimum review required
- team
users:
- alan-agius4 # Alan Agius
- AleksanderBodurri # Aleksander Bodurri
- alxhub # Alex Rickabaugh
- AndrewKushnir # Andrew Kushnir
- andrewseguin # Andrew Seguin
- atscott # Andrew Scott
- clydin # Charles Lyding
- crisbeto # Kristiyan Kostadinov
- devversion # Paul Gschwendtner
- dgp1130 # Doug Parker
- dylhunn # Dylan Hunn
- jeanmeche # Matthieu Riegler
- jelbourn # Jeremy Elbourn
- jessicajaniuk # Jessica Janiuk
- JiaLiPassion # Jia Li
- JoostK # Joost Koehoorn
- josephperrott # Joey Perrott
- MarkTechson # Mark Thompson (Techson)
- mgechev # Minko Gechev
- mmalerba # Miles Malerba
- pkozlowski-opensource # Pawel Kozlowski
- twerske # Emma Twersky
- zarend # Zach Arend
+6
View File
@@ -5,6 +5,12 @@
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"BazelBuild.vscode-bazel",
"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",
//"errata-ai.vale-server",
],
}
+8
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,
@@ -12,12 +18,14 @@
"**/node_modules/**": true,
"**/bazel-out/**": true,
"**/dist/**": true,
"**/aio/src/generated/**": true,
},
"search.exclude": {
"**/node_modules": true,
"**/bower_components": true,
"**/bazel-out": true,
"**/dist": true,
"**/aio/src/generated": true,
".history": true,
},
"git.ignoreLimitWarning": true,
+147529
View File
File diff suppressed because one or more lines are too long
-148049
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -2,4 +2,4 @@
# yarn lockfile v1
yarn-path ".yarn/releases/yarn-1.22.22.cjs"
yarn-path ".yarn/releases/yarn-1.22.19.cjs"
+3 -2
View File
@@ -64,9 +64,10 @@ config_setting(
nodejs_binary(
name = "yarn_vendored",
data = [".yarn/releases/yarn-1.22.22.cjs"],
entry_point = ".yarn/releases/yarn-1.22.22.cjs",
data = [".yarn/releases/yarn-1.22.19.cjs"],
entry_point = ".yarn/releases/yarn-1.22.19.cjs",
visibility = [
"//aio/tools/examples/shared:__pkg__",
"//integration:__subpackages__",
],
)
+1559 -3843
View File
File diff suppressed because it is too large Load Diff
+13 -8
View File
@@ -32,7 +32,7 @@ Stack Overflow is a much better place to ask questions since:
To save your and our time, we will systematically close all issues that are requests for general support and redirect people to Stack Overflow.
If you would like to chat about the question in real-time, you can reach out via [the Angular community Discord server][discord].
If you would like to chat about the question in real-time, you can reach out via [our Discord server][discord].
## <a name="issue"></a> Found a Bug?
@@ -89,7 +89,7 @@ Before you submit your Pull Request (PR) consider the following guidelines:
We cannot accept code without a signed CLA.
Make sure you author all contributed Git commits with email address associated with your CLA signature.
4. [Fork](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo) the [angular/angular](https://github.com/angular/angular/fork) repo.
4. [Fork](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo) the angular/angular repo.
5. In your forked repository, make your changes in a new git branch:
@@ -138,7 +138,7 @@ If we ask for changes via code reviews then:
git push
```
For more info on working with fixup commits see [here](./contributing-docs/using-fixup-commits.md).
For more info on working with fixup commits see [here](docs/FIXUP_COMMITS.md).
That's it! Thank you for your contribution!
@@ -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](contributing-docs/building-and-testing-angular.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
@@ -302,7 +302,7 @@ There are currently a few exceptions to the "use package name" rule:
* `dev-infra`: used for dev-infra related changes within the directories /scripts and /tools
* `docs-infra`: used for docs-app (angular.dev) related changes within the /adev directory of the repo
* `docs-infra`: used for docs-app (angular.io) related changes within the /aio directory of the repo
* `migrations`: used for changes to the `ng update` migrations.
@@ -353,9 +353,9 @@ DEPRECATED: <what is deprecated>
Closes #<pr number>
```
Breaking Change section should start with the phrase `BREAKING CHANGE: ` followed by a summary of the breaking change, a blank line, and a detailed description of the breaking change that also includes migration instructions.
Breaking Change section should start with the phrase "BREAKING CHANGE: " followed by a summary of the breaking change, a blank line, and a detailed description of the breaking change that also includes migration instructions.
Similarly, a Deprecation section should start with `DEPRECATED: ` followed by a short description of what is deprecated, a blank line, and a detailed description of the deprecation that also mentions the recommended update path.
Similarly, a Deprecation section should start with "DEPRECATED: " followed by a short description of what is deprecated, a blank line, and a detailed description of the deprecation that also mentions the recommended update path.
### Revert commits
@@ -389,11 +389,16 @@ 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
[dev-doc]: ./contributing-docs/building-and-testing-angular.md
[dev-doc]: https://github.com/angular/angular/blob/main/docs/DEVELOPER.md
[github]: https://github.com/angular/angular
[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
+1 -1
View File
@@ -1,6 +1,6 @@
The MIT License
Copyright (c) 2010-2024 Google LLC. https://angular.dev/license
Copyright (c) 2010-2023 Google LLC. https://angular.io/license
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+22 -7
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>
@@ -18,7 +18,7 @@
·
<a href="https://github.com/angular/angular/issues">Submit an Issue</a>
·
<a href="https://blog.angular.dev/">Blog</a>
<a href="https://blog.angular.io/">Blog</a>
<br>
<br>
</p>
@@ -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
@@ -101,7 +116,7 @@ Angular is cross-platform, fast, scalable, has incredible tooling, and is loved
## Ecosystem
<p>
<img src="/contributing-docs/images/angular-ecosystem-logos.png" alt="angular ecosystem logos" width="500px" height="auto">
<img src="/docs/images/angular-ecosystem-logos.png" alt="angular ecosystem logos" width="500px" height="auto">
</p>
- [Angular Command Line (CLI)][cli]
@@ -113,7 +128,7 @@ Angular is cross-platform, fast, scalable, has incredible tooling, and is loved
## Upgrading
Check out our [upgrade guide](https://angular.dev/update-guide/) to find out the best way to upgrade your project.
Check out our [upgrade guide](https://update.angular.io/) to find out the best way to upgrade your project.
## Contributing
@@ -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
+1 -1
View File
@@ -1,3 +1,3 @@
Angular is part of Google [Open Source Software Vulnerability Reward Program](https://bughunters.google.com/about/rules/6521337925468160/google-open-source-software-vulnerability-reward-program-rules). For vulnerabilities in Angular, please submit your report [here](https://bughunters.google.com/report).
For more information, check out [Angular's security policy](https://angular.dev/best-practices/security).
For more information, check out [Angular's security policy](https://angular.io/guide/security).
+68 -27
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 = [
@@ -49,17 +64,7 @@ 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"),
},
# We need at least Node 18.17 due to some transitive dependencies.
node_version = "18.20.0",
node_version = "18.13.0",
)
# Download npm dependencies.
@@ -75,7 +80,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-d30a56c19bafaac67cf44e605ed8c2c0e45b0a51.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 +99,54 @@ 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
# the source directory stamped as a filegroup in the manual BUILD contents below.
all_node_modules_target_name = "node_modules_all",
data = [
YARN_LABEL,
"//:.yarnrc",
],
# Disabled because, when False, yarn_install preserves the node_modules folder
# with bin symlinks in the external repository. This is needed to link the shared
# set of deps for example e2es.
exports_directories_only = False,
manual_build_file_contents = """\
filegroup(
name = "node_modules_files",
srcs = ["node_modules"],
)
""",
package_json = "//aio/tools/examples/shared:package.json",
yarn = YARN_LABEL,
yarn_lock = "//aio/tools/examples/shared:yarn.lock",
)
load("@aspect_bazel_lib//lib:repositories.bzl", "aspect_bazel_lib_dependencies")
aspect_bazel_lib_dependencies()
@@ -143,10 +196,10 @@ cldr_xml_data_repository(
# sass rules
http_archive(
name = "io_bazel_rules_sass",
sha256 = "b00f13a280fc60ef2a1d142b31c629075bac841c980a0c3462190f338e5d584a",
strip_prefix = "rules_sass-6e23fb1351f392f7fe7a07038cd537770fe97742",
sha256 = "7a90567717c3417a23ff4b21963a698a6e9aa669ac9e682121ea33f218a2816a",
strip_prefix = "rules_sass-425ecafa8268bc013d684216363fe75bc802323e",
urls = [
"https://github.com/bazelbuild/rules_sass/archive/6e23fb1351f392f7fe7a07038cd537770fe97742.zip",
"https://github.com/bazelbuild/rules_sass/archive/425ecafa8268bc013d684216363fe75bc802323e.zip",
],
)
@@ -181,15 +234,3 @@ http_archive(
strip_prefix = "sc-4.8.2-osx",
url = "https://saucelabs.com/downloads/sc-4.8.2-osx.zip",
)
yarn_install(
name = "npm_ts_versions",
data = [
YARN_LABEL,
"//:.yarnrc",
],
exports_directories_only = False,
package_json = "//packages/core/schematics/migrations/signal-migration/test/ts-versions:package.json",
yarn = YARN_LABEL,
yarn_lock = "//packages/core/schematics/migrations/signal-migration/test/ts-versions:yarn.lock",
)
+36 -83
View File
@@ -1,17 +1,9 @@
load("@npm//@angular/build-tooling/bazel/remote-execution:index.bzl", "ENABLE_NETWORK")
load("@npm//@angular/build-tooling/bazel/http-server:index.bzl", "http_server")
load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
load("//:packages.bzl", "link_packages")
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"])
exports_files([
"tsconfig.json",
])
# All source and configuration files required to build the docs app
APPLICATION_FILES = [
"angular.json",
@@ -22,30 +14,21 @@ APPLICATION_FILES = [
["src/**/*"],
exclude = [
"src/**/*.spec.ts",
# Temporarily exclude generated sources produced by the non-bazel
# build until the whole project is built by bazel and this directory
# isn't needed.
"src/generated/**/*",
],
)
TEST_FILES = APPLICATION_FILES + [
"karma.conf.js",
"test-main.ts",
"tsconfig.spec.json",
] + glob(
["src/**/*.spec.ts"],
["**/*.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/docs",
"@npm//@angular/build",
APPLICATION_DEPS = link_packages([
"@npm//@angular-devkit/build-angular",
"@npm//@angular/animations",
"@npm//@angular/cdk",
@@ -53,6 +36,7 @@ APPLICATION_DEPS = [
"@npm//@angular/compiler",
"@npm//@angular/compiler-cli",
"@npm//@angular/core",
"@npm//@angular/docs",
"@npm//@angular/forms",
"@npm//@angular/material",
"@npm//@angular/platform-browser",
@@ -64,6 +48,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",
@@ -80,91 +71,56 @@ APPLICATION_DEPS = [
"@npm//@lezer/highlight",
"@npm//@lezer/javascript",
"@npm//@lezer/common",
"@npm//@stackblitz/sdk",
"@npm//open-in-idx",
"@npm//@webcontainer/api",
"@npm//@xterm/xterm",
"@npm//@xterm/addon-fit",
"@npm//algoliasearch",
"@npm//xterm",
"@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",
"@npm//jasmine",
"@npm//jasmine-core",
"@npm//karma-chrome-launcher",
"@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",
srcs = APPLICATION_FILES,
)
bool_flag(
name = "prerender_adev",
build_setting_default = False,
)
config_setting(
name = "no_prerender",
flag_values = {
":prerender_adev": "false",
},
)
config_setting(
name = "prerender",
flag_values = {
":prerender_adev": "true",
},
)
config_based_architect_flags = select({
":no_prerender": ["--no-prerender"],
":prerender": ["--prerender"],
})
architect(
name = "build",
args = [
"angular-dev:build",
"--output-path=build",
] + config_based_architect_flags,
],
chdir = "$(RULEDIR)",
data = ensure_local_package_deps(APPLICATION_DEPS) + APPLICATION_ASSETS + [
data = APPLICATION_DEPS + [
":application_files_bin",
],
env = {
"NG_BUILD_OPTIMIZE_CHUNKS": "1",
},
# Network is required to inline fonts.
exec_properties = ENABLE_NETWORK,
output_dir = True,
tags = [
"no-remote-exec",
],
)
http_server(
architect(
name = "serve",
additional_root_paths = [
"angular/adev/build/browser",
args = [
"angular-dev:serve",
"--poll=1000",
"--live-reload",
"--watch",
],
chdir = package_name(),
data = APPLICATION_DEPS + [
":application_files_bin",
],
enable_dev_ui = True,
deps = [":build"],
)
architect_test(
@@ -174,10 +130,7 @@ architect_test(
"--no-watch",
],
chdir = package_name(),
data = ensure_local_package_deps(TEST_DEPS) + TEST_FILES + APPLICATION_ASSETS + [
"//adev/tools:windows-chromium-path",
"@npm//@angular/build-tooling/bazel/browsers/chromium",
],
data = TEST_DEPS + TEST_FILES,
env = {
"CHROME_BIN": "../$(CHROMIUM)",
},
-53
View File
@@ -1,53 +0,0 @@
# [Angular.dev](https://www.angular.dev)
This site is built with Angular.
The content is written primarily 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
```
If you are having issues with the docs building, see the [FAQs](#faqs) section.
## 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).
## FAQs
### The build is failing and I'm seeing `bazel:bazel failed: missing input file` messages.
This is most likely due to a bazel dependency / caching issue. To resolve this, run the following command:
```
# Try this first
yarn bazel clean
# If that doesn't work, try it with the expunge flag
yarn bazel clean --expunge
```
+14 -18
View File
@@ -17,24 +17,25 @@
"prefix": "adev",
"architect": {
"build": {
"builder": "@angular/build:application",
"builder": "@angular-devkit/build-angular:application",
"options": {
"externalDependencies": ["path"],
"define": {
// We need this until xterm 5.6.0 is released
// see https://github.com/xtermjs/xterm.js/pull/4940
"self": "this"
},
"externalDependencies": [
"path"
],
"outputPath": "dist/angular-dev",
"index": "src/index.html",
"browser": "src/main.ts",
"server": "src/main.server.ts",
"ssr": true,
"polyfills": [],
"prerender": true,
"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": {
@@ -84,10 +85,10 @@
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"polyfills": ["zone.js", "zone.js/testing"],
"tsConfig": "tsconfig.spec.json",
"include": ["src/app"],
"karmaConfig": "karma.conf.js",
"main": "test-main.ts",
"inlineStyleLanguage": "scss",
"assets": ["src/favicon.ico", "src/assets"],
"styles": ["@angular/docs/styles/global-styles.scss"],
@@ -99,11 +100,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"
}
}
+1 -1
View File
@@ -5,7 +5,7 @@
"ignore": ["**/.*"],
"headers": [
{
"source": "assets/images/tutorials/common/*.jpg",
"source": "assets/tutorials/common/*.jpg",
"headers": [
{
"key": "Cross-Origin-Resource-Policy",
+8 -12
View File
@@ -1,7 +1,7 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
const {getAdjustedChromeBinPathForWindows} = require('../adev/tools/windows-chromium-path');
const {getAdjustedChromeBinPathForWindows} = require('../aio/tools/windows-chromium-path');
process.env.CHROME_BIN = getAdjustedChromeBinPathForWindows();
@@ -21,7 +21,7 @@ module.exports = function (config) {
'/dummy/image': 'src/assets/images/logos/angular/angular.png',
},
client: {
clearContext: false, // leave Jasmine Spec Runner output visible in browser
clearContext: false, // leave Jasmine Spec Runner output visible in browser
jasmine: {
// you can add configuration options for Jasmine here
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
@@ -32,12 +32,15 @@ module.exports = function (config) {
},
},
jasmineHtmlReporter: {
suppressAll: true, // removes the duplicated traces
suppressAll: true // removes the duplicated traces
},
coverageReporter: {
dir: require('path').join(__dirname, './coverage/site'),
subdir: '.',
reporters: [{type: 'html'}, {type: 'text-summary'}],
reporters: [
{ type: 'html' },
{ type: 'text-summary' }
],
},
reporters: ['progress', 'kjhtml', 'jasmine-seed'],
port: 9876,
@@ -48,14 +51,7 @@ module.exports = function (config) {
ChromeHeadlessNoSandbox: {
base: 'ChromeHeadless',
// See /integration/README.md#browser-tests for more info on these args
flags: [
'--no-sandbox',
'--headless',
'--disable-gpu',
'--disable-dev-shm-usage',
'--hide-scrollbars',
'--mute-audio',
],
flags: ['--no-sandbox', '--headless', '--disable-gpu', '--disable-dev-shm-usage', '--hide-scrollbars', '--mute-audio'],
},
},
browsers: ['ChromeHeadlessNoSandbox'],
+135
View File
@@ -0,0 +1,135 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {input, confirm} from '@inquirer/prompts';
import {existsSync} from 'fs';
import {copyFile, mkdir, writeFile} from 'fs/promises';
import {dirname, join} from 'path';
import {fileURLToPath} from 'url';
import {copyFolder} from './utils/fs.mjs';
const EXAMPLES_BASE = join(
dirname(fileURLToPath(import.meta.url)),
'../../src/content/examples',
);
const STACKBLITZ_TEMPLATE = join(
dirname(fileURLToPath(import.meta.url)),
'../../src/content/stackblitz-template',
);
const MAIN_TS_FILENAME = 'main.ts';
const STACKBLITZ_CONFIG_FILENAME = 'stackblitz.json';
createExample();
async function createExample(): Promise<void> {
console.info('Create example');
const name = await input({message: 'What is the example name?'});
const description = await input({message: 'Could you provide the description of the example?'});
const tags: string[] = [];
let addMoreTags = true;
while (addMoreTags) {
const tag = await input({message: 'Could you provide the tag of the example?'});
if (!!tag) {
tags.push(tag);
}
console.info();
addMoreTags = await confirm({message: 'Would you like to add another tag?', default: true});
}
const shouldCopySrcAppFolderFromTemplate = await confirm({
message: 'Would you like to copy /src/app/**.* from template?',
default: true,
});
const shouldCopyMainTsFromTemplate = await confirm({
message: 'Would you like to copy /src/main.ts from template?',
default: false,
});
const examplePath = join(EXAMPLES_BASE, name);
await createEmptyExample(examplePath, name, description, tags);
await copyFilesFromTemplate(
examplePath,
shouldCopySrcAppFolderFromTemplate,
shouldCopyMainTsFromTemplate,
);
}
/**
* Create the directory and marker files for the new example.
*/
async function createEmptyExample(
examplePath: string,
exampleName: string,
description: string,
tags: string[],
): Promise<void> {
validateExampleName(exampleName);
await ensureExamplePath(examplePath);
await writeStackBlitzFile(examplePath, description, tags);
}
function validateExampleName(exampleName: string): void {
if (/\s/.test(exampleName)) {
throw new Error(`Unable to create example. The example name contains spaces: '${exampleName}'`);
}
}
/**
* Ensure that the new example directory exists.
*/
async function ensureExamplePath(examplePath: string): Promise<void> {
if (existsSync(examplePath)) {
throw new Error(
`Unable to create example. The path to the new example already exists: ${examplePath}`,
);
}
await mkdir(examplePath);
}
/**
* Write the `stackblitz.json` file into the new example.
*/
async function writeStackBlitzFile(
examplePath: string,
description: string,
tags: string[],
): Promise<void> {
const config = {
description,
ignore: ['**/*.d.ts', '**/*.js', '**/*.[1,2].*'],
tags,
};
await writeFile(
join(examplePath, STACKBLITZ_CONFIG_FILENAME),
JSON.stringify(config, null, 2) + '\n',
);
}
async function copyFilesFromTemplate(
examplePath: string,
shouldCopySrcAppFolderFromTemplate: boolean,
shouldCopyMainTsFromTemplate: boolean,
): Promise<void> {
if (shouldCopySrcAppFolderFromTemplate) {
const appTemplateFolderPath = join(STACKBLITZ_TEMPLATE, 'src/app');
const exampleAppFolderPath = join(examplePath, 'src/app');
await copyFolder(appTemplateFolderPath, exampleAppFolderPath);
}
if (shouldCopyMainTsFromTemplate) {
const mainTsTemplatePath = join(STACKBLITZ_TEMPLATE, 'src', MAIN_TS_FILENAME);
const exampleMainTsPath = join(examplePath, 'src', MAIN_TS_FILENAME);
await copyFile(mainTsTemplatePath, exampleMainTsPath);
}
}
@@ -0,0 +1,158 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import ts from 'typescript';
import * as fs from 'fs';
import {dirname, join, relative} from 'path';
import {fileURLToPath} from 'url';
import {readFile, writeFile} from 'fs/promises';
const TYPESCRIPT_EXTENSION = '.ts';
const SKIP_FILES_WITH_EXTENSIONS = ['.e2e-spec.ts', '.spec.ts', '.po.ts'];
const EXAMPLES_PATH = `../../content/examples`;
interface File {
path: string;
content: string;
}
interface AnalyzedFiles {
path: string;
componentNames: string[];
}
/** Absolute disk path to the project directory. */
const examplesDir = join(
dirname(fileURLToPath(import.meta.url)),
'../../src/content/examples',
);
const projectDir = join(dirname(fileURLToPath(import.meta.url)), '../../src');
const previewsComponentMapFileName = 'previews.ts';
main();
async function main() {
const files = await retrieveAllTypescriptFiles(
examplesDir,
(path) => !SKIP_FILES_WITH_EXTENSIONS.some((extensionToSkip) => path.endsWith(extensionToSkip)),
);
const filesWithComponent = files
.map((file) => ({
componentNames: analyzeFile(file),
path: file.path,
}))
.filter((result) => result.componentNames.length > 0);
const previewsComponentMap = generatePreviewsComponentMap(filesWithComponent);
fs.mkdirSync(join(projectDir, 'assets/previews'), {recursive: true});
await writeFile(
join(projectDir, 'assets/previews', previewsComponentMapFileName),
previewsComponentMap,
);
}
/** Recursively search the provided directory for all typescript files and asynchronously load them. */
function retrieveAllTypescriptFiles(
baseDir: string,
predicateFn: (path: string) => boolean,
): Promise<File[]> {
const typescriptFiles: Promise<File>[] = [];
const checkFilesInDirectory = (dir: string) => {
const files = fs.readdirSync(dir, {withFileTypes: true});
for (const file of files) {
const fullPathToFile = join(dir, file.name);
const relativeFilePath = relative(baseDir, fullPathToFile);
if (
file.isFile() &&
file.name.endsWith(TYPESCRIPT_EXTENSION) &&
predicateFn(relativeFilePath)
) {
typescriptFiles.push(
readFile(fullPathToFile, {encoding: 'utf-8'}).then((fileContent) => {
return {
path: relativeFilePath,
content: fileContent,
};
}),
);
} else if (file.isDirectory()) {
checkFilesInDirectory(fullPathToFile);
}
}
};
checkFilesInDirectory(baseDir);
return Promise.all(typescriptFiles);
}
/** Returns list of the `Standalone` @Component class names for given file */
function analyzeFile(file: File): string[] {
const componentClassNames: string[] = [];
const sourceFile = ts.createSourceFile(file.path, file.content, ts.ScriptTarget.Latest, false);
const visitNode = (node: ts.Node): void => {
if (ts.isClassDeclaration(node)) {
const decorators = ts.getDecorators(node);
const componentName = node.name ? node.name.text : null;
if (decorators && decorators.length) {
for (const decorator of decorators) {
const call = decorator.expression;
if (
ts.isCallExpression(call) &&
ts.isIdentifier(call.expression) &&
call.expression.text === 'Component' &&
call.arguments.length > 0 &&
ts.isObjectLiteralExpression(call.arguments[0])
) {
const hasStandaloneProperty = call.arguments[0].properties.some(
(property) =>
property.name &&
ts.isIdentifier(property.name) &&
property.name.text === 'standalone',
);
if (hasStandaloneProperty && componentName) {
componentClassNames.push(componentName);
}
}
}
}
}
ts.forEachChild(node, visitNode);
};
visitNode(sourceFile);
return componentClassNames;
}
function generatePreviewsComponentMap(data: AnalyzedFiles[]): string {
let result = '';
for (const fileData of data) {
for (const componentName of fileData.componentNames) {
const key = `${fileData.path}${
fileData.componentNames.length > 1 ? '_' + componentName : ''
}`.replace(/\\/g, '/');
result += `['${key}']: () => import('${EXAMPLES_PATH}/${fileData.path
.replace(/\\/g, '/')
.replace('.ts', '')}').then(c => c.${componentName}),\n`;
}
}
return fs
.readFileSync('scripts/examples/previews-components.template', 'utf8')
.replace(/\${previewsComponents}/g, result);
}
@@ -0,0 +1,23 @@
/*!
* @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
*/
/**
******************************************************************************
* DO NOT MANUALLY EDIT THIS FILE. THIS FILE IS AUTOMATICALLY GENERATED.
******************************************************************************
*/
import {Type} from '@angular/core';
/**
* Map of the previews components, values are functions which returns the promise of the component type, which will be displayed as preview in the ExampleViewer component.
* Keys has to be equal to paths written down in the docs markdown files.
*/
export const PREVIEWS_COMPONENTS_MAP: Record<string, () => Promise<Type<unknown>>> = {
${previewsComponents}
};
@@ -0,0 +1,221 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {dirname, join} from 'path';
import {readFile, writeFile} from 'fs/promises';
import {
ASSETS_EXAMPLE_PATH,
CSS_TS_COPYRIGHT,
EXAMPLES_PATH,
HTML_COPYRIGHT,
STACKBLITZ_TEMPLATE_PATH,
STACKBLITZ_CONFIG_FILENAME,
TEMPORARY_EXAMPLES_PATH,
EXCLUDE_FILES_FOR_STACKBLITZ,
} from './utils/examples-constants.mjs';
import {copyFolder, createFolder, removeFolder} from './utils/fs.mjs';
import jsdom from 'jsdom';
import {glob} from 'glob';
import {regionParser} from './../../prerender/markdown-pipeline/regions/region-parser.mjs';
interface StackblitzConfig {
ignore: string[];
file: string;
tags: string[];
description: string;
}
export async function generateStackblitzExample(
exampleFolderName: string,
primaryFilePath: string,
title: string,
) {
const exampleDir = join(EXAMPLES_PATH, exampleFolderName);
const temporaryExampleDir = join(TEMPORARY_EXAMPLES_PATH, exampleFolderName);
const config = await readFile(join(exampleDir, STACKBLITZ_CONFIG_FILENAME), 'utf-8');
const stackblitzConfig: StackblitzConfig = JSON.parse(config);
primaryFilePath = join(...primaryFilePath.split('/'));
await createFolder(temporaryExampleDir);
await combineTemplateWithExample(exampleDir, temporaryExampleDir);
await generateStackblitzHtml(
temporaryExampleDir,
stackblitzConfig,
exampleFolderName,
primaryFilePath,
title,
);
await removeFolder(temporaryExampleDir);
}
async function combineTemplateWithExample(
exampleDir: string,
temporaryExampleDir: string,
): Promise<void> {
// Copy template files to TEMP folder
await copyFolder(STACKBLITZ_TEMPLATE_PATH, temporaryExampleDir);
// Copy example files to TEMP folder
await copyFolder(exampleDir, temporaryExampleDir);
}
async function generateStackblitzHtml(
temporaryExampleDir: string,
stackBlitzConfig: StackblitzConfig,
exampleFolderName: string,
primaryFilePath: string,
title: string,
): Promise<void> {
const defaultIncludes = [
'**/*.ts',
'**/*.js',
'**/*.css',
'**/*.html',
'**/*.md',
'**/*.json',
'**/*.svg',
];
const exampleFilePaths = await glob(defaultIncludes, {
cwd: temporaryExampleDir,
nodir: true,
dot: true,
ignore: stackBlitzConfig.ignore,
});
const postData = await createPostData(
temporaryExampleDir,
stackBlitzConfig,
exampleFilePaths,
title,
);
const primaryFile = getPrimaryFile(primaryFilePath ?? stackBlitzConfig.file, exampleFilePaths);
const html = createStackblitzHtml(postData, primaryFile);
const stackblitzHtmlPath = join(
join(ASSETS_EXAMPLE_PATH, exampleFolderName),
`${primaryFile}.html`,
);
await createFolder(dirname(stackblitzHtmlPath));
await writeFile(stackblitzHtmlPath, html, 'utf-8');
}
function getPrimaryFile(primaryFilePath: string, exampleFilePaths: string[]): string {
if (primaryFilePath) {
if (!exampleFilePaths.some((filePath) => filePath === primaryFilePath)) {
throw new Error(`The specified primary file (${primaryFilePath}) does not exist!`);
}
return primaryFilePath;
} else {
const defaultPrimaryFilePaths = [
'src/app/app.component.html',
'src/app/app.component.ts',
'src/app/main.ts',
];
const primaryFile = defaultPrimaryFilePaths.find((path) =>
exampleFilePaths.some((filePath) => filePath === path),
);
if (!primaryFile) {
throw new Error(
`None of the default primary files (${defaultPrimaryFilePaths.join(', ')}) exists.`,
);
}
return primaryFile;
}
}
async function createPostData(
exampleDir: string,
config: StackblitzConfig,
exampleFilePaths: string[],
title: string,
): Promise<Record<string, string>> {
const postData: Record<string, string> = {};
for (const filePath of exampleFilePaths) {
if (EXCLUDE_FILES_FOR_STACKBLITZ.some((excludedFile) => filePath.endsWith(excludedFile))) {
continue;
}
let content = await readFile(join(exampleDir, filePath), 'utf-8');
content = appendCopyright(filePath, content);
content = extractRegions(filePath, content);
postData[`project[files][${filePath}]`] = content;
}
const tags = ['angular', 'example', ...(config.tags || [])];
tags.forEach((tag, index) => (postData[`project[tags][${index}]`] = tag));
postData['project[description]'] = `Angular Example - ${config.description}`;
postData['project[template]'] = 'node';
postData['project[title]'] = title ?? 'Angular Example';
return postData;
}
function createStackblitzHtml(postData: Record<string, string>, primaryFile: string): string {
const baseHtml = createBaseStackblitzHtml(primaryFile);
const doc = new jsdom.JSDOM(baseHtml).window.document;
const form = doc.querySelector('form');
for (const [key, value] of Object.entries(postData)) {
const element = htmlToElement(doc, `<input type="hidden" name="${key}">`);
if (element && form) {
element.setAttribute('value', value as string);
form.appendChild(element);
}
}
return doc.documentElement.outerHTML;
}
function createBaseStackblitzHtml(primaryFile: string) {
const file = `?file=${primaryFile}`;
const action = `https://stackblitz.com/run${file}`;
return `
<!DOCTYPE html><html lang="en"><body>
<form id="mainForm" method="post" action="${action}" target="_self"></form>
<script>
var embedded = 'ctl=1';
var isEmbedded = window.location.search.indexOf(embedded) > -1;
if (isEmbedded) {
var form = document.getElementById('mainForm');
var action = form.action;
var actionHasParams = action.indexOf('?') > -1;
var symbol = actionHasParams ? '&' : '?'
form.action = form.action + symbol + embedded;
}
document.getElementById("mainForm").submit();
</script>
</body></html>
`.trim();
}
function appendCopyright(filename: string, content: string): string {
if (filename.endsWith('.html')) {
return `${HTML_COPYRIGHT}${content}`;
} else if (filename.endsWith('.ts') || filename.endsWith('.css')) {
return `${CSS_TS_COPYRIGHT}${content}`;
}
return content;
}
function htmlToElement(document: Document, html: string) {
const div = document.createElement('div');
div.innerHTML = html;
return div.firstElementChild;
}
function extractRegions(path: string, contents: string): string {
const regionParserResult = regionParser(contents, path);
return regionParserResult.contents;
}
+8
View File
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"ts-node": {
"compilerOptions": {
"module": "es2020"
}
}
}
@@ -0,0 +1,55 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {dirname, join} from 'path';
import {fileURLToPath} from 'url';
const BASE = dirname(fileURLToPath(import.meta.url));
// Directory paths
export const ASSETS_EXAMPLE_PATH = join(
BASE,
'../../../src/assets/content/examples',
);
export const EXAMPLES_PATH = join(BASE, '../../../src/content/examples');
export const STACKBLITZ_TEMPLATE_PATH = join(
BASE,
'../../../src/content/stackblitz-template',
);
export const TEMPORARY_EXAMPLES_PATH = join(fileURLToPath(import.meta.url), '../../../../TEMP');
// Extensions
export const TEST_FILES_EXTENSION_SUFFIX = '.spec.ts';
export const TEST_FILES_E2E_EXTENSION_SUFFIX = '.e2e-spec.ts';
// Filename
// TODO: BUILD.bazel and example-config will be deprecated when migration to standalone examples will be done.
export const BUILD_BAZEL_FILENAME = 'BUILD.bazel';
export const EXAMPLE_CONFIG_FILENAME = 'example-config.json';
export const STACKBLITZ_CONFIG_FILENAME = 'stackblitz.json';
// Copyright
const PAD = '\n\n';
const COPYRIGHT =
'@license\n' +
'Copyright Google LLC All Rights Reserved.\n' +
'\n' +
'Use of this source code is governed by an MIT-style license that can be\n' +
'found in the LICENSE file at https://angular.dev/license\n';
export const CSS_TS_COPYRIGHT = `/*\n${COPYRIGHT}\n*/${PAD}`;
export const HTML_COPYRIGHT = `<!-- \n${COPYRIGHT}\n-->${PAD}`;
// Exclude
export const EXCLUDE_FILES_FOR_STACKBLITZ = [
STACKBLITZ_CONFIG_FILENAME,
BUILD_BAZEL_FILENAME,
EXAMPLE_CONFIG_FILENAME,
TEST_FILES_EXTENSION_SUFFIX,
TEST_FILES_E2E_EXTENSION_SUFFIX,
];
+77
View File
@@ -0,0 +1,77 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {Dirent, existsSync, readdirSync} from 'fs';
import {copyFile, mkdir, readFile, readdir, rm, stat} from 'fs/promises';
import {join, relative} from 'path';
export async function copyFolder(source: string, destination: string) {
if (!existsSync(destination)) {
await mkdir(destination, {recursive: true});
}
const files = await readdir(source);
for (const file of files) {
const sourcePath = join(source, file);
const destPath = join(destination, file);
const stats = await stat(sourcePath);
const isDirectory = await stats.isDirectory();
if (isDirectory) {
await copyFolder(sourcePath, destPath);
} else {
await copyFile(sourcePath, destPath);
}
}
}
/** Recursively search the provided directory for all files which satisfy predicate and asynchronously load them. */
export function retrieveFiles(
baseDir: string,
predicate?: (file: Dirent) => boolean,
): Promise<{path: string; content: string}[]> {
const filesWithContent: Promise<{path: string; content: string}>[] = [];
const checkFilesInDirectory = (dir: string) => {
const files = readdirSync(dir, {withFileTypes: true});
for (const file of files) {
const fullPathToFile = join(dir, file.name);
if (file.isFile() && (predicate ? predicate(file) : true)) {
filesWithContent.push(
readFile(fullPathToFile, {encoding: 'utf-8'}).then((fileContent) => {
return {
path: relative(baseDir, fullPathToFile),
content: fileContent,
};
}),
);
} else if (file.isDirectory()) {
checkFilesInDirectory(fullPathToFile);
}
}
};
checkFilesInDirectory(baseDir);
return Promise.all(filesWithContent);
}
export async function createFolder(path: string): Promise<void> {
if (!existsSync(path)) {
await mkdir(path, {recursive: true});
}
}
export async function removeFolder(path: string): Promise<void> {
if (existsSync(path)) {
await rm(path, {recursive: true});
}
}
-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'] = `ADEV_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);
});
-49
View File
@@ -1,49 +0,0 @@
load("//tools:defaults.bzl", "ng_module", "ng_package")
package(default_visibility = ["//visibility:private"])
ng_module(
name = "docs",
srcs = [
"index.ts",
],
module_name = "@angular/docs",
deps = [
"//adev/shared-docs/components",
"//adev/shared-docs/constants",
"//adev/shared-docs/directives",
"//adev/shared-docs/interfaces",
"//adev/shared-docs/pipes",
"//adev/shared-docs/providers",
"//adev/shared-docs/services",
"//adev/shared-docs/testing",
"//adev/shared-docs/utils",
],
)
ng_package(
name = "npm_package",
srcs = [
"package.json",
"//adev/shared-docs/icons",
"//adev/shared-docs/pipeline:BUILD.bazel",
"//adev/shared-docs/pipeline:_guides.bzl",
"//adev/shared-docs/pipeline:_playground.bzl",
"//adev/shared-docs/pipeline:_stackblitz.bzl",
"//adev/shared-docs/pipeline:_tutorial.bzl",
"//adev/shared-docs/pipeline:guides.mjs",
"//adev/shared-docs/pipeline:guides-no-mermaid.mjs",
"//adev/shared-docs/pipeline:playground.mjs",
"//adev/shared-docs/pipeline:stackblitz.mjs",
"//adev/shared-docs/pipeline:tutorial.mjs",
"//adev/shared-docs/pipeline/examples/template:files",
"//adev/shared-docs/pipeline/tutorials/common:files",
"//adev/shared-docs/styles",
],
visibility = [
"//adev:__pkg__",
],
deps = [
":docs",
],
)
-28
View File
@@ -1,28 +0,0 @@
load("//tools:defaults.bzl", "ts_library")
package(default_visibility = ["//visibility:private"])
ts_library(
name = "components",
srcs = [
"index.ts",
],
visibility = [
"//adev/shared-docs:__pkg__",
],
deps = [
"//adev/shared-docs/components/algolia-icon",
"//adev/shared-docs/components/breadcrumb",
"//adev/shared-docs/components/cookie-popup",
"//adev/shared-docs/components/copy-source-code-button",
"//adev/shared-docs/components/icon",
"//adev/shared-docs/components/navigation-list",
"//adev/shared-docs/components/search-dialog",
"//adev/shared-docs/components/select",
"//adev/shared-docs/components/slide-toggle",
"//adev/shared-docs/components/table-of-contents",
"//adev/shared-docs/components/text-field",
"//adev/shared-docs/components/top-level-banner",
"//adev/shared-docs/components/viewers",
],
)
@@ -1,20 +0,0 @@
load("//tools:defaults.bzl", "ng_module")
package(default_visibility = ["//visibility:private"])
ng_module(
name = "algolia-icon",
srcs = [
"algolia-icon.component.ts",
],
assets = [
"algolia-icon.component.html",
],
visibility = [
"//adev/shared-docs/components:__pkg__",
"//adev/shared-docs/components/search-dialog:__pkg__",
],
deps = [
"//packages/core",
],
)
@@ -1,52 +0,0 @@
<!-- Algolia logo -->
<svg
id="Layer_1"
class="docs-algolia-logo"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 2196.2 500"
>
<defs>
<style>
.cls-1,
.cls-2 {
fill: #003dff;
}
.cls-2 {
fill-rule: evenodd;
}
</style>
</defs>
<path
class="cls-2"
d="M1070.38,275.3V5.91c0-3.63-3.24-6.39-6.82-5.83l-50.46,7.94c-2.87,.45-4.99,2.93-4.99,5.84l.17,273.22c0,12.92,0,92.7,95.97,95.49,3.33,.1,6.09-2.58,6.09-5.91v-40.78c0-2.96-2.19-5.51-5.12-5.84-34.85-4.01-34.85-47.57-34.85-54.72Z"
/>
<rect class="cls-1" x="1845.88" y="104.73" width="62.58" height="277.9" rx="5.9" ry="5.9" />
<path
class="cls-2"
d="M1851.78,71.38h50.77c3.26,0,5.9-2.64,5.9-5.9V5.9c0-3.62-3.24-6.39-6.82-5.83l-50.77,7.95c-2.87,.45-4.99,2.92-4.99,5.83v51.62c0,3.26,2.64,5.9,5.9,5.9Z"
/>
<path
class="cls-2"
d="M1764.03,275.3V5.91c0-3.63-3.24-6.39-6.82-5.83l-50.46,7.94c-2.87,.45-4.99,2.93-4.99,5.84l.17,273.22c0,12.92,0,92.7,95.97,95.49,3.33,.1,6.09-2.58,6.09-5.91v-40.78c0-2.96-2.19-5.51-5.12-5.84-34.85-4.01-34.85-47.57-34.85-54.72Z"
/>
<path
class="cls-2"
d="M1631.95,142.72c-11.14-12.25-24.83-21.65-40.78-28.31-15.92-6.53-33.26-9.85-52.07-9.85-18.78,0-36.15,3.17-51.92,9.85-15.59,6.66-29.29,16.05-40.76,28.31-11.47,12.23-20.38,26.87-26.76,44.03-6.38,17.17-9.24,37.37-9.24,58.36,0,20.99,3.19,36.87,9.55,54.21,6.38,17.32,15.14,32.11,26.45,44.36,11.29,12.23,24.83,21.62,40.6,28.46,15.77,6.83,40.12,10.33,52.4,10.48,12.25,0,36.78-3.82,52.7-10.48,15.92-6.68,29.46-16.23,40.78-28.46,11.29-12.25,20.05-27.04,26.25-44.36,6.22-17.34,9.24-33.22,9.24-54.21,0-20.99-3.34-41.19-10.03-58.36-6.38-17.17-15.14-31.8-26.43-44.03Zm-44.43,163.75c-11.47,15.75-27.56,23.7-48.09,23.7-20.55,0-36.63-7.8-48.1-23.7-11.47-15.75-17.21-34.01-17.21-61.2,0-26.89,5.59-49.14,17.06-64.87,11.45-15.75,27.54-23.52,48.07-23.52,20.55,0,36.63,7.78,48.09,23.52,11.47,15.57,17.36,37.98,17.36,64.87,0,27.19-5.72,45.3-17.19,61.2Z"
/>
<path
class="cls-2"
d="M894.42,104.73h-49.33c-48.36,0-90.91,25.48-115.75,64.1-14.52,22.58-22.99,49.63-22.99,78.73,0,44.89,20.13,84.92,51.59,111.1,2.93,2.6,6.05,4.98,9.31,7.14,12.86,8.49,28.11,13.47,44.52,13.47,1.23,0,2.46-.03,3.68-.09,.36-.02,.71-.05,1.07-.07,.87-.05,1.75-.11,2.62-.2,.34-.03,.68-.08,1.02-.12,.91-.1,1.82-.21,2.73-.34,.21-.03,.42-.07,.63-.1,32.89-5.07,61.56-30.82,70.9-62.81v57.83c0,3.26,2.64,5.9,5.9,5.9h50.42c3.26,0,5.9-2.64,5.9-5.9V110.63c0-3.26-2.64-5.9-5.9-5.9h-56.32Zm0,206.92c-12.2,10.16-27.97,13.98-44.84,15.12-.16,.01-.33,.03-.49,.04-1.12,.07-2.24,.1-3.36,.1-42.24,0-77.12-35.89-77.12-79.37,0-10.25,1.96-20.01,5.42-28.98,11.22-29.12,38.77-49.74,71.06-49.74h49.33v142.83Z"
/>
<path
class="cls-2"
d="M2133.97,104.73h-49.33c-48.36,0-90.91,25.48-115.75,64.1-14.52,22.58-22.99,49.63-22.99,78.73,0,44.89,20.13,84.92,51.59,111.1,2.93,2.6,6.05,4.98,9.31,7.14,12.86,8.49,28.11,13.47,44.52,13.47,1.23,0,2.46-.03,3.68-.09,.36-.02,.71-.05,1.07-.07,.87-.05,1.75-.11,2.62-.2,.34-.03,.68-.08,1.02-.12,.91-.1,1.82-.21,2.73-.34,.21-.03,.42-.07,.63-.1,32.89-5.07,61.56-30.82,70.9-62.81v57.83c0,3.26,2.64,5.9,5.9,5.9h50.42c3.26,0,5.9-2.64,5.9-5.9V110.63c0-3.26-2.64-5.9-5.9-5.9h-56.32Zm0,206.92c-12.2,10.16-27.97,13.98-44.84,15.12-.16,.01-.33,.03-.49,.04-1.12,.07-2.24,.1-3.36,.1-42.24,0-77.12-35.89-77.12-79.37,0-10.25,1.96-20.01,5.42-28.98,11.22-29.12,38.77-49.74,71.06-49.74h49.33v142.83Z"
/>
<path
class="cls-2"
d="M1314.05,104.73h-49.33c-48.36,0-90.91,25.48-115.75,64.1-11.79,18.34-19.6,39.64-22.11,62.59-.58,5.3-.88,10.68-.88,16.14s.31,11.15,.93,16.59c4.28,38.09,23.14,71.61,50.66,94.52,2.93,2.6,6.05,4.98,9.31,7.14,12.86,8.49,28.11,13.47,44.52,13.47h0c17.99,0,34.61-5.93,48.16-15.97,16.29-11.58,28.88-28.54,34.48-47.75v50.26h-.11v11.08c0,21.84-5.71,38.27-17.34,49.36-11.61,11.08-31.04,16.63-58.25,16.63-11.12,0-28.79-.59-46.6-2.41-2.83-.29-5.46,1.5-6.27,4.22l-12.78,43.11c-1.02,3.46,1.27,7.02,4.83,7.53,21.52,3.08,42.52,4.68,54.65,4.68,48.91,0,85.16-10.75,108.89-32.21,21.48-19.41,33.15-48.89,35.2-88.52V110.63c0-3.26-2.64-5.9-5.9-5.9h-56.32Zm0,64.1s.65,139.13,0,143.36c-12.08,9.77-27.11,13.59-43.49,14.7-.16,.01-.33,.03-.49,.04-1.12,.07-2.24,.1-3.36,.1-1.32,0-2.63-.03-3.94-.1-40.41-2.11-74.52-37.26-74.52-79.38,0-10.25,1.96-20.01,5.42-28.98,11.22-29.12,38.77-49.74,71.06-49.74h49.33Z"
/>
<path
class="cls-1"
d="M249.83,0C113.3,0,2,110.09,.03,246.16c-2,138.19,110.12,252.7,248.33,253.5,42.68,.25,83.79-10.19,120.3-30.03,3.56-1.93,4.11-6.83,1.08-9.51l-23.38-20.72c-4.75-4.21-11.51-5.4-17.36-2.92-25.48,10.84-53.17,16.38-81.71,16.03-111.68-1.37-201.91-94.29-200.13-205.96,1.76-110.26,92-199.41,202.67-199.41h202.69V407.41l-115-102.18c-3.72-3.31-9.42-2.66-12.42,1.31-18.46,24.44-48.53,39.64-81.93,37.34-46.33-3.2-83.87-40.5-87.34-86.81-4.15-55.24,39.63-101.52,94-101.52,49.18,0,89.68,37.85,93.91,85.95,.38,4.28,2.31,8.27,5.52,11.12l29.95,26.55c3.4,3.01,8.79,1.17,9.63-3.3,2.16-11.55,2.92-23.58,2.07-35.92-4.82-70.34-61.8-126.93-132.17-131.26-80.68-4.97-148.13,58.14-150.27,137.25-2.09,77.1,61.08,143.56,138.19,145.26,32.19,.71,62.03-9.41,86.14-26.95l150.26,133.2c6.44,5.71,16.61,1.14,16.61-7.47V9.48C499.66,4.25,495.42,0,490.18,0H249.83Z"
/>
</svg>

Before

Width:  |  Height:  |  Size: 5.0 KiB

@@ -1,18 +0,0 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {ChangeDetectionStrategy, Component} from '@angular/core';
@Component({
selector: 'docs-algolia-icon',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [],
templateUrl: './algolia-icon.component.html',
})
export class AlgoliaIcon {}
@@ -1,54 +0,0 @@
load("//tools:defaults.bzl", "karma_web_test_suite", "ng_module", "ts_library")
load("@io_bazel_rules_sass//:defs.bzl", "sass_binary")
package(default_visibility = ["//visibility:private"])
ng_module(
name = "breadcrumb",
srcs = [
"breadcrumb.component.ts",
],
assets = [
":breadcrumb.component.css",
"breadcrumb.component.html",
],
visibility = [
"//adev/shared-docs/components:__pkg__",
"//adev/shared-docs/components/viewers:__pkg__",
],
deps = [
"//adev/shared-docs/interfaces",
"//adev/shared-docs/services",
"//packages/common",
"//packages/core",
"//packages/router",
],
)
sass_binary(
name = "style",
src = "breadcrumb.component.scss",
)
ts_library(
name = "test_lib",
testonly = True,
srcs = glob(
["*.spec.ts"],
),
deps = [
":breadcrumb",
"//adev/shared-docs/interfaces",
"//adev/shared-docs/services",
"//packages/core",
"//packages/core/testing",
"//packages/platform-browser",
"//packages/router",
"//packages/router/testing",
],
)
karma_web_test_suite(
name = "test",
deps = [":test_lib"],
)
@@ -1,13 +0,0 @@
@for (breadcrumb of breadcrumbItems(); track breadcrumb) {
<div class="docs-breadcrumb">
@if (breadcrumb.path) {
@if (breadcrumb.isExternal) {
<a [href]="breadcrumb.path">{{ breadcrumb.label }}</a>
} @else {
<a [routerLink]="'/' + breadcrumb.path">{{ breadcrumb.label }}</a>
}
} @else {
<span>{{ breadcrumb.label }}</span>
}
</div>
}
@@ -1,25 +0,0 @@
:host {
display: flex;
align-items: center;
padding-block-end: 1.5rem;
}
.docs-breadcrumb {
span {
color: var(--quaternary-contrast);
font-size: 0.875rem;
display: flex;
align-items: center;
}
&:not(:last-child) {
span {
&::after {
content: 'chevron_right';
font-family: var(--icons);
margin-inline: 0.5rem;
color: var(--quinary-contrast);
}
}
}
}
@@ -1,83 +0,0 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {Breadcrumb} from './breadcrumb.component';
import {NavigationState} from '../../services';
import {NavigationItem} from '../../interfaces';
import {By} from '@angular/platform-browser';
import {RouterTestingModule} from '@angular/router/testing';
import {provideExperimentalZonelessChangeDetection} from '@angular/core';
describe('Breadcrumb', () => {
let fixture: ComponentFixture<Breadcrumb>;
let navigationStateSpy: jasmine.SpyObj<NavigationState>;
beforeEach(() => {
navigationStateSpy = jasmine.createSpyObj('NavigationState', ['activeNavigationItem']);
TestBed.configureTestingModule({
imports: [Breadcrumb, RouterTestingModule],
providers: [
provideExperimentalZonelessChangeDetection(),
{
provide: NavigationState,
useValue: navigationStateSpy,
},
],
});
fixture = TestBed.createComponent(Breadcrumb);
});
it('should display proper breadcrumb structure based on navigation state', () => {
navigationStateSpy.activeNavigationItem.and.returnValue(item);
fixture.detectChanges();
const breadcrumbs = fixture.debugElement.queryAll(By.css('.docs-breadcrumb span'));
expect(breadcrumbs.length).toBe(2);
expect(breadcrumbs[0].nativeElement.innerText).toEqual('Grandparent');
expect(breadcrumbs[1].nativeElement.innerText).toEqual('Parent');
});
it('should display breadcrumb links when navigation item has got path', () => {
navigationStateSpy.activeNavigationItem.and.returnValue(exampleItemWithPath);
fixture.detectChanges();
const breadcrumbs = fixture.debugElement.queryAll(By.css('.docs-breadcrumb a'));
expect(breadcrumbs.length).toBe(1);
expect(breadcrumbs[0].nativeElement.innerText).toEqual('Parent');
expect(breadcrumbs[0].nativeElement.href).toEqual(`${window.origin}/example`);
});
});
const grandparent: NavigationItem = {
label: 'Grandparent',
};
const parent: NavigationItem = {
label: 'Parent',
parent: grandparent,
};
const item: NavigationItem = {
label: 'Active Item',
parent: parent,
};
const parentWithPath: NavigationItem = {
label: 'Parent',
path: '/example',
};
const exampleItemWithPath: NavigationItem = {
label: 'Active Item',
parent: parentWithPath,
};
@@ -1,49 +0,0 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {ChangeDetectionStrategy, Component, OnInit, inject, signal} from '@angular/core';
import {NavigationState} from '../../services/index';
import {NavigationItem} from '../../interfaces/index';
import {RouterLink} from '@angular/router';
@Component({
selector: 'docs-breadcrumb',
standalone: true,
imports: [RouterLink],
templateUrl: './breadcrumb.component.html',
styleUrls: ['./breadcrumb.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class Breadcrumb implements OnInit {
private readonly navigationState = inject(NavigationState);
breadcrumbItems = signal<NavigationItem[]>([]);
ngOnInit(): void {
this.setBreadcrumbItemsBasedOnNavigationStructure();
}
private setBreadcrumbItemsBasedOnNavigationStructure(): void {
let breadcrumbs: NavigationItem[] = [];
const traverse = (node: NavigationItem | null) => {
if (!node) {
return;
}
if (node.parent) {
breadcrumbs = [node.parent, ...breadcrumbs];
traverse(node.parent);
}
};
traverse(this.navigationState.activeNavigationItem());
this.breadcrumbItems.set(breadcrumbs);
}
}
@@ -1,49 +0,0 @@
load("//tools:defaults.bzl", "karma_web_test_suite", "ng_module", "ts_library")
load("@io_bazel_rules_sass//:defs.bzl", "sass_binary")
package(default_visibility = ["//visibility:private"])
ng_module(
name = "cookie-popup",
srcs = [
"cookie-popup.component.ts",
],
assets = [
":cookie-popup.component.css",
"cookie-popup.component.html",
],
visibility = [
"//adev/shared-docs/components:__pkg__",
],
deps = [
"//adev/shared-docs/providers",
"//adev/shared-docs/utils",
"//packages/common",
"//packages/core",
],
)
sass_binary(
name = "style",
src = "cookie-popup.component.scss",
)
ts_library(
name = "test_lib",
testonly = True,
srcs = glob(
["*.spec.ts"],
),
deps = [
":cookie-popup",
"//adev/shared-docs/providers",
"//adev/shared-docs/testing",
"//packages/core",
"//packages/core/testing",
],
)
karma_web_test_suite(
name = "test",
deps = [":test_lib"],
)
@@ -1,22 +0,0 @@
@if (!hasAccepted()) {
<div class="docs-cookies-popup docs-invert-mode">
<p>This site uses cookies from Google to deliver its services and to analyze traffic.</p>
<div>
<a href="https://policies.google.com/technologies/cookies" target="_blank" rel="noopener">
<button class="docs-primary-btn" [attr.text]="'Learn more'" aria-label="Learn More">
Learn more
</button>
</a>
<button
type="button"
(click)="accept()"
class="docs-primary-btn"
[attr.text]="'Ok, Got it'"
aria-label="Ok, Got it"
>
Ok, Got it
</button>
</div>
</div>
}
@@ -1,40 +0,0 @@
:host {
position: fixed;
bottom: 0.5rem;
right: 0.5rem;
z-index: var(--z-index-cookie-consent);
opacity: 0;
visibility: hidden;
animation: 1s linear forwards 0.5s fadeIn;
}
.docs-cookies-popup {
padding: 1rem;
background-color: var(--page-background);
border: 1px solid var(--senary-contrast);
border-radius: 0.25rem;
font-size: 0.875rem;
max-width: 265px;
transition: background-color 0.3s ease, border-color 0.3s ease, color 0.3s ease;
box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.1);
> div {
display: flex;
gap: 0.5rem;
align-items: center;
width: 100%;
margin-block-start: 1rem;
}
p {
margin-block: 0;
color: var(--primary-contrast);
}
}
@keyframes fadeIn {
100% {
opacity: 100%;
visibility: visible;
}
}
@@ -1,82 +0,0 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {CookiePopup, STORAGE_KEY} from './cookie-popup.component';
import {LOCAL_STORAGE} from '../../providers/index';
import {MockLocalStorage} from '../../testing/index';
import {provideExperimentalZonelessChangeDetection} from '@angular/core';
describe('CookiePopup', () => {
let fixture: ComponentFixture<CookiePopup>;
let mockLocalStorage = new MockLocalStorage();
beforeEach(() => {
TestBed.configureTestingModule({
imports: [CookiePopup],
providers: [
provideExperimentalZonelessChangeDetection(),
{
provide: LOCAL_STORAGE,
useValue: mockLocalStorage,
},
],
});
});
it('should make the popup visible by default', () => {
initComponent(false);
expect(getCookiesPopup()).not.toBeNull();
});
it('should hide the cookies popup if the user has already accepted cookies', () => {
initComponent(true);
expect(getCookiesPopup()).toBeNull();
});
it('should hide the cookies popup', () => {
initComponent(false);
accept();
fixture.detectChanges();
expect(getCookiesPopup()).toBeNull();
});
it('should store the user confirmation', () => {
initComponent(false);
expect(mockLocalStorage.getItem(STORAGE_KEY)).toBeNull();
accept();
expect(mockLocalStorage.getItem(STORAGE_KEY)).toBe('true');
});
// Helpers
function getCookiesPopup() {
return (fixture.nativeElement as HTMLElement).querySelector('.docs-cookies-popup');
}
function accept() {
(fixture.nativeElement as HTMLElement)
.querySelector<HTMLButtonElement>('button[text="Ok, Got it"]')
?.click();
}
function initComponent(cookiesAccepted: boolean) {
mockLocalStorage.setItem(STORAGE_KEY, cookiesAccepted ? 'true' : null);
fixture = TestBed.createComponent(CookiePopup);
fixture.detectChanges();
}
});
@@ -1,54 +0,0 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {ChangeDetectionStrategy, Component, inject, signal} from '@angular/core';
import {LOCAL_STORAGE} from '../../providers/index';
import {setCookieConsent} from '../../utils';
/**
* Decelare gtag as part of the window in this file as gtag is expected to already be loaded.
*/
declare const window: Window & typeof globalThis & {gtag?: Function};
export const STORAGE_KEY = 'docs-accepts-cookies';
@Component({
selector: 'docs-cookie-popup',
standalone: true,
templateUrl: './cookie-popup.component.html',
styleUrls: ['./cookie-popup.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CookiePopup {
private readonly localStorage = inject(LOCAL_STORAGE);
/** Whether the user has accepted the cookie disclaimer. */
hasAccepted = signal<boolean>(false);
constructor() {
// Needs to be in a try/catch, because some browsers will
// throw when using `localStorage` in private mode.
try {
this.hasAccepted.set(this.localStorage?.getItem(STORAGE_KEY) === 'true');
} catch {
this.hasAccepted.set(false);
}
}
/** Accepts the cookie disclaimer. */
protected accept(): void {
try {
this.localStorage?.setItem(STORAGE_KEY, 'true');
} catch {}
this.hasAccepted.set(true);
// Enable Google Analytics consent properties
setCookieConsent('granted');
}
}
@@ -1,43 +0,0 @@
load("//tools:defaults.bzl", "karma_web_test_suite", "ng_module", "ts_library")
package(default_visibility = ["//visibility:private"])
ng_module(
name = "copy-source-code-button",
srcs = [
"copy-source-code-button.component.ts",
],
assets = [
"copy-source-code-button.component.html",
],
visibility = [
"//adev/shared-docs/components:__pkg__",
"//adev/shared-docs/components/viewers:__pkg__",
],
deps = [
"//adev/shared-docs/components/icon",
"//packages/common",
"//packages/core",
"@npm//@angular/cdk",
],
)
ts_library(
name = "test_lib",
testonly = True,
srcs = glob(
["*.spec.ts"],
),
deps = [
":copy-source-code-button",
"//packages/core",
"//packages/core/testing",
"//packages/platform-browser",
"@npm//@angular/cdk",
],
)
karma_web_test_suite(
name = "test",
deps = [":test_lib"],
)
@@ -1,18 +0,0 @@
<i>
<svg
aria-hidden="true"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
class="docs-copy"
>
<path
d="M5 22C4.45 22 3.97917 21.8042 3.5875 21.4125C3.19583 21.0208 3 20.55 3 20V6H5V20H16V22H5ZM9 18C8.45 18 7.97917 17.8042 7.5875 17.4125C7.19583 17.0208 7 16.55 7 16V4C7 3.45 7.19583 2.97917 7.5875 2.5875C7.97917 2.19583 8.45 2 9 2H18C18.55 2 19.0208 2.19583 19.4125 2.5875C19.8042 2.97917 20 3.45 20 4V16C20 16.55 19.8042 17.0208 19.4125 17.4125C19.0208 17.8042 18.55 18 18 18H9ZM9 16H18V4H9V16Z"
fill="#A39FA9"
/>
</svg>
</i>
<docs-icon class="docs-check">check</docs-icon>
@@ -1,127 +0,0 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {ComponentFixture, TestBed, fakeAsync, tick} from '@angular/core/testing';
import {
CONFIRMATION_DISPLAY_TIME_MS,
CopySourceCodeButton,
} from './copy-source-code-button.component';
import {
ChangeDetectionStrategy,
Component,
provideExperimentalZonelessChangeDetection,
signal,
} from '@angular/core';
import {By} from '@angular/platform-browser';
import {Clipboard} from '@angular/cdk/clipboard';
const SUCCESSFULLY_COPY_CLASS_NAME = 'docs-copy-source-code-button-success';
const FAILED_COPY_CLASS_NAME = 'docs-copy-source-code-button-failed';
describe('CopySourceCodeButton', () => {
let component: CodeSnippetWrapper;
let fixture: ComponentFixture<CodeSnippetWrapper>;
let copySpy: jasmine.Spy<(text: string) => boolean>;
beforeEach(async () => {
TestBed.configureTestingModule({
imports: [CodeSnippetWrapper],
providers: [provideExperimentalZonelessChangeDetection()],
});
fixture = TestBed.createComponent(CodeSnippetWrapper);
component = fixture.componentInstance;
await fixture.whenStable();
});
beforeEach(() => {
const clipboardService = TestBed.inject(Clipboard);
copySpy = spyOn(clipboardService, 'copy');
});
it('should call clipboard service when clicked on copy source code', async () => {
const expectedCodeToBeCopied = 'npm install -g @angular/cli';
component.code.set(expectedCodeToBeCopied);
await fixture.whenStable();
const button = fixture.debugElement.query(By.directive(CopySourceCodeButton)).nativeElement;
button.click();
expect(copySpy.calls.argsFor(0)[0].trim()).toBe(expectedCodeToBeCopied);
});
it('should not copy lines marked as deleted when code snippet contains diff', async () => {
const codeInHtmlFormat = `
<code>
<div class="line remove"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> *<span class="hljs-attr">ngFor</span>=<span class="hljs-string">"let product of products"</span>&gt;</span></div>
<div class="line add"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> *<span class="hljs-attr">ngFor</span>=<span class="hljs-string">"let product of products()"</span>&gt;</span></div>
</code>
`;
const expectedCodeToBeCopied = `<div *ngFor="let product of products()">`;
component.code.set(codeInHtmlFormat);
await fixture.whenStable();
const button = fixture.debugElement.query(By.directive(CopySourceCodeButton)).nativeElement;
button.click();
expect(copySpy.calls.argsFor(0)[0].trim()).toBe(expectedCodeToBeCopied);
});
it(`should set ${SUCCESSFULLY_COPY_CLASS_NAME} for ${CONFIRMATION_DISPLAY_TIME_MS} ms when copy was executed properly`, fakeAsync(() => {
component.code.set('example');
fixture.detectChanges();
const button = fixture.debugElement.query(By.directive(CopySourceCodeButton)).nativeElement;
button.click();
fixture.detectChanges();
expect(button).toHaveClass(SUCCESSFULLY_COPY_CLASS_NAME);
tick(CONFIRMATION_DISPLAY_TIME_MS);
fixture.detectChanges();
expect(button).not.toHaveClass(SUCCESSFULLY_COPY_CLASS_NAME);
}));
it(`should set ${FAILED_COPY_CLASS_NAME} for ${CONFIRMATION_DISPLAY_TIME_MS} ms when copy failed`, fakeAsync(() => {
component.code.set('example');
copySpy.and.throwError('Fake copy error');
fixture.detectChanges();
const button = fixture.debugElement.query(By.directive(CopySourceCodeButton)).nativeElement;
button.click();
fixture.detectChanges();
expect(button).toHaveClass(FAILED_COPY_CLASS_NAME);
tick(CONFIRMATION_DISPLAY_TIME_MS);
fixture.detectChanges();
expect(button).not.toHaveClass(FAILED_COPY_CLASS_NAME);
}));
});
@Component({
template: `
<pre>
<code [innerHtml]="code()"></code>
</pre>
<button docs-copy-source-code></button>
`,
imports: [CopySourceCodeButton],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
})
class CodeSnippetWrapper {
code = signal('');
}
@@ -1,89 +0,0 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ElementRef,
WritableSignal,
inject,
signal,
} from '@angular/core';
import {CommonModule} from '@angular/common';
import {Clipboard} from '@angular/cdk/clipboard';
import {IconComponent} from '../icon/icon.component';
export const REMOVED_LINE_CLASS_NAME = '.line.remove';
export const CONFIRMATION_DISPLAY_TIME_MS = 2000;
@Component({
selector: 'button[docs-copy-source-code]',
standalone: true,
imports: [CommonModule, IconComponent],
templateUrl: './copy-source-code-button.component.html',
host: {
'type': 'button',
'aria-label': 'Copy example source to clipboard',
'title': 'Copy example source',
'(click)': 'copySourceCode()',
'[class.docs-copy-source-code-button-success]': 'showCopySuccess()',
'[class.docs-copy-source-code-button-failed]': 'showCopyFailure()',
},
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CopySourceCodeButton {
private readonly changeDetector = inject(ChangeDetectorRef);
private readonly clipboard = inject(Clipboard);
private readonly elementRef = inject(ElementRef);
protected readonly showCopySuccess = signal(false);
protected readonly showCopyFailure = signal(false);
copySourceCode(): void {
try {
const codeElement = this.elementRef.nativeElement.parentElement.querySelector(
'code',
) as HTMLElement;
const sourceCode = this.getSourceCode(codeElement);
this.clipboard.copy(sourceCode);
this.showResult(this.showCopySuccess);
} catch {
this.showResult(this.showCopyFailure);
}
}
private getSourceCode(codeElement: HTMLElement): string {
this.showCopySuccess.set(false);
this.showCopyFailure.set(false);
const removedLines: NodeList = codeElement.querySelectorAll(REMOVED_LINE_CLASS_NAME);
if (removedLines.length) {
// Get only those lines which are not marked as removed
const formattedText = Array.from(codeElement.querySelectorAll('.line:not(.remove)'))
.map((line) => (line as HTMLDivElement).innerText)
.join('\n');
return formattedText.trim();
} else {
const text: string = codeElement.innerText || '';
return text.replace(/\n\n\n/g, ``).trim();
}
}
private showResult(messageState: WritableSignal<boolean>) {
messageState.set(true);
setTimeout(() => {
messageState.set(false);
// It's required for code snippets embedded in the ExampleViewer.
this.changeDetector.markForCheck();
}, CONFIRMATION_DISPLAY_TIME_MS);
}
}
@@ -1,33 +0,0 @@
load("//tools:defaults.bzl", "ng_module")
load("@io_bazel_rules_sass//:defs.bzl", "sass_binary")
package(default_visibility = ["//visibility:private"])
ng_module(
name = "icon",
srcs = [
"icon.component.ts",
],
assets = [
":icon.component.css",
"icon.component.html",
],
visibility = [
"//adev/shared-docs/components:__pkg__",
"//adev/shared-docs/components/copy-source-code-button:__pkg__",
"//adev/shared-docs/components/navigation-list:__pkg__",
"//adev/shared-docs/components/table-of-contents:__pkg__",
"//adev/shared-docs/components/text-field:__pkg__",
"//adev/shared-docs/components/top-level-banner:__pkg__",
"//adev/shared-docs/components/viewers:__pkg__",
],
deps = [
"//packages/common",
"//packages/core",
],
)
sass_binary(
name = "style",
src = "icon.component.scss",
)
@@ -1 +0,0 @@
<ng-content></ng-content>
@@ -1,3 +0,0 @@
.docs-icon_high-contrast {
color: var(--primary-contrast);
}
@@ -1,55 +0,0 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {DOCUMENT} from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
afterNextRender,
computed,
inject,
signal,
} from '@angular/core';
@Component({
selector: 'docs-icon',
standalone: true,
templateUrl: './icon.component.html',
styleUrl: './icon.component.scss',
host: {
'[class]': 'MATERIAL_SYMBOLS_OUTLINED',
'[style.font-size.px]': 'fontSize()',
'aria-hidden': 'true',
'translate': 'no',
},
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class IconComponent {
fontSize = computed(() => {
return IconComponent.isFontLoaded() ? null : 0;
});
protected readonly MATERIAL_SYMBOLS_OUTLINED = 'material-symbols-outlined';
private static isFontLoaded = signal(false);
/** Share the same promise across different instances of the component */
private static whenFontLoad?: Promise<FontFace[]> | undefined;
constructor() {
if (IconComponent.isFontLoaded()) {
return;
}
const document = inject(DOCUMENT);
afterNextRender(async () => {
IconComponent.whenFontLoad ??= document.fonts.load('normal 1px "Material Symbols Outlined"');
await IconComponent.whenFontLoad;
IconComponent.isFontLoaded.set(true);
});
}
}
-18
View File
@@ -1,18 +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 * from './viewers/docs-viewer/docs-viewer.component';
export * from './cookie-popup/cookie-popup.component';
export * from './navigation-list/navigation-list.component';
export * from './select/select.component';
export * from './slide-toggle/slide-toggle.component';
export * from './table-of-contents/table-of-contents.component';
export * from './text-field/text-field.component';
export * from './icon/icon.component';
export * from './search-dialog/search-dialog.component';
export * from './top-level-banner/top-level-banner.component';
@@ -1,58 +0,0 @@
load("//tools:defaults.bzl", "karma_web_test_suite", "ng_module", "ts_library")
load("@io_bazel_rules_sass//:defs.bzl", "sass_binary")
package(default_visibility = ["//visibility:private"])
ng_module(
name = "navigation-list",
srcs = [
"navigation-list.component.ts",
],
assets = [
":navigation-list.component.css",
"navigation-list.component.html",
],
visibility = [
"//adev/shared-docs/components:__pkg__",
],
deps = [
"//adev/shared-docs/components/icon",
"//adev/shared-docs/interfaces",
"//adev/shared-docs/pipes",
"//adev/shared-docs/services",
"//packages/common",
"//packages/core",
"//packages/router",
],
)
sass_binary(
name = "style",
src = "navigation-list.component.scss",
deps = [
"//adev/shared-docs/styles",
],
)
ts_library(
name = "test_lib",
testonly = True,
srcs = glob(
["*.spec.ts"],
),
deps = [
":navigation-list",
"//adev/shared-docs/interfaces",
"//adev/shared-docs/services",
"//packages/core",
"//packages/core/testing",
"//packages/platform-browser",
"//packages/router",
"//packages/router/testing",
],
)
karma_web_test_suite(
name = "test",
deps = [":test_lib"],
)

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