diff --git a/packages/core/src/reflection/reflection_capabilities.ts b/packages/core/src/reflection/reflection_capabilities.ts index 744f3053810..b2e1ae694e7 100644 --- a/packages/core/src/reflection/reflection_capabilities.ts +++ b/packages/core/src/reflection/reflection_capabilities.ts @@ -63,7 +63,7 @@ export const ES2015_INHERITED_CLASS_WITH_CTOR = * and inherit a constructor. */ export const ES2015_INHERITED_CLASS_WITH_DELEGATE_CTOR = - /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(\)\s*{\s*super\(\.\.\.arguments\)/; + /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(\)\s*{[^}]*super\(\.\.\.arguments\)/; /** * Determine whether a stringified type is a class which delegates its constructor diff --git a/packages/core/test/reflection/reflector_spec.ts b/packages/core/test/reflection/reflector_spec.ts index 556182c4cd4..9af4fd30b90 100644 --- a/packages/core/test/reflection/reflector_spec.ts +++ b/packages/core/test/reflection/reflector_spec.ts @@ -292,6 +292,51 @@ class TestObj { expect(isDelegateCtor(ChildWithCtorComplexBase)).toBe(false); }); + it('should deal with coverage instrumentation statements', () => { + // The Istanbul coverage tool augments code with additional statements to capture coverage + // information, and this test verifies that those do not interfere with our ability to + // detect delegate constructors. + const Es2015ClassNoCtor = `class TestService extends Parent { + constructor() { + cov_8nt6qq5zt().f[2]++; + cov_8nt6qq5zt().s[6]++; + super(...arguments); + cov_8nt6qq5zt().s[7]++; + this.foo = 'bar'; + } + }`; + const Es2015ClassWithCtor = `class TestService extends Parent { + constructor() { + cov_8nt6qq5zt().f[2]++; + cov_8nt6qq5zt().s[6]++; + super(); + cov_8nt6qq5zt().s[7]++; + this.foo = 'bar'; + } + }`; + const Es5ClassNoCtor = `function TestService() { + cov_8nt6qq5zt().f[4]++; + var _this = (cov_8nt6qq5zt().s[8]++, (cov_8nt6qq5zt().b[0][0]++, _super !== null) && (cov_8nt6qq5zt().b[0][1]++, _super.apply(this, arguments)) || (cov_8nt6qq5zt().b[0][2]++, this)); + cov_8nt6qq5zt().s[9]++; + _this.foo = 'bar'; + cov_8nt6qq5zt().s[10]++; + return _this; + }`; + const Es5ClassWithCtor = `function TestService() { + cov_8nt6qq5zt().f[4]++; + var _this = _super.call(); + cov_8nt6qq5zt().s[9]++; + _this.foo = 'bar'; + cov_8nt6qq5zt().s[10]++; + return _this; + }`; + + expect(isDelegateCtor(Es2015ClassNoCtor)).toBe(true); + expect(isDelegateCtor(Es2015ClassWithCtor)).toBe(false); + expect(isDelegateCtor(Es5ClassNoCtor)).toBe(true); + expect(isDelegateCtor(Es5ClassWithCtor)).toBe(false); + }); + it('should properly handle all class forms', () => { const ctor = (str: string) => expect(isDelegateCtor(str)).toBe(false); const noCtor = (str: string) => expect(isDelegateCtor(str)).toBe(true); @@ -299,6 +344,7 @@ class TestObj { ctor(`class Bar extends Foo {constructor(){}}`); ctor(`class Bar extends Foo { constructor ( ) {} }`); ctor(`class Bar extends Foo { other(){}; constructor(){} }`); + ctor(`class Bar extends Foo { constructor(){} a(){super(...arguments)} }`); noCtor(`class extends Foo{}`); noCtor(`class extends Foo {}`);