diff --git a/.bazelrc b/.bazelrc index 872b401b8af9..60c7b1d54ad7 100644 --- a/.bazelrc +++ b/.bazelrc @@ -92,7 +92,7 @@ test --test_output=errors ################################ # Use the Angular team internal GCP instance for remote execution. -build:remote --remote_instance_name=projects/internal-200822/instances/default_instance +build:remote --remote_instance_name=projects/internal-200822/instances/primary_instance build:remote --project_id=internal-200822 # Starting with Bazel 0.27.0 strategies do not need to be explicitly @@ -105,20 +105,15 @@ build:remote --remote_executor=remotebuildexecution.googleapis.com build:remote --remote_timeout=600 build:remote --jobs=150 - # Setup the toolchain and platform for the remote build execution. The platform -# is automatically configured by the "rbe_autoconfig" rule in the project workpsace. -build:remote --host_javabase=@rbe_ubuntu1604_angular//java:jdk -build:remote --javabase=@rbe_ubuntu1604_angular//java:jdk -build:remote --host_java_toolchain=@bazel_tools//tools/jdk:toolchain_hostjdk8 -build:remote --java_toolchain=@bazel_tools//tools/jdk:toolchain_hostjdk8 -build:remote --crosstool_top=@rbe_ubuntu1604_angular//cc:toolchain -build:remote --action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1 -build:remote --extra_toolchains=@rbe_ubuntu1604_angular//config:cc-toolchain -build:remote --extra_execution_platforms=//tools:rbe_ubuntu1604-angular -build:remote --host_platform=//tools:rbe_ubuntu1604-angular -build:remote --platforms=//tools:rbe_ubuntu1604-angular - - # Set remote caching settings +# Setup the toolchain and platform for the remote build execution. The platform +# is provided by the shared dev-infra package and targets k8 remote containers. +build:remote --crosstool_top=@npm//@angular/dev-infra-private/bazel/remote-execution/cpp:cc_toolchain_suite +build:remote --extra_toolchains=@npm//@angular/dev-infra-private/bazel/remote-execution/cpp:cc_toolchain +build:remote --extra_execution_platforms=//tools:rbe_platform_with_network_access +build:remote --host_platform=//tools:rbe_platform_with_network_access +build:remote --platforms=//tools:rbe_platform_with_network_access + +# Set remote caching settings build:remote --remote_accept_cached=true # Force remote executions to consider the entire run as linux. diff --git a/.bazelversion b/.bazelversion index 54f6b9be19dc..fcdb2e109f68 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1,3 +1 @@ 4.0.0 -# [NB: this comment has to be after the first line, see https://github.com/bazelbuild/bazelisk/issues/117] -# When updating the Bazel version you also need to update the RBE toolchains version in WORKSPACE diff --git a/.circleci/config.yml b/.circleci/config.yml index bcab988200a5..125a8bd7f81b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,7 +10,7 @@ version: 2.1 orbs: - browser-tools: circleci/browser-tools@1.0.1 + browser-tools: circleci/browser-tools@1.1.3 # Variables @@ -29,6 +29,8 @@ var_5: &only_release_branches filters: branches: only: + - main + # TODO(BRANCH_RENAME_CLEANUP): remove - master - /\d+\.\d+\.x/ @@ -68,6 +70,14 @@ executors: # Command Definitions # https://circleci.com/docs/2.0/reusing-config/#authoring-reusable-commands commands: + fail_fast: + steps: + - run: + name: 'Cancel workflow on fail' + when: on_fail + command: | + curl -X POST --header "Content-Type: application/json" "https://circleci.com/api/v2/workflow/${CIRCLE_WORKFLOW_ID}/cancel?circle-token=${CIRCLE_TOKEN}" + custom_attach_workspace: description: Attach workspace at a predefined location steps: @@ -97,7 +107,7 @@ commands: openssl aes-256-cbc -d -in .circleci/gcp_token -md md5 -k "${<< parameters.key >>}" -out /home/circleci/.gcp_credentials; sudo bash -c "echo -e 'build --google_credentials=/home/circleci/.gcp_credentials' >> .bazelrc.user"; # Upload/don't upload local results to cache based on environment - if [[ -n "{$CIRCLE_PR_NUMBER}" ]]; then + if [[ -n "{$CIRCLE_PULL_REQUEST}" ]]; then sudo bash -c "echo -e 'build:remote --remote_upload_local_results=false\n' >> .bazelrc.user"; echo "Not uploading local build results to remote cache."; else @@ -154,11 +164,6 @@ jobs: steps: - custom_attach_workspace - run: yarn lint - - run: 'yarn bazel:format -mode=check || - (echo "BUILD files not formatted. Please run ''yarn bazel:format''" ; exit 1)' - # Run the skylark linter to check our Bazel rules - - run: 'yarn bazel:lint || - (echo -e "\n.bzl files have lint errors. Please run ''yarn bazel:lint-fix''"; exit 1)' validate: executor: action-executor @@ -172,6 +177,15 @@ jobs: else echo "This build is not over a PR, nothing to do." fi + - run: + name: Validate Code Formatting + command: yarn -s ng-dev format changed <> --check + - run: + name: Validate NgBot Configuration + command: yarn ng-dev ngbot verify + - run: + name: Validate Circular Dependencies + command: yarn ts-circular-deps:check - run: command: yarn -s admin validate @@ -203,6 +217,7 @@ jobs: command: | mkdir /mnt/ramdisk/e2e-yarn node ./tests/legacy-cli/run_e2e --nb-shards=${CIRCLE_NODE_TOTAL} --shard=${CIRCLE_NODE_INDEX} <<# parameters.snapshots >>--ng-snapshots<> --yarn --tmpdir=/mnt/ramdisk/e2e-yarn --glob="{tests/basic/**,tests/update/**,tests/commands/add/**}" + - fail_fast test-browsers: executor: @@ -228,6 +243,7 @@ jobs: - run: node ./tests/legacy-cli/run_e2e ./tests/legacy-cli/e2e/tests/misc/browsers.ts --ve - run: node ./tests/legacy-cli/run_e2e ./tests/legacy-cli/e2e/tests/misc/browsers.ts - run: ./scripts/saucelabs/stop-tunnel.sh + - fail_fast build: executor: action-executor @@ -246,6 +262,7 @@ jobs: - run: command: yarn bazel:test no_output_timeout: 20m + - fail_fast snapshot_publish: executor: action-executor @@ -263,6 +280,7 @@ jobs: name: Deployment to Snapshot command: | yarn admin snapshots --verbose --githubTokenFile=${HOME}/github_token + - fail_fast # Windows jobs e2e-cli-win: @@ -283,11 +301,12 @@ jobs: - run: name: Execute E2E Tests command: | - if (Test-Path env:CIRCLE_PR_NUMBER) { + if (Test-Path env:CIRCLE_PULL_REQUEST) { node tests\legacy-cli\run_e2e.js "--glob={tests/basic/**,tests/i18n/extract-ivy*.ts,tests/build/profile.ts}" --nb-shards=$env:CIRCLE_NODE_TOTAL --shard=$env:CIRCLE_NODE_INDEX } else { node tests\legacy-cli\run_e2e.js --nb-shards=$env:CIRCLE_NODE_TOTAL --shard=$env:CIRCLE_NODE_INDEX } + - fail_fast workflows: version: 2 @@ -316,18 +335,20 @@ workflows: name: e2e-cli-ng-snapshots snapshots: true requires: - - e2e-cli + - build filters: branches: only: - renovate/angular + - main + # TODO(BRANCH_RENAME_CLEANUP): remove - master - e2e-cli: name: e2e-cli-node-12 - nodeversion: '12.18' + nodeversion: '12.20' <<: *only_release_branches requires: - - e2e-cli + - build - test-browsers: requires: - build @@ -343,7 +364,7 @@ workflows: # Windows jobs - e2e-cli-win: requires: - - test + - build # Publish jobs - snapshot_publish: @@ -352,3 +373,25 @@ workflows: - build - test - e2e-cli + + nightly: + triggers: + - schedule: + cron: '0 0 * * *' + filters: + branches: + only: + - 12.2.x + jobs: + # Linux jobs + - setup + - build: + requires: + - setup + - e2e-cli: + name: e2e-cli-nightly + requires: + - build + - test-browsers: + requires: + - build diff --git a/.circleci/env.sh b/.circleci/env.sh index d24334473255..eef417500d18 100755 --- a/.circleci/env.sh +++ b/.circleci/env.sh @@ -22,7 +22,7 @@ setPublicVar PATH "${HOME}/.npm-global/bin:${PATH}"; # Define SauceLabs environment variables for CircleCI. #################################################################################################### setPublicVar SAUCE_USERNAME "angular-tooling"; -setSecretVar SAUCE_ACCESS_KEY "8c4ffce86ae6-c419-8ef4-0513-54267305"; +setSecretVar SAUCE_ACCESS_KEY "e05dabf6fe0e-2c18-abf4-496d-1d010490"; setPublicVar SAUCE_LOG_FILE /tmp/angular/sauce-connect.log setPublicVar SAUCE_READY_FILE /tmp/angular/sauce-connect-ready-file.lock setPublicVar SAUCE_PID_FILE /tmp/angular/sauce-connect-pid-file.lock diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000000..c3cc98e062af --- /dev/null +++ b/.eslintignore @@ -0,0 +1,13 @@ +/bazel-out/ +/dist-schema/ +/goldens/public-api +/packages/angular_devkit/build_angular/test/ +/packages/angular_devkit/build_webpack/test/ +/packages/angular_devkit/schematics_cli/blank/project-files/ +/packages/angular_devkit/schematics_cli/blank/schematic-files/ +/packages/angular_devkit/schematics_cli/schematic/files/ +/tests/ +.yarn/ +dist/ +node_modules/ +third_party/ \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 000000000000..930377419a9e --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,118 @@ +{ + "root": true, + "env": { + "es6": true, + "node": true + }, + "extends": [ + "eslint:recommended", + "plugin:import/typescript", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking", + "prettier" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "tsconfig.json", + "sourceType": "module" + }, + "plugins": ["eslint-plugin-import", "header", "@typescript-eslint"], + "rules": { + "@typescript-eslint/consistent-type-assertions": "error", + "@typescript-eslint/no-explicit-any": "error", + "@typescript-eslint/no-non-null-assertion": "error", + "@typescript-eslint/no-unnecessary-qualifier": "error", + "@typescript-eslint/no-unused-expressions": "error", + "curly": "error", + "header/header": [ + "error", + "block", + [ + "*", + " * @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.io/license", + " " + ], + 2 + ], + "import/first": "error", + "import/newline-after-import": "error", + "import/no-absolute-path": "error", + "import/no-duplicates": "error", + "import/no-extraneous-dependencies": ["off", { "devDependencies": false }], + "import/no-unassigned-import": ["error", { "allow": ["symbol-observable"] }], + "import/order": [ + "error", + { + "alphabetize": { "order": "asc" }, + "groups": [["builtin", "external"], "parent", "sibling", "index"] + } + ], + "max-len": [ + "error", + { + "code": 140, + "ignoreUrls": true + } + ], + "max-lines-per-function": ["error", { "max": 200 }], + "no-caller": "error", + "no-console": "error", + "no-empty": ["error", { "allowEmptyCatch": true }], + "no-eval": "error", + "no-multiple-empty-lines": ["error"], + "no-throw-literal": "error", + "padding-line-between-statements": [ + "error", + { + "blankLine": "always", + "prev": "*", + "next": "return" + } + ], + "sort-imports": ["error", { "ignoreDeclarationSort": true }], + "spaced-comment": [ + "error", + "always", + { + "markers": ["/"] + } + ], + + /* TODO: evaluate usage of these rules and fix issues as needed */ + "no-case-declarations": "off", + "no-fallthrough": "off", + "no-underscore-dangle": "off", + "no-useless-escape": "off", + "@typescript-eslint/await-thenable": "off", + "@typescript-eslint/ban-types": "off", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/no-implied-eval": "off", + "@typescript-eslint/no-var-requires": "off", + "@typescript-eslint/no-unnecessary-type-assertion": "off", + "@typescript-eslint/no-unsafe-assignment": "off", + "@typescript-eslint/no-unsafe-call": "off", + "@typescript-eslint/no-unsafe-member-access": "off", + "@typescript-eslint/no-unsafe-return": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/prefer-regexp-exec": "off", + "@typescript-eslint/require-await": "off", + "@typescript-eslint/restrict-plus-operands": "off", + "@typescript-eslint/restrict-template-expressions": "off", + "@typescript-eslint/unbound-method": "off" + }, + "overrides": [ + { + "files": ["!packages/**", "**/*_spec.ts"], + "rules": { + "import/no-extraneous-dependencies": ["error", { "devDependencies": true }], + "max-lines-per-function": "off", + "no-console": "off" + } + } + ] +} diff --git a/.github/ISSUE_TEMPLATE/1-bug-report.md b/.github/ISSUE_TEMPLATE/1-bug-report.md index c24ab5b7ef34..bc0cec42df0e 100644 --- a/.github/ISSUE_TEMPLATE/1-bug-report.md +++ b/.github/ISSUE_TEMPLATE/1-bug-report.md @@ -2,6 +2,7 @@ name: "\U0001F41E Bug report" about: Report a bug in Angular CLI --- + - # 🐞 Bug report ### Command (mark with an `x`) + @@ -34,26 +35,24 @@ Existing issues often contain information about workarounds, resolution, or prog - [ ] version - [ ] doc - ### Is this a regression? Yes, the previous version in which this bug was not present was: .... - ### Description A clear and concise description of the problem... - ## 🔬 Minimal Reproduction + ## 🔥 Exception or Error +

 
 
 
 
- ## 🌍 Your Environment +

 
 
@@ -77,6 +77,7 @@ You can read more about issue submission guidelines here: https://github.com/ang
 
**Anything else relevant?** + diff --git a/.github/ISSUE_TEMPLATE/2-feature-request.md b/.github/ISSUE_TEMPLATE/2-feature-request.md index 9210f5135779..f129bc107360 100644 --- a/.github/ISSUE_TEMPLATE/2-feature-request.md +++ b/.github/ISSUE_TEMPLATE/2-feature-request.md @@ -1,8 +1,8 @@ --- name: "\U0001F680 Feature request" about: Suggest a feature for Angular CLI - --- + - # 🚀 Feature request - ### Command (mark with an `x`) + + - [ ] new - [ ] build - [ ] serve @@ -36,12 +36,13 @@ Existing issues often contain information about workarounds, resolution, or prog - [ ] doc ### Description - A clear and concise description of the problem or missing capability... + A clear and concise description of the problem or missing capability... ### Describe the solution you'd like - If you have a solution in mind, please describe it. + If you have a solution in mind, please describe it. ### Describe alternatives you've considered + Have you considered any alternative solutions or workarounds? diff --git a/.github/ISSUE_TEMPLATE/3-docs-bug.md b/.github/ISSUE_TEMPLATE/3-docs-bug.md index 7cd9ec28753a..7270bb2a963f 100644 --- a/.github/ISSUE_TEMPLATE/3-docs-bug.md +++ b/.github/ISSUE_TEMPLATE/3-docs-bug.md @@ -1,7 +1,6 @@ --- -name: "📚 Docs or angular.io issue report" +name: '📚 Docs or angular.io issue report' about: Report an issue in Angular's documentation or angular.io application - --- 🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑 diff --git a/.github/ISSUE_TEMPLATE/4-security-issue-disclosure.md b/.github/ISSUE_TEMPLATE/4-security-issue-disclosure.md index 70736318d2a3..a5c2c1707fda 100644 --- a/.github/ISSUE_TEMPLATE/4-security-issue-disclosure.md +++ b/.github/ISSUE_TEMPLATE/4-security-issue-disclosure.md @@ -1,7 +1,6 @@ --- name: ⚠️ Security issue disclosure about: Report a security issue in Angular Framework, Material, or CLI - --- 🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑 diff --git a/.github/ISSUE_TEMPLATE/5-support-request.md b/.github/ISSUE_TEMPLATE/5-support-request.md index cdbd2e887db7..509f8d4797bc 100644 --- a/.github/ISSUE_TEMPLATE/5-support-request.md +++ b/.github/ISSUE_TEMPLATE/5-support-request.md @@ -1,14 +1,13 @@ --- -name: "❓ Support request" +name: '❓ Support request' about: Questions and requests for support - --- 🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑 Please do not file questions or support requests on the GitHub issues tracker. -You can get your questions answered using other communication channels. Please see: +You can get your questions answered using other communication channels. Please see: https://github.com/angular/angular-cli/blob/master/CONTRIBUTING.md#question Thank you! diff --git a/.github/ISSUE_TEMPLATE/6-angular-framework.md b/.github/ISSUE_TEMPLATE/6-angular-framework.md index 8a689c55de35..8ab207b2389f 100644 --- a/.github/ISSUE_TEMPLATE/6-angular-framework.md +++ b/.github/ISSUE_TEMPLATE/6-angular-framework.md @@ -1,7 +1,6 @@ --- -name: "⚡Angular Framework" +name: '⚡Angular Framework' about: Issues and feature requests for Angular Framework - --- 🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑 diff --git a/.github/ISSUE_TEMPLATE/7-angular-material.md b/.github/ISSUE_TEMPLATE/7-angular-material.md index fab3fe5b67c8..10b27db5c86f 100644 --- a/.github/ISSUE_TEMPLATE/7-angular-material.md +++ b/.github/ISSUE_TEMPLATE/7-angular-material.md @@ -1,7 +1,6 @@ --- name: "\U0001F48E Angular Material" about: Issues and feature requests for Angular Material - --- 🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑 diff --git a/.github/SAVED_REPLIES.md b/.github/SAVED_REPLIES.md index 29e19832903c..466b8ad5ee52 100644 --- a/.github/SAVED_REPLIES.md +++ b/.github/SAVED_REPLIES.md @@ -4,52 +4,52 @@ The following are canned responses that the Angular CLI team should use to close Since GitHub currently doesn't allow us to have a repository-wide or organization-wide list of [saved replies](https://help.github.com/articles/working-with-saved-replies/), these replies need to be maintained by individual team members. Since the responses can be modified in the future, all responses are versioned to simplify the process of keeping the responses up to date. - ## Angular CLI: Already Fixed (v1) + ``` Thanks for reporting this issue. Luckily, it has already been fixed in one of the recent releases. Please update to the most recent version to resolve the problem. If the problem persists in your application after upgrading, please open a new issue, provide a simple repository reproducing the problem, and describe the difference between the expected and current behavior. You can use `ng new repro-app` to create a new project where you reproduce the problem. ``` - ## Angular CLI: Don't Understand (v1) + ``` I'm sorry, but we don't understand the problem you are reporting. If the problem persists, please open a new issue, provide a simple repository reproducing the problem, and describe the difference between the expected and current behavior. You can use `ng new repro-app` to create a new project where you reproduce the problem. ``` - ## Angular CLI: Duplicate (v1.1) + ``` Thanks for reporting this issue. However, this issue is a duplicate of #. Please subscribe to that issue for future updates. ``` - ## Angular CLI: Insufficient Information Provided (v1) + ``` Thanks for reporting this issue. However, you didn't provide sufficient information for us to understand and reproduce the problem. Please check out [our submission guidelines](https://github.com/angular/angular-cli/blob/master/CONTRIBUTING.md#-submitting-an-issue) to understand why we can't act on issues that are lacking important information. If the problem persists, please file a new issue and ensure you provide all of the required information when filling out the issue template. ``` - ## Angular CLI: NPM install issue (v1) + ``` This seems like a problem with your node/npm and not with Angular CLI. Please have a look at the [fixing npm permissions page](https://docs.npmjs.com/getting-started/fixing-npm-permissions), [common errors page](https://docs.npmjs.com/troubleshooting/common-errors), [npm issue tracker](https://github.com/npm/npm/issues), or open a new issue if the problem you are experiencing isn't known. ``` - ## Angular CLI: Issue Outside of Angular CLI (v1.1) + ``` I'm sorry, but this issue is not caused by Angular CLI. Please contact the author(s) of the project or file an issue on their issue tracker. ``` - ## Angular CLI: Non-reproducible (v1) + ``` I'm sorry, but we can't reproduce the problem following the instructions you provided. Remember that we have a large number of issues to resolve, and have only a limited amount of time to reproduce your issue. @@ -60,24 +60,24 @@ If the problem persists, please open a new issue following [our submission guide A good way to make a minimal repro is to create a new app via `ng new repro-app` and adding the minimum possible code to show the problem. Then you can push this repository to github and link it here. ``` - ## Angular CLI: Obsolete (v1) + ``` Thanks for reporting this issue. This issue is now obsolete due to changes in the recent releases. Please update to the most recent Angular CLI version. If the problem persists after upgrading, please open a new issue, provide a simple repository reproducing the problem, and describe the difference between the expected and current behavior. ``` - ## Angular CLI: Support Request (v1) + ``` Hello, we reviewed this issue and determined that it doesn't fall into the bug report or feature request category. This issue tracker is not suitable for support requests, please repost your issue on [StackOverflow](http://stackoverflow.com/) using tag `angular-cli`. If you are wondering why we don't resolve support issues via the issue tracker, please [check out this explanation](https://github.com/angular/angular-cli/blob/master/CONTRIBUTING.md#-got-a-question-or-problem). ``` - ## Angular CLI: Static Analysis errors (v1) + ``` Hello, errors like `Error encountered resolving symbol values statically` mean that there has been some problem in statically analyzing your app. @@ -93,6 +93,7 @@ In that case, please open an issue in https://github.com/angular/angular. ``` ## Angular CLI: Lockfiles (v1) + ``` I'd like to remind everyone that **you only have reproducible installs if you use a lockfile**. Both [NPM v5+](https://docs.npmjs.com/files/package-locks) and [Yarn](https://yarnpkg.com/lang/en/docs/yarn-lock/) support lockfiles. If your CI works one day but not the next and you did not change your code or `package.json`, it is likely because one of your dependencies had a bad release and you did not have a lockfile. diff --git a/.github/angular-robot.yml b/.github/angular-robot.yml index 03cda7b51d33..e4a402d300b3 100644 --- a/.github/angular-robot.yml +++ b/.github/angular-robot.yml @@ -7,18 +7,20 @@ merge: # set to true to disable disabled: false # the name of the status - context: "ci/angular: merge status" + context: 'ci/angular: merge status' # text to show when all checks pass - successText: "All checks passed!" + successText: 'All checks passed!' # text to show when some checks are failing - failureText: "The following checks are failing:" + failureText: 'The following checks are failing:' # comment that will be added to a PR when there is a conflict, leave empty or set to false to disable - mergeConflictComment: "Hi @{{PRAuthor}}! This PR has merge conflicts due to recent upstream merges. -\nPlease help to unblock it by resolving these conflicts. Thanks!" + mergeConflictComment: >- + Hi @{{PRAuthor}}! This PR has merge conflicts due to recent upstream merges. + + Please help to unblock it by resolving these conflicts. Thanks! # label to monitor - mergeLabel: "action: merge" + mergeLabel: 'action: merge' # list of checks that will determine if the merge label can be added checks: @@ -28,39 +30,44 @@ merge: requireReviews: true # list of labels that a PR needs to have, checked with a regexp (e.g. "target:" will work for the label "target: major") requiredLabels: - - "target: *" - - "cla: yes" + - 'target: *' + - 'cla: yes' # list of labels that a PR shouldn't have, checked after the required labels with a regexp forbiddenLabels: - - "action: cleanup" - - "action: review" - - "PR state: blocked" - - "cla: no" + - 'action: cleanup' + - 'action: review' + - 'PR state: blocked' + - 'cla: no' # list of PR statuses that need to be successful requiredStatuses: - - "ci/circleci: build" - - "ci/circleci: setup" - - "ci/circleci: lint" - - "ci/circleci: validate" - - "ci/circleci: test" - - "ci/circleci: e2e-cli-win" - - "ci/circleci: e2e-cli" - - "ci/circleci: test-browsers" - - "ci/angular: size" - - "cla/google" + - 'ci/circleci: build' + - 'ci/circleci: setup' + - 'ci/circleci: lint' + - 'ci/circleci: validate' + - 'ci/circleci: test' + - 'ci/circleci: e2e-cli-win' + - 'ci/circleci: e2e-cli' + - 'ci/circleci: test-browsers' + - 'ci/angular: size' + - 'cla/google' # the comment that will be added when the merge label is added despite failing checks, leave empty or set to false to disable # {{MERGE_LABEL}} will be replaced by the value of the mergeLabel option # {{PLACEHOLDER}} will be replaced by the list of failing checks - mergeRemovedComment: "I see that you just added the `{{MERGE_LABEL}}` label, but the following checks are still failing: -\n{{PLACEHOLDER}} -\n -\n**If you want your PR to be merged, it has to pass all the CI checks.** -\n -\nIf you can't get the PR to a green state due to flakes or broken master, please try rebasing to master and/or restarting the CI job. If that fails and you believe that the issue is not due to your change, please contact the caretaker and ask for help." + mergeRemovedComment: >- + I see that you just added the `{{MERGE_LABEL}}` label, but the following + checks are still failing: + {{PLACEHOLDER}} + + **If you want your PR to be merged, it has to pass all the CI checks.** + + If you can't get the PR to a green state due to flakes or broken master, + please try rebasing to master and/or restarting the CI job. If that fails + and you believe that the issue is not due to your change, please contact the + caretaker and ask for help. # options for the triage plugin triage: # set to true to disable @@ -71,30 +78,24 @@ triage: defaultMilestone: 12, # arrays of labels that determine if an issue has been triaged by the caretaker l1TriageLabels: - - - - "comp: *" + - - 'comp: *' # arrays of labels that determine if an issue has been fully triaged l2TriageLabels: - - - - "type: bug/fix" - - "severity*" - - "freq*" - - "comp: *" - - - - "type: feature" - - "comp: *" - - - - "type: refactor" - - "comp: *" - - - - "type: RFC / Discussion / question" - - "comp: *" - - - - "type: docs" - - "comp: *" + - - 'type: bug/fix' + - 'severity*' + - 'freq*' + - 'comp: *' + - - 'type: feature' + - 'comp: *' + - - 'type: refactor' + - 'comp: *' + - - 'type: RFC / Discussion / question' + - 'comp: *' + - - 'type: docs' + - 'comp: *' # Size checking size: - circleCiStatusName: "ci/circleci: e2e-cli" + circleCiStatusName: 'ci/circleci: e2e-cli' maxSizeIncrease: 10000 comment: false diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 6499bb344192..cc8aa2b2c506 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,16 +1,16 @@ version: 2 updates: - - package-ecosystem: "npm" - directory: "/" + - package-ecosystem: 'npm' + directory: '/' schedule: - interval: "daily" + interval: 'daily' commit-message: - prefix: "build" + prefix: 'build' labels: - - "comp: build & ci" - - "target: patch" - - "action: merge" + - 'comp: build & ci' + - 'target: patch' + - 'action: merge' # Disable version updates # This does not affect security updates open-pull-requests-limit: 0 diff --git a/.github/workflows/dev-infra.yml b/.github/workflows/dev-infra.yml new file mode 100644 index 000000000000..51fe79480f75 --- /dev/null +++ b/.github/workflows/dev-infra.yml @@ -0,0 +1,14 @@ +name: DevInfra + +on: + pull_request_target: + types: [opened, synchronize, reopened] + +jobs: + breaking-changes-label: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: angular/dev-infra/github-actions/breaking-changes-label@861dc90572784e714aeaa9dfb20ceebeb57cdb07 + with: + angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} diff --git a/.github/workflows/lock-closed.yml b/.github/workflows/lock-closed.yml index b43e8601204e..c8e81beac98a 100644 --- a/.github/workflows/lock-closed.yml +++ b/.github/workflows/lock-closed.yml @@ -9,6 +9,6 @@ jobs: lock_closed: runs-on: ubuntu-latest steps: - - uses: angular/dev-infra/github-actions/lock-closed@0fc6f4d839e93312ed0dd9a2be88d4c11e947a0b + - uses: angular/dev-infra/github-actions/lock-closed@4f335a4c1f01f20bf905acee2d68c7248f50f2a0 with: lock-bot-key: ${{ secrets.LOCK_BOT_PRIVATE_KEY }} diff --git a/.gitignore b/.gitignore index 357df0969694..91652321da0e 100644 --- a/.gitignore +++ b/.gitignore @@ -41,9 +41,11 @@ npm-debug.log* yarn-error.log* .ng_pkg_build/ .ng-dev.log +.ng-dev.err*.log .ng-dev.user* .husky/_ .bazelrc.user +.eslintcache # Mac OSX Finder files. **/.DS_Store diff --git a/.husky/.gitignore b/.husky/.gitignore deleted file mode 100644 index 31354ec13899..000000000000 --- a/.husky/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_ diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 000000000000..84611a58eec9 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname $0)/_/husky.sh" + +yarn -s ng-dev format staged; \ No newline at end of file diff --git a/.monorepo.json b/.monorepo.json index cab101ad56e0..0cf9710d62e8 100644 --- a/.monorepo.json +++ b/.monorepo.json @@ -41,12 +41,9 @@ "Angular CLI": "http://github.com/angular/angular-cli" }, "packages": { - "@_/benchmark": { - }, - "@_/builders": { - }, - "devkit": { - }, + "@_/benchmark": {}, + "@_/builders": {}, + "devkit": {}, "@angular/cli": { "name": "Angular CLI", "section": "Tooling", diff --git a/.ng-dev/commit-message.ts b/.ng-dev/commit-message.ts index 06bd8eb244fc..03f02ef856ea 100644 --- a/.ng-dev/commit-message.ts +++ b/.ng-dev/commit-message.ts @@ -1,5 +1,9 @@ // tslint:disable-next-line: no-implicit-dependencies -import { COMMIT_TYPES, CommitMessageConfig, ScopeRequirement } from '@angular/dev-infra-private/commit-message/config'; +import { + COMMIT_TYPES, + CommitMessageConfig, + ScopeRequirement, +} from '@angular/dev-infra-private/ng-dev/commit-message/config'; import { packages } from '../lib/packages'; /** @@ -16,7 +20,5 @@ export const commitMessage: CommitMessageConfig = { maxLineLength: Infinity, minBodyLength: 0, minBodyLengthTypeExcludes: ['docs'], - scopes: [ - ...Object.keys(packages), - ], + scopes: [...Object.keys(packages)], }; diff --git a/.ng-dev/config.ts b/.ng-dev/config.ts index a5d99ef26f13..1727da8f3df9 100644 --- a/.ng-dev/config.ts +++ b/.ng-dev/config.ts @@ -1,3 +1,5 @@ export { commitMessage } from './commit-message'; +export { format } from './format'; export { github } from './github'; export { merge } from './merge'; +export { release } from './release'; diff --git a/.ng-dev/format.ts b/.ng-dev/format.ts new file mode 100644 index 000000000000..b7cf1afb190a --- /dev/null +++ b/.ng-dev/format.ts @@ -0,0 +1,11 @@ +import { FormatConfig } from '@angular/dev-infra-private/ng-dev/format/config'; + +/** + * Configuration for the `ng-dev format` command. + */ +export const format: FormatConfig = { + 'prettier': { + matchers: ['**/*.{ts,js,json,yml,yaml,md}'], + }, + 'buildifier': true, +}; diff --git a/.ng-dev/github.ts b/.ng-dev/github.ts index 9d5a406aaa14..b1af287af493 100644 --- a/.ng-dev/github.ts +++ b/.ng-dev/github.ts @@ -1,4 +1,4 @@ -import { GithubConfig } from '@angular/dev-infra-private/utils/config'; +import { GithubConfig } from '@angular/dev-infra-private/ng-dev/utils/config'; /** * Github configuration for the ng-dev command. This repository is @@ -7,4 +7,5 @@ import { GithubConfig } from '@angular/dev-infra-private/utils/config'; export const github: GithubConfig = { owner: 'angular', name: 'angular-cli', + mainBranchName: 'main', }; diff --git a/.ng-dev/merge.ts b/.ng-dev/merge.ts index eb41a469caad..7dcdede80310 100644 --- a/.ng-dev/merge.ts +++ b/.ng-dev/merge.ts @@ -1,5 +1,5 @@ -import { DevInfraMergeConfig } from '@angular/dev-infra-private/pr/merge/config'; -import { getDefaultTargetLabelConfiguration } from '@angular/dev-infra-private/pr/merge/defaults'; +import { DevInfraMergeConfig } from '@angular/dev-infra-private/ng-dev/pr/merge/config'; +import { getDefaultTargetLabelConfiguration } from '@angular/dev-infra-private/ng-dev/pr/merge/defaults'; import { github } from './github'; import { release } from './release'; @@ -7,15 +7,14 @@ import { release } from './release'; * Configuration for the merge tool in `ng-dev`. This sets up the labels which * are respected by the merge script (e.g. the target labels). */ -export const merge: DevInfraMergeConfig['merge'] = async api => { +export const merge: DevInfraMergeConfig['merge'] = async (api) => { return { githubApiMerge: { default: 'rebase', - labels: [ - {pattern: 'squash commits', method: 'squash'}, - ], + labels: [{ pattern: 'squash commits', method: 'squash' }], }, claSignedLabel: 'cla: yes', + breakingChangeLabel: 'flag: breaking change', mergeReadyLabel: /^action: merge(-assistance)?/, caretakerNoteLabel: /(action: merge-assistance)/, commitMessageFixupLabel: 'commit message fixup', diff --git a/.ng-dev/release.ts b/.ng-dev/release.ts index 175b763add66..c6071a9313f6 100644 --- a/.ng-dev/release.ts +++ b/.ng-dev/release.ts @@ -1,11 +1,23 @@ -import { ReleaseConfig } from '@angular/dev-infra-private/release/config'; -import { packages } from '../lib/packages'; +import '../lib/bootstrap-local'; + +import { ReleaseConfig } from '@angular/dev-infra-private/ng-dev/release/config'; +import { releasePackages } from '../lib/packages'; +import buildPackages from '../scripts/build'; + +const npmPackages = Object.keys(releasePackages); /** Configuration for the `ng-dev release` command. */ export const release: ReleaseConfig = { - npmPackages: Object.keys(packages), - // TODO: Set up package building. - buildPackages: async () => [], - // TODO: Set up generating changelogs - generateReleaseNotesForHead: async () => {}, + npmPackages, + buildPackages: () => buildPackages(), + releaseNotes: { + groupOrder: [ + '@angular/cli', + '@schematics/angular', + '@angular-devkit/architect-cli', + '@angular-devkit/schematics-cli', + ], + }, + publishRegistry: 'https://wombat-dressing-room.appspot.com', + releasePrLabels: ['action: merge'], }; diff --git a/.npmrc b/.npmrc new file mode 100644 index 000000000000..c42da845b449 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +engine-strict = true diff --git a/.prettierignore b/.prettierignore index fbcd212375a5..d1cd003e83c5 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1 +1,14 @@ -/etc/api +/bazel-out/ +/docs/design/analytics.md +/dist-schema/ +/goldens/public-api +/packages/angular_devkit/build_angular/test/ +/packages/angular_devkit/core/src/workspace/json/test/ +/packages/angular_devkit/schematics_cli/blank/project-files/ +/packages/angular_devkit/schematics_cli/blank/schematic-files/ +/packages/angular_devkit/schematics_cli/schematic/files/ +/README.md +/CONTRIBUTING.md +.yarn/ +dist/ +third_party/ \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index 5e2863a11f68..8ef20e3c1ea0 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,6 @@ { "printWidth": 100, + "quoteProps": "preserve", "singleQuote": true, "trailingComma": "all" } diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000000..1226ca89e070 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,9965 @@ + + +# 12.2.18 (2022-07-21) + +### @angular-devkit/build-angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | --------------------------------------- | +| [4d723ca95](https://github.com/angular/angular-cli/commit/4d723ca95913fd8643059d22151571f240cec998) | fix | update terser to address CVE-2022-25858 | + +## Special Thanks + +Alan Agius, Joey Perrott and Paul Gschwendtner + + + + + +# 12.2.17 (2022-03-31) + +### @angular-devkit/architect-cli + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ---------------------------- | +| [ccb0f95f3](https://github.com/angular/angular-cli/commit/ccb0f95f33ff0d23a0ff9b237d0d78fc4c864787) | fix | update `minimist` to `1.2.6` | + +### @angular-devkit/schematics-cli + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ---------------------------- | +| [abcdf4df2](https://github.com/angular/angular-cli/commit/abcdf4df20c29907ee28a38842942464addcf259) | fix | update `minimist` to `1.2.6` | + +### @angular-devkit/benchmark + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ---------------------------- | +| [2656a330e](https://github.com/angular/angular-cli/commit/2656a330eb365f37c3b6f8894436b4449d157e63) | fix | update `minimist` to `1.2.6` | + +## Special Thanks + +Alan Agius + + + + + +# 12.2.16 (2022-01-31) + +### @angular-devkit/build-angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------- | +| [ebfdcc635](https://github.com/angular/angular-cli/commit/ebfdcc635ad700bc4696a36131203e172de6c59b) | fix | invalid browsers version ranges | + +## Special Thanks + +Alan Agius + + + + + +# 12.2.15 (2022-01-12) + +### @angular-devkit/build-angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | --------------------------------------------------- | +| [526115fdb](https://github.com/angular/angular-cli/commit/526115fdb7d35ff01f5dbdb6027d9f5e925e4056) | fix | updated webpack-dev-server to latest security patch | + +## Special Thanks + +iRealNirmal + + + + + +# 12.2.14 (2021-12-07) + +### @angular/cli + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------------------------------------------------- | +| [30295b33e](https://github.com/angular/angular-cli/commit/30295b33ed74667f31e9d3a4a0017910a85fd734) | fix | error when updating Angular packages across multi-major migrations | +| [e07bd059e](https://github.com/angular/angular-cli/commit/e07bd059e3d6bc6b40191c036c467595ed119da7) | fix | logic which determines which temp version of the CLI is to be download during `ng update` | +| [ce1ec0420](https://github.com/angular/angular-cli/commit/ce1ec0420770a8e28c1c1301df9e5eb4548d4c53) | fix | update `ng update` output for Angular packages | +| [dd9f8df52](https://github.com/angular/angular-cli/commit/dd9f8df5204d639272f183795ebd48d7994df427) | fix | update `pacote` to `12.0.2` | + +## Special Thanks + +Alan Agius and Doug Parker + + + + + +# 12.2.13 (2021-11-03) + +### @angular-devkit/build-angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------------- | +| [a2bd940e4](https://github.com/angular/angular-cli/commit/a2bd940e4ab44db57b0fc69d5346d2862a19c879) | fix | add verbose logging for differential loading and i18n | + +## Special Thanks + +Charles Lyding and Doug Parker + + + + + +# 12.2.12 (2021-10-27) + +### @angular-devkit/build-angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ---------------------------------------------------------------- | +| [2decc2d26](https://github.com/angular/angular-cli/commit/2decc2d265ad32df3a7834337f82f00d723eaa74) | fix | avoid extra filesystem access with i18n and differential loading | +| [802b1b037](https://github.com/angular/angular-cli/commit/802b1b0378c1816dbfd8f4320b5d69e82f0c7aa6) | fix | remove potential race condition in i18n worker execution | +| [cce88c2e1](https://github.com/angular/angular-cli/commit/cce88c2e1cb673434dcd495dea1df751ca9d3592) | fix | update `critters` to version `0.0.12` | + +## Special Thanks + +Alan Agius, Charles Lyding and Mikhail Vasiliev + + + + + +# 12.2.11 (2021-10-20) + +### @angular/cli + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | -------------------------------------------------------- | +| [e0112603c](https://github.com/angular/angular-cli/commit/e0112603c139847c649413ba95faef93d9b74bf0) | fix | add engine field support for npm 8 and higher | +| [b93e63ff6](https://github.com/angular/angular-cli/commit/b93e63ff6b99ecdf4d5861feea3dd5b5adf86061) | fix | correct grammar error in Analytics consent prompt | +| [008094bd1](https://github.com/angular/angular-cli/commit/008094bd1690aa73fdfd18852fd7b8b274c22e7f) | fix | run stable migrations when package version is prerelease | + +### @angular-devkit/build-angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------ | +| [227bf2e86](https://github.com/angular/angular-cli/commit/227bf2e86b8a6e6fe41fdbc0f77365d96d79d831) | fix | add "Failed to compile" message | +| [6173609c5](https://github.com/angular/angular-cli/commit/6173609c5b1fd27c75cee8dd9b67de9ef332ef98) | fix | transform remapped sourcemap into a plain object | +| [349047523](https://github.com/angular/angular-cli/commit/349047523ad0110a25d7f730cd0160b76dcfc265) | fix | update `esbuild` to 0.13.8 | +| [892eeadd1](https://github.com/angular/angular-cli/commit/892eeadd11f8b702094640addc8a6f16236e5e08) | fix | update `mini-css-extract-plugin` to 2.4.2 | +| [8d52d9b7f](https://github.com/angular/angular-cli/commit/8d52d9b7faa44be5063905ed54b3c0d12d506af4) | fix | use a separate worker pool for i18n inlining | + +## Special Thanks + +Alan Agius, Charles Lyding, Extacy and Sushrit_Lawliet + + + + + +# 12.2.10 (2021-10-13) + +### @angular/cli + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | --------------------------------------------------------------- | +| [73a47af80](https://github.com/angular/angular-cli/commit/73a47af80e15a4b9d5b97956458bacafb43138bd) | fix | accept `UA-00000-0` format in analytics `tracking` id | +| [d2e24d396](https://github.com/angular/angular-cli/commit/d2e24d396551ff89d6178c8bdb56db30531e1bb0) | fix | generate new random user ID when passing empty string to `uuid` | + +### @schematics/angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | --------------------------------------------------- | +| [f6ed31fdf](https://github.com/angular/angular-cli/commit/f6ed31fdf2fe0f2a73f09c39e82e4b6bd6ccc6a6) | fix | wrap bootstrapping code in an HMR compatible manner | + +### @angular-devkit/build-angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------------------- | +| [7b01a0004](https://github.com/angular/angular-cli/commit/7b01a000432810f09c7871a95c9d2e6e5f35af85) | fix | enable custom `es2015` conditional exports | +| [892567487](https://github.com/angular/angular-cli/commit/8925674870973ce58e4f5b911fd3768811248916) | fix | improve fidelity and performance of babel loader sourcemaps | + +## Special Thanks + +Alan Agius and Charles Lyding + + + + + +# 12.2.9 (2021-10-06) + +### @angular-devkit/build-angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ---------------------------------------------------- | +| [9d45b7752](https://github.com/angular/angular-cli/commit/9d45b77522a9693c4876fdfd741e8869e89e0268) | fix | add web-streams-polyfill to downlevel exclusion list | +| [ccedf53a8](https://github.com/angular/angular-cli/commit/ccedf53a820a748b56c84528294b36c7af30dbaf) | fix | update `esbuild` to `0.13.4` | + +## Special Thanks + +Alan Agius and Charles Lyding + + + + + +# 12.2.8 (2021-10-01) + +### @angular-devkit/build-angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------------- | +| [821a1b5a9](https://github.com/angular/angular-cli/commit/821a1b5a949d53f2e82f734062b711a166d42e24) | fix | babel adjust enum plugin incorrectly transforming loose enums | + +## Special Thanks + +Paul Gschwendtner + + + + + +# 12.2.7 (2021-09-22) + +### @angular-devkit/build-angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | --------------------------------------------- | +| [d856b4d23](https://github.com/angular/angular-cli/commit/d856b4d2369bea76ce65fc5f6d1585145ad41618) | fix | support WASM-based esbuild optimizer fallback | + +## Special Thanks + +Alan Agius and Charles Lyding + + + + + +# 12.2.6 (2021-09-15) + +### @angular/cli + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------------------------- | +| [8b21effad](https://github.com/angular/angular-cli/commit/8b21effad673877cf1a82ef7d0601393a65517fb) | fix | handle `FORCE_COLOR` when stdout is not instance of `WriteStream` | + +### @angular-devkit/build-angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------------------------- | +| [ea60f0f52](https://github.com/angular/angular-cli/commit/ea60f0f527f2ab8fc5acc967138c4ae993946923) | fix | handle `FORCE_COLOR` when stdout is not instance of `WriteStream` | + +## Special Thanks + +Alan Agius + + + + + +# 12.2.5 (2021-09-08) + +### @angular-devkit/build-angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | -------------------------------------------------------- | +| [0498768c5](https://github.com/angular/angular-cli/commit/0498768c54de225a40c28fdf27bb1fc43959ba20) | fix | disable dev-server response compression | +| [367fce2e9](https://github.com/angular/angular-cli/commit/367fce2e9f9389c41f2ed5361ef6749198c49785) | fix | improve Safari browserslist to esbuild target conversion | + +## Special Thanks: + +Alan Agius and Charles Lyding + + + +# 12.2.4 (2021-09-01) + +### @angular-devkit/build-angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------- | +| [aaadef026](https://github.com/angular/angular-cli/commit/aaadef02698ba729ca04ccd4159bda5b6582babb) | fix | update `esbuild` to `0.12.24` | +| [f8a9f4a01](https://github.com/angular/angular-cli/commit/f8a9f4a0100286b7cf656ffbe486c3424cad5172) | fix | update `mini-css-extract-plugin` to `2.2.1` | + +## Special Thanks + +Alan Agius + + + +# 12.2.3 (2021-08-26) + +### @angular-devkit/build-angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | -------------------------------------------------------------- | +| [3e3321857](https://github.com/angular/angular-cli/commit/3e33218578007f93a131dc8be569e9985179098f) | fix | RGBA converted to hex notation in component styles breaks IE11 | + +## Special Thanks: + +Alan Agius and Trevor Karjanis + + + +# 12.2.2 (2021-08-18) + +### @angular-devkit/build-angular + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | +| [a55118a75](https://github.com/angular/angular-cli/commit/a55118a753555c0082cfd434379559df7e3eb7f9) | fix: provide supported browsers to esbuild | +| [81baa4f95](https://github.com/angular/angular-cli/commit/81baa4f956443fcc718f9021fd23ab7064d04607) | fix: update Angular peer dependencies to 12.2 stable | +| [297410ae8](https://github.com/angular/angular-cli/commit/297410ae860860d71905639cf38b49ff05813845) | fix: handle undefined entrypoints when marking async chunks | + +### @ngtools/webpack + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | +| [b7199f366](https://github.com/angular/angular-cli/commit/b7199f366841d976b502ad5f1923e24ea2f6b302) | fix: update Angular peer dependencies to 12.2 stable | + +## Special Thanks: + +Alan Agius, Charles Lyding, Joey Perrott and Simon Primetzhofer + + + +# 12.2.1 (2021-08-11) + +### @angular/cli + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | +| [8dc3c895a](https://github.com/angular/angular-cli/commit/8dc3c895a6531316e672031c8d0815781f0c089a) | fix(@angular/cli): show error when using non-TTY terminal without passing `--skip-confirmation` during `ng add` | + +### @angular-devkit/schematics-cli + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | +| [eded01270](https://github.com/angular/angular-cli/commit/eded01270f9aa70f6ba4806a068de8d1c0a52454) | fix(@angular-devkit/schematics-cli): log when in debug and/or dry run modes | + +### @angular-devkit/build-angular + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | +| [22e0208a9](https://github.com/angular/angular-cli/commit/22e0208a9ee6257213b3bf93ac61a2c3d4ac9504) | fix(@angular-devkit/build-angular): ensure native async is downlevelled in third-party libraries | +| [9b4b86fb0](https://github.com/angular/angular-cli/commit/9b4b86fb0d9c88a3c714f5eabf925859bb7b71bb) | fix(@angular-devkit/build-angular): support both pure annotation forms for static properties | +| [cea028090](https://github.com/angular/angular-cli/commit/cea0280908db39308ac5fa37374b138ceb79ecea) | fix(@angular-devkit/build-angular): do not consume inline sourcemaps when vendor sourcemaps is disabled. | +| [e7ec0346e](https://github.com/angular/angular-cli/commit/e7ec0346e69c090ded7d9ec6d3574deb79926db0) | fix(@angular-devkit/build-angular): avoid attempting to optimize copied JavaScript assets | +| [4f757c2bc](https://github.com/angular/angular-cli/commit/4f757c2bcf1356d33eaa86bc3b715c0a6b7c2ed8) | fix(@angular-devkit/build-angular): handle null maps in JavaScript optimizer worker | + +## Special Thanks: + +Alan Agius and Charles Lyding + + + +# 12.2.0 (2021-08-04) + +### @angular/cli + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | +| [259e26979](https://github.com/angular/angular-cli/commit/259e26979ebc712ee08fd36fb68a9576c1e02447) | fix(@angular/cli): merge npmrc files values | +| [c1eddbdc9](https://github.com/angular/angular-cli/commit/c1eddbdc98631fdfff287ce566d79ed43b601e0f) | fix(@angular/cli): handle `YARN_` environment variables during `ng update` and `ng add` | +| [6b00d1270](https://github.com/angular/angular-cli/commit/6b00d1270acaf33f32ee68c4254ce06951ddcb8c) | fix(@angular/cli): handle NPM_CONFIG environment variables during ng update and ng add | +| [88ee85c41](https://github.com/angular/angular-cli/commit/88ee85c4178e37b72001e8946b70a46ba739a0b7) | fix(@angular/cli): disable update notifier when retrieving package manager version during `ng version` | + +### @angular-devkit/build-angular + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | +| [d750c686f](https://github.com/angular/angular-cli/commit/d750c686fd26f3ccfccb039027bd816a91279497) | fix(@angular-devkit/build-angular): add priority to copy-webpack-plugin patterns | +| [4bcd1dc9e](https://github.com/angular/angular-cli/commit/4bcd1dc9ee744343a465d73d51d4a062964a3714) | fix(@angular-devkit/build-angular): allow classes with pure annotated static properties to be optimized | +| [ceade0c27](https://github.com/angular/angular-cli/commit/ceade0c27e4b8b0e731e6ca5128fd86cf071d029) | fix(@angular-devkit/build-angular): dasherize disable-host-check suggestion | +| [8383c6b42](https://github.com/angular/angular-cli/commit/8383c6b421f7005a25a3bff0826048f3a24f3030) | fix(@angular-devkit/build-angular): silence Sass compiler warnings from 3rd party stylesheets | +| [07763702f](https://github.com/angular/angular-cli/commit/07763702fd244ba44aebb714a295dbf5ba72b91d) | fix(@angular-devkit/build-angular): force linker `sourceMapping` option to false. | +| [a5c69722f](https://github.com/angular/angular-cli/commit/a5c69722ffeceb72dcd46901c2bb983e5dc8bf32) | fix(@angular-devkit/build-angular): ensure `NG_PERSISTENT_BUILD_CACHE` always creates a cache in the specified cache directory | +| [c65b04999](https://github.com/angular/angular-cli/commit/c65b049996a8de9d9fcc66631872424cbe5f13f9) | fix(@angular-devkit/build-angular): fail browser build when index generation fails | +| [3d71c63b3](https://github.com/angular/angular-cli/commit/3d71c63b3a11946ebfca3f0d97d4fbf8dca16255) | fix(@angular-devkit/build-angular): fix issue were `@media all` causing critical CSS inling to fail | +| [9a04975a2](https://github.com/angular/angular-cli/commit/9a04975a2170c3ecc2c09c32bd15a89c613e198f) | fix(@angular-devkit/build-angular): `extractLicenses` didn't have an effect when using server builder | +| [2ac8e9c0e](https://github.com/angular/angular-cli/commit/2ac8e9c0e131bf7fcb2c6e92500eeaa112efcefb) | fix(@angular-devkit/build-angular): display incompatibility errors | +| [2c2b49919](https://github.com/angular/angular-cli/commit/2c2b499193fb319e1c9cb92318610353b7720e2b) | fix(@angular-devkit/build-angular): limit advanced terser passes to two | +| [1be3b0783](https://github.com/angular/angular-cli/commit/1be3b07836659487e4aa9b8c71c673635e268a60) | fix(@angular-devkit/build-angular): exclude `outputPath` from persistent build cache key | +| [fefd6d042](https://github.com/angular/angular-cli/commit/fefd6d04213e61d3f48c0484d8c6a8dcff1ecd34) | perf(@angular-devkit/build-angular): use `esbuild` as a CSS optimizer for component styles | +| [18cfa0431](https://github.com/angular/angular-cli/commit/18cfa04317230f934ccba798c080543bb389725f) | feat(@angular-devkit/build-angular): add support to inline Adobe Fonts | +| [9a751f0f8](https://github.com/angular/angular-cli/commit/9a751f0f81919d67f5eeeaecbe807d5c216f6a7a) | fix(@angular-devkit/build-angular): handle `ENOENT` and `ENOTDIR` errors when deleting outputs | +| [41e645792](https://github.com/angular/angular-cli/commit/41e64579213b9d4a7c976ea45daa6b32d980df10) | fix(@angular-devkit/build-angular): downlevel `for await...of` when targetting ES2018+ | +| [070a13364](https://github.com/angular/angular-cli/commit/070a1336478d721bbbb474622f50fab455cda26c) | fix(@angular-devkit/build-angular): configure webpack target in common configuration | +| [da32daa75](https://github.com/angular/angular-cli/commit/da32daa75d08d4be177af5fa16088398d7fb427b) | perf(@angular-devkit/build-angular): use combination of `esbuild` and `terser` as a JavaScript optimizer | +| [6a2b11906](https://github.com/angular/angular-cli/commit/6a2b11906e4173562a82b3654ff662dd05513049) | perf(@angular-devkit/build-angular): cache JavaScriptOptimizerPlugin results | +| [ab17b1721](https://github.com/angular/angular-cli/commit/ab17b1721c05366e592cf805ad6d25e672b314bf) | fix(@angular-devkit/build-angular): handle ng-packagr errors more gracefully. | +| [d4c5f8518](https://github.com/angular/angular-cli/commit/d4c5f8518d4801b9fd76de289a015dcbb8d8f69b) | fix(@angular-devkit/build-angular): control linker template sourcemapping via builder sourcemap options | +| [06181c2fb](https://github.com/angular/angular-cli/commit/06181c2fbf5a20396b2d0e2b3925ceb1276947fb) | fix(@angular-devkit/build-angular): parse web-workers in tests when webWorkerTsConfig is defined | + +### @angular-devkit/build-webpack + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | +| [615353022](https://github.com/angular/angular-cli/commit/61535302204a2a767f85053b7efaa6ac5ac64098) | fix(@angular-devkit/build-webpack): emit result when webpack is closed | + +### @ngtools/webpack + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | +| [dbbcf5c8c](https://github.com/angular/angular-cli/commit/dbbcf5c8c4ec4427609942f4ef7053c1b51773c9) | fix(@ngtools/webpack): only track file dependencies | +| [7536338e0](https://github.com/angular/angular-cli/commit/7536338e0becc7f9cde62becbde58e18a270cb31) | fix(@ngtools/webpack): allow generated assets of Angular component resources | +| [720feee34](https://github.com/angular/angular-cli/commit/720feee34f910fc11c40e2f68d919d61b7d6cbec) | fix(@ngtools/webpack): avoid non-actionable template type-checker syntax diagnostics | +| [6a7bcf330](https://github.com/angular/angular-cli/commit/6a7bcf3300b459aef80fcf98f2475c977f6244dc) | fix(@ngtools/webpack): encode component style data | +| [12c14b565](https://github.com/angular/angular-cli/commit/12c14b56537d65d6986e245ab1ae4dd9aa8dd378) | fix(@ngtools/webpack): remove no longer needed component styles workaround | + +### @schematics/angular + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | +| [20fd33f6d](https://github.com/angular/angular-cli/commit/20fd33f6d4ce6cef1feb508a0221222e83a85630) | feat(@schematics/angular): destroy test module after every test | +| [5b10d4f54](https://github.com/angular/angular-cli/commit/5b10d4f549ebc12645ad08cba8ab7b91eaa87d28) | fix(@schematics/angular): remove unsafe any usage in application spec file | +| [1b5e18e7b](https://github.com/angular/angular-cli/commit/1b5e18e7b401efb7ec73d99c4d77d9b29e956724) | fix(@schematics/angular): replace interactive `div` with `button` in application component template | +| [0907b6941](https://github.com/angular/angular-cli/commit/0907b694174d6d684d965baf6cd37b87f49742e8) | fix(@schematics/angular): use stricter semver for `karma-jasmine-html-reporter` | +| [8ad1539c5](https://github.com/angular/angular-cli/commit/8ad1539c5e73bad30eb6eb340379d64db208098c) | fix(@schematics/angular): add 'none' value for the 'style' option of the component schematic | +| [e5ba29c7d](https://github.com/angular/angular-cli/commit/e5ba29c7d54cbd83057cf23a21119ea5a3146993) | fix(@schematics/angular): display warning during migrations when using third-party builders | +| [a44dc02fe](https://github.com/angular/angular-cli/commit/a44dc02feecaf8735f2dc6128a5b6cc5666b4434) | fix(@schematics/angular): add devtools to ng new | + +## Special Thanks: + +Alan Agius, Charles Lyding, David Scourfield, Doug Parker, hien-pham, Joey Perrott, LeonEck, Mike +Jancar, twerske, Vaibhav Singh and originalfrostig + + + +# 12.2.0-rc.0 (2021-07-28) + +### @angular/cli + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | ------------------------------------------- | +| [259e26979](https://github.com/angular/angular-cli/commit/259e26979ebc712ee08fd36fb68a9576c1e02447) | fix(@angular/cli): merge npmrc files values | + +### @angular-devkit/build-angular + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | +| [d750c686f](https://github.com/angular/angular-cli/commit/d750c686fd26f3ccfccb039027bd816a91279497) | fix(@angular-devkit/build-angular): add priority to copy-webpack-plugin patterns | + +### @angular-devkit/build-webpack + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | +| [615353022](https://github.com/angular/angular-cli/commit/61535302204a2a767f85053b7efaa6ac5ac64098) | fix(@angular-devkit/build-webpack): emit result when webpack is closed | + +## Special Thanks: + +Alan Agius, Charles Lyding, Joey Perrott and originalfrostig + + + +# 12.1.4 (2021-07-28) + +### @angular/cli + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | ------------------------------------------- | +| [e02c97dd0](https://github.com/angular/angular-cli/commit/e02c97dd09399443438b32cf1ad47fa0f7011df3) | fix(@angular/cli): merge npmrc files values | + +### @schematics/angular + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | +| [cfc267426](https://github.com/angular/angular-cli/commit/cfc267426716e9ecf0c9833720cb35298284f699) | fix(@schematics/angular): ensure valid SemVer range for new project Angular packages | + +### @angular-devkit/build-angular + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | +| [55c0bddc8](https://github.com/angular/angular-cli/commit/55c0bddc8b2425309f00733eca96c06f60f867d5) | fix(@angular-devkit/build-angular): add priority to copy-webpack-plugin patterns | + +### @angular-devkit/build-webpack + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | +| [b3736a3c0](https://github.com/angular/angular-cli/commit/b3736a3c09f39f5ee5dc12d98535fe4b6803ea3b) | fix(@angular-devkit/build-webpack): emit result when webpack is closed | + +## Special Thanks: + +Alan Agius, Charles Lyding, Joey Perrott and originalfrostig + + + +# 12.2.0-next.3 (2021-07-21) + +### @angular/cli + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | +| [c1eddbdc9](https://github.com/angular/angular-cli/commit/c1eddbdc98631fdfff287ce566d79ed43b601e0f) | fix(@angular/cli): handle `YARN_` environment variables during `ng update` and `ng add` | +| [6b00d1270](https://github.com/angular/angular-cli/commit/6b00d1270acaf33f32ee68c4254ce06951ddcb8c) | fix(@angular/cli): handle NPM_CONFIG environment variables during ng update and ng add | + +### @angular-devkit/build-angular + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | +| [4bcd1dc9e](https://github.com/angular/angular-cli/commit/4bcd1dc9ee744343a465d73d51d4a062964a3714) | fix(@angular-devkit/build-angular): allow classes with pure annotated static properties to be optimized | +| [ceade0c27](https://github.com/angular/angular-cli/commit/ceade0c27e4b8b0e731e6ca5128fd86cf071d029) | fix(@angular-devkit/build-angular): dasherize disable-host-check suggestion | + +## Special Thanks: + +Alan Agius, Charles Lyding, Joey Perrott, LeonEck and Mike Jancar + + + +# 12.1.3 (2021-07-21) + +### @angular/cli + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | +| [eaa2378b6](https://github.com/angular/angular-cli/commit/eaa2378b6bc69a2485cce742ef95b0b94ae994c6) | fix(@angular/cli): handle `YARN_` environment variables during `ng update` and `ng add` | +| [4b9a41bde](https://github.com/angular/angular-cli/commit/4b9a41bdedcdc4e115e8956d31126c5bf6f442ca) | fix(@angular/cli): handle NPM_CONFIG environment variables during ng update and ng add | + +### @angular-devkit/build-angular + +| Commit | Description | +| --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | +| [04e9ffe4f](https://github.com/angular/angular-cli/commit/04e9ffe4f6b262ce5ef630310bed318e1466d238) | fix(@angular-devkit/build-angular): allow classes with pure annotated static properties to be optimized | +| [6ae17e265](https://github.com/angular/angular-cli/commit/6ae17e26547a0174f7a8910c514016db60fe4c7a) | fix(@angular-devkit/build-angular): dasherize disable-host-check suggestion | + +## Special Thanks: + +Alan Agius, Charles Lyding, Joey Perrott, LeonEck and Mike Jancar + + + +# v12.2.0-next.2 (2021-07-14) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (12.2.0-next.2)

Commit + Description + Notes +
+ + + silence Sass compiler warnings from 3rd party stylesheets + + [Closes #21235]
+
+ +
+ + + force linker `sourceMapping` option to false. + + [Closes #21271]
+
+ +
+ + + ensure `NG_PERSISTENT_BUILD_CACHE` always creates a cache in the specified cache directory +
+ + + fail browser build when index generation fails +
+ + + fix issue were `@media all` causing critical CSS inling to fail + + [Closes #20804]
+
+ +
+ + + `extractLicenses` didn't have an effect when using server builder +
+ + + display incompatibility errors + + [Closes #21322]
+
+ +
+ + + limit advanced terser passes to two +
+ + + exclude `outputPath` from persistent build cache key + + [Closes #21275]
+
+ +
+ + + use `esbuild` as a CSS optimizer for component styles +

@ngtools/webpack (12.2.0-next.2)

Commit + Description + Notes +
+ + + only track file dependencies + + [Closes #21228]
+
+ +
+ + + allow generated assets of Angular component resources +
+ + + avoid non-actionable template type-checker syntax diagnostics +

@schematics/angular (12.2.0-next.2)

Commit + Description + Notes +
+ + + destroy test module after every test + + [Closes #21280]
+
+ +
+ + + remove unsafe any usage in application spec file +
+ + + replace interactive `div` with `button` in application component template +
+ + + use stricter semver for `karma-jasmine-html-reporter` +
+ +--- + +--- + +# Special Thanks + +Alan Agius, Charles Lyding, Joey Perrott + + + +# v12.1.2 (2021-07-14) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (12.1.2)

Commit + Description + Notes +
+ + + silence Sass compiler warnings from 3rd party stylesheets + + [Closes #21235]
+
+ +
+ + + ensure `NG_PERSISTENT_BUILD_CACHE` always creates a cache in the specified cache directory +
+ + + force linker `sourceMapping` option to false. + + [Closes #21271]
+
+ +
+ + + fail browser build when index generation fails +
+ + + `extractLicenses` didn't have an effect when using server builder +
+ + + fix issue were `@media all` causing critical CSS inling to fail + + [Closes #20804]
+
+ +
+ + + display incompatibility errors + + [Closes #21322]
+
+ +
+ + + exclude `outputPath` from persistent build cache key + + [Closes #21275]
+
+ +

@ngtools/webpack (12.1.2)

Commit + Description + Notes +
+ + + only track file dependencies + + [Closes #21228]
+
+ +
+ + + allow generated assets of Angular component resources +
+ + + avoid non-actionable template type-checker syntax diagnostics +

@schematics/angular (12.1.2)

Commit + Description + Notes +
+ + + remove unsafe any usage in application spec file +
+ + + replace interactive `div` with `button` in application component template +
+ + + use stricter semver for `karma-jasmine-html-reporter` +
+ +--- + +--- + +# Special Thanks + +Alan Agius, Charles Lyding, Joey Perrott, Terence D. Honles + + + +# v12.1.1 (2021-07-01) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (12.1.1)

Commit + Description + Notes +
+ + + handle `ENOENT` and `ENOTDIR` errors when deleting outputs + + [Closes #21202]
+
+ +
+ + + downlevel `for await...of` when targetting ES2018+ + + [Closes #21196]
+
+ +
+ + + configure webpack target in common configuration + + [Closes #21239]
+
+ +
+ + + update `mini-css-extract-plugin` to `1.6.2` +
+ + + update `webpack` to `5.41.1` +

@angular/cli (12.1.1)

Commit + Description + Notes +
+ + + disable update notifier when retrieving package manager version during `ng version` + + [Closes #21172]
+
+ +

@ngtools/webpack (12.1.1)

Commit + Description + Notes +
+ + + encode component style data + + [Closes #21236]
+
+ +
+ +--- + +--- + +# Special Thanks + +Alan Agius, Charles Lyding, Doug Parker + + +# v12.2.0-next.1 (2021-07-01) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (12.2.0-next.1)

Commit + Description + Notes +
+ + + add support to inline Adobe Fonts + + [Closes #21186]
+
+ +
+ + + handle `ENOENT` and `ENOTDIR` errors when deleting outputs + + [Closes #21202]
+
+ +
+ + + downlevel `for await...of` when targetting ES2018+ + + [Closes #21196]
+
+ +
+ + + configure webpack target in common configuration + + [Closes #21239]
+
+ +
+ + + use combination of `esbuild` and `terser` as a JavaScript optimizer +
+ + + cache JavaScriptOptimizerPlugin results +

@angular/cli (12.2.0-next.1)

Commit + Description + Notes +
+ + + disable update notifier when retrieving package manager version during `ng version` + + [Closes #21172]
+
+ +

@ngtools/webpack (12.2.0-next.1)

Commit + Description + Notes +
+ + + encode component style data + + [Closes #21236]
+
+ +
+ +--- + +--- + +# Special Thanks + +Alan Agius, Charles Lyding, Doug Parker + + +# v12.2.0-next.0 (2021-06-24) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (12.1.0)

Commit + Description + Notes +
+ + + handle ng-packagr errors more gracefully. +
+ + + control linker template sourcemapping via builder sourcemap options +
+ + + parse web-workers in tests when webWorkerTsConfig is defined +

@ngtools/webpack (12.1.0)

Commit + Description + Notes +
+ + + remove no longer needed component styles workaround +

@schematics/angular (12.1.0)

Commit + Description + Notes +
+ + + add 'none' value for the 'style' option of the component schematic +
+ + + display warning during migrations when using third-party builders +
+ + + add devtools to ng new +
+ +--- + +--- + +# Special Thanks + +Alan Agius, Charles Lyding, Doug Parker, Vaibhav Singh, Joey Perrott, twerske, David Scourfield, hien-pham + + +# v12.1.0 (2021-06-24) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (12.1.0)

Commit + Description + Notes +
+ + + enable webpack Trusted Types support +
+ + + deprecate protractor builder +
+ + + suppport using TypeScript 4.3 +
+ + + revert open to 8.0.2 + + [Closes #20807]
+
+ +
+ + + correctly ignore inline styles during i18n extraction +
+ + + use the name as chunk filename instead of id +
+ + + handle ng-packagr errors more gracefully. +
+ + + control linker template sourcemapping via builder sourcemap options +
+ + + parse web-workers in tests when webWorkerTsConfig is defined +
+ + + use CSS optimization plugin that leverages workers +
+ + + enable opt-in usage of file system cache +

@angular/cli (12.1.0)

Commit + Description + Notes +
+ + + show Node.js version support status in version command + + [Closes #20879]
+
+ +
+ + + handle unscoped authentication details in `.npmrc` files +
+ + + don't resolve `.npmrc` from parent directories +

@ngtools/webpack (12.1.0)

Commit + Description + Notes +
+ + + support using TypeScript 4.3 +
+ + + remove redundant inline style cache +
+ + + ensure plugin provided Webpack instance is used +
+ + + disable caching for ngcc synchronous Webpack resolver +
+ + + remove no longer needed component styles workaround +

@schematics/angular (12.1.0)

Commit + Description + Notes +
+ + + create new projects with TypeScript 4.3 +
+ + + add migration to replace deprecated `--prod` + + [Closes #21036]
+
+ +
+ + + add 'none' value for the 'style' option of the component schematic +
+ + + display warning during migrations when using third-party builders +
+ + + add devtools to ng new +
+ +--- + +--- + +# Special Thanks + +Alan Agius, Charles Lyding, Doug Parker, Joey Perrott, Bjarki, Vaibhav Singh, twerske, David Scourfield, hien-pham, Alberto Calvo, Paul Gschwendtner, Keen Yee Liau + + +# v12.1.0-next.6 (2021-06-17) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (12.1.0-next.6)

Commit + Description + Notes +
+ + + don't parse `new Worker` syntax when `webWorkerTsConfig` is not defined in karma builder + + [Closes #21108]
+
+ +
+ + + explicitly set compilation target in test configuration + + [Closes #21111]
+
+ +
+ + + use the name as chunk filename instead of id +
+ + + enable opt-in usage of file system cache +

@angular/cli (12.1.0-next.6)

Commit + Description + Notes +
+ + + handle unscoped authentication details in `.npmrc` files +
+ + + don't resolve `.npmrc` from parent directories +

@schematics/angular (12.1.0-next.6)

Commit + Description + Notes +
+ + + add migration to replace deprecated `--prod` + + [Closes #21036]
+
+ +
+ +--- + +--- + +# Special Thanks + +Alan Agius, Joey Perrott, Alberto Calvo, Charles Lyding + + +# v12.0.5 (2021-06-17) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (12.0.5)

Commit + Description + Notes +
+ + + don't parse `new Worker` syntax when `webWorkerTsConfig` is not defined in karma builder + + [Closes #21108]
+
+ +
+ + + explicitly set compilation target in test configuration + + [Closes #21111]
+
+ +

@angular/cli (12.0.5)

Commit + Description + Notes +
+ + + handle unscoped authentication details in .npmrc files +
+ +--- + +--- + +# Special Thanks + +Alan Agius, Joey Perrott + + + +# v12.1.0-next.5 (2021-06-10) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (12.1.0-next.5)

Commit + Description + Notes +
+ + + suppport using TypeScript 4.3 +
+ + + ensure all Webpack Stats assets are present on rebuilds + + [Closes #21038]
+
+ +
+ + + dispose Sass worker resources on Webpack shutdown + + [Closes #20985]
+
+ +
+ + + show progress during re-builds +
+ + + correctly mark async chunks as non initial in dev-server +
+ + + add web-workers in lazy chunks in stats output + + [Closes #21059]
+
+ +
+ + + styles CSS files not available in unit tests + + [Closes #21054]
+
+ +
+ + + reduce memory usage by cleaning output directory before emitting +

@angular-devkit/schematics (12.1.0-next.5)

Commit + Description + Notes +
+ + + handle updating renamed files + + [Closes #14255]
+
+ + + [Closes #21083]
+
+ +

@angular/cli (12.1.0-next.5)

Commit + Description + Notes +
+ + + avoid shell exec when bootstrapping update command +
+ + + correctly redirect nested Angular schematic dependency requests + + [Closes #21075]
+
+ +

@ngtools/webpack (12.1.0-next.5)

Commit + Description + Notes +
+ + + support using TypeScript 4.3 +
+ + + ensure plugin provided Webpack instance is used +
+ + + disable caching for ngcc synchronous Webpack resolver +

@schematics/angular (12.1.0-next.5)

Commit + Description + Notes +
+ + + create new projects with TypeScript 4.3 +
+ + + added webWorkerTsConfig into test option +
+ + + working with formatting +
+ +--- + +--- + +# Special Thanks + +Charles Lyding, Alan Agius, Doug Parker, Santosh Mahto, Joey Perrott + + +# v12.0.4 (2021-06-09) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (12.0.4)

Commit + Description + Notes +
+ + + ensure all Webpack Stats assets are present on rebuilds + + [Closes #21038]
+
+ +
+ + + dispose Sass worker resources on Webpack shutdown + + [Closes #20985]
+
+ +
+ + + show progress during re-builds +
+ + + correctly mark async chunks as non initial in dev-server +
+ + + add web-workers in lazy chunks in stats output + + [Closes #21059]
+
+ +
+ + + styles CSS files not available in unit tests + + [Closes #21054]
+
+ +
+ + + reduce memory usage by cleaning output directory before emitting +

@angular-devkit/schematics (12.0.4)

Commit + Description + Notes +
+ + + handle updating renamed files + + [Closes #14255]
+
+ + + [Closes #21083]
+
+ +

@angular/cli (12.0.4)

Commit + Description + Notes +
+ + + avoid shell exec when bootstrapping update command +
+ + + correctly redirect nested Angular schematic dependency requests + + [Closes #21075]
+
+ +

@ngtools/webpack (12.0.4)

Commit + Description + Notes +
+ + + ensure plugin provided Webpack instance is used +

@schematics/angular (12.0.4)

Commit + Description + Notes +
+ + + added webWorkerTsConfig into test option +
+ + + working with formatting +
+ +--- + +--- + +# Special Thanks + +Alan Agius, Charles Lyding, Santosh Mahto, Joey Perrott, Doug Parker + + +# v12.0.3 (2021-06-02) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (12.0.3)

Commit + Description + Notes +
+ + + do not resolve web-workers in server builds + + [Closes #20877]
+
+ +
+ + + provided earlier build feedback in console + + [Closes #20957]
+
+ +
+ + + correctly ignore inline styles during i18n extraction + + [Closes #20968]
+
+ +
+ + + update `license-webpack-plugin` to `2.3.19` +

@angular-devkit/build-webpack (0.1200.3)

Commit + Description + Notes +
+ + + include only required stats in webpackStats +

@angular-devkit/core (12.0.3)

Commit + Description + Notes +
+ + + show allowed enum values when validation on enum fails +
+ + + handle complex smart defaults in schemas +
+ + + handle async schema validations +
+ + + transform path using getSystemPath for NodeJsAsyncHost's `exists` method +

@angular/cli (12.0.3)

Commit + Description + Notes +
+ + + update supported range of node versions to be less restrictive + + [Closes #20796]
+
+ +

@ngtools/webpack (12.0.3)

Commit + Description + Notes +
+ + + normalize paths when adding file dependencies + + [Closes #20891]
+
+ +
+ + + remove redundant inline style cache +

@schematics/angular (12.0.3)

Commit + Description + Notes +
+ + + make version 12 workspace config migration idempotent + + [Closes #20979]
+
+ +
+ + + show better error when non existing project is passed to the component schematic +
+ +--- + +--- + +# Special Thanks + +Alan Agius, Doug Parker, Charles Lyding, why520crazy + + +# v12.1.0-next.4 (2021-06-02) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (12.1.0-next.4)

Commit + Description + Notes +
+ + + do not resolve web-workers in server builds + + [Closes #20877]
+
+ +
+ + + provided earlier build feedback in console + + [Closes #20957]
+
+ +
+ + + correctly ignore inline styles during i18n extraction +

@angular-devkit/build-webpack (0.1201.0-next.4)

Commit + Description + Notes +
+ + + include only required stats in webpackStats +

@angular-devkit/core (12.1.0-next.4)

Commit + Description + Notes +
+ + + show allowed enum values when validation on enum fails +
+ + + handle complex smart defaults in schemas +
+ + + handle async schema validations +
+ + + transform path using getSystemPath for NodeJsAsyncHost's `exists` method +

@angular/cli (12.1.0-next.4)

Commit + Description + Notes +
+ + + update supported range of node versions to be less restrictive + + [Closes #20796]
+
+ +

@ngtools/webpack (12.1.0-next.4)

Commit + Description + Notes +
+ + + normalize paths when adding file dependencies + + [Closes #20891]
+
+ +
+ + + remove redundant inline style cache +

@schematics/angular (12.1.0-next.4)

Commit + Description + Notes +
+ + + make version 12 workspace config migration idempotent + + [Closes #20979]
+
+ +
+ + + show better error when non existing project is passed to the component schematic +
+ +--- + +--- + +# Special Thanks + +Alan Agius, Doug Parker, Charles Lyding, why520crazy + + +# v12.1.0-next.3 (2021-05-26) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (12.1.0-next.3)

Commit + Description + Notes +
+ + + enable webpack Trusted Types support +
+ + + deprecate protractor builder +
+ + + ensure Sass worker implementation supports Node.js 12.14 +
+ + + don't add `.hot-update.js` script tags + + [Closes #20855]
+
+ +
+ + + correctly generate ServiceWorker config on Windows + + [Closes #20894]
+
+ +
+ + + ensure latest inline stylesheet data is used during rebuilds +
+ + + allow i18n extraction on application that uses web-workers + + [Closes #20930]
+
+ +
+ + + hide stacktraces from dart-sass errors +
+ + + resolve absolute outputPath properly + + [Closes #20935]
+
+ +
+ + + show `--disable-host-check` warning only when not using `disableHostCheck` + + [Closes #20951]
+
+ +
+ + + disable CSS optimization parallelism for components styles + + [Closes #20883]
+
+ +
+ + + load postcss-preset-env configuration once +

@angular/cli (12.1.0-next.3)

Commit + Description + Notes +
+ + + show Node.js version support status in version command + + [Closes #20879]
+
+ +
+ + + ng update on windows to allow path +

@ngtools/webpack (12.1.0-next.3)

Commit + Description + Notes +
+ + + re-emit component stylesheet assets + + [Closes #20882]
+
+ +
+ +--- + +--- + +# Special Thanks + +Alan Agius, Charles Lyding, Doug Parker, Bjarki, Hassan Sani, JoostK, George Kalpakas, Joey Perrott + + +# v12.0.2 (2021-05-26) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (12.0.2)

Commit + Description + Notes +
+ + + ensure Sass worker implementation supports Node.js 12.14 +
+ + + don't add `.hot-update.js` script tags + + [Closes #20855]
+
+ +
+ + + correctly generate ServiceWorker config on Windows + + [Closes #20894]
+
+ +
+ + + ensure latest inline stylesheet data is used during rebuilds +
+ + + allow i18n extraction on application that uses web-workers + + [Closes #20930]
+
+ +
+ + + hide stacktraces from dart-sass errors +
+ + + resolve absolute outputPath properly + + [Closes #20935]
+
+ +
+ + + show `--disable-host-check` warning only when not using `disableHostCheck` + + [Closes #20951]
+
+ +
+ + + update PostCSS to 8.3 +
+ + + disable CSS optimization parallelism for components styles + + [Closes #20883]
+
+ +
+ + + load postcss-preset-env configuration once +

@angular/cli (12.0.2)

Commit + Description + Notes +
+ + + ng update on windows to allow path +

@ngtools/webpack (12.0.2)

Commit + Description + Notes +
+ + + re-emit component stylesheet assets + + [Closes #20882]
+
+ +
+ +--- + +--- + +# Special Thanks + +Alan Agius, Charles Lyding, Doug Parker, Hassan Sani, JoostK, George Kalpakas, Joey Perrott + + +# v12.0.1 (2021-05-19) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (12.0.1)

Commit + Description + Notes +
+ + + add experimental web-assembly + + [Closes #20762]
+
+ +
+ + + fix error with inline styles when running extract-i18n +
+ + + add `NG_BUILD_MAX_WORKERS` settimgs to control maximum number of workers +
+ + + non injected styles should not count as initial + + [Closes #20781]
+
+ +
+ + + revert open to 8.0.2 + + [Closes #20807]
+
+ +
+ + + correctly resolve babel runtime helpers + + [Closes #20800]
+
+ +
+ + + compile schema in synchronously + + [Closes #20847]
+
+ +
+ + + execute dart-sass in a worker +
+ + + reduce JSON stats +
+ + + use CSS optimization plugin that leverages workers +
+ + + render Sass using a pool of workers +
+ + + clean no-longer used assets during builds +

@angular/cli (12.0.1)

Commit + Description + Notes +
+ + + cannot locate bin for temporary package +
+ + + clean node modules directory prior to updating +
+ + + improve `--prod` deprecation warning + + [Closes #20806]
+
+ +

@ngtools/webpack (12.0.1)

Commit + Description + Notes +
+ + + reduce non-watch mode TypeScript diagnostic analysis overhead +

@schematics/angular (12.0.1)

Commit + Description + Notes +
+ + + remove --prod option from README template +
+ + + don't add `skipTest` option to module schematic options + + [Closes #20811]
+
+ +
+ + + add migration to remove `skipTests` from `@schematics/angular:module` + + [Closes #20848]
+
+ +
+ +--- + +--- + +# Special Thanks + +Alan Agius, Charles Lyding, Joey Perrott, Keen Yee Liau, Luca Vazzano, Pankaj Patil, Ryan Lester, Terence D. Honles, Alan Cohen + + + +# v12.1.0-next.2 (2021-05-19) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (12.1.0-next.2)

Commit + Description + Notes +
+ + + add experimental web-assembly + + [Closes #20762]
+
+ +
+ + + add `NG_BUILD_MAX_WORKERS` settimgs to control maximum number of workers +
+ + + non injected styles should not count as initial + + [Closes #20781]
+
+ +
+ + + revert open to 8.0.2 + + [Closes #20807]
+
+ +
+ + + correctly resolve babel runtime helpers + + [Closes #20800]
+
+ +
+ + + compile schema in synchronously + + [Closes #20847]
+
+ +
+ + + execute dart-sass in a worker +
+ + + reduce JSON stats +
+ + + use CSS optimization plugin that leverages workers +
+ + + render Sass using a pool of workers +
+ + + clean no-longer used assets during builds +

@angular/cli (12.1.0-next.2)

Commit + Description + Notes +
+ + + cannot locate bin for temporary package +
+ + + clean node modules directory prior to updating +
+ + + improve `--prod` deprecation warning + + [Closes #20806]
+
+ +

@ngtools/webpack (12.1.0-next.2)

Commit + Description + Notes +
+ + + reduce non-watch mode TypeScript diagnostic analysis overhead +

@schematics/angular (12.1.0-next.2)

Commit + Description + Notes +
+ + + remove --prod option from README template +
+ + + don't add `skipTest` option to module schematic options + + [Closes #20811]
+
+ +
+ + + add migration to remove `skipTests` from `@schematics/angular:module` + + [Closes #20848]
+
+ +
+ +--- + +--- + +# Special Thanks + +Alan Agius, Charles Lyding, Joey Perrott, Keen Yee Liau, Luca Vazzano, Pankaj Patil, Ryan Lester, Alan Cohen, Paul Gschwendtner + + +# v12.0.0 (2021-05-12) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/architect (0.1200.0)

Commit + Description + Notes +
+ + + add implementation for defaultConfiguration +

@angular-devkit/build-angular (12.0.0)

Commit + Description + Notes +
+ + + add `postcss-preset-env` with stage 3 features +
+ + + drop support for karma version 5.2 +
+ + + drop support for ng-packagr version 11 +
+ + + enable inlineCritical by default +
+ + + show warning during build when project requires IE 11 support +
+ + + expose legacy-migrate message format +
+ + + integrate JIT mode linker + + [Closes #20281]
+
+ +
+ + + upgrade to Webpack 5 throughout the build system +
+ + + support processing component inline CSS styles +
+ + + support specifying stylesheet language for inline component styles +
+ + + remove left-over `experimentalRollupPass` option +
+ + + support writing large Webpack stat outputs +
+ + + ensure output directory is present before writing stats JSON +
+ + + remove deprecated View Engine support for i18n extraction +
+ + + remove usage of deprecated View Engine compiler +
+ + + remove deprecated i18nLocale and i18nFormat options from i18n-extract +
+ + + update karma builder to use non-deprecated API +
+ + + disable webpack cache when using `NG_BUILD_CACHE` +
+ + + remove duplicate application bundle generation complete message +
+ + + mark programmatic builder execution functions as experimental +
+ + + avoid double build optimizer processing +
+ + + replace Webpack 4 `hashForChunk` hook usage +
+ + + use new Webpack watch API in karma webpack plugin +
+ + + recover from CSS optimization errors +
+ + + disable Webpack 5 automatic public path support +
+ + + always inject live reload client when using live reload +
+ + + change several builder options defaults +
+ + + show warning when using stylus +
+ + + avoid triggering file change after file build +
+ + + remove left-over `forkTypeChecker` option +
+ + + disable CSS declaration sorting optimizations + + [Closes #20693]
+
+ +
+ + + disable `showCircularDependencies` by default +
+ + + use Webpack's GC memory caching in watch mode +
+ + + improve incremental time during Karma tests +
+ + + avoid async downlevel for known ES2015 code +

@angular-devkit/build-optimizer (0.1200.0)

Commit + Description + Notes +
+ + + support Webpack 5 +

@angular-devkit/build-webpack (0.1200.0)

Commit + Description + Notes +
+ + + provide output path in builder results +
+ + + support Webpack 5 +

@angular-devkit/core (12.0.0)

Commit + Description + Notes +
+ + + add handling for `defaultConfiguration` target definition property +
+ + + update schema validator +
+ + + ensure job input values are processed in order +
+ + + improve handling of set schema values + + [Closes #20594]
+
+ +

@angular/cli (12.0.0)

Commit + Description + Notes +
+ + + add `defaultConfiguration` property to architect schema +
+ + + deprecate `--prod` command line argument +
+ + + confirm ng add action before installation +
+ + + support TypeScript 4.2 +
+ + + ensure odd number Node.js version message is a warning +
+ + + remove npm 7 incompatibility notification +
+ + + avoid exceptions for expected errors in architect commands +
+ + + ensure update migrations are fully executed +
+ + + exclude deprecated packages with removal migrations from update +
+ + + add message update updating from non LTS versions of the CLI +
+ + + ignore `tsickle` during updates +
+ + + run all migrations when updating from or between prereleases +
+ + + add package manager name and version in `ng version` output +
+ + + Support XDG Base Directory Specfication +
+ + + don't display options multiple times in schematics help output +
+ + + change package installation to async +
+ + + infer schematic defaults correctly when using `--project` + + [Closes #20666]
+
+ +
+ + + propagate update's force option to package managers +
+ + + allow unsetting config when value is `undefined` +
+ + + allow config object to be of JSON. +
+ + + disallow additional properties in builders sections +

@ngtools/webpack (12.0.0)

Commit + Description + Notes +
+ + + support Webpack 5 +
+ + + drop support for string based lazy loading +
+ + + support multiple plugin instances per compilation +
+ + + support generating data URIs for inline component styles in JIT +
+ + + support processing inline component styles in AOT +
+ + + remove Webpack 5 deprecation warning in resource loader +
+ + + use correct Webpack asset stage in resource loader +
+ + + remove Webpack plugin for deprecated ViewEngine compiler +
+ + + only track actual resource file dependencies +
+ + + avoid adding transitive dependencies to Webpack's dependency graph +
+ + + use precalculated dependencies in unused file check +
+ + + only check affected files for Angular semantic diagnostics +
+ + + cache results of processed inline resources +
+ + + rebuild Angular required files asynchronously +
+ + + reduce source file and Webpack module iteration +

@schematics/angular (12.0.0)

Commit + Description + Notes +
+ + + add migration to remove deprecated options from 'angular.json' +
+ + + strict mode by default +
+ + + use new zone.js entry-points +
+ + + add migration to use new zone.js entry-points +
+ + + add migration to remove emitDecoratorMetadata +
+ + + augment `universal` schematics to import `platform-server` shims + + [Closes #40559]
+
+ +
+ + + update new project dependencies version + + [Closes #20106]
+
+ +
+ + + production builds by default +
+ + + deprecate `legacyBrowsers` application and ng-new option +
+ + + add migration to remove `lazyModules` configuration option +
+ + + add migration to update lazy loading string syntax to use dynamic imports +
+ + + update several TypeScript compilation target (Syntax) +
+ + + remove tslint and codelyzer from new projects + + [Closes #20105]
+
+ + + [Closes #18465]
+
+ +
+ + + add production by default optional migration +
+ + + update new workspaces to use Karma 6.3 +
+ + + remove `entryComponent` from `component` schematic +
+ + + configure new libraries to be published in Ivy partial mode +
+ + + update `jasmine-spec-reporter` to version 7 +
+ + + migrate web workers to support Webpack 5 +
+ + + only update removed v12 options in migration +
+ + + add `additionalProperties` to all schemas +
+ + + remove references to the prod flag +
+ + + only show legacy browsers deprecation warning when option is used +
+ + + remove leftover workspace tslint config +
+ + + correctly handle adding multi-line strings to `@NgModule` metadata +
+ + + run update-i18n migration for server builder +
+ + + update web-worker to support Webpack 5 +
+ + + set `inlineStyleLanguage` when application `style` option is used +
+ + + set `inlineStyleLanguage` for universal if present in build options +
+ + + remove jasmine-spec-reporter and ts-node from default workspace +
+ + + remove Protractor from home page +
+ + + remove lint command from package.json + + [Closes #20618]
+
+ +
+ + + fix migration for namedChunks and option +
+ + + add "type" option in enum schematic +
+ + + only run `emitDecoratorMetadata` removal migration in safe workspaces +
+ + + replace `clientProject` with `project` +
+ +--- + +  + +# Breaking Changes + +

+ @schematics/angular: remove `stylus` from `style` options (fd729ac) +

+`styl` (Stylus) is no longer a supported value as `style` in `application`, `component`, `ng-new` schematics. Stylus is not actively maintained and only 0.3% of the Angular CLI users use it. + +(cherry picked from commit 0272fc55b67d1a3f986b996c8eb21aea31eedf51) + +

+ @angular-devkit/build-angular: change several builder options defaults (656f8d7) +

+A number of browser and server builder options have had their default values changed. The aim of these changes is to reduce the configuration complexity and support the new "production builds by default" initiative. + +**Browser builder** +| Option | Previous default value | New default value | +|----------------------------------------|---------------------------|-------------------| +| optimization | false | true | +| aot | false | true | +| buildOptimizer | false | true | +| sourceMap | true | false | +| extractLicenses | false | true | +| namedChunks | true | false | +| vendorChunk | true | false | + +**Server builder** +| Option | Previous default value | New default value | +|---------------|------------------------|-------------------| +| optimization | false | true | +| sourceMap | true | false | + +(cherry picked from commit 0a74d0d28daf68510459ed73ef048c91bfcabbbc) + +

+ @angular-devkit/core: update schema validator (0875313) +

+support for JSON Schema draft-04 and draft-06 is removed. If you have schemas using the `id` keyword replace them with `$id`. For an interim period we will auto rename any top level `id` keyword to `$id`. + +**NB**: This change only effects schematics and builders authors. + +

+ @angular-devkit/build-angular: upgrade to Webpack 5 throughout the build system (d883ce5) +

+Webpack 5 lazy loaded file name changes +Webpack 5 generates similar but differently named files for lazy loaded JavaScript files in development configurations (when the `namedChunks` option is enabled). +For the majority of users this change should have no effect on the application and/or build process. Production builds should also not be affected as the `namedChunks` option is disabled by default in production configurations. +However, if a project's post-build process makes assumptions as to the file names then adjustments may need to be made to account for the new naming paradigm. +Such post-build processes could include custom file transformations after the build, integration into service-side frameworks, or deployment procedures. +Example development file name change: `lazy-lazy-module.js` --> `src_app_lazy_lazy_module_ts.js` + +Webpack 5 now includes web worker support. However, the structure of the URL within the `Worker` constructor must be in a specific format that differs from the current requirement. +Web worker usage should be updated as shown below (where `./app.worker` should be replaced with the actual worker name): +Before: `new Worker('./app.worker', ...)` +After: `new Worker(new URL('./app.worker', import.meta.url), ...)` + +

+ @ngtools/webpack: remove Webpack plugin for deprecated ViewEngine compiler (160102a) +

+Removal of View Engine support from application builds +With the removal of the deprecated View Engine compiler in Angular version 12 for applications, the View Engine Webpack plugin has been removed. +The Ivy-based Webpack plugin is the default used within the Angular CLI. +If using a custom standalone Webpack configuration, the removed `AngularCompilerPlugin` should be replaced with the Ivy-based `AngularWebpackPlugin`. + +

+ @angular-devkit/build-angular: remove deprecated i18n options from server and browser builder (5cf9a08) +

+Removal of deprecated browser and server command options. +- `i18nFile`, use `locales` object in the project metadata instead. +- `i18nFormat`, No longer needed as the format will be determined automatically. +- `i18nLocale`, use `localize` option instead. + +

+ @angular-devkit/build-angular: remove deprecated i18nLocale and i18nFormat options from i18n-extract (eca5a01) +

+Removal of deprecated `extract-i18n` command options +The deprecated `i18nLocale` option has been removed and the `i18n.sourceLocale` within a project's configuration should be used instead. +The deprecated `i18nFormat` option has been removed and the `format` option should be used instead. + +

+ @angular-devkit/build-angular: remove usage of deprecated View Engine compiler (677913f) +

+Removal of View Engine support from application builds +With the removal of the deprecated View Engine compiler in Angular version 12 for applications, Ivy-based compilation will always be used when building an application. +The default behavior for applications is to use the Ivy compiler when building and no changes are required for these applications. +For applications that have opted-out of Ivy, a warning will be shown and an Ivy-based build will be attempted. If the build fails, +the application may need to be updated to become Ivy compatible. + +

+ @schematics/angular: remove `entryComponent` from `component` schematic (8582ddc) +

+`entryComponent` option has been removed from the `component` schematic as this was intended to be used with the the now no longer supported ViewEngine rendering engine. + +

+ @angular-devkit/build-angular: remove view engine app-shell generation (1c2aeeb) +

+App-shell builder now only supports generation using Ivy + +

+ @angular-devkit/build-angular: remove deprecated View Engine support for i18n extraction (012700a) +

+Removal of View Engine support from i18n extraction +With the removal of the deprecated View Engine compiler in Angular version 12 for applications, the `ng extract-i18n` command will now always use the Ivy compiler. +The `--ivy` option has also been removed as Ivy-based extraction is always enabled. +The default behavior for applications is to use the Ivy compiler for building/extraction and no changes are required for these applications. +For applications that have opted-out of Ivy, a warning will be shown and Ivy-based extraction will be attempted. If the extraction fails, +the application may need to be updated to become Ivy compatible. + +

+ @angular/cli: confirm ng add action before installation (985dc1a) +

+The `ng add` command will now ask the user to confirm the package and version prior to installing and executing an uninstalled package. +This new behavior allows a user to abort the action if the version selected is not appropriate or if a typo occurred on the command line and an incorrect package would be installed. +A `--skip-confirmation` option has been added to skip the prompt and directly install and execute the package. This option is useful in CI and non-TTY scenarios such as automated scripts. + +

+ @angular-devkit/build-angular: remove deprecated `lazyModules` option (8d66912) +

+Server and Browser builder `lazyModules` option has been removed without replacement. + +

+ @ngtools/webpack: drop support for string based lazy loading (0dc7327) +

+With this change we drop support for string based lazy loading `./lazy.module#LazyModule` use dynamic imports instead. + +The following options which were used to support the above syntax were removed without replacement. + +- discoverLazyRoutes +- additionalLazyModules +- additionalLazyModuleResources +- contextElementDependencyConstructor + +

+ @angular-devkit/build-angular: enable inlineCritical by default (aa3ea88) +

+Critical CSS inlining is now enabled by default. If you wish to turn this off set `inlineCritical` to `false`. + +See: https://angular.io/guide/workspace-config#optimization-configuration + +

+ @angular-devkit/build-angular: drop support for zone.js 0.10 (f309516) +

+Minimum supported `zone.js` version is `0.11.4` + +

+ @angular-devkit/build-angular: drop support for ng-packagr version 11 (44e75be) +

+Minimum supported `ng-packagr` version is `12.0.0-next` + +

+ @angular-devkit/build-angular: drop support for karma version 5.2 (fa5cf53) +

+Minimum supported `karma` version is `6.0.0` + +

+ set minimum Node.js version to 12.13 (d1f6169) +

+Node.js version 10 will become EOL on 2021-04-30. +Angular CLI 12 will require Node.js 12.13+ or 14.15+. Node.js 12.13 and 14.15 are the first LTS releases for their respective majors. + +

+ @angular-devkit/build-angular: remove file-loader dependency (6732294) +

+The unsupported/undocumented, Webpack specific functionality to `import`/`require()` a non-module file has been removed. + +Before + +```js +import img from './images/asset.png'; +``` + +After + +```html + +``` + +--- + +# Special Thanks + +Alan Agius, Charles Lyding, Keen Yee Liau, Joey Perrott, Doug Parker, Cédric Exbrayat, Douglas Parker, George Kalpakas, Sam Bulatov, Joshua Chapman, Santosh Yadav, David Shevitz, Kristiyan Kostadinov + + +# v12.0.0-rc.3 (2021-05-10) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular/cli (12.0.0-rc.3)

Commit + Description + Notes +
+ + + propagate update's force option to package managers +
+ + + allow unsetting config when value is `undefined` +
+ + + allow config object to be of JSON. +
+ + + disallow additional properties in builders sections +
+ +--- + +# Special Thanks + +Alan Agius, Charles Lyding, Joey Perrott + + +# v12.0.0-rc.2 (2021-05-05) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (12.0.0-rc.2)

Commit + Description + Notes +
+ + + disable CSS declaration sorting optimizations + + [Closes #20693]
+
+ +

@angular/cli (12.0.0-rc.2)

Commit + Description + Notes +
+ + + don't display options multiple times in schematics help output +
+ + + change package installation to async +
+ + + infer schematic defaults correctly when using `--project` + + [Closes #20666]
+
+ +

@ngtools/webpack (12.0.0-rc.2)

Commit + Description + Notes +
+ + + rebuild Angular required files asynchronously +
+ + + reduce source file and Webpack module iteration +

@schematics/angular (12.0.0-rc.2)

Commit + Description + Notes +
+ + + add "type" option in enum schematic +
+ + + only run `emitDecoratorMetadata` removal migration in safe workspaces +
+ + + replace `clientProject` with `project` +
+ +--- + +--- + +# Special Thanks + +Alan Agius, Charles Lyding, Keen Yee Liau, Sam Bulatov, Doug Parker + + +# v12.0.0-rc.1 (2021-04-28) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (12.0.0-rc.1)

Commit + Description + Notes +
+ + + remove left-over `forkTypeChecker` option +
+ + + output webpack-dev-server and webpack-dev-middleware errors +
+ + + improve incremental time during Karma tests +
+ + + avoid async downlevel for known ES2015 code +

@angular-devkit/core (12.0.0-rc.1)

Commit + Description + Notes +
+ + + improve handling of set schema values + + [Closes #20594]
+
+ +

@angular/cli (12.0.0-rc.1)

Commit + Description + Notes +
+ + + add package manager name and version in `ng version` output +
+ + + Support XDG Base Directory Specfication +

@schematics/angular (12.0.0-rc.1)

Commit + Description + Notes +
+ + + remove jasmine-spec-reporter and ts-node from default workspace +
+ + + remove Protractor from home page +
+ + + remove lint command from package.json + + [Closes #20618]
+
+ +
+ + + avoid unuse imports for canLoad guard generation +
+ + + fix migration for namedChunks and option +

@angular-devkit/schematics-cli (12.0.0-rc.1)

Commit + Description + Notes +
+ + + accept windows like paths for schematics +
+ +--- + +--- + +# Special Thanks + +Alan Agius, Charles Lyding, Joey Perrott, Cédric Exbrayat, Doug Parker, Joshua Chapman, Billy Lando, Santosh Yadav, mzocateli + + +# v12.0.0-rc.0 (2021-04-21) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (12.0.0-rc.0)

Commit + Description + Notes +
+ + + avoid double build optimizer processing +
+ + + replace Webpack 4 `hashForChunk` hook usage +
+ + + use new Webpack watch API in karma webpack plugin +
+ + + recover from CSS optimization errors +
+ + + disable Webpack 5 automatic public path support +
+ + + always inject live reload client when using live reload +
+ + + change several builder options defaults +
+ + + show warning when using stylus +
+ + + set Tailwind CSS mode when using Tailwind +
+ + + avoid triggering file change after file build +
+ + + use Webpack's GC memory caching in watch mode +

@angular/cli (12.0.0-rc.0)

Commit + Description + Notes +
+ + + ignore `tsickle` during updates +
+ + + run all migrations when updating from or between prereleases +

@ngtools/webpack (12.0.0-rc.0)

Commit + Description + Notes +
+ + + only track actual resource file dependencies +
+ + + cache results of processed inline resources +

@schematics/angular (12.0.0-rc.0)

Commit + Description + Notes +
+ + + set `inlineStyleLanguage` when application `style` option is used +
+ + + set `inlineStyleLanguage` for universal if present in build options +
+ +--- + +# Breaking Changes + +

+ @schematics/angular: remove `stylus` from `style` options (fd729ac) +

+`styl` (Stylus) is no longer a supported value as `style` in `application`, `component`, `ng-new` schematics. Stylus is not actively maintained and only 0.3% of the Angular CLI users use it. + +(cherry picked from commit 0272fc55b67d1a3f986b996c8eb21aea31eedf51) + +

+ @angular-devkit/build-angular: change several builder options defaults (656f8d7) +

+A number of browser and server builder options have had their default values changed. The aim of these changes is to reduce the configuration complexity and support the new "production builds by default" initiative. + +**Browser builder** +| Option | Previous default value | New default value | +|----------------------------------------|---------------------------|-------------------| +| optimization | false | true | +| aot | false | true | +| buildOptimizer | false | true | +| sourceMap | true | false | +| extractLicenses | false | true | +| namedChunks | true | false | +| vendorChunk | true | false | + +**Server builder** +| Option | Previous default value | New default value | +|---------------|------------------------|-------------------| +| optimization | false | true | +| sourceMap | true | false | + +(cherry picked from commit 0a74d0d28daf68510459ed73ef048c91bfcabbbc) + +--- + +# Special Thanks + +Alan Agius, Charles Lyding, Keen Yee Liau, Joey Perrott, David Shevitz + + +# v12.0.0-next.9 (2021-04-14) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (12.0.0-next.9)

Commit + Description + Notes +
+ + + upgrade to Webpack 5 throughout the build system +
+ + + support processing component inline CSS styles +
+ + + support specifying stylesheet language for inline component styles +
+ + + update karma builder to use non-deprecated API +
+ + + disable webpack cache when using `NG_BUILD_CACHE` +
+ + + remove duplicate application bundle generation complete message +
+ + + mark programmatic builder execution functions as experimental +

@angular-devkit/build-webpack (0.1200.0-next.9)

Commit + Description + Notes +
+ + + support Webpack 5 +

@angular-devkit/core (12.0.0-next.9)

Commit + Description + Notes +
+ + + update schema validator +

@angular/cli (12.0.0-next.9)

Commit + Description + Notes +
+ + + add message update updating from non LTS versions of the CLI +

@ngtools/webpack (12.0.0-next.9)

Commit + Description + Notes +
+ + + support multiple plugin instances per compilation +
+ + + support generating data URIs for inline component styles in JIT +
+ + + support processing inline component styles in AOT +

@schematics/angular (12.0.0-next.9)

Commit + Description + Notes +
+ + + configure new libraries to be published in Ivy partial mode +
+ + + update `jasmine-spec-reporter` to version 7 +
+ + + migrate web workers to support Webpack 5 +
+ + + update web-worker to support Webpack 5 +
+ +--- + +# Breaking Changes + +

+ @angular-devkit/core: update schema validator (0875313) +

+support for JSON Schema draft-04 and draft-06 is removed. If you have schemas using the `id` keyword replace them with `$id`. For an interim period we will auto rename any top level `id` keyword to `$id`. + +**NB**: This change only effects schematics and builders authors. + +

+ @angular-devkit/build-angular: upgrade to Webpack 5 throughout the build system (d883ce5) +

+Webpack 5 generates similar but differently named files for lazy loaded JavaScript files in development configurations (when the `namedChunks` option is enabled). +For the majority of users this change should have no effect on the application and/or build process. Production builds should also not be affected as the `namedChunks` option is disabled by default in production configurations. +However, if a project's post-build process makes assumptions as to the file names then adjustments may need to be made to account for the new naming paradigm. +Such post-build processes could include custom file transformations after the build, integration into service-side frameworks, or deployment procedures. +Example development file name change: `lazy-lazy-module.js` --> `src_app_lazy_lazy_module_ts.js` + +

+ @angular-devkit/build-angular: upgrade to Webpack 5 throughout the build system (d883ce5) +

+Webpack 5 now includes web worker support. However, the structure of the URL within the `Worker` constructor must be in a specific format that differs from the current requirement. +Web worker usage should be updated as shown below (where `./app.worker` should be replaced with the actual worker name): + +Before: + +``` +new Worker('./app.worker', ...) +``` + +After: + +``` +new Worker(new URL('./app.worker', import.meta.url), ...) +``` + +--- + +# Special Thanks + +Alan Agius, Charles Lyding, Keen Yee Liau, Doug Parker, Douglas Parker + + +# v12.0.0-next.8 (2021-04-07) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (0.1200.0-next.8)

Commit + Description + Notes +
+ + + remove deprecated i18nLocale and i18nFormat options from i18n-extract +

@ngtools/webpack (12.0.0-next.8)

Commit + Description + Notes +
+ + + remove Webpack plugin for deprecated ViewEngine compiler +

@schematics/angular (12.0.0-next.8)

Commit + Description + Notes +
+ + + run update-i18n migration for server builder +
+ +--- + +# Breaking Changes + +

+ @ngtools/webpack: remove Webpack plugin for deprecated ViewEngine compiler (160102a) +

+Removal of View Engine support from application builds +With the removal of the deprecated View Engine compiler in Angular version 12 for applications, the View Engine Webpack plugin has been removed. +The Ivy-based Webpack plugin is the default used within the Angular CLI. +If using a custom standalone Webpack configuration, the removed `AngularCompilerPlugin` should be replaced with the Ivy-based `AngularWebpackPlugin`. + +

+ @angular-devkit/build-angular: remove deprecated i18n options from server and browser builder (5cf9a08) +

+Removal of deprecated browser and server command options. +- `i18nFile`, use `locales` object in the project metadata instead. +- `i18nFormat`, No longer needed as the format will be determined automatically. +- `i18nLocale`, use `localize` option instead. + +

+ @angular-devkit/build-angular: remove deprecated i18nLocale and i18nFormat options from i18n-extract (eca5a01) +

+Removal of deprecated `extract-i18n` command options +The deprecated `i18nLocale` option has been removed and the `i18n.sourceLocale` within a project's configuration should be used instead. +The deprecated `i18nFormat` option has been removed and the `format` option should be used instead. + +--- + +# Special Thanks + +Charles Lyding, Renovate Bot, Alan Agius, Doug Parker, Joey Perrott + + +# v12.0.0-next.7 (2021-04-02) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (0.1200.0-next.7)

Commit + Description + Notes +
+ + + validate scripts and styles bundleName + + [Closes #20360]
+
+ +
+ + + remove deprecated View Engine support for i18n extraction +
+ + + remove usage of deprecated View Engine compiler +

@angular/cli (12.0.0-next.7)

Commit + Description + Notes +
+ + + ensure update migrations are fully executed +
+ + + exclude deprecated packages with removal migrations from update +

@ngtools/webpack (12.0.0-next.7)

Commit + Description + Notes +
+ + + use correct Webpack asset stage in resource loader +
+ + + only check affected files for Angular semantic diagnostics +

@schematics/angular (12.0.0-next.7)

Commit + Description + Notes +
+ + + remove `entryComponent` from `component` schematic +
+ + + correctly handle adding multi-line strings to `@NgModule` metadata +
+ + + explicitly specify ServiceWorker registration strategy +
+ +--- + +# Breaking Changes + +

+ @angular-devkit/build-angular: remove usage of deprecated View Engine compiler (677913f) +

+Removal of View Engine support from application builds +With the removal of the deprecated View Engine compiler in Angular version 12 for applications, Ivy-based compilation will always be used when building an application. +The default behavior for applications is to use the Ivy compiler when building and no changes are required for these applications. +For applications that have opted-out of Ivy, a warning will be shown and an Ivy-based build will be attempted. If the build fails, +the application may need to be updated to become Ivy compatible. + +

+ @schematics/angular: remove `entryComponent` from `component` schematic (8582ddc) +

+`entryComponent` option has been removed from the `component` schematic as this was intended to be used with the the now no longer supported ViewEngine rendering engine. + +

+ @angular-devkit/build-angular: remove view engine app-shell generation (1c2aeeb) +

+App-shell builder now only supports generation using Ivy + +

+ @angular-devkit/build-angular: remove deprecated View Engine support for i18n extraction (012700a) +

+Removal of View Engine support from i18n extraction +With the removal of the deprecated View Engine compiler in Angular version 12 for applications, the `ng extract-i18n` command will now always use the Ivy compiler. +The `--ivy` option has also been removed as Ivy-based extraction is always enabled. +The default behavior for applications is to use the Ivy compiler for building/extraction and no changes are required for these applications. +For applications that have opted-out of Ivy, a warning will be shown and Ivy-based extraction will be attempted. If the extraction fails, +the application may need to be updated to become Ivy compatible. + +--- + +# Special Thanks + +Charles Lyding, Alan Agius, Renovate Bot, George Kalpakas, Joey Perrott, Keen Yee Liau + + +# v12.0.0-next.6 (2021-03-24) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (0.1200.0-next.6)

Commit + Description + Notes +
+ + + ensure output directory is present before writing stats JSON +

@schematics/angular (12.0.0-next.6)

Commit + Description + Notes +
+ + + add production by default optional migration +
+ + + update new workspaces to use Karma 6.3 +
+ + + remove leftover workspace tslint config +
+ +--- + +--- + +# Special Thanks + +Renovate Bot, Alan Agius, Charles Lyding, Keen Yee Liau + + +# v12.0.0-next.5 (2021-03-18) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (0.1200.0-next.5)

Commit + Description + Notes +
+ + + expose legacy-migrate message format +
+ + + integrate JIT mode linker + + [Closes #20281]
+
+ +
+ + + display correct filename for bundles that are ES2016+ +
+ + + don't load an input sourcemap from file when using Babel +
+ + + support writing large Webpack stat outputs +
+ + + skip FESM2015 from `async` transformation +
+ + + remove Webpack Stats.toJson usage in analytics plugin +
+ + + remove Webpack Stats.toJson usage in karma plugin +
+ + + enforce Babel not to load sourcemaps from file +
+ + + disable `showCircularDependencies` by default +

@angular-devkit/build-webpack (0.1200.0-next.5)

Commit + Description + Notes +
+ + + provide output path in builder results +

@angular/cli (12.0.0-next.5)

Commit + Description + Notes +
+ + + confirm ng add action before installation +
+ + + support TypeScript 4.2 +
+ + + remove `project` from required properties in ng-packagr schema +

@ngtools/webpack (12.0.0-next.5)

Commit + Description + Notes +
+ + + remove Webpack 5 deprecation warning in resource loader +
+ + + avoid adding transitive dependencies to Webpack's dependency graph +
+ + + use precalculated dependencies in unused file check +

@schematics/angular (12.0.0-next.5)

Commit + Description + Notes +
+ + + update several TypeScript compilation target (Syntax) +
+ + + remove tslint and codelyzer from new projects + + [Closes #20105]
+
+ + + [Closes #18465]
+
+ +
+ + + remove references to the prod flag +
+ + + fix youtube icon margin +
+ + + only show legacy browsers deprecation warning when option is used +
+ + + remove Native value from viewEncapsulation option +
+ + + use title for svg on home page +
+ +--- + +# Breaking Changes + +

+ @angular/cli: confirm ng add action before installation (985dc1a) +

+The `ng add` command will now ask the user to confirm the package and version prior to installing and executing an uninstalled package. +This new behavior allows a user to abort the action if the version selected is not appropriate or if a typo occurred on the command line and an incorrect package would be installed. +A `--skip-confirmation` option has been added to skip the prompt and directly install and execute the package. This option is useful in CI and non-TTY scenarios such as automated scripts. + +--- + +# Special Thanks + +Alan Agius, Charles Lyding, Renovate Bot, Doug Parker, Cédric Exbrayat, Kristiyan Kostadinov, Mouad Ennaciri, Omar Hasan + + +# v12.0.0-next.4 (2021-03-10) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/architect (0.1200.0-next.4)

Commit + Description + Notes +
+ + + add implementation for defaultConfiguration +

@angular-devkit/build-angular (0.1200.0-next.4)

Commit + Description + Notes +
+ + + show warning during build when project requires IE 11 support +
+ + + only remove nomodule and defer attributes empty values + + + [Closes #20207]
+
+ +

@angular-devkit/core (12.0.0-next.4)

Commit + Description + Notes +
+ + + add handling for `defaultConfiguration` target definition property +

@angular/cli (12.0.0-next.4)

Commit + Description + Notes +
+ + + deprecate `--prod` command line argument +
+ + + add `defaultConfiguration` property to architect schema +
+ + + avoid exceptions for expected errors in architect commands +
+ + + add ng-packagr builder schema in IDE schema +

@ngtools/webpack (12.0.0-next.4)

Commit + Description + Notes +
+ + + drop support for string based lazy loading +

@schematics/angular (12.0.0-next.4)

Commit + Description + Notes +
+ + + add migration to update lazy loading string syntax to use dynamic imports +
+ + + add migration to remove `lazyModules` configuration option +
+ + + deprecate `legacyBrowsers` application and ng-new option +
+ + + production builds by default +
+ + + add `additionalProperties` to all schemas +
+ +--- + +# Breaking Changes + +

+ @angular-devkit/build-angular: remove deprecated `lazyModules` option (8d66912) +

+Server and Browser builder `lazyModules` option has been removed without replacement. + +

+ @ngtools/webpack: drop support for string based lazy loading (0dc7327) +

+With this change we drop support for string based lazy loading `./lazy.module#LazyModule` use dynamic imports instead. + +The following options which were used to support the above syntax were removed without replacement. + +- discoverLazyRoutes +- additionalLazyModules +- additionalLazyModuleResources +- contextElementDependencyConstructor + +--- + +# Special Thanks + +Alan Agius, Charles Lyding, Renovate Bot, Joey Perrott + + +# v12.0.0-next.3 (2021-03-03) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (0.1200.0-next.3)

Commit + Description + Notes +
+ + + enable inlineCritical by default +
+ + + remove left-over `experimentalRollupPass` option +
+ + + inline critical font-face rules when using crittical css inlining +

@schematics/angular (12.0.0-next.3)

Commit + Description + Notes +
+ + + update ng new links +
+ +--- + +# Breaking Changes + +

+ @angular-devkit/build-angular: enable inlineCritical by default (aa3ea88) +

+Critical CSS inlining is now enabled by default. If you wish to turn this off set `inlineCritical` to `false`. + +See: https://angular.io/guide/workspace-config#optimization-configuration + +--- + +# Special Thanks + +Renovate Bot, Charles Lyding, Alan Agius, Keen Yee Liau, Douglas Parker, twerske + + +# v12.0.0-next.2 (2021-02-24) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (0.1200.0-next.2)

Commit + Description + Notes +
+ + + only show index and service worker status once +
+ + + disable declaration and declarationMap + + + [Closes #20103]
+
+ +

@angular/cli (12.0.0-next.2)

Commit + Description + Notes +
+ + + remove npm 7 incompatibility notification +

@schematics/angular (12.0.0-next.2)

Commit + Description + Notes +
+ + + update new project dependencies version + + [Closes #20106]
+
+ +
+ + + augment `universal` schematics to import `platform-server` shims + + [Closes #40559]
+
+ +
+ + + add migration to remove emitDecoratorMetadata +
+ +--- + +--- + +# Special Thanks + +Renovate Bot, Charles Lyding, Alan Agius, Doug Parker, Joey Perrott, Jefiozie, George Kalpakas, Keen Yee Liau + + +# v12.0.0-next.1 (2021-02-17) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (0.1200.0-next.1)

Commit + Description + Notes +
+ + + drop support for ng-packagr version 11 +
+ + + drop support for karma version 5.2 +

@angular-devkit/build-optimizer (0.1200.0-next.1)

Commit + Description + Notes +
+ + + support Webpack 5 +

@angular/cli (12.0.0-next.1)

Commit + Description + Notes +
+ + + support update migration packages with no entry points + + + [Closes #20032]
+
+ +
+ + + ensure odd number Node.js version message is a warning +
+ + + improve error logging when resolving update migrations +

@ngtools/webpack (12.0.0-next.1)

Commit + Description + Notes +
+ + + support Webpack 5 +
+ + + normalize paths when pruning AOT rebuild requests +

@schematics/angular (12.0.0-next.1)

Commit + Description + Notes +
+ + + add migration to use new zone.js entry-points +
+ + + use new zone.js entry-points +
+ +--- + +# Breaking Changes + +

+ @angular-devkit/build-angular: drop support for zone.js 0.10 (f309516) +

+Minimum supported `zone.js` version is `0.11.4` + +

+ @angular-devkit/build-angular: drop support for ng-packagr version 11 (44e75be) +

+Minimum supported `ng-packagr` version is `12.0.0-next` + +

+ @angular-devkit/build-angular: drop support for karma version 5.2 (fa5cf53) +

+Minimum supported `karma` version is `6.0.0` + +--- + +# Special Thanks + +Renovate Bot, Alan Agius, Charles Lyding, Keen Yee Liau, Aravind V Nair + + +# v12.0.0-next.0 (2021-02-11) + +# Commits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

@angular-devkit/build-angular (0.1200.0-next.0)

Commit + Description + Notes +
+ + + add `postcss-preset-env` with stage 3 features +
+ + + ensure i18n extraction sourcemaps are fully configured +
+ + + the root Tailwind configuration file is always picked +
+ + + fixed ignoring of karma plugins config + + + [Closes #19993]
+
+ +

@angular-devkit/core (12.0.0-next.0)

Commit + Description + Notes +
+ + + ensure job input values are processed in order +

@angular/cli (12.0.0-next.0)

Commit + Description + Notes +
+ + + update NPM 7 guidance +

@ngtools/webpack (12.0.0-next.0)

Commit + Description + Notes +
+ + + reduce overhead of Angular compiler rebuild requests +

@schematics/angular (12.0.0-next.0)

Commit + Description + Notes +
+ + + strict mode by default +
+ + + add migration to remove deprecated options from 'angular.json' +
+ + + only update removed v12 options in migration +
+ +--- + +# Breaking Changes + +

+ set minimum Node.js version to 12.13 (d1f6169) +

+Node.js version 10 will become EOL on 2021-04-30. +Angular CLI 12 will require Node.js 12.13+ or 14.15+. Node.js 12.13 and 14.15 are the first LTS releases for their respective majors. + +

+ @angular-devkit/build-angular: remove file-loader dependency (6732294) +

+The unsupported/undocumented, Webpack specific functionality to `import`/`require()` a non-module file has been removed. + +Before + +```js +import img from './images/asset.png'; +``` + +After + +```html + +``` + +--- + +# Special Thanks + +Renovate Bot, Charles Lyding, Alan Agius, Doug Parker, Bruno Baia, Amadou Sall, S. Iftekhar Hossain + +--- + +**Note: For release notes prior to this CHANGELOG see [release notes](https://github.com/angular/angular-cli/releases).** diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2c0ac1a2d099..7797df999f36 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -288,18 +288,18 @@ To test if your change effect the public API you need to run the API guardian on For example in case `@angular-devkit/core` package was modified you need to run: ```bash -yarn bazel test //etc/api:angular_devkit_core_api +yarn bazel test //goldens/public-api:angular_devkit_core_api ``` You can also test all packages by running: ```bash -yarn bazel test //etc/api ... +yarn bazel test //goldens/public-api ... ``` If you modified the public API, the test will fail. To update the golden files you need to run: ```bash -yarn bazel run //etc/api:angular_devkit_core_api.accept +yarn bazel run //goldens/public-api:angular_devkit_core_api.accept ``` **Note**: In some cases we use aliased symbols to create namespaces. diff --git a/README.md b/README.md index 340f9daa8e70..4bae010dfd5a 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ To get started locally, follow these instructions: 1. If you haven't done it already, [make a fork of this repo](https://github.com/angular/angular-cli/fork). 1. Clone to your local computer using `git`. -1. Make sure that you have Node 10.13 or later installed. See instructions [here](https://nodejs.org/en/download/). +1. Make sure that you have Node 12.14 or 14.0 installed. See instructions [here](https://nodejs.org/en/download/). 1. Make sure that you have `yarn` installed; see instructions [here](https://yarnpkg.com/lang/en/docs/install/). 1. Run `yarn` (no arguments) from the root of your clone of this project to install dependencies. diff --git a/WORKSPACE b/WORKSPACE index 5d9b136e9034..e2a27f373a6d 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -7,8 +7,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "build_bazel_rules_nodejs", - sha256 = "55a25a762fcf9c9b88ab54436581e671bc9f4f523cb5a1bd32459ebec7be68a8", - urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/3.2.2/rules_nodejs-3.2.2.tar.gz"], + sha256 = "8f5f192ba02319254aaf2cdcca00ec12eaafeb979a80a1e946773c520ae0a2c9", + urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/3.7.0/rules_nodejs-3.7.0.tar.gz"], ) # Check the bazel version and download npm dependencies @@ -31,52 +31,13 @@ check_rules_nodejs_version(minimum_version_string = "2.0.0") # Setup the Node.js toolchain node_repositories( - node_version = "12.20.2", + node_version = "14.16.1", package_json = ["//:package.json"], - yarn_version = "1.22.4", ) yarn_install( name = "npm", - data = [ - "//:tools/yarn/check-yarn.js", - ], package_json = "//:package.json", strict_visibility = False, # Needed for ts-api-guardian. More info about this can be found https://github.com/bazelbuild/rules_nodejs/wiki#strict_visibility-on-yarn_install-and-npm_install-now-defaults-true-2199 yarn_lock = "//:yarn.lock", ) - -########################## -# Remote Execution Setup # -########################## -# Bring in bazel_toolchains for RBE setup configuration. -http_archive( - name = "bazel_toolchains", - sha256 = "1adf5db506a7e3c465a26988514cfc3971af6d5b3c2218925cd6e71ee443fc3f", - strip_prefix = "bazel-toolchains-4.0.0", - url = "https://github.com/bazelbuild/bazel-toolchains/archive/4.0.0.tar.gz", -) - -load("@bazel_toolchains//rules:environments.bzl", "clang_env") -load("@bazel_toolchains//rules:rbe_repo.bzl", "rbe_autoconfig") - -rbe_autoconfig( - name = "rbe_ubuntu1604_angular", - # Need to specify a base container digest in order to ensure that we can use the checked-in - # platform configurations for the "ubuntu16_04" image. Otherwise the autoconfig rule would - # need to pull the image and run it in order determine the toolchain configuration. See: - # https://github.com/bazelbuild/bazel-toolchains/blob/4.0.0/configs/ubuntu16_04_clang/versions.bzl - base_container_digest = "sha256:f6568d8168b14aafd1b707019927a63c2d37113a03bcee188218f99bd0327ea1", - # Note that if you change the `digest`, you might also need to update the - # `base_container_digest` to make sure marketplace.gcr.io/google/rbe-ubuntu16-04-webtest: - # and marketplace.gcr.io/google/rbe-ubuntu16-04: have - # the same Clang and JDK installed. Clang is needed because of the dependency on - # @com_google_protobuf. Java is needed for the Bazel's test executor Java tool. - digest = "sha256:f743114235a43355bf8324e2ba0fa6a597236fe06f7bc99aaa9ac703631c306b", - env = clang_env(), - registry = "marketplace.gcr.io", - # We can't use the default "ubuntu16_04" RBE image provided by the autoconfig because we need - # a specific Linux kernel that comes with "libx11" in order to run headless browser tests. - repository = "google/rbe-ubuntu16-04-webtest", - use_checked_in_confs = "Force", -) diff --git a/bin/README.md b/bin/README.md index 6f3d6c17fbd2..8995780c706b 100644 --- a/bin/README.md +++ b/bin/README.md @@ -6,11 +6,11 @@ Each file in this directory follows this pattern: 1. JavaScript only. 1. Requires `../lib/bootstrap-local.js` to bootstrap TypeScript and Node integration. -1. Requires `../lib/packages` and use the package metadata to find the binary script for the -package the script is bootstrapping. +1. Requires `../lib/packages` and use the package metadata to find the binary script for the + package the script is bootstrapping. 1. Call out main, or simply require the file if it has no export. -`devkit-admin` does not follow this pattern as it needs to setup logging and run some localized +`devkit-admin` does not follow this pattern as it needs to setup logging and run some localized logic. In order to add a new script, you should make sure it's in the root `package.json`, so people diff --git a/bin/architect b/bin/architect index 7885feefe26a..664ffb1a9785 100755 --- a/bin/architect +++ b/bin/architect @@ -1,11 +1,12 @@ #!/usr/bin/env node /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + 'use strict'; diff --git a/bin/benchmark b/bin/benchmark index 4ada663d8bfc..cd97efb60fd5 100755 --- a/bin/benchmark +++ b/bin/benchmark @@ -1,11 +1,12 @@ #!/usr/bin/env node /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + 'use strict'; diff --git a/bin/build-optimizer b/bin/build-optimizer index 6f540387043c..7b784140fbd3 100755 --- a/bin/build-optimizer +++ b/bin/build-optimizer @@ -1,11 +1,12 @@ #!/usr/bin/env node /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + 'use strict'; diff --git a/bin/devkit-admin b/bin/devkit-admin index 707a854a5b37..e84cee4e7b4a 100755 --- a/bin/devkit-admin +++ b/bin/devkit-admin @@ -1,11 +1,12 @@ #!/usr/bin/env node /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + 'use strict'; /** diff --git a/bin/ng b/bin/ng index d43c5512e47b..2835ad006929 100755 --- a/bin/ng +++ b/bin/ng @@ -1,11 +1,12 @@ #!/usr/bin/env node /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + 'use strict'; diff --git a/bin/schematics b/bin/schematics index ea3f5176befa..773dff5b360d 100755 --- a/bin/schematics +++ b/bin/schematics @@ -1,11 +1,12 @@ #!/usr/bin/env node /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + 'use strict'; diff --git a/docs/README.md b/docs/README.md index a8f139c01847..1aa9fc8f9262 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ # `/docs` Folder -This folder is used for all documentation. It contains a number of subfolders with short +This folder is used for all documentation. It contains a number of subfolders with short descriptions here. ## `/docs/design` diff --git a/docs/design/analytics.md b/docs/design/analytics.md index 1658f5d4b91a..88fcd37b8247 100644 --- a/docs/design/analytics.md +++ b/docs/design/analytics.md @@ -1,20 +1,23 @@ # Usage Metrics Gathering + This document list exactly what is gathered and how. Any change to analytics should most probably include a change to this document. # Pageview + Each command creates a pageview with the path `/command/${commandName}/${subcommandName}`. IE. `ng generate component my-component --dryRun` would create a page view with the path `/command/generate/@schematics_angular/component`. We use page views to keep track of sessions more effectively, and to tag events to a page. -Project names and target names will be removed. +Project names and target names will be removed. The command `ng run some-project:lint:some-configuration` will create a page view with the path `/command/run`. # Dimensions + Google Analytics Custom Dimensions are used to track system values and flag values. These dimensions are aggregated automatically on the backend. @@ -37,6 +40,7 @@ PROJECT NAME TO BUILD OR A MODULE NAME.** Note: There's a limit of 20 custom dimensions. ### List Of All Dimensions + | Id | Flag | Type | |:---:|:---|:---| @@ -65,6 +69,7 @@ Note: There's a limit of 20 custom dimensions. # Metrics ### List of All Metrics + | Id | Flag | Type | |:---:|:---|:---| @@ -86,12 +91,14 @@ Note: There's a limit of 20 custom dimensions. # Operating System and Node Version + A User Agent string is built to "fool" Google Analytics into reading the Operating System and version fields from it. The base dimensions are used for those. Node version is our App ID, but a dimension is also used to get the numeric MAJOR.MINOR of node. # Debugging + Using `DEBUG=universal-analytics` will report all calls to the universal-analytics library, including queuing events and sending them to the server. @@ -105,6 +112,7 @@ Using `DEBUG=ng:analytics:log` will show what we actually send to GA. See [the `debug` NPM library](https://www.npmjs.com/package/debug) for more information. # Disabling Usage Analytics + There are 2 ways of disabling usage analytics: 1. using `ng analytics off` (or changing the global configuration file yourself). This is the same @@ -115,9 +123,10 @@ There are 2 ways of disabling usage analytics: below). # CI + A special user named `ci` is used for analytics for tracking CI information. This is a convention and is in no way enforced. Running on CI by default will disable analytics (because of a lack of TTY on STDIN/OUT). It can be manually enabled using either a global configuration with a value of `ci`, or using the -`NG_CLI_ANALYTICS=ci` environment variable. +`NG_CLI_ANALYTICS=ci` environment variable. diff --git a/docs/design/build-system.md b/docs/design/build-system.md index 93df444fa2ce..fe730f3f9fdd 100644 --- a/docs/design/build-system.md +++ b/docs/design/build-system.md @@ -8,6 +8,7 @@ This document describes a top level view of the functionality in `@angular-devki Deprecated or soon to be removed features are not described here. In broad strokes the main areas are: + - loading and processing sources - code splitting - production optimizations @@ -16,7 +17,6 @@ In broad strokes the main areas are: Many tools are used in this process, and most of these steps happen within a [Webpack](https://webpack.js.org/) build. We maintain a number of Webpack-centric plugins in this repository, some of these are public but most are private since they are very specific to our setup. - ## Overview diagram Below is a diagram of processing sources go through. @@ -31,7 +31,6 @@ Relative paths, such as `./raw-css-loader.ts`, refer to internal plugins, while Sources for Angular CLI browser apps are comprised of TypeScript files, style sheets, assets, scripts, and third party dependencies. A given build will load these sources from disk, process them, and bundle them together. - ### TypeScript and Ahead-Of-Time Compilation Angular builds rely heavily on TypeScript-specific functionality for [Ahead-of-Time template compilation](https://angular.io/guide/aot-compiler) (AOT). @@ -58,20 +57,17 @@ Global stylesheets are injected into the `index.html` file, while component styl The build system supports plain CSS stylesheets as well as the Sass, LESS and Stylus CSS pre-processors. Stylesheet processing functionality is provided by `sass-loader`, `less-loader`, `stylus-loader`, `postcss-loader`, `postcss-import`, augmented in the build system by custom webpack plugins. - ### Assets Assets in the build system refer specifically to a list of files or directories that are meant to be copied verbatim as build artifacts. These files are not processed and commonly include images, favicons, pdfs and other generic file types. They are loaded into the compilation using `copy-webpack-plugin`. - ### Scripts Scripts in the build system refer specifically to JavaScript files that are meant to be loaded directly on `index.html` without being processed. They are loaded into the compilation using a custom webpack plugin. - ### Third party dependencies Third party dependencies are mostly inside `node_modules` and are referenced via imports in source files. @@ -89,7 +85,6 @@ Once the actual JavaScript file is determined, it is loaded into the compilation This resolution strategy supports the [Angular Package Format](https://docs.google.com/document/d/1CZC2rcpxffTDfRDs6p1cfbmKNLA6x5O-NtkJglDaBVs/edit#heading=h.k0mh3o8u5hx). - ## Code splitting Code is automatically split into different files (or chunks, for js files) based on a few different triggers. @@ -102,13 +97,11 @@ If multiple asynchronous chunks contain a reference to the same module, it is pl There is also a special chunk called `runtime` that contains the module loading logic and is loaded before the others. - ## Optimizations The build system contains optimizations aimed at improving the performance (for development builds) or the size of artifacts (for production builds). These are often mutually exclusive and thus we cannot just default to always using them. - ### Development optimizations Development optimizations focus on reducing rebuild time on watched builds. @@ -125,7 +118,6 @@ In development however, we skip the CSS extraction and leave it as JavaScript co Watched builds split the processing load of TypeScript compilation between file emission on the main process and type checking on a forked process. Large projects can also opt-out of AOT compilation for faster rebuilds. - ### Production optimizations Angular CLI focuses on enabling tree-shaking (removing unused modules) and dead code elimination (removing unused module code). @@ -153,7 +145,6 @@ Modules that were concatenated when lazy modules are not present might not be co Aside from tree-shaking, scripts and styles (as defined in the sources above) also undergo optimizations via [Terser](https://github.com/terser/terser) and [CleanCSS](https://github.com/jakubpawlowicz/clean-css) respectively. - ## Post-processing steps There are some steps that are meant to operate over whole applications and thus happen after the compilation finishes and outputs files. @@ -161,29 +152,31 @@ The steps are described in the order in which they are executed during a build. The execution order was determined based on the complexity of the step with a primary goal of minimizing the repetition of computationally expensive operations. ### Differential Loading + Differential loading is a strategy that allows your web application to support multiple browsers, but only load the necessary code that the browser needs. When differential loading is enabled, the CLI generates two distinct variants of application bundles. -* The first contains ES2015 syntax, takes advantage of built-in support in modern browsers, ships fewer polyfills, and results in a smaller total size. -* The second contains code in the older ES5 syntax, along with all necessary polyfills for Angular to function. This results in a larger total size, but supports older browsers. +- The first contains ES2015 syntax, takes advantage of built-in support in modern browsers, ships fewer polyfills, and results in a smaller total size. +- The second contains code in the older ES5 syntax, along with all necessary polyfills for Angular to function. This results in a larger total size, but supports older browsers. This process as designed has the advantage that only one full compilation of the application in ES2015 syntax is required. This removes a large amount of otherwise unnecessary and duplicate processing such as module resolution and dead code elimination. It also guarantees that the application is ES5 compliant including third-party code. The two variants of application bundles are created by the following steps: -1) A full build of the application is performed using an ES2015 output target. -The application's global stylesheets, scripts, and assets are also processed during this step via the full build. These elements are reused for both of application variants. -2) A copy of the JavaScript output application files are transformed (commonly referred to as down-leveled) to ES5 compatible syntax. -ES2015+ syntax elements such as classes are converted into functionally equivalent ES5 code structures. -3) An additional ES5-only polyfills file is generated that contains the required Angular polyfills for ES5-only browsers. -4) A single index HTML file is created that references both application variants and is designed to only load the appropriate files for each browser. + +1. A full build of the application is performed using an ES2015 output target. + The application's global stylesheets, scripts, and assets are also processed during this step via the full build. These elements are reused for both of application variants. +2. A copy of the JavaScript output application files are transformed (commonly referred to as down-leveled) to ES5 compatible syntax. + ES2015+ syntax elements such as classes are converted into functionally equivalent ES5 code structures. +3. An additional ES5-only polyfills file is generated that contains the required Angular polyfills for ES5-only browsers. +4. A single index HTML file is created that references both application variants and is designed to only load the appropriate files for each browser. To support loading the file sets in the appropriate browsers, the HTML `script` element's `type` and `nomodule` attributes are leveraged. Browsers will only load a script with a known type. The ES2015 files are referenced using a type of `module` which is only supported on browsers that support ES2015+ code. Since browsers that do not support ES2015+ code also do not support the `module` script type, these scripts are ignored for browsers that cannot parse and execute the ES2015 code. Browsers that support the `module` script type also support the `nomodule` attribute. -This attribute instructs a browser that supports module scripts to ignore the script with the attribute. There is one browser exception in this case: Safari 10.1. +This attribute instructs a browser that supports module scripts to ignore the script with the attribute. There is one browser exception in this case: Safari 10.1. This browser supports module scripts but does not support the `nomodule` attribute. To support this case, a special polyfill script is included to provide a workaround for the browser. This arrangement of script elements ensures that ES5-only browsers will only execute the ES5 script files and browsers that support ES2015+ will only execute the ES2015 script files. @@ -198,4 +191,4 @@ This sort of localization produces one application for each locale, each in thei The third and last post-processing step is the creation of a [service worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API). A listing of final application files is taken, fingerprinted according to their content, and added to the service worker manifest. -This must be the last step because it needs each application file to not be modified further. \ No newline at end of file +This must be the last step because it needs each application file to not be modified further. diff --git a/docs/design/deployurl-basehref.md b/docs/design/deployurl-basehref.md index 160975423aeb..71a804c073e4 100644 --- a/docs/design/deployurl-basehref.md +++ b/docs/design/deployurl-basehref.md @@ -1,18 +1,18 @@ -| | Deploy URL | Base HREF | -|--|:--:|:--:| -| Initial scripts (index.html) | ✅ 👍 | ✅ 👍 | -| Initial stylesheets (index.html) | ✅ 👍 | ✅ 👍 | -| Lazy scripts (routes/import()/etc.) | ✅ 👍 | ✅ 👍 | -| Processed CSS resources (images/fonts/etc.) | ✅ 👍 | ✅ 👍 | -| Relative template (HTML) assets | ❌ 👎 | ✅ 👍 | -| Angular Router Default Base (APP_BASE_HREF) | ❌ | ✅ *1 | -| Single reference in deployed Application | ❌ 👎 | ✅ 👍 | -| Special resource logic within CLI | ✅ 👎 | ❌ 👍 | -| Relative fetch/XMLHttpRequest | ❌ | ✅ | +| | Deploy URL | Base HREF | +| ------------------------------------------- | :--------: | :-------: | +| Initial scripts (index.html) | ✅ 👍 | ✅ 👍 | +| Initial stylesheets (index.html) | ✅ 👍 | ✅ 👍 | +| Lazy scripts (routes/import()/etc.) | ✅ 👍 | ✅ 👍 | +| Processed CSS resources (images/fonts/etc.) | ✅ 👍 | ✅ 👍 | +| Relative template (HTML) assets | ❌ 👎 | ✅ 👍 | +| Angular Router Default Base (APP_BASE_HREF) | ❌ | ✅ \*1 | +| Single reference in deployed Application | ❌ 👎 | ✅ 👍 | +| Special resource logic within CLI | ✅ 👎 | ❌ 👍 | +| Relative fetch/XMLHttpRequest | ❌ | ✅ | ✅ - has/affects the item/trait ❌ - does not have/affect the item/trait 👍 - favorable behavior 👎 - unfavorable behavior -*1 -- Users with more complicated setups may need to manually configure the `APP_BASE_HREF` token within the application. (e.g., application routing base is `/` but assets/scripts/etc. are at `/assets/`) \ No newline at end of file +\*1 -- Users with more complicated setups may need to manually configure the `APP_BASE_HREF` token within the application. (e.g., application routing base is `/` but assets/scripts/etc. are at `/assets/`) diff --git a/docs/design/ngConfig.md b/docs/design/ngConfig.md index bfb7377a992a..17be6f3a0070 100644 --- a/docs/design/ngConfig.md +++ b/docs/design/ngConfig.md @@ -4,11 +4,11 @@ Currently, a project scaffolded with the CLI has no way of specifying options and configurations affecting their projects. There are ways to affect the build (with the `angular-cli-build.js` file), but the following questions cannot be answered without actual project options: -* Where in my directory is my karma.conf file? -* What is my firebase database URL? -* Where is my client code? -* How can I use a different lazy-loading boundary prefix (or none at all)? -* Any other backend I want to run prior to `ng serve`? +- Where in my directory is my karma.conf file? +- What is my firebase database URL? +- Where is my client code? +- How can I use a different lazy-loading boundary prefix (or none at all)? +- Any other backend I want to run prior to `ng serve`? # Proposed Solution @@ -18,7 +18,6 @@ One solution would be to keep the data in the `package.json`. Unfortunately, the Instead of polluting the package file, a `.angular-cli.json` file will be created that contains all the values. Access to that file will be allowed to the user if he knows the structure of the file (unknown keys will be kept but ignored), and it's easy to read and write. - ## Fallback There should be two `.angular-cli.json` files; one for the project and a general one. The general one should contain information that can be useful when scaffolding new apps, or informations about the user. @@ -39,7 +38,7 @@ Every PR that would change the schema should include the update to the `d.ts`. The new command `get` should be used to output values on the terminal. It takes a set of flags and an optional array of [paths](#path); -* `--glob` or `-g`; the path follows a glob format, where `*` can be replaced by any amount of characters and `?` by a single character. This will output `name=value` for each values matched. +- `--glob` or `-g`; the path follows a glob format, where `*` can be replaced by any amount of characters and `?` by a single character. This will output `name=value` for each values matched. Otherwise, outputs the value of the path passed in. If multiple paths are passed in, they follow the format of `name=value`. @@ -47,14 +46,14 @@ Otherwise, outputs the value of the path passed in. If multiple paths are passed The new command `set` should be used to set values in the local configuration file. It takes a set of flags and an optional array of `[path](#path)=value`; -* `--global`; sets the value in the global configuration. -* `--remove`; removes the key (no value should be passed in). +- `--global`; sets the value in the global configuration. +- `--remove`; removes the key (no value should be passed in). The schema needs to be taken into account when setting the value of the field; -* If the field is a number, the string received from the command line is parsed. `NaN` throws an error. -* If the field is an object, an error is thrown. -* If the path is inside an object but the object hasn't been defined yet, sets the object with empty values (use the schema to create a valid object). +- If the field is a number, the string received from the command line is parsed. `NaN` throws an error. +- If the field is an object, an error is thrown. +- If the path is inside an object but the object hasn't been defined yet, sets the object with empty values (use the schema to create a valid object). #### Path @@ -77,8 +76,12 @@ A simple API would return the TypeScript interface: ```typescript class Config { // ... - get local(): ICliConfig { /* ... */ } - get global(): ICliConfig { /* ... */ } + get local(): ICliConfig { + /* ... */ + } + get global(): ICliConfig { + /* ... */ + } } ``` @@ -115,14 +118,14 @@ The following stands true: ```typescript const config = new Config(/* ... */); -console.log(config.local.key1.key2.value); // 0, even if it doesn't exist. -console.log(config.local.key1.key2.value2); // 2, local overrides. -console.log(config.local.key1.key2.value3); // 3. -console.log(config.local.key1.key2.value4); // Schema's default value. +console.log(config.local.key1.key2.value); // 0, even if it doesn't exist. +console.log(config.local.key1.key2.value2); // 2, local overrides. +console.log(config.local.key1.key2.value3); // 3. +console.log(config.local.key1.key2.value4); // Schema's default value. -console.log(config.global.key1.key2.value); // 0. -console.log(config.global.key1.key2.value2); // 1, only global. -console.log(config.global.key1.key2.value3); // Schema's default value. +console.log(config.global.key1.key2.value); // 0. +console.log(config.global.key1.key2.value2); // 1, only global. +console.log(config.global.key1.key2.value3); // Schema's default value. config.local.key1.key2.value = 1; // Now the value is 1 inside the local. Global stays the same. @@ -132,7 +135,7 @@ config.local.key1.key2.value3 = 5; config.global.key1.key2.value4 = 99; // The local config stays the same. -console.log(config.local.key1.key2.value4); // 99, the global value. +console.log(config.local.key1.key2.value4); // 99, the global value. -config.save(); // Commits if there's a change to global and/or local. +config.save(); // Commits if there's a change to global and/or local. ``` diff --git a/docs/design/third-party-libraries.md b/docs/design/third-party-libraries.md index 0428efe62832..69ac6a7c8de5 100644 --- a/docs/design/third-party-libraries.md +++ b/docs/design/third-party-libraries.md @@ -10,18 +10,18 @@ with metadata that we expect. This document explores ways to improve on the proc The following use cases need to be supported by `ng install`: 1. Support for _any_ thirdparties, ultimately falling back to running `npm install` only and -doing nothing else, if necessary. + doing nothing else, if necessary. 1. Not a new package manager. 1. Metadata storage by thirdparties in `package.json`. This must be accessible by plugins for -the build process or even when scaffolding. + the build process or even when scaffolding. 1. Proper configuration of SystemJs in the browser. 1. SystemJS configuration managed by the user needs to be kept separated from the autogenerated -part. + part. 1. The build process right now is faulty because the `tmp/` directory used by Broccoli is -inside the project. TypeScript when using `moduleResolution: "node"` can resolve the -`node_modules` directory (since it's in an ancestor folder), which means that TypeScript -compiles properly, but the build does not copy files used by TypeScript to `dist/`. We need -to proper map the imports and move them to `tmp` before compiling, then to `dist/` properly. + inside the project. TypeScript when using `moduleResolution: "node"` can resolve the + `node_modules` directory (since it's in an ancestor folder), which means that TypeScript + compiles properly, but the build does not copy files used by TypeScript to `dist/`. We need + to proper map the imports and move them to `tmp` before compiling, then to `dist/` properly. 1. Potentially hook into scaffolding. 1. Potentially hook into the build. 1. Safe uninstall path. @@ -34,27 +34,32 @@ Here's a few stories that should work right off: $ ng new my-app && cd my-app/ $ ng install jquery ``` + ^(this makes jQuery available in the index) ```sh $ ng install angularfire2 > Please specify your Firebase database URL [my-app.firebaseio.com]: _ ``` + ^(makes firebase available and provided to the App) ```sh $ ng install angularfire2 --dbUrl=my-firebase-db.example.com ``` + ^(skip prompts for values passed on the command line) ```sh $ ng install angularfire2 --quiet ``` + ^(using `--quiet` to skip all prompts and use default values) ```sh $ ng install less ``` + ^(now compiles CSS files with less for the appropriate extensions) # Proposed Solution @@ -80,13 +85,16 @@ The `install` task will perform the following subtasks: These packages can be used to wrap libraries that we want to support but can't update easily, like Jasmine or LESS. + 1. **Install typings.** See the [Typings](#typings) section. 1. **Run `postinstall` scripts.** # Proof of Concept + A proof of concept is being developed. # Hooks + The third party library can implement hooks into the scaffolding, and the build system. The CLI's tasks will look for the proper hooks prior to running and execute them. @@ -96,12 +104,14 @@ checking for the `package['angular-cli']['hooks']['${hookName}']`. The hooks are tree, there is no guarantee for the order of execution. ## Install Hooks + The only tricky part here is install hooks. The installed package should recursively call its `(pre|post|)install` hooks only on packages that are newly installed. It should call `(pre|post|)reinstall` on those who were already installed. A map of the currently installed packages should be kept before performing `npm install`. # appData + The `angular-cli` key in the generated app should be used for Angular CLI specific data. This includes the CLI configuration itself, as well as third-parties library configuration. @@ -137,11 +147,12 @@ in the data without user interaction. The special strings `${...}` can be used t with special values in the default string values. The values are taken from the `package.json`. We use a declarative style to enforce sensible defaults and make sure developers think about -this. *In the case where developers want more complex interaction, they can use the -install/uninstall hooks to prompt users.* But 3rd party libraries developers need to be aware +this. _In the case where developers want more complex interaction, they can use the +install/uninstall hooks to prompt users._ But 3rd party libraries developers need to be aware that those hooks might not prompt users (no STDIN) and throw an error. # Providers + Adding Angular providers to the app should be seamless. The install process will create a `providers.js` from all the providers contained in all the dependencies. The User can disclude providers it doesn't want. @@ -163,15 +174,18 @@ ng providers database angularfirebase2 Or, alternatively, the user can add its own providers and dependencies to its components. # Dependencies + Because dependencies are handled by `npm`, we don't have to handle it. # Typings + Typings should be added, but failure to find typings should not be a failure of installation. The user might still want to install custom typings himself in the worst case. The `typings` package can be used to install/verify that typings exist. If the typings do not exist natively, we should tell the user to install the ambient version if he wants to. # Index.html + We do not touch the `index.html` file during the installation task. The default page should link to a SystemJS configuration file that is auto generated by the CLI and not user configurable (see SystemJS below). If the user install a third party library, like jQuery, and @@ -181,6 +195,7 @@ The `index.html` also includes a section to configure SystemJS that can be manag This is separate from the generated code. # SystemJS + It is important that SystemJS works without any modifications by the user. It is also important to leave the liberty to the user to change the SystemJS configuration so that it fits their needs. @@ -190,6 +205,7 @@ being pulled from a CDN in production. During the `ng build` process for product SystemJS configuration script will be rebuilt to fetch from the CDN. # Upgrade Strategy + The upgrade process simply uses NPM. If new appData is added, it should be added manually using a migration hook for `postinstall`. diff --git a/docs/process/bazel.md b/docs/process/bazel.md index fb540e7b61ea..fe136061fe25 100644 --- a/docs/process/bazel.md +++ b/docs/process/bazel.md @@ -52,7 +52,6 @@ Then you will find the intermediate test files in `bazel-out/k8-fastbuild/bin`, Tests that are sharded, via the `shard_count` attribute, can fail if you reduce the number of tests or focus only a few. This will cause some shards to execute 0 tests, which makes the exit with an error code. - Tests that are marked as flaky, via the `flaky` attribute, will repeat when they fail. This will cause any focused test to be repeated multiple time, since the presence of focused tests causes jasmine to exit with a non-zero exit code. @@ -67,4 +66,3 @@ with the yarn workspace symlinks in node_modules. 1. Yarn workspaces is not compatible with Bazel-managed deps [(#12736)](https://github.com/angular/angular-cli/issues/12736) - diff --git a/docs/process/release.md b/docs/process/release.md index 76593d04d31f..0405c483377d 100644 --- a/docs/process/release.md +++ b/docs/process/release.md @@ -2,9 +2,10 @@ 1. Clone the Angular-CLI repo. A local copy works just fine. 1. Create an upstream remote: - ```bash - $ git remote add upstream https://github.com/angular/angular-cli.git - ``` + +```bash +$ git remote add upstream https://github.com/angular/angular-cli.git +``` # Caretaker @@ -16,21 +17,22 @@ Each shift consists of two caretakers. The primary caretaker is responsible for merging PRs to master and patch whereas the secondary caretaker is responsible for the release. Primary-secondary pairs are as follows: -Primary | Secondary ---------|---------- -Alan | Doug -Charles | Keen -Filipe | Joey +| Primary | Secondary | +| ------- | --------- | +| Alan | Doug | +| Charles | Keen | +| Filipe | Joey | ## Merging PRs The list of PRs which are currently ready to merge (approved with passing status checks) can be found with [this search](https://github.com/angular/angular-cli/pulls?q=is%3Apr+is%3Aopen+label%3A%22PR+action%3A+merge%22+-is%3Adraft). This list should be checked daily and any ready PRs should be merged. For each PR, check the -`target` label to understand where it should be merged to. You can find which branches a specific +`target` label to understand where it should be merged to. You can find which branches a specific PR will be merged into with the `yarn ng-dev pr check-target-branches ` command. When ready to merge a PR, run the following command: + ``` yarn ng-dev pr merge ``` @@ -51,16 +53,22 @@ In general, cherry picks for LTS should only be done if it meets one of the crit # Release -## Before releasing +For each version to be released, check out the associated branch and: -Update `Angular` version in [`packages/schematics/angular/utility/latest-versions.ts`](https://github.com/angular/angular-cli/blob/master/packages/schematics/angular/utility/latest-versions.ts). - -## Shepparding +1. Increment the CLI version number in + [`package.json`](https://github.com/angular/angular-cli/blob/master/package.json). +1. Update `Angular` version in + [`packages/schematics/angular/utility/latest-versions.ts`](https://github.com/angular/angular-cli/blob/master/packages/schematics/angular/utility/latest-versions.ts) + to match the lastest framework patch version for the associated minor. + - This number _usually_ aligns with the CLI version **but not always**. Framework may have + required a hotfix release, which could desync the two version numbers. Check the latest version + with `yarn info @angular/core dist-tags` or look at the most recent FW release in the + [#news channel](https://angular-team.slack.com/archives/C0439GUGA). As commits are cherry-picked when PRs are merged, creating the release should be a matter of creating a tag. ```bash -git add packages/schematics/angular/utility/latest-versions.ts +git add packages/schematics/angular/utility/latest-versions.ts package.json git commit -m 'release: vXX' git tag -a 'vXX' -m 'release: tag vXX' ``` @@ -80,12 +88,12 @@ Now push the commit and the tag to the upstream repository. **Make sure to use git push upstream --follow-tags ``` -### Authenticating +## Authenticating **This can ONLY be done by a Google employee.** Log in to the Wombat publishing service using your own github and google.com -account to publish. This enforces the login is done using 2Factor auth. +account to publish. This enforces the login is done using 2Factor auth. Run `npm login --registry https://wombat-dressing-room.appspot.com`: @@ -97,7 +105,7 @@ After closing the tab, you have successfully logged in, it is time to publish. **NOTE: After publishing, remove the token added to your `~/.npmrc` file to logout.** -### Publishing +## Publishing **This can ONLY be done by a Google employee.** @@ -107,12 +115,14 @@ For the first release of a major version, follow the instructions in [Publishing a Major Version](#publishing-a-major-version) section. For non-major release, check out the patch branch (e.g. `9.1.x`), then run: + ```bash rm -rf node_modules/ && yarn install --frozen-lockfile # Reload dependencies yarn admin publish --tag latest ``` If also publishing a prerelease, check out `master`, then run: + ```bash rm -rf node_modules/ && yarn install --frozen-lockfile # Reload dependencies yarn admin publish --tag next @@ -128,7 +138,7 @@ rm -rf node_modules/ && yarn # Reload dependencies yarn admin publish --tag v8-lts ``` -### Release Notes +## Release Notes `yarn run -s admin changelog` takes `from` and `to` arguments which are any valid git ref. @@ -149,25 +159,11 @@ using the `--githubToken` flag. You just then have to confirm the draft. > **Tags containing `next` or `rc` should be marked as pre-release.** -## Post-release Version Update +## Post-release -**For each released version**: - -Update the package versions to reflect the *next* release version in **both**: -1. `version` in [`package.json`](https://github.com/angular/angular-cli/blob/master/package.json#L3) -1. `DevkitBuildAngular` in [`packages/schematics/angular/utility/latest-versions.ts`](https://github.com/angular/angular-cli/blob/master/packages/schematics/angular/utility/latest-versions.ts) - -```sh -git checkout -b release-bump-vXX -git commit package.json packages/schematics/angular/utility/latest-versions.ts -m "build: bump version to vXX" -git push -u origin release-bump-vXX -``` - -Then make a PR and assign it to the next primary caretaker. - -Don't forget to update the Slack [#tools](https://angular-team.slack.com/archives/C46U16D4Z) channel topic and also post -links to all the version bump PRs. If anyone else on the team notices these links missing, they should ask the caretaker -to make sure the post-release version bump is not forgotten. +Don't forget to update the Slack [#tools](https://angular-team.slack.com/archives/C46U16D4Z) channel +topic with the next caretaker shift from the +[calendar](https://calendar.google.com/calendar/embed?src=angular.io_jf53juok1lhpm84hv6bo6fmgbc%40group.calendar.google.com&ctz=America%2FLos_Angeles). ## Publishing a Major Version @@ -188,3 +184,13 @@ packages. ```bash yarn admin dist-tag --version 10.0.0 --tag latest ``` + +## Changing shifts + +If you need to update the +[caretaker calendar](https://calendar.google.com/calendar/embed?src=angular.io_jf53juok1lhpm84hv6bo6fmgbc%40group.calendar.google.com&ctz=America%2FLos_Angeles) +to modify shifts, **make sure you are logged in as your @angular.io account** and +click the "+ Google Calendar" button in the bottom right to add it to your Google +Calendar account. You should then be able to find and modify events on +calendar.google.com. The calendar is a part of the `angular.io` organization, so +events can only be modified by users in the same organization. diff --git a/docs/specifications/schematic-prompts.md b/docs/specifications/schematic-prompts.md index 08092ef20235..a7c83e6e6d94 100644 --- a/docs/specifications/schematic-prompts.md +++ b/docs/specifications/schematic-prompts.md @@ -1,8 +1,8 @@ # Schematic Prompts -Schematic prompts provide the ability to introduce user interaction into the schematic execution. The schematic runtime supports the ability to allow schematic options to be configured to display a customizable question to the user and then use the response as the value for the option. These prompts are displayed before the execution of the schematic. This allows users direct the operation of the schematic without requiring indepth knowledge of the full spectrum of options available to the user. +Schematic prompts provide the ability to introduce user interaction into the schematic execution. The schematic runtime supports the ability to allow schematic options to be configured to display a customizable question to the user and then use the response as the value for the option. These prompts are displayed before the execution of the schematic. This allows users direct the operation of the schematic without requiring indepth knowledge of the full spectrum of options available to the user. -To enable this capability, the JSON Schema used to define the schematic's options supports extensions to allow the declarative definition of the prompts and their respective behavior. No additional logic or changes are required to the JavaScript for a schematic to support the prompts. +To enable this capability, the JSON Schema used to define the schematic's options supports extensions to allow the declarative definition of the prompts and their respective behavior. No additional logic or changes are required to the JavaScript for a schematic to support the prompts. ## Basic Usage @@ -10,67 +10,69 @@ To illustrate the addition of a prompt to an existing schematic the following ex ```json { - "properties": { - "name": { - "type": "string", - "minLength": 1, - "default": "world" - }, - "useColor": { - "type": "boolean" - } + "properties": { + "name": { + "type": "string", + "minLength": 1, + "default": "world" + }, + "useColor": { + "type": "boolean" } + } } ``` -Suppose it would be preferred if the user was asked for their name. This can be accomplished by augmenting the `name` property definition with an `x-prompt` field. +Suppose it would be preferred if the user was asked for their name. This can be accomplished by augmenting the `name` property definition with an `x-prompt` field. + ```json "x-prompt": "What is your name?" ``` -In most cases, only the text of the prompt is required. To minimize the amount of necessary configuration, the above _shorthand_ form is supported and will typically be all that is required. Full details regarding the _longhand_ form can be found in the **Configuration Reference** section. -Adding a prompt to allow the user to decided whether the schematic will use color when executing its hello action is also very similar. The schema with both prompts would be as follows: +In most cases, only the text of the prompt is required. To minimize the amount of necessary configuration, the above _shorthand_ form is supported and will typically be all that is required. Full details regarding the _longhand_ form can be found in the **Configuration Reference** section. + +Adding a prompt to allow the user to decided whether the schematic will use color when executing its hello action is also very similar. The schema with both prompts would be as follows: + ```json { - "properties": { - "name": { - "type": "string", - "minLength": 1, - "default": "world", - "x-prompt": "What is your name?" - }, - "useColor": { - "type": "boolean", - "x-prompt": "Would you like the response in color?" - } + "properties": { + "name": { + "type": "string", + "minLength": 1, + "default": "world", + "x-prompt": "What is your name?" + }, + "useColor": { + "type": "boolean", + "x-prompt": "Would you like the response in color?" } + } } ``` Prompts have several different types which provide the ability to display an input method that best represents the schematic option's potential values. -* `confirmation` - A **yes** or **no** question; ideal for boolean options -* `input` - textual input; ideal for string or number options -* `list` - a predefined set of items which may be selected +- `confirmation` - A **yes** or **no** question; ideal for boolean options +- `input` - textual input; ideal for string or number options +- `list` - a predefined set of items which may be selected -When using the _shorthand_ form, the most appropriate type will automatically be selected based on the property's schema. In the example, the `name` prompt will use an `input` type because it it is a `string` property. The `useColor` prompt will use a `confirmation` type because it is a boolean property with `yes` corresponding to `true` and `no` corresponding to `false`. +When using the _shorthand_ form, the most appropriate type will automatically be selected based on the property's schema. In the example, the `name` prompt will use an `input` type because it it is a `string` property. The `useColor` prompt will use a `confirmation` type because it is a boolean property with `yes` corresponding to `true` and `no` corresponding to `false`. -It is also important that the response from the user conforms to the contraints of the property. By specifying constraints using the JSON schema, the prompt runtime will automatically validate the response provided by the user. If the value is not acceptable, the user will be asked to enter a new value. This ensures that any values passed to the schematic will meet the expectations of the schematic's implementation and removes the need to add additional checks within the schematic's code. +It is also important that the response from the user conforms to the contraints of the property. By specifying constraints using the JSON schema, the prompt runtime will automatically validate the response provided by the user. If the value is not acceptable, the user will be asked to enter a new value. This ensures that any values passed to the schematic will meet the expectations of the schematic's implementation and removes the need to add additional checks within the schematic's code. -## Configuration Reference +## Configuration Reference -The `x-prompt` field supports two alternatives to enable a prompt for a schematic option. A shorthand form when additional customization is not required and a longhand form providing the ability for more control over the prompt. All user responses are validated against the property's schema. For example, string type properties can use a minimum length or regular expression constraint to control the allowed values. In the event the response fails validation, the user will be asked to enter a new value. +The `x-prompt` field supports two alternatives to enable a prompt for a schematic option. A shorthand form when additional customization is not required and a longhand form providing the ability for more control over the prompt. All user responses are validated against the property's schema. For example, string type properties can use a minimum length or regular expression constraint to control the allowed values. In the event the response fails validation, the user will be asked to enter a new value. ### Longhand Form -In the this form, the `x-prompt` field is an object with subfields that can be used to customize the behavior of the prompt. Note that some fields only apply to specific prompt types. - -| Field | Data Value | Default | -|-|-|-| -| `type` | `confirmation`, `input`, `list` | see shorthand section for details -| `message` | string | N/A (required) -| `items` | string and/or `label`/`value` object pair | only valid with type `list` +In the this form, the `x-prompt` field is an object with subfields that can be used to customize the behavior of the prompt. Note that some fields only apply to specific prompt types. +| Field | Data Value | Default | +| --------- | ----------------------------------------- | --------------------------------- | +| `type` | `confirmation`, `input`, `list` | see shorthand section for details | +| `message` | string | N/A (required) | +| `items` | string and/or `label`/`value` object pair | only valid with type `list` | ### Shorthand Form @@ -78,44 +80,44 @@ In the this form, the `x-prompt` field is an object with subfields that can be u For this usage, the type of the prompt is determined by the type of the containing property. -| Property Schema | Prompt Type | Notes | -|-|:-:|:-:| -| `"type": "boolean"` | `confirmation` | | -| `"type": "string"` | `input` | | -| `"type": "number"` | `input` | only valid numbers accepted | -| `"type": "integer"` | `input` | only valid numbers accepted | -| `"enum": [...]` | `list` | enum members become list selections +| Property Schema | Prompt Type | Notes | +| ------------------- | :------------: | :---------------------------------: | +| `"type": "boolean"` | `confirmation` | | +| `"type": "string"` | `input` | | +| `"type": "number"` | `input` | only valid numbers accepted | +| `"type": "integer"` | `input` | only valid numbers accepted | +| `"enum": [...]` | `list` | enum members become list selections | ### `x-prompt` Schema ```json { - "oneOf": [ - { "type": "string" }, - { - "type": "object", - "properties": { - "type": { "type": "string" }, - "message": { "type": "string" }, - "items": { - "type": "array", - "items": { - "oneOf": [ - { "type": "string" }, - { - "type": "object", - "properties": { - "label": { "type": "string" }, - "value": { } - }, - "required": [ "value" ] - } - ] - } - } - }, - "required": [ "message" ] + "oneOf": [ + { "type": "string" }, + { + "type": "object", + "properties": { + "type": { "type": "string" }, + "message": { "type": "string" }, + "items": { + "type": "array", + "items": { + "oneOf": [ + { "type": "string" }, + { + "type": "object", + "properties": { + "label": { "type": "string" }, + "value": {} + }, + "required": ["value"] + } + ] + } } - ] + }, + "required": ["message"] + } + ] } -``` \ No newline at end of file +``` diff --git a/docs/specifications/update.md b/docs/specifications/update.md index da02a01a7cac..00f1d3f2819b 100644 --- a/docs/specifications/update.md +++ b/docs/specifications/update.md @@ -1,4 +1,3 @@ - # Update Command `ng update` is a new command in the CLI to update one or multiple packages, its peer dependencies, and the peer dependencies that depends on it. @@ -11,16 +10,16 @@ If there are inconsistencies, for example if peer dependencies cannot be matches ng update [options] ``` -You can specify more than one package. Each package follows the convention of `[@scope/]packageName[@version-range-or-dist-tag]`. Packages not found in your dependencies will trigger an error. Any package that has a higher version in your `package.json` will trigger an error. +You can specify more than one package. Each package follows the convention of `[@scope/]packageName[@version-range-or-dist-tag]`. Packages not found in your dependencies will trigger an error. Any package that has a higher version in your `package.json` will trigger an error. -| Flag | Argument | Description | -|---|---|---| -| `--all` | `boolean` | If true, implies that all dependencies should be updated. Defaults is false, using dependencies from the command line instead. | -| `--force` | `boolean` | If true, skip the verification step and perform the update even if some peer dependencies would be invalidated. Peer dependencies errors will still be shown as warning. Defaults to false. | -| `--next` | `boolean` | If true, allows version discovery to include Beta and RC. Defaults to false. | -| `--migrate-only` | `boolean` | If true, don't change the `package.json` file, only apply migration scripts. | -| `--from` | `version` | Apply migrations from a certain version number. | -| `--to` | `version` | Apply migrations up to a certain version number (inclusive). By default will update to the installed version. | +| Flag | Argument | Description | +| ---------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--all` | `boolean` | If true, implies that all dependencies should be updated. Defaults is false, using dependencies from the command line instead. | +| `--force` | `boolean` | If true, skip the verification step and perform the update even if some peer dependencies would be invalidated. Peer dependencies errors will still be shown as warning. Defaults to false. | +| `--next` | `boolean` | If true, allows version discovery to include Beta and RC. Defaults to false. | +| `--migrate-only` | `boolean` | If true, don't change the `package.json` file, only apply migration scripts. | +| `--from` | `version` | Apply migrations from a certain version number. | +| `--to` | `version` | Apply migrations up to a certain version number (inclusive). By default will update to the installed version. | ## Details @@ -28,39 +27,37 @@ The schematic performs the following steps, in order: 1. Get all installed package names and versions from the `package.json` into `dependencyMap: Map`. 1. From that map, fetch all `package.json` from the NPM repository, which contains all versions, and gather them in a `Map`. - 1. At the same time, update the `Map<>` with the version of the package which is believed to be installed (largest version number matching the version range). - 1. **WARNING**: this might not be the exact installed versions, unfortunately. We should have a proper `package-lock.json` loader, and support `yarn.lock` as well, but these are stretch goals (and where do we stop). -1. For each packages mentioned on the command line, update to the target version (by default largest non-beta non-rc version): - - ```python - # ARGV The packages being requested by the user. - # NPM A map of package name to a map of version to PackageJson structure. - # V A map of package name to available versions. - # PKG A map of package name to PackageJson structure, for the installed versions. - # next A flag for the "--next" command line argument. - - # First add all updating packages' peer dependencies. This should be recursive but simplified - # here for readability. - ARGV += [ NPM[p][max([ v for v in V[p] if (not is_beta(v) or next) ])].peerDependencies - for p in ARGV ] - - for p in ARGV: - x = max([ v for v in V[p] if (not is_beta(v) or next) ]) - - for other in set(PKG.keys()) - set([ p ]): - # Verify all packages' peer dependencies. - if has(other.peerDependencies, p) and !compatible(x, other.peerDependencies[p]): - showError('Cannot update dependency "%s": "%s" is incompatible with the updated dependency' % (x, other)) - - if any( has(other.peerDependencies, peer) and !compatible(x, other.peerDependencies[peer]) - for peer in PKG[p].peerDependencies.keys() ): - showError('Cannot update dependency "%s": "%s" depends on an incompatible peer dependency' % (x, other)) - - update_package_json(p, x) +1. At the same time, update the `Map<>` with the version of the package which is believed to be installed (largest version number matching the version range). +1. **WARNING**: this might not be the exact installed versions, unfortunately. We should have a proper `package-lock.json` loader, and support `yarn.lock` as well, but these are stretch goals (and where do we stop). +1. For each packages mentioned on the command line, update to the target version (by default largest non-beta non-rc version): + +```python +# ARGV The packages being requested by the user. +# NPM A map of package name to a map of version to PackageJson structure. +# V A map of package name to available versions. +# PKG A map of package name to PackageJson structure, for the installed versions. +# next A flag for the "--next" command line argument. + +# First add all updating packages' peer dependencies. This should be recursive but simplified +# here for readability. +ARGV += [ NPM[p][max([ v for v in V[p] if (not is_beta(v) or next) ])].peerDependencies + for p in ARGV ] + +for p in ARGV: + x = max([ v for v in V[p] if (not is_beta(v) or next) ]) + + for other in set(PKG.keys()) - set([ p ]): + # Verify all packages' peer dependencies. + if has(other.peerDependencies, p) and !compatible(x, other.peerDependencies[p]): + showError('Cannot update dependency "%s": "%s" is incompatible with the updated dependency' % (x, other)) + + if any( has(other.peerDependencies, peer) and !compatible(x, other.peerDependencies[peer]) + for peer in PKG[p].peerDependencies.keys() ): + showError('Cannot update dependency "%s": "%s" depends on an incompatible peer dependency' % (x, other)) + + update_package_json(p, x) ``` - - ## Library Developers Libraries are responsible for defining their own update schematics. The `ng update` tool will update the package.json, and if it detects the `"ng-update"` key in package.json of the library, will run the update schematic on it (with version information metadata). @@ -71,14 +68,15 @@ If a library does not define the `"ng-update"` key in their package.json, they a In order to implement migrations in a library, the author must add the `ng-update` key to its `package.json`. This key contains the following fields: -| Field Name | Type | Description | -|---|---|---| -| `requirements` | `{ [packageName: string]: VersionRange }` | A map of package names to version to check for minimal requirement. If one of the libraries listed here does not match the version range specified in `requirements`, an error will be shown to the user to manually update those libraries. For example, `@angular/core` does not support updates from versions earlier than 5, so this field would be `{ '@angular/core': '>= 5' }`. -| `migrations` | `string` | A relative path (or resolved using Node module resolution) to a Schematics collection definition. | -| `packageGroup` | `string[]` | A list of npm packages that are to be grouped together. When running the update schematic it will automatically include all packages as part of the packageGroup in the update (if the user also installed them). | -| `packageGroupName` | `string` | The name of the packageGroup to use. By default, uses the first package in the packageGroup. The packageGroupName needs to be part of the packageGroup and should be a valid package name. | +| Field Name | Type | Description | +| ------------------ | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `requirements` | `{ [packageName: string]: VersionRange }` | A map of package names to version to check for minimal requirement. If one of the libraries listed here does not match the version range specified in `requirements`, an error will be shown to the user to manually update those libraries. For example, `@angular/core` does not support updates from versions earlier than 5, so this field would be `{ '@angular/core': '>= 5' }`. | +| `migrations` | `string` | A relative path (or resolved using Node module resolution) to a Schematics collection definition. | +| `packageGroup` | `string[]` | A list of npm packages that are to be grouped together. When running the update schematic it will automatically include all packages as part of the packageGroup in the update (if the user also installed them). | +| `packageGroupName` | `string` | The name of the packageGroup to use. By default, uses the first package in the packageGroup. The packageGroupName needs to be part of the packageGroup and should be a valid package name. | #### Example given: + Library my-lib wants to have 2 steps to update from version 4 -> 4.5 and 4.5 to 5. It would add this information in its `package.json`: ```json @@ -150,10 +148,11 @@ There might be additional packages that are outdated. I have a dependency on Angular, Material and CLI. I want to update the CLI, then Angular, then Material in separate steps. #### Details + 1. `ng update @angular/cli`. -Updates the CLI and packages that have a peer dependencies on the CLI (none), running refactoring tools from CLI 1 to 6. + Updates the CLI and packages that have a peer dependencies on the CLI (none), running refactoring tools from CLI 1 to 6. 1. `ng update @angular/core`. -Updates the Core package and all packages that have a peer dependency on it. This can get tricky if `@angular/material` get caught in the update because the version installed does not directly allow the new version of `@angular/core`. In this case + Updates the Core package and all packages that have a peer dependency on it. This can get tricky if `@angular/material` get caught in the update because the version installed does not directly allow the new version of `@angular/core`. In this case ### Complex Case @@ -182,10 +181,9 @@ ng update @angular/material ``` - update `@angular/material` to latest version, that should be compatible with the current `@angular/core`. -- if that version is not compatible with you +- if that version is not compatible with you - tell the user about a higher version that requires an update to `@angular/core`. - ## Notes 1. if someone is on CLI 1.5, the command is not supported. The user needs to update to `@angular/cli@latest`, then `ng update @angular/cli`. Post install hook will check versions of cli configuration and show a message to run the `ng update` command. diff --git a/etc/README.md b/etc/README.md deleted file mode 100644 index b0c2447c9b1d..000000000000 --- a/etc/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# `/etc` Folder - -This folder is for files that doesn't fit in other directories in the root folder. diff --git a/etc/api/BUILD.bazel b/etc/api/BUILD.bazel deleted file mode 100644 index 1d70fb1c9a14..000000000000 --- a/etc/api/BUILD.bazel +++ /dev/null @@ -1,54 +0,0 @@ -load("@npm//ts-api-guardian:index.bzl", "ts_api_guardian_test") - -[ts_api_guardian_test( - name = "%s_%s_%sapi" % ( - bundle[0], - bundle[1], - bundle[2].replace("src/", "").replace("index", "").replace("_golden-api", "").replace("/", "_"), - ), - actual = "angular_cli/packages/%s/%s/npm_package/%s.d.ts" % ( - bundle[0], - bundle[1], - bundle[2], - ), - allow_module_identifiers = [ - "fs", - "ts", - "ajv", - "Symbol", - "webpack", - ], - data = glob([ - "%s/%s/**/*.d.ts" % ( - bundle[0], - bundle[1], - ), - ]) + [ - "//packages/%s/%s:npm_package" % ( - bundle[0], - bundle[1], - ), - ], - golden = "angular_cli/etc/api/%s/%s/%s.d.ts" % ( - bundle[0], - bundle[1], - bundle[2], - ), - # We don't want to analyse these exports nor add them to the golden files - # in most cases it's because Ts API Guardian doesn't support Symbol Aliases. - # Note: $ must be escaped to $$ because these patterns will be executed by shell - # and $ has a special meaning there. - strip_export_pattern = [ - # @angular-devkit/architect - "^BuilderProgressState$$", - # @angular-devkit/schematics - "^workflow$$", - "^formats$$", - # @angular-devkit/build-optimizer - "^buildOptimizerLoader$$", - ], - # At the moment using this will ignore a big change - use_angular_tag_rules = False, -) for bundle in [b[:-len(".d.ts")].split("/", 2) for b in glob( - ["**/*.d.ts"], -)]] diff --git a/etc/api/angular_devkit/architect/src/index.d.ts b/etc/api/angular_devkit/architect/src/index.d.ts deleted file mode 100644 index ec27026f5791..000000000000 --- a/etc/api/angular_devkit/architect/src/index.d.ts +++ /dev/null @@ -1,95 +0,0 @@ -export declare class Architect { - constructor(_host: ArchitectHost, registry?: json.schema.SchemaRegistry, additionalJobRegistry?: experimental.jobs.Registry); - has(name: experimental.jobs.JobName): Observable; - scheduleBuilder(name: string, options: json.JsonObject, scheduleOptions?: ScheduleOptions): Promise; - scheduleTarget(target: Target, overrides?: json.JsonObject, scheduleOptions?: ScheduleOptions): Promise; -} - -export interface BuilderContext { - readonly analytics: analytics.Analytics; - builder: BuilderInfo; - currentDirectory: string; - id: number; - logger: logging.LoggerApi; - target?: Target; - workspaceRoot: string; - addTeardown(teardown: () => (Promise | void)): void; - getBuilderNameForTarget(target: Target): Promise; - getProjectMetadata(projectName: string): Promise; - getProjectMetadata(target: Target): Promise; - getTargetOptions(target: Target): Promise; - reportProgress(current: number, total?: number, status?: string): void; - reportRunning(): void; - reportStatus(status: string): void; - scheduleBuilder(builderName: string, options?: json.JsonObject, scheduleOptions?: ScheduleOptions): Promise; - scheduleTarget(target: Target, overrides?: json.JsonObject, scheduleOptions?: ScheduleOptions): Promise; - validateOptions(options: json.JsonObject, builderName: string): Promise; -} - -export interface BuilderHandlerFn { - (input: A, context: BuilderContext): BuilderOutputLike; -} - -export declare type BuilderInfo = json.JsonObject & { - builderName: string; - description: string; - optionSchema: json.schema.JsonSchema; -}; - -export declare type BuilderInput = json.JsonObject & RealBuilderInput; - -export declare type BuilderOutput = json.JsonObject & RealBuilderOutput; - -export declare type BuilderOutputLike = AsyncIterable | SubscribableOrPromise | BuilderOutput; - -export declare type BuilderProgress = json.JsonObject & RealBuilderProgress & TypedBuilderProgress; - -export declare type BuilderProgressReport = BuilderProgress & ({ - target?: Target; - builder: BuilderInfo; -}); - -export declare type BuilderRegistry = experimental.jobs.Registry; - -export interface BuilderRun { - id: number; - info: BuilderInfo; - output: Observable; - progress: Observable; - result: Promise; - stop(): Promise; -} - -export declare function createBuilder(fn: BuilderHandlerFn): Builder; - -export declare function fromAsyncIterable(iterable: AsyncIterable): Observable; - -export declare function isBuilderOutput(obj: any): obj is BuilderOutput; - -export interface ScheduleOptions { - analytics?: analytics.Analytics; - logger?: logging.Logger; -} - -export declare function scheduleTargetAndForget(context: BuilderContext, target: Target, overrides?: json.JsonObject, scheduleOptions?: ScheduleOptions): Observable; - -export declare type Target = json.JsonObject & RealTarget; - -export declare function targetFromTargetString(str: string): Target; - -export declare function targetStringFromTarget({ project, target, configuration }: Target): string; - -export declare type TypedBuilderProgress = ({ - state: BuilderProgressState.Stopped; -} | { - state: BuilderProgressState.Error; - error: json.JsonValue; -} | { - state: BuilderProgressState.Waiting; - status?: string; -} | { - state: BuilderProgressState.Running; - status?: string; - current: number; - total?: number; -}); diff --git a/etc/api/angular_devkit/architect/testing/index.d.ts b/etc/api/angular_devkit/architect/testing/index.d.ts deleted file mode 100644 index 8c3b4f571820..000000000000 --- a/etc/api/angular_devkit/architect/testing/index.d.ts +++ /dev/null @@ -1,31 +0,0 @@ -export declare class TestingArchitectHost implements ArchitectHost { - currentDirectory: string; - workspaceRoot: string; - constructor(workspaceRoot?: string, currentDirectory?: string, _backendHost?: ArchitectHost | null); - addBuilder(builderName: string, builder: Builder, description?: string, optionSchema?: json.schema.JsonSchema): void; - addBuilderFromPackage(packageName: string): Promise; - addTarget(target: Target, builderName: string, options?: json.JsonObject): void; - getBuilderNameForTarget(target: Target): Promise; - getCurrentDirectory(): Promise; - getOptionsForTarget(target: Target): Promise; - getProjectMetadata(target: Target | string): Promise; - getWorkspaceRoot(): Promise; - loadBuilder(info: BuilderInfo): Promise; - resolveBuilder(builderName: string): Promise; -} - -export declare class TestProjectHost extends NodeJsSyncHost { - protected _templateRoot: Path; - constructor(_templateRoot: Path); - appendToFile(path: string, str: string): void; - copyFile(from: string, to: string): void; - fileMatchExists(dir: string, regex: RegExp): PathFragment | undefined; - initialize(): Observable; - replaceInFile(path: string, match: RegExp | string, replacement: string): void; - restore(): Observable; - root(): Path; - scopedSync(): virtualFs.SyncDelegateHost; - writeMultipleFiles(files: { - [path: string]: string | ArrayBufferLike | Buffer; - }): void; -} diff --git a/etc/api/angular_devkit/benchmark/src/index.d.ts b/etc/api/angular_devkit/benchmark/src/index.d.ts deleted file mode 100644 index 5a35f3d1b139..000000000000 --- a/etc/api/angular_devkit/benchmark/src/index.d.ts +++ /dev/null @@ -1,100 +0,0 @@ -export interface AggregatedMetric extends Metric { - componentValues: number[]; -} - -export interface AggregatedProcessStats { - cpu: number; - ctime: number; - elapsed: number; - memory: number; - pid: number; - ppid: number; - processes: number; - timestamp: number; -} - -export declare const aggregateMetricGroups: (g1: MetricGroup, g2: MetricGroup) => MetricGroup; - -export declare const aggregateMetrics: (m1: Metric | AggregatedMetric, m2: Metric | AggregatedMetric) => AggregatedMetric; - -export declare type BenchmarkReporter = (command: Command, groups: MetricGroup[]) => void; - -export declare type Capture = (stats: Observable) => Observable; - -export declare class Command { - args: string[]; - cmd: string; - cwd: string; - expectedExitCode: number; - constructor(cmd: string, args?: string[], cwd?: string, expectedExitCode?: number); - toString(): string; -} - -export declare const cumulativeMovingAverage: (acc: number, val: number, accSize: number) => number; - -export declare const defaultReporter: (logger: logging.Logger) => BenchmarkReporter; - -export declare const defaultStatsCapture: Capture; - -export declare class LocalMonitoredProcess implements MonitoredProcess { - stats$: Observable; - stderr$: Observable; - stdout$: Observable; - constructor(command: Command, useProcessTime?: boolean); - resetElapsedTimer(): void; - run(): Observable; -} - -export declare function main({ args, stdout, stderr, }: MainOptions): Promise<0 | 1>; - -export interface MainOptions { - args: string[]; - stderr?: ProcessOutput; - stdout?: ProcessOutput; -} - -export declare const max: (v1: number, v2: number) => number; - -export declare class MaximumRetriesExceeded extends BaseException { - constructor(retries: number); -} - -export interface Metric { - componentValues?: number[]; - name: string; - unit: string; - value: number; -} - -export interface MetricGroup { - metrics: (Metric | AggregatedMetric)[]; - name: string; -} - -export interface MonitoredProcess { - stats$: Observable; - stderr$: Observable; - stdout$: Observable; - run(): Observable; - toString(): string; -} - -export declare function runBenchmark({ command, captures, reporters, iterations, retries, logger, }: RunBenchmarkOptions): Observable; - -export interface RunBenchmarkOptions { - captures: Capture[]; - command: Command; - expectedExitCode?: number; - iterations?: number; - logger?: logging.Logger; - reporters: BenchmarkReporter[]; - retries?: number; -} - -export declare function runBenchmarkWatch({ command, captures, reporters, iterations, retries, logger, watchMatcher, watchTimeout, watchCommand, }: RunBenchmarkWatchOptions): Observable; - -export interface RunBenchmarkWatchOptions extends RunBenchmarkOptions { - watchCommand: Command; - watchMatcher: string; - watchTimeout?: number; -} diff --git a/etc/api/angular_devkit/build_optimizer/src/_golden-api.d.ts b/etc/api/angular_devkit/build_optimizer/src/_golden-api.d.ts deleted file mode 100644 index b22aeaa7522c..000000000000 --- a/etc/api/angular_devkit/build_optimizer/src/_golden-api.d.ts +++ /dev/null @@ -1,32 +0,0 @@ -export declare function buildOptimizer(options: BuildOptimizerOptions): TransformJavascriptOutput; - -export declare const buildOptimizerLoaderPath: string; - -export declare class BuildOptimizerWebpackPlugin { - apply(compiler: Compiler): void; -} - -export default function buildOptimizerLoader(this: { - resourcePath: string; - _module: { - factoryMeta: { - skipBuildOptimizer?: boolean; - sideEffectFree?: boolean; - }; - }; - cacheable(): void; - callback(error?: Error | null, content?: string, sourceMap?: unknown): void; - getOptions(): unknown; -}, content: string, previousSourceMap: RawSourceMap): void; - -export declare function getPrefixClassesTransformer(): ts.TransformerFactory; - -export declare function getPrefixFunctionsTransformer(): ts.TransformerFactory; - -export declare function getScrubFileTransformer(program?: ts.Program): ts.TransformerFactory; - -export declare function getScrubFileTransformerForCore(program?: ts.Program): ts.TransformerFactory; - -export declare function getWrapEnumsTransformer(): ts.TransformerFactory; - -export declare function transformJavascript(options: TransformJavascriptOptions): TransformJavascriptOutput; diff --git a/etc/api/angular_devkit/core/node/_golden-api.d.ts b/etc/api/angular_devkit/core/node/_golden-api.d.ts deleted file mode 100644 index a897c6bb88e4..000000000000 --- a/etc/api/angular_devkit/core/node/_golden-api.d.ts +++ /dev/null @@ -1,42 +0,0 @@ -export declare function createConsoleLogger(verbose?: boolean, stdout?: ProcessOutput, stderr?: ProcessOutput, colors?: Partial string>>): logging.Logger; - -export declare function isDirectory(filePath: string): boolean; - -export declare function isFile(filePath: string): boolean; - -export declare class NodeJsAsyncHost implements virtualFs.Host { - get capabilities(): virtualFs.HostCapabilities; - delete(path: Path): Observable; - exists(path: Path): Observable; - isDirectory(path: Path): Observable; - isFile(path: Path): Observable; - list(path: Path): Observable; - read(path: Path): Observable; - rename(from: Path, to: Path): Observable; - stat(path: Path): Observable>; - watch(path: Path, _options?: virtualFs.HostWatchOptions): Observable | null; - write(path: Path, content: virtualFs.FileBuffer): Observable; -} - -export declare class NodeJsSyncHost implements virtualFs.Host { - get capabilities(): virtualFs.HostCapabilities; - delete(path: Path): Observable; - exists(path: Path): Observable; - isDirectory(path: Path): Observable; - isFile(path: Path): Observable; - list(path: Path): Observable; - read(path: Path): Observable; - rename(from: Path, to: Path): Observable; - stat(path: Path): Observable>; - watch(path: Path, _options?: virtualFs.HostWatchOptions): Observable | null; - write(path: Path, content: virtualFs.FileBuffer): Observable; -} - -export declare class NodeModuleJobRegistry implements core_experimental.jobs.Registry { - protected _resolve(name: string): string | null; - get(name: core_experimental.jobs.JobName): Observable | null>; -} - -export interface ProcessOutput { - write(buffer: string | Buffer): boolean; -} diff --git a/etc/api/angular_devkit/core/node/testing/index.d.ts b/etc/api/angular_devkit/core/node/testing/index.d.ts deleted file mode 100644 index 8c3e41b98aad..000000000000 --- a/etc/api/angular_devkit/core/node/testing/index.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -export declare class TempScopedNodeJsSyncHost extends virtualFs.ScopedHost { - protected _root: Path; - protected _sync?: virtualFs.SyncDelegateHost; - get files(): Path[]; - get root(): Path; - get sync(): virtualFs.SyncDelegateHost; - constructor(); -} diff --git a/etc/api/angular_devkit/core/src/_golden-api.d.ts b/etc/api/angular_devkit/core/src/_golden-api.d.ts deleted file mode 100644 index 10390f0ff530..000000000000 --- a/etc/api/angular_devkit/core/src/_golden-api.d.ts +++ /dev/null @@ -1,1097 +0,0 @@ -export declare function addUndefinedDefaults(value: JsonValue, _pointer: JsonPointer, schema?: JsonSchema): JsonValue; - -export declare class AliasHost extends ResolverHost { - protected _aliases: Map; - get aliases(): Map; - protected _resolve(path: Path): Path; -} - -export interface Analytics { - event(category: string, action: string, options?: EventOptions): void; - flush(): Promise; - pageview(path: string, options?: PageviewOptions): void; - screenview(screenName: string, appName: string, options?: ScreenviewOptions): void; - timing(category: string, variable: string, time: string | number, options?: TimingOptions): void; -} - -export declare type AnalyticsForwarderFn = (report: JsonObject & AnalyticsReport) => void; - -export declare type AnalyticsReport = AnalyticsReportEvent | AnalyticsReportScreenview | AnalyticsReportPageview | AnalyticsReportTiming; - -export interface AnalyticsReportBase extends JsonObject { - kind: AnalyticsReportKind; -} - -export declare class AnalyticsReporter { - protected _analytics: Analytics; - constructor(_analytics: Analytics); - report(report: AnalyticsReport): void; -} - -export interface AnalyticsReportEvent extends AnalyticsReportBase { - action: string; - category: string; - kind: AnalyticsReportKind.Event; - options: JsonObject & EventOptions; -} - -export declare enum AnalyticsReportKind { - Event = "event", - Screenview = "screenview", - Pageview = "pageview", - Timing = "timing" -} - -export interface AnalyticsReportPageview extends AnalyticsReportBase { - kind: AnalyticsReportKind.Pageview; - options: JsonObject & PageviewOptions; - path: string; -} - -export interface AnalyticsReportScreenview extends AnalyticsReportBase { - appName: string; - kind: AnalyticsReportKind.Screenview; - options: JsonObject & ScreenviewOptions; - screenName: string; -} - -export interface AnalyticsReportTiming extends AnalyticsReportBase { - category: string; - kind: AnalyticsReportKind.Timing; - options: JsonObject & TimingOptions; - time: string | number; - variable: string; -} - -export declare function asPosixPath(path: Path): PosixPath; - -export declare function asWindowsPath(path: Path): WindowsPath; - -export declare class BaseException extends Error { - constructor(message?: string); -} - -export declare function basename(path: Path): PathFragment; - -export declare function buildJsonPointer(fragments: string[]): JsonPointer; - -export declare function camelize(str: string): string; - -export declare function capitalize(str: string): string; - -export declare class CircularDependencyFoundException extends BaseException { - constructor(); -} - -export declare function classify(str: string): string; - -export declare function clean(array: Array): Array; - -export declare class ContentHasMutatedException extends BaseException { - constructor(path: string); -} - -export declare class CordHost extends SimpleMemoryHost { - protected _back: ReadonlyHost; - protected _filesToCreate: Set; - protected _filesToDelete: Set; - protected _filesToOverwrite: Set; - protected _filesToRename: Map; - protected _filesToRenameRevert: Map; - get backend(): ReadonlyHost; - get capabilities(): HostCapabilities; - constructor(_back: ReadonlyHost); - clone(): CordHost; - commit(host: Host, force?: boolean): Observable; - create(path: Path, content: FileBuffer): Observable; - delete(path: Path): Observable; - exists(path: Path): Observable; - isDirectory(path: Path): Observable; - isFile(path: Path): Observable; - list(path: Path): Observable; - overwrite(path: Path, content: FileBuffer): Observable; - read(path: Path): Observable; - records(): CordHostRecord[]; - rename(from: Path, to: Path): Observable; - stat(path: Path): Observable | null; - watch(path: Path, options?: HostWatchOptions): null; - willCreate(path: Path): boolean; - willDelete(path: Path): boolean; - willOverwrite(path: Path): boolean; - willRename(path: Path): boolean; - willRenameTo(path: Path, to: Path): boolean; - write(path: Path, content: FileBuffer): Observable; -} - -export interface CordHostCreate { - content: FileBuffer; - kind: 'create'; - path: Path; -} - -export interface CordHostDelete { - kind: 'delete'; - path: Path; -} - -export interface CordHostOverwrite { - content: FileBuffer; - kind: 'overwrite'; - path: Path; -} - -export declare type CordHostRecord = CordHostCreate | CordHostOverwrite | CordHostRename | CordHostDelete; - -export interface CordHostRename { - from: Path; - kind: 'rename'; - to: Path; -} - -export declare class CoreSchemaRegistry implements SchemaRegistry { - constructor(formats?: SchemaFormat[]); - protected _resolver(ref: string, validate?: ValidateFunction): { - context?: ValidateFunction; - schema?: JsonObject; - }; - addFormat(format: SchemaFormat): void; - addPostTransform(visitor: JsonVisitor, deps?: JsonVisitor[]): void; - addPreTransform(visitor: JsonVisitor, deps?: JsonVisitor[]): void; - addSmartDefaultProvider(source: string, provider: SmartDefaultProvider): void; - compile(schema: JsonSchema): Observable; - flatten(schema: JsonObject): Observable; - registerUriHandler(handler: UriHandler): void; - usePromptProvider(provider: PromptProvider): void; - useXDeprecatedProvider(onUsage: (message: string) => void): void; -} - -export declare function createSyncHost(handler: SyncHostHandler): Host; - -export declare function createWorkspaceHost(host: virtualFs.Host): WorkspaceHost; - -export interface CustomDimensionsAndMetricsOptions { - dimensions?: (boolean | number | string)[]; - metrics?: (boolean | number | string)[]; -} - -export declare function dasherize(str: string): string; - -export declare function decamelize(str: string): string; - -export declare function deepCopy(value: T): T; - -export declare type DefinitionCollectionListener = (name: string, action: 'add' | 'remove' | 'replace', newValue: V | undefined, oldValue: V | undefined, collection: DefinitionCollection) => void; - -export declare class DependencyNotFoundException extends BaseException { - constructor(); -} - -export declare function dirname(path: Path): Path; - -export declare class Empty implements ReadonlyHost { - readonly capabilities: HostCapabilities; - exists(path: Path): Observable; - isDirectory(path: Path): Observable; - isFile(path: Path): Observable; - list(path: Path): Observable; - read(path: Path): Observable; - stat(path: Path): Observable | null>; -} - -export interface EventOptions extends CustomDimensionsAndMetricsOptions { - label?: string; - value?: string; -} - -export declare function extname(path: Path): string; - -export declare class FileAlreadyExistException extends BaseException { - constructor(path: string); -} - -export declare const fileBuffer: TemplateTag; - -export declare type FileBuffer = ArrayBuffer; - -export declare type FileBufferLike = ArrayBufferLike; - -export declare function fileBufferToString(fileBuffer: FileBuffer): string; - -export declare class FileDoesNotExistException extends BaseException { - constructor(path: string); -} - -export declare class ForwardingAnalytics implements Analytics { - protected _fn: AnalyticsForwarderFn; - constructor(_fn: AnalyticsForwarderFn); - event(category: string, action: string, options?: EventOptions): void; - flush(): Promise; - pageview(path: string, options?: PageviewOptions): void; - screenview(screenName: string, appName: string, options?: ScreenviewOptions): void; - timing(category: string, variable: string, time: string | number, options?: TimingOptions): void; -} - -export declare function fragment(path: string): PathFragment; - -export declare function getSystemPath(path: Path): string; - -export declare function getTypesOfSchema(schema: JsonSchema): Set; - -export interface Host extends ReadonlyHost { - delete(path: Path): Observable; - rename(from: Path, to: Path): Observable; - watch(path: Path, options?: HostWatchOptions): Observable | null; - write(path: Path, content: FileBufferLike): Observable; -} - -export interface HostCapabilities { - synchronous: boolean; -} - -export interface HostWatchEvent { - readonly path: Path; - readonly time: Date; - readonly type: HostWatchEventType; -} - -export declare const enum HostWatchEventType { - Changed = 0, - Created = 1, - Deleted = 2, - Renamed = 3 -} - -export interface HostWatchOptions { - readonly persistent?: boolean; - readonly recursive?: boolean; -} - -export declare function indentBy(indentations: number): TemplateTag; - -export declare class IndentLogger extends Logger { - constructor(name: string, parent?: Logger | null, indentation?: string); -} - -export declare class InvalidJsonCharacterException extends JsonException { - character: number; - invalidChar: string; - line: number; - offset: number; - constructor(context: JsonParserContext); -} - -export declare class InvalidPathException extends BaseException { - constructor(path: string); -} - -export declare class InvalidUpdateRecordException extends BaseException { - constructor(); -} - -export declare function isAbsolute(p: Path): boolean; - -export declare function isJsonArray(value: JsonValue): value is JsonArray; - -export declare function isJsonObject(value: JsonValue): value is JsonObject; - -export declare function isPromise(obj: any): obj is Promise; - -export declare function join(p1: Path, ...others: string[]): Path; - -export declare function joinJsonPointer(root: JsonPointer, ...others: string[]): JsonPointer; - -export interface JsonArray extends Array { -} - -export interface JsonAstArray extends JsonAstNodeBase { - readonly elements: JsonAstNode[]; - readonly kind: 'array'; - readonly value: JsonArray; -} - -export interface JsonAstComment extends JsonAstNodeBase { - readonly content: string; - readonly kind: 'comment'; -} - -export interface JsonAstConstantFalse extends JsonAstNodeBase { - readonly kind: 'false'; - readonly value: false; -} - -export interface JsonAstConstantNull extends JsonAstNodeBase { - readonly kind: 'null'; - readonly value: null; -} - -export interface JsonAstConstantTrue extends JsonAstNodeBase { - readonly kind: 'true'; - readonly value: true; -} - -export interface JsonAstIdentifier extends JsonAstNodeBase { - readonly kind: 'identifier'; - readonly value: string; -} - -export interface JsonAstKeyValue extends JsonAstNodeBase { - readonly key: JsonAstString | JsonAstIdentifier; - readonly kind: 'keyvalue'; - readonly value: JsonAstNode; -} - -export interface JsonAstMultilineComment extends JsonAstNodeBase { - readonly content: string; - readonly kind: 'multicomment'; -} - -export declare type JsonAstNode = JsonAstNumber | JsonAstString | JsonAstIdentifier | JsonAstArray | JsonAstObject | JsonAstConstantFalse | JsonAstConstantNull | JsonAstConstantTrue; - -export interface JsonAstNodeBase { - readonly comments?: (JsonAstComment | JsonAstMultilineComment)[]; - readonly end: Position; - readonly start: Position; - readonly text: string; -} - -export interface JsonAstNumber extends JsonAstNodeBase { - readonly kind: 'number'; - readonly value: number; -} - -export interface JsonAstObject extends JsonAstNodeBase { - readonly kind: 'object'; - readonly properties: JsonAstKeyValue[]; - readonly value: JsonObject; -} - -export interface JsonAstString extends JsonAstNodeBase { - readonly kind: 'string'; - readonly value: string; -} - -export declare class JsonException extends BaseException { -} - -export interface JsonObject { - [prop: string]: JsonValue; -} - -export declare enum JsonParseMode { - Strict = 0, - CommentsAllowed = 1, - SingleQuotesAllowed = 2, - IdentifierKeyNamesAllowed = 4, - TrailingCommasAllowed = 8, - HexadecimalNumberAllowed = 16, - MultiLineStringAllowed = 32, - LaxNumberParsingAllowed = 64, - NumberConstantsAllowed = 128, - Default = 0, - Loose = 255, - Json = 0, - Json5 = 255 -} - -export interface JsonParserContext { - readonly mode: JsonParseMode; - readonly original: string; - position: Position; - previous: Position; -} - -export declare type JsonPointer = string & { - __PRIVATE_DEVKIT_JSON_POINTER: void; -}; - -export interface JsonSchemaVisitor { - (current: JsonObject | JsonArray, pointer: JsonPointer, parentSchema?: JsonObject | JsonArray, index?: string): void; -} - -export declare type JsonValue = JsonAstNode['value']; - -export interface JsonVisitor { - (value: JsonValue, pointer: JsonPointer, schema?: JsonObject, root?: JsonObject | JsonArray): Observable | JsonValue; -} - -export declare class LevelCapLogger extends LevelTransformLogger { - readonly levelCap: LogLevel; - readonly name: string; - readonly parent: Logger | null; - constructor(name: string, parent: Logger | null, levelCap: LogLevel); - static levelMap: { - [cap: string]: { - [level: string]: string; - }; - }; -} - -export declare class LevelTransformLogger extends Logger { - readonly levelTransform: (level: LogLevel) => LogLevel; - readonly name: string; - readonly parent: Logger | null; - constructor(name: string, parent: Logger | null, levelTransform: (level: LogLevel) => LogLevel); - createChild(name: string): Logger; - log(level: LogLevel, message: string, metadata?: JsonObject): void; -} - -export declare function levenshtein(a: string, b: string): number; - -export interface LogEntry extends LoggerMetadata { - level: LogLevel; - message: string; - timestamp: number; -} - -export declare class Logger extends Observable implements LoggerApi { - protected _metadata: LoggerMetadata; - protected get _observable(): Observable; - protected set _observable(v: Observable); - protected readonly _subject: Subject; - readonly name: string; - readonly parent: Logger | null; - constructor(name: string, parent?: Logger | null); - asApi(): LoggerApi; - complete(): void; - createChild(name: string): Logger; - debug(message: string, metadata?: JsonObject): void; - error(message: string, metadata?: JsonObject): void; - fatal(message: string, metadata?: JsonObject): void; - forEach(next: (value: LogEntry) => void, PromiseCtor?: typeof Promise): Promise; - info(message: string, metadata?: JsonObject): void; - lift(operator: Operator): Observable; - log(level: LogLevel, message: string, metadata?: JsonObject): void; - next(entry: LogEntry): void; - subscribe(): Subscription; - subscribe(observer: PartialObserver): Subscription; - subscribe(next?: (value: LogEntry) => void, error?: (error: Error) => void, complete?: () => void): Subscription; - toString(): string; - warn(message: string, metadata?: JsonObject): void; -} - -export interface LoggerApi { - createChild(name: string): Logger; - debug(message: string, metadata?: JsonObject): void; - error(message: string, metadata?: JsonObject): void; - fatal(message: string, metadata?: JsonObject): void; - info(message: string, metadata?: JsonObject): void; - log(level: LogLevel, message: string, metadata?: JsonObject): void; - warn(message: string, metadata?: JsonObject): void; -} - -export interface LoggerMetadata extends JsonObject { - name: string; - path: string[]; -} - -export declare class LoggingAnalytics implements Analytics { - protected _logger: Logger; - constructor(_logger: Logger); - event(category: string, action: string, options?: EventOptions): void; - flush(): Promise; - pageview(path: string, options?: PageviewOptions): void; - screenview(screenName: string, appName: string, options?: ScreenviewOptions): void; - timing(category: string, variable: string, time: string | number, options?: TimingOptions): void; -} - -export declare type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal'; - -export declare function mapObject(obj: { - [k: string]: T; -}, mapper: (k: string, v: T) => V): { - [k: string]: V; -}; - -export declare class MergeConflictException extends BaseException { - constructor(path: string); -} - -export declare class MultiAnalytics implements Analytics { - protected _backends: Analytics[]; - constructor(_backends?: Analytics[]); - event(category: string, action: string, options?: EventOptions): void; - flush(): Promise; - pageview(path: string, options?: PageviewOptions): void; - push(...backend: Analytics[]): void; - screenview(screenName: string, appName: string, options?: ScreenviewOptions): void; - timing(category: string, variable: string, time: string | number, options?: TimingOptions): void; -} - -export declare enum NgCliAnalyticsDimensions { - CpuCount = 1, - CpuSpeed = 2, - RamInGigabytes = 3, - NodeVersion = 4, - NgAddCollection = 6, - NgIvyEnabled = 8, - BuildErrors = 20 -} - -export declare const NgCliAnalyticsDimensionsFlagInfo: { - [name: string]: [string, string]; -}; - -export declare enum NgCliAnalyticsMetrics { - NgComponentCount = 1, - UNUSED_2 = 2, - UNUSED_3 = 3, - UNUSED_4 = 4, - BuildTime = 5, - NgOnInitCount = 6, - InitialChunkSize = 7, - TotalChunkCount = 8, - TotalChunkSize = 9, - LazyChunkCount = 10, - LazyChunkSize = 11, - AssetCount = 12, - AssetSize = 13, - PolyfillSize = 14, - CssSize = 15 -} - -export declare const NgCliAnalyticsMetricsFlagInfo: { - [name: string]: [string, string]; -}; - -export declare function noCacheNormalize(path: string): Path; - -export declare class NoopAnalytics implements Analytics { - event(): void; - flush(): Promise; - pageview(): void; - screenview(): void; - timing(): void; -} - -export declare function normalize(path: string): Path; - -export declare const NormalizedRoot: Path; - -export declare const NormalizedSep: Path; - -export declare class NullLogger extends Logger { - constructor(parent?: Logger | null); - asApi(): LoggerApi; -} - -export declare function oneLine(strings: TemplateStringsArray, ...values: any[]): string; - -export interface PageviewOptions extends CustomDimensionsAndMetricsOptions { - hostname?: string; - title?: string; -} - -export declare function parseJson(input: string, mode?: JsonParseMode, options?: ParseJsonOptions): JsonValue; - -export declare function parseJsonAst(input: string, mode?: JsonParseMode): JsonAstNode; - -export interface ParseJsonOptions { - path?: string; -} - -export declare function parseJsonPointer(pointer: JsonPointer): string[]; - -export declare class PartiallyOrderedSet implements Set { - get [Symbol.toStringTag](): 'Set'; - get size(): number; - [Symbol.iterator](): Generator; - protected _checkCircularDependencies(item: T, deps: Set): void; - add(item: T, deps?: (Set | T[])): this; - clear(): void; - delete(item: T): boolean; - entries(): IterableIterator<[T, T]>; - forEach(callbackfn: (value: T, value2: T, set: PartiallyOrderedSet) => void, thisArg?: any): void; - has(item: T): boolean; - keys(): IterableIterator; - values(): IterableIterator; -} - -export declare const path: TemplateTag; - -export declare type Path = string & { - __PRIVATE_DEVKIT_PATH: void; -}; - -export declare class PathCannotBeFragmentException extends BaseException { - constructor(path: string); -} - -export declare type PathFragment = Path & { - __PRIVATE_DEVKIT_PATH_FRAGMENT: void; -}; - -export declare class PathIsDirectoryException extends BaseException { - constructor(path: string); -} - -export declare class PathIsFileException extends BaseException { - constructor(path: string); -} - -export declare class PathMustBeAbsoluteException extends BaseException { - constructor(path: string); -} - -export declare class PathSpecificJsonException extends JsonException { - exception: JsonException; - path: string; - constructor(path: string, exception: JsonException); -} - -export declare class PatternMatchingHost extends ResolverHost { - protected _patterns: Map; - protected _resolve(path: Path): Path; - addPattern(pattern: string | string[], replacementFn: ReplacementFunction): void; -} - -export interface Position { - readonly character: number; - readonly line: number; - readonly offset: number; -} - -export declare type PosixPath = string & { - __PRIVATE_DEVKIT_POSIX_PATH: void; -}; - -export declare class PriorityQueue { - get size(): number; - constructor(_comparator: (x: T, y: T) => number); - clear(): void; - peek(): T | undefined; - pop(): T | undefined; - push(item: T): void; - toArray(): Array; -} - -export interface ProjectDefinition { - readonly extensions: Record; - prefix?: string; - root: string; - sourceRoot?: string; - readonly targets: TargetDefinitionCollection; -} - -export declare class ProjectDefinitionCollection extends DefinitionCollection { - constructor(initial?: Record, listener?: DefinitionCollectionListener); - add(definition: { - name: string; - root: string; - sourceRoot?: string; - prefix?: string; - targets?: Record; - [key: string]: unknown; - }): ProjectDefinition; - set(name: string, value: ProjectDefinition): this; -} - -export interface PromptDefinition { - default?: string | string[] | number | boolean | null; - id: string; - items?: Array; - message: string; - multiselect?: boolean; - propertyTypes: Set; - raw?: string | JsonObject; - type: string; - validator?: (value: JsonValue) => boolean | string | Promise; -} - -export declare type PromptProvider = (definitions: Array) => SubscribableOrPromise<{ - [id: string]: JsonValue; -}>; - -export interface ReadonlyHost { - readonly capabilities: HostCapabilities; - exists(path: Path): Observable; - isDirectory(path: Path): Observable; - isFile(path: Path): Observable; - list(path: Path): Observable; - read(path: Path): Observable; - stat(path: Path): Observable | null> | null; -} - -export declare function readWorkspace(path: string, host: WorkspaceHost, format?: WorkspaceFormat): Promise<{ - workspace: WorkspaceDefinition; -}>; - -export interface ReferenceResolver { - (ref: string, context?: ContextT): { - context?: ContextT; - schema?: JsonObject; - }; -} - -export declare function relative(from: Path, to: Path): Path; - -export declare type ReplacementFunction = (path: Path) => Path; - -export declare function resetNormalizeCache(): void; - -export declare function resolve(p1: Path, p2: Path): Path; - -export declare abstract class ResolverHost implements Host { - protected _delegate: Host; - get capabilities(): HostCapabilities; - constructor(_delegate: Host); - protected abstract _resolve(path: Path): Path; - delete(path: Path): Observable; - exists(path: Path): Observable; - isDirectory(path: Path): Observable; - isFile(path: Path): Observable; - list(path: Path): Observable; - read(path: Path): Observable; - rename(from: Path, to: Path): Observable; - stat(path: Path): Observable | null> | null; - watch(path: Path, options?: HostWatchOptions): Observable | null; - write(path: Path, content: FileBuffer): Observable; -} - -export declare class SafeReadonlyHost implements ReadonlyHost { - get capabilities(): HostCapabilities; - constructor(_delegate: ReadonlyHost); - exists(path: Path): Observable; - isDirectory(path: Path): Observable; - isFile(path: Path): Observable; - list(path: Path): Observable; - read(path: Path): Observable; - stat(path: Path): Observable | null> | null; -} - -export interface SchemaFormat { - formatter: SchemaFormatter; - name: string; -} - -export declare type SchemaFormatter = Format; - -export interface SchemaKeywordValidator { - (data: JsonValue, schema: JsonValue, parent: JsonObject | JsonArray | undefined, parentProperty: string | number | undefined, pointer: JsonPointer, rootData: JsonValue): boolean | Observable; -} - -export interface SchemaRegistry { - addFormat(format: SchemaFormat): void; - addPostTransform(visitor: JsonVisitor, deps?: JsonVisitor[]): void; - addPreTransform(visitor: JsonVisitor, deps?: JsonVisitor[]): void; - addSmartDefaultProvider(source: string, provider: SmartDefaultProvider): void; - compile(schema: Object): Observable; - flatten(schema: JsonObject | string): Observable; - usePromptProvider(provider: PromptProvider): void; - useXDeprecatedProvider(onUsage: (message: string) => void): void; -} - -export declare class SchemaValidationException extends BaseException { - readonly errors: SchemaValidatorError[]; - constructor(errors?: SchemaValidatorError[], baseMessage?: string); - static createMessages(errors?: SchemaValidatorError[]): string[]; -} - -export interface SchemaValidator { - (data: JsonValue, options?: SchemaValidatorOptions): Observable; -} - -export declare type SchemaValidatorError = ErrorObject; - -export interface SchemaValidatorOptions { - applyPostTransforms?: boolean; - applyPreTransforms?: boolean; - withPrompts?: boolean; -} - -export interface SchemaValidatorResult { - data: JsonValue; - errors?: SchemaValidatorError[]; - success: boolean; -} - -export declare class ScopedHost extends ResolverHost { - protected _root: Path; - constructor(delegate: Host, _root?: Path); - protected _resolve(path: Path): Path; -} - -export interface ScreenviewOptions extends CustomDimensionsAndMetricsOptions { - appId?: string; - appInstallerId?: string; - appVersion?: string; -} - -export declare class SimpleMemoryHost implements Host<{}> { - protected _cache: Map>; - get capabilities(): HostCapabilities; - constructor(); - protected _delete(path: Path): void; - protected _exists(path: Path): boolean; - protected _isDirectory(path: Path): boolean; - protected _isFile(path: Path): boolean; - protected _list(path: Path): PathFragment[]; - protected _newDirStats(): { - inspect(): string; - isFile(): boolean; - isDirectory(): boolean; - size: number; - atime: Date; - ctime: Date; - mtime: Date; - birthtime: Date; - content: null; - }; - protected _newFileStats(content: FileBuffer, oldStats?: Stats): { - inspect(): string; - isFile(): boolean; - isDirectory(): boolean; - size: number; - atime: Date; - ctime: Date; - mtime: Date; - birthtime: Date; - content: ArrayBuffer; - }; - protected _read(path: Path): FileBuffer; - protected _rename(from: Path, to: Path): void; - protected _stat(path: Path): Stats | null; - protected _toAbsolute(path: Path): Path; - protected _updateWatchers(path: Path, type: HostWatchEventType): void; - protected _watch(path: Path, options?: HostWatchOptions): Observable; - protected _write(path: Path, content: FileBuffer): void; - delete(path: Path): Observable; - exists(path: Path): Observable; - isDirectory(path: Path): Observable; - isFile(path: Path): Observable; - list(path: Path): Observable; - read(path: Path): Observable; - rename(from: Path, to: Path): Observable; - reset(): void; - stat(path: Path): Observable | null> | null; - watch(path: Path, options?: HostWatchOptions): Observable | null; - write(path: Path, content: FileBuffer): Observable; -} - -export interface SimpleMemoryHostStats { - readonly content: FileBuffer | null; -} - -export interface SmartDefaultProvider { - (schema: JsonObject): T | Observable; -} - -export declare function split(path: Path): PathFragment[]; - -export declare type Stats = T & { - isFile(): boolean; - isDirectory(): boolean; - readonly size: number; - readonly atime: Date; - readonly mtime: Date; - readonly ctime: Date; - readonly birthtime: Date; -}; - -export declare function stringToFileBuffer(str: string): FileBuffer; - -export declare function stripIndent(strings: TemplateStringsArray, ...values: any[]): string; - -export declare function stripIndents(strings: TemplateStringsArray, ...values: any[]): string; - -export declare class SyncDelegateHost { - protected _delegate: Host; - get capabilities(): HostCapabilities; - get delegate(): Host; - constructor(_delegate: Host); - protected _doSyncCall(observable: Observable): ResultT; - delete(path: Path): void; - exists(path: Path): boolean; - isDirectory(path: Path): boolean; - isFile(path: Path): boolean; - list(path: Path): PathFragment[]; - read(path: Path): FileBuffer; - rename(from: Path, to: Path): void; - stat(path: Path): Stats | null; - watch(path: Path, options?: HostWatchOptions): Observable | null; - write(path: Path, content: FileBufferLike): void; -} - -export interface SyncHostHandler { - delete(path: Path): void; - exists(path: Path): boolean; - isDirectory(path: Path): boolean; - isFile(path: Path): boolean; - list(path: Path): PathFragment[]; - read(path: Path): FileBuffer; - rename(from: Path, to: Path): void; - stat(path: Path): Stats | null; - write(path: Path, content: FileBufferLike): void; -} - -export declare class SynchronousDelegateExpectedException extends BaseException { - constructor(); -} - -export interface TargetDefinition { - builder: string; - configurations?: Record | undefined>; - defaultConfiguration?: string; - options?: Record; -} - -export declare class TargetDefinitionCollection extends DefinitionCollection { - constructor(initial?: Record, listener?: DefinitionCollectionListener); - add(definition: { - name: string; - } & TargetDefinition): TargetDefinition; - set(name: string, value: TargetDefinition): this; -} - -export declare function template(content: string, options?: TemplateOptions): (input: T) => string; - -export interface TemplateAst { - children: TemplateAstNode[]; - content: string; - fileName: string; -} - -export interface TemplateAstBase { - end: Position; - start: Position; -} - -export interface TemplateAstComment extends TemplateAstBase { - kind: 'comment'; - text: string; -} - -export interface TemplateAstContent extends TemplateAstBase { - content: string; - kind: 'content'; -} - -export interface TemplateAstEscape extends TemplateAstBase { - expression: string; - kind: 'escape'; -} - -export interface TemplateAstEvaluate extends TemplateAstBase { - expression: string; - kind: 'evaluate'; -} - -export interface TemplateAstInterpolate extends TemplateAstBase { - expression: string; - kind: 'interpolate'; -} - -export declare type TemplateAstNode = TemplateAstContent | TemplateAstEvaluate | TemplateAstComment | TemplateAstEscape | TemplateAstInterpolate; - -export interface TemplateOptions { - fileName?: string; - module?: boolean | { - exports: {}; - }; - sourceMap?: boolean; - sourceRoot?: string; - sourceURL?: string; -} - -export declare function templateParser(sourceText: string, fileName: string): TemplateAst; - -export interface TemplateTag { - (template: TemplateStringsArray, ...substitutions: any[]): R; -} - -export declare namespace test { - type TestLogRecord = { - kind: 'write' | 'read' | 'delete' | 'list' | 'exists' | 'isDirectory' | 'isFile' | 'stat' | 'watch'; - path: Path; - } | { - kind: 'rename'; - from: Path; - to: Path; - }; - class TestHost extends SimpleMemoryHost { - protected _records: TestLogRecord[]; - protected _sync: SyncDelegateHost<{}> | null; - get files(): Path[]; - get records(): TestLogRecord[]; - get sync(): SyncDelegateHost<{}>; - constructor(map?: { - [path: string]: string; - }); - $exists(path: string): boolean; - $isDirectory(path: string): boolean; - $isFile(path: string): boolean; - $list(path: string): PathFragment[]; - $read(path: string): string; - $write(path: string, content: string): void; - protected _delete(path: Path): void; - protected _exists(path: Path): boolean; - protected _isDirectory(path: Path): boolean; - protected _isFile(path: Path): boolean; - protected _list(path: Path): PathFragment[]; - protected _read(path: Path): ArrayBuffer; - protected _rename(from: Path, to: Path): void; - protected _stat(path: Path): Stats | null; - protected _watch(path: Path, options?: HostWatchOptions): Observable; - protected _write(path: Path, content: FileBuffer): void; - clearRecords(): void; - clone(): TestHost; - } -} - -export interface TimingOptions extends CustomDimensionsAndMetricsOptions { - label?: string; -} - -export declare class TransformLogger extends Logger { - constructor(name: string, transform: (stream: Observable) => Observable, parent?: Logger | null); -} - -export declare function trimNewlines(strings: TemplateStringsArray, ...values: any[]): string; - -export declare function underscore(str: string): string; - -export declare class UnexpectedEndOfInputException extends JsonException { - constructor(_context: JsonParserContext); -} - -export declare class UnimplementedException extends BaseException { - constructor(); -} - -export declare class UnknownException extends BaseException { - constructor(message: string); -} - -export declare class UnsupportedPlatformException extends BaseException { - constructor(); -} - -export declare type UriHandler = (uri: string) => Observable | Promise | null | undefined; - -export declare function visitJson(json: JsonValue, visitor: JsonVisitor, schema?: JsonSchema, refResolver?: ReferenceResolver, context?: ContextT): Observable; - -export declare function visitJsonSchema(schema: JsonSchema, visitor: JsonSchemaVisitor): void; - -export declare type WindowsPath = string & { - __PRIVATE_DEVKIT_WINDOWS_PATH: void; -}; - -export interface WorkspaceDefinition { - readonly extensions: Record; - readonly projects: ProjectDefinitionCollection; -} - -export declare enum WorkspaceFormat { - JSON = 0 -} - -export interface WorkspaceHost { - isDirectory(path: string): Promise; - isFile(path: string): Promise; - readFile(path: string): Promise; - writeFile(path: string, data: string): Promise; -} - -export declare function writeWorkspace(workspace: WorkspaceDefinition, host: WorkspaceHost, path?: string, format?: WorkspaceFormat): Promise; diff --git a/etc/api/angular_devkit/schematics/src/_golden-api.d.ts b/etc/api/angular_devkit/schematics/src/_golden-api.d.ts deleted file mode 100644 index 444923c61bc1..000000000000 --- a/etc/api/angular_devkit/schematics/src/_golden-api.d.ts +++ /dev/null @@ -1,620 +0,0 @@ -export declare type Action = CreateFileAction | OverwriteFileAction | RenameFileAction | DeleteFileAction; - -export interface ActionBase { - readonly id: number; - readonly parent: number; - readonly path: Path; -} - -export declare class ActionList implements Iterable { - get length(): number; - [Symbol.iterator](): IterableIterator; - protected _action(action: Partial): void; - create(path: Path, content: Buffer): void; - delete(path: Path): void; - find(predicate: (value: Action) => boolean): Action | null; - forEach(fn: (value: Action, index: number, array: Action[]) => void, thisArg?: {}): void; - get(i: number): Action; - has(action: Action): boolean; - optimize(): void; - overwrite(path: Path, content: Buffer): void; - push(action: Action): void; - rename(path: Path, to: Path): void; -} - -export declare function apply(source: Source, rules: Rule[]): Source; - -export declare function applyContentTemplate(options: T): FileOperator; - -export declare function applyPathTemplate(data: T, options?: PathTemplateOptions): FileOperator; - -export declare function applyTemplates(options: T): Rule; - -export declare function applyToSubtree(path: string, rules: Rule[]): Rule; - -export declare function asSource(rule: Rule): Source; - -export declare type AsyncFileOperator = (tree: FileEntry) => Observable; - -export declare abstract class BaseWorkflow implements Workflow { - protected _context: WorkflowExecutionContext[]; - protected _dryRun: boolean; - protected _engine: Engine<{}, {}>; - protected _engineHost: EngineHost<{}, {}>; - protected _force: boolean; - protected _host: virtualFs.Host; - protected _lifeCycle: Subject; - protected _registry: schema.CoreSchemaRegistry; - protected _reporter: Subject; - get context(): Readonly; - get engine(): Engine<{}, {}>; - get engineHost(): EngineHost<{}, {}>; - get lifeCycle(): Observable; - get registry(): schema.SchemaRegistry; - get reporter(): Observable; - constructor(options: BaseWorkflowOptions); - protected _createSinks(): Sink[]; - execute(options: Partial & RequiredWorkflowExecutionContext): Observable; -} - -export interface BaseWorkflowOptions { - dryRun?: boolean; - engineHost: EngineHost<{}, {}>; - force?: boolean; - host: virtualFs.Host; - registry?: schema.CoreSchemaRegistry; -} - -export declare function branchAndMerge(rule: Rule, strategy?: MergeStrategy): Rule; - -export declare function callRule(rule: Rule, input: Tree | Observable, context: SchematicContext): Observable; - -export declare function callSource(source: Source, context: SchematicContext): Observable; - -export declare function chain(rules: Rule[]): Rule; - -export declare class CircularCollectionException extends BaseException { - constructor(name: string); -} - -export interface Collection { - readonly baseDescriptions?: Array>; - readonly description: CollectionDescription; - createSchematic(name: string, allowPrivate?: boolean): Schematic; - listSchematicNames(): string[]; -} - -export declare type CollectionDescription = CollectionMetadataT & { - readonly name: string; - readonly extends?: string[]; -}; - -export declare class CollectionImpl implements Collection { - readonly baseDescriptions?: CollectionDescription[] | undefined; - get description(): CollectionDescription; - get name(): string; - constructor(_description: CollectionDescription, _engine: SchematicEngine, baseDescriptions?: CollectionDescription[] | undefined); - createSchematic(name: string, allowPrivate?: boolean): Schematic; - listSchematicNames(): string[]; -} - -export declare function composeFileOperators(operators: FileOperator[]): FileOperator; - -export declare class ContentHasMutatedException extends BaseException { - constructor(path: string); -} - -export declare function contentTemplate(options: T): Rule; - -export interface CreateFileAction extends ActionBase { - readonly content: Buffer; - readonly kind: 'c'; -} - -export declare class DelegateTree implements Tree { - protected _other: Tree; - get actions(): Action[]; - get root(): DirEntry; - constructor(_other: Tree); - apply(action: Action, strategy?: MergeStrategy): void; - beginUpdate(path: string): UpdateRecorder; - branch(): Tree; - commitUpdate(record: UpdateRecorder): void; - create(path: string, content: Buffer | string): void; - delete(path: string): void; - exists(path: string): boolean; - get(path: string): FileEntry | null; - getDir(path: string): DirEntry; - merge(other: Tree, strategy?: MergeStrategy): void; - overwrite(path: string, content: Buffer | string): void; - read(path: string): Buffer | null; - rename(from: string, to: string): void; - visit(visitor: FileVisitor): void; -} - -export interface DeleteFileAction extends ActionBase { - readonly kind: 'd'; -} - -export interface DirEntry { - readonly parent: DirEntry | null; - readonly path: Path; - readonly subdirs: PathFragment[]; - readonly subfiles: PathFragment[]; - dir(name: PathFragment): DirEntry; - file(name: PathFragment): FileEntry | null; - visit(visitor: FileVisitor): void; -} - -export interface DryRunCreateEvent { - content: Buffer; - kind: 'create'; - path: string; -} - -export interface DryRunDeleteEvent { - kind: 'delete'; - path: string; -} - -export interface DryRunErrorEvent { - description: 'alreadyExist' | 'doesNotExist'; - kind: 'error'; - path: string; -} - -export declare type DryRunEvent = DryRunErrorEvent | DryRunDeleteEvent | DryRunCreateEvent | DryRunUpdateEvent | DryRunRenameEvent; - -export interface DryRunRenameEvent { - kind: 'rename'; - path: string; - to: string; -} - -export declare class DryRunSink extends HostSink { - protected _fileAlreadyExistExceptionSet: Set; - protected _fileDoesNotExistExceptionSet: Set; - protected _subject: Subject; - readonly reporter: Observable; - constructor(host: virtualFs.Host, force?: boolean); - _done(): Observable; - protected _fileAlreadyExistException(path: string): void; - protected _fileDoesNotExistException(path: string): void; -} - -export interface DryRunUpdateEvent { - content: Buffer; - kind: 'update'; - path: string; -} - -export declare function empty(): Source; - -export declare class EmptyTree extends HostTree { - constructor(); -} - -export interface Engine { - readonly defaultMergeStrategy: MergeStrategy; - readonly workflow: Workflow | null; - createCollection(name: string, requester?: Collection): Collection; - createContext(schematic: Schematic, parent?: Partial>, executionOptions?: Partial): TypedSchematicContext; - createSchematic(name: string, collection: Collection): Schematic; - createSourceFromUrl(url: Url, context: TypedSchematicContext): Source; - executePostTasks(): Observable; - transformOptions(schematic: Schematic, options: OptionT, context?: TypedSchematicContext): Observable; -} - -export interface EngineHost { - readonly defaultMergeStrategy?: MergeStrategy; - createCollectionDescription(name: string, requester?: CollectionDescription): CollectionDescription; - createSchematicDescription(name: string, collection: CollectionDescription): SchematicDescription | null; - createSourceFromUrl(url: Url, context: TypedSchematicContext): Source | null; - createTaskExecutor(name: string): Observable; - getSchematicRuleFactory(schematic: SchematicDescription, collection: CollectionDescription): RuleFactory; - hasTaskExecutor(name: string): boolean; - listSchematicNames(collection: CollectionDescription): string[]; - transformContext(context: TypedSchematicContext): TypedSchematicContext | void; - transformOptions(schematic: SchematicDescription, options: OptionT, context?: TypedSchematicContext): Observable; -} - -export interface ExecutionOptions { - interactive: boolean; - scope: string; -} - -export declare function externalSchematic(collectionName: string, schematicName: string, options: OptionT, executionOptions?: Partial): Rule; - -export declare class FileAlreadyExistException extends BaseException { - constructor(path: string); -} - -export declare class FileDoesNotExistException extends BaseException { - constructor(path: string); -} - -export interface FileEntry { - readonly content: Buffer; - readonly path: Path; -} - -export declare type FileOperator = (entry: FileEntry) => FileEntry | null; - -export interface FilePredicate { - (path: Path, entry?: Readonly | null): T; -} - -export declare type FileVisitor = FilePredicate; - -export declare const FileVisitorCancelToken: symbol; - -export declare function filter(predicate: FilePredicate): Rule; - -export declare class FilterHostTree extends HostTree { - constructor(tree: HostTree, filter?: FilePredicate); -} - -export declare function forEach(operator: FileOperator): Rule; - -export declare class HostCreateTree extends HostTree { - constructor(host: virtualFs.ReadonlyHost); -} - -export declare class HostDirEntry implements DirEntry { - protected _host: virtualFs.SyncDelegateHost; - protected _tree: Tree; - readonly parent: DirEntry | null; - readonly path: Path; - get subdirs(): PathFragment[]; - get subfiles(): PathFragment[]; - constructor(parent: DirEntry | null, path: Path, _host: virtualFs.SyncDelegateHost, _tree: Tree); - dir(name: PathFragment): DirEntry; - file(name: PathFragment): FileEntry | null; - visit(visitor: FileVisitor): void; -} - -export declare class HostSink extends SimpleSinkBase { - protected _filesToCreate: Map; - protected _filesToDelete: Set; - protected _filesToRename: Set<[Path, Path]>; - protected _filesToUpdate: Map; - protected _force: boolean; - protected _host: virtualFs.Host; - constructor(_host: virtualFs.Host, _force?: boolean); - protected _createFile(path: Path, content: Buffer): Observable; - protected _deleteFile(path: Path): Observable; - _done(): Observable; - protected _overwriteFile(path: Path, content: Buffer): Observable; - protected _renameFile(from: Path, to: Path): Observable; - protected _validateCreateAction(action: CreateFileAction): Observable; - protected _validateFileExists(p: Path): Observable; -} - -export declare class HostTree implements Tree { - protected _backend: virtualFs.ReadonlyHost<{}>; - get actions(): Action[]; - get root(): DirEntry; - constructor(_backend?: virtualFs.ReadonlyHost<{}>); - protected _normalizePath(path: string): Path; - protected _willCreate(path: Path): boolean; - protected _willDelete(path: Path): boolean; - protected _willOverwrite(path: Path): boolean; - protected _willRename(path: Path): boolean; - apply(action: Action, strategy?: MergeStrategy): void; - beginUpdate(path: string): UpdateRecorder; - branch(): Tree; - commitUpdate(record: UpdateRecorder): void; - create(path: string, content: Buffer | string): void; - delete(path: string): void; - exists(path: string): boolean; - get(path: string): FileEntry | null; - getDir(path: string): DirEntry; - merge(other: Tree, strategy?: MergeStrategy): void; - overwrite(path: string, content: Buffer | string): void; - read(path: string): Buffer | null; - rename(from: string, to: string): void; - visit(visitor: FileVisitor): void; - static isHostTree(tree: Tree): tree is HostTree; -} - -export declare const htmlSelectorFormat: schema.SchemaFormat; - -export declare class InvalidPipeException extends BaseException { - constructor(name: string); -} - -export declare class InvalidRuleResultException extends BaseException { - constructor(value?: {}); -} - -export declare class InvalidSchematicsNameException extends BaseException { - constructor(name: string); -} - -export declare class InvalidSourceResultException extends BaseException { - constructor(value?: {}); -} - -export declare class InvalidUpdateRecordException extends BaseException { - constructor(); -} - -export declare function isAction(action: any): action is Action; - -export declare function isContentAction(action: Action): action is CreateFileAction | OverwriteFileAction; - -export interface LifeCycleEvent { - kind: 'start' | 'end' | 'workflow-start' | 'workflow-end' | 'post-tasks-start' | 'post-tasks-end'; -} - -export declare class MergeConflictException extends BaseException { - constructor(path: string); -} - -export declare enum MergeStrategy { - AllowOverwriteConflict = 2, - AllowCreationConflict = 4, - AllowDeleteConflict = 8, - Default = 0, - Error = 1, - ContentOnly = 2, - Overwrite = 14 -} - -export declare function mergeWith(source: Source, strategy?: MergeStrategy): Rule; - -export declare function move(from: string, to?: string): Rule; - -export declare function noop(): Rule; - -export declare class OptionIsNotDefinedException extends BaseException { - constructor(name: string); -} - -export interface OverwriteFileAction extends ActionBase { - readonly content: Buffer; - readonly kind: 'o'; -} - -export declare function partitionApplyMerge(predicate: FilePredicate, ruleYes: Rule, ruleNo?: Rule): Rule; - -export declare const pathFormat: schema.SchemaFormat; - -export declare function pathTemplate(options: T): Rule; - -export declare type PathTemplateData = { - [key: string]: PathTemplateValue | PathTemplateData | PathTemplatePipeFunction; -}; - -export interface PathTemplateOptions { - interpolationEnd: string; - interpolationStart: string; - pipeSeparator?: string; -} - -export declare type PathTemplatePipeFunction = (x: string) => PathTemplateValue; - -export declare type PathTemplateValue = boolean | string | number | undefined; - -export declare class PrivateSchematicException extends BaseException { - constructor(name: string, collection: CollectionDescription<{}>); -} - -export interface RandomOptions { - multi?: boolean | number; - multiFiles?: boolean | number; - root?: string; -} - -export interface RenameFileAction extends ActionBase { - readonly kind: 'r'; - readonly to: Path; -} - -export declare function renameTemplateFiles(): Rule; - -export interface RequiredWorkflowExecutionContext { - collection: string; - options: object; - schematic: string; -} - -export declare type Rule = (tree: Tree, context: SchematicContext) => Tree | Observable | Rule | Promise | void; - -export declare type RuleFactory = (options: T) => Rule; - -export declare function schematic(schematicName: string, options: OptionT, executionOptions?: Partial): Rule; - -export interface Schematic { - readonly collection: Collection; - readonly description: SchematicDescription; - call(options: OptionT, host: Observable, parentContext?: Partial>, executionOptions?: Partial): Observable; -} - -export declare type SchematicContext = TypedSchematicContext<{}, {}>; - -export declare type SchematicDescription = SchematicMetadataT & { - readonly collection: CollectionDescription; - readonly name: string; - readonly private?: boolean; - readonly hidden?: boolean; -}; - -export declare class SchematicEngine implements Engine { - protected _workflow?: Workflow | undefined; - get defaultMergeStrategy(): MergeStrategy; - get workflow(): Workflow | null; - constructor(_host: EngineHost, _workflow?: Workflow | undefined); - createCollection(name: string, requester?: Collection): Collection; - createContext(schematic: Schematic, parent?: Partial>, executionOptions?: Partial): TypedSchematicContext; - createSchematic(name: string, collection: Collection, allowPrivate?: boolean): Schematic; - createSourceFromUrl(url: Url, context: TypedSchematicContext): Source; - executePostTasks(): Observable; - listSchematicNames(collection: Collection): string[]; - transformOptions(schematic: Schematic, options: OptionT, context?: TypedSchematicContext): Observable; -} - -export declare class SchematicEngineConflictingException extends BaseException { - constructor(); -} - -export declare class SchematicImpl implements Schematic { - get collection(): Collection; - get description(): SchematicDescription; - constructor(_description: SchematicDescription, _factory: RuleFactory<{}>, _collection: Collection, _engine: Engine); - call(options: OptionT, host: Observable, parentContext?: Partial>, executionOptions?: Partial): Observable; -} - -export declare class SchematicsException extends BaseException { -} - -export declare abstract class SimpleSinkBase implements Sink { - postCommit: () => void | Observable; - postCommitAction: (action: Action) => void | Observable; - preCommit: () => void | Observable; - preCommitAction: (action: Action) => void | Action | PromiseLike | Observable; - protected abstract _createFile(path: string, content: Buffer): Observable; - protected abstract _deleteFile(path: string): Observable; - protected abstract _done(): Observable; - protected _fileAlreadyExistException(path: string): void; - protected _fileDoesNotExistException(path: string): void; - protected abstract _overwriteFile(path: string, content: Buffer): Observable; - protected abstract _renameFile(path: string, to: string): Observable; - protected _validateCreateAction(action: CreateFileAction): Observable; - protected _validateDeleteAction(action: DeleteFileAction): Observable; - protected abstract _validateFileExists(p: string): Observable; - protected _validateOverwriteAction(action: OverwriteFileAction): Observable; - protected _validateRenameAction(action: RenameFileAction): Observable; - commit(tree: Tree): Observable; - commitSingleAction(action: Action): Observable; - validateSingleAction(action: Action): Observable; -} - -export interface Sink { - commit(tree: Tree): Observable; -} - -export declare function source(tree: Tree): Source; - -export declare type Source = (context: SchematicContext) => Tree | Observable; - -export declare const standardFormats: schema.SchemaFormat[]; - -export interface TaskConfiguration { - dependencies?: Array; - name: string; - options?: T; -} - -export interface TaskConfigurationGenerator { - toConfiguration(): TaskConfiguration; -} - -export declare type TaskExecutor = (options: T | undefined, context: SchematicContext) => Promise | Observable; - -export interface TaskExecutorFactory { - readonly name: string; - create(options?: T): Promise | Observable; -} - -export interface TaskId { - readonly id: number; -} - -export interface TaskInfo { - readonly configuration: TaskConfiguration; - readonly context: SchematicContext; - readonly id: number; - readonly priority: number; -} - -export declare class TaskScheduler { - constructor(_context: SchematicContext); - finalize(): ReadonlyArray; - schedule(taskConfiguration: TaskConfiguration): TaskId; -} - -export declare function template(options: T): Rule; - -export declare const TEMPLATE_FILENAME_RE: RegExp; - -export declare type Tree = TreeInterface; - -export interface TreeConstructor { - branch(tree: TreeInterface): TreeInterface; - empty(): TreeInterface; - merge(tree: TreeInterface, other: TreeInterface, strategy?: MergeStrategy): TreeInterface; - optimize(tree: TreeInterface): TreeInterface; - partition(tree: TreeInterface, predicate: FilePredicate): [TreeInterface, TreeInterface]; -} - -export declare const TreeSymbol: symbol; - -export interface TypedSchematicContext { - readonly analytics?: analytics.Analytics; - readonly debug: boolean; - readonly engine: Engine; - readonly interactive: boolean; - readonly logger: logging.LoggerApi; - readonly schematic: Schematic; - readonly strategy: MergeStrategy; - addTask(task: TaskConfigurationGenerator, dependencies?: Array): TaskId; -} - -export declare class UnimplementedException extends BaseException { - constructor(); -} - -export declare class UnknownActionException extends BaseException { - constructor(action: Action); -} - -export declare class UnknownCollectionException extends BaseException { - constructor(name: string); -} - -export declare class UnknownPipeException extends BaseException { - constructor(name: string); -} - -export declare class UnknownSchematicException extends BaseException { - constructor(name: string, collection: CollectionDescription<{}>); -} - -export declare class UnknownTaskDependencyException extends BaseException { - constructor(id: TaskId); -} - -export declare class UnknownUrlSourceProtocol extends BaseException { - constructor(url: string); -} - -export declare class UnregisteredTaskException extends BaseException { - constructor(name: string, schematic?: SchematicDescription<{}, {}>); -} - -export declare class UnsuccessfulWorkflowExecution extends BaseException { - constructor(); -} - -export interface UpdateRecorder { - insertLeft(index: number, content: Buffer | string): UpdateRecorder; - insertRight(index: number, content: Buffer | string): UpdateRecorder; - remove(index: number, length: number): UpdateRecorder; -} - -export declare function url(urlString: string): Source; - -export declare function when(predicate: FilePredicate, operator: FileOperator): FileOperator; - -export interface Workflow { - readonly context: Readonly; - execute(options: Partial & RequiredWorkflowExecutionContext): Observable; -} - -export interface WorkflowExecutionContext extends RequiredWorkflowExecutionContext { - allowPrivate?: boolean; - debug: boolean; - logger: logging.Logger; - parentContext?: Readonly; -} diff --git a/etc/api/angular_devkit/schematics/testing/index.d.ts b/etc/api/angular_devkit/schematics/testing/index.d.ts deleted file mode 100644 index 76192b31b905..000000000000 --- a/etc/api/angular_devkit/schematics/testing/index.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -export declare class SchematicTestRunner { - get engine(): SchematicEngine<{}, {}>; - get logger(): logging.Logger; - get tasks(): TaskConfiguration[]; - constructor(_collectionName: string, collectionPath: string); - callRule(rule: Rule, tree: Tree, parentContext?: Partial): Observable; - registerCollection(collectionName: string, collectionPath: string): void; - runExternalSchematicAsync(collectionName: string, schematicName: string, opts?: SchematicSchemaT, tree?: Tree): Observable; - runSchematicAsync(schematicName: string, opts?: SchematicSchemaT, tree?: Tree): Observable; -} - -export declare class UnitTestTree extends DelegateTree { - get files(): string[]; - readContent(path: string): string; -} diff --git a/goldens/BUILD.bazel b/goldens/BUILD.bazel new file mode 100644 index 000000000000..3b3283026537 --- /dev/null +++ b/goldens/BUILD.bazel @@ -0,0 +1,8 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "public-api", + srcs = glob([ + "public-api/**/*.md", + ]), +) diff --git a/goldens/circular-deps/packages.json b/goldens/circular-deps/packages.json new file mode 100644 index 000000000000..fe51488c7066 --- /dev/null +++ b/goldens/circular-deps/packages.json @@ -0,0 +1 @@ +[] diff --git a/goldens/public-api/angular_devkit/architect/src/index.md b/goldens/public-api/angular_devkit/architect/src/index.md new file mode 100644 index 000000000000..3c61b83eb5c3 --- /dev/null +++ b/goldens/public-api/angular_devkit/architect/src/index.md @@ -0,0 +1,151 @@ +## API Report File for "@angular-devkit/architect" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { analytics } from '@angular-devkit/core'; +import { experimental } from '@angular-devkit/core'; +import { json } from '@angular-devkit/core'; +import { logging } from '@angular-devkit/core'; +import { Observable } from 'rxjs'; +import { SubscribableOrPromise } from 'rxjs'; + +// @public (undocumented) +export class Architect { + constructor(_host: ArchitectHost, registry?: json.schema.SchemaRegistry, additionalJobRegistry?: experimental.jobs.Registry); + // (undocumented) + has(name: experimental.jobs.JobName): Observable; + // (undocumented) + scheduleBuilder(name: string, options: json.JsonObject, scheduleOptions?: ScheduleOptions): Promise; + // (undocumented) + scheduleTarget(target: Target, overrides?: json.JsonObject, scheduleOptions?: ScheduleOptions): Promise; +} + +// @public +export interface BuilderContext { + addTeardown(teardown: () => Promise | void): void; + readonly analytics: analytics.Analytics; + builder: BuilderInfo; + currentDirectory: string; + getBuilderNameForTarget(target: Target): Promise; + // (undocumented) + getProjectMetadata(projectName: string): Promise; + // (undocumented) + getProjectMetadata(target: Target): Promise; + getTargetOptions(target: Target): Promise; + id: number; + logger: logging.LoggerApi; + reportProgress(current: number, total?: number, status?: string): void; + reportRunning(): void; + reportStatus(status: string): void; + scheduleBuilder(builderName: string, options?: json.JsonObject, scheduleOptions?: ScheduleOptions_2): Promise; + scheduleTarget(target: Target, overrides?: json.JsonObject, scheduleOptions?: ScheduleOptions_2): Promise; + target?: Target; + validateOptions(options: json.JsonObject, builderName: string): Promise; + workspaceRoot: string; +} + +// @public +export interface BuilderHandlerFn { + (input: A, context: BuilderContext): BuilderOutputLike; +} + +// @public +export type BuilderInfo = json.JsonObject & { + builderName: string; + description: string; + optionSchema: json.schema.JsonSchema; +}; + +// @public +export type BuilderInput = json.JsonObject & Schema; + +// @public (undocumented) +export type BuilderOutput = json.JsonObject & Schema_2; + +// @public +export type BuilderOutputLike = AsyncIterable | SubscribableOrPromise | BuilderOutput; + +// @public (undocumented) +export type BuilderProgress = json.JsonObject & Schema_3 & TypedBuilderProgress; + +// @public +export type BuilderProgressReport = BuilderProgress & { + target?: Target; + builder: BuilderInfo; +}; + +// @public (undocumented) +export enum BuilderProgressState { + // (undocumented) + Error = "error", + // (undocumented) + Running = "running", + // (undocumented) + Stopped = "stopped", + // (undocumented) + Waiting = "waiting" +} + +// @public (undocumented) +export type BuilderRegistry = experimental.jobs.Registry; + +// @public +export interface BuilderRun { + id: number; + info: BuilderInfo; + output: Observable; + progress: Observable; + result: Promise; + stop(): Promise; +} + +// @public (undocumented) +export function createBuilder(fn: BuilderHandlerFn): Builder; + +// @public (undocumented) +export function fromAsyncIterable(iterable: AsyncIterable): Observable; + +// @public (undocumented) +export function isBuilderOutput(obj: any): obj is BuilderOutput; + +// @public (undocumented) +export interface ScheduleOptions { + // (undocumented) + analytics?: analytics.Analytics; + // (undocumented) + logger?: logging.Logger; +} + +// @public +export function scheduleTargetAndForget(context: BuilderContext, target: Target, overrides?: json.JsonObject, scheduleOptions?: ScheduleOptions_2): Observable; + +// @public (undocumented) +export type Target = json.JsonObject & Target_2; + +// @public +export function targetFromTargetString(str: string): Target; + +// @public +export function targetStringFromTarget({ project, target, configuration }: Target): string; + +// @public +export type TypedBuilderProgress = { + state: BuilderProgressState.Stopped; +} | { + state: BuilderProgressState.Error; + error: json.JsonValue; +} | { + state: BuilderProgressState.Waiting; + status?: string; +} | { + state: BuilderProgressState.Running; + status?: string; + current: number; + total?: number; +}; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/goldens/public-api/angular_devkit/build_angular/src/index.md b/goldens/public-api/angular_devkit/build_angular/src/index.md new file mode 100644 index 000000000000..929172cb118f --- /dev/null +++ b/goldens/public-api/angular_devkit/build_angular/src/index.md @@ -0,0 +1,327 @@ +## API Report File for "@angular-devkit/build-angular" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { BuilderContext } from '@angular-devkit/architect'; +import { BuilderOutput } from '@angular-devkit/architect'; +import { BuildResult } from '@angular-devkit/build-webpack'; +import { ConfigOptions } from 'karma'; +import { DevServerBuildOutput } from '@angular-devkit/build-webpack'; +import { json } from '@angular-devkit/core'; +import { JsonObject } from '@angular-devkit/core'; +import { Observable } from 'rxjs'; +import webpack from 'webpack'; +import * as webpack_2 from 'webpack'; +import { WebpackLoggingCallback } from '@angular-devkit/build-webpack'; + +// @public (undocumented) +export type AssetPattern = AssetPatternObject | string; + +// @public (undocumented) +export interface AssetPatternObject { + followSymlinks?: boolean; + glob: string; + ignore?: string[]; + input: string; + output: string; +} + +// @public +export interface BrowserBuilderOptions { + allowedCommonJsDependencies?: string[]; + aot?: boolean; + assets?: AssetPattern[]; + baseHref?: string; + budgets?: Budget[]; + buildOptimizer?: boolean; + commonChunk?: boolean; + crossOrigin?: CrossOrigin; + deleteOutputPath?: boolean; + deployUrl?: string; + // @deprecated + extractCss?: boolean; + extractLicenses?: boolean; + fileReplacements?: FileReplacement[]; + i18nMissingTranslation?: I18NMissingTranslation; + index: IndexUnion; + inlineStyleLanguage?: InlineStyleLanguage; + localize?: Localize; + main: string; + namedChunks?: boolean; + ngswConfigPath?: string; + optimization?: OptimizationUnion; + outputHashing?: OutputHashing; + outputPath: string; + poll?: number; + polyfills?: string; + preserveSymlinks?: boolean; + progress?: boolean; + resourcesOutputPath?: string; + scripts?: ExtraEntryPoint[]; + serviceWorker?: boolean; + // @deprecated + showCircularDependencies?: boolean; + sourceMap?: SourceMapUnion; + statsJson?: boolean; + stylePreprocessorOptions?: StylePreprocessorOptions; + styles?: ExtraEntryPoint[]; + subresourceIntegrity?: boolean; + tsConfig: string; + vendorChunk?: boolean; + verbose?: boolean; + watch?: boolean; + webWorkerTsConfig?: string; +} + +// @public +export type BrowserBuilderOutput = json.JsonObject & BuilderOutput & { + baseOutputPath: string; + outputPaths: string[]; + outputPath: string; +}; + +// @public (undocumented) +export interface Budget { + baseline?: string; + error?: string; + maximumError?: string; + maximumWarning?: string; + minimumError?: string; + minimumWarning?: string; + name?: string; + type: Type; + warning?: string; +} + +// @public +export enum CrossOrigin { + // (undocumented) + Anonymous = "anonymous", + // (undocumented) + None = "none", + // (undocumented) + UseCredentials = "use-credentials" +} + +// @public (undocumented) +export type DevServerBuilderOptions = Schema & json.JsonObject; + +// @public +export type DevServerBuilderOutput = DevServerBuildOutput & { + baseUrl: string; +}; + +// @public +export function executeBrowserBuilder(options: BrowserBuilderOptions, context: BuilderContext, transforms?: { + webpackConfiguration?: ExecutionTransformer; + logging?: WebpackLoggingCallback; + indexHtml?: IndexHtmlTransform; +}): Observable; + +// @public +export function executeDevServerBuilder(options: DevServerBuilderOptions, context: BuilderContext, transforms?: { + webpackConfiguration?: ExecutionTransformer; + logging?: WebpackLoggingCallback; + indexHtml?: IndexHtmlTransform; +}): Observable; + +// @public +export function executeExtractI18nBuilder(options: ExtractI18nBuilderOptions, context: BuilderContext, transforms?: { + webpackConfiguration?: ExecutionTransformer; +}): Promise; + +// @public +export function executeKarmaBuilder(options: KarmaBuilderOptions, context: BuilderContext, transforms?: { + webpackConfiguration?: ExecutionTransformer; + karmaOptions?: (options: KarmaConfigOptions) => KarmaConfigOptions; +}): Observable; + +// @public +export function executeNgPackagrBuilder(options: NgPackagrBuilderOptions, context: BuilderContext): Observable; + +// @public +export function executeProtractorBuilder(options: ProtractorBuilderOptions, context: BuilderContext): Promise; + +// @public +export function executeServerBuilder(options: ServerBuilderOptions, context: BuilderContext, transforms?: { + webpackConfiguration?: ExecutionTransformer; +}): Observable; + +// @public +export type ExecutionTransformer = (input: T) => T | Promise; + +// @public (undocumented) +export type ExtractI18nBuilderOptions = Schema_2 & JsonObject; + +// @public (undocumented) +export type ExtraEntryPoint = ExtraEntryPointObject | string; + +// @public (undocumented) +export interface ExtraEntryPointObject { + bundleName?: string; + inject?: boolean; + input: string; +} + +// @public (undocumented) +export interface FileReplacement { + // (undocumented) + replace?: string; + // (undocumented) + replaceWith?: string; + // (undocumented) + src?: string; + // (undocumented) + with?: string; +} + +// @public +export interface KarmaBuilderOptions { + assets?: AssetPattern_2[]; + browsers?: string; + codeCoverage?: boolean; + codeCoverageExclude?: string[]; + fileReplacements?: FileReplacement_2[]; + include?: string[]; + inlineStyleLanguage?: InlineStyleLanguage_2; + karmaConfig: string; + main: string; + poll?: number; + polyfills?: string; + preserveSymlinks?: boolean; + progress?: boolean; + reporters?: string[]; + scripts?: ExtraEntryPoint_2[]; + sourceMap?: SourceMapUnion_3; + stylePreprocessorOptions?: StylePreprocessorOptions_2; + styles?: ExtraEntryPoint_2[]; + tsConfig: string; + watch?: boolean; + webWorkerTsConfig?: string; +} + +// @public (undocumented) +export type KarmaConfigOptions = ConfigOptions & { + buildWebpack?: unknown; + configFile?: string; +}; + +// @public +export interface NgPackagrBuilderOptions { + project: string; + tsConfig?: string; + watch?: boolean; +} + +// @public (undocumented) +export interface OptimizationObject { + fonts?: FontsUnion; + scripts?: boolean; + styles?: StylesUnion; +} + +// @public +export type OptimizationUnion = boolean | OptimizationObject; + +// @public +export enum OutputHashing { + // (undocumented) + All = "all", + // (undocumented) + Bundles = "bundles", + // (undocumented) + Media = "media", + // (undocumented) + None = "none" +} + +// @public +export interface ProtractorBuilderOptions { + baseUrl?: string; + devServerTarget?: string; + grep?: string; + host?: string; + invertGrep?: boolean; + port?: number; + protractorConfig: string; + specs?: string[]; + suite?: string; + webdriverUpdate?: boolean; +} + +// @public (undocumented) +export interface ServerBuilderOptions { + bundleDependencies?: BundleDependenciesUnion; + deleteOutputPath?: boolean; + deployUrl?: string; + externalDependencies?: string[]; + extractLicenses?: boolean; + fileReplacements?: FileReplacement_3[]; + i18nMissingTranslation?: I18NMissingTranslation_2; + inlineStyleLanguage?: InlineStyleLanguage_3; + localize?: Localize_2; + main: string; + namedChunks?: boolean; + optimization?: OptimizationUnion_3; + outputHashing?: OutputHashing_2; + outputPath: string; + poll?: number; + preserveSymlinks?: boolean; + progress?: boolean; + resourcesOutputPath?: string; + // @deprecated + showCircularDependencies?: boolean; + sourceMap?: SourceMapUnion_4; + statsJson?: boolean; + stylePreprocessorOptions?: StylePreprocessorOptions_3; + tsConfig: string; + verbose?: boolean; + watch?: boolean; +} + +// @public +export type ServerBuilderOutput = json.JsonObject & BuilderOutput & { + baseOutputPath: string; + outputPaths: string[]; + outputPath: string; +}; + +// @public (undocumented) +export interface SourceMapObject { + hidden?: boolean; + scripts?: boolean; + styles?: boolean; + vendor?: boolean; +} + +// @public +export type SourceMapUnion = boolean | SourceMapObject; + +// @public +export interface StylePreprocessorOptions { + includePaths?: string[]; +} + +// @public +export enum Type { + // (undocumented) + All = "all", + // (undocumented) + AllScript = "allScript", + // (undocumented) + Any = "any", + // (undocumented) + AnyComponentStyle = "anyComponentStyle", + // (undocumented) + AnyScript = "anyScript", + // (undocumented) + Bundle = "bundle", + // (undocumented) + Initial = "initial" +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/goldens/public-api/angular_devkit/build_optimizer/src/index.md b/goldens/public-api/angular_devkit/build_optimizer/src/index.md new file mode 100644 index 000000000000..390e23bfac2d --- /dev/null +++ b/goldens/public-api/angular_devkit/build_optimizer/src/index.md @@ -0,0 +1,57 @@ +## API Report File for "@angular-devkit/build-optimizer" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { Compiler } from 'webpack'; +import { RawSourceMap } from 'source-map'; +import * as ts from 'typescript'; + +// @public (undocumented) +export function buildOptimizer(options: BuildOptimizerOptions): TransformJavascriptOutput; + +// @public (undocumented) +export function buildOptimizerLoader(this: { + resourcePath: string; + _module: { + factoryMeta: { + skipBuildOptimizer?: boolean; + sideEffectFree?: boolean; + }; + }; + cacheable(): void; + callback(error?: Error | null, content?: string, sourceMap?: unknown): void; + getOptions(): unknown; +}, content: string, previousSourceMap: RawSourceMap): void; + +// @public (undocumented) +export const buildOptimizerLoaderPath: string; + +// @public (undocumented) +export class BuildOptimizerWebpackPlugin { + // (undocumented) + apply(compiler: Compiler): void; +} + +// @public (undocumented) +export function getPrefixClassesTransformer(): ts.TransformerFactory; + +// @public (undocumented) +export function getPrefixFunctionsTransformer(): ts.TransformerFactory; + +// @public (undocumented) +export function getScrubFileTransformer(program?: ts.Program): ts.TransformerFactory; + +// @public (undocumented) +export function getScrubFileTransformerForCore(program?: ts.Program): ts.TransformerFactory; + +// @public (undocumented) +export function getWrapEnumsTransformer(): ts.TransformerFactory; + +// @public (undocumented) +export function transformJavascript(options: TransformJavascriptOptions): TransformJavascriptOutput; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/goldens/public-api/angular_devkit/build_webpack/src/index.md b/goldens/public-api/angular_devkit/build_webpack/src/index.md new file mode 100644 index 000000000000..312a1a6d319c --- /dev/null +++ b/goldens/public-api/angular_devkit/build_webpack/src/index.md @@ -0,0 +1,78 @@ +## API Report File for "@angular-devkit/build-webpack" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { BuilderContext } from '@angular-devkit/architect'; +import { BuilderOutput } from '@angular-devkit/architect'; +import { Observable } from 'rxjs'; +import webpack from 'webpack'; +import WebpackDevServer from 'webpack-dev-server'; + +// @public (undocumented) +export type BuildResult = BuilderOutput & { + emittedFiles?: EmittedFiles[]; + webpackStats?: webpack.StatsCompilation; + outputPath: string; +}; + +// @public (undocumented) +export type DevServerBuildOutput = BuildResult & { + port: number; + family: string; + address: string; +}; + +// @public (undocumented) +export interface EmittedFiles { + // (undocumented) + asset?: boolean; + // (undocumented) + extension: string; + // (undocumented) + file: string; + // (undocumented) + id?: string; + // (undocumented) + initial: boolean; + // (undocumented) + name?: string; +} + +// @public (undocumented) +export function runWebpack(config: webpack.Configuration, context: BuilderContext, options?: { + logging?: WebpackLoggingCallback; + webpackFactory?: WebpackFactory; + shouldProvideStats?: boolean; +}): Observable; + +// @public (undocumented) +export function runWebpackDevServer(config: webpack.Configuration, context: BuilderContext, options?: { + devServerConfig?: WebpackDevServer.Configuration; + logging?: WebpackLoggingCallback; + webpackFactory?: WebpackFactory; + webpackDevServerFactory?: WebpackDevServerFactory; +}): Observable; + +// @public (undocumented) +export type WebpackBuilderSchema = Schema; + +// @public (undocumented) +export type WebpackDevServerFactory = typeof WebpackDevServer; + +// @public (undocumented) +export interface WebpackFactory { + // (undocumented) + (config: webpack.Configuration): Observable | webpack.Compiler; +} + +// @public (undocumented) +export interface WebpackLoggingCallback { + // (undocumented) + (stats: webpack.Stats, config: webpack.Configuration): void; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/goldens/public-api/angular_devkit/core/node/index.md b/goldens/public-api/angular_devkit/core/node/index.md new file mode 100644 index 000000000000..9369e9a056a3 --- /dev/null +++ b/goldens/public-api/angular_devkit/core/node/index.md @@ -0,0 +1,1322 @@ +## API Report File for "@angular-devkit/core_node" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { ErrorObject } from 'ajv'; +import { Format } from 'ajv'; +import { Observable } from 'rxjs'; +import { Observer } from 'rxjs'; +import { Operator } from 'rxjs'; +import { PartialObserver } from 'rxjs'; +import { Stats as Stats_2 } from 'fs'; +import { Subject } from 'rxjs'; +import { SubscribableOrPromise } from 'rxjs'; +import { Subscription } from 'rxjs'; +import { ValidateFunction } from 'ajv'; + +// @public (undocumented) +function addUndefinedDefaults(value: JsonValue, _pointer: JsonPointer, schema?: JsonSchema): JsonValue; + +// @public +class AliasHost extends ResolverHost { + // (undocumented) + get aliases(): Map; + // (undocumented) + protected _aliases: Map; + // (undocumented) + protected _resolve(path: Path): Path; +} + +// @public (undocumented) +function buildJsonPointer(fragments: string[]): JsonPointer; + +// @public (undocumented) +class ChannelAlreadyExistException extends BaseException { + constructor(name: string); +} + +// @public +class CordHost extends SimpleMemoryHost { + constructor(_back: ReadonlyHost); + // (undocumented) + protected _back: ReadonlyHost; + // (undocumented) + get backend(): ReadonlyHost; + // (undocumented) + get capabilities(): HostCapabilities; + clone(): CordHost; + commit(host: Host, force?: boolean): Observable; + create(path: Path, content: FileBuffer): Observable; + // (undocumented) + delete(path: Path): Observable; + // (undocumented) + exists(path: Path): Observable; + // (undocumented) + protected _filesToCreate: Set; + // (undocumented) + protected _filesToDelete: Set; + // (undocumented) + protected _filesToOverwrite: Set; + // (undocumented) + protected _filesToRename: Map; + // (undocumented) + protected _filesToRenameRevert: Map; + // (undocumented) + isDirectory(path: Path): Observable; + // (undocumented) + isFile(path: Path): Observable; + // (undocumented) + list(path: Path): Observable; + // (undocumented) + overwrite(path: Path, content: FileBuffer): Observable; + // (undocumented) + read(path: Path): Observable; + // (undocumented) + records(): CordHostRecord[]; + // (undocumented) + rename(from: Path, to: Path): Observable; + // (undocumented) + stat(path: Path): Observable | null; + // (undocumented) + watch(path: Path, options?: HostWatchOptions): null; + // (undocumented) + willCreate(path: Path): boolean; + // (undocumented) + willDelete(path: Path): boolean; + // (undocumented) + willOverwrite(path: Path): boolean; + // (undocumented) + willRename(path: Path): boolean; + // (undocumented) + willRenameTo(path: Path, to: Path): boolean; + // (undocumented) + write(path: Path, content: FileBuffer): Observable; +} + +// @public (undocumented) +interface CordHostCreate { + // (undocumented) + content: FileBuffer; + // (undocumented) + kind: 'create'; + // (undocumented) + path: Path; +} + +// @public (undocumented) +interface CordHostDelete { + // (undocumented) + kind: 'delete'; + // (undocumented) + path: Path; +} + +// @public (undocumented) +interface CordHostOverwrite { + // (undocumented) + content: FileBuffer; + // (undocumented) + kind: 'overwrite'; + // (undocumented) + path: Path; +} + +// @public (undocumented) +type CordHostRecord = CordHostCreate | CordHostOverwrite | CordHostRename | CordHostDelete; + +// @public (undocumented) +interface CordHostRename { + // (undocumented) + from: Path; + // (undocumented) + kind: 'rename'; + // (undocumented) + to: Path; +} + +// @public (undocumented) +class CoreSchemaRegistry implements SchemaRegistry { + constructor(formats?: SchemaFormat[]); + // (undocumented) + addFormat(format: SchemaFormat): void; + addPostTransform(visitor: JsonVisitor, deps?: JsonVisitor[]): void; + addPreTransform(visitor: JsonVisitor, deps?: JsonVisitor[]): void; + // (undocumented) + addSmartDefaultProvider(source: string, provider: SmartDefaultProvider): void; + compile(schema: JsonSchema): Observable; + // @deprecated + flatten(schema: JsonObject): Observable; + // (undocumented) + registerUriHandler(handler: UriHandler): void; + // (undocumented) + protected _resolver(ref: string, validate?: ValidateFunction): { + context?: ValidateFunction; + schema?: JsonObject; + }; + // (undocumented) + usePromptProvider(provider: PromptProvider): void; + // (undocumented) + useXDeprecatedProvider(onUsage: (message: string) => void): void; +} + +// @public +export function createConsoleLogger(verbose?: boolean, stdout?: ProcessOutput, stderr?: ProcessOutput, colors?: Partial string>>): logging.Logger; + +// @public +function createDispatcher(options?: Partial>): JobDispatcher; + +// @public +function createJobFactory(loader: () => Promise>, options?: Partial): JobHandler; + +// @public +function createJobHandler(fn: SimpleJobHandlerFn, options?: Partial): JobHandler; + +// @public +function createLoggerJob(job: JobHandler, logger: LoggerApi): JobHandler; + +// @public (undocumented) +function createSyncHost(handler: SyncHostHandler): Host; + +// @public (undocumented) +class Empty implements ReadonlyHost { + // (undocumented) + readonly capabilities: HostCapabilities; + // (undocumented) + exists(path: Path): Observable; + // (undocumented) + isDirectory(path: Path): Observable; + // (undocumented) + isFile(path: Path): Observable; + // (undocumented) + list(path: Path): Observable; + // (undocumented) + read(path: Path): Observable; + // (undocumented) + stat(path: Path): Observable | null>; +} + +declare namespace experimental { + export { + NodeModuleJobRegistry + } +} +export { experimental } + +// @public +class FallbackRegistry implements Registry { + constructor(_fallbacks?: Registry[]); + // (undocumented) + addFallback(registry: Registry): void; + // (undocumented) + protected _fallbacks: Registry[]; + // (undocumented) + get(name: JobName): Observable | null>; +} + +// @public (undocumented) +type FileBuffer = ArrayBuffer; + +// @public (undocumented) +const fileBuffer: TemplateTag; + +// @public (undocumented) +type FileBufferLike = ArrayBufferLike; + +// @public (undocumented) +function fileBufferToString(fileBuffer: FileBuffer): string; + +declare namespace fs { + export { + isFile, + isDirectory + } +} +export { fs } + +// @public (undocumented) +function getTypesOfSchema(schema: JsonSchema): Set; + +// @public (undocumented) +interface Host extends ReadonlyHost { + // (undocumented) + delete(path: Path): Observable; + // (undocumented) + rename(from: Path, to: Path): Observable; + // (undocumented) + watch(path: Path, options?: HostWatchOptions): Observable | null; + // (undocumented) + write(path: Path, content: FileBufferLike): Observable; +} + +// @public (undocumented) +interface HostCapabilities { + // (undocumented) + synchronous: boolean; +} + +// @public (undocumented) +interface HostWatchEvent { + // (undocumented) + readonly path: Path; + // (undocumented) + readonly time: Date; + // (undocumented) + readonly type: HostWatchEventType; +} + +// @public (undocumented) +const enum HostWatchEventType { + // (undocumented) + Changed = 0, + // (undocumented) + Created = 1, + // (undocumented) + Deleted = 2, + // (undocumented) + Renamed = 3 +} + +// @public (undocumented) +interface HostWatchOptions { + // (undocumented) + readonly persistent?: boolean; + // (undocumented) + readonly recursive?: boolean; +} + +// @public (undocumented) +class IndentLogger extends Logger { + constructor(name: string, parent?: Logger | null, indentation?: string); +} + +// @public @deprecated (undocumented) +function isDirectory(filePath: string): boolean; + +// @public @deprecated (undocumented) +function isFile(filePath: string): boolean; + +// @public (undocumented) +function isJobHandler(value: unknown): value is JobHandler; + +// @public (undocumented) +function isJsonSchema(value: unknown): value is JsonSchema; + +// @public +interface Job { + readonly argument: ArgumentT; + readonly description: Observable; + getChannel(name: string, schema?: schema.JsonSchema): Observable; + readonly inboundBus: Observer>; + readonly input: Observer; + readonly outboundBus: Observable>; + readonly output: Observable; + ping(): Observable; + readonly state: JobState; + stop(): void; +} + +// @public (undocumented) +class JobArgumentSchemaValidationError extends schema.SchemaValidationException { + constructor(errors?: schema.SchemaValidatorError[]); +} + +// @public +interface JobDescription extends JsonObject { + // (undocumented) + readonly argument: DeepReadonly; + // (undocumented) + readonly input: DeepReadonly; + // (undocumented) + readonly name: JobName; + // (undocumented) + readonly output: DeepReadonly; +} + +// @public +interface JobDispatcher extends JobHandler { + addConditionalJob(predicate: (args: A) => boolean, name: string): void; + setDefaultJob(name: JobName | null | JobHandler): void; +} + +// @public (undocumented) +class JobDoesNotExistException extends BaseException { + constructor(name: JobName); +} + +// @public +interface JobHandler { + // (undocumented) + (argument: ArgT, context: JobHandlerContext): Observable>; + // (undocumented) + jobDescription: Partial; +} + +// @public +interface JobHandlerContext { + // (undocumented) + readonly dependencies: Job[]; + // (undocumented) + readonly description: JobDescription; + // (undocumented) + readonly inboundBus: Observable>; + // (undocumented) + readonly scheduler: Scheduler; +} + +// @public (undocumented) +type JobInboundMessage = JobInboundMessagePing | JobInboundMessageStop | JobInboundMessageInput; + +// @public +interface JobInboundMessageBase extends JsonObject { + readonly kind: JobInboundMessageKind; +} + +// @public +interface JobInboundMessageInput extends JobInboundMessageBase { + // (undocumented) + readonly kind: JobInboundMessageKind.Input; + readonly value: InputT; +} + +// @public +enum JobInboundMessageKind { + // (undocumented) + Input = "in", + // (undocumented) + Ping = "ip", + // (undocumented) + Stop = "is" +} + +// @public +interface JobInboundMessagePing extends JobInboundMessageBase { + readonly id: number; + // (undocumented) + readonly kind: JobInboundMessageKind.Ping; +} + +// @public (undocumented) +class JobInboundMessageSchemaValidationError extends schema.SchemaValidationException { + constructor(errors?: schema.SchemaValidatorError[]); +} + +// @public +interface JobInboundMessageStop extends JobInboundMessageBase { + // (undocumented) + readonly kind: JobInboundMessageKind.Stop; +} + +// @public +type JobName = string; + +// @public (undocumented) +class JobNameAlreadyRegisteredException extends BaseException { + constructor(name: JobName); +} + +// @public +type JobOutboundMessage = JobOutboundMessageOnReady | JobOutboundMessageStart | JobOutboundMessageOutput | JobOutboundMessageChannelCreate | JobOutboundMessageChannelMessage | JobOutboundMessageChannelError | JobOutboundMessageChannelComplete | JobOutboundMessageEnd | JobOutboundMessagePong; + +// @public +interface JobOutboundMessageBase { + readonly description: JobDescription; + readonly kind: JobOutboundMessageKind; +} + +// @public +interface JobOutboundMessageChannelBase extends JobOutboundMessageBase { + readonly name: string; +} + +// @public +interface JobOutboundMessageChannelComplete extends JobOutboundMessageChannelBase { + // (undocumented) + readonly kind: JobOutboundMessageKind.ChannelComplete; +} + +// @public +interface JobOutboundMessageChannelCreate extends JobOutboundMessageChannelBase { + // (undocumented) + readonly kind: JobOutboundMessageKind.ChannelCreate; +} + +// @public +interface JobOutboundMessageChannelError extends JobOutboundMessageChannelBase { + readonly error: JsonValue; + // (undocumented) + readonly kind: JobOutboundMessageKind.ChannelError; +} + +// @public +interface JobOutboundMessageChannelMessage extends JobOutboundMessageChannelBase { + // (undocumented) + readonly kind: JobOutboundMessageKind.ChannelMessage; + readonly message: JsonValue; +} + +// @public +interface JobOutboundMessageEnd extends JobOutboundMessageBase { + // (undocumented) + readonly kind: JobOutboundMessageKind.End; +} + +// @public +enum JobOutboundMessageKind { + // (undocumented) + ChannelComplete = "cc", + // (undocumented) + ChannelCreate = "cn", + // (undocumented) + ChannelError = "ce", + // (undocumented) + ChannelMessage = "cm", + // (undocumented) + End = "e", + // (undocumented) + OnReady = "c", + // (undocumented) + Output = "o", + // (undocumented) + Pong = "p", + // (undocumented) + Start = "s" +} + +// @public +interface JobOutboundMessageOnReady extends JobOutboundMessageBase { + // (undocumented) + readonly kind: JobOutboundMessageKind.OnReady; +} + +// @public +interface JobOutboundMessageOutput extends JobOutboundMessageBase { + // (undocumented) + readonly kind: JobOutboundMessageKind.Output; + readonly value: OutputT; +} + +// @public +interface JobOutboundMessagePong extends JobOutboundMessageBase { + readonly id: number; + // (undocumented) + readonly kind: JobOutboundMessageKind.Pong; +} + +// @public +interface JobOutboundMessageStart extends JobOutboundMessageBase { + // (undocumented) + readonly kind: JobOutboundMessageKind.Start; +} + +// @public (undocumented) +class JobOutputSchemaValidationError extends schema.SchemaValidationException { + constructor(errors?: schema.SchemaValidatorError[]); +} + +declare namespace jobs { + export { + isJobHandler, + JobName, + JobHandler, + JobHandlerContext, + JobDescription, + JobInboundMessageKind, + JobInboundMessageBase, + JobInboundMessagePing, + JobInboundMessageStop, + JobInboundMessageInput, + JobInboundMessage, + JobOutboundMessageKind, + JobOutboundMessageBase, + JobOutboundMessageOnReady, + JobOutboundMessageStart, + JobOutboundMessageOutput, + JobOutboundMessageChannelBase, + JobOutboundMessageChannelMessage, + JobOutboundMessageChannelError, + JobOutboundMessageChannelCreate, + JobOutboundMessageChannelComplete, + JobOutboundMessageEnd, + JobOutboundMessagePong, + JobOutboundMessage, + JobState, + Job, + ScheduleJobOptions, + Registry, + Scheduler, + createJobHandler, + createJobFactory, + createLoggerJob, + ChannelAlreadyExistException, + SimpleJobHandlerContext, + SimpleJobHandlerFn, + JobNameAlreadyRegisteredException, + JobDoesNotExistException, + createDispatcher, + JobDispatcher, + FallbackRegistry, + RegisterJobOptions, + SimpleJobRegistry, + JobArgumentSchemaValidationError, + JobInboundMessageSchemaValidationError, + JobOutputSchemaValidationError, + SimpleScheduler, + strategy + } +} + +// @public +enum JobState { + Ended = "ended", + Errored = "errored", + Queued = "queued", + Ready = "ready", + Started = "started" +} + +// @public (undocumented) +function joinJsonPointer(root: JsonPointer, ...others: string[]): JsonPointer; + +// @public (undocumented) +type JsonPointer = string & { + __PRIVATE_DEVKIT_JSON_POINTER: void; +}; + +// @public +type JsonSchema = JsonObject | boolean; + +// @public (undocumented) +interface JsonSchemaVisitor { + // (undocumented) + (current: JsonObject | JsonArray, pointer: JsonPointer, parentSchema?: JsonObject | JsonArray, index?: string): void; +} + +// @public (undocumented) +interface JsonVisitor { + // (undocumented) + (value: JsonValue, pointer: JsonPointer, schema?: JsonObject, root?: JsonObject | JsonArray): Observable | JsonValue; +} + +// @public (undocumented) +class LevelCapLogger extends LevelTransformLogger { + constructor(name: string, parent: Logger | null, levelCap: LogLevel); + // (undocumented) + readonly levelCap: LogLevel; + // (undocumented) + static levelMap: { + [cap: string]: { + [level: string]: string; + }; + }; + // (undocumented) + readonly name: string; + // (undocumented) + readonly parent: Logger | null; +} + +// @public (undocumented) +class LevelTransformLogger extends Logger { + constructor(name: string, parent: Logger | null, levelTransform: (level: LogLevel) => LogLevel); + // (undocumented) + createChild(name: string): Logger; + // (undocumented) + readonly levelTransform: (level: LogLevel) => LogLevel; + // (undocumented) + log(level: LogLevel, message: string, metadata?: JsonObject): void; + // (undocumented) + readonly name: string; + // (undocumented) + readonly parent: Logger | null; +} + +// @public (undocumented) +interface LogEntry extends LoggerMetadata { + // (undocumented) + level: LogLevel; + // (undocumented) + message: string; + // (undocumented) + timestamp: number; +} + +// @public (undocumented) +class Logger extends Observable implements LoggerApi { + constructor(name: string, parent?: Logger | null); + // (undocumented) + asApi(): LoggerApi; + // (undocumented) + complete(): void; + // (undocumented) + createChild(name: string): Logger; + // (undocumented) + debug(message: string, metadata?: JsonObject): void; + // (undocumented) + error(message: string, metadata?: JsonObject): void; + // (undocumented) + fatal(message: string, metadata?: JsonObject): void; + // (undocumented) + forEach(next: (value: LogEntry) => void, PromiseCtor?: typeof Promise): Promise; + // (undocumented) + info(message: string, metadata?: JsonObject): void; + // (undocumented) + lift(operator: Operator): Observable; + // (undocumented) + log(level: LogLevel, message: string, metadata?: JsonObject): void; + // (undocumented) + protected _metadata: LoggerMetadata; + // (undocumented) + readonly name: string; + // (undocumented) + next(entry: LogEntry): void; + // (undocumented) + protected get _observable(): Observable; + protected set _observable(v: Observable); + // (undocumented) + readonly parent: Logger | null; + // (undocumented) + protected readonly _subject: Subject; + // (undocumented) + subscribe(): Subscription; + // (undocumented) + subscribe(observer: PartialObserver): Subscription; + // (undocumented) + subscribe(next?: (value: LogEntry) => void, error?: (error: Error) => void, complete?: () => void): Subscription; + // (undocumented) + toString(): string; + // (undocumented) + warn(message: string, metadata?: JsonObject): void; +} + +// @public (undocumented) +interface LoggerApi { + // (undocumented) + createChild(name: string): Logger; + // (undocumented) + debug(message: string, metadata?: JsonObject): void; + // (undocumented) + error(message: string, metadata?: JsonObject): void; + // (undocumented) + fatal(message: string, metadata?: JsonObject): void; + // (undocumented) + info(message: string, metadata?: JsonObject): void; + // (undocumented) + log(level: LogLevel, message: string, metadata?: JsonObject): void; + // (undocumented) + warn(message: string, metadata?: JsonObject): void; +} + +// @public (undocumented) +interface LoggerMetadata extends JsonObject { + // (undocumented) + name: string; + // (undocumented) + path: string[]; +} + +// @public (undocumented) +type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal'; + +// @public +function mergeSchemas(...schemas: (JsonSchema | undefined)[]): JsonSchema; + +// @public +export class NodeJsAsyncHost implements virtualFs.Host { + // (undocumented) + get capabilities(): virtualFs.HostCapabilities; + // (undocumented) + delete(path: Path): Observable; + // (undocumented) + exists(path: Path): Observable; + // (undocumented) + isDirectory(path: Path): Observable; + // (undocumented) + isFile(path: Path): Observable; + // (undocumented) + list(path: Path): Observable; + // (undocumented) + read(path: Path): Observable; + // (undocumented) + rename(from: Path, to: Path): Observable; + // (undocumented) + stat(path: Path): Observable>; + // (undocumented) + watch(path: Path, _options?: virtualFs.HostWatchOptions): Observable | null; + // (undocumented) + write(path: Path, content: virtualFs.FileBuffer): Observable; +} + +// @public +export class NodeJsSyncHost implements virtualFs.Host { + // (undocumented) + get capabilities(): virtualFs.HostCapabilities; + // (undocumented) + delete(path: Path): Observable; + // (undocumented) + exists(path: Path): Observable; + // (undocumented) + isDirectory(path: Path): Observable; + // (undocumented) + isFile(path: Path): Observable; + // (undocumented) + list(path: Path): Observable; + // (undocumented) + read(path: Path): Observable; + // (undocumented) + rename(from: Path, to: Path): Observable; + // (undocumented) + stat(path: Path): Observable>; + // (undocumented) + watch(path: Path, _options?: virtualFs.HostWatchOptions): Observable | null; + // (undocumented) + write(path: Path, content: virtualFs.FileBuffer): Observable; +} + +// @public (undocumented) +class NodeModuleJobRegistry implements experimental_2.jobs.Registry { + get(name: experimental_2.jobs.JobName): Observable | null>; + // (undocumented) + protected _resolve(name: string): string | null; +} + +// @public (undocumented) +class NullLogger extends Logger { + constructor(parent?: Logger | null); + // (undocumented) + asApi(): LoggerApi; +} + +// @public (undocumented) +function parseJsonPointer(pointer: JsonPointer): string[]; + +// @public (undocumented) +class PatternMatchingHost extends ResolverHost { + // (undocumented) + addPattern(pattern: string | string[], replacementFn: ReplacementFunction): void; + // (undocumented) + protected _patterns: Map; + // (undocumented) + protected _resolve(path: Path): Path; +} + +// @public (undocumented) +export interface ProcessOutput { + // (undocumented) + write(buffer: string | Buffer): boolean; +} + +// @public (undocumented) +interface PromptDefinition { + // (undocumented) + default?: string | string[] | number | boolean | null; + // (undocumented) + id: string; + // (undocumented) + items?: Array; + // (undocumented) + message: string; + // (undocumented) + multiselect?: boolean; + // (undocumented) + propertyTypes: Set; + // (undocumented) + raw?: string | JsonObject; + // (undocumented) + type: string; + // (undocumented) + validator?: (value: JsonValue) => boolean | string | Promise; +} + +// @public (undocumented) +type PromptProvider = (definitions: Array) => SubscribableOrPromise<{ + [id: string]: JsonValue; +}>; + +// @public (undocumented) +interface ReadonlyHost { + // (undocumented) + readonly capabilities: HostCapabilities; + // (undocumented) + exists(path: Path): Observable; + // (undocumented) + isDirectory(path: Path): Observable; + // (undocumented) + isFile(path: Path): Observable; + // (undocumented) + list(path: Path): Observable; + // (undocumented) + read(path: Path): Observable; + // (undocumented) + stat(path: Path): Observable | null> | null; +} + +// @public (undocumented) +interface ReferenceResolver { + // (undocumented) + (ref: string, context?: ContextT): { + context?: ContextT; + schema?: JsonObject; + }; +} + +// @public +interface RegisterJobOptions extends Partial { +} + +// @public (undocumented) +interface Registry { + get(name: JobName): Observable | null>; +} + +// @public (undocumented) +type ReplacementFunction = (path: Path) => Path; + +// @public +abstract class ResolverHost implements Host { + constructor(_delegate: Host); + // (undocumented) + get capabilities(): HostCapabilities; + // (undocumented) + protected _delegate: Host; + // (undocumented) + delete(path: Path): Observable; + // (undocumented) + exists(path: Path): Observable; + // (undocumented) + isDirectory(path: Path): Observable; + // (undocumented) + isFile(path: Path): Observable; + // (undocumented) + list(path: Path): Observable; + // (undocumented) + read(path: Path): Observable; + // (undocumented) + rename(from: Path, to: Path): Observable; + // (undocumented) + protected abstract _resolve(path: Path): Path; + // (undocumented) + stat(path: Path): Observable | null> | null; + // (undocumented) + watch(path: Path, options?: HostWatchOptions): Observable | null; + // (undocumented) + write(path: Path, content: FileBuffer): Observable; +} + +// @public +class SafeReadonlyHost implements ReadonlyHost { + constructor(_delegate: ReadonlyHost); + // (undocumented) + get capabilities(): HostCapabilities; + // (undocumented) + exists(path: Path): Observable; + // (undocumented) + isDirectory(path: Path): Observable; + // (undocumented) + isFile(path: Path): Observable; + // (undocumented) + list(path: Path): Observable; + // (undocumented) + read(path: Path): Observable; + // (undocumented) + stat(path: Path): Observable | null> | null; +} + +// @public +interface ScheduleJobOptions { + dependencies?: Job | Job[]; +} + +// @public +interface Scheduler { + getDescription(name: JobName): Observable; + has(name: JobName): Observable; + pause(): () => void; + schedule(name: JobName, argument: A, options?: ScheduleJobOptions): Job; +} + +// @public (undocumented) +interface SchemaFormat { + // (undocumented) + formatter: SchemaFormatter; + // (undocumented) + name: string; +} + +// @public (undocumented) +type SchemaFormatter = Format; + +// @public (undocumented) +interface SchemaKeywordValidator { + // (undocumented) + (data: JsonValue, schema: JsonValue, parent: JsonObject | JsonArray | undefined, parentProperty: string | number | undefined, pointer: JsonPointer, rootData: JsonValue): boolean | Observable; +} + +// @public (undocumented) +interface SchemaRegistry { + // (undocumented) + addFormat(format: SchemaFormat): void; + addPostTransform(visitor: JsonVisitor, deps?: JsonVisitor[]): void; + addPreTransform(visitor: JsonVisitor, deps?: JsonVisitor[]): void; + // (undocumented) + addSmartDefaultProvider(source: string, provider: SmartDefaultProvider): void; + // (undocumented) + compile(schema: Object): Observable; + // @deprecated (undocumented) + flatten(schema: JsonObject | string): Observable; + // (undocumented) + usePromptProvider(provider: PromptProvider): void; + // (undocumented) + useXDeprecatedProvider(onUsage: (message: string) => void): void; +} + +// @public (undocumented) +class SchemaValidationException extends BaseException { + constructor(errors?: SchemaValidatorError[], baseMessage?: string); + // (undocumented) + static createMessages(errors?: SchemaValidatorError[]): string[]; + // (undocumented) + readonly errors: SchemaValidatorError[]; +} + +// @public (undocumented) +interface SchemaValidator { + // (undocumented) + (data: JsonValue, options?: SchemaValidatorOptions): Observable; +} + +// @public (undocumented) +type SchemaValidatorError = Partial; + +// @public (undocumented) +interface SchemaValidatorOptions { + // (undocumented) + applyPostTransforms?: boolean; + // (undocumented) + applyPreTransforms?: boolean; + // (undocumented) + withPrompts?: boolean; +} + +// @public (undocumented) +interface SchemaValidatorResult { + // (undocumented) + data: JsonValue; + // (undocumented) + errors?: SchemaValidatorError[]; + // (undocumented) + success: boolean; +} + +// @public (undocumented) +class ScopedHost extends ResolverHost { + constructor(delegate: Host, _root?: Path); + // (undocumented) + protected _resolve(path: Path): Path; + // (undocumented) + protected _root: Path; +} + +// @public +interface SimpleJobHandlerContext extends JobHandlerContext { + // (undocumented) + createChannel: (name: string) => Observer; + // (undocumented) + input: Observable; +} + +// @public +type SimpleJobHandlerFn = (input: A, context: SimpleJobHandlerContext) => O | Promise | Observable; + +// @public +class SimpleJobRegistry implements Registry { + // (undocumented) + get(name: JobName): Observable | null>; + getJobNames(): JobName[]; + register(name: JobName, handler: JobHandler, options?: RegisterJobOptions): void; + register(handler: JobHandler, options?: RegisterJobOptions & { + name: string; + }): void; + // (undocumented) + protected _register(name: JobName, handler: JobHandler, options: RegisterJobOptions): void; +} + +// @public (undocumented) +class SimpleMemoryHost implements Host<{}> { + constructor(); + // (undocumented) + protected _cache: Map>; + // (undocumented) + get capabilities(): HostCapabilities; + // (undocumented) + delete(path: Path): Observable; + // (undocumented) + protected _delete(path: Path): void; + // (undocumented) + exists(path: Path): Observable; + // (undocumented) + protected _exists(path: Path): boolean; + // (undocumented) + isDirectory(path: Path): Observable; + // (undocumented) + protected _isDirectory(path: Path): boolean; + // (undocumented) + isFile(path: Path): Observable; + // (undocumented) + protected _isFile(path: Path): boolean; + // (undocumented) + list(path: Path): Observable; + // (undocumented) + protected _list(path: Path): PathFragment[]; + // (undocumented) + protected _newDirStats(): { + inspect(): string; + isFile(): boolean; + isDirectory(): boolean; + size: number; + atime: Date; + ctime: Date; + mtime: Date; + birthtime: Date; + content: null; + }; + // (undocumented) + protected _newFileStats(content: FileBuffer, oldStats?: Stats): { + inspect(): string; + isFile(): boolean; + isDirectory(): boolean; + size: number; + atime: Date; + ctime: Date; + mtime: Date; + birthtime: Date; + content: ArrayBuffer; + }; + // (undocumented) + read(path: Path): Observable; + // (undocumented) + protected _read(path: Path): FileBuffer; + // (undocumented) + rename(from: Path, to: Path): Observable; + // (undocumented) + protected _rename(from: Path, to: Path): void; + // (undocumented) + reset(): void; + // (undocumented) + stat(path: Path): Observable | null> | null; + // (undocumented) + protected _stat(path: Path): Stats | null; + // (undocumented) + protected _toAbsolute(path: Path): Path; + // (undocumented) + protected _updateWatchers(path: Path, type: HostWatchEventType): void; + // (undocumented) + watch(path: Path, options?: HostWatchOptions): Observable | null; + // (undocumented) + protected _watch(path: Path, options?: HostWatchOptions): Observable; + // (undocumented) + write(path: Path, content: FileBuffer): Observable; + protected _write(path: Path, content: FileBuffer): void; +} + +// @public (undocumented) +interface SimpleMemoryHostStats { + // (undocumented) + readonly content: FileBuffer | null; +} + +// @public +class SimpleScheduler implements Scheduler { + constructor(_jobRegistry: Registry, _schemaRegistry?: schema.SchemaRegistry); + getDescription(name: JobName): Observable; + has(name: JobName): Observable; + // (undocumented) + protected _jobRegistry: Registry; + pause(): () => void; + schedule(name: JobName, argument: A, options?: ScheduleJobOptions): Job; + // (undocumented) + protected _scheduleJob(name: JobName, argument: A, options: ScheduleJobOptions, waitable: Observable): Job; + // (undocumented) + protected _schemaRegistry: schema.SchemaRegistry; +} + +// @public (undocumented) +interface SmartDefaultProvider { + // (undocumented) + (schema: JsonObject): T | Observable; +} + +// @public (undocumented) +type Stats = T & { + isFile(): boolean; + isDirectory(): boolean; + readonly size: number; + readonly atime: Date; + readonly mtime: Date; + readonly ctime: Date; + readonly birthtime: Date; +}; + +// @public (undocumented) +namespace strategy { + // (undocumented) + type JobStrategy = (handler: JobHandler, options?: Partial>) => JobHandler; + function memoize(replayMessages?: boolean): JobStrategy; + function reuse(replayMessages?: boolean): JobStrategy; + function serialize(): JobStrategy; +} + +// @public (undocumented) +function stringToFileBuffer(str: string): FileBuffer; + +// @public +class SyncDelegateHost { + constructor(_delegate: Host); + // (undocumented) + get capabilities(): HostCapabilities; + // (undocumented) + get delegate(): Host; + // (undocumented) + protected _delegate: Host; + // (undocumented) + delete(path: Path): void; + // (undocumented) + protected _doSyncCall(observable: Observable): ResultT; + // (undocumented) + exists(path: Path): boolean; + // (undocumented) + isDirectory(path: Path): boolean; + // (undocumented) + isFile(path: Path): boolean; + // (undocumented) + list(path: Path): PathFragment[]; + // (undocumented) + read(path: Path): FileBuffer; + // (undocumented) + rename(from: Path, to: Path): void; + // (undocumented) + stat(path: Path): Stats | null; + // (undocumented) + watch(path: Path, options?: HostWatchOptions): Observable | null; + // (undocumented) + write(path: Path, content: FileBufferLike): void; +} + +// @public (undocumented) +interface SyncHostHandler { + // (undocumented) + delete(path: Path): void; + // (undocumented) + exists(path: Path): boolean; + // (undocumented) + isDirectory(path: Path): boolean; + // (undocumented) + isFile(path: Path): boolean; + // (undocumented) + list(path: Path): PathFragment[]; + // (undocumented) + read(path: Path): FileBuffer; + // (undocumented) + rename(from: Path, to: Path): void; + // (undocumented) + stat(path: Path): Stats | null; + // (undocumented) + write(path: Path, content: FileBufferLike): void; +} + +// @public (undocumented) +class SynchronousDelegateExpectedException extends BaseException { + constructor(); +} + +// @public (undocumented) +namespace test { + // (undocumented) + class TestHost extends SimpleMemoryHost { + // (undocumented) + $exists(path: string): boolean; + // (undocumented) + $isDirectory(path: string): boolean; + // (undocumented) + $isFile(path: string): boolean; + // (undocumented) + $list(path: string): PathFragment[]; + // (undocumented) + $read(path: string): string; + // (undocumented) + $write(path: string, content: string): void; + constructor(map?: { + [path: string]: string; + }); + // (undocumented) + clearRecords(): void; + // (undocumented) + clone(): TestHost; + // (undocumented) + protected _delete(path: Path): void; + // (undocumented) + protected _exists(path: Path): boolean; + // (undocumented) + get files(): Path[]; + // (undocumented) + protected _isDirectory(path: Path): boolean; + // (undocumented) + protected _isFile(path: Path): boolean; + // (undocumented) + protected _list(path: Path): PathFragment[]; + // (undocumented) + protected _read(path: Path): ArrayBuffer; + // (undocumented) + get records(): TestLogRecord[]; + // (undocumented) + protected _records: TestLogRecord[]; + // (undocumented) + protected _rename(from: Path, to: Path): void; + // (undocumented) + protected _stat(path: Path): Stats | null; + // (undocumented) + get sync(): SyncDelegateHost<{}>; + // (undocumented) + protected _sync: SyncDelegateHost<{}> | null; + // (undocumented) + protected _watch(path: Path, options?: HostWatchOptions): Observable; + // (undocumented) + protected _write(path: Path, content: FileBuffer): void; + } + // (undocumented) + type TestLogRecord = { + kind: 'write' | 'read' | 'delete' | 'list' | 'exists' | 'isDirectory' | 'isFile' | 'stat' | 'watch'; + path: Path; + } | { + kind: 'rename'; + from: Path; + to: Path; + }; +} + +// @public (undocumented) +class TransformLogger extends Logger { + constructor(name: string, transform: (stream: Observable) => Observable, parent?: Logger | null); +} + +declare namespace transforms { + export { + addUndefinedDefaults + } +} + +// @public (undocumented) +type UriHandler = (uri: string) => Observable | Promise | null | undefined; + +// @public +function visitJson(json: JsonValue, visitor: JsonVisitor, schema?: JsonSchema, refResolver?: ReferenceResolver, context?: ContextT): Observable; + +// @public (undocumented) +function visitJsonSchema(schema: JsonSchema, visitor: JsonSchemaVisitor): void; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/goldens/public-api/angular_devkit/core/src/index.md b/goldens/public-api/angular_devkit/core/src/index.md new file mode 100644 index 000000000000..2bdb179410ad --- /dev/null +++ b/goldens/public-api/angular_devkit/core/src/index.md @@ -0,0 +1,2367 @@ +## API Report File for "@angular-devkit/core" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { ErrorObject } from 'ajv'; +import { Format } from 'ajv'; +import { Observable } from 'rxjs'; +import { Observer } from 'rxjs'; +import { Operator } from 'rxjs'; +import { PartialObserver } from 'rxjs'; +import { Position as Position_2 } from 'source-map'; +import { Subject } from 'rxjs'; +import { SubscribableOrPromise } from 'rxjs'; +import { Subscription } from 'rxjs'; +import { ValidateFunction } from 'ajv'; + +// @public (undocumented) +function addUndefinedDefaults(value: JsonValue, _pointer: JsonPointer, schema?: JsonSchema): JsonValue; + +// @public +class AliasHost extends ResolverHost { + // (undocumented) + get aliases(): Map; + // (undocumented) + protected _aliases: Map; + // (undocumented) + protected _resolve(path: Path): Path; +} + +// @public +interface Analytics { + // (undocumented) + event(category: string, action: string, options?: EventOptions): void; + // (undocumented) + flush(): Promise; + // (undocumented) + pageview(path: string, options?: PageviewOptions): void; + // (undocumented) + screenview(screenName: string, appName: string, options?: ScreenviewOptions): void; + // (undocumented) + timing(category: string, variable: string, time: string | number, options?: TimingOptions): void; +} + +declare namespace analytics { + export { + NgCliAnalyticsDimensions, + NgCliAnalyticsMetrics, + NgCliAnalyticsDimensionsFlagInfo, + NgCliAnalyticsMetricsFlagInfo, + CustomDimensionsAndMetricsOptions, + EventOptions, + ScreenviewOptions, + PageviewOptions, + TimingOptions, + Analytics, + AnalyticsReportKind, + AnalyticsReportBase, + AnalyticsReportEvent, + AnalyticsReportScreenview, + AnalyticsReportPageview, + AnalyticsReportTiming, + AnalyticsReport, + AnalyticsForwarderFn, + ForwardingAnalytics, + AnalyticsReporter, + LoggingAnalytics, + MultiAnalytics, + NoopAnalytics + } +} +export { analytics } + +// @public +type AnalyticsForwarderFn = (report: JsonObject & AnalyticsReport) => void; + +// @public (undocumented) +type AnalyticsReport = AnalyticsReportEvent | AnalyticsReportScreenview | AnalyticsReportPageview | AnalyticsReportTiming; + +// @public (undocumented) +interface AnalyticsReportBase extends JsonObject { + // (undocumented) + kind: AnalyticsReportKind; +} + +// @public (undocumented) +class AnalyticsReporter { + constructor(_analytics: Analytics); + // (undocumented) + protected _analytics: Analytics; + // (undocumented) + report(report: AnalyticsReport): void; +} + +// @public (undocumented) +interface AnalyticsReportEvent extends AnalyticsReportBase { + // (undocumented) + action: string; + // (undocumented) + category: string; + // (undocumented) + kind: AnalyticsReportKind.Event; + // (undocumented) + options: JsonObject & EventOptions; +} + +// @public (undocumented) +enum AnalyticsReportKind { + // (undocumented) + Event = "event", + // (undocumented) + Pageview = "pageview", + // (undocumented) + Screenview = "screenview", + // (undocumented) + Timing = "timing" +} + +// @public (undocumented) +interface AnalyticsReportPageview extends AnalyticsReportBase { + // (undocumented) + kind: AnalyticsReportKind.Pageview; + // (undocumented) + options: JsonObject & PageviewOptions; + // (undocumented) + path: string; +} + +// @public (undocumented) +interface AnalyticsReportScreenview extends AnalyticsReportBase { + // (undocumented) + appName: string; + // (undocumented) + kind: AnalyticsReportKind.Screenview; + // (undocumented) + options: JsonObject & ScreenviewOptions; + // (undocumented) + screenName: string; +} + +// @public (undocumented) +interface AnalyticsReportTiming extends AnalyticsReportBase { + // (undocumented) + category: string; + // (undocumented) + kind: AnalyticsReportKind.Timing; + // (undocumented) + options: JsonObject & TimingOptions; + // (undocumented) + time: string | number; + // (undocumented) + variable: string; +} + +// @public (undocumented) +export function asPosixPath(path: Path): PosixPath; + +// @public (undocumented) +export function asWindowsPath(path: Path): WindowsPath; + +// @public +export class BaseException extends Error { + constructor(message?: string); +} + +// @public +export function basename(path: Path): PathFragment; + +// @public (undocumented) +function buildJsonPointer(fragments: string[]): JsonPointer; + +// @public +function camelize(str: string): string; + +// @public +function capitalize(str: string): string; + +// @public (undocumented) +class ChannelAlreadyExistException extends BaseException { + constructor(name: string); +} + +// @public (undocumented) +export class CircularDependencyFoundException extends BaseException { + constructor(); +} + +// @public +function classify(str: string): string; + +// @public @deprecated (undocumented) +export function clean(array: Array): Array; + +// @public (undocumented) +export class ContentHasMutatedException extends BaseException { + constructor(path: string); +} + +// @public +class CordHost extends SimpleMemoryHost { + constructor(_back: ReadonlyHost); + // (undocumented) + protected _back: ReadonlyHost; + // (undocumented) + get backend(): ReadonlyHost; + // (undocumented) + get capabilities(): HostCapabilities; + clone(): CordHost; + commit(host: Host, force?: boolean): Observable; + create(path: Path, content: FileBuffer): Observable; + // (undocumented) + delete(path: Path): Observable; + // (undocumented) + exists(path: Path): Observable; + // (undocumented) + protected _filesToCreate: Set; + // (undocumented) + protected _filesToDelete: Set; + // (undocumented) + protected _filesToOverwrite: Set; + // (undocumented) + protected _filesToRename: Map; + // (undocumented) + protected _filesToRenameRevert: Map; + // (undocumented) + isDirectory(path: Path): Observable; + // (undocumented) + isFile(path: Path): Observable; + // (undocumented) + list(path: Path): Observable; + // (undocumented) + overwrite(path: Path, content: FileBuffer): Observable; + // (undocumented) + read(path: Path): Observable; + // (undocumented) + records(): CordHostRecord[]; + // (undocumented) + rename(from: Path, to: Path): Observable; + // (undocumented) + stat(path: Path): Observable | null; + // (undocumented) + watch(path: Path, options?: HostWatchOptions): null; + // (undocumented) + willCreate(path: Path): boolean; + // (undocumented) + willDelete(path: Path): boolean; + // (undocumented) + willOverwrite(path: Path): boolean; + // (undocumented) + willRename(path: Path): boolean; + // (undocumented) + willRenameTo(path: Path, to: Path): boolean; + // (undocumented) + write(path: Path, content: FileBuffer): Observable; +} + +// @public (undocumented) +interface CordHostCreate { + // (undocumented) + content: FileBuffer; + // (undocumented) + kind: 'create'; + // (undocumented) + path: Path; +} + +// @public (undocumented) +interface CordHostDelete { + // (undocumented) + kind: 'delete'; + // (undocumented) + path: Path; +} + +// @public (undocumented) +interface CordHostOverwrite { + // (undocumented) + content: FileBuffer; + // (undocumented) + kind: 'overwrite'; + // (undocumented) + path: Path; +} + +// @public (undocumented) +type CordHostRecord = CordHostCreate | CordHostOverwrite | CordHostRename | CordHostDelete; + +// @public (undocumented) +interface CordHostRename { + // (undocumented) + from: Path; + // (undocumented) + kind: 'rename'; + // (undocumented) + to: Path; +} + +// @public (undocumented) +class CoreSchemaRegistry implements SchemaRegistry { + constructor(formats?: SchemaFormat[]); + // (undocumented) + addFormat(format: SchemaFormat): void; + addPostTransform(visitor: JsonVisitor, deps?: JsonVisitor[]): void; + addPreTransform(visitor: JsonVisitor, deps?: JsonVisitor[]): void; + // (undocumented) + addSmartDefaultProvider(source: string, provider: SmartDefaultProvider): void; + compile(schema: JsonSchema): Observable; + // @deprecated + flatten(schema: JsonObject): Observable; + // (undocumented) + registerUriHandler(handler: UriHandler): void; + // (undocumented) + protected _resolver(ref: string, validate?: ValidateFunction): { + context?: ValidateFunction; + schema?: JsonObject; + }; + // (undocumented) + usePromptProvider(provider: PromptProvider): void; + // (undocumented) + useXDeprecatedProvider(onUsage: (message: string) => void): void; +} + +// @public +function createDispatcher(options?: Partial>): JobDispatcher; + +// @public +function createJobFactory(loader: () => Promise>, options?: Partial): JobHandler; + +// @public +function createJobHandler(fn: SimpleJobHandlerFn, options?: Partial): JobHandler; + +// @public +function createLoggerJob(job: JobHandler, logger: LoggerApi): JobHandler; + +// @public (undocumented) +function createSyncHost(handler: SyncHostHandler): Host; + +// @public (undocumented) +function createWorkspaceHost(host: virtualFs.Host): WorkspaceHost; + +// @public +interface CustomDimensionsAndMetricsOptions { + // (undocumented) + dimensions?: (boolean | number | string)[]; + // (undocumented) + metrics?: (boolean | number | string)[]; +} + +// @public +function dasherize(str: string): string; + +// @public +function decamelize(str: string): string; + +// @public (undocumented) +export function deepCopy(value: T): T; + +// @public (undocumented) +export type DeepReadonly = T extends (infer R)[] ? DeepReadonlyArray : T extends Function ? T : T extends object ? DeepReadonlyObject : T; + +// @public (undocumented) +export interface DeepReadonlyArray extends Array> { +} + +// @public (undocumented) +export type DeepReadonlyObject = { + readonly [P in keyof T]: DeepReadonly; +}; + +// @public (undocumented) +type DefinitionCollectionListener = (name: string, action: 'add' | 'remove' | 'replace', newValue: V | undefined, oldValue: V | undefined, collection: DefinitionCollection) => void; + +// @public (undocumented) +export class DependencyNotFoundException extends BaseException { + constructor(); +} + +// @public +export function dirname(path: Path): Path; + +// @public (undocumented) +class Empty implements ReadonlyHost { + // (undocumented) + readonly capabilities: HostCapabilities; + // (undocumented) + exists(path: Path): Observable; + // (undocumented) + isDirectory(path: Path): Observable; + // (undocumented) + isFile(path: Path): Observable; + // (undocumented) + list(path: Path): Observable; + // (undocumented) + read(path: Path): Observable; + // (undocumented) + stat(path: Path): Observable | null>; +} + +// @public (undocumented) +interface EventOptions extends CustomDimensionsAndMetricsOptions { + // (undocumented) + label?: string; + // (undocumented) + value?: string; +} + +declare namespace experimental { + export { + jobs + } +} +export { experimental } + +// @public (undocumented) +export function extname(path: Path): string; + +// @public +class FallbackRegistry implements Registry { + constructor(_fallbacks?: Registry[]); + // (undocumented) + addFallback(registry: Registry): void; + // (undocumented) + protected _fallbacks: Registry[]; + // (undocumented) + get(name: JobName): Observable | null>; +} + +// @public (undocumented) +export class FileAlreadyExistException extends BaseException { + constructor(path: string); +} + +// @public (undocumented) +type FileBuffer = ArrayBuffer; + +// @public (undocumented) +const fileBuffer: TemplateTag; + +// @public (undocumented) +type FileBufferLike = ArrayBufferLike; + +// @public (undocumented) +function fileBufferToString(fileBuffer: FileBuffer): string; + +// @public (undocumented) +export class FileDoesNotExistException extends BaseException { + constructor(path: string); +} + +// @public +class ForwardingAnalytics implements Analytics { + constructor(_fn: AnalyticsForwarderFn); + // (undocumented) + event(category: string, action: string, options?: EventOptions): void; + // (undocumented) + flush(): Promise; + // (undocumented) + protected _fn: AnalyticsForwarderFn; + // (undocumented) + pageview(path: string, options?: PageviewOptions): void; + // (undocumented) + screenview(screenName: string, appName: string, options?: ScreenviewOptions): void; + // (undocumented) + timing(category: string, variable: string, time: string | number, options?: TimingOptions): void; +} + +// @public (undocumented) +export function fragment(path: string): PathFragment; + +// @public (undocumented) +export function getSystemPath(path: Path): string; + +// @public (undocumented) +function getTypesOfSchema(schema: JsonSchema): Set; + +// @public (undocumented) +interface Host extends ReadonlyHost { + // (undocumented) + delete(path: Path): Observable; + // (undocumented) + rename(from: Path, to: Path): Observable; + // (undocumented) + watch(path: Path, options?: HostWatchOptions): Observable | null; + // (undocumented) + write(path: Path, content: FileBufferLike): Observable; +} + +// @public (undocumented) +interface HostCapabilities { + // (undocumented) + synchronous: boolean; +} + +// @public (undocumented) +interface HostWatchEvent { + // (undocumented) + readonly path: Path; + // (undocumented) + readonly time: Date; + // (undocumented) + readonly type: HostWatchEventType; +} + +// @public (undocumented) +const enum HostWatchEventType { + // (undocumented) + Changed = 0, + // (undocumented) + Created = 1, + // (undocumented) + Deleted = 2, + // (undocumented) + Renamed = 3 +} + +// @public (undocumented) +interface HostWatchOptions { + // (undocumented) + readonly persistent?: boolean; + // (undocumented) + readonly recursive?: boolean; +} + +// @public (undocumented) +function indentBy(indentations: number): TemplateTag; + +// @public (undocumented) +class IndentLogger extends Logger { + constructor(name: string, parent?: Logger | null, indentation?: string); +} + +// @public @deprecated +export class InvalidJsonCharacterException extends JsonException { + constructor(context: JsonParserContext); + // (undocumented) + character: number; + // (undocumented) + invalidChar: string; + // (undocumented) + line: number; + // (undocumented) + offset: number; +} + +// @public (undocumented) +export class InvalidPathException extends BaseException { + constructor(path: string); +} + +// @public (undocumented) +export class InvalidUpdateRecordException extends BaseException { + constructor(); +} + +// @public +export function isAbsolute(p: Path): boolean; + +// @public (undocumented) +function isJobHandler(value: unknown): value is JobHandler; + +// @public (undocumented) +export function isJsonArray(value: JsonValue): value is JsonArray; + +// @public (undocumented) +export function isJsonObject(value: JsonValue): value is JsonObject; + +// @public (undocumented) +function isJsonSchema(value: unknown): value is JsonSchema; + +// @public +export function isPromise(obj: any): obj is Promise; + +// @public +interface Job { + readonly argument: ArgumentT; + readonly description: Observable; + getChannel(name: string, schema?: schema.JsonSchema): Observable; + readonly inboundBus: Observer>; + readonly input: Observer; + readonly outboundBus: Observable>; + readonly output: Observable; + ping(): Observable; + readonly state: JobState; + stop(): void; +} + +// @public (undocumented) +class JobArgumentSchemaValidationError extends schema.SchemaValidationException { + constructor(errors?: schema.SchemaValidatorError[]); +} + +// @public +interface JobDescription extends JsonObject { + // (undocumented) + readonly argument: DeepReadonly; + // (undocumented) + readonly input: DeepReadonly; + // (undocumented) + readonly name: JobName; + // (undocumented) + readonly output: DeepReadonly; +} + +// @public +interface JobDispatcher extends JobHandler { + addConditionalJob(predicate: (args: A) => boolean, name: string): void; + setDefaultJob(name: JobName | null | JobHandler): void; +} + +// @public (undocumented) +class JobDoesNotExistException extends BaseException { + constructor(name: JobName); +} + +// @public +interface JobHandler { + // (undocumented) + (argument: ArgT, context: JobHandlerContext): Observable>; + // (undocumented) + jobDescription: Partial; +} + +// @public +interface JobHandlerContext { + // (undocumented) + readonly dependencies: Job[]; + // (undocumented) + readonly description: JobDescription; + // (undocumented) + readonly inboundBus: Observable>; + // (undocumented) + readonly scheduler: Scheduler; +} + +// @public (undocumented) +type JobInboundMessage = JobInboundMessagePing | JobInboundMessageStop | JobInboundMessageInput; + +// @public +interface JobInboundMessageBase extends JsonObject { + readonly kind: JobInboundMessageKind; +} + +// @public +interface JobInboundMessageInput extends JobInboundMessageBase { + // (undocumented) + readonly kind: JobInboundMessageKind.Input; + readonly value: InputT; +} + +// @public +enum JobInboundMessageKind { + // (undocumented) + Input = "in", + // (undocumented) + Ping = "ip", + // (undocumented) + Stop = "is" +} + +// @public +interface JobInboundMessagePing extends JobInboundMessageBase { + readonly id: number; + // (undocumented) + readonly kind: JobInboundMessageKind.Ping; +} + +// @public (undocumented) +class JobInboundMessageSchemaValidationError extends schema.SchemaValidationException { + constructor(errors?: schema.SchemaValidatorError[]); +} + +// @public +interface JobInboundMessageStop extends JobInboundMessageBase { + // (undocumented) + readonly kind: JobInboundMessageKind.Stop; +} + +// @public +type JobName = string; + +// @public (undocumented) +class JobNameAlreadyRegisteredException extends BaseException { + constructor(name: JobName); +} + +// @public +type JobOutboundMessage = JobOutboundMessageOnReady | JobOutboundMessageStart | JobOutboundMessageOutput | JobOutboundMessageChannelCreate | JobOutboundMessageChannelMessage | JobOutboundMessageChannelError | JobOutboundMessageChannelComplete | JobOutboundMessageEnd | JobOutboundMessagePong; + +// @public +interface JobOutboundMessageBase { + readonly description: JobDescription; + readonly kind: JobOutboundMessageKind; +} + +// @public +interface JobOutboundMessageChannelBase extends JobOutboundMessageBase { + readonly name: string; +} + +// @public +interface JobOutboundMessageChannelComplete extends JobOutboundMessageChannelBase { + // (undocumented) + readonly kind: JobOutboundMessageKind.ChannelComplete; +} + +// @public +interface JobOutboundMessageChannelCreate extends JobOutboundMessageChannelBase { + // (undocumented) + readonly kind: JobOutboundMessageKind.ChannelCreate; +} + +// @public +interface JobOutboundMessageChannelError extends JobOutboundMessageChannelBase { + readonly error: JsonValue; + // (undocumented) + readonly kind: JobOutboundMessageKind.ChannelError; +} + +// @public +interface JobOutboundMessageChannelMessage extends JobOutboundMessageChannelBase { + // (undocumented) + readonly kind: JobOutboundMessageKind.ChannelMessage; + readonly message: JsonValue; +} + +// @public +interface JobOutboundMessageEnd extends JobOutboundMessageBase { + // (undocumented) + readonly kind: JobOutboundMessageKind.End; +} + +// @public +enum JobOutboundMessageKind { + // (undocumented) + ChannelComplete = "cc", + // (undocumented) + ChannelCreate = "cn", + // (undocumented) + ChannelError = "ce", + // (undocumented) + ChannelMessage = "cm", + // (undocumented) + End = "e", + // (undocumented) + OnReady = "c", + // (undocumented) + Output = "o", + // (undocumented) + Pong = "p", + // (undocumented) + Start = "s" +} + +// @public +interface JobOutboundMessageOnReady extends JobOutboundMessageBase { + // (undocumented) + readonly kind: JobOutboundMessageKind.OnReady; +} + +// @public +interface JobOutboundMessageOutput extends JobOutboundMessageBase { + // (undocumented) + readonly kind: JobOutboundMessageKind.Output; + readonly value: OutputT; +} + +// @public +interface JobOutboundMessagePong extends JobOutboundMessageBase { + readonly id: number; + // (undocumented) + readonly kind: JobOutboundMessageKind.Pong; +} + +// @public +interface JobOutboundMessageStart extends JobOutboundMessageBase { + // (undocumented) + readonly kind: JobOutboundMessageKind.Start; +} + +// @public (undocumented) +class JobOutputSchemaValidationError extends schema.SchemaValidationException { + constructor(errors?: schema.SchemaValidatorError[]); +} + +declare namespace jobs { + export { + isJobHandler, + JobName, + JobHandler, + JobHandlerContext, + JobDescription, + JobInboundMessageKind, + JobInboundMessageBase, + JobInboundMessagePing, + JobInboundMessageStop, + JobInboundMessageInput, + JobInboundMessage, + JobOutboundMessageKind, + JobOutboundMessageBase, + JobOutboundMessageOnReady, + JobOutboundMessageStart, + JobOutboundMessageOutput, + JobOutboundMessageChannelBase, + JobOutboundMessageChannelMessage, + JobOutboundMessageChannelError, + JobOutboundMessageChannelCreate, + JobOutboundMessageChannelComplete, + JobOutboundMessageEnd, + JobOutboundMessagePong, + JobOutboundMessage, + JobState, + Job, + ScheduleJobOptions, + Registry, + Scheduler, + createJobHandler, + createJobFactory, + createLoggerJob, + ChannelAlreadyExistException, + SimpleJobHandlerContext, + SimpleJobHandlerFn, + JobNameAlreadyRegisteredException, + JobDoesNotExistException, + createDispatcher, + JobDispatcher, + FallbackRegistry, + RegisterJobOptions, + SimpleJobRegistry, + JobArgumentSchemaValidationError, + JobInboundMessageSchemaValidationError, + JobOutputSchemaValidationError, + SimpleScheduler, + strategy + } +} + +// @public +enum JobState { + Ended = "ended", + Errored = "errored", + Queued = "queued", + Ready = "ready", + Started = "started" +} + +// @public +export function join(p1: Path, ...others: string[]): Path; + +// @public (undocumented) +function joinJsonPointer(root: JsonPointer, ...others: string[]): JsonPointer; + +declare namespace json { + export { + schema, + isJsonObject, + isJsonArray, + Position, + JsonAstNode, + JsonAstNodeBase, + JsonAstNumber, + JsonAstString, + JsonAstIdentifier, + JsonArray, + JsonAstArray, + JsonObject, + JsonAstKeyValue, + JsonAstObject, + JsonAstConstantFalse, + JsonAstConstantNull, + JsonAstConstantTrue, + JsonAstMultilineComment, + JsonAstComment, + JsonValue, + parseJsonAst, + parseJson, + JsonException, + InvalidJsonCharacterException, + UnexpectedEndOfInputException, + PathSpecificJsonException, + JsonParserContext, + JsonParseMode, + ParseJsonOptions + } +} +export { json } + +// @public (undocumented) +export interface JsonArray extends Array { +} + +// @public (undocumented) +export interface JsonAstArray extends JsonAstNodeBase { + // (undocumented) + readonly elements: JsonAstNode[]; + // (undocumented) + readonly kind: 'array'; + // (undocumented) + readonly value: JsonArray; +} + +// @public (undocumented) +export interface JsonAstComment extends JsonAstNodeBase { + // (undocumented) + readonly content: string; + // (undocumented) + readonly kind: 'comment'; +} + +// @public (undocumented) +export interface JsonAstConstantFalse extends JsonAstNodeBase { + // (undocumented) + readonly kind: 'false'; + // (undocumented) + readonly value: false; +} + +// @public (undocumented) +export interface JsonAstConstantNull extends JsonAstNodeBase { + // (undocumented) + readonly kind: 'null'; + // (undocumented) + readonly value: null; +} + +// @public (undocumented) +export interface JsonAstConstantTrue extends JsonAstNodeBase { + // (undocumented) + readonly kind: 'true'; + // (undocumented) + readonly value: true; +} + +// @public (undocumented) +export interface JsonAstIdentifier extends JsonAstNodeBase { + // (undocumented) + readonly kind: 'identifier'; + // (undocumented) + readonly value: string; +} + +// @public (undocumented) +export interface JsonAstKeyValue extends JsonAstNodeBase { + // (undocumented) + readonly key: JsonAstString | JsonAstIdentifier; + // (undocumented) + readonly kind: 'keyvalue'; + // (undocumented) + readonly value: JsonAstNode; +} + +// @public (undocumented) +export interface JsonAstMultilineComment extends JsonAstNodeBase { + // (undocumented) + readonly content: string; + // (undocumented) + readonly kind: 'multicomment'; +} + +// @public (undocumented) +export type JsonAstNode = JsonAstNumber | JsonAstString | JsonAstIdentifier | JsonAstArray | JsonAstObject | JsonAstConstantFalse | JsonAstConstantNull | JsonAstConstantTrue; + +// @public (undocumented) +export interface JsonAstNodeBase { + // (undocumented) + readonly comments?: (JsonAstComment | JsonAstMultilineComment)[]; + // (undocumented) + readonly end: Position; + // (undocumented) + readonly start: Position; + // (undocumented) + readonly text: string; +} + +// @public (undocumented) +export interface JsonAstNumber extends JsonAstNodeBase { + // (undocumented) + readonly kind: 'number'; + // (undocumented) + readonly value: number; +} + +// @public (undocumented) +export interface JsonAstObject extends JsonAstNodeBase { + // (undocumented) + readonly kind: 'object'; + // (undocumented) + readonly properties: JsonAstKeyValue[]; + // (undocumented) + readonly value: JsonObject; +} + +// @public (undocumented) +export interface JsonAstString extends JsonAstNodeBase { + // (undocumented) + readonly kind: 'string'; + // (undocumented) + readonly value: string; +} + +// @public (undocumented) +export class JsonException extends BaseException { +} + +// @public (undocumented) +export interface JsonObject { + // (undocumented) + [prop: string]: JsonValue; +} + +// @public +export enum JsonParseMode { + // (undocumented) + CommentsAllowed = 1, + // (undocumented) + Default = 0, + // (undocumented) + HexadecimalNumberAllowed = 16, + // (undocumented) + IdentifierKeyNamesAllowed = 4, + // (undocumented) + Json = 0, + // (undocumented) + Json5 = 255, + // (undocumented) + LaxNumberParsingAllowed = 64, + // (undocumented) + Loose = 255, + // (undocumented) + MultiLineStringAllowed = 32, + // (undocumented) + NumberConstantsAllowed = 128, + // (undocumented) + SingleQuotesAllowed = 2, + // (undocumented) + Strict = 0, + // (undocumented) + TrailingCommasAllowed = 8 +} + +// @public @deprecated +export interface JsonParserContext { + // (undocumented) + readonly mode: JsonParseMode; + // (undocumented) + readonly original: string; + // (undocumented) + position: Position; + // (undocumented) + previous: Position; +} + +// @public (undocumented) +type JsonPointer = string & { + __PRIVATE_DEVKIT_JSON_POINTER: void; +}; + +// @public +type JsonSchema = JsonObject | boolean; + +// @public (undocumented) +interface JsonSchemaVisitor { + // (undocumented) + (current: JsonObject | JsonArray, pointer: JsonPointer, parentSchema?: JsonObject | JsonArray, index?: string): void; +} + +// @public (undocumented) +export type JsonValue = JsonAstNode['value']; + +// @public (undocumented) +interface JsonVisitor { + // (undocumented) + (value: JsonValue, pointer: JsonPointer, schema?: JsonObject, root?: JsonObject | JsonArray): Observable | JsonValue; +} + +// @public (undocumented) +class LevelCapLogger extends LevelTransformLogger { + constructor(name: string, parent: Logger | null, levelCap: LogLevel); + // (undocumented) + readonly levelCap: LogLevel; + // (undocumented) + static levelMap: { + [cap: string]: { + [level: string]: string; + }; + }; + // (undocumented) + readonly name: string; + // (undocumented) + readonly parent: Logger | null; +} + +// @public (undocumented) +class LevelTransformLogger extends Logger { + constructor(name: string, parent: Logger | null, levelTransform: (level: LogLevel) => LogLevel); + // (undocumented) + createChild(name: string): Logger; + // (undocumented) + readonly levelTransform: (level: LogLevel) => LogLevel; + // (undocumented) + log(level: LogLevel, message: string, metadata?: JsonObject): void; + // (undocumented) + readonly name: string; + // (undocumented) + readonly parent: Logger | null; +} + +// @public +function levenshtein(a: string, b: string): number; + +// @public (undocumented) +interface LogEntry extends LoggerMetadata { + // (undocumented) + level: LogLevel; + // (undocumented) + message: string; + // (undocumented) + timestamp: number; +} + +// @public (undocumented) +class Logger extends Observable implements LoggerApi { + constructor(name: string, parent?: Logger | null); + // (undocumented) + asApi(): LoggerApi; + // (undocumented) + complete(): void; + // (undocumented) + createChild(name: string): Logger; + // (undocumented) + debug(message: string, metadata?: JsonObject): void; + // (undocumented) + error(message: string, metadata?: JsonObject): void; + // (undocumented) + fatal(message: string, metadata?: JsonObject): void; + // (undocumented) + forEach(next: (value: LogEntry) => void, PromiseCtor?: typeof Promise): Promise; + // (undocumented) + info(message: string, metadata?: JsonObject): void; + // (undocumented) + lift(operator: Operator): Observable; + // (undocumented) + log(level: LogLevel, message: string, metadata?: JsonObject): void; + // (undocumented) + protected _metadata: LoggerMetadata; + // (undocumented) + readonly name: string; + // (undocumented) + next(entry: LogEntry): void; + // (undocumented) + protected get _observable(): Observable; + protected set _observable(v: Observable); + // (undocumented) + readonly parent: Logger | null; + // (undocumented) + protected readonly _subject: Subject; + // (undocumented) + subscribe(): Subscription; + // (undocumented) + subscribe(observer: PartialObserver): Subscription; + // (undocumented) + subscribe(next?: (value: LogEntry) => void, error?: (error: Error) => void, complete?: () => void): Subscription; + // (undocumented) + toString(): string; + // (undocumented) + warn(message: string, metadata?: JsonObject): void; +} + +// @public (undocumented) +interface LoggerApi { + // (undocumented) + createChild(name: string): Logger; + // (undocumented) + debug(message: string, metadata?: JsonObject): void; + // (undocumented) + error(message: string, metadata?: JsonObject): void; + // (undocumented) + fatal(message: string, metadata?: JsonObject): void; + // (undocumented) + info(message: string, metadata?: JsonObject): void; + // (undocumented) + log(level: LogLevel, message: string, metadata?: JsonObject): void; + // (undocumented) + warn(message: string, metadata?: JsonObject): void; +} + +// @public (undocumented) +interface LoggerMetadata extends JsonObject { + // (undocumented) + name: string; + // (undocumented) + path: string[]; +} + +declare namespace logging { + export { + IndentLogger, + LevelTransformLogger, + LevelCapLogger, + LoggerMetadata, + LogEntry, + LoggerApi, + LogLevel, + Logger, + NullLogger, + TransformLogger + } +} +export { logging } + +// @public +class LoggingAnalytics implements Analytics { + constructor(_logger: Logger); + // (undocumented) + event(category: string, action: string, options?: EventOptions): void; + // (undocumented) + flush(): Promise; + // (undocumented) + protected _logger: Logger; + // (undocumented) + pageview(path: string, options?: PageviewOptions): void; + // (undocumented) + screenview(screenName: string, appName: string, options?: ScreenviewOptions): void; + // (undocumented) + timing(category: string, variable: string, time: string | number, options?: TimingOptions): void; +} + +// @public (undocumented) +type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal'; + +// @public @deprecated (undocumented) +export function mapObject(obj: { + [k: string]: T; +}, mapper: (k: string, v: T) => V): { + [k: string]: V; +}; + +// @public (undocumented) +export class MergeConflictException extends BaseException { + constructor(path: string); +} + +// @public +function mergeSchemas(...schemas: (JsonSchema | undefined)[]): JsonSchema; + +// @public +class MultiAnalytics implements Analytics { + constructor(_backends?: Analytics[]); + // (undocumented) + protected _backends: Analytics[]; + // (undocumented) + event(category: string, action: string, options?: EventOptions): void; + // (undocumented) + flush(): Promise; + // (undocumented) + pageview(path: string, options?: PageviewOptions): void; + // (undocumented) + push(...backend: Analytics[]): void; + // (undocumented) + screenview(screenName: string, appName: string, options?: ScreenviewOptions): void; + // (undocumented) + timing(category: string, variable: string, time: string | number, options?: TimingOptions): void; +} + +// @public +enum NgCliAnalyticsDimensions { + // (undocumented) + BuildErrors = 20, + // (undocumented) + CpuCount = 1, + // (undocumented) + CpuSpeed = 2, + // (undocumented) + NgAddCollection = 6, + // (undocumented) + NgIvyEnabled = 8, + // (undocumented) + NodeVersion = 4, + // (undocumented) + RamInGigabytes = 3 +} + +// @public (undocumented) +const NgCliAnalyticsDimensionsFlagInfo: { + [name: string]: [string, string]; +}; + +// @public (undocumented) +enum NgCliAnalyticsMetrics { + // (undocumented) + AssetCount = 12, + // (undocumented) + AssetSize = 13, + // (undocumented) + BuildTime = 5, + // (undocumented) + CssSize = 15, + // (undocumented) + InitialChunkSize = 7, + // (undocumented) + LazyChunkCount = 10, + // (undocumented) + LazyChunkSize = 11, + // (undocumented) + NgComponentCount = 1, + // (undocumented) + NgOnInitCount = 6, + // (undocumented) + PolyfillSize = 14, + // (undocumented) + TotalChunkCount = 8, + // (undocumented) + TotalChunkSize = 9, + // (undocumented) + UNUSED_2 = 2, + // (undocumented) + UNUSED_3 = 3, + // (undocumented) + UNUSED_4 = 4 +} + +// @public (undocumented) +const NgCliAnalyticsMetricsFlagInfo: { + [name: string]: [string, string]; +}; + +// @public +export function noCacheNormalize(path: string): Path; + +// @public +class NoopAnalytics implements Analytics { + // (undocumented) + event(): void; + // (undocumented) + flush(): Promise; + // (undocumented) + pageview(): void; + // (undocumented) + screenview(): void; + // (undocumented) + timing(): void; +} + +// @public +export function normalize(path: string): Path; + +// @public +export const NormalizedRoot: Path; + +// @public +export const NormalizedSep: Path; + +// @public (undocumented) +class NullLogger extends Logger { + constructor(parent?: Logger | null); + // (undocumented) + asApi(): LoggerApi; +} + +// @public (undocumented) +function oneLine(strings: TemplateStringsArray, ...values: any[]): string; + +// @public (undocumented) +interface PageviewOptions extends CustomDimensionsAndMetricsOptions { + // (undocumented) + hostname?: string; + // (undocumented) + title?: string; +} + +// @public @deprecated +export function parseJson(input: string, mode?: JsonParseMode, options?: ParseJsonOptions): JsonValue; + +// @public @deprecated +export function parseJsonAst(input: string, mode?: JsonParseMode): JsonAstNode; + +// @public @deprecated +export interface ParseJsonOptions { + path?: string; +} + +// @public (undocumented) +function parseJsonPointer(pointer: JsonPointer): string[]; + +// @public (undocumented) +export class PartiallyOrderedSet implements Set { + // (undocumented) + [Symbol.iterator](): Generator; + // (undocumented) + get [Symbol.toStringTag](): 'Set'; + // (undocumented) + add(item: T, deps?: Set | T[]): this; + // (undocumented) + protected _checkCircularDependencies(item: T, deps: Set): void; + // (undocumented) + clear(): void; + // (undocumented) + delete(item: T): boolean; + entries(): IterableIterator<[T, T]>; + // (undocumented) + forEach(callbackfn: (value: T, value2: T, set: PartiallyOrderedSet) => void, thisArg?: any): void; + // (undocumented) + has(item: T): boolean; + keys(): IterableIterator; + // (undocumented) + get size(): number; + values(): IterableIterator; +} + +// @public +export type Path = string & { + __PRIVATE_DEVKIT_PATH: void; +}; + +// @public (undocumented) +export const path: TemplateTag; + +// @public (undocumented) +export class PathCannotBeFragmentException extends BaseException { + constructor(path: string); +} + +// @public +export type PathFragment = Path & { + __PRIVATE_DEVKIT_PATH_FRAGMENT: void; +}; + +// @public (undocumented) +export class PathIsDirectoryException extends BaseException { + constructor(path: string); +} + +// @public (undocumented) +export class PathIsFileException extends BaseException { + constructor(path: string); +} + +// @public (undocumented) +export class PathMustBeAbsoluteException extends BaseException { + constructor(path: string); +} + +// @public @deprecated +export class PathSpecificJsonException extends JsonException { + constructor(path: string, exception: JsonException); + // (undocumented) + exception: JsonException; + // (undocumented) + path: string; +} + +// @public (undocumented) +class PatternMatchingHost extends ResolverHost { + // (undocumented) + addPattern(pattern: string | string[], replacementFn: ReplacementFunction): void; + // (undocumented) + protected _patterns: Map; + // (undocumented) + protected _resolve(path: Path): Path; +} + +// @public +export interface Position { + // (undocumented) + readonly character: number; + // (undocumented) + readonly line: number; + // (undocumented) + readonly offset: number; +} + +// @public (undocumented) +export type PosixPath = string & { + __PRIVATE_DEVKIT_POSIX_PATH: void; +}; + +// @public +export class PriorityQueue { + constructor(_comparator: (x: T, y: T) => number); + // (undocumented) + clear(): void; + // (undocumented) + peek(): T | undefined; + // (undocumented) + pop(): T | undefined; + // (undocumented) + push(item: T): void; + // (undocumented) + get size(): number; + // (undocumented) + toArray(): Array; +} + +// @public (undocumented) +interface ProjectDefinition { + // (undocumented) + readonly extensions: Record; + // (undocumented) + prefix?: string; + // (undocumented) + root: string; + // (undocumented) + sourceRoot?: string; + // (undocumented) + readonly targets: TargetDefinitionCollection; +} + +// @public (undocumented) +class ProjectDefinitionCollection extends DefinitionCollection { + constructor(initial?: Record, listener?: DefinitionCollectionListener); + // (undocumented) + add(definition: { + name: string; + root: string; + sourceRoot?: string; + prefix?: string; + targets?: Record; + [key: string]: unknown; + }): ProjectDefinition; + // (undocumented) + set(name: string, value: ProjectDefinition): this; +} + +// @public (undocumented) +interface PromptDefinition { + // (undocumented) + default?: string | string[] | number | boolean | null; + // (undocumented) + id: string; + // (undocumented) + items?: Array; + // (undocumented) + message: string; + // (undocumented) + multiselect?: boolean; + // (undocumented) + propertyTypes: Set; + // (undocumented) + raw?: string | JsonObject; + // (undocumented) + type: string; + // (undocumented) + validator?: (value: JsonValue) => boolean | string | Promise; +} + +// @public (undocumented) +type PromptProvider = (definitions: Array) => SubscribableOrPromise<{ + [id: string]: JsonValue; +}>; + +// @public (undocumented) +interface ReadonlyHost { + // (undocumented) + readonly capabilities: HostCapabilities; + // (undocumented) + exists(path: Path): Observable; + // (undocumented) + isDirectory(path: Path): Observable; + // (undocumented) + isFile(path: Path): Observable; + // (undocumented) + list(path: Path): Observable; + // (undocumented) + read(path: Path): Observable; + // (undocumented) + stat(path: Path): Observable | null> | null; +} + +// @public +function readWorkspace(path: string, host: WorkspaceHost, format?: WorkspaceFormat): Promise<{ + workspace: WorkspaceDefinition; +}>; + +// @public (undocumented) +export type Readwrite = { + -readonly [P in keyof T]: T[P]; +}; + +// @public (undocumented) +interface ReferenceResolver { + // (undocumented) + (ref: string, context?: ContextT): { + context?: ContextT; + schema?: JsonObject; + }; +} + +// @public +interface RegisterJobOptions extends Partial { +} + +// @public (undocumented) +interface Registry { + get(name: JobName): Observable | null>; +} + +// @public +export function relative(from: Path, to: Path): Path; + +// @public (undocumented) +type ReplacementFunction = (path: Path) => Path; + +// @public +export function resetNormalizeCache(): void; + +// @public +export function resolve(p1: Path, p2: Path): Path; + +// @public +abstract class ResolverHost implements Host { + constructor(_delegate: Host); + // (undocumented) + get capabilities(): HostCapabilities; + // (undocumented) + protected _delegate: Host; + // (undocumented) + delete(path: Path): Observable; + // (undocumented) + exists(path: Path): Observable; + // (undocumented) + isDirectory(path: Path): Observable; + // (undocumented) + isFile(path: Path): Observable; + // (undocumented) + list(path: Path): Observable; + // (undocumented) + read(path: Path): Observable; + // (undocumented) + rename(from: Path, to: Path): Observable; + // (undocumented) + protected abstract _resolve(path: Path): Path; + // (undocumented) + stat(path: Path): Observable | null> | null; + // (undocumented) + watch(path: Path, options?: HostWatchOptions): Observable | null; + // (undocumented) + write(path: Path, content: FileBuffer): Observable; +} + +// @public +class SafeReadonlyHost implements ReadonlyHost { + constructor(_delegate: ReadonlyHost); + // (undocumented) + get capabilities(): HostCapabilities; + // (undocumented) + exists(path: Path): Observable; + // (undocumented) + isDirectory(path: Path): Observable; + // (undocumented) + isFile(path: Path): Observable; + // (undocumented) + list(path: Path): Observable; + // (undocumented) + read(path: Path): Observable; + // (undocumented) + stat(path: Path): Observable | null> | null; +} + +// @public +interface ScheduleJobOptions { + dependencies?: Job | Job[]; +} + +// @public +interface Scheduler { + getDescription(name: JobName): Observable; + has(name: JobName): Observable; + pause(): () => void; + schedule(name: JobName, argument: A, options?: ScheduleJobOptions): Job; +} + +declare namespace schema { + export { + transforms, + JsonPointer, + SchemaValidatorResult, + SchemaValidatorError, + SchemaValidatorOptions, + SchemaValidator, + SchemaFormatter, + SchemaFormat, + SmartDefaultProvider, + SchemaKeywordValidator, + PromptDefinition, + PromptProvider, + SchemaRegistry, + JsonSchemaVisitor, + JsonVisitor, + buildJsonPointer, + joinJsonPointer, + parseJsonPointer, + UriHandler, + SchemaValidationException, + CoreSchemaRegistry, + isJsonSchema, + mergeSchemas, + JsonSchema, + visitJson, + visitJsonSchema, + ReferenceResolver, + getTypesOfSchema + } +} +export { schema } + +// @public (undocumented) +interface SchemaFormat { + // (undocumented) + formatter: SchemaFormatter; + // (undocumented) + name: string; +} + +// @public (undocumented) +type SchemaFormatter = Format; + +// @public (undocumented) +interface SchemaKeywordValidator { + // (undocumented) + (data: JsonValue, schema: JsonValue, parent: JsonObject | JsonArray | undefined, parentProperty: string | number | undefined, pointer: JsonPointer, rootData: JsonValue): boolean | Observable; +} + +// @public (undocumented) +interface SchemaRegistry { + // (undocumented) + addFormat(format: SchemaFormat): void; + addPostTransform(visitor: JsonVisitor, deps?: JsonVisitor[]): void; + addPreTransform(visitor: JsonVisitor, deps?: JsonVisitor[]): void; + // (undocumented) + addSmartDefaultProvider(source: string, provider: SmartDefaultProvider): void; + // (undocumented) + compile(schema: Object): Observable; + // @deprecated (undocumented) + flatten(schema: JsonObject | string): Observable; + // (undocumented) + usePromptProvider(provider: PromptProvider): void; + // (undocumented) + useXDeprecatedProvider(onUsage: (message: string) => void): void; +} + +// @public (undocumented) +class SchemaValidationException extends BaseException { + constructor(errors?: SchemaValidatorError[], baseMessage?: string); + // (undocumented) + static createMessages(errors?: SchemaValidatorError[]): string[]; + // (undocumented) + readonly errors: SchemaValidatorError[]; +} + +// @public (undocumented) +interface SchemaValidator { + // (undocumented) + (data: JsonValue, options?: SchemaValidatorOptions): Observable; +} + +// @public (undocumented) +type SchemaValidatorError = Partial; + +// @public (undocumented) +interface SchemaValidatorOptions { + // (undocumented) + applyPostTransforms?: boolean; + // (undocumented) + applyPreTransforms?: boolean; + // (undocumented) + withPrompts?: boolean; +} + +// @public (undocumented) +interface SchemaValidatorResult { + // (undocumented) + data: JsonValue; + // (undocumented) + errors?: SchemaValidatorError[]; + // (undocumented) + success: boolean; +} + +// @public (undocumented) +class ScopedHost extends ResolverHost { + constructor(delegate: Host, _root?: Path); + // (undocumented) + protected _resolve(path: Path): Path; + // (undocumented) + protected _root: Path; +} + +// @public (undocumented) +interface ScreenviewOptions extends CustomDimensionsAndMetricsOptions { + // (undocumented) + appId?: string; + // (undocumented) + appInstallerId?: string; + // (undocumented) + appVersion?: string; +} + +// @public +interface SimpleJobHandlerContext extends JobHandlerContext { + // (undocumented) + createChannel: (name: string) => Observer; + // (undocumented) + input: Observable; +} + +// @public +type SimpleJobHandlerFn = (input: A, context: SimpleJobHandlerContext) => O | Promise | Observable; + +// @public +class SimpleJobRegistry implements Registry { + // (undocumented) + get(name: JobName): Observable | null>; + getJobNames(): JobName[]; + register(name: JobName, handler: JobHandler, options?: RegisterJobOptions): void; + register(handler: JobHandler, options?: RegisterJobOptions & { + name: string; + }): void; + // (undocumented) + protected _register(name: JobName, handler: JobHandler, options: RegisterJobOptions): void; +} + +// @public (undocumented) +class SimpleMemoryHost implements Host<{}> { + constructor(); + // (undocumented) + protected _cache: Map>; + // (undocumented) + get capabilities(): HostCapabilities; + // (undocumented) + delete(path: Path): Observable; + // (undocumented) + protected _delete(path: Path): void; + // (undocumented) + exists(path: Path): Observable; + // (undocumented) + protected _exists(path: Path): boolean; + // (undocumented) + isDirectory(path: Path): Observable; + // (undocumented) + protected _isDirectory(path: Path): boolean; + // (undocumented) + isFile(path: Path): Observable; + // (undocumented) + protected _isFile(path: Path): boolean; + // (undocumented) + list(path: Path): Observable; + // (undocumented) + protected _list(path: Path): PathFragment[]; + // (undocumented) + protected _newDirStats(): { + inspect(): string; + isFile(): boolean; + isDirectory(): boolean; + size: number; + atime: Date; + ctime: Date; + mtime: Date; + birthtime: Date; + content: null; + }; + // (undocumented) + protected _newFileStats(content: FileBuffer, oldStats?: Stats): { + inspect(): string; + isFile(): boolean; + isDirectory(): boolean; + size: number; + atime: Date; + ctime: Date; + mtime: Date; + birthtime: Date; + content: ArrayBuffer; + }; + // (undocumented) + read(path: Path): Observable; + // (undocumented) + protected _read(path: Path): FileBuffer; + // (undocumented) + rename(from: Path, to: Path): Observable; + // (undocumented) + protected _rename(from: Path, to: Path): void; + // (undocumented) + reset(): void; + // (undocumented) + stat(path: Path): Observable | null> | null; + // (undocumented) + protected _stat(path: Path): Stats | null; + // (undocumented) + protected _toAbsolute(path: Path): Path; + // (undocumented) + protected _updateWatchers(path: Path, type: HostWatchEventType): void; + // (undocumented) + watch(path: Path, options?: HostWatchOptions): Observable | null; + // (undocumented) + protected _watch(path: Path, options?: HostWatchOptions): Observable; + // (undocumented) + write(path: Path, content: FileBuffer): Observable; + protected _write(path: Path, content: FileBuffer): void; +} + +// @public (undocumented) +interface SimpleMemoryHostStats { + // (undocumented) + readonly content: FileBuffer | null; +} + +// @public +class SimpleScheduler implements Scheduler { + constructor(_jobRegistry: Registry, _schemaRegistry?: schema.SchemaRegistry); + getDescription(name: JobName): Observable; + has(name: JobName): Observable; + // (undocumented) + protected _jobRegistry: Registry; + pause(): () => void; + schedule(name: JobName, argument: A, options?: ScheduleJobOptions): Job; + // (undocumented) + protected _scheduleJob(name: JobName, argument: A, options: ScheduleJobOptions, waitable: Observable): Job; + // (undocumented) + protected _schemaRegistry: schema.SchemaRegistry; +} + +// @public (undocumented) +interface SmartDefaultProvider { + // (undocumented) + (schema: JsonObject): T | Observable; +} + +// @public +export function split(path: Path): PathFragment[]; + +// @public (undocumented) +type Stats = T & { + isFile(): boolean; + isDirectory(): boolean; + readonly size: number; + readonly atime: Date; + readonly mtime: Date; + readonly ctime: Date; + readonly birthtime: Date; +}; + +// @public (undocumented) +namespace strategy { + // (undocumented) + type JobStrategy = (handler: JobHandler, options?: Partial>) => JobHandler; + function memoize(replayMessages?: boolean): JobStrategy; + function reuse(replayMessages?: boolean): JobStrategy; + function serialize(): JobStrategy; +} + +declare namespace strings { + export { + decamelize, + dasherize, + camelize, + classify, + underscore, + capitalize, + levenshtein + } +} +export { strings } + +// @public (undocumented) +function stringToFileBuffer(str: string): FileBuffer; + +// @public (undocumented) +function stripIndent(strings: TemplateStringsArray, ...values: any[]): string; + +// @public (undocumented) +function stripIndents(strings: TemplateStringsArray, ...values: any[]): string; + +// @public +class SyncDelegateHost { + constructor(_delegate: Host); + // (undocumented) + get capabilities(): HostCapabilities; + // (undocumented) + get delegate(): Host; + // (undocumented) + protected _delegate: Host; + // (undocumented) + delete(path: Path): void; + // (undocumented) + protected _doSyncCall(observable: Observable): ResultT; + // (undocumented) + exists(path: Path): boolean; + // (undocumented) + isDirectory(path: Path): boolean; + // (undocumented) + isFile(path: Path): boolean; + // (undocumented) + list(path: Path): PathFragment[]; + // (undocumented) + read(path: Path): FileBuffer; + // (undocumented) + rename(from: Path, to: Path): void; + // (undocumented) + stat(path: Path): Stats | null; + // (undocumented) + watch(path: Path, options?: HostWatchOptions): Observable | null; + // (undocumented) + write(path: Path, content: FileBufferLike): void; +} + +// @public (undocumented) +interface SyncHostHandler { + // (undocumented) + delete(path: Path): void; + // (undocumented) + exists(path: Path): boolean; + // (undocumented) + isDirectory(path: Path): boolean; + // (undocumented) + isFile(path: Path): boolean; + // (undocumented) + list(path: Path): PathFragment[]; + // (undocumented) + read(path: Path): FileBuffer; + // (undocumented) + rename(from: Path, to: Path): void; + // (undocumented) + stat(path: Path): Stats | null; + // (undocumented) + write(path: Path, content: FileBufferLike): void; +} + +// @public (undocumented) +class SynchronousDelegateExpectedException extends BaseException { + constructor(); +} + +declare namespace tags { + export { + oneLine, + indentBy, + stripIndent, + stripIndents, + trimNewlines, + TemplateTag + } +} +export { tags } + +// @public (undocumented) +interface TargetDefinition { + // (undocumented) + builder: string; + // (undocumented) + configurations?: Record | undefined>; + // (undocumented) + defaultConfiguration?: string; + // (undocumented) + options?: Record; +} + +// @public (undocumented) +class TargetDefinitionCollection extends DefinitionCollection { + constructor(initial?: Record, listener?: DefinitionCollectionListener); + // (undocumented) + add(definition: { + name: string; + } & TargetDefinition): TargetDefinition; + // (undocumented) + set(name: string, value: TargetDefinition): this; +} + +// @public +export function template(content: string, options?: TemplateOptions): (input: T) => string; + +// @public +export interface TemplateAst { + // (undocumented) + children: TemplateAstNode[]; + // (undocumented) + content: string; + // (undocumented) + fileName: string; +} + +// @public +export interface TemplateAstBase { + // (undocumented) + end: Position_2; + // (undocumented) + start: Position_2; +} + +// @public +export interface TemplateAstComment extends TemplateAstBase { + // (undocumented) + kind: 'comment'; + // (undocumented) + text: string; +} + +// @public +export interface TemplateAstContent extends TemplateAstBase { + // (undocumented) + content: string; + // (undocumented) + kind: 'content'; +} + +// @public +export interface TemplateAstEscape extends TemplateAstBase { + // (undocumented) + expression: string; + // (undocumented) + kind: 'escape'; +} + +// @public +export interface TemplateAstEvaluate extends TemplateAstBase { + // (undocumented) + expression: string; + // (undocumented) + kind: 'evaluate'; +} + +// @public +export interface TemplateAstInterpolate extends TemplateAstBase { + // (undocumented) + expression: string; + // (undocumented) + kind: 'interpolate'; +} + +// @public (undocumented) +export type TemplateAstNode = TemplateAstContent | TemplateAstEvaluate | TemplateAstComment | TemplateAstEscape | TemplateAstInterpolate; + +// @public (undocumented) +export interface TemplateOptions { + // (undocumented) + fileName?: string; + // (undocumented) + module?: boolean | { + exports: {}; + }; + // (undocumented) + sourceMap?: boolean; + // (undocumented) + sourceRoot?: string; + // (undocumented) + sourceURL?: string; +} + +// @public +export function templateParser(sourceText: string, fileName: string): TemplateAst; + +// @public +interface TemplateTag { + // (undocumented) + (template: TemplateStringsArray, ...substitutions: any[]): R; +} + +// @public (undocumented) +namespace test { + // (undocumented) + class TestHost extends SimpleMemoryHost { + // (undocumented) + $exists(path: string): boolean; + // (undocumented) + $isDirectory(path: string): boolean; + // (undocumented) + $isFile(path: string): boolean; + // (undocumented) + $list(path: string): PathFragment[]; + // (undocumented) + $read(path: string): string; + // (undocumented) + $write(path: string, content: string): void; + constructor(map?: { + [path: string]: string; + }); + // (undocumented) + clearRecords(): void; + // (undocumented) + clone(): TestHost; + // (undocumented) + protected _delete(path: Path): void; + // (undocumented) + protected _exists(path: Path): boolean; + // (undocumented) + get files(): Path[]; + // (undocumented) + protected _isDirectory(path: Path): boolean; + // (undocumented) + protected _isFile(path: Path): boolean; + // (undocumented) + protected _list(path: Path): PathFragment[]; + // (undocumented) + protected _read(path: Path): ArrayBuffer; + // (undocumented) + get records(): TestLogRecord[]; + // (undocumented) + protected _records: TestLogRecord[]; + // (undocumented) + protected _rename(from: Path, to: Path): void; + // (undocumented) + protected _stat(path: Path): Stats | null; + // (undocumented) + get sync(): SyncDelegateHost<{}>; + // (undocumented) + protected _sync: SyncDelegateHost<{}> | null; + // (undocumented) + protected _watch(path: Path, options?: HostWatchOptions): Observable; + // (undocumented) + protected _write(path: Path, content: FileBuffer): void; + } + // (undocumented) + type TestLogRecord = { + kind: 'write' | 'read' | 'delete' | 'list' | 'exists' | 'isDirectory' | 'isFile' | 'stat' | 'watch'; + path: Path; + } | { + kind: 'rename'; + from: Path; + to: Path; + }; +} + +// @public (undocumented) +interface TimingOptions extends CustomDimensionsAndMetricsOptions { + // (undocumented) + label?: string; +} + +// @public (undocumented) +class TransformLogger extends Logger { + constructor(name: string, transform: (stream: Observable) => Observable, parent?: Logger | null); +} + +declare namespace transforms { + export { + addUndefinedDefaults + } +} + +// @public (undocumented) +function trimNewlines(strings: TemplateStringsArray, ...values: any[]): string; + +// @public +function underscore(str: string): string; + +// @public @deprecated +export class UnexpectedEndOfInputException extends JsonException { + constructor(_context: JsonParserContext); +} + +// @public (undocumented) +export class UnimplementedException extends BaseException { + constructor(); +} + +// @public (undocumented) +export class UnknownException extends BaseException { + constructor(message: string); +} + +// @public (undocumented) +export class UnsupportedPlatformException extends BaseException { + constructor(); +} + +// @public (undocumented) +type UriHandler = (uri: string) => Observable | Promise | null | undefined; + +declare namespace virtualFs { + export { + AliasHost, + stringToFileBuffer, + fileBufferToString, + fileBuffer, + createSyncHost, + SyncHostHandler, + Empty, + FileBuffer, + FileBufferLike, + HostWatchOptions, + HostWatchEventType, + Stats, + HostWatchEvent, + HostCapabilities, + ReadonlyHost, + Host, + SimpleMemoryHostStats, + SimpleMemoryHost, + ReplacementFunction, + PatternMatchingHost, + CordHostCreate, + CordHostOverwrite, + CordHostRename, + CordHostDelete, + CordHostRecord, + CordHost, + SafeReadonlyHost, + ScopedHost, + SynchronousDelegateExpectedException, + SyncDelegateHost, + ResolverHost, + test + } +} +export { virtualFs } + +// @public +function visitJson(json: JsonValue, visitor: JsonVisitor, schema?: JsonSchema, refResolver?: ReferenceResolver, context?: ContextT): Observable; + +// @public (undocumented) +function visitJsonSchema(schema: JsonSchema, visitor: JsonSchemaVisitor): void; + +// @public (undocumented) +export type WindowsPath = string & { + __PRIVATE_DEVKIT_WINDOWS_PATH: void; +}; + +// @public (undocumented) +interface WorkspaceDefinition { + // (undocumented) + readonly extensions: Record; + // (undocumented) + readonly projects: ProjectDefinitionCollection; +} + +// @public +enum WorkspaceFormat { + // (undocumented) + JSON = 0 +} + +// @public (undocumented) +interface WorkspaceHost { + // (undocumented) + isDirectory(path: string): Promise; + // (undocumented) + isFile(path: string): Promise; + // (undocumented) + readFile(path: string): Promise; + // (undocumented) + writeFile(path: string, data: string): Promise; +} + +declare namespace workspaces { + export { + WorkspaceHost, + createWorkspaceHost, + WorkspaceFormat, + readWorkspace, + writeWorkspace, + WorkspaceDefinition, + ProjectDefinition, + TargetDefinition, + DefinitionCollectionListener, + ProjectDefinitionCollection, + TargetDefinitionCollection + } +} +export { workspaces } + +// @public +function writeWorkspace(workspace: WorkspaceDefinition, host: WorkspaceHost, path?: string, format?: WorkspaceFormat): Promise; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/goldens/public-api/angular_devkit/schematics/src/index.md b/goldens/public-api/angular_devkit/schematics/src/index.md new file mode 100644 index 000000000000..a65d73a318b2 --- /dev/null +++ b/goldens/public-api/angular_devkit/schematics/src/index.md @@ -0,0 +1,1044 @@ +## API Report File for "@angular-devkit/schematics" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { analytics } from '@angular-devkit/core'; +import { BaseException } from '@angular-devkit/core'; +import { logging } from '@angular-devkit/core'; +import { Observable } from 'rxjs'; +import { Path } from '@angular-devkit/core'; +import { PathFragment } from '@angular-devkit/core'; +import { schema } from '@angular-devkit/core'; +import { Subject } from 'rxjs'; +import { Url } from 'url'; +import { virtualFs } from '@angular-devkit/core'; + +// @public (undocumented) +export type Action = CreateFileAction | OverwriteFileAction | RenameFileAction | DeleteFileAction; + +// @public (undocumented) +export interface ActionBase { + // (undocumented) + readonly id: number; + // (undocumented) + readonly parent: number; + // (undocumented) + readonly path: Path; +} + +// @public (undocumented) +export class ActionList implements Iterable { + // (undocumented) + [Symbol.iterator](): IterableIterator; + // (undocumented) + protected _action(action: Partial): void; + // (undocumented) + create(path: Path, content: Buffer): void; + // (undocumented) + delete(path: Path): void; + // (undocumented) + find(predicate: (value: Action) => boolean): Action | null; + // (undocumented) + forEach(fn: (value: Action, index: number, array: Action[]) => void, thisArg?: {}): void; + // (undocumented) + get(i: number): Action; + // (undocumented) + has(action: Action): boolean; + // (undocumented) + get length(): number; + // (undocumented) + optimize(): void; + // (undocumented) + overwrite(path: Path, content: Buffer): void; + // (undocumented) + push(action: Action): void; + // (undocumented) + rename(path: Path, to: Path): void; +} + +// @public +export function apply(source: Source, rules: Rule[]): Source; + +// @public (undocumented) +export function applyContentTemplate(options: T): FileOperator; + +// @public (undocumented) +export function applyPathTemplate(data: T, options?: PathTemplateOptions): FileOperator; + +// @public (undocumented) +export function applyTemplates(options: T): Rule; + +// @public (undocumented) +export function applyToSubtree(path: string, rules: Rule[]): Rule; + +// @public (undocumented) +export function asSource(rule: Rule): Source; + +// @public (undocumented) +export type AsyncFileOperator = (tree: FileEntry) => Observable; + +// @public +abstract class BaseWorkflow implements Workflow { + constructor(options: BaseWorkflowOptions); + // (undocumented) + get context(): Readonly; + // (undocumented) + protected _context: WorkflowExecutionContext[]; + // (undocumented) + protected _createSinks(): Sink[]; + // (undocumented) + protected _dryRun: boolean; + // (undocumented) + get engine(): Engine<{}, {}>; + // (undocumented) + protected _engine: Engine<{}, {}>; + // (undocumented) + get engineHost(): EngineHost<{}, {}>; + // (undocumented) + protected _engineHost: EngineHost<{}, {}>; + // (undocumented) + execute(options: Partial & RequiredWorkflowExecutionContext): Observable; + // (undocumented) + protected _force: boolean; + // (undocumented) + protected _host: virtualFs.Host; + // (undocumented) + get lifeCycle(): Observable; + // (undocumented) + protected _lifeCycle: Subject; + // (undocumented) + get registry(): schema.SchemaRegistry; + // (undocumented) + protected _registry: schema.CoreSchemaRegistry; + // (undocumented) + get reporter(): Observable; + // (undocumented) + protected _reporter: Subject; +} + +// @public (undocumented) +interface BaseWorkflowOptions { + // (undocumented) + dryRun?: boolean; + // (undocumented) + engineHost: EngineHost<{}, {}>; + // (undocumented) + force?: boolean; + // (undocumented) + host: virtualFs.Host; + // (undocumented) + registry?: schema.CoreSchemaRegistry; +} + +// @public (undocumented) +export function branchAndMerge(rule: Rule, strategy?: MergeStrategy): Rule; + +// @public (undocumented) +export function callRule(rule: Rule, input: Tree_2 | Observable, context: SchematicContext): Observable; + +// @public (undocumented) +export function callSource(source: Source, context: SchematicContext): Observable; + +// @public +export function chain(rules: Rule[]): Rule; + +// @public (undocumented) +export class CircularCollectionException extends BaseException { + constructor(name: string); +} + +// @public +export interface Collection { + // (undocumented) + readonly baseDescriptions?: Array>; + // (undocumented) + createSchematic(name: string, allowPrivate?: boolean): Schematic; + // (undocumented) + readonly description: CollectionDescription; + // (undocumented) + listSchematicNames(): string[]; +} + +// @public +export type CollectionDescription = CollectionMetadataT & { + readonly name: string; + readonly extends?: string[]; +}; + +// @public (undocumented) +export class CollectionImpl implements Collection { + constructor(_description: CollectionDescription, _engine: SchematicEngine, baseDescriptions?: CollectionDescription[] | undefined); + // (undocumented) + readonly baseDescriptions?: CollectionDescription[] | undefined; + // (undocumented) + createSchematic(name: string, allowPrivate?: boolean): Schematic; + // (undocumented) + get description(): CollectionDescription; + // (undocumented) + listSchematicNames(): string[]; + // (undocumented) + get name(): string; +} + +// @public (undocumented) +export function composeFileOperators(operators: FileOperator[]): FileOperator; + +// @public (undocumented) +export class ContentHasMutatedException extends BaseException { + constructor(path: string); +} + +// @public (undocumented) +export function contentTemplate(options: T): Rule; + +// @public (undocumented) +export interface CreateFileAction extends ActionBase { + // (undocumented) + readonly content: Buffer; + // (undocumented) + readonly kind: 'c'; +} + +// @public (undocumented) +export class DelegateTree implements Tree_2 { + constructor(_other: Tree_2); + // (undocumented) + get actions(): Action[]; + // (undocumented) + apply(action: Action, strategy?: MergeStrategy): void; + // (undocumented) + beginUpdate(path: string): UpdateRecorder; + // (undocumented) + branch(): Tree_2; + // (undocumented) + commitUpdate(record: UpdateRecorder): void; + // (undocumented) + create(path: string, content: Buffer | string): void; + // (undocumented) + delete(path: string): void; + // (undocumented) + exists(path: string): boolean; + // (undocumented) + get(path: string): FileEntry | null; + // (undocumented) + getDir(path: string): DirEntry; + // (undocumented) + merge(other: Tree_2, strategy?: MergeStrategy): void; + // (undocumented) + protected _other: Tree_2; + // (undocumented) + overwrite(path: string, content: Buffer | string): void; + // (undocumented) + read(path: string): Buffer | null; + // (undocumented) + rename(from: string, to: string): void; + // (undocumented) + get root(): DirEntry; + // (undocumented) + visit(visitor: FileVisitor): void; +} + +// @public (undocumented) +export interface DeleteFileAction extends ActionBase { + // (undocumented) + readonly kind: 'd'; +} + +// @public (undocumented) +export interface DirEntry { + // (undocumented) + dir(name: PathFragment): DirEntry; + // (undocumented) + file(name: PathFragment): FileEntry | null; + // (undocumented) + readonly parent: DirEntry | null; + // (undocumented) + readonly path: Path; + // (undocumented) + readonly subdirs: PathFragment[]; + // (undocumented) + readonly subfiles: PathFragment[]; + // (undocumented) + visit(visitor: FileVisitor): void; +} + +// @public (undocumented) +export interface DryRunCreateEvent { + // (undocumented) + content: Buffer; + // (undocumented) + kind: 'create'; + // (undocumented) + path: string; +} + +// @public (undocumented) +export interface DryRunDeleteEvent { + // (undocumented) + kind: 'delete'; + // (undocumented) + path: string; +} + +// @public (undocumented) +export interface DryRunErrorEvent { + // (undocumented) + description: 'alreadyExist' | 'doesNotExist'; + // (undocumented) + kind: 'error'; + // (undocumented) + path: string; +} + +// @public (undocumented) +export type DryRunEvent = DryRunErrorEvent | DryRunDeleteEvent | DryRunCreateEvent | DryRunUpdateEvent | DryRunRenameEvent; + +// @public (undocumented) +export interface DryRunRenameEvent { + // (undocumented) + kind: 'rename'; + // (undocumented) + path: string; + // (undocumented) + to: string; +} + +// @public (undocumented) +export class DryRunSink extends HostSink { + constructor(host: virtualFs.Host, force?: boolean); + // (undocumented) + _done(): Observable; + // (undocumented) + protected _fileAlreadyExistException(path: string): void; + // (undocumented) + protected _fileAlreadyExistExceptionSet: Set; + // (undocumented) + protected _fileDoesNotExistException(path: string): void; + // (undocumented) + protected _fileDoesNotExistExceptionSet: Set; + // (undocumented) + readonly reporter: Observable; + // (undocumented) + protected _subject: Subject; +} + +// @public (undocumented) +export interface DryRunUpdateEvent { + // (undocumented) + content: Buffer; + // (undocumented) + kind: 'update'; + // (undocumented) + path: string; +} + +// @public +export function empty(): Source; + +// @public (undocumented) +export class EmptyTree extends HostTree { + constructor(); +} + +// @public +export interface Engine { + // (undocumented) + createCollection(name: string, requester?: Collection): Collection; + // (undocumented) + createContext(schematic: Schematic, parent?: Partial>, executionOptions?: Partial): TypedSchematicContext; + // (undocumented) + createSchematic(name: string, collection: Collection): Schematic; + // (undocumented) + createSourceFromUrl(url: Url, context: TypedSchematicContext): Source; + // (undocumented) + readonly defaultMergeStrategy: MergeStrategy; + // (undocumented) + executePostTasks(): Observable; + // (undocumented) + transformOptions(schematic: Schematic, options: OptionT, context?: TypedSchematicContext): Observable; + // (undocumented) + readonly workflow: Workflow | null; +} + +// @public +export interface EngineHost { + // (undocumented) + createCollectionDescription(name: string, requester?: CollectionDescription): CollectionDescription; + // (undocumented) + createSchematicDescription(name: string, collection: CollectionDescription): SchematicDescription | null; + // (undocumented) + createSourceFromUrl(url: Url, context: TypedSchematicContext): Source | null; + // (undocumented) + createTaskExecutor(name: string): Observable; + // (undocumented) + readonly defaultMergeStrategy?: MergeStrategy; + // (undocumented) + getSchematicRuleFactory(schematic: SchematicDescription, collection: CollectionDescription): RuleFactory; + // (undocumented) + hasTaskExecutor(name: string): boolean; + // (undocumented) + listSchematicNames(collection: CollectionDescription): string[]; + // (undocumented) + transformContext(context: TypedSchematicContext): TypedSchematicContext | void; + // (undocumented) + transformOptions(schematic: SchematicDescription, options: OptionT, context?: TypedSchematicContext): Observable; +} + +// @public (undocumented) +export interface ExecutionOptions { + // (undocumented) + interactive: boolean; + // (undocumented) + scope: string; +} + +// @public +export function externalSchematic(collectionName: string, schematicName: string, options: OptionT, executionOptions?: Partial): Rule; + +// @public (undocumented) +export class FileAlreadyExistException extends BaseException { + constructor(path: string); +} + +// @public (undocumented) +export class FileDoesNotExistException extends BaseException { + constructor(path: string); +} + +// @public (undocumented) +export interface FileEntry { + // (undocumented) + readonly content: Buffer; + // (undocumented) + readonly path: Path; +} + +// @public +export type FileOperator = (entry: FileEntry) => FileEntry | null; + +// @public (undocumented) +export interface FilePredicate { + // (undocumented) + (path: Path, entry?: Readonly | null): T; +} + +// @public (undocumented) +export type FileVisitor = FilePredicate; + +// @public (undocumented) +export const FileVisitorCancelToken: symbol; + +// @public (undocumented) +export function filter(predicate: FilePredicate): Rule; + +// @public (undocumented) +export class FilterHostTree extends HostTree { + constructor(tree: HostTree, filter?: FilePredicate); +} + +// @public (undocumented) +export function forEach(operator: FileOperator): Rule; + +declare namespace formats { + export { + htmlSelectorFormat, + pathFormat, + standardFormats + } +} +export { formats } + +// @public (undocumented) +export class HostCreateTree extends HostTree { + constructor(host: virtualFs.ReadonlyHost); +} + +// @public (undocumented) +export class HostDirEntry implements DirEntry { + constructor(parent: DirEntry | null, path: Path, _host: virtualFs.SyncDelegateHost, _tree: Tree_2); + // (undocumented) + dir(name: PathFragment): DirEntry; + // (undocumented) + file(name: PathFragment): FileEntry | null; + // (undocumented) + protected _host: virtualFs.SyncDelegateHost; + // (undocumented) + readonly parent: DirEntry | null; + // (undocumented) + readonly path: Path; + // (undocumented) + get subdirs(): PathFragment[]; + // (undocumented) + get subfiles(): PathFragment[]; + // (undocumented) + protected _tree: Tree_2; + // (undocumented) + visit(visitor: FileVisitor): void; +} + +// @public (undocumented) +export class HostSink extends SimpleSinkBase { + constructor(_host: virtualFs.Host, _force?: boolean); + // (undocumented) + protected _createFile(path: Path, content: Buffer): Observable; + // (undocumented) + protected _deleteFile(path: Path): Observable; + // (undocumented) + _done(): Observable; + // (undocumented) + protected _filesToCreate: Map; + // (undocumented) + protected _filesToDelete: Set; + // (undocumented) + protected _filesToRename: Set<[Path, Path]>; + // (undocumented) + protected _filesToUpdate: Map; + // (undocumented) + protected _force: boolean; + // (undocumented) + protected _host: virtualFs.Host; + // (undocumented) + protected _overwriteFile(path: Path, content: Buffer): Observable; + // (undocumented) + protected _renameFile(from: Path, to: Path): Observable; + // (undocumented) + protected _validateCreateAction(action: CreateFileAction): Observable; + // (undocumented) + protected _validateFileExists(p: Path): Observable; +} + +// @public (undocumented) +export class HostTree implements Tree_2 { + constructor(_backend?: virtualFs.ReadonlyHost<{}>); + // (undocumented) + get actions(): Action[]; + // (undocumented) + apply(action: Action, strategy?: MergeStrategy): void; + // (undocumented) + protected _backend: virtualFs.ReadonlyHost<{}>; + // (undocumented) + beginUpdate(path: string): UpdateRecorder; + // (undocumented) + branch(): Tree_2; + // (undocumented) + commitUpdate(record: UpdateRecorder): void; + // (undocumented) + create(path: string, content: Buffer | string): void; + // (undocumented) + delete(path: string): void; + // (undocumented) + exists(path: string): boolean; + // (undocumented) + get(path: string): FileEntry | null; + // (undocumented) + getDir(path: string): DirEntry; + // (undocumented) + static isHostTree(tree: Tree_2): tree is HostTree; + // (undocumented) + merge(other: Tree_2, strategy?: MergeStrategy): void; + // (undocumented) + protected _normalizePath(path: string): Path; + // (undocumented) + overwrite(path: string, content: Buffer | string): void; + // (undocumented) + read(path: string): Buffer | null; + // (undocumented) + rename(from: string, to: string): void; + // (undocumented) + get root(): DirEntry; + // (undocumented) + visit(visitor: FileVisitor): void; + // (undocumented) + protected _willCreate(path: Path): boolean; + // (undocumented) + protected _willDelete(path: Path): boolean; + // (undocumented) + protected _willOverwrite(path: Path): boolean; + // (undocumented) + protected _willRename(path: Path): boolean; +} + +// @public (undocumented) +const htmlSelectorFormat: schema.SchemaFormat; + +// @public (undocumented) +export class InvalidPipeException extends BaseException { + constructor(name: string); +} + +// @public +export class InvalidRuleResultException extends BaseException { + constructor(value?: {}); +} + +// @public (undocumented) +export class InvalidSchematicsNameException extends BaseException { + constructor(name: string); +} + +// @public (undocumented) +export class InvalidSourceResultException extends BaseException { + constructor(value?: {}); +} + +// @public (undocumented) +export class InvalidUpdateRecordException extends BaseException { + constructor(); +} + +// @public @deprecated (undocumented) +export function isAction(action: any): action is Action; + +// @public (undocumented) +export function isContentAction(action: Action): action is CreateFileAction | OverwriteFileAction; + +// @public (undocumented) +interface LifeCycleEvent { + // (undocumented) + kind: 'start' | 'end' | 'workflow-start' | 'workflow-end' | 'post-tasks-start' | 'post-tasks-end'; +} + +// @public (undocumented) +export class MergeConflictException extends BaseException { + constructor(path: string); +} + +// @public (undocumented) +export enum MergeStrategy { + // (undocumented) + AllowCreationConflict = 4, + // (undocumented) + AllowDeleteConflict = 8, + // (undocumented) + AllowOverwriteConflict = 2, + // (undocumented) + ContentOnly = 2, + // (undocumented) + Default = 0, + // (undocumented) + Error = 1, + // (undocumented) + Overwrite = 14 +} + +// @public +export function mergeWith(source: Source, strategy?: MergeStrategy): Rule; + +// @public (undocumented) +export function move(from: string, to?: string): Rule; + +// @public (undocumented) +export function noop(): Rule; + +// @public (undocumented) +export class OptionIsNotDefinedException extends BaseException { + constructor(name: string); +} + +// @public (undocumented) +export interface OverwriteFileAction extends ActionBase { + // (undocumented) + readonly content: Buffer; + // (undocumented) + readonly kind: 'o'; +} + +// @public (undocumented) +export function partitionApplyMerge(predicate: FilePredicate, ruleYes: Rule, ruleNo?: Rule): Rule; + +// @public (undocumented) +const pathFormat: schema.SchemaFormat; + +// @public (undocumented) +export function pathTemplate(options: T): Rule; + +// @public (undocumented) +export type PathTemplateData = { + [key: string]: PathTemplateValue | PathTemplateData | PathTemplatePipeFunction; +}; + +// @public (undocumented) +export interface PathTemplateOptions { + // (undocumented) + interpolationEnd: string; + // (undocumented) + interpolationStart: string; + // (undocumented) + pipeSeparator?: string; +} + +// @public (undocumented) +export type PathTemplatePipeFunction = (x: string) => PathTemplateValue; + +// @public (undocumented) +export type PathTemplateValue = boolean | string | number | undefined; + +// @public (undocumented) +export class PrivateSchematicException extends BaseException { + constructor(name: string, collection: CollectionDescription<{}>); +} + +// @public (undocumented) +export interface RandomOptions { + // (undocumented) + multi?: boolean | number; + // (undocumented) + multiFiles?: boolean | number; + // (undocumented) + root?: string; +} + +// @public (undocumented) +export interface RenameFileAction extends ActionBase { + // (undocumented) + readonly kind: 'r'; + // (undocumented) + readonly to: Path; +} + +// @public +export function renameTemplateFiles(): Rule; + +// @public (undocumented) +interface RequiredWorkflowExecutionContext { + // (undocumented) + collection: string; + // (undocumented) + options: object; + // (undocumented) + schematic: string; +} + +// @public (undocumented) +export type Rule = (tree: Tree_2, context: SchematicContext) => Tree_2 | Observable | Rule | Promise | void; + +// @public +export type RuleFactory = (options: T) => Rule; + +// @public +export interface Schematic { + // (undocumented) + call(options: OptionT, host: Observable, parentContext?: Partial>, executionOptions?: Partial): Observable; + // (undocumented) + readonly collection: Collection; + // (undocumented) + readonly description: SchematicDescription; +} + +// @public +export function schematic(schematicName: string, options: OptionT, executionOptions?: Partial): Rule; + +// @public +export type SchematicContext = TypedSchematicContext<{}, {}>; + +// @public +export type SchematicDescription = SchematicMetadataT & { + readonly collection: CollectionDescription; + readonly name: string; + readonly private?: boolean; + readonly hidden?: boolean; +}; + +// @public (undocumented) +export class SchematicEngine implements Engine { + constructor(_host: EngineHost, _workflow?: Workflow | undefined); + // (undocumented) + createCollection(name: string, requester?: Collection): Collection; + // (undocumented) + createContext(schematic: Schematic, parent?: Partial>, executionOptions?: Partial): TypedSchematicContext; + // (undocumented) + createSchematic(name: string, collection: Collection, allowPrivate?: boolean): Schematic; + // (undocumented) + createSourceFromUrl(url: Url, context: TypedSchematicContext): Source; + // (undocumented) + get defaultMergeStrategy(): MergeStrategy; + // (undocumented) + executePostTasks(): Observable; + // (undocumented) + listSchematicNames(collection: Collection): string[]; + // (undocumented) + transformOptions(schematic: Schematic, options: OptionT, context?: TypedSchematicContext): Observable; + // (undocumented) + get workflow(): Workflow | null; + // (undocumented) + protected _workflow?: Workflow | undefined; +} + +// @public (undocumented) +export class SchematicEngineConflictingException extends BaseException { + constructor(); +} + +// @public (undocumented) +export class SchematicImpl implements Schematic { + constructor(_description: SchematicDescription, _factory: RuleFactory<{}>, _collection: Collection, _engine: Engine); + // (undocumented) + call(options: OptionT, host: Observable, parentContext?: Partial>, executionOptions?: Partial): Observable; + // (undocumented) + get collection(): Collection; + // (undocumented) + get description(): SchematicDescription; +} + +// @public (undocumented) +export class SchematicsException extends BaseException { +} + +// @public (undocumented) +export abstract class SimpleSinkBase implements Sink { + // (undocumented) + commit(tree: Tree_2): Observable; + // (undocumented) + commitSingleAction(action: Action): Observable; + // (undocumented) + protected abstract _createFile(path: string, content: Buffer): Observable; + // (undocumented) + protected abstract _deleteFile(path: string): Observable; + // (undocumented) + protected abstract _done(): Observable; + // (undocumented) + protected _fileAlreadyExistException(path: string): void; + // (undocumented) + protected _fileDoesNotExistException(path: string): void; + // (undocumented) + protected abstract _overwriteFile(path: string, content: Buffer): Observable; + // (undocumented) + postCommit: () => void | Observable; + // (undocumented) + postCommitAction: (action: Action) => void | Observable; + // (undocumented) + preCommit: () => void | Observable; + // (undocumented) + preCommitAction: (action: Action) => void | Action | PromiseLike | Observable; + // (undocumented) + protected abstract _renameFile(path: string, to: string): Observable; + // (undocumented) + protected _validateCreateAction(action: CreateFileAction): Observable; + // (undocumented) + protected _validateDeleteAction(action: DeleteFileAction): Observable; + // (undocumented) + protected abstract _validateFileExists(p: string): Observable; + // (undocumented) + protected _validateOverwriteAction(action: OverwriteFileAction): Observable; + // (undocumented) + protected _validateRenameAction(action: RenameFileAction): Observable; + // (undocumented) + validateSingleAction(action: Action): Observable; +} + +// @public (undocumented) +export interface Sink { + // (undocumented) + commit(tree: Tree_2): Observable; +} + +// @public +export type Source = (context: SchematicContext) => Tree_2 | Observable; + +// @public +export function source(tree: Tree_2): Source; + +// @public (undocumented) +const standardFormats: schema.SchemaFormat[]; + +// @public (undocumented) +export interface TaskConfiguration { + // (undocumented) + dependencies?: Array; + // (undocumented) + name: string; + // (undocumented) + options?: T; +} + +// @public (undocumented) +export interface TaskConfigurationGenerator { + // (undocumented) + toConfiguration(): TaskConfiguration; +} + +// @public (undocumented) +export type TaskExecutor = (options: T | undefined, context: SchematicContext) => Promise | Observable; + +// @public (undocumented) +export interface TaskExecutorFactory { + // (undocumented) + create(options?: T): Promise | Observable; + // (undocumented) + readonly name: string; +} + +// @public (undocumented) +export interface TaskId { + // (undocumented) + readonly id: number; +} + +// @public (undocumented) +export interface TaskInfo { + // (undocumented) + readonly configuration: TaskConfiguration; + // (undocumented) + readonly context: SchematicContext; + // (undocumented) + readonly id: number; + // (undocumented) + readonly priority: number; +} + +// @public (undocumented) +export class TaskScheduler { + constructor(_context: SchematicContext); + // (undocumented) + finalize(): ReadonlyArray; + // (undocumented) + schedule(taskConfiguration: TaskConfiguration): TaskId; +} + +// @public (undocumented) +export function template(options: T): Rule; + +// @public (undocumented) +export const TEMPLATE_FILENAME_RE: RegExp; + +// @public (undocumented) +export type Tree = Tree_2; + +// @public (undocumented) +export const Tree: TreeConstructor; + +// @public (undocumented) +export interface TreeConstructor { + // (undocumented) + branch(tree: Tree_2): Tree_2; + // (undocumented) + empty(): Tree_2; + // (undocumented) + merge(tree: Tree_2, other: Tree_2, strategy?: MergeStrategy): Tree_2; + // (undocumented) + optimize(tree: Tree_2): Tree_2; + // (undocumented) + partition(tree: Tree_2, predicate: FilePredicate): [Tree_2, Tree_2]; +} + +// @public (undocumented) +export const TreeSymbol: symbol; + +// @public +export interface TypedSchematicContext { + // (undocumented) + addTask(task: TaskConfigurationGenerator, dependencies?: Array): TaskId; + // @deprecated (undocumented) + readonly analytics?: analytics.Analytics; + // (undocumented) + readonly debug: boolean; + // (undocumented) + readonly engine: Engine; + // (undocumented) + readonly interactive: boolean; + // (undocumented) + readonly logger: logging.LoggerApi; + // (undocumented) + readonly schematic: Schematic; + // (undocumented) + readonly strategy: MergeStrategy; +} + +// @public (undocumented) +export class UnimplementedException extends BaseException { + constructor(); +} + +// @public (undocumented) +export class UnknownActionException extends BaseException { + constructor(action: Action); +} + +// @public (undocumented) +export class UnknownCollectionException extends BaseException { + constructor(name: string); +} + +// @public (undocumented) +export class UnknownPipeException extends BaseException { + constructor(name: string); +} + +// @public (undocumented) +export class UnknownSchematicException extends BaseException { + constructor(name: string, collection: CollectionDescription<{}>); +} + +// @public (undocumented) +export class UnknownTaskDependencyException extends BaseException { + constructor(id: TaskId); +} + +// @public (undocumented) +export class UnknownUrlSourceProtocol extends BaseException { + constructor(url: string); +} + +// @public (undocumented) +export class UnregisteredTaskException extends BaseException { + constructor(name: string, schematic?: SchematicDescription<{}, {}>); +} + +// @public (undocumented) +export class UnsuccessfulWorkflowExecution extends BaseException { + constructor(); +} + +// @public (undocumented) +export interface UpdateRecorder { + // (undocumented) + insertLeft(index: number, content: Buffer | string): UpdateRecorder; + // (undocumented) + insertRight(index: number, content: Buffer | string): UpdateRecorder; + // (undocumented) + remove(index: number, length: number): UpdateRecorder; +} + +// @public (undocumented) +export function url(urlString: string): Source; + +// @public (undocumented) +export function when(predicate: FilePredicate, operator: FileOperator): FileOperator; + +// @public (undocumented) +interface Workflow { + // (undocumented) + readonly context: Readonly; + // (undocumented) + execute(options: Partial & RequiredWorkflowExecutionContext): Observable; +} + +declare namespace workflow { + export { + BaseWorkflowOptions, + BaseWorkflow, + RequiredWorkflowExecutionContext, + WorkflowExecutionContext, + LifeCycleEvent, + Workflow + } +} +export { workflow } + +// @public (undocumented) +interface WorkflowExecutionContext extends RequiredWorkflowExecutionContext { + // (undocumented) + allowPrivate?: boolean; + // (undocumented) + debug: boolean; + // (undocumented) + logger: logging.Logger; + // (undocumented) + parentContext?: Readonly; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/etc/api/angular_devkit/schematics/tasks/index.d.ts b/goldens/public-api/angular_devkit/schematics/tasks/index.md similarity index 51% rename from etc/api/angular_devkit/schematics/tasks/index.d.ts rename to goldens/public-api/angular_devkit/schematics/tasks/index.md index 1ce44e1880fd..4875a046ae74 100644 --- a/etc/api/angular_devkit/schematics/tasks/index.d.ts +++ b/goldens/public-api/angular_devkit/schematics/tasks/index.md @@ -1,43 +1,80 @@ -export declare class NodePackageInstallTask implements TaskConfigurationGenerator { +## API Report File for "@angular-devkit/schematics_tasks" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { JsonObject } from '@angular-devkit/core'; + +// @public (undocumented) +export class NodePackageInstallTask implements TaskConfigurationGenerator { + constructor(workingDirectory?: string); + constructor(options: NodePackageInstallTaskOptions); + // (undocumented) hideOutput: boolean; + // (undocumented) packageManager?: string; + // (undocumented) packageName?: string; + // (undocumented) quiet: boolean; - workingDirectory?: string; - constructor(options: NodePackageInstallTaskOptions); - constructor(workingDirectory?: string); + // (undocumented) toConfiguration(): TaskConfiguration; + // (undocumented) + workingDirectory?: string; } -export declare class NodePackageLinkTask implements TaskConfigurationGenerator { +// @public (undocumented) +export class NodePackageLinkTask implements TaskConfigurationGenerator { + constructor(packageName?: string | undefined, workingDirectory?: string | undefined); + // (undocumented) packageName?: string | undefined; + // (undocumented) quiet: boolean; - workingDirectory?: string | undefined; - constructor(packageName?: string | undefined, workingDirectory?: string | undefined); + // (undocumented) toConfiguration(): TaskConfiguration; + // (undocumented) + workingDirectory?: string | undefined; } -export declare class RepositoryInitializerTask implements TaskConfigurationGenerator { - commitOptions?: CommitOptions | undefined; - workingDirectory?: string | undefined; +// @public (undocumented) +export class RepositoryInitializerTask implements TaskConfigurationGenerator { constructor(workingDirectory?: string | undefined, commitOptions?: CommitOptions | undefined); + // (undocumented) + commitOptions?: CommitOptions | undefined; + // (undocumented) toConfiguration(): TaskConfiguration; + // (undocumented) + workingDirectory?: string | undefined; } -export declare class RunSchematicTask implements TaskConfigurationGenerator> { +// @public (undocumented) +export class RunSchematicTask implements TaskConfigurationGenerator> { + constructor(s: string, o: T); + constructor(c: string, s: string, o: T); + // (undocumented) protected _collection: string | null; + // (undocumented) protected _options: T; + // (undocumented) protected _schematic: string; - constructor(c: string, s: string, o: T); - constructor(s: string, o: T); + // (undocumented) toConfiguration(): TaskConfiguration>; } -export declare class TslintFixTask implements TaskConfigurationGenerator { - protected _configOrPath: null | string | JsonObject; - protected _options: TslintFixTaskOptionsBase; +// @public @deprecated (undocumented) +export class TslintFixTask implements TaskConfigurationGenerator { constructor(config: JsonObject, options: TslintFixTaskOptionsBase); constructor(options: TslintFixTaskOptionsBase); constructor(path: string, options: TslintFixTaskOptionsBase); + // (undocumented) + protected _configOrPath: null | string | JsonObject; + // (undocumented) + protected _options: TslintFixTaskOptionsBase; + // (undocumented) toConfiguration(): TaskConfiguration; } + +// (No @packageDocumentation comment for this package) + +``` diff --git a/goldens/public-api/angular_devkit/schematics/testing/index.md b/goldens/public-api/angular_devkit/schematics/testing/index.md new file mode 100644 index 000000000000..48a4f5a7bb4f --- /dev/null +++ b/goldens/public-api/angular_devkit/schematics/testing/index.md @@ -0,0 +1,43 @@ +## API Report File for "@angular-devkit/schematics_testing" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { analytics } from '@angular-devkit/core'; +import { logging } from '@angular-devkit/core'; +import { Observable } from 'rxjs'; +import { Path } from '@angular-devkit/core'; +import { PathFragment } from '@angular-devkit/core'; +import { Url } from 'url'; + +// @public (undocumented) +export class SchematicTestRunner { + constructor(_collectionName: string, collectionPath: string); + // (undocumented) + callRule(rule: Rule, tree: Tree_2, parentContext?: Partial): Observable; + // (undocumented) + get engine(): SchematicEngine<{}, {}>; + // (undocumented) + get logger(): logging.Logger; + // (undocumented) + registerCollection(collectionName: string, collectionPath: string): void; + // (undocumented) + runExternalSchematicAsync(collectionName: string, schematicName: string, opts?: SchematicSchemaT, tree?: Tree_2): Observable; + // (undocumented) + runSchematicAsync(schematicName: string, opts?: SchematicSchemaT, tree?: Tree_2): Observable; + // (undocumented) + get tasks(): TaskConfiguration[]; +} + +// @public (undocumented) +export class UnitTestTree extends DelegateTree { + // (undocumented) + get files(): string[]; + // (undocumented) + readContent(path: string): string; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/etc/api/angular_devkit/schematics/tools/index.d.ts b/goldens/public-api/angular_devkit/schematics/tools/index.md similarity index 50% rename from etc/api/angular_devkit/schematics/tools/index.d.ts rename to goldens/public-api/angular_devkit/schematics/tools/index.md index 3573352ab41e..325fb9680214 100644 --- a/etc/api/angular_devkit/schematics/tools/index.d.ts +++ b/goldens/public-api/angular_devkit/schematics/tools/index.md @@ -1,165 +1,282 @@ -export declare class CollectionCannotBeResolvedException extends BaseException { +## API Report File for "@angular-devkit/schematics_tools" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +/// + +import { analytics } from '@angular-devkit/core'; +import { BaseException } from '@angular-devkit/core'; +import { InvalidJsonCharacterException } from '@angular-devkit/core'; +import { JsonObject } from '@angular-devkit/core'; +import { logging } from '@angular-devkit/core'; +import { Observable } from 'rxjs'; +import { Path } from '@angular-devkit/core'; +import { PathFragment } from '@angular-devkit/core'; +import { schema } from '@angular-devkit/core'; +import { UnexpectedEndOfInputException } from '@angular-devkit/core'; +import { Url } from 'url'; +import { virtualFs } from '@angular-devkit/core'; +import { workflow } from '@angular-devkit/schematics'; + +// @public (undocumented) +export class CollectionCannotBeResolvedException extends BaseException { constructor(name: string); } -export declare class CollectionMissingFieldsException extends BaseException { +// @public (undocumented) +export class CollectionMissingFieldsException extends BaseException { constructor(name: string); } -export declare class CollectionMissingSchematicsMapException extends BaseException { +// @public (undocumented) +export class CollectionMissingSchematicsMapException extends BaseException { constructor(name: string); } -export declare type ContextTransform = (context: FileSystemSchematicContext) => FileSystemSchematicContext; +// @public (undocumented) +export type ContextTransform = (context: FileSystemSchematicContext) => FileSystemSchematicContext; -export declare class ExportStringRef { +// @public +export class ExportStringRef { + constructor(ref: string, parentPath?: string, inner?: boolean); + // (undocumented) get module(): string; + // (undocumented) get path(): string; + // (undocumented) get ref(): T | undefined; - constructor(ref: string, parentPath?: string, inner?: boolean); } -export declare class FactoryCannotBeResolvedException extends BaseException { +// @public (undocumented) +export class FactoryCannotBeResolvedException extends BaseException { constructor(name: string); } -export declare type FileSystemCollection = Collection; +// @public (undocumented) +export type FileSystemCollection = Collection; -export declare type FileSystemCollectionDesc = CollectionDescription; +// @public (undocumented) +export type FileSystemCollectionDesc = CollectionDescription; +// @public (undocumented) export interface FileSystemCollectionDescription { + // (undocumented) readonly name: string; + // (undocumented) readonly path: string; + // (undocumented) readonly schematics: { [name: string]: FileSystemSchematicDesc; }; + // (undocumented) readonly version?: string; } -export declare type FileSystemEngine = Engine; +// @public +export type FileSystemEngine = Engine; -export declare class FileSystemEngineHost extends FileSystemEngineHostBase { - protected _root: string; +// @public +export class FileSystemEngineHost extends FileSystemEngineHostBase { constructor(_root: string); + // (undocumented) + createTaskExecutor(name: string): Observable; + // (undocumented) + hasTaskExecutor(name: string): boolean; + // (undocumented) protected _resolveCollectionPath(name: string): string; + // (undocumented) protected _resolveReferenceString(refString: string, parentPath: string): { ref: RuleFactory<{}>; path: string; } | null; + // (undocumented) + protected _root: string; + // (undocumented) protected _transformCollectionDescription(name: string, desc: Partial): FileSystemCollectionDesc; + // (undocumented) protected _transformSchematicDescription(name: string, _collection: FileSystemCollectionDesc, desc: Partial): FileSystemSchematicDesc; - createTaskExecutor(name: string): Observable; - hasTaskExecutor(name: string): boolean; } -export declare abstract class FileSystemEngineHostBase implements FileSystemEngineHost { - protected abstract _resolveCollectionPath(name: string, requester?: string): string; - protected abstract _resolveReferenceString(name: string, parentPath: string): { - ref: RuleFactory<{}>; - path: string; - } | null; - protected abstract _transformCollectionDescription(name: string, desc: Partial): FileSystemCollectionDesc; - protected abstract _transformSchematicDescription(name: string, collection: FileSystemCollectionDesc, desc: Partial): FileSystemSchematicDesc; +// @public +export abstract class FileSystemEngineHostBase implements FileSystemEngineHost_2 { + // (undocumented) createCollectionDescription(name: string, requester?: FileSystemCollectionDesc): FileSystemCollectionDesc; + // (undocumented) createSchematicDescription(name: string, collection: FileSystemCollectionDesc): FileSystemSchematicDesc | null; + // (undocumented) createSourceFromUrl(url: Url): Source | null; + // (undocumented) createTaskExecutor(name: string): Observable; + // (undocumented) getSchematicRuleFactory(schematic: FileSystemSchematicDesc, _collection: FileSystemCollectionDesc): RuleFactory; + // (undocumented) hasTaskExecutor(name: string): boolean; + // (undocumented) listSchematicNames(collection: FileSystemCollectionDesc): string[]; + // (undocumented) registerContextTransform(t: ContextTransform): void; + // (undocumented) registerOptionsTransform(t: OptionTransform): void; + // (undocumented) registerTaskExecutor(factory: TaskExecutorFactory, options?: T): void; + // (undocumented) + protected abstract _resolveCollectionPath(name: string, requester?: string): string; + // (undocumented) + protected abstract _resolveReferenceString(name: string, parentPath: string): { + ref: RuleFactory<{}>; + path: string; + } | null; + // (undocumented) + protected abstract _transformCollectionDescription(name: string, desc: Partial): FileSystemCollectionDesc; + // (undocumented) transformContext(context: FileSystemSchematicContext): FileSystemSchematicContext; + // (undocumented) transformOptions(schematic: FileSystemSchematicDesc, options: OptionT, context?: FileSystemSchematicContext): Observable; + // (undocumented) + protected abstract _transformSchematicDescription(name: string, collection: FileSystemCollectionDesc, desc: Partial): FileSystemSchematicDesc; } -export declare type FileSystemSchematic = Schematic; +// @public (undocumented) +export type FileSystemSchematic = Schematic; -export declare type FileSystemSchematicContext = TypedSchematicContext; +// @public (undocumented) +export type FileSystemSchematicContext = TypedSchematicContext; -export declare type FileSystemSchematicDesc = SchematicDescription; +// @public (undocumented) +export type FileSystemSchematicDesc = SchematicDescription; +// @public (undocumented) export interface FileSystemSchematicDescription extends FileSystemSchematicJsonDescription { + // (undocumented) readonly factoryFn: RuleFactory<{}>; + // (undocumented) readonly path: string; + // (undocumented) readonly schemaJson?: JsonObject; } +// @public (undocumented) export interface FileSystemSchematicJsonDescription { + // (undocumented) readonly aliases?: string[]; + // (undocumented) readonly collection: FileSystemCollectionDescription; + // (undocumented) readonly description: string; + // (undocumented) readonly extends?: string; + // (undocumented) readonly factory: string; + // (undocumented) readonly name: string; + // (undocumented) readonly schema?: string; } -export declare class InvalidCollectionJsonException extends BaseException { +// @public (undocumented) +export class InvalidCollectionJsonException extends BaseException { constructor(_name: string, path: string, jsonException?: UnexpectedEndOfInputException | InvalidJsonCharacterException); } -export declare class NodeModulesEngineHost extends FileSystemEngineHostBase { +// @public +export class NodeModulesEngineHost extends FileSystemEngineHostBase { constructor(paths?: string[] | undefined); + // (undocumented) protected _resolveCollectionPath(name: string, requester?: string): string; + // (undocumented) protected _resolveReferenceString(refString: string, parentPath: string): { ref: RuleFactory<{}>; path: string; } | null; + // (undocumented) protected _transformCollectionDescription(name: string, desc: Partial): FileSystemCollectionDesc; + // (undocumented) protected _transformSchematicDescription(name: string, _collection: FileSystemCollectionDesc, desc: Partial): FileSystemSchematicDesc; } -export declare class NodeModulesTestEngineHost extends NodeModulesEngineHost { - get tasks(): TaskConfiguration<{}>[]; - protected _resolveCollectionPath(name: string, requester?: string): string; +// @public +export class NodeModulesTestEngineHost extends NodeModulesEngineHost { + // (undocumented) clearTasks(): void; + // (undocumented) registerCollection(name: string, path: string): void; + // (undocumented) + protected _resolveCollectionPath(name: string, requester?: string): string; + // (undocumented) + get tasks(): TaskConfiguration<{}>[]; + // (undocumented) transformContext(context: FileSystemSchematicContext): FileSystemSchematicContext; } -export declare class NodePackageDoesNotSupportSchematics extends BaseException { +// @public (undocumented) +export class NodePackageDoesNotSupportSchematics extends BaseException { constructor(name: string); } -export declare class NodeWorkflow extends workflow.BaseWorkflow { - get engine(): FileSystemEngine; - get engineHost(): NodeModulesEngineHost; +// @public +export class NodeWorkflow extends workflow.BaseWorkflow { + constructor(root: string, options: NodeWorkflowOptions); constructor(host: virtualFs.Host, options: NodeWorkflowOptions & { root?: Path; }); - constructor(root: string, options: NodeWorkflowOptions); + // (undocumented) + get engine(): FileSystemEngine; + // (undocumented) + get engineHost(): NodeModulesEngineHost; } +// @public (undocumented) export interface NodeWorkflowOptions { + // (undocumented) dryRun?: boolean; + // (undocumented) engineHostCreator?: (options: NodeWorkflowOptions) => NodeModulesEngineHost; + // (undocumented) force?: boolean; + // (undocumented) optionTransforms?: OptionTransform[]; + // (undocumented) packageManager?: string; + // (undocumented) + packageManagerForce?: boolean; + // (undocumented) packageRegistry?: string; + // (undocumented) registry?: schema.CoreSchemaRegistry; + // (undocumented) resolvePaths?: string[]; + // (undocumented) schemaValidation?: boolean; } -export declare type OptionTransform = (schematic: FileSystemSchematicDescription, options: T, context?: FileSystemSchematicContext) => Observable | PromiseLike | R; +// @public (undocumented) +export type OptionTransform = (schematic: FileSystemSchematicDescription, options: T, context?: FileSystemSchematicContext) => Observable | PromiseLike | R; -export declare class SchematicMissingDescriptionException extends BaseException { +// @public (undocumented) +export class SchematicMissingDescriptionException extends BaseException { constructor(name: string); } -export declare class SchematicMissingFactoryException extends BaseException { +// @public (undocumented) +export class SchematicMissingFactoryException extends BaseException { constructor(name: string); } -export declare class SchematicMissingFieldsException extends BaseException { +// @public (undocumented) +export class SchematicMissingFieldsException extends BaseException { constructor(name: string); } -export declare class SchematicNameCollisionException extends BaseException { +// @public (undocumented) +export class SchematicNameCollisionException extends BaseException { constructor(name: string); } -export declare function validateOptionsWithSchema(registry: schema.SchemaRegistry): (schematic: FileSystemSchematicDescription, options: T, context?: FileSystemSchematicContext | undefined) => Observable; +// @public (undocumented) +export function validateOptionsWithSchema(registry: schema.SchemaRegistry): (schematic: FileSystemSchematicDescription, options: T, context?: FileSystemSchematicContext | undefined) => Observable; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/goldens/public-api/manage.js b/goldens/public-api/manage.js new file mode 100644 index 000000000000..66029f35e4a5 --- /dev/null +++ b/goldens/public-api/manage.js @@ -0,0 +1,54 @@ +const {exec} = require('shelljs'); +const minimist = require('minimist'); + +// Remove all command line flags from the arguments. +const argv = minimist(process.argv.slice(2)); +// The command the user would like to run, either 'accept' or 'test' +const USER_COMMAND = argv._[0]; +// The shell command to query for all Public API guard tests. +const BAZEL_PUBLIC_API_TARGET_QUERY_CMD = + `yarn -s bazel query --output label 'kind(nodejs_test, ...) intersect attr("tags", "api_guard", ...)'` +// Bazel targets for testing Public API goldens +process.stdout.write('Gathering all Public API targets'); +const ALL_PUBLIC_API_TESTS = exec(BAZEL_PUBLIC_API_TARGET_QUERY_CMD, {silent: true}) + .trim() + .split('\n') + .map(test => test.trim()); +process.stdout.clearLine(); +process.stdout.cursorTo(0); +// Bazel targets for generating Public API goldens +const ALL_PUBLIC_API_ACCEPTS = ALL_PUBLIC_API_TESTS.map(test => `${test}.accept`); + +/** + * Run the provided bazel commands on each provided target individually. + */ +function runBazelCommandOnTargets(command, targets, present) { + for (const target of targets) { + process.stdout.write(`${present}: ${target}`); + const commandResult = exec(`yarn -s bazel ${command} ${target}`, {silent: true}); + process.stdout.clearLine(); + process.stdout.cursorTo(0); + if (commandResult.code) { + console.error(`Failed ${command}: ${target}`); + console.group(); + console.error(commandResult.stdout || commandResult.stderr); + console.groupEnd(); + } else { + console.log(`Successful ${command}: ${target}`); + } + } +} + +switch (USER_COMMAND) { + case 'accept': + runBazelCommandOnTargets('run', ALL_PUBLIC_API_ACCEPTS, 'Running'); + break; + case 'test': + runBazelCommandOnTargets('test', ALL_PUBLIC_API_TESTS, 'Testing'); + break; + default: + console.warn('Invalid command provided.'); + console.warn(); + console.warn(`Run this script with either "accept" and "test"`); + break; +} \ No newline at end of file diff --git a/goldens/public-api/ngtools/webpack/src/index.md b/goldens/public-api/ngtools/webpack/src/index.md new file mode 100644 index 000000000000..81003ff2d8c9 --- /dev/null +++ b/goldens/public-api/ngtools/webpack/src/index.md @@ -0,0 +1,65 @@ +## API Report File for "@ngtools/webpack" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { Compiler } from 'webpack'; +import { CompilerOptions } from '@angular/compiler-cli'; +import type { LoaderContext } from 'webpack'; + +// @public (undocumented) +function angularWebpackLoader(this: LoaderContext, content: string, map: string): void; +export default angularWebpackLoader; + +// @public (undocumented) +export const AngularWebpackLoaderPath: string; + +// @public (undocumented) +export class AngularWebpackPlugin { + constructor(options?: Partial); + // (undocumented) + apply(compiler: Compiler): void; + // (undocumented) + get options(): AngularWebpackPluginOptions; +} + +// @public (undocumented) +export interface AngularWebpackPluginOptions { + // (undocumented) + compilerOptions?: CompilerOptions; + // (undocumented) + directTemplateLoading: boolean; + // (undocumented) + emitClassMetadata: boolean; + // (undocumented) + emitNgModuleScope: boolean; + // (undocumented) + fileReplacements: Record; + // (undocumented) + inlineStyleFileExtension?: string; + // @deprecated (undocumented) + inlineStyleMimeType?: string; + // (undocumented) + jitMode: boolean; + // (undocumented) + substitutions: Record; + // (undocumented) + tsconfig: string; +} + +// @public @deprecated (undocumented) +export namespace ivy { + const // (undocumented) + AngularWebpackLoaderPath: string; + const // (undocumented) + AngularWebpackPlugin: typeof ivyInternal.AngularWebpackPlugin; + // (undocumented) + export type AngularPluginOptions = ivyInternal.AngularWebpackPluginOptions; + // (undocumented) + export type AngularWebpackPlugin = ivyInternal.AngularWebpackPlugin; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/lib/bootstrap-local.js b/lib/bootstrap-local.js index e491aad25108..c6441e56f47d 100644 --- a/lib/bootstrap-local.js +++ b/lib/bootstrap-local.js @@ -1,10 +1,11 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + /* eslint-disable no-console */ 'use strict'; const debug = require('debug'); @@ -26,7 +27,7 @@ debugLocal('starting bootstrap local'); // This processes any extended configs const compilerOptions = ts.getParsedCommandLineOfConfigFile( path.join(__dirname, '../tsconfig-test.json'), - { }, + {}, ts.sys, ).options; @@ -37,8 +38,10 @@ if (process.env['DEVKIT_PROFILING']) { try { profiler = require('v8-profiler-node8'); } catch (err) { - throw new Error(`Could not require 'v8-profiler-node8'. You must install it separetely with` + - `'npm install v8-profiler-node8 --no-save.\n\nOriginal error:\n\n${err}`); + throw new Error( + `Could not require 'v8-profiler-node8'. You must install it separetely with` + + `'npm install v8-profiler-node8 --no-save.\n\nOriginal error:\n\n${err}`, + ); } profiler.startProfiling(); @@ -72,7 +75,6 @@ if (process.env['DEVKIT_LONG_STACK_TRACE']) { global._DevKitIsLocal = true; global._DevKitRoot = path.resolve(__dirname, '..'); - const oldRequireTs = require.extensions['.ts']; require.extensions['.ts'] = function (m, filename) { // If we're in node module, either call the old hook or simply compile the @@ -104,7 +106,6 @@ require.extensions['.ts'] = function (m, filename) { } }; - require.extensions['.ejs'] = function (m, filename) { debugBuildEjs(filename); @@ -120,7 +121,6 @@ const builtinModules = Object.keys(process.binding('natives')); const packages = require('./packages').packages; // If we're running locally, meaning npm linked. This is basically "developer mode". if (!__dirname.match(new RegExp(`\\${path.sep}node_modules\\${path.sep}`))) { - // We mock the module loader so that we can fake our packages when running locally. const Module = require('module'); const oldLoad = Module._load; @@ -143,7 +143,7 @@ if (!__dirname.match(new RegExp(`\\${path.sep}node_modules\\${path.sep}`))) { } else if (resolved && resolved.match(/[\\\/]node_modules[\\\/]/)) { return resolved; } else { - const match = Object.keys(packages).find(pkgName => request.startsWith(pkgName + '/')); + const match = Object.keys(packages).find((pkgName) => request.startsWith(pkgName + '/')); if (match) { const p = path.join(packages[match].root, request.substr(match.length)); return oldResolve.call(this, p, parent); @@ -168,7 +168,10 @@ if (!__dirname.match(new RegExp(`\\${path.sep}node_modules\\${path.sep}`))) { // This script has the be synchronous, so we spawnSync instead of, say, requiring the runner and calling // the method directly. - const tmpJsonSchemaPath = path.join(tmpRoot, maybeTsPath.replace(/[^0-9a-zA-Z.]/g, '_')); + const tmpJsonSchemaPath = path.join( + tmpRoot, + maybeTsPath.replace(/[^0-9a-zA-Z.]/g, '_'), + ); try { if (!fs.existsSync(tmpJsonSchemaPath)) { const quicktypeRunnerPath = path.join(__dirname, '../tools/quicktype_runner.js'); diff --git a/lib/packages.ts b/lib/packages.ts index 8b5d3ca91304..ece8839d7771 100644 --- a/lib/packages.ts +++ b/lib/packages.ts @@ -1,12 +1,11 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ -// tslint:disable-next-line: no-global-tslint-disable -// tslint:disable: no-implicit-dependencies + import { JsonObject } from '@angular-devkit/core'; import { execSync } from 'child_process'; import * as fs from 'fs'; @@ -16,11 +15,10 @@ import * as ts from 'typescript'; const distRoot = path.join(__dirname, '../dist'); const { packages: monorepoPackages } = require('../.monorepo.json'); - export interface PackageInfo { name: string; root: string; - bin: { [name: string]: string}; + bin: { [name: string]: string }; relative: string; main: string; dist: string; @@ -40,7 +38,6 @@ export interface PackageInfo { } export type PackageMap = { [name: string]: PackageInfo }; - export function loadRootPackageJson() { return require('../package.json'); } @@ -76,19 +73,20 @@ function loadPackageJson(p: string) { case 'keywords': const a = pkg[key] || []; const b = Object.keys( - root[key].concat(a).reduce((acc: {[k: string]: boolean}, curr: string) => { + root[key].concat(a).reduce((acc: { [k: string]: boolean }, curr: string) => { acc[curr] = true; return acc; - }, {})); + }, {}), + ); pkg[key] = b; break; // Overwrite engines to a common default. case 'engines': pkg['engines'] = { - 'node': '>= 12.13.0', - 'npm': '^6.11.0 || ^7.5.6', + 'node': '^12.14.1 || >=14.0.0', + 'npm': '^6.11.0 || ^7.5.6 || >=8.0.0', 'yarn': '>= 1.13.0', }; break; @@ -102,54 +100,62 @@ function loadPackageJson(p: string) { return pkg; } +function* _findPrimaryPackageJsonFiles(dir: string, exclude: RegExp): Iterable { + const subdirectories = []; + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const p = path.join(dir, entry.name); -function _findAllPackageJson(dir: string, exclude: RegExp): string[] { - const result: string[] = []; - fs.readdirSync(dir) - .forEach(fileName => { - const p = path.join(dir, fileName); - - if (exclude.test(p)) { - return; - } else if (/[\/\\]node_modules[\/\\]/.test(p)) { - return; - } else if (fileName == 'package.json') { - result.push(p); - } else if (fs.statSync(p).isDirectory() && fileName != 'node_modules') { - result.push(..._findAllPackageJson(p, exclude)); - } - }); + if (exclude.test(p)) { + continue; + } - return result; -} + if (entry.isDirectory() && entry.name !== 'node_modules') { + subdirectories.push(p); + continue; + } + + if (entry.name === 'package.json') { + yield p; + // First package.json found will be the package's root package.json + // Secondary entrypoint package.json files should not be found here + return; + } + } + + for (const directory of subdirectories) { + yield* _findPrimaryPackageJsonFiles(directory, exclude); + } +} const tsConfigPath = path.join(__dirname, '../tsconfig.json'); const tsConfig = ts.readConfigFile(tsConfigPath, ts.sys.readFile); -const pattern = '^(' - + (tsConfig.config.exclude as string[]) - .map(ex => path.join(path.dirname(tsConfigPath), ex)) - .map(ex => '(' - + ex - .replace(/[\-\[\]{}()+?./\\^$|]/g, '\\$&') - .replace(/(\\\\|\\\/)\*\*/g, '((\/|\\\\).+?)?') - .replace(/\*/g, '[^/\\\\]*') - + ')') - .join('|') - + ')($|/|\\\\)'; +const pattern = + '^(' + + (tsConfig.config.exclude as string[]) + .map((ex) => path.join(path.dirname(tsConfigPath), ex)) + .map( + (ex) => + '(' + + ex + .replace(/[\-\[\]{}()+?./\\^$|]/g, '\\$&') + .replace(/(\\\\|\\\/)\*\*/g, '((/|\\\\).+?)?') + .replace(/\*/g, '[^/\\\\]*') + + ')', + ) + .join('|') + + ')($|/|\\\\)'; const excludeRe = new RegExp(pattern); // Find all the package.json that aren't excluded from tsconfig. -const packageJsonPaths = _findAllPackageJson(path.join(__dirname, '..'), excludeRe) - // Remove the root package.json. - .filter(p => p != path.join(__dirname, '../package.json')); - +const packageJsonPaths = [ + ..._findPrimaryPackageJsonFiles(path.join(__dirname, '..', 'packages'), excludeRe), +]; function _exec(cmd: string) { return execSync(cmd).toString().trim(); } - let gitShaCache: string; function _getSnapshotHash(_pkg: PackageInfo): string { if (!gitShaCache) { @@ -159,7 +165,6 @@ function _getSnapshotHash(_pkg: PackageInfo): string { return gitShaCache; } - const stableVersion = loadRootPackageJson().version; const experimentalVersion = stableToExperimentalVersion(stableVersion); @@ -177,71 +182,73 @@ export function stableToExperimentalVersion(stable: string): string { // All the supported packages. Go through the packages directory and create a map of // name => PackageInfo. This map is partial as it lacks some information that requires the // map itself to finish building. -export const packages: PackageMap = - packageJsonPaths - .map(pkgPath => ({ root: path.dirname(pkgPath) })) - .reduce((packages: PackageMap, pkg) => { - const pkgRoot = pkg.root; - const packageJson = loadPackageJson(path.join(pkgRoot, 'package.json')); - const name = packageJson['name']; - if (!name) { - // Only build the entry if there's a package name. - return packages; - } - if (!(name in monorepoPackages)) { - throw new Error( - `Package ${name} found in ${JSON.stringify(pkg.root)}, not found in .monorepo.json.`, - ); - } - - const bin: {[name: string]: string} = {}; - Object.keys(packageJson['bin'] || {}).forEach(binName => { - let p = path.resolve(pkg.root, packageJson['bin'][binName]); - if (!fs.existsSync(p)) { - p = p.replace(/\.js$/, '.ts'); - } - bin[binName] = p; - }); - - const experimental = !!packageJson.private || !!packageJson.experimental; - - packages[name] = { - build: path.join(distRoot, pkgRoot.substr(path.dirname(__dirname).length)), - dist: path.join(distRoot, name), - root: pkgRoot, - relative: path.relative(path.dirname(__dirname), pkgRoot), - main: path.resolve(pkgRoot, 'src/index.ts'), - private: !!packageJson.private, - experimental, - // yarn doesn't take kindly to @ in tgz filenames - // https://github.com/yarnpkg/yarn/issues/6339 - tar: path.join(distRoot, name.replace(/\/|@/g, '_') + '.tgz'), - bin, - name, - packageJson, - - snapshot: !!monorepoPackages[name].snapshotRepo, - snapshotRepo: monorepoPackages[name].snapshotRepo, - get snapshotHash() { - return _getSnapshotHash(this); - }, - - dependencies: [], - reverseDependencies: [], - version: experimental ? experimentalVersion : stableVersion, - }; - +export const packages: PackageMap = packageJsonPaths + .map((pkgPath) => ({ root: path.dirname(pkgPath) })) + .reduce((packages: PackageMap, pkg) => { + const pkgRoot = pkg.root; + const packageJson = loadPackageJson(path.join(pkgRoot, 'package.json')); + const name = packageJson['name']; + if (!name) { + // Only build the entry if there's a package name. return packages; - }, {}); + } + if (!(name in monorepoPackages)) { + throw new Error( + `Package ${name} found in ${JSON.stringify(pkg.root)}, not found in .monorepo.json.`, + ); + } + const bin: { [name: string]: string } = {}; + Object.keys(packageJson['bin'] || {}).forEach((binName) => { + let p = path.resolve(pkg.root, packageJson['bin'][binName]); + if (!fs.existsSync(p)) { + p = p.replace(/\.js$/, '.ts'); + } + bin[binName] = p; + }); + + const experimental = !!packageJson.private || !!packageJson.experimental; + + packages[name] = { + build: path.join(distRoot, pkgRoot.substr(path.dirname(__dirname).length)), + dist: path.join(distRoot, name), + root: pkgRoot, + relative: path.relative(path.dirname(__dirname), pkgRoot), + main: path.resolve(pkgRoot, 'src/index.ts'), + private: !!packageJson.private, + experimental, + // yarn doesn't take kindly to @ in tgz filenames + // https://github.com/yarnpkg/yarn/issues/6339 + tar: path.join(distRoot, name.replace(/\/|@/g, '_') + '.tgz'), + bin, + name, + packageJson, + + snapshot: !!monorepoPackages[name].snapshotRepo, + snapshotRepo: monorepoPackages[name].snapshotRepo, + get snapshotHash() { + return _getSnapshotHash(this); + }, + + dependencies: [], + reverseDependencies: [], + version: experimental ? experimentalVersion : stableVersion, + }; + + return packages; + }, {}); // Update with dependencies. for (const pkgName of Object.keys(packages)) { const pkg = packages[pkgName]; const pkgJson = require(path.join(pkg.root, 'package.json')); - pkg.dependencies = Object.keys(packages).filter(name => { - return name in (pkgJson.dependencies || {}) - || name in (pkgJson.devDependencies || {}); + pkg.dependencies = Object.keys(packages).filter((name) => { + return name in (pkgJson.dependencies || {}) || name in (pkgJson.devDependencies || {}); }); - pkg.dependencies.forEach(depName => packages[depName].reverseDependencies.push(pkgName)); + pkg.dependencies.forEach((depName) => packages[depName].reverseDependencies.push(pkgName)); } + +/** The set of packages which are built and released. */ +export const releasePackages = Object.fromEntries( + Object.entries(packages).filter(([_, pkg]) => !pkg.private), +); diff --git a/lib/registries.ts b/lib/registries.ts index 0bfea087bc2e..2e21b8a4716d 100644 --- a/lib/registries.ts +++ b/lib/registries.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license diff --git a/package.json b/package.json index add85949007f..648764434235 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/devkit-repo", - "version": "12.0.0-rc.0", + "version": "12.2.18", "private": true, "description": "Software Development Kit for Angular", "bin": { @@ -20,30 +20,31 @@ ], "scripts": { "admin": "node ./bin/devkit-admin", - "bazel:format": "find . -type f \\( -name \"*.bzl\" -or -name WORKSPACE -or -name BUILD -or -name BUILD.bazel \\) ! -path \"*/node_modules/*\" | xargs buildifier -v --warnings=attr-cfg,attr-license,attr-non-empty,attr-output-default,attr-single-file,constant-glob,ctx-args,depset-iteration,depset-union,dict-concatenation,duplicated-name,filetype,git-repository,http-archive,integer-division,load,load-on-top,native-build,native-package,output-group,package-name,package-on-top,positional-args,redefined-variable,repository-name,same-origin-load,string-iteration,unused-variable", - "bazel:lint": "yarn bazel:format --lint=warn", - "bazel:lint-fix": "yarn bazel:format --lint=fix", - "bazel:test": "bazel test //packages/... //etc/... ", + "bazel:test": "bazel test //packages/...", "build": "node ./bin/devkit-admin build", "build-tsc": "tsc -p tsconfig.json", "debug:test": "node --inspect-brk ./bin/devkit-admin test", "debug:test-large": "node --inspect-brk ./bin/devkit-admin test --large --spec-reporter", - "lint": "tslint --project tsconfig.json", + "lint": "eslint --cache --max-warnings=0 \"**/*.ts\"", "templates": "node ./bin/devkit-admin templates", "validate": "node ./bin/devkit-admin validate", - "preinstall": "node ./tools/yarn/check-yarn.js", "postinstall": "yarn webdriver-update && yarn ngcc && yarn husky install", "//webdriver-update-README": "ChromeDriver version must match Puppeteer Chromium version, see https://github.com/GoogleChrome/puppeteer/releases http://chromedriver.chromium.org/downloads", - "webdriver-update": "webdriver-manager update --standalone false --gecko false --versions.chrome 89.0.4389.0", - "ngcc": "ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points" + "webdriver-update": "webdriver-manager update --standalone false --gecko false --versions.chrome 91.0.4472.19", + "ngcc": "ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points", + "public-api:check": "node goldens/public-api/manage.js test", + "public-api:update": "node goldens/public-api/manage.js accept", + "ts-circular-deps:check": "ng-dev ts-circular-deps check --config ./packages/circular-deps-test.conf.js", + "ts-circular-deps:approve": "ng-dev ts-circular-deps approve --config ./packages/circular-deps-test.conf.js" }, "repository": { "type": "git", "url": "https://github.com/angular/angular-cli.git" }, "engines": { - "node": ">=12.13.0 <15.0.0", - "yarn": ">=1.22.4" + "node": "^12.14.1 || ^14.0.0", + "yarn": ">=1.21.1 <2", + "npm": "Please use yarn instead of NPM to install dependencies" }, "author": "Angular Authors", "license": "MIT", @@ -62,50 +63,56 @@ "@angular/compiler-cli" ] }, + "resolutions": { + "**/@types/copy-webpack-plugin/webpack": "5.50.0", + "ajv-formats/ajv": "8.6.2" + }, "devDependencies": { - "@angular/animations": "12.0.0-next.8", - "@angular/cdk": "11.2.9", - "@angular/common": "12.0.0-next.8", - "@angular/compiler": "12.0.0-next.8", - "@angular/compiler-cli": "12.0.0-next.8", - "@angular/core": "12.0.0-next.8", - "@angular/dev-infra-private": "https://github.com/angular/dev-infra-private-builds.git#0d8382f30f70ab220961c2d731c782519025332e", - "@angular/forms": "12.0.0-next.8", - "@angular/localize": "12.0.0-next.8", - "@angular/material": "11.2.9", - "@angular/platform-browser": "12.0.0-next.8", - "@angular/platform-browser-dynamic": "12.0.0-next.8", - "@angular/platform-server": "12.0.0-next.8", - "@angular/router": "12.0.0-next.8", - "@angular/service-worker": "12.0.0-next.8", - "@babel/core": "7.13.13", - "@babel/generator": "7.13.9", - "@babel/plugin-transform-runtime": "7.13.10", - "@babel/preset-env": "7.13.12", - "@babel/runtime": "7.13.10", - "@babel/template": "7.12.13", - "@bazel/bazelisk": "1.7.5", + "@ampproject/remapping": "1.0.1", + "@angular/animations": "12.2.1", + "@angular/cdk": "12.1.4", + "@angular/common": "12.2.1", + "@angular/compiler": "12.2.1", + "@angular/compiler-cli": "12.2.1", + "@angular/core": "12.2.1", + "@angular/dev-infra-private": "https://github.com/angular/dev-infra-private-builds.git#07a43c542704985a77ecabb4be12038e67419a65", + "@angular/forms": "12.2.1", + "@angular/localize": "12.2.1", + "@angular/material": "12.1.4", + "@angular/platform-browser": "12.2.1", + "@angular/platform-browser-dynamic": "12.2.1", + "@angular/platform-server": "12.2.1", + "@angular/router": "12.2.1", + "@angular/service-worker": "12.2.1", + "@babel/core": "7.14.8", + "@babel/generator": "7.14.8", + "@babel/helper-annotate-as-pure": "7.14.5", + "@babel/plugin-proposal-async-generator-functions": "7.14.7", + "@babel/plugin-transform-runtime": "7.14.5", + "@babel/preset-env": "7.14.8", + "@babel/runtime": "7.14.8", + "@babel/template": "7.14.5", + "@bazel/bazelisk": "1.10.1", "@bazel/buildifier": "4.0.1", - "@bazel/jasmine": "3.2.2", - "@bazel/typescript": "3.2.2", - "@discoveryjs/json-ext": "0.5.2", + "@bazel/jasmine": "3.7.0", + "@bazel/typescript": "3.7.0", + "@discoveryjs/json-ext": "0.5.3", "@jsdevtools/coverage-istanbul-loader": "3.0.5", - "@types/babel__core": "7.1.14", - "@types/babel__template": "7.4.0", + "@types/babel__core": "7.1.15", + "@types/babel__template": "7.4.1", "@types/cacache": "^15.0.0", "@types/caniuse-lite": "^1.0.0", - "@types/copy-webpack-plugin": "^6.0.0", - "@types/cssnano": "^4.0.0", + "@types/copy-webpack-plugin": "^8.0.0", "@types/debug": "^4.1.2", "@types/express": "^4.16.0", "@types/find-cache-dir": "^3.0.0", "@types/glob": "^7.1.1", "@types/http-proxy": "^1.17.4", "@types/inquirer": "^7.3.0", - "@types/jasmine": "~3.6.0", + "@types/jasmine": "~3.8.0", "@types/karma": "^6.3.0", "@types/loader-utils": "^2.0.0", - "@types/minimatch": "3.0.4", + "@types/minimatch": "3.0.5", "@types/minimist": "^1.2.0", "@types/node": "~12.12.6", "@types/node-fetch": "^2.1.6", @@ -115,118 +122,119 @@ "@types/postcss-preset-env": "^6.7.1", "@types/progress": "^2.0.3", "@types/resolve": "^1.17.1", - "@types/rimraf": "^3.0.0", + "@types/sass": "^1.16.0", "@types/semver": "^7.0.0", "@types/text-table": "^0.2.1", "@types/uuid": "^8.0.0", "@types/webpack-dev-server": "^3.1.7", + "@typescript-eslint/eslint-plugin": "4.28.5", + "@typescript-eslint/parser": "4.28.5", "@yarnpkg/lockfile": "1.1.0", - "ajv": "8.1.0", - "ajv-formats": "2.0.2", + "ajv": "8.6.2", + "ajv-formats": "2.1.0", "ansi-colors": "4.1.1", "babel-loader": "8.2.2", "bootstrap": "^4.0.0", "browserslist": "^4.9.1", - "cacache": "15.0.6", + "cacache": "15.2.0", "caniuse-lite": "^1.0.30001032", "circular-dependency-plugin": "5.2.2", "codelyzer": "^6.0.0", "common-tags": "^1.8.0", - "conventional-changelog": "^3.0.0", "conventional-commits-parser": "^3.0.0", - "copy-webpack-plugin": "8.1.1", - "core-js": "3.10.1", - "critters": "0.0.10", - "css-loader": "5.2.1", - "cssnano": "5.0.1", + "copy-webpack-plugin": "9.0.1", + "core-js": "3.16.0", + "critters": "0.0.12", + "css-loader": "6.2.0", + "css-minimizer-webpack-plugin": "3.0.2", "debug": "^4.1.1", - "enhanced-resolve": "5.7.0", + "esbuild": "0.13.8", + "esbuild-wasm": "0.13.8", + "eslint": "7.31.0", + "eslint-config-prettier": "8.3.0", + "eslint-plugin-header": "3.1.1", + "eslint-plugin-import": "2.23.4", "express": "4.17.1", "fast-json-stable-stringify": "2.1.0", "find-cache-dir": "3.3.1", "font-awesome": "^4.7.0", "gh-got": "^9.0.0", "git-raw-commits": "^2.0.0", - "glob": "7.1.6", + "glob": "7.1.7", "http-proxy": "^1.18.1", "https-proxy-agent": "5.0.0", - "husky": "6.0.0", - "inquirer": "8.0.0", + "husky": "7.0.1", + "inquirer": "8.1.2", "jasmine": "^3.3.1", - "jasmine-core": "~3.7.0", + "jasmine-core": "~3.8.0", "jasmine-spec-reporter": "~7.0.0", - "jest-worker": "26.6.2", "jquery": "^3.3.1", "jsonc-parser": "3.0.0", "karma": "~6.3.0", "karma-chrome-launcher": "~3.1.0", "karma-coverage": "~2.0.3", "karma-jasmine": "~4.0.0", - "karma-jasmine-html-reporter": "^1.5.0", + "karma-jasmine-html-reporter": "~1.7.0", "karma-source-map-support": "1.4.0", "less": "4.1.1", - "less-loader": "8.1.0", + "less-loader": "10.0.1", "license-checker": "^25.0.0", + "license-webpack-plugin": "2.3.20", "loader-utils": "2.0.0", "magic-string": "0.25.7", - "mini-css-extract-plugin": "1.4.1", + "mini-css-extract-plugin": "2.4.2", "minimatch": "3.0.4", - "minimist": "^1.2.0", - "ng-packagr": "~12.0.0-next.0", + "minimist": "1.2.6", + "ng-packagr": "~12.1.2", "node-fetch": "^2.2.0", - "npm-registry-client": "8.6.0", - "open": "8.0.5", - "ora": "5.4.0", - "pacote": "11.3.1", + "open": "8.2.1", + "ora": "5.4.1", + "pacote": "12.0.2", "parse5-html-rewriting-stream": "6.0.1", "pidtree": "^0.5.0", "pidusage": "^2.0.17", + "piscina": "3.1.0", "popper.js": "^1.14.1", - "postcss": "8.2.10", - "postcss-import": "14.0.1", - "postcss-loader": "5.2.0", + "postcss": "8.3.6", + "postcss-import": "14.0.2", + "postcss-loader": "6.1.1", "postcss-preset-env": "6.7.0", "prettier": "^2.0.0", "protractor": "~7.0.0", - "puppeteer": "8.0.0", - "quicktype-core": "^6.0.69", - "raw-loader": "4.0.2", - "regenerator-runtime": "0.13.7", - "resolve-url-loader": "3.1.2", - "rimraf": "3.0.2", + "puppeteer": "10.1.0", + "quicktype-core": "6.0.69", + "regenerator-runtime": "0.13.9", + "resolve-url-loader": "4.0.0", "rxjs": "6.6.7", - "sass": "1.32.8", - "sass-loader": "11.0.1", + "rxjs-7": "npm:rxjs@7.4.0", + "sass": "1.36.0", + "sass-loader": "12.1.0", "sauce-connect-proxy": "https://saucelabs.com/downloads/sc-4.6.4-linux.tar.gz", "semver": "7.3.5", "source-map": "0.7.3", - "source-map-loader": "1.1.3", + "source-map-loader": "3.0.0", "source-map-support": "0.5.19", "spdx-satisfies": "^5.0.0", - "style-loader": "2.0.0", + "style-loader": "3.2.1", "stylus": "0.54.8", - "stylus-loader": "4.3.3", - "symbol-observable": "3.0.0", - "tar": "^6.0.0", + "stylus-loader": "6.1.0", + "symbol-observable": "4.0.0", + "tar": "^6.1.6", "temp": "^0.9.0", - "terser": "5.6.1", - "terser-webpack-plugin": "4.2.3", + "terser": "5.14.2", + "terser-webpack-plugin": "5.1.4", "text-table": "0.2.0", - "through2": "^4.0.0", "tree-kill": "1.2.2", - "ts-api-guardian": "0.6.0", - "ts-node": "^9.0.0", - "tslib": "^2.0.0", + "ts-node": "^10.0.0", + "tslib": "2.3.0", "tslint": "^6.1.3", - "tslint-no-circular-imports": "^0.7.0", - "tslint-sonarts": "1.9.0", - "typescript": "4.2.4", - "verdaccio": "5.0.1", + "typescript": "4.3.5", + "verdaccio": "5.1.2", "verdaccio-auth-memory": "^10.0.0", - "webpack": "5.32.0", - "webpack-dev-middleware": "4.1.0", - "webpack-dev-server": "3.11.2", - "webpack-merge": "5.7.3", + "webpack": "5.50.0", + "webpack-dev-middleware": "5.0.0", + "webpack-dev-server": "3.11.3", + "webpack-merge": "5.8.0", "webpack-subresource-integrity": "1.5.2", "zone.js": "^0.11.3" } diff --git a/packages/README.md b/packages/README.md index eb38cb395147..aab7eadc1c92 100644 --- a/packages/README.md +++ b/packages/README.md @@ -4,5 +4,5 @@ This folder is the root of all defined packages in this repository. Packages that are marked as `private: true` will not be published to NPM. -This folder includes a directory for every scope in NPM, without the `@` sign. Then one folder +This folder includes a directory for every scope in NPM, without the `@` sign. Then one folder per package, which contains the `package.json`. diff --git a/packages/angular/cli/BUILD.bazel b/packages/angular/cli/BUILD.bazel index bea36e5ac0d0..018eccf08753 100644 --- a/packages/angular/cli/BUILD.bazel +++ b/packages/angular/cli/BUILD.bazel @@ -81,13 +81,17 @@ ts_library( "@npm//@types/node", "@npm//@types/npm-package-arg", "@npm//@types/resolve", - "@npm//@types/rimraf", "@npm//@types/semver", "@npm//@types/uuid", + "@npm//@yarnpkg/lockfile", "@npm//ansi-colors", + "@npm//ini", "@npm//jsonc-parser", + "@npm//npm-package-arg", "@npm//open", "@npm//ora", + "@npm//pacote", + "@npm//semver", ], ) diff --git a/packages/angular/cli/README.md b/packages/angular/cli/README.md index 96b40aacbad5..954dcd7d702c 100644 --- a/packages/angular/cli/README.md +++ b/packages/angular/cli/README.md @@ -1,6 +1,7 @@ ## Angular CLI + [![Dependency Status][david-badge]][david-badge-url] [![devDependency Status][david-dev-badge]][david-dev-badge-url] @@ -14,7 +15,6 @@ [![GitHub forks](https://img.shields.io/github/forks/angular/angular-cli.svg?style=social&label=Fork)](https://github.com/angular/angular-cli/fork) [![GitHub stars](https://img.shields.io/github/stars/angular/angular-cli.svg?style=social&label=Star)](https://github.com/angular/angular-cli) - ## Note If you are updating from a beta or RC version, check out our [1.0 Update Guide](https://github.com/angular/angular-cli/wiki/stories-1.0-update). @@ -30,25 +30,27 @@ with NPM 5.5.1 or higher. ## Table of Contents -* [Installation](#installation) -* [Usage](#usage) -* [Generating a New Project](#generating-and-serving-an-angular-project-via-a-development-server) -* [Generating Components, Directives, Pipes and Services](#generating-components-directives-pipes-and-services) -* [Updating Angular CLI](#updating-angular-cli) -* [Development Hints for working on Angular CLI](#development-hints-for-working-on-angular-cli) -* [Documentation](#documentation) -* [License](#license) +- [Installation](#installation) +- [Usage](#usage) +- [Generating a New Project](#generating-and-serving-an-angular-project-via-a-development-server) +- [Generating Components, Directives, Pipes and Services](#generating-components-directives-pipes-and-services) +- [Updating Angular CLI](#updating-angular-cli) +- [Development Hints for working on Angular CLI](#development-hints-for-working-on-angular-cli) +- [Documentation](#documentation) +- [License](#license) ## Installation **BEFORE YOU INSTALL:** please read the [prerequisites](#prerequisites) ### Install Globally + ```bash npm install -g @angular/cli ``` ### Install Locally + ```bash npm install @angular/cli ``` @@ -58,6 +60,7 @@ To run a locally installed version of the angular-cli, you can call `ng` command Alternatively, you can install [npx](https://www.npmjs.com/package/npx) and run `npx ng ` within the local directory where `npm install @angular/cli` was run, which will use the locally installed angular-cli. ### Install Specific Version (Example: 6.1.1) + ```bash npm install -g @angular/cli@6.1.1 ``` @@ -75,6 +78,7 @@ ng new PROJECT-NAME cd PROJECT-NAME ng serve ``` + Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. You can configure the default HTTP host and port used by the development server with two command-line options : @@ -102,33 +106,32 @@ ng g component ./newer-cmp ng g component feature/new-cmp # and your component will be generated in src/app/feature/new-cmp ``` -You can find all possible blueprints in the table below: - -Scaffold | Usage ---- | --- -[Component](https://angular.io/cli/generate#component) | `ng g component my-new-component` -[Directive](https://angular.io/cli/generate#directive) | `ng g directive my-new-directive` -[Pipe](https://angular.io/cli/generate#pipe) | `ng g pipe my-new-pipe` -[Service](https://angular.io/cli/generate#service) | `ng g service my-new-service` -[Class](https://angular.io/cli/generate#class) | `ng g class my-new-class` -[Guard](https://angular.io/cli/generate#guard) | `ng g guard my-new-guard` -[Interface](https://angular.io/cli/generate#interface) | `ng g interface my-new-interface` -[Enum](https://angular.io/cli/generate#enum) | `ng g enum my-new-enum` -[Module](https://angular.io/cli/generate#module) | `ng g module my-module` - +You can find all possible blueprints in the table below: +| Scaffold | Usage | +| ------------------------------------------------------ | --------------------------------- | +| [Component](https://angular.io/cli/generate#component) | `ng g component my-new-component` | +| [Directive](https://angular.io/cli/generate#directive) | `ng g directive my-new-directive` | +| [Pipe](https://angular.io/cli/generate#pipe) | `ng g pipe my-new-pipe` | +| [Service](https://angular.io/cli/generate#service) | `ng g service my-new-service` | +| [Class](https://angular.io/cli/generate#class) | `ng g class my-new-class` | +| [Guard](https://angular.io/cli/generate#guard) | `ng g guard my-new-guard` | +| [Interface](https://angular.io/cli/generate#interface) | `ng g interface my-new-interface` | +| [Enum](https://angular.io/cli/generate#enum) | `ng g enum my-new-enum` | +| [Module](https://angular.io/cli/generate#module) | `ng g module my-module` | angular-cli will add reference to `components`, `directives` and `pipes` automatically in the `app.module.ts`. If you need to add this references to another custom module, follow these steps: - 1. `ng g module new-module` to create a new module - 2. call `ng g component new-module/new-component` +1. `ng g module new-module` to create a new module +2. call `ng g component new-module/new-component` This should add the new `component`, `directive` or `pipe` reference to the `new-module` you've created. ### Updating Angular CLI If you're using Angular CLI `1.0.0-beta.28` or less, you need to uninstall `angular-cli` package. It should be done due to changing of package's name and scope from `angular-cli` to `@angular/cli`: + ```bash npm uninstall -g angular-cli npm uninstall --save-dev angular-cli @@ -137,6 +140,7 @@ npm uninstall --save-dev angular-cli To update Angular CLI to a new version, you must update both the global package and your project's local package. Global package: + ```bash npm uninstall -g @angular/cli npm cache verify @@ -145,6 +149,7 @@ npm install -g @angular/cli@latest ``` Local project package: + ```bash rm -rf node_modules dist # use rmdir /S/Q node_modules dist in Windows Command Prompt; use rm -r -fo node_modules,dist in Windows PowerShell npm install --save-dev @angular/cli@latest @@ -155,7 +160,6 @@ If you are updating to 1.0 from a beta or RC version, check out our [1.0 Update You can find more details about changes between versions in [the Releases tab on GitHub](https://github.com/angular/angular-cli/releases). - ## Development Hints for working on Angular CLI ### Working with master @@ -231,15 +235,17 @@ For more informations about Node.js debugging in VS Code, see the related [VS Co In order to investigate performance issues, CPU profiling is often useful. To capture a CPU profiling, you can: + 1. install the v8-profiler-node8 dependency: `npm install v8-profiler-node8 --no-save` 1. set the NG_CLI_PROFILING Environment variable to the file name you want: - * on Unix systems (Linux & Mac OS X): ̀`export NG_CLI_PROFILING=my-profile` - * on Windows: ̀̀`setx NG_CLI_PROFILING my-profile` + - on Unix systems (Linux & Mac OS X): ̀`export NG_CLI_PROFILING=my-profile` + - on Windows: ̀̀`setx NG_CLI_PROFILING my-profile` Then, just run the ng command on which you want to capture a CPU profile. You will then obtain a `my-profile.cpuprofile` file in the folder from which you ran the ng command. You can use the Chrome Devtools to process it. To do so: + 1. open `chrome://inspect/#devices` in Chrome 1. click on "Open dedicated DevTools for Node" 1. go to the "profiler" tab @@ -256,7 +262,6 @@ The documentation for the Angular CLI is located on our [documentation website]( [MIT](https://github.com/angular/angular-cli/blob/master/LICENSE) - [travis-badge]: https://travis-ci.org/angular/angular-cli.svg?branch=master [travis-badge-url]: https://travis-ci.org/angular/angular-cli [david-badge]: https://david-dm.org/angular/angular-cli.svg @@ -266,4 +271,3 @@ The documentation for the Angular CLI is located on our [documentation website]( [npm-badge]: https://img.shields.io/npm/v/@angular/cli.svg [npm-badge-url]: https://www.npmjs.com/package/@angular/cli [license-url]: https://github.com/angular/angular-cli/blob/master/LICENSE - diff --git a/packages/angular/cli/bin/ng b/packages/angular/cli/bin/ng index 09aea2a41bf0..889851add1f7 100755 --- a/packages/angular/cli/bin/ng +++ b/packages/angular/cli/bin/ng @@ -29,15 +29,15 @@ if (version[0] % 2 === 1 && version[0] > 14) { } else if ( version[0] < 12 || version[0] === 13 || - (version[0] === 12 && version[1] < 13) || + (version[0] === 12 && version[1] < 14) || (version[0] === 14 && version[1] < 15) ) { - // Error and exit if less than 12.13 or 13.x or less than 14.15 + // Error and exit if less than 12.14 or 13.x or less than 14.15 console.error( 'Node.js version ' + process.version + ' detected.\n' + - 'The Angular CLI requires a minimum Node.js version of either v12.13 or v14.15.\n\n' + + 'The Angular CLI requires a minimum Node.js version of either v12.14 or v14.15.\n\n' + 'Please update your Node.js version or visit https://nodejs.org/ for additional instructions.\n', ); diff --git a/packages/angular/cli/bin/postinstall/analytics-prompt.js b/packages/angular/cli/bin/postinstall/analytics-prompt.js index 04121439939e..b24c319ede10 100644 --- a/packages/angular/cli/bin/postinstall/analytics-prompt.js +++ b/packages/angular/cli/bin/postinstall/analytics-prompt.js @@ -10,7 +10,7 @@ try { analytics .hasGlobalAnalyticsConfiguration() - .then(hasGlobalConfig => { + .then((hasGlobalConfig) => { if (!hasGlobalConfig) { return analytics.promptGlobalAnalytics(); } diff --git a/packages/angular/cli/commands/add-impl.ts b/packages/angular/cli/commands/add-impl.ts index 4f0188cd0415..722fac678db4 100644 --- a/packages/angular/cli/commands/add-impl.ts +++ b/packages/angular/cli/commands/add-impl.ts @@ -1,12 +1,14 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { analytics, tags } from '@angular-devkit/core'; import { NodePackageDoesNotSupportSchematics } from '@angular-devkit/schematics/tools'; +import npa from 'npm-package-arg'; import { dirname, join } from 'path'; import { intersects, prerelease, rcompare, satisfies, valid, validRange } from 'semver'; import { PackageManager } from '../lib/config/workspace-schema'; @@ -27,12 +29,10 @@ import { Spinner } from '../utilities/spinner'; import { isTTY } from '../utilities/tty'; import { Schema as AddCommandSchema } from './add'; -const npa = require('npm-package-arg'); - export class AddCommand extends SchematicCommand { - readonly allowPrivateSchematics = true; + override readonly allowPrivateSchematics = true; - async initialize(options: AddCommandSchema & Arguments) { + override async initialize(options: AddCommandSchema & Arguments) { if (options.registry) { return super.initialize({ ...options, packageRegistry: options.registry }); } else { @@ -61,21 +61,12 @@ export class AddCommand extends SchematicCommand { return 1; } - if (packageIdentifier.registry && this.isPackageInstalled(packageIdentifier.name)) { - let validVersion = false; - const installedVersion = await this.findProjectVersion(packageIdentifier.name); - if (installedVersion) { - if (packageIdentifier.type === 'range') { - validVersion = satisfies(installedVersion, packageIdentifier.fetchSpec); - } else if (packageIdentifier.type === 'version') { - const v1 = valid(packageIdentifier.fetchSpec); - const v2 = valid(installedVersion); - validVersion = v1 !== null && v1 === v2; - } else if (!packageIdentifier.rawSpec) { - validVersion = true; - } - } - + if ( + packageIdentifier.name && + packageIdentifier.registry && + this.isPackageInstalled(packageIdentifier.name) + ) { + const validVersion = await this.isProjectVersionValid(packageIdentifier); if (validVersion) { // Already installed so just run schematic this.logger.info('Skipping installation: Package already installed'); @@ -91,7 +82,7 @@ export class AddCommand extends SchematicCommand { const usingYarn = packageManager === PackageManager.Yarn; spinner.info(`Using package manager: ${colors.grey(packageManager)}`); - if (packageIdentifier.type === 'tag' && !packageIdentifier.rawSpec) { + if (packageIdentifier.name && packageIdentifier.type === 'tag' && !packageIdentifier.rawSpec) { // only package name provided; search for viable version // plus special cases for packages that did not have peer deps setup spinner.start('Searching for compatible package version...'); @@ -125,12 +116,14 @@ export class AddCommand extends SchematicCommand { } else { packageIdentifier = npa.resolve(latestManifest.name, latestManifest.version); } - spinner.succeed(`Found compatible package version: ${colors.grey(packageIdentifier)}.`); + spinner.succeed( + `Found compatible package version: ${colors.grey(packageIdentifier.toString())}.`, + ); } else if (!latestManifest || (await this.hasMismatchedPeer(latestManifest))) { // 'latest' is invalid so search for most recent matching package const versionManifests = Object.values(packageMetadata.versions).filter( (value: PackageManifest) => !prerelease(value.version) && !value.deprecated, - ) as PackageManifest[]; + ); versionManifests.sort((a, b) => rcompare(a.version, b.version, true)); @@ -146,11 +139,15 @@ export class AddCommand extends SchematicCommand { spinner.warn("Unable to find compatible package. Using 'latest'."); } else { packageIdentifier = newIdentifier; - spinner.succeed(`Found compatible package version: ${colors.grey(packageIdentifier)}.`); + spinner.succeed( + `Found compatible package version: ${colors.grey(packageIdentifier.toString())}.`, + ); } } else { packageIdentifier = npa.resolve(latestManifest.name, latestManifest.version); - spinner.succeed(`Found compatible package version: ${colors.grey(packageIdentifier)}.`); + spinner.succeed( + `Found compatible package version: ${colors.grey(packageIdentifier.toString())}.`, + ); } } @@ -159,7 +156,7 @@ export class AddCommand extends SchematicCommand { try { spinner.start('Loading package information from registry...'); - const manifest = await fetchPackageManifest(packageIdentifier, this.logger, { + const manifest = await fetchPackageManifest(packageIdentifier.toString(), this.logger, { registry: options.registry, verbose: options.verbose, usingYarn, @@ -169,9 +166,7 @@ export class AddCommand extends SchematicCommand { collectionName = manifest.name; if (await this.hasMismatchedPeer(manifest)) { - spinner.warn( - 'Package has unmet peer dependencies. Adding the package may not succeed.', - ); + spinner.warn('Package has unmet peer dependencies. Adding the package may not succeed.'); } else { spinner.succeed(`Package information loaded.`); } @@ -190,7 +185,7 @@ export class AddCommand extends SchematicCommand { ); if (!confirmationResponse) { - if (!isTTY) { + if (!isTTY()) { this.logger.error( 'No terminal detected. ' + `'--skip-confirmation' can be used to bypass installation confirmation. ` + @@ -203,45 +198,62 @@ export class AddCommand extends SchematicCommand { } } - try { - spinner.start('Installing package...'); - if (savePackage === false) { - // Temporary packages are located in a different directory - // Hence we need to resolve them using the temp path - const tempPath = installTempPackage( - packageIdentifier.raw, - undefined, - packageManager, - options.registry ? [`--registry="${options.registry}"`] : undefined, - ); - const resolvedCollectionPath = require.resolve( - join(collectionName, 'package.json'), - { - paths: [tempPath], - }, - ); + if (savePackage === false) { + // Temporary packages are located in a different directory + // Hence we need to resolve them using the temp path + const { status, tempNodeModules } = await installTempPackage( + packageIdentifier.raw, + packageManager, + options.registry ? [`--registry="${options.registry}"`] : undefined, + ); + const resolvedCollectionPath = require.resolve(join(collectionName, 'package.json'), { + paths: [tempNodeModules], + }); - collectionName = dirname(resolvedCollectionPath); - } else { - installPackage( - packageIdentifier.raw, - undefined, - packageManager, - savePackage, - options.registry ? [`--registry="${options.registry}"`] : undefined, - ); + if (status !== 0) { + return status; } - spinner.succeed('Package successfully installed.'); - } catch (error) { - spinner.fail(`Package installation failed: ${error.message}`); - return 1; + collectionName = dirname(resolvedCollectionPath); + } else { + const status = await installPackage( + packageIdentifier.raw, + packageManager, + savePackage, + options.registry ? [`--registry="${options.registry}"`] : undefined, + ); + + if (status !== 0) { + return status; + } } return this.executeSchematic(collectionName, options['--']); } - async reportAnalytics( + private async isProjectVersionValid(packageIdentifier: npa.Result): Promise { + if (!packageIdentifier.name) { + return false; + } + + let validVersion = false; + const installedVersion = await this.findProjectVersion(packageIdentifier.name); + if (installedVersion) { + if (packageIdentifier.type === 'range' && packageIdentifier.fetchSpec) { + validVersion = satisfies(installedVersion, packageIdentifier.fetchSpec); + } else if (packageIdentifier.type === 'version') { + const v1 = valid(packageIdentifier.fetchSpec); + const v2 = valid(installedVersion); + validVersion = v1 !== null && v1 === v2; + } else if (!packageIdentifier.rawSpec) { + validVersion = true; + } + } + + return validVersion; + } + + override async reportAnalytics( paths: string[], options: AddCommandSchema & Arguments, dimensions: (boolean | number | string)[] = [], diff --git a/packages/angular/cli/commands/add.json b/packages/angular/cli/commands/add.json index 014ec5ab4d6b..99cd82d897fb 100644 --- a/packages/angular/cli/commands/add.json +++ b/packages/angular/cli/commands/add.json @@ -42,8 +42,7 @@ "default": false } }, - "required": [ - ] + "required": [] }, { "$ref": "./definitions.json#/definitions/interactive" diff --git a/packages/angular/cli/commands/add.md b/packages/angular/cli/commands/add.md index 465438a4e5b2..09cd2e239d76 100644 --- a/packages/angular/cli/commands/add.md +++ b/packages/angular/cli/commands/add.md @@ -2,6 +2,7 @@ Adds the npm package for a published library to your workspace, and configures the project in the current working directory (or the default project if you are not in a project directory) to use that library, as specified by the library's schematic. For example, adding `@angular/pwa` configures your project for PWA support: + ```bash ng add @angular/pwa ``` diff --git a/packages/angular/cli/commands/analytics-impl.ts b/packages/angular/cli/commands/analytics-impl.ts index 9174005d7b18..b0cc575ad173 100644 --- a/packages/angular/cli/commands/analytics-impl.ts +++ b/packages/angular/cli/commands/analytics-impl.ts @@ -1,10 +1,11 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { promptGlobalAnalytics, promptProjectAnalytics, @@ -12,8 +13,7 @@ import { } from '../models/analytics'; import { Command } from '../models/command'; import { Arguments } from '../models/interface'; -import { ProjectSetting, Schema as AnalyticsCommandSchema, SettingOrProject } from './analytics'; - +import { Schema as AnalyticsCommandSchema, ProjectSetting, SettingOrProject } from './analytics'; export class AnalyticsCommand extends Command { public async run(options: AnalyticsCommandSchema & Arguments) { @@ -33,10 +33,14 @@ export class AnalyticsCommand extends Command { return 2; } - } else if (options.settingOrProject == SettingOrProject.Project - && options.projectSetting === undefined) { - this.logger.error(`Argument ${JSON.stringify(options.settingOrProject)} requires a second ` - + `argument of one of the following value: on, off.`); + } else if ( + options.settingOrProject == SettingOrProject.Project && + options.projectSetting === undefined + ) { + this.logger.error( + `Argument ${JSON.stringify(options.settingOrProject)} requires a second ` + + `argument of one of the following value: on, off.`, + ); return 2; } diff --git a/packages/angular/cli/commands/analytics-long.md b/packages/angular/cli/commands/analytics-long.md index 60e0d86686e8..87b9925d1473 100644 --- a/packages/angular/cli/commands/analytics-long.md +++ b/packages/angular/cli/commands/analytics-long.md @@ -1,7 +1,8 @@ -The value of *settingOrProject* is one of the following. -* "on" : Enables analytics gathering and reporting for the user. -* "off" : Disables analytics gathering and reporting for the user. -* "ci" : Enables analytics and configures reporting for use with Continuous Integration, -which uses a common CI user. -* "prompt" : Prompts the user to set the status interactively. -* "project" : Sets the default status for the project to the *projectSetting* value, which can be any of the other values. The *projectSetting* argument is ignored for all other values of *settingOrProject*. \ No newline at end of file +The value of _settingOrProject_ is one of the following. + +- "on" : Enables analytics gathering and reporting for the user. +- "off" : Disables analytics gathering and reporting for the user. +- "ci" : Enables analytics and configures reporting for use with Continuous Integration, + which uses a common CI user. +- "prompt" : Prompts the user to set the status interactively. +- "project" : Sets the default status for the project to the _projectSetting_ value, which can be any of the other values. The _projectSetting_ argument is ignored for all other values of _settingOrProject_. diff --git a/packages/angular/cli/commands/analytics.json b/packages/angular/cli/commands/analytics.json index e34234d0e39d..ee2612b20399 100644 --- a/packages/angular/cli/commands/analytics.json +++ b/packages/angular/cli/commands/analytics.json @@ -14,13 +14,7 @@ { "properties": { "settingOrProject": { - "enum": [ - "on", - "off", - "ci", - "project", - "prompt" - ], + "enum": ["on", "off", "ci", "project", "prompt"], "description": "Directly enables or disables all usage analytics for the user, or prompts the user to set the status interactively, or sets the default status for the project.", "$default": { "$source": "argv", @@ -28,11 +22,7 @@ } }, "projectSetting": { - "enum": [ - "on", - "off", - "prompt" - ], + "enum": ["on", "off", "prompt"], "description": "Sets the default analytics enablement status for the project.", "$default": { "$source": "argv", @@ -40,9 +30,7 @@ } } }, - "required": [ - "settingOrProject" - ] + "required": ["settingOrProject"] }, { "$ref": "./definitions.json#/definitions/base" } ] diff --git a/packages/angular/cli/commands/build-impl.ts b/packages/angular/cli/commands/build-impl.ts index 0bdd50b57949..2d983a7514b1 100644 --- a/packages/angular/cli/commands/build-impl.ts +++ b/packages/angular/cli/commands/build-impl.ts @@ -1,18 +1,19 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { ArchitectCommand, ArchitectCommandOptions } from '../models/architect-command'; import { Arguments } from '../models/interface'; import { Schema as BuildCommandSchema } from './build'; export class BuildCommand extends ArchitectCommand { - public readonly target = 'build'; + public override readonly target = 'build'; - public async run(options: ArchitectCommandOptions & Arguments) { + public override async run(options: ArchitectCommandOptions & Arguments) { return this.runArchitectTarget(options); } } diff --git a/packages/angular/cli/commands/build.json b/packages/angular/cli/commands/build.json index 2dbe778cafed..df9d93b85a19 100644 --- a/packages/angular/cli/commands/build.json +++ b/packages/angular/cli/commands/build.json @@ -4,7 +4,7 @@ "description": "Compiles an Angular app into an output directory named dist/ at the given output path. Must be executed from within a workspace directory.", "$longDescription": "./build-long.md", - "$aliases": [ "b" ], + "$aliases": ["b"], "$scope": "in", "$type": "architect", "$impl": "./build-impl#BuildCommand", diff --git a/packages/angular/cli/commands/config-impl.ts b/packages/angular/cli/commands/config-impl.ts index 329bc499a6f2..8736ad7ed807 100644 --- a/packages/angular/cli/commands/config-impl.ts +++ b/packages/angular/cli/commands/config-impl.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license @@ -10,21 +10,21 @@ import { JsonValue, tags } from '@angular-devkit/core'; import { v4 as uuidV4 } from 'uuid'; import { Command } from '../models/command'; import { Arguments, CommandScope } from '../models/interface'; -import { - getWorkspaceRaw, - migrateLegacyGlobalConfig, - validateWorkspace, -} from '../utilities/config'; +import { getWorkspaceRaw, migrateLegacyGlobalConfig, validateWorkspace } from '../utilities/config'; import { JSONFile, parseJson } from '../utilities/json-file'; import { Schema as ConfigCommandSchema } from './config'; -const validCliPaths = new Map string) | undefined>([ +const validCliPaths = new Map< + string, + ((arg: string | number | boolean | undefined) => string) | undefined +>([ ['cli.warnings.versionMismatch', undefined], ['cli.defaultCollection', undefined], ['cli.packageManager', undefined], + ['cli.analytics', undefined], ['cli.analyticsSharing.tracking', undefined], - ['cli.analyticsSharing.uuid', v => v ? `${v}` : uuidV4()], + ['cli.analyticsSharing.uuid', (v) => (v === '' ? uuidV4() : `${v}`)], ]); /** @@ -55,25 +55,40 @@ function parseJsonPath(path: string): (string | number)[] { const indices = match[2] .slice(1, -1) .split('][') - .map(x => (/^\d$/.test(x) ? +x : x.replace(/\"|\'/g, ''))); + .map((x) => (/^\d$/.test(x) ? +x : x.replace(/\"|\'/g, ''))); result.push(...indices); } } - return result.filter(fragment => fragment != null); + return result.filter((fragment) => fragment != null); } function normalizeValue(value: string | undefined | boolean | number): JsonValue | undefined { const valueString = `${value}`.trim(); - if (valueString === 'true') { - return true; - } else if (valueString === 'false') { - return false; - } else if (isFinite(+valueString)) { + switch (valueString) { + case 'true': + return true; + case 'false': + return false; + case 'null': + return null; + case 'undefined': + return undefined; + } + + if (isFinite(+valueString)) { return +valueString; } - return value || undefined; + try { + // We use `JSON.parse` instead of `parseJson` because the latter will parse UUIDs + // and convert them into a numberic entities. + // Example: 73b61974-182c-48e4-b4c6-30ddf08c5c98 -> 73. + // These values should never contain comments, therefore using `JSON.parse` is safe. + return JSON.parse(valueString); + } catch { + return value; + } } export class ConfigCommand extends Command { @@ -94,7 +109,7 @@ export class ConfigCommand extends Command { We found a global configuration that was used in Angular CLI 1. It has been automatically migrated.`); } - } catch { } + } catch {} } if (options.value == undefined) { diff --git a/packages/angular/cli/commands/config-long.md b/packages/angular/cli/commands/config-long.md index 5f6052b3894a..7f44f63b3b32 100644 --- a/packages/angular/cli/commands/config-long.md +++ b/packages/angular/cli/commands/config-long.md @@ -10,4 +10,4 @@ while on the command line options can be given in either camelCase or dash-case. For further details, see [Workspace Configuration](guide/workspace-config). -For configuration of CLI usage analytics, see [Gathering an Viewing CLI Usage Analytics](./usage-analytics-gathering). \ No newline at end of file +For configuration of CLI usage analytics, see [Gathering an Viewing CLI Usage Analytics](./usage-analytics-gathering). diff --git a/packages/angular/cli/commands/config.json b/packages/angular/cli/commands/config.json index 95a1f874119b..bec13fca4c0f 100644 --- a/packages/angular/cli/commands/config.json +++ b/packages/angular/cli/commands/config.json @@ -36,8 +36,7 @@ "aliases": ["g"] } }, - "required": [ - ] + "required": [] }, { "$ref": "./definitions.json#/definitions/base" } ] diff --git a/packages/angular/cli/commands/definitions.json b/packages/angular/cli/commands/definitions.json index 5da8c67159a2..a18355349f46 100644 --- a/packages/angular/cli/commands/definitions.json +++ b/packages/angular/cli/commands/definitions.json @@ -16,9 +16,7 @@ "configuration": { "description": "One or more named builder configurations as a comma-separated list as specified in the \"configurations\" section of angular.json.\nThe builder uses the named configurations to run the given target.\nFor more information, see https://angular.io/guide/workspace-config#alternate-build-configurations.\nSetting this explicitly overrides the \"--prod\" flag.", "type": "string", - "aliases": [ - "c" - ] + "aliases": ["c"] }, "prod": { "description": "Shorthand for \"--configuration=production\".\nSet the build configuration to the production target.\nBy default, the production target is set up in the workspace configuration such that all builds make use of bundling, limited tree-shaking, and also limited dead code elimination.", @@ -43,13 +41,13 @@ "dryRun": { "type": "boolean", "default": false, - "aliases": [ "d" ], + "aliases": ["d"], "description": "Run through and reports activity without writing out results." }, "force": { "type": "boolean", "default": false, - "aliases": [ "f" ], + "aliases": ["f"], "description": "Force overwriting of existing files." } } diff --git a/packages/angular/cli/commands/deploy-impl.ts b/packages/angular/cli/commands/deploy-impl.ts index 4572f27d8995..92b0ecd96f8e 100644 --- a/packages/angular/cli/commands/deploy-impl.ts +++ b/packages/angular/cli/commands/deploy-impl.ts @@ -1,10 +1,11 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { ArchitectCommand } from '../models/architect-command'; import { Arguments } from '../models/interface'; import { Schema as DeployCommandSchema } from './deploy'; @@ -24,10 +25,12 @@ Find more packages on npm https://www.npmjs.com/search?q=ng%20deploy `; export class DeployCommand extends ArchitectCommand { - public readonly target = 'deploy'; - public readonly missingTargetError = BuilderMissing; + public override readonly target = 'deploy'; + public override readonly missingTargetError = BuilderMissing; - public async initialize(options: DeployCommandSchema & Arguments): Promise { + public override async initialize( + options: DeployCommandSchema & Arguments, + ): Promise { if (!options.help) { return super.initialize(options); } diff --git a/packages/angular/cli/commands/deploy-long.md b/packages/angular/cli/commands/deploy-long.md index afe619565c0a..9d13ad2a9890 100644 --- a/packages/angular/cli/commands/deploy-long.md +++ b/packages/angular/cli/commands/deploy-long.md @@ -19,4 +19,4 @@ For example: } } } - ``` \ No newline at end of file +``` diff --git a/packages/angular/cli/commands/deploy.json b/packages/angular/cli/commands/deploy.json index 31f6d8e7e4c5..cc7c860dde1c 100644 --- a/packages/angular/cli/commands/deploy.json +++ b/packages/angular/cli/commands/deploy.json @@ -22,9 +22,7 @@ "configuration": { "description": "One or more named builder configurations as a comma-separated list as specified in the \"configurations\" section of angular.json.\nThe builder uses the named configurations to run the given target.\nFor more information, see https://angular.io/guide/workspace-config#alternate-build-configurations.", "type": "string", - "aliases": [ - "c" - ] + "aliases": ["c"] } }, "required": [] diff --git a/packages/angular/cli/commands/doc-impl.ts b/packages/angular/cli/commands/doc-impl.ts index 1c1fc86d1535..b39665b68abe 100644 --- a/packages/angular/cli/commands/doc-impl.ts +++ b/packages/angular/cli/commands/doc-impl.ts @@ -1,12 +1,12 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ -import * as open from 'open'; +import open from 'open'; import { Command } from '../models/command'; import { Arguments } from '../models/interface'; import { Schema as DocCommandSchema } from './doc'; @@ -37,10 +37,10 @@ export class DocCommand extends Command { // we try to get the current Angular version of the project // and use it if we can find it try { - /* tslint:disable-next-line:no-implicit-dependencies */ + /* eslint-disable-next-line import/no-extraneous-dependencies */ const currentNgVersion = (await import('@angular/core')).VERSION.major; domain = `v${currentNgVersion}.angular.io`; - } catch (e) { } + } catch (e) {} } let searchUrl = `https://${domain}/api?query=${options.keyword}`; diff --git a/packages/angular/cli/commands/doc.json b/packages/angular/cli/commands/doc.json index de6cf2ff6323..bb01549c6099 100644 --- a/packages/angular/cli/commands/doc.json +++ b/packages/angular/cli/commands/doc.json @@ -4,7 +4,7 @@ "description": "Opens the official Angular documentation (angular.io) in a browser, and searches for a given keyword.", "$longDescription": "", - "$aliases": [ "d" ], + "$aliases": ["d"], "$type": "native", "$impl": "./doc-impl#DocCommand", @@ -26,7 +26,7 @@ "default": false, "description": "Search all of angular.io. Otherwise, searches only API reference documentation." }, - "version" : { + "version": { "oneOf": [ { "type": "number", @@ -39,8 +39,7 @@ "description": "Contains the version of Angular to use for the documentation. If not provided, the command uses your current Angular core version." } }, - "required": [ - ] + "required": [] }, { "$ref": "./definitions.json#/definitions/base" } ] diff --git a/packages/angular/cli/commands/e2e-impl.ts b/packages/angular/cli/commands/e2e-impl.ts index f24a44ca4122..5a1df466d97d 100644 --- a/packages/angular/cli/commands/e2e-impl.ts +++ b/packages/angular/cli/commands/e2e-impl.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license @@ -10,12 +10,25 @@ import { ArchitectCommand } from '../models/architect-command'; import { Arguments } from '../models/interface'; import { Schema as E2eCommandSchema } from './e2e'; - export class E2eCommand extends ArchitectCommand { - public readonly target = 'e2e'; - public readonly multiTarget = true; + public override readonly target = 'e2e'; + public override readonly multiTarget = true; + public override readonly missingTargetError = ` +Cannot find "e2e" target for the specified project. + +You should add a package that implements end-to-end testing capabilities. + +For example: + Cypress: ng add @cypress/schematic + Nightwatch: ng add @nightwatch/schematics + WebdriverIO: ng add @wdio/schematics + +More options will be added to the list as they become available. +`; - public async run(options: E2eCommandSchema & Arguments) { - return this.runArchitectTarget(options); + override async initialize(options: E2eCommandSchema & Arguments) { + if (!options.help) { + return super.initialize(options); + } } } diff --git a/packages/angular/cli/commands/e2e-long.md b/packages/angular/cli/commands/e2e-long.md index 6b651df713d9..26363135a8ce 100644 --- a/packages/angular/cli/commands/e2e-long.md +++ b/packages/angular/cli/commands/e2e-long.md @@ -1,2 +1,4 @@ -Must be executed from within a workspace directory. -When a project name is not supplied, it will execute for all projects. \ No newline at end of file +The command takes an optional project name, as specified in the `projects` section of the `angular.json` workspace configuration file. +When a project name is not supplied, executes the `e2e` builder for the default project. + +To use the `ng e2e` command, use `ng add` to add a package that implements end-to-end testing capabilities. Adding the package automatically updates your workspace configuration, adding an `e2e` [CLI builder](guide/cli-builder). diff --git a/packages/angular/cli/commands/e2e.json b/packages/angular/cli/commands/e2e.json index 602d4d0560a7..a8c8cccc4b62 100644 --- a/packages/angular/cli/commands/e2e.json +++ b/packages/angular/cli/commands/e2e.json @@ -1,10 +1,10 @@ { "$schema": "http://json-schema.org/draft-07/schema", "$id": "ng-cli://commands/e2e.json", - "description": "Builds and serves an Angular app, then runs end-to-end tests using Protractor.", + "description": "Builds and serves an Angular app, then runs end-to-end tests.", "$longDescription": "./e2e-long.md", - "$aliases": [ "e" ], + "$aliases": ["e"], "$scope": "in", "$type": "architect", "$impl": "./e2e-impl#E2eCommand", diff --git a/packages/angular/cli/commands/easter-egg-impl.ts b/packages/angular/cli/commands/easter-egg-impl.ts index 8e70d46dc827..3857c38444a5 100644 --- a/packages/angular/cli/commands/easter-egg-impl.ts +++ b/packages/angular/cli/commands/easter-egg-impl.ts @@ -1,10 +1,11 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { Command } from '../models/command'; import { colors } from '../utilities/color'; import { Schema as AwesomeCommandSchema } from './easter-egg'; diff --git a/packages/angular/cli/commands/easter-egg.json b/packages/angular/cli/commands/easter-egg.json index b42b12b1156e..79d9e1bb2edf 100644 --- a/packages/angular/cli/commands/easter-egg.json +++ b/packages/angular/cli/commands/easter-egg.json @@ -8,7 +8,5 @@ "$impl": "./easter-egg-impl#AwesomeCommand", "type": "object", - "allOf": [ - { "$ref": "./definitions.json#/definitions/base" } - ] + "allOf": [{ "$ref": "./definitions.json#/definitions/base" }] } diff --git a/packages/angular/cli/commands/extract-i18n-impl.ts b/packages/angular/cli/commands/extract-i18n-impl.ts index 00a8e2e4ce2d..3520d57d3e2d 100644 --- a/packages/angular/cli/commands/extract-i18n-impl.ts +++ b/packages/angular/cli/commands/extract-i18n-impl.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license @@ -11,21 +11,25 @@ import { Arguments } from '../models/interface'; import { Schema as ExtractI18nCommandSchema } from './extract-i18n'; export class ExtractI18nCommand extends ArchitectCommand { - public readonly target = 'extract-i18n'; + public override readonly target = 'extract-i18n'; - public async run(options: ExtractI18nCommandSchema & Arguments) { + public override async run(options: ExtractI18nCommandSchema & Arguments) { const version = process.version.substr(1).split('.'); if (Number(version[0]) === 12 && Number(version[1]) === 0) { this.logger.error( - 'Due to a defect in Node.js 12.0, the command is not supported on this Node.js version. ' - + 'Please upgrade to Node.js 12.1 or later.'); + 'Due to a defect in Node.js 12.0, the command is not supported on this Node.js version. ' + + 'Please upgrade to Node.js 12.1 or later.', + ); return 1; } const commandName = process.argv[2]; if (['xi18n', 'i18n-extract'].includes(commandName)) { - this.logger.warn(`Warning: "ng ${commandName}" has been deprecated and will be removed in a future major version. Please use "ng extract-i18n" instead.`); + this.logger.warn( + `Warning: "ng ${commandName}" has been deprecated and will be removed in a future major version. ` + + 'Please use "ng extract-i18n" instead.', + ); } return this.runArchitectTarget(options); diff --git a/packages/angular/cli/commands/generate-impl.ts b/packages/angular/cli/commands/generate-impl.ts index c32ccd7b87ea..49d71dd3555c 100644 --- a/packages/angular/cli/commands/generate-impl.ts +++ b/packages/angular/cli/commands/generate-impl.ts @@ -1,10 +1,11 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { Arguments, SubCommandDescription } from '../models/interface'; import { SchematicCommand } from '../models/schematic-command'; import { colors } from '../utilities/color'; @@ -15,7 +16,7 @@ export class GenerateCommand extends SchematicCommand { // Allows us to resolve aliases before reporting analytics longSchematicName: string | undefined; - async initialize(options: GenerateCommandSchema & Arguments) { + override async initialize(options: GenerateCommandSchema & Arguments) { // Fill up the schematics property of the command description. const [collectionName, schematicName] = await this.parseSchematicInfo(options); this.collectionName = collectionName; @@ -52,7 +53,7 @@ export class GenerateCommand extends SchematicCommand { } } - this.description.options.forEach(option => { + this.description.options.forEach((option) => { if (option.name == 'schematic') { option.subcommands = subcommands; } @@ -74,7 +75,7 @@ export class GenerateCommand extends SchematicCommand { }); } - async reportAnalytics( + override async reportAnalytics( paths: string[], options: GenerateCommandSchema & Arguments, ): Promise { @@ -89,7 +90,9 @@ export class GenerateCommand extends SchematicCommand { ); } - private async parseSchematicInfo(options: GenerateCommandSchema): Promise<[string, string | undefined]> { + private async parseSchematicInfo( + options: GenerateCommandSchema, + ): Promise<[string, string | undefined]> { let collectionName = await this.getDefaultSchematicCollection(); let schematicName = options.schematic; @@ -101,12 +104,12 @@ export class GenerateCommand extends SchematicCommand { return [collectionName, schematicName]; } - public async printHelp() { + public override async printHelp() { await super.printHelp(); this.logger.info(''); // Find the generate subcommand. - const subcommand = this.description.options.filter(x => x.subcommands)[0]; + const subcommand = this.description.options.filter((x) => x.subcommands)[0]; if (Object.keys((subcommand && subcommand.subcommands) || {}).length == 1) { this.logger.info(`\nTo see help for a schematic run:`); this.logger.info(colors.cyan(` ng generate --help`)); diff --git a/packages/angular/cli/commands/generate.json b/packages/angular/cli/commands/generate.json index 833fe78436b3..53228340abd4 100644 --- a/packages/angular/cli/commands/generate.json +++ b/packages/angular/cli/commands/generate.json @@ -4,7 +4,7 @@ "description": "Generates and/or modifies files based on a schematic.", "$longDescription": "", - "$aliases": [ "g" ], + "$aliases": ["g"], "$scope": "in", "$type": "schematics", "$impl": "./generate-impl#GenerateCommand", @@ -22,8 +22,7 @@ } } }, - "required": [ - ] + "required": [] }, { "$ref": "./definitions.json#/definitions/base" }, { "$ref": "./definitions.json#/definitions/schematic" }, diff --git a/packages/angular/cli/commands/help-impl.ts b/packages/angular/cli/commands/help-impl.ts index 9c30c5e2f608..c7ccc282493d 100644 --- a/packages/angular/cli/commands/help-impl.ts +++ b/packages/angular/cli/commands/help-impl.ts @@ -1,10 +1,11 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { Command } from '../models/command'; import { colors } from '../utilities/color'; import { Schema as HelpCommandSchema } from './help'; diff --git a/packages/angular/cli/commands/help-long.md b/packages/angular/cli/commands/help-long.md index b104a1a6c03e..cc4b790f906e 100644 --- a/packages/angular/cli/commands/help-long.md +++ b/packages/angular/cli/commands/help-long.md @@ -1,7 +1,7 @@ - For help with individual commands, use the `--help` or `-h` option with the command. +For help with individual commands, use the `--help` or `-h` option with the command. - For example, +For example, - ```sh - ng help serve - ``` +```sh +ng help serve +``` diff --git a/packages/angular/cli/commands/help.json b/packages/angular/cli/commands/help.json index 266a6d72aa6d..a6513118d0e4 100644 --- a/packages/angular/cli/commands/help.json +++ b/packages/angular/cli/commands/help.json @@ -9,7 +9,5 @@ "$impl": "./help-impl#HelpCommand", "type": "object", - "allOf": [ - { "$ref": "./definitions.json#/definitions/base" } - ] + "allOf": [{ "$ref": "./definitions.json#/definitions/base" }] } diff --git a/packages/angular/cli/commands/lint-impl.ts b/packages/angular/cli/commands/lint-impl.ts index af2df1aaab64..8067ea26eea4 100644 --- a/packages/angular/cli/commands/lint-impl.ts +++ b/packages/angular/cli/commands/lint-impl.ts @@ -1,10 +1,11 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { ArchitectCommand } from '../models/architect-command'; import { Arguments } from '../models/interface'; import { Schema as LintCommandSchema } from './lint'; @@ -19,11 +20,11 @@ For example: `; export class LintCommand extends ArchitectCommand { - readonly target = 'lint'; - readonly multiTarget = true; - readonly missingTargetError = MissingBuilder; + override readonly target = 'lint'; + override readonly multiTarget = true; + override readonly missingTargetError = MissingBuilder; - async initialize(options: LintCommandSchema & Arguments): Promise { + override async initialize(options: LintCommandSchema & Arguments): Promise { if (!options.help) { return super.initialize(options); } diff --git a/packages/angular/cli/commands/lint-long.md b/packages/angular/cli/commands/lint-long.md index 1588c8438fff..1c912b2489d7 100644 --- a/packages/angular/cli/commands/lint-long.md +++ b/packages/angular/cli/commands/lint-long.md @@ -1,5 +1,5 @@ The command takes an optional project name, as specified in the `projects` section of the `angular.json` workspace configuration file. -When a project name is not supplied, executes the `lint` builder for the default project. +When a project name is not supplied, executes the `lint` builder for all projects. To use the `ng lint` command, use `ng add` to add a package that implements linting capabilities. Adding the package automatically updates your workspace configuration, adding a lint [CLI builder](guide/cli-builder). For example: @@ -17,4 +17,4 @@ For example: } } } - ``` \ No newline at end of file +``` diff --git a/packages/angular/cli/commands/lint.json b/packages/angular/cli/commands/lint.json index e157fe583f57..824632e79f76 100644 --- a/packages/angular/cli/commands/lint.json +++ b/packages/angular/cli/commands/lint.json @@ -24,9 +24,7 @@ "configuration": { "description": "One or more named builder configurations as a comma-separated list as specified in the \"configurations\" section of angular.json.\nThe builder uses the named configurations to run the given target.\nFor more information, see https://angular.io/guide/workspace-config#alternate-build-configurations.", "type": "string", - "aliases": [ - "c" - ] + "aliases": ["c"] } }, "required": [] diff --git a/packages/angular/cli/commands/new-impl.ts b/packages/angular/cli/commands/new-impl.ts index 55a91ea41fcc..b4869de0f043 100644 --- a/packages/angular/cli/commands/new-impl.ts +++ b/packages/angular/cli/commands/new-impl.ts @@ -1,31 +1,29 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { Arguments } from '../models/interface'; import { SchematicCommand } from '../models/schematic-command'; -import { ensureCompatibleNpm } from '../utilities/package-manager'; +import { VERSION } from '../models/version'; import { Schema as NewCommandSchema } from './new'; - export class NewCommand extends SchematicCommand { - public readonly allowMissingWorkspace = true; - schematicName = 'ng-new'; + public override readonly allowMissingWorkspace = true; + override schematicName = 'ng-new'; - async initialize(options: NewCommandSchema & Arguments) { - this.collectionName = options.collection || await this.getDefaultSchematicCollection(); + override async initialize(options: NewCommandSchema & Arguments) { + this.collectionName = options.collection || (await this.getDefaultSchematicCollection()); return super.initialize(options); } public async run(options: NewCommandSchema & Arguments) { // Register the version of the CLI in the registry. - const packageJson = require('../package.json'); - const version = packageJson.version; - + const version = VERSION.full; this._workflow.registry.addSmartDefaultProvider('ng-cli-version', () => version); return this.runSchematic({ @@ -37,5 +35,4 @@ export class NewCommand extends SchematicCommand { force: !!options.force, }); } - } diff --git a/packages/angular/cli/commands/new.json b/packages/angular/cli/commands/new.json index 640104d61524..90efa76056be 100644 --- a/packages/angular/cli/commands/new.json +++ b/packages/angular/cli/commands/new.json @@ -4,7 +4,7 @@ "description": "Creates a new workspace and an initial Angular application.", "$longDescription": "./new.md", - "$aliases": [ "n" ], + "$aliases": ["n"], "$scope": "out", "$type": "schematic", "$impl": "./new-impl#NewCommand", @@ -15,13 +15,13 @@ "properties": { "collection": { "type": "string", - "aliases": [ "c" ], + "aliases": ["c"], "description": "A collection of schematics to use in generating the initial application." }, "verbose": { "type": "boolean", "default": false, - "aliases": [ "v" ], + "aliases": ["v"], "description": "Add more details to output logging." } }, diff --git a/packages/angular/cli/commands/new.md b/packages/angular/cli/commands/new.md index 5d344b5d4312..ca3f14b8d696 100644 --- a/packages/angular/cli/commands/new.md +++ b/packages/angular/cli/commands/new.md @@ -3,14 +3,14 @@ Creates and initializes a new Angular application that is the default project fo Provides interactive prompts for optional configuration, such as adding routing support. All prompts can safely be allowed to default. -* The new workspace folder is given the specified project name, and contains configuration files at the top level. +- The new workspace folder is given the specified project name, and contains configuration files at the top level. -* By default, the files for a new initial application (with the same name as the workspace) are placed in the `src/` subfolder. Corresponding end-to-end tests are placed in the `e2e/` subfolder. +- By default, the files for a new initial application (with the same name as the workspace) are placed in the `src/` subfolder. Corresponding end-to-end tests are placed in the `e2e/` subfolder. -* The new application's configuration appears in the `projects` section of the `angular.json` workspace configuration file, under its project name. +- The new application's configuration appears in the `projects` section of the `angular.json` workspace configuration file, under its project name. -* Subsequent applications that you generate in the workspace reside in the `projects/` subfolder. +- Subsequent applications that you generate in the workspace reside in the `projects/` subfolder. -If you plan to have multiple applications in the workspace, you can create an empty workspace by setting the `--createApplication` option to false. +If you plan to have multiple applications in the workspace, you can create an empty workspace by setting the `--create-application` option to false. You can then use `ng generate application` to create an initial application. -This allows a workspace name different from the initial app name, and ensures that all applications reside in the `/projects` subfolder, matching the structure of the configuration file. \ No newline at end of file +This allows a workspace name different from the initial app name, and ensures that all applications reside in the `/projects` subfolder, matching the structure of the configuration file. diff --git a/packages/angular/cli/commands/run-impl.ts b/packages/angular/cli/commands/run-impl.ts index feefe731fa5b..d9cee91850aa 100644 --- a/packages/angular/cli/commands/run-impl.ts +++ b/packages/angular/cli/commands/run-impl.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license @@ -11,7 +11,7 @@ import { Arguments } from '../models/interface'; import { Schema as RunCommandSchema } from './run'; export class RunCommand extends ArchitectCommand { - public async run(options: ArchitectCommandOptions & Arguments) { + public override async run(options: ArchitectCommandOptions & Arguments) { if (options.target) { return this.runArchitectTarget(options); } else { diff --git a/packages/angular/cli/commands/run-long.md b/packages/angular/cli/commands/run-long.md index a95bbd78a27a..65a307fcd771 100644 --- a/packages/angular/cli/commands/run-long.md +++ b/packages/angular/cli/commands/run-long.md @@ -13,4 +13,4 @@ Execute the command using the following format. ``` ng run project:target[:configuration] -``` \ No newline at end of file +``` diff --git a/packages/angular/cli/commands/run.json b/packages/angular/cli/commands/run.json index cd269a7b34b2..f4e2287dbf35 100644 --- a/packages/angular/cli/commands/run.json +++ b/packages/angular/cli/commands/run.json @@ -24,11 +24,10 @@ "configuration": { "description": "One or more named builder configurations as a comma-separated list as specified in the \"configurations\" section of angular.json.\nThe builder uses the named configurations to run the given target.\nFor more information, see https://angular.io/guide/workspace-config#alternate-build-configurations.", "type": "string", - "aliases": [ "c" ] + "aliases": ["c"] } }, - "required": [ - ] + "required": [] }, { "$ref": "./definitions.json#/definitions/base" diff --git a/packages/angular/cli/commands/serve-impl.ts b/packages/angular/cli/commands/serve-impl.ts index 04b51eee4e4a..9d8dc3bec6eb 100644 --- a/packages/angular/cli/commands/serve-impl.ts +++ b/packages/angular/cli/commands/serve-impl.ts @@ -1,22 +1,23 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { ArchitectCommand, ArchitectCommandOptions } from '../models/architect-command'; import { Arguments } from '../models/interface'; import { Schema as ServeCommandSchema } from './serve'; export class ServeCommand extends ArchitectCommand { - public readonly target = 'serve'; + public override readonly target = 'serve'; - public validate(_options: ArchitectCommandOptions & Arguments) { + public validate() { return true; } - public async run(options: ArchitectCommandOptions & Arguments) { + public override async run(options: ArchitectCommandOptions & Arguments) { return this.runArchitectTarget(options); } } diff --git a/packages/angular/cli/commands/serve.json b/packages/angular/cli/commands/serve.json index 8926362231d1..efc7ba4089ae 100644 --- a/packages/angular/cli/commands/serve.json +++ b/packages/angular/cli/commands/serve.json @@ -4,7 +4,7 @@ "description": "Builds and serves your app, rebuilding on file changes.", "$longDescription": "", - "$aliases": [ "s" ], + "$aliases": ["s"], "$scope": "in", "$type": "architect", "$impl": "./serve-impl#ServeCommand", diff --git a/packages/angular/cli/commands/test-impl.ts b/packages/angular/cli/commands/test-impl.ts index 28f09df4d7b2..511520b0f02b 100644 --- a/packages/angular/cli/commands/test-impl.ts +++ b/packages/angular/cli/commands/test-impl.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license @@ -11,10 +11,10 @@ import { Arguments } from '../models/interface'; import { Schema as TestCommandSchema } from './test'; export class TestCommand extends ArchitectCommand { - public readonly target = 'test'; - public readonly multiTarget = true; + public override readonly target = 'test'; + public override readonly multiTarget = true; - public async run(options: ArchitectCommandOptions & Arguments) { + public override async run(options: ArchitectCommandOptions & Arguments) { return this.runArchitectTarget(options); } } diff --git a/packages/angular/cli/commands/test-long.md b/packages/angular/cli/commands/test-long.md index 64dae312ab47..25086c174e15 100644 --- a/packages/angular/cli/commands/test-long.md +++ b/packages/angular/cli/commands/test-long.md @@ -1,2 +1,2 @@ Takes the name of the project, as specified in the `projects` section of the `angular.json` workspace configuration file. -When a project name is not supplied, it will execute for all projects. \ No newline at end of file +When a project name is not supplied, it will execute for all projects. diff --git a/packages/angular/cli/commands/test.json b/packages/angular/cli/commands/test.json index a9ebb3f8044c..5fb4ce014c48 100644 --- a/packages/angular/cli/commands/test.json +++ b/packages/angular/cli/commands/test.json @@ -4,7 +4,7 @@ "description": "Runs unit tests in a project.", "$longDescription": "./test-long.md", - "$aliases": [ "t" ], + "$aliases": ["t"], "$scope": "in", "$type": "architect", "$impl": "./test-impl#TestCommand", diff --git a/packages/angular/cli/commands/update-impl.ts b/packages/angular/cli/commands/update-impl.ts index f4f1f724254e..ad6285b931e6 100644 --- a/packages/angular/cli/commands/update-impl.ts +++ b/packages/angular/cli/commands/update-impl.ts @@ -1,22 +1,25 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { UnsuccessfulWorkflowExecution } from '@angular-devkit/schematics'; import { NodeWorkflow } from '@angular-devkit/schematics/tools'; import { execSync } from 'child_process'; import * as fs from 'fs'; +import npa from 'npm-package-arg'; import * as path from 'path'; import * as semver from 'semver'; import { PackageManager } from '../lib/config/workspace-schema'; import { Command } from '../models/command'; import { Arguments } from '../models/interface'; import { SchematicEngineHost } from '../models/schematic-engine-host'; +import { VERSION } from '../models/version'; import { colors } from '../utilities/color'; -import { runTempPackageBin } from '../utilities/install-package'; +import { installAllPackages, runTempPackageBin } from '../utilities/install-package'; import { writeErrorToLogFile } from '../utilities/log-file'; import { ensureCompatibleNpm, getPackageManager } from '../utilities/package-manager'; import { @@ -34,17 +37,11 @@ import { } from '../utilities/package-tree'; import { Schema as UpdateCommandSchema } from './update'; -const npa = require('npm-package-arg') as (selector: string) => PackageIdentifier; const pickManifest = require('npm-pick-manifest') as ( metadata: PackageMetadata, selector: string, ) => PackageManifest; -const NG_VERSION_9_POST_MSG = colors.cyan( - '\nYour project has been updated to Angular version 9!\n' + - 'For more info, please see: https://v9.angular.io/guide/updating-to-version-9', -); - const UPDATE_SCHEMATIC_COLLECTION = path.join( __dirname, '../src/commands/update/schematic/collection.json', @@ -60,24 +57,24 @@ const disableVersionCheck = disableVersionCheckEnv !== '0' && disableVersionCheckEnv.toLowerCase() !== 'false'; +const ANGULAR_PACKAGES_REGEXP = /^@(?:angular|nguniversal)\//; + export class UpdateCommand extends Command { - public readonly allowMissingWorkspace = true; + public override readonly allowMissingWorkspace = true; private workflow!: NodeWorkflow; private packageManager = PackageManager.Npm; - async initialize() { + override async initialize(options: UpdateCommandSchema & Arguments) { this.packageManager = await getPackageManager(this.context.root); - this.workflow = new NodeWorkflow( - this.context.root, - { - packageManager: this.packageManager, - // __dirname -> favor @schematics/update from this package - // Otherwise, use packages from the active workspace (migrations) - resolvePaths: [__dirname, this.context.root], - schemaValidation: true, - engineHostCreator: (options) => new SchematicEngineHost(options.resolvePaths), - }, - ); + this.workflow = new NodeWorkflow(this.context.root, { + packageManager: this.packageManager, + packageManagerForce: options.force, + // __dirname -> favor @schematics/update from this package + // Otherwise, use packages from the active workspace (migrations) + resolvePaths: [__dirname, this.context.root], + schemaValidation: true, + engineHostCreator: (options) => new SchematicEngineHost(options.resolvePaths), + }); } private async executeSchematic( @@ -89,7 +86,7 @@ export class UpdateCommand extends Command { let logs: string[] = []; const files = new Set(); - const reporterSubscription = this.workflow.reporter.subscribe(event => { + const reporterSubscription = this.workflow.reporter.subscribe((event) => { // Strip leading slash to prevent confusion. const eventPath = event.path.startsWith('/') ? event.path.substr(1) : event.path; @@ -119,11 +116,11 @@ export class UpdateCommand extends Command { } }); - const lifecycleSubscription = this.workflow.lifeCycle.subscribe(event => { + const lifecycleSubscription = this.workflow.lifeCycle.subscribe((event) => { if (event.kind == 'end' || event.kind == 'post-tasks-start') { if (!error) { // Output the logging queue, no error happened. - logs.forEach(log => this.logger.info(` ${log}`)); + logs.forEach((log) => this.logger.info(` ${log}`)); logs = []; } } @@ -146,12 +143,14 @@ export class UpdateCommand extends Command { return { success: !error, files }; } catch (e) { if (e instanceof UnsuccessfulWorkflowExecution) { - this.logger.error(`${colors.symbols.cross} Migration failed. See above for further details.\n`); + this.logger.error( + `${colors.symbols.cross} Migration failed. See above for further details.\n`, + ); } else { const logPath = writeErrorToLogFile(e); this.logger.fatal( `${colors.symbols.cross} Migration failed: ${e.message}\n` + - ` See "${logPath}" for further details.\n`, + ` See "${logPath}" for further details.\n`, ); } @@ -169,7 +168,7 @@ export class UpdateCommand extends Command { commit?: boolean, ): Promise { const collection = this.workflow.engine.createCollection(collectionPath); - const name = collection.listSchematicNames().find(name => name === migrationName); + const name = collection.listSchematicNames().find((name) => name === migrationName); if (!name) { this.logger.error(`Cannot find migration '${migrationName}' in '${packageName}'.`); @@ -191,10 +190,14 @@ export class UpdateCommand extends Command { private async executeMigrations( packageName: string, collectionPath: string, - range: semver.Range, + from: string, + to: string, commit?: boolean, ): Promise { const collection = this.workflow.engine.createCollection(collectionPath); + const migrationRange = new semver.Range( + '>' + (semver.prerelease(from) ? from.split('-')[0] + '-0' : from) + ' <=' + to.split('-')[0], + ); const migrations = []; for (const name of collection.listSchematicNames()) { @@ -207,7 +210,7 @@ export class UpdateCommand extends Command { continue; } - if (semver.satisfies(description.version, range, { includePrerelease: true })) { + if (semver.satisfies(description.version, migrationRange, { includePrerelease: true })) { migrations.push(description as typeof schematic.description & { version: string }); } } @@ -218,15 +221,13 @@ export class UpdateCommand extends Command { return true; } - this.logger.info( - colors.cyan(`** Executing migrations of package '${packageName}' **\n`), - ); + this.logger.info(colors.cyan(`** Executing migrations of package '${packageName}' **\n`)); return this.executePackageMigrations(migrations, packageName, commit); } private async executePackageMigrations( - migrations: Iterable<{ name: string; description: string; collection: { name: string }}>, + migrations: Iterable<{ name: string; description: string; collection: { name: string } }>, packageName: string, commit = false, ): Promise { @@ -234,8 +235,9 @@ export class UpdateCommand extends Command { const [title, ...description] = migration.description.split('. '); this.logger.info( - colors.cyan(colors.symbols.pointer) + ' ' + - colors.bold(title.endsWith('.') ? title : title + '.'), + colors.cyan(colors.symbols.pointer) + + ' ' + + colors.bold(title.endsWith('.') ? title : title + '.'), ); if (description.length) { @@ -268,23 +270,30 @@ export class UpdateCommand extends Command { return true; } - // tslint:disable-next-line:no-big-function + // eslint-disable-next-line max-lines-per-function async run(options: UpdateCommandSchema & Arguments) { await ensureCompatibleNpm(this.context.root); - // Check if the current installed CLI version is older than the latest version. - if (!disableVersionCheck && await this.checkCLILatestVersion(options.verbose, options.next)) { - this.logger.warn( - `The installed local Angular CLI version is older than the latest ${options.next ? 'pre-release' : 'stable'} version.\n` + - 'Installing a temporary version to perform the update.', + // Check if the current installed CLI version is older than the latest compatible version. + if (!disableVersionCheck) { + const cliVersionToInstall = await this.checkCLIVersion( + options['--'], + options.verbose, + options.next, ); - return runTempPackageBin( - `@angular/cli@${options.next ? 'next' : 'latest'}`, - this.logger, - this.packageManager, - process.argv.slice(2), - ); + if (cliVersionToInstall) { + this.logger.warn( + 'The installed Angular CLI version is outdated.\n' + + `Installing a temporary Angular CLI versioned ${cliVersionToInstall} to perform the update.`, + ); + + return runTempPackageBin( + `@angular/cli@${cliVersionToInstall}`, + this.packageManager, + process.argv.slice(2), + ); + } } const logVerbose = (message: string) => { @@ -294,9 +303,10 @@ export class UpdateCommand extends Command { }; if (options.all) { - const updateCmd = this.packageManager === PackageManager.Yarn - ? `'yarn upgrade-interactive' or 'yarn upgrade'` - : `'${this.packageManager} update'`; + const updateCmd = + this.packageManager === PackageManager.Yarn + ? `'yarn upgrade-interactive' or 'yarn upgrade'` + : `'${this.packageManager} update'`; this.logger.warn(` '--all' functionality has been removed as updating multiple packages at once is not recommended. @@ -319,7 +329,7 @@ export class UpdateCommand extends Command { return 1; } - if (packages.some(v => v.name === packageIdentifier.name)) { + if (packages.some((v) => v.name === packageIdentifier.name)) { this.logger.error(`Duplicate package '${packageIdentifier.name}' specified.`); return 1; @@ -334,7 +344,7 @@ export class UpdateCommand extends Command { packageIdentifier.fetchSpec = 'next'; } - packages.push(packageIdentifier); + packages.push(packageIdentifier as PackageIdentifier); } catch (e) { this.logger.error(e.message); @@ -386,7 +396,9 @@ export class UpdateCommand extends Command { if (options.migrateOnly) { if (!options.from && typeof options.migrateOnly !== 'string') { - this.logger.error('"from" option is required when using the "migrate-only" option without a migration name.'); + this.logger.error( + '"from" option is required when using the "migrate-only" option without a migration name.', + ); return 1; } else if (packages.length !== 1) { @@ -449,8 +461,7 @@ export class UpdateCommand extends Command { if (migrations.startsWith('../')) { this.logger.error( - 'Package contains an invalid migrations field. ' + - 'Paths outside the package root are not permitted.', + 'Package contains an invalid migrations field. Paths outside the package root are not permitted.', ); return 1; @@ -476,9 +487,9 @@ export class UpdateCommand extends Command { } } - let success = false; + let result: boolean; if (typeof options.migrateOnly == 'string') { - success = await this.executeMigration( + result = await this.executeMigration( packageName, migrations, options.migrateOnly, @@ -492,32 +503,16 @@ export class UpdateCommand extends Command { return 1; } - const migrationRange = new semver.Range( - '>' + from + ' <=' + (options.to || packageNode.version), - ); - - success = await this.executeMigrations( + result = await this.executeMigrations( packageName, migrations, - migrationRange, + from, + options.to || packageNode.version, options.createCommits, ); } - if (success) { - if ( - packageName === '@angular/core' - && options.from - && +options.from.split('.')[0] < 9 - && (options.to || packageNode.version).split('.')[0] === '9' - ) { - this.logger.info(NG_VERSION_9_POST_MSG); - } - - return 0; - } - - return 1; + return result ? 0 : 1; } const requests: { @@ -607,33 +602,40 @@ export class UpdateCommand extends Command { return 1; } - if (node.package?.name === '@angular/cli') { - // Migrations for non LTS versions of Angular CLI are no longer included in @schematics/angular v12. + if (manifest.version === node.package?.version) { + this.logger.info(`Package '${packageName}' is already up to date.`); + continue; + } + + if (node.package && ANGULAR_PACKAGES_REGEXP.test(node.package.name)) { + const { name, version } = node.package; const toBeInstalledMajorVersion = +manifest.version.split('.')[0]; - const currentMajorVersion = +node.package.version.split('.')[0]; - if (currentMajorVersion < 9 && toBeInstalledMajorVersion >= 12) { - const updateVersions: Record = { - 1: 6, - 6: 7, - 7: 8, - 8: 9, - }; - - const updateTo = updateVersions[currentMajorVersion]; - this.logger.error('Updating multiple major versions at once is not recommended. ' + - `Run 'ng update @angular/cli@${updateTo}' in your workspace directory ` + - `to update to latest '${updateTo}.x' version of '@angular/cli'.\n\n` + - 'For more information about the update process, see https://update.angular.io/.'); + const currentMajorVersion = +version.split('.')[0]; + + if (toBeInstalledMajorVersion - currentMajorVersion > 1) { + // Only allow updating a single version at a time. + if (currentMajorVersion < 6) { + // Before version 6, the major versions were not always sequential. + // Example @angular/core skipped version 3, @angular/cli skipped versions 2-5. + this.logger.error( + `Updating multiple major versions of '${name}' at once is not supported. Please migrate each major version individually.\n` + + `For more information about the update process, see https://update.angular.io/.`, + ); + } else { + const nextMajorVersionFromCurrent = currentMajorVersion + 1; + + this.logger.error( + `Updating multiple major versions of '${name}' at once is not supported. Please migrate each major version individually.\n` + + `Run 'ng update ${name}@${nextMajorVersionFromCurrent}' in your workspace directory ` + + `to update to latest '${nextMajorVersionFromCurrent}.x' version of '${name}'.\n\n` + + `For more information about the update process, see https://update.angular.io/?v=${currentMajorVersion}.0-${nextMajorVersionFromCurrent}.0`, + ); + } return 1; } } - if (manifest.version === node.package?.version) { - this.logger.info(`Package '${packageName}' is already up to date.`); - continue; - } - packagesToUpdate.push(requestIdentifier.toString()); } @@ -647,19 +649,39 @@ export class UpdateCommand extends Command { next: !!options.next, packageManager: this.packageManager, packages: packagesToUpdate, - migrateExternal: true, }); + if (success) { + try { + // Remove existing node modules directory to provide a stronger guarantee that packages + // will be hoisted into the correct locations. + await fs.promises.rmdir(path.join(this.context.root, 'node_modules'), { + recursive: true, + maxRetries: 3, + }); + } catch {} + + const result = await installAllPackages( + this.packageManager, + options.force ? ['--force'] : [], + this.context.root, + ); + if (result !== 0) { + return result; + } + } + if (success && options.createCommits) { const committed = this.commit( - `Angular CLI update for packages - ${packagesToUpdate.join(', ')}`); + `Angular CLI update for packages - ${packagesToUpdate.join(', ')}`, + ); if (!committed) { return 1; } } // This is a temporary workaround to allow data to be passed back from the update schematic - // tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any const migrations = (global as any).externalMigrations as { package: string; collection: string; @@ -733,7 +755,8 @@ export class UpdateCommand extends Command { const result = await this.executeMigrations( migration.package, migrations, - new semver.Range('>' + migration.from + ' <=' + migration.to), + migration.from, + migration.to, options.createCommits, ); @@ -741,10 +764,6 @@ export class UpdateCommand extends Command { return 0; } } - - if (migrations.some(m => m.package === '@angular/core' && m.to.split('.')[0] === '9' && +m.from.split('.')[0] < 9)) { - this.logger.info(NG_VERSION_9_POST_MSG); - } } return success ? 0 : 1; @@ -774,8 +793,7 @@ export class UpdateCommand extends Command { try { createCommit(message); } catch (err) { - this.logger.error( - `Failed to commit update (${message}):\n${err.stderr}`); + this.logger.error(`Failed to commit update (${message}):\n${err.stderr}`); return false; } @@ -784,8 +802,7 @@ export class UpdateCommand extends Command { const hash = findCurrentGitSha(); const shortMessage = message.split('\n')[0]; if (hash) { - this.logger.info(` Committed migration step (${getShortHash(hash)}): ${ - shortMessage}.`); + this.logger.info(` Committed migration step (${getShortHash(hash)}): ${shortMessage}.`); } else { // Commit was successful, but reading the hash was not. Something weird happened, // but nothing that would stop the update. Just log the weirdness and continue. @@ -798,7 +815,10 @@ export class UpdateCommand extends Command { private checkCleanGit(): boolean { try { - const topLevel = execSync('git rev-parse --show-toplevel', { encoding: 'utf8', stdio: 'pipe' }); + const topLevel = execSync('git rev-parse --show-toplevel', { + encoding: 'utf8', + stdio: 'pipe', + }); const result = execSync('git status --porcelain', { encoding: 'utf8', stdio: 'pipe' }); if (result.trim().length === 0) { return true; @@ -821,14 +841,16 @@ export class UpdateCommand extends Command { } /** - * Checks if the current installed CLI version is older than the latest version. - * @returns `true` when the installed version is older. - */ - private async checkCLILatestVersion(verbose = false, next = false): Promise { - const { version: installedCLIVersion } = require('../package.json'); - - const LatestCLIManifest = await fetchPackageManifest( - `@angular/cli@${next ? 'next' : 'latest'}`, + * Checks if the current installed CLI version is older or newer than a compatible version. + * @returns the version to install or null when there is no update to install. + */ + private async checkCLIVersion( + packagesToUpdate: string[] | undefined, + verbose = false, + next = false, + ): Promise { + const { version } = await fetchPackageManifest( + `@angular/cli@${this.getCLIUpdateRunnerVersion(packagesToUpdate, next)}`, this.logger, { verbose, @@ -836,7 +858,38 @@ export class UpdateCommand extends Command { }, ); - return semver.lt(installedCLIVersion, LatestCLIManifest.version); + return VERSION.full === version ? null : version; + } + + private getCLIUpdateRunnerVersion( + packagesToUpdate: string[] | undefined, + next: boolean, + ): string | number { + if (next) { + return 'next'; + } + + const updatingAngularPackage = packagesToUpdate?.find((r) => ANGULAR_PACKAGES_REGEXP.test(r)); + if (updatingAngularPackage) { + // If we are updating any Angular package we can update the CLI to the target version because + // migrations for @angular/core@13 can be executed using Angular/cli@13. + // This is same behaviour as `npx @angular/cli@13 update @angular/core@13`. + + // `@angular/cli@13` -> ['', 'angular/cli', '13'] + // `@angular/cli` -> ['', 'angular/cli'] + const tempVersion = coerceVersionNumber(updatingAngularPackage.split('@')[2]); + + return semver.parse(tempVersion)?.major ?? 'latest'; + } + + // When not updating an Angular package we cannot determine which schematic runtime the migration should to be executed in. + // Typically, we can assume that the `@angular/cli` was updated previously. + // Example: Angular official packages are typically updated prior to NGRX etc... + // Therefore, we only update to the latest patch version of the installed major version of the Angular CLI. + + // This is important because we might end up in a scenario where locally Angular v12 is installed, updating NGRX from 11 to 12. + // We end up using Angular ClI v13 to run the migrations if we run the migrations using the CLI installed major version + 1 logic. + return VERSION.major; } } @@ -869,7 +922,7 @@ function createCommit(message: string) { */ function findCurrentGitSha(): string | null { try { - const hash = execSync('git rev-parse HEAD', {encoding: 'utf8', stdio: 'pipe'}); + const hash = execSync('git rev-parse HEAD', { encoding: 'utf8', stdio: 'pipe' }); return hash.trim(); } catch { diff --git a/packages/angular/cli/commands/update.json b/packages/angular/cli/commands/update.json index c2eace203830..7de5a1935146 100644 --- a/packages/angular/cli/commands/update.json +++ b/packages/angular/cli/commands/update.json @@ -28,7 +28,7 @@ } }, "force": { - "description": "If false, will error out if installed packages are incompatible with the update.", + "description": "Ignore peer dependency version mismatches. Passes the `--force` flag to the package manager when installing packages.", "default": false, "type": "boolean" }, diff --git a/packages/angular/cli/commands/version-impl.ts b/packages/angular/cli/commands/version-impl.ts index 1619eccee6d8..4503cfdc84cd 100644 --- a/packages/angular/cli/commands/version-impl.ts +++ b/packages/angular/cli/commands/version-impl.ts @@ -1,15 +1,23 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + +import { execSync } from 'child_process'; import * as path from 'path'; import { Command } from '../models/command'; import { colors } from '../utilities/color'; +import { getPackageManager } from '../utilities/package-manager'; import { Schema as VersionCommandSchema } from './version'; +/** + * Major versions of Node.js that are officially supported by Angular. + */ +const SUPPORTED_NODE_MAJORS = [12, 14]; + interface PartialPackageInfo { name: string; version: string; @@ -27,6 +35,9 @@ export class VersionCommand extends Command { workspacePackage = require(path.resolve(this.context.root, 'package.json')); } catch {} + const [nodeMajor] = process.versions.node.split('.').map((part) => Number(part)); + const unsupportedNodeVersion = !SUPPORTED_NODE_MAJORS.includes(nodeMajor); + const patterns = [ /^@angular\/.*/, /^@angular-devkit\/.*/, @@ -48,19 +59,16 @@ export class VersionCommand extends Command { ]; const versions = packageNames - .filter(x => patterns.some(p => p.test(x))) - .reduce( - (acc, name) => { - if (name in acc) { - return acc; - } + .filter((x) => patterns.some((p) => p.test(x))) + .reduce((acc, name) => { + if (name in acc) { + return acc; + } - acc[name] = this.getVersion(name); + acc[name] = this.getVersion(name); - return acc; - }, - {} as { [module: string]: string }, - ); + return acc; + }, {} as { [module: string]: string }); const ngCliVersion = cliPackage.version; let angularCoreVersion = ''; @@ -97,14 +105,15 @@ export class VersionCommand extends Command { |___/ ` .split('\n') - .map(x => colors.red(x)) + .map((x) => colors.red(x)) .join('\n'); this.logger.info(asciiArt); this.logger.info( ` Angular CLI: ${ngCliVersion} - Node: ${process.versions.node} + Node: ${process.versions.node}${unsupportedNodeVersion ? ' (Unsupported)' : ''} + Package Manager: ${await this.getPackageManager()} OS: ${process.platform} ${process.arch} Angular: ${angularCoreVersion} @@ -128,11 +137,17 @@ export class VersionCommand extends Command { Package${namePad.slice(7)}Version -------${namePad.replace(/ /g, '-')}------------------ ${Object.keys(versions) - .map(module => `${module}${namePad.slice(module.length)}${versions[module]}`) + .map((module) => `${module}${namePad.slice(module.length)}${versions[module]}`) .sort() .join('\n')} `.replace(/^ {6}/gm, ''), ); + + if (unsupportedNodeVersion) { + this.logger.warn( + `Warning: The current version of Node (${process.versions.node}) is not supported by Angular.`, + ); + } } private getVersion(moduleName: string): string { @@ -141,7 +156,7 @@ export class VersionCommand extends Command { // Try to find the package in the workspace try { - packagePath = require.resolve(`${moduleName}/package.json`, { paths: [ this.context.root ]}); + packagePath = require.resolve(`${moduleName}/package.json`, { paths: [this.context.root] }); } catch {} // If not found, try to find within the CLI @@ -163,4 +178,24 @@ export class VersionCommand extends Command { return version || ''; } + + private async getPackageManager(): Promise { + try { + const manager = await getPackageManager(this.context.root); + const version = execSync(`${manager} --version`, { + encoding: 'utf8', + stdio: ['ignore', 'pipe', 'ignore'], + env: { + ...process.env, + // NPM updater notifier will prevents the child process from closing until it timeout after 3 minutes. + NO_UPDATE_NOTIFIER: '1', + NPM_CONFIG_UPDATE_NOTIFIER: 'false', + }, + }).trim(); + + return `${manager} ${version}`; + } catch { + return ''; + } + } } diff --git a/packages/angular/cli/commands/version.json b/packages/angular/cli/commands/version.json index 657cb14dce71..8f4c3ff1fdd1 100644 --- a/packages/angular/cli/commands/version.json +++ b/packages/angular/cli/commands/version.json @@ -4,12 +4,10 @@ "description": "Outputs Angular CLI version.", "$longDescription": "", - "$aliases": [ "v" ], + "$aliases": ["v"], "$scope": "all", "$impl": "./version-impl#VersionCommand", "type": "object", - "allOf": [ - { "$ref": "./definitions.json#/definitions/base" } - ] + "allOf": [{ "$ref": "./definitions.json#/definitions/base" }] } diff --git a/packages/angular/cli/lib/cli/index.ts b/packages/angular/cli/lib/cli/index.ts index 398a4734a572..679757fb6580 100644 --- a/packages/angular/cli/lib/cli/index.ts +++ b/packages/angular/cli/lib/cli/index.ts @@ -1,10 +1,11 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { createConsoleLogger } from '@angular-devkit/core/node'; import { format } from 'util'; import { runCommand } from '../../models/command-runner'; @@ -16,41 +17,38 @@ import { findWorkspaceFile } from '../../utilities/project'; export { VERSION, Version } from '../../models/version'; const debugEnv = process.env['NG_DEBUG']; -const isDebug = - debugEnv !== undefined && - debugEnv !== '0' && - debugEnv.toLowerCase() !== 'false'; +const isDebug = debugEnv !== undefined && debugEnv !== '0' && debugEnv.toLowerCase() !== 'false'; -// tslint:disable: no-console -export default async function(options: { testing?: boolean; cliArgs: string[] }) { +/* eslint-disable no-console */ +export default async function (options: { testing?: boolean; cliArgs: string[] }) { // This node version check ensures that the requirements of the project instance of the CLI are met - const version = process.versions.node.split('.').map(part => Number(part)); - if (version[0] < 10 || version[0] === 11 || (version[0] === 10 && version[1] < 13)) { + const version = process.versions.node.split('.').map((part) => Number(part)); + if (version[0] < 12 || (version[0] === 12 && version[1] < 14)) { process.stderr.write( `Node.js version ${process.version} detected.\n` + - 'The Angular CLI requires a minimum Node.js version of either v10.13 or v12.0.\n\n' + - 'Please update your Node.js version or visit https://nodejs.org/ for additional instructions.\n', + 'The Angular CLI requires a minimum v12.14.\n\n' + + 'Please update your Node.js version or visit https://nodejs.org/ for additional instructions.\n', ); return 3; } const logger = createConsoleLogger(isDebug, process.stdout, process.stderr, { - info: s => (colors.enabled ? s : removeColor(s)), - debug: s => (colors.enabled ? s : removeColor(s)), - warn: s => (colors.enabled ? colors.bold.yellow(s) : removeColor(s)), - error: s => (colors.enabled ? colors.bold.red(s) : removeColor(s)), - fatal: s => (colors.enabled ? colors.bold.red(s) : removeColor(s)), + info: (s) => (colors.enabled ? s : removeColor(s)), + debug: (s) => (colors.enabled ? s : removeColor(s)), + warn: (s) => (colors.enabled ? colors.bold.yellow(s) : removeColor(s)), + error: (s) => (colors.enabled ? colors.bold.red(s) : removeColor(s)), + fatal: (s) => (colors.enabled ? colors.bold.red(s) : removeColor(s)), }); // Redirect console to logger - console.info = console.log = function(...args) { + console.info = console.log = function (...args) { logger.info(format(...args)); }; - console.warn = function(...args) { + console.warn = function (...args) { logger.warn(format(...args)); }; - console.error = function(...args) { + console.error = function (...args) { logger.error(format(...args)); }; @@ -113,7 +111,7 @@ export default async function(options: { testing?: boolean; cliArgs: string[] }) } if (options.testing) { - // tslint:disable-next-line: no-debugger + // eslint-disable-next-line no-debugger debugger; throw err; } diff --git a/packages/angular/cli/lib/config/workspace-schema.json b/packages/angular/cli/lib/config/workspace-schema.json index 43bd1e07ddb4..58835571837b 100644 --- a/packages/angular/cli/lib/config/workspace-schema.json +++ b/packages/angular/cli/lib/config/workspace-schema.json @@ -27,7 +27,7 @@ "projects": { "type": "object", "patternProperties": { - "^(?:@[a-zA-Z0-9_-]+\/)?[a-zA-Z0-9_-]+$": { + "^(?:@[a-zA-Z0-9_-]+/)?[a-zA-Z0-9_-]+$": { "$ref": "#/definitions/project" } }, @@ -35,9 +35,7 @@ } }, "additionalProperties": false, - "required": [ - "version" - ], + "required": ["version"], "definitions": { "cliOptions": { "type": "object", @@ -49,12 +47,7 @@ "packageManager": { "description": "Specify which package manager tool to use.", "type": "string", - "enum": [ - "npm", - "cnpm", - "yarn", - "pnpm" - ] + "enum": ["npm", "cnpm", "yarn", "pnpm"] }, "warnings": { "description": "Control CLI specific console warnings", @@ -67,10 +60,7 @@ } }, "analytics": { - "type": [ - "boolean", - "string" - ], + "type": ["boolean", "string"], "description": "Share anonymous usage data with the Angular Team at Google." }, "analyticsSharing": { @@ -79,11 +69,12 @@ "tracking": { "description": "Analytics sharing info tracking ID.", "type": "string", - "pattern": "^GA-\\d+-\\d+$" + "pattern": "^(GA|UA)?-\\d+-\\d+$" }, "uuid": { "description": "Analytics sharing info universally unique identifier.", - "type": "string" + "type": "string", + "format": "uuid" } } } @@ -173,10 +164,7 @@ "projectType": { "type": "string", "description": "Project type.", - "enum": [ - "application", - "library" - ] + "enum": ["application", "library"] }, "architect": { "type": "object", @@ -191,37 +179,23 @@ } } }, - "required": [ - "root", - "projectType" - ], + "required": ["root", "projectType"], "anyOf": [ { - "required": [ - "architect" - ], + "required": ["architect"], "not": { - "required": [ - "targets" - ] + "required": ["targets"] } }, { - "required": [ - "targets" - ], + "required": ["targets"], "not": { - "required": [ - "architect" - ] + "required": ["architect"] } }, { "not": { - "required": [ - "targets", - "architect" - ] + "required": ["targets", "architect"] } } ], @@ -351,12 +325,12 @@ } } }, - "required": [ - "builder" - ] + "additionalProperties": false, + "required": ["builder"] }, { "type": "object", + "additionalProperties": false, "properties": { "builder": { "const": "@angular-devkit/build-angular:app-shell" @@ -378,6 +352,7 @@ }, { "type": "object", + "additionalProperties": false, "properties": { "builder": { "const": "@angular-devkit/build-angular:browser" @@ -399,6 +374,7 @@ }, { "type": "object", + "additionalProperties": false, "properties": { "builder": { "const": "@angular-devkit/build-angular:dev-server" @@ -420,6 +396,7 @@ }, { "type": "object", + "additionalProperties": false, "properties": { "builder": { "const": "@angular-devkit/build-angular:extract-i18n" @@ -441,6 +418,7 @@ }, { "type": "object", + "additionalProperties": false, "properties": { "builder": { "const": "@angular-devkit/build-angular:karma" @@ -462,6 +440,7 @@ }, { "type": "object", + "additionalProperties": false, "properties": { "builder": { "const": "@angular-devkit/build-angular:protractor" @@ -483,6 +462,7 @@ }, { "type": "object", + "additionalProperties": false, "properties": { "builder": { "const": "@angular-devkit/build-angular:server" @@ -504,6 +484,7 @@ }, { "type": "object", + "additionalProperties": false, "properties": { "builder": { "const": "@angular-devkit/build-angular:tslint" @@ -525,10 +506,15 @@ }, { "type": "object", + "additionalProperties": false, "properties": { "builder": { "const": "@angular-devkit/build-angular:ng-packagr" }, + "defaultConfiguration": { + "type": "string", + "description": "A default named configuration to use when a target configuration is not provided." + }, "options": { "$ref": "../../../../angular_devkit/build_angular/src/ng-packagr/schema.json" }, @@ -561,9 +547,7 @@ "$ref": "#/definitions/schematicOptions" } }, - "required": [ - "version" - ] + "required": ["version"] } } -} \ No newline at end of file +} diff --git a/packages/angular/cli/lib/init.ts b/packages/angular/cli/lib/init.ts index b817d8342145..cf18b8bcd77b 100644 --- a/packages/angular/cli/lib/init.ts +++ b/packages/angular/cli/lib/init.ts @@ -1,56 +1,20 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import 'symbol-observable'; // symbol polyfill must go first -// tslint:disable-next-line:ordered-imports import-groups -import * as fs from 'fs'; +import { promises as fs } from 'fs'; import * as path from 'path'; import { SemVer } from 'semver'; -import { Duplex } from 'stream'; +import { VERSION } from '../models/version'; import { colors } from '../utilities/color'; import { isWarningEnabled } from '../utilities/config'; -// Check if we need to profile this CLI run. -if (process.env['NG_CLI_PROFILING']) { - let profiler: { - startProfiling: (name?: string, recsamples?: boolean) => void; - stopProfiling: (name?: string) => unknown; - }; - try { - profiler = require('v8-profiler-node8'); // tslint:disable-line:no-implicit-dependencies - } catch (err) { - throw new Error( - `Could not require 'v8-profiler-node8'. You must install it separetely with ` + - `'npm install v8-profiler-node8 --no-save'.\n\nOriginal error:\n\n${err}`, - ); - } - - profiler.startProfiling(); - - const exitHandler = (options: { cleanup?: boolean; exit?: boolean }) => { - if (options.cleanup) { - const cpuProfile = profiler.stopProfiling(); - fs.writeFileSync( - path.resolve(process.cwd(), process.env.NG_CLI_PROFILING || '') + '.cpuprofile', - JSON.stringify(cpuProfile), - ); - } - - if (options.exit) { - process.exit(); - } - }; - - process.on('exit', () => exitHandler({ cleanup: true })); - process.on('SIGINT', () => exitHandler({ exit: true })); - process.on('uncaughtException', () => exitHandler({ exit: true })); -} - (async () => { /** * Disable Browserslist old data warning as otherwise with every release we'd need to update this dependency @@ -81,19 +45,20 @@ if (process.env['NG_CLI_PROFILING']) { const projectLocalCli = require.resolve('@angular/cli', { paths: [process.cwd()] }); cli = await import(projectLocalCli); - const globalVersion = new SemVer(require('../package.json').version); + const globalVersion = new SemVer(VERSION.full); // Older versions might not have the VERSION export let localVersion = cli.VERSION?.full; if (!localVersion) { try { - localVersion = require(path.join(path.dirname(projectLocalCli), '../../package.json')) - .version; - } catch (error) { - // tslint:disable-next-line no-console - console.error( - 'Version mismatch check skipped. Unable to retrieve local version: ' + error, + const localPackageJson = await fs.readFile( + path.join(path.dirname(projectLocalCli), '../../package.json'), + 'utf-8', ); + localVersion = (JSON.parse(localPackageJson) as { version: string }).version; + } catch (error) { + // eslint-disable-next-line no-console + console.error('Version mismatch check skipped. Unable to retrieve local version: ' + error); } } @@ -101,14 +66,18 @@ if (process.env['NG_CLI_PROFILING']) { try { isGlobalGreater = !!localVersion && globalVersion.compare(localVersion) > 0; } catch (error) { - // tslint:disable-next-line no-console + // eslint-disable-next-line no-console console.error('Version mismatch check skipped. Unable to compare local version: ' + error); } if (isGlobalGreater) { // If using the update command and the global version is greater, use the newer update command // This allows improvements in update to be used in older versions that do not have bootstrapping - if (process.argv[2] === 'update') { + if ( + process.argv[2] === 'update' && + cli.VERSION && + cli.VERSION.major - globalVersion.major <= 1 + ) { cli = await import('./cli'); } else if (await isWarningEnabled('versionMismatch')) { // Otherwise, use local version and warn if global is newer than local @@ -117,7 +86,7 @@ if (process.env['NG_CLI_PROFILING']) { `version (${localVersion}). The local Angular CLI version is used.\n\n` + 'To disable this warning use "ng config -g cli.warnings.versionMismatch false".'; - // tslint:disable-next-line no-console + // eslint-disable-next-line no-console console.error(colors.yellow(warning)); } } @@ -134,17 +103,19 @@ if (process.env['NG_CLI_PROFILING']) { } return cli; -})().then(cli => { - return cli({ - cliArgs: process.argv.slice(2), - inputStream: process.stdin, - outputStream: process.stdout, +})() + .then((cli) => { + return cli({ + cliArgs: process.argv.slice(2), + inputStream: process.stdin, + outputStream: process.stdout, + }); + }) + .then((exitCode: number) => { + process.exit(exitCode); + }) + .catch((err: Error) => { + // eslint-disable-next-line no-console + console.error('Unknown error: ' + err.toString()); + process.exit(127); }); -}).then((exitCode: number) => { - process.exit(exitCode); -}) -.catch((err: Error) => { - // tslint:disable-next-line no-console - console.error('Unknown error: ' + err.toString()); - process.exit(127); -}); diff --git a/packages/angular/cli/models/analytics-collector.ts b/packages/angular/cli/models/analytics-collector.ts index 2d9d7f204aff..6754d5037059 100644 --- a/packages/angular/cli/models/analytics-collector.ts +++ b/packages/angular/cli/models/analytics-collector.ts @@ -1,14 +1,14 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license - * */ + import { analytics } from '@angular-devkit/core'; import { execSync } from 'child_process'; -import * as debug from 'debug'; +import debug from 'debug'; import * as https from 'https'; import * as os from 'os'; import * as querystring from 'querystring'; @@ -85,10 +85,7 @@ export class AnalyticsCollector implements analytics.Analytics { private readonly parameters: Record = {}; private readonly analyticsLogDebug = debug('ng:analytics:log'); - constructor( - trackingId: string, - userId: string, - ) { + constructor(trackingId: string, userId: string) { // API Version this.parameters['v'] = '1'; // User ID @@ -113,8 +110,12 @@ export class AnalyticsCollector implements analytics.Analytics { this.parameters['cd' + analytics.NgCliAnalyticsDimensions.CpuCount] = os.cpus().length; // Get the first CPU's speed. It's very rare to have multiple CPUs of different speed (in most // non-ARM configurations anyway), so that's all we care about. - this.parameters['cd' + analytics.NgCliAnalyticsDimensions.CpuSpeed] = Math.floor(os.cpus()[0].speed); - this.parameters['cd' + analytics.NgCliAnalyticsDimensions.RamInGigabytes] = Math.round(os.totalmem() / (1024 * 1024 * 1024)); + this.parameters['cd' + analytics.NgCliAnalyticsDimensions.CpuSpeed] = Math.floor( + os.cpus()[0].speed, + ); + this.parameters['cd' + analytics.NgCliAnalyticsDimensions.RamInGigabytes] = Math.round( + os.totalmem() / (1024 * 1024 * 1024), + ); this.parameters['cd' + analytics.NgCliAnalyticsDimensions.NodeVersion] = nodeVersion; } @@ -128,7 +129,12 @@ export class AnalyticsCollector implements analytics.Analytics { this.addToQueue('pageview', { dp, dh, dt, metrics, dimensions }); } - timing(utc: string, utv: string, utt: string | number, options: analytics.TimingOptions = {}): void { + timing( + utc: string, + utv: string, + utt: string | number, + options: analytics.TimingOptions = {}, + ): void { const { label: utl, metrics, dimensions } = options; this.addToQueue('timing', { utc, utv, utt, utl, metrics, dimensions }); } @@ -163,7 +169,10 @@ export class AnalyticsCollector implements analytics.Analytics { private addToQueue(eventType: 'pageview', parameters: PageviewParameters): void; private addToQueue(eventType: 'timing', parameters: TimingParameters): void; private addToQueue(eventType: 'screenview', parameters: ScreenviewParameters): void; - private addToQueue(eventType: 'event' | 'pageview' | 'timing' | 'screenview', parameters: BaseParameters): void { + private addToQueue( + eventType: 'event' | 'pageview' | 'timing' | 'screenview', + parameters: BaseParameters, + ): void { const { metrics, dimensions, ...restParameters } = parameters; const data = { ...this.parameters, @@ -180,21 +189,26 @@ export class AnalyticsCollector implements analytics.Analytics { this.analyticsLogDebug('send event: %j', data); return new Promise((resolve, reject) => { - const request = https.request({ - host: 'www.google-analytics.com', - method: 'POST', - path: data.length > 1 ? '/batch' : '/collect', - }, response => { - if (response.statusCode !== 200) { - reject(new Error(`Analytics reporting failed with status code: ${response.statusCode}.`)); - - return; - } - }); + const request = https.request( + { + host: 'www.google-analytics.com', + method: 'POST', + path: data.length > 1 ? '/batch' : '/collect', + }, + (response) => { + if (response.statusCode !== 200) { + reject( + new Error(`Analytics reporting failed with status code: ${response.statusCode}.`), + ); + + return; + } + }, + ); request.on('error', reject); - const queryParameters = data.map(p => querystring.stringify(p)).join('\n'); + const queryParameters = data.map((p) => querystring.stringify(p)).join('\n'); request.write(queryParameters); request.end(resolve); }); @@ -204,12 +218,14 @@ export class AnalyticsCollector implements analytics.Analytics { * Creates the dimension and metrics variables to add to the queue. * @private */ - private customVariables(options: analytics.CustomDimensionsAndMetricsOptions): Record { + private customVariables( + options: analytics.CustomDimensionsAndMetricsOptions, + ): Record { const additionals: Record = {}; const { dimensions, metrics } = options; - dimensions?.forEach((v, i) => additionals[`cd${i}`] = v); - metrics?.forEach((v, i) => additionals[`cm${i}`] = v); + dimensions?.forEach((v, i) => (additionals[`cd${i}`] = v)); + metrics?.forEach((v, i) => (additionals[`cm${i}`] = v)); return additionals; } @@ -282,7 +298,6 @@ function _buildUserAgentString() { } } - /** * Get a language code. * @private @@ -311,7 +326,7 @@ function _getWindowsLanguageCode(): string | undefined { // This is true on Windows XP, 7, 8 and 10 AFAIK. Would return empty string or fail if it // doesn't work. return execSync('wmic.exe os get locale').toString().trim(); - } catch { } + } catch {} return undefined; } diff --git a/packages/angular/cli/models/analytics.ts b/packages/angular/cli/models/analytics.ts index 5883499f5ae2..1171e801dc49 100644 --- a/packages/angular/cli/models/analytics.ts +++ b/packages/angular/cli/models/analytics.ts @@ -1,20 +1,22 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { json, tags } from '@angular-devkit/core'; -import * as debug from 'debug'; +import debug from 'debug'; import * as inquirer from 'inquirer'; import { v4 as uuidV4 } from 'uuid'; +import { VERSION } from '../models/version'; import { colors } from '../utilities/color'; import { getWorkspace, getWorkspaceRaw } from '../utilities/config'; import { isTTY } from '../utilities/tty'; import { AnalyticsCollector } from './analytics-collector'; -// tslint:disable: no-console +/* eslint-disable no-console */ const analyticsDebug = debug('ng:analytics'); // Generate analytics, including settings and users. let _defaultAngularCliPropertyCache: string; @@ -26,7 +28,7 @@ export const AnalyticsProperties = { return _defaultAngularCliPropertyCache; } - const v = require('../package.json').version; + const v = VERSION.full; // The logic is if it's a full version then we should use the prod GA property. if (/^\d+\.\d+\.\d+$/.test(v) && v !== '0.0.0') { @@ -50,7 +52,7 @@ export const analyticsPackageSafelist = [ ]; export function isPackageNameSafeForAnalytics(name: string): boolean { - return analyticsPackageSafelist.some(pattern => { + return analyticsPackageSafelist.some((pattern) => { if (typeof pattern == 'string') { return pattern === name; } else { @@ -85,7 +87,6 @@ export function setAnalyticsConfig(level: 'global' | 'local', value: string | bo config.save(); analyticsDebug('done'); - } /** @@ -173,7 +174,7 @@ export async function promptProjectAnalytics(force = false): Promise { if (answers.analytics) { console.log(''); console.log(tags.stripIndent` - Thank you for sharing anonymous usage data. Would you change your mind, the following + Thank you for sharing anonymous usage data. Should you change your mind, the following command will disable this feature entirely: ${colors.yellow('ng analytics project off')} @@ -206,7 +207,7 @@ export async function hasGlobalAnalyticsConfiguration(): Promise { if (analyticsConfig !== null && analyticsConfig !== undefined) { return true; } - } catch { } + } catch {} return false; } @@ -277,14 +278,13 @@ export async function getGlobalAnalytics(): Promise { try { const globalWorkspace = await getWorkspace('local'); - const analyticsConfig: string | undefined | null | { uid?: string } = globalWorkspace - && globalWorkspace.getCli() - && globalWorkspace.getCli()['analytics']; + const analyticsConfig: string | undefined | null | { uid?: string } = + globalWorkspace && globalWorkspace.getCli() && globalWorkspace.getCli()['analytics']; if (analyticsConfig !== undefined) { return true; } - } catch { } + } catch {} return false; } @@ -299,7 +299,8 @@ export async function getWorkspaceAnalytics(): Promise extends Command { protected _architect!: Architect; protected _architectHost!: WorkspaceNodeModulesArchitectHost; protected _registry!: json.schema.SchemaRegistry; - protected readonly useReportAnalytics = false; + protected override readonly useReportAnalytics = false; // If this command supports running multiple targets. protected multiTarget = false; @@ -35,10 +36,10 @@ export abstract class ArchitectCommand< target: string | undefined; missingTargetError: string | undefined; - public async initialize(options: T & Arguments): Promise { + public override async initialize(options: T & Arguments): Promise { this._registry = new json.schema.CoreSchemaRegistry(); this._registry.addPostTransform(json.schema.transforms.addUndefinedDefaults); - this._registry.useXDeprecatedProvider(msg => this.logger.warn(msg)); + this._registry.useXDeprecatedProvider((msg) => this.logger.warn(msg)); if (!this.workspace) { this.logger.fatal('A workspace is required for this command.'); @@ -46,7 +47,10 @@ export abstract class ArchitectCommand< return 1; } - this._architectHost = new WorkspaceNodeModulesArchitectHost(this.workspace, this.workspace.basePath); + this._architectHost = new WorkspaceNodeModulesArchitectHost( + this.workspace, + this.workspace.basePath, + ); this._architect = new Architect(this._architectHost, this._registry); if (!this.target) { @@ -81,14 +85,18 @@ export abstract class ArchitectCommand< } if (targetProjectNames.length === 0) { - this.logger.fatal(this.missingTargetError || `No projects support the '${this.target}' target.`); + this.logger.fatal( + this.missingTargetError || `No projects support the '${this.target}' target.`, + ); return 1; } if (projectName && !targetProjectNames.includes(projectName)) { - this.logger.fatal(this.missingTargetError || - `Project '${projectName}' does not support the '${this.target}' target.`); + this.logger.fatal( + this.missingTargetError || + `Project '${projectName}' does not support the '${this.target}' target.`, + ); return 1; } @@ -116,7 +124,9 @@ export abstract class ArchitectCommand< const builderLeftovers = parsedOptions['--'] || []; leftoverMap.set(name, { optionDefs, parsedOptions }); - potentialProjectNames = new Set(builderLeftovers.filter(x => potentialProjectNames.has(x))); + potentialProjectNames = new Set( + builderLeftovers.filter((x) => potentialProjectNames.has(x)), + ); } if (potentialProjectNames.size === 1) { @@ -169,7 +179,9 @@ export abstract class ArchitectCommand< // This is a special case where we just return. return; } else { - this.logger.fatal(this.missingTargetError || 'Cannot determine project or target for command.'); + this.logger.fatal( + this.missingTargetError || 'Cannot determine project or target for command.', + ); return 1; } @@ -202,10 +214,7 @@ export abstract class ArchitectCommand< return await this.runArchitectTarget(options); } - protected async runSingleTarget( - target: Target, - targetOptions: string[], - ) { + protected async runSingleTarget(target: Target, targetOptions: string[]) { // We need to build the builderSpec twice because architect does not understand // overrides separately (getting the configuration builds the whole project, including // overrides). @@ -221,7 +230,7 @@ export abstract class ArchitectCommand< typeof builderDesc.optionSchema === 'object' && builderDesc.optionSchema.additionalProperties; if (overrides['--'] && !allowAdditionalProperties) { - (overrides['--'] || []).forEach(additional => { + (overrides['--'] || []).forEach((additional) => { this.logger.fatal(`Unknown option: '${additional.split(/=/)[0]}'`); }); @@ -229,7 +238,7 @@ export abstract class ArchitectCommand< } await this.reportAnalytics([this.description.name], { - ...await this._architectHost.getOptionsForTarget(target) as unknown as T, + ...((await this._architectHost.getOptionsForTarget(target)) as unknown as T), ...overrides, }); @@ -260,10 +269,7 @@ export abstract class ArchitectCommand< // Running them in parallel would jumble the log messages. let result = 0; for (const project of this.getProjectNamesByTarget(this.target)) { - result |= await this.runSingleTarget( - { ...targetSpec, project } as Target, - extra, - ); + result |= await this.runSingleTarget({ ...targetSpec, project } as Target, extra); } return result; @@ -275,7 +281,7 @@ export abstract class ArchitectCommand< const newErrors: schema.SchemaValidatorError[] = []; for (const schemaError of e.errors) { if (schemaError.keyword === 'additionalProperties') { - const unknownProperty = schemaError.params.additionalProperty; + const unknownProperty = schemaError.params?.additionalProperty; if (unknownProperty in options) { const dashes = unknownProperty.length === 1 ? '-' : '--'; this.logger.fatal(`Unknown option: '${dashes}${unknownProperty}'`); @@ -298,7 +304,7 @@ export abstract class ArchitectCommand< private getProjectNamesByTarget(targetName: string): string[] { const allProjectsForTargetName: string[] = []; - // tslint:disable-next-line: no-non-null-assertion + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion for (const [name, project] of this.workspace!.projects) { if (project.targets.has(targetName)) { allProjectsForTargetName.push(name); @@ -311,7 +317,7 @@ export abstract class ArchitectCommand< } else { // For single target commands, we try the default project first, // then the full list if it has a single project, then error out. - // tslint:disable-next-line: no-non-null-assertion + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const maybeDefaultProject = this.workspace!.extensions['defaultProject'] as string; if (maybeDefaultProject && allProjectsForTargetName.includes(maybeDefaultProject)) { return [maybeDefaultProject]; @@ -338,14 +344,24 @@ export abstract class ArchitectCommand< project = commandOptions.project; target = this.target; if (commandOptions.prod) { + const defaultConfig = + project && + target && + this.workspace?.projects.get(project)?.targets.get(target)?.defaultConfiguration; + + this.logger.warn( + defaultConfig === 'production' + ? 'Option "--prod" is deprecated: No need to use this option as this builder defaults to configuration "production".' + : 'Option "--prod" is deprecated: Use "--configuration production" instead.', + ); // The --prod flag will always be the first configuration, available to be overwritten // by following configurations. - this.logger.warn('Option "--prod" is deprecated: Use "--configuration production" instead.'); configuration = 'production'; } if (commandOptions.configuration) { - configuration = - `${configuration ? `${configuration},` : ''}${commandOptions.configuration}`; + configuration = `${configuration ? `${configuration},` : ''}${ + commandOptions.configuration + }`; } } diff --git a/packages/angular/cli/models/command-runner.ts b/packages/angular/cli/models/command-runner.ts index c5b08db13867..0b8b01fe4baa 100644 --- a/packages/angular/cli/models/command-runner.ts +++ b/packages/angular/cli/models/command-runner.ts @@ -1,10 +1,11 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { analytics, isJsonObject, @@ -60,7 +61,10 @@ export interface CommandMapOptions { * Create the analytics instance. * @private */ -async function _createAnalytics(workspace: boolean, skipPrompt = false): Promise { +async function _createAnalytics( + workspace: boolean, + skipPrompt = false, +): Promise { let config = await getGlobalAnalytics(); // If in workspace and global analytics is enabled, defer to workspace level if (workspace && config) { @@ -118,7 +122,9 @@ export async function runCommand( logger: logging.Logger, workspace: AngularWorkspace | undefined, commands: CommandMapOptions = standardCommands, - options: { analytics?: analytics.Analytics; currentDirectory: string } = { currentDirectory: process.cwd() }, + options: { analytics?: analytics.Analytics; currentDirectory: string } = { + currentDirectory: process.cwd(), + }, ): Promise { // This registry is exclusively used for flattening schemas, and not for validating. const registry = new schema.CoreSchemaRegistry([]); @@ -188,7 +194,7 @@ export async function runCommand( const aliasDesc = await loadCommandDescription(name, commands[name], registry); const aliases = aliasDesc.aliases; - if (aliases && aliases.some(alias => alias === commandName)) { + if (aliases && aliases.some((alias) => alias === commandName)) { commandName = name; description = aliasDesc; break; @@ -232,8 +238,7 @@ export async function runCommand( }); const analytics = - options.analytics || - (await _createAnalytics(!!workspace, description.name === 'update')); + options.analytics || (await _createAnalytics(!!workspace, description.name === 'update')); const context = { workspace, analytics, diff --git a/packages/angular/cli/models/command.ts b/packages/angular/cli/models/command.ts index cbea60d17478..d40b21620d98 100644 --- a/packages/angular/cli/models/command.ts +++ b/packages/angular/cli/models/command.ts @@ -1,10 +1,11 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { analytics, logging, strings, tags } from '@angular-devkit/core'; import { colors } from '../utilities/color'; import { AngularWorkspace } from '../utilities/config'; @@ -15,7 +16,6 @@ import { CommandDescriptionMap, CommandScope, Option, - SubCommandDescription, } from './interface'; export interface BaseCommandOptions { @@ -51,10 +51,9 @@ export abstract class Command return 0; } - async printJsonHelp(_options: T & Arguments): Promise { - const replacer = (key: string, value: string) => key === 'name' - ? strings.dasherize(value) - : value; + async printJsonHelp(): Promise { + const replacer = (key: string, value: string) => + key === 'name' ? strings.dasherize(value) : value; this.logger.info(JSON.stringify(this.description, replacer, 2)); return 0; @@ -64,32 +63,27 @@ export abstract class Command this.logger.info(this.description.description); const name = this.description.name; - const args = this.description.options.filter(x => x.positional !== undefined); - const opts = this.description.options.filter(x => x.positional === undefined); + const args = this.description.options.filter((x) => x.positional !== undefined); + const opts = this.description.options.filter((x) => x.positional === undefined); - const argDisplay = args && args.length > 0 ? ' ' + args.map(a => `<${a.name}>`).join(' ') : ''; + const argDisplay = + args && args.length > 0 ? ' ' + args.map((a) => `<${a.name}>`).join(' ') : ''; const optionsDisplay = opts && opts.length > 0 ? ` [options]` : ``; this.logger.info(`usage: ng ${name}${argDisplay}${optionsDisplay}`); this.logger.info(''); } - protected async printHelpSubcommand(subcommand: SubCommandDescription) { - this.logger.info(subcommand.description); - - await this.printHelpOptions(subcommand.options); - } - protected async printHelpOptions(options: Option[] = this.description.options) { - const args = options.filter(opt => opt.positional !== undefined); - const opts = options.filter(opt => opt.positional === undefined); + const args = options.filter((opt) => opt.positional !== undefined); + const opts = options.filter((opt) => opt.positional === undefined); const formatDescription = (description: string) => ` ${description.replace(/\n/g, '\n ')}`; if (args.length > 0) { this.logger.info(`arguments:`); - args.forEach(o => { + args.forEach((o) => { this.logger.info(` ${colors.cyan(o.name)}`); if (o.description) { this.logger.info(formatDescription(o.description)); @@ -102,12 +96,12 @@ export abstract class Command } this.logger.info(`options:`); opts - .filter(o => !o.hidden) + .filter((o) => !o.hidden) .sort((a, b) => a.name.localeCompare(b.name)) - .forEach(o => { + .forEach((o) => { const aliases = o.aliases && o.aliases.length > 0 - ? '(' + o.aliases.map(a => `-${a}`).join(' ') + ')' + ? '(' + o.aliases.map((a) => `-${a}`).join(' ') + ')' : ''; this.logger.info(` ${colors.cyan('--' + strings.dasherize(o.name))} ${aliases}`); if (o.description) { @@ -125,6 +119,7 @@ export abstract class Command The ${this.description.name} command requires to be run outside of a project, but a project definition was found at "${this.workspace.filePath}". `); + // eslint-disable-next-line no-throw-literal throw 1; } break; @@ -134,6 +129,7 @@ export abstract class Command The ${this.description.name} command requires to be run in an Angular project, but a project definition could not be found. `); + // eslint-disable-next-line no-throw-literal throw 1; } break; @@ -175,7 +171,7 @@ export abstract class Command if (options.help === true) { return this.printHelp(); } else if (options.help === 'json' || options.help === 'JSON') { - return this.printJsonHelp(options); + return this.printJsonHelp(); } else { const startTime = +new Date(); if (this.useReportAnalytics) { diff --git a/packages/angular/cli/models/error.ts b/packages/angular/cli/models/error.ts index 5d9d323ed103..dacdd2f3a38d 100644 --- a/packages/angular/cli/models/error.ts +++ b/packages/angular/cli/models/error.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license diff --git a/packages/angular/cli/models/interface.ts b/packages/angular/cli/models/interface.ts index e5374e0f5e0d..9c908d913247 100644 --- a/packages/angular/cli/models/interface.ts +++ b/packages/angular/cli/models/interface.ts @@ -1,10 +1,11 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { analytics, json, logging } from '@angular-devkit/core'; import { AngularWorkspace } from '../utilities/config'; @@ -38,7 +39,7 @@ export interface CommandInterface { * Command constructor. */ export interface CommandConstructor { - new( + new ( context: CommandContext, description: CommandDescription, logger: logging.Logger, @@ -157,7 +158,7 @@ export interface Option { /** * Deprecation. If this flag is not false a warning will be shown on the console. Either `true` * or a string to show the user as a notice. - */ + */ deprecated?: boolean | string; } diff --git a/packages/angular/cli/models/parser.ts b/packages/angular/cli/models/parser.ts index 54bb8ebad85b..b1e98d0b3f2a 100644 --- a/packages/angular/cli/models/parser.ts +++ b/packages/angular/cli/models/parser.ts @@ -1,15 +1,14 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license - * */ + import { BaseException, logging, strings } from '@angular-devkit/core'; import { Arguments, Option, OptionType, Value } from './interface'; - export class ParseArgumentException extends BaseException { constructor( public readonly comments: string[], @@ -20,7 +19,6 @@ export class ParseArgumentException extends BaseException { } } - function _coerceType(str: string | undefined, type: OptionType, v?: Value): Value | undefined { switch (type) { case OptionType.Any: @@ -31,8 +29,8 @@ function _coerceType(str: string | undefined, type: OptionType, v?: Value): Valu return _coerceType(str, OptionType.Boolean, v) !== undefined ? _coerceType(str, OptionType.Boolean, v) : _coerceType(str, OptionType.Number, v) !== undefined - ? _coerceType(str, OptionType.Number, v) - : _coerceType(str, OptionType.String, v); + ? _coerceType(str, OptionType.Number, v) + : _coerceType(str, OptionType.String, v); case OptionType.String: return str || ''; @@ -66,8 +64,8 @@ function _coerceType(str: string | undefined, type: OptionType, v?: Value): Valu return Array.isArray(v) ? v.concat(str || '') : v === undefined - ? [str || ''] - : [v + '', str || '']; + ? [str || ''] + : [v + '', str || '']; default: return undefined; @@ -93,18 +91,15 @@ function _coerce(str: string | undefined, o: Option | null, v?: Value): Value | } } - function _getOptionFromName(name: string, options: Option[]): Option | undefined { - const camelName = /(-|_)/.test(name) - ? strings.camelize(name) - : name; + const camelName = /(-|_)/.test(name) ? strings.camelize(name) : name; for (const option of options) { if (option.name === name || option.name === camelName) { return option; } - if (option.aliases.some(x => x === name || x === camelName)) { + if (option.aliases.some((x) => x === name || x === camelName)) { return option; } } @@ -121,14 +116,21 @@ function _removeLeadingDashes(key: string): string { function _assignOption( arg: string, nextArg: string | undefined, - { options, parsedOptions, leftovers, ignored, errors, warnings }: { - options: Option[], - parsedOptions: Arguments, - positionals: string[], - leftovers: string[], - ignored: string[], - errors: string[], - warnings: string[], + { + options, + parsedOptions, + leftovers, + ignored, + errors, + warnings, + }: { + options: Option[]; + parsedOptions: Arguments; + positionals: string[]; + leftovers: string[]; + ignored: string[]; + errors: string[]; + warnings: string[]; }, ) { const from = arg.startsWith('--') ? 2 : 1; @@ -192,9 +194,9 @@ function _assignOption( if (parsedOptions[option.name] !== v) { if (parsedOptions[option.name] !== undefined && option.type !== OptionType.Array) { warnings.push( - `Option ${JSON.stringify(option.name)} was already specified with value ` - + `${JSON.stringify(parsedOptions[option.name])}. The new value ${JSON.stringify(v)} ` - + `will override it.`, + `Option ${JSON.stringify(option.name)} was already specified with value ` + + `${JSON.stringify(parsedOptions[option.name])}. The new value ${JSON.stringify(v)} ` + + `will override it.`, ); } @@ -203,7 +205,7 @@ function _assignOption( } else { let error = `Argument ${key} could not be parsed using value ${JSON.stringify(value)}.`; if (option.enum) { - error += ` Valid values are: ${option.enum.map(x => JSON.stringify(x)).join(', ')}.`; + error += ` Valid values are: ${option.enum.map((x) => JSON.stringify(x)).join(', ')}.`; } else { error += `Valid type(s) is: ${(option.types || [option.type]).join(', ')}`; } @@ -215,7 +217,7 @@ function _assignOption( if (/^[a-z]+[A-Z]/.test(key)) { warnings.push( 'Support for camel case arguments has been deprecated and will be removed in a future major version.\n' + - `Use '--${strings.dasherize(key)}' instead of '--${key}'.`, + `Use '--${strings.dasherize(key)}' instead of '--${key}'.`, ); } } @@ -223,7 +225,6 @@ function _assignOption( return consumedNextArg; } - /** * Parse the arguments in a consistent way, but without having any option definition. This tries * to assess what the user wants in a free form. For example, using `--name=false` will set the @@ -261,7 +262,7 @@ export function parseFreeFormArguments(args: string[]): Arguments { parsedOptions[name] = v; } } else if (arg.startsWith('-')) { - arg.split('').forEach(x => parsedOptions[x] = true); + arg.split('').forEach((x) => (parsedOptions[x] = true)); } else { leftovers.push(arg); } @@ -274,7 +275,6 @@ export function parseFreeFormArguments(args: string[]): Arguments { return parsedOptions; } - /** * Parse the arguments in a consistent way, from a list of standardized options. * The result object will have a key per option name, with the `_` key reserved for positional @@ -357,7 +357,7 @@ export function parseArguments( // simpler. if (positionals.length > 0) { let pos = 0; - for (let i = 0; i < positionals.length;) { + for (let i = 0; i < positionals.length; ) { let found = false; let incrementPos = false; let incrementI = true; @@ -394,7 +394,7 @@ export function parseArguments( } if (warnings.length > 0 && logger) { - warnings.forEach(message => logger.warn(message)); + warnings.forEach((message) => logger.warn(message)); } if (errors.length > 0) { diff --git a/packages/angular/cli/models/parser_spec.ts b/packages/angular/cli/models/parser_spec.ts index cd6b3c09e801..1f543d8d560e 100644 --- a/packages/angular/cli/models/parser_spec.ts +++ b/packages/angular/cli/models/parser_spec.ts @@ -1,39 +1,58 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license - * */ -// tslint:disable:no-global-tslint-disable no-big-function + import { logging } from '@angular-devkit/core'; import { Arguments, Option, OptionType } from './interface'; import { ParseArgumentException, parseArguments } from './parser'; describe('parseArguments', () => { const options: Option[] = [ - { name: 'bool', aliases: [ 'b' ], type: OptionType.Boolean, description: '' }, - { name: 'num', aliases: [ 'n' ], type: OptionType.Number, description: '' }, - { name: 'str', aliases: [ 's' ], type: OptionType.String, description: '' }, - { name: 'strUpper', aliases: [ 'S' ], type: OptionType.String, description: '' }, + { name: 'bool', aliases: ['b'], type: OptionType.Boolean, description: '' }, + { name: 'num', aliases: ['n'], type: OptionType.Number, description: '' }, + { name: 'str', aliases: ['s'], type: OptionType.String, description: '' }, + { name: 'strUpper', aliases: ['S'], type: OptionType.String, description: '' }, { name: 'helloWorld', aliases: [], type: OptionType.String, description: '' }, { name: 'helloBool', aliases: [], type: OptionType.Boolean, description: '' }, - { name: 'arr', aliases: [ 'a' ], type: OptionType.Array, description: '' }, + { name: 'arr', aliases: ['a'], type: OptionType.Array, description: '' }, { name: 'p1', positional: 0, aliases: [], type: OptionType.String, description: '' }, { name: 'p2', positional: 1, aliases: [], type: OptionType.String, description: '' }, { name: 'p3', positional: 2, aliases: [], type: OptionType.Number, description: '' }, - { name: 't1', aliases: [], type: OptionType.Boolean, - types: [OptionType.Boolean, OptionType.String], description: '' }, - { name: 't2', aliases: [], type: OptionType.Boolean, - types: [OptionType.Boolean, OptionType.Number], description: '' }, - { name: 't3', aliases: [], type: OptionType.Number, - types: [OptionType.Number, OptionType.Any], description: '' }, + { + name: 't1', + aliases: [], + type: OptionType.Boolean, + types: [OptionType.Boolean, OptionType.String], + description: '', + }, + { + name: 't2', + aliases: [], + type: OptionType.Boolean, + types: [OptionType.Boolean, OptionType.Number], + description: '', + }, + { + name: 't3', + aliases: [], + type: OptionType.Number, + types: [OptionType.Number, OptionType.Any], + description: '', + }, { name: 'e1', aliases: [], type: OptionType.String, enum: ['hello', 'world'], description: '' }, { name: 'e2', aliases: [], type: OptionType.String, enum: ['hello', ''], description: '' }, - { name: 'e3', aliases: [], type: OptionType.Boolean, - types: [OptionType.Boolean, OptionType.String], enum: ['json', true, false], - description: '' }, + { + name: 'e3', + aliases: [], + type: OptionType.Boolean, + types: [OptionType.Boolean, OptionType.String], + enum: ['json', true, false], + description: '', + }, ]; const tests: { [test: string]: Partial | ['!!!', Partial, string[]] } = { @@ -75,10 +94,15 @@ describe('parseArguments', () => { '--bool val1 --etc --num val2 --v': [ '!!!', { bool: true, p1: 'val1', p2: 'val2', '--': ['--etc', '--v'] }, - ['--num' ], + ['--num'], ], - '--bool val1 --etc --num=1 val2 --v': { bool: true, num: 1, p1: 'val1', p2: 'val2', - '--': ['--etc', '--v'] }, + '--bool val1 --etc --num=1 val2 --v': { + bool: true, + num: 1, + p1: 'val1', + p2: 'val2', + '--': ['--etc', '--v'], + }, '--arr=a d': { arr: ['a'], p1: 'd' }, '--arr=a --arr=b --arr c d': { arr: ['a', 'b', 'c'], p1: 'd' }, '--arr=1 --arr --arr c d': { arr: ['1', '', 'c'], p1: 'd' }, @@ -121,7 +145,7 @@ describe('parseArguments', () => { '--e1=yellow': ['!!!', {}, ['--e1=yellow']], '--e1': ['!!!', {}, ['--e1']], '--e1 true': ['!!!', { p1: 'true' }, ['--e1']], - '--e1=true': ['!!!', {}, ['--e1=true']], + '--e1=true': ['!!!', {}, ['--e1=true']], '--e2 hello': { e2: 'hello' }, '--e2=hello': { e2: 'hello' }, '--e2 yellow': { p1: 'yellow', e2: '' }, @@ -138,13 +162,13 @@ describe('parseArguments', () => { '--e3=true': { e3: true }, 'a b c 1': { p1: 'a', p2: 'b', '--': ['c', '1'] }, - '-p=1 -c=prod': {'--': ['-p=1', '-c=prod'] }, - '--p --c': {'--': ['--p', '--c'] }, - '--p=123': {'--': ['--p=123'] }, - '--p -c': {'--': ['--p', '-c'] }, - '-p --c': {'--': ['-p', '--c'] }, - '-p --c 123': {'--': ['-p', '--c', '123'] }, - '--c 123 -p': {'--': ['--c', '123', '-p'] }, + '-p=1 -c=prod': { '--': ['-p=1', '-c=prod'] }, + '--p --c': { '--': ['--p', '--c'] }, + '--p=123': { '--': ['--p=123'] }, + '--p -c': { '--': ['--p', '-c'] }, + '-p --c': { '--': ['-p', '--c'] }, + '-p --c 123': { '--': ['-p', '--c', '123'] }, + '--c 123 -p': { '--': ['--c', '123', '-p'] }, }; Object.entries(tests).forEach(([str, expected]) => { @@ -172,14 +196,12 @@ describe('parseArguments', () => { }); it('handles a flag being added multiple times', () => { - const options = [ - { name: 'bool', aliases: [], type: OptionType.Boolean, description: '' }, - ]; + const options = [{ name: 'bool', aliases: [], type: OptionType.Boolean, description: '' }]; const logger = new logging.Logger(''); const messages: string[] = []; - logger.subscribe(entry => messages.push(entry.message)); + logger.subscribe((entry) => messages.push(entry.message)); let result = parseArguments(['--bool'], options, logger); expect(result).toEqual({ bool: true }); diff --git a/packages/angular/cli/models/schematic-command.ts b/packages/angular/cli/models/schematic-command.ts index fa73b260487c..884ba71f7d9d 100644 --- a/packages/angular/cli/models/schematic-command.ts +++ b/packages/angular/cli/models/schematic-command.ts @@ -1,18 +1,12 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ -import { - logging, - normalize, - schema, - strings, - tags, - workspaces, -} from '@angular-devkit/core'; + +import { logging, normalize, schema, strings, tags, workspaces } from '@angular-devkit/core'; import { DryRunEvent, UnsuccessfulWorkflowExecution, @@ -62,10 +56,10 @@ export class UnknownCollectionError extends Error { } export abstract class SchematicCommand< - T extends BaseSchematicSchema & BaseCommandOptions + T extends BaseSchematicSchema & BaseCommandOptions, > extends Command { protected readonly allowPrivateSchematics: boolean = false; - protected readonly useReportAnalytics = false; + protected override readonly useReportAnalytics = false; protected _workflow!: NodeWorkflow; protected defaultCollectionName = '@schematics/angular'; @@ -76,7 +70,7 @@ export abstract class SchematicCommand< super(context, description, logger); } - public async initialize(options: T & Arguments) { + public override async initialize(options: T & Arguments) { await this.createWorkflow(options); if (this.schematicName) { @@ -88,7 +82,8 @@ export abstract class SchematicCommand< schematic.description.schemaJson || {}, ); - this.description.options.push(...options.filter(x => !x.hidden)); + this.description.description = schematic.description.description; + this.description.options.push(...options.filter((x) => !x.hidden)); // Remove any user analytics from schematics that are NOT part of our safelist. for (const o of this.description.options) { @@ -99,11 +94,11 @@ export abstract class SchematicCommand< } } - public async printHelp() { + public override async printHelp() { await super.printHelp(); this.logger.info(''); - const subCommandOption = this.description.options.filter(x => x.subcommands)[0]; + const subCommandOption = this.description.options.filter((x) => x.subcommands)[0]; if (!subCommandOption || !subCommandOption.subcommands) { return 0; @@ -115,7 +110,7 @@ export abstract class SchematicCommand< this.logger.info('Available Schematics:'); const namesPerCollection: { [c: string]: string[] } = {}; - schematicNames.forEach(name => { + schematicNames.forEach((name) => { let [collectionName, schematicName] = name.split(/:/, 2); if (!schematicName) { schematicName = collectionName; @@ -130,24 +125,21 @@ export abstract class SchematicCommand< }); const defaultCollection = await this.getDefaultSchematicCollection(); - Object.keys(namesPerCollection).forEach(collectionName => { + Object.keys(namesPerCollection).forEach((collectionName) => { const isDefault = defaultCollection == collectionName; this.logger.info(` Collection "${collectionName}"${isDefault ? ' (default)' : ''}:`); - namesPerCollection[collectionName].forEach(schematicName => { + namesPerCollection[collectionName].forEach((schematicName) => { this.logger.info(` ${schematicName}`); }); }); - } else if (schematicNames.length == 1) { - this.logger.info('Help for schematic ' + schematicNames[0]); - await this.printHelpSubcommand(subCommandOption.subcommands[schematicNames[0]]); } return 0; } - async printHelpUsage() { - const subCommandOption = this.description.options.filter(x => x.subcommands)[0]; + override async printHelpUsage() { + const subCommandOption = this.description.options.filter((x) => x.subcommands)[0]; if (!subCommandOption || !subCommandOption.subcommands) { return; @@ -157,7 +149,7 @@ export abstract class SchematicCommand< if (schematicNames.length == 1) { this.logger.info(this.description.description); - const opts = this.description.options.filter(x => x.positional === undefined); + const opts = this.description.options.filter((x) => x.positional === undefined); const [collectionName, schematicName] = schematicNames[0].split(/:/)[0]; // Display if this is not the default collectionName, @@ -168,10 +160,10 @@ export abstract class SchematicCommand< : schematicNames[0]; const schematicOptions = subCommandOption.subcommands[schematicNames[0]].options; - const schematicArgs = schematicOptions.filter(x => x.positional !== undefined); + const schematicArgs = schematicOptions.filter((x) => x.positional !== undefined); const argDisplay = schematicArgs.length > 0 - ? ' ' + schematicArgs.map(a => `<${strings.dasherize(a.name)}>`).join(' ') + ? ' ' + schematicArgs.map((a) => `<${strings.dasherize(a.name)}>`).join(' ') : ''; this.logger.info(tags.oneLine` @@ -213,16 +205,13 @@ export abstract class SchematicCommand< } return options - .filter(o => o.format === 'path') - .map(o => o.name) - .reduce( - (acc, curr) => { - acc[curr] = workingDir; + .filter((o) => o.format === 'path') + .map((o) => o.name) + .reduce((acc, curr) => { + acc[curr] = workingDir; - return acc; - }, - {} as { [name: string]: string }, - ); + return acc; + }, {} as { [name: string]: string }); } /* @@ -242,28 +231,39 @@ export abstract class SchematicCommand< packageRegistry: options.packageRegistry, // A schema registry is required to allow customizing addUndefinedDefaults registry: new schema.CoreSchemaRegistry(formats.standardFormats), - resolvePaths: !!this.workspace - // Workspace - ? this.collectionName === this.defaultCollectionName - // Favor __dirname for @schematics/angular to use the build-in version - ? [__dirname, process.cwd(), root] + resolvePaths: this.workspace + ? // Workspace + this.collectionName === this.defaultCollectionName + ? // Favor __dirname for @schematics/angular to use the build-in version + [__dirname, process.cwd(), root] : [process.cwd(), root, __dirname] - // Global - : [__dirname, process.cwd()], + : // Global + [__dirname, process.cwd()], schemaValidation: true, optionTransforms: [ // Add configuration file defaults - async (schematic, current) => ({ - ...(await getSchematicDefaults(schematic.collection.name, schematic.name, getProjectName())), - ...current, - }), + async (schematic, current) => { + const projectName = + typeof (current as Record).project === 'string' + ? ((current as Record).project as string) + : getProjectName(); + + return { + ...(await getSchematicDefaults(schematic.collection.name, schematic.name, projectName)), + ...current, + }; + }, ], engineHostCreator: (options) => new SchematicEngineHost(options.resolvePaths), }); const getProjectName = () => { if (this.workspace) { - const projectNames = getProjectsByPath(this.workspace, process.cwd(), this.workspace.basePath); + const projectNames = getProjectsByPath( + this.workspace, + process.cwd(), + this.workspace.basePath, + ); if (projectNames.length === 1) { return projectNames[0]; @@ -288,7 +288,7 @@ export abstract class SchematicCommand< workflow.registry.addPostTransform(schema.transforms.addUndefinedDefaults); workflow.registry.addSmartDefaultProvider('projectName', getProjectName); - workflow.registry.useXDeprecatedProvider(msg => this.logger.warn(msg)); + workflow.registry.useXDeprecatedProvider((msg) => this.logger.warn(msg)); let shouldReportAnalytics = true; workflow.engineHost.registerOptionsTransform(async (_, options) => { @@ -303,8 +303,8 @@ export abstract class SchematicCommand< if (options.interactive !== false && isTTY()) { workflow.registry.usePromptProvider((definitions: Array) => { const questions: inquirer.QuestionCollection = definitions - .filter(definition => !options.defaults || definition.default === undefined) - .map(definition => { + .filter((definition) => !options.defaults || definition.default === undefined) + .map((definition) => { const question: inquirer.Question = { name: definition.id, message: definition.message, @@ -313,7 +313,7 @@ export abstract class SchematicCommand< const validator = definition.validator; if (validator) { - question.validate = input => validator(input); + question.validate = (input) => validator(input); // Filter allows transformation of the value prior to validation question.filter = async (input) => { @@ -348,13 +348,13 @@ export abstract class SchematicCommand< break; case 'list': question.type = definition.multiselect ? 'checkbox' : 'list'; - (question as inquirer.CheckboxQuestion).choices = definition.items?.map(item => { + (question as inquirer.CheckboxQuestion).choices = definition.items?.map((item) => { return typeof item == 'string' ? item : { - name: item.label, - value: item.value, - }; + name: item.label, + value: item.value, + }; }); break; default: @@ -437,10 +437,11 @@ export abstract class SchematicCommand< } const allowAdditionalProperties = - typeof schematic.description.schemaJson === 'object' && schematic.description.schemaJson.additionalProperties; + typeof schematic.description.schemaJson === 'object' && + schematic.description.schemaJson.additionalProperties; if (args['--'] && !allowAdditionalProperties) { - args['--'].forEach(additional => { + args['--'].forEach((additional) => { this.logger.fatal(`Unknown option: '${additional.split(/=/)[0]}'`); }); @@ -448,14 +449,9 @@ export abstract class SchematicCommand< } const pathOptions = o ? this.setPathOptions(o, workingDir) : {}; - let input = { ...pathOptions, ...args }; - - // Read the default values from the workspace. - const projectName = input.project !== undefined ? '' + input.project : null; - const defaults = await getSchematicDefaults(collectionName, schematicName, projectName); - input = { - ...defaults, - ...input, + const input = { + ...pathOptions, + ...args, ...options.additionalOptions, }; @@ -491,11 +487,11 @@ export abstract class SchematicCommand< } }); - workflow.lifeCycle.subscribe(event => { + workflow.lifeCycle.subscribe((event) => { if (event.kind == 'end' || event.kind == 'post-tasks-start') { if (!error) { // Output the logging queue, no error happened. - loggingQueue.forEach(log => this.logger.info(log)); + loggingQueue.forEach((log) => this.logger.info(log)); } loggingQueue = []; @@ -513,7 +509,7 @@ export abstract class SchematicCommand< } } - return new Promise(resolve => { + return new Promise((resolve) => { workflow .execute({ collection: collectionName, @@ -585,7 +581,7 @@ function getProjectsByPath( const projects = Array.from(workspace.projects.entries()) .map(([name, project]) => [systemPath.resolve(root, project.root), name] as [string, string]) - .filter(tuple => isInside(tuple[0], path)) + .filter((tuple) => isInside(tuple[0], path)) // Sort tuples by depth, with the deeper ones first. Since the first member is a path and // we filtered all invalid paths, the longest will be the deepest (and in case of equality // the sort is stable and the first declared project will win). @@ -596,7 +592,7 @@ function getProjectsByPath( } else if (projects.length > 1) { const firstPath = projects[0][0]; - return projects.filter(v => v[0] === firstPath).map(v => v[1]); + return projects.filter((v) => v[0] === firstPath).map((v) => v[1]); } return []; diff --git a/packages/angular/cli/models/schematic-engine-host.ts b/packages/angular/cli/models/schematic-engine-host.ts index 478973f78a54..208ff61f0ebf 100644 --- a/packages/angular/cli/models/schematic-engine-host.ts +++ b/packages/angular/cli/models/schematic-engine-host.ts @@ -1,14 +1,16 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { RuleFactory, SchematicsException, Tree } from '@angular-devkit/schematics'; import { NodeModulesEngineHost } from '@angular-devkit/schematics/tools'; import { readFileSync } from 'fs'; import { parse as parseJson } from 'jsonc-parser'; +import nodeModule from 'module'; import { dirname, resolve } from 'path'; import { Script } from 'vm'; @@ -32,19 +34,24 @@ function shouldWrapSchematic(schematicFile: string): boolean { } } + const normalizedSchematicFile = schematicFile.replace(/\\/g, '/'); // Never wrap the internal update schematic when executed directly // It communicates with the update command via `global` - if (/[\/\\]node_modules[\/\\]@angular[\/\\]cli[\/\\]/.test(schematicFile)) { + // But we still want to redirect schematics located in `@angular/cli/node_modules`. + if ( + normalizedSchematicFile.includes('node_modules/@angular/cli/') && + !normalizedSchematicFile.includes('node_modules/@angular/cli/node_modules/') + ) { return false; } // Default is only first-party Angular schematic packages // Angular schematics are safe to use in the wrapped VM context - return /[\/\\]node_modules[\/\\]@(?:angular|schematics|nguniversal)[\/\\]/.test(schematicFile); + return /\/node_modules\/@(?:angular|schematics|nguniversal)\//.test(normalizedSchematicFile); } export class SchematicEngineHost extends NodeModulesEngineHost { - protected _resolveReferenceString(refString: string, parentPath: string) { + protected override _resolveReferenceString(refString: string, parentPath: string) { const [path, name] = refString.split('#', 2); // Mimic behavior of ExportStringRef class used in default behavior const fullPath = path[0] === '.' ? resolve(parentPath ?? process.cwd(), path) : path; @@ -114,10 +121,7 @@ function wrap( moduleCache: Map, exportName?: string, ): () => unknown { - const { createRequire, createRequireFromPath } = require('module'); - // Node.js 10.x does not support `createRequire` so fallback to `createRequireFromPath` - // `createRequireFromPath` is deprecated in 12+ and can be removed once 10.x support is removed - const scopedRequire = createRequire?.(schematicFile) || createRequireFromPath(schematicFile); + const scopedRequire = nodeModule.createRequire(schematicFile); const customRequire = function (id: string) { if (legacyModules[id]) { diff --git a/packages/angular/cli/models/version.ts b/packages/angular/cli/models/version.ts index 1c8003543d21..0ee4e0c8c828 100644 --- a/packages/angular/cli/models/version.ts +++ b/packages/angular/cli/models/version.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license diff --git a/packages/angular/cli/package.json b/packages/angular/cli/package.json index d8e9d6c02cfc..c24e66384029 100644 --- a/packages/angular/cli/package.json +++ b/packages/angular/cli/package.json @@ -31,21 +31,23 @@ "@schematics/angular": "0.0.0", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.1", - "debug": "4.3.1", + "debug": "4.3.2", "ini": "2.0.0", - "inquirer": "8.0.0", + "inquirer": "8.1.2", "jsonc-parser": "3.0.0", - "npm-package-arg": "8.1.2", + "npm-package-arg": "8.1.5", "npm-pick-manifest": "6.1.1", - "open": "8.0.5", - "ora": "5.4.0", - "pacote": "11.3.1", + "open": "8.2.1", + "ora": "5.4.1", + "pacote": "12.0.2", "resolve": "1.20.0", - "rimraf": "3.0.2", "semver": "7.3.5", - "symbol-observable": "3.0.0", + "symbol-observable": "4.0.0", "uuid": "8.3.2" }, + "devDependencies": { + "rxjs": "6.6.7" + }, "ng-update": { "migrations": "@schematics/angular/migrations/migration-collection.json", "packageGroup": { diff --git a/packages/angular/cli/src/commands/update/schematic/index.ts b/packages/angular/cli/src/commands/update/schematic/index.ts index d7995edca3eb..39eee7e4fd41 100644 --- a/packages/angular/cli/src/commands/update/schematic/index.ts +++ b/packages/angular/cli/src/commands/update/schematic/index.ts @@ -1,30 +1,25 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { logging, tags } from '@angular-devkit/core'; -import { - Rule, - SchematicContext, - SchematicsException, - TaskId, - Tree, -} from '@angular-devkit/schematics'; -import { NodePackageInstallTask, RunSchematicTask } from '@angular-devkit/schematics/tasks'; +import { Rule, SchematicContext, SchematicsException, Tree } from '@angular-devkit/schematics'; import * as npa from 'npm-package-arg'; import * as semver from 'semver'; -import { getNpmPackageJson } from './npm'; -import { NpmRepositoryPackageJson } from './npm-package-json'; -import { Dependency, JsonSchemaForNpmPackageJsonFiles } from './package-json'; +import { Dependency, JsonSchemaForNpmPackageJsonFiles } from '../../../../utilities/package-json'; +import { + NpmRepositoryPackageJson, + getNpmPackageJson, +} from '../../../../utilities/package-metadata'; import { Schema as UpdateSchema } from './schema'; -type VersionRange = string & { __VERSION_RANGE: void; }; +type VersionRange = string & { __VERSION_RANGE: void }; type PeerVersionTransform = string | ((range: string) => string); - // Angular guarantees that a major is compatible with its following major (so packages that depend // on Angular 5 are also compatible with Angular 6). This is, in code, represented by verifying // that all other packages that have a peer dependency of `"@angular/core": "^5.0.0"` actually @@ -56,7 +51,6 @@ export function angularMajorCompatGuarantee(range: string) { return semver.validRange(newRange) || range; } - // This is a map of packageGroupName to range extending function. If it isn't found, the range is // kept the same. const knownPeerCompatibleList: { [name: string]: PeerVersionTransform } = { @@ -79,7 +73,7 @@ interface PackageInfo { interface UpdateMetadata { packageGroupName?: string; - packageGroup: { [ packageName: string ]: string }; + packageGroup: { [packageName: string]: string }; requirements: { [packageName: string]: string }; migrations?: string; } @@ -111,8 +105,8 @@ function _updatePeerVersion(infoMap: Map, name: string, ran function _validateForwardPeerDependencies( name: string, infoMap: Map, - peers: {[name: string]: string}, - peersMeta: { [name: string]: { optional?: boolean }}, + peers: { [name: string]: string }, + peersMeta: { [name: string]: { optional?: boolean } }, logger: logging.LoggerApi, next: boolean, ): boolean { @@ -123,26 +117,31 @@ function _validateForwardPeerDependencies( const isOptional = peersMeta[peer] && !!peersMeta[peer].optional; if (!maybePeerInfo) { if (!isOptional) { - logger.warn([ - `Package ${JSON.stringify(name)} has a missing peer dependency of`, - `${JSON.stringify(peer)} @ ${JSON.stringify(range)}.`, - ].join(' ')); + logger.warn( + [ + `Package ${JSON.stringify(name)} has a missing peer dependency of`, + `${JSON.stringify(peer)} @ ${JSON.stringify(range)}.`, + ].join(' '), + ); } continue; } - const peerVersion = maybePeerInfo.target && maybePeerInfo.target.packageJson.version - ? maybePeerInfo.target.packageJson.version - : maybePeerInfo.installed.version; + const peerVersion = + maybePeerInfo.target && maybePeerInfo.target.packageJson.version + ? maybePeerInfo.target.packageJson.version + : maybePeerInfo.installed.version; logger.debug(` Range intersects(${range}, ${peerVersion})...`); if (!semver.satisfies(peerVersion, range, { includePrerelease: next || undefined })) { - logger.error([ - `Package ${JSON.stringify(name)} has an incompatible peer dependency to`, - `${JSON.stringify(peer)} (requires ${JSON.stringify(range)},`, - `would install ${JSON.stringify(peerVersion)})`, - ].join(' ')); + logger.error( + [ + `Package ${JSON.stringify(name)} has an incompatible peer dependency to`, + `${JSON.stringify(peer)} (requires ${JSON.stringify(range)},`, + `would install ${JSON.stringify(peerVersion)})`, + ].join(' '), + ); validationFailed = true; continue; @@ -152,7 +151,6 @@ function _validateForwardPeerDependencies( return validationFailed; } - function _validateReversePeerDependencies( name: string, version: string, @@ -178,6 +176,7 @@ function _validateReversePeerDependencies( 'codelyzer', '@schematics/update', '@angular-devkit/build-ng-packagr', + 'tsickle', ]; if (ignoredPackages.includes(installed)) { continue; @@ -187,12 +186,14 @@ function _validateReversePeerDependencies( const extendedRange = _updatePeerVersion(infoMap, peer, range); if (!semver.satisfies(version, extendedRange, { includePrerelease: next || undefined })) { - logger.error([ - `Package ${JSON.stringify(installed)} has an incompatible peer dependency to`, - `${JSON.stringify(name)} (requires`, - `${JSON.stringify(range)}${extendedRange == range ? '' : ' (extended)'},`, - `would install ${JSON.stringify(version)}).`, - ].join(' ')); + logger.error( + [ + `Package ${JSON.stringify(installed)} has an incompatible peer dependency to`, + `${JSON.stringify(name)} (requires`, + `${JSON.stringify(range)}${extendedRange == range ? '' : ' (extended)'},`, + `would install ${JSON.stringify(version)}).`, + ].join(' '), + ); return true; } @@ -209,15 +210,15 @@ function _validateUpdatePackages( logger: logging.LoggerApi, ): void { logger.debug('Updating the following packages:'); - infoMap.forEach(info => { + infoMap.forEach((info) => { if (info.target) { logger.debug(` ${info.name} => ${info.target.version}`); } }); let peerErrors = false; - infoMap.forEach(info => { - const {name, target} = info; + infoMap.forEach((info) => { + const { name, target } = info; if (!target) { return; } @@ -226,29 +227,33 @@ function _validateUpdatePackages( logger.debug(`${name}...`); const { peerDependencies = {}, peerDependenciesMeta = {} } = target.packageJson; - peerErrors = _validateForwardPeerDependencies(name, infoMap, peerDependencies, - peerDependenciesMeta, pkgLogger, next) || peerErrors; - peerErrors - = _validateReversePeerDependencies(name, target.version, infoMap, pkgLogger, next) - || peerErrors; + peerErrors = + _validateForwardPeerDependencies( + name, + infoMap, + peerDependencies, + peerDependenciesMeta, + pkgLogger, + next, + ) || peerErrors; + peerErrors = + _validateReversePeerDependencies(name, target.version, infoMap, pkgLogger, next) || + peerErrors; }); if (!force && peerErrors) { - throw new SchematicsException(tags.stripIndents - `Incompatible peer dependencies found. + throw new SchematicsException(tags.stripIndents`Incompatible peer dependencies found. Peer dependency warnings when installing dependencies means that those dependencies might not work correctly together. You can use the '--force' option to ignore incompatible peer dependencies and instead address these warnings later.`); } } - function _performUpdate( tree: Tree, context: SchematicContext, infoMap: Map, logger: logging.LoggerApi, migrateOnly: boolean, - migrateExternal: boolean, ): void { const packageJsonContent = tree.read('/package.json'); if (!packageJsonContent) { @@ -270,16 +275,15 @@ function _performUpdate( }; const toInstall = [...infoMap.values()] - .map(x => [x.name, x.target, x.installed]) - // tslint:disable-next-line:no-non-null-assertion - .filter(([name, target, installed]) => { - return !!name && !!target && !!installed; - }) as [string, PackageVersionInfo, PackageVersionInfo][]; + .map((x) => [x.name, x.target, x.installed]) + .filter(([name, target, installed]) => { + return !!name && !!target && !!installed; + }) as [string, PackageVersionInfo, PackageVersionInfo][]; toInstall.forEach(([name, target, installed]) => { logger.info( - `Updating package.json with dependency ${name} ` - + `@ ${JSON.stringify(target.version)} (was ${JSON.stringify(installed.version)})...`, + `Updating package.json with dependency ${name} ` + + `@ ${JSON.stringify(target.version)} (was ${JSON.stringify(installed.version)})...`, ); if (packageJson.dependencies && packageJson.dependencies[name]) { @@ -306,11 +310,8 @@ function _performUpdate( const newContent = JSON.stringify(packageJson, null, 2); if (packageJsonContent.toString() != newContent || migrateOnly) { - let installTask: TaskId[] = []; if (!migrateOnly) { - // If something changed, also hook up the task. tree.overwrite('/package.json', JSON.stringify(packageJson, null, 2)); - installTask = [context.addTask(new NodePackageInstallTask())]; } const externalMigrations: {}[] = []; @@ -324,70 +325,27 @@ function _performUpdate( return; } - const collection = ( - target.updateMetadata.migrations.match(/^[./]/) - ? name + '/' - : '' - ) + target.updateMetadata.migrations; - - if (migrateExternal) { - externalMigrations.push({ - package: name, - collection, - from: installed.version, - to: target.version, - }); + const collection = + (target.updateMetadata.migrations.match(/^[./]/) ? name + '/' : '') + + target.updateMetadata.migrations; - return; - } + externalMigrations.push({ + package: name, + collection, + from: installed.version, + to: target.version, + }); - context.addTask(new RunSchematicTask('@schematics/update', 'migrate', { - package: name, - collection, - from: installed.version, - to: target.version, - }), - installTask, - ); + return; }); if (externalMigrations.length > 0) { - // tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any (global as any).externalMigrations = externalMigrations; } } } -function _migrateOnly( - info: PackageInfo | undefined, - context: SchematicContext, - from: string, - to?: string, -) { - if (!info) { - return; - } - - const target = info.installed; - if (!target || !target.updateMetadata.migrations) { - return; - } - - const collection = ( - target.updateMetadata.migrations.match(/^[./]/) - ? info.name + '/' - : '' - ) + target.updateMetadata.migrations; - - context.addTask(new RunSchematicTask('@schematics/update', 'migrate', { - package: info.name, - collection, - from: from, - to: to || target.version, - }), - ); -} - function _getUpdateMetadata( packageJson: JsonSchemaForNpmPackageJsonFiles, logger: logging.LoggerApi, @@ -407,19 +365,20 @@ function _getUpdateMetadata( const packageGroup = metadata['packageGroup']; // Verify that packageGroup is an array of strings or an map of versions. This is not an error // but we still warn the user and ignore the packageGroup keys. - if (Array.isArray(packageGroup) && packageGroup.every(x => typeof x == 'string')) { + if (Array.isArray(packageGroup) && packageGroup.every((x) => typeof x == 'string')) { result.packageGroup = packageGroup.reduce((group, name) => { group[name] = packageJson.version; return group; }, result.packageGroup); - } else if (typeof packageGroup == 'object' && packageGroup - && Object.values(packageGroup).every(x => typeof x == 'string')) { + } else if ( + typeof packageGroup == 'object' && + packageGroup && + Object.values(packageGroup).every((x) => typeof x == 'string') + ) { result.packageGroup = packageGroup; } else { - logger.warn( - `packageGroup metadata of package ${packageJson.name} is malformed. Ignoring.`, - ); + logger.warn(`packageGroup metadata of package ${packageJson.name} is malformed. Ignoring.`); } result.packageGroupName = Object.keys(result.packageGroup)[0]; @@ -432,12 +391,12 @@ function _getUpdateMetadata( if (metadata['requirements']) { const requirements = metadata['requirements']; // Verify that requirements are - if (typeof requirements != 'object' - || Array.isArray(requirements) - || Object.keys(requirements).some(name => typeof requirements[name] != 'string')) { - logger.warn( - `requirements metadata of package ${packageJson.name} is malformed. Ignoring.`, - ); + if ( + typeof requirements != 'object' || + Array.isArray(requirements) || + Object.keys(requirements).some((name) => typeof requirements[name] != 'string') + ) { + logger.warn(`requirements metadata of package ${packageJson.name} is malformed. Ignoring.`); } else { result.requirements = requirements; } @@ -455,7 +414,6 @@ function _getUpdateMetadata( return result; } - function _usageMessage( options: UpdateSchema, infoMap: Map, @@ -464,10 +422,39 @@ function _usageMessage( const packageGroups = new Map(); const packagesToUpdate = [...infoMap.entries()] .map(([name, info]) => { - const tag = options.next - ? (info.npmPackageJson['dist-tags']['next'] ? 'next' : 'latest') : 'latest'; - const version = info.npmPackageJson['dist-tags'][tag]; - const target = info.npmPackageJson.versions[version]; + let tag = options.next + ? info.npmPackageJson['dist-tags']['next'] + ? 'next' + : 'latest' + : 'latest'; + let version = info.npmPackageJson['dist-tags'][tag]; + let target = info.npmPackageJson.versions[version]; + + const versionDiff = semver.diff(info.installed.version, version); + if ( + versionDiff !== 'patch' && + versionDiff !== 'minor' && + /^@(?:angular|nguniversal)\//.test(name) + ) { + const installedMajorVersion = semver.parse(info.installed.version)?.major; + const toInstallMajorVersion = semver.parse(version)?.major; + if ( + installedMajorVersion !== undefined && + toInstallMajorVersion !== undefined && + installedMajorVersion < toInstallMajorVersion - 1 + ) { + const nextMajorVersion = `${installedMajorVersion + 1}.`; + const nextMajorVersions = Object.keys(info.npmPackageJson.versions) + .filter((v) => v.startsWith(nextMajorVersion)) + .sort((a, b) => (a > b ? -1 : 1)); + + if (nextMajorVersions.length) { + version = nextMajorVersions[0]; + target = info.npmPackageJson.versions[version]; + tag = ''; + } + } + } return { name, @@ -477,8 +464,8 @@ function _usageMessage( target, }; }) - .filter(({ name, info, version, target }) => { - return (target && semver.compare(info.installed.version, version) < 0); + .filter(({ info, version, target }) => { + return target && semver.compare(info.installed.version, version) < 0; }) .filter(({ target }) => { return target['ng-update']; @@ -487,8 +474,8 @@ function _usageMessage( // Look for packageGroup. if (target['ng-update'] && target['ng-update']['packageGroup']) { const packageGroup = target['ng-update']['packageGroup']; - const packageGroupName = target['ng-update']['packageGroupName'] - || target['ng-update']['packageGroup'][0]; + const packageGroupName = + target['ng-update']['packageGroupName'] || target['ng-update']['packageGroup'][0]; if (packageGroupName) { if (packageGroups.has(name)) { return null; @@ -501,14 +488,16 @@ function _usageMessage( } let command = `ng update ${name}`; - if (tag == 'next') { + if (!tag) { + command += `@${semver.parse(version)?.major || version}`; + } else if (tag == 'next') { command += ' --next'; } return [name, `${info.installed.version} -> ${version} `, command]; }) - .filter(x => x !== null) - .sort((a, b) => a && b ? a[0].localeCompare(b[0]) : 0); + .filter((x) => x !== null) + .sort((a, b) => (a && b ? a[0].localeCompare(b[0]) : 0)); if (packagesToUpdate.length == 0) { logger.info('We analyzed your package.json and everything seems to be in order. Good work!'); @@ -516,24 +505,21 @@ function _usageMessage( return; } - logger.info( - 'We analyzed your package.json, there are some packages to update:\n', - ); + logger.info('We analyzed your package.json, there are some packages to update:\n'); // Find the largest name to know the padding needed. - let namePad = Math.max(...[...infoMap.keys()].map(x => x.length)) + 2; + let namePad = Math.max(...[...infoMap.keys()].map((x) => x.length)) + 2; if (!Number.isFinite(namePad)) { namePad = 30; } const pads = [namePad, 25, 0]; logger.info( - ' ' - + ['Name', 'Version', 'Command to update'].map((x, i) => x.padEnd(pads[i])).join(''), + ' ' + ['Name', 'Version', 'Command to update'].map((x, i) => x.padEnd(pads[i])).join(''), ); - logger.info(' ' + '-'.repeat(pads.reduce((s, x) => s += x, 0) + 20)); + logger.info(' ' + '-'.repeat(pads.reduce((s, x) => (s += x), 0) + 20)); - packagesToUpdate.forEach(fields => { + packagesToUpdate.forEach((fields) => { if (!fields) { return; } @@ -542,14 +528,13 @@ function _usageMessage( }); logger.info( - `\nThere might be additional packages which don't provide 'ng update' capabilities that are outdated.\n` - + `You can update the additional packages by running the update command of your package manager.`, + `\nThere might be additional packages which don't provide 'ng update' capabilities that are outdated.\n` + + `You can update the additional packages by running the update command of your package manager.`, ); return; } - function _buildPackageInfo( tree: Tree, packages: Map, @@ -560,9 +545,7 @@ function _buildPackageInfo( const name = npmPackageJson.name; const packageJsonRange = allDependencies.get(name); if (!packageJsonRange) { - throw new SchematicsException( - `Package ${JSON.stringify(name)} was not found in package.json.`, - ); + throw new SchematicsException(`Package ${JSON.stringify(name)} was not found in package.json.`); } // Find out the currently installed version. Either from the package.json or the node_modules/ @@ -575,10 +558,7 @@ function _buildPackageInfo( } if (!installedVersion) { // Find the version from NPM that fits the range to max. - installedVersion = semver.maxSatisfying( - Object.keys(npmPackageJson.versions), - packageJsonRange, - ); + installedVersion = semver.maxSatisfying(Object.keys(npmPackageJson.versions), packageJsonRange); } if (!installedVersion) { @@ -615,10 +595,10 @@ function _buildPackageInfo( const target: PackageVersionInfo | undefined = targetVersion ? { - version: targetVersion, - packageJson: npmPackageJson.versions[targetVersion], - updateMetadata: _getUpdateMetadata(npmPackageJson.versions[targetVersion], logger), - } + version: targetVersion, + packageJson: npmPackageJson.versions[targetVersion], + updateMetadata: _getUpdateMetadata(npmPackageJson.versions[targetVersion], logger), + } : undefined; // Check if there's an installed version. @@ -635,7 +615,6 @@ function _buildPackageInfo( }; } - function _buildPackageList( options: UpdateSchema, projectDeps: Map, @@ -644,9 +623,7 @@ function _buildPackageList( // Parse the packages options to set the targeted version. const packages = new Map(); const commandLinePackages = - (options.packages && options.packages.length > 0) - ? options.packages - : []; + options.packages && options.packages.length > 0 ? options.packages : []; for (const pkg of commandLinePackages) { // Split the version asked on command line. @@ -670,7 +647,6 @@ function _buildPackageList( return packages; } - function _addPackageGroup( tree: Tree, packages: Map, @@ -685,9 +661,10 @@ function _addPackageGroup( const info = _buildPackageInfo(tree, packages, allDependencies, npmPackageJson, logger); - const version = (info.target && info.target.version) - || npmPackageJson['dist-tags'][maybePackage] - || maybePackage; + const version = + (info.target && info.target.version) || + npmPackageJson['dist-tags'][maybePackage] || + maybePackage; if (!npmPackageJson.versions[version]) { return; } @@ -700,7 +677,7 @@ function _addPackageGroup( if (!packageGroup) { return; } - if (Array.isArray(packageGroup) && !packageGroup.some(x => typeof x != 'string')) { + if (Array.isArray(packageGroup) && !packageGroup.some((x) => typeof x != 'string')) { packageGroup = packageGroup.reduce((acc, curr) => { acc[curr] = maybePackage; @@ -709,9 +686,10 @@ function _addPackageGroup( } // Only need to check if it's an object because we set it right the time before. - if (typeof packageGroup != 'object' - || packageGroup === null - || Object.values(packageGroup).some(v => typeof v != 'string') + if ( + typeof packageGroup != 'object' || + packageGroup === null || + Object.values(packageGroup).some((v) => typeof v != 'string') ) { logger.warn(`packageGroup metadata of package ${npmPackageJson.name} is malformed.`); @@ -719,9 +697,9 @@ function _addPackageGroup( } Object.keys(packageGroup) - .filter(name => !packages.has(name)) // Don't override names from the command line. - .filter(name => allDependencies.has(name)) // Remove packages that aren't installed. - .forEach(name => { + .filter((name) => !packages.has(name)) // Don't override names from the command line. + .filter((name) => allDependencies.has(name)) // Remove packages that aren't installed. + .forEach((name) => { packages.set(name, packageGroup[name]); }); } @@ -747,9 +725,10 @@ function _addPeerDependencies( const info = _buildPackageInfo(tree, packages, allDependencies, npmPackageJson, logger); - const version = (info.target && info.target.version) - || npmPackageJson['dist-tags'][maybePackage] - || maybePackage; + const version = + (info.target && info.target.version) || + npmPackageJson['dist-tags'][maybePackage] || + maybePackage; if (!npmPackageJson.versions[version]) { return; } @@ -778,7 +757,6 @@ function _addPeerDependencies( } } - function _getAllDependencies(tree: Tree): Array { const packageJsonContent = tree.read('/package.json'); if (!packageJsonContent) { @@ -793,9 +771,9 @@ function _getAllDependencies(tree: Tree): Array } return [ - ...Object.entries(packageJson.peerDependencies || {}) as Array<[string, VersionRange]>, - ...Object.entries(packageJson.devDependencies || {}) as Array<[string, VersionRange]>, - ...Object.entries(packageJson.dependencies || {}) as Array<[string, VersionRange]>, + ...(Object.entries(packageJson.peerDependencies || {}) as Array<[string, VersionRange]>), + ...(Object.entries(packageJson.devDependencies || {}) as Array<[string, VersionRange]>), + ...(Object.entries(packageJson.dependencies || {}) as Array<[string, VersionRange]>), ]; } @@ -828,7 +806,7 @@ function isPkgFromRegistry(name: string, specifier: string): boolean { return !!result.registry; } -export default function(options: UpdateSchema): Rule { +export default function (options: UpdateSchema): Rule { if (!options.packages) { // We cannot just return this because we need to fetch the packages from NPM still for the // help/guide to show. @@ -852,48 +830,52 @@ export default function(options: UpdateSchema): Rule { return async (tree: Tree, context: SchematicContext) => { const logger = context.logger; - const npmDeps = new Map(_getAllDependencies(tree).filter(([name, specifier]) => { - try { - return isPkgFromRegistry(name, specifier); - } catch { - logger.warn(`Package ${name} was not found on the registry. Skipping.`); - - return false; - } - })); + const npmDeps = new Map( + _getAllDependencies(tree).filter(([name, specifier]) => { + try { + return isPkgFromRegistry(name, specifier); + } catch { + logger.warn(`Package ${name} was not found on the registry. Skipping.`); + + return false; + } + }), + ); const packages = _buildPackageList(options, npmDeps, logger); // Grab all package.json from the npm repository. This requires a lot of HTTP calls so we // try to parallelize as many as possible. - const allPackageMetadata = await Promise.all(Array.from(npmDeps.keys()).map(depName => getNpmPackageJson( - depName, - logger, - { registryUrl: options.registry, usingYarn, verbose: options.verbose }, - ))); + const allPackageMetadata = await Promise.all( + Array.from(npmDeps.keys()).map((depName) => + getNpmPackageJson(depName, logger, { + registry: options.registry, + usingYarn, + verbose: options.verbose, + }), + ), + ); // Build a map of all dependencies and their packageJson. - const npmPackageJsonMap = allPackageMetadata.reduce( - (acc, npmPackageJson) => { - // If the package was not found on the registry. It could be private, so we will just - // ignore. If the package was part of the list, we will error out, but will simply ignore - // if it's either not requested (so just part of package.json. silently) or if it's a - // `--all` situation. There is an edge case here where a public package peer depends on a - // private one, but it's rare enough. - if (!npmPackageJson.name) { - if (npmPackageJson.requestedName && packages.has(npmPackageJson.requestedName)) { - throw new SchematicsException( - `Package ${JSON.stringify(npmPackageJson.requestedName)} was not found on the ` - + 'registry. Cannot continue as this may be an error.'); - } - } else { - // If a name is present, it is assumed to be fully populated - acc.set(npmPackageJson.name, npmPackageJson as NpmRepositoryPackageJson); + const npmPackageJsonMap = allPackageMetadata.reduce((acc, npmPackageJson) => { + // If the package was not found on the registry. It could be private, so we will just + // ignore. If the package was part of the list, we will error out, but will simply ignore + // if it's either not requested (so just part of package.json. silently) or if it's a + // `--all` situation. There is an edge case here where a public package peer depends on a + // private one, but it's rare enough. + if (!npmPackageJson.name) { + if (npmPackageJson.requestedName && packages.has(npmPackageJson.requestedName)) { + throw new SchematicsException( + `Package ${JSON.stringify(npmPackageJson.requestedName)} was not found on the ` + + 'registry. Cannot continue as this may be an error.', + ); } + } else { + // If a name is present, it is assumed to be fully populated + acc.set(npmPackageJson.name, npmPackageJson as NpmRepositoryPackageJson); + } - return acc; - }, - new Map(), - ); + return acc; + }, new Map()); // Augment the command line package list with packageGroups and forward peer dependencies. // Each added package may uncover new package groups and peer dependencies, so we must @@ -919,24 +901,13 @@ export default function(options: UpdateSchema): Rule { // Now that we have all the information, check the flags. if (packages.size > 0) { if (options.migrateOnly && options.from && options.packages) { - _migrateOnly( - packageInfoMap.get(options.packages[0]), - context, - options.from, - options.to, - ); - return; } - const sublog = new logging.LevelCapLogger( - 'validation', - logger.createChild(''), - 'warn', - ); + const sublog = new logging.LevelCapLogger('validation', logger.createChild(''), 'warn'); _validateUpdatePackages(packageInfoMap, !!options.force, !!options.next, sublog); - _performUpdate(tree, context, packageInfoMap, logger, !!options.migrateOnly, !!options.migrateExternal); + _performUpdate(tree, context, packageInfoMap, logger, !!options.migrateOnly); } else { _usageMessage(options, packageInfoMap, logger); } diff --git a/packages/angular/cli/src/commands/update/schematic/index_spec.ts b/packages/angular/cli/src/commands/update/schematic/index_spec.ts index dfa1dd51695d..c133647bb2a3 100644 --- a/packages/angular/cli/src/commands/update/schematic/index_spec.ts +++ b/packages/angular/cli/src/commands/update/schematic/index_spec.ts @@ -1,20 +1,18 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ -// tslint:disable:no-big-function import { normalize, virtualFs } from '@angular-devkit/core'; import { HostTree } from '@angular-devkit/schematics'; import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; -import { map } from 'rxjs/operators'; // tslint:disable-line: no-implicit-dependencies +import { map } from 'rxjs/operators'; import * as semver from 'semver'; import { angularMajorCompatGuarantee } from './index'; - describe('angularMajorCompatGuarantee', () => { [ '5.0.0', @@ -26,7 +24,7 @@ describe('angularMajorCompatGuarantee', () => { '6.1.0-beta.0', '6.1.0-rc.0', '6.10.11', - ].forEach(golden => { + ].forEach((golden) => { it('works with ' + JSON.stringify(golden), () => { expect(semver.satisfies(golden, angularMajorCompatGuarantee('^5.0.0'))).toBeTruthy(); }); @@ -36,7 +34,7 @@ describe('angularMajorCompatGuarantee', () => { describe('@schematics/update', () => { const schematicRunner = new SchematicTestRunner( '@schematics/update', - require.resolve('../collection.json'), + require.resolve('./collection.json'), ); let host: virtualFs.test.TestHost; let appTree: UnitTestTree = new UnitTestTree(new HostTree()); @@ -53,44 +51,63 @@ describe('@schematics/update', () => { appTree = new UnitTestTree(new HostTree(host)); }); - it('ignores dependencies not hosted on the NPM registry', done => { - const tree = new UnitTestTree(new HostTree(new virtualFs.test.TestHost({ - '/package.json': `{ + it('ignores dependencies not hosted on the NPM registry', (done) => { + const tree = new UnitTestTree( + new HostTree( + new virtualFs.test.TestHost({ + '/package.json': `{ "name": "blah", "dependencies": { "@angular-devkit-tests/update-base": "file:update-base-1.0.0.tgz" } }`, - }))); + }), + ), + ); - schematicRunner.runSchematicAsync('update', undefined, tree).pipe( - map(t => { - const packageJson = JSON.parse(t.readContent('/package.json')); - expect(packageJson['dependencies']['@angular-devkit-tests/update-base']) - .toBe('file:update-base-1.0.0.tgz'); - }), - ).toPromise().then(done, done.fail); + schematicRunner + .runSchematicAsync('update', undefined, tree) + .pipe( + map((t) => { + const packageJson = JSON.parse(t.readContent('/package.json')); + expect(packageJson['dependencies']['@angular-devkit-tests/update-base']).toBe( + 'file:update-base-1.0.0.tgz', + ); + }), + ) + .toPromise() + .then(done, done.fail); }, 45000); it('should not error with yarn 2.0 protocols', async () => { - const tree = new UnitTestTree(new HostTree(new virtualFs.test.TestHost({ - '/package.json': `{ + const tree = new UnitTestTree( + new HostTree( + new virtualFs.test.TestHost({ + '/package.json': `{ "name": "blah", "dependencies": { "src": "src@link:./src", "@angular-devkit-tests/update-base": "1.0.0" } }`, - }))); + }), + ), + ); - const newTree = await schematicRunner.runSchematicAsync('update', { - packages: ['@angular-devkit-tests/update-base'], - }, tree).toPromise(); + const newTree = await schematicRunner + .runSchematicAsync( + 'update', + { + packages: ['@angular-devkit-tests/update-base'], + }, + tree, + ) + .toPromise(); const { dependencies } = JSON.parse(newTree.readContent('/package.json')); expect(dependencies['@angular-devkit-tests/update-base']).toBe('1.1.0'); }); - it('updates Angular as compatible with Angular N-1', done => { + it('updates Angular as compatible with Angular N-1', (done) => { // Add the basic migration package. const content = virtualFs.fileBufferToString(host.sync.read(normalize('/package.json'))); const packageJson = JSON.parse(content); @@ -104,33 +121,25 @@ describe('@schematics/update', () => { virtualFs.stringToFileBuffer(JSON.stringify(packageJson)), ); - schematicRunner.runSchematicAsync('update', { - packages: ['@angular/core@^6.0.0'], - }, appTree).pipe( - map(tree => { - const packageJson = JSON.parse(tree.readContent('/package.json')); - expect(packageJson['dependencies']['@angular/core'][0]).toBe('6'); - - // Check install task. - expect(schematicRunner.tasks).toEqual([ - { - name: 'node-package', - options: jasmine.objectContaining({ - command: 'install', - }), - }, - { - name: 'run-schematic', - options: jasmine.objectContaining({ - name: 'migrate', - }), - }, - ]); - }), - ).toPromise().then(done, done.fail); + schematicRunner + .runSchematicAsync( + 'update', + { + packages: ['@angular/core@^6.0.0'], + }, + appTree, + ) + .pipe( + map((tree) => { + const packageJson = JSON.parse(tree.readContent('/package.json')); + expect(packageJson['dependencies']['@angular/core'][0]).toBe('6'); + }), + ) + .toPromise() + .then(done, done.fail); }, 45000); - it('updates Angular as compatible with Angular N-1 (2)', done => { + it('updates Angular as compatible with Angular N-1 (2)', (done) => { // Add the basic migration package. const content = virtualFs.fileBufferToString(host.sync.read(normalize('/package.json'))); const packageJson = JSON.parse(content); @@ -150,33 +159,25 @@ describe('@schematics/update', () => { virtualFs.stringToFileBuffer(JSON.stringify(packageJson)), ); - schematicRunner.runSchematicAsync('update', { - packages: ['@angular/core@^6.0.0'], - }, appTree).pipe( - map(tree => { - const packageJson = JSON.parse(tree.readContent('/package.json')); - expect(packageJson['dependencies']['@angular/core'][0]).toBe('6'); - expect(packageJson['dependencies']['rxjs'][0]).toBe('6'); - expect(packageJson['dependencies']['typescript'][0]).toBe('2'); - expect(packageJson['dependencies']['typescript'][2]).not.toBe('4'); - - // Check install task. - expect(schematicRunner.tasks).toEqual([ - { - name: 'node-package', - options: jasmine.objectContaining({ - command: 'install', - }), - }, - { - name: 'run-schematic', - options: jasmine.objectContaining({ - name: 'migrate', - }), - }, - ]); - }), - ).toPromise().then(done, done.fail); + schematicRunner + .runSchematicAsync( + 'update', + { + packages: ['@angular/core@^6.0.0'], + }, + appTree, + ) + .pipe( + map((tree) => { + const packageJson = JSON.parse(tree.readContent('/package.json')); + expect(packageJson['dependencies']['@angular/core'][0]).toBe('6'); + expect(packageJson['dependencies']['rxjs'][0]).toBe('6'); + expect(packageJson['dependencies']['typescript'][0]).toBe('2'); + expect(packageJson['dependencies']['typescript'][2]).not.toBe('4'); + }), + ) + .toPromise() + .then(done, done.fail); }, 45000); it('uses packageGroup for versioning', async () => { @@ -191,29 +192,26 @@ describe('@schematics/update', () => { virtualFs.stringToFileBuffer(JSON.stringify(packageJson)), ); - await schematicRunner.runSchematicAsync('update', { - packages: ['@angular-devkit-tests/update-package-group-1'], - }, appTree).pipe( - map(tree => { - const packageJson = JSON.parse(tree.readContent('/package.json')); - const deps = packageJson['dependencies']; - expect(deps['@angular-devkit-tests/update-package-group-1']).toBe('1.2.0'); - expect(deps['@angular-devkit-tests/update-package-group-2']).toBe('2.0.0'); - - // Check install task. - expect(schematicRunner.tasks).toEqual([ - { - name: 'node-package', - options: jasmine.objectContaining({ - command: 'install', - }), - }, - ]); - }), - ).toPromise(); + await schematicRunner + .runSchematicAsync( + 'update', + { + packages: ['@angular-devkit-tests/update-package-group-1'], + }, + appTree, + ) + .pipe( + map((tree) => { + const packageJson = JSON.parse(tree.readContent('/package.json')); + const deps = packageJson['dependencies']; + expect(deps['@angular-devkit-tests/update-package-group-1']).toBe('1.2.0'); + expect(deps['@angular-devkit-tests/update-package-group-2']).toBe('2.0.0'); + }), + ) + .toPromise(); }, 45000); - it('can migrate only', done => { + it('can migrate only', (done) => { // Add the basic migration package. const content = virtualFs.fileBufferToString(host.sync.read(normalize('/package.json'))); const packageJson = JSON.parse(content); @@ -223,30 +221,29 @@ describe('@schematics/update', () => { virtualFs.stringToFileBuffer(JSON.stringify(packageJson)), ); - schematicRunner.runSchematicAsync('update', { - packages: ['@angular-devkit-tests/update-migrations'], - migrateOnly: true, - }, appTree).pipe( - map(tree => { - const packageJson = JSON.parse(tree.readContent('/package.json')); - expect(packageJson['dependencies']['@angular-devkit-tests/update-base']).toBe('1.0.0'); - expect(packageJson['dependencies']['@angular-devkit-tests/update-migrations']) - .toBe('1.0.0'); - - // Check install task. - expect(schematicRunner.tasks).toEqual([ - { - name: 'run-schematic', - options: jasmine.objectContaining({ - name: 'migrate', - }), - }, - ]); - }), - ).toPromise().then(done, done.fail); + schematicRunner + .runSchematicAsync( + 'update', + { + packages: ['@angular-devkit-tests/update-migrations'], + migrateOnly: true, + }, + appTree, + ) + .pipe( + map((tree) => { + const packageJson = JSON.parse(tree.readContent('/package.json')); + expect(packageJson['dependencies']['@angular-devkit-tests/update-base']).toBe('1.0.0'); + expect(packageJson['dependencies']['@angular-devkit-tests/update-migrations']).toBe( + '1.0.0', + ); + }), + ) + .toPromise() + .then(done, done.fail); }, 45000); - it('can migrate from only', done => { + it('can migrate from only', (done) => { // Add the basic migration package. const content = virtualFs.fileBufferToString(host.sync.read(normalize('/package.json'))); const packageJson = JSON.parse(content); @@ -256,34 +253,29 @@ describe('@schematics/update', () => { virtualFs.stringToFileBuffer(JSON.stringify(packageJson)), ); - schematicRunner.runSchematicAsync('update', { - packages: ['@angular-devkit-tests/update-migrations'], - migrateOnly: true, - from: '0.1.2', - }, appTree).pipe( - map(tree => { - const packageJson = JSON.parse(tree.readContent('/package.json')); - expect(packageJson['dependencies']['@angular-devkit-tests/update-migrations']) - .toBe('1.6.0'); - - // Check install task. - expect(schematicRunner.tasks).toEqual([ - { - name: 'run-schematic', - options: jasmine.objectContaining({ - name: 'migrate', - options: jasmine.objectContaining({ - from: '0.1.2', - to: '1.6.0', - }), - }), - }, - ]); - }), - ).toPromise().then(done, done.fail); + schematicRunner + .runSchematicAsync( + 'update', + { + packages: ['@angular-devkit-tests/update-migrations'], + migrateOnly: true, + from: '0.1.2', + }, + appTree, + ) + .pipe( + map((tree) => { + const packageJson = JSON.parse(tree.readContent('/package.json')); + expect(packageJson['dependencies']['@angular-devkit-tests/update-migrations']).toBe( + '1.6.0', + ); + }), + ) + .toPromise() + .then(done, done.fail); }, 45000); - it('can install and migrate with --from (short version number)', done => { + it('can install and migrate with --from (short version number)', (done) => { // Add the basic migration package. const content = virtualFs.fileBufferToString(host.sync.read(normalize('/package.json'))); const packageJson = JSON.parse(content); @@ -293,34 +285,29 @@ describe('@schematics/update', () => { virtualFs.stringToFileBuffer(JSON.stringify(packageJson)), ); - schematicRunner.runSchematicAsync('update', { - packages: ['@angular-devkit-tests/update-migrations'], - migrateOnly: true, - from: '0', - }, appTree).pipe( - map(tree => { - const packageJson = JSON.parse(tree.readContent('/package.json')); - expect(packageJson['dependencies']['@angular-devkit-tests/update-migrations']) - .toBe('1.6.0'); - - // Check install task. - expect(schematicRunner.tasks).toEqual([ - { - name: 'run-schematic', - options: jasmine.objectContaining({ - name: 'migrate', - options: jasmine.objectContaining({ - from: '0.0.0', - to: '1.6.0', - }), - }), - }, - ]); - }), - ).toPromise().then(done, done.fail); + schematicRunner + .runSchematicAsync( + 'update', + { + packages: ['@angular-devkit-tests/update-migrations'], + migrateOnly: true, + from: '0', + }, + appTree, + ) + .pipe( + map((tree) => { + const packageJson = JSON.parse(tree.readContent('/package.json')); + expect(packageJson['dependencies']['@angular-devkit-tests/update-migrations']).toBe( + '1.6.0', + ); + }), + ) + .toPromise() + .then(done, done.fail); }, 45000); - it('validates peer dependencies', done => { + it('validates peer dependencies', (done) => { const content = virtualFs.fileBufferToString(host.sync.read(normalize('/package.json'))); const packageJson = JSON.parse(content); const dependencies = packageJson['dependencies']; @@ -335,21 +322,31 @@ describe('@schematics/update', () => { ); const messages: string[] = []; - schematicRunner.logger.subscribe(x => messages.push(x.message)); + schematicRunner.logger.subscribe((x) => messages.push(x.message)); const hasPeerdepMsg = (dep: string) => - messages.some(str => str.includes(`missing peer dependency of "${dep}"`)); + messages.some((str) => str.includes(`missing peer dependency of "${dep}"`)); - schematicRunner.runSchematicAsync('update', { - packages: ['@angular-devkit/build-angular'], - next: true, - }, appTree).pipe( - map(() => { - expect(hasPeerdepMsg('@angular/compiler-cli')) - .toBeTruthy(`Should show @angular/compiler-cli message.`); - expect(hasPeerdepMsg('typescript')).toBeTruthy(`Should show typescript message.`); - expect(hasPeerdepMsg('@angular/localize')) - .toBeFalsy(`Should not show @angular/localize message.`); - }), - ).toPromise().then(done, done.fail); + schematicRunner + .runSchematicAsync( + 'update', + { + packages: ['@angular-devkit/build-angular'], + next: true, + }, + appTree, + ) + .pipe( + map(() => { + expect(hasPeerdepMsg('@angular/compiler-cli')).toBeTruthy( + `Should show @angular/compiler-cli message.`, + ); + expect(hasPeerdepMsg('typescript')).toBeTruthy(`Should show typescript message.`); + expect(hasPeerdepMsg('@angular/localize')).toBeFalsy( + `Should not show @angular/localize message.`, + ); + }), + ) + .toPromise() + .then(done, done.fail); }, 45000); }); diff --git a/packages/angular/cli/src/commands/update/schematic/npm-package-json.ts b/packages/angular/cli/src/commands/update/schematic/npm-package-json.ts deleted file mode 100644 index 675c45c0fffb..000000000000 --- a/packages/angular/cli/src/commands/update/schematic/npm-package-json.ts +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @license - * Copyright Google Inc. 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.io/license - */ -import { JsonSchemaForNpmPackageJsonFiles } from './package-json'; - -export interface NpmRepositoryPackageJson { - name: string; - requestedName: string; - description: string; - - 'dist-tags': { - [name: string]: string; - }; - versions: { - [version: string]: JsonSchemaForNpmPackageJsonFiles; - }; - time: { - modified: string; - created: string; - - [version: string]: string; - }; -} diff --git a/packages/angular/cli/src/commands/update/schematic/npm.ts b/packages/angular/cli/src/commands/update/schematic/npm.ts deleted file mode 100644 index d7e48ab7737d..000000000000 --- a/packages/angular/cli/src/commands/update/schematic/npm.ts +++ /dev/null @@ -1,170 +0,0 @@ -/** - * @license - * Copyright Google Inc. 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.io/license - */ -import { logging } from '@angular-devkit/core'; -import { existsSync, readFileSync } from 'fs'; -import { homedir } from 'os'; -import * as path from 'path'; -import { NpmRepositoryPackageJson } from './npm-package-json'; - -const ini = require('ini'); -const lockfile = require('@yarnpkg/lockfile'); -const pacote = require('pacote'); - -type PackageManagerOptions = Record; - -const npmPackageJsonCache = new Map>>(); -let npmrc: PackageManagerOptions; - -function readOptions( - logger: logging.LoggerApi, - yarn = false, - showPotentials = false, -): PackageManagerOptions { - const cwd = process.cwd(); - const baseFilename = yarn ? 'yarnrc' : 'npmrc'; - const dotFilename = '.' + baseFilename; - - let globalPrefix: string; - if (process.env.PREFIX) { - globalPrefix = process.env.PREFIX; - } else { - globalPrefix = path.dirname(process.execPath); - if (process.platform !== 'win32') { - globalPrefix = path.dirname(globalPrefix); - } - } - - const defaultConfigLocations = [ - path.join(globalPrefix, 'etc', baseFilename), - path.join(homedir(), dotFilename), - ]; - - const projectConfigLocations: string[] = [ - path.join(cwd, dotFilename), - ]; - const root = path.parse(cwd).root; - for (let curDir = path.dirname(cwd); curDir && curDir !== root; curDir = path.dirname(curDir)) { - projectConfigLocations.unshift(path.join(curDir, dotFilename)); - } - - if (showPotentials) { - logger.info(`Locating potential ${baseFilename} files:`); - } - - const options: PackageManagerOptions = {}; - for (const location of [...defaultConfigLocations, ...projectConfigLocations]) { - if (existsSync(location)) { - if (showPotentials) { - logger.info(`Trying '${location}'...found.`); - } - - const data = readFileSync(location, 'utf8'); - // Normalize RC options that are needed by 'npm-registry-fetch'. - // See: https://github.com/npm/npm-registry-fetch/blob/ebddbe78a5f67118c1f7af2e02c8a22bcaf9e850/index.js#L99-L126 - const rcConfig: PackageManagerOptions = yarn ? lockfile.parse(data) : ini.parse(data); - for (const [key, value] of Object.entries(rcConfig)) { - switch (key) { - case 'noproxy': - case 'no-proxy': - options['noProxy'] = value; - break; - case 'maxsockets': - options['maxSockets'] = value; - break; - case 'https-proxy': - case 'proxy': - options['proxy'] = value; - break; - case 'strict-ssl': - options['strictSSL'] = value; - break; - case 'local-address': - options['localAddress'] = value; - break; - case 'cafile': - if (typeof value === 'string') { - const cafile = path.resolve(path.dirname(location), value); - try { - options['ca'] = readFileSync(cafile, 'utf8').replace(/\r?\n/g, '\n'); - } catch { } - } - break; - default: - options[key] = value; - break; - } - } - } else if (showPotentials) { - logger.info(`Trying '${location}'...not found.`); - } - } - - // Substitute any environment variable references - for (const key in options) { - const value = options[key]; - if (typeof value === 'string') { - options[key] = value.replace(/\$\{([^\}]+)\}/, (_, name) => process.env[name] || ''); - } - } - - return options; -} - -/** - * Get the NPM repository's package.json for a package. This is p - * @param {string} packageName The package name to fetch. - * @param {string} registryUrl The NPM Registry URL to use. - * @param {LoggerApi} logger A logger instance to log debug information. - * @returns An observable that will put the pacakge.json content. - * @private - */ -export function getNpmPackageJson( - packageName: string, - logger: logging.LoggerApi, - options?: { - registryUrl?: string; - usingYarn?: boolean; - verbose?: boolean; - }, -): Promise> { - const cachedResponse = npmPackageJsonCache.get(packageName); - if (cachedResponse) { - return cachedResponse; - } - - if (!npmrc) { - try { - npmrc = readOptions(logger, false, options && options.verbose); - } catch { } - - if (options && options.usingYarn) { - try { - npmrc = { ...npmrc, ...readOptions(logger, true, options && options.verbose) }; - } catch { } - } - } - - const resultPromise: Promise = pacote.packument( - packageName, - { - fullMetadata: true, - ...npmrc, - ...(options && options.registryUrl ? { registry: options.registryUrl } : {}), - }, - ); - - // TODO: find some way to test this - const response = resultPromise.catch((err) => { - logger.warn(err.message || err); - - return { requestedName: packageName }; - }); - npmPackageJsonCache.set(packageName, response); - - return response; -} diff --git a/packages/angular/cli/src/commands/update/schematic/schema.json b/packages/angular/cli/src/commands/update/schematic/schema.json index 1a6378de6485..9811d1a3fe9a 100644 --- a/packages/angular/cli/src/commands/update/schematic/schema.json +++ b/packages/angular/cli/src/commands/update/schematic/schema.json @@ -57,19 +57,8 @@ "description": "The preferred package manager configuration files to use for registry settings.", "type": "string", "default": "npm", - "enum": [ - "npm", - "yarn", - "cnpm", - "pnpm" - ] - }, - "migrateExternal": { - "type": "boolean", - "default": false, - "hidden": true + "enum": ["npm", "yarn", "cnpm", "pnpm"] } }, - "required": [ - ] + "required": [] } diff --git a/packages/angular/cli/utilities/color.ts b/packages/angular/cli/utilities/color.ts index ad77d8230fc7..8ddcadf3d1eb 100644 --- a/packages/angular/cli/utilities/color.ts +++ b/packages/angular/cli/utilities/color.ts @@ -1,15 +1,42 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import * as ansiColors from 'ansi-colors'; import { WriteStream } from 'tty'; type AnsiColors = typeof ansiColors; -const supportsColor = process.stdout instanceof WriteStream && process.stdout.getColorDepth() > 1; + +function supportColor(): boolean { + if (process.env.FORCE_COLOR !== undefined) { + // 2 colors: FORCE_COLOR = 0 (Disables colors), depth 1 + // 16 colors: FORCE_COLOR = 1, depth 4 + // 256 colors: FORCE_COLOR = 2, depth 8 + // 16,777,216 colors: FORCE_COLOR = 3, depth 16 + // See: https://nodejs.org/dist/latest-v12.x/docs/api/tty.html#tty_writestream_getcolordepth_env + // and https://github.com/nodejs/node/blob/b9f36062d7b5c5039498e98d2f2c180dca2a7065/lib/internal/tty.js#L106; + switch (process.env.FORCE_COLOR) { + case '': + case 'true': + case '1': + case '2': + case '3': + return true; + default: + return false; + } + } + + if (process.stdout instanceof WriteStream) { + return process.stdout.getColorDepth() > 1; + } + + return false; +} export function removeColor(text: string): string { // This has been created because when colors.enabled is false unstyle doesn't work @@ -20,6 +47,6 @@ export function removeColor(text: string): string { // Create a separate instance to prevent unintended global changes to the color configuration // Create function is not defined in the typings. See: https://github.com/doowb/ansi-colors/pull/44 const colors = (ansiColors as AnsiColors & { create: () => AnsiColors }).create(); -colors.enabled = supportsColor; +colors.enabled = supportColor(); export { colors }; diff --git a/packages/angular/cli/utilities/config.ts b/packages/angular/cli/utilities/config.ts index 2042e9d903bf..d5ce06a835d4 100644 --- a/packages/angular/cli/utilities/config.ts +++ b/packages/angular/cli/utilities/config.ts @@ -1,10 +1,11 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { json, workspaces } from '@angular-devkit/core'; import { existsSync, readFileSync, statSync, writeFileSync } from 'fs'; import * as os from 'os'; @@ -47,14 +48,24 @@ function getSchemaLocation(): string { export const workspaceSchemaPath = getSchemaLocation(); -const configNames = [ 'angular.json', '.angular.json' ]; +const configNames = ['angular.json', '.angular.json']; const globalFileName = '.angular-config.json'; function xdgConfigHome(home: string, configFile?: string): string { // https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html + const xdgConfigHome = process.env['XDG_CONFIG_HOME'] || path.join(home, '.config'); + const xdgAngularHome = path.join(xdgConfigHome, 'angular'); + + return configFile ? path.join(xdgAngularHome, configFile) : xdgAngularHome; +} + +function xdgConfigHomeOld(home: string): string { + // Check the configuration files in the old location that should be: + // - $XDG_CONFIG_HOME/.angular-config.json (if XDG_CONFIG_HOME is set) + // - $HOME/.config/angular/.angular-config.json (otherwise) const p = process.env['XDG_CONFIG_HOME'] || path.join(home, '.config', 'angular'); - return configFile ? path.join(p, configFile) : p; + return path.join(p, '.angular-config.json'); } function projectFilePath(projectPath?: string): string | null { @@ -77,10 +88,22 @@ function globalFilePath(): string | null { // note that createGlobalSettings() will continue creating // global file in home directory, with this user will have // choice to move change its location to meet XDG convention - const xdgConfig = xdgConfigHome(home, globalFileName); + const xdgConfig = xdgConfigHome(home, 'config.json'); if (existsSync(xdgConfig)) { return xdgConfig; } + // NOTE: This check is for the old configuration location, for more + // information see https://github.com/angular/angular-cli/pull/20556 + const xdgConfigOld = xdgConfigHomeOld(home); + if (existsSync(xdgConfigOld)) { + /* eslint-disable no-console */ + console.warn( + `Old configuration location detected: ${xdgConfigOld}\n` + + `Please move the file to the new location ~/.config/angular/config.json`, + ); + + return xdgConfigOld; + } const p = path.join(home, globalFileName); if (existsSync(p)) { @@ -107,12 +130,12 @@ export class AngularWorkspace { // Temporary helper functions to support refactoring - // tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any getCli(): Record { return (this.workspace.extensions['cli'] as Record) || {}; } - // tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any getProjectCli(projectName: string): Record { const project = this.workspace.projects.get(projectName); @@ -200,7 +223,9 @@ export function getWorkspaceRaw( } export async function validateWorkspace(data: json.JsonObject): Promise { - const schema = readAndParseJson(path.join(__dirname, '../lib/config/schema.json')) as json.schema.JsonSchema; + const schema = readAndParseJson( + path.join(__dirname, '../lib/config/schema.json'), + ) as json.schema.JsonSchema; const { formats } = await import('@angular-devkit/schematics'); const registry = new json.schema.CoreSchemaRegistry(formats.standardFormats); const validator = await registry.compile(schema).toPromise(); diff --git a/packages/angular/cli/utilities/find-up.ts b/packages/angular/cli/utilities/find-up.ts index 81891a96e565..3427d7ba15f4 100644 --- a/packages/angular/cli/utilities/find-up.ts +++ b/packages/angular/cli/utilities/find-up.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license diff --git a/packages/angular/cli/utilities/install-package.ts b/packages/angular/cli/utilities/install-package.ts index ac79d26ceb73..8142135915a5 100644 --- a/packages/angular/cli/utilities/install-package.ts +++ b/packages/angular/cli/utilities/install-package.ts @@ -1,37 +1,79 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ -import { logging } from '@angular-devkit/core'; -import { spawnSync } from 'child_process'; -import { existsSync, mkdtempSync, readFileSync, realpathSync, writeFileSync } from 'fs'; +import { spawn, spawnSync } from 'child_process'; +import { existsSync, mkdtempSync, readFileSync, realpathSync, rmdirSync, writeFileSync } from 'fs'; import { tmpdir } from 'os'; import { join, resolve } from 'path'; -import * as rimraf from 'rimraf'; import { PackageManager } from '../lib/config/workspace-schema'; -import { colors } from '../utilities/color'; import { NgAddSaveDepedency } from '../utilities/package-metadata'; +import { Spinner } from './spinner'; interface PackageManagerOptions { silent: string; saveDev: string; install: string; + installAll?: string; prefix: string; noLockfile: string; } -export function installPackage( +export async function installAllPackages( + packageManager: PackageManager = PackageManager.Npm, + extraArgs: string[] = [], + cwd = process.cwd(), +): Promise<1 | 0> { + const packageManagerArgs = getPackageManagerArguments(packageManager); + + const installArgs: string[] = []; + if (packageManagerArgs.installAll) { + installArgs.push(packageManagerArgs.installAll); + } + installArgs.push(packageManagerArgs.silent); + + const spinner = new Spinner(); + spinner.start('Installing packages...'); + + const bufferedOutput: { stream: NodeJS.WriteStream; data: Buffer }[] = []; + + return new Promise((resolve, reject) => { + const childProcess = spawn(packageManager, [...installArgs, ...extraArgs], { + stdio: 'pipe', + shell: true, + cwd, + }).on('close', (code: number) => { + if (code === 0) { + spinner.succeed('Packages successfully installed.'); + resolve(0); + } else { + spinner.stop(); + bufferedOutput.forEach(({ stream, data }) => stream.write(data)); + spinner.fail('Package install failed, see above.'); + reject(1); + } + }); + + childProcess.stdout?.on('data', (data: Buffer) => + bufferedOutput.push({ stream: process.stdout, data: data }), + ); + childProcess.stderr?.on('data', (data: Buffer) => + bufferedOutput.push({ stream: process.stderr, data: data }), + ); + }); +} + +export async function installPackage( packageName: string, - logger: logging.Logger | undefined, packageManager: PackageManager = PackageManager.Npm, save: Exclude = true, extraArgs: string[] = [], cwd = process.cwd(), -) { +): Promise<1 | 0> { const packageManagerArgs = getPackageManagerArguments(packageManager); const installArgs: string[] = [ @@ -40,43 +82,55 @@ export function installPackage( packageManagerArgs.silent, ]; - logger?.info(colors.green(`Installing packages for tooling via ${packageManager}.`)); + const spinner = new Spinner(); + spinner.start('Installing package...'); if (save === 'devDependencies') { installArgs.push(packageManagerArgs.saveDev); } - - const { status, stderr, stdout, error } = spawnSync(packageManager, [...installArgs, ...extraArgs], { - stdio: 'pipe', - shell: true, - encoding: 'utf8', - cwd, + const bufferedOutput: { stream: NodeJS.WriteStream; data: Buffer }[] = []; + + return new Promise((resolve, reject) => { + const childProcess = spawn(packageManager, [...installArgs, ...extraArgs], { + stdio: 'pipe', + shell: true, + cwd, + }).on('close', (code: number) => { + if (code === 0) { + spinner.succeed('Package successfully installed.'); + resolve(0); + } else { + spinner.stop(); + bufferedOutput.forEach(({ stream, data }) => stream.write(data)); + spinner.fail('Package install failed, see above.'); + reject(1); + } + }); + + childProcess.stdout?.on('data', (data: Buffer) => + bufferedOutput.push({ stream: process.stdout, data: data }), + ); + childProcess.stderr?.on('data', (data: Buffer) => + bufferedOutput.push({ stream: process.stderr, data: data }), + ); }); - - if (status !== 0) { - let errorMessage = ((error && error.message) || stderr || stdout || '').trim(); - if (errorMessage) { - errorMessage += '\n'; - } - throw new Error(errorMessage + `Package install failed${errorMessage ? ', see above' : ''}.`); - } - - logger?.info(colors.green(`Installed packages for tooling via ${packageManager}.`)); } -export function installTempPackage( +export async function installTempPackage( packageName: string, - logger: logging.Logger | undefined, packageManager: PackageManager = PackageManager.Npm, extraArgs?: string[], -): string { +): Promise<{ + status: 1 | 0; + tempNodeModules: string; +}> { const tempPath = mkdtempSync(join(realpathSync(tmpdir()), 'angular-cli-packages-')); // clean up temp directory on process exit process.on('exit', () => { try { - rimraf.sync(tempPath); - } catch { } + rmdirSync(tempPath, { recursive: true, maxRetries: 3 }); + } catch {} }); // NPM will warn when a `package.json` is not found in the install directory @@ -88,12 +142,15 @@ export function installTempPackage( // While we can use `npm init -y` we will end up needing to update the 'package.json' anyways // because of missing fields. - writeFileSync(join(tempPath, 'package.json'), JSON.stringify({ - name: 'temp-cli-install', - description: 'temp-cli-install', - repository: 'temp-cli-install', - license: 'MIT', - })); + writeFileSync( + join(tempPath, 'package.json'), + JSON.stringify({ + name: 'temp-cli-install', + description: 'temp-cli-install', + repository: 'temp-cli-install', + license: 'MIT', + }), + ); // setup prefix/global modules path const packageManagerArgs = getPackageManagerArguments(packageManager); @@ -106,23 +163,26 @@ export function installTempPackage( packageManagerArgs.noLockfile, ]; - installPackage(packageName, logger, packageManager, true, installArgs, tempPath); - - return tempNodeModules; + return { + status: await installPackage(packageName, packageManager, true, installArgs, tempPath), + tempNodeModules, + }; } -export function runTempPackageBin( +export async function runTempPackageBin( packageName: string, - logger: logging.Logger, packageManager: PackageManager = PackageManager.Npm, args: string[] = [], -): number { - const tempNodeModulesPath = installTempPackage(packageName, logger, packageManager); +): Promise { + const { status: code, tempNodeModules } = await installTempPackage(packageName, packageManager); + if (code !== 0) { + return code; + } // Remove version/tag etc... from package name // Ex: @angular/cli@latest -> @angular/cli const packageNameNoVersion = packageName.substring(0, packageName.lastIndexOf('@')); - const pkgLocation = join(tempNodeModulesPath, packageNameNoVersion); + const pkgLocation = join(tempNodeModules, packageNameNoVersion); const packageJsonPath = join(pkgLocation, 'package.json'); // Get a binary location for this package @@ -143,11 +203,8 @@ export function runTempPackageBin( throw new Error(`Cannot locate bin for temporary package: ${packageNameNoVersion}.`); } - const argv = [binPath, ...args]; - - const { status, error } = spawnSync('node', argv, { + const { status, error } = spawnSync(process.execPath, [binPath, ...args], { stdio: 'inherit', - shell: true, env: { ...process.env, NG_DISABLE_VERSION_CHECK: 'true', @@ -177,6 +234,7 @@ function getPackageManagerArguments(packageManager: PackageManager): PackageMana silent: '--silent', saveDev: '--save-dev', install: 'add', + installAll: 'install', prefix: '--prefix', noLockfile: '--no-lockfile', }; @@ -185,6 +243,7 @@ function getPackageManagerArguments(packageManager: PackageManager): PackageMana silent: '--quiet', saveDev: '--save-dev', install: 'install', + installAll: 'install', prefix: '--prefix', noLockfile: '--no-package-lock', }; diff --git a/packages/angular/cli/utilities/json-file.ts b/packages/angular/cli/utilities/json-file.ts index d076e73c542f..1afa0b3f7041 100644 --- a/packages/angular/cli/utilities/json-file.ts +++ b/packages/angular/cli/utilities/json-file.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license @@ -9,8 +9,15 @@ import { JsonValue } from '@angular-devkit/core'; import { readFileSync, writeFileSync } from 'fs'; import { - Node, ParseError, applyEdits, findNodeAtLocation, - getNodeValue, modify, parse, parseTree, printParseErrorCode, + Node, + ParseError, + applyEdits, + findNodeAtLocation, + getNodeValue, + modify, + parse, + parseTree, + printParseErrorCode, } from 'jsonc-parser'; export type InsertionIndex = (properties: string[]) => number; @@ -20,9 +27,7 @@ export type JSONPath = (string | number)[]; export class JSONFile { content: string; - constructor( - private readonly path: string, - ) { + constructor(private readonly path: string) { const buffer = readFileSync(this.path); if (buffer) { this.content = buffer.toString(); @@ -61,7 +66,11 @@ export class JSONFile { return node === undefined ? undefined : getNodeValue(node); } - modify(jsonPath: JSONPath, value: JsonValue | undefined, insertInOrder?: InsertionIndex | false): boolean { + modify( + jsonPath: JSONPath, + value: JsonValue | undefined, + insertInOrder?: InsertionIndex | false, + ): boolean { if (value === undefined && this.get(jsonPath) === undefined) { // Cannot remove a value which doesn't exist. return false; @@ -70,23 +79,19 @@ export class JSONFile { let getInsertionIndex: InsertionIndex | undefined; if (insertInOrder === undefined) { const property = jsonPath.slice(-1)[0]; - getInsertionIndex = properties => [...properties, property].sort().findIndex(p => p === property); + getInsertionIndex = (properties) => + [...properties, property].sort().findIndex((p) => p === property); } else if (insertInOrder !== false) { getInsertionIndex = insertInOrder; } - const edits = modify( - this.content, - jsonPath, - value, - { - getInsertionIndex, - formattingOptions: { - insertSpaces: true, - tabSize: 2, - }, + const edits = modify(this.content, jsonPath, value, { + getInsertionIndex, + formattingOptions: { + insertSpaces: true, + tabSize: 2, }, - ); + }); if (edits.length === 0) { return false; @@ -103,7 +108,7 @@ export class JSONFile { } } -// tslint:disable-next-line: no-any +// eslint-disable-next-line @typescript-eslint/no-explicit-any export function readAndParseJson(path: string): any { const errors: ParseError[] = []; const content = parse(readFileSync(path, 'utf-8'), errors, { allowTrailingComma: true }); @@ -116,10 +121,14 @@ export function readAndParseJson(path: string): any { function formatError(path: string, errors: ParseError[]): never { const { error, offset } = errors[0]; - throw new Error(`Failed to parse "${path}" as JSON AST Object. ${printParseErrorCode(error)} at location: ${offset}.`); + throw new Error( + `Failed to parse "${path}" as JSON AST Object. ${printParseErrorCode( + error, + )} at location: ${offset}.`, + ); } -// tslint:disable-next-line: no-any +// eslint-disable-next-line @typescript-eslint/no-explicit-any export function parseJson(content: string): any { return parse(content, undefined, { allowTrailingComma: true }); } diff --git a/packages/angular/cli/utilities/json-schema.ts b/packages/angular/cli/utilities/json-schema.ts index e2974080318a..f396d4a063d9 100644 --- a/packages/angular/cli/utilities/json-schema.ts +++ b/packages/angular/cli/utilities/json-schema.ts @@ -1,10 +1,11 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { BaseException, json } from '@angular-devkit/core'; import { ExportStringRef } from '@angular-devkit/schematics/tools'; import { readFileSync } from 'fs'; @@ -19,9 +20,8 @@ import { Value, } from '../models/interface'; - export class CommandJsonPathException extends BaseException { - constructor(public readonly path: string, public readonly name: string) { + constructor(public readonly path: string, public override readonly name: string) { super(`File ${path} was not found while constructing the subcommand ${name}.`); } } @@ -52,14 +52,14 @@ export async function parseJsonSchemaToSubCommandDescription( const aliases: string[] = []; if (json.isJsonArray(schema.$aliases)) { - schema.$aliases.forEach(value => { + schema.$aliases.forEach((value) => { if (typeof value == 'string') { aliases.push(value); } }); } if (json.isJsonArray(schema.aliases)) { - schema.aliases.forEach(value => { + schema.aliases.forEach((value) => { if (typeof value == 'string') { aliases.push(value); } @@ -106,8 +106,7 @@ export async function parseJsonSchemaToCommandDescription( registry: json.schema.SchemaRegistry, schema: json.JsonObject, ): Promise { - const subcommand = - await parseJsonSchemaToSubCommandDescription(name, jsonPath, registry, schema); + const subcommand = await parseJsonSchemaToSubCommandDescription(name, jsonPath, registry, schema); // Before doing any work, let's validate the implementation. if (typeof schema.$impl != 'string') { @@ -172,27 +171,31 @@ export async function parseJsonSchemaToOptions( } // We only support number, string or boolean (or array of those), so remove everything else. - const types = [...typeSet].filter(x => { - switch (x) { - case 'boolean': - case 'number': - case 'string': - return true; - - case 'array': - // Only include arrays if they're boolean, string or number. - if (json.isJsonObject(current.items) - && typeof current.items.type == 'string' - && ['boolean', 'number', 'string'].includes(current.items.type)) { + const types = [...typeSet] + .filter((x) => { + switch (x) { + case 'boolean': + case 'number': + case 'string': return true; - } - return false; + case 'array': + // Only include arrays if they're boolean, string or number. + if ( + json.isJsonObject(current.items) && + typeof current.items.type == 'string' && + ['boolean', 'number', 'string'].includes(current.items.type) + ) { + return true; + } - default: - return false; - } - }).map(x => _getEnumFromValue(x, OptionType, OptionType.String)); + return false; + + default: + return false; + } + }) + .map((x) => _getEnumFromValue(x, OptionType, OptionType.String)); if (types.length == 0) { // This means it's not usable on the command line. e.g. an Object. @@ -200,7 +203,7 @@ export async function parseJsonSchemaToOptions( } // Only keep enum values we support (booleans, numbers and strings). - const enumValues = (json.isJsonArray(current.enum) && current.enum || []).filter(x => { + const enumValues = ((json.isJsonArray(current.enum) && current.enum) || []).filter((x) => { switch (typeof x) { case 'boolean': case 'number': @@ -235,15 +238,19 @@ export async function parseJsonSchemaToOptions( const type = types[0]; const $default = current.$default; - const $defaultIndex = (json.isJsonObject($default) && $default['$source'] == 'argv') - ? $default['index'] : undefined; - const positional: number | undefined = typeof $defaultIndex == 'number' - ? $defaultIndex : undefined; + const $defaultIndex = + json.isJsonObject($default) && $default['$source'] == 'argv' ? $default['index'] : undefined; + const positional: number | undefined = + typeof $defaultIndex == 'number' ? $defaultIndex : undefined; const required = json.isJsonArray(current.required) - ? current.required.indexOf(name) != -1 : false; - const aliases = json.isJsonArray(current.aliases) ? [...current.aliases].map(x => '' + x) - : current.alias ? ['' + current.alias] : []; + ? current.required.indexOf(name) != -1 + : false; + const aliases = json.isJsonArray(current.aliases) + ? [...current.aliases].map((x) => '' + x) + : current.alias + ? ['' + current.alias] + : []; const format = typeof current.format == 'string' ? current.format : undefined; const visible = current.visible === undefined || current.visible === true; const hidden = !!current.hidden || !visible; @@ -253,22 +260,22 @@ export async function parseJsonSchemaToOptions( // Deprecated is set only if it's true or a string. const xDeprecated = current['x-deprecated']; - const deprecated = (xDeprecated === true || typeof xDeprecated === 'string') - ? xDeprecated : undefined; + const deprecated = + xDeprecated === true || typeof xDeprecated === 'string' ? xDeprecated : undefined; const option: Option = { name, description: '' + (current.description === undefined ? '' : current.description), - ...types.length == 1 ? { type } : { type, types }, - ...defaultValue !== undefined ? { default: defaultValue } : {}, - ...enumValues && enumValues.length > 0 ? { enum: enumValues } : {}, + ...(types.length == 1 ? { type } : { type, types }), + ...(defaultValue !== undefined ? { default: defaultValue } : {}), + ...(enumValues && enumValues.length > 0 ? { enum: enumValues } : {}), required, aliases, - ...format !== undefined ? { format } : {}, + ...(format !== undefined ? { format } : {}), hidden, - ...userAnalytics ? { userAnalytics } : {}, - ...deprecated !== undefined ? { deprecated } : {}, - ...positional !== undefined ? { positional } : {}, + ...(userAnalytics ? { userAnalytics } : {}), + ...(deprecated !== undefined ? { deprecated } : {}), + ...(positional !== undefined ? { positional } : {}), }; options.push(option); diff --git a/packages/angular/cli/utilities/json-schema_spec.ts b/packages/angular/cli/utilities/json-schema_spec.ts index 09822cef7730..f300cc4bc077 100644 --- a/packages/angular/cli/utilities/json-schema_spec.ts +++ b/packages/angular/cli/utilities/json-schema_spec.ts @@ -1,11 +1,11 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license - * */ + import { schema } from '@angular-devkit/core'; import { readFileSync } from 'fs'; import { join } from 'path'; @@ -24,9 +24,7 @@ describe('parseJsonSchemaToCommandDescription', () => { '$impl': './version-impl#VersionCommand', 'type': 'object', - 'allOf': [ - { '$ref': './definitions.json#/definitions/base' }, - ], + 'allOf': [{ '$ref': './definitions.json#/definitions/base' }], }; beforeEach(() => { @@ -34,7 +32,9 @@ describe('parseJsonSchemaToCommandDescription', () => { registry.registerUriHandler((uri: string) => { if (uri.startsWith('ng-cli://')) { const content = readFileSync( - join(__dirname, '..', uri.substr('ng-cli://'.length)), 'utf-8'); + join(__dirname, '..', uri.substr('ng-cli://'.length)), + 'utf-8', + ); return Promise.resolve(JSON.parse(content)); } else { diff --git a/packages/angular/cli/utilities/log-file.ts b/packages/angular/cli/utilities/log-file.ts index 4e5d33bb4571..41dc036fc028 100644 --- a/packages/angular/cli/utilities/log-file.ts +++ b/packages/angular/cli/utilities/log-file.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license diff --git a/packages/angular/cli/src/commands/update/schematic/package-json.ts b/packages/angular/cli/utilities/package-json.ts similarity index 98% rename from packages/angular/cli/src/commands/update/schematic/package-json.ts rename to packages/angular/cli/utilities/package-json.ts index b4162f6fd232..359f451ff9b7 100644 --- a/packages/angular/cli/src/commands/update/schematic/package-json.ts +++ b/packages/angular/cli/utilities/package-json.ts @@ -1,16 +1,17 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + /** * This file was automatically generated by json-schema-to-typescript. * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, * and run json-schema-to-typescript to regenerate this file. */ -// tslint:disable +/* eslint-disable */ export type JsonSchemaForNpmPackageJsonFiles = CoreProperties & JspmDefinition & @@ -22,7 +23,8 @@ export type JsonSchemaForNpmPackageJsonFiles = CoreProperties & | { bundledDependencies?: BundledDependency; [k: string]: any; - }) & { + } + ) & { [k: string]: any; }; /** diff --git a/packages/angular/cli/utilities/package-manager.ts b/packages/angular/cli/utilities/package-manager.ts index 911e445dc04a..2cb64781d854 100644 --- a/packages/angular/cli/utilities/package-manager.ts +++ b/packages/angular/cli/utilities/package-manager.ts @@ -1,10 +1,11 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { execSync } from 'child_process'; import { existsSync } from 'fs'; import { join } from 'path'; @@ -31,7 +32,7 @@ export function supportsNpm(): boolean { } export async function getPackageManager(root: string): Promise { - let packageManager = await getConfiguredPackageManager() as PackageManager | null; + let packageManager = (await getConfiguredPackageManager()) as PackageManager | null; if (packageManager) { return packageManager; } @@ -65,14 +66,14 @@ export async function ensureCompatibleNpm(root: string): Promise { } try { - const versionText = execSync('npm --version', {encoding: 'utf8', stdio: 'pipe'}).trim(); + const versionText = execSync('npm --version', { encoding: 'utf8', stdio: 'pipe' }).trim(); const version = valid(versionText); if (!version) { return; } if (satisfies(version, '>=7 <7.5.6')) { - // tslint:disable-next-line: no-console + // eslint-disable-next-line no-console console.warn( `npm version ${version} detected.` + ' When using npm 7 with the Angular CLI, npm version 7.5.6 or higher is recommended.', diff --git a/packages/angular/cli/utilities/package-metadata.ts b/packages/angular/cli/utilities/package-metadata.ts index 2a528ca06b89..eb658f632c7d 100644 --- a/packages/angular/cli/utilities/package-metadata.ts +++ b/packages/angular/cli/utilities/package-metadata.ts @@ -1,21 +1,40 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { logging } from '@angular-devkit/core'; import { existsSync, readFileSync } from 'fs'; import { homedir } from 'os'; import * as path from 'path'; +import { JsonSchemaForNpmPackageJsonFiles } from './package-json'; -const ini = require('ini'); const lockfile = require('@yarnpkg/lockfile'); +const ini = require('ini'); const pacote = require('pacote'); -export interface PackageDependencies { - [dependency: string]: string; +const npmPackageJsonCache = new Map>>(); + +export interface NpmRepositoryPackageJson { + name: string; + requestedName: string; + description: string; + + 'dist-tags': { + [name: string]: string; + }; + versions: { + [version: string]: JsonSchemaForNpmPackageJsonFiles; + }; + time: { + modified: string; + created: string; + + [version: string]: string; + }; } export type NgAddSaveDepedency = 'dependencies' | 'devDependencies' | boolean; @@ -36,17 +55,16 @@ export interface PackageManifest { license?: string; private?: boolean; deprecated?: boolean; - - dependencies: PackageDependencies; - devDependencies: PackageDependencies; - peerDependencies: PackageDependencies; - optionalDependencies: PackageDependencies; + dependencies: Record; + devDependencies: Record; + peerDependencies: Record; + optionalDependencies: Record; 'ng-add'?: { save?: NgAddSaveDepedency; }; 'ng-update'?: { migrations: string; - packageGroup: { [name: string]: string }; + packageGroup: Record; }; } @@ -57,7 +75,9 @@ export interface PackageMetadata { 'dist-tags'?: unknown; } -type PackageManagerOptions = Record; +interface PackageManagerOptions extends Record { + forceAuth?: Record; +} let npmrc: PackageManagerOptions; @@ -65,12 +85,12 @@ function ensureNpmrc(logger: logging.LoggerApi, usingYarn: boolean, verbose: boo if (!npmrc) { try { npmrc = readOptions(logger, false, verbose); - } catch { } + } catch {} if (usingYarn) { try { npmrc = { ...npmrc, ...readOptions(logger, true, verbose) }; - } catch { } + } catch {} } } } @@ -100,16 +120,18 @@ function readOptions( ]; const projectConfigLocations: string[] = [path.join(cwd, dotFilename)]; - const root = path.parse(cwd).root; - for (let curDir = path.dirname(cwd); curDir && curDir !== root; curDir = path.dirname(curDir)) { - projectConfigLocations.unshift(path.join(curDir, dotFilename)); + if (yarn) { + const root = path.parse(cwd).root; + for (let curDir = path.dirname(cwd); curDir && curDir !== root; curDir = path.dirname(curDir)) { + projectConfigLocations.unshift(path.join(curDir, dotFilename)); + } } if (showPotentials) { logger.info(`Locating potential ${baseFilename} files:`); } - const options: PackageManagerOptions = {}; + let rcOptions: PackageManagerOptions = {}; for (const location of [...defaultConfigLocations, ...projectConfigLocations]) { if (existsSync(location)) { if (showPotentials) { @@ -120,48 +142,90 @@ function readOptions( // Normalize RC options that are needed by 'npm-registry-fetch'. // See: https://github.com/npm/npm-registry-fetch/blob/ebddbe78a5f67118c1f7af2e02c8a22bcaf9e850/index.js#L99-L126 const rcConfig: PackageManagerOptions = yarn ? lockfile.parse(data) : ini.parse(data); - for (const [key, value] of Object.entries(rcConfig)) { - switch (key) { - case 'noproxy': - case 'no-proxy': - options['noProxy'] = value; - break; - case 'maxsockets': - options['maxSockets'] = value; - break; - case 'https-proxy': - case 'proxy': - options['proxy'] = value; - break; - case 'strict-ssl': - options['strictSSL'] = value; - break; - case 'local-address': - options['localAddress'] = value; - break; - case 'cafile': - if (typeof value === 'string') { - const cafile = path.resolve(path.dirname(location), value); - try { - options['ca'] = readFileSync(cafile, 'utf8').replace(/\r?\n/g, '\n'); - } catch { } - } - break; - default: - options[key] = value; - break; - } - } - } else if (showPotentials) { - logger.info(`Trying '${location}'...not found.`); + + rcOptions = normalizeOptions(rcConfig, location, rcOptions); + } + } + + const envVariablesOptions: PackageManagerOptions = {}; + for (const [key, value] of Object.entries(process.env)) { + if (!value) { + continue; } + + let normalizedName = key.toLowerCase(); + if (normalizedName.startsWith('npm_config_')) { + normalizedName = normalizedName.substring(11); + } else if (yarn && normalizedName.startsWith('yarn_')) { + normalizedName = normalizedName.substring(5); + } else { + continue; + } + + normalizedName = normalizedName.replace(/(?!^)_/g, '-'); // don't replace _ at the start of the key.s + envVariablesOptions[normalizedName] = value; } - // Substitute any environment variable references - for (const key in options) { - const value = options[key]; + return normalizeOptions(envVariablesOptions, undefined, rcOptions); +} + +function normalizeOptions( + rawOptions: PackageManagerOptions, + location = process.cwd(), + existingNormalizedOptions: PackageManagerOptions = {}, +): PackageManagerOptions { + const options = { ...existingNormalizedOptions }; + + for (const [key, value] of Object.entries(rawOptions)) { + let substitutedValue = value; + + // Substitute any environment variable references. if (typeof value === 'string') { - options[key] = value.replace(/\$\{([^\}]+)\}/, (_, name) => process.env[name] || ''); + substitutedValue = value.replace(/\$\{([^\}]+)\}/, (_, name) => process.env[name] || ''); + } + + switch (key) { + // Unless auth options are scope with the registry url it appears that npm-registry-fetch ignores them, + // even though they are documented. + // https://github.com/npm/npm-registry-fetch/blob/8954f61d8d703e5eb7f3d93c9b40488f8b1b62ac/README.md + // https://github.com/npm/npm-registry-fetch/blob/8954f61d8d703e5eb7f3d93c9b40488f8b1b62ac/auth.js#L45-L91 + case '_authToken': + case 'token': + case 'username': + case 'password': + case '_auth': + case 'auth': + options['forceAuth'] ??= {}; + options['forceAuth'][key] = substitutedValue; + break; + case 'noproxy': + case 'no-proxy': + options['noProxy'] = substitutedValue; + break; + case 'maxsockets': + options['maxSockets'] = substitutedValue; + break; + case 'https-proxy': + case 'proxy': + options['proxy'] = substitutedValue; + break; + case 'strict-ssl': + options['strictSSL'] = substitutedValue; + break; + case 'local-address': + options['localAddress'] = substitutedValue; + break; + case 'cafile': + if (typeof substitutedValue === 'string') { + const cafile = path.resolve(path.dirname(location), substitutedValue); + try { + options['ca'] = readFileSync(cafile, 'utf8').replace(/\r?\n/g, '\n'); + } catch {} + } + break; + default: + options[key] = substitutedValue; + break; } } @@ -237,19 +301,13 @@ export async function fetchPackageMetadata( export async function fetchPackageManifest( name: string, logger: logging.LoggerApi, - options?: { + options: { registry?: string; usingYarn?: boolean; verbose?: boolean; - }, + } = {}, ): Promise { - const { usingYarn, verbose, registry } = { - registry: undefined, - usingYarn: false, - verbose: false, - ...options, - }; - + const { usingYarn = false, verbose = false, registry } = options; ensureNpmrc(logger, usingYarn, verbose); const response = await pacote.manifest(name, { @@ -260,3 +318,38 @@ export async function fetchPackageManifest( return normalizeManifest(response); } + +export function getNpmPackageJson( + packageName: string, + logger: logging.LoggerApi, + options: { + registry?: string; + usingYarn?: boolean; + verbose?: boolean; + } = {}, +): Promise> { + const cachedResponse = npmPackageJsonCache.get(packageName); + if (cachedResponse) { + return cachedResponse; + } + + const { usingYarn = false, verbose = false, registry } = options; + ensureNpmrc(logger, usingYarn, verbose); + + const resultPromise: Promise = pacote.packument(packageName, { + fullMetadata: true, + ...npmrc, + ...(registry ? { registry } : {}), + }); + + // TODO: find some way to test this + const response = resultPromise.catch((err) => { + logger.warn(err.message || err); + + return { requestedName: packageName }; + }); + + npmPackageJsonCache.set(packageName, response); + + return response; +} diff --git a/packages/angular/cli/utilities/package-tree.ts b/packages/angular/cli/utilities/package-tree.ts index d3e617fe5f69..9be8740a414b 100644 --- a/packages/angular/cli/utilities/package-tree.ts +++ b/packages/angular/cli/utilities/package-tree.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license @@ -67,7 +67,7 @@ export async function getProjectDependencies(dir: string): Promise (); + const results = new Map(); for (const [name, version] of getAllDependencies(pkg)) { const packageJsonPath = findPackageJson(dir, name); if (!packageJsonPath) { diff --git a/packages/angular/cli/utilities/project.ts b/packages/angular/cli/utilities/project.ts index cd133cd0323a..db119818e723 100644 --- a/packages/angular/cli/utilities/project.ts +++ b/packages/angular/cli/utilities/project.ts @@ -1,10 +1,11 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { normalize } from '@angular-devkit/core'; import * as fs from 'fs'; import * as os from 'os'; diff --git a/packages/angular/cli/utilities/prompt.ts b/packages/angular/cli/utilities/prompt.ts index fcbd0c2ea572..97be8988662a 100644 --- a/packages/angular/cli/utilities/prompt.ts +++ b/packages/angular/cli/utilities/prompt.ts @@ -1,10 +1,11 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import * as inquirer from 'inquirer'; import { isTTY } from './tty'; diff --git a/packages/angular/cli/utilities/spinner.ts b/packages/angular/cli/utilities/spinner.ts index f7b8d8550662..e641815eedca 100644 --- a/packages/angular/cli/utilities/spinner.ts +++ b/packages/angular/cli/utilities/spinner.ts @@ -1,12 +1,12 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ -import * as ora from 'ora'; +import ora from 'ora'; import { colors } from './color'; export class Spinner { diff --git a/packages/angular/cli/utilities/tty.ts b/packages/angular/cli/utilities/tty.ts index dd5931e26fb6..1e5658ebfd57 100644 --- a/packages/angular/cli/utilities/tty.ts +++ b/packages/angular/cli/utilities/tty.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license diff --git a/packages/angular/pwa/pwa/index.ts b/packages/angular/pwa/pwa/index.ts index e6cabae37856..0e6731adedc8 100644 --- a/packages/angular/pwa/pwa/index.ts +++ b/packages/angular/pwa/pwa/index.ts @@ -1,10 +1,11 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { Rule, SchematicsException, @@ -29,9 +30,9 @@ function updateIndexFile(path: string): Rule { throw new SchematicsException(`Could not read index file: ${path}`); } - const rewriter = new (await import('parse5-html-rewriting-stream'))(); + const rewriter = new (await import('parse5-html-rewriting-stream')).default(); let needsNoScript = true; - rewriter.on('startTag', startTag => { + rewriter.on('startTag', (startTag) => { if (startTag.tagName === 'noscript') { needsNoScript = false; } @@ -39,7 +40,7 @@ function updateIndexFile(path: string): Rule { rewriter.emitStartTag(startTag); }); - rewriter.on('endTag', endTag => { + rewriter.on('endTag', (endTag) => { if (endTag.tagName === 'head') { rewriter.emitRaw(' \n'); rewriter.emitRaw(' \n'); @@ -52,7 +53,7 @@ function updateIndexFile(path: string): Rule { rewriter.emitEndTag(endTag); }); - return new Promise(resolve => { + return new Promise((resolve) => { const input = new Readable({ encoding: 'utf8', read(): void { @@ -80,8 +81,8 @@ function updateIndexFile(path: string): Rule { }; } -export default function(options: PwaOptions): Rule { - return async host => { +export default function (options: PwaOptions): Rule { + return async (host) => { if (!options.title) { options.title = options.project; } @@ -160,15 +161,14 @@ export default function(options: PwaOptions): Rule { return chain([ updateWorkspace(workspace), externalSchematic('@schematics/angular', 'service-worker', swOptions), - mergeWith(apply(url('./files/root'), [ - template({ ...options }), - move(sourcePath), - ])), - mergeWith(apply(url('./files/assets'), [ - template({ ...options }), - move(posix.join(sourcePath, 'assets')), - ])), - ...[...indexFiles].map(path => updateIndexFile(path)), + mergeWith(apply(url('./files/root'), [template({ ...options }), move(sourcePath)])), + mergeWith( + apply(url('./files/assets'), [ + template({ ...options }), + move(posix.join(sourcePath, 'assets')), + ]), + ), + ...[...indexFiles].map((path) => updateIndexFile(path)), ]); }; } diff --git a/packages/angular/pwa/pwa/index_spec.ts b/packages/angular/pwa/pwa/index_spec.ts index ea8dd9f5e461..a5cc155950f7 100644 --- a/packages/angular/pwa/pwa/index_spec.ts +++ b/packages/angular/pwa/pwa/index_spec.ts @@ -1,10 +1,11 @@ /** * @license - * Copyright Google Inc. All Rights Reserved. + * 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.io/license */ + import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; import * as path from 'path'; import { Schema as PwaOptions } from './schema'; @@ -39,105 +40,130 @@ describe('PWA Schematic', () => { }; beforeEach(async () => { - appTree = await schematicRunner.runExternalSchematicAsync('@schematics/angular', 'workspace', workspaceOptions).toPromise(); - appTree = await schematicRunner.runExternalSchematicAsync( - '@schematics/angular', - 'application', - appOptions, - appTree, - ).toPromise(); + appTree = await schematicRunner + .runExternalSchematicAsync('@schematics/angular', 'workspace', workspaceOptions) + .toPromise(); + appTree = await schematicRunner + .runExternalSchematicAsync('@schematics/angular', 'application', appOptions, appTree) + .toPromise(); }); it('should run the service worker schematic', (done) => { - schematicRunner.runSchematicAsync('ng-add', defaultOptions, appTree).toPromise().then(tree => { - const configText = tree.readContent('/angular.json'); - const config = JSON.parse(configText); - const swFlag = config.projects.bar.architect.build.options.serviceWorker; - expect(swFlag).toEqual(true); - done(); - }, done.fail); + schematicRunner + .runSchematicAsync('ng-add', defaultOptions, appTree) + .toPromise() + .then((tree) => { + const configText = tree.readContent('/angular.json'); + const config = JSON.parse(configText); + const swFlag = config.projects.bar.architect.build.options.serviceWorker; + expect(swFlag).toEqual(true); + done(); + }, done.fail); }); it('should create icon files', (done) => { const dimensions = [72, 96, 128, 144, 152, 192, 384, 512]; const iconPath = '/projects/bar/src/assets/icons/icon-'; - schematicRunner.runSchematicAsync('ng-add', defaultOptions, appTree).toPromise().then(tree => { - dimensions.forEach(d => { - const path = `${iconPath}${d}x${d}.png`; - expect(tree.exists(path)).toEqual(true); - }); - done(); - }, done.fail); + schematicRunner + .runSchematicAsync('ng-add', defaultOptions, appTree) + .toPromise() + .then((tree) => { + dimensions.forEach((d) => { + const path = `${iconPath}${d}x${d}.png`; + expect(tree.exists(path)).toEqual(true); + }); + done(); + }, done.fail); }); it('should create a manifest file', (done) => { - schematicRunner.runSchematicAsync('ng-add', defaultOptions, appTree).toPromise().then(tree => { - expect(tree.exists('/projects/bar/src/manifest.webmanifest')).toEqual(true); - done(); - }, done.fail); + schematicRunner + .runSchematicAsync('ng-add', defaultOptions, appTree) + .toPromise() + .then((tree) => { + expect(tree.exists('/projects/bar/src/manifest.webmanifest')).toEqual(true); + done(); + }, done.fail); }); it('should set the name & short_name in the manifest file', (done) => { - schematicRunner.runSchematicAsync('ng-add', defaultOptions, appTree).toPromise().then(tree => { - const manifestText = tree.readContent('/projects/bar/src/manifest.webmanifest'); - const manifest = JSON.parse(manifestText); - - expect(manifest.name).toEqual(defaultOptions.title); - expect(manifest.short_name).toEqual(defaultOptions.title); - done(); - }, done.fail); + schematicRunner + .runSchematicAsync('ng-add', defaultOptions, appTree) + .toPromise() + .then((tree) => { + const manifestText = tree.readContent('/projects/bar/src/manifest.webmanifest'); + const manifest = JSON.parse(manifestText); + + expect(manifest.name).toEqual(defaultOptions.title); + expect(manifest.short_name).toEqual(defaultOptions.title); + done(); + }, done.fail); }); it('should set the name & short_name in the manifest file when no title provided', (done) => { - const options = {...defaultOptions, title: undefined}; - schematicRunner.runSchematicAsync('ng-add', options, appTree).toPromise().then(tree => { - const manifestText = tree.readContent('/projects/bar/src/manifest.webmanifest'); - const manifest = JSON.parse(manifestText); - - expect(manifest.name).toEqual(defaultOptions.project); - expect(manifest.short_name).toEqual(defaultOptions.project); - done(); - }, done.fail); + const options = { ...defaultOptions, title: undefined }; + schematicRunner + .runSchematicAsync('ng-add', options, appTree) + .toPromise() + .then((tree) => { + const manifestText = tree.readContent('/projects/bar/src/manifest.webmanifest'); + const manifest = JSON.parse(manifestText); + + expect(manifest.name).toEqual(defaultOptions.project); + expect(manifest.short_name).toEqual(defaultOptions.project); + done(); + }, done.fail); }); it('should update the index file', (done) => { - schematicRunner.runSchematicAsync('ng-add', defaultOptions, appTree).toPromise().then(tree => { - const content = tree.readContent('projects/bar/src/index.html'); - - expect(content).toMatch(//); - expect(content).toMatch(//); - expect(content) - .toMatch(/