Skip to content

Commit 274dc15

Browse files
JoostKjosephperrott
authored andcommitted
fix(core): detect synthesized constructors that have been downleveled using TS 4.2 (angular#41305)
TypeScript 4.2 has changed its emitted syntax for synthetic constructors when using `downlevelIteration`, which affects ES5 bundles that have been downleveled from ES2015 bundles. This is typically the case for UMD bundles in the APF spec, as they are generated by downleveling the ESM2015 bundle into ES5. The reflection capabilities in the runtime need to recognize this new form to correctly deal with synthesized constructors, as otherwise JIT compilation could generate invalid factory functions. Fixes angular#41298 PR Close angular#41305
1 parent 8d3da56 commit 274dc15

File tree

3 files changed

+50
-8
lines changed

3 files changed

+50
-8
lines changed

packages/core/src/reflection/reflection_capabilities.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,22 @@ import {GetterFn, MethodFn, SetterFn} from './types';
3434
* var _this = _super.apply(this, arguments) || this;
3535
* ```
3636
*
37+
* downleveled to ES5 with `downlevelIteration` for TypeScript < 4.2:
3738
* ```
3839
* function MyClass() {
3940
* var _this = _super.apply(this, __spread(arguments)) || this;
4041
* ```
4142
*
43+
* or downleveled to ES5 with `downlevelIteration` for TypeScript >= 4.2:
44+
* ```
45+
* function MyClass() {
46+
* var _this = _super.apply(this, __spreadArray([], __read(arguments))) || this;
47+
* ```
48+
*
4249
* More details can be found in: https://github.com/angular/angular/issues/38453.
4350
*/
4451
export const ES5_DELEGATE_CTOR =
45-
/^function\s+\S+\(\)\s*{[\s\S]+\.apply\(this,\s*(arguments|[^()]+\(arguments\))\)/;
52+
/^function\s+\S+\(\)\s*{[\s\S]+\.apply\(this,\s*(arguments|(?:[^()]+\(\[\],)?[^()]+\(arguments\))\)/;
4653
/** Regular expression that detects ES2015 classes which extend from other classes. */
4754
export const ES2015_INHERITED_CLASS = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{/;
4855
/**

packages/core/test/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ genrule(
2727
$(execpath @npm//typescript/bin:tsc) $< --outDir $$es2015_out_dir --target ES2015 \
2828
--types --module umd
2929
$(execpath @npm//typescript/bin:tsc) --outFile $@ $$es2015_out_file --allowJs \
30-
--types --target ES5
30+
--types --target ES5 --downlevelIteration
3131
""",
3232
tools = ["@npm//typescript/bin:tsc"],
3333
)

packages/core/test/reflection/reflector_spec.ts

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -202,13 +202,48 @@ class TestObj {
202202
});
203203

204204
// See: https://github.com/angular/angular/issues/38453
205-
it('should support ES2015 downleveled classes', () => {
206-
const {ChildNoCtor, ChildNoCtorPrivateProps, ChildWithCtor} =
207-
require('./es5_downleveled_inheritance_fixture');
205+
it('should support ES2015 downleveled classes (workspace TypeScript version) (downlevelIteration=true)',
206+
() => {
207+
const {ChildNoCtor, ChildNoCtorPrivateProps, ChildWithCtor} =
208+
require('./es5_downleveled_inheritance_fixture');
209+
210+
expect(isDelegateCtor(ChildNoCtor.toString())).toBe(true);
211+
expect(isDelegateCtor(ChildNoCtorPrivateProps.toString())).toBe(true);
212+
expect(isDelegateCtor(ChildWithCtor.toString())).toBe(false);
213+
});
214+
215+
it('should support ES2015 downleveled classes (<TS4.2) (downlevelIteration=true)', () => {
216+
const ChildNoCtor = `function ChildNoCtor() {
217+
return _super !== null && _super.apply(this, arguments) || this;
218+
}`;
219+
const ChildNoCtorPrivateProps = `function ChildNoCtorPrivateProps() {
220+
var _this = _super.apply(this, __spread(arguments)) || this;
221+
_this.x = 10;
222+
return _this;
223+
}`;
224+
const ChildWithCtor = `function ChildWithCtor() {
225+
return _super.call(this) || this;
226+
}`;
227+
expect(isDelegateCtor(ChildNoCtor)).toBe(true);
228+
expect(isDelegateCtor(ChildNoCtorPrivateProps)).toBe(true);
229+
expect(isDelegateCtor(ChildWithCtor)).toBe(false);
230+
});
208231

209-
expect(isDelegateCtor(ChildNoCtor.toString())).toBe(true);
210-
expect(isDelegateCtor(ChildNoCtorPrivateProps.toString())).toBe(true);
211-
expect(isDelegateCtor(ChildWithCtor.toString())).toBe(false);
232+
it('should support ES2015 downleveled classes (>=TS4.2) (downlevelIteration=true)', () => {
233+
const ChildNoCtor = `function ChildNoCtor() {
234+
return _super !== null && _super.apply(this, arguments) || this;
235+
}`;
236+
const ChildNoCtorPrivateProps = `function ChildNoCtorPrivateProps() {
237+
var _this = _super.apply(this, __spreadArray([], __read(arguments))) || this;
238+
_this.x = 10;
239+
return _this;
240+
}`;
241+
const ChildWithCtor = `function ChildWithCtor() {
242+
return _super.call(this) || this;
243+
}`;
244+
expect(isDelegateCtor(ChildNoCtor)).toBe(true);
245+
expect(isDelegateCtor(ChildNoCtorPrivateProps)).toBe(true);
246+
expect(isDelegateCtor(ChildWithCtor)).toBe(false);
212247
});
213248

214249
it('should support ES2015 classes when minified', () => {

0 commit comments

Comments
 (0)