From 863c7eaafee28d9979ae3a4666330b9317bdd79d Mon Sep 17 00:00:00 2001 From: Joey Perrott Date: Wed, 10 Sep 2025 16:56:37 +0000 Subject: [PATCH] build: migrate vscode extension into repo (#63924) Migrate the vscode extension for angular into this repository. PR Close #63924 --- .bazelignore | 8 +- .github/workflows/ci.yml | 15 + .github/workflows/pr.yml | 15 + .gitignore | 3 - .ng-dev/commit-message.mts | 2 + .ng-dev/format.mts | 3 + .pnpmfile.cjs | 2 +- .vscode/launch.json | 94 + .vscode/tasks.json | 43 + MODULE.bazel | 4 + package.json | 2 +- pnpm-lock.yaml | 1823 ++++++++++++++++- pnpm-workspace.yaml | 5 + vscode-ng-language-service/BUILD.bazel | 109 + vscode-ng-language-service/CHANGELOG.md | 1148 +++++++++++ vscode-ng-language-service/DEVELOPER.md | 79 + vscode-ng-language-service/README.md | 69 + vscode-ng-language-service/angular.png | Bin 0 -> 149516 bytes vscode-ng-language-service/client/BUILD.bazel | 39 + .../client/src/BUILD.bazel | 19 + .../client/src/client.ts | 676 ++++++ .../client/src/commands.ts | 239 +++ .../client/src/embedded_support.ts | 147 ++ .../client/src/extension.ts | 34 + .../client/src/providers.ts | 64 + .../client/src/tests/BUILD.bazel | 34 + .../client/src/tests/embedded_support_spec.ts | 125 ++ .../client/src/tests/tsconfig.json | 5 + .../client/src/tests/tsconfig.tsbuildinfo | 1 + .../client/tsconfig.json | 10 + vscode-ng-language-service/common/BUILD.bazel | 32 + .../common/initialize.ts | 21 + .../common/notifications.ts | 32 + vscode-ng-language-service/common/requests.ts | 57 + vscode-ng-language-service/common/resolver.ts | 106 + .../common/tests/BUILD.bazel | 32 + .../common/tests/resolver_spec.ts | 58 + .../common/tests/tsconfig.json | 5 + .../common/tests/tsconfig.tsbuildinfo | 1 + .../common/tsconfig.json | 3 + .../integration/BUILD.bazel | 34 + .../integration/e2e/BUILD.bazel | 43 + .../integration/e2e/completion_spec.ts | 20 + .../integration/e2e/definition_spec.ts | 37 + .../integration/e2e/helper.ts | 39 + .../integration/e2e/hover_spec.ts | 21 + .../integration/e2e/index.ts | 32 + .../integration/e2e/jasmine.ts | 44 + .../integration/lsp/BUILD.bazel | 33 + .../integration/lsp/ivy_spec.ts | 1004 +++++++++ .../integration/lsp/test_utils.ts | 136 ++ .../integration/pre_apf_project/BUILD.bazel | 12 + .../pre_apf_project/app/app.component.ts | 11 + .../pre_apf_project/app/app.module.ts | 12 + .../pre_apf_project/app/foo.component.html | 4 + .../pre_apf_project/app/foo.component.ts | 8 + .../integration/pre_apf_project/package.json | 12 + .../integration/pre_apf_project/tsconfig.json | 15 + .../pre_standalone_project/BUILD.bazel | 12 + .../app/app.component.ts | 11 + .../pre_standalone_project/app/app.module.ts | 12 + .../app/foo.component.html | 4 + .../app/foo.component.ts | 8 + .../pre_standalone_project/package.json | 8 + .../pre_standalone_project/tsconfig.json | 15 + .../integration/project/BUILD.bazel | 35 + .../integration/project/app/app.component.ts | 12 + .../integration/project/app/app.module.ts | 13 + .../integration/project/app/bar.component.ts | 19 + .../project/app/foo.component.html | 7 + .../integration/project/app/foo.component.ts | 17 + .../project/libs/post/ng-package.json | 7 + .../project/libs/post/package.json | 10 + .../project/libs/post/src/index.ts | 1 + .../libs/post/src/lib/post.component.ts | 15 + .../project/libs/post/tsconfig.json | 16 + .../integration/project/package.json | 19 + .../integration/project/tsconfig.json | 22 + .../integration/test_constants.ts | 27 + .../integration/tsconfig.json | 9 + .../integration/tsconfig.tsbuildinfo | 1 + .../integration/workspace/BUILD.bazel | 12 + .../integration/workspace/package.json | 12 + .../projects/demo/src/app/app.component.ts | 10 + .../projects/demo/src/app/app.module.ts | 10 + .../workspace/projects/demo/tsconfig.json | 14 + .../integration/workspace/tsconfig.json | 30 + vscode-ng-language-service/package.json | 303 +++ vscode-ng-language-service/server/BUILD.bazel | 91 + vscode-ng-language-service/server/README.md | 6 + .../server/bin/ngserver | 2 + vscode-ng-language-service/server/esbuild.mjs | 7 + .../server/package.json | 31 + .../server/src/BUILD.bazel | 28 + .../server/src/banner.ts | 40 + .../server/src/cmdline_utils.ts | 124 ++ .../server/src/completion.ts | 177 ++ .../server/src/diagnostic.ts | 63 + .../server/src/embedded_support.ts | 129 ++ .../server/src/logger.ts | 150 ++ .../server/src/server.ts | 74 + .../server/src/server_host.ts | 213 ++ .../server/src/session.ts | 1643 +++++++++++++++ .../server/src/tests/BUILD.bazel | 41 + .../server/src/tests/cmdline_utils_spec.ts | 56 + .../server/src/tests/embedded_support_spec.ts | 44 + .../server/src/tests/text_render_spec.ts | 249 +++ .../server/src/tests/tsconfig.json | 6 + .../server/src/tests/tsconfig.tsbuildinfo | 1 + .../server/src/tests/utils_spec.ts | 90 + .../server/src/tests/version_provider_spec.ts | 35 + .../server/src/text_render.ts | 295 +++ .../server/src/utils.ts | 263 +++ .../server/src/version_provider.ts | 131 ++ .../server/tsconfig.json | 6 + .../syntaxes/BUILD.bazel | 57 + vscode-ng-language-service/syntaxes/README.md | 49 + .../syntaxes/expression.json | 972 +++++++++ .../syntaxes/host-object-literal.json | 102 + .../syntaxes/inline-styles.json | 98 + .../syntaxes/inline-template.json | 76 + .../syntaxes/let-declaration.json | 52 + .../syntaxes/src/BUILD.bazel | 20 + .../syntaxes/src/build.ts | 62 + .../syntaxes/src/expression.ts | 982 +++++++++ .../syntaxes/src/host-object-literal.ts | 99 + .../syntaxes/src/inline-styles.ts | 56 + .../syntaxes/src/inline-template.ts | 44 + .../syntaxes/src/template-blocks.ts | 96 + .../syntaxes/src/template-let-declaration.ts | 43 + .../syntaxes/src/template-tag.ts | 122 ++ .../syntaxes/src/template.ts | 29 + .../syntaxes/src/types.ts | 15 + .../syntaxes/template-blocks.json | 137 ++ .../syntaxes/template-tag.json | 172 ++ .../syntaxes/template.json | 31 + .../syntaxes/test/BUILD.bazel | 48 + .../syntaxes/test/cases.ts | 66 + .../syntaxes/test/data/expression.html | 100 + .../syntaxes/test/data/expression.html.snap | 1206 +++++++++++ .../syntaxes/test/data/host-object-literal.ts | 80 + .../test/data/host-object-literal.ts.snap | 427 ++++ .../syntaxes/test/data/inline-styles.ts | 26 + .../syntaxes/test/data/inline-styles.ts.snap | 157 ++ .../syntaxes/test/data/inline-template.ts | 32 + .../test/data/inline-template.ts.snap | 120 ++ .../syntaxes/test/data/let-declaration.html | 31 + .../test/data/let-declaration.html.snap | 192 ++ .../syntaxes/test/data/template-blocks.html | 62 + .../test/data/template-blocks.html.snap | 329 +++ .../syntaxes/test/data/template-tag.html | 78 + .../syntaxes/test/data/template-tag.html.snap | 772 +++++++ .../syntaxes/test/data/template.html | 2 + .../syntaxes/test/data/template.html.snap | 21 + .../syntaxes/test/driver.ts | 65 + .../test/dummy/css.tmLanguage-dummy.json | 4 + .../test/dummy/html.tmLanguage-dummy.json | 4 + .../test/dummy/js.tmLanguage-dummy.json | 4 + .../test/dummy/scss.tmLanguage-dummy.json | 4 + .../syntaxes/test/tsconfig.json | 6 + .../syntaxes/tsconfig.json | 6 + vscode-ng-language-service/tsconfig.json | 12 + 162 files changed, 18463 insertions(+), 72 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json create mode 100644 vscode-ng-language-service/BUILD.bazel create mode 100644 vscode-ng-language-service/CHANGELOG.md create mode 100644 vscode-ng-language-service/DEVELOPER.md create mode 100644 vscode-ng-language-service/README.md create mode 100644 vscode-ng-language-service/angular.png create mode 100644 vscode-ng-language-service/client/BUILD.bazel create mode 100644 vscode-ng-language-service/client/src/BUILD.bazel create mode 100644 vscode-ng-language-service/client/src/client.ts create mode 100644 vscode-ng-language-service/client/src/commands.ts create mode 100644 vscode-ng-language-service/client/src/embedded_support.ts create mode 100644 vscode-ng-language-service/client/src/extension.ts create mode 100644 vscode-ng-language-service/client/src/providers.ts create mode 100644 vscode-ng-language-service/client/src/tests/BUILD.bazel create mode 100644 vscode-ng-language-service/client/src/tests/embedded_support_spec.ts create mode 100644 vscode-ng-language-service/client/src/tests/tsconfig.json create mode 100644 vscode-ng-language-service/client/src/tests/tsconfig.tsbuildinfo create mode 100644 vscode-ng-language-service/client/tsconfig.json create mode 100644 vscode-ng-language-service/common/BUILD.bazel create mode 100644 vscode-ng-language-service/common/initialize.ts create mode 100644 vscode-ng-language-service/common/notifications.ts create mode 100644 vscode-ng-language-service/common/requests.ts create mode 100644 vscode-ng-language-service/common/resolver.ts create mode 100644 vscode-ng-language-service/common/tests/BUILD.bazel create mode 100644 vscode-ng-language-service/common/tests/resolver_spec.ts create mode 100644 vscode-ng-language-service/common/tests/tsconfig.json create mode 100644 vscode-ng-language-service/common/tests/tsconfig.tsbuildinfo create mode 100644 vscode-ng-language-service/common/tsconfig.json create mode 100644 vscode-ng-language-service/integration/BUILD.bazel create mode 100644 vscode-ng-language-service/integration/e2e/BUILD.bazel create mode 100644 vscode-ng-language-service/integration/e2e/completion_spec.ts create mode 100644 vscode-ng-language-service/integration/e2e/definition_spec.ts create mode 100644 vscode-ng-language-service/integration/e2e/helper.ts create mode 100644 vscode-ng-language-service/integration/e2e/hover_spec.ts create mode 100644 vscode-ng-language-service/integration/e2e/index.ts create mode 100644 vscode-ng-language-service/integration/e2e/jasmine.ts create mode 100644 vscode-ng-language-service/integration/lsp/BUILD.bazel create mode 100644 vscode-ng-language-service/integration/lsp/ivy_spec.ts create mode 100644 vscode-ng-language-service/integration/lsp/test_utils.ts create mode 100644 vscode-ng-language-service/integration/pre_apf_project/BUILD.bazel create mode 100644 vscode-ng-language-service/integration/pre_apf_project/app/app.component.ts create mode 100644 vscode-ng-language-service/integration/pre_apf_project/app/app.module.ts create mode 100644 vscode-ng-language-service/integration/pre_apf_project/app/foo.component.html create mode 100644 vscode-ng-language-service/integration/pre_apf_project/app/foo.component.ts create mode 100644 vscode-ng-language-service/integration/pre_apf_project/package.json create mode 100644 vscode-ng-language-service/integration/pre_apf_project/tsconfig.json create mode 100644 vscode-ng-language-service/integration/pre_standalone_project/BUILD.bazel create mode 100644 vscode-ng-language-service/integration/pre_standalone_project/app/app.component.ts create mode 100644 vscode-ng-language-service/integration/pre_standalone_project/app/app.module.ts create mode 100644 vscode-ng-language-service/integration/pre_standalone_project/app/foo.component.html create mode 100644 vscode-ng-language-service/integration/pre_standalone_project/app/foo.component.ts create mode 100644 vscode-ng-language-service/integration/pre_standalone_project/package.json create mode 100644 vscode-ng-language-service/integration/pre_standalone_project/tsconfig.json create mode 100644 vscode-ng-language-service/integration/project/BUILD.bazel create mode 100644 vscode-ng-language-service/integration/project/app/app.component.ts create mode 100644 vscode-ng-language-service/integration/project/app/app.module.ts create mode 100644 vscode-ng-language-service/integration/project/app/bar.component.ts create mode 100644 vscode-ng-language-service/integration/project/app/foo.component.html create mode 100644 vscode-ng-language-service/integration/project/app/foo.component.ts create mode 100644 vscode-ng-language-service/integration/project/libs/post/ng-package.json create mode 100644 vscode-ng-language-service/integration/project/libs/post/package.json create mode 100644 vscode-ng-language-service/integration/project/libs/post/src/index.ts create mode 100644 vscode-ng-language-service/integration/project/libs/post/src/lib/post.component.ts create mode 100644 vscode-ng-language-service/integration/project/libs/post/tsconfig.json create mode 100644 vscode-ng-language-service/integration/project/package.json create mode 100644 vscode-ng-language-service/integration/project/tsconfig.json create mode 100644 vscode-ng-language-service/integration/test_constants.ts create mode 100644 vscode-ng-language-service/integration/tsconfig.json create mode 100644 vscode-ng-language-service/integration/tsconfig.tsbuildinfo create mode 100644 vscode-ng-language-service/integration/workspace/BUILD.bazel create mode 100644 vscode-ng-language-service/integration/workspace/package.json create mode 100644 vscode-ng-language-service/integration/workspace/projects/demo/src/app/app.component.ts create mode 100644 vscode-ng-language-service/integration/workspace/projects/demo/src/app/app.module.ts create mode 100644 vscode-ng-language-service/integration/workspace/projects/demo/tsconfig.json create mode 100644 vscode-ng-language-service/integration/workspace/tsconfig.json create mode 100644 vscode-ng-language-service/package.json create mode 100644 vscode-ng-language-service/server/BUILD.bazel create mode 100644 vscode-ng-language-service/server/README.md create mode 100644 vscode-ng-language-service/server/bin/ngserver create mode 100644 vscode-ng-language-service/server/esbuild.mjs create mode 100644 vscode-ng-language-service/server/package.json create mode 100644 vscode-ng-language-service/server/src/BUILD.bazel create mode 100644 vscode-ng-language-service/server/src/banner.ts create mode 100644 vscode-ng-language-service/server/src/cmdline_utils.ts create mode 100644 vscode-ng-language-service/server/src/completion.ts create mode 100644 vscode-ng-language-service/server/src/diagnostic.ts create mode 100644 vscode-ng-language-service/server/src/embedded_support.ts create mode 100644 vscode-ng-language-service/server/src/logger.ts create mode 100644 vscode-ng-language-service/server/src/server.ts create mode 100644 vscode-ng-language-service/server/src/server_host.ts create mode 100644 vscode-ng-language-service/server/src/session.ts create mode 100644 vscode-ng-language-service/server/src/tests/BUILD.bazel create mode 100644 vscode-ng-language-service/server/src/tests/cmdline_utils_spec.ts create mode 100644 vscode-ng-language-service/server/src/tests/embedded_support_spec.ts create mode 100644 vscode-ng-language-service/server/src/tests/text_render_spec.ts create mode 100644 vscode-ng-language-service/server/src/tests/tsconfig.json create mode 100644 vscode-ng-language-service/server/src/tests/tsconfig.tsbuildinfo create mode 100644 vscode-ng-language-service/server/src/tests/utils_spec.ts create mode 100644 vscode-ng-language-service/server/src/tests/version_provider_spec.ts create mode 100644 vscode-ng-language-service/server/src/text_render.ts create mode 100644 vscode-ng-language-service/server/src/utils.ts create mode 100644 vscode-ng-language-service/server/src/version_provider.ts create mode 100644 vscode-ng-language-service/server/tsconfig.json create mode 100644 vscode-ng-language-service/syntaxes/BUILD.bazel create mode 100644 vscode-ng-language-service/syntaxes/README.md create mode 100644 vscode-ng-language-service/syntaxes/expression.json create mode 100644 vscode-ng-language-service/syntaxes/host-object-literal.json create mode 100644 vscode-ng-language-service/syntaxes/inline-styles.json create mode 100644 vscode-ng-language-service/syntaxes/inline-template.json create mode 100644 vscode-ng-language-service/syntaxes/let-declaration.json create mode 100644 vscode-ng-language-service/syntaxes/src/BUILD.bazel create mode 100644 vscode-ng-language-service/syntaxes/src/build.ts create mode 100644 vscode-ng-language-service/syntaxes/src/expression.ts create mode 100644 vscode-ng-language-service/syntaxes/src/host-object-literal.ts create mode 100644 vscode-ng-language-service/syntaxes/src/inline-styles.ts create mode 100644 vscode-ng-language-service/syntaxes/src/inline-template.ts create mode 100644 vscode-ng-language-service/syntaxes/src/template-blocks.ts create mode 100644 vscode-ng-language-service/syntaxes/src/template-let-declaration.ts create mode 100644 vscode-ng-language-service/syntaxes/src/template-tag.ts create mode 100644 vscode-ng-language-service/syntaxes/src/template.ts create mode 100644 vscode-ng-language-service/syntaxes/src/types.ts create mode 100644 vscode-ng-language-service/syntaxes/template-blocks.json create mode 100644 vscode-ng-language-service/syntaxes/template-tag.json create mode 100644 vscode-ng-language-service/syntaxes/template.json create mode 100644 vscode-ng-language-service/syntaxes/test/BUILD.bazel create mode 100644 vscode-ng-language-service/syntaxes/test/cases.ts create mode 100644 vscode-ng-language-service/syntaxes/test/data/expression.html create mode 100644 vscode-ng-language-service/syntaxes/test/data/expression.html.snap create mode 100644 vscode-ng-language-service/syntaxes/test/data/host-object-literal.ts create mode 100644 vscode-ng-language-service/syntaxes/test/data/host-object-literal.ts.snap create mode 100644 vscode-ng-language-service/syntaxes/test/data/inline-styles.ts create mode 100644 vscode-ng-language-service/syntaxes/test/data/inline-styles.ts.snap create mode 100644 vscode-ng-language-service/syntaxes/test/data/inline-template.ts create mode 100644 vscode-ng-language-service/syntaxes/test/data/inline-template.ts.snap create mode 100644 vscode-ng-language-service/syntaxes/test/data/let-declaration.html create mode 100644 vscode-ng-language-service/syntaxes/test/data/let-declaration.html.snap create mode 100644 vscode-ng-language-service/syntaxes/test/data/template-blocks.html create mode 100644 vscode-ng-language-service/syntaxes/test/data/template-blocks.html.snap create mode 100644 vscode-ng-language-service/syntaxes/test/data/template-tag.html create mode 100644 vscode-ng-language-service/syntaxes/test/data/template-tag.html.snap create mode 100644 vscode-ng-language-service/syntaxes/test/data/template.html create mode 100644 vscode-ng-language-service/syntaxes/test/data/template.html.snap create mode 100644 vscode-ng-language-service/syntaxes/test/driver.ts create mode 100644 vscode-ng-language-service/syntaxes/test/dummy/css.tmLanguage-dummy.json create mode 100644 vscode-ng-language-service/syntaxes/test/dummy/html.tmLanguage-dummy.json create mode 100644 vscode-ng-language-service/syntaxes/test/dummy/js.tmLanguage-dummy.json create mode 100644 vscode-ng-language-service/syntaxes/test/dummy/scss.tmLanguage-dummy.json create mode 100644 vscode-ng-language-service/syntaxes/test/tsconfig.json create mode 100644 vscode-ng-language-service/syntaxes/tsconfig.json create mode 100644 vscode-ng-language-service/tsconfig.json diff --git a/.bazelignore b/.bazelignore index 377aaff5b60..181e5392d11 100644 --- a/.bazelignore +++ b/.bazelignore @@ -4,7 +4,7 @@ # https://github.com/bazelbuild/bazel/issues/8106 .git node_modules -dist +dist/ # All integration test node_modules folders integration/animations/node_modules @@ -39,6 +39,7 @@ integration/legacy-animations/node_modules integration/legacy-animations-async/node_modules integration/typings_test_ts59/node_modules modules/ssr-benchmarks/node_modules +vscode-ng-language-service/integration/project/dist/ # For rules_js adev/node_modules @@ -69,3 +70,8 @@ packages/service-worker/node_modules packages/zone.js/test/typings/node_modules packages/zone.js/node_modules tools/bazel/rules_angular_store/node_modules +vscode-ng-language-service/node_modules +vscode-ng-language-service/integration/pre_standalone_project/node_modules +vscode-ng-language-service/integration/workspace/node_modules +vscode-ng-language-service/integration/pre_apf_project/node_modules +vscode-ng-language-service/integration/project/node_modules diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a9f85ac479c..55d867fab9c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -119,6 +119,21 @@ jobs: - name: Build adev in fast mode to ensure it continues to work run: pnpm bazel build //adev:build + vscode-ng-language-service: + runs-on: + labels: ubuntu-latest + steps: + - name: Initialize environment + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@d776aff2258f15fc3dc1e63852887518eec3ad75 + - name: Setup Bazel + uses: angular/dev-infra/github-actions/bazel/setup@d776aff2258f15fc3dc1e63852887518eec3ad75 + - name: Setup Bazel RBE + uses: angular/dev-infra/github-actions/bazel/configure-remote@d776aff2258f15fc3dc1e63852887518eec3ad75 + - name: Install node modules + run: pnpm install --frozen-lockfile + - name: Run tests + run: pnpm bazel test //vscode-ng-language-service/... + publish-snapshots: runs-on: labels: ubuntu-latest diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 62a4ab8d201..f4993544014 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -127,6 +127,21 @@ jobs: - name: Build adev in fast mode to ensure it continues to work run: pnpm bazel build //adev:build + vscode-ng-language-service: + runs-on: + labels: ubuntu-latest + steps: + - name: Initialize environment + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@d776aff2258f15fc3dc1e63852887518eec3ad75 + - name: Setup Bazel + uses: angular/dev-infra/github-actions/bazel/setup@d776aff2258f15fc3dc1e63852887518eec3ad75 + - name: Setup Bazel RBE + uses: angular/dev-infra/github-actions/bazel/configure-remote@d776aff2258f15fc3dc1e63852887518eec3ad75 + - name: Install node modules + run: pnpm install --frozen-lockfile + - name: Run tests + run: pnpm bazel test //vscode-ng-language-service/... + zone-js: runs-on: labels: ubuntu-latest diff --git a/.gitignore b/.gitignore index 8c124604a98..d6214dd5f44 100644 --- a/.gitignore +++ b/.gitignore @@ -16,9 +16,6 @@ pubspec.lock !.devcontainer/recommended-devcontainer.json !.devcontainer/recommended-Dockerfile .settings/ -.vscode/launch.json -.vscode/settings.json -.vscode/tasks.json *.swo *.swp modules/.settings diff --git a/.ng-dev/commit-message.mts b/.ng-dev/commit-message.mts index 524b37608ac..4403de82edb 100644 --- a/.ng-dev/commit-message.mts +++ b/.ng-dev/commit-message.mts @@ -25,6 +25,7 @@ export const commitMessage: CommitMessageConfig = { 'forms', 'http', 'language-service', + 'language-server', 'localize', 'migrations', 'packaging', @@ -34,6 +35,7 @@ export const commitMessage: CommitMessageConfig = { 'router', 'service-worker', 'upgrade', + 'vscode-extension', 'zone.js', ], }; diff --git a/.ng-dev/format.mts b/.ng-dev/format.mts index 186bdff9e9b..23a8902e6d1 100644 --- a/.ng-dev/format.mts +++ b/.ng-dev/format.mts @@ -25,6 +25,9 @@ export const format: FormatConfig = { // Ignore generated javascript file(s) '!.github/actions/deploy-docs-site/main.js', + + // Ignore testing data files for language service + '!vscode-ng-language-service/syntaxes/test/data/*.ts', ], }, 'buildifier': true, diff --git a/.pnpmfile.cjs b/.pnpmfile.cjs index f29c5a1c3fb..38a831f6af2 100644 --- a/.pnpmfile.cjs +++ b/.pnpmfile.cjs @@ -42,7 +42,7 @@ function readPackage(pkg, context) { // Change all locally generated packages to directly depend on the other local packages, instead // of expecting them as peerDependencies automatically as we do not auto install peer deps. The // package is also removed from peerDependencies as it was moved over and will just cause errors. - if (localAngularPackages.includes(key)) { + if (localAngularPackages.includes(key) && pkg.version === '0.0.0-PLACEHOLDER') { pkg.dependencies = { ...pkg.dependencies, [key]: 'workspace: *', diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000000..364441d2a68 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,94 @@ +// A launch configuration that compiles the extension and then opens it inside a new window +{ + "version": "0.2.0", + "configurations": [ + { + "type": "extensionHost", + "request": "launch", + "name": "Launch Dev Client", + "runtimeExecutable": "${execPath}", + "args": [ + "--disable-extensions", + "--extensionDevelopmentPath=${workspaceFolder}" + ], + "outFiles": [ + "${workspaceFolder}/dist/bin/vscode-ng-language-service/client/src/*.js" + ], + "preLaunchTask": { + "type": "npm", + "script": "vscode:watch" + } + }, + { + "type": "extensionHost", + "request": "launch", + "name": "Launch Prod Client", + "runtimeExecutable": "${execPath}", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}/dist/bin/vscode-ng-language-service/npm" + ], + "sourceMaps": false, + "preLaunchTask": "build vsix" + }, + { + "type": "node", + "request": "attach", + "name": "Attach to Server", + "port": 6009, + "restart": true, + "outFiles": [ + "${workspaceFolder}/dist/bin/vscode-ng-language-service/server/src/*.js" + ] + }, + { + "type": "node", + "request": "attach", + "name": "Attach to Jasmine", + "port": 9229, + "restart": true, + "outFiles": [ + "${workspaceFolder}/dist/bin/vscode-ng-language-service/**/*.js" + ], + }, + { + "name": "Integration test: Attach to server", + "port": 9330, + "request": "attach", + "skipFiles": [ + "/**" + ], + "outFiles": [ + "${workspaceFolder}/dist/bin/vscode-ng-language-service/integration/lsp/*.js" + ], + "type": "node" + }, + { + "name": "E2E Test", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--disable-extensions", + "--extensionDevelopmentPath=${workspaceFolder}/dist/bin/vscode-ng-language-service/npm", + "--extensionTestsPath=${workspaceFolder}/dist/bin/vscode-ng-language-service/integration/e2e/jasmine", + "${workspaceFolder}/vscode-ng-language-service/integration/project" + ], + "outFiles": [ + "${workspaceFolder}/dist/bin/vscode-ng-language-service/integration/e2e/*.js" + ], + "preLaunchTask": { + "type": "npm", + "script": "compile:integration" + } + } + ], + "compounds": [ + { + "name": "Dev Client + Server", + "configurations": [ + "Launch Dev Client", + "Attach to Server" + ] + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000000..df7e2e153d8 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,43 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "npm", + "script": "compile", + "group": "build", + "presentation": { + "panel": "dedicated", + "reveal": "never" + }, + "problemMatcher": [ + "$tsc" + ] + }, + { + "type": "npm", + "script": "vscode:watch", + "isBackground": true, + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "panel": "dedicated", + "reveal": "never" + }, + "problemMatcher": { + "base": "$tsc-watch", + "background": { + "activeOnStart": true, + "beginsPattern": "^iBazel \\[\\d{1,2}:\\d{1,2}(?:AM|PM)\\]: Querying for files to watch.*", + "endsPattern": "^INFO: Build completed successfully, \\d+ total action(s)?" + } + } + }, + { + "type": "shell", + "label": "build vsix", + "command": "pnpm bazel build //vscode-ng-language-service:npm --config=release" + } + ] +} diff --git a/MODULE.bazel b/MODULE.bazel index 8ad6ae8d5f2..bc94a15d8f9 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -96,6 +96,10 @@ npm.npm_translate_lock( "//packages/service-worker:package.json", "//packages/upgrade:package.json", "//tools/bazel/rules_angular_store:package.json", + "//vscode-ng-language-service/integration/pre_apf_project:package.json", + "//vscode-ng-language-service/integration/pre_standalone_project:package.json", + "//vscode-ng-language-service/integration/project:package.json", + "//vscode-ng-language-service/integration/workspace:package.json", ], npmrc = "//:.npmrc", pnpm_lock = "//:pnpm-lock.yaml", diff --git a/package.json b/package.json index fe2c43a56ec..706353b45ea 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "ng-dev": "tsx --tsconfig .ng-dev/tsconfig.json node_modules/@angular/ng-dev/bundles/cli.mjs", "build": "tsx --tsconfig scripts/tsconfig.json scripts/build/build-packages-dist.mts", "test": "bazelisk test", - "test:ci": "bazelisk test -- //... -//integration/... -//adev/... -//devtools/... -//modules/ssr-benchmarks/...", + "test:ci": "bazelisk test -- //... -//integration/... -//adev/... -//vscode-ng-language-service/... -//devtools/... -//modules/ssr-benchmarks/...", "integration-tests:ci": "bazelisk test -- //integration/...", "test-tsec": "bazelisk test //... --build_tag_filters=tsec --test_tag_filters=tsec", "lint": "pnpm --silent tslint && pnpm --silent ng-dev format changed --check", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 85c48e44da1..cace104066d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ overrides: packageExtensionsChecksum: sha256-3L73Fw32UVtE6x5BJxJPBtQtH/mgsr31grNpdhHP1IY= -pnpmfileChecksum: sha256-+7KlkWdGv7+7wb/qym+KoHN4eBGq9TNblo2Ln6HTxz0= +pnpmfileChecksum: sha256-LDBE/t1gL6QCKvsgYzYxZaZlgGBTCaL/3QUNg+cLWBE= patchedDependencies: dagre-d3-es@7.0.11: @@ -23,7 +23,7 @@ importers: dependencies: '@angular-devkit/build-angular': specifier: 21.0.0-next.4 - version: 21.0.0-next.4(@angular/ssr@21.0.0-next.4)(@types/node@20.19.17)(bufferutil@4.0.9)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9))(protractor@7.0.0)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2)))(tsx@4.20.5)(typescript@5.9.2)(vitest@3.2.4(@types/node@20.19.17)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1) + version: 21.0.0-next.4(@angular/compiler-cli@packages+compiler-cli)(@angular/compiler@packages+compiler)(@angular/core@packages+core)(@angular/localize@packages+localize)(@angular/platform-browser@packages+platform-browser)(@angular/platform-server@packages+platform-server)(@angular/service-worker@packages+service-worker)(@angular/ssr@21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(@angular/platform-server@packages+platform-server)(@angular/router@packages+router))(@types/node@20.19.17)(bufferutil@4.0.9)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9))(protractor@7.0.0)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2)))(tsx@4.20.5)(typescript@5.9.2)(vitest@3.2.4(@types/node@20.19.17)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1) '@angular-devkit/core': specifier: 21.0.0-next.4 version: 21.0.0-next.4(chokidar@4.0.3) @@ -38,10 +38,10 @@ importers: version: link:packages/benchpress '@angular/build': specifier: 21.0.0-next.4 - version: 21.0.0-next.4(@angular/ssr@21.0.0-next.4)(@types/node@20.19.17)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9))(less@4.4.1)(postcss@8.5.6)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2)))(terser@5.44.0)(tslib@2.8.1)(tsx@4.20.5)(typescript@5.9.2)(vitest@3.2.4(@types/node@20.19.17)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1) + version: 21.0.0-next.4(@angular/compiler-cli@packages+compiler-cli)(@angular/compiler@packages+compiler)(@angular/core@packages+core)(@angular/localize@packages+localize)(@angular/platform-browser@packages+platform-browser)(@angular/platform-server@packages+platform-server)(@angular/service-worker@packages+service-worker)(@angular/ssr@21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(@angular/platform-server@packages+platform-server)(@angular/router@packages+router))(@types/node@20.19.17)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9))(less@4.4.1)(postcss@8.5.6)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2)))(terser@5.44.0)(tslib@2.8.1)(tsx@4.20.5)(typescript@5.9.2)(vitest@3.2.4(@types/node@20.19.17)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1) '@angular/cdk': specifier: 21.0.0-next.4 - version: 21.0.0-next.4(rxjs@7.8.2) + version: 21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(rxjs@7.8.2) '@angular/cli': specifier: 21.0.0-next.4 version: 21.0.0-next.4(@types/node@20.19.17)(chokidar@4.0.3) @@ -71,7 +71,7 @@ importers: version: link:packages/localize '@angular/material': specifier: 21.0.0-next.4 - version: 21.0.0-next.4(@angular/cdk@21.0.0-next.4(rxjs@7.8.2))(rxjs@7.8.2) + version: 21.0.0-next.4(@angular/cdk@21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(rxjs@7.8.2))(@angular/common@packages+common)(@angular/core@packages+core)(@angular/forms@packages+forms)(@angular/platform-browser@packages+platform-browser)(rxjs@7.8.2) '@angular/platform-browser': specifier: workspace:* version: link:packages/platform-browser @@ -89,7 +89,7 @@ importers: version: link:packages/service-worker '@angular/ssr': specifier: 21.0.0-next.4 - version: 21.0.0-next.4 + version: 21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(@angular/platform-server@packages+platform-server)(@angular/router@packages+router) '@angular/upgrade': specifier: 'workspace: *' version: link:packages/upgrade @@ -269,10 +269,10 @@ importers: version: 0.30.19 ngx-flamegraph: specifier: 0.1.1 - version: 0.1.1 + version: 0.1.1(@angular/common@packages+common)(@angular/core@packages+core) ngx-progressbar: specifier: ^14.0.0 - version: 14.0.0(@angular/cdk@21.0.0-next.4(rxjs@7.8.2))(rxjs@7.8.2) + version: 14.0.0(@angular/cdk@21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(rxjs@7.8.2))(@angular/common@packages+common)(@angular/core@packages+core)(rxjs@7.8.2) open-in-idx: specifier: ^0.1.1 version: 0.1.1 @@ -390,7 +390,7 @@ importers: version: 7.8.6(@types/node@20.19.17) '@nginfra/angular-linking': specifier: ^1.0.10 - version: 1.0.10 + version: 1.0.10(@angular/compiler-cli@packages+compiler-cli) '@octokit/graphql': specifier: ^9.0.0 version: 9.0.1 @@ -423,7 +423,7 @@ importers: version: 0.5.16 angular-split: specifier: ^20.0.0 - version: 20.0.0(rxjs@7.8.2) + version: 20.0.0(@angular/common@packages+common)(@angular/core@packages+core)(rxjs@7.8.2) check-side-effects: specifier: 0.0.23 version: 0.0.23 @@ -525,16 +525,16 @@ importers: version: 5.37.0 '@angular-devkit/build-angular': specifier: 21.0.0-next.4 - version: 21.0.0-next.4(@angular/ssr@21.0.0-next.4)(@types/node@24.5.2)(bufferutil@4.0.9)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9)(utf-8-validate@6.0.5))(protractor@7.0.0)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2)))(tsx@4.20.5)(typescript@5.9.2)(utf-8-validate@6.0.5)(vitest@3.2.4(@types/node@24.5.2)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6)(utf-8-validate@6.0.5))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1) + version: 21.0.0-next.4(@angular/compiler-cli@packages+compiler-cli)(@angular/compiler@packages+compiler)(@angular/core@packages+core)(@angular/localize@packages+localize)(@angular/platform-browser@packages+platform-browser)(@angular/platform-server@packages+platform-server)(@angular/service-worker@packages+service-worker)(@angular/ssr@21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(@angular/platform-server@packages+platform-server)(@angular/router@packages+router))(@types/node@24.5.2)(bufferutil@4.0.9)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9)(utf-8-validate@6.0.5))(protractor@7.0.0)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2)))(tsx@4.20.5)(typescript@5.9.2)(utf-8-validate@6.0.5)(vitest@3.2.4(@types/node@24.5.2)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6)(utf-8-validate@6.0.5))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1) '@angular/animations': specifier: workspace:* version: link:../packages/animations '@angular/build': specifier: 21.0.0-next.4 - version: 21.0.0-next.4(@angular/ssr@21.0.0-next.4)(@types/node@24.5.2)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.4.1)(postcss@8.5.6)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2)))(terser@5.44.0)(tslib@2.8.1)(tsx@4.20.5)(typescript@5.9.2)(vitest@3.2.4(@types/node@24.5.2)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6)(utf-8-validate@6.0.5))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1) + version: 21.0.0-next.4(@angular/compiler-cli@packages+compiler-cli)(@angular/compiler@packages+compiler)(@angular/core@packages+core)(@angular/localize@packages+localize)(@angular/platform-browser@packages+platform-browser)(@angular/platform-server@packages+platform-server)(@angular/service-worker@packages+service-worker)(@angular/ssr@21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(@angular/platform-server@packages+platform-server)(@angular/router@packages+router))(@types/node@24.5.2)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.4.1)(postcss@8.5.6)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2)))(terser@5.44.0)(tslib@2.8.1)(tsx@4.20.5)(typescript@5.9.2)(vitest@3.2.4(@types/node@24.5.2)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6)(utf-8-validate@6.0.5))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1) '@angular/cdk': specifier: 21.0.0-next.4 - version: 21.0.0-next.4(rxjs@7.8.2) + version: 21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(rxjs@7.8.2) '@angular/cli': specifier: 21.0.0-next.4 version: 21.0.0-next.4(@types/node@24.5.2)(chokidar@4.0.3) @@ -558,7 +558,7 @@ importers: version: link:../packages/forms '@angular/material': specifier: 21.0.0-next.4 - version: 21.0.0-next.4(@angular/cdk@21.0.0-next.4(rxjs@7.8.2))(rxjs@7.8.2) + version: 21.0.0-next.4(@angular/cdk@21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(rxjs@7.8.2))(@angular/common@packages+common)(@angular/core@packages+core)(@angular/forms@packages+forms)(@angular/platform-browser@packages+platform-browser)(rxjs@7.8.2) '@angular/platform-browser': specifier: workspace:* version: link:../packages/platform-browser @@ -570,7 +570,7 @@ importers: version: link:../packages/router '@angular/ssr': specifier: 21.0.0-next.4 - version: 21.0.0-next.4 + version: 21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(@angular/platform-server@packages+platform-server)(@angular/router@packages+router) '@codemirror/autocomplete': specifier: 6.18.7 version: 6.18.7 @@ -663,7 +663,7 @@ importers: version: 5.37.0 angular-split: specifier: 20.0.0 - version: 20.0.0(rxjs@7.8.2) + version: 20.0.0(@angular/common@packages+common)(@angular/core@packages+core)(rxjs@7.8.2) crelt: specifier: 1.0.6 version: 1.0.6 @@ -702,7 +702,7 @@ importers: version: 11.12.0 ngx-progressbar: specifier: 14.0.0 - version: 14.0.0(@angular/cdk@21.0.0-next.4(rxjs@7.8.2))(rxjs@7.8.2) + version: 14.0.0(@angular/cdk@21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(rxjs@7.8.2))(@angular/common@packages+common)(@angular/core@packages+core)(rxjs@7.8.2) open-in-idx: specifier: 0.1.1 version: 0.1.1 @@ -871,7 +871,7 @@ importers: version: link:../packages/benchpress '@angular/build': specifier: 21.0.0-next.4 - version: 21.0.0-next.4(@angular/ssr@21.0.0-next.4)(@types/node@24.5.2)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.4.1)(postcss@8.5.6)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2)))(terser@5.44.0)(tslib@2.8.1)(tsx@4.20.5)(typescript@5.9.2)(vitest@3.2.4(@types/node@24.5.2)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6)(utf-8-validate@6.0.5))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1) + version: 21.0.0-next.4(@angular/compiler-cli@packages+compiler-cli)(@angular/compiler@packages+compiler)(@angular/core@packages+core)(@angular/localize@packages+localize)(@angular/platform-browser@packages+platform-browser)(@angular/platform-server@packages+platform-server)(@angular/service-worker@packages+service-worker)(@angular/ssr@21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(@angular/platform-server@packages+platform-server)(@angular/router@packages+router))(@types/node@24.5.2)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.4.1)(postcss@8.5.6)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2)))(terser@5.44.0)(tslib@2.8.1)(tsx@4.20.5)(typescript@5.9.2)(vitest@3.2.4(@types/node@24.5.2)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6)(utf-8-validate@6.0.5))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1) '@angular/common': specifier: workspace:* version: link:../packages/common @@ -955,7 +955,7 @@ importers: dependencies: '@angular/core': specifier: ^21.0.0-next - version: 21.0.0-next.4 + version: 21.0.0-next.4(@angular/compiler@packages+compiler) reflect-metadata: specifier: ^0.2.0 version: 0.2.2 @@ -1042,7 +1042,7 @@ importers: version: link:../../../animations '@angular/build': specifier: 21.0.0-next.4 - version: 21.0.0-next.4(@angular/ssr@21.0.0-next.4)(@types/node@24.5.2)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.4.1)(postcss@8.5.6)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2)))(terser@5.44.0)(tslib@2.8.1)(tsx@4.20.5)(typescript@5.9.2)(vitest@3.2.4(@types/node@24.5.2)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6)(utf-8-validate@6.0.5))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1) + version: 21.0.0-next.4(@angular/compiler-cli@packages+compiler-cli)(@angular/compiler@packages+compiler)(@angular/core@packages+core)(@angular/localize@packages+localize)(@angular/platform-browser@packages+platform-browser)(@angular/platform-server@packages+platform-server)(@angular/service-worker@packages+service-worker)(@angular/ssr@21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(@angular/platform-server@packages+platform-server)(@angular/router@packages+router))(@types/node@24.5.2)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.4.1)(postcss@8.5.6)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2)))(terser@5.44.0)(tslib@2.8.1)(tsx@4.20.5)(typescript@5.9.2)(vitest@3.2.4(@types/node@24.5.2)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6)(utf-8-validate@6.0.5))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1) '@angular/common': specifier: workspace:* version: link:../../../common @@ -1317,6 +1317,191 @@ importers: specifier: workspace:* version: link:../../../packages/compiler-cli + vscode-ng-language-service: + dependencies: + '@angular/language-service': + specifier: 20.3.0 + version: 20.3.0 + typescript: + specifier: 5.9.2 + version: 5.9.2 + vscode-html-languageservice: + specifier: ^4.2.5 + version: 4.2.5 + vscode-jsonrpc: + specifier: 6.0.0 + version: 6.0.0 + vscode-languageclient: + specifier: 7.0.0 + version: 7.0.0 + vscode-languageserver: + specifier: 7.0.0 + version: 7.0.0 + vscode-languageserver-textdocument: + specifier: ^1.0.7 + version: 1.0.12 + vscode-uri: + specifier: 3.0.7 + version: 3.0.7 + devDependencies: + '@angular/core': + specifier: ^20.0.0-rc.2 + version: 20.3.0(@angular/compiler@packages+compiler)(rxjs@6.6.7) + '@types/jasmine': + specifier: 3.10.7 + version: 3.10.7 + '@types/node': + specifier: 18.19.39 + version: 18.19.39 + '@types/vscode': + specifier: 1.67.0 + version: 1.67.0 + balanced-match: + specifier: 1.0.2 + version: 1.0.2 + brace-expansion: + specifier: 1.1.12 + version: 1.1.12 + concat-map: + specifier: 0.0.1 + version: 0.0.1 + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + esbuild: + specifier: 0.14.39 + version: 0.14.39 + jasmine: + specifier: 5.10.0 + version: 5.10.0 + jasmine-core: + specifier: 5.10.0 + version: 5.10.0 + jasmine-reporters: + specifier: 2.5.2 + version: 2.5.2 + lru-cache: + specifier: 6.0.0 + version: 6.0.0 + minimatch: + specifier: 3.1.2 + version: 3.1.2 + prettier: + specifier: 2.7.1 + version: 2.7.1 + rxjs: + specifier: 6.6.7 + version: 6.6.7 + semver: + specifier: 7.7.2 + version: 7.7.2 + source-map-support: + specifier: 0.5.21 + version: 0.5.21 + ts-node: + specifier: ^10.8.1 + version: 10.9.2(@types/node@18.19.39)(typescript@5.9.2) + vsce: + specifier: 1.100.1 + version: 1.100.1 + vscode-languageserver-protocol: + specifier: 3.16.0 + version: 3.16.0 + vscode-languageserver-types: + specifier: 3.16.0 + version: 3.16.0 + vscode-nls: + specifier: 5.2.0 + version: 5.2.0 + vscode-test: + specifier: 1.6.1 + version: 1.6.1 + vscode-tmgrammar-test: + specifier: 0.0.11 + version: 0.0.11 + yallist: + specifier: 4.0.0 + version: 4.0.0 + + vscode-ng-language-service/integration/pre_apf_project: + dependencies: + '@angular/common': + specifier: 12.2.16 + version: 12.2.16(@angular/core@12.2.16(rxjs@6.6.7)(zone.js@0.11.5))(rxjs@6.6.7) + '@angular/compiler': + specifier: 12.2.16 + version: 12.2.16 + '@angular/compiler-cli': + specifier: 12.2.16 + version: 12.2.16(@angular/compiler@12.2.16) + '@angular/core': + specifier: 12.2.16 + version: 12.2.16(rxjs@6.6.7)(zone.js@0.11.5) + rxjs: + specifier: 6.6.7 + version: 6.6.7 + zone.js: + specifier: 0.11.5 + version: 0.11.5 + + vscode-ng-language-service/integration/pre_standalone_project: + dependencies: + '@angular/common': + specifier: 18.2.10 + version: 18.2.10(@angular/core@18.2.10) + '@angular/core': + specifier: 18.2.10 + version: 18.2.10 + + vscode-ng-language-service/integration/project: + dependencies: + '@angular/common': + specifier: 18.1.0-rc.0 + version: 18.1.0-rc.0(@angular/core@18.1.0-rc.0(rxjs@6.6.7)(zone.js@0.11.5))(rxjs@6.6.7) + '@angular/compiler': + specifier: 18.1.0-rc.0 + version: 18.1.0-rc.0(@angular/core@18.1.0-rc.0(rxjs@6.6.7)(zone.js@0.11.5)) + '@angular/compiler-cli': + specifier: 18.1.0-rc.0 + version: 18.1.0-rc.0(@angular/compiler@18.1.0-rc.0(@angular/core@18.1.0-rc.0(rxjs@6.6.7)(zone.js@0.11.5)))(typescript@5.5.4) + '@angular/core': + specifier: 18.1.0-rc.0 + version: 18.1.0-rc.0(rxjs@6.6.7)(zone.js@0.11.5) + rxjs: + specifier: 6.6.7 + version: 6.6.7 + zone.js: + specifier: 0.11.5 + version: 0.11.5 + devDependencies: + ng-packagr: + specifier: ^18.0.0-next.0 + version: 18.2.1(@angular/compiler-cli@18.1.0-rc.0(@angular/compiler@18.1.0-rc.0(@angular/core@18.1.0-rc.0(rxjs@6.6.7)(zone.js@0.11.5)))(typescript@5.5.4))(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.5.4)))(tslib@2.8.1)(typescript@5.5.4) + typescript: + specifier: ~5.5.3 + version: 5.5.4 + + vscode-ng-language-service/integration/workspace: + dependencies: + '@angular/common': + specifier: 13.3.9 + version: 13.3.9(@angular/core@13.3.9(rxjs@6.6.7)(zone.js@0.11.5))(rxjs@6.6.7) + '@angular/compiler': + specifier: 13.3.9 + version: 13.3.9 + '@angular/compiler-cli': + specifier: 13.3.9 + version: 13.3.9(@angular/compiler@13.3.9) + '@angular/core': + specifier: 13.3.9 + version: 13.3.9(rxjs@6.6.7)(zone.js@0.11.5) + rxjs: + specifier: 6.6.7 + version: 6.6.7 + zone.js: + specifier: 0.11.5 + version: 0.11.5 + packages: '@actions/core@1.11.1': @@ -1411,6 +1596,12 @@ packages: resolution: {integrity: sha512-Oee2o4aHIogXtAVyoe7dOhLvPu6UXXxPUcpC1Y5SzozboFkeFlEhW3dMy7fibZKDx/LYdS9SNSUJu4GDYTF4eA==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: + '@angular/compiler-cli': ^21.0.0-next.0 + '@angular/core': ^21.0.0-next.0 + '@angular/localize': ^21.0.0-next.0 + '@angular/platform-browser': ^21.0.0-next.0 + '@angular/platform-server': ^21.0.0-next.0 + '@angular/service-worker': ^21.0.0-next.0 '@angular/ssr': ^21.0.0-next.4 '@web/test-runner': ^0.20.0 browser-sync: ^3.0.2 @@ -1422,6 +1613,16 @@ packages: tailwindcss: ^2.0.0 || ^3.0.0 || ^4.0.0 typescript: '>=5.9 <6.0' peerDependenciesMeta: + '@angular/core': + optional: true + '@angular/localize': + optional: true + '@angular/platform-browser': + optional: true + '@angular/platform-server': + optional: true + '@angular/service-worker': + optional: true '@angular/ssr': optional: true '@web/test-runner': @@ -1470,6 +1671,13 @@ packages: resolution: {integrity: sha512-ie1kczL0VH8y1wbaATevcGkc4W69y3DOc5Qw5xKFbjGnQpqC53MdNkgiuNWyGwNAz1S2pBiUORmXAACHLFFLEA==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: + '@angular/compiler': ^21.0.0-next.0 + '@angular/compiler-cli': ^21.0.0-next.0 + '@angular/core': ^21.0.0-next.0 + '@angular/localize': ^21.0.0-next.0 + '@angular/platform-browser': ^21.0.0-next.0 + '@angular/platform-server': ^21.0.0-next.0 + '@angular/service-worker': ^21.0.0-next.0 '@angular/ssr': ^21.0.0-next.4 karma: ^6.4.0 less: ^4.2.0 @@ -1480,6 +1688,16 @@ packages: typescript: '>=5.9 <6.0' vitest: ^3.1.1 peerDependenciesMeta: + '@angular/core': + optional: true + '@angular/localize': + optional: true + '@angular/platform-browser': + optional: true + '@angular/platform-server': + optional: true + '@angular/service-worker': + optional: true '@angular/ssr': optional: true karma: @@ -1498,6 +1716,8 @@ packages: '@angular/cdk@21.0.0-next.4': resolution: {integrity: sha512-CtAqlp4YMBDRamkyxPhd7zjPuOqNxTLbxqCmaxT26th+tmylpUr9CWSCkEhjGvjI3NfsNM385GLyUzGRxdqYXQ==} peerDependencies: + '@angular/common': ^21.0.0-0 || ^21.1.0-0 || ^21.2.0-0 || ^21.3.0-0 || ^22.0.0-0 + '@angular/core': ^21.0.0-0 || ^21.1.0-0 || ^21.2.0-0 || ^21.3.0-0 || ^22.0.0-0 rxjs: ^6.5.3 || ^7.4.0 '@angular/cli@21.0.0-next.4': @@ -1505,18 +1725,132 @@ packages: engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} hasBin: true + '@angular/common@12.2.16': + resolution: {integrity: sha512-FEqTXTEsnbDInqV1yFlm97Tz1OFqZS5t0TUkm8gzXRgpIce/F/jLwAg0u1VQkgOsno6cNm0xTWPoZgu85NI4ug==} + engines: {node: ^12.14.1 || >=14.0.0} + peerDependencies: + '@angular/core': 12.2.16 + rxjs: ^6.5.3 || ^7.0.0 + + '@angular/common@13.3.9': + resolution: {integrity: sha512-+bTleNL1XGlzuxLbVbsol82/33IW2pJasQN8ViraxKIElT2F8ooBJevIBMCSIcdvxvMBGAjn4ayQJr6tkPqPaw==} + engines: {node: ^12.20.0 || ^14.15.0 || >=16.10.0} + peerDependencies: + '@angular/core': 13.3.9 + rxjs: ^6.5.3 || ^7.4.0 + + '@angular/common@18.1.0-rc.0': + resolution: {integrity: sha512-gkJ7xfUESRFTZB85+pbShzZgRgjlc5fGP7FObH3UlvUJTy1PIXvvcodAAiiWLl0ZMD+jeie08El/DLeO8ikpNQ==} + engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0} + peerDependencies: + '@angular/core': 18.1.0-rc.0 + rxjs: ^6.5.3 || ^7.4.0 + + '@angular/common@18.2.10': + resolution: {integrity: sha512-YzTCmuqLiOuT+Yv07vuKymDWiebOVZ8BuXakJiz4EM7FMoOw5gICHJ04jepZSjDNWpA16e7kJSdt5ucnmvCFDQ==} + engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0} + peerDependencies: + '@angular/core': 18.2.10 + + '@angular/compiler-cli@12.2.16': + resolution: {integrity: sha512-tlalh8SJvdCWbUPRUR5GamaP+wSc/GuCsoUZpSbcczGKgSlbaEVXUYtVXm8/wuT6Slk2sSEbRs7tXGF2i7qxVw==} + engines: {node: ^12.14.1 || >=14.0.0} + hasBin: true + peerDependencies: + '@angular/compiler': 12.2.16 + + '@angular/compiler-cli@13.3.9': + resolution: {integrity: sha512-jf4iG7uqE1ZW2mJgKJyDyFby/sVQDlGOtUl68TMf8r06koWeny5nk/LhL7jp3Q6rgN2ZdYALtPTRSj7HVQD8pA==} + engines: {node: ^12.20.0 || ^14.15.0 || >=16.10.0} + hasBin: true + peerDependencies: + '@angular/compiler': 13.3.9 + + '@angular/compiler-cli@18.1.0-rc.0': + resolution: {integrity: sha512-+7ALPi04nkkH4NySqOWLi/aQ6bCTMFsAKaNMLkJvlrq/Mey1H3UhfFauKozaOl+fJc76tVOshuRM4MgF/OSE5g==} + engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0} + hasBin: true + peerDependencies: + '@angular/compiler': 18.1.0-rc.0 + typescript: '>=5.4 <5.6' + + '@angular/compiler@12.2.16': + resolution: {integrity: sha512-nsYEw+yu8QyeqPf9nAmG419i1mtGM4v8+U+S3eQHQFXTgJzLymMykWHYu2ETdjUpNSLK6xcIQDBWtWnWSfJjAA==} + engines: {node: ^12.14.1 || >=14.0.0} + + '@angular/compiler@13.3.9': + resolution: {integrity: sha512-fXmcN9PIUTJ9Vw2QyQE9vtW95K5ML9bVI7409Zf3DAQJEo4IhX2eUjgiGF3RtSn9Kdjj3tZY0xSbGGwp1hTBIA==} + engines: {node: ^12.20.0 || ^14.15.0 || >=16.10.0} + + '@angular/compiler@18.1.0-rc.0': + resolution: {integrity: sha512-qAmQNgrotkhhaUZ8Z+hnp+rxhw6kcNRCuu3/UNEAL6qKDxYFI8fmh5bAVkqHP5eD9zias5GSCOIm8eJi5/vZHA==} + engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0} + peerDependencies: + '@angular/core': 18.1.0-rc.0 + peerDependenciesMeta: + '@angular/core': + optional: true + + '@angular/core@12.2.16': + resolution: {integrity: sha512-jsmvaRdAfng99z2a9mAmkfcsCE1wm+tBYVDxnc5JquSXznwtncjzcoc2X0J0dzrkCDvzFfpTsZ9vehylytBc+A==} + engines: {node: ^12.14.1 || >=14.0.0} + peerDependencies: + rxjs: ^6.5.3 || ^7.0.0 + zone.js: ~0.11.4 + + '@angular/core@13.3.9': + resolution: {integrity: sha512-LaY3yBDgN/efG11x/cwVeuC4gUG3YUMmk/sgAP3L1VGawYOiKoJ76decFpy6y4UgYPShQQRzpZQEVXF405jrLg==} + engines: {node: ^12.20.0 || ^14.15.0 || >=16.10.0} + peerDependencies: + rxjs: ^6.5.3 || ^7.4.0 + zone.js: ~0.11.4 + + '@angular/core@18.1.0-rc.0': + resolution: {integrity: sha512-+DPirFXTHIuelawSFr8hPN4nF6IVcu6FvfTnxAqkdQ8eqjLdLa45n0rki1cY8OeMC7K2/7YClISDO9GRzqOcqA==} + engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0} + peerDependencies: + rxjs: ^6.5.3 || ^7.4.0 + zone.js: ~0.14.0 + + '@angular/core@18.2.10': + resolution: {integrity: sha512-EfxVz0pLaxnOppOYkdhnaUkk8HZT+uxaAGpJD3ppAa7YAWTE9xIGoNJmtS33cZNNOnvriMkdv7yn6pDtV4ct+Q==} + engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0} + + '@angular/core@20.3.0': + resolution: {integrity: sha512-4uH2TAMm1nXqQ9lcZyyNkjcdQ0Fjcf9Hh0HYrhMOEV6GAUHvM2I8Vr2dSQ40p/UKLEfe9+cpZ78EPocqPQCG6A==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@angular/compiler': 20.3.0 + rxjs: ^6.5.3 || ^7.4.0 + peerDependenciesMeta: + '@angular/compiler': + optional: true + '@angular/core@21.0.0-next.4': resolution: {integrity: sha512-z7M/YyV6GapAH/qEz5v4O/HARNXkquIs8rxg2QY1PhZXWueWel9GXmMceIANrP5zv7GZL8oU64oGTSv2icwJVQ==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@angular/compiler': 21.0.0-next.4 + peerDependenciesMeta: + '@angular/compiler': + optional: true '@angular/domino@https://codeload.github.com/angular/domino/tar.gz/93e720f143d0296dd2726ffbcf4fc12283363a7b': resolution: {tarball: https://codeload.github.com/angular/domino/tar.gz/93e720f143d0296dd2726ffbcf4fc12283363a7b} version: 2.1.6 + '@angular/language-service@20.3.0': + resolution: {integrity: sha512-QyXlT/S68HUUEMiQLFQ1bt+aClj+eQSfZZZ+syIsH8otx+YCHf2c74/LwD+sP7f3bEuWBncod1X7sbDRcZOrmA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + '@angular/material@21.0.0-next.4': resolution: {integrity: sha512-6PsUM5VAuauj/vYUkRBxCJTWPDjrf7HYhc8sWFND30CeeGRwlhd04dOxniPRcW3Z13cll9OpnmntOElp2+7Blw==} peerDependencies: '@angular/cdk': 21.0.0-next.4 + '@angular/common': ^21.0.0-0 || ^21.1.0-0 || ^21.2.0-0 || ^21.3.0-0 || ^22.0.0-0 + '@angular/core': ^21.0.0-0 || ^21.1.0-0 || ^21.2.0-0 || ^21.3.0-0 || ^22.0.0-0 + '@angular/forms': ^21.0.0-0 || ^21.1.0-0 || ^21.2.0-0 || ^21.3.0-0 || ^22.0.0-0 + '@angular/platform-browser': ^21.0.0-0 || ^21.1.0-0 || ^21.2.0-0 || ^21.3.0-0 || ^22.0.0-0 rxjs: ^6.5.3 || ^7.4.0 '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/388e486d3909cd065e26c368d4e465dfae76a156': @@ -1526,6 +1860,14 @@ packages: '@angular/ssr@21.0.0-next.4': resolution: {integrity: sha512-iEzscdEuGpQIVzgk08LHWfz739ayLqqnKimacgIX978zocEHgKmqFMfZS0ExWzw8RsiWyuhy5D6GN0cyJCws5g==} + peerDependencies: + '@angular/common': ^21.0.0-next.0 + '@angular/core': ^21.0.0-next.0 + '@angular/platform-server': ^21.0.0-next.0 + '@angular/router': ^21.0.0-next.0 + peerDependenciesMeta: + '@angular/platform-server': + optional: true '@antfu/install-pkg@1.1.0': resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} @@ -1563,6 +1905,10 @@ packages: resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==} engines: {node: '>=6.9.0'} + '@babel/core@7.24.7': + resolution: {integrity: sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==} + engines: {node: '>=6.9.0'} + '@babel/core@7.26.10': resolution: {integrity: sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==} engines: {node: '>=6.9.0'} @@ -2339,6 +2685,12 @@ packages: '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + '@esbuild/aix-ppc64@0.23.1': + resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/aix-ppc64@0.25.10': resolution: {integrity: sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==} engines: {node: '>=18'} @@ -2351,6 +2703,12 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/android-arm64@0.23.1': + resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm64@0.25.10': resolution: {integrity: sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==} engines: {node: '>=18'} @@ -2363,6 +2721,12 @@ packages: cpu: [arm64] os: [android] + '@esbuild/android-arm@0.23.1': + resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-arm@0.25.10': resolution: {integrity: sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==} engines: {node: '>=18'} @@ -2375,6 +2739,12 @@ packages: cpu: [arm] os: [android] + '@esbuild/android-x64@0.23.1': + resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/android-x64@0.25.10': resolution: {integrity: sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==} engines: {node: '>=18'} @@ -2387,6 +2757,12 @@ packages: cpu: [x64] os: [android] + '@esbuild/darwin-arm64@0.23.1': + resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-arm64@0.25.10': resolution: {integrity: sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==} engines: {node: '>=18'} @@ -2399,6 +2775,12 @@ packages: cpu: [arm64] os: [darwin] + '@esbuild/darwin-x64@0.23.1': + resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/darwin-x64@0.25.10': resolution: {integrity: sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==} engines: {node: '>=18'} @@ -2411,6 +2793,12 @@ packages: cpu: [x64] os: [darwin] + '@esbuild/freebsd-arm64@0.23.1': + resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-arm64@0.25.10': resolution: {integrity: sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==} engines: {node: '>=18'} @@ -2423,6 +2811,12 @@ packages: cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-x64@0.23.1': + resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.10': resolution: {integrity: sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==} engines: {node: '>=18'} @@ -2435,6 +2829,12 @@ packages: cpu: [x64] os: [freebsd] + '@esbuild/linux-arm64@0.23.1': + resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm64@0.25.10': resolution: {integrity: sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==} engines: {node: '>=18'} @@ -2447,6 +2847,12 @@ packages: cpu: [arm64] os: [linux] + '@esbuild/linux-arm@0.23.1': + resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-arm@0.25.10': resolution: {integrity: sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==} engines: {node: '>=18'} @@ -2459,6 +2865,12 @@ packages: cpu: [arm] os: [linux] + '@esbuild/linux-ia32@0.23.1': + resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-ia32@0.25.10': resolution: {integrity: sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==} engines: {node: '>=18'} @@ -2471,6 +2883,12 @@ packages: cpu: [ia32] os: [linux] + '@esbuild/linux-loong64@0.23.1': + resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-loong64@0.25.10': resolution: {integrity: sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==} engines: {node: '>=18'} @@ -2483,6 +2901,12 @@ packages: cpu: [loong64] os: [linux] + '@esbuild/linux-mips64el@0.23.1': + resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-mips64el@0.25.10': resolution: {integrity: sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==} engines: {node: '>=18'} @@ -2495,6 +2919,12 @@ packages: cpu: [mips64el] os: [linux] + '@esbuild/linux-ppc64@0.23.1': + resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-ppc64@0.25.10': resolution: {integrity: sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==} engines: {node: '>=18'} @@ -2507,6 +2937,12 @@ packages: cpu: [ppc64] os: [linux] + '@esbuild/linux-riscv64@0.23.1': + resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-riscv64@0.25.10': resolution: {integrity: sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==} engines: {node: '>=18'} @@ -2519,6 +2955,12 @@ packages: cpu: [riscv64] os: [linux] + '@esbuild/linux-s390x@0.23.1': + resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-s390x@0.25.10': resolution: {integrity: sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==} engines: {node: '>=18'} @@ -2531,6 +2973,12 @@ packages: cpu: [s390x] os: [linux] + '@esbuild/linux-x64@0.23.1': + resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/linux-x64@0.25.10': resolution: {integrity: sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==} engines: {node: '>=18'} @@ -2555,6 +3003,12 @@ packages: cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-x64@0.23.1': + resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.10': resolution: {integrity: sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==} engines: {node: '>=18'} @@ -2567,6 +3021,12 @@ packages: cpu: [x64] os: [netbsd] + '@esbuild/openbsd-arm64@0.23.1': + resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-arm64@0.25.10': resolution: {integrity: sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==} engines: {node: '>=18'} @@ -2579,6 +3039,12 @@ packages: cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-x64@0.23.1': + resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.10': resolution: {integrity: sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==} engines: {node: '>=18'} @@ -2603,6 +3069,12 @@ packages: cpu: [arm64] os: [openharmony] + '@esbuild/sunos-x64@0.23.1': + resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/sunos-x64@0.25.10': resolution: {integrity: sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==} engines: {node: '>=18'} @@ -2615,6 +3087,12 @@ packages: cpu: [x64] os: [sunos] + '@esbuild/win32-arm64@0.23.1': + resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-arm64@0.25.10': resolution: {integrity: sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==} engines: {node: '>=18'} @@ -2627,6 +3105,12 @@ packages: cpu: [arm64] os: [win32] + '@esbuild/win32-ia32@0.23.1': + resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-ia32@0.25.10': resolution: {integrity: sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==} engines: {node: '>=18'} @@ -2639,6 +3123,12 @@ packages: cpu: [ia32] os: [win32] + '@esbuild/win32-x64@0.23.1': + resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@esbuild/win32-x64@0.25.10': resolution: {integrity: sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==} engines: {node: '>=18'} @@ -3527,11 +4017,14 @@ packages: '@nginfra/angular-linking@1.0.10': resolution: {integrity: sha512-31zx+PCN8tBlC0FYUuCxS4uVPJLAlBhi4UVp6QgoQG44RsOHKTmcRORMVSJdPLRgRuCJkY45kj+PE3AxsgiUKA==} + peerDependencies: + '@angular/compiler-cli': '*' '@ngtools/webpack@21.0.0-next.4': resolution: {integrity: sha512-zJ5tiGS1ehw/NTgqvWGrt2Gp7I/9u12n4YGk8Hsha2/Nn3Z/JTUQ7TjL5qH/U7/+Ge6LccpDjFGI6V0q5vz8zA==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: + '@angular/compiler-cli': ^21.0.0-next.0 typescript: '>=5.9 <6.0' webpack: ^5.54.0 @@ -3558,6 +4051,10 @@ packages: resolution: {integrity: sha512-kAQTcEN9E8ERLVg5AsGwLNoFb+oEG6engbqAU2P43gD4JEIkNGMHdVQ096FsOAAYpZPB0RSt0zgInKIAS1l5QA==} engines: {node: ^20.17.0 || >=22.9.0} + '@npmcli/fs@3.1.1': + resolution: {integrity: sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + '@npmcli/fs@4.0.0': resolution: {integrity: sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q==} engines: {node: ^18.17.0 || >=20.5.0} @@ -4039,6 +4536,24 @@ packages: rollup: optional: true + '@rollup/plugin-json@6.1.0': + resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-node-resolve@15.3.1': + resolution: {integrity: sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/plugin-node-resolve@16.0.1': resolution: {integrity: sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==} engines: {node: '>=14.0.0'} @@ -4193,6 +4708,11 @@ packages: cpu: [x64] os: [win32] + '@rollup/wasm-node@4.50.1': + resolution: {integrity: sha512-3oCUcKNdkemnqy6r12UdAtfYMWywGxVHSCQvtDYeEtnOcOQC/SihSXkO6+rByH2ZhbgfeTbqLiw1NDGfJDptyg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + '@rushstack/node-core-library@5.14.0': resolution: {integrity: sha512-eRong84/rwQUlATGFW3TMTYVyqL1vfW9Lf10PH+mVGfIb9HzU3h5AASNIw+axnBLjnD0n3rT5uQBwu9fvzATrg==} peerDependencies: @@ -4298,6 +4818,10 @@ packages: resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} engines: {node: '>=10'} + '@tootallnate/once@1.1.2': + resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} + engines: {node: '>= 6'} + '@tootallnate/once@2.0.0': resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} @@ -4565,6 +5089,9 @@ packages: '@types/istanbul-reports@3.0.4': resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + '@types/jasmine@3.10.7': + resolution: {integrity: sha512-brLuHhITMz4YV2IxLstAJtyRJgtWfLqFKiqiJFvFWMSmydpAmn42CE4wfw7ywkSk02UrufhtzipTcehk8FctoQ==} + '@types/jasmine@5.1.9': resolution: {integrity: sha512-8t4HtkW4wxiPVedMpeZ63n3vlWxEIquo/zc1Tm8ElU+SqVV7+D3Na2PWaJUp179AzTragMWVwkMv7mvty0NfyQ==} @@ -4595,6 +5122,9 @@ packages: '@types/node@11.15.54': resolution: {integrity: sha512-1RWYiq+5UfozGsU6MwJyFX6BtktcT10XRjvcAQmskCtMcW3tPske88lM/nHv7BQG1w9KBXI1zPGuu5PnNCX14g==} + '@types/node@18.19.39': + resolution: {integrity: sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==} + '@types/node@20.19.17': resolution: {integrity: sha512-gfehUI8N1z92kygssiuWvLiwcbOB3IRktR6hTDgJlXMYh5OvkPSRmgfoBUmfZt+vhwJtX7v1Yw4KvvAf7c5QKQ==} @@ -4695,6 +5225,9 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/vscode@1.67.0': + resolution: {integrity: sha512-GH8BDf8cw9AC9080uneJfulhSa7KHSMI2s/CyKePXoGNos9J486w2V4YKoeNUqIEkW4hKoEAWp6/cXTwyGj47g==} + '@types/which@1.3.2': resolution: {integrity: sha512-8oDqyLC7eD4HM307boe2QWKyuzdzWBj56xI/imSl2cpL+U3tCMaTAkMJ4ee5JBZ/FsOJlvRGeIShiZDAl1qERA==} @@ -5065,6 +5598,8 @@ packages: angular-split@20.0.0: resolution: {integrity: sha512-MtoR8NeFgzBDqiXaSbXPGFqpYsNsaI5W8w2mM/JpYyyU9hkrQ8b3GVhxraR/kGFGEDVmfEUGaqmy2yG0hraOHQ==} peerDependencies: + '@angular/common': '>=19.0.0' + '@angular/core': '>=19.0.0' rxjs: '>=7.0.0' angular@1.5.11: @@ -5307,6 +5842,9 @@ packages: aws4@1.13.2: resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} + azure-devops-node-api@11.2.0: + resolution: {integrity: sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==} + b4a@1.7.1: resolution: {integrity: sha512-ZovbrBV0g6JxK5cGUF1Suby1vLfKjv4RWi8IxoaO/Mon8BDD9I21RxjHFtgQ+kskJqLAVyQZly3uMBui+vhc8Q==} peerDependencies: @@ -5443,6 +5981,10 @@ packages: bidi-js@1.0.3: resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + big-integer@1.6.52: + resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} + engines: {node: '>=0.6'} + big.js@5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} @@ -5456,6 +5998,9 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + binary@0.3.0: + resolution: {integrity: sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==} + bl@1.2.3: resolution: {integrity: sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==} @@ -5473,6 +6018,9 @@ packages: engines: {node: '>=6.9.x'} hasBin: true + bluebird@3.4.7: + resolution: {integrity: sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==} + bluebird@3.7.2: resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} @@ -5544,12 +6092,20 @@ packages: buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + buffer-indexof-polyfill@1.0.2: + resolution: {integrity: sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==} + engines: {node: '>=0.10'} + buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + buffers@0.1.1: + resolution: {integrity: sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==} + engines: {node: '>=0.2.0'} + bufferutil@4.0.9: resolution: {integrity: sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==} engines: {node: '>=6.14.2'} @@ -5574,6 +6130,10 @@ packages: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + cacache@18.0.4: + resolution: {integrity: sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==} + engines: {node: ^16.14.0 || >=18.0.0} + cacache@19.0.1: resolution: {integrity: sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==} engines: {node: ^18.17.0 || >=20.5.0} @@ -5631,6 +6191,9 @@ packages: caniuse-lite@1.0.30001743: resolution: {integrity: sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==} + canonical-path@1.0.0: + resolution: {integrity: sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg==} + capital-case@1.0.4: resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==} @@ -5647,6 +6210,9 @@ packages: chainsaw@0.0.9: resolution: {integrity: sha512-nG8PYH+/4xB+8zkV4G844EtfvZ5tTiLFoX3dZ4nhF4t3OCKIb9UvaFyNmeZO2zOSmRWzBoTD+napN6hiL+EgcA==} + chainsaw@0.1.0: + resolution: {integrity: sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==} + chalk@1.1.3: resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==} engines: {node: '>=0.10.0'} @@ -5694,6 +6260,13 @@ packages: checkpoint-stream@0.1.2: resolution: {integrity: sha512-eYXIcydL3mPjjEVLxHdi1ISgTwmxGJZ8vyJ3lYVvFTDRyTOZMTbKZdRJqiA7Gi1rPcwOyyzcrZmGLL8ff7e69w==} + cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + + cheerio@1.1.2: + resolution: {integrity: sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg==} + engines: {node: '>=20.18.1'} + chevrotain-allstar@0.3.1: resolution: {integrity: sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==} peerDependencies: @@ -5886,6 +6459,10 @@ packages: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -6162,6 +6739,9 @@ packages: webpack: optional: true + css-select@5.2.2: + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + css-select@6.0.0: resolution: {integrity: sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==} @@ -6175,6 +6755,10 @@ packages: css-value@0.0.1: resolution: {integrity: sha512-FUV3xaJ63buRLgHrLQVlVgQnQdR4yqdLGaDu7g8CQcWjInDfM9plBTPI9FRfpahju1UBSaMckeb2/46ApS/V1Q==} + css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} + css-what@7.0.0: resolution: {integrity: sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==} engines: {node: '>= 6'} @@ -6540,6 +7124,9 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + denodeify@1.2.1: + resolution: {integrity: sha512-KNTihKNmQENUZeKu5fzfpzRqR5S2VMp4gl9RFHiWzj9DfvYQPMJ6XHKNaQxaGCXwPk6y9yme3aUoaiAe+KX+vg==} + depd@1.1.2: resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} engines: {node: '>= 0.6'} @@ -6548,6 +7135,14 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} + dependency-graph@0.11.0: + resolution: {integrity: sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==} + engines: {node: '>= 0.6.0'} + + dependency-graph@1.0.0: + resolution: {integrity: sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg==} + engines: {node: '>=4'} + deprecation@2.3.1: resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} @@ -6654,6 +7249,9 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} + duplexer2@0.1.4: + resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} + duplexify@3.7.1: resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==} @@ -6722,6 +7320,9 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} + encoding-sniffer@0.2.1: + resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} + encoding@0.1.13: resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} @@ -6748,6 +7349,9 @@ packages: resolution: {integrity: sha512-kKvD1tO6BM+oK9HzCPpUdRb4vKFQY/FPTFmurMvh6LlN68VMrdj77w8yp51/kDbpkFOS9J8w5W6zIzgM2H8/hw==} engines: {node: '>= 0.4'} + entities@2.0.3: + resolution: {integrity: sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==} + entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} @@ -6809,14 +7413,144 @@ packages: engines: {node: '>=0.8.0'} deprecated: This project has been deprecated for "npm install es-module-loader" based on the newer loader spec. + esbuild-android-64@0.14.39: + resolution: {integrity: sha512-EJOu04p9WgZk0UoKTqLId9VnIsotmI/Z98EXrKURGb3LPNunkeffqQIkjS2cAvidh+OK5uVrXaIP229zK6GvhQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + esbuild-android-arm64@0.14.39: + resolution: {integrity: sha512-+twajJqO7n3MrCz9e+2lVOnFplRsaGRwsq1KL/uOy7xK7QdRSprRQcObGDeDZUZsacD5gUkk6OiHiYp6RzU3CA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + esbuild-darwin-64@0.14.39: + resolution: {integrity: sha512-ImT6eUw3kcGcHoUxEcdBpi6LfTRWaV6+qf32iYYAfwOeV+XaQ/Xp5XQIBiijLeo+LpGci9M0FVec09nUw41a5g==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + esbuild-darwin-arm64@0.14.39: + resolution: {integrity: sha512-/fcQ5UhE05OiT+bW5v7/up1bDsnvaRZPJxXwzXsMRrr7rZqPa85vayrD723oWMT64dhrgWeA3FIneF8yER0XTw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + esbuild-freebsd-64@0.14.39: + resolution: {integrity: sha512-oMNH8lJI4wtgN5oxuFP7BQ22vgB/e3Tl5Woehcd6i2r6F3TszpCnNl8wo2d/KvyQ4zvLvCWAlRciumhQg88+kQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + esbuild-freebsd-arm64@0.14.39: + resolution: {integrity: sha512-1GHK7kwk57ukY2yI4ILWKJXaxfr+8HcM/r/JKCGCPziIVlL+Wi7RbJ2OzMcTKZ1HpvEqCTBT/J6cO4ZEwW4Ypg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + esbuild-linux-32@0.14.39: + resolution: {integrity: sha512-g97Sbb6g4zfRLIxHgW2pc393DjnkTRMeq3N1rmjDUABxpx8SjocK4jLen+/mq55G46eE2TA0MkJ4R3SpKMu7dg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + esbuild-linux-64@0.14.39: + resolution: {integrity: sha512-4tcgFDYWdI+UbNMGlua9u1Zhu0N5R6u9tl5WOM8aVnNX143JZoBZLpCuUr5lCKhnD0SCO+5gUyMfupGrHtfggQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + esbuild-linux-arm64@0.14.39: + resolution: {integrity: sha512-23pc8MlD2D6Px1mV8GMglZlKgwgNKAO8gsgsLLcXWSs9lQsCYkIlMo/2Ycfo5JrDIbLdwgP8D2vpfH2KcBqrDQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + esbuild-linux-arm@0.14.39: + resolution: {integrity: sha512-t0Hn1kWVx5UpCzAJkKRfHeYOLyFnXwYynIkK54/h3tbMweGI7dj400D1k0Vvtj2u1P+JTRT9tx3AjtLEMmfVBQ==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + esbuild-linux-mips64le@0.14.39: + resolution: {integrity: sha512-epwlYgVdbmkuRr5n4es3B+yDI0I2e/nxhKejT9H0OLxFAlMkeQZxSpxATpDc9m8NqRci6Kwyb/SfmD1koG2Zuw==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + esbuild-linux-ppc64le@0.14.39: + resolution: {integrity: sha512-W/5ezaq+rQiQBThIjLMNjsuhPHg+ApVAdTz2LvcuesZFMsJoQAW2hutoyg47XxpWi7aEjJGrkS26qCJKhRn3QQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + esbuild-linux-riscv64@0.14.39: + resolution: {integrity: sha512-IS48xeokcCTKeQIOke2O0t9t14HPvwnZcy+5baG13Z1wxs9ZrC5ig5ypEQQh4QMKxURD5TpCLHw2W42CLuVZaA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + esbuild-linux-s390x@0.14.39: + resolution: {integrity: sha512-zEfunpqR8sMomqXhNTFEKDs+ik7HC01m3M60MsEjZOqaywHu5e5682fMsqOlZbesEAAaO9aAtRBsU7CHnSZWyA==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + esbuild-netbsd-64@0.14.39: + resolution: {integrity: sha512-Uo2suJBSIlrZCe4E0k75VDIFJWfZy+bOV6ih3T4MVMRJh1lHJ2UyGoaX4bOxomYN3t+IakHPyEoln1+qJ1qYaA==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + esbuild-openbsd-64@0.14.39: + resolution: {integrity: sha512-secQU+EpgUPpYjJe3OecoeGKVvRMLeKUxSMGHnK+aK5uQM3n1FPXNJzyz1LHFOo0WOyw+uoCxBYdM4O10oaCAA==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + esbuild-plugin-umd-wrapper@3.0.0: resolution: {integrity: sha512-Ht3jrO7r8oF8FgPIhMnfNQvYLHhz2QA1ggPqfBhoVq0VfYNczqJ6nwQ4PhO5UvrUymn+Q0Nc50xpiDbxI+KR2Q==} + esbuild-sunos-64@0.14.39: + resolution: {integrity: sha512-qHq0t5gePEDm2nqZLb+35p/qkaXVS7oIe32R0ECh2HOdiXXkj/1uQI9IRogGqKkK+QjDG+DhwiUw7QoHur/Rwg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + esbuild-wasm@0.25.9: resolution: {integrity: sha512-Jpv5tCSwQg18aCqCRD3oHIX/prBhXMDapIoG//A+6+dV0e7KQMGFg85ihJ5T1EeMjbZjON3TqFy0VrGAnIHLDA==} engines: {node: '>=18'} hasBin: true + esbuild-windows-32@0.14.39: + resolution: {integrity: sha512-XPjwp2OgtEX0JnOlTgT6E5txbRp6Uw54Isorm3CwOtloJazeIWXuiwK0ONJBVb/CGbiCpS7iP2UahGgd2p1x+Q==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + esbuild-windows-64@0.14.39: + resolution: {integrity: sha512-E2wm+5FwCcLpKsBHRw28bSYQw0Ikxb7zIMxw3OPAkiaQhLVr3dnVO8DofmbWhhf6b97bWzg37iSZ45ZDpLw7Ow==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + esbuild-windows-arm64@0.14.39: + resolution: {integrity: sha512-sBZQz5D+Gd0EQ09tZRnz/PpVdLwvp/ufMtJ1iDFYddDaPpZXKqPyaxfYBLs3ueiaksQ26GGa7sci0OqFzNs7KA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + esbuild@0.14.39: + resolution: {integrity: sha512-2kKujuzvRWYtwvNjYDY444LQIA3TyJhJIX3Yo4+qkFlDDtGlSicWgeHVJqMUP/2sSfH10PGwfsj+O2ro1m10xQ==} + engines: {node: '>=12'} + hasBin: true + + esbuild@0.23.1: + resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} + engines: {node: '>=18'} + hasBin: true + esbuild@0.25.10: resolution: {integrity: sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==} engines: {node: '>=18'} @@ -7102,6 +7836,10 @@ packages: resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} engines: {node: '>= 0.8'} + find-cache-dir@3.3.2: + resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} + engines: {node: '>=8'} + find-up-simple@1.0.1: resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} engines: {node: '>=18'} @@ -7253,6 +7991,11 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + fstream@1.0.12: + resolution: {integrity: sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==} + engines: {node: '>=0.6'} + deprecated: This package is no longer supported. + function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} @@ -7610,6 +8353,10 @@ packages: resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} engines: {node: '>=0.10.0'} + hosted-git-info@4.1.0: + resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} + engines: {node: '>=10'} + hosted-git-info@7.0.2: resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} engines: {node: ^16.14.0 || >=18.0.0} @@ -7662,6 +8409,10 @@ packages: http-parser-js@0.5.10: resolution: {integrity: sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==} + http-proxy-agent@4.0.1: + resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==} + engines: {node: '>= 6'} + http-proxy-agent@5.0.0: resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} engines: {node: '>= 6'} @@ -7822,6 +8573,9 @@ packages: resolution: {integrity: sha512-+N0ngpO3e7cRUWOJAS7qw0IZIVc6XPrW4MlFBdD066F2L4k1L6ker3hLqSq7iXxU5tgS4WGkIUElWn5vogAEnw==} engines: {node: ^18.17.0 || >=20.5.0} + injection-js@2.5.0: + resolution: {integrity: sha512-UpY2ONt4xbht4GhSqQ2zMJ1rBIQq4uOY+DlR6aOeYyqK7xadXt7UQbJIyxmgk288bPMkIZKjViieHm0O0i72Jw==} + install-artifact-from-github@1.4.0: resolution: {integrity: sha512-+y6WywKZREw5rq7U2jvr2nmZpT7cbWbQQ0N/qfcseYnzHFz2cZz1Et52oY+XttYuYeTkI8Y+R2JNWj68MpQFSg==} hasBin: true @@ -8675,6 +9429,12 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + linkify-it@2.2.0: + resolution: {integrity: sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==} + + listenercount@1.0.1: + resolution: {integrity: sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==} + listr2@3.14.0: resolution: {integrity: sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==} engines: {node: '>=10.0.0'} @@ -8860,6 +9620,10 @@ packages: magic-string@0.25.9: resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} + magic-string@0.26.7: + resolution: {integrity: sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==} + engines: {node: '>=12'} + magic-string@0.30.19: resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} @@ -8893,6 +9657,10 @@ packages: resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} engines: {node: '>=0.10.0'} + markdown-it@10.0.0: + resolution: {integrity: sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==} + hasBin: true + marked-terminal@7.3.0: resolution: {integrity: sha512-t4rBvPsHc57uE/2nJOLmMbZCQ4tgAccAED3ngXQqW6g+TxA488JzJ+FK3lQkzBQOI1mRV/r/Kq+1ZlJ4D0owQw==} engines: {node: '>=16.0.0'} @@ -8926,6 +9694,9 @@ packages: mdn-data@2.12.2: resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} + mdurl@1.0.1: + resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==} + media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} @@ -9173,6 +9944,9 @@ packages: resolution: {integrity: sha512-32GSKM3Wyc8dg/p39lWPKYu8zci9mJFzV1Np9Of0ZEpe6Fhssn/FbI7ywAMd40uX+p3ZKh3T5EeCFv81qS3HmQ==} engines: {node: '>= 10.13.0'} + mute-stream@0.0.8: + resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + mute-stream@2.0.0: resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} engines: {node: ^18.17.0 || >=20.5.0} @@ -9224,13 +9998,31 @@ packages: resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} engines: {node: '>= 0.4.0'} + ng-packagr@18.2.1: + resolution: {integrity: sha512-dy9ZDpZb3QpAz+Y/m8VAu7ctr2VrnRU3gmQwJagnNybVJtCsKn3lZA3IW7Z7GTLoG5IALSPouiCgiB/C8ozv7w==} + engines: {node: ^18.19.1 || >=20.11.1} + hasBin: true + peerDependencies: + '@angular/compiler-cli': ^18.0.0 || ^18.2.0-next.0 + tailwindcss: ^2.0.0 || ^3.0.0 + tslib: ^2.3.0 + typescript: '>=5.4 <5.6' + peerDependenciesMeta: + tailwindcss: + optional: true + ngx-flamegraph@0.1.1: resolution: {integrity: sha512-BTyyOnPDXW0Xi5iOd+H03atdiCNdnYNzpkNJ4iqTrkYGJnOnzaMEzdlaN9Jt3Qpjcs3oyvUoJvD85xZnZpzTyQ==} + peerDependencies: + '@angular/common': ^20.0.0 + '@angular/core': ^20.0.0 ngx-progressbar@14.0.0: resolution: {integrity: sha512-tDj7h5F2aSI4/XaJjs50FnELVe6qFqyz3vVq22acacd3oDW2EyJB4c+IYaxMf5972OdTw0WL4n6UwQ3dqC+gCA==} peerDependencies: '@angular/cdk': '>=17.3.0' + '@angular/common': '>=17.3.0' + '@angular/core': '>=17.3.0' rxjs: '>=7.0.0' no-case@3.0.4: @@ -9465,10 +10257,18 @@ packages: ordered-binary@1.6.0: resolution: {integrity: sha512-IQh2aMfMIDbPjI/8a3Edr+PiOpcsB7yo8NdW7aHWVaoR/pcDldunMvnnwbk/auPGqmKeAdxtZl7MHX/QmPwhvQ==} + os-homedir@1.0.2: + resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==} + engines: {node: '>=0.10.0'} + os-tmpdir@1.0.2: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} + osenv@0.1.5: + resolution: {integrity: sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==} + deprecated: This package is no longer supported. + ospath@1.2.2: resolution: {integrity: sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==} @@ -9584,12 +10384,21 @@ packages: resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} engines: {node: '>=0.10.0'} + parse-semver@1.1.1: + resolution: {integrity: sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==} + parse5-html-rewriting-stream@8.0.0: resolution: {integrity: sha512-wzh11mj8KKkno1pZEu+l2EVeWsuKDfR5KNWZOTsslfUX8lPDZx77m9T0kIoAVkFtD1nx6YF8oh4BnPHvxMtNMw==} parse5-htmlparser2-tree-adapter@6.0.1: resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} + parse5-htmlparser2-tree-adapter@7.1.0: + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} + + parse5-parser-stream@7.1.2: + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} + parse5-sax-parser@8.0.0: resolution: {integrity: sha512-/dQ8UzHZwnrzs3EvDj6IkKrD/jIZyTlB+8XrHJvcjNgRdmWruNdN9i9RK/JtxakmlUdPwKubKPTCqvbTgzGhrw==} @@ -9750,6 +10559,9 @@ packages: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} + piscina@4.9.2: + resolution: {integrity: sha512-Fq0FERJWFEUpB4eSY59wSNwXD4RYqR+nR/WiEVcZW8IWfVBxJJafcgTEZDQo8k3w0sUarJ8RyVbbUF4GQ2LGbQ==} + piscina@5.1.3: resolution: {integrity: sha512-0u3N7H4+hbr40KjuVn2uNhOcthu/9usKhnw5vT3J7ply79v3D3M8naI00el9Klcy16x557VsEkkUQaHCWFXC/g==} engines: {node: '>=20.x'} @@ -9905,6 +10717,11 @@ packages: preact@10.27.2: resolution: {integrity: sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg==} + prettier@2.7.1: + resolution: {integrity: sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==} + engines: {node: '>=10.13.0'} + hasBin: true + prettier@3.6.2: resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} engines: {node: '>=14'} @@ -10029,7 +10846,6 @@ packages: engines: {node: '>=0.6.0', teleport: '>=0.2.0'} deprecated: |- You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other. - (For a CapTP with native promises, see @endo/eventual-send and @endo/captp) qjobs@1.2.0: @@ -10105,6 +10921,10 @@ packages: resolution: {integrity: sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==} engines: {node: '>=18'} + read@1.0.7: + resolution: {integrity: sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==} + engines: {node: '>=0.8'} + readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} @@ -10131,6 +10951,9 @@ packages: resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==} engines: {node: '>= 10.13.0'} + reflect-metadata@0.1.14: + resolution: {integrity: sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==} + reflect-metadata@0.2.2: resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} @@ -10383,6 +11206,10 @@ packages: rw@1.3.3: resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + rxjs@6.6.7: + resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} + engines: {npm: '>=2.0.0'} + rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} @@ -11392,6 +12219,9 @@ packages: typed-query-selector@2.12.0: resolution: {integrity: sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==} + typed-rest-client@1.8.11: + resolution: {integrity: sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==} + typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} @@ -11407,6 +12237,11 @@ packages: engines: {node: '>=4.2.0'} hasBin: true + typescript@5.5.4: + resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} + engines: {node: '>=14.17'} + hasBin: true + typescript@5.8.2: resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==} engines: {node: '>=14.17'} @@ -11426,6 +12261,9 @@ packages: resolution: {integrity: sha512-O3oYyCMPYgNNHuO7Jjk3uacJWZF8loBgwrfd/5LE/HyZ3lUIOdniQ7DNXJcIgZbwioZxk0fLfI4EVnetdiX5jg==} hasBin: true + uc.micro@1.0.6: + resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==} + ufo@1.6.1: resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} @@ -11445,6 +12283,9 @@ packages: resolution: {integrity: sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==} engines: {node: '>=0.10.0'} + underscore@1.13.7: + resolution: {integrity: sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==} + undertaker-registry@2.0.0: resolution: {integrity: sha512-+hhVICbnp+rlzZMgxXenpvTxpuvA67Bfgtt+O9WOE5jo7w/dyiF1VmoZVIHvP2EkUjsyKyTwYKlLhA+j47m1Ew==} engines: {node: '>= 10.13.0'} @@ -11453,6 +12294,9 @@ packages: resolution: {integrity: sha512-tO/bf30wBbTsJ7go80j0RzA2rcwX6o7XPBpeFcb+jzoeb4pfMM2zUeSDIkY1AWqeZabWxaQZ/h8N9t35QKDLPQ==} engines: {node: '>=10.13.0'} + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} @@ -11498,10 +12342,18 @@ packages: resolution: {integrity: sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==} engines: {node: '>= 0.8.0'} + unique-filename@3.0.0: + resolution: {integrity: sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + unique-filename@4.0.0: resolution: {integrity: sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==} engines: {node: ^18.17.0 || >=20.5.0} + unique-slug@4.0.0: + resolution: {integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + unique-slug@5.0.0: resolution: {integrity: sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==} engines: {node: ^18.17.0 || >=20.5.0} @@ -11557,6 +12409,9 @@ packages: resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} engines: {node: '>=8'} + unzipper@0.10.14: + resolution: {integrity: sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==} + update-browserslist-db@1.1.3: resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} hasBin: true @@ -11579,6 +12434,9 @@ packages: url-join@0.0.1: resolution: {integrity: sha512-H6dnQ/yPAAVzMQRvEvyz01hhfQL5qRWSEt7BX8t9DqnPw9BjMb64fjIRq76Uvf1hkHp+mTZvEVJ5guXOT0Xqaw==} + url-join@1.1.0: + resolution: {integrity: sha512-zz1wZk4Lb5PTVwZ3HWDmm8XnlPvmOof6/fjdDPA5yBrUcbtV64U6bV832Zf1BtU2WkBBWaUT46wCs+l0HP5nhg==} + url-join@4.0.1: resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} @@ -11791,23 +12649,71 @@ packages: tslint: '*' typescript: '*' + vsce@1.100.1: + resolution: {integrity: sha512-1VjLyse5g6e2eQ6jUpslu7IDq44velwF8Jy8s7ePdwGNuG8EzfmaOfVyig3ZSMJ0l8DiJmZllx5bRAB4RMdnHg==} + engines: {node: '>= 10'} + deprecated: vsce has been renamed to @vscode/vsce. Install using @vscode/vsce instead. + hasBin: true + + vscode-html-languageservice@4.2.5: + resolution: {integrity: sha512-dbr10KHabB9EaK8lI0XZW7SqOsTfrNyT3Nuj0GoPi4LjGKUmMiLtsqzfedIzRTzqY+w0FiLdh0/kQrnQ0tLxrw==} + + vscode-jsonrpc@6.0.0: + resolution: {integrity: sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg==} + engines: {node: '>=8.0.0 || >=10.0.0'} + vscode-jsonrpc@8.2.0: resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} engines: {node: '>=14.0.0'} + vscode-languageclient@7.0.0: + resolution: {integrity: sha512-P9AXdAPlsCgslpP9pRxYPqkNYV7Xq8300/aZDpO35j1fJm/ncize8iGswzYlcvFw5DQUx4eVk+KvfXdL0rehNg==} + engines: {vscode: ^1.52.0} + + vscode-languageserver-protocol@3.16.0: + resolution: {integrity: sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A==} + vscode-languageserver-protocol@3.17.5: resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} vscode-languageserver-textdocument@1.0.12: resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + vscode-languageserver-types@3.16.0: + resolution: {integrity: sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA==} + vscode-languageserver-types@3.17.5: resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + vscode-languageserver@7.0.0: + resolution: {integrity: sha512-60HTx5ID+fLRcgdHfmz0LDZAXYEV68fzwG0JWwEPBode9NuMYTIxuYXPg4ngO8i8+Ou0lM7y6GzaYWbiDL0drw==} + hasBin: true + vscode-languageserver@9.0.1: resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} hasBin: true + vscode-nls@5.2.0: + resolution: {integrity: sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==} + + vscode-oniguruma@1.7.0: + resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==} + + vscode-test@1.6.1: + resolution: {integrity: sha512-086q88T2ca1k95mUzffvbzb7esqQNvJgiwY4h29ukPhFo8u+vXOOmelUoU5EQUHs3Of8+JuQ3oGdbVCqaxuTXA==} + engines: {node: '>=8.9.3'} + deprecated: This package has been renamed to @vscode/test-electron, please update to the new name + + vscode-textmate@5.5.0: + resolution: {integrity: sha512-jToQkPGMNKn0eyKyitYeINJF0NoD240aYyKPIWJv5W2jfPt++jIRg0OSergubtGhbw6SoefkvBYEpX7TsfoSUQ==} + + vscode-tmgrammar-test@0.0.11: + resolution: {integrity: sha512-Bd60x/OeBLAQnIxiR2GhUic1CQZOFfWM8Pd43HjdEUBf/0vcvYAlFQikOXvv+zkItHLznjKaDX7VWKPVYUF9ug==} + hasBin: true + + vscode-uri@3.0.7: + resolution: {integrity: sha512-eOpPHogvorZRobNqJGhapa0JdwaxpjVvyBp0QIUMRMSf8ZAlqOdEquKuRmw9Qwu0qXtJIWqFtMkmvJjUZmMjVA==} + vscode-uri@3.0.8: resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} @@ -12230,6 +13136,12 @@ packages: zod@4.1.11: resolution: {integrity: sha512-WPsqwxITS2tzx1bzhIKsEs19ABD5vmCVa4xBo2tq/SrV4RNZtfws1EnCWQXM6yh8bD08a1idvkB5MZSBiZsjwg==} + zone.js@0.11.5: + resolution: {integrity: sha512-D1/7VxEuQ7xk6z/kAROe4SUbd9CzxY4zOwVGnGHerd/SgLIVU5f4esDzQUsOCeArn933BZfWMKydH7l7dPEp0g==} + + zone.js@0.14.10: + resolution: {integrity: sha512-YGAhaO7J5ywOXW6InXNlLmfU194F8lVgu7bRntUF3TiG8Y3nBK0x1UJJuHUP/e8IyihkjCYqhCScpSwnlaSRkQ==} + zone.js@0.15.1: resolution: {integrity: sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==} @@ -12372,19 +13284,14 @@ snapshots: transitivePeerDependencies: - chokidar - '@angular-devkit/build-angular@21.0.0-next.4(@angular/ssr@21.0.0-next.4)(@types/node@20.19.17)(bufferutil@4.0.9)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9))(protractor@7.0.0)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2)))(tsx@4.20.5)(typescript@5.9.2)(vitest@3.2.4(@types/node@20.19.17)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1)': + '@angular-devkit/build-angular@21.0.0-next.4(@angular/compiler-cli@packages+compiler-cli)(@angular/compiler@packages+compiler)(@angular/core@packages+core)(@angular/localize@packages+localize)(@angular/platform-browser@packages+platform-browser)(@angular/platform-server@packages+platform-server)(@angular/service-worker@packages+service-worker)(@angular/ssr@21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(@angular/platform-server@packages+platform-server)(@angular/router@packages+router))(@types/node@20.19.17)(bufferutil@4.0.9)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9))(protractor@7.0.0)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2)))(tsx@4.20.5)(typescript@5.9.2)(vitest@3.2.4(@types/node@20.19.17)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2100.0-next.4(chokidar@4.0.3) '@angular-devkit/build-webpack': 0.2100.0-next.4(chokidar@4.0.3)(webpack-dev-server@5.2.2(bufferutil@4.0.9)(webpack@5.101.3(esbuild@0.25.9)))(webpack@5.101.3(esbuild@0.25.9)) '@angular-devkit/core': 21.0.0-next.4(chokidar@4.0.3) - '@angular/build': 21.0.0-next.4(@angular/ssr@21.0.0-next.4)(@types/node@20.19.17)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9))(less@4.4.1)(postcss@8.5.6)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2)))(terser@5.44.0)(tslib@2.8.1)(tsx@4.20.5)(typescript@5.9.2)(vitest@3.2.4(@types/node@20.19.17)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1) + '@angular/build': 21.0.0-next.4(@angular/compiler-cli@packages+compiler-cli)(@angular/compiler@packages+compiler)(@angular/core@packages+core)(@angular/localize@packages+localize)(@angular/platform-browser@packages+platform-browser)(@angular/platform-server@packages+platform-server)(@angular/service-worker@packages+service-worker)(@angular/ssr@21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(@angular/platform-server@packages+platform-server)(@angular/router@packages+router))(@types/node@20.19.17)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9))(less@4.4.1)(postcss@8.5.6)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2)))(terser@5.44.0)(tslib@2.8.1)(tsx@4.20.5)(typescript@5.9.2)(vitest@3.2.4(@types/node@20.19.17)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1) '@angular/compiler-cli': link:packages/compiler-cli - '@angular/core': link:packages/core - '@angular/localize': link:packages/localize - '@angular/platform-browser': link:packages/platform-browser - '@angular/platform-server': link:packages/platform-server - '@angular/service-worker': link:packages/service-worker '@babel/core': 7.28.4 '@babel/generator': 7.28.3 '@babel/helper-annotate-as-pure': 7.27.3 @@ -12395,7 +13302,7 @@ snapshots: '@babel/preset-env': 7.28.3(@babel/core@7.28.4) '@babel/runtime': 7.28.4 '@discoveryjs/json-ext': 0.6.3 - '@ngtools/webpack': 21.0.0-next.4(typescript@5.9.2)(webpack@5.101.3(esbuild@0.25.9)) + '@ngtools/webpack': 21.0.0-next.4(@angular/compiler-cli@packages+compiler-cli)(typescript@5.9.2)(webpack@5.101.3(esbuild@0.25.9)) ansi-colors: 4.1.3 autoprefixer: 10.4.21(postcss@8.5.6) babel-loader: 10.0.0(@babel/core@7.28.4)(webpack@5.101.3(esbuild@0.25.9)) @@ -12436,12 +13343,18 @@ snapshots: webpack-merge: 6.0.1 webpack-subresource-integrity: 5.1.0(webpack@5.101.3(esbuild@0.25.9)) optionalDependencies: - '@angular/ssr': 21.0.0-next.4 + '@angular/core': link:packages/core + '@angular/localize': link:packages/localize + '@angular/platform-browser': link:packages/platform-browser + '@angular/platform-server': link:packages/platform-server + '@angular/service-worker': link:packages/service-worker + '@angular/ssr': 21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(@angular/platform-server@packages+platform-server)(@angular/router@packages+router) esbuild: 0.25.9 karma: 6.4.4(bufferutil@4.0.9)(utf-8-validate@6.0.5) protractor: 7.0.0 tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2)) transitivePeerDependencies: + - '@angular/compiler' - '@rspack/core' - '@swc/core' - '@types/node' @@ -12463,19 +13376,14 @@ snapshots: - webpack-cli - yaml - '@angular-devkit/build-angular@21.0.0-next.4(@angular/ssr@21.0.0-next.4)(@types/node@24.5.2)(bufferutil@4.0.9)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9)(utf-8-validate@6.0.5))(protractor@7.0.0)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2)))(tsx@4.20.5)(typescript@5.9.2)(utf-8-validate@6.0.5)(vitest@3.2.4(@types/node@24.5.2)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6)(utf-8-validate@6.0.5))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1)': + '@angular-devkit/build-angular@21.0.0-next.4(@angular/compiler-cli@packages+compiler-cli)(@angular/compiler@packages+compiler)(@angular/core@packages+core)(@angular/localize@packages+localize)(@angular/platform-browser@packages+platform-browser)(@angular/platform-server@packages+platform-server)(@angular/service-worker@packages+service-worker)(@angular/ssr@21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(@angular/platform-server@packages+platform-server)(@angular/router@packages+router))(@types/node@24.5.2)(bufferutil@4.0.9)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9)(utf-8-validate@6.0.5))(protractor@7.0.0)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2)))(tsx@4.20.5)(typescript@5.9.2)(utf-8-validate@6.0.5)(vitest@3.2.4(@types/node@24.5.2)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6)(utf-8-validate@6.0.5))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2100.0-next.4(chokidar@4.0.3) '@angular-devkit/build-webpack': 0.2100.0-next.4(chokidar@4.0.3)(webpack-dev-server@5.2.2(bufferutil@4.0.9)(webpack@5.101.3(esbuild@0.25.9)))(webpack@5.101.3(esbuild@0.25.9)) '@angular-devkit/core': 21.0.0-next.4(chokidar@4.0.3) - '@angular/build': 21.0.0-next.4(@angular/ssr@21.0.0-next.4)(@types/node@24.5.2)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.4.1)(postcss@8.5.6)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2)))(terser@5.44.0)(tslib@2.8.1)(tsx@4.20.5)(typescript@5.9.2)(vitest@3.2.4(@types/node@24.5.2)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6)(utf-8-validate@6.0.5))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1) + '@angular/build': 21.0.0-next.4(@angular/compiler-cli@packages+compiler-cli)(@angular/compiler@packages+compiler)(@angular/core@packages+core)(@angular/localize@packages+localize)(@angular/platform-browser@packages+platform-browser)(@angular/platform-server@packages+platform-server)(@angular/service-worker@packages+service-worker)(@angular/ssr@21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(@angular/platform-server@packages+platform-server)(@angular/router@packages+router))(@types/node@24.5.2)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.4.1)(postcss@8.5.6)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2)))(terser@5.44.0)(tslib@2.8.1)(tsx@4.20.5)(typescript@5.9.2)(vitest@3.2.4(@types/node@24.5.2)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6)(utf-8-validate@6.0.5))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1) '@angular/compiler-cli': link:packages/compiler-cli - '@angular/core': link:packages/core - '@angular/localize': link:packages/localize - '@angular/platform-browser': link:packages/platform-browser - '@angular/platform-server': link:packages/platform-server - '@angular/service-worker': link:packages/service-worker '@babel/core': 7.28.4 '@babel/generator': 7.28.3 '@babel/helper-annotate-as-pure': 7.27.3 @@ -12486,7 +13394,7 @@ snapshots: '@babel/preset-env': 7.28.3(@babel/core@7.28.4) '@babel/runtime': 7.28.4 '@discoveryjs/json-ext': 0.6.3 - '@ngtools/webpack': 21.0.0-next.4(typescript@5.9.2)(webpack@5.101.3(esbuild@0.25.9)) + '@ngtools/webpack': 21.0.0-next.4(@angular/compiler-cli@packages+compiler-cli)(typescript@5.9.2)(webpack@5.101.3(esbuild@0.25.9)) ansi-colors: 4.1.3 autoprefixer: 10.4.21(postcss@8.5.6) babel-loader: 10.0.0(@babel/core@7.28.4)(webpack@5.101.3(esbuild@0.25.9)) @@ -12527,12 +13435,18 @@ snapshots: webpack-merge: 6.0.1 webpack-subresource-integrity: 5.1.0(webpack@5.101.3(esbuild@0.25.9)) optionalDependencies: - '@angular/ssr': 21.0.0-next.4 + '@angular/core': link:packages/core + '@angular/localize': link:packages/localize + '@angular/platform-browser': link:packages/platform-browser + '@angular/platform-server': link:packages/platform-server + '@angular/service-worker': link:packages/service-worker + '@angular/ssr': 21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(@angular/platform-server@packages+platform-server)(@angular/router@packages+router) esbuild: 0.25.9 karma: 6.4.4(bufferutil@4.0.9)(utf-8-validate@6.0.5) protractor: 7.0.0 tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2)) transitivePeerDependencies: + - '@angular/compiler' - '@rspack/core' - '@swc/core' - '@types/node' @@ -12591,17 +13505,12 @@ snapshots: transitivePeerDependencies: - chokidar - '@angular/build@21.0.0-next.4(@angular/ssr@21.0.0-next.4)(@types/node@20.19.17)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9))(less@4.4.1)(postcss@8.5.6)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2)))(terser@5.44.0)(tslib@2.8.1)(tsx@4.20.5)(typescript@5.9.2)(vitest@3.2.4(@types/node@20.19.17)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1)': + '@angular/build@21.0.0-next.4(@angular/compiler-cli@packages+compiler-cli)(@angular/compiler@packages+compiler)(@angular/core@packages+core)(@angular/localize@packages+localize)(@angular/platform-browser@packages+platform-browser)(@angular/platform-server@packages+platform-server)(@angular/service-worker@packages+service-worker)(@angular/ssr@21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(@angular/platform-server@packages+platform-server)(@angular/router@packages+router))(@types/node@20.19.17)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9))(less@4.4.1)(postcss@8.5.6)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2)))(terser@5.44.0)(tslib@2.8.1)(tsx@4.20.5)(typescript@5.9.2)(vitest@3.2.4(@types/node@20.19.17)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2100.0-next.4(chokidar@4.0.3) '@angular/compiler': link:packages/compiler '@angular/compiler-cli': link:packages/compiler-cli - '@angular/core': link:packages/core - '@angular/localize': link:packages/localize - '@angular/platform-browser': link:packages/platform-browser - '@angular/platform-server': link:packages/platform-server - '@angular/service-worker': link:packages/service-worker '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-split-export-declaration': 7.24.7 @@ -12629,7 +13538,12 @@ snapshots: vite: 7.1.5(@types/node@20.19.17)(jiti@2.5.1)(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1) watchpack: 2.4.4 optionalDependencies: - '@angular/ssr': 21.0.0-next.4 + '@angular/core': link:packages/core + '@angular/localize': link:packages/localize + '@angular/platform-browser': link:packages/platform-browser + '@angular/platform-server': link:packages/platform-server + '@angular/service-worker': link:packages/service-worker + '@angular/ssr': 21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(@angular/platform-server@packages+platform-server)(@angular/router@packages+router) karma: 6.4.4(bufferutil@4.0.9)(utf-8-validate@6.0.5) less: 4.4.1 lmdb: 3.4.2 @@ -12649,17 +13563,12 @@ snapshots: - tsx - yaml - '@angular/build@21.0.0-next.4(@angular/ssr@21.0.0-next.4)(@types/node@24.5.2)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.4.1)(postcss@8.5.6)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2)))(terser@5.44.0)(tslib@2.8.1)(tsx@4.20.5)(typescript@5.9.2)(vitest@3.2.4(@types/node@24.5.2)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6)(utf-8-validate@6.0.5))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1)': + '@angular/build@21.0.0-next.4(@angular/compiler-cli@packages+compiler-cli)(@angular/compiler@packages+compiler)(@angular/core@packages+core)(@angular/localize@packages+localize)(@angular/platform-browser@packages+platform-browser)(@angular/platform-server@packages+platform-server)(@angular/service-worker@packages+service-worker)(@angular/ssr@21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(@angular/platform-server@packages+platform-server)(@angular/router@packages+router))(@types/node@24.5.2)(chokidar@4.0.3)(jiti@2.5.1)(karma@6.4.4(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.4.1)(postcss@8.5.6)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2)))(terser@5.44.0)(tslib@2.8.1)(tsx@4.20.5)(typescript@5.9.2)(vitest@3.2.4(@types/node@24.5.2)(jiti@2.5.1)(jsdom@27.0.0(bufferutil@4.0.9)(postcss@8.5.6)(utf-8-validate@6.0.5))(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1))(yaml@2.8.1)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2100.0-next.4(chokidar@4.0.3) '@angular/compiler': link:packages/compiler '@angular/compiler-cli': link:packages/compiler-cli - '@angular/core': link:packages/core - '@angular/localize': link:packages/localize - '@angular/platform-browser': link:packages/platform-browser - '@angular/platform-server': link:packages/platform-server - '@angular/service-worker': link:packages/service-worker '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-split-export-declaration': 7.24.7 @@ -12687,7 +13596,12 @@ snapshots: vite: 7.1.5(@types/node@24.5.2)(jiti@2.5.1)(less@4.4.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5)(yaml@2.8.1) watchpack: 2.4.4 optionalDependencies: - '@angular/ssr': 21.0.0-next.4 + '@angular/core': link:packages/core + '@angular/localize': link:packages/localize + '@angular/platform-browser': link:packages/platform-browser + '@angular/platform-server': link:packages/platform-server + '@angular/service-worker': link:packages/service-worker + '@angular/ssr': 21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(@angular/platform-server@packages+platform-server)(@angular/router@packages+router) karma: 6.4.4(bufferutil@4.0.9)(utf-8-validate@6.0.5) less: 4.4.1 lmdb: 3.4.2 @@ -12707,7 +13621,7 @@ snapshots: - tsx - yaml - '@angular/cdk@21.0.0-next.4(rxjs@7.8.2)': + '@angular/cdk@21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(rxjs@7.8.2)': dependencies: '@angular/common': link:packages/common '@angular/core': link:packages/core @@ -12765,18 +13679,144 @@ snapshots: - chokidar - supports-color - '@angular/core@21.0.0-next.4': + '@angular/common@12.2.16(@angular/core@12.2.16(rxjs@6.6.7)(zone.js@0.11.5))(rxjs@6.6.7)': dependencies: - '@angular/compiler': link:packages/compiler + '@angular/core': 12.2.16(rxjs@6.6.7)(zone.js@0.11.5) + rxjs: 6.6.7 + tslib: 2.8.1 + + '@angular/common@13.3.9(@angular/core@13.3.9(rxjs@6.6.7)(zone.js@0.11.5))(rxjs@6.6.7)': + dependencies: + '@angular/core': 13.3.9(rxjs@6.6.7)(zone.js@0.11.5) + rxjs: 6.6.7 + tslib: 2.8.1 + + '@angular/common@18.1.0-rc.0(@angular/core@18.1.0-rc.0(rxjs@6.6.7)(zone.js@0.11.5))(rxjs@6.6.7)': + dependencies: + '@angular/core': 18.1.0-rc.0(rxjs@6.6.7)(zone.js@0.11.5) + rxjs: 6.6.7 + tslib: 2.8.1 + + '@angular/common@18.2.10(@angular/core@18.2.10)': + dependencies: + '@angular/core': 18.2.10 rxjs: 7.8.2 tslib: 2.8.1 + + '@angular/compiler-cli@12.2.16(@angular/compiler@12.2.16)': + dependencies: + '@angular/compiler': 12.2.16 + '@babel/core': 7.28.4 + '@babel/types': 7.28.4 + canonical-path: 1.0.0 + chokidar: 3.6.0 + convert-source-map: 1.9.0 + dependency-graph: 0.11.0 + magic-string: 0.25.9 + minimist: 1.2.8 + reflect-metadata: 0.1.14 + semver: 7.7.2 + source-map: 0.6.1 + sourcemap-codec: 1.4.8 + tslib: 2.8.1 + typescript: 5.9.0-beta + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + + '@angular/compiler-cli@13.3.9(@angular/compiler@13.3.9)': + dependencies: + '@angular/compiler': 13.3.9 + '@babel/core': 7.28.4 + chokidar: 3.6.0 + convert-source-map: 1.9.0 + dependency-graph: 0.11.0 + magic-string: 0.26.7 + reflect-metadata: 0.1.14 + semver: 7.7.2 + sourcemap-codec: 1.4.8 + tslib: 2.8.1 + typescript: 5.9.0-beta + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + + '@angular/compiler-cli@18.1.0-rc.0(@angular/compiler@18.1.0-rc.0(@angular/core@18.1.0-rc.0(rxjs@6.6.7)(zone.js@0.11.5)))(typescript@5.5.4)': + dependencies: + '@angular/compiler': 18.1.0-rc.0(@angular/core@18.1.0-rc.0(rxjs@6.6.7)(zone.js@0.11.5)) + '@babel/core': 7.24.7 + '@jridgewell/sourcemap-codec': 1.5.5 + chokidar: 3.6.0 + convert-source-map: 1.9.0 + reflect-metadata: 0.2.2 + semver: 7.7.2 + tslib: 2.8.1 + typescript: 5.5.4 + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + + '@angular/compiler@12.2.16': + dependencies: + tslib: 2.8.1 + + '@angular/compiler@13.3.9': + dependencies: + tslib: 2.8.1 + + '@angular/compiler@18.1.0-rc.0(@angular/core@18.1.0-rc.0(rxjs@6.6.7)(zone.js@0.11.5))': + dependencies: + tslib: 2.8.1 + optionalDependencies: + '@angular/core': 18.1.0-rc.0(rxjs@6.6.7)(zone.js@0.11.5) + + '@angular/core@12.2.16(rxjs@6.6.7)(zone.js@0.11.5)': + dependencies: + rxjs: 6.6.7 + tslib: 2.8.1 + zone.js: 0.11.5 + + '@angular/core@13.3.9(rxjs@6.6.7)(zone.js@0.11.5)': + dependencies: + rxjs: 6.6.7 + tslib: 2.8.1 + zone.js: 0.11.5 + + '@angular/core@18.1.0-rc.0(rxjs@6.6.7)(zone.js@0.11.5)': + dependencies: + rxjs: 6.6.7 + tslib: 2.8.1 + zone.js: 0.11.5 + + '@angular/core@18.2.10': + dependencies: + rxjs: 7.8.2 + tslib: 2.8.1 + zone.js: 0.14.10 + + '@angular/core@20.3.0(@angular/compiler@packages+compiler)(rxjs@6.6.7)': + dependencies: + rxjs: 6.6.7 + tslib: 2.8.1 zone.js: 0.15.1 + optionalDependencies: + '@angular/compiler': link:packages/compiler + + '@angular/core@21.0.0-next.4(@angular/compiler@packages+compiler)': + dependencies: + rxjs: 6.6.7 + tslib: 2.8.1 + zone.js: 0.15.1 + optionalDependencies: + '@angular/compiler': link:packages/compiler '@angular/domino@https://codeload.github.com/angular/domino/tar.gz/93e720f143d0296dd2726ffbcf4fc12283363a7b': {} - '@angular/material@21.0.0-next.4(@angular/cdk@21.0.0-next.4(rxjs@7.8.2))(rxjs@7.8.2)': + '@angular/language-service@20.3.0': {} + + '@angular/material@21.0.0-next.4(@angular/cdk@21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(rxjs@7.8.2))(@angular/common@packages+common)(@angular/core@packages+core)(@angular/forms@packages+forms)(@angular/platform-browser@packages+platform-browser)(rxjs@7.8.2)': dependencies: - '@angular/cdk': 21.0.0-next.4(rxjs@7.8.2) + '@angular/cdk': 21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(rxjs@7.8.2) '@angular/common': link:packages/common '@angular/core': link:packages/core '@angular/forms': link:packages/forms @@ -12845,13 +13885,14 @@ snapshots: - '@modelcontextprotocol/sdk' - '@react-native-async-storage/async-storage' - '@angular/ssr@21.0.0-next.4': + '@angular/ssr@21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(@angular/platform-server@packages+platform-server)(@angular/router@packages+router)': dependencies: '@angular/common': link:packages/common '@angular/core': link:packages/core - '@angular/platform-server': link:packages/platform-server '@angular/router': link:packages/router tslib: 2.8.1 + optionalDependencies: + '@angular/platform-server': link:packages/platform-server '@antfu/install-pkg@1.1.0': dependencies: @@ -12914,6 +13955,26 @@ snapshots: '@babel/compat-data@7.28.4': {} + '@babel/core@7.24.7': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.3 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.24.7) + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.4 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.4 + '@babel/types': 7.28.4 + convert-source-map: 2.0.0 + debug: 4.4.3(supports-color@10.2.2) + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/core@7.26.10': dependencies: '@ampproject/remapping': 2.3.0 @@ -13025,6 +14086,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-module-transforms@7.28.3(@babel/core@7.24.7)': + dependencies: + '@babel/core': 7.24.7 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.28.4 + transitivePeerDependencies: + - supports-color + '@babel/helper-module-transforms@7.28.3(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -13935,102 +15005,153 @@ snapshots: tslib: 2.8.1 optional: true + '@esbuild/aix-ppc64@0.23.1': + optional: true + '@esbuild/aix-ppc64@0.25.10': optional: true '@esbuild/aix-ppc64@0.25.9': optional: true + '@esbuild/android-arm64@0.23.1': + optional: true + '@esbuild/android-arm64@0.25.10': optional: true '@esbuild/android-arm64@0.25.9': optional: true + '@esbuild/android-arm@0.23.1': + optional: true + '@esbuild/android-arm@0.25.10': optional: true '@esbuild/android-arm@0.25.9': optional: true + '@esbuild/android-x64@0.23.1': + optional: true + '@esbuild/android-x64@0.25.10': optional: true '@esbuild/android-x64@0.25.9': optional: true + '@esbuild/darwin-arm64@0.23.1': + optional: true + '@esbuild/darwin-arm64@0.25.10': optional: true '@esbuild/darwin-arm64@0.25.9': optional: true + '@esbuild/darwin-x64@0.23.1': + optional: true + '@esbuild/darwin-x64@0.25.10': optional: true '@esbuild/darwin-x64@0.25.9': optional: true + '@esbuild/freebsd-arm64@0.23.1': + optional: true + '@esbuild/freebsd-arm64@0.25.10': optional: true '@esbuild/freebsd-arm64@0.25.9': optional: true + '@esbuild/freebsd-x64@0.23.1': + optional: true + '@esbuild/freebsd-x64@0.25.10': optional: true '@esbuild/freebsd-x64@0.25.9': optional: true + '@esbuild/linux-arm64@0.23.1': + optional: true + '@esbuild/linux-arm64@0.25.10': optional: true '@esbuild/linux-arm64@0.25.9': optional: true + '@esbuild/linux-arm@0.23.1': + optional: true + '@esbuild/linux-arm@0.25.10': optional: true '@esbuild/linux-arm@0.25.9': optional: true + '@esbuild/linux-ia32@0.23.1': + optional: true + '@esbuild/linux-ia32@0.25.10': optional: true '@esbuild/linux-ia32@0.25.9': optional: true + '@esbuild/linux-loong64@0.23.1': + optional: true + '@esbuild/linux-loong64@0.25.10': optional: true '@esbuild/linux-loong64@0.25.9': optional: true + '@esbuild/linux-mips64el@0.23.1': + optional: true + '@esbuild/linux-mips64el@0.25.10': optional: true '@esbuild/linux-mips64el@0.25.9': optional: true + '@esbuild/linux-ppc64@0.23.1': + optional: true + '@esbuild/linux-ppc64@0.25.10': optional: true '@esbuild/linux-ppc64@0.25.9': optional: true + '@esbuild/linux-riscv64@0.23.1': + optional: true + '@esbuild/linux-riscv64@0.25.10': optional: true '@esbuild/linux-riscv64@0.25.9': optional: true + '@esbuild/linux-s390x@0.23.1': + optional: true + '@esbuild/linux-s390x@0.25.10': optional: true '@esbuild/linux-s390x@0.25.9': optional: true + '@esbuild/linux-x64@0.23.1': + optional: true + '@esbuild/linux-x64@0.25.10': optional: true @@ -14043,18 +15164,27 @@ snapshots: '@esbuild/netbsd-arm64@0.25.9': optional: true + '@esbuild/netbsd-x64@0.23.1': + optional: true + '@esbuild/netbsd-x64@0.25.10': optional: true '@esbuild/netbsd-x64@0.25.9': optional: true + '@esbuild/openbsd-arm64@0.23.1': + optional: true + '@esbuild/openbsd-arm64@0.25.10': optional: true '@esbuild/openbsd-arm64@0.25.9': optional: true + '@esbuild/openbsd-x64@0.23.1': + optional: true + '@esbuild/openbsd-x64@0.25.10': optional: true @@ -14067,24 +15197,36 @@ snapshots: '@esbuild/openharmony-arm64@0.25.9': optional: true + '@esbuild/sunos-x64@0.23.1': + optional: true + '@esbuild/sunos-x64@0.25.10': optional: true '@esbuild/sunos-x64@0.25.9': optional: true + '@esbuild/win32-arm64@0.23.1': + optional: true + '@esbuild/win32-arm64@0.25.10': optional: true '@esbuild/win32-arm64@0.25.9': optional: true + '@esbuild/win32-ia32@0.23.1': + optional: true + '@esbuild/win32-ia32@0.25.10': optional: true '@esbuild/win32-ia32@0.25.9': optional: true + '@esbuild/win32-x64@0.23.1': + optional: true + '@esbuild/win32-x64@0.25.10': optional: true @@ -15369,7 +16511,7 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true - '@nginfra/angular-linking@1.0.10': + '@nginfra/angular-linking@1.0.10(@angular/compiler-cli@packages+compiler-cli)': dependencies: '@angular/compiler-cli': link:packages/compiler-cli '@babel/core': 7.26.10 @@ -15380,7 +16522,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@ngtools/webpack@21.0.0-next.4(typescript@5.9.2)(webpack@5.101.3(esbuild@0.25.9))': + '@ngtools/webpack@21.0.0-next.4(@angular/compiler-cli@packages+compiler-cli)(typescript@5.9.2)(webpack@5.101.3(esbuild@0.25.9))': dependencies: '@angular/compiler-cli': link:packages/compiler-cli typescript: 5.9.2 @@ -15421,6 +16563,10 @@ snapshots: transitivePeerDependencies: - supports-color + '@npmcli/fs@3.1.1': + dependencies: + semver: 7.7.2 + '@npmcli/fs@4.0.0': dependencies: semver: 7.7.2 @@ -15885,6 +17031,22 @@ snapshots: optionalDependencies: rollup: 4.52.2 + '@rollup/plugin-json@6.1.0(rollup@4.52.2)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.52.2) + optionalDependencies: + rollup: 4.52.2 + + '@rollup/plugin-node-resolve@15.3.1(rollup@4.52.2)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.52.2) + '@types/resolve': 1.20.2 + deepmerge: 4.3.1 + is-module: 1.0.0 + resolve: 1.22.10 + optionalDependencies: + rollup: 4.52.2 + '@rollup/plugin-node-resolve@16.0.1(rollup@4.52.2)': dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.52.2) @@ -15984,6 +17146,12 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.52.2': optional: true + '@rollup/wasm-node@4.50.1': + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + '@rushstack/node-core-library@5.14.0(@types/node@20.19.17)': dependencies: ajv: 8.13.0 @@ -16122,6 +17290,8 @@ snapshots: dependencies: defer-to-connect: 2.0.1 + '@tootallnate/once@1.1.2': {} + '@tootallnate/once@2.0.0': {} '@tootallnate/quickjs-emscripten@0.23.0': {} @@ -16428,6 +17598,8 @@ snapshots: dependencies: '@types/istanbul-lib-report': 3.0.3 + '@types/jasmine@3.10.7': {} + '@types/jasmine@5.1.9': {} '@types/jasminewd2@2.0.13': @@ -16460,6 +17632,10 @@ snapshots: '@types/node@11.15.54': {} + '@types/node@18.19.39': + dependencies: + undici-types: 5.26.5 + '@types/node@20.19.17': dependencies: undici-types: 6.21.0 @@ -16580,6 +17756,8 @@ snapshots: '@types/unist@3.0.3': {} + '@types/vscode@1.67.0': {} + '@types/which@1.3.2': {} '@types/which@3.0.4': {} @@ -16963,7 +18141,7 @@ snapshots: angular-mocks@1.8.3: {} - angular-split@20.0.0(rxjs@7.8.2): + angular-split@20.0.0(@angular/common@packages+common)(@angular/core@packages+core)(rxjs@7.8.2): dependencies: '@angular/common': link:packages/common '@angular/core': link:packages/core @@ -17196,6 +18374,11 @@ snapshots: aws4@1.13.2: {} + azure-devops-node-api@11.2.0: + dependencies: + tunnel: 0.0.6 + typed-rest-client: 1.8.11 + b4a@1.7.1: {} babel-jest@30.1.2(@babel/core@7.28.4): @@ -17367,6 +18550,8 @@ snapshots: dependencies: require-from-string: 2.0.2 + big-integer@1.6.52: {} + big.js@5.2.2: {} big.js@7.0.1: {} @@ -17375,6 +18560,11 @@ snapshots: binary-extensions@2.3.0: {} + binary@0.3.0: + dependencies: + buffers: 0.1.1 + chainsaw: 0.1.0 + bl@1.2.3: dependencies: readable-stream: 2.3.8 @@ -17398,6 +18588,8 @@ snapshots: dependencies: minimist: 1.2.8 + bluebird@3.4.7: {} + bluebird@3.7.2: {} body-parser@1.20.3: @@ -17501,6 +18693,8 @@ snapshots: buffer-from@1.1.2: {} + buffer-indexof-polyfill@1.0.2: {} + buffer@5.7.1: dependencies: base64-js: 1.5.1 @@ -17511,6 +18705,8 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 + buffers@0.1.1: {} + bufferutil@4.0.9: dependencies: node-gyp-build: 4.8.4 @@ -17527,6 +18723,21 @@ snapshots: cac@6.7.14: {} + cacache@18.0.4: + dependencies: + '@npmcli/fs': 3.1.1 + fs-minipass: 3.0.3 + glob: 10.4.5 + lru-cache: 10.4.3 + minipass: 7.1.2 + minipass-collect: 2.0.1 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + p-map: 4.0.0 + ssri: 10.0.5 + tar: 6.2.1 + unique-filename: 3.0.0 + cacache@19.0.1: dependencies: '@npmcli/fs': 4.0.0 @@ -17604,6 +18815,8 @@ snapshots: caniuse-lite@1.0.30001743: {} + canonical-path@1.0.0: {} + capital-case@1.0.4: dependencies: no-case: 3.0.4 @@ -17626,6 +18839,10 @@ snapshots: dependencies: traverse: 0.3.9 + chainsaw@0.1.0: + dependencies: + traverse: 0.3.9 + chalk@1.1.3: dependencies: ansi-styles: 2.2.1 @@ -17691,6 +18908,29 @@ snapshots: split-array-stream: 1.0.3 through2: 2.0.5 + cheerio-select@2.1.0: + dependencies: + boolbase: 1.0.0 + css-select: 5.2.2 + css-what: 6.2.2 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + + cheerio@1.1.2: + dependencies: + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.2.2 + encoding-sniffer: 0.2.1 + htmlparser2: 10.0.0 + parse5: 7.3.0 + parse5-htmlparser2-tree-adapter: 7.1.0 + parse5-parser-stream: 7.1.2 + undici: 7.16.0 + whatwg-mimetype: 4.0.0 + chevrotain-allstar@0.3.1(chevrotain@11.0.3): dependencies: chevrotain: 11.0.3 @@ -17907,6 +19147,8 @@ snapshots: commander@10.0.1: {} + commander@12.1.0: {} + commander@2.20.3: {} commander@4.1.1: {} @@ -18213,6 +19455,14 @@ snapshots: optionalDependencies: webpack: 5.101.3(esbuild@0.25.9) + css-select@5.2.2: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + css-select@6.0.0: dependencies: boolbase: 1.0.0 @@ -18230,6 +19480,8 @@ snapshots: css-value@0.0.1: {} + css-what@6.2.2: {} + css-what@7.0.0: {} cssesc@3.0.0: {} @@ -18636,10 +19888,16 @@ snapshots: delayed-stream@1.0.0: {} + denodeify@1.2.1: {} + depd@1.1.2: {} depd@2.0.0: {} + dependency-graph@0.11.0: {} + + dependency-graph@1.0.0: {} + deprecation@2.3.1: {} dequal@2.0.3: {} @@ -18750,6 +20008,10 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 + duplexer2@0.1.4: + dependencies: + readable-stream: 2.3.8 + duplexify@3.7.1: dependencies: end-of-stream: 1.4.5 @@ -18813,6 +20075,11 @@ snapshots: encodeurl@2.0.0: {} + encoding-sniffer@0.2.1: + dependencies: + iconv-lite: 0.6.3 + whatwg-encoding: 3.1.1 + encoding@0.1.13: dependencies: iconv-lite: 0.6.3 @@ -18856,6 +20123,8 @@ snapshots: punycode: 1.4.1 safe-regex-test: 1.1.0 + entities@2.0.3: {} + entities@4.5.0: {} entities@6.0.1: {} @@ -18961,10 +20230,120 @@ snapshots: dependencies: when: 3.7.8 + esbuild-android-64@0.14.39: + optional: true + + esbuild-android-arm64@0.14.39: + optional: true + + esbuild-darwin-64@0.14.39: + optional: true + + esbuild-darwin-arm64@0.14.39: + optional: true + + esbuild-freebsd-64@0.14.39: + optional: true + + esbuild-freebsd-arm64@0.14.39: + optional: true + + esbuild-linux-32@0.14.39: + optional: true + + esbuild-linux-64@0.14.39: + optional: true + + esbuild-linux-arm64@0.14.39: + optional: true + + esbuild-linux-arm@0.14.39: + optional: true + + esbuild-linux-mips64le@0.14.39: + optional: true + + esbuild-linux-ppc64le@0.14.39: + optional: true + + esbuild-linux-riscv64@0.14.39: + optional: true + + esbuild-linux-s390x@0.14.39: + optional: true + + esbuild-netbsd-64@0.14.39: + optional: true + + esbuild-openbsd-64@0.14.39: + optional: true + esbuild-plugin-umd-wrapper@3.0.0: {} + esbuild-sunos-64@0.14.39: + optional: true + esbuild-wasm@0.25.9: {} + esbuild-windows-32@0.14.39: + optional: true + + esbuild-windows-64@0.14.39: + optional: true + + esbuild-windows-arm64@0.14.39: + optional: true + + esbuild@0.14.39: + optionalDependencies: + esbuild-android-64: 0.14.39 + esbuild-android-arm64: 0.14.39 + esbuild-darwin-64: 0.14.39 + esbuild-darwin-arm64: 0.14.39 + esbuild-freebsd-64: 0.14.39 + esbuild-freebsd-arm64: 0.14.39 + esbuild-linux-32: 0.14.39 + esbuild-linux-64: 0.14.39 + esbuild-linux-arm: 0.14.39 + esbuild-linux-arm64: 0.14.39 + esbuild-linux-mips64le: 0.14.39 + esbuild-linux-ppc64le: 0.14.39 + esbuild-linux-riscv64: 0.14.39 + esbuild-linux-s390x: 0.14.39 + esbuild-netbsd-64: 0.14.39 + esbuild-openbsd-64: 0.14.39 + esbuild-sunos-64: 0.14.39 + esbuild-windows-32: 0.14.39 + esbuild-windows-64: 0.14.39 + esbuild-windows-arm64: 0.14.39 + + esbuild@0.23.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.23.1 + '@esbuild/android-arm': 0.23.1 + '@esbuild/android-arm64': 0.23.1 + '@esbuild/android-x64': 0.23.1 + '@esbuild/darwin-arm64': 0.23.1 + '@esbuild/darwin-x64': 0.23.1 + '@esbuild/freebsd-arm64': 0.23.1 + '@esbuild/freebsd-x64': 0.23.1 + '@esbuild/linux-arm': 0.23.1 + '@esbuild/linux-arm64': 0.23.1 + '@esbuild/linux-ia32': 0.23.1 + '@esbuild/linux-loong64': 0.23.1 + '@esbuild/linux-mips64el': 0.23.1 + '@esbuild/linux-ppc64': 0.23.1 + '@esbuild/linux-riscv64': 0.23.1 + '@esbuild/linux-s390x': 0.23.1 + '@esbuild/linux-x64': 0.23.1 + '@esbuild/netbsd-x64': 0.23.1 + '@esbuild/openbsd-arm64': 0.23.1 + '@esbuild/openbsd-x64': 0.23.1 + '@esbuild/sunos-x64': 0.23.1 + '@esbuild/win32-arm64': 0.23.1 + '@esbuild/win32-ia32': 0.23.1 + '@esbuild/win32-x64': 0.23.1 + esbuild@0.25.10: optionalDependencies: '@esbuild/aix-ppc64': 0.25.10 @@ -19384,6 +20763,12 @@ snapshots: transitivePeerDependencies: - supports-color + find-cache-dir@3.3.2: + dependencies: + commondir: 1.0.1 + make-dir: 3.1.0 + pkg-dir: 4.2.0 + find-up-simple@1.0.1: {} find-up@4.1.0: @@ -19651,6 +21036,13 @@ snapshots: fsevents@2.3.3: optional: true + fstream@1.0.12: + dependencies: + graceful-fs: 4.2.11 + inherits: 2.0.4 + mkdirp: 0.5.6 + rimraf: 2.7.1 + function-bind@1.1.2: {} function.prototype.name@1.1.8: @@ -20151,6 +21543,10 @@ snapshots: dependencies: parse-passwd: 1.0.0 + hosted-git-info@4.1.0: + dependencies: + lru-cache: 6.0.0 + hosted-git-info@7.0.2: dependencies: lru-cache: 10.4.3 @@ -20212,6 +21608,14 @@ snapshots: http-parser-js@0.5.10: {} + http-proxy-agent@4.0.1: + dependencies: + '@tootallnate/once': 1.1.2 + agent-base: 6.0.2(supports-color@10.2.2) + debug: 4.4.3(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + http-proxy-agent@5.0.0(supports-color@10.2.2): dependencies: '@tootallnate/once': 2.0.0 @@ -20381,6 +21785,10 @@ snapshots: ini@5.0.0: {} + injection-js@2.5.0: + dependencies: + tslib: 2.8.1 + install-artifact-from-github@1.4.0: optional: true @@ -21476,6 +22884,12 @@ snapshots: lines-and-columns@1.2.4: {} + linkify-it@2.2.0: + dependencies: + uc.micro: 1.0.6 + + listenercount@1.0.1: {} + listr2@3.14.0(enquirer@2.4.1): dependencies: cli-truncate: 2.1.0 @@ -21676,6 +23090,10 @@ snapshots: dependencies: sourcemap-codec: 1.4.8 + magic-string@0.26.7: + dependencies: + sourcemap-codec: 1.4.8 + magic-string@0.30.19: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -21733,6 +23151,14 @@ snapshots: map-cache@0.2.2: {} + markdown-it@10.0.0: + dependencies: + argparse: 1.0.10 + entities: 2.0.3 + linkify-it: 2.2.0 + mdurl: 1.0.1 + uc.micro: 1.0.6 + marked-terminal@7.3.0(marked@13.0.3): dependencies: ansi-escapes: 7.1.0 @@ -21770,6 +23196,8 @@ snapshots: mdn-data@2.12.2: {} + mdurl@1.0.1: {} + media-typer@0.3.0: {} media-typer@1.1.0: {} @@ -22043,6 +23471,8 @@ snapshots: mute-stdout@2.0.0: {} + mute-stream@0.0.8: {} + mute-stream@2.0.0: {} mz@2.7.0: @@ -22083,15 +23513,46 @@ snapshots: netmask@2.0.2: {} - ngx-flamegraph@0.1.1: + ng-packagr@18.2.1(@angular/compiler-cli@18.1.0-rc.0(@angular/compiler@18.1.0-rc.0(@angular/core@18.1.0-rc.0(rxjs@6.6.7)(zone.js@0.11.5)))(typescript@5.5.4))(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.5.4)))(tslib@2.8.1)(typescript@5.5.4): + dependencies: + '@angular/compiler-cli': 18.1.0-rc.0(@angular/compiler@18.1.0-rc.0(@angular/core@18.1.0-rc.0(rxjs@6.6.7)(zone.js@0.11.5)))(typescript@5.5.4) + '@rollup/plugin-json': 6.1.0(rollup@4.52.2) + '@rollup/plugin-node-resolve': 15.3.1(rollup@4.52.2) + '@rollup/wasm-node': 4.50.1 + ajv: 8.17.1 + ansi-colors: 4.1.3 + browserslist: 4.26.2 + cacache: 18.0.4 + chokidar: 3.6.0 + commander: 12.1.0 + convert-source-map: 2.0.0 + dependency-graph: 1.0.0 + esbuild: 0.23.1 + fast-glob: 3.3.3 + find-cache-dir: 3.3.2 + injection-js: 2.5.0 + jsonc-parser: 3.3.1 + less: 4.4.1 + ora: 5.4.1 + piscina: 4.9.2 + postcss: 8.5.6 + rxjs: 7.8.2 + sass: 1.92.1 + tslib: 2.8.1 + typescript: 5.5.4 + optionalDependencies: + rollup: 4.52.2 + tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.5.4)) + + ngx-flamegraph@0.1.1(@angular/common@packages+common)(@angular/core@packages+core): dependencies: '@angular/common': link:packages/common '@angular/core': link:packages/core tslib: 2.8.1 - ngx-progressbar@14.0.0(@angular/cdk@21.0.0-next.4(rxjs@7.8.2))(rxjs@7.8.2): + ngx-progressbar@14.0.0(@angular/cdk@21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(rxjs@7.8.2))(@angular/common@packages+common)(@angular/core@packages+core)(rxjs@7.8.2): dependencies: - '@angular/cdk': 21.0.0-next.4(rxjs@7.8.2) + '@angular/cdk': 21.0.0-next.4(@angular/common@packages+common)(@angular/core@packages+core)(rxjs@7.8.2) '@angular/common': link:packages/common '@angular/core': link:packages/core rxjs: 7.8.2 @@ -22370,8 +23831,15 @@ snapshots: ordered-binary@1.6.0: optional: true + os-homedir@1.0.2: {} + os-tmpdir@1.0.2: {} + osenv@0.1.5: + dependencies: + os-homedir: 1.0.2 + os-tmpdir: 1.0.2 + ospath@1.2.2: {} outvariant@1.4.3: {} @@ -22507,6 +23975,10 @@ snapshots: parse-passwd@1.0.0: {} + parse-semver@1.1.1: + dependencies: + semver: 5.7.2 + parse5-html-rewriting-stream@8.0.0: dependencies: entities: 6.0.1 @@ -22517,6 +23989,15 @@ snapshots: dependencies: parse5: 6.0.1 + parse5-htmlparser2-tree-adapter@7.1.0: + dependencies: + domhandler: 5.0.3 + parse5: 7.3.0 + + parse5-parser-stream@7.1.2: + dependencies: + parse5: 7.3.0 + parse5-sax-parser@8.0.0: dependencies: parse5: 8.0.0 @@ -22648,6 +24129,10 @@ snapshots: pirates@4.0.7: {} + piscina@4.9.2: + optionalDependencies: + '@napi-rs/nice': 1.1.1 + piscina@5.1.3: optionalDependencies: '@napi-rs/nice': 1.1.1 @@ -22715,6 +24200,15 @@ snapshots: ts-node: 10.9.2(@types/node@20.19.17)(typescript@5.9.2) optional: true + postcss-load-config@4.0.2(postcss@8.5.6)(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.5.4)): + dependencies: + lilconfig: 3.1.3 + yaml: 2.8.1 + optionalDependencies: + postcss: 8.5.6 + ts-node: 10.9.2(@types/node@24.5.2)(typescript@5.5.4) + optional: true + postcss-load-config@4.0.2(postcss@8.5.6)(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2)): dependencies: lilconfig: 3.1.3 @@ -22796,6 +24290,8 @@ snapshots: preact@10.27.2: {} + prettier@2.7.1: {} + prettier@3.6.2: {} pretty-bytes@5.6.0: {} @@ -23067,6 +24563,10 @@ snapshots: type-fest: 4.41.0 unicorn-magic: 0.1.0 + read@1.0.7: + dependencies: + mute-stream: 0.0.8 + readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -23105,6 +24605,8 @@ snapshots: dependencies: resolve: 1.22.10 + reflect-metadata@0.1.14: {} + reflect-metadata@0.2.2: {} reflect.getprototypeof@1.0.10: @@ -23433,6 +24935,10 @@ snapshots: rw@1.3.3: {} + rxjs@6.6.7: + dependencies: + tslib: 1.14.1 + rxjs@7.8.2: dependencies: tslib: 2.8.1 @@ -24230,6 +25736,34 @@ snapshots: - ts-node optional: true + tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.5.4)): + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.3 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.7 + lilconfig: 3.1.3 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-import: 15.1.0(postcss@8.5.6) + postcss-js: 4.1.0(postcss@8.5.6) + postcss-load-config: 4.0.2(postcss@8.5.6)(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.5.4)) + postcss-nested: 6.2.0(postcss@8.5.6) + postcss-selector-parser: 6.1.2 + resolve: 1.22.10 + sucrase: 3.35.0 + transitivePeerDependencies: + - ts-node + optional: true + tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2)): dependencies: '@alloc/quick-lru': 5.2.0 @@ -24528,6 +26062,24 @@ snapshots: ts-interface-checker@0.1.13: {} + ts-node@10.9.2(@types/node@18.19.39)(typescript@5.9.2): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 18.19.39 + acorn: 8.15.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.9.2 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -24546,6 +26098,25 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + ts-node@10.9.2(@types/node@24.5.2)(typescript@5.5.4): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 24.5.2 + acorn: 8.15.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.5.4 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optional: true + ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -24705,6 +26276,12 @@ snapshots: typed-query-selector@2.12.0: {} + typed-rest-client@1.8.11: + dependencies: + qs: 6.14.0 + tunnel: 0.0.6 + underscore: 1.13.7 + typedarray-to-buffer@3.1.5: dependencies: is-typedarray: 1.0.0 @@ -24724,6 +26301,8 @@ snapshots: typescript@3.2.4: {} + typescript@5.5.4: {} + typescript@5.8.2: {} typescript@5.9.0-beta: {} @@ -24732,6 +26311,8 @@ snapshots: ua-parser-js@0.7.41: {} + uc.micro@1.0.6: {} + ufo@1.6.1: {} uglify-js@3.19.3: @@ -24751,6 +26332,8 @@ snapshots: unc-path-regex@0.1.2: {} + underscore@1.13.7: {} + undertaker-registry@2.0.0: {} undertaker@2.0.0: @@ -24760,6 +26343,8 @@ snapshots: last-run: 2.0.0 undertaker-registry: 2.0.0 + undici-types@5.26.5: {} + undici-types@6.21.0: {} undici-types@7.12.0: {} @@ -24791,10 +26376,18 @@ snapshots: dependencies: qs: 6.14.0 + unique-filename@3.0.0: + dependencies: + unique-slug: 4.0.0 + unique-filename@4.0.0: dependencies: unique-slug: 5.0.0 + unique-slug@4.0.0: + dependencies: + imurmurhash: 0.1.4 + unique-slug@5.0.0: dependencies: imurmurhash: 0.1.4 @@ -24871,6 +26464,19 @@ snapshots: untildify@4.0.0: {} + unzipper@0.10.14: + dependencies: + big-integer: 1.6.52 + binary: 0.3.0 + bluebird: 3.4.7 + buffer-indexof-polyfill: 1.0.2 + duplexer2: 0.1.4 + fstream: 1.0.12 + graceful-fs: 4.2.11 + listenercount: 1.0.1 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + update-browserslist-db@1.1.3(browserslist@4.26.2): dependencies: browserslist: 4.26.2 @@ -24912,6 +26518,8 @@ snapshots: url-join@0.0.1: {} + url-join@1.1.0: {} + url-join@4.0.1: {} url-template@2.0.8: {} @@ -25225,8 +26833,53 @@ snapshots: tslint: 6.1.3(typescript@5.9.2) typescript: 5.9.2 + vsce@1.100.1: + dependencies: + azure-devops-node-api: 11.2.0 + chalk: 2.4.2 + cheerio: 1.1.2 + commander: 6.2.1 + denodeify: 1.2.1 + glob: 7.2.3 + hosted-git-info: 4.1.0 + leven: 3.1.0 + lodash: 4.17.21 + markdown-it: 10.0.0 + mime: 1.6.0 + minimatch: 3.1.2 + osenv: 0.1.5 + parse-semver: 1.1.1 + read: 1.0.7 + semver: 5.7.2 + tmp: 0.2.5 + typed-rest-client: 1.8.11 + url-join: 1.1.0 + xml2js: 0.4.23 + yauzl: 2.10.0 + yazl: 2.5.1 + + vscode-html-languageservice@4.2.5: + dependencies: + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.16.0 + vscode-nls: 5.2.0 + vscode-uri: 3.0.7 + + vscode-jsonrpc@6.0.0: {} + vscode-jsonrpc@8.2.0: {} + vscode-languageclient@7.0.0: + dependencies: + minimatch: 3.1.2 + semver: 7.7.2 + vscode-languageserver-protocol: 3.16.0 + + vscode-languageserver-protocol@3.16.0: + dependencies: + vscode-jsonrpc: 6.0.0 + vscode-languageserver-types: 3.16.0 + vscode-languageserver-protocol@3.17.5: dependencies: vscode-jsonrpc: 8.2.0 @@ -25234,12 +26887,44 @@ snapshots: vscode-languageserver-textdocument@1.0.12: {} + vscode-languageserver-types@3.16.0: {} + vscode-languageserver-types@3.17.5: {} + vscode-languageserver@7.0.0: + dependencies: + vscode-languageserver-protocol: 3.16.0 + vscode-languageserver@9.0.1: dependencies: vscode-languageserver-protocol: 3.17.5 + vscode-nls@5.2.0: {} + + vscode-oniguruma@1.7.0: {} + + vscode-test@1.6.1: + dependencies: + http-proxy-agent: 4.0.1 + https-proxy-agent: 7.0.6(supports-color@10.2.2) + rimraf: 3.0.2 + unzipper: 0.10.14 + transitivePeerDependencies: + - supports-color + + vscode-textmate@5.5.0: {} + + vscode-tmgrammar-test@0.0.11: + dependencies: + chalk: 2.4.2 + commander: 2.20.3 + diff: 4.0.2 + glob: 7.2.3 + vscode-oniguruma: 1.7.0 + vscode-textmate: 5.5.0 + + vscode-uri@3.0.7: {} + vscode-uri@3.0.8: {} w3c-keyname@2.2.8: {} @@ -25763,6 +27448,12 @@ snapshots: zod@4.1.11: {} + zone.js@0.11.5: + dependencies: + tslib: 2.8.1 + + zone.js@0.14.10: {} + zone.js@0.15.1: {} zwitch@2.0.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 817d8dc3f57..c96105d833b 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -26,6 +26,11 @@ packages: - packages/zone.js/ - packages/zone.js/test/typings/ - tools/bazel/rules_angular_store/ + - vscode-ng-language-service + - vscode-ng-language-service/integration/pre_standalone_project + - vscode-ng-language-service/integration/workspace + - vscode-ng-language-service/integration/pre_apf_project + - vscode-ng-language-service/integration/project allowedDeprecatedVersions: angular: '*' diff --git a/vscode-ng-language-service/BUILD.bazel b/vscode-ng-language-service/BUILD.bazel new file mode 100644 index 00000000000..fea50c3796e --- /dev/null +++ b/vscode-ng-language-service/BUILD.bazel @@ -0,0 +1,109 @@ +load("@aspect_bazel_lib//lib:expand_template.bzl", "expand_template_rule") +load("@aspect_rules_js//js:defs.bzl", "js_library") +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@aspect_rules_ts//ts:defs.bzl", "ts_config") +load("@npm//:defs.bzl", "npm_link_all_packages") +load("@npm//vscode-ng-language-service:vsce/package_json.bzl", vsce_bin = "bin") + +npm_link_all_packages(name = "node_modules") + +js_library( + name = "package_json", + srcs = ["package.json"], + visibility = ["//vscode-ng-language-service/syntaxes/test:__pkg__"], +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + visibility = ["//visibility:public"], +) + +expand_template_rule( + name = "package_json_expanded", + out = "package_expanded.json", + stamp_substitutions = { + "0.0.0-PLACEHOLDER": "{{BUILD_SCM_VERSION}}", + }, + substitutions = { + "./bazel-bin/client/src/extension": "./index", + }, + template = "package.json", +) + +npm_package( + name = "vsix_sandbox", + srcs = [ + "package_expanded.json", + "angular.png", + "CHANGELOG.md", + "README.md", + "//vscode-ng-language-service/client:index.js", + "//vscode-ng-language-service/server:npm_files", + "//vscode-ng-language-service/syntaxes:npm_files", + # Transitive closure of npm deps needed for vsce; this set was determined manually by + # running `bazel build //:vsix` and burning down missing packages. We do this so that we + # don't have to run an additional `npm install` action to create a node_modules within the + # //:npm npm_package where the vsce build takes place. + "//vscode-ng-language-service:node_modules/@angular/language-service", + "//vscode-ng-language-service:node_modules/balanced-match", + "//vscode-ng-language-service:node_modules/brace-expansion", + "//vscode-ng-language-service:node_modules/concat-map", + "//vscode-ng-language-service:node_modules/lru-cache", + "//vscode-ng-language-service:node_modules/minimatch", + "//vscode-ng-language-service:node_modules/semver", + "//vscode-ng-language-service:node_modules/typescript", + "//vscode-ng-language-service:node_modules/vscode-jsonrpc", + "//vscode-ng-language-service:node_modules/vscode-html-languageservice", + "//vscode-ng-language-service:node_modules/vscode-languageclient", + "//vscode-ng-language-service:node_modules/vscode-languageserver-protocol", + "//vscode-ng-language-service:node_modules/vscode-languageserver-textdocument", + "//vscode-ng-language-service:node_modules/vscode-languageserver-types", + "//vscode-ng-language-service:node_modules/vscode-languageserver", + "//vscode-ng-language-service:node_modules/vscode-nls", + "//vscode-ng-language-service:node_modules/vscode-uri", + "//vscode-ng-language-service:node_modules/yallist", + ], + exclude_srcs_patterns = [ + "*.map", + "**/*.map", + ], + include_srcs_packages = [ + "**", + ], + replace_prefixes = { + "package_expanded.json": "package.json", + "server/package_expanded.json": "server/package.json", + "client/": "", + "syntaxes/src/": "syntaxes/", + }, +) + +vsce_bin.vsce( + name = "vsix", + srcs = [ + ":vsix_sandbox", + ], + outs = ["ng-template.vsix"], + args = [ + "package", + "-o", + "../ng-template.vsix", + ], + chdir = "vscode-ng-language-service/vsix_sandbox", + # vsce requires npm on the PATH; we can get this from the Bazel rules_nodejs but it is not + # included by default in rules_js binary rules so we include it here explicitly + include_npm = True, +) + +npm_package( + name = "npm", + srcs = [ + ":vsix", + ":vsix_sandbox", + ], + root_paths = [ + "vsix_sandbox", + ], + visibility = ["//vscode-ng-language-service/integration:__subpackages__"], +) diff --git a/vscode-ng-language-service/CHANGELOG.md b/vscode-ng-language-service/CHANGELOG.md new file mode 100644 index 00000000000..a31a8b565c9 --- /dev/null +++ b/vscode-ng-language-service/CHANGELOG.md @@ -0,0 +1,1148 @@ +# 20.2.2 + +This release upgrades `@angular/language-service` to v20.2.0-rc.1. + +| Commit | Type | Description | +| -- | -- | -- | +| [c81e345e72](https://github.com/angular/angular/commit/c81e345e726b5b281621159c789e6d80a9f328e2) | feat | support auto-import for attribute completions ([#62797](https://github.com/angular/angular/pull/62797)) | +| [4aa120ac00](https://github.com/angular/angular/commit/4aa120ac000a569a29e45e9c6db9e4f32c61d183) | fix | error when type checking host bindings of generic directive ([#63061](https://github.com/angular/angular/pull/63061)) | + + +# 20.2.1 + +This release upgrades `@angular/language-service` to v20.2.0-next.6. + +| Commit | Type | Description | +| -- | -- | -- | +| [812463c563](https://github.com/angular/angular/commit/812463c5636effe5bd5ba5c7c7fc65c3cc08d047) | fix | Ignore diagnostics on ngTemplateContextGuard lines in TCB ([#63054](https://github.com/angular/angular/pull/63054)) | +| [45b030b5ce](https://github.com/angular/angular/commit/45b030b5ce1e116a88fe1c2fe133f654fb1f66c5) | fix | prevent dom event assertion in TCB generation on older angular versions ([#63053](https://github.com/angular/angular/pull/63053)) | + +# 20.2.0 + +This release upgrades `@angular/language-service` to v20.2.0-next.5. + +* [feat(language-service): support to report the deprecated API in the template](https://github.com/angular/vscode-ng-language-service/pull/2192) + +# 20.1.1 + +* [fix(server): Remove custom semantic tokens to fix regression in file highlighting](https://github.com/angular/vscode-ng-language-service/pull/2197) + +# 20.1.0 +This release upgrades `@angular/language-service` to v20.1.0-rc.0. + +* [feat(language-server): Support semantic tokens for components in templates](https://github.com/angular/vscode-ng-language-service/commit/1c0fd4e94daf3d082c0f629d9ec0e32ff290b354) +* [feat(language-server): Support external modules in autocomplete](https://github.com/angular/vscode-ng-language-service/commit/a39e01df7d474b1495ea93dd64c26880c54ec4de) +* [feat(language-service): Quick fix missing required inputs](https://github.com/angular/angular/commit/5d2e85920e714560e8d06bfb9c41d9312eeaae3b) + +# 20.0.1 +This release upgrades `@angular/language-service` to v20.0.0-rc.2. + +* [fix(language-server): fix Always retain prior results for all files](https://github.com/angular/angular/pull/61487) + +# 20.0.0 +This release upgrades `@angular/language-service` to v20.0.0-rc.0. + +* [feat(language-server): support type checking of host bindings](https://github.com/angular/angular/pull/60267) + +# 19.2.4 +This release upgrades `@angular/language-service` to v19.2.7. + +* [fix(language-service): Do not provide element completions in end tag](https://github.com/angular/angular/commit/a22b13f99041eb6931471aaa81391f9ab0ad7c6d) +* [fix(language-service): Ensure dollar signs are escaped in completions](https://github.com/angular/angular/commit/b9cf414790f5217cd5c73f7520a11031bde6c864) +* [fix(language-server): Do best-effort to initialize composite project](https://github.com/angular/vscode-ng-language-service/commit/f0c8831c1d66c13a48deae1dd4abe636825a8676) + +# 19.2.3 +This release upgrades `@angular/language-service` to v19.2.5. + +* [fix(language-service): Produce fatal diagnostic on duplicate decorated properties](https://github.com/angular/angular/commit/f4c4b10ea8dc263c30d1051a83a72486344d81e4) +* [fix(language-service): Update adapter to log instead of throw errors](https://github.com/angular/angular/commit/ea62a4f3172d0618a33e8e95b49e133cfee6b15d) +* [fix(syntaxes): variable token for @let binding](https://github.com/angular/vscode-ng-language-service/commit/0aa2aa572dedcad4c5fc3c6825227396f4e99f21) +* [fix(syntaxes): keyword token for track](https://github.com/angular/vscode-ng-language-service/commit/8c84410f61ed87e261a83458af10af18cbf669a9) +* [fix(syntaxes): Semicolons not tokenized](https://github.com/angular/vscode-ng-language-service/commit/39057fc2dbb37125778fb2c5c517c661f9399996) + +# 19.2.2 +This release upgrades `@angular/language-service` to v19.2.4. + +* Bumps `@angular/language-server` to use the latest language-service version of Angular. +* [fix: report more accurate diagnostic for invalid import](https://github.com/angular/angular/commit/aa8ea7a5b227913e3f15270dac48479481c47f9a) + +# 19.2.1 +This release upgrades `@angular/language-service` to v19.2.2. + +* [feat(syntaxes): support template literals (#2152)](https://github.com/angular/vscode-ng-language-service/commit/de5d9650caa3a9de1b50e9815acb2a631f14ab3d) +* [Updates the bundled version of the Angular compiler to fix enum resolution errors](https://github.com/angular/angular/commit/4fa5d18e5a57be03979b73be03a3d280c6dc0cb5) +* [feat: forward tags for quick info from type definitions](https://github.com/angular/angular/commit/3f0116607dc3ad7e31cb4d895a56094f77c82f5d) + +# 19.2.0 +This release upgrades `@angular/language-service` to v19.2.0. + +* [fix(language-service): provide correct rename info for elements (#60088)](https://github.com/angular/angular/pull/60088) + +# 19.1.0 +This release upgrades `@angular/language-service` to v19.1.4. + +* [fix: replace the closing symbol for inputs/outputs (#2142)](https://github.com/angular/vscode-ng-language-service/pull/2142) +* [fix(extension): Fix grouping of Angular commands into submenu (#2136)](https://github.com/angular/vscode-ng-language-service/pull/2136) + +# 19.0.4 +This release upgrades `@angular/language-service` to v19.0.6. + +* [fix(compiler-cli): consider pre-release versions when detecting feature support #59061](https://github.com/angular/angular/pull/59061) + +# 19.0.3 +This release upgrades `@angular/language-service` to v19.0.1. + +* [Fixes for the unused standalone imports](https://github.com/angular/angular/pull/58719) +* [Improved diagnostics for `host` binding issues](https://github.com/angular/angular/pull/58870) + +# 19.0.2 +This release upgrades `@angular/language-service` to v19.0.0-rc.3. + +* [Better diagnostics for unused standalone imports](https://github.com/angular/angular/commit/9bbb01c85e763b0457456a2393a834db15008671) +* [Migration fixes for the signal input and queries code actions](https://github.com/angular/angular/pull/58581) + +# 19.0.1 + +* **fix**: [improve detection of Angular core version in monorepo setup](https://github.com/angular/vscode-ng-language-service/commit/6692c40500cabe7f1fae9cc12e6298946a2e37ee) + +# 19.0.0 +This release upgrades `@angular/language-service` to v19.0.0-rc.1. + +* **feat**: Code refactoring action to migrate `@Input` to signal inputs. + * https://v19.angular.dev/reference/migrations/signal-inputs +* **feat**: Code refactoring action to migrate decorator queries to signal queries. +e.g. `@ViewChild` to `viewChild()`. + * https://v19.angular.dev/reference/migrations/signal-queries + +To use any of the new code refactoring actions, click on an input or query, and wait for +the code refactoring lightbulb to appear. You can also click on the class header to update +inputs or queries for the full class! + +# 19.0.0-next.0 +This release upgrades `@angular/language-service` to v19.0.0-next.6. + + +| Commit | Type | Description | +| -- | -- | -- | +| [8da9fb49b5](https://github.com/angular/angular/commit/8da9fb49b54e50de2d028691f73fb773def62ecd) | feat | add code fix for unused standalone imports ([#57605](https://github.com/angular/angular/pull/57605)) | +| [1f067f4507](https://github.com/angular/angular/commit/1f067f4507b6e908fe991d5de0dc4d3a627ab2f9) | feat | add code reactoring action to migrate `@Input` to signal-input ([#57214](https://github.com/angular/angular/pull/57214)) | +| [56ee47f2ec](https://github.com/angular/angular/commit/56ee47f2ec6e983e2ffdf59476ab29a92590811e) | feat | allow code refactorings to compute edits asynchronously ([#57214](https://github.com/angular/angular/pull/57214)) | +| [6ec0c6bcee](https://github.com/angular/vscode-ng-language-service/commit/7c1330694cc50a166f45d48641c2e06ec0c6bcee) | feat | Allow specific diagnostics to be suppressed ([#57675](https://github.com/angular/angular/pull/57675)) + +# 18.2.0 +This release upgrades `@angular/language-service` to v18.2.0-rc.0. + +* feat: integrate code refactorings from language-service via LSP (#2050) + +# 18.1.2 +This release upgrades `@angular/language-service` to v18.1.0. + +* fix(syntaxes): add back block syntaxes to injection for entire TS file (#2065) + +# 18.1.1 + +* fix(syntaxes): inject template tags to top-level source.ts (#2058) + +# 18.1.0 + +This release upgrades `@angular/language-service` to v18.1.0-rc.0. + +* feat(syntaxes): add support for let declarations (#2042) +* feat: generate the import declaration for the completion item code actions (#2031) +* fix(server): disable let syntax when not supported (#2047) + +# 18.0.0 +This release upgrades `@angular/language-service` to v18.0.0. + +* fix: allow external projects to use provided compiler options ([#55035](https://github.com/angular/angular/pull/55035)) +* fix: avoid generating TS syntactic diagnostics for templates ([#55091](https://github.com/angular/angular/pull/55091)) +* fix: implement getDefinitionAtPosition for Angular templates ([#55269](https://github.com/angular/angular/pull/55269)) +* fix: prevent underlying TS Service from handling template files ([#55003](https://github.com/angular/angular/pull/55003)) +* fix: use type-only import in plugin factory ([#55996](https://github.com/angular/angular/pull/55996)) +* fix(syntaxes): Only match known block names (#2034) (dceedb686) + +# 17.2.2 +This release upgrades `@angular/language-service` to v17.2.1. + +* fix: pass oldest Angular version in the workspace to the compiler (#2003) + + +# 17.2.1 +This release rolls back the `@angular/language-service` version to v17.2.0-next.0 to resolve an issue reported in ticket [#2001](https://github.com/angular/vscode-ng-language-service/issues/2001). + + +# 17.2.0 +This release upgrades `@angular/language-service` to v17.2.0-rc.1. + +* fix(syntaxes): Do not highlight bindings outside element tags (#1725) (28739e4) + + +# 17.1.0 +This release upgrades `@angular/language-service` to v17.1.0. It is based on the final RC of `@angular/compiler`. + +* feat: Complete inside @switch ([#52153](https://github.com/angular/angular/pull/52153)) +* feat: Enable go to definition of styleUrl ([#51746](https://github.com/angular/angular/pull/51746)) +* feat: Implement outlining spans for control flow blocks ([#52062](https://github.com/angular/angular/pull/52062)) +* feat: Support autocompletion for blocks ([#52121](https://github.com/angular/angular/pull/52121)) +* fix: Autocomplete block keywords in more cases ([#52198](https://github.com/angular/angular/pull/52198)) +* fix(syntaxes): Do not apply block syntax highlighting to JS and CSS in templates (#1952) + +# 17.0.2 +This release upgrades `@angular/language-service` to v17.0.2. + +* fix(client,server): Correctly use bundled version unless tsdk is specified (#1970) (46b9a56a2) +* fix(server): Do not disable language service for solution style root tsconfig (#1972) (d8689bee4) +* fix(language-service): incorrect inferred type of for loop implicit variables (https://github.com/angular/angular/pull/52732) + +# 17.0.1 +This release upgrades `@angular/language-service` to v17.0.1. + +* fix: Disable block syntax parsing when no project in workspace supports it (#1962) (#1964) (e276a57d4) +* fix(syntaxes): Single quote should end `as` alias match (#1956) (d7dab5264) +* fix(syntaxes): Adjust block syntax highlighting to require `(` or `{` on same line (#1961) (075047ae3) +* fix(syntaxes): Use expression.ng instead of JS for block expressions (#1960) (e17fc5c35) + +# 17.0.0 +This release upgrades `@angular/language-service` to v17.0.0-rc.3. + +* fix(syntaxes): Support scss for inline styles (#1951) +* fix(syntaxes): Support multiline block expressions +* feat: Complete inside @switch (https://github.com/angular/angular/pull/52153) +* fix: correct incomplete escaping (https://github.com/angular/angular/pull/51557) +* fix: fix Autocomplete block keywords in more cases (https://github.com/angular/angular/pull/52198) + +# 17.0.0-next.2 +This release upgrades `@angular/language-service` to v17.0.0-next.8. + +* feat(server): Add folding range support for Angular template syntax (#1938) +* feat: support block completions (#1937) + +# 17.0.0-next.1 +This release upgrades `@angular/language-service` to v17.0.0-next.7. + +# 17.0.0-next.0 +This release upgrades `@angular/language-service` to v17.0.0-next.6. + +* feat(syntaxes): Add support for block syntaxes +* fix(client): fix detection of Angular context after string interpolation +* feat: Enable go to definition of styleUrl (https://github.com/angular/angular/pull/51746) + +# 16.2.0 +This release upgrades the `@angular/language-service` to v16.2.8 + +* fix: Retain correct language service when ts.Project reloads ([#51912](https://github.com/angular/angular/commit/08482f2c7dcbcd100981dfb266a6e63f64432328)) +* fix(server): support to show the tag info in the jsDoc (#1904) +* fix(client): fix detection of Angular context after string interpolation (#1922) + +# 16.1.8 +This release upgrades `@angular/language-service` to v16.1.8. + +* Update the bundled version of TypeScript to 5.1.3 + +# 16.1.4 +This release upgrades `@angular/language-service` to v16.1.4. + +# 16.0.0-next.0 +This release upgrades `@angular/language-service` to v16.0.0-next.4. + +* fix(server): Respect the client capabilities "textDocument.{declaration,typeDefinition}.linkSupport." +https://github.com/angular/vscode-ng-language-service/commit/8751840d6be1ddb1900be8713eabf0c7796e5ca8 + +# 15.2.0 + +This release upgrades `@angular/language-service` to v15.2.0. + +* fix(server): Fall back to bundled TS version if specified TSDK is too old ([#1863](https://github.com/angular/vscode-ng-language-service/pull/1863)) + +# 15.2.0-next.0 + +This release upgrades `@angular/language-service` to v15.2.0-next.1. + +* feat: Add option to disable code actions ([#1849](https://github.com/angular/vscode-ng-language-service/pull/1849)) + +# 15.1.0 + +This release upgrades `@angular/language-service` to v15.1.0. + +* feat: Allow auto-imports to suggest multiple possible imports. ([#47955](https://github.com/angular/angular/pull/47955)) + +# 15.0.4 + +This release upgrades `@angular/language-service` to v15.0.4. + +* perf(extension): Ensure Angular code actions are only retrieved in Angular contexts (#1842) + +# 15.0.3 + +This release upgrades `@angular/language-service` to v15.0.3. + +* fix(server): filter unsupported code action to improve performance on save (#1834) +* fix(compiler-cli): Produce diagnostic rather than crash when using invalid hostDirective ([#48314](https://github.com/angular/angular/pull/48314)) + +# 15.0.2 + +This release upgrades `@angular/language-service` to v15.0.2. + +* fix(extension): Ensure older projects that require View Engine can function (#1826) + +# 15.0.1 + +This release fixes an incorrectly bundled `vsix` in the v15.0.0 release. + +# 15.0.0 + +This release upgrades `@angular/language-service` to v15.0.0. + +* feat(server): provide folding ranges for inline templates (#1779) +* fix(server): resolve tsdk correctly when settings specify a relative location (#1765) +* fix(server): send diagnostic range to the Angular language service when fixing code errors (#1747) +* fix: support deeply nested pnpm virtual store node_modules paths in resolveAndRunNgcc (#1742) +* feat(server): support code actions (#1723) +* feat(language-service): Quick fix to import a component when its selector is used ([#47088](https://github.com/angular/angular/pull/47088)) +* feat(language-service): support to fix invalid banana in box ([#47393](https://github.com/angular/angular/pull/47393)) + +# v14.2.0 + +This release upgrades `@angular/language-service` to v14.2.0. + +* feat: support fix the component missing member (#46764) +* fix: support deeply nested pnpm virtual store node_modules paths in resolveAndRunNgcc (#1742) (511218f10) +* feat: support code action (#1723) (a5ecf2df6) + +# v14.1.0 + +This release upgrades `@angular/language-service` to v14.1.0 + +* feat(extension): Update untrusted workspace support from 'false' to 'limited' (#1695) (7d904ca20) +* feat(extension): Update virtualWorkspace support to allow syntax highlighting (#1694) (f8b0db869) + +# v14.0.1 + +* fix(extension): disable rename override to allow built in TS renaming (#1687) + +# v14.0.0 + +This release upgrades `@angular/language-service` to v14.0.0 + +* feat: Add option to disable ngcc (#1620) +* feat(extension): Support renaming from TypeScript files (#1589) +* feat(extension): Add option to force strict templates (#1646) (17fdb9ec6) +* feat: add command to run ngcc manually (#1621) (dd0e0009b) +* Fix detection of Angular for v14+ projects ([#45998](https://github.com/angular/angular/pull/45998)) +* Prevent TSServer from removing templates from project ([#45965](https://github.com/angular/angular/pull/45965)) + +# v13.3.4 + +This release upgrades `@angular/language-service` to v13.3.8. + +| Commit | Type | Description | +| -- | -- | -- | +| [b4eb9ed884](https://github.com/angular/angular/commit/b4eb9ed884a82ba741abb503c974df7ec0d0048a) | fix | Prevent TSServer from removing templates from project ([#45965](https://github.com/angular/angular/pull/45965)) | + +# v13.2.3 + +This release upgrades `@angular/language-service` to v13.2.2. + +* build(server): Update node version to match angular/angular (including v16) (#1612) (8d2420f11) + +# v13.2.2 + +This release upgrades `@angular/language-service` to v13.2.1. + +* fix(server): return the right range for the original source file of DTS (#1604) (2caa6cf23) + + +# v13.2.1 + +Skipped due to release process mistake. + +# v13.2.0 + +This release upgrades `@angular/language-service` to v13.2.0. + +* feat(server): Definitions for sources compiled with `declarationMap` go to + original source + + +# v13.1.0 + +This release upgrades `@angular/language-service` to v13.1.0. + +* fix: Correctly parse inputs and selectors with dollar signs (#44268) + +# v13.0.0 + +This release upgrades `@angular/language-service` to v13.0.0. +For a complete change log see +[here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1300-2021-11-03). + +1. feat: provide snippets for attribute (#1509) (0428c31fa) +1. feat: Add support for going to template from component (#1491) (3014713e1) +1. feat(server): add related information to diagnostics (#1492) (04b215b09) +1. feat: add config to enable auto-apply optional chaining on nullable symbol (#1469) (4fcbdb74a) + +# v12.2.3 + +This release upgrades `@angular/language-service` to v12.2.12. + +This release contains various internal refactorings and dependency updates. + +# v12.2.2 + +This release upgrades `@angular/language-service` to v12.2.10. + +* support resolving ngcc from APF v13 output (#1523) (f8aa9927c) + +# v12.2.1 + +This release upgrades `@angular/language-service` to v12.2.9. + +This release contains various internal refactorings and dependency updates. + +# v12.2.0 + +This release upgrades `@angular/language-service` to v12.2.0. +For a complete change log see +[here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1220-2021-08-04). + +1. fix(language-service): provide literal completions as well as context completions (https://github.com/angular/angular/pull/42729) + + +# v12.1.4 + +This release upgrades `@angular/language-service` to v12.1.4. +For a complete change log see +[here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1214-2021-07-28). + +1. fix(language-server): rename response should use URI instead of file name (#1462) (49d81aa4a) +1. fix(language-server): Only enable language service on open projects (#1461) (26f6fcf1b) +1. fix: unchanged files sometimes have no Angular information for string… (#1453) (9ca675a3a) + +# v12.1.3 + +This release upgrades `@angular/language-service` to v12.1.3. +For a complete change log see +[here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1213-2021-07-21). + +1. fix(server): Only provide InsertReplaceEdit when the client supports it (#1452) (7c22c4c3a) + +# v12.1.2 + +This release upgrades `@angular/language-service` to v12.1.2. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1212-2021-07-14). + +1. fix(language-server): Ensure LS is enabled in same order as project initialization for solution-style projects (#1447) (68ee8344e) +1. fix(compiler-cli): return directives for an element on a microsyntax template (https://github.com/angular/angular/pull/42640) + +# v12.1.1 + +This release upgrades `@angular/language-service` to v12.1.1. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1211-2021-06-30). + +* update to TS 4.3.4 (#1428) (fb6681ee6) + +# v12.1.0 + + +This release upgrades `@angular/language-service` to v12.1.0. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1210-2021-06-24). + +Features: +1. feat: Allow renaming from string literals in TS files (#1337) (9dba839b3) + +# v12.0.5 + +Bug fixes: + +1. fix(completions): fix completions for inputs / outputs (#1405) (d602cf933) +2. fix(language-service): fix autocomplete info display for attributes (https://github.com/angular/angular/pull/42472) + + +# v12.0.4 + +This release upgrades `@angular/language-service` to v12.0.3. + +Bug fixes: +1. compiler-cli: better detect classes that are indirectly exported (#42207) + +# v12.0.3 +This release upgrades `@angular/language-service` to v12.0.2. + +* fix: support nullish coalesce for syntax highlighting (#1376) (fa8a98678) + +# v12.0.2 + +* fix: only give html provider completions for inline templates (#1369) (98d5c97bb) +* fix: avoid showing MISSING: command for code lens in templates (#1370) (fa5212faf) +* perf: Avoid making Angular-related decisions for files not in an Angular project (#1360) (f83b02eb0) +* fix: remove angular.ngdk configuration (#1361) (797140c2b) +* fix: remove message about disabled LS if ngcc fails (#1359) (0fdc5fb20) + +# v12.0.1 + +This release fixes a bug where View Engine is not launched for older projects +even though the Angular version is resolved correctly. +This is because the configuration value is typed as `boolean`, and defaults to +`false` even when the value is not set. (d6cb5cb5ad) + + +# v12.0.0 + +This release upgrades `@angular/language-service` to v12.0.0. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1200-2021-05-12). + +New features: +1. add support for signature help (#1277) (ec148073f) +1. forward completion and hover requests to html providers for inline templates (72ee5c71c) +1. Allow users to hide strictTemplates prompt (bd612107a) +1. Add codelens with a link to go to the component from a template (76e234281) +1. add command to go to component(s) from external template (d1ca20a14) +1. update typescript to v4.2.3 (730ce54bf) + +Bug fixes: +1. fix: files incorrectly determined as not being in an Angular project (#1331) (43bcbb732) +1. remove TSC_NONPOLLING_WATCHER env variable and provide default watchOptions (#1323) (6eb2984cb) +1. Use View Engine LS for projects < v9 (7ff10b898) +1. Use View Engine LS for projects < v9 (2585e0310) +1. set minimum TS version to 4.2 (ea3a73900) +1. pass watch options to watchFile and watchDirectory (bae335dc4) +1. make Ivy LS the default (c23612f9b) +1. do not resolve CodeLens command until LS is enabled (#1260) (93b47487a) +1. dispose reporters and notification handlers when client is stopped (aa8ac6eb9) +1. only restart language server on angular configuration change (fb5f89590) +1. do not minify the client code (1068ef40a) +1. logger should print one timestamp for an entire group (f3930c1dc) +1. do not load plugins except @angular/language-service (0901addfd) +1. turn off logging by default (f5925ff26) +1. do not watch directories in google3 (6a8a2d9b2) +1. force enable Ivy and strictTemplates in google3 (9182c4cc5) +1. use single entry point for @angular/language-service (93c541f2e) +1. detect @angular/core in google3 and don't run ngcc (ea1a7de77) +1. retain typecheck files after project reload (bc9d9fc78) +1. do not pass execArgv to ngcc process (460ef30f2) +1. show Go to component in HTML files only (d4e70c641) +1. attempt to resolve tsdk using fs path (7a8cb6084) +1. Revert back to boolean type for experimental-ivy flag (c1daa2cc0) +1. remove TSC_NONPOLLING_WATCHER env variable (17708d44c) +1. ensure project language service is the Angular LS (dfedf3cbb) +1. unable to load ivy native plugin (b08b295b2) + +Performance improvements: +1. Avoid making Angular-related decisions for files not in an Angular project (#1259) (d8666d835) +1. check diagnostics in most recently used order (dcd32294a) +1. Compute diagnostics for a single file if it is external template (237d3f6df) +1. prevent requests from being sent to the sesrver when outside Angular context (5c3eda19d) +1. yield after checking diagnostics for an open file (d4ab1a21e) +1. Support request cancellation (af0b5a46c) + +# v11.2.14 + +Bug fixes: +1. files incorrectly determined as not being in an Angular project (#1331) (d26daaaa5) +2. remove TSC_NONPOLLING_WATCHER env variable and provide default watchOptions (#1323) (#1326) (bbd0c60fa) + +# v11.2.13 +This release upgrades `@angular/language-service` to v11.2.12. + +Bug fixes: +1. High CPU usage when idle due to file watching (#1317) (06f1add66) + +# v11.2.12 +This release upgrades `@angular/language-service` to v11.2.11. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#11211-2021-04-21). + +Bug fixes: +1. compiler-cli: autocomplete literal types in templates (296f887) + + +# v11.2.11 + +This release upgrades `@angular/language-service` to v11.2.10. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#11210-2021-04-14). + +Bug fixes: +1. language-service: bound attributes should not break directive matching (#41597) (3dbcc7f) +1. language-service: resolve to the pre-compiled style when compiled css url is provided (#41538) (3d54980) +1. language-service: use 'any' instead of failing for inline TCBs (#41513) (f76873e) + +Performance improvements: +1. Avoid making Angular-related decisions for files not in an Angular project +(#1259) (154cf5efa) + +# v11.2.10 + +This release upgrades `@angular/language-service` to v11.2.9. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1129-2021-04-07). + +Bug fixes: +1. Allow analysis to continue with invalid style url (#41403) (#41489) (07131fa) +1. Dispose reporters and notification handlers when client is stopped (ef5297de7) +1. Only restart language server on angular configuration change (ba99ed814) + +Performance improvements: +1. Add perf tracing to LanguageService (#41401) (7b0a800) + +# v11.2.9 +This release upgrades `@angular/language-service` to v11.2.7. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1127-2021-03-24). + +bug fixes in `@angular/language-service`: +* **compiler-cli:** add `useInlining` option to type check config ([#41268](https://github.com/angular/angular/issues/41268)) ([57644e9](https://github.com/angular/angular/commit/57644e95aadbfe9c8f336be77a22f7a5e1859758)), closes [#40963](https://github.com/angular/angular/issues/40963) +* **language-service:** show suggestion when type inference is suboptimal ([#41072](https://github.com/angular/angular/issues/41072)) ([18cd7a0](https://github.com/angular/angular/commit/18cd7a0c6921983556fe1fffbff93d42ae138007)), closes [angular/vscode-ng-language-service#1155](https://github.com/angular/vscode-ng-language-service/issues/1155) [#41042](https://github.com/angular/angular/issues/41042) + +# v11.2.8 + +- perf: prevent requests from being sent to the server when outside Angular context (fcbdf938e) +- build: Switch to esbuild instead of rollup for the client and banner (27ccba8d0) +- perf: check diagnostics in most recently used order (7f2873f6f56fbaff6c8232389ce64f3e60484a09) +- perf: Compute diagnostics for a single file if it is external template (a2b77fa7680c8328c67f77e3765fc179702405c0) +- fix: logger should print one timestamp for an entire group (4d94f40d4c699916b379c9dab38a9e9e254e6c3e) + +# v11.2.7 + +This release reverts the following commits due to [#1198](https://github.com/angular/vscode-ng-language-service/issues/1198): + +- perf: prevent requests from being sent to the server when outside Angular context (fcbdf938e) +- build: Switch to esbuild instead of rollup for the client and banner (27ccba8d0) + +# v11.2.6 + +This release upgrades `@angular/language-service` to v11.2.5. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1125-2021-03-10). + +This release contains various performance improvements. + +# v11.2.5 + +This release contains a few performance improvements. + +Bug fixes: +- do not load plugins except @angular/language-service +- turn off logging by default +- do not watch directories in google3 + +# v11.2.4 + +This release upgrades `@angular/language-service` to v11.2.4. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1124-2021-03-03). + +Bug fixes in `@angular/language-service`: +- Add plugin option to force strictTemplates (#41063) (95f748c) +- Always attempt HTML AST to template AST conversion for LS (#41068) (6dd5497), closes angular/vscode-ng-language-service#1140 +- can't provide the Input and Output custom binding property name (#41005) (1b1b65e) +- don't show external template diagnostics in ts files (#41070) (9322e6a), closes #41032 +- only provide template results on reference requests (#41041) (ef87953) +- provide element completions after open tag < (#41068) (f09e7ab), closes angular/vscode-ng-language-service#1140 + +Bug fixes in `@angular/language-server`: +- force enable Ivy and strictTemplates in google3 +- detect @angular/core in google3 and don't run ngcc +- retain typecheck files after project reload +- do not pass execArgv to ngcc process +- attempt to resolve tsdk using fs path +- Revert back to boolean type for experimental-ivy flag +- remove TSC_NONPOLLING_WATCHER env variable +- ensure project language service is the Angular LS + +# v11.2.3 + +This release upgrades `@angular/language-service` to v11.2.2. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1110-2021-01-20). + +Performance improvements: +- The Ivy Language Service no longer slows down the operation of plain TS language service features when editing TS code outside of a template. + +# v11.2.2 + +This release upgrades `@angular/language-service` to v11.2.1. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1200-next1-2021-02-17). + +# v11.2.1 + +This release fixes a bug in the initialization of tsserver plugin that prevented +the Ivy-native language service from being loaded correctly. +See https://github.com/angular/vscode-ng-language-service/issues/1109 + +# v11.2.0 + +This release upgrades `@angular/language-service` to v11.2.0. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1120-2021-02-10). + +Bug fixes: +- disable rename feature when strictTemplates is disabled +- implement realpath to resolve symlinks +- recognize incomplete pipe bindings with whitespace + +Features: +- Prompt to use the Ivy Language Service if VE is detected +- Add Command to view template typecheck block +- Add diagnostics to suggest turning on strict mode + +# v11.1.3 + +This release upgrades `@angular/language-service` to v11.1.2. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1112-2021-02-03). + +# v11.1.2 + +No major updates in this release. + +# v11.1.1 + +This release upgrades `@angular/language-service` to v11.1.1. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1111-2021-01-27). + +# v11.1.0 + +Ivy-native language service is officially available for preview! +To try it, go to Preferences > Settings > Angular > check experimental-ivy. + +This release upgrades `@angular/language-service` to v11.1.0. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1110-2021-01-20). + +# 0.1101.0-rc.1 + +Bug fixes: +- update min TS and NG versions +- ngserver script could not find index.js + +# v0.1101.0-rc.0 + +This release upgrades `@angular/language-service` to v11.1.0-rc.0. + +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1110-rc0-2021-01-13). + +Bug fixes: +- prevent project from closing when only a template file is open + +Features: +- enable tracing of LSP messages and payload + +# v0.1101.0-next.2 + +This release upgrades `@angular/language-service` to v11.1.0-next.4. + +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1110-next4-2021-01-06). + +# v0.1101.0-next.1 + +This release upgrades `@angular/language-service` to v11.1.0-next.3. + +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1110-next3-2020-12-16). + +# v0.1101.0-next.0 + +This release upgrades `@angular/language-service` to v11.1.0-next.2. + +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1110-next2-2020-12-09). + +Bug fixes: +- `require.resolve` not working in vscode, resulting in ngcc failure. +- Restart language server on configuration change. + +# v0.1100.0 + +This release upgrades `@angular/language-service` to v11.0.0. + +For a complete change log see [here](https://github.com/angular/angular/blob/11.0.x/CHANGELOG.md#1100-2020-11-11). + +Bug fixes: +- LS not showing existing diagnotics on file open (#966) + +# v0.1100.0-rc.1 + +This release upgrades `@angular/language-service` to v11.0.0-rc.3. + +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1100-rc3-2020-11-09). + +# v0.1100.0-rc.0 + +This release upgrades `@angular/language-service` to v11.0.0-rc.1. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1100-rc1-2020-10-28). + +# v0.1000.8 + +This release upgrades `@angular/language-service` to v10.0.14. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#10014-2020-08-26). + +# v0.1000.7 + +This release upgrades `@angular/language-service` to v10.0.7. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1007-2020-07-30). + +This release fixes a bug caused by the upgrade of bundle format from ES5 to +ES2015. + +Bug fixes: +- Metadata should not include methods on Object.prototype (#38292) (879ff08) + +# v0.1000.6 + +This release upgrades `@angular/language-service` to v10.0.6. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1006-2020-07-28). + +# v0.1000.5 + +This release upgrades `@angular/language-service` to v10.0.5. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1005-2020-07-22). + +The `.umd` suffix has been removed from the bundle filename. + +# v0.1000.4 + +This release upgrades `@angular/language-service` to v10.0.4. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1004-2020-07-15). + +Features: +- Upgrade bundle format to ES2015. + +Bug fixes: +- Remove completion for string (#37983) (387e838) + +# v0.1000.3 + +This release upgrades `@angular/language-service` to v10.0.3. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1003-2020-07-08). + +Bug fixes: +- Do not match inline template grammars inside a template itself (#839) + +# v0.1000.2 + +This release upgrades `@angular/language-service` to v10.0.2. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1002-2020-06-30). + +Bug fixes: +- incorrect autocomplete results on unknown symbol (#37518) (7c0b25f) + +# v0.1000.1 + +This release upgrades `@angular/language-service` to v10.0.1. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1001-2020-06-26). + +This release fixes support for ["solution-style"](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-9.html#support-for-solution-style-tsconfigjson-files) tsconfig. + +Bug fixes: +- reinstate getExternalFiles() (#37750) (ad6680f) + +# v0.1000.0 + +This release upgrades `@angular/language-service` to v10.0.0 and `typescript` to v3.9.5. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1000-2020-06-24). + +Known issues: +- This release does not yet support ["solution-style"](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-9.html#support-for-solution-style-tsconfigjson-files) tsconfig. +It is expected to be fixed in `v0.1000.1` release. Please follow [#824](https://github.com/angular/vscode-ng-language-service/issues/824) for updates. + +Bug fixes: +- Improve signature selection by finding exact match (#37494) (e97a2d4) +- Recover from error in analyzing NgModules (#37108) (2c1f35e) +- Do not invalidate `@angular/core` module (#36783) (dd049ca) +- infer type of elements of array-like objects (#36312) (fe2b692), closes #36191 +- properly evaluate types in comparable expressions (#36529) (8be0972) +- use empty statement as parent of type node (#36989) (a32cbed) +- use the HtmlAst to get the span of HTML tag (#36371) (81195a2) +- wrong completions in conditional operator (#37505) (32020f9) + +Deprecations: +- Remove HTML entities autocompletion (#37515) (67bd88b) + +# v0.1000.0-rc.1 + +This release upgrades `@angular/language-service` to v10.0.0-rc.2. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1000-rc2-2020-06-01). + +# v0.1000.0-rc.0 + +This release upgrades `@angular/language-service` to v10.0.0-rc.0. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#1000-rc0-2020-05-21). + +# v0.901.9 + +This release upgrades `@angular/language-service` to v9.1.9. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#919-2020-05-20). + +# v0.901.8 + +This release upgrades `@angular/language-service` to v9.1.8. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#918-2020-05-20). + +# v0.901.7 + +This release upgrades `@angular/language-service` to v9.1.7. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#917-2020-05-13). + +# v0.901.6 + +This release upgrades `@angular/language-service` to v9.1.6. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#916-2020-05-08). + +# v0.901.5 + +This release upgrades `@angular/language-service` to v9.1.5. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#915-2020-05-07). + +# v0.901.4 + +This release upgrades `@angular/language-service` to v9.1.4. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#914-2020-04-29). + +Bug fixes: +- do not invalidate `@angular/core` module (#36783) (d3a77ea) + +# v0.901.3 + +This release upgrades `@angular/language-service` to v9.1.3. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#913-2020-04-22). + +Bug fixes: +- properly evaluate types in comparable expressions (#36529) (5bab498) + +# v0.901.2 + +This release upgrades `@angular/language-service` to v9.1.2. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#912-2020-04-15). + +# v0.901.1 + +This release upgrades `@angular/language-service` to v9.1.1. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#911-2020-04-07). + +Bug fixes: +- infer type of elements of array-like objects (#36312) (ff523c9), closes #36191 +- use the HtmlAst to get the span of HTML tag (#36371) (ffa4e11) +- log message when language service is enabled for a project + +# v0.901.0 + +This release upgrades `@angular/language-service` to v9.1.0. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#910-2020-03-25). + +New features: +- improve non-callable error message (#35271) (acc483e) +- modularize error messages (#35678) (47a1811), closes #32663 + +Bug fixes: +- Catch failure to open script when language service is disabled (#699) +- Suggest ? and ! operator on nullable receiver (#35200) (3cc24a9) +- fix calculation of pipe spans (#35986) (406419b) +- get the right 'ElementAst' in the nested HTML tag (#35317) (8e354da) +- infer $implicit value for ngIf template contexts (#35941) (18b1bd4) +- infer context type of structural directives (#35537) (#35561) (54fd33f) +- provide completions for the structural directive that only injects the 'ViewContainerRef' (#35466) (66c06eb) +- provide hover for interpolation in attribute value (#35494) (049f118), closes PR#34847 +- resolve the real path for symlink (#35895) (4e1d780) +- resolve the variable from the template context first (#35982) (3d46a45) + +# v0.900.18 + +This release upgrades `@angular/language-service` to v9.0.7. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#907-2020-03-18). + +Bug fixes: +- infer $implicit value for ngIf template contexts (#35941) (f5e4410) + +# v0.900.17 + +This release upgrades `@angular/language-service` to v9.0.6. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#906-2020-03-10). + +Bug fixes: +- resolve the variable from the template context first (#35982) (f882ff0) +- improve missing core.d.ts error message + +# v0.900.16 + +This release upgrades `@angular/language-service` to v9.0.5. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#905-2020-03-04). + +New features: +- modularize error messages (#35678) (bcff873) + +Bug fixes: +- apply Angular template grammar syntax only to HTML derivative files + +# v0.900.15 + +This release upgrades `@angular/language-service` to v9.0.4. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#904-2020-02-27). + +Bug fixes: +- get the right 'ElementAst' in the nested HTML tag (#35317) (7403ba1) +- infer context type of structural directives (#35537) (#35561) (a491f7e) +- provide hover for interpolation in attribute value (#35494) (0700279) + +# v0.900.14 + +This release introduces TextMate grammar for Angular template expressions. +Special thanks to @ghaschel, @ayazhafiz, and @dannymcgee. + +# v0.900.13 + +This release upgrades `@angular/language-service` to v9.0.2. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#902-2020-02-19). + +New features: +- Trigger autocomplete on pipe + +Bug fixes: +- Editor buffer out of sync with file on disk + +# v0.900.12 + +This release upgrades `@angular/language-service` to v9.0.1. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#901-2020-02-12). + +Bug fixes: +- Suggest ? and ! operator on nullable receiver (#35200) (3cc24a9) + +# v0.900.11 + +This release upgrades `@angular/language-service` to v9.0.0. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#900-2020-02-06). + +# v0.900.10 + +This release upgrades `@angular/language-service` to v9.0.0-rc.14. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#900-rc14-2020-02-03). + +# v0.900.9 + +This release upgrades `@angular/language-service` to v9.0.0-rc.13. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#900-rc13-2020-02-01). + +Bug fixes: +- more accurate and specific binding scopes (#598) +- check that a language service exists for discovered projects (#562) + +# v0.900.8 + +This release upgrades `@angular/language-service` to v9.0.0-rc.12. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#900-rc12-2020-01-30). + +New features: +- completions for output $event properties in (#34570) (2a53727) +- provide completion for $event variable (#34570) (c246787) +- provide hover for microsyntax in structural directive (#34847) (baf4a63) + +Bug fixes: +- prune duplicate returned definitions (#34995) (71f5417) +- remove repeated symbol definitions for structural directive (#34847) (35916d3) +- warn, not error, on missing context members (#35036) (0e76821) +- enable debug mode only when it is strictly turned on + +# v0.900.7 + +This release upgrades `@angular/language-service` to v9.0.0-rc.11. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#900-rc11-2020-01-24). + +New features: +- Specific suggestions for template context diags (#34751) (cc7fca4) +- Support multiple symbol definitions (#34782) (2f2396c) + +Bug fixes: +- Diagnostic span should point to class name (#34932) (c9db7bd) + +# v0.900.6 + +This release upgrades `@angular/language-service` to v9.0.0-rc.10. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#900-rc10-2020-01-22). + +It also upgrades `vscode-languageclient` and `vscode-languageserver` to major +version 6. + +New features: +- Completions support for template reference variables +- Provide completion for $event variable +- Support hover/definitions for structural directive +- Add grammar for template bindings + +# v0.900.5 + +This release upgrades `@angular/language-service` to v9.0.0-rc.9. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#900-rc9-2020-01-15). + +It also upgrades `typescript` to v3.7.4. + +New features: +- Support hover/definitions for structural directive +- More detailed grammar scopes for template property binding syntax +- Textmate grammar for template event bindings +- Reenable probing language service and tsserver from active workspace +- Priortize workspace version when resolving ts and ng +- Add grammar for two-way bindings +- Trigger autocomplete on '$' character +- Upgrade `vscode-jsonrpc` to major version v5 + +Bug fixes: +- Language service works with HTML without TS files open +- Fix CRLF offset in inline template +- Do not use an i18n parser for templates +- Require min typescript v3.7 + +# v0.900.4 + +This release upgrades `@angular/language-service` to v9.0.0-rc.8. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#900-rc8-2020-01-08). + +New features: +- Append symbol type to hover tooltip (#34515) (381b895) +- Show documentation on hover (#34506) (1660095) +- Add textmate grammar for template property bindings + +Bug fixes: +- completions after "let x of |" in ngFor (#34473) (ca8b584) +- correctly parse expressions in an attribute (#34517) (7a0d6e7) +- pipe method should not include parentheses (#34485) (2845596) +- whitelist all html elements + +# v0.900.3 + +This release upgrades `@angular/language-service` to v9.0.0-rc.7. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#900-rc7-2019-12-18). + +New features: +- add textmate grammar for inline CSS styles +- add syntax highlighting grammar for interpolations + +Bug fixes: +- reset loading status when the language service fails to load the project +- correctly specify embedded languages in an Angular template +- HTML path should include last node before cursor +- Proper completions for properties and events + +# v0.900.2 + +This release upgrades `@angular/language-service` to v9.0.0-rc.6. +For a complete change log see [here](https://github.com/angular/angular/blob/main/CHANGELOG.md#900-rc6-2019-12-11). + +Bug fixes: +- Fixed accessing a string index signature using dot notation +- Remove `getExternalFiles()` +- Fixed JS primitive type name +- Simplify resolution logic in banner + +# v0.900.1 + +Bug fixes: +- Fixed crash when extension is loaded in VSCode Insiders +- Fixed error message `No metadata found for component` +- Fixed indexed type errors in template +- Fixed error message `Unknown method "bind"` +- Fixed type of exported values in `ngFor` +- Fixed error message `Component is not included in a module` + +New features: +- Syntax highlighting for inline templates +- Method completions now include parentheses at the end + +# v0.900.0 +This release is a substantial overhaul of the Angular language service that brings +significant performance improvements. + +New features: +- Added "go to definition" for `templateUrl` and `styleUrls`. +- Hover tooltip now shows the `NgModule` a directive is declared in. +- Added `angular.ngdk` config for specifying location of `@angular/language-service`. +- Added vscode command to restart the extension. +- Display loading indicator while project is loading. diff --git a/vscode-ng-language-service/DEVELOPER.md b/vscode-ng-language-service/DEVELOPER.md new file mode 100644 index 00000000000..5548ab0a98a --- /dev/null +++ b/vscode-ng-language-service/DEVELOPER.md @@ -0,0 +1,79 @@ +# Monorepo setup + +This repository is a monorepo. All build outputs are created in the `bazel-bin` directory. + +The `dependencies` in root [`package.json`](package.json) must include all production dependencies +of the client **and** and the server. + +The dependencies of the `server` need to be duplicated in the root [`package.json`](package.json). +Therefore, if a new prod dependency is added to the server, it needs to be +added to both [`package.json`](package.json) and [`server/package.json`](server/package.json). + +## Navigating Projects in IDE + +This repository contains multiple TypeScript projects, each with its own `tsconfig.json`. +TypeScript's [project references](https://www.typescriptlang.org/docs/handbook/project-references.html) are used to handle the builds. +As a result, some projects depend on the `.d.ts` output of their dependencies, like `client` +and `server` depend on `common`. In order to navigate the projects in your IDE, +you need to first build them by running +```shell +pnpm compile +``` + +If you'd like to force a clean build, you can delete the existing build artifacts +by running +```shell +pnpm bazel build //:npm --config=release +``` + +## Formatting source code + +This repository uses a common toolset provided in the angular organization for formatting, `ng-dev`. It is installed as a standard npm package, +and can be run locally with `pnpm format`. + +## Test Local Changes in VSCode + +Any changes made to the code in this repository or the upstream +`@angular/language-service` package can be immediately tested out in a +development version of VSCode. The instructions below explain how to bring up +a local instance and then install a local version of `@angular/language-service`. + +### Check TypeScript version + +First, make sure that the TypeScript version in `@angular/angular` is the same +as that used in this repository. If not, update the following files: + +1. `typescript` dependency in [`package.json`](package.json) +2. `MIN_TS_VERSION` in [`version_provider.ts`](server/src/version_provider.ts) + +### Launch VSCode in Extension Development Host + +The scripts in `.vscode` directory are setup to automatically compile the code, +then launch a new instance of VSCode with the Angular extension installed. +To do so, either + +1. Press F5, or +2. Go to Run on the sidebar, select `Launch Client` from the task list + +After the client is launched, you can optionally choose to attach a debugger to +the local instance. To do so, + +1. Go to Run on the sidebar, select `Attach to Server` from the task list + +As a shortcut, there's also a task setup to automatically launch the client and +attach the debugger in a single step. To do so, + +1. Go to Run on the sidebar, select `Client + Server` from the task list + +Note: Because we are building with bazel, any breakpoints need to be set on the files in `bazel-bin/...` or by adding a `debugger;` statement before compilation. + +### Install Local `@angular/language-service` + +If changes are made to the upstream language service package, they can also be +tested locally. This involves building the NPM package, then updating the server +dependency. To do so, run the following script from the `@angular/angular` +repository. + +```bash +./packages/language-service/build.sh /path/to/vscode-ng-language-service +``` diff --git a/vscode-ng-language-service/README.md b/vscode-ng-language-service/README.md new file mode 100644 index 00000000000..576d5ec09ca --- /dev/null +++ b/vscode-ng-language-service/README.md @@ -0,0 +1,69 @@ +# Angular Language Service + +![demo](https://github.com/angular/vscode-ng-language-service/raw/main/demo.gif) + +## Features + +This extension provides a rich editing experience for Angular templates, both inline +and external templates including: + +* Completions lists +* AOT Diagnostic messages +* Quick info +* Go to definition + +## Download + +Download the extension from [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=Angular.ng-template). + +## Configuring compiler options for the Angular Language Service + +The Angular Language Service uses the same set of options that are used to compile the application. +To get the most complete information in the editor, set the `strictTemplates` option in `tsconfig.json`, +as shown in the following example: + +``` +"angularCompilerOptions": { + "strictTemplates": true +} +``` + +For more information, see the [Angular compiler options](https://angular.io/guide/angular-compiler-options) guide. + +## Versioning + +The language service extension relies on the `@angular/language-service` and `typescript` packages +for its backend. `@angular/language-service` is always bundled with the extension, and is always +the latest version at the time of the release. +`typescript` is loaded, in order of priority, from: + +1. The path specified by `typescript.tsdk` in project or global settings. +2. _(Recommended)_ The version of `typescript` bundled with the Angular Language Service extension. +3. The version of `typescript` present in the current workspace's node_modules. + +We suggest **not** specifying `typescript.tsdk` in your VSCode settings +per method (1) above. If the `typescript` package is loaded by +methods (1) or (3), there is a potential for a mismatch between +the API expected by `@angular/language-service` and the API provided by `typescript`. This could +lead to a failure of the language service extension. + +For more information, please see [#594](https://github.com/angular/vscode-ng-language-service/issues/594). + +## Installing a particular release build + +Download the `.vsix` file for the release that you want to install from the [releases](https://github.com/angular/vscode-ng-language-service/releases) tab. + +*Do not open the .vsix file directly*. Instead, in Visual Studio code, go to the extensions tab. Click on the "..." menu in the upper right corner of the extensions tab, select "Install from vsix..." and then select the .vsix file for the release you just downloaded. + +The extension can also be installed with the following command: + +``` +code --install-extension /path/to/ngls.vsix +``` + +## Angular Language Service for Other Editors + +- [coc-angular](https://github.com/iamcco/coc-angular) for ([Neo](https://neovim.io))[vim](https://www.vim.org/) +- [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig/blob/master/doc/configs.md#angularls) for [Neovim](https://neovim.io) +- [Wild Web Developer](https://github.com/eclipse/wildwebdeveloper) for Eclipse +- [lsp-mode](https://github.com/emacs-lsp/lsp-mode) for Emacs diff --git a/vscode-ng-language-service/angular.png b/vscode-ng-language-service/angular.png new file mode 100644 index 0000000000000000000000000000000000000000..388aac6696b3e7283b21202837794245a6823757 GIT binary patch literal 149516 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%0AigAz=p)E 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 + /** A map that indicates whether Angular could be found in the file's project. */ + private readonly fileToIsInAngularProjectMap = new Map(); + + constructor(private readonly context: vscode.ExtensionContext) { + vscode.workspace.registerTextDocumentContentProvider('angular-embedded-content', { + provideTextDocumentContent: (uri) => { + return this.virtualDocumentContents.get(uri.toString()); + }, + }); + + this.outputChannel = vscode.window.createOutputChannel(this.name); + // Options to control the language client + this.clientOptions = { + // Register the server for Angular templates and TypeScript documents + documentSelector: [ + // scheme: 'file' means listen to changes to files on disk only + // other option is 'untitled', for buffer in the editor (like a new doc) + {scheme: 'file', language: 'html'}, + {scheme: 'file', language: 'typescript'}, + ], + synchronize: { + fileEvents: [ + // Notify the server about file changes to tsconfig.json contained in the workspace + vscode.workspace.createFileSystemWatcher('**/tsconfig.json'), + ], + }, + // Don't let our output console pop open + revealOutputChannelOn: lsp.RevealOutputChannelOn.Never, + outputChannel: this.outputChannel, + markdown: { + isTrusted: true, + }, + middleware: { + provideCodeActions: async ( + document: vscode.TextDocument, + range: vscode.Range, + context: vscode.CodeActionContext, + token: vscode.CancellationToken, + next: lsp.ProvideCodeActionsSignature, + ) => { + // Code actions can trigger also outside of `@Component(<...>)` fields. + if (await this.isInAngularProject(document)) { + return next(document, range, context, token); + } + }, + prepareRename: async ( + document: vscode.TextDocument, + position: vscode.Position, + token: vscode.CancellationToken, + next: lsp.PrepareRenameSignature, + ) => { + // We are able to provide renames for many types of string literals: template strings, + // pipe names, and hopefully in the future selectors and input/output aliases. Because + // TypeScript isn't able to provide renames for these, we can more or less + // guarantee that the Angular Language service will be called for the rename as the + // fallback. We specifically do not provide renames outside of string literals + // because we cannot ensure our extension is prioritized for renames in TS files (see + // https://github.com/microsoft/vscode/issues/115354) we disable renaming completely so we + // can provide consistent expectations. + if ( + (await this.isInAngularProject(document)) && + isInsideStringLiteral(document, position) + ) { + return next(document, position, token); + } + }, + provideDefinition: async ( + document: vscode.TextDocument, + position: vscode.Position, + token: vscode.CancellationToken, + next: lsp.ProvideDefinitionSignature, + ) => { + if ( + (await this.isInAngularProject(document)) && + isNotTypescriptOrSupportedDecoratorField(document, position) + ) { + return next(document, position, token); + } + }, + provideTypeDefinition: async ( + document: vscode.TextDocument, + position: vscode.Position, + token: vscode.CancellationToken, + next, + ) => { + if ( + (await this.isInAngularProject(document)) && + isNotTypescriptOrSupportedDecoratorField(document, position) + ) { + return next(document, position, token); + } + }, + provideHover: async ( + document: vscode.TextDocument, + position: vscode.Position, + token: vscode.CancellationToken, + next: lsp.ProvideHoverSignature, + ) => { + if ( + !(await this.isInAngularProject(document)) || + !isNotTypescriptOrSupportedDecoratorField(document, position) + ) { + return; + } + + const angularResultsPromise = next(document, position, token); + + // Include results for inline HTML via virtual document and native html providers. + if (document.languageId === 'typescript') { + const vdocUri = this.createVirtualHtmlDoc(document); + const htmlProviderResultsPromise = vscode.commands.executeCommand( + 'vscode.executeHoverProvider', + vdocUri, + position, + ); + + const [angularResults, htmlProviderResults] = await Promise.all([ + angularResultsPromise, + htmlProviderResultsPromise, + ]); + return angularResults ?? htmlProviderResults?.[0]; + } + + return angularResultsPromise; + }, + provideSignatureHelp: async ( + document: vscode.TextDocument, + position: vscode.Position, + context: vscode.SignatureHelpContext, + token: vscode.CancellationToken, + next: lsp.ProvideSignatureHelpSignature, + ) => { + if ( + (await this.isInAngularProject(document)) && + isNotTypescriptOrSupportedDecoratorField(document, position) + ) { + return next(document, position, context, token); + } + }, + provideCompletionItem: async ( + document: vscode.TextDocument, + position: vscode.Position, + context: vscode.CompletionContext, + token: vscode.CancellationToken, + next: lsp.ProvideCompletionItemsSignature, + ) => { + // If not in inline template, do not perform request forwarding + if ( + !(await this.isInAngularProject(document)) || + !isNotTypescriptOrSupportedDecoratorField(document, position) + ) { + return; + } + const angularCompletionsPromise = next(document, position, context, token) as Promise< + vscode.CompletionItem[] | null | undefined + >; + + // Include results for inline HTML via virtual document and native html providers. + if (document.languageId === 'typescript') { + const vdocUri = this.createVirtualHtmlDoc(document); + // This will not include angular stuff because the vdoc is not associated with an + // angular component + const htmlProviderCompletionsPromise = + vscode.commands.executeCommand( + 'vscode.executeCompletionItemProvider', + vdocUri, + position, + context.triggerCharacter, + ); + const [angularCompletions, htmlProviderCompletions] = await Promise.all([ + angularCompletionsPromise, + htmlProviderCompletionsPromise, + ]); + return [...(angularCompletions ?? []), ...(htmlProviderCompletions?.items ?? [])]; + } + + return angularCompletionsPromise; + }, + provideFoldingRanges: async ( + document: vscode.TextDocument, + context: vscode.FoldingContext, + token: vscode.CancellationToken, + next, + ) => { + if (!(await this.isInAngularProject(document))) { + return null; + } + return next(document, context, token); + }, + }, + }; + } + + async applyWorkspaceEdits(workspaceEdits: lsp.WorkspaceEdit[]) { + for (const edit of workspaceEdits) { + const workspaceEdit = this.client?.protocol2CodeConverter.asWorkspaceEdit(edit); + if (workspaceEdit === undefined) { + continue; + } + await vscode.workspace.applyEdit(workspaceEdit); + } + } + + private async isInAngularProject(doc: vscode.TextDocument): Promise { + if (this.client === null) { + return false; + } + const uri = doc.uri.toString(); + if (this.fileToIsInAngularProjectMap.has(uri)) { + return this.fileToIsInAngularProjectMap.get(uri)!; + } + + try { + const response = await this.client.sendRequest(IsInAngularProject, { + textDocument: this.client.code2ProtocolConverter.asTextDocumentIdentifier(doc), + }); + if (response == null) { + // If the response indicates the answer can't be determined at the moment, return `false` + // but do not cache the result so we can try to get the real answer on follow-up requests. + return false; + } + this.fileToIsInAngularProjectMap.set(uri, response); + return response; + } catch { + return false; + } + } + + private createVirtualHtmlDoc(document: vscode.TextDocument): vscode.Uri { + const originalUri = document.uri.toString(); + const vdocUri = vscode.Uri.file(encodeURIComponent(originalUri) + '.html').with({ + scheme: 'angular-embedded-content', + authority: 'html', + }); + this.virtualDocumentContents.set(vdocUri.toString(), document.getText()); + return vdocUri; + } + + /** + * Spin up the language server in a separate process and establish a connection. + */ + async start(): Promise { + if (this.client !== null) { + throw new Error(`An existing client is running. Call stop() first.`); + } + + // Node module for the language server + const args = await this.constructArgs(); + const prodBundle = this.context.asAbsolutePath('server'); + const devBundle = this.context.asAbsolutePath( + path.join('bazel-bin', 'server', 'src', 'server.js'), + ); + + // If the extension is launched in debug mode then the debug server options are used + // Otherwise the run options are used + const serverOptions: lsp.ServerOptions = { + run: { + module: this.context.asAbsolutePath('server'), + transport: lsp.TransportKind.ipc, + args, + }, + debug: { + // VS Code Insider launches extensions in debug mode by default but users + // install prod bundle so we have to check whether dev bundle exists. + module: fs.existsSync(devBundle) ? devBundle : prodBundle, + transport: lsp.TransportKind.ipc, + options: { + // Argv options for Node.js + execArgv: [ + // do not lazily evaluate the code so all breakpoints are respected + '--nolazy', + // If debugging port is changed, update .vscode/launch.json as well + '--inspect=6009', + ], + env: { + NG_DEBUG: true, + }, + }, + args, + }, + }; + + if (!extensionVersionCompatibleWithAllProjects(serverOptions.run.module)) { + vscode.window.showWarningMessage( + `A project in the workspace is using a newer version of Angular than the language service extension. ` + + `This may cause the extension to show incorrect diagnostics.`, + ); + } + + // Create the language client and start the client. + const forceDebug = process.env['NG_DEBUG'] === 'true'; + this.client = new lsp.LanguageClient( + // This is the ID for Angular-specific configurations, like "angular.log". + // See contributes.configuration in package.json. + 'angular', + this.name, + serverOptions, + this.clientOptions, + forceDebug, + ); + this.disposables.push(this.client.start()); + await this.client.onReady(); + // Must wait for the client to be ready before registering notification + // handlers. + this.disposables.push(registerNotificationHandlers(this.client)); + } + + /** + * Construct the arguments that's used to spawn the server process. + * @param ctx vscode extension context + */ + private async constructArgs(): Promise { + const config = vscode.workspace.getConfiguration(); + const args: string[] = ['--logToConsole']; + + const ngLog: string = config.get('angular.log', 'off'); + if (ngLog !== 'off') { + // Log file does not yet exist on disk. It is up to the server to create the file. + const logFile = path.join(this.context.logUri.fsPath, 'nglangsvc.log'); + args.push('--logFile', logFile); + args.push('--logVerbosity', ngLog); + } + + const ngProbeLocations = getProbeLocations(this.context.extensionPath); + args.push('--ngProbeLocations', ngProbeLocations.join(',')); + + const includeAutomaticOptionalChainCompletions = config.get( + 'angular.suggest.includeAutomaticOptionalChainCompletions', + ); + if (includeAutomaticOptionalChainCompletions) { + args.push('--includeAutomaticOptionalChainCompletions'); + } + + const includeCompletionsWithSnippetText = config.get( + 'angular.suggest.includeCompletionsWithSnippetText', + ); + if (includeCompletionsWithSnippetText) { + args.push('--includeCompletionsWithSnippetText'); + } + + const includeCompletionsForModuleExports = config.get('angular.suggest.autoImports'); + args.push( + '--includeCompletionsForModuleExports', + includeCompletionsForModuleExports === undefined + ? 'true' + : includeCompletionsForModuleExports.toString(), + ); + + // Sort the versions from oldest to newest. + const angularVersions = (await getAngularVersionsInWorkspace(this.outputChannel)).sort( + (a, b) => (a.version.greaterThanOrEqual(b.version) ? 1 : -1), + ); + + // Only disable block syntax if we find angular/core and every one we find does not support + // block syntax + if (angularVersions.length > 0) { + const disableBlocks = angularVersions.every((v) => v.version.major < 17); + const disableLet = angularVersions.every((v) => { + return v.version.major < 18 || (v.version.major === 18 && v.version.minor < 1); + }); + + if (disableBlocks) { + args.push('--disableBlockSyntax'); + this.outputChannel.appendLine( + `All workspace roots are using versions of Angular that do not support control flow block syntax.` + + ` Block syntax parsing in templates will be disabled.`, + ); + } + + if (disableLet) { + args.push('--disableLetSyntax'); + this.outputChannel.appendLine( + `All workspace roots are using versions of Angular that do not support @let syntax.` + + ` @let syntax parsing in templates will be disabled.`, + ); + } + } + + // Pass the earliest Angular version along to the compiler for maximum compatibility. + if (angularVersions.length > 0) { + args.push('--angularCoreVersion', angularVersions[0].version.toString()); + this.outputChannel.appendLine( + `Using Angular version ${angularVersions[0].version.toString()}.`, + ); + } + + const forceStrictTemplates = config.get('angular.forceStrictTemplates'); + if (forceStrictTemplates) { + args.push('--forceStrictTemplates'); + } + + const suppressAngularDiagnosticCodes = config.get( + 'angular.suppressAngularDiagnosticCodes', + ); + if (suppressAngularDiagnosticCodes) { + args.push('--suppressAngularDiagnosticCodes', suppressAngularDiagnosticCodes); + } + + const tsdk = config.get('typescript.tsdk', ''); + if (tsdk.trim().length > 0) { + args.push('--tsdk', tsdk); + } + const tsProbeLocations = [...getProbeLocations(this.context.extensionPath)]; + args.push('--tsProbeLocations', tsProbeLocations.join(',')); + + return args; + } + + /** + * Kill the language client and perform some clean ups. + */ + async stop(): Promise { + if (this.client === null) { + return; + } + await this.client.stop(); + this.outputChannel.clear(); + this.dispose(); + this.client = null; + this.fileToIsInAngularProjectMap.clear(); + this.virtualDocumentContents.clear(); + } + + /** + * Requests a template typecheck block at the current cursor location in the + * specified editor. + */ + async getTcbUnderCursor(textEditor: vscode.TextEditor): Promise { + if (this.client === null) { + return undefined; + } + const c2pConverter = this.client.code2ProtocolConverter; + // Craft a request by converting vscode params to LSP. The corresponding + // response is in LSP. + const response = await this.client.sendRequest(GetTcbRequest, { + textDocument: c2pConverter.asTextDocumentIdentifier(textEditor.document), + position: c2pConverter.asPosition(textEditor.selection.active), + }); + if (response === null) { + return undefined; + } + const p2cConverter = this.client.protocol2CodeConverter; + // Convert the response from LSP back to vscode. + return { + uri: p2cConverter.asUri(response.uri), + content: response.content, + selections: p2cConverter.asRanges(response.selections), + }; + } + + get initializeResult(): lsp.InitializeResult | undefined { + return this.client?.initializeResult; + } + + async getComponentsForOpenExternalTemplate( + textEditor: vscode.TextEditor, + ): Promise { + if (this.client === null) { + return undefined; + } + + const response = await this.client.sendRequest(GetComponentsWithTemplateFile, { + textDocument: this.client.code2ProtocolConverter.asTextDocumentIdentifier( + textEditor.document, + ), + }); + if (response === undefined) { + return undefined; + } + + const p2cConverter = this.client.protocol2CodeConverter; + return response.map( + (v) => new vscode.Location(p2cConverter.asUri(v.uri), p2cConverter.asRange(v.range)), + ); + } + + async getTemplateLocationForComponent( + textEditor: vscode.TextEditor, + ): Promise { + if (this.client === null) { + return null; + } + const c2pConverter = this.client.code2ProtocolConverter; + // Craft a request by converting vscode params to LSP. The corresponding + // response is in LSP. + const response = await this.client.sendRequest(GetTemplateLocationForComponent, { + textDocument: c2pConverter.asTextDocumentIdentifier(textEditor.document), + position: c2pConverter.asPosition(textEditor.selection.active), + }); + if (response === null) { + return null; + } + const p2cConverter = this.client.protocol2CodeConverter; + return new vscode.Location( + p2cConverter.asUri(response.uri), + p2cConverter.asRange(response.range), + ); + } + + dispose() { + for (let d = this.disposables.pop(); d !== undefined; d = this.disposables.pop()) { + d.dispose(); + } + } +} + +function registerNotificationHandlers(client: lsp.LanguageClient): vscode.Disposable { + const disposables: vscode.Disposable[] = []; + disposables.push( + client.onNotification(ProjectLoadingStart, () => { + vscode.window.withProgress( + { + location: vscode.ProgressLocation.Window, + title: 'Initializing Angular language features', + }, + () => + new Promise((resolve) => { + client.onNotification(ProjectLoadingFinish, resolve); + }), + ); + }), + ); + + disposables.push( + client.onNotification(SuggestStrictMode, async (params: SuggestStrictModeParams) => { + const config = vscode.workspace.getConfiguration(); + if ( + config.get('angular.enable-strict-mode-prompt') === false || + config.get('angular.forceStrictTemplates') + ) { + return; + } + + const openTsConfig = 'Open tsconfig.json'; + // Markdown is not generally supported in `showInformationMessage()`, + // but links are supported. See + // https://github.com/microsoft/vscode/issues/20595#issuecomment-281099832 + const doNotPromptAgain = 'Do not show again for this workspace'; + const selection = await vscode.window.showInformationMessage( + 'Some language features are not available. To access all features, enable ' + + '[strictTemplates](https://angular.io/guide/angular-compiler-options#stricttemplates) in ' + + '[angularCompilerOptions](https://angular.io/guide/angular-compiler-options).', + openTsConfig, + doNotPromptAgain, + ); + if (selection === openTsConfig) { + const document = await vscode.workspace.openTextDocument(params.configFilePath); + vscode.window.showTextDocument(document); + } else if (selection === doNotPromptAgain) { + config.update( + 'angular.enable-strict-mode-prompt', + false, + vscode.ConfigurationTarget.Workspace, + ); + } + }), + ); + + disposables.push( + client.onNotification(OpenOutputChannel, () => { + client.outputChannel.show(); + }), + ); + + return vscode.Disposable.from(...disposables); +} + +/** + * Return the paths for the module that corresponds to the specified `configValue`, + * and use the specified `bundled` as fallback if none is provided. + * @param configName + * @param bundled + */ +function getProbeLocations(bundled: string): string[] { + const locations = []; + // Prioritize the bundled version + locations.push(bundled); + // Look in workspaces currently open + const workspaceFolders = vscode.workspace.workspaceFolders || []; + for (const folder of workspaceFolders) { + locations.push(folder.uri.fsPath); + } + return locations; +} + +function extensionVersionCompatibleWithAllProjects(serverModuleLocation: string): boolean { + const languageServiceVersion = resolve( + '@angular/language-service', + serverModuleLocation, + )?.version; + if (languageServiceVersion === undefined) { + return true; + } + + const workspaceFolders = vscode.workspace.workspaceFolders || []; + for (const workspaceFolder of workspaceFolders) { + const angularCore = resolve('@angular/core', workspaceFolder.uri.fsPath); + if (angularCore === undefined) { + continue; + } + if (!languageServiceVersion.greaterThanOrEqual(angularCore.version, 'minor')) { + return false; + } + } + return true; +} + +/** + * Traverses through the currently open VSCode workspace (i.e. all open folders) + * and finds all `@angular/core` versions installed based on `package.json` files. + */ +async function getAngularVersionsInWorkspace( + outputChannel: vscode.OutputChannel, +): Promise { + const packageJsonFiles = await vscode.workspace.findFiles( + '**/package.json', + // Skip looking inside `node_module` folders as those contain irrelevant files. + '**/node_modules/**', + ); + const packageJsonRoots = packageJsonFiles.map((f) => path.dirname(f.fsPath)); + const angularCoreModules = new Set(); + + outputChannel.appendLine(`package.json roots detected: ${packageJsonRoots.join(',\n ')}`); + + for (const packageJsonRoot of packageJsonRoots) { + const angularCore = resolve('@angular/core', packageJsonRoot); + if (angularCore === undefined) { + continue; + } + angularCoreModules.add(angularCore); + } + return Array.from(angularCoreModules); +} diff --git a/vscode-ng-language-service/client/src/commands.ts b/vscode-ng-language-service/client/src/commands.ts new file mode 100644 index 00000000000..e666ca64761 --- /dev/null +++ b/vscode-ng-language-service/client/src/commands.ts @@ -0,0 +1,239 @@ +/** + * @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 * as vscode from 'vscode'; +import * as lsp from 'vscode-languageclient/node'; + +import { + OpenJsDocLinkCommand_Args, + OpenJsDocLinkCommandId, + ServerOptions, +} from '../../common/initialize'; + +import {AngularLanguageClient} from './client'; +import {ANGULAR_SCHEME, TcbContentProvider} from './providers'; + +/** + * Represent a vscode command with an ID and an impl function `execute`. + */ +type Command = + | { + id: string; + isTextEditorCommand: false; + execute(_: T): Promise; + } + | { + id: string; + isTextEditorCommand: true; + execute(textEditor: vscode.TextEditor): Promise; + }; + +/** + * Restart the language server by killing the process then spanwing a new one. + * @param client language client + * @param context extension context for adding disposables + */ +function restartNgServer(client: AngularLanguageClient): Command { + return { + id: 'angular.restartNgServer', + isTextEditorCommand: false, + async execute() { + await client.stop(); + await client.start(); + }, + }; +} + +/** + * Open the current server log file in a new editor. + */ +function openLogFile(client: AngularLanguageClient): Command { + return { + id: 'angular.openLogFile', + isTextEditorCommand: false, + async execute() { + const serverOptions: ServerOptions | undefined = client.initializeResult?.serverOptions; + if (!serverOptions?.logFile) { + // Show a MessageItem to help users automatically update the + // configuration option then restart the server. + const selection = await vscode.window.showErrorMessage( + `Angular server logging is off. Please set 'angular.log' and restart the server.`, + 'Enable logging and restart server', + ); + if (selection) { + const isGlobalConfig = false; + await vscode.workspace + .getConfiguration() + .update('angular.log', 'verbose', isGlobalConfig); + // Server will automatically restart because the config is changed + } + return; + } + const document = await vscode.workspace.openTextDocument(serverOptions.logFile); + return vscode.window.showTextDocument(document); + }, + }; +} + +/** + * Command getTemplateTcb displays a typecheck block for the template a user has + * an active selection over, if any. + * @param ngClient LSP client for the active session + * @param context extension context to which disposables are pushed + */ +function getTemplateTcb( + ngClient: AngularLanguageClient, + context: vscode.ExtensionContext, +): Command { + const TCB_HIGHLIGHT_DECORATION = vscode.window.createTextEditorDecorationType({ + // See https://code.visualstudio.com/api/references/theme-color#editor-colors + backgroundColor: new vscode.ThemeColor('editor.selectionHighlightBackground'), + }); + + const tcbProvider = new TcbContentProvider(); + const disposable = vscode.workspace.registerTextDocumentContentProvider( + ANGULAR_SCHEME, + tcbProvider, + ); + context.subscriptions.push(disposable); + + return { + id: 'angular.getTemplateTcb', + isTextEditorCommand: true, + async execute(textEditor: vscode.TextEditor) { + tcbProvider.clear(); + const response = await ngClient.getTcbUnderCursor(textEditor); + if (response === undefined) { + return undefined; + } + // Change the scheme of the URI from `file` to `ng` so that the document + // content is requested from our own `TcbContentProvider`. + const tcbUri = response.uri.with({ + scheme: ANGULAR_SCHEME, + }); + tcbProvider.update(tcbUri, response.content); + const editor = await vscode.window.showTextDocument(tcbUri, { + viewColumn: vscode.ViewColumn.Beside, + preserveFocus: true, // cursor remains in the active editor + }); + editor.setDecorations(TCB_HIGHLIGHT_DECORATION, response.selections); + }, + }; +} + +/** + * Command goToComponentWithTemplateFile finds components which reference an external template in + * their `templateUrl`s. + * + * @param ngClient LSP client for the active session + */ +function goToComponentWithTemplateFile(ngClient: AngularLanguageClient): Command { + return { + id: 'angular.goToComponentWithTemplateFile', + isTextEditorCommand: true, + async execute(textEditor: vscode.TextEditor) { + const locations = await ngClient.getComponentsForOpenExternalTemplate(textEditor); + if (locations === undefined) { + return; + } + + vscode.commands.executeCommand( + 'editor.action.goToLocations', + textEditor.document.uri, + textEditor.selection.active, + locations, + 'peek' /** what to do when there are multiple results */, + ); + }, + }; +} + +/** + * Command goToTemplateForComponent finds the template for a component. + * + * @param ngClient LSP client for the active session + */ +function goToTemplateForComponent(ngClient: AngularLanguageClient): Command { + return { + id: 'angular.goToTemplateForComponent', + isTextEditorCommand: true, + async execute(textEditor: vscode.TextEditor) { + const location = await ngClient.getTemplateLocationForComponent(textEditor); + if (location === null) { + return; + } + + vscode.commands.executeCommand( + 'editor.action.goToLocations', + textEditor.document.uri, + textEditor.selection.active, + [location], + 'goto' /** What to do when there are multiple results (there can't be) */, + ); + }, + }; +} + +/** + * Proxy command for opening links in jsdoc comments. + * + * This is needed to avoid incorrectly rewriting uris. + */ +function openJsDocLinkCommand(): Command { + return { + id: OpenJsDocLinkCommandId, + isTextEditorCommand: false, + async execute(args) { + return await vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(args.file), < + vscode.TextDocumentShowOptions + >{ + selection: new vscode.Range( + new vscode.Position(args.position?.start.line ?? 0, args.position?.start.character ?? 0), + new vscode.Position(args.position?.end.line ?? 0, args.position?.end.character ?? 0), + ), + }); + }, + }; +} + +function applyCodeActionCommand(ngClient: AngularLanguageClient): Command { + return { + id: 'angular.applyCompletionCodeAction', + isTextEditorCommand: false, + async execute(args: lsp.WorkspaceEdit[]) { + await ngClient.applyWorkspaceEdits(args); + }, + }; +} + +/** + * Register all supported vscode commands for the Angular extension. + * @param client language client + * @param context extension context for adding disposables + */ +export function registerCommands( + client: AngularLanguageClient, + context: vscode.ExtensionContext, +): void { + const commands: Command[] = [ + restartNgServer(client), + openLogFile(client), + getTemplateTcb(client, context), + goToComponentWithTemplateFile(client), + goToTemplateForComponent(client), + openJsDocLinkCommand(), + applyCodeActionCommand(client), + ]; + + for (const command of commands) { + const disposable = command.isTextEditorCommand + ? vscode.commands.registerTextEditorCommand(command.id, command.execute) + : vscode.commands.registerCommand(command.id, command.execute); + context.subscriptions.push(disposable); + } +} diff --git a/vscode-ng-language-service/client/src/embedded_support.ts b/vscode-ng-language-service/client/src/embedded_support.ts new file mode 100644 index 00000000000..c5ac1514ba9 --- /dev/null +++ b/vscode-ng-language-service/client/src/embedded_support.ts @@ -0,0 +1,147 @@ +/** + * @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 * as ts from 'typescript'; +import * as vscode from 'vscode'; + +const ANGULAR_PROPERTY_ASSIGNMENTS = new Set([ + 'template', + 'templateUrl', + 'styleUrls', + 'styleUrl', + 'host', +]); + +/** + * Determines if the position is inside a decorator + * property that supports language service features. + */ +export function isNotTypescriptOrSupportedDecoratorField( + document: vscode.TextDocument, + position: vscode.Position, +): boolean { + if (document.languageId !== 'typescript') { + return true; + } + return isPropertyAssignmentToStringOrStringInArray( + document.getText(), + document.offsetAt(position), + ANGULAR_PROPERTY_ASSIGNMENTS, + ); +} + +/** + * Determines if the position is inside a string literal. Returns `true` if the document language is + * not TypeScript. + */ +export function isInsideStringLiteral( + document: vscode.TextDocument, + position: vscode.Position, +): boolean { + if (document.languageId !== 'typescript') { + return true; + } + const offset = document.offsetAt(position); + const scanner = ts.createScanner(ts.ScriptTarget.ESNext, true /* skipTrivia */); + scanner.setText(document.getText()); + + let token: ts.SyntaxKind = scanner.scan(); + while (token !== ts.SyntaxKind.EndOfFileToken && scanner.getStartPos() < offset) { + const isStringToken = + token === ts.SyntaxKind.StringLiteral || + token === ts.SyntaxKind.NoSubstitutionTemplateLiteral; + const isCursorInToken = + scanner.getStartPos() <= offset && + scanner.getStartPos() + scanner.getTokenText().length >= offset; + if (isCursorInToken && isStringToken) { + return true; + } + token = scanner.scan(); + } + return false; +} + +/** + * Basic scanner to determine if we're inside a string of a property with one of the given names. + * + * This scanner is not currently robust or perfect but provides us with an accurate answer _most_ of + * the time. + * + * False positives are OK here. Though this will give some false positives for determining if a + * position is within an Angular context, i.e. an object like `{template: ''}` that is not inside an + * `@Component` or `{styleUrls: [someFunction('stringL¦iteral')]}`, the @angular/language-service + * will always give us the correct answer. This helper gives us a quick win for optimizing the + * number of requests we send to the server. + * + * TODO(atscott): tagged templates don't work: #1872 / + * https://github.com/Microsoft/TypeScript/issues/20055 + */ +function isPropertyAssignmentToStringOrStringInArray( + documentText: string, + offset: number, + propertyAssignmentNames: Set, +): boolean { + const scanner = ts.createScanner(ts.ScriptTarget.ESNext, true /* skipTrivia */); + scanner.setText(documentText); + + let token: ts.SyntaxKind = scanner.scan(); + let lastToken: ts.SyntaxKind | undefined; + let lastTokenText: string | undefined; + let unclosedBraces = 0; + let unclosedBrackets = 0; + let propertyAssignmentContext = false; + while (token !== ts.SyntaxKind.EndOfFileToken && scanner.getStartPos() < offset) { + if ( + lastToken === ts.SyntaxKind.Identifier && + lastTokenText !== undefined && + token === ts.SyntaxKind.ColonToken && + propertyAssignmentNames.has(lastTokenText) + ) { + propertyAssignmentContext = true; + token = scanner.scan(); + continue; + } + if (unclosedBraces === 0 && unclosedBrackets === 0 && isPropertyAssignmentTerminator(token)) { + propertyAssignmentContext = false; + } + + if (token === ts.SyntaxKind.OpenBracketToken) { + unclosedBrackets++; + } else if (token === ts.SyntaxKind.OpenBraceToken) { + unclosedBraces++; + } else if (token === ts.SyntaxKind.CloseBracketToken) { + unclosedBrackets--; + } else if (token === ts.SyntaxKind.CloseBraceToken) { + unclosedBraces--; + } + + const isStringToken = + token === ts.SyntaxKind.StringLiteral || + token === ts.SyntaxKind.NoSubstitutionTemplateLiteral; + const isCursorInToken = + scanner.getStartPos() <= offset && + scanner.getStartPos() + scanner.getTokenText().length >= offset; + if (propertyAssignmentContext && isCursorInToken && isStringToken) { + return true; + } + + lastTokenText = scanner.getTokenText(); + lastToken = token; + token = scanner.scan(); + } + + return false; +} + +function isPropertyAssignmentTerminator(token: ts.SyntaxKind) { + return ( + token === ts.SyntaxKind.EndOfFileToken || + token === ts.SyntaxKind.CommaToken || + token === ts.SyntaxKind.SemicolonToken || + token === ts.SyntaxKind.CloseBraceToken + ); +} diff --git a/vscode-ng-language-service/client/src/extension.ts b/vscode-ng-language-service/client/src/extension.ts new file mode 100644 index 00000000000..0688e94c4a5 --- /dev/null +++ b/vscode-ng-language-service/client/src/extension.ts @@ -0,0 +1,34 @@ +/** + * @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 * as vscode from 'vscode'; + +import {AngularLanguageClient} from './client'; +import {registerCommands} from './commands'; + +export function activate(context: vscode.ExtensionContext) { + const client = new AngularLanguageClient(context); + + // Push the disposable to the context's subscriptions so that the + // client can be deactivated on extension deactivation + registerCommands(client, context); + + // Restart the server on configuration change. + const disposable = vscode.workspace.onDidChangeConfiguration( + async (e: vscode.ConfigurationChangeEvent) => { + if (!e.affectsConfiguration('angular')) { + return; + } + await client.stop(); + await client.start(); + }, + ); + context.subscriptions.push(client, disposable); + + client.start(); +} diff --git a/vscode-ng-language-service/client/src/providers.ts b/vscode-ng-language-service/client/src/providers.ts new file mode 100644 index 00000000000..f5953f8ecc2 --- /dev/null +++ b/vscode-ng-language-service/client/src/providers.ts @@ -0,0 +1,64 @@ +/** + * @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 * as vscode from 'vscode'; + +export const ANGULAR_SCHEME = 'ng'; + +/** + * Allocate a provider of documents corresponding to the `ng` URI scheme, + * which we will use to provide a virtual document with the TCB contents. + * + * We use a virtual document provider rather than opening an untitled file to + * ensure the buffer remains readonly (https://github.com/microsoft/vscode/issues/4873). + */ +export class TcbContentProvider implements vscode.TextDocumentContentProvider { + /** + * Event emitter used to notify VSCode of a change to the TCB virtual document, + * prompting it to re-evaluate the document content. This is needed to bust + * VSCode's document cache if someone requests a TCB that was previously opened. + * https://code.visualstudio.com/api/extension-guides/virtual-documents#update-virtual-documents + */ + private readonly onDidChangeEmitter = new vscode.EventEmitter(); + /** + * Name of the typecheck file. + */ + private tcbFile: vscode.Uri | null = null; + /** + * Content of the entire typecheck file. + */ + private tcbContent: string | null = null; + + /** + * This callback is invoked only when user explicitly requests to view or + * update typecheck file. We do not automatically update the typecheck document + * when the source file changes. + */ + readonly onDidChange = this.onDidChangeEmitter.event; + + provideTextDocumentContent( + uri: vscode.Uri, + token: vscode.CancellationToken, + ): vscode.ProviderResult { + if (uri.toString() !== this.tcbFile?.toString()) { + return null; + } + return this.tcbContent; + } + + update(uri: vscode.Uri, content: string) { + this.tcbFile = uri; + this.tcbContent = content; + this.onDidChangeEmitter.fire(uri); + } + + clear() { + this.tcbFile = null; + this.tcbContent = null; + } +} diff --git a/vscode-ng-language-service/client/src/tests/BUILD.bazel b/vscode-ng-language-service/client/src/tests/BUILD.bazel new file mode 100644 index 00000000000..85c87484019 --- /dev/null +++ b/vscode-ng-language-service/client/src/tests/BUILD.bazel @@ -0,0 +1,34 @@ +load("@aspect_rules_jasmine//jasmine:defs.bzl", "jasmine_test") +load("@aspect_rules_ts//ts:defs.bzl", "ts_config", "ts_project") + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//vscode-ng-language-service:tsconfig", + "//vscode-ng-language-service/client:tsconfig", + ], +) + +ts_project( + name = "tests", + srcs = glob(["*.ts"]), + declaration = True, + source_map = True, + tsconfig = ":tsconfig", + deps = [ + "//vscode-ng-language-service:node_modules/@types/jasmine", + "//vscode-ng-language-service:node_modules/@types/vscode", + "//vscode-ng-language-service:node_modules/vscode-languageserver-textdocument", + "//vscode-ng-language-service/client/src", + ], +) + +jasmine_test( + name = "test", + args = ["*_spec.js"], + chdir = package_name(), + data = [":tests"], + node_modules = "//vscode-ng-language-service:node_modules", + tags = ["unit_test"], +) diff --git a/vscode-ng-language-service/client/src/tests/embedded_support_spec.ts b/vscode-ng-language-service/client/src/tests/embedded_support_spec.ts new file mode 100644 index 00000000000..0df2894cc7b --- /dev/null +++ b/vscode-ng-language-service/client/src/tests/embedded_support_spec.ts @@ -0,0 +1,125 @@ +/** + * @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 * as vscode from 'vscode'; +import {DocumentUri, TextDocument} from 'vscode-languageserver-textdocument'; + +import {isNotTypescriptOrSupportedDecoratorField} from '../embedded_support'; + +describe('embedded language support', () => { + describe('isInsideAngularContext', () => { + it('empty file', () => { + test('¦', isNotTypescriptOrSupportedDecoratorField, false); + }); + + it('just after template', () => { + test( + `const foo = {template: '
'¦}`, + isNotTypescriptOrSupportedDecoratorField, + false, + ); + }); + + it('inside template', () => { + test( + `const foo = {template: '
¦
'}`, + isNotTypescriptOrSupportedDecoratorField, + true, + ); + }); + + it('just after templateUrl', () => { + test( + `const foo = {templateUrl: './abc.html'¦}`, + isNotTypescriptOrSupportedDecoratorField, + false, + ); + }); + + it('inside templateUrl', () => { + test( + `const foo = {templateUrl: './abc¦.html'}`, + isNotTypescriptOrSupportedDecoratorField, + true, + ); + }); + + it('just after styleUrls', () => { + test( + `const foo = {styleUrls: ['./abc.css']¦}`, + isNotTypescriptOrSupportedDecoratorField, + false, + ); + }); + + it('inside first item of styleUrls', () => { + test( + `const foo = {styleUrls: ['./abc.c¦ss', 'def.css']}`, + isNotTypescriptOrSupportedDecoratorField, + true, + ); + }); + + it('inside second item of styleUrls', () => { + test( + `const foo = {styleUrls: ['./abc.css', 'def¦.css']}`, + isNotTypescriptOrSupportedDecoratorField, + true, + ); + }); + + it('inside second item of styleUrls, when first is complicated function', () => { + test( + `const foo = {styleUrls: [getCss({strict: true, dirs: ['apple', 'banana']}), 'def¦.css']}`, + isNotTypescriptOrSupportedDecoratorField, + true, + ); + }); + + it('inside non-string item of styleUrls', () => { + test( + `const foo = {styleUrls: [getCss({strict: true¦, dirs: ['apple', 'banana']}), 'def.css']}`, + isNotTypescriptOrSupportedDecoratorField, + false, + ); + }); + }); +}); + +function test( + fileWithCursor: string, + testFn: (doc: vscode.TextDocument, position: vscode.Position) => boolean, + expectation: boolean, +): void { + const {cursor, text} = extractCursorInfo(fileWithCursor); + + const vdoc = TextDocument.create( + 'test.ts' as DocumentUri, + 'typescript', + 0, + text, + ) as {} as vscode.TextDocument; + (vdoc as any).fileName = 'test.ts'; + const actual = testFn(vdoc, vdoc.positionAt(cursor)); + expect(actual).toBe(expectation); +} + +/** + * Given a text snippet which contains exactly one cursor symbol ('¦'), extract both the offset of + * that cursor within the text as well as the text snippet without the cursor. + */ +function extractCursorInfo(textWithCursor: string): {cursor: number; text: string} { + const cursor = textWithCursor.indexOf('¦'); + if (cursor === -1 || textWithCursor.indexOf('¦', cursor + 1) !== -1) { + throw new Error(`Expected to find exactly one cursor symbol '¦'`); + } + + return { + cursor, + text: textWithCursor.substr(0, cursor) + textWithCursor.substr(cursor + 1), + }; +} diff --git a/vscode-ng-language-service/client/src/tests/tsconfig.json b/vscode-ng-language-service/client/src/tests/tsconfig.json new file mode 100644 index 00000000000..1150548edb8 --- /dev/null +++ b/vscode-ng-language-service/client/src/tests/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + } +} \ No newline at end of file diff --git a/vscode-ng-language-service/client/src/tests/tsconfig.tsbuildinfo b/vscode-ng-language-service/client/src/tests/tsconfig.tsbuildinfo new file mode 100644 index 00000000000..8fb46aff5ed --- /dev/null +++ b/vscode-ng-language-service/client/src/tests/tsconfig.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./embedded_support_spec.ts"],"version":"5.9.2"} \ No newline at end of file diff --git a/vscode-ng-language-service/client/tsconfig.json b/vscode-ng-language-service/client/tsconfig.json new file mode 100644 index 00000000000..89ddb1330de --- /dev/null +++ b/vscode-ng-language-service/client/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "rootDirs": [ + ".", + "../dist" + ] + }, +} \ No newline at end of file diff --git a/vscode-ng-language-service/common/BUILD.bazel b/vscode-ng-language-service/common/BUILD.bazel new file mode 100644 index 00000000000..1b8c7020e4b --- /dev/null +++ b/vscode-ng-language-service/common/BUILD.bazel @@ -0,0 +1,32 @@ +load("@aspect_rules_ts//ts:defs.bzl", "ts_config", "ts_project") + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + visibility = [ + "//vscode-ng-language-service/client:__subpackages__", + "//vscode-ng-language-service/common:__subpackages__", + "//vscode-ng-language-service/integration:__subpackages__", + "//vscode-ng-language-service/server:__subpackages__", + ], + deps = ["//vscode-ng-language-service:tsconfig"], +) + +ts_project( + name = "common", + srcs = glob(["*.ts"]), + declaration = True, + source_map = True, + tsconfig = ":tsconfig", + visibility = [ + "//vscode-ng-language-service/client:__subpackages__", + "//vscode-ng-language-service/common:__subpackages__", + "//vscode-ng-language-service/integration:__subpackages__", + "//vscode-ng-language-service/server:__subpackages__", + ], + deps = [ + "//vscode-ng-language-service:node_modules/@types/node", + "//vscode-ng-language-service:node_modules/vscode-jsonrpc", + "//vscode-ng-language-service:node_modules/vscode-languageserver-protocol", + ], +) diff --git a/vscode-ng-language-service/common/initialize.ts b/vscode-ng-language-service/common/initialize.ts new file mode 100644 index 00000000000..e5b387c939a --- /dev/null +++ b/vscode-ng-language-service/common/initialize.ts @@ -0,0 +1,21 @@ +/** + * @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 + */ + +export interface ServerOptions { + logFile?: string; +} + +export interface OpenJsDocLinkCommand_Args { + readonly file: string; + readonly position?: { + start: {character: number; line: number}; + end: {character: number; line: number}; + }; +} + +export const OpenJsDocLinkCommandId = 'angular.openJsDocLink'; diff --git a/vscode-ng-language-service/common/notifications.ts b/vscode-ng-language-service/common/notifications.ts new file mode 100644 index 00000000000..a6515d12ed5 --- /dev/null +++ b/vscode-ng-language-service/common/notifications.ts @@ -0,0 +1,32 @@ +/** + * @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 {NotificationType, NotificationType0} from 'vscode-jsonrpc'; + +export const ProjectLoadingStart = new NotificationType0('angular/projectLoadingStart'); +export const ProjectLoadingFinish = new NotificationType0('angular/projectLoadingFinish'); + +export interface ProjectLanguageServiceParams { + projectName: string; + languageServiceEnabled: boolean; +} + +export const ProjectLanguageService = new NotificationType( + 'angular/projectLanguageService', +); + +export interface SuggestStrictModeParams { + configFilePath: string; + message: string; +} + +export const SuggestStrictMode = new NotificationType( + 'angular/suggestStrictMode', +); + +export const OpenOutputChannel = new NotificationType('angular/OpenOutputChannel'); diff --git a/vscode-ng-language-service/common/requests.ts b/vscode-ng-language-service/common/requests.ts new file mode 100644 index 00000000000..42bc78c2875 --- /dev/null +++ b/vscode-ng-language-service/common/requests.ts @@ -0,0 +1,57 @@ +/** + * @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 * as lsp from 'vscode-languageserver-protocol'; + +export const GetComponentsWithTemplateFile = new lsp.RequestType< + GetComponentsWithTemplateFileParams, + lsp.Location[], + /* error */ void +>('angular/getComponentsWithTemplateFile'); + +export interface GetComponentsWithTemplateFileParams { + textDocument: lsp.TextDocumentIdentifier; +} + +export const GetTemplateLocationForComponent = new lsp.RequestType< + GetTemplateLocationForComponentParams, + lsp.Location, + /* error */ void +>('angular/getTemplateLocationForComponent'); + +export interface GetTemplateLocationForComponentParams { + textDocument: lsp.TextDocumentIdentifier; + position: lsp.Position; +} + +export interface GetTcbParams { + textDocument: lsp.TextDocumentIdentifier; + position: lsp.Position; +} + +export const GetTcbRequest = new lsp.RequestType< + GetTcbParams, + GetTcbResponse | null, + /* error */ void +>('angular/getTcb'); + +export interface GetTcbResponse { + uri: lsp.DocumentUri; + content: string; + selections: lsp.Range[]; +} + +export const IsInAngularProject = new lsp.RequestType< + IsInAngularProjectParams, + boolean | null, + /* error */ void +>('angular/isAngularCoreInOwningProject'); + +export interface IsInAngularProjectParams { + textDocument: lsp.TextDocumentIdentifier; +} diff --git a/vscode-ng-language-service/common/resolver.ts b/vscode-ng-language-service/common/resolver.ts new file mode 100644 index 00000000000..8ab64515b4e --- /dev/null +++ b/vscode-ng-language-service/common/resolver.ts @@ -0,0 +1,106 @@ +/** + * @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 * as fs from 'fs'; + +/** + * Represents a valid node module that has been successfully resolved. + */ +export interface NodeModule { + name: string; + resolvedPath: string; + version: Version; +} + +export function resolve( + packageName: string, + location: string, + rootPackage?: string, +): NodeModule | undefined { + rootPackage = rootPackage || packageName; + try { + const packageJsonPath = require.resolve(`${rootPackage}/package.json`, { + paths: [location], + }); + // Do not use require() to read JSON files since it's a potential security + // vulnerability. + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); + const resolvedPath = require.resolve(packageName, { + paths: [location], + }); + return { + name: packageName, + resolvedPath, + version: new Version(packageJson.version), + }; + } catch {} +} + +export class Version { + readonly major: number; + readonly minor: number; + readonly patch: number; + + constructor(private readonly versionStr: string) { + const [major, minor, patch] = Version.parseVersionStr(versionStr); + this.major = major; + this.minor = minor; + this.patch = patch; + } + + greaterThanOrEqual(other: Version, compare: 'patch' | 'minor' | 'major' = 'patch'): boolean { + if (this.major < other.major) { + return false; + } + if (this.major > other.major || (this.major === other.major && compare === 'major')) { + return true; + } + if (this.minor < other.minor) { + return false; + } + if (this.minor > other.minor || (this.minor === other.minor && compare === 'minor')) { + return true; + } + return this.patch >= other.patch; + } + + isVersionZero() { + return this.versionStr === '0.0.0'; + } + + toString(): string { + return this.versionStr; + } + + /** + * Converts the specified `versionStr` to its number constituents. Invalid + * number value is represented as negative number. + * @param versionStr + */ + static parseVersionStr(versionStr: string): [number, number, number] { + const [major, minor, patch] = versionStr.split('.').map(parseNonNegativeInt); + return [ + major === undefined ? 0 : major, + minor === undefined ? 0 : minor, + patch === undefined ? 0 : patch, + ]; + } +} + +/** + * Converts the specified string `a` to non-negative integer. + * Returns -1 if the result is NaN. + * @param a + */ +function parseNonNegativeInt(a: string): number { + // parseInt() will try to convert as many as possible leading characters that + // are digits. This means a string like "123abc" will be converted to 123. + // For our use case, this is sufficient. + const i = parseInt(a, 10 /* radix */); + return isNaN(i) ? -1 : i; +} diff --git a/vscode-ng-language-service/common/tests/BUILD.bazel b/vscode-ng-language-service/common/tests/BUILD.bazel new file mode 100644 index 00000000000..3e772208c22 --- /dev/null +++ b/vscode-ng-language-service/common/tests/BUILD.bazel @@ -0,0 +1,32 @@ +load("@aspect_rules_jasmine//jasmine:defs.bzl", "jasmine_test") +load("@aspect_rules_ts//ts:defs.bzl", "ts_config", "ts_project") + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//vscode-ng-language-service:tsconfig", + "//vscode-ng-language-service/common:tsconfig", + ], +) + +ts_project( + name = "tests", + srcs = glob(["*.ts"]), + declaration = True, + source_map = True, + tsconfig = ":tsconfig", + deps = [ + "//vscode-ng-language-service:node_modules/@types/jasmine", + "//vscode-ng-language-service/common", + ], +) + +jasmine_test( + name = "test", + args = ["*_spec.js"], + chdir = package_name(), + data = [":tests"], + node_modules = "//vscode-ng-language-service:node_modules", + tags = ["unit_test"], +) diff --git a/vscode-ng-language-service/common/tests/resolver_spec.ts b/vscode-ng-language-service/common/tests/resolver_spec.ts new file mode 100644 index 00000000000..21bfdc24971 --- /dev/null +++ b/vscode-ng-language-service/common/tests/resolver_spec.ts @@ -0,0 +1,58 @@ +/** + * @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 {Version} from '../resolver'; + +describe('Version', () => { + it('should parse version string correctly', () => { + const cases: Array<[string, number, number, number]> = [ + // version string | major | minor | patch + ['1', 1, 0, 0], + ['1.2', 1, 2, 0], + ['1.2.3', 1, 2, 3], + ['9.0.0-rc.1+126.sha-0c38aae.with-local-changes', 9, 0, 0], + ]; + for (const [versionStr, major, minor, patch] of cases) { + const v = new Version(versionStr); + expect(v.major).toBe(major); + expect(v.minor).toBe(minor); + expect(v.patch).toBe(patch); + } + }); + + it('should compare versions correctly', () => { + const cases: Array<[string, string, boolean]> = [ + // lhs | rhs | result + ['1', '1', true], + ['1', '2', false], + ['2', '2.0', true], + ['2', '2.1', false], + ['2', '2.0.0', true], + ['2', '2.0.1', false], + + ['1.2', '1', true], + ['1.2', '2', false], + ['2.2', '2.1', true], + ['2.2', '2.7', false], + ['3.2', '3.2.0', true], + ['3.2', '3.2.1', false], + + ['1.2.3', '1', true], + ['1.2.3', '2', false], + ['2.2.3', '2.1', true], + ['2.2.3', '2.3', false], + ['3.2.3', '3.2.2', true], + ['3.2.3', '3.2.4', false], + ]; + for (const [s1, s2, result] of cases) { + const v1 = new Version(s1); + const v2 = new Version(s2); + expect(v1.greaterThanOrEqual(v2)).toBe(result, `Expect ${v1} >= ${v2}`); + } + }); +}); diff --git a/vscode-ng-language-service/common/tests/tsconfig.json b/vscode-ng-language-service/common/tests/tsconfig.json new file mode 100644 index 00000000000..9c3be988d5a --- /dev/null +++ b/vscode-ng-language-service/common/tests/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + }, +} diff --git a/vscode-ng-language-service/common/tests/tsconfig.tsbuildinfo b/vscode-ng-language-service/common/tests/tsconfig.tsbuildinfo new file mode 100644 index 00000000000..c8da036d8e6 --- /dev/null +++ b/vscode-ng-language-service/common/tests/tsconfig.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./resolver_spec.ts"],"version":"5.9.2"} \ No newline at end of file diff --git a/vscode-ng-language-service/common/tsconfig.json b/vscode-ng-language-service/common/tsconfig.json new file mode 100644 index 00000000000..48610a17ff3 --- /dev/null +++ b/vscode-ng-language-service/common/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../tsconfig.json", +} diff --git a/vscode-ng-language-service/integration/BUILD.bazel b/vscode-ng-language-service/integration/BUILD.bazel new file mode 100644 index 00000000000..c7077a9cd18 --- /dev/null +++ b/vscode-ng-language-service/integration/BUILD.bazel @@ -0,0 +1,34 @@ +load("@aspect_rules_ts//ts:defs.bzl", "ts_config", "ts_project") + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + visibility = ["//vscode-ng-language-service/integration:__subpackages__"], + deps = [ + "//vscode-ng-language-service:tsconfig", + "//vscode-ng-language-service/server:tsconfig", + ], +) + +ts_project( + name = "integration", + # NB: there is an import cycle between integration/lsp/*.ts and integration/test_constants.ts so + # they cannot be broken up into separate ts_project targets + srcs = glob([ + "*.ts", + ]) + ["//vscode-ng-language-service/integration/lsp:srcs"], + declaration = True, + source_map = True, + tsconfig = ":tsconfig", + visibility = [ + "//vscode-ng-language-service/integration:__subpackages__", + ], + deps = [ + "//vscode-ng-language-service:node_modules/@types/jasmine", + "//vscode-ng-language-service:node_modules/@types/node", + "//vscode-ng-language-service:node_modules/vscode-jsonrpc", + "//vscode-ng-language-service:node_modules/vscode-languageserver-protocol", + "//vscode-ng-language-service:node_modules/vscode-uri", + "//vscode-ng-language-service/common", + ], +) diff --git a/vscode-ng-language-service/integration/e2e/BUILD.bazel b/vscode-ng-language-service/integration/e2e/BUILD.bazel new file mode 100644 index 00000000000..900e483c237 --- /dev/null +++ b/vscode-ng-language-service/integration/e2e/BUILD.bazel @@ -0,0 +1,43 @@ +load("@aspect_rules_js//js:defs.bzl", "js_test") +load("@aspect_rules_ts//ts:defs.bzl", "ts_project") + +ts_project( + name = "e2e", + srcs = glob(["*.ts"]), + declaration = True, + source_map = True, + tsconfig = "//vscode-ng-language-service/integration:tsconfig", + visibility = [ + "//vscode-ng-language-service/integration:__subpackages__", + ], + deps = [ + "//vscode-ng-language-service:node_modules/@types/jasmine", + "//vscode-ng-language-service:node_modules/@types/node", + "//vscode-ng-language-service:node_modules/@types/vscode", + "//vscode-ng-language-service:node_modules/vscode-test", + "//vscode-ng-language-service/integration", + ], +) + +js_test( + name = "test", + data = [ + ":e2e", + "//vscode-ng-language-service:npm", + "//vscode-ng-language-service/integration", + "//vscode-ng-language-service/integration/project", + # Depend on //:node_modules/jasmine as a temporary work-around for jasmine escaping its + # runfiles likely due to esm import issue in rules_js https://github.com/aspect-build/rules_js/issues/362 + "//vscode-ng-language-service:node_modules/jasmine", + ], + entry_point = ":index.js", + # This test downloads vscode & installs it which is not allowed in the sandbox + # due to file system protection. It is tagged local so it runs outside of + # the sandbox. It would need some redesign to allow for sandbox execution. + # Tagged manual so that `bazel test //...` doesn't run it automatically. + tags = [ + "e2e", + "local", + "manual", + ], +) diff --git a/vscode-ng-language-service/integration/e2e/completion_spec.ts b/vscode-ng-language-service/integration/e2e/completion_spec.ts new file mode 100644 index 00000000000..8d365ec3028 --- /dev/null +++ b/vscode-ng-language-service/integration/e2e/completion_spec.ts @@ -0,0 +1,20 @@ +import * as vscode from 'vscode'; + +import {activate, COMPLETION_COMMAND, FOO_TEMPLATE_URI} from './helper'; + +describe('Angular Ivy LS completions', () => { + beforeAll(async () => { + await activate(FOO_TEMPLATE_URI); + }); + + it(`does not duplicate HTML completions in external templates`, async () => { + const position = new vscode.Position(0, 0); + const completionItem = await vscode.commands.executeCommand( + COMPLETION_COMMAND, + FOO_TEMPLATE_URI, + position, + ); + const regionCompletions = completionItem?.items?.filter((i) => i.label === '#region') ?? []; + expect(regionCompletions.length).toBe(1); + }); +}); diff --git a/vscode-ng-language-service/integration/e2e/definition_spec.ts b/vscode-ng-language-service/integration/e2e/definition_spec.ts new file mode 100644 index 00000000000..a3bc492c5a5 --- /dev/null +++ b/vscode-ng-language-service/integration/e2e/definition_spec.ts @@ -0,0 +1,37 @@ +import * as vscode from 'vscode'; + +import {APP_COMPONENT} from '../test_constants'; + +import {activate} from './helper'; + +const DEFINITION_COMMAND = 'vscode.executeDefinitionProvider'; +const APP_COMPONENT_URI = vscode.Uri.file(APP_COMPONENT); + +describe('Angular Ivy LS', () => { + beforeAll(async () => { + await activate(APP_COMPONENT_URI); + }, 25000 /* 25 seconds */); + + it(`returns definition for variable in template`, async () => { + // vscode Position is zero-based + // template: `

Hello {{name}}

`, + // ^-------- here + const position = new vscode.Position(4, 25); + // For a complete list of standard commands, see + // https://code.visualstudio.com/api/references/commands + const definitions = await vscode.commands.executeCommand( + DEFINITION_COMMAND, + APP_COMPONENT_URI, + position, + ); + expect(definitions?.length).toBe(1); + const def = definitions![0]; + expect(def.targetUri.fsPath).toBe(APP_COMPONENT); // in the same document + const {start, end} = def.targetRange; + // Should start and end on line 6 + expect(start.line).toBe(7); + expect(end.line).toBe(7); + expect(start.character).toBe(2); + expect(end.character).toBe(start.character + `name`.length); + }); +}); diff --git a/vscode-ng-language-service/integration/e2e/helper.ts b/vscode-ng-language-service/integration/e2e/helper.ts new file mode 100644 index 00000000000..78b6f5c1acc --- /dev/null +++ b/vscode-ng-language-service/integration/e2e/helper.ts @@ -0,0 +1,39 @@ +import * as vscode from 'vscode'; + +import {APP_COMPONENT, FOO_TEMPLATE} from '../test_constants'; + +export const COMPLETION_COMMAND = 'vscode.executeCompletionItemProvider'; +export const HOVER_COMMAND = 'vscode.executeHoverProvider'; +export const DEFINITION_COMMAND = 'vscode.executeDefinitionProvider'; +export const APP_COMPONENT_URI = vscode.Uri.file(APP_COMPONENT); +export const FOO_TEMPLATE_URI = vscode.Uri.file(FOO_TEMPLATE); + +function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +export async function activate(uri: vscode.Uri) { + // set default timeout to 30 seconds + jasmine.DEFAULT_TIMEOUT_INTERVAL = 30_000; + await vscode.window.showTextDocument(uri); + await waitForDefinitionsToBeAvailable(20); +} + +async function waitForDefinitionsToBeAvailable(maxSeconds: number) { + let tries = 0; + while (tries < maxSeconds) { + const position = new vscode.Position(4, 25); + // For a complete list of standard commands, see + // https://code.visualstudio.com/api/references/commands + const definitions = await vscode.commands.executeCommand( + DEFINITION_COMMAND, + APP_COMPONENT_URI, + position, + ); + if (definitions && definitions.length > 0) { + return; + } + tries++; + await sleep(1000); + } +} diff --git a/vscode-ng-language-service/integration/e2e/hover_spec.ts b/vscode-ng-language-service/integration/e2e/hover_spec.ts new file mode 100644 index 00000000000..a8c3c23ad38 --- /dev/null +++ b/vscode-ng-language-service/integration/e2e/hover_spec.ts @@ -0,0 +1,21 @@ +import * as vscode from 'vscode'; + +import {activate, FOO_TEMPLATE_URI, HOVER_COMMAND} from './helper'; + +// This hover tests appear to be the only flaky ones in the suite. Disable until they can +// consistently pass. +xdescribe('Angular Ivy LS quick info', () => { + beforeAll(async () => { + await activate(FOO_TEMPLATE_URI); + }); + + it(`returns quick info from built in extension for class in template`, async () => { + const position = new vscode.Position(1, 8); + const quickInfo = await vscode.commands.executeCommand( + HOVER_COMMAND, + FOO_TEMPLATE_URI, + position, + ); + expect(quickInfo?.length).toBe(1); + }); +}); diff --git a/vscode-ng-language-service/integration/e2e/index.ts b/vscode-ng-language-service/integration/e2e/index.ts new file mode 100644 index 00000000000..71374287a5a --- /dev/null +++ b/vscode-ng-language-service/integration/e2e/index.ts @@ -0,0 +1,32 @@ +import {join} from 'path'; +import {runTests} from 'vscode-test'; + +import {IS_BAZEL, PACKAGE_ROOT, PROJECT_PATH} from '../test_constants'; + +async function main() { + const EXT_DEVELOPMENT_PATH = IS_BAZEL + ? join(PACKAGE_ROOT, 'npm') + : join(PACKAGE_ROOT, 'dist', 'npm'); + const EXT_TESTS_PATH = IS_BAZEL + ? join(PACKAGE_ROOT, 'integration', 'e2e', 'jasmine') + : join(PACKAGE_ROOT, 'dist', 'integration', 'e2e', 'jasmine'); + + try { + await runTests({ + // Keep version in sync with vscode engine version in package.json + version: '1.74.3', + extensionDevelopmentPath: EXT_DEVELOPMENT_PATH, + extensionTestsPath: EXT_TESTS_PATH, + launchArgs: [ + PROJECT_PATH, + // This disables all extensions except the one being tested + '--disable-extensions', + ], + }); + } catch (err) { + console.error('Failed to run tests', err); + process.exit(1); + } +} + +main(); diff --git a/vscode-ng-language-service/integration/e2e/jasmine.ts b/vscode-ng-language-service/integration/e2e/jasmine.ts new file mode 100644 index 00000000000..e135cde17ad --- /dev/null +++ b/vscode-ng-language-service/integration/e2e/jasmine.ts @@ -0,0 +1,44 @@ +import Jasmine = require('jasmine'); + +export async function run(): Promise { + const jasmine = new Jasmine({projectBaseDir: __dirname}); + + jasmine.loadConfig({ + spec_files: ['*_spec.js'], + }); + + // For whatever reason, the built-in jasmine reporter printin does not make it to the console + // output when the tests are run. In addition, allowing the default implementation to call + // `process.exit(1)` messes up the console reporting. The overrides below allow for both the + // proper exit code and the proper console reporting. + let failed = false; + jasmine.configureDefaultReporter({ + // The `print` function passed the reporter will be called to print its results. + print: function (message: string) { + if (message.trim()) { + console.log(message); + } + }, + }); + jasmine.completionReporter = { + specDone: (result: jasmine.SpecResult): void | Promise => { + if (result.failedExpectations.length > 0) { + failed = true; + } + console.log(result); + }, + }; + + console.log(`Expecting to run ${jasmine.specFiles.length} specs.`); + + console.log(JSON.stringify(jasmine.specFiles, null, 2)); + + if (jasmine.specFiles.length === 0) { + throw new Error('No specs found'); + } + + await jasmine.execute(); + if (failed) { + process.exit(1); + } +} diff --git a/vscode-ng-language-service/integration/lsp/BUILD.bazel b/vscode-ng-language-service/integration/lsp/BUILD.bazel new file mode 100644 index 00000000000..393d379ecc0 --- /dev/null +++ b/vscode-ng-language-service/integration/lsp/BUILD.bazel @@ -0,0 +1,33 @@ +load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin") +load("@aspect_rules_jasmine//jasmine:defs.bzl", "jasmine_test") + +jasmine_test( + name = "test", + args = ["*_spec.js"], + chdir = package_name(), + data = [ + "//vscode-ng-language-service/integration", + "//vscode-ng-language-service/integration/pre_standalone_project", + "//vscode-ng-language-service/integration/pre_standalone_project:node_modules/@angular/common", + "//vscode-ng-language-service/integration/pre_standalone_project:node_modules/@angular/core", + "//vscode-ng-language-service/integration/project", + "//vscode-ng-language-service/integration/project:node_modules/@angular/common", + "//vscode-ng-language-service/integration/project:node_modules/@angular/core", + "//vscode-ng-language-service/server:index", + ], + node_modules = "//vscode-ng-language-service:node_modules", + shard_count = 2, + tags = [ + "e2e", + "no-remote", + "no-sandbox", + ], +) + +copy_to_bin( + name = "srcs", + srcs = glob(["*.ts"]), + # NB: there is an import cycle between integration/lsp/*.ts and integration/test_constants.ts so + # they cannot be broken up into separate ts_project targets + visibility = ["//vscode-ng-language-service/integration:__subpackages__"], +) diff --git a/vscode-ng-language-service/integration/lsp/ivy_spec.ts b/vscode-ng-language-service/integration/lsp/ivy_spec.ts new file mode 100644 index 00000000000..f6272a50036 --- /dev/null +++ b/vscode-ng-language-service/integration/lsp/ivy_spec.ts @@ -0,0 +1,1004 @@ +/** + * @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 * as fs from 'fs'; +import {join} from 'path'; +import {promisify} from 'util'; +import {MessageConnection} from 'vscode-jsonrpc'; +import * as lsp from 'vscode-languageserver-protocol'; +import {URI} from 'vscode-uri'; + +import { + ProjectLanguageService, + ProjectLanguageServiceParams, + SuggestStrictMode, + SuggestStrictModeParams, +} from '../../common/notifications'; +import { + GetComponentsWithTemplateFile, + GetTcbRequest, + GetTemplateLocationForComponent, + IsInAngularProject, +} from '../../common/requests'; +import { + APP_COMPONENT, + APP_COMPONENT_MODULE_URI, + APP_COMPONENT_URI, + BAR_COMPONENT, + BAR_COMPONENT_URI, + FOO_COMPONENT, + FOO_COMPONENT_URI, + FOO_TEMPLATE, + FOO_TEMPLATE_URI, + IS_BAZEL, + PRE_STANDALONE_PROJECT_PATH, + PROJECT_PATH, + TSCONFIG, +} from '../test_constants'; + +import { + convertPathToFileUrl, + createConnection, + createTracer, + initializeServer, + openTextDocument, + ServerOptions, +} from './test_utils'; + +const setTimeoutP = promisify(setTimeout); + +describe('Angular Ivy language server', () => { + jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; /* 10 seconds */ + + let client: MessageConnection; + + beforeEach(async () => { + await initServer({}); + }); + + afterEach(() => { + client.dispose(); + }); + + async function initServer(options: Partial) { + client = createConnection({ + ivy: true, + ...options, + }); + // If debugging, set to + // - lsp.Trace.Messages to inspect request/response/notification, or + // - lsp.Trace.Verbose to inspect payload + client.trace(lsp.Trace.Off, createTracer()); + client.listen(); + await initializeServer(client); + } + + it('should handle hover on inline template', async () => { + openTextDocument(client, APP_COMPONENT); + const response = await client.sendRequest(lsp.HoverRequest.type, { + textDocument: { + uri: APP_COMPONENT_URI, + }, + position: {line: 4, character: 25}, + }); + expect(response?.contents).toContain({ + language: 'typescript', + value: '(property) AppComponent.name: string', + }); + }); + + it('should show diagnostics for inline template on open', async () => { + openTextDocument(client, APP_COMPONENT); + const diagnostics = await getDiagnosticsForFile(client, APP_COMPONENT); + expect(diagnostics.length).toBe(0); + }); + + it('should show diagnostics for external template on open', async () => { + client.sendNotification(lsp.DidOpenTextDocumentNotification.type, { + textDocument: { + uri: FOO_TEMPLATE_URI, + languageId: 'html', + version: 1, + text: `{{ doesnotexist }}`, + }, + }); + const diagnostics = await getDiagnosticsForFile(client, FOO_TEMPLATE); + expect(diagnostics.length).toBe(1); + expect(diagnostics[0].message).toBe( + `Property 'doesnotexist' does not exist on type 'FooComponent'.`, + ); + expect(diagnostics[0].relatedInformation).toBeDefined(); + expect(diagnostics[0].relatedInformation!.length).toBe(1); + expect(diagnostics[0].relatedInformation![0].message).toBe( + `Error occurs in the template of component FooComponent.`, + ); + expect(diagnostics[0].relatedInformation![0].location.uri).toBe(FOO_COMPONENT_URI); + }); + + it('should support request cancellation', async () => { + openTextDocument(client, APP_COMPONENT); + // Send a request and immediately cancel it + const promise = client.sendRequest(lsp.HoverRequest.type, { + textDocument: { + uri: FOO_COMPONENT_URI, + }, + position: {line: 4, character: 25}, + }); + // Request above is tagged with ID = 1 + client.sendNotification('$/cancelRequest', {id: 1}); + await expectAsync(promise).toBeRejectedWith( + jasmine.objectContaining({ + code: lsp.LSPErrorCodes.RequestCancelled, + }), + ); + }); + + it('does not break after opening `.d.ts` file from external template', async () => { + client.sendNotification(lsp.DidOpenTextDocumentNotification.type, { + textDocument: { + uri: FOO_TEMPLATE_URI, + languageId: 'html', + version: 1, + text: `
`, + }, + }); + const response = (await client.sendRequest(lsp.DefinitionRequest.type, { + textDocument: { + uri: FOO_TEMPLATE_URI, + }, + position: {line: 0, character: 7}, + })) as lsp.LocationLink[]; + // 2 results - the NgIf class and the ngIf input + expect(Array.isArray(response)).toBe(true); + const {targetUri} = response[0]; + expect(targetUri.endsWith('angular/common/index.d.ts')).toBeTrue(); + // Open the `.d.ts` file + openTextDocument(client, URI.parse(targetUri).fsPath); + // try a hover operation again on *ngIf + const hoverResponse = await client.sendRequest(lsp.HoverRequest.type, { + textDocument: { + uri: FOO_TEMPLATE_URI, + }, + position: {line: 0, character: 7}, + }); + expect(hoverResponse?.contents).toContain({ + language: 'typescript', + value: 'declare (property) NgIf.ngIf: boolean', + }); + }); + + it('goes to definition of original source when compiled with source maps', async () => { + client.sendNotification(lsp.DidOpenTextDocumentNotification.type, { + textDocument: { + uri: FOO_TEMPLATE_URI, + languageId: 'html', + version: 1, + text: ``, + }, + }); + const response = (await client.sendRequest(lsp.DefinitionRequest.type, { + textDocument: { + uri: FOO_TEMPLATE_URI, + }, + position: {line: 0, character: 1}, + })) as lsp.LocationLink[]; + expect(Array.isArray(response)).toBe(true); + const {targetUri} = response[0]; + expect(targetUri).toContain('libs/post/src/lib/post.component.ts'); + }); + + it('provides folding ranges for inline templates', async () => { + openTextDocument( + client, + APP_COMPONENT, + ` +import {Component, EventEmitter, Input, Output} from '@angular/core'; + +@Component({ + selector: 'my-app', + template: \` +
+ + Hello {{name}} + +
\`, +}) +export class AppComponent { + name = 'Angular'; + @Input() appInput = ''; + @Output() appOutput = new EventEmitter(); +}`, + ); + const response = (await client.sendRequest(lsp.FoldingRangeRequest.type, { + textDocument: { + uri: APP_COMPONENT_URI, + }, + })) as lsp.FoldingRange[]; + expect(Array.isArray(response)).toBe(true); + // 1 folding range for the div, 1 for the span + expect(response.length).toEqual(2); + expect(response).toContain({startLine: 6, endLine: 9}); + expect(response).toContain({startLine: 7, endLine: 8}); + }); + + it('provides folding ranges for control flow', async () => { + openTextDocument( + client, + APP_COMPONENT, + ` +import {Component, EventEmitter, Input, Output} from '@angular/core'; + +@Component({ + selector: 'my-app', + template: \` + @if (1) { + 1 + } @else { + 2 + } + + @switch (name) { + @case ('') { + 3 + } @default { + 4 + } + }5 + + @defer { + 6 + } @placeholder { + 7 + } @error { + 8 + } @loading { + 9 + } + + @for (item of items; track $index) { + 10 + } @empty { + 11 + } + \`, +}) +export class AppComponent { + name = 'Angular'; + items = []; +}`, + ); + const response = (await client.sendRequest(lsp.FoldingRangeRequest.type, { + textDocument: { + uri: APP_COMPONENT_URI, + }, + })) as lsp.FoldingRange[]; + expect(Array.isArray(response)).toBe(true); + // 2 folding ranges for the if/else, 3 for the switch, 4 for defer, 2 for repeater + expect(response.length).toEqual(11); + expect(response).toContain({startLine: 6, endLine: 7}); // if + expect(response).toContain({startLine: 8, endLine: 9}); // else + expect(response).toContain({startLine: 12, endLine: 17}); // switch + expect(response).toContain({startLine: 13, endLine: 14}); // case + expect(response).toContain({startLine: 15, endLine: 16}); // default + expect(response).toContain({startLine: 20, endLine: 21}); // defer + expect(response).toContain({startLine: 22, endLine: 23}); // placeholder + expect(response).toContain({startLine: 24, endLine: 25}); // error + expect(response).toContain({startLine: 26, endLine: 27}); // loading + expect(response).toContain({startLine: 30, endLine: 31}); // for + expect(response).toContain({startLine: 32, endLine: 33}); // empty + }); + + describe('signature help', () => { + it('should show signature help for an empty call', async () => { + client.sendNotification(lsp.DidOpenTextDocumentNotification.type, { + textDocument: { + uri: FOO_TEMPLATE_URI, + languageId: 'html', + version: 1, + text: `{{ title.toString() }}`, + }, + }); + const response = (await client.sendRequest(lsp.SignatureHelpRequest.type, { + textDocument: { + uri: FOO_TEMPLATE_URI, + }, + position: {line: 0, character: 18}, + }))!; + expect(response).not.toBeNull(); + expect(response.signatures.length).toEqual(1); + expect(response.signatures[0].label).toContain('(): string'); + }); + + it('should show signature help with multiple arguments', async () => { + client.sendNotification(lsp.DidOpenTextDocumentNotification.type, { + textDocument: { + uri: FOO_TEMPLATE_URI, + languageId: 'html', + version: 1, + text: `{{ title.substr(0, ) }}`, + }, + }); + const response = (await client.sendRequest(lsp.SignatureHelpRequest.type, { + textDocument: { + uri: FOO_TEMPLATE_URI, + }, + position: {line: 0, character: 19}, + }))!; + expect(response).not.toBeNull(); + expect(response.signatures.length).toEqual(1); + expect(response.signatures[0].label).toContain('(from: number, length?: number): string'); + expect(response.signatures[0].parameters).not.toBeUndefined(); + expect(response.activeParameter).toBe(1); + + const label = response.signatures[0].label; + const paramLabels = response.signatures[0].parameters!.map((param) => { + const [start, end] = param.label as [number, number]; + return label.substring(start, end); + }); + expect(paramLabels).toEqual(['from: number', 'length?: number']); + }); + }); + + describe('project reload', () => { + const dummy = `${PROJECT_PATH}/node_modules/__foo__`; + + afterEach(() => { + fs.unlinkSync(dummy); + }); + + it('should retain typecheck files', async () => { + openTextDocument(client, APP_COMPONENT); + // Create a file in node_modules, this will trigger a project reload via + // the directory watcher + fs.writeFileSync(dummy, ''); + // Project reload happens after 250ms delay + // https://github.com/microsoft/TypeScript/blob/3c32f6e154ead6749b76ec9c19cbfdd2acad97d6/src/server/editorServices.ts#L957 + await setTimeoutP(500); + // The following operation would result in compiler crash if typecheck + // files are not retained after project reload + const diagnostics = await getDiagnosticsForFile(client, APP_COMPONENT); + expect(diagnostics.length).toBe(0); + }); + }); + + describe('completions', () => { + it('for events', async () => { + openTextDocument(client, FOO_TEMPLATE, ``); + const response = (await client.sendRequest(lsp.CompletionRequest.type, { + textDocument: { + uri: FOO_TEMPLATE_URI, + }, + position: {line: 0, character: 9}, + })) as lsp.CompletionItem[]; + const outputCompletion = response.find((i) => i.label === '(appOutput)')!; + expect(outputCompletion.kind).toEqual(lsp.CompletionItemKind.Property); + // // replace range includes the closing ) + expect((outputCompletion.textEdit as lsp.TextEdit).range).toEqual({ + start: {line: 0, character: 8}, + end: {line: 0, character: 10}, + }); + }); + }); + + describe('renaming', () => { + describe('from template files', () => { + beforeEach(async () => { + openTextDocument(client, FOO_TEMPLATE); + }); + + it('should handle prepare rename request for property read', async () => { + const response = (await client.sendRequest(lsp.PrepareRenameRequest.type, { + textDocument: { + uri: FOO_TEMPLATE_URI, + }, + position: {line: 0, character: 3}, + })) as {range: lsp.Range; placeholder: string}; + expect(response.range).toEqual({ + start: {line: 0, character: 2}, + end: {line: 0, character: 7}, + }); + expect(response.placeholder).toEqual('title'); + }); + + const expectedRenameInComponent = { + range: { + start: {line: 7, character: 2}, + end: {line: 7, character: 7}, + }, + newText: 'subtitle', + }; + const expectedRenameInTemplate = { + range: { + start: {line: 0, character: 2}, + end: {line: 0, character: 7}, + }, + newText: 'subtitle', + }; + + it('should handle rename request for property read', async () => { + const response = await client.sendRequest(lsp.RenameRequest.type, { + textDocument: { + uri: FOO_TEMPLATE_URI, + }, + position: {line: 0, character: 3}, + newName: 'subtitle', + }); + expect(response).not.toBeNull(); + expect(response?.changes?.[FOO_TEMPLATE_URI].length).toBe(1); + expect(response?.changes?.[FOO_TEMPLATE_URI]).toContain(expectedRenameInTemplate); + expect(response?.changes?.[FOO_COMPONENT_URI].length).toBe(1); + expect(response?.changes?.[FOO_COMPONENT_URI]).toContain(expectedRenameInComponent); + }); + }); + + describe('from typescript files', () => { + beforeEach(async () => { + openTextDocument(client, APP_COMPONENT); + }); + + it('should handle prepare rename request for inline template property read', async () => { + const response = (await client.sendRequest(lsp.PrepareRenameRequest.type, { + textDocument: { + uri: APP_COMPONENT_URI, + }, + position: {line: 4, character: 25}, + })) as {range: lsp.Range; placeholder: string}; + expect(response.range).toEqual({ + start: {line: 4, character: 25}, + end: {line: 4, character: 29}, + }); + expect(response.placeholder).toEqual('name'); + }); + + describe('property rename', () => { + const expectedRenameInComponent = { + range: { + start: {line: 8, character: 2}, + end: {line: 8, character: 6}, + }, + newText: 'surname', + }; + const expectedRenameInTemplate = { + range: { + start: {line: 4, character: 25}, + end: {line: 4, character: 29}, + }, + newText: 'surname', + }; + + it('should handle rename request for property read in a template', async () => { + const response = await client.sendRequest(lsp.RenameRequest.type, { + textDocument: { + uri: APP_COMPONENT_URI, + }, + position: {line: 4, character: 25}, + newName: 'surname', + }); + expect(response).not.toBeNull(); + expect(response?.changes?.[APP_COMPONENT_URI].length).toBe(2); + expect(response?.changes?.[APP_COMPONENT_URI]).toContain(expectedRenameInComponent); + expect(response?.changes?.[APP_COMPONENT_URI]).toContain(expectedRenameInTemplate); + }); + + it('should handle rename request for property in the component', async () => { + const response = await client.sendRequest(lsp.RenameRequest.type, { + textDocument: { + uri: APP_COMPONENT_URI, + }, + position: {line: 8, character: 4}, + newName: 'surname', + }); + expect(response).not.toBeNull(); + expect(response?.changes?.[APP_COMPONENT_URI].length).toBe(2); + expect(response?.changes?.[APP_COMPONENT_URI]).toContain(expectedRenameInComponent); + expect(response?.changes?.[APP_COMPONENT_URI]).toContain(expectedRenameInTemplate); + }); + }); + }); + }); + + describe('compiler options', () => { + const originalConfig = fs.readFileSync(TSCONFIG, 'utf-8'); + if (IS_BAZEL) { + // Under Bazel, the tsconfig.json file in the output tree is write protected. + // We change the file permissions here so that the fs.writeFileSync(TSCONFIG, ...) + // calls below don't fail under Bazel. This should be fixed in the future by + // use an in-memory FS harness for the server. + fs.chmodSync(TSCONFIG, 0o644); + } + + afterEach(() => { + // TODO(kyliau): Use an in-memory FS harness for the server + fs.writeFileSync(TSCONFIG, originalConfig); + }); + + describe('strictTemplates: false', () => { + beforeEach(async () => { + const config = JSON.parse(originalConfig); + config.angularCompilerOptions.strictTemplates = false; + fs.writeFileSync(TSCONFIG, JSON.stringify(config, null, 2)); + + openTextDocument(client, APP_COMPONENT); + }); + + it('should suggest strict mode', async () => { + const configFilePath = await onSuggestStrictMode(client); + expect(configFilePath.endsWith('integration/project/tsconfig.json')).toBeTrue(); + }); + + it('should disable renaming when strict mode is disabled', async () => { + await onSuggestStrictMode(client); + + const prepareRenameResponse = (await client.sendRequest(lsp.PrepareRenameRequest.type, { + textDocument: { + uri: FOO_COMPONENT_URI, + }, + position: {line: 4, character: 25}, + })) as {range: lsp.Range; placeholder: string}; + expect(prepareRenameResponse).toBeNull(); + + const renameResponse = await client.sendRequest(lsp.RenameRequest.type, { + textDocument: { + uri: FOO_COMPONENT_URI, + }, + position: {line: 4, character: 25}, + newName: 'surname', + }); + expect(renameResponse).toBeNull(); + }); + }); + }); + + it('should handle getTcb request', async () => { + openTextDocument(client, FOO_TEMPLATE); + const response = await client.sendRequest(GetTcbRequest, { + textDocument: { + uri: FOO_TEMPLATE_URI, + }, + position: {line: 0, character: 3}, + }); + expect(response).toBeDefined(); + }); + + it('should handle goToComponent request', async () => { + openTextDocument(client, FOO_TEMPLATE); + const response = await client.sendRequest(GetComponentsWithTemplateFile, { + textDocument: { + uri: FOO_TEMPLATE_URI, + }, + }); + expect(response).toBeDefined(); + }); + + it('should handle GetTemplateLocationForComponent request', async () => { + openTextDocument(client, FOO_TEMPLATE); + const response = await client.sendRequest(GetTemplateLocationForComponent, { + textDocument: { + uri: FOO_COMPONENT_URI, + }, + position: {line: 6, character: 0}, + }); + expect(response).toBeDefined(); + expect(response.uri).toContain('foo.component.html'); + }); + + it('should handle GetTemplateLocationForComponent request when not in component', async () => { + openTextDocument(client, FOO_TEMPLATE); + const response = await client.sendRequest(GetTemplateLocationForComponent, { + textDocument: { + uri: FOO_COMPONENT_URI, + }, + position: {line: 1, character: 0}, + }); + expect(response).toBeNull(); + }); + + it('should handle apps where standalone is not enabled by default (pre v19)', async () => { + await initServer({angularCoreVersion: '18.0.0'}); + const moduleFile = join(PRE_STANDALONE_PROJECT_PATH, 'app/app.module.ts'); + + openTextDocument(client, moduleFile); + const diagnostics = await getDiagnosticsForFile(client, moduleFile); + expect(diagnostics.length).toBe(0); + }); + + it('should provide a "go to component" codelens', async () => { + openTextDocument(client, FOO_TEMPLATE); + const codeLensResponse = await client.sendRequest(lsp.CodeLensRequest.type, { + textDocument: { + uri: FOO_TEMPLATE_URI, + }, + }); + expect(codeLensResponse).toBeDefined(); + const [codeLens] = codeLensResponse!; + expect(codeLens.data.uri).toEqual(FOO_TEMPLATE_URI); + + const codeLensResolveResponse = await client.sendRequest( + lsp.CodeLensResolveRequest.type, + codeLensResponse![0], + ); + expect(codeLensResolveResponse).toBeDefined(); + expect(codeLensResolveResponse?.command?.title).toEqual('Go to component'); + }); + + it('detects an Angular project', async () => { + openTextDocument(client, FOO_TEMPLATE); + const templateResponse = await client.sendRequest(IsInAngularProject, { + textDocument: { + uri: FOO_TEMPLATE_URI, + }, + }); + expect(templateResponse).toBe(true); + const componentResponse = await client.sendRequest(IsInAngularProject, { + textDocument: { + uri: FOO_COMPONENT_URI, + }, + }); + expect(componentResponse).toBe(true); + }); + + describe('auto-import component', () => { + it('should generate import in the different file', async () => { + openTextDocument(client, FOO_TEMPLATE, ` res.label === 'bar-component')!; + const detail = await client.sendRequest(lsp.CompletionResolveRequest.type, libPostResponse); + expect(detail.command?.command).toEqual('angular.applyCompletionCodeAction'); + expect(detail.command?.arguments?.[0]).toEqual([ + { + 'changes': { + [APP_COMPONENT_MODULE_URI]: [ + { + 'newText': '\nimport { BarComponent } from "./bar.component";', + 'range': { + 'start': {'line': 5, 'character': 45}, + 'end': {'line': 5, 'character': 45}, + }, + }, + { + 'newText': 'imports: [CommonModule, PostModule, BarComponent]', + 'range': { + 'start': {'line': 8, 'character': 2}, + 'end': {'line': 8, 'character': 37}, + }, + }, + ], + }, + }, + ]); + }); + + it('should generate import in the current file', async () => { + openTextDocument(client, BAR_COMPONENT); + const response = (await client.sendRequest(lsp.CompletionRequest.type, { + textDocument: { + uri: BAR_COMPONENT_URI, + }, + position: {line: 13, character: 14}, + })) as lsp.CompletionItem[]; + const libPostResponse = response.find((res) => res.label === 'baz-component')!; + const detail = await client.sendRequest(lsp.CompletionResolveRequest.type, libPostResponse); + expect(detail.additionalTextEdits).toEqual([ + { + 'newText': ',\n imports: [BazComponent]', + 'range': {'start': {'line': 14, 'character': 18}, 'end': {'line': 14, 'character': 18}}, + }, + ]); + }); + }); +}); + +describe('auto-apply optional chaining', () => { + jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; /* 10 seconds */ + + let client: MessageConnection; + beforeEach(async () => { + client = createConnection({ + ivy: true, + includeAutomaticOptionalChainCompletions: true, + }); + // If debugging, set to + // - lsp.Trace.Messages to inspect request/response/notification, or + // - lsp.Trace.Verbose to inspect payload + client.trace(lsp.Trace.Off, createTracer()); + client.listen(); + await initializeServer(client); + }); + + afterEach(() => { + client.dispose(); + }); + + it('should work on nullable symbol', async () => { + openTextDocument( + client, + FOO_COMPONENT, + ` + import {Component} from '@angular/core'; + @Component({ + templateUrl: 'foo.component.html', + }) + export class FooComponent { + person?: undefined|{name: string}; + } + `, + ); + openTextDocument(client, FOO_TEMPLATE, `{{ person.n }}`); + const response = (await client.sendRequest(lsp.CompletionRequest.type, { + textDocument: { + uri: FOO_TEMPLATE_URI, + }, + position: {line: 0, character: 11}, + })) as lsp.CompletionItem[]; + const completion = response.find((i) => i.label === 'name')!; + expect(completion.kind).toEqual(lsp.CompletionItemKind.Property); + expect((completion.textEdit as lsp.TextEdit).newText).toEqual('?.name'); + }); + + it('should work on NonNullable symbol', async () => { + openTextDocument(client, FOO_TEMPLATE, `{{ title.substr }}`); + const response = (await client.sendRequest(lsp.CompletionRequest.type, { + textDocument: { + uri: FOO_TEMPLATE_URI, + }, + position: {line: 0, character: 15}, + })) as lsp.CompletionItem[]; + const completion = response.find((i) => i.label === 'substr')!; + expect(completion.kind).toEqual(lsp.CompletionItemKind.Method); + expect((completion.textEdit as lsp.TextEdit).newText).toEqual('substr'); + }); +}); + +describe('insert snippet text', () => { + jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; /* 10 seconds */ + + let client: MessageConnection; + beforeEach(async () => { + client = createConnection({ + ivy: true, + includeCompletionsWithSnippetText: true, + }); + // If debugging, set to + // - lsp.Trace.Messages to inspect request/response/notification, or + // - lsp.Trace.Verbose to inspect payload + client.trace(lsp.Trace.Off, createTracer()); + client.listen(); + await initializeServer(client); + }); + + afterEach(() => { + client.dispose(); + }); + + it('should be able to complete for an attribute with the value is empty', async () => { + openTextDocument(client, FOO_TEMPLATE, ``); + const response = (await client.sendRequest(lsp.CompletionRequest.type, { + textDocument: { + uri: FOO_TEMPLATE_URI, + }, + position: {line: 0, character: 14}, + })) as lsp.CompletionItem[]; + const completion = response.find((i) => i.label === '(appOutput)')!; + expect(completion.kind).toEqual(lsp.CompletionItemKind.Property); + expect(completion.insertTextFormat).toEqual(lsp.InsertTextFormat.Snippet); + expect((completion.textEdit as lsp.TextEdit).newText).toEqual('(appOutput)="$1"'); + }); + + it('should not be included in the completion for an attribute with a value', async () => { + openTextDocument(client, FOO_TEMPLATE, ``); + const response = (await client.sendRequest(lsp.CompletionRequest.type, { + textDocument: { + uri: FOO_TEMPLATE_URI, + }, + position: {line: 0, character: 17}, + })) as lsp.CompletionItem[]; + const completion = response.find((i) => i.label === 'appInput')!; + expect(completion.kind).toEqual(lsp.CompletionItemKind.Property); + expect(completion.insertTextFormat).toBeUndefined; + expect((completion.textEdit as lsp.TextEdit).newText).toEqual('appInput'); + }); +}); + +describe('code fixes', () => { + jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; /* 10 seconds */ + + let client: MessageConnection; + beforeEach(async () => { + client = createConnection({ + ivy: true, + includeCompletionsWithSnippetText: true, + }); + // If debugging, set to + // - lsp.Trace.Messages to inspect request/response/notification, or + // - lsp.Trace.Verbose to inspect payload + client.trace(lsp.Trace.Off, createTracer()); + client.listen(); + await initializeServer(client); + }); + + afterEach(() => { + client.dispose(); + }); + + it('should fix error when property does not exist on type', async () => { + openTextDocument(client, FOO_TEMPLATE, `{{titl}}`); + const diags = await getDiagnosticsForFile(client, FOO_TEMPLATE); + const codeActions = (await client.sendRequest(lsp.CodeActionRequest.type, { + textDocument: { + uri: FOO_TEMPLATE_URI, + }, + range: lsp.Range.create(lsp.Position.create(0, 3), lsp.Position.create(0, 3)), + context: lsp.CodeActionContext.create(diags), + })) as lsp.CodeAction[]; + const expectedCodeActionInTemplate = { + 'edit': { + 'changes': { + [FOO_TEMPLATE_URI]: [ + { + 'newText': 'title', + 'range': {'start': {'line': 0, 'character': 2}, 'end': {'line': 0, 'character': 6}}, + }, + ], + }, + }, + }; + expect(codeActions).toContain(jasmine.objectContaining(expectedCodeActionInTemplate)); + }); + + it('should fix error when the range the user selects is larger than the diagnostic', async () => { + const template = `{{titl}}`; + openTextDocument(client, FOO_TEMPLATE, template); + const diags = await getDiagnosticsForFile(client, FOO_TEMPLATE); + const codeActions = (await client.sendRequest(lsp.CodeActionRequest.type, { + textDocument: { + uri: FOO_TEMPLATE_URI, + }, + range: lsp.Range.create( + lsp.Position.create(0, 0), + lsp.Position.create(0, template.length - 1), + ), + context: lsp.CodeActionContext.create(diags), + })) as lsp.CodeAction[]; + const expectedCodeActionInTemplate = { + 'edit': { + 'changes': { + [FOO_TEMPLATE_URI]: [ + { + 'newText': 'title', + 'range': {'start': {'line': 0, 'character': 8}, 'end': {'line': 0, 'character': 12}}, + }, + ], + }, + }, + }; + expect(codeActions).toContain(jasmine.objectContaining(expectedCodeActionInTemplate)); + }); + + describe('should work', () => { + beforeEach(async () => { + openTextDocument( + client, + FOO_COMPONENT, + ` + import {Component, NgModule} from '@angular/core'; + @Component({ + template: '{{tite}}{{bannr}}', + }) + export class AppComponent { + title = ''; + banner = ''; + } + `, + ); + }); + + it('for "fixSpelling"', async () => { + const fixSpellingCodeAction = await client.sendRequest(lsp.CodeActionResolveRequest.type, { + title: '', + data: { + fixId: 'fixSpelling', + document: lsp.TextDocumentIdentifier.create(FOO_COMPONENT_URI), + }, + }); + const expectedFixSpellingInTemplate = { + 'edit': { + 'changes': { + [FOO_COMPONENT_URI]: [ + { + 'newText': 'title', + 'range': { + 'start': {'line': 3, 'character': 21}, + 'end': {'line': 3, 'character': 25}, + }, + }, + { + 'newText': 'banner', + 'range': { + 'start': {'line': 3, 'character': 29}, + 'end': {'line': 3, 'character': 34}, + }, + }, + ], + }, + }, + }; + expect(fixSpellingCodeAction).toEqual( + jasmine.objectContaining(expectedFixSpellingInTemplate), + ); + }); + + it('for "fixMissingMember"', async () => { + const fixMissingMemberCodeAction = await client.sendRequest( + lsp.CodeActionResolveRequest.type, + { + title: '', + data: { + fixId: 'fixMissingMember', + document: lsp.TextDocumentIdentifier.create(FOO_COMPONENT_URI), + }, + }, + ); + const expectedFixMissingMemberInComponent = { + 'edit': { + 'changes': { + [FOO_COMPONENT_URI]: [ + { + 'newText': 'tite: any;\n', + 'range': {'start': {'line': 8, 'character': 0}, 'end': {'line': 8, 'character': 0}}, + }, + { + 'newText': 'bannr: any;\n', + 'range': {'start': {'line': 8, 'character': 0}, 'end': {'line': 8, 'character': 0}}, + }, + ], + }, + }, + }; + expect(fixMissingMemberCodeAction).toEqual( + jasmine.objectContaining(expectedFixMissingMemberInComponent), + ); + }); + }); +}); + +function onSuggestStrictMode(client: MessageConnection): Promise { + return new Promise((resolve) => { + client.onNotification(SuggestStrictMode, (params: SuggestStrictModeParams) => { + resolve(params.configFilePath); + }); + }); +} + +function onLanguageServiceStateNotification(client: MessageConnection): Promise { + return new Promise((resolve) => { + client.onNotification(ProjectLanguageService, (params: ProjectLanguageServiceParams) => { + resolve(params.languageServiceEnabled); + }); + }); +} + +function getDiagnosticsForFile( + client: MessageConnection, + fileName: string, +): Promise { + return new Promise((resolve) => { + client.onNotification( + lsp.PublishDiagnosticsNotification.type, + (params: lsp.PublishDiagnosticsParams) => { + if (params.uri === convertPathToFileUrl(fileName)) { + resolve(params.diagnostics); + } + }, + ); + }); +} diff --git a/vscode-ng-language-service/integration/lsp/test_utils.ts b/vscode-ng-language-service/integration/lsp/test_utils.ts new file mode 100644 index 00000000000..53a1ac6b823 --- /dev/null +++ b/vscode-ng-language-service/integration/lsp/test_utils.ts @@ -0,0 +1,136 @@ +/** + * @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 {fork} from 'child_process'; +import * as fs from 'fs'; +import { + createMessageConnection, + IPCMessageReader, + IPCMessageWriter, + MessageConnection, +} from 'vscode-jsonrpc/node'; +import * as lsp from 'vscode-languageserver-protocol'; +import {URI} from 'vscode-uri'; + +import {PROJECT_PATH, SERVER_PATH} from '../test_constants'; + +export interface ServerOptions { + ivy: boolean; + includeAutomaticOptionalChainCompletions?: boolean; + includeCompletionsWithSnippetText?: boolean; + angularCoreVersion?: string; +} + +export function createConnection(serverOptions: ServerOptions): MessageConnection { + const argv: string[] = [ + '--node-ipc', + '--tsProbeLocations', + SERVER_PATH, + '--ngProbeLocations', + [SERVER_PATH, PROJECT_PATH].join(','), + ]; + if (!serverOptions.ivy) { + argv.push('--viewEngine'); + } + if (serverOptions.includeAutomaticOptionalChainCompletions) { + argv.push('--includeAutomaticOptionalChainCompletions'); + } + if (serverOptions.includeCompletionsWithSnippetText) { + argv.push('--includeCompletionsWithSnippetText'); + } + if (serverOptions.angularCoreVersion) { + argv.push('--angularCoreVersion', serverOptions.angularCoreVersion); + } + const server = fork(SERVER_PATH, argv, { + cwd: PROJECT_PATH, + // uncomment to debug server process + // execArgv: ['--inspect-brk=9330'] + }); + server.on('close', (code: number) => { + if (code !== null && code !== 0) { + throw new Error(`Server exited with code: ${code}`); + } + }); + const connection = createMessageConnection( + new IPCMessageReader(server), + new IPCMessageWriter(server), + ); + connection.onDispose(() => { + server.kill(); + }); + return connection; +} + +export function initializeServer(client: MessageConnection): Promise { + return client.sendRequest(lsp.InitializeRequest.type, { + /** + * The process id of the parent process that started the server. It is + * always the current process. + */ + processId: process.pid, + rootUri: `file://${PROJECT_PATH}`, + capabilities: { + textDocument: { + completion: { + completionItem: { + snippetSupport: true, + }, + }, + moniker: {}, + definition: {linkSupport: true}, + typeDefinition: {linkSupport: true}, + }, + }, + /** + * Options are 'off' | 'messages' | 'verbose'. + * To debug test failure, set to 'verbose'. + */ + trace: 'off', + workspaceFolders: null, + }); +} + +export function openTextDocument(client: MessageConnection, filePath: string, newText?: string) { + let languageId = 'unknown'; + if (filePath.endsWith('ts')) { + languageId = 'typescript'; + } else if (filePath.endsWith('html')) { + languageId = 'html'; + } + client.sendNotification(lsp.DidOpenTextDocumentNotification.type, { + textDocument: { + uri: convertPathToFileUrl(filePath), + languageId, + version: 1, + text: newText ?? fs.readFileSync(filePath, 'utf-8'), + }, + }); +} + +export function convertPathToFileUrl(filePath: string): string { + return URI.file(filePath).toString(); +} + +export function createTracer(): lsp.Tracer { + return { + log(messageOrDataObject: string | any, data?: string) { + if (typeof messageOrDataObject === 'string') { + const message = messageOrDataObject; + console.log(`[Trace - ${new Date().toLocaleTimeString()}] ${message}`); + if (data) { + console.log(data); + } + } else { + const dataObject = messageOrDataObject; + console.log( + `[Trace - ${new Date().toLocaleTimeString()}] ` + JSON.stringify(dataObject, null, 2), + ); + } + }, + }; +} diff --git a/vscode-ng-language-service/integration/pre_apf_project/BUILD.bazel b/vscode-ng-language-service/integration/pre_apf_project/BUILD.bazel new file mode 100644 index 00000000000..7e8979d367e --- /dev/null +++ b/vscode-ng-language-service/integration/pre_apf_project/BUILD.bazel @@ -0,0 +1,12 @@ +load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages(name = "node_modules") + +copy_to_bin( + name = "pre_apf_project", + srcs = glob(["**"]), + visibility = [ + "//vscode-ng-language-service/server/src/tests:__pkg__", + ], +) diff --git a/vscode-ng-language-service/integration/pre_apf_project/app/app.component.ts b/vscode-ng-language-service/integration/pre_apf_project/app/app.component.ts new file mode 100644 index 00000000000..582265a2f36 --- /dev/null +++ b/vscode-ng-language-service/integration/pre_apf_project/app/app.component.ts @@ -0,0 +1,11 @@ +import {Component, EventEmitter, Input, Output} from '@angular/core'; + +@Component({ + selector: 'my-app', + template: `

Hello {{name}}

`, +}) +export class AppComponent { + name = 'Angular'; + @Input() appInput = ''; + @Output() appOutput = new EventEmitter(); +} diff --git a/vscode-ng-language-service/integration/pre_apf_project/app/app.module.ts b/vscode-ng-language-service/integration/pre_apf_project/app/app.module.ts new file mode 100644 index 00000000000..11c89f19b14 --- /dev/null +++ b/vscode-ng-language-service/integration/pre_apf_project/app/app.module.ts @@ -0,0 +1,12 @@ +import {CommonModule} from '@angular/common'; +import {NgModule} from '@angular/core'; + +import {AppComponent} from './app.component'; +import {FooComponent} from './foo.component'; + +@NgModule({ + imports: [CommonModule], + declarations: [AppComponent, FooComponent], + bootstrap: [AppComponent], +}) +export class AppModule {} diff --git a/vscode-ng-language-service/integration/pre_apf_project/app/foo.component.html b/vscode-ng-language-service/integration/pre_apf_project/app/foo.component.html new file mode 100644 index 00000000000..e7c655511e3 --- /dev/null +++ b/vscode-ng-language-service/integration/pre_apf_project/app/foo.component.html @@ -0,0 +1,4 @@ +{{title | uppercase}} + + subtitle + \ No newline at end of file diff --git a/vscode-ng-language-service/integration/pre_apf_project/app/foo.component.ts b/vscode-ng-language-service/integration/pre_apf_project/app/foo.component.ts new file mode 100644 index 00000000000..0a6a2a7dd8b --- /dev/null +++ b/vscode-ng-language-service/integration/pre_apf_project/app/foo.component.ts @@ -0,0 +1,8 @@ +import {Component} from '@angular/core'; + +@Component({ + templateUrl: 'foo.component.html', +}) +export class FooComponent { + title = 'Foo Component'; +} diff --git a/vscode-ng-language-service/integration/pre_apf_project/package.json b/vscode-ng-language-service/integration/pre_apf_project/package.json new file mode 100644 index 00000000000..ba95ecea0f3 --- /dev/null +++ b/vscode-ng-language-service/integration/pre_apf_project/package.json @@ -0,0 +1,12 @@ +{ + "name": "angular-ls-integration-test-project", + "private": true, + "dependencies": { + "@angular/common": "12.2.16", + "@angular/compiler": "12.2.16", + "@angular/compiler-cli": "12.2.16", + "@angular/core": "12.2.16", + "rxjs": "6.6.7", + "zone.js": "0.11.5" + } +} \ No newline at end of file diff --git a/vscode-ng-language-service/integration/pre_apf_project/tsconfig.json b/vscode-ng-language-service/integration/pre_apf_project/tsconfig.json new file mode 100644 index 00000000000..3e9457d1876 --- /dev/null +++ b/vscode-ng-language-service/integration/pre_apf_project/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "moduleResolution": "node", + "experimentalDecorators": true, + "target": "es2015", + "strict": true, + "typeRoots": [ + "node_modules/@types" + ] + }, + "angularCompilerOptions": { + "strictTemplates": true, + "strictInjectionParameters": true + } +} diff --git a/vscode-ng-language-service/integration/pre_standalone_project/BUILD.bazel b/vscode-ng-language-service/integration/pre_standalone_project/BUILD.bazel new file mode 100644 index 00000000000..764aac9930b --- /dev/null +++ b/vscode-ng-language-service/integration/pre_standalone_project/BUILD.bazel @@ -0,0 +1,12 @@ +load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages(name = "node_modules") + +copy_to_bin( + name = "pre_standalone_project", + srcs = glob(["**"]), + visibility = [ + "//vscode-ng-language-service/integration/lsp:__pkg__", + ], +) diff --git a/vscode-ng-language-service/integration/pre_standalone_project/app/app.component.ts b/vscode-ng-language-service/integration/pre_standalone_project/app/app.component.ts new file mode 100644 index 00000000000..582265a2f36 --- /dev/null +++ b/vscode-ng-language-service/integration/pre_standalone_project/app/app.component.ts @@ -0,0 +1,11 @@ +import {Component, EventEmitter, Input, Output} from '@angular/core'; + +@Component({ + selector: 'my-app', + template: `

Hello {{name}}

`, +}) +export class AppComponent { + name = 'Angular'; + @Input() appInput = ''; + @Output() appOutput = new EventEmitter(); +} diff --git a/vscode-ng-language-service/integration/pre_standalone_project/app/app.module.ts b/vscode-ng-language-service/integration/pre_standalone_project/app/app.module.ts new file mode 100644 index 00000000000..11c89f19b14 --- /dev/null +++ b/vscode-ng-language-service/integration/pre_standalone_project/app/app.module.ts @@ -0,0 +1,12 @@ +import {CommonModule} from '@angular/common'; +import {NgModule} from '@angular/core'; + +import {AppComponent} from './app.component'; +import {FooComponent} from './foo.component'; + +@NgModule({ + imports: [CommonModule], + declarations: [AppComponent, FooComponent], + bootstrap: [AppComponent], +}) +export class AppModule {} diff --git a/vscode-ng-language-service/integration/pre_standalone_project/app/foo.component.html b/vscode-ng-language-service/integration/pre_standalone_project/app/foo.component.html new file mode 100644 index 00000000000..e7c655511e3 --- /dev/null +++ b/vscode-ng-language-service/integration/pre_standalone_project/app/foo.component.html @@ -0,0 +1,4 @@ +{{title | uppercase}} + + subtitle + \ No newline at end of file diff --git a/vscode-ng-language-service/integration/pre_standalone_project/app/foo.component.ts b/vscode-ng-language-service/integration/pre_standalone_project/app/foo.component.ts new file mode 100644 index 00000000000..0a6a2a7dd8b --- /dev/null +++ b/vscode-ng-language-service/integration/pre_standalone_project/app/foo.component.ts @@ -0,0 +1,8 @@ +import {Component} from '@angular/core'; + +@Component({ + templateUrl: 'foo.component.html', +}) +export class FooComponent { + title = 'Foo Component'; +} diff --git a/vscode-ng-language-service/integration/pre_standalone_project/package.json b/vscode-ng-language-service/integration/pre_standalone_project/package.json new file mode 100644 index 00000000000..20334888290 --- /dev/null +++ b/vscode-ng-language-service/integration/pre_standalone_project/package.json @@ -0,0 +1,8 @@ +{ + "name": "angular-ls-integration-test-project", + "private": true, + "dependencies": { + "@angular/common": "18.2.10", + "@angular/core": "18.2.10" + } +} diff --git a/vscode-ng-language-service/integration/pre_standalone_project/tsconfig.json b/vscode-ng-language-service/integration/pre_standalone_project/tsconfig.json new file mode 100644 index 00000000000..3e9457d1876 --- /dev/null +++ b/vscode-ng-language-service/integration/pre_standalone_project/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "moduleResolution": "node", + "experimentalDecorators": true, + "target": "es2015", + "strict": true, + "typeRoots": [ + "node_modules/@types" + ] + }, + "angularCompilerOptions": { + "strictTemplates": true, + "strictInjectionParameters": true + } +} diff --git a/vscode-ng-language-service/integration/project/BUILD.bazel b/vscode-ng-language-service/integration/project/BUILD.bazel new file mode 100644 index 00000000000..96485469c73 --- /dev/null +++ b/vscode-ng-language-service/integration/project/BUILD.bazel @@ -0,0 +1,35 @@ +load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin") +load("@npm//:defs.bzl", "npm_link_all_packages") +load("@npm//vscode-ng-language-service/integration/project:ng-packagr/package_json.bzl", ng_packagr_bin = "bin") + +npm_link_all_packages(name = "node_modules") + +copy_to_bin( + name = "project_srcs", + srcs = glob(["**"]), +) + +ng_packagr_bin.ng_packagr( + name = "dist", + srcs = [ + ":node_modules", + ":project_srcs", + ], + args = [ + "-p", + "libs/post/ng-package.json", + "-c", + "libs/post/tsconfig.json", + ], + chdir = package_name(), + out_dirs = ["dist"], +) + +filegroup( + name = "project", + srcs = [ + ":dist", + ":project_srcs", + ], + visibility = ["//vscode-ng-language-service/integration:__subpackages__"], +) diff --git a/vscode-ng-language-service/integration/project/app/app.component.ts b/vscode-ng-language-service/integration/project/app/app.component.ts new file mode 100644 index 00000000000..23414950826 --- /dev/null +++ b/vscode-ng-language-service/integration/project/app/app.component.ts @@ -0,0 +1,12 @@ +import {Component, EventEmitter, Input, Output} from '@angular/core'; + +@Component({ + selector: 'my-app', + template: `

Hello {{name}}

`, + standalone: false, +}) +export class AppComponent { + name = 'Angular'; + @Input() appInput = ''; + @Output() appOutput = new EventEmitter(); +} diff --git a/vscode-ng-language-service/integration/project/app/app.module.ts b/vscode-ng-language-service/integration/project/app/app.module.ts new file mode 100644 index 00000000000..2dd0bddb476 --- /dev/null +++ b/vscode-ng-language-service/integration/project/app/app.module.ts @@ -0,0 +1,13 @@ +import {CommonModule} from '@angular/common'; +import {NgModule} from '@angular/core'; +import {PostModule} from 'post'; + +import {AppComponent} from './app.component'; +import {FooComponent} from './foo.component'; + +@NgModule({ + imports: [CommonModule, PostModule], + declarations: [AppComponent, FooComponent], + bootstrap: [AppComponent], +}) +export class AppModule {} diff --git a/vscode-ng-language-service/integration/project/app/bar.component.ts b/vscode-ng-language-service/integration/project/app/bar.component.ts new file mode 100644 index 00000000000..9d67660bcaa --- /dev/null +++ b/vscode-ng-language-service/integration/project/app/bar.component.ts @@ -0,0 +1,19 @@ +import {Component} from '@angular/core'; + +@Component({ + selector: 'baz-component', + template: `

Hello {{name}}

`, + standalone: true, +}) +export class BazComponent { + name = 'Angular'; +} + +@Component({ + selector: 'bar-component', + template: `<`, + standalone: true, +}) +export class BarComponent { + name = 'Angular'; +} diff --git a/vscode-ng-language-service/integration/project/app/foo.component.html b/vscode-ng-language-service/integration/project/app/foo.component.html new file mode 100644 index 00000000000..83020b15e36 --- /dev/null +++ b/vscode-ng-language-service/integration/project/app/foo.component.html @@ -0,0 +1,7 @@ +{{title | uppercase}} + + subtitle + {{sig()}} + {{x.sig()}} + + diff --git a/vscode-ng-language-service/integration/project/app/foo.component.ts b/vscode-ng-language-service/integration/project/app/foo.component.ts new file mode 100644 index 00000000000..74f32e8f128 --- /dev/null +++ b/vscode-ng-language-service/integration/project/app/foo.component.ts @@ -0,0 +1,17 @@ +import {Component, signal} from '@angular/core'; + +@Component({ + templateUrl: 'foo.component.html', + standalone: false, +}) +export class FooComponent { + title = 'Foo Component'; + sig = signal(1); + x = { + sig: signal(1), + }; + /** returns 1 */ + method() { + return 1; + } +} diff --git a/vscode-ng-language-service/integration/project/libs/post/ng-package.json b/vscode-ng-language-service/integration/project/libs/post/ng-package.json new file mode 100644 index 00000000000..86c8cce00b1 --- /dev/null +++ b/vscode-ng-language-service/integration/project/libs/post/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/post", + "lib": { + "entryFile": "src/index.ts" + } +} \ No newline at end of file diff --git a/vscode-ng-language-service/integration/project/libs/post/package.json b/vscode-ng-language-service/integration/project/libs/post/package.json new file mode 100644 index 00000000000..42094bbe71c --- /dev/null +++ b/vscode-ng-language-service/integration/project/libs/post/package.json @@ -0,0 +1,10 @@ +{ + "name": "post", + "version": "0.0.1", + "peerDependencies": { + "@angular/core": "^13.0.0" + }, + "dependencies": { + "tslib": "^2.3.0" + } +} \ No newline at end of file diff --git a/vscode-ng-language-service/integration/project/libs/post/src/index.ts b/vscode-ng-language-service/integration/project/libs/post/src/index.ts new file mode 100644 index 00000000000..93f9e29cd8c --- /dev/null +++ b/vscode-ng-language-service/integration/project/libs/post/src/index.ts @@ -0,0 +1 @@ +export * from './lib/post.component'; diff --git a/vscode-ng-language-service/integration/project/libs/post/src/lib/post.component.ts b/vscode-ng-language-service/integration/project/libs/post/src/lib/post.component.ts new file mode 100644 index 00000000000..6a621ab517c --- /dev/null +++ b/vscode-ng-language-service/integration/project/libs/post/src/lib/post.component.ts @@ -0,0 +1,15 @@ +import {Component, NgModule} from '@angular/core'; + +@Component({ + selector: 'lib-post', + template: '{{random}}', +}) +export class PostComponent { + random = Math.random(); +} + +@NgModule({ + declarations: [PostComponent], + exports: [PostComponent], +}) +export class PostModule {} diff --git a/vscode-ng-language-service/integration/project/libs/post/tsconfig.json b/vscode-ng-language-service/integration/project/libs/post/tsconfig.json new file mode 100644 index 00000000000..6399a9ed163 --- /dev/null +++ b/vscode-ng-language-service/integration/project/libs/post/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.json", + "files": [], + "include": [ + "**/*.ts" + ], + "compilerOptions": { + "outDir": "../../tsc-dist/post", + "rootDir": ".", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "sourceMap": true, + "types": [] + }, +} \ No newline at end of file diff --git a/vscode-ng-language-service/integration/project/package.json b/vscode-ng-language-service/integration/project/package.json new file mode 100644 index 00000000000..0cd007752fb --- /dev/null +++ b/vscode-ng-language-service/integration/project/package.json @@ -0,0 +1,19 @@ +{ + "name": "angular-ls-integration-test-project", + "private": true, + "dependencies": { + "@angular/common": "18.1.0-rc.0", + "@angular/compiler": "18.1.0-rc.0", + "@angular/compiler-cli": "18.1.0-rc.0", + "@angular/core": "18.1.0-rc.0", + "rxjs": "6.6.7", + "zone.js": "0.11.5" + }, + "devDependencies": { + "ng-packagr": "^18.0.0-next.0", + "typescript": "~5.5.3" + }, + "scripts": { + "build": "ng-packagr -p libs/post/ng-package.json -c libs/post/tsconfig.json" + } +} diff --git a/vscode-ng-language-service/integration/project/tsconfig.json b/vscode-ng-language-service/integration/project/tsconfig.json new file mode 100644 index 00000000000..cfecdf22a23 --- /dev/null +++ b/vscode-ng-language-service/integration/project/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "moduleResolution": "node", + "experimentalDecorators": true, + "target": "es2015", + "strict": true, + "typeRoots": [ + "node_modules/@types" + ], + "baseUrl": ".", + "paths": { + "post": [ + "dist/post" + ] + } + }, + "angularCompilerOptions": { + "strictTemplates": true, + "typeCheckHostBindings": true, + "strictInjectionParameters": true + } +} diff --git a/vscode-ng-language-service/integration/test_constants.ts b/vscode-ng-language-service/integration/test_constants.ts new file mode 100644 index 00000000000..eb8e03a1149 --- /dev/null +++ b/vscode-ng-language-service/integration/test_constants.ts @@ -0,0 +1,27 @@ +import {join, resolve} from 'path'; + +import {convertPathToFileUrl} from './lsp/test_utils'; + +export const IS_BAZEL = !!process.env['TEST_TARGET']; +export const PACKAGE_ROOT = IS_BAZEL ? resolve(__dirname, '..') : resolve(__dirname, '../..'); +export const SERVER_PATH = IS_BAZEL + ? join(PACKAGE_ROOT, 'server', 'index.js') + : join(PACKAGE_ROOT, 'dist', 'npm', 'server', 'index.js'); +export const PROJECT_PATH = join(PACKAGE_ROOT, 'integration', 'project'); +export const PRE_STANDALONE_PROJECT_PATH = join( + PACKAGE_ROOT, + 'integration', + 'pre_standalone_project', +); + +export const APP_COMPONENT = join(PROJECT_PATH, 'app', 'app.component.ts'); +export const APP_COMPONENT_URI = convertPathToFileUrl(APP_COMPONENT); +export const BAR_COMPONENT = join(PROJECT_PATH, 'app', 'bar.component.ts'); +export const BAR_COMPONENT_URI = convertPathToFileUrl(BAR_COMPONENT); +export const APP_COMPONENT_MODULE = join(PROJECT_PATH, 'app', 'app.module.ts'); +export const APP_COMPONENT_MODULE_URI = convertPathToFileUrl(APP_COMPONENT_MODULE); +export const FOO_TEMPLATE = join(PROJECT_PATH, 'app', 'foo.component.html'); +export const FOO_TEMPLATE_URI = convertPathToFileUrl(FOO_TEMPLATE); +export const FOO_COMPONENT = join(PROJECT_PATH, 'app', 'foo.component.ts'); +export const FOO_COMPONENT_URI = convertPathToFileUrl(FOO_COMPONENT); +export const TSCONFIG = join(PROJECT_PATH, 'tsconfig.json'); diff --git a/vscode-ng-language-service/integration/tsconfig.json b/vscode-ng-language-service/integration/tsconfig.json new file mode 100644 index 00000000000..cbbad09fd92 --- /dev/null +++ b/vscode-ng-language-service/integration/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "rootDirs": [ + "..", + "dist" + ] + }, +} \ No newline at end of file diff --git a/vscode-ng-language-service/integration/tsconfig.tsbuildinfo b/vscode-ng-language-service/integration/tsconfig.tsbuildinfo new file mode 100644 index 00000000000..1598a02cd87 --- /dev/null +++ b/vscode-ng-language-service/integration/tsconfig.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./test_constants.ts","./e2e/completion_spec.ts","./e2e/definition_spec.ts","./e2e/helper.ts","./e2e/hover_spec.ts","./e2e/index.ts","./e2e/jasmine.ts","./lsp/ivy_spec.ts","./lsp/test_utils.ts","./pre_apf_project/app/app.component.ts","./pre_apf_project/app/app.module.ts","./pre_apf_project/app/foo.component.ts","./pre_standalone_project/app/app.component.ts","./pre_standalone_project/app/app.module.ts","./pre_standalone_project/app/foo.component.ts","./project/app/app.component.ts","./project/app/app.module.ts","./project/app/bar.component.ts","./project/app/foo.component.ts","./project/dist/post/index.d.ts","./project/dist/post/lib/post.component.d.ts","./project/libs/post/src/index.ts","./project/libs/post/src/lib/post.component.ts","./workspace/projects/demo/src/app/app.component.ts","./workspace/projects/demo/src/app/app.module.ts"],"errors":true,"version":"5.9.2"} \ No newline at end of file diff --git a/vscode-ng-language-service/integration/workspace/BUILD.bazel b/vscode-ng-language-service/integration/workspace/BUILD.bazel new file mode 100644 index 00000000000..8971cec78dc --- /dev/null +++ b/vscode-ng-language-service/integration/workspace/BUILD.bazel @@ -0,0 +1,12 @@ +load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages(name = "node_modules") + +copy_to_bin( + name = "workspace", + srcs = glob(["**"]), + visibility = [ + "//vscode-ng-language-service/server/src/tests:__pkg__", + ], +) diff --git a/vscode-ng-language-service/integration/workspace/package.json b/vscode-ng-language-service/integration/workspace/package.json new file mode 100644 index 00000000000..1364c261829 --- /dev/null +++ b/vscode-ng-language-service/integration/workspace/package.json @@ -0,0 +1,12 @@ +{ + "name": "workspace", + "private": true, + "dependencies": { + "@angular/common": "13.3.9", + "@angular/compiler": "13.3.9", + "@angular/compiler-cli": "13.3.9", + "@angular/core": "13.3.9", + "rxjs": "6.6.7", + "zone.js": "0.11.5" + } +} diff --git a/vscode-ng-language-service/integration/workspace/projects/demo/src/app/app.component.ts b/vscode-ng-language-service/integration/workspace/projects/demo/src/app/app.component.ts new file mode 100644 index 00000000000..60ebb41954f --- /dev/null +++ b/vscode-ng-language-service/integration/workspace/projects/demo/src/app/app.component.ts @@ -0,0 +1,10 @@ +import {Component} from '@angular/core'; + +@Component({ + selector: 'app-root', + template: `

Welcome to {{title}}!

`, + styles: [], +}) +export class AppComponent { + title = 'demo'; +} diff --git a/vscode-ng-language-service/integration/workspace/projects/demo/src/app/app.module.ts b/vscode-ng-language-service/integration/workspace/projects/demo/src/app/app.module.ts new file mode 100644 index 00000000000..f47aed7ca57 --- /dev/null +++ b/vscode-ng-language-service/integration/workspace/projects/demo/src/app/app.module.ts @@ -0,0 +1,10 @@ +import {NgModule} from '@angular/core'; + +import {AppComponent} from './app.component'; + +@NgModule({ + declarations: [AppComponent], + providers: [], + bootstrap: [AppComponent], +}) +export class AppModule {} diff --git a/vscode-ng-language-service/integration/workspace/projects/demo/tsconfig.json b/vscode-ng-language-service/integration/workspace/projects/demo/tsconfig.json new file mode 100644 index 00000000000..923867fb4a5 --- /dev/null +++ b/vscode-ng-language-service/integration/workspace/projects/demo/tsconfig.json @@ -0,0 +1,14 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/app", + "types": [] + }, + "files": [ + "src/app/app.module.ts", + ], + "include": [ + "src/**/*.d.ts" + ] +} diff --git a/vscode-ng-language-service/integration/workspace/tsconfig.json b/vscode-ng-language-service/integration/workspace/tsconfig.json new file mode 100644 index 00000000000..a1df478821c --- /dev/null +++ b/vscode-ng-language-service/integration/workspace/tsconfig.json @@ -0,0 +1,30 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist/out-tsc", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "sourceMap": true, + "declaration": false, + "downlevelIteration": true, + "experimentalDecorators": true, + "moduleResolution": "node", + "importHelpers": true, + "target": "es2015", + "module": "es2020", + "lib": [ + "es2018", + "dom" + ] + }, + "angularCompilerOptions": { + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true, + "typeCheckHostBindings": true + } +} diff --git a/vscode-ng-language-service/package.json b/vscode-ng-language-service/package.json new file mode 100644 index 00000000000..8b56347e8c3 --- /dev/null +++ b/vscode-ng-language-service/package.json @@ -0,0 +1,303 @@ +{ + "name": "ng-template", + "displayName": "Angular Language Service", + "description": "Editor services for Angular templates", + "version": "20.2.2", + "publisher": "Angular", + "icon": "angular.png", + "license": "MIT", + "keywords": [ + "Angular", + "multi-root ready" + ], + "engines": { + "vscode": "^1.74.3" + }, + "capabilities": { + "untrustedWorkspaces": { + "supported": true + }, + "virtualWorkspaces": { + "supported": "limited", + "description": "The Language Server Protocol does not support remote file systems. Functionality is limited to syntax highlighting only." + } + }, + "categories": [ + "Programming Languages" + ], + "contributes": { + "commands": [ + { + "command": "angular.restartNgServer", + "title": "Restart Angular Language server", + "category": "Angular" + }, + { + "command": "angular.openLogFile", + "title": "Open Angular Server log", + "category": "Angular" + }, + { + "command": "angular.getTemplateTcb", + "title": "View Template Typecheck Block", + "category": "Angular" + }, + { + "command": "angular.goToComponentWithTemplateFile", + "title": "Go to component", + "category": "Angular" + }, + { + "command": "angular.goToTemplateForComponent", + "title": "Go to template", + "category": "Angular" + } + ], + "submenus": [ + { + "id": "angular.submenu", + "label": "Angular" + } + ], + "menus": { + "commandPalette": [ + { + "command": "angular.goToComponentWithTemplateFile", + "when": "editorLangId == html && !virtualWorkspace" + }, + { + "command": "angular.goToTemplateForComponent", + "when": "editorLangId == typescript && !virtualWorkspace" + }, + { + "command": "angular.getTemplateTcb", + "when": "!virtualWorkspace" + } + ], + "editor/context": [ + { + "submenu": "angular.submenu", + "group": "angular" + } + ], + "angular.submenu": [ + { + "when": "(resourceLangId == html || resourceLangId == typescript) && !virtualWorkspace", + "command": "angular.getTemplateTcb", + "group": "debug" + }, + { + "when": "resourceLangId == html && !virtualWorkspace", + "command": "angular.goToComponentWithTemplateFile", + "group": "navigation" + }, + { + "when": "resourceLangId == typescript && !virtualWorkspace", + "command": "angular.goToTemplateForComponent", + "group": "navigation" + } + ] + }, + "configuration": { + "title": "Angular Language Service", + "properties": { + "angular.log": { + "type": "string", + "enum": [ + "off", + "terse", + "normal", + "verbose" + ], + "default": "off", + "description": "Enables logging of the Angular server to a file. This log can be used to diagnose Angular Server issues. The log may contain file paths, source code, and other potentially sensitive information from your project." + }, + "angular.enable-strict-mode-prompt": { + "type": "boolean", + "default": true, + "markdownDescription": "Prompt to enable the [strictTemplates](https://angular.dev/reference/configs/angular-compiler-options#stricttemplates) flag in [angularCompilerOptions](https://angular.dev/reference/configs/angular-compiler-options). Note that strict mode is only available when using Ivy." + }, + "angular.trace.server": { + "type": "string", + "scope": "window", + "enum": [ + "off", + "messages", + "verbose" + ], + "default": "off", + "description": "Traces the communication between VS Code and the Angular language server." + }, + "angular.suggest.includeAutomaticOptionalChainCompletions": { + "type": "boolean", + "default": true, + "markdownDescription": "Enable showing completions on potentially undefined values that insert an optional chain call. Requires TS 3.7+ and strict null checks to be enabled." + }, + "angular.suggest.includeCompletionsWithSnippetText": { + "type": "boolean", + "default": true, + "markdownDescription": "Enable snippet completions from Angular language server. Requires using TypeScript 4.3+ in the workspace." + }, + "angular.suggest.autoImports": { + "type": "boolean", + "default": true, + "markdownDescription": "Enable/disable auto import suggestions for the exported Angular components from the current project." + }, + "angular.forceStrictTemplates": { + "type": "boolean", + "default": false, + "markdownDescription": "Enabling this option will force the language service to use [strictTemplates](https://angular.dev/reference/configs/angular-compiler-options#stricttemplates) and ignore the user settings in the `tsconfig.json`." + }, + "angular.suppressAngularDiagnosticCodes": { + "type": "string", + "default": "", + "markdownDescription": "A comma-separated list of error codes in templates whose diagnostics should be ignored." + } + } + }, + "grammars": [ + { + "path": "./syntaxes/inline-template.json", + "scopeName": "inline-template.ng", + "injectTo": [ + "source.ts" + ], + "embeddedLanguages": { + "text.html.derivative": "html", + "source.css": "css", + "source.js": "javascript" + } + }, + { + "path": "./syntaxes/inline-styles.json", + "scopeName": "inline-styles.ng", + "injectTo": [ + "source.ts" + ], + "embeddedLanguages": { + "source.css.scss": "scss" + } + }, + { + "path": "./syntaxes/template.json", + "scopeName": "template.ng", + "injectTo": [ + "text.html.derivative", + "source.ts" + ], + "embeddedLanguages": { + "text.html": "html", + "source.css": "css", + "expression.ng": "javascript" + } + }, + { + "path": "./syntaxes/template-blocks.json", + "scopeName": "template.blocks.ng", + "injectTo": [ + "text.html.derivative", + "source.ts" + ], + "embeddedLanguages": { + "text.html": "html", + "control.block.expression.ng": "javascript", + "control.block.body.ng": "html" + } + }, + { + "path": "./syntaxes/let-declaration.json", + "scopeName": "template.let.ng", + "injectTo": [ + "text.html.derivative", + "source.ts" + ] + }, + { + "path": "./syntaxes/host-object-literal.json", + "scopeName": "host-object-literal.ng", + "injectTo": [ + "source.ts" + ], + "embeddedLanguages": { + "text.html.derivative": "html", + "expression.ng": "javascript", + "source.ts": "typescript" + } + }, + { + "path": "./syntaxes/template-tag.json", + "scopeName": "template.tag.ng", + "injectTo": [ + "text.html.derivative", + "source.ts" + ] + }, + { + "path": "./syntaxes/expression.json", + "scopeName": "expression.ng" + } + ] + }, + "activationEvents": [ + "onLanguage:html", + "onLanguage:typescript" + ], + "main": "./bazel-bin/client/src/extension", + "scripts": { + "ng-dev": "tsx --tsconfig .ng-dev/tsconfig.json node_modules/@angular/ng-dev/bundles/cli.mjs", + "build:syntaxes": "bazel run //vscode-ng-language-service/syntaxes:syntaxes", + "format": "pnpm ng-dev format all", + "watch": "ibazel build //vscode-ng-language-service:index.js //vscode-ng-language-service/server:index.js", + "package": "pnpm bazel build //vscode-ng-language-service:npm --config=release", + "test": "bazel test --test_tag_filters=unit_test //vscode-ng-language-service/...", + "test:watch": "ibazel test --test_tag_filters=unit_test //vscode-ng-language-service/...", + "test:lsp": "bazel test --test_output=streamed //vscode-ng-language-service/integration/lsp:test", + "test:e2e": "bazel test --test_output=streamed //vscode-ng-language-service/integration/e2e:test", + "test:inspect-client": "bazel run --config=debug //vscode-ng-language-service/client/src/tests:test", + "test:inspect-common": "bazel run --config=debug //vscode-ng-language-service/common/tests:test", + "test:inspect-server": "bazel run --config=debug //vscode-ng-language-service/server/src/tests:test", + "test:inspect-syntaxes": "bazel run --config=debug //vscode-ng-language-service/syntaxes/test:test" + }, + "dependencies": { + "@angular/language-service": "20.3.0", + "typescript": "5.9.2", + "vscode-html-languageservice": "^4.2.5", + "vscode-jsonrpc": "6.0.0", + "vscode-languageclient": "7.0.0", + "vscode-languageserver": "7.0.0", + "vscode-languageserver-textdocument": "^1.0.7", + "vscode-uri": "3.0.7" + }, + "devDependencies": { + "@angular/core": "^20.0.0-rc.2", + "@types/jasmine": "3.10.7", + "@types/node": "18.19.39", + "@types/vscode": "1.67.0", + "balanced-match": "1.0.2", + "brace-expansion": "1.1.12", + "concat-map": "0.0.1", + "cross-env": "^7.0.3", + "esbuild": "0.14.39", + "jasmine-core": "5.10.0", + "jasmine-reporters": "2.5.2", + "jasmine": "5.10.0", + "lru-cache": "6.0.0", + "minimatch": "3.1.2", + "prettier": "2.7.1", + "rxjs": "6.6.7", + "semver": "7.7.2", + "source-map-support": "0.5.21", + "ts-node": "^10.8.1", + "vsce": "1.100.1", + "vscode-languageserver-protocol": "3.16.0", + "vscode-languageserver-types": "3.16.0", + "vscode-nls": "5.2.0", + "vscode-test": "1.6.1", + "vscode-tmgrammar-test": "0.0.11", + "yallist": "4.0.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/angular/vscode-ng-language-service" + } +} diff --git a/vscode-ng-language-service/server/BUILD.bazel b/vscode-ng-language-service/server/BUILD.bazel new file mode 100644 index 00000000000..61293c055e0 --- /dev/null +++ b/vscode-ng-language-service/server/BUILD.bazel @@ -0,0 +1,91 @@ +load("@aspect_bazel_lib//lib:expand_template.bzl", "expand_template_rule") +load("@aspect_rules_esbuild//esbuild:defs.bzl", "esbuild") +load("@aspect_rules_ts//ts:defs.bzl", "ts_config") + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + visibility = [ + "//vscode-ng-language-service/integration:__subpackages__", + "//vscode-ng-language-service/server:__subpackages__", + ], + deps = [ + "//vscode-ng-language-service:tsconfig", + ], +) + +esbuild( + name = "banner", + config = { + # This is described in more detail in the `server/banner.ts` but this line actually overrides + # the built-in `require` function by adding a line at the bottom of the generated banner code + # to assign the override function to the `require` name. + "footer": {"js": "require = requireOverride;"}, + # Workaround for https://github.com/aspect-build/rules_esbuild/issues/58 + "resolveExtensions": [".js"], + }, + entry_point = "//vscode-ng-language-service/server/src:banner.js", + external = [ + "path", + ], + format = "cjs", + # Do not enable minification. It seems to break the extension on Windows (with WSL). See #1198. + minify = False, + platform = "node", + sourcemap = "external", + deps = [ + "//:node_modules/source-map-support", + "//vscode-ng-language-service/server/src", + ], +) + +esbuild( + name = "index", + srcs = [ + ":banner", + ], + config = "esbuild.mjs", + entry_point = "//vscode-ng-language-service/server/src:server.js", + external = [ + "fs", + "path", + "typescript/lib/tsserverlibrary", + "vscode-languageserver", + "vscode-uri", + "vscode-jsonrpc", + "vscode-languageserver-textdocument", + "vscode-html-languageservice", + ], + format = "cjs", + # Do not enable minification. It seems to break the extension on Windows (with WSL). See #1198. + minify = False, + platform = "node", + sourcemap = "external", + visibility = [ + "//vscode-ng-language-service/integration:__subpackages__", + ], + deps = [ + "//:node_modules/source-map-support", + "//vscode-ng-language-service/server/src", + ], +) + +expand_template_rule( + name = "package_json_expanded", + out = "package_expanded.json", + stamp_substitutions = { + "0.0.0-PLACEHOLDER": "{{BUILD_SCM_VERSION}}", + }, + template = "package.json", +) + +filegroup( + name = "npm_files", + srcs = [ + "README.md", + "bin/ngserver", + "index.js", + "package_expanded.json", + ], + visibility = ["//vscode-ng-language-service:__pkg__"], +) diff --git a/vscode-ng-language-service/server/README.md b/vscode-ng-language-service/server/README.md new file mode 100644 index 00000000000..ae4d5b35c74 --- /dev/null +++ b/vscode-ng-language-service/server/README.md @@ -0,0 +1,6 @@ +# @angular/language-server + +This package contains the Language Server Protocol ([LSP](https://microsoft.github.io/language-server-protocol/)) implementation of the Angular Language Service. + +## Usage +See `node index.js --help` diff --git a/vscode-ng-language-service/server/bin/ngserver b/vscode-ng-language-service/server/bin/ngserver new file mode 100644 index 00000000000..4d45527ed41 --- /dev/null +++ b/vscode-ng-language-service/server/bin/ngserver @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('../index.js') diff --git a/vscode-ng-language-service/server/esbuild.mjs b/vscode-ng-language-service/server/esbuild.mjs new file mode 100644 index 00000000000..44d23297ded --- /dev/null +++ b/vscode-ng-language-service/server/esbuild.mjs @@ -0,0 +1,7 @@ +import {readFileSync} from 'fs'; +const banner = readFileSync('vscode-ng-language-service/server/banner.js', 'utf8'); +export default { + banner: {js: banner}, + // Workaround for https://github.com/aspect-build/rules_esbuild/issues/58 + resolveExtensions: ['.js'], +}; diff --git a/vscode-ng-language-service/server/package.json b/vscode-ng-language-service/server/package.json new file mode 100644 index 00000000000..4e492271265 --- /dev/null +++ b/vscode-ng-language-service/server/package.json @@ -0,0 +1,31 @@ +{ + "name": "@angular/language-server", + "description": "LSP server for Angular Language Service", + "version": "0.0.0-PLACEHOLDER", + "repository": { + "type": "git", + "url": "https://github.com/angular/vscode-ng-language-service.git" + }, + "author": "Angular", + "license": "MIT", + "engines": { + "node": "^20.11.1 || ^22.11.0" + }, + "bin": { + "ngserver": "./bin/ngserver" + }, + "dependencies": { + "@angular/language-service": "20.2.0-rc.1", + "vscode-html-languageservice": "^4.2.5", + "vscode-jsonrpc": "6.0.0", + "vscode-languageserver": "7.0.0", + "vscode-languageserver-textdocument": "^1.0.7", + "vscode-uri": "3.0.7" + }, + "devDependencies": { + "test": "3.3.0" + }, + "publishConfig": { + "registry": "https://wombat-dressing-room.appspot.com" + } +} diff --git a/vscode-ng-language-service/server/src/BUILD.bazel b/vscode-ng-language-service/server/src/BUILD.bazel new file mode 100644 index 00000000000..2b9e20ac454 --- /dev/null +++ b/vscode-ng-language-service/server/src/BUILD.bazel @@ -0,0 +1,28 @@ +load("@aspect_rules_ts//ts:defs.bzl", "ts_project") + +ts_project( + name = "src", + srcs = glob(["*.ts"]), + declaration = True, + source_map = True, + tags = [ + # Because the testing intentionally reaches into the output directories and crosses the sandbox + # boundaries, we need to explicitly make sure that this target is built locally so the testing + # can find expected files. + "no-remote-exec", + ], + tsconfig = "//vscode-ng-language-service/server:tsconfig", + visibility = [ + "//vscode-ng-language-service/server:__subpackages__", + ], + deps = [ + "//:node_modules/@angular/language-service", + "//:node_modules/typescript", + "//vscode-ng-language-service:node_modules/@types/node", + "//vscode-ng-language-service:node_modules/vscode-html-languageservice", + "//vscode-ng-language-service:node_modules/vscode-languageserver", + "//vscode-ng-language-service:node_modules/vscode-languageserver-textdocument", + "//vscode-ng-language-service:node_modules/vscode-uri", + "//vscode-ng-language-service/common", + ], +) diff --git a/vscode-ng-language-service/server/src/banner.ts b/vscode-ng-language-service/server/src/banner.ts new file mode 100644 index 00000000000..a631918acae --- /dev/null +++ b/vscode-ng-language-service/server/src/banner.ts @@ -0,0 +1,40 @@ +/** + * @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 {parseCommandLine} from './cmdline_utils'; +import {resolveTsServer} from './version_provider'; + +const originalRequire = require; + +/** + * This method provides a custom implementation for the require function to resolve + * `typescript` module at runtime. We provide this as an override to the built-in + * 'require' method using the banner funcionality of esbuild. That is, esbuild will + * compile the server and add this banner to the top of the compilation so any place + * in the server code that uses `require` will get routed through this override. + * + * Refer also to `esbuild` rules in the server package, the `bannerConfig` which overrides the + * `require` using the `footer` option, and the `serverConfig` which provides the banner code at the + * top of the server output using the `banner` option. + * + * @param moduleName The module to resolve + * @returns + */ +export function requireOverride(moduleName: string) { + const TSSERVER = 'typescript/lib/tsserverlibrary'; + if (moduleName === 'typescript') { + throw new Error(`Import '${TSSERVER}' instead of 'typescript'`); + } + if (moduleName === TSSERVER) { + const {tsProbeLocations, tsdk} = parseCommandLine(process.argv); + moduleName = resolveTsServer(tsProbeLocations, tsdk).resolvedPath; + } + return originalRequire(moduleName); +} + +requireOverride.resolve = originalRequire.resolve; diff --git a/vscode-ng-language-service/server/src/cmdline_utils.ts b/vscode-ng-language-service/server/src/cmdline_utils.ts new file mode 100644 index 00000000000..0e2f019170e --- /dev/null +++ b/vscode-ng-language-service/server/src/cmdline_utils.ts @@ -0,0 +1,124 @@ +/** + * @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 + */ + +function findArgument(argv: string[], argName: string): string | undefined { + const index = argv.indexOf(argName); + if (index < 0 || index === argv.length - 1) { + return; + } + return argv[index + 1]; +} + +function findArgumentWithDefault( + argv: string[], + argName: string, + defaultValue: T, +): T | string | undefined { + const index = argv.indexOf(argName); + if (index < 0) { + return defaultValue; + } + if (index === argv.length - 1) { + return undefined; + } + const argValue = argv[index + 1]; + if (argValue.startsWith('-')) { + return undefined; + } else { + return argValue; + } +} + +function parseBooleanArgument(argv: string[], argName: string): boolean { + const argValue = findArgumentWithDefault(argv, argName, 'true'); + if (argValue === undefined || argValue === 'true') { + return true; + } + return false; +} + +function parseStringArray(argv: string[], argName: string): string[] { + const arg = findArgument(argv, argName); + if (!arg) { + return []; + } + return arg.split(','); +} + +function hasArgument(argv: string[], argName: string): boolean { + return argv.includes(argName); +} + +interface CommandLineOptions { + help: boolean; + logFile?: string; + logVerbosity?: string; + logToConsole: boolean; + ngProbeLocations: string[]; + tsProbeLocations: string[]; + tsdk: string | null; + includeAutomaticOptionalChainCompletions: boolean; + includeCompletionsWithSnippetText: boolean; + includeCompletionsForModuleExports: boolean; + forceStrictTemplates: boolean; + disableBlockSyntax: boolean; + disableLetSyntax: boolean; + angularCoreVersion?: string; + suppressAngularDiagnosticCodes?: string; +} + +export function parseCommandLine(argv: string[]): CommandLineOptions { + return { + help: hasArgument(argv, '--help'), + logFile: findArgument(argv, '--logFile'), + logVerbosity: findArgument(argv, '--logVerbosity'), + logToConsole: hasArgument(argv, '--logToConsole'), + ngProbeLocations: parseStringArray(argv, '--ngProbeLocations'), + tsProbeLocations: parseStringArray(argv, '--tsProbeLocations'), + tsdk: findArgument(argv, '--tsdk') ?? null, + includeAutomaticOptionalChainCompletions: hasArgument( + argv, + '--includeAutomaticOptionalChainCompletions', + ), + includeCompletionsWithSnippetText: hasArgument(argv, '--includeCompletionsWithSnippetText'), + includeCompletionsForModuleExports: parseBooleanArgument( + argv, + '--includeCompletionsForModuleExports', + ), + forceStrictTemplates: hasArgument(argv, '--forceStrictTemplates'), + disableBlockSyntax: hasArgument(argv, '--disableBlockSyntax'), + disableLetSyntax: hasArgument(argv, '--disableLetSyntax'), + angularCoreVersion: findArgument(argv, '--angularCoreVersion'), + suppressAngularDiagnosticCodes: findArgument(argv, '--suppressAngularDiagnosticCodes'), + }; +} + +export function generateHelpMessage(argv: string[]) { + return `Angular Language Service that implements the Language Server Protocol (LSP). + + Usage: ${argv[0]} ${argv[1]} [options] + + Options: + --help: Prints help message. + --logFile: Location to log messages. Logging to file is disabled if not provided. + --logVerbosity: terse|normal|verbose|requestTime. See ts.server.LogLevel. + --logToConsole: Enables logging to console via 'window/logMessage'. Defaults to false. + --ngProbeLocations: Path of @angular/language-service. Required. + --tsProbeLocations: Path of typescript. Required. + --includeAutomaticOptionalChainCompletions: Shows completions on potentially undefined values that insert an optional chain call. Requires TS 3.7+ and strict null checks to be enabled. + --includeCompletionsWithSnippetText: Enables snippet completions from Angular language server; + --forceStrictTemplates: Forces the language service to use strictTemplates and ignore the user settings in the 'tsconfig.json'. + --suppressAngularDiagnosticCodes: A comma-separated list of error codes in templates whose diagnostics should be ignored. + + Additional options supported by vscode-languageserver: + --clientProcessId=: Automatically kills the server if the client process dies. + --node-ipc: Communicate using Node's IPC. This is the default. + --stdio: Communicate over stdin/stdout. + --socket=: Communicate using Unix socket. + `; +} diff --git a/vscode-ng-language-service/server/src/completion.ts b/vscode-ng-language-service/server/src/completion.ts new file mode 100644 index 00000000000..07fd78eb015 --- /dev/null +++ b/vscode-ng-language-service/server/src/completion.ts @@ -0,0 +1,177 @@ +/** + * @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 * as ts from 'typescript/lib/tsserverlibrary'; +import * as lsp from 'vscode-languageserver'; + +import {lspPositionToTsPosition, tsTextSpanToLspRange} from './utils'; + +// TODO: Move this to `@angular/language-service`. +enum CompletionKind { + attribute = 'attribute', + block = 'block', + htmlAttribute = 'html attribute', + property = 'property', + component = 'component', + directive = 'directive', + element = 'element', + event = 'event', + key = 'key', + method = 'method', + pipe = 'pipe', + type = 'type', + reference = 'reference', + variable = 'variable', + entity = 'entity', +} + +/** + * Information about the origin of an `lsp.CompletionItem`, which is stored in the + * `lsp.CompletionItem.data` property. + * + * On future requests for details about a completion item, this information allows the language + * service to determine the context for the original completion request, in order to return more + * detailed results. + */ +export interface NgCompletionOriginData { + /** + * Used to validate the type of `lsp.CompletionItem.data` is correct, since that field is type + * `any`. + */ + kind: 'ngCompletionOriginData'; + + filePath: string; + position: lsp.Position; + + tsData?: ts.CompletionEntryData; +} + +/** + * Extract `NgCompletionOriginData` from an `lsp.CompletionItem` if present. + */ +export function readNgCompletionData(item: lsp.CompletionItem): NgCompletionOriginData | null { + if (item.data === undefined) { + return null; + } + + // Validate that `item.data.kind` is actually the right tag, and narrow its type in the process. + const data: NgCompletionOriginData | {kind?: never} = item.data; + if (data.kind !== 'ngCompletionOriginData') { + return null; + } + + return data; +} + +/** + * Convert Angular's CompletionKind to LSP CompletionItemKind. + * @param kind Angular's CompletionKind + */ +function ngCompletionKindToLspCompletionItemKind(kind: CompletionKind): lsp.CompletionItemKind { + switch (kind) { + case CompletionKind.attribute: + case CompletionKind.htmlAttribute: + case CompletionKind.property: + case CompletionKind.event: + return lsp.CompletionItemKind.Property; + case CompletionKind.directive: + case CompletionKind.component: + case CompletionKind.element: + case CompletionKind.key: + return lsp.CompletionItemKind.Class; + case CompletionKind.method: + return lsp.CompletionItemKind.Method; + case CompletionKind.pipe: + return lsp.CompletionItemKind.Function; + case CompletionKind.type: + return lsp.CompletionItemKind.Interface; + case CompletionKind.reference: + case CompletionKind.variable: + return lsp.CompletionItemKind.Variable; + case CompletionKind.block: + return lsp.CompletionItemKind.Keyword; + case CompletionKind.entity: + default: + return lsp.CompletionItemKind.Text; + } +} + +/** + * Convert ts.CompletionEntry to LSP Completion Item. + * @param entry completion entry + * @param position position where completion is requested. + * @param scriptInfo + */ +export function tsCompletionEntryToLspCompletionItem( + entry: ts.CompletionEntry, + position: lsp.Position, + scriptInfo: ts.server.ScriptInfo, +): lsp.CompletionItem { + const item = lsp.CompletionItem.create(entry.name); + // Even though `entry.kind` is typed as ts.ScriptElementKind, it's + // really Angular's CompletionKind. This is because ts.ScriptElementKind does + // not sufficiently capture the HTML entities. + // This is a limitation of being a tsserver plugin. + const kind = entry.kind as unknown as CompletionKind; + item.kind = ngCompletionKindToLspCompletionItemKind(kind); + item.detail = entry.kind; + item.sortText = entry.sortText; + // Text that actually gets inserted to the document. It could be different + // from 'entry.name'. For example, a method name could be 'greet', but the + // insertText is 'greet()'. + const insertText = entry.insertText || entry.name; + item.textEdit = createTextEdit(scriptInfo, entry, position, insertText); + + // If the user enables the config `includeAutomaticOptionalChainCompletions`, the `insertText` + // range will include the dot. the `insertText` should be assigned to the `filterText` to filter + // the completion items. + item.filterText = entry.insertText; + if (entry.isSnippet) { + item.insertTextFormat = lsp.InsertTextFormat.Snippet; + } + + item.data = { + kind: 'ngCompletionOriginData', + filePath: scriptInfo.fileName, + position, + tsData: entry.data, + } as NgCompletionOriginData; + return item; +} + +function createTextEdit( + scriptInfo: ts.server.ScriptInfo, + entry: ts.CompletionEntry, + position: lsp.Position, + insertText: string, +) { + if (entry.replacementSpan === undefined) { + return lsp.TextEdit.insert(position, insertText); + } else { + /** + * The Angular Language Service does not return `InsertReplaceEdit`. + * There is no need to allow the developer to choose how to insert the completion. + * + * For example, `
+ +
+
+
+ + + + + + + + + +
+
+ + + + + + + + +
+ + + + + + + +
+
+ +
+
+
+
+ +
+
+
+ +
+
+
+
+ + + +
+
+ +
diff --git a/vscode-ng-language-service/syntaxes/test/data/template-tag.html.snap b/vscode-ng-language-service/syntaxes/test/data/template-tag.html.snap new file mode 100644 index 00000000000..2370abb74ec --- /dev/null +++ b/vscode-ng-language-service/syntaxes/test/data/template-tag.html.snap @@ -0,0 +1,772 @@ +> +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html punctuation.definition.ng-binding-name.begin.html +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html +# ^^^^^^^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html entity.other.ng-binding-name.ngStyle.html +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.property.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.property.html string.quoted.html punctuation.definition.string.begin.html +# ^ template.tag.ng meta.ng-binding.property.html expression.ng +# ^ template.tag.ng meta.ng-binding.property.html expression.ng string.quoted.single.ts punctuation.definition.string.begin.ts +# ^^^^^^^^^^^^ template.tag.ng meta.ng-binding.property.html expression.ng string.quoted.single.ts +# ^ template.tag.ng meta.ng-binding.property.html expression.ng string.quoted.single.ts punctuation.definition.string.end.ts +# ^^ template.tag.ng meta.ng-binding.property.html expression.ng +# ^ template.tag.ng meta.ng-binding.property.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.property.html expression.ng +# ^ template.tag.ng meta.ng-binding.property.html expression.ng keyword.operator.arithmetic.ts +# ^ template.tag.ng meta.ng-binding.property.html expression.ng +# ^ template.tag.ng meta.ng-binding.property.html expression.ng constant.numeric.decimal.ts +# ^ template.tag.ng meta.ng-binding.property.html expression.ng +# ^ template.tag.ng meta.ng-binding.property.html expression.ng keyword.operator.arithmetic.ts +# ^ template.tag.ng meta.ng-binding.property.html expression.ng +# ^ template.tag.ng meta.ng-binding.property.html expression.ng constant.numeric.decimal.ts +# ^ template.tag.ng meta.ng-binding.property.html expression.ng +# ^ template.tag.ng meta.ng-binding.property.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +>
+#^ template.tag.ng meta.ng-binding.property.html expression.ng meta.array.literal.ts meta.brace.square.ts +# ^ template.tag.ng meta.ng-binding.property.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html entity.other.ng-binding-name.style.right.%.html +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html entity.other.ng-binding-name.style.right.%.html punctuation.accessor.html +# ^^^^^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html entity.other.ng-binding-name.style.right.%.html +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html entity.other.ng-binding-name.style.right.%.html punctuation.accessor.html +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html entity.other.ng-binding-name.style.right.%.html +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.property.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.property.html string.quoted.html punctuation.definition.string.begin.html +# ^^^ template.tag.ng meta.ng-binding.property.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.property.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^^^^^^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html entity.other.ng-binding-name.@animation.trigger.html +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html entity.other.ng-binding-name.@animation.trigger.html punctuation.accessor.html +# ^^^^^^^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html entity.other.ng-binding-name.@animation.trigger.html +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.property.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.property.html string.quoted.html punctuation.definition.string.begin.html +# ^^^ template.tag.ng meta.ng-binding.property.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.property.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +> +#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html punctuation.definition.ng-binding-name.begin.html +# ^^^^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html entity.other.ng-binding-name.attr.aria-label.html +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html entity.other.ng-binding-name.attr.aria-label.html punctuation.accessor.html +# ^^^^^^^^^^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html entity.other.ng-binding-name.attr.aria-label.html +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.property.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.property.html string.quoted.html punctuation.definition.string.begin.html +# ^^^ template.tag.ng meta.ng-binding.property.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.property.html string.quoted.html punctuation.definition.string.end.html +# ^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^^^^^^^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html entity.other.ng-binding-name.my-property.html +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.property.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.property.html string.quoted.html punctuation.definition.string.begin.html +# ^^^ template.tag.ng meta.ng-binding.property.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.property.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^^^^^^^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html entity.other.ng-binding-name.my_property.html +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.property.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.property.html string.quoted.html punctuation.definition.string.begin.html +# ^^^ template.tag.ng meta.ng-binding.property.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.property.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^^^^^^^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html entity.other.ng-binding-name.myProperty$.html +# ^ template.tag.ng meta.ng-binding.property.html entity.other.attribute-name.html entity.other.ng-binding-name.property.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.property.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.property.html string.quoted.html punctuation.definition.string.begin.html +# ^^^ template.tag.ng meta.ng-binding.property.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.property.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +>
+#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ template.tag.ng +>
+#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ template.tag.ng +> +> +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ template.tag.ng +> +#^^^^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html entity.other.ng-binding-name.click.html +# ^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.event.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.event.html string.quoted.html punctuation.definition.string.begin.html +# ^^^^^^^ template.tag.ng meta.ng-binding.event.html expression.ng entity.name.function.ts +# ^ template.tag.ng meta.ng-binding.event.html expression.ng meta.brace.round.ts +# ^^^^^^ template.tag.ng meta.ng-binding.event.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.event.html expression.ng meta.brace.round.ts +# ^ template.tag.ng meta.ng-binding.event.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^^^^ template.tag.ng +> +#^^^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^^^^^^^^^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html entity.other.ng-binding-name.ngModelChange.html +# ^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.event.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.event.html string.quoted.html punctuation.definition.string.begin.html +# ^^^^^^^^^^^^^ template.tag.ng meta.ng-binding.event.html expression.ng entity.name.function.ts +# ^ template.tag.ng meta.ng-binding.event.html expression.ng meta.brace.round.ts +# ^^^^^^ template.tag.ng meta.ng-binding.event.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.event.html expression.ng meta.brace.round.ts +# ^ template.tag.ng meta.ng-binding.event.html string.quoted.html punctuation.definition.string.end.html +# ^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^^^^^^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html entity.other.ng-binding-name.@animation.done.html +# ^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html entity.other.ng-binding-name.@animation.done.html punctuation.accessor.html +# ^^^^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html entity.other.ng-binding-name.@animation.done.html +# ^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.event.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.event.html string.quoted.html punctuation.definition.string.begin.html +# ^^^^^^^^^^^^^^^ template.tag.ng meta.ng-binding.event.html expression.ng entity.name.function.ts +# ^ template.tag.ng meta.ng-binding.event.html expression.ng meta.brace.round.ts +# ^^^^^^ template.tag.ng meta.ng-binding.event.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.event.html expression.ng meta.brace.round.ts +# ^ template.tag.ng meta.ng-binding.event.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +>
+#^ template.tag.ng meta.ng-binding.event.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html punctuation.definition.ng-binding-name.begin.html +# ^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html +# ^^^^^^^^^^^^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html entity.other.ng-binding-name.extraSpacing.html +# ^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html +# ^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.event.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.event.html string.quoted.html punctuation.definition.string.begin.html +# ^^^^^^^^^^^^^^ template.tag.ng meta.ng-binding.event.html expression.ng entity.name.function.ts +# ^ template.tag.ng meta.ng-binding.event.html expression.ng meta.brace.round.ts +# ^^^^^^ template.tag.ng meta.ng-binding.event.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.event.html expression.ng meta.brace.round.ts +# ^ template.tag.ng meta.ng-binding.event.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^^^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html entity.other.ng-binding-name.myEvent.html +# ^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.event.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.event.html string.quoted.html punctuation.definition.string.begin.html +# ^^^^^^^^^ template.tag.ng meta.ng-binding.event.html expression.ng entity.name.function.ts +# ^ template.tag.ng meta.ng-binding.event.html expression.ng meta.brace.round.ts +# ^^^^^^ template.tag.ng meta.ng-binding.event.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.event.html expression.ng meta.brace.round.ts +# ^ template.tag.ng meta.ng-binding.event.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^^^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^^^^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html entity.other.ng-binding-name.my-event.html +# ^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.event.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.event.html string.quoted.html punctuation.definition.string.begin.html +# ^^^^^^^^^ template.tag.ng meta.ng-binding.event.html expression.ng entity.name.function.ts +# ^ template.tag.ng meta.ng-binding.event.html expression.ng meta.brace.round.ts +# ^^^^^^ template.tag.ng meta.ng-binding.event.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.event.html expression.ng meta.brace.round.ts +# ^ template.tag.ng meta.ng-binding.event.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^^^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^^^^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html entity.other.ng-binding-name.my_event.html +# ^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.event.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.event.html string.quoted.html punctuation.definition.string.begin.html +# ^^^^^^^^^ template.tag.ng meta.ng-binding.event.html expression.ng entity.name.function.ts +# ^ template.tag.ng meta.ng-binding.event.html expression.ng meta.brace.round.ts +# ^^^^^^ template.tag.ng meta.ng-binding.event.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.event.html expression.ng meta.brace.round.ts +# ^ template.tag.ng meta.ng-binding.event.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^^^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^^^^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html entity.other.ng-binding-name.myEvent$.html +# ^ template.tag.ng meta.ng-binding.event.html entity.other.attribute-name.html entity.other.ng-binding-name.event.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.event.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.event.html string.quoted.html punctuation.definition.string.begin.html +# ^^^^^^^^^ template.tag.ng meta.ng-binding.event.html expression.ng entity.name.function.ts +# ^ template.tag.ng meta.ng-binding.event.html expression.ng meta.brace.round.ts +# ^^^^^^ template.tag.ng meta.ng-binding.event.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.event.html expression.ng meta.brace.round.ts +# ^ template.tag.ng meta.ng-binding.event.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^^^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ template.tag.ng +> +> +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ template.tag.ng +> +#^^^^^^^^ template.tag.ng +# ^^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html entity.other.ng-binding-name.click.html +# ^^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.two-way.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.two-way.html string.quoted.html punctuation.definition.string.begin.html +# ^^^^^^^^^ template.tag.ng meta.ng-binding.two-way.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.two-way.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html punctuation.definition.ng-binding-name.begin.html +# ^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html +# ^^^^^^^^^^^^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html entity.other.ng-binding-name.extraSpacing.html +# ^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html +# ^^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.two-way.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.two-way.html string.quoted.html punctuation.definition.string.begin.html +# ^^^^^^^^^^^^ template.tag.ng meta.ng-binding.two-way.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.two-way.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^^^^^^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html entity.other.ng-binding-name.@animation.done.html +# ^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html entity.other.ng-binding-name.@animation.done.html punctuation.accessor.html +# ^^^^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html entity.other.ng-binding-name.@animation.done.html +# ^^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.two-way.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.two-way.html string.quoted.html punctuation.definition.string.begin.html +# ^^^^^^^^^ template.tag.ng meta.ng-binding.two-way.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.two-way.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^ template.tag.ng +# ^^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^^^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html entity.other.ng-binding-name.my-prop.html +# ^^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.two-way.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.two-way.html string.quoted.html punctuation.definition.string.begin.html +# ^^^^^^ template.tag.ng meta.ng-binding.two-way.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.two-way.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^^^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^ template.tag.ng +# ^^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^^^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html entity.other.ng-binding-name.my_prop.html +# ^^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.two-way.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.two-way.html string.quoted.html punctuation.definition.string.begin.html +# ^^^^^^ template.tag.ng meta.ng-binding.two-way.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.two-way.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^^^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^ template.tag.ng +# ^^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^^^^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html entity.other.ng-binding-name.$my_prop.html +# ^^ template.tag.ng meta.ng-binding.two-way.html entity.other.attribute-name.html entity.other.ng-binding-name.two-way.html punctuation.definition.ng-binding-name.end.html +# ^ template.tag.ng meta.ng-binding.two-way.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.two-way.html string.quoted.html punctuation.definition.string.begin.html +# ^^^^^^ template.tag.ng meta.ng-binding.two-way.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.two-way.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^^^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ template.tag.ng +> +> +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ template.tag.ng +> +#^^^^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^^^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html entity.other.ng-binding-name.ngModel.html +# ^ template.tag.ng meta.ng-binding.template.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.begin.html +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html entity.other.ng-binding-name.ngFor.html +# ^ template.tag.ng meta.ng-binding.template.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.begin.html +# ^^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.expression.of.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^^^^^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html entity.other.ng-binding-name.custom-if.html +# ^ template.tag.ng meta.ng-binding.template.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.begin.html +# ^^^^ template.tag.ng meta.ng-binding.template.html expression.ng constant.language.boolean.true.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.comparison.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng constant.language.boolean.false.ts +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^^^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^^^^^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html entity.other.ng-binding-name.custom_if.html +# ^ template.tag.ng meta.ng-binding.template.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.begin.html +# ^^^^ template.tag.ng meta.ng-binding.template.html expression.ng constant.language.boolean.true.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.comparison.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng constant.language.boolean.false.ts +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^^^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^^^^^^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html entity.other.ng-binding-name.custom_$if.html +# ^ template.tag.ng meta.ng-binding.template.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.begin.html +# ^^^^ template.tag.ng meta.ng-binding.template.html expression.ng constant.language.boolean.true.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.comparison.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng constant.language.boolean.false.ts +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^^^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ template.tag.ng +> +> +#^^^^^^^^^^^^^^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^^^^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html entity.other.ng-binding-name.ngFor.html +# ^ template.tag.ng meta.ng-binding.template.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.begin.html +# ^^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.assignment.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng punctuation.terminator.statement.ts +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html entity.other.ng-binding-name.ngFor.html +# ^ template.tag.ng meta.ng-binding.template.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.begin.html +# ^^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.assignment.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^^^^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html entity.other.ng-binding-name.ngFor.html +# ^ template.tag.ng meta.ng-binding.template.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.begin.html +# ^^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.assignment.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng punctuation.terminator.statement.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng punctuation.terminator.statement.ts +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html entity.other.ng-binding-name.ngFor.html +# ^ template.tag.ng meta.ng-binding.template.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.begin.html +# ^^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.assignment.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng punctuation.terminator.statement.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html entity.other.ng-binding-name.ngFor.html +# ^ template.tag.ng meta.ng-binding.template.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.begin.html +# ^^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.expression.of.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng punctuation.terminator.statement.ts +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html entity.other.ng-binding-name.ngFor.html +# ^ template.tag.ng meta.ng-binding.template.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.begin.html +# ^^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.expression.of.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^^^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html entity.other.ng-binding-name.ngFor.html +# ^ template.tag.ng meta.ng-binding.template.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.begin.html +# ^^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.expression.of.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng punctuation.terminator.statement.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.as.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng entity.name.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng punctuation.terminator.statement.ts +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html entity.other.ng-binding-name.ngFor.html +# ^ template.tag.ng meta.ng-binding.template.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.begin.html +# ^^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.expression.of.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng punctuation.terminator.statement.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.as.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng entity.name.type.ts +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html punctuation.definition.ng-binding-name.begin.html +# ^^^^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html entity.other.ng-binding-name.ngIf.html +# ^ template.tag.ng meta.ng-binding.template.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.begin.html +# ^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.as.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng entity.name.type.ts +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html entity.other.ng-binding-name.ngFor.html +# ^ template.tag.ng meta.ng-binding.template.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.begin.html +# ^^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.expression.of.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng punctuation.terminator.statement.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.assignment.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng punctuation.terminator.statement.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.assignment.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html entity.other.ng-binding-name.ngFor.html +# ^ template.tag.ng meta.ng-binding.template.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.begin.html +# ^^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.expression.of.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng punctuation.terminator.statement.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.assignment.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng punctuation.terminator.statement.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.assignment.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng punctuation.terminator.statement.ts +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html entity.other.ng-binding-name.ngFor.html +# ^ template.tag.ng meta.ng-binding.template.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.begin.html +# ^^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.expression.of.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng punctuation.terminator.statement.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.assignment.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng punctuation.terminator.statement.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.as.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^ template.tag.ng meta.ng-binding.template.html expression.ng entity.name.type.ts +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html entity.other.ng-binding-name.ngFor.html +# ^ template.tag.ng meta.ng-binding.template.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.begin.html +# ^^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.expression.of.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng punctuation.terminator.statement.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.assignment.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng punctuation.terminator.statement.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.as.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^ template.tag.ng meta.ng-binding.template.html expression.ng entity.name.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng punctuation.terminator.statement.ts +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +> +> +#^^^^^^^^^^^^^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html punctuation.definition.ng-binding-name.begin.html +# ^^^^^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html entity.other.ng-binding-name.ngFor.html +# ^ template.tag.ng meta.ng-binding.template.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.begin.html +# ^^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.expression.of.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng punctuation.terminator.statement.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.as.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng entity.name.type.ts +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +>
+#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ template.tag.ng +> +#^^^^^^^^^^^^^^ template.tag.ng +>
+#^^^^^ template.tag.ng +# ^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html punctuation.definition.ng-binding-name.begin.html +# ^^^^ template.tag.ng meta.ng-binding.template.html entity.other.attribute-name.html entity.other.ng-binding-name.template.html entity.other.ng-binding-name.ngIf.html +# ^ template.tag.ng meta.ng-binding.template.html punctuation.separator.key-value.html +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.begin.html +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng variable.other.readwrite.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng keyword.operator.logical.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^^^^ template.tag.ng meta.ng-binding.template.html expression.ng entity.name.function.pipe.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^^ template.tag.ng meta.ng-binding.template.html expression.ng storage.type.as.ts +# ^ template.tag.ng meta.ng-binding.template.html expression.ng +# ^ template.tag.ng meta.ng-binding.template.html expression.ng entity.name.type.ts +# ^ template.tag.ng meta.ng-binding.template.html string.quoted.html punctuation.definition.string.end.html +# ^^^^^^^^ template.tag.ng +> \ No newline at end of file diff --git a/vscode-ng-language-service/syntaxes/test/data/template.html b/vscode-ng-language-service/syntaxes/test/data/template.html new file mode 100644 index 00000000000..66e72e520ba --- /dev/null +++ b/vscode-ng-language-service/syntaxes/test/data/template.html @@ -0,0 +1,2 @@ + +
{{ call(1 + 2 + 3) }}
\ No newline at end of file diff --git a/vscode-ng-language-service/syntaxes/test/data/template.html.snap b/vscode-ng-language-service/syntaxes/test/data/template.html.snap new file mode 100644 index 00000000000..991d0a6cc48 --- /dev/null +++ b/vscode-ng-language-service/syntaxes/test/data/template.html.snap @@ -0,0 +1,21 @@ +> +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ template.ng +>
{{ call(1 + 2 + 3) }}
+#^^^^^ template.ng +# ^^ template.ng punctuation.definition.block.ts +# ^ template.ng expression.ng +# ^^^^ template.ng expression.ng entity.name.function.ts +# ^ template.ng expression.ng meta.brace.round.ts +# ^ template.ng expression.ng constant.numeric.decimal.ts +# ^ template.ng expression.ng +# ^ template.ng expression.ng keyword.operator.arithmetic.ts +# ^ template.ng expression.ng +# ^ template.ng expression.ng constant.numeric.decimal.ts +# ^ template.ng expression.ng +# ^ template.ng expression.ng keyword.operator.arithmetic.ts +# ^ template.ng expression.ng +# ^ template.ng expression.ng constant.numeric.decimal.ts +# ^ template.ng expression.ng meta.brace.round.ts +# ^ template.ng expression.ng +# ^^ template.ng punctuation.definition.block.ts +# ^^^^^^^ template.ng \ No newline at end of file diff --git a/vscode-ng-language-service/syntaxes/test/driver.ts b/vscode-ng-language-service/syntaxes/test/driver.ts new file mode 100644 index 00000000000..0ebd73e246f --- /dev/null +++ b/vscode-ng-language-service/syntaxes/test/driver.ts @@ -0,0 +1,65 @@ +#!/usr/bin/env node +// Usage: +// pnpm test:syntaxes [options] +// +// Options: +// -u update snapshot files (always passes) + +import 'jasmine'; + +import * as cp from 'child_process'; +import * as fs from 'fs'; +import * as path from 'path'; +import {cases} from './cases'; + +interface TestCase { + name: string; + scopeName: string; + grammarFiles: string[]; + testFile: string; +} + +const dummyGrammarDir = 'syntaxes/test/dummy'; +const DUMMY_GRAMMARS = fs + .readdirSync(dummyGrammarDir) + .map((file: string) => path.join(dummyGrammarDir, file)); + +/** Wraps node's spawn in a Promise. */ +function spawn(...args: Parameters): Promise { + const child = cp.spawn(...args); + + return new Promise((resolve, reject) => { + child.on('exit', (code: number) => { + if (code === 0) resolve(0); + else reject(code); + }); + }); +} + +async function snapshotTest({scopeName, grammarFiles, testFile}: TestCase): Promise { + grammarFiles.push(...DUMMY_GRAMMARS); + const grammarOptions = grammarFiles.reduce((acc, file) => [...acc, '-g', file], [] as string[]); + const extraArgs = process.argv.slice(3); + const options = [ + 'node_modules/vscode-tmgrammar-test/dist/src/snapshot.js', + '-s', + scopeName, + ...grammarOptions, + '-t', + testFile, + ...extraArgs, + ]; + + return spawn('node', options, {stdio: 'inherit' /* use parent process IO */}).catch( + (code) => code, + ); +} + +describe('snapshot tests', () => { + for (let tc of cases) { + it(`should work for ${tc.name}`, async () => { + const ec = await snapshotTest(tc); + expect(ec).toBe(0); + }); + } +}); diff --git a/vscode-ng-language-service/syntaxes/test/dummy/css.tmLanguage-dummy.json b/vscode-ng-language-service/syntaxes/test/dummy/css.tmLanguage-dummy.json new file mode 100644 index 00000000000..5e6df8ec8c6 --- /dev/null +++ b/vscode-ng-language-service/syntaxes/test/dummy/css.tmLanguage-dummy.json @@ -0,0 +1,4 @@ +{ + "comment": "Dummy CSS TextMate grammar for use in testing", + "scopeName": "source.css" +} diff --git a/vscode-ng-language-service/syntaxes/test/dummy/html.tmLanguage-dummy.json b/vscode-ng-language-service/syntaxes/test/dummy/html.tmLanguage-dummy.json new file mode 100644 index 00000000000..bd67f348232 --- /dev/null +++ b/vscode-ng-language-service/syntaxes/test/dummy/html.tmLanguage-dummy.json @@ -0,0 +1,4 @@ +{ + "comment": "Dummy HTML TextMate grammar for use in testing", + "scopeName": "text.html.derivative" +} diff --git a/vscode-ng-language-service/syntaxes/test/dummy/js.tmLanguage-dummy.json b/vscode-ng-language-service/syntaxes/test/dummy/js.tmLanguage-dummy.json new file mode 100644 index 00000000000..ac9f4a19156 --- /dev/null +++ b/vscode-ng-language-service/syntaxes/test/dummy/js.tmLanguage-dummy.json @@ -0,0 +1,4 @@ +{ + "comment": "Dummy JS TextMate grammar for use in testing", + "scopeName": "source.js" +} diff --git a/vscode-ng-language-service/syntaxes/test/dummy/scss.tmLanguage-dummy.json b/vscode-ng-language-service/syntaxes/test/dummy/scss.tmLanguage-dummy.json new file mode 100644 index 00000000000..a7d61be1385 --- /dev/null +++ b/vscode-ng-language-service/syntaxes/test/dummy/scss.tmLanguage-dummy.json @@ -0,0 +1,4 @@ +{ + "comment": "Dummy SCSS TextMate grammar for use in testing", + "scopeName": "source.css.scss" +} diff --git a/vscode-ng-language-service/syntaxes/test/tsconfig.json b/vscode-ng-language-service/syntaxes/test/tsconfig.json new file mode 100644 index 00000000000..b4e5ff40ae0 --- /dev/null +++ b/vscode-ng-language-service/syntaxes/test/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "resolveJsonModule": true, + } +} diff --git a/vscode-ng-language-service/syntaxes/tsconfig.json b/vscode-ng-language-service/syntaxes/tsconfig.json new file mode 100644 index 00000000000..df890c60543 --- /dev/null +++ b/vscode-ng-language-service/syntaxes/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "types": ["node"] + } +} diff --git a/vscode-ng-language-service/tsconfig.json b/vscode-ng-language-service/tsconfig.json new file mode 100644 index 00000000000..afd1fdb28fb --- /dev/null +++ b/vscode-ng-language-service/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "es2017", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "strict": true, + "esModuleInterop": true, + "declaration": true, + "skipLibCheck": true + } +}