Skip to content

Commit d7440c4

Browse files
petebacondarwinkara
authored andcommitted
fix(ngcc): ensure reflection hosts can handle TS 3.9 IIFE wrapped classes (#36989)
In TS 3.9, ES2015 output can contain ES classes that are wrapped in an IIFE. So now ES2015 class declarations can look like one of: ``` class OuterClass1 {} ``` ``` let OuterClass = class InnerClass {}; ``` ``` var AliasClass; let OuterClass = AliasClass = class InnerClass {}; ``` ``` let OuterClass = (() => class InnerClass {}}; ``` ``` var AliasClass; let OuterClass = AliasClass = (() => class InnerClass {})(); ``` ``` let OuterClass = (() => { let AdjacentClass = class InnerClass {}; // ... static properties or decorators attached to `AdjacentClass` return AdjacentClass; })(); ``` ``` var AliasClass; let OuterClass = AliasClass = (() => { let AdjacentClass = class InnerClass {}; // ... static properties or decorators attached to `AdjacentClass` return AdjacentClass; })(); ``` The `Esm5ReflectionHost` already handles slightly different IIFE wrappers around function-based classes. This can be substantially reused when fixing `Esm2015ReflectionHost`, since there is a lot of commonality between the two. This commit moves code from the `Esm5ReflectionHost` into the `Esm2015ReflectionHost` and looks to share as much as possible between the two hosts. PR Close #36989
1 parent a2b8dc1 commit d7440c4

File tree

8 files changed

+793
-468
lines changed

8 files changed

+793
-468
lines changed

packages/compiler-cli/ngcc/src/host/esm2015_host.ts

Lines changed: 464 additions & 199 deletions
Large diffs are not rendered by default.

packages/compiler-cli/ngcc/src/host/esm5_host.ts

Lines changed: 80 additions & 238 deletions
Large diffs are not rendered by default.

packages/compiler-cli/ngcc/src/host/ngcc_host.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ export interface NgccClassSymbol {
4848
* declaration.
4949
*/
5050
implementation: ts.Symbol;
51+
52+
/**
53+
* Represents the symbol corresponding to a variable within a class IIFE that may be used to
54+
* attach static properties or decorated.
55+
*/
56+
adjacent?: ts.Symbol;
5157
}
5258

5359
/**

packages/compiler-cli/ngcc/test/host/commonjs_host_spec.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {getDeclaration} from '../../../src/ngtsc/testing';
1414
import {loadFakeCore, loadTestFiles} from '../../../test/helpers';
1515
import {CommonJsReflectionHost} from '../../src/host/commonjs_host';
1616
import {DelegatingReflectionHost} from '../../src/host/delegating_host';
17-
import {getIifeBody} from '../../src/host/esm5_host';
17+
import {getIifeBody} from '../../src/host/esm2015_host';
1818
import {NgccReflectionHost} from '../../src/host/ngcc_host';
1919
import {BundleProgram} from '../../src/packages/bundle_program';
2020
import {MockLogger} from '../helpers/mock_logger';
@@ -2212,7 +2212,8 @@ exports.MissingClass2 = MissingClass2;
22122212
createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle));
22132213
const outerNode = getDeclaration(
22142214
bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration);
2215-
const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!;
2215+
const innerNode = (getIifeBody(outerNode.initializer!) as ts.Block)
2216+
.statements.find(isNamedFunctionDeclaration)!;
22162217
const classSymbol = host.getClassSymbol(outerNode);
22172218

22182219
expect(classSymbol).toBeDefined();
@@ -2227,7 +2228,8 @@ exports.MissingClass2 = MissingClass2;
22272228
createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle));
22282229
const outerNode = getDeclaration(
22292230
bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration);
2230-
const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!;
2231+
const innerNode = (getIifeBody(outerNode.initializer!) as ts.Block)
2232+
.statements.find(isNamedFunctionDeclaration)!;
22312233
const classSymbol = host.getClassSymbol(innerNode);
22322234

22332235
expect(classSymbol).toBeDefined();
@@ -2243,7 +2245,8 @@ exports.MissingClass2 = MissingClass2;
22432245
createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle));
22442246
const outerNode = getDeclaration(
22452247
bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration);
2246-
const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!;
2248+
const innerNode = (getIifeBody(outerNode.initializer!) as ts.Block)
2249+
.statements.find(isNamedFunctionDeclaration)!;
22472250

22482251
const innerSymbol = host.getClassSymbol(innerNode)!;
22492252
const outerSymbol = host.getClassSymbol(outerNode)!;
@@ -2260,7 +2263,8 @@ exports.MissingClass2 = MissingClass2;
22602263
const outerNode = getDeclaration(
22612264
bundle.program, SIMPLE_CLASS_FILE.name, 'NoParensClass',
22622265
isNamedVariableDeclaration);
2263-
const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!;
2266+
const innerNode = (getIifeBody(outerNode.initializer!) as ts.Block)
2267+
.statements.find(isNamedFunctionDeclaration)!;
22642268
const classSymbol = host.getClassSymbol(outerNode);
22652269

22662270
expect(classSymbol).toBeDefined();
@@ -2277,7 +2281,8 @@ exports.MissingClass2 = MissingClass2;
22772281
const outerNode = getDeclaration(
22782282
bundle.program, SIMPLE_CLASS_FILE.name, 'InnerParensClass',
22792283
isNamedVariableDeclaration);
2280-
const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!;
2284+
const innerNode = (getIifeBody(outerNode.initializer!) as ts.Block)
2285+
.statements.find(isNamedFunctionDeclaration)!;
22812286
const classSymbol = host.getClassSymbol(outerNode);
22822287

22832288
expect(classSymbol).toBeDefined();
@@ -2345,7 +2350,8 @@ exports.MissingClass2 = MissingClass2;
23452350
createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle));
23462351
const outerNode = getDeclaration(
23472352
bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isVariableDeclaration);
2348-
const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!;
2353+
const innerNode = (getIifeBody(outerNode.initializer!) as ts.Block)
2354+
.statements.find(isNamedFunctionDeclaration)!;
23492355
expect(host.isClass(innerNode)).toBe(true);
23502356
});
23512357

0 commit comments

Comments
 (0)