As a part of #54154, an old parser behavior came up where two-way bindings were parsed by appending `= $event` to the event side. This was problematic, because it allowed some non-writable expressions to be passed into two-way bindings.
These changes introduce a migration that will change the two-way bindings into two separate input/output bindings that represent the old behavior so that in a future version we can throw a parser error for the invalid expressions.
```ts
// Before
@Component({
template: `<input [(ngModel)]="a && b"/>`
})
export class MyComp {}
// After
@Component({
template: `<input [ngModel]="a && b" (ngModelChange)="a && (b = $event)"/>`
})
export class MyComp {}
```
PR Close#54630
Contains the following minor improvements to the block entities migration:
* The migration won't be stopped anymore if it can't read a template file.
* The migration will exit early if a template doesn't contain the two characters we need to migrate.
* Reduced the amount of code that is wrapped by a try/catch to avoid suppressing errors.
PR Close#52209
PR #49672 added a g3-flavored migration for compiler option removal, but g3
doesn't use those options at all. So this migration is unnecessary and we
can remove it.
PR Close#52141
#51891 introduces a new syntax that assigns a new meaning to the `@` and `}` in Angular templates. This is problematic for existing apps which may have the characters in their templates already, because it can lead to syntax errors.
These changes add an `ng update` schematic that will replace any usages of the special characters with their HTML entities.
PR Close#51905
The class-based guard and resolver interfaces are deprecated. The
`Router` types only support functional guards definitions. Classes can
still be used as the underlying implementation of functional guards and
resolvers but there will not be an interface requiring a specific structure
for those classes.
There are also helper functions like `mapToCanActivate` that allow
converting the existing class-based guards directly to functional guards
at the route definition. This will be done in a separate migration.
PR Close#49337
Makes the following minor improvements to our current schematic utilities:
* `closestNode` now takes a TS predicate function instead of a `SyntaxKind`. This allows it automatically infer the type of the match.
* `getImportSpecifier` now accepts a regex for the module name. This will be useful for some upcoming migrations.
* Splits the logic for creating the migration program options into a separate function so that it's easier to reuse.
* `createMigrationProgram` now returns the program directly, instead of a literal with some other information.
* `FakeReadFileFn` and `createMigrationCompilerHost` aren't exported anymore since they aren't used anywhere.
PR Close#48790
This is basically a pre-step for combining devmode and prodmode into a
single compilation. We are already achieving this now, and can claim
with confidence that we reduced possible actions by half. This is
especially important now that prodmode is used more often, but rules
potentially still using the devmode ESM sources. We can avoid double
compilations (which existed before the whole ESM migration too!).
We will measure this more when we have more concrete documentation
of the changes & a better planning document.
Changes:
* ts_library will no longer generate devmode `d.ts`. Definitions are
generated as part of prodmode. That way only prodmode can be exposed
via providers.
* applied the same to `ng_module`.
* updates migrations to bundle because *everything* using `ts_library`
is now ESM. This is actually also useful in the future if
schematics rely on e.g. the compiler.
* updates schematics for localize to also bundle. similar reason as
above.
PR Close#48521
The Angular CLI does not yet support schematics running as ESM. For
this reason we switch the schematics BUILD targets to explicitly
use ESM (as an exception in the repo).
PR Close#48521
These migrations can no longer run due to a single update version policy (IE: from 13 to 14, 14 to 15 etc..). Therefore these are redundant and can be deleted.
We also remove the `-beta` suffix from the version which is not needed as the Angular CLI will add the prerelease suffixes automatically.
PR Close#48414
As of Angular v15, the deprecated `relativeLinkResolution` config option of the Router is removed. This migration cleans up (removes) the `relativeLinkResolution` fields from the Router config objects in applications code.
```ts
import { RouterModule } from '@angular/router';
RouterModule.forRoot([], {
relativeLinkResolution: 'legacy',
enableTracing: false,
});
```
```ts
import { RouterModule } from '@angular/router';
RouterModule.forRoot([], {
// the `relativeLinkResolution` is removed
enableTracing: false,
});
```
PR Close#47604
Since Angular v15, the `RouterLink` contains the logic of the `RouterLinkWithHref` directive and now developers can always import and use the `RouterLink` directive when they need to add a `[routerLink]` in templates. This migration finds all imports and usages of the `RouterLinkWithHref` class and rewrites them to `RouterLink` instead.
```ts
import { RouterLinkWithHref } from '@angular/router';
@Component({
standalone: true,
template: `<a [routerLink]="'/abc'">`,
imports: [RouterLinkWithHref]
})
export class MyComponent {
@ViewChild(RouterLinkWithHref) aLink!: RouterLinkWithHref;
}
```
```ts
import { RouterLink } from '@angular/router';
@Component({
standalone: true,
template: `<a [routerLink]="'/abc'">`,
imports: [RouterLink]
})
export class MyComponent {
@ViewChild(RouterLink) aLink!: RouterLink;
}
```
PR Close#47599
Places that use `pathMatch` need an explicit `Route` or `Routes` type on
the variable so TypeScript does not infer the type as just 'string'.
PR Close#45084
Previously, the migration only migrated constructor calls. Now, the migration will rewrite every usage, in all contexts. Both ways are technically correct, but migrating all symbols is likely to produce clearer and more readable results.
PR Close#45311
Consider a file that imports `FormControl` and then never uses it. In that case, we don't need to add the import for `UntypedFormControl`.
By examining constructor calls *first*, we can identify these cases and skip over them.
This will reduce the memory footprint of the migration when run in tsunami, hopefully making OOM errors less likely.
PR Close#45288
The typed forms migration was previously designed to add `<any>` type parameters to existing forms classes. However, due to some design changes, the new opt-out strategy requires untyped versions of the classes, as introduced in #45205 and #45268.
This PR updates the migration to import these new classes (in an idempotent manner), and replace constructor calls with the new classes. It respects qualified imports as well. Finally, the code has been refactored to move as much common code as possible into `util.ts`.
PR Close#45281
Proactively replaces our usages of the deprecated `ts.create*` methods in favor of using `ts.factory.create*` so that we're not surprised when the TS removes them in the future. Also accounts for some cases where the signature had changed.
PR Close#45134
When using `ng update` users cannot update multiple major versions at the same time. Therefore migrations that are not targeting version 14 cannot be run and therefore we are removing them.
PR Close#44857
Make the following fixes:
* When submitting the entire migration in a disabled state, I commented out more code than strictly required
* Responding to some final review comments caused two conditions to become flipped
* Always use explicit checks instead of boolean corecion
* Fix one missed any cast in a test case
PR Close#44540
This migration will insert `<AnyForUntypedForms>` or `<AnyForUntypedForms[]>` at existing uses of `AbstractControl` classes, as well as calls to `FormBuilder` methods.
We need to submit this ahead of time in order to get started with the migration in google3.
PR Close#44449
Set up exporting the migration rules from the google3 directly from the internal
@angular/migrations package. This package is an internal only package to be
exposed for loading TSLint rules.
PR Close#43980
The `NgComponentTemplateVisitor` helper was always referring back to the original source file on disk
rather than the virtual file in the migration. This meant that some template migrations could attempt
to modify the template multiple times resulting in invalid output.
As an example the `migration-v13-router-link-empty-expression` migrates the following template:
```
<div [routerLink]></div>
```
to
```
<div [routerLink]="[]"></div>
```
But if the template was referenced multiple times in the program, such as when the component was
referenced in the source and test entry-points, the migration would result in things like:
```
<div [routerLink]="[]"="[]"></div>
```
Fixes#44005.
PR Close#44013
With this change we remove no longer needed migrations. These migrations are no longer accessible following a change angular/angular-cli#21986 in the Angular CLI. The CLI now shows an error message when users try to update `@angular/` and `@nguniversal/` packages across multiple major versions.
Example to update from version 11 to version 13 the recommand approach is to run the following commands
```
ng update @angular/core@12
ng update @angular/core@13 (which is the same as ng update @angular/core)
```
NB: It is recommand that when update from one major to another, users verify that their applications is working as expected.
PR Close#43947
With this change we remove no longer needed migrations. These migrations are no longer accessible following a change https://github.com/angular/angular-cli/pull/21986 in the Angular CLI. The CLI now shows an error message when users try to update `@angular/` and `@nguniversal/` packages across multiple major versions.
Example to update from version 11 to version 13 the recommand approach is to run the following commands
```
ng update @angular/core@12
ng update @angular/core@13 (which is the same as ng update @angular/core)
```
NB: It is recommand that when update from one major to another, users verify that their applications is working as expected.
PR Close#43942
Currently the TestBed teardown migration is set up in a similar way to all other migrations where we take a `CallExpression`, add a parameter to it, print it, and replace the existing call. The problem is that doing so while preserving the `expression` of the original `CallExpression` can cause comments to be duplicated. This can happen quite frequently, because by default the CLI generates comments before `initTestModule` calls.
To work around it, these changes make the migration more precise by inserting a new parameter or replacing and existing one using string manipulation.
This requires a bit more code, but it's more reliable than the following alternatives:
1. Using `getFullStart` and `getFullWidth` to replace the node. This would work with our current setup, but the problem is that `getFullStart` also includes whitespace and newlines before the leading comment. This can cause us to mess up the user's formatting and figuring out which whitespace to keep and which one to remove is tricky.
2. Recreating the `CallExpression.expression` when constructing the new node. This would also work since it'll drop any existing comments, but the problem is that `CallExpression.expression` can be a wide variety of nodes which we would have to account for. We can't use `getMutableClone`, because it preserves the comments.
Fixes#43739.
PR Close#43776
Since the `destroyAfterEach` teardown behavior is enabled by default now, existing tests that depended on the old behavior can start to fail. These changes add an automated migration that explicitly adds `destroyAfterEach: false` to existing tests.
The migration works by looking for `initTestEnvironment` calls across the entire app and adding the flag to them. If no calls were found, the migration will add the flag to all `configureTestingModule` and `withModule` calls instead.
PR Close#43353
Currently, migrations and schematics must be in CommonJS format. However, framework packages will only be ESM from v13 and onward. To support this configuration, dynamic import expressions are now used to load `@angular/compiler-cli` and its new secondary entry point `@angular/compiler-cli/private/migrations`. Dynamic imports within Node.js allow the `@angular/core` migrations’ CommonJS code to load ESM code. Unfortunately, TypeScript will currently, unconditionally down-level dynamic import into a require call. `require` calls cannot load ESM code and will result in a runtime error. To workaround this, a Function constructor is used to prevent TypeScript from changing the dynamic import. Once TypeScript provides support for keeping the dynamic import this workaround can be dropped and replaced with a standard dynamic import. Due to the use of the dynamic import, a reference to the dynamically loaded modules must now be passed to all locations that use values from the modules.
PR Close#43657
As outlined in the previous commit which enabled the `esModuleInterop`
TypeScript compiler option, we need to update all namespace imports
for `typescript` to default imports. This is needed to allow for
TypeScript to be imported at runtime from an ES module.
Similar changes are needed for modules like `semver` where the types incorrectly
suggest named exports that will not exist at runtime when imported from ESM.
This commit refactors all imports to match with the lint rule we have
configured in the previous commit. See the previous commit for more
details on why certain imports have been changed.
A special case are the imports to `@babel/core` and `@babel/types`. For
these a special interop is needed as both default imports, or named
imports break the other module format. e.g default imports would work
well for ESM, but it breaks for CJS. For CJS, the named imports would
only work, but in ESM, only the default export exist. We work around
this for now until the devmode is using ESM as well (which would be
consistent with prodmode and gives us more valuable test results). More
details on the interop can be found in the `babel_core.ts` files (two
interops are needed for both localize/or the compiler-cli).
PR Close#43431
The Angular Core and localize package currently use deep imports for
code that is shipped. This is problematic as we want to ship the
compiler-cli as full-ESM. To achieve this we need to use a bundler and
this breaks deep imports.
We use a bundler for the compiler CLI because for full ESM
compatibility, we would need to explicitly add the `.js` extension
to all relative imports. This is very cumbersome and prone to mistakes
so to mitigate this problem in a safe way, we bundle the compiler-cli.
Note: Deep imports continue to exist for the language service as it
bundles the compiler-cli.
PR Close#43431
This reverts commit ab3de40ba3, which is
itself a revert of the original commit. Thus, this restores the changes
to schematics in support of ESM.
Now that g3 has a local modification for load_esm, we can restore this
functionality.
PR Close#43637
Currently, migrations and schematics must be in CommonJS format. However, framework packages will only be ESM from v13 and onward. To support this configuration, dynamic import expressions are now used to load `@angular/compiler`. Dynamic imports within Node.js allow the `@angular/core` migrations’ CommonJS code to load ESM code. Unfortunately, TypeScript will currently, unconditionally down-level dynamic import into a require call. `require` calls cannot load ESM code and will result in a runtime error. To workaround this, a Function constructor is used to prevent TypeScript from changing the dynamic import. Once TypeScript provides support for keeping the dynamic import this workaround can be dropped and replaced with a standard dynamic import. Due to the use of the dynamic import, a reference to the compiler module must now be passed to all locations that use values from the `@angular/compiler` package.
PR Close#43627
A base class that can be used to implement a Render3 Template AST visitor is now used throughout the `@angular/core` migrations. This class is used instead of the `NullVisitor` found within the `@angular/compiler` because the `NullVisitor` requires a deep import which is no longer supported with the ESM bundled packages as of v13. The `NullVisitor` is also fairly trivial in regards to its implementation and the new base class also provides additional helper methods for migration specific behavior. This removes all remaining deep imports of the `@angular/compiler` package from the `@angular/core` migrations while avoiding the need to modify the `@angular/compiler` package.
PR Close#43627
Most of the deep imports into the `@angular/compiler` package in the `@angular/core` migrations are for template AST types that are available as exports from the main entry point of the package (albeit under slightly different names). For the available main entry point exports, the deep imports have been transitioned to no longer use the deep import.
PR Close#43627
The previous replacement logic would not account for the CRLF line
endings when applying replacements because it would replace the whole
template with `template.content.length` which would not account for
CRLF. This update applies individual expression edits at each location
in the template rather than attempting to replace the whole template
contents with a new string that contains the migrations.
fixes#43416
PR Close#43519
The migration was previously touching files that did not have any
expressions to migrate. This change ensures that the migration doesn't
commit any updates on files that do not need them.
This change, however, does not address the underlying issue with the
migration and CRLF (which is fixed in a follow-up change).
Related to #43416
PR Close#43519
With this change we change the logic to locate the tsconfig files. The public API to locate, read and parse the workspace configuration should be use instead of the custom implemented logic.
The custom implemented logic depended on methods which have long been deprecated and are not removed in version 13 of the Angular CLI. This was not caught during development/UT because this repo is using outdated Angular Tooling packages.
This change also updates a number of spec files which previously creating an invalid Angular workspace configuration file.
Closes#43334
PR Close#43343