The compiler wasn't handling `@let` declarations placed inside i18n blocks. The problem is that `assignI18nSlotDependencies` phase assigns the `target` of i18n ops much earlier than the `@let` optimization. If the `@let` ends up getting optimized because it isn't used in any child views, the pointer in the i18n instruction becomes invalid. This hadn't surfaced so far, because we didn't optimize `declareLet` ops, however once we do, we start hitting assertions that the optimized `declareLet` isn't used anywhere.
These changes resolve the issue by moving the i18n phases after the `@let` optimization.
PR Close#60512
We have some code that avoids `storeLet` calls for declarations only used in the same view, however we didn't previously remove the corresponding `declareLet` calls, because of the following case:
```
@let foo = something$ | async; <!-- First in the template -->
{{foo}}
```
Here we need a `TNode` (created by `declareLet`) in order for DI to work correctly. Since this is only required when using pipes, we can optimize away expressions that do not have pipes.
PR Close#60512
As part of the Bazel toolchain migration we noticed that implicit types
generated by the TypeScript compiler sometimes end up referencing types
from other packages (i.e. cross-package imports).
These imports currently work just because the Bazel `ts_library` and
`ng_module` rules automatically inserted a `<amd-module
name="@angular/x" />` into `.d.ts` of packages. This helped TS figure
out how to import a given file. Notably this is custom logic that is not
occuring in vanilla TS or Angular compilations—so we will drop this
magic as part of the toolchain cleanup!
To improve code quality and keep the existing behavior working, we are
doing the following:
- adding a lint rule that reduces the risk of such imports breaking. The
failure scenario without the rule is that API goldens show unexpected
diffs, and types might be duplicated in a different package!
- keeping the `<amd-module` headers, but we manually insert them into
the package entry-points. This should ensure we don't regress
anywhere; while we also improved general safety around this above.
Long-term, isolated declarations or a lint rule from eslint-typescript
can make this even more robust.
PR Close#61312
Updates the template type checker to produce symbols for selectorless nodes. This is necessary for integration into the language service.
PR Close#61240
The template symbol builder works by finding the variables referring to template AST nodes with specific offsets and resolving them to directives. Afterwards it goes through the directives and resolves their host directives.
The problem is that host directives are added with the exact same offsets as their host which means they get added once initially and again when resolving host directives.
These changes resolve the issue by de-duplicating them.
PR Close#61240
In the event of an invalid `schemas` field for an Angular module, an
empty schema array will now be used instead of a fatal error occurring.
A build will still fail in this case with the error reported as a
diagnostic. However, for the language service, this allows the module
to exist in the compiler registry and prevents cascading diagnostics
within an IDE due to "missing" modules/components. The originating
schema related errors will still be reported in the IDE.
PR Close#61220
Based on some recent discussions, these changes remove the logic that resolves selectorless references from variables. It also updates the wording so it's clearer where selectorless references are supported.
PR Close#61158
We have several cases where we need a visitor that traverses both the template and expression ASTs fully. Currently we're re-implementing the visitor each time which means that we need to update multiple visitors every time something changes.
These changes add a single base class that we can reuse to simplify such cases in the future.
PR Close#61158
Fixes that we weren't emitting references to selectorless pipes, because we were checking the name of the pipe, rather than the local name of the symbol.
PR Close#61100
These changes connect the dependency analysis data from the previous commits with the template type checker which allows us to fully type check a selectorless component.
Also includes tests for all of the new selectorless behaviors that have been introduced so far.
PR Close#61100
The `ComponentHandler.resolve` method is ~500 lines and is a bit hard to follow due to some very long `if` statements. These changes split the functionality across several smaller methods to make it easier to manage.
PR Close#61018
Currently to create an `R3TargetBinder`, we have to pass some sort of directive matcher, however we also have a couple of use cases where we use the binder to do analysis that's unrelated to directives (e.g. resolving the `@defer` blocks). In these cases having to create a dummy matcher adds some slight overhead and makes the code harder to reason about since it looks like directive matching may be happening.
These changes update the `R3TargetBinder` to allow for `null` to be passed as the directive matcher.
PR Close#61018
An earlier commit that introduced tracking of selectorless directives to the template binder made it so `getDirectivesOfNode` returns _all_ of the matched directives while a new method called `getOwnedDirectives` would return only the ones brought in by the specific node.
In hindsight, this is likely to cause bugs in the future, because it's unclear whether to reach for `getDirectivesOfNode` or `getOwnedDirectives`. These changes remove `getOwnedDirectives` and make it so in selectorless `getDirectivesOfNode` accepts the directive AST node itself.
Another goal of this refactor is that the TCB shouldn't have to check the `selectorlessEnabled` config option.
PR Close#61018
Adds a new diagnostic that ensures that a standalone component using custom structural directives in a template has the necessary imports for those directives.
Fixes#37322
PR Close#59443
Adds the logic that will generate type checking code in the TCB for the selectorless AST nodes.
Note that we're still missing the logic that determines which symbols are available in the template and exposes them to the template binder. That will come in a future change.
PR Close#60977
Updates the template binder to include information about directives owned by a specific component/directive node and the names of template symbols that don't exist. These will be used when generating the type check block.
PR Close#60977
Updates the `DomSchemaChecker` to require the tag name as a string, rather than the entire DOM node. This makes selectorless a bit easier to intergrate.
PR Close#60977
Updates the template binder to account for the new selectorless AST nodes. This is a prerequisite to supporting template type checking of the new syntax.
PR Close#60952
Updates the target binder to allow either a selector-based or selectorless matcher to be passed in. This will allow us to skip some of the overhead when matching directives to nodes.
PR Close#60952
This commit adds the support for the `in` keyword as a relational operator, with the same precedence as the other relational operators (<,>, <=, >=)
BREAKING CHANGE: 'in' in an expression now refers to the operator
PR Close#58432
Since APF can contain shared chunks, where e.g. `eetemplate` lives, the
`coreHasSymbol` check is no longer reliable. Right now it even prevents
the version range check (that is reliably working) from running because
we detect a `index.d.ts` file but simply don't find the requested
symbol in there (we don't expand exports via type checker).
PR Close#60825
Currently when we transpile the HMR update module, we use the project's compiler options verbatim. This appears to break down with some module types, whereas we have to use a native export.
These changes override the compiler options to ensure that the user's options don't end up breaking HMR.
Fixes#60795.
PR Close#60797
Renames the `hostProperty` instruction to `domProperty` since it's not really host-specific and we can use it for other DOM-specific operations in the future.
PR Close#60608
Currently the TCB generation code doesn't handle targeted events (e.g. `(document:click)`) which ends up binding to the current element and can have type inference implications. These changes take the event's `target` into account.
PR Close#60561
By default, the compiler-cli uses the relative import strategy when
there is no `rootDir` or `rootDirs`. This is expected as everything is
assumed to be somehow reachable through relative imports.
With `rootDirs` that allow for a "virtual file system"-like environment,
the compiler is not necessarily able to always construct proper relative
imports. The compiler includes the `LogicalProjectStrategy` for this
reason. This strategy is able to respect `rootDirs` to construct
relative paths when possible.
This logic currently accidentally triggers when there is a `rootDir`
set. This option is not to be confused with the virtual directory
option called `rootDirs`. The compiler currently confuses this and
accidentally enters this mode when there is just a `rootDir`— breaking
in monorepos that imports can point outside the `rootDir` to e.g. other
compilation unit's `.d.ts` (which is valid; just not `.ts` sources can
live outside the root dir).
This is necessary for our Bazel toolchain migration.
PR Close#60555
Node.js v18 will reach End-of-Life on April 30, 2025, and will no longer be supported in Angular v20.
Node.js Release Schedule: https://github.com/nodejs/release#release-schedule
BREAKING CHANGE:
- Angular no longer supports Node.js v18.
- Node.js versions 22.0 to 22.10 are also no longer supported.
Before upgrading to Angular v20, ensure the Node.js version is at least 20.11.1.
For the full list of supported versions, visit: https://angular.dev/reference/versions
PR Close#60545