fix(ngcc): support minified ES5 scenarios (#33777)

The reflection hosts have been updated to support the following
code forms, which were found in some minified library code:

* The class IIFE not being wrapped in parentheses.
* Calls to `__decorate()` being combined with the IIFE return statement.

PR Close #33777
This commit is contained in:
Pete Bacon Darwin
2019-11-13 08:40:51 +00:00
committed by Kara Erickson
parent d21471e24e
commit 1e1e242570
6 changed files with 210 additions and 15 deletions

View File

@ -1104,7 +1104,8 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
* does not match.
*/
protected getHelperCall(statement: ts.Statement, helperNames: string[]): ts.CallExpression|null {
if (ts.isExpressionStatement(statement)) {
if ((ts.isExpressionStatement(statement) || ts.isReturnStatement(statement)) &&
statement.expression) {
let expression = statement.expression;
while (isAssignment(expression)) {
expression = expression.right;

View File

@ -11,7 +11,7 @@ import * as ts from 'typescript';
import {ClassDeclaration, ClassMember, ClassMemberKind, Declaration, Decorator, FunctionDefinition, Parameter, TsHelperFn, isNamedVariableDeclaration, reflectObjectLiteral} from '../../../src/ngtsc/reflection';
import {getNameText, hasNameIdentifier, stripDollarSuffix} from '../utils';
import {Esm2015ReflectionHost, ParamInfo, getPropertyValueFromSymbol, isAssignmentStatement} from './esm2015_host';
import {Esm2015ReflectionHost, ParamInfo, getPropertyValueFromSymbol, isAssignment, isAssignmentStatement} from './esm2015_host';
import {NgccClassSymbol} from './ngcc_host';
/**
@ -602,23 +602,36 @@ function getClassDeclarationFromInnerFunctionDeclaration(node: ts.Node):
}
export function getIifeBody(declaration: ts.Declaration): ts.Block|undefined {
if (!ts.isVariableDeclaration(declaration) || !declaration.initializer ||
!ts.isParenthesizedExpression(declaration.initializer)) {
if (!ts.isVariableDeclaration(declaration) || !declaration.initializer) {
return undefined;
}
const call = declaration.initializer;
return ts.isCallExpression(call.expression) &&
ts.isFunctionExpression(call.expression.expression) ?
call.expression.expression.body :
undefined;
const call = stripParentheses(declaration.initializer);
if (!ts.isCallExpression(call)) {
return undefined;
}
const fn = stripParentheses(call.expression);
if (!ts.isFunctionExpression(fn)) {
return undefined;
}
return fn.body;
}
function getReturnIdentifier(body: ts.Block): ts.Identifier|undefined {
const returnStatement = body.statements.find(ts.isReturnStatement);
return returnStatement && returnStatement.expression &&
ts.isIdentifier(returnStatement.expression) ?
returnStatement.expression :
undefined;
if (!returnStatement || !returnStatement.expression) {
return undefined;
}
if (ts.isIdentifier(returnStatement.expression)) {
return returnStatement.expression;
}
if (isAssignment(returnStatement.expression) &&
ts.isIdentifier(returnStatement.expression.left)) {
return returnStatement.expression.left;
}
return undefined;
}
function getReturnStatement(declaration: ts.Expression | undefined): ts.ReturnStatement|undefined {