A previous PR introduced a new compiler abstraction that tracks *all* known exports and re-exports of Angular traits. This PR harnesses that abstraction in the language service, in order to allow automatic imports of pipes.
PR Close#48354
NgModules can re-export other NgModules, which transitively includes all traits exported by the re-exported NgModule. We want to be able to suggest *all* re-exports of a component when trying to auto-import it.
Previously, we used an approximation when importing from NgModules: we looked at a Component's metadata, and just imported the declaring NgModule. However, this is not technically correct -- the declaring NgModule it is not necessarily the same one that exports it for the current scope. (Indeed, there could be multiple re-exports!) As a replacement, I have implemented a more general solution.
This PR introduces a new class on the template type checker, called `NgModuleIndex`. When queried, it conducts a depth-first-search over the NgModule import/export graph, in order to find all NgModules anywhere in the current dependency graph, as well as all exports of those NgModules. This allows the language service to suggest all of the re-exports, in addition to the original export.
PR Close#48354
`MetadataReaderWithIndex.getKnown` currently returns an iterator. It will be easier to work with for upcoming usages if it returns an array instead.
PR Close#48354
Currently, the auto-import tests are very difficult to debug, because the `expect`ations are buried several function calls deep, and also because the multi-line replacements are hard to deal with. The auto-import tests now use a different approach, which can be easily debugged from the failure message. In addition, several new tests have been added to cover more cases.
PR Close#48354
```ts
@NgModule({
imports: [RouterModule.forRoot([{path: '/enigma', component: EnigmaComponent}])],
providers: [{provide: APP_BASE_HREF, useValue: '/en'}]
})
export class AppModule {}
```
Navigating to `/enigma` will redirect to `/en/igma` not to `/en/enigma` as it expects
Fixes: #45744
PR Close#48489
Class and `InjectionToken`-based guards and resolvers are not as configurable,
are less re-usable, require more boilerplate, cannot be defined inline with the route,
and require more in-depth knowledge of Angular features (`Injectable`/providers).
In short, they're less powerful and more cumbersome.
In addition, continued support increases the API surface which in turn increases
bundle size, code complexity, the learning curve and API surface to teach,
maintenance cost, and cognitive load (needing to grok several different types
of information in a single place).
Lastly, supporting only the `CanXFn` types for guards and `ResolveFn` type
for resolvers in the `Route` interface will enable better code
completion and integration with TypeScript. For example, when writing an
inline functional resolver today, the function is typed as `any` and
does not provide completions for the `ResolveFn` parameters. By
restricting the type to only `ResolveFn`, in the example below
TypeScript would be able to correctly identify the `route` parameter as
`ActivatedRouteSnapshot` and when authoring the inline route, the
language service would be able to autocomplete the function parameters.
```
const userRoute: Route = {
path: 'user/:id',
resolve: {
"user": (route) => inject(UserService).getUser(route.params['id']);
}
};
```
Importantly, this deprecation only affects the support for class and
`InjectionToken` guards at the `Route` definition. `Injectable` classes
and `InjectionToken` providers are _not_ being deprecated in the general
sense. Functional guards are robust enough to even support the existing
class-based guards through a transform:
```
function mapToCanMatch(providers: Array<Type<{canMatch: CanMatchFn}>>): CanMatchFn[] {
return providers.map(provider => (...params) => inject(provider).canMatch(...params));
}
const route = {
path: 'admin',
canMatch: mapToCanMatch([AdminGuard]),
};
```
With regards to tests, because of the ability to map `Injectable`
classes to guard functions as outlined above, nothing _needs_ to change
if projects prefer testing guards the way they do today. Functional
guards can also be written in a way that's either testable with
`runInContext` or by passing mock implementations of dependencies.
For example:
```
export function myGuardWithMockableDeps(
dep1 = inject(MyService),
dep2 = inject(MyService2),
dep3 = inject(MyService3),
) { }
const route = {
path: 'admin',
canActivate: [() => myGuardWithMockableDeps()]
}
// test file
const guardResultWithMockDeps = myGuardWithMockableDeps(mockService1, mockService2, mockService3);
const guardResultWithRealDeps = TestBed.inject(EnvironmentInjector).runInContext(myGuardWithMockableDeps);
```
DEPRECATED: Class and `InjectionToken` guards and resolvers are
deprecated. Instead, write guards as plain JavaScript functions and
inject dependencies with `inject` from `@angular/core`.
PR Close#47924
apply different quality of life improvements to the shadow
css unit tests:
- refactor the tests so that they are nicely divided in multiple files
in a logical manner instead of having most of them all in a single big file
- remove the css normalization logic inconsistently used throughout the tests, which
causes tests to be inconsistent and it also introduced unintuitive checks
- provide a shared shim utility function (instead of re-defining it
multiple times)
- add a `toEqualCss` matcher that can be used in the tests in order to
match css strings without caring about spacing and indentation
PR Close#48443
This commits changes the fetch depth from 1 to 0 in the update-events` and `update-cli-help` actions. This is required as otherwise the PR creation would fail when the forked (https://github.com/angular-robot/angular) is not in sync with (https://github.com/angular/angular) ie the later has commits which are not in the former.
PR Close#48698
Previously, a single curly bracket was used to interpolate the `ANGULAR_CLI_BUILDS_READONLY_GITHUB_TOKEN` value which caused the value not to be provided correctly.
PR Close#48690
Currently the Github action-triggered code uses the `GITHUB_TOKEN`
for querying the CLI snapshot builds repository. This does not work
because the Github actions token is scoped to the orginating
repository, even for queries to a read public repository.
We fix this by using a personal access token. The token is
readonly and only exists to avoid potential rate limiting.
PR Close#48681
The VSCode extension looks for `@angular/language-service/package.json`
using `require`. This currently breaks as of the ESM changes because
we introduced the `exports` field but did not expose the `package.json`.
This commit fixes it.
Co-authored-By: Andrew Scott <atscott@google.com>
Co-authored-By: Dylan Hunn <dylhunn@gmail.com>
PR Close#48678
Fixes a deprecation warning that was being logged by compiler when generating aliases, because we weren't going through `ts.factory` to create an AST node.
PR Close#48652
Similar to the Saucelabs job, the jasmine default timeout can be
increased to avoid the common jasmine timeouts. We cannot control
how fast Selenium e.g. loads a page or not.
PR Close#48671
Prior to this change the universal example was broken as the example type was not retrieved correctly in bazel which caused the `_renameFile` method to be called with incorrect context.
Closes#48664
PR Close#48665
This commit prepares the code of the `BrowserTestingModule` to include the `MockPlatformLocation` by deafult in the future. With this change, the set of providers to add the `MockPlatformLocation` would be disabled by a flag, which will be switched in v16.
PR Close#48651