forked from angular/angular
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(core): detect DI parameters in JIT mode for downleveled ES2015 cl…
…asses (angular#38463) In the Angular Package Format, we always shipped UMD bundles and previously even ES5 module output. With V10, we removed the ES5 module output but kept the UMD ES5 output. For this, we were able to remove our second TypeScript transpilation. Instead we started only building ES2015 output and then downleveled it to ES5 UMD for the NPM packages. This worked as expected but unveiled an issue in the `@angular/core` reflection capabilities. In JIT mode, Angular determines constructor parameters (for DI) using the `ReflectionCapabilities`. The reflection capabilities basically read runtime metadata of classes to determine the DI parameters. Such metadata can be either stored in static class properties like `ctorParameters` or within TypeScript's `design:params`. If Angular comes across a class that does not have any parameter metadata, it tries to detect if the given class is actually delegating to an inherited class. It does this naively in JIT by checking if the stringified class (function in ES5) matches a certain pattern. e.g. ```js function MatTable() { var _this = _super.apply(this, arguments) || this; ``` These patterns are reluctant to changes of the class output. If a class is not recognized properly, the DI parameters will be assumed empty and the class is **incorrectly** constructed without arguments. This actually happened as part of v10 now. Since we downlevel ES2015 to ES5 (instead of previously compiling sources directly to ES5), the class output changed slightly so that Angular no longer detects it. e.g. ```js var _this = _super.apply(this, __spread(arguments)) || this; ``` This happens because the ES2015 output will receive an auto-generated constructor if the class defines class properties. This constructor is then already containing an explicit `super` call. ```js export class MatTable extends CdkTable { constructor() { super(...arguments); this.disabled = true; } } ``` If we then downlevel this file to ES5 with `--downlevelIteration`, TypeScript adjusts the `super` call so that the spread operator is no longer used (not supported in ES5). The resulting super call is different to the super call that would have been emitted if we would directly transpile to ES5. Ultimately, Angular no longer detects such classes as having an delegate constructor -> and DI breaks. We fix this by expanding the rather naive RegExp patterns used for the reflection capabilities so that downleveled pass-through/delegate constructors are properly detected. There is a risk of a false-positive as we cannot detect whether `__spread` is actually the TypeScript spread helper, but given the reflection patterns already make lots of assumptions (e.g. that `super` is actually the superclass, we should be fine making this assumption too. The false-positive would not result in a broken app, but rather in unnecessary providers being injected (as a noop). Fixes angular#38453 PR Close angular#38463
- Loading branch information
1 parent
81c3e80
commit ca07da4
Showing
6 changed files
with
108 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
packages/core/test/reflection/es2015_inheritance_fixture.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC 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 | ||
*/ | ||
|
||
// AMD module name is required so that this file can be loaded in the Karma tests. | ||
/// <amd-module name="angular/packages/core/test/reflection/es5_downleveled_inheritance_fixture" /> | ||
|
||
class Parent {} | ||
|
||
export class ChildNoCtor extends Parent {} | ||
export class ChildWithCtor extends Parent { | ||
constructor() { | ||
super(); | ||
} | ||
} | ||
export class ChildNoCtorPrivateProps extends Parent { | ||
x = 10; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters