Add the runtime primitives `ɵɵboundaryCreate` and `ɵɵboundaryUpdate` to
the core instructions, which handle synchronous view destruction and
provide the `ON_ERROR` interceptor hooks.
Also include the initial compiler AST representations for the new syntax
including the Lexer tokenization and HTML Parser integration. This lays
the foundational structure for `@boundary` prior to code generation.
Co-authored-by: Matthieu Riegler <kyro38@gmail.com>
PR Close#70463
Only touch tsconfig files for targets that use an Angular builder, including community ones like Nx, so non-Angular projects in mixed workspaces are left alone.
Fixes#69837
Currently the standalone migration only copies symbols referenced from the NgModule metadata into the main file. Top-level `registerLocaleData` calls, and the default imports they depend on, are dropped silently when the module file is pruned, which breaks locale resolution at runtime with a "Missing locale data" error.
Copies top-level `registerLocaleData` calls from the file of the bootstrapped module into the main file, and adds support for carrying over default imports which were previously skipped silently by the reference resolution.
Fixes#50886
We keep getting PRs that target single usages of `hasOwnProperty` and we have ~100 of them. These changes aim to address the issue centrally by swapping out all the instances and adding a lint rule against introducing new ones.
The control flow migration determines whether an `*ngIf` uses a `then`
and/or `else` clause by regex matching the raw microsyntax string for
the literal keywords `then`/`else`. The regexes only checked that the
keyword was preceded by a non-word character, but not that it was
followed by one.
As a result, a template reference name that merely starts with `then`
(e.g. `else thenBlock`) or `else` was misidentified as the `then`/`else`
keyword itself. This caused the migration to take the wrong code path
(e.g. then+else instead of else-only), which in turn made
`getTemplateName()` compute a `slice(start, end)` with `start > end`,
producing an empty template name. That empty placeholder was never
resolved and was silently emitted as an invalid
`<ng-template [ngTemplateOutlet]=""></ng-template>`, dropping the
original template content without any warning.
Add a negative lookahead `(?![\w\d])` to both regexes so `then`/`else`
are only matched as whole keywords, not as a prefix of a longer
template reference name.
Fixes#69914
When only some NgClass usages are migrated (partial migration),
the NgClass import should be preserved in the module/component
imports if it is still used elsewhere.
Currently, signal migration schematics in best effort mode doesn't do a very good job migrating input writes when there is a nested property access in templates.
In event handlers, no attempt is made to migrate a nested access in the left-hand-side of assignments or anything in their right-hand-side. E.g., nothing will happen here:
`(ngModelChange)="inputD.prop = $event + inputF"`.
Additionally, when a migration attempt is made, parentheses are often incorrectly placed on the parent, both in event handlers and two-way bindings:
`(ngModelChange)="inputC = $event"` is migrated to `(ngModelChange)="inputC = $event()"`.
`[(ngModel)]="inputB.prop.prop"` is migrated to `[(ngModel)]="inputB.prop().prop"`.
When `rootDir` was set in a project's tsconfig (e.g. `rootDir: "src"`),
tsurge-based migrations would fail because `projectRoot` was derived from
`rootDir`, causing `rootRelativePath` to be computed relative to `src/`
instead of the workspace root. This produced paths like `app/app.ts`
instead of `src/app/app.ts`, which the DevKit tree could not resolve.
Fix by overriding `info.projectRoot` to `absoluteFrom(info.program.getCurrentDirectory())`
immediately after program creation, ensuring workspace-relative paths are
used for all tree updates.
Add `@content(propName)` blocks for passing template content to foreign
component properties by name. Previously, only a single set of direct children
could be passed to a foreign component via the default `children` property.
With this change, developers can project distinct template content to multiple
specific properties on the foreign component:
```html
<FancyButton [label]="title">
@content(icon) {
<span>Icon</span>
}
@content(description) {
<span>Description text</span>
}
<span>Other children</span>
</FancyButton>
```
Specifically:
- Add support to the HTML lexer for `@content` blocks.
- Introduce `ContentBlock` AST node to represent `@content` blocks.
- Implement validation ensuring `@content` blocks have exactly one parameter
representing a valid JS identifier.
- Throw an error during ingestion if a `@content` block is placed anywhere
other than as a direct child of a foreign component.
- Map `@content` blocks to properties of the props object passed to
`ɵɵforeignComponent`.
- Update compliance and unit tests to cover these changes.
```
The following:
`@Output() someChange = new EventEmitter<void>();`
is correctly migrated to:
`readonly someChange = output<void>();`
However, a TODO is incorrectly inserted for subsequent emissions from
`someChange`, stating that an argument is expected.
Currently if a `@for` loop doesn't have a `track` expression we don't produce an AST for it at all which means no type checking and language service support for it.
These changes make it so we produce the AST anyways since it gives the user more tools to resolve the issue (e.g. autocompletion when writing the `track` expression).
Removes the @angular/compiler import from the safe optional chaining migration. This import is not needed as the compiler package import is side-effectful and has no functional use here.
This migration ensure that existing code is wrapped by the `$safeNavigationMigration` magic function when necessary to maintain the pre-exisiting behavior of exisiting optional chaining expressions.
becomes input + linkedSignal
When a component has both a model() property and a conflicting output property (e.g., foo model + fooChange output), this migration converts the model() to an input() + linkedSignal() pattern to avoid naming conflicts.
Fixes#67340
This fixes an issue where when removing NgClass from the imports array of a component, an extra trailing comma would be left behind if it was the last element in that component`.
This fixes an issue where when removing NgClass from the imports array of a component, an extra trailing comma would be left behind if it was the last element in that component`.
This commit updates provideClientHydration to automatically enable incremental hydration by default. It also introduces a new withNoIncrementalHydration feature for opting out, adds conflict safety checks, and includes a schematic migration.
Decouple `SymbolBuilder` from the full `BoundTarget` interface by introducing a purpose-built `SymbolBoundTarget` interface containing only the 4 methods required for symbol resolution. This eliminates the need for the large, pass-through `BoundTargetAdapter` and further isolates `SymbolBuilder` from compiler-internal implementation details.
Also minimize `TypeCheckableDirectiveMetaAdapter` by redefining `SymbolDirectiveMeta` to not extend `DirectiveMeta`, exposing only the properties actually used by `SymbolBuilder`.
Removed dead code `getDirectiveMeta` in `template_symbol_builder.ts` which was unused.
These changes improve maintainability and ensure a cleaner architecture by strictly defining the boundaries of what `SymbolBuilder` needs from the rest of the system.
By limiting the required inputs to only what's necessary for the implementation, we make it easier to re-use
the implementation between different compiler architectures
This updates the SymbolBuilder to no longer use ts.TypeChecker internally to
build symbols for the language service. These lookups are deferred/done later
using the newly expanded template type checker API.
Avoid substring matching on importClause.getText() which caused suffix collisions (e.g., BarComponent vs FooBarComponent). Use AST-based matching for default and named (including aliased) imports to reliably resolve the correct import path when generating loadComponent.
Fix inject migration in multi-project workspace. The inject migration doesn't work when targeting one of the projects due to either not finding any files in other projects or considering them external thus it throws a SchematicsException
Fixes: #66074
This fixes an issue where when removing NgStyle from the imports array of a component, an extra trailing comma would be left behind if it was the last element in that component`.
Currently the migration that add `ChangeDetectionStrategy.Eager` to components tries to add the properties as last in the object literal. This can be tricky, because TS doesn't reflect the commas in the AST so we need have to do brittle string lookups to know where to insert it.
These changes switch to inserting the property before the last pre-existing property which should be a bit more robust.
Exisiting applications will be migrated to keep using the XHR backend to prevent any breaking changes. `withXhr()` is to the `provideHttpClient` provider function.
`provideRoutes` was deprecated in v15.
BREAKING CHANGE: `provideRoutes()` has been removed. Use `provideRouter()` or `ROUTES` as multi token if necessary.
In v22, `OnPush` becomes the default strategy. To maintain the ChangeDetection behavior of exisiting apps, components without an explicit change detectino strategy will get `Eager` assigned.